nux-4.0.8+18.10.20180623/0000755000000000000000000000000015136456560010605 5ustar nux-4.0.8+18.10.20180623/AUTHORS0000644000000000000000000000004213313373365011645 0ustar Jay Taoko nux-4.0.8+18.10.20180623/COPYING0000644000000000000000000001672713313373365011651 0ustar 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. nux-4.0.8+18.10.20180623/COPYING.gpl0000644000000000000000000010437413313373365012426 0ustar GNU 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. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . nux-4.0.8+18.10.20180623/COPYING.lgpl-v2.10000644000000000000000000006364213313373365013270 0ustar GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.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. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! nux-4.0.8+18.10.20180623/ChangeLog0000644000000000000000000000000113313373365012342 0ustar nux-4.0.8+18.10.20180623/INSTALL0000644000000000000000000003661013313373365011640 0ustar Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command `./configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. nux-4.0.8+18.10.20180623/Makefile.am0000644000000000000000000000057413313373365012643 0ustar SUBDIRS = data NuxCore NuxGraphics Nux examples gputests tests tools CXXFLAGS += -fno-permissive include $(top_srcdir)/Makefile.am.coverage include doxygen-include.am if BUILD_DOCUMENTATION all: doxygen-doc endif DISTCLEANFILES = doc/html/* doc/* EXTRA_DIST = $(DX_CONFIG) autogen.sh COPYING.gpl COPYING.lgpl-v2.1 .bzrignore check-headless: cd tests; $(MAKE) check-headless nux-4.0.8+18.10.20180623/Makefile.am.coverage0000644000000000000000000000257213313373365014435 0ustar # Coverage targets .PHONY: clean-gcno clean-gcda \ coverage-html generate-coverage-html clean-coverage-html \ coverage-gcovr generate-coverage-gcovr clean-coverage-gcovr clean-local: clean-gcno clean-coverage-html clean-coverage-gcovr if HAVE_GCOV clean-gcno: @echo Removing old coverage instrumentation -find -name '*.gcno' -print | xargs -r rm clean-gcda: @echo Removing old coverage results -find -name '*.gcda' -print | xargs -r rm coverage-html: -$(MAKE) $(AM_MAKEFLAGS) -k check $(MAKE) $(AM_MAKEFLAGS) generate-coverage-html generate-coverage-html: @echo Collecting coverage data $(LCOV) --directory $(top_builddir) --capture --output-file coverage.info --no-checksum --compat-libtool $(LCOV) --extract coverage.info "$(abs_top_srcdir)/*" -o coverage.info LANG=C $(GENHTML) --prefix $(top_builddir) --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info clean-coverage-html: clean-gcda -$(LCOV) --directory $(top_builddir) -z -rm -rf coverage.info coveragereport if HAVE_GCOVR coverage-gcovr: -$(MAKE) $(AM_MAKEFLAGS) -k check $(MAKE) $(AM_MAKEFLAGS) generate-coverage-gcovr generate-coverage-gcovr: @echo Generating coverage GCOVR report $(GCOVR) --xml -r $(top_builddir) -o $(top_builddir)/coverage.xml clean-coverage-gcovr: clean-gcda -rm -rf $(top_builddir)/coverage.xml endif # HAVE_GCOVR endif # HAVE_GCOV nux-4.0.8+18.10.20180623/NEWS0000644000000000000000000000000213313373365011270 0ustar nux-4.0.8+18.10.20180623/Nux/0000755000000000000000000000000013313373365011353 5ustar nux-4.0.8+18.10.20180623/Nux/ABI.h.in0000644000000000000000000000053213313373365012524 0ustar #ifndef ABI_H #define ABI_H // Increase the number (to the current date) everytime you propose a branch that breaks the API or ABI // The number format is : year/month/day // e.g.: december 1st, 2011 is: 20111201 // So far there is no provision for more than one break in a day. #define NUX_ABIVERSION @NUX_ABI_VERSION@ #endif // ABI_H nux-4.0.8+18.10.20180623/Nux/AbstractButton.cpp0000644000000000000000000001024513313373365015020 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * Gordon Allott * */ #include "Nux.h" #include "AbstractButton.h" #include "StaticText.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(AbstractButton); AbstractButton::AbstractButton(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , visual_state_(VISUAL_STATE_NORMAL) { active_ = false; mouse_pressed_ = false; static_text_ = NULL; label_color_ = color::White; same_size_as_content_ = false; label_font_size_ = 0; // use default point size defined in nux::StaticText mouse_click.connect(sigc::mem_fun(this, &AbstractButton::RecvClick)); mouse_down.connect(sigc::mem_fun(this, &AbstractButton::RecvMouseDown)); mouse_double_click.connect(sigc::mem_fun(this, &AbstractButton::RecvMouseDown)); mouse_up.connect(sigc::mem_fun(this, &AbstractButton::RecvMouseUp)); mouse_move.connect(sigc::mem_fun(this, &AbstractButton::RecvMouseMove)); mouse_enter.connect(sigc::mem_fun(this, &AbstractButton::RecvMouseEnter)); mouse_leave.connect(sigc::mem_fun(this, &AbstractButton::RecvMouseLeave)); } AbstractButton::~AbstractButton() { } bool AbstractButton::Active() const { return active_; } void AbstractButton::SetActive(bool active) { if (active) Activate(); else Deactivate(); } ButtonVisualState AbstractButton::GetVisualState() { return visual_state_; } void AbstractButton::RecvMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (IsMousePointerInside()) { visual_state_ = VISUAL_STATE_PRELIGHT; } else { visual_state_ = VISUAL_STATE_NORMAL; } mouse_pressed_ = false; visual_state_change.emit(this); QueueDraw(); } void AbstractButton::RecvMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { visual_state_ = VISUAL_STATE_PRESSED; mouse_pressed_ = true; visual_state_change.emit(this); QueueDraw(); } void AbstractButton::RecvMouseMove(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { } void AbstractButton::RecvMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (mouse_pressed_) { visual_state_ = VISUAL_STATE_PRESSED; } else { visual_state_ = VISUAL_STATE_PRELIGHT; } visual_state_change.emit(this); QueueDraw(); } void AbstractButton::RecvMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { visual_state_ = VISUAL_STATE_NORMAL; visual_state_change.emit(this); QueueDraw(); } void AbstractButton::SetLabelColor(const Color &color) { label_color_ = color; if (static_text_) static_text_->SetTextColor(label_color_); QueueDraw(); } Color AbstractButton::GetLabelColor() { return label_color_; } ButtonVisualState AbstractButton::GetVisualState() const { return visual_state_; } void AbstractButton::SetLabelFontSize(int point) { if (point < 0) return; label_font_size_ = point; if (static_text_) { static_text_->SetTextPointSize(label_font_size_); ComputeContentSize(); QueueDraw(); } } int AbstractButton::GetLabelFontSize() const { return label_font_size_; } } nux-4.0.8+18.10.20180623/Nux/AbstractButton.h0000644000000000000000000001040113313373365014457 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ABSTRACTBUTTON_H #define ABSTRACTBUTTON_H #include "View.h" #include "NuxCore/Property.h" namespace nux { class StaticText; enum ButtonVisualState { VISUAL_STATE_PRESSED = 0, VISUAL_STATE_NORMAL = 1, VISUAL_STATE_PRELIGHT = 2, VISUAL_STATE_DISABLED = 3 }; //! The base class of button type widgets. /*! AbstractButton is the direct base class of Button, CheckBox and RadioButton. It is a base class for ToggleButton. */ class AbstractButton : public View { NUX_DECLARE_OBJECT_TYPE(AbstractButton, View); public: AbstractButton(NUX_FILE_LINE_PROTO); virtual ~AbstractButton(); sigc::signal visual_state_change; //! Returns the visual state of the AbstractButton /*! Returns the visual state of the AbstractButton. @return The visual state of the AbstractButton. */ ButtonVisualState GetVisualState(); //! Return the active state of the button. /*! Return the active state of the button. A Button has a non-persistent active state. It always returns false. CheckBox, RadionButton and ToggleButton return true if they are active. @return True if the button object is in an active state. */ bool Active() const; //! Activate the button. /*! Activate the button. If this object is a Button, then it has no persistent state and the function does nothing. */ virtual void Activate() = 0; //! Deactivate the button. /*! Deactivate the button. If this object is a Button, then it has no persistent state and the function does nothing. */ virtual void Deactivate() = 0; //! Set the state of the button. /*! Set the sate of the button. The button is either activated or deactivated. @param active The button state. */ virtual void SetActive(bool active); //! Set the text color. /*! Set the text color. @param color the text color. */ void SetLabelColor(const Color &color); //! Get the text color. /*! Get the text color. @return The text color. */ Color GetLabelColor(); //! Get the button visual state. /*! Get the button visual state. @return The button visual state. */ ButtonVisualState GetVisualState() const; virtual void SetLabelFontSize(int point); int GetLabelFontSize() const; protected: //! The state of the AbstractButton. bool active_; bool mouse_pressed_; //! Visual state of the button object. ButtonVisualState visual_state_; // Common attribute for all the classes that inherit from AbstractButton. std::string label_; Color label_color_; StaticText *static_text_; int label_font_size_; bool same_size_as_content_; int pre_layout_width_; int pre_layout_height_; virtual void RecvMouseUp (int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseMove (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvClick (int x, int y, unsigned long button_flags, unsigned long key_flags) = 0; }; } #endif // ABSTRACTBUTTON_H nux-4.0.8+18.10.20180623/Nux/AbstractCheckedButton.cpp0000644000000000000000000001430313313373365016266 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "HLayout.h" #include "AbstractCheckedButton.h" #include "StaticText.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(AbstractCheckedButton); AbstractCheckedButton::AbstractCheckedButton(const std::string &str, bool state, NUX_FILE_LINE_DECL) : AbstractButton(NUX_FILE_LINE_PARAM) { label_ = str; active_ = state; hlayout_ = 0; static_text_ = new StaticText(label_, NUX_TRACKER_LOCATION); static_text_->SetTextColor(label_color_); hlayout_ = new HLayout(NUX_TRACKER_LOCATION); check_area_ = new BasicView(NUX_TRACKER_LOCATION); check_area_->SetInputEventSensitivity(false); static_text_->SetInputEventSensitivity(false); // Set Geometry check_area_->SetMinMaxSize(14, 14); hlayout_->SetSpaceBetweenChildren(4); hlayout_->SetContentDistribution(MAJOR_POSITION_LEFT); hlayout_->AddView(check_area_, 0, MINOR_POSITION_CENTER, MINOR_SIZE_MATCHCONTENT); hlayout_->AddView(static_text_, 1, MINOR_POSITION_CENTER, MINOR_SIZE_MATCHCONTENT); // // This is convenient to make the layout and the AbstractCheckedButton fit the check area and the caption area. // // Since the check area is bigger than 4x4, it will force the layout and the AbstractCheckedButton to grow. // // This is useful if the AbstractCheckedButton is put in a vertical layout and it has a stretch factor of 0. Then the width of the AbstractCheckedButton // // will be adjusted to fit the minimum width of the check area and the caption area. // { // hlayout_->SetMinimumSize(1, 1); // SetMinimumSize(14, 14); // ApplyMinWidth(); // ApplyMinHeight(); // } hlayout_->SetScaleFactor(0); SetLayout(hlayout_); } AbstractCheckedButton::~AbstractCheckedButton() { } void AbstractCheckedButton::SetLabel(const std::string &checkbox_label) { label_ = checkbox_label; static_text_->SetText(label_); QueueDraw(); } std::string AbstractCheckedButton::GetLabel() const { return label_; } void AbstractCheckedButton::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); GetPainter().PaintBackground(graphics_engine, base); InteractState is; is.is_on = active_; if (visual_state_ == VISUAL_STATE_PRESSED) { is.is_focus = true; } else if (visual_state_ == VISUAL_STATE_PRELIGHT) { is.is_prelight = true; } else { is.is_focus = false; is.is_prelight = false; } GetPainter().PushPaintLayerStack(); { GetPainter().PaintCheckBox(graphics_engine, check_area_->GetGeometry(), is, Color(0xff000000)); static_text_->ProcessDraw(graphics_engine, true); } GetPainter().PopPaintLayerStack(); graphics_engine.PopClippingRectangle(); } long AbstractCheckedButton::ComputeContentSize() { if (view_layout_) { PreLayoutManagement(); int old_width = GetBaseWidth(); int old_height = GetBaseHeight(); // Let the text view be as large as possible. static_text_->SetMaximumWidth(AREA_MAX_WIDTH); // Constrain the vertical expansion of the color selector. view_layout_->SetBaseHeight(1); long ret = view_layout_->ComputeContentSize(); PostLayoutManagement(ret); { // Check if the text view goes out of the AbstractCheckedButton area. Geometry base = GetGeometry(); Geometry text_geo = static_text_->GetGeometry(); // Intersect the AbstractCheckedButton and the text view Geometry intersection = base.Intersect(text_geo); if (intersection != text_geo) { // The text view goes outside of the AbstractCheckedButton area. We have to clip it static_text_->SetMaximumWidth(intersection.width); // Assign a size of 1 to the layout and call ComputeContentSize. // Inside the StaticText::ComputeContentSize there is code that takes care of size negociation. view_layout_->SetBaseWidth(1); ret = view_layout_->ComputeContentSize(); // Assign the layout geometry to the AbstractCheckedButton view. PostLayoutManagement(ret); } } int new_width = GetBaseWidth(); int new_height = GetBaseHeight(); long size_compliance = 0; // The layout has been resized to tightly pack its content if (new_width > old_width) { size_compliance |= eLargerWidth; // need scrollbar } else if (new_width < old_width) { size_compliance |= eSmallerWidth; } else { size_compliance |= eCompliantWidth; } // The layout has been resized to tightly pack its content if (new_height > old_height) { size_compliance |= eLargerHeight; // need scrollbar } else if (new_height < old_height) { size_compliance |= eSmallerHeight; } else { size_compliance |= eCompliantHeight; } return size_compliance; } else { PreLayoutManagement(); int ret = PostLayoutManagement(eCompliantHeight | eCompliantWidth); return ret; } return 0; } void AbstractCheckedButton::SetLabelFontSize(int point) { AbstractButton::SetLabelFontSize(point); if (static_text_ == NULL) return; static_text_->SetTextPointSize(point); ComputeContentSize(); QueueDraw(); } } nux-4.0.8+18.10.20180623/Nux/AbstractCheckedButton.h0000644000000000000000000000632713313373365015742 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ABSTRACTCHECKEDBUTTON_H #define ABSTRACTCHECKEDBUTTON_H #include "AbstractButton.h" namespace nux { class HLayout; class InputArea; class StaticText; //! AbstractCheckedButton class /*! Acts as a base class for CheckBox and radioButton.\n */ class AbstractCheckedButton: public AbstractButton { NUX_DECLARE_OBJECT_TYPE(AbstractCheckedButton, AbstractButton); public: AbstractCheckedButton(const std::string &str, bool state = false, NUX_FILE_LINE_PROTO); virtual ~AbstractCheckedButton(); //! Emitted when the button is clicked. sigc::signal click; //! Emitted when the active state changes. /*! Emitted when the active state changes, as a result of a mouse click or an API call.\n \sa Activate, Deactivate. */ sigc::signal state_change; //! Set the label. /*! Set the label of this AbstractCheckedButton. If the \a label argument is an empty string, then the the AbstractCheckedButton label is destroyed, and the content of the AbstractCheckedButton is re-arranged accordingly. @param label The label of the AbstractCheckedButton. */ void SetLabel(const std::string &checkbox_label); //!Return the label of this AbstractCheckedButton. /*! Return the label of this AbstractCheckedButton. @return The AbstractCheckedButton label string. */ std::string GetLabel() const; //! Activate the check box. /*! Activate the check box. */ virtual void Activate() = 0; //! Deactivate the check box. /*! Deactivate the check box. */ virtual void Deactivate() = 0; virtual void SetLabelFontSize(int point); protected: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw) = 0; virtual void RecvClick(int x, int y, unsigned long button_flags, unsigned long key_flags) = 0; virtual long ComputeContentSize(); HLayout *hlayout_; InputArea *check_area_; private: //! Override of Area::SetMinimumHeight and made private. /*! Prevent changing the minimum height of the StaticText view. */ virtual void SetMinimumHeight(int h){}; //! Override of Area::SetMaximumHeight and made private. /*! Prevent changing the maximum height of the StaticText view. */ virtual void SetMaximumHeight(int h){}; }; } #endif // ABSTRACTCHECKEDBUTTON_H nux-4.0.8+18.10.20180623/Nux/AbstractComboBox.cpp0000644000000000000000000001052413313373365015255 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "AbstractComboBox.h" #include "HLayout.h" #include "StaticText.h" namespace nux { Color AbstractComboBox::m_sCOMBO_COLOR = Color(0x009F9F00); Color AbstractComboBox::m_sCOMBO_BUTTON_COLOR = Color(0x00FFFFFF); Color AbstractComboBox::m_sCOMBO_MOUSEOVER_COLOR = Color(0x55FFFFFF); AbstractComboBox::AbstractComboBox(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_MenuIsActive(false) { m_hlayout = new HLayout(NUX_TRACKER_LOCATION); _combo_box_area = new BasicView(NUX_TRACKER_LOCATION); _combo_box_opening_area = new BasicView(NUX_TRACKER_LOCATION); m_hlayout->AddView(_combo_box_area, 1); m_hlayout->AddView(_combo_box_opening_area, 0); m_hlayout->SetHorizontalExternalMargin(0); m_hlayout->SetVerticalExternalMargin(0); SetLayout(m_hlayout); _combo_box_area->mouse_enter.connect(sigc::mem_fun(this, &AbstractComboBox::RecvMouseEnter)); _combo_box_area->mouse_leave.connect(sigc::mem_fun(this, &AbstractComboBox::RecvMouseLeave)); _combo_box_opening_area->mouse_enter.connect(sigc::mem_fun(this, &AbstractComboBox::RecvMouseEnter)); _combo_box_opening_area->mouse_leave.connect(sigc::mem_fun(this, &AbstractComboBox::RecvMouseLeave)); SetTextColor(color::Black); _pango_static_text = new StaticText("", NUX_TRACKER_LOCATION); } AbstractComboBox::~AbstractComboBox() { if (_pango_static_text) _pango_static_text->Dispose(); _pango_static_text = 0; } void AbstractComboBox::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); GetPainter().PaintBackground(graphics_engine, base); GetPainter().PaintShape(graphics_engine, base, m_sCOMBO_COLOR, eSHAPE_CORNER_ROUND4); { //GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), _combo_box_area->GetGeometry(), _combo_box_area->GetBaseString().c_str(), GetTextColor(), eAlignTextLeft); _pango_static_text->SetGeometry(_combo_box_area->GetGeometry()); _pango_static_text->ProcessDraw(graphics_engine, true); } Geometry button_geo = _combo_box_opening_area->GetGeometry(); button_geo.OffsetSize(-5, -2); button_geo.OffsetPosition(+4, +1); if (_combo_box_area->IsMouseInside() || _combo_box_opening_area->IsMouseInside()) GetPainter().PaintShape(graphics_engine, button_geo, m_sCOMBO_MOUSEOVER_COLOR, eSHAPE_CORNER_ROUND4); else GetPainter().PaintShape(graphics_engine, button_geo, m_sCOMBO_BUTTON_COLOR, eSHAPE_CORNER_ROUND4); GeometryPositioning gp(eHACenter, eVACenter); Geometry GeoPo = ComputeGeometryPositioning(button_geo, GetTheme().GetImageGeometry(eCOMBOBOX_OPEN_BUTTON), gp); GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eCOMBOBOX_OPEN_BUTTON); Geometry popup_geometry; popup_geometry.SetX(_combo_box_area->GetBaseX()); popup_geometry.SetY(_combo_box_area->GetBaseY() + _combo_box_area->GetBaseHeight()); popup_geometry.SetWidth(_combo_box_area->GetBaseWidth()); popup_geometry.SetHeight(_combo_box_area->GetBaseHeight()); graphics_engine.PopClippingRectangle(); } void AbstractComboBox::DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void AbstractComboBox::RecvMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void AbstractComboBox::RecvMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } } nux-4.0.8+18.10.20180623/Nux/AbstractComboBox.h0000644000000000000000000000344313313373365014724 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ABSTRACTCOMBOBOX_H #define ABSTRACTCOMBOBOX_H namespace nux { class StaticText; class HLayout; class AbstractComboBox: public View { public: AbstractComboBox(NUX_FILE_LINE_PROTO); virtual ~AbstractComboBox(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); StaticText * GetStaticText() { return _pango_static_text; } protected: HLayout *m_hlayout; BasicView *_combo_box_area; BasicView *_combo_box_opening_area; StaticText *_pango_static_text; bool m_MenuIsActive; bool m_IsOpeningMenu; static Color m_sCOMBO_COLOR; static Color m_sCOMBO_BUTTON_COLOR; static Color m_sCOMBO_MOUSEOVER_COLOR; }; } #endif // ABSTRACTCOMBOBOX_H nux-4.0.8+18.10.20180623/Nux/AbstractPaintLayer.cpp0000644000000000000000000000104613313373365015614 0ustar #include "Nux.h" #include "AbstractPaintLayer.h" namespace nux { AbstractPaintLayer::AbstractPaintLayer() { } AbstractPaintLayer::~AbstractPaintLayer() { } void AbstractPaintLayer::SetGeometry(const Geometry &geo) { geometry_ = geo; } Geometry const& AbstractPaintLayer::GetGeometry() const { return geometry_; } void AbstractPaintLayer::SetModelViewMatrix(const Matrix4 &mat) { model_view_matrix_ = mat; } Matrix4 AbstractPaintLayer::GetModelViewMatrix() { return model_view_matrix_; } } nux-4.0.8+18.10.20180623/Nux/AbstractPaintLayer.h0000644000000000000000000000330013313373365015254 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ABSTRACTPAINTLAYER_H #define ABSTRACTPAINTLAYER_H namespace nux { class AbstractPaintLayer { public: enum PaintLayerType { PaintLayer_Color, PaintLayer_Shape, PaintLayer_ShapeROP, PaintLayer_Texture, PaintLayer_DeviceTexture, PaintLayer_ImageStyle, }; AbstractPaintLayer(); virtual ~AbstractPaintLayer(); virtual AbstractPaintLayer *Clone() const = 0; //Virtual Constructor Idiom virtual void Renderlayer(GraphicsEngine &graphics_engine) = 0; virtual void SetGeometry(const Geometry &geo); //! Preserve the model view matrix at the moment layer is pushed on the paint layer stack. See Painter class. void SetModelViewMatrix(const Matrix4 &mat); Matrix4 GetModelViewMatrix(); Geometry const& GetGeometry() const; protected: Geometry geometry_; Matrix4 model_view_matrix_; }; } #endif // ABSTRACTPAINTLAYER_H nux-4.0.8+18.10.20180623/Nux/AbstractThread.cpp0000644000000000000000000000413613313373365014756 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "AbstractThread.h" namespace nux { class WindowThread; class SystemThread; NUX_IMPLEMENT_OBJECT_TYPE(AbstractThread); AbstractThread::AbstractThread(AbstractThread *Parent) : parent_(Parent) , user_init_func_(NULL) , user_exit_func_(NULL) { } AbstractThread::~AbstractThread() { } void AbstractThread::TerminateChildWindows() { std::list::iterator it; for (it = children_thread_list_.begin(); it != children_thread_list_.end(); it++) { if ((*it)->Type().IsObjectType(WindowThread::StaticObjectType)) { // Exit the main loop of a window. static_cast(*it)->ExitMainLoop(); } } } void AbstractThread::JoinChildThreads() { #if defined(NUX_OS_WINDOWS) size_t sz = children_thread_list_.size(); if (sz == 0) { return; } HANDLE *hdl = new HANDLE[sz]; int i = 0; std::list::iterator it; for (it = children_thread_list_.begin(); it != children_thread_list_.end(); ++it, ++i) { hdl[i] = (*it)->GetThreadHandle(); } unsigned int result = WaitForMultipleObjects(sz, hdl, FALSE, INFINITE); #else //#error WindowThread::JoinChildThreads has not been implemented for this platform. // Todo #endif return; } } nux-4.0.8+18.10.20180623/Nux/AbstractThread.h0000644000000000000000000000441413313373365014422 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ABSTRACTTHREAD_H #define ABSTRACTTHREAD_H namespace nux { typedef void(*ThreadUserInitFunc) (NThread *, void *InitData); typedef void(*ThreadUserExitFunc) (NThread *, void *ExitData); typedef void(*ThreadMainFunc) (NThread *, void *MainData); class AbstractThread: public NThread, public sigc::trackable { NUX_DECLARE_OBJECT_TYPE(AbstractThread, NThread); public: AbstractThread(AbstractThread *Parent); virtual ~AbstractThread(); protected: virtual int Run(void *) = 0; virtual ThreadState StartChildThread(AbstractThread *thread, bool Modal) = 0; virtual void AddChildThread(AbstractThread *) = 0; virtual void RemoveChildThread(AbstractThread *) = 0; virtual void ChildHasFinished(AbstractThread *app) = 0; virtual void TerminateChildThreads() = 0; void TerminateChildWindows(); void JoinChildThreads(); std::list children_thread_list_; AbstractThread *parent_; ThreadUserInitFunc user_init_func_; ThreadUserExitFunc user_exit_func_; /*! This pointer maybe set by the user in ThreadInitFunc and reused in ThreadExitFunc */ void *initialization_data_; std::list m_ThreadList; private: AbstractThread(const AbstractThread &); // Does not make sense for a singleton. This is a self assignment. AbstractThread &operator= (const AbstractThread &); // Declare operator adress-of as private AbstractThread *operator &(); }; } #endif // ABSTRACTTHREAD_H nux-4.0.8+18.10.20180623/Nux/ActionItem.cpp0000644000000000000000000001035313313373365014115 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/GLTextureResourceManager.h" #include "ActionItem.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(ActionItem); ActionItem::ActionItem(const char *label, int UserValue, NUX_FILE_LINE_DECL) : Object(true, NUX_FILE_LINE_PARAM) , m_UserValue(UserValue) , m_Label("") , m_IsActivated(true) , m_Menu(0) , m_Enable(true) { m_Icon = 0; SetLabel(label); } ActionItem::~ActionItem() { if (m_Icon) m_Icon->UnReference(); } void ActionItem::DrawAsMenuItem(GraphicsEngine &graphics_engine, InputArea &area, bool is_highlighted, bool /* draw_icone */) { Geometry geo = area.GetGeometry(); Geometry icon_geo(0, 0, 20, 20); Geometry text_geo = geo; text_geo.OffsetPosition(24, 2); text_geo.OffsetSize(2 * 24, 2 * 2); icon_geo.SetX(geo.x + 2); icon_geo.SetY(geo.y + 2); const char *label = GetLabel(); if (is_highlighted) { GetPainter().Paint2DQuadColor(graphics_engine, geo, Color(COLOR_FOREGROUND_SECONDARY)); } if (m_Icon) GetPainter().Draw2DTextureAligned(graphics_engine, m_Icon, icon_geo, TextureAlignmentStyle(eTACenter, eTACenter)); GetPainter().PaintTextLineStatic(graphics_engine, GetSysFont(), text_geo, std::string(label), Color(0xFF000000), eAlignTextLeft); } void ActionItem::DrawAsToolButton(GraphicsEngine &graphics_engine, InputArea &area) { Geometry base = area.GetGeometry(); if (area.IsMouseOwner()) { if (area.IsMouseInside()) { GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BACKGROUND_SECONDARY), eSHAPE_CORNER_ROUND2); GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BLACK), eSTROKE_CORNER_ROUND2); } else { GetPainter().PaintShape(graphics_engine, base, Color(COLOR_FOREGROUND_PRIMARY), eSHAPE_CORNER_ROUND2); GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BLACK), eSTROKE_CORNER_ROUND2); } } else { if (area.IsMouseInside() /*TODO: && (!area.MouseFocusOnOtherArea())*/) { GetPainter().PaintShape(graphics_engine, base, Color(COLOR_FOREGROUND_PRIMARY), eSHAPE_CORNER_ROUND2); GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BLACK), eSTROKE_CORNER_ROUND2); } else { GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BACKGROUND_SECONDARY), eSHAPE_CORNER_ROUND2); GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BLACK), eSTROKE_CORNER_ROUND2); } } GetPainter().Draw2DTextureAligned(graphics_engine, m_Icon, base, TextureAlignmentStyle(eTACenter, eTACenter)); } void ActionItem::Activate(bool b) { m_IsActivated = b; } void ActionItem::Trigger() const { sigAction.emit(); } void ActionItem::Enable(bool b) { m_Enable = b; } bool ActionItem::isEnabled() const { return m_Enable; } void ActionItem::SetLabel(const char *label) { m_Label = label; } const char *ActionItem::GetLabel() const { return m_Label.c_str(); } void ActionItem::SetIcon(const BaseTexture* icon) { if (m_Icon) m_Icon->UnReference(); m_Icon = icon->Clone(); } // NUXTODO: should return the bitmap data instead or a const pointer?. const BaseTexture* ActionItem::GetIcon() { return m_Icon; } //void ActionItem::SetMenu(Menu* menu) //{ // m_Menu = menu; //} //Menu* ActionItem::GetMenu() const //{ // return m_Menu; //} } nux-4.0.8+18.10.20180623/Nux/ActionItem.h0000644000000000000000000000405613313373365013565 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ACTIONITEM_H #define ACTIONITEM_H #include "NuxGraphics/GraphicsEngine.h" namespace nux { class MenuBar; class MenuPage; class ActionItem: public Object { public: NUX_DECLARE_OBJECT_TYPE (ActionItem, Object); ActionItem (const TCHAR *label = 0, int UserValue = 0, NUX_FILE_LINE_PROTO); ~ActionItem(); void Activate (bool b); void Trigger() const; void DrawAsMenuItem (GraphicsEngine &GfxContext, InputArea &area, bool is_highlighted, bool draw_icone); void DrawAsToolButton (GraphicsEngine &GfxContext, InputArea &area); void Enable (bool b); bool isEnabled() const; void SetLabel (const TCHAR *label); const TCHAR *GetLabel() const; int GetUserValue() const { return m_UserValue; } // void SetMenu(MenuPage* menu); // MenuPage* GetMenu() const; void SetFont (ObjectPtr font); void SetIcon (const BaseTexture* icon); const BaseTexture* GetIcon(); sigc::signal sigAction; private: //! A value defined by the user at construction time. int m_UserValue; BaseTexture* m_Icon; std::string m_Label; bool m_IsActivated; MenuPage *m_Menu; bool m_Enable; friend class MenuBar; friend class MenuPage; }; } #endif // ACTIONITEM_H nux-4.0.8+18.10.20180623/Nux/AnimatedTextureArea.cpp0000644000000000000000000001027613313373365015761 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/ImageSurface.h" #include "AnimatedTextureArea.h" namespace nux { AnimatedTextureArea::AnimatedTextureArea(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_UserTexture(0) { SetMinMaxSize(32, 32); mouse_down.connect(sigc::mem_fun(this, &AnimatedTextureArea::RecvMouseDown)); mouse_drag.connect(sigc::mem_fun(this, &AnimatedTextureArea::RecvMouseDrag)); m_TimerFunctor = new TimerFunctor(); m_TimerFunctor->tick.connect(sigc::mem_fun(this, &AnimatedTextureArea::TimerNextFrame)); } AnimatedTextureArea::~AnimatedTextureArea() { GetTimer().RemoveTimerHandler(m_TimerHandler); m_TimerHandler = 0; delete m_TimerFunctor; m_TimerFunctor = 0; } void AnimatedTextureArea::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { if (m_UserTexture) { GetPainter().PaintBackground(graphics_engine, GetGeometry()); graphics_engine.GetRenderStates().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); nux::Geometry base = GetGeometry(); nux::TexCoordXForm texxform; graphics_engine.QRP_1Tex(base.x, base.y, base.width, base.height, m_UserTexture->GetDeviceTexture(), texxform, nux::color::White); graphics_engine.GetRenderStates().SetBlend(false); } } void AnimatedTextureArea::DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void AnimatedTextureArea::SetTexture(TextureFrameAnimation *t) { m_UserTexture = t; if (m_UserTexture) { ObjectPtr< CachedTextureFrameAnimation > Texture = GetGraphicsDisplay()->GetGraphicsEngine()->CacheResource(m_UserTexture); ObjectPtr AnimatedTexture = Texture->m_Texture; //Texture->m_Texture.CastRef(); ObjectPtr Texture2D = Texture->m_Texture; //Texture->m_Texture.CastRef(); AnimatedTexture->SetFiltering(GL_LINEAR, GL_LINEAR); AnimatedTexture->SetWrap(GL_CLAMP, GL_CLAMP, GL_CLAMP); } QueueDraw(); } void AnimatedTextureArea::RecvMouseDown(int x, int y, long /* button_flags */, long /* key_flags */) { sigMouseDown.emit(x, y); } void AnimatedTextureArea::RecvMouseDrag(int x, int y, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { sigMouseDrag.emit(x, y); } void AnimatedTextureArea::StartAnimation() { if (m_TimerHandler.IsValid()) { GetTimer().RemoveTimerHandler(m_TimerHandler); m_TimerHandler = 0; } m_TimerHandler = GetTimer().AddOneShotTimer(41, m_TimerFunctor, 0); QueueDraw(); } void AnimatedTextureArea::StopAnimation() { if (m_TimerHandler.IsValid()) { GetTimer().RemoveTimerHandler(m_TimerHandler); m_TimerHandler = 0; } } void AnimatedTextureArea::TimerNextFrame(void * /* v */) { if (m_UserTexture) { ObjectPtr< CachedTextureFrameAnimation > Texture = GetGraphicsDisplay()->GetGraphicsEngine()->CacheResource(m_UserTexture); ObjectPtr AnimatedTexture = Texture->m_Texture; //Texture->m_Texture.CastRef(); ObjectPtr Texture2D = Texture->m_Texture; //Texture->m_Texture.CastRef(); AnimatedTexture->PresentNextFrame(); m_TimerHandler = GetTimer().AddOneShotTimer(41, m_TimerFunctor, 0); } QueueDraw(); } } nux-4.0.8+18.10.20180623/Nux/AnimatedTextureArea.h0000644000000000000000000000341113313373365015417 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ANIMATEDTEXTUREAREA_H #define ANIMATEDTEXTUREAREA_H #include "NuxGraphics/GraphicsEngine.h" #include "TimerProc.h" namespace nux { class AnimatedTextureArea : public View { public: AnimatedTextureArea(NUX_FILE_LINE_PROTO); ~AnimatedTextureArea(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); void SetTexture(TextureFrameAnimation *Texture); void RecvMouseDown(int x, int y, long button_flags, long key_flags); void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); sigc::signal sigMouseDown; sigc::signal sigMouseDrag; void StartAnimation(); void StopAnimation(); private: void TimerNextFrame(void *v); TimerFunctor *m_TimerFunctor; TimerHandle m_TimerHandler; TextureFrameAnimation *m_UserTexture; }; } #endif // ANIMATEDTEXTUREAREA_H nux-4.0.8+18.10.20180623/Nux/Area.cpp0000644000000000000000000006702413313373365012740 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Area.h" #include "NuxGraphics/GraphicsEngine.h" #include "Layout.h" #include "BaseWindow.h" #if !defined(NUX_MINIMAL) # include "VSplitter.h" # include "HSplitter.h" # include "MenuPage.h" #endif #ifdef NUX_GESTURES_SUPPORT #include "NuxGraphics/GestureEvent.h" #endif namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(Area); Area::Area(NUX_FILE_LINE_DECL) : InitiallyUnownedObject(NUX_FILE_LINE_PARAM) , redirect_rendering_to_texture_(false) , update_backup_texture_(false) , present_redirected_view_(true) , copy_previous_fbo_for_background_(true) , geometry_(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT) , min_size_(AREA_MIN_WIDTH, AREA_MIN_HEIGHT) , max_size_(AREA_MAX_WIDTH, AREA_MAX_HEIGHT) , layout_done_(true) { window_thread_ = GetWindowThread(); visible_ = true; view_enabled_ = true; parent_area_ = NULL; next_object_to_key_focus_area_ = NULL; has_key_focus_ = false; scale_factor_ = 1; sensitive_ = true; on_geometry_change_reconfigure_parent_layout_ = true; accept_mouse_wheel_event_ = false; accept_keyboard_event_ = false; _2d_xform.Identity(); _3d_xform.Identity(); _3d_area = false; } Area::~Area() { // It is possible that the window thread has been deleted before the area // itself, so check prior to calling RemoveObjectFromLayoutQueue. WindowThread* wt = GetWindowThread(); if (wt) { // It is possible that the object is in the refresh list. Remove it here // before it is deleted. wt->RemoveObjectFromLayoutQueue(this); } ResetDownwardPathToKeyFocusArea(); ResetUpwardPathToKeyFocusArea(); } std::string const& Area::GetBaseString() const { return base_string_; } void Area::SetBaseString(std::string const& caption) { base_string_ = caption; } void Area::CheckMinSize() { int w = min_size_.width; w = Max(AREA_MIN_WIDTH, w); int h = min_size_.height; h = Max(AREA_MIN_HEIGHT, h); min_size_ = Size(w, h); if (min_size_.width > max_size_.width) { max_size_.width = min_size_.width; } if (min_size_.height > max_size_.height) { max_size_.height = min_size_.height; } if (geometry_.width < min_size_.width) { geometry_.width = min_size_.width; } if (geometry_.height < min_size_.height ) { geometry_.height = min_size_.height; } } void Area::CheckMaxSize() { int w = max_size_.width; w = w <= AREA_MAX_WIDTH ? w : AREA_MAX_WIDTH; int h = max_size_.height; h = h <= AREA_MAX_HEIGHT ? h: AREA_MAX_HEIGHT; max_size_ = Size(w, h); if (min_size_.width > max_size_.width) { min_size_.width = max_size_.width; } if (min_size_.height > max_size_.height) { min_size_.height = max_size_.height; } if (geometry_.width > max_size_.width) { geometry_.width = max_size_.width; } if (geometry_.height > max_size_.height) { geometry_.height = max_size_.height; } } void Area::SetMinimumSize(int w, int h) { nuxAssert(w >= 0); nuxAssert(h >= 0); min_size_ = Size(w, h); CheckMinSize(); ReconfigureParentLayout(); } void Area::SetMaximumSize(int w, int h) { nuxAssert(w >= 0); nuxAssert(h >= 0); max_size_ = Size(w, h); CheckMaxSize(); ReconfigureParentLayout(); } void Area::SetMinMaxSize(int w, int h) { nuxAssert(w >= 0); nuxAssert(h >= 0); SetMinimumSize(w, h); SetMaximumSize(w, h); //ReconfigureParentLayout(); } void Area::ApplyMinWidth() { geometry_.width = min_size_.width; ReconfigureParentLayout(); } void Area::ApplyMinHeight() { geometry_.height = min_size_.height; ReconfigureParentLayout(); } void Area::ApplyMaxWidth() { geometry_.width = max_size_.width; ReconfigureParentLayout(); } void Area::ApplyMaxHeight() { geometry_.height = max_size_.height; ReconfigureParentLayout(); } Size Area::GetMinimumSize() const { return min_size_; } Size Area::GetMaximumSize() const { return max_size_; } void Area::SetMinimumWidth(int w) { nuxAssert(w >= 0); min_size_.width = w; CheckMinSize(); ReconfigureParentLayout(); } void Area::SetMaximumWidth(int w) { nuxAssert(w >= 0); max_size_.width = w; CheckMaxSize(); ReconfigureParentLayout(); } void Area::SetMinimumHeight(int h) { nuxAssert(h >= 0); min_size_.height = h; CheckMinSize(); ReconfigureParentLayout(); } void Area::SetMaximumHeight(int h) { nuxAssert(h >= 0); max_size_.height = h; CheckMaxSize(); ReconfigureParentLayout(); } int Area::GetMinimumWidth() const { return min_size_.width; } int Area::GetMaximumWidth() const { return max_size_.width; } int Area::GetMinimumHeight() const { return min_size_.height; } int Area::GetMaximumHeight() const { return max_size_.height; } unsigned int Area::GetScaleFactor() { return scale_factor_; } void Area::SetScaleFactor(unsigned int sf) { // re implemented by Layout scale_factor_ = sf; } bool Area::SetParentObject(Area *parent) { if (parent == 0) { nuxAssertMsg(0, "[Area::SetParentObject] Invalid parent obejct."); return false; } if (parent_area_ && (parent_area_ != parent)) { nuxAssertMsg(0, "[Area::SetParentObject] Object already has a parent. You must UnParent the object before you can parenting again."); return false; } if (parent_area_) { // Already parented to the same area. Return. return true; } parent_area_ = parent; Reference(); return true; } void Area::UnParentObject() { // If the area is on the path to the key focus area, or has focus, reset it. if (has_key_focus_ || next_object_to_key_focus_area_) { GetWindowThread()->GetWindowCompositor().SetKeyFocusArea(NULL, KEY_NAV_NONE); } if (parent_area_) { parent_area_ = 0; UnReference(); } } Area *Area::GetParentObject() const { return parent_area_; } int Area::GetX() const { return geometry_.x; } int Area::GetBaseX() const { return GetX(); } int Area::GetY() const { return geometry_.y; } int Area::GetBaseY() const { return GetY(); } int Area::GetWidth() const { return geometry_.width; } int Area::GetBaseWidth() const { return GetWidth(); } int Area::GetHeight() const { return geometry_.height; } int Area::GetBaseHeight() const { return GetHeight(); } void Area::SetGeometry(int x, int y, int w, int h) { h = nux::Clamp (h, min_size_.height, max_size_.height); w = nux::Clamp (w, min_size_.width, max_size_.width); bool detected_size_change = false; bool detected_position_change = false; if (geometry_.x != x || geometry_.y != y) detected_position_change = true; if (geometry_.width != w || geometry_.height != h) detected_size_change = true; if (!detected_position_change && !detected_size_change) return; GeometryChangePending(detected_position_change, detected_size_change); geometry_.Set(x, y, w, h); ReconfigureParentLayout(); GeometryChanged(detected_position_change, detected_size_change); geometry_changed.emit(this, geometry_); if (detected_position_change) position_changed.emit(this, x, y); if (detected_size_change) size_changed.emit(this, w, h); } void Area::SetGeometry(const Geometry &geo) { SetGeometry(geo.x, geo.y, geo.width, geo.height); } Geometry const& Area::GetGeometry() const { return geometry_; } void Area::SetX(int x) { SetGeometry(x, geometry_.y, geometry_.width, geometry_.height); } void Area::SetY (int y) { SetGeometry(geometry_.x, y, geometry_.width, geometry_.height); } void Area::SetBaseX(int x) { SetX(x); } void Area::SetBaseY(int y) { SetY(y); } void Area::SetXY(int x, int y) { SetGeometry(x, y, geometry_.width, geometry_.height); } void Area::SetBaseXY(int x, int y) { SetXY(x, y); } void Area::SetSize(int w, int h) { SetGeometry(geometry_.x, geometry_.y, w, h); } void Area::SetBaseSize(int w, int h) { SetSize(w, h); } void Area::SetWidth(int w) { SetGeometry(geometry_.x, geometry_.y, w, geometry_.height); } void Area::SetBaseWidth(int w) { SetWidth(w); } void Area::SetHeight(int h) { SetGeometry(geometry_.x, geometry_.y, geometry_.width, h); } void Area::SetBaseHeight(int h) { SetHeight(h); } long Area::ComputeContentSize() { return (eCompliantWidth | eCompliantHeight); } void Area::ComputeContentPosition(float /* offsetX */, float /* offsetY */) { } void Area::SetReconfigureParentLayoutOnGeometryChange(bool reconfigure_parent_layout) { on_geometry_change_reconfigure_parent_layout_ = reconfigure_parent_layout; } bool Area::ReconfigureParentLayoutOnGeometryChange() { return on_geometry_change_reconfigure_parent_layout_; } void Area::ReconfigureParentLayout(Area *child) { if (on_geometry_change_reconfigure_parent_layout_ == false) return; if (window_thread_ && window_thread_->IsComputingLayout()) { // there is no need to do the following while we are already computing the layout. // If we do, we will end up in an infinite loop. return; } if (this->Type().IsDerivedFromType(View::StaticObjectType)) { // The object that is being resized is a View object and it has a parent. if (this->OwnsTheReference() == false && this->GetParentObject()) { // Only reference parented areas. this->Reference(); } View *ic = static_cast(this); if (ic->CanBreakLayout()) { #if !defined(NUX_MINIMAL) if ((child != 0) && (ic->Type().IsObjectType(VSplitter::StaticObjectType) || ic->Type().IsObjectType(HSplitter::StaticObjectType))) { // If this element is a Splitter, then we submit its child to the refresh list. We don't want to submit the // splitter because this will cause a redraw of all parts of the splitter(costly and unnecessary). window_thread_->QueueObjectLayout(child); } else #endif { window_thread_->QueueObjectLayout(ic); } } else if (ic->parent_area_) { ic->parent_area_->ReconfigureParentLayout(this); } else { window_thread_->QueueObjectLayout(ic); } } else if (this->Type().IsDerivedFromType(Layout::StaticObjectType)) { // The object that is being resized is a View object and it has a parent. if (this->OwnsTheReference() == false && this->GetParentObject()) { // Only reference parented areas. this->Reference(); } Layout *layout = static_cast(this); if (layout->parent_area_) { if (layout->parent_area_->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = (View *) (layout->parent_area_); if (ic->CanBreakLayout()) { #if !defined(NUX_MINIMAL) if ((child != 0) && (ic->Type().IsObjectType(VSplitter::StaticObjectType) || ic->Type().IsObjectType(HSplitter::StaticObjectType))) { // If the parent of this element is a splitter, then we submit // its child to the refresh list. We don't want to submit the // splitter because this will cause a redraw of all parts of the // splitter(costly and unnecessary). window_thread_->QueueObjectLayout(this); } else #endif { window_thread_->QueueObjectLayout(ic); } } else { // The parent object of an object of type View is a Layout object type. layout->parent_area_->ReconfigureParentLayout(this); } } else { layout->parent_area_->ReconfigureParentLayout(this); } } else { // This is possibly the Main layout or the layout of a floating object(popup for example) unless the layout is not part of the object tree. window_thread_->QueueObjectLayout(layout); } } else { // The object that is being resized is a InputArea object. if (this->parent_area_) { // The object that is being resized is a View object and it has a parent. if (this->OwnsTheReference() == false && this->GetParentObject()) { // Only reference parented areas. this->Reference(); } // The parent object of an object of type InputArea is a Layout object type. this->parent_area_->ReconfigureParentLayout(this); } } } void Area::RequestBottomUpLayoutComputation(Area *bo_initiator) { if (parent_area_ && parent_area_->IsLayout()) { parent_area_->RequestBottomUpLayoutComputation(bo_initiator); } } void Area::SetVisible(bool visible) { if (IsLayout()) return; if (visible_ == visible) return; visible_ = visible; OnVisibleChanged.emit(this, visible_); } bool Area::IsVisible() { return visible_; } void Area::SetSensitive(bool sensitive) { SetInputEventSensitivity(sensitive); } void Area::SetInputEventSensitivity(bool sensitive) { if (IsLayout()) return; if (sensitive_ == sensitive) return; sensitive_ = sensitive; OnSensitiveChanged.emit(this, sensitive_); } bool Area::IsSensitive() const { return GetInputEventSensitivity(); } bool Area::GetInputEventSensitivity() const { return sensitive_; } MinorDimensionPosition Area::GetPositioning() { return minor_axis_position_; } void Area::SetPositioning(MinorDimensionPosition p) { minor_axis_position_ = p; } MinorDimensionSize Area::GetExtend() { return minor_axis_size_; } void Area::SetExtend(MinorDimensionSize ext) { minor_axis_size_ = ext; } float Area::GetPercentage() { return minor_axis_size_scale_; } void Area::SetPercentage(float p) { minor_axis_size_scale_ = p; } bool Area::IsLayoutDone() { return layout_done_; } void Area::SetLayoutDone(bool b) { layout_done_ = b; } bool Area::IsArea() const { return this->Type().IsDerivedFromType(Area::StaticObjectType); } bool Area::IsInputArea() const { return this->Type().IsDerivedFromType(InputArea::StaticObjectType); } bool Area::IsView() const { return this->Type().IsDerivedFromType(View::StaticObjectType); } bool Area::IsLayout() const { return this->Type().IsDerivedFromType(Layout::StaticObjectType); } bool Area::IsViewWindow() const { return this->Type().IsDerivedFromType(BaseWindow::StaticObjectType); } bool Area::IsSpaceLayout() const { return this->Type().IsDerivedFromType(SpaceLayout::StaticObjectType); } void Area::Set2DMatrix(const Matrix4 &mat) { _2d_xform = mat; } void Area::Set2DTranslation(float tx, float ty, float tz) { _2d_xform.Translate(tx, ty, tz); } Matrix4 Area::Get2DMatrix() const { return _2d_xform; } Matrix4 Area::Get3DMatrix() const { return _3d_xform; } bool Area::Is3DArea() const { return _3d_area; } static void MatrixXFormGeometry(const Matrix4 &matrix, Geometry &geo) { Vector4 in(geo.x, geo.y, 0, 1); // This is mean only for translation matrices. It will not work with matrices containing rotations or scalings. Vector4 out = matrix * in; geo.x = out.x; geo.y = out.y; } void Area::InnerGetAbsoluteGeometry(Geometry &geometry) { if (this->Type().IsDerivedFromType(BaseWindow::StaticObjectType) || (this == window_thread_->GetLayout())) { geometry.OffsetPosition(geometry_.x, geometry_.y); return; } MatrixXFormGeometry(_2d_xform, geometry); Area *parent = GetParentObject(); if (parent) parent->InnerGetAbsoluteGeometry(geometry); } Geometry Area::GetAbsoluteGeometry() const { if (Type().IsDerivedFromType(BaseWindow::StaticObjectType) || #if !defined(NUX_MINIMAL) Type().IsDerivedFromType(MenuPage::StaticObjectType) || #endif (this == window_thread_->GetLayout())) { // Do not apply the _2D_xform matrix to a BaseWindow or the main layout return geometry_; } else { nux::Geometry geo = geometry_; MatrixXFormGeometry(_2d_xform, geo); Area *parent = GetParentObject(); if (parent) parent->InnerGetAbsoluteGeometry(geo); return geo; } } int Area::GetAbsoluteX() const { return GetAbsoluteGeometry().x; } int Area::GetAbsoluteY() const { return GetAbsoluteGeometry().y; } int Area::GetAbsoluteWidth() const { return GetAbsoluteGeometry().width; } int Area::GetAbsoluteHeight() const { return GetAbsoluteGeometry().height; } void Area::InnerGetRootGeometry(Geometry &geometry) { if (this->Type().IsDerivedFromType(BaseWindow::StaticObjectType) || (this == window_thread_->GetLayout())) return; MatrixXFormGeometry(_2d_xform, geometry); Area *parent = GetParentObject(); if (parent) parent->InnerGetRootGeometry(geometry); } Geometry Area::GetRootGeometry() const { nux::Geometry geo = geometry_; MatrixXFormGeometry(_2d_xform, geo); if (Type().IsDerivedFromType(BaseWindow::StaticObjectType) || (this == window_thread_->GetLayout())) { return geo; } else { Area *parent = GetParentObject(); if (parent) parent->InnerGetRootGeometry(geo); return geo; } } int Area::GetRootX() const { return GetRootGeometry().x; } int Area::GetRootY() const { return GetRootGeometry().y; } int Area::GetRootWidth() const { return GetRootGeometry().width; } int Area::GetRootHeight() const { return GetRootGeometry().height; } Area* Area::GetToplevel() { return GetRootParent(); } Area* Area::GetRootParent() { if (Type().IsDerivedFromType(BaseWindow::StaticObjectType) || (this == window_thread_->GetLayout())) { return this; } Area* parent = GetParentObject(); if (!parent) //we didn't find a way to salvation! { return 0; } return parent->GetRootParent(); } Area* Area::GetTopLevelViewWindow() { Area* area = GetRootParent(); if (area && area->IsViewWindow()) return area; return NULL; } bool Area::HasTopLevelParent() { if (GetRootParent()) { return true; } return false; } bool Area::IsChildOf(Area* parent) { if (this == parent) return true; if (!parent || !parent_area_) return false; return parent_area_->IsChildOf(parent); } void Area::QueueRelayout() { window_thread_->QueueObjectLayout(this); } void Area::SetAcceptKeyboardEvent(bool accept_keyboard_event) { accept_keyboard_event_ = accept_keyboard_event; } bool Area::AcceptKeyboardEvent() const { return accept_keyboard_event_; } void Area::SetAcceptMouseWheelEvent(bool accept_mouse_wheel_event) { accept_mouse_wheel_event_ = accept_mouse_wheel_event; } bool Area::AcceptMouseWheelEvent() const { return accept_mouse_wheel_event_; } bool Area::TestMousePointerInclusion(const Point& mouse_position, NuxEventType event_type) { if ((IsLayout() == false) && ((visible_ == false) || (sensitive_ == false) || (view_enabled_ == false))) { // If this area is not a view and: // - it is insensitive to input event // - it is not enabled // - it is not visible // then return false. return false; } bool mouse_pointer_inside_area = false; #if !defined(NUX_MINIMAL) if (Type().IsDerivedFromType(MenuPage::StaticObjectType)) { // A MenuPage geometry is already in absolute coordinates. mouse_pointer_inside_area = geometry_.IsInside(mouse_position); } else #endif { mouse_pointer_inside_area = GetAbsoluteGeometry().IsInside(mouse_position); } if ((event_type == NUX_MOUSE_WHEEL) && mouse_pointer_inside_area) { if (accept_mouse_wheel_event_ == false) return false; } return mouse_pointer_inside_area; } bool Area::TestMousePointerInclusionFilterMouseWheel(const Point& mouse_position, NuxEventType /* event_type */) { if ((IsLayout() == false) && ((visible_ == false) || (sensitive_ == false) || (view_enabled_ == false))) { // If this area is not a view and: // - it is insensitive to input event // - it is not enabled // - it is not visible // then return false. return false; } bool mouse_pointer_inside_area = false; #if !defined(NUX_MINIMAL) if (Type().IsDerivedFromType(MenuPage::StaticObjectType)) { // A MenuPage geometry is already in absolute coordinates. mouse_pointer_inside_area = geometry_.IsInside(mouse_position); } else #endif { mouse_pointer_inside_area = GetAbsoluteGeometry().IsInside(mouse_position); } return mouse_pointer_inside_area; } Area* Area::FindAreaUnderMouse(const Point& /* mouse_position */, NuxEventType /* event_type */) { return NULL; } Area* Area::FindKeyFocusArea(unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state) { if (has_key_focus_) { return this; } else if (next_object_to_key_focus_area_) { return next_object_to_key_focus_area_->FindKeyFocusArea(key_symbol, x11_key_code, special_keys_state); } return NULL; } void Area::SetNextObjectToKeyFocusArea(Area* area) { next_object_to_key_focus_area_ = area; } Area* Area::GetNextObjectToKeyFocusArea() { return next_object_to_key_focus_area_; } void Area::SetPathToKeyFocusArea() { has_key_focus_ = true; next_object_to_key_focus_area_ = NULL; Area* child = this; Area* parent = GetParentObject(); while (parent) { parent->next_object_to_key_focus_area_ = child; parent->next_object_to_key_focus_area_->Reference(); parent->has_key_focus_ = false; child = parent; parent = parent->GetParentObject(); } } void Area::ResetDownwardPathToKeyFocusArea() { has_key_focus_ = false; if (next_object_to_key_focus_area_) { next_object_to_key_focus_area_->ResetDownwardPathToKeyFocusArea(); } if (next_object_to_key_focus_area_) next_object_to_key_focus_area_->UnReference(); next_object_to_key_focus_area_ = NULL; } void Area::ResetUpwardPathToKeyFocusArea() { has_key_focus_ = false; if (parent_area_) { parent_area_->ResetUpwardPathToKeyFocusArea(); } if (next_object_to_key_focus_area_) next_object_to_key_focus_area_->UnReference(); next_object_to_key_focus_area_ = NULL; } bool Area::InspectKeyEvent(unsigned int /* event_type */, unsigned int /* keysym */, const char* /* character */) { return false; } Area* Area::KeyNavIteration(KeyNavDirection /* direction */) { return NULL; } bool Area::HasKeyFocus() const { return has_key_focus_; } bool Area::IsMousePointerInside() const { Geometry geo = GetAbsoluteGeometry(); Point position = GetWindowThread()->GetWindowCompositor().GetMousePosition(); if (geo.IsInside(position)) return true; return false; } /*** Support for redirected rendering ***/ void Area::SetRedirectRenderingToTexture(bool redirect) { if (redirect_rendering_to_texture_ == redirect) { return; } if (!redirect_rendering_to_texture_ && redirect) { update_backup_texture_ = true; } redirect_rendering_to_texture_ = redirect; if (redirect == false) { // Free the texture of this view backup_fbo_.Release(); backup_texture_.Release(); backup_depth_texture_.Release(); prev_fbo_.Release(); } } bool Area::RedirectRenderingToTexture() const { return redirect_rendering_to_texture_; } void Area::SetUpdateBackupTextureForChildRendering(bool update) { update_backup_texture_ = update; } ObjectPtr Area::BackupTexture() const { // if RedirectRenderingToTexture() is false, then backup_texture_ is not a valid smart pointer. return backup_texture_; } bool Area::UpdateBackupTextureForChildRendering() const { return update_backup_texture_; } void Area::PrepareParentRedirectedView() { Area* parent = GetParentObject(); while (parent) { if (parent->RedirectRenderingToTexture()) { if (parent->UpdateBackupTextureForChildRendering()) break; parent->SetUpdateBackupTextureForChildRendering(true); parent->PrepareParentRedirectedView(); } else { parent->PrepareParentRedirectedView(); break; } } } bool Area::HasParentRedirectedView() { Area* parent = GetParentObject(); while (parent && !parent->Type().IsDerivedFromType(View::StaticObjectType)) { parent = parent->GetParentObject(); } if (parent) { View* view = static_cast(parent); if (view->RedirectRenderingToTexture()) { return true; } else { return view->HasParentRedirectedView(); } } return false; } Area* Area::RedirectedAncestor() { Area* parent = GetParentObject(); while (parent) { if (parent->RedirectRenderingToTexture()) { return parent; } parent = parent->GetParentObject(); } return NULL; } void Area::SetCopyPreviousFboTexture(bool copy_background) { copy_previous_fbo_for_background_ = copy_background; } void Area::SetPresentRedirectedView(bool present_redirected_view) { present_redirected_view_ = present_redirected_view; } bool Area::PresentRedirectedView() const { return present_redirected_view_; } #ifdef NUX_GESTURES_SUPPORT Area* Area::GetInputAreaHitByGesture(const GestureEvent & /* event */) { return nullptr; } bool Area::IsGestureInsideArea(const nux::GestureEvent &event) const { if (event.IsDirectTouch()) { Geometry geometry = GetAbsoluteGeometry(); Point p; for (const auto touch_point : event.GetTouches()) { p.x = (int)touch_point.x; p.y = (int)touch_point.y; if (!geometry.IsInside(p)) return false; } return true; } else { return GetAbsoluteGeometry().IsInside(event.GetFocus()); } } #endif // NUX_GESTURES_SUPPORT } nux-4.0.8+18.10.20180623/Nux/Area.h0000644000000000000000000007267313313373365012413 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef BASEOBJECT_H #define BASEOBJECT_H #include #include #include "NuxCore/InitiallyUnownedObject.h" #include "NuxGraphics/Events.h" #include "Utils.h" #include "WidgetMetrics.h" namespace nux { class WindowThread; class GraphicsEngine; class IOpenGLBaseTexture; class IOpenGLFrameBufferObject; #ifdef NUX_GESTURES_SUPPORT class GestureEvent; #endif // NUX_GESTURES_SUPPORT // In a Horizontal/Vertical Layout, the following enum have the respective meanings: // eFull: the object has the full height/width of the parent layout(minus margins) // ePercentage: the object has a height/width that is a percentage of the parent layout(minus margins) // eFix: the object has a fixed height/width // Another way to see it // eFix = The minor dimension of the object will remain what it is. But the positioning in the // minor dimension inside the layout can be controlled with MinorDimensionPosition. // eFull = The minor dimension of the object will take the entire size that is offered by the parent layout. // MinorDimensionPosition has no effect if MinorDimensionSize = eFull // eContent = The minor dimension of the object will be set to 1 by its parent and later on, the minor dimension will be // resized larger by the children of the element if necessary. // typedef enum { MINOR_SIZE_FULL, MINOR_SIZE_PERCENTAGE, MINOR_SIZE_FIX, MINOR_SIZE_MATCHCONTENT, eFull = MINOR_SIZE_FULL, //!< Deprecated. ePercentage = MINOR_SIZE_PERCENTAGE, //!< Deprecated. eFix = MINOR_SIZE_FIX, //!< Deprecated. eMatchContent = MINOR_SIZE_MATCHCONTENT, //!< Deprecated. } MinorDimensionSize; //! Policy for and element position in the minor dimension of a layout. typedef enum { MINOR_POSITION_START, //!< Place the element at the start of the layout(Hlayout and VLayout) MINOR_POSITION_CENTER, //!< Place the element at the center of the layout(Hlayout and VLayout) MINOR_POSITION_END, //!< Place the element at the end of the layout(Hlayout and VLayout) MINOR_POSITION_TOP = MINOR_POSITION_START, //!< Deprecated. MINOR_POSITION_LEFT = MINOR_POSITION_START, //!< Deprecated. MINOR_POSITION_BOTTOM = MINOR_POSITION_END, //!< Deprecated. MINOR_POSITION_RIGHT = MINOR_POSITION_END, //!< Deprecated. eAbove = MINOR_POSITION_START, //!< Deprecated. eBelow = MINOR_POSITION_END, //!< Deprecated. eLeft = MINOR_POSITION_START, //!< Deprecated. eRight = MINOR_POSITION_END, //!< Deprecated. eCenter = MINOR_POSITION_CENTER, //!< Deprecated. } MinorDimensionPosition; //! Control how a layout distribute its children position. /*! Applies to layouts that have more space than their children can use. These options control how a layouts places its children inside of itself. */ typedef enum { MAJOR_POSITION_CENTER, //!< Stack elements in the center of the layout(for HLayout and VLayout). MAJOR_POSITION_START, //!< Stack elements at the begining of the layout(for HLayout and VLayout). MAJOR_POSITION_END, //!< Stack elements at the end of the layout(for HLayout and VLayout). MAJOR_POSITION_SPREAD, //!< Spread elements evenly inside the layout(for HLayout and VLayout). MAJOR_POSITION_TOP = MAJOR_POSITION_START, //!< Deprecated. MAJOR_POSITION_BOTTOM = MAJOR_POSITION_END, //!< Deprecated. MAJOR_POSITION_LEFT = MAJOR_POSITION_START, //!< Deprecated. MAJOR_POSITION_RIGHT = MAJOR_POSITION_END, //!< Deprecated. eStackTop = MAJOR_POSITION_START, //!< Deprecated. eStackBottom = MAJOR_POSITION_END, //!< Deprecated. eStackLeft = MAJOR_POSITION_START, //!< Deprecated. eStackRight = MAJOR_POSITION_END, //!< Deprecated. eStackCenter = MAJOR_POSITION_CENTER, //!< Deprecated. eStackExpand = MAJOR_POSITION_SPREAD, //!< Deprecated. } LayoutContentDistribution; //! For internal use only. /*! For internal use only. */ typedef enum { SIZE_EQUAL_WIDTH = (1L), SIZE_EQUAL_HEIGHT = (1L) << 1, SIZE_SMALLER_WIDTH = (1L) << 2, SIZE_SMALLER_HEIGHT = (1L) << 3, SIZE_LARGER_WIDTH = (1L) << 4, SIZE_LARGER_HEIGHT = (1L) << 5, SIZE_FORCE_COMPLY = (1L) << 6, eCompliantWidth = SIZE_EQUAL_WIDTH, //!< Deprecated. eCompliantHeight = SIZE_EQUAL_HEIGHT, //!< Deprecated. eSmallerWidth = SIZE_SMALLER_WIDTH, //!< Deprecated. eSmallerHeight = SIZE_SMALLER_HEIGHT, //!< Deprecated. eLargerWidth = SIZE_LARGER_WIDTH, //!< Deprecated. eLargerHeight = SIZE_LARGER_HEIGHT, //!< Deprecated. eForceComply = SIZE_FORCE_COMPLY, //!< Deprecated. } SizeCompliance; enum KeyNavDirection { KEY_NAV_NONE, KEY_NAV_UP, KEY_NAV_DOWN, KEY_NAV_RIGHT, KEY_NAV_LEFT, KEY_NAV_TAB_NEXT, KEY_NAV_TAB_PREVIOUS, KEY_NAV_ENTER, }; class Layout; class View; class Area; class Area: public InitiallyUnownedObject { NUX_DECLARE_OBJECT_TYPE(Area, InitiallyUnownedObject); public: Area(NUX_FILE_LINE_DECL); virtual ~Area(); int GetX() const; int GetY() const; int GetWidth() const; int GetHeight() const; void SetX(int x); void SetY(int y); void SetXY(int x, int y); void SetWidth(int w); void SetHeight(int h); int GetBaseX() const; int GetBaseY() const; int GetBaseWidth() const; int GetBaseHeight() const; void SetBaseX(int x); void SetBaseY(int y); void SetBaseXY(int x, int y); void SetBaseWidth(int w); void SetBaseHeight(int h); //! Set the size of the object. /* Set the size of the object. The size is adjusted to respect the min and max size policy \sa SetWidth(), SetHeight(), SetMinimumSize(), SetMaximumSize(). */ virtual void SetSize(int w, int h); virtual void SetBaseSize(int w, int h); virtual void SetMinimumSize(int w, int h); virtual void SetMaximumSize(int w, int h); virtual void SetMinMaxSize(int w, int h); virtual void SetMinimumWidth(int w); virtual void SetMaximumWidth(int w); virtual void SetMinimumHeight(int h); virtual void SetMaximumHeight(int h); virtual int GetMinimumWidth() const; virtual int GetMaximumWidth() const; virtual int GetMinimumHeight() const; virtual int GetMaximumHeight() const; virtual void ApplyMinWidth(); virtual void ApplyMinHeight(); virtual void ApplyMaxWidth(); virtual void ApplyMaxHeight(); virtual Size GetMinimumSize() const; virtual Size GetMaximumSize() const; //! Get the geometry of the object. /*! @return The Geometry of the object. @sa GetBaseWidth(), GetBaseHeight(), GetBaseX(), GetBaseY(). */ Geometry const& GetGeometry() const; //! Set the geometry of the object. /*! Set the width, height, and x, y position of the object on the screen. @param x Horizontal position. @param y Vertical position. @param w Width. @param h Height. \sa SetBaseWidth(), SetBaseHeight(), SetBaseX(), SetBaseY(). */ virtual void SetGeometry(int x, int y, int w, int h); //! Set the geometry of the object. /*! This is an overloaded member function, provided for convenience. It behaves essentially like SetGeometry(int x, int y, int w, int h). @param geo Geometry object. \sa SetWidth(), SetHeight(), SetX(), SetY(). */ void SetBaseString(std::string const& caption); std::string const& GetBaseString() const; virtual void SetGeometry(const Geometry& geo); //! Deprecated. Use GetToplevel. Area* GetToplevel(); //! Return the root parent of the rendering tree for this area. /*! The root parent of the rendering tree is either a BaseWindow or the main layout. If the object isn't hooked to the rendering tree the function returns NULL. @return The root parent of the rendering tree or NULL. */ Area* GetRootParent(); //! Return the Top level BaseWindow of this area. /*! @return The top level BaseWindow or NULL. */ Area* GetTopLevelViewWindow(); //! Return true is this area has a top level parent. /*! @return True if this area has a top level parent. */ bool HasTopLevelParent(); //! Return true is area is a child of the given parent in the widget tree. /*! @param parent Area to test if it is a parent of this area. @return True if this area is area is a child of parent in the widget tree. */ bool IsChildOf(Area* parent); /*! Test if a point is inside the area. @param p A 2D point. @param event_type The type of mouse event(a parameter of FindAreaUnderMouse). @return True if p is located inside the Area. */ bool TestMousePointerInclusion(const Point& mouse_position, NuxEventType event_type); /*! Test if a point is inside the area and if the area accepts mouse wheel events. @param p A 2D point. @param event_type The type of mouse event(a parameter of FindAreaUnderMouse). @param filter_mouse_wheel_event If the event type is NUX_MOUSE_WHEEL and the mouse is over this area and this area does not accept mouse wheel events, then return false. @return True if p is located inside the Area. */ bool TestMousePointerInclusionFilterMouseWheel(const Point& mouse_position, NuxEventType event); //! Test if the mouse pointer is inside the area. /*! Return true if the mouse pointer is inside the area. @return True if the mouse pointer is inside the area. */ bool IsMousePointerInside() const; virtual long ComputeContentSize(); virtual void ComputeContentPosition(float offsetX, float offsetY); virtual bool IsArea() const; virtual bool IsInputArea() const; virtual bool IsView() const; virtual bool IsLayout() const; virtual bool IsSpaceLayout() const; virtual bool IsViewWindow() const; Area * GetParentObject() const; //! Set visibility of the area /*! If visible, an area will be drawn. Default: true. @param visible if the area is visible to the user */ void SetVisible(bool visible); //! Get the visibility of the area /*! Gets whether the area is visible to the user and will be visible to the user. Default is true. @return whether the area is visible */ bool IsVisible(); //! Deprecated. Use SetInputEventSensitivity. void SetSensitive(bool); //! Set input event sensitivity of the area. /*! A insensitive Area will not receive input events.\n If the Area has a layout, the event will be passed down to it. Sensitivity only control an area's ability to receive input events(keyboard, mouse, touch). An area that is not sensitive will return false in \a TestMousePointerInclusion, \a TestMousePointerInclusionFilterMouseWheel and \a AcceptKeyNavFocus.\n Sensitivity does not affect layouts since they do not process events. By default, an area is sensitive. @param sensitive If the area should receive input events */ void SetInputEventSensitivity(bool sensitive); //! Deprecated. Use GetInputEventSensitivity. bool IsSensitive() const; //! Get input event sensitivity of the area is sensitive /*! Gets whether the area is sensitive to input events @return whether the area is visible */ bool GetInputEventSensitivity() const; sigc::signal ChildFocusChanged; // sends parent + child /*! This signal is received whether the area receiving or loosing the keyboard focus. If the second parameter is true, it means the area is receiving the focus. The third parameter of this signal indicates the keyboard action that triggered this area to receive or loose the keyboard focus. */ sigc::signal key_nav_focus_change; /*! This signal is received when the area has the key focus and the ENTER key has been pressed. */ sigc::signal key_nav_focus_activate; //! Queue a relayout /*! Queues a relayout before the next paint cycle. This is safe to call multiple times within a cycle. */ void QueueRelayout(); //! Get the area scale factor. /*! The scale factor is used to control the layout of area objects inside HLayout and VLayout. \sa HLayout, VLayout. @return the Area scale factor. */ virtual unsigned int GetScaleFactor(); //! Set the area scale factor. /*! The scale factor is used to control the layout of area objects inside HLayout and VLayout. \sa HLayout, VLayout. @param the scale factor. */ virtual void SetScaleFactor(unsigned int sf); virtual MinorDimensionPosition GetPositioning(); virtual void SetPositioning(MinorDimensionPosition p); virtual MinorDimensionSize GetExtend(); virtual void SetExtend(MinorDimensionSize ext); virtual float GetPercentage(); virtual void SetPercentage(float f); virtual bool IsLayoutDone(); virtual void SetLayoutDone(bool b); void Set2DMatrix(const Matrix4 &mat); void Set2DTranslation(float tx, float ty, float tz); Matrix4 Get2DMatrix() const; Matrix4 Get3DMatrix() const; bool Is3DArea() const; //! Return the position of this object with regard to the top left corner of the physical window. /*! Return the position of the Area inside the physical window. For the main layout set in WindowThread, The following functions are equivalent: \li GetGeometry() \li GetRootGeometry() \li GetAbsoluteGeometry() */ virtual Geometry GetAbsoluteGeometry() const; //! Return the area absolute x coordinate. int GetAbsoluteX() const; //! Return the area absolute y coordinate. int GetAbsoluteY() const; //! Return the area absolute width. /*! As long as _2d_xform contains only translations, the absolute width is the same as value returned by GetBaseWidth(); */ int GetAbsoluteWidth() const; //! Return the area absolute height. /*! As long as _2d_xform contains only translations, the absolute height is the same as value returned by GetBaseHeight(); */ int GetAbsoluteHeight() const; //! Return the position of this object with regard to its top level parent(the main layout or a BaseWindow). /*! Return the position of the Area inside the physical window. For the main layout set in WindowThread or for a BaseWindow, GetRootGeometry() is equivalent to GetGeometry(). */ virtual Geometry GetRootGeometry() const; //! Return the area root x coordinate. int GetRootX() const; //! Return the area root y coordinate. int GetRootY() const; //! Return the area root width. /*! As long as _2d_xform contains only translations, the root width is the same as value returned by GetBaseWidth(); */ int GetRootWidth() const; //! Return the area root height. /*! As long as _2d_xform contains only translations, the root width is the same as value returned by GetBaseWidth(); */ int GetRootHeight() const; sigc::signal OnResize; //!< Signal emitted when an area is resized. sigc::signal OnVisibleChanged; sigc::signal OnSensitiveChanged; /*! This signal is only meant to inform of a change of size. When receiving this signal don't do anything that could change the size of this object. Or you risk creating an infinite loop. */ sigc::signal geometry_changed; /*! This signal emitted when the size of the area has changed. It is emitted after geometry_changed. */ sigc::signal size_changed; /*! This signal emitted when the position of the area has changed. It is emitted after geometry_changed. */ sigc::signal position_changed; /*! SetParentObject/UnParentObject are protected API. They are not meant to be used directly by users. Users add widgets to layouts and layout have to be attached to a composition for objects to be rendered. Setting a parent to and child widget does not mean that when the parent is rendered, the child is also rendered. For instance, setting a button to be the child of a check-box means absolutely nothing is terms of rendering. The check-box draw function would have to be aware of the existence of the button in order to render it.\n A view with a parent cannot be parented to another area for rendering. It has to be un-parented first.\n A layout with a parent cannot be parented to another area for rendering. It has to be un-parented first.\n In essence only View and Layouts should be calling SetParentObject/UnParentObject.\n SetParentObject returns true if it was successful. @param parent The object that will become the parent of this area. @return True if the object is successfully parented. */ virtual bool SetParentObject(Area *parent); //! Un-parent and area /*! For un-parented areas the following functions are equivalent: \li GetGeometry() \li GetRootGeometry() \li GetAbsoluteGeometry() */ virtual void UnParentObject(); /*! Return the area under the mouse pointer. @return The Area under the mouse pointer. */ virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); virtual Area* FindKeyFocusArea(unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state); /*! Mark the path from this area to its top level parent as the one to follow \n to get to the area that has the keyboard. */ void SetPathToKeyFocusArea(); /*! Erase the path from this area to the child area that has the keyboard. */ void ResetDownwardPathToKeyFocusArea(); /*! Erase the path that marks this object as part of the keyboard focus chain, \n from this area to its top level parent. */ void ResetUpwardPathToKeyFocusArea(); //! Return True if the the area knows what to do with the key event. /*! For a View to receive the key_up and key_down signal, it must override this function and return true. @param even_type Event type is either EVENT_KEY_DOWN or EVENT_KEY_UP. @param keysym The key symbol. @param characters The character string of the key. @return bool True if the View wants to received the key events signals. */ virtual bool InspectKeyEvent(unsigned int event_type, unsigned int keysym, const char* character); virtual Area* KeyNavIteration(KeyNavDirection direction); bool HasKeyFocus() const; //! Set to True to initiate a layout reconfiguration when the geometry of this widget changes. /*! When the geometry of an area changes, the new geometry can be recursively propagated to all its parent so a layout reconfiguration is initiated. \sa ReconfigureParentLayout() \sa on_geometry_change_reconfigure_parent_layout_ @param reconfigure_parent_layout Set it to True to reconfigure this area parent layouts. */ void SetReconfigureParentLayoutOnGeometryChange(bool reconfigure_parent_layout); //! Return True if the the parent layouts of this area should be reconfigured on geometry changed. /*! @return True if the parent layouts of this area must be reconfigured on a geometry change. */ bool ReconfigureParentLayoutOnGeometryChange(); //! Enable keyboard event processing. /*! @param accept_key_event Set it to true if the area accepts keyboard events. */ void SetAcceptKeyboardEvent(bool accept_key_event); //! Return true if the Area is interested in keyboard events. /*! @return True if the area accepts in keyboard events. */ bool AcceptKeyboardEvent() const; //! Enable mouse wheel event processing. /*! @param accept_mouse_wheel_event Set it to true if the area accepts mouse wheel events. */ void SetAcceptMouseWheelEvent(bool accept_mouse_wheel_event); //! Return true if the area is accepts mouse wheel events. /*! @return True if the area accepts mouse wheel events. */ bool AcceptMouseWheelEvent() const; protected: /* This function is reimplemented in Layout as it need to perform some special operations. It does nothing for Area and View classes. */ //virtual void RemoveChildObject(smptr(Area)); /*! This signal is only meant to inform that the size is about to change. When overriding this function, don't do anything that could change the size of this object. Or you risk creating an infinite loop. */ virtual void GeometryChangePending(bool /* position_about_to_change */, bool /* size_about_to_change */) {} /*! This signal is only meant to inform that the size has changed. When overriding this function, don't do anything that could change the size of this object. Or you risk creating an infinite loop. */ virtual void GeometryChanged(bool /* position_has_changed */, bool /* size_has_changed */) {} //! Request a Layout recompute after a change of size /* When an object size changes, it is necessary for its parent structure to initiate a layout re computation in order preserve the layout structure defined by the user through the API. */ virtual void RequestBottomUpLayoutComputation(Area *bo_initiator); //! Return the absolute geometry starting with a relative geometry passed as argument. void InnerGetAbsoluteGeometry(Geometry &geometry); //! Return the absolute geometry starting with a relative geometry passed as argument. void InnerGetRootGeometry(Geometry &geometry); bool on_geometry_change_reconfigure_parent_layout_; //! If this variable is true, then this area has the keyboard focus. bool has_key_focus_; void SetNextObjectToKeyFocusArea(Area*); //! Gets the next object in the chain that ends with the area that has the keyboard focus. /*! Gets the next object in the chain that ends with the area that has the keyboard focus. The next object is a child of this area. @return An area that is the next object in the chain that leads to the area that has the keyboard focus. */ Area* GetNextObjectToKeyFocusArea(); //! If this variable is not NULL, then this area is part of the keyboard focus chain. Area* next_object_to_key_focus_area_; /**********************************************/ /*** Begin support for redirected rendering ***/ /**********************************************/ public: //! Redirect the rendering of this view to a texture. /*! Redirect the rendering of this view to a texture. \sa BackupTexture(). @param redirect If true, redirect the rendering of this view to a texture. */ virtual void SetRedirectRenderingToTexture(bool redirect); /*! @return True if the rendering of this view is done in a texture. */ virtual bool RedirectRenderingToTexture() const; //! Return the texture of this View if RedirectRenderingToTexture is enabled. /* Return the texture of this View if RedirectRenderingToTexture is enabled. If RedirectRenderingToTexture() is false, then backup_texture_ is not a valid smart pointer. @return the device texture that contains the rendering of this view. */ ObjectPtr BackupTexture() const; /*! The use of this function is a bit arcan but it gives more rendering options to redirected areas. */ void SetCopyPreviousFboTexture(bool copy); /*! Activate/Deactivate the presentation of the redirected texture in the rendering tree. */ void SetPresentRedirectedView(bool present_redirected_view); /*! @return True if the redirected texture is displayed in the rendering tree. */ bool PresentRedirectedView() const; protected: //! Redirect the rendering of the view to a texture. bool redirect_rendering_to_texture_; bool update_backup_texture_; bool present_redirected_view_; //! The texture that holds the rendering of this view. ObjectPtr backup_texture_; ObjectPtr backup_depth_texture_; ObjectPtr background_texture_; ObjectPtr backup_fbo_; ObjectPtr prev_fbo_; Geometry prev_viewport_; Matrix4 model_view_matrix_; Matrix4 perspective_matrix_; /*! If true, copy the area in the previous fbo texture into background_texture_. */ bool copy_previous_fbo_for_background_; /*! Implemented in nux::View and nux::Layout. Report to a parent view with redirect_rendering_to_texture_ set to true that one of its children needs to be redrawn. */ virtual void PrepareParentRedirectedView(); virtual bool HasParentRedirectedView(); Area* RedirectedAncestor(); /*! Inform this view that one of its children has requested a draw. This view must have its rendering redirected to a texture. @param update True if this view is redirected and one of its children has requested a draw. */ virtual void SetUpdateBackupTextureForChildRendering(bool update); virtual bool UpdateBackupTextureForChildRendering() const; /********************************************/ /*** End support for redirected rendering ***/ /********************************************/ #ifdef NUX_GESTURES_SUPPORT //! Returns the InputArea hit by the given gesture virtual Area* GetInputAreaHitByGesture(const GestureEvent &event); //! Returns whether the gesture from the given event is fully inside this area. /*! For getures from direct devices (e.g. touchscreens), it checks whether all touch points lie within this area's boundaries. For gestures from indirect devices (e.g. touchpads) it checks whether the gesture's focus point lies inside this area. */ bool IsGestureInsideArea(const GestureEvent &event) const; #endif // NUX_GESTURES_SUPPORT private: void ReconfigureParentLayout(Area *child = 0); void CheckMinSize(); void CheckMaxSize(); Geometry geometry_; //!< The area geometry. //! Define a parent child structure /* An object of the class Area may have another of the class Layout as Parent. An object of the class View may have an object of the class Layout as parent. An object of the class Layout may have a parent of the class Layout or View as parent. A Area cannot have children(that may change later). */ Area* parent_area_; bool visible_; //!< Visible state of the area. bool sensitive_; //!< Input sensitive state of the area bool view_enabled_; //!< The enable state of a view. std::string base_string_; //!< A text string property for this area. Size min_size_; //!< A text string property for this area. Size max_size_; //!< A text string property for this area. // Parameters used in layouts unsigned int scale_factor_; //!< Factor for element expansion. MinorDimensionPosition minor_axis_position_; //!< Area position hint MinorDimensionSize minor_axis_size_; //!< Area dimension hint float minor_axis_size_scale_; //!< Area size percentage value. bool layout_done_; //!< Area layout status flag. Matrix4 _2d_xform; //!< 2D transformation matrix for this area and its children. Contains only translations. Matrix4 _3d_xform; //!< 3D transformation matrix for the area in a perspective space. bool _3d_area; //!< True if the area is resides in a 3D space. std::list _children_list; bool accept_mouse_wheel_event_; bool accept_keyboard_event_; WindowThread* window_thread_; friend class Layout; friend class View; friend class WindowCompositor; friend class WindowThread; #if !defined(NUX_MINIMAL) friend class HSplitter; friend class VSplitter; #endif }; } #endif // BASEOBJECT_H nux-4.0.8+18.10.20180623/Nux/BaseWindow.cpp0000644000000000000000000003543413313373365014132 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/GLTextureResourceManager.h" #include "Layout.h" #include "HLayout.h" #include "WindowCompositor.h" #include "BaseWindow.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(BaseWindow); /* Elements inside the Window have coordinates based on the top-left corner of the window. This is true whether we are drawing or computing the layout. When computing the layout, use x_root and y_root to pass the top-left corner position of the window. When drawing, make a similar adjustment. */ BaseWindow::BaseWindow(const char *WindowName, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , _paint_layer(new ColorLayer(Color(0xFF707070))) , _opacity(1.0f) , _present_in_embedded_mode(false) , _contents_ready_for_presentation(false) { premultiply = true; _name = WindowName; _child_need_redraw = true; m_TopBorder = 0; m_Border = 0; _size_match_layout = false; _is_visible = false; _is_modal = false; #if defined(USE_X11) m_input_window_enabled = false; m_input_window = 0; #endif m_layout = 0; m_configure_notify_callback = NULL; m_configure_notify_callback_data = NULL; _entering_visible_state = false; _entering_hidden_state = false; _enter_focus_input_area = NULL; accept_key_nav_focus_ = false; SetAcceptKeyNavFocusOnMouseDown(false); // Should be at the end of the constructor GetWindowThread()->GetWindowCompositor().RegisterWindow(this); SetMinimumSize(1, 1); SetGeometry(Geometry(100, 100, 320, 200)); } BaseWindow::~BaseWindow() { if (_enter_focus_input_area) { _enter_focus_input_area->UnReference(); } #if defined(USE_X11) if (m_input_window) delete m_input_window; #endif } Area* BaseWindow::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; if (m_layout) { nuxAssert(m_layout->IsLayout()); Area* found_area = m_layout->FindAreaUnderMouse(mouse_position, event_type); if (found_area) return found_area; } if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } void BaseWindow::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); // The elements position inside the window are referenced to top-left window corner. So bring base to(0, 0). base.SetX(0); base.SetY(0); graphics_engine.PushClippingRectangle(base); GetPainter().PushDrawLayer(graphics_engine, base, _paint_layer.get()); GetPainter().PopBackground(); graphics_engine.PopClippingRectangle(); } void BaseWindow::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); // The elements position inside the window are referenced to top-left window corner. So bring base to(0, 0). base.SetX(0); base.SetY(0); GetPainter().PushLayer(graphics_engine, base, _paint_layer.get()); if (m_layout) { graphics_engine.PushClippingRectangle(base); m_layout->ProcessDraw(graphics_engine, force_draw); graphics_engine.PopClippingRectangle(); } GetPainter().PopBackground(); } void BaseWindow::SetConfigureNotifyCallback(ConfigureNotifyCallback Callback, void *Data) { m_configure_notify_callback = Callback; m_configure_notify_callback_data = Data; } Layout* BaseWindow::GetLayout() { return m_layout; } bool BaseWindow::SetLayout(Layout *layout) { if (View::SetLayout(layout) == false) return false; m_layout = layout; Geometry geo = GetGeometry(); Geometry layout_geo = Geometry(geo.x + m_Border, geo.y + m_TopBorder, geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder); m_layout->SetGeometry(layout_geo); // When this call returns the layout computation is done. ComputeContentSize(); // or use //GetWindowThread()->QueueObjectLayout(m_layout); return true; } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. void BaseWindow::PreLayoutManagement() { Geometry geo = GetGeometry(); if (m_configure_notify_callback) { (*m_configure_notify_callback)(GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data); if (geo.IsNull()) { nuxDebugMsg("[BaseWindow::PreLayoutManagement] Received an invalid Geometry."); geo = GetGeometry(); } else { Area::SetGeometry(geo); // Get the geometry adjusted with respect to min and max dimension of this area. geo = GetGeometry(); } } if (m_layout) { Geometry layout_geo = Geometry(m_Border, m_TopBorder, geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder); if (IsSizeMatchContent()) m_layout->SetGeometry(Geometry(0, 0, 1, 1)); else m_layout->SetGeometry(layout_geo); } } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. long BaseWindow::PostLayoutManagement(long /* LayoutResult */) { if (IsSizeMatchContent() && m_layout) { Geometry layout_geometry = m_layout->GetGeometry(); Geometry WindowGeometry = Geometry(GetGeometry().x, GetGeometry().y, layout_geometry.GetWidth() + 2 * m_Border, layout_geometry.GetHeight() + m_Border + m_TopBorder); Area::SetGeometry(WindowGeometry); } // A BaseWindow must kill the result of the management and pass it to the parent Layout. return (eCompliantHeight | eCompliantWidth); //return result; } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. void BaseWindow::ComputeContentPosition(float /* offsetX */, float /* offsetY */) { } #if defined(NUX_OS_LINUX) void BaseWindow::EnableInputWindow(bool b, const char* title, bool take_focus, bool override_redirect) { #if defined(USE_X11) if (b) { if (m_input_window == 0) m_input_window = new XInputWindow(title, take_focus, override_redirect); m_input_window->Show(); m_input_window->SetGeometry(GetGeometry()); m_input_window_enabled = true; } else { if (m_input_window) m_input_window->Hide(); m_input_window_enabled = false; } #endif } bool BaseWindow::InputWindowEnabled() { #if defined(USE_X11) return m_input_window_enabled; #else return false; #endif } void BaseWindow::InputWindowEnableStruts(bool enable) { #if defined(USE_X11) if (m_input_window) m_input_window->EnableStruts(enable); #endif } bool BaseWindow::InputWindowStrutsEnabled() { #if defined(USE_X11) return m_input_window_enabled && m_input_window->StrutsEnabled(); #else return false; #endif } void BaseWindow::InputWindowEnableOverlayStruts(bool enable) { #if defined(USE_X11) if (m_input_window) m_input_window->EnableOverlayStruts(enable); #endif } bool BaseWindow::InputWindowOverlayStrutsEnabled() { #if defined(USE_X11) return m_input_window && m_input_window->OverlayStrutsEnabled(); #else return false; #endif } void BaseWindow::SetInputFocus() { #if defined(USE_X11) if (m_input_window) m_input_window->SetInputFocus(); #endif } Window BaseWindow::GetInputWindowId() { #if defined(USE_X11) if (m_input_window) return m_input_window->GetWindow(); else return 0; #else return 0; #endif } #endif void BaseWindow::SetGeometry(const Geometry &geo) { Area::SetGeometry(geo); #if defined(USE_X11) if (m_input_window) m_input_window->SetGeometry(geo); #endif //LayoutWindowElements(); //ComputeContentSize(); } void BaseWindow::LayoutWindowElements() { // Define the geometry of some of the component of the window. Otherwise, if the composition layout is not set, // then the component won't be correctly placed after a SetGeometry. This can be redondant if the composition layout is set. GetGeometry(); } void BaseWindow::SetBorder(int border) { if (m_Border != border) { m_Border = border; } } void BaseWindow::SetTopBorder(int border) { if (m_TopBorder != border) { m_TopBorder = border; } } int BaseWindow::GetBorder() const { return m_Border; } int BaseWindow::GetTopBorder() const { return m_TopBorder; } void BaseWindow::ShowWindow(bool visible, bool StartModal /* = false */) { if (visible == _is_visible) return; _is_visible = visible; _is_modal = StartModal; if (_is_visible) { if (m_layout) { m_layout->SetGeometry(GetGeometry()); } _entering_visible_state = true; sigVisible.emit(this); GetWindowThread()->GetWindowCompositor().sigVisibleViewWindow.emit(this); ComputeContentSize(); } else { SetEnterFocusInputArea(NULL); _entering_hidden_state = true; sigHidden.emit(this); GetWindowThread()->GetWindowCompositor().sigHiddenViewWindow.emit(this); } if (_is_modal) GetWindowThread()->GetWindowCompositor().StartModalWindow(ObjectWeakPtr(this)); // Whether this view is added or removed, call QueueDraw. in the case where this view is removed, this is a signal // that the region below this view need to be redrawn. QueueDraw(); } bool BaseWindow::IsVisible() const { return _is_visible; } void BaseWindow::StopModal() { _is_visible = false; _is_modal = false; //ShowWindow(false); GetWindowThread()->GetWindowCompositor().StopModalWindow(ObjectWeakPtr (this)); } bool BaseWindow::IsModal() const { return _is_modal; } void BaseWindow::NotifyConfigurationChange(int /* Width */, int /* Height */) { Geometry geo = GetGeometry(); if (m_configure_notify_callback) { (*m_configure_notify_callback) (GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data); if (geo.IsNull()) { nuxDebugMsg("[BaseWindow::NotifyConfigurationChange] Received an invalid Geometry."); geo = GetGeometry(); } else { Area::SetGeometry(geo); // Get the geometry adjusted with respect to min and max dimension of this area. geo = GetGeometry(); } } else { return; } } void BaseWindow::SetBackgroundLayer(AbstractPaintLayer *layer) { NUX_RETURN_IF_NULL(layer); _paint_layer.reset(layer->Clone()); } void BaseWindow::SetBackgroundColor(const Color &color) { _paint_layer.reset(new ColorLayer(color)); } void BaseWindow::PushHigher(BaseWindow* floating_view) { GetWindowThread()->GetWindowCompositor().PushHigher(this, floating_view); } void BaseWindow::PushToFront() { GetWindowThread()->GetWindowCompositor().PushToFront(this); } void BaseWindow::PushToBack() { GetWindowThread()->GetWindowCompositor().PushToBack(this); } bool BaseWindow::ChildNeedsRedraw() { return _child_need_redraw; } void* BaseWindow::GetBackupTextureData(int &width, int &height, int &format) { return GetWindowThread()->GetWindowCompositor().GetBackupTextureData(this, width, height, format); } void BaseWindow::PresentInEmbeddedModeOnThisFrame(bool force) { nuxAssertMsg (GetWindowThread()->IsEmbeddedWindow(), "[BaseWindow::PresentInEmbeddedModeOnThisFrame] only " "supported in embdded mode"); /* Invisible windows are never presented */ if (!IsVisible()) return; if (nux::GetWindowThread()->AddToPresentationList(this, force)) _present_in_embedded_mode = true; } void BaseWindow::MarkPresentedInEmbeddedMode() { _present_in_embedded_mode = false; _last_presented_geometry_in_embedded_mode = GetAbsoluteGeometry(); } nux::Geometry const& BaseWindow::LastPresentedGeometryInEmbeddedMode() const { return _last_presented_geometry_in_embedded_mode; } bool BaseWindow::AllowPresentationInEmbeddedMode() const { return _present_in_embedded_mode; } void BaseWindow::PrepareParentRedirectedView() { Area::PrepareParentRedirectedView(); if (GetWindowThread()->IsEmbeddedWindow()) PresentInEmbeddedModeOnThisFrame(); } void BaseWindow::SetEnterFocusInputArea(InputArea *input_area) { if (_enter_focus_input_area) { _enter_focus_input_area->UnReference(); } _enter_focus_input_area = input_area; if (_enter_focus_input_area) _enter_focus_input_area->Reference(); } void BaseWindow::SetOpacity(float opacity) { if (_opacity == opacity) return; _opacity = opacity; _opacity = CLAMP(_opacity, 0.0f, 1.0f); QueueDraw(); } float BaseWindow::GetOpacity() { return _opacity; } void BaseWindow::SetAcceptKeyNavFocus(bool accept) { accept_key_nav_focus_ = accept; } bool BaseWindow::AcceptKeyNavFocus() { return accept_key_nav_focus_; } #ifdef NUX_GESTURES_SUPPORT Area* BaseWindow::GetInputAreaHitByGesture(const nux::GestureEvent &event) { if (!IsVisible()) return nullptr; if (!IsGestureInsideArea(event)) return nullptr; if (m_layout) { Area *area_hit = m_layout->GetInputAreaHitByGesture(event); if (area_hit) return area_hit; } if (HasSubscriptionForGesture(event)) return this; else return nullptr; } #endif } nux-4.0.8+18.10.20180623/Nux/BaseWindow.h0000644000000000000000000002276413313373365013601 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef BASEWINDOW_H #define BASEWINDOW_H #include #include "ScrollView.h" #include "NuxGraphics/Events.h" #if defined(USE_X11) # include "NuxGraphics/XInputWindow.h" #endif #include "InputArea.h" #include "PaintLayer.h" namespace nux { class BaseWindow; typedef BaseWindow ViewWindow; class HLayout; class PopUpWindow; #ifdef NUX_GESTURES_SUPPORT class GestureEvent; #endif //typedef TopView BaseWindow; /*! A user provided callback to assert the size and position of a floating area. The callback receives a proposed size and position for the floating area. Inside the callback, the size and position of the floating area can be modified. @param int The width of the window. @param int The height of the window. @param Geometry& The tentative size of the window. */ typedef void(*ConfigureNotifyCallback) (int, int, Geometry &, void *); /*! A floating area on top of the main window. A BaseWindow is referenced by the WindowCompositor who calls Reference on the BaseWindow during registration. */ class BaseWindow: public View { NUX_DECLARE_OBJECT_TYPE(BaseWindow, View); public: BaseWindow(const char *WindowName = "", NUX_FILE_LINE_PROTO); virtual ~BaseWindow(); nux::Property premultiply; virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual Layout* GetLayout(); virtual bool SetLayout(Layout *layout); //! Push the view one level up the ViewWindow stack. /*! Push this view one level up the ViewWindow stack. Does it even if the view is hidden. */ void PushHigher(BaseWindow* floating_view); //! Push the view one level down the ViewWindow stack. /*! Push this view one level down the ViewWindow stack. Does it even if the view is hidden. */ void PushLower(BaseWindow* floating_view); //! Push the view to the front of the ViewWindow stack. /*! Push this view to the top of the ViewWindow stack. Does it even if the view is hidden. If a valid ViewWindow has been forced at the top of the stack with a call to WindowCompositor::SetAlwaysOnFrontWindow(), then this view will be positioned one level below that view. \sa SetAlwaysOnFrontWindow(); */ void PushToFront(); //! Push the view to the back of the ViewWindow stack. /*! Push this view to the back of the ViewWindow stack. Does it even if the view is hidden. */ void PushToBack(); //! Set the window size to respect the layout container. /*! Set the window size to be such that the container layout size remains the same after ComputeSizeLayout2 is called on the layout. The window elements(title bar, minimize and close buttons) are positioned accordingly. The size grip is not responding anymore. @param b If b is true, the window size respect the size the layout container. */ virtual void SetWindowSizeMatchLayout(bool b) { _size_match_layout = b; } //! Check if the window size is constrained to the layout container size. /*! Check if the window size is constrained to the layout container size. @return If the return value is true, the window size is constrained by the size the layout container. */ bool IsSizeMatchContent() const { return _size_match_layout; } virtual void ShowWindow(bool b, bool StartModal = false); void StopModal(); bool IsModal() const; bool IsVisible() const; virtual void SetGeometry(const Geometry &geo); /*! Call this function to set a callback function that is called when this object is need to be resized or re-positioned. @param Callback Function to be called to set the this object size and position. @param Data The callback data. */ void SetConfigureNotifyCallback(ConfigureNotifyCallback Callback, void *Data); void SetBackgroundLayer(AbstractPaintLayer *layer); void SetBackgroundColor(const Color &color); void SetOpacity(float opacity); float GetOpacity(); #if defined(NUX_OS_LINUX) void EnableInputWindow(bool b, const char* title = "nux input window", bool take_focus = False, bool override_redirect = False); bool InputWindowEnabled(); void InputWindowEnableStruts(bool enable); bool InputWindowStrutsEnabled(); void InputWindowEnableOverlayStruts(bool enable); bool InputWindowOverlayStrutsEnabled(); void SetInputFocus(); Window GetInputWindowId(); #endif //! Set an InputArea to receive the keyboard focus when the BaseWIndow receives the NUX_WINDOW_ENTER_FOCUS event. /*! \sa _enter_focus_input_area. @param input_area An InputArea pointer object. Must be a child of this BaseWindow. */ void SetEnterFocusInputArea(InputArea *input_area); //! Get the backup texture data of this BaseWindow, void* GetBackupTextureData(int &width, int &height, int &format); //! Emit a signal when the BaseWindow becomes visible. sigc::signal sigVisible; //! Emit a signal when the BaseWindow becomes hidden. sigc::signal sigHidden; std::string GetWindowName() { return _name; } void PresentInEmbeddedModeOnThisFrame(bool force = false); void MarkPresentedInEmbeddedMode(); bool AllowPresentationInEmbeddedMode() const; nux::Geometry const& LastPresentedGeometryInEmbeddedMode() const; void PrepareParentRedirectedView(); #ifdef NUX_GESTURES_SUPPORT virtual Area* GetInputAreaHitByGesture(const nux::GestureEvent &event); #endif protected: void SetAcceptKeyNavFocus(bool accept); bool accept_key_nav_focus_; virtual bool AcceptKeyNavFocus(); //! Callback function to set the window position and size. ConfigureNotifyCallback m_configure_notify_callback; //! Callback data for ConfigureNotifyCallback. void *m_configure_notify_callback_data; //sigc::signal< bool, unsigned int, unsigned int, Geometry & > sigRequestConfigure; Layout *m_layout; friend class ComboBox_Logic_WindowView; virtual void PreLayoutManagement(); virtual long PostLayoutManagement(long LayoutResult); virtual void ComputeContentPosition(float offsetX, float offsetY); //! Layout the window elements. /*! Layout elements such as button on the title bar, and the resize widget according to the current geometry of the window. Also initiate the computation of the child layout if there is one. */ virtual void LayoutWindowElements(); /*! Floating Area need to be informed when the main window has been resized. @param Width New width of the window. @param Height New height of the window. */ virtual void NotifyConfigurationChange(int Width, int Height); int GetBorder() const; int GetTopBorder() const; void SetBorder(int border); void SetTopBorder(int border); int m_TopBorder; int m_Border; boost::scoped_ptr _paint_layer; bool _entering_visible_state; //!< the window is about to be made visible during event processing bool _entering_hidden_state; //!< the window is about to be made hidden during event processing bool ChildNeedsRedraw(); #if defined(USE_X11) bool m_input_window_enabled; XInputWindow *m_input_window; #endif private: //! Contains the background of the texture. Can be used to blur. It is set by the window compositor. ObjectPtr _background_texture; std::string _name; bool _size_match_layout; bool _is_visible; bool _is_modal; InputArea *_enter_focus_input_area; //!< An input Area to set the keyboad focus on in response to NUX_WINDOW_ENTER_FOCUS. std::list m_InterfaceObject; bool _child_need_redraw; //! * * Authored by: Jay Taoko * */ #include "Nux/Nux.h" #include "BasicView.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(BasicView); BasicView::BasicView(NUX_FILE_LINE_DECL) : nux::View(NUX_FILE_LINE_PARAM) { } BasicView::~BasicView() { } void BasicView::Draw(nux::GraphicsEngine& /* graphics_engine */, bool /* force_draw */) { // Draw nothing // For debug only: // graphics_engine.QRP_Color(GetBaseX(), GetBaseY(), GetBaseWidth(), GetBaseHeight(), nux::color::Pink); } } nux-4.0.8+18.10.20180623/Nux/BasicView.h0000644000000000000000000000206613313373365013404 0ustar /* * Copyright 2012 Inalogic Inc. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see * * * Authored by: Jay Taoko * */ #ifndef BASIC_VIEW_H #define BASIC_VIEW_H namespace nux { //! A very basic View object with no rendering. class BasicView: public nux::View { NUX_DECLARE_OBJECT_TYPE(BasicView, View); public: BasicView(NUX_FILE_LINE_PROTO); ~BasicView(); protected: void Draw(nux::GraphicsEngine& graphics_engine, bool force_draw); }; } #endif // BASIC_VIEW_H nux-4.0.8+18.10.20180623/Nux/Button.cpp0000644000000000000000000003061513313373365013337 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Button.h" #include "StaticText.h" #include "HLayout.h" #include "VLayout.h" #include "TextureArea.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(Button); Button::Button(TextureArea *image, NUX_FILE_LINE_DECL) : AbstractButton(NUX_FILE_LINE_PARAM) { image_ = NULL; Initialize(std::string(), image); } Button::Button(const std::string& button_label, NUX_FILE_LINE_DECL) : AbstractButton(NUX_FILE_LINE_PARAM) { image_ = NULL; Initialize(button_label, NULL); } Button::Button(const std::string& button_label, TextureArea *image, NUX_FILE_LINE_DECL) : AbstractButton(NUX_FILE_LINE_PARAM) { image_ = NULL; Initialize(button_label, image); } Button::Button(NUX_FILE_LINE_DECL) : AbstractButton(NUX_FILE_LINE_PARAM) { image_ = NULL; Initialize(std::string(), NULL); } Button::~Button() { if (image_) image_->UnReference(); if (static_text_) static_text_->UnReference(); } void Button::Initialize(const std::string &str, TextureArea *image) { same_size_as_content_ = true; persistent_active_state_ = false; layout_type_ = HORIZONTAL; item_order_ = IMAGE_FIRST; distribution_ = CENTER_OF_LAYOUT; space_between_items_ = 0; layout_top_padding_ = 2; layout_right_padding_ = 2; layout_bottom_padding_ = 2; layout_left_padding_ = 2; int clip = 2; left_clip_ = clip; right_clip_ = clip; top_clip_ = clip; bottom_clip_ = clip; // Set Geometry SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); image_minimum_size_ = Size(16, 16); image_maximum_size_ = Size(AREA_MAX_WIDTH, AREA_MAX_HEIGHT); BuildLayout(str, image); } void Button::SetImage(TextureArea *image) { if (image == NULL) return; BuildLayout(label_, image); } void Button::SetLabel(const std::string &button_label) { BuildLayout(button_label, image_); } TextureArea* Button::GetImage() { if (image_ == NULL) return NULL; TextureArea *texture_area = new TextureArea(); texture_area->SetPaintLayer(image_->GetPaintLayer()); return texture_area; } std::string Button::GetLabel() const { return label_; } void Button::SetImageMinimumSize(int width, int height) { image_minimum_size_ = Size(width, height); if (image_) image_->SetMinimumSize(width, height); } void Button::SetImageMaximumSize(int width, int height) { image_maximum_size_ = Size(width, height); if (image_) image_->SetMaximumSize(width, height); } void Button::SetLayoutPadding(int top, int right, int bottom, int left) { layout_top_padding_ = top >= 0 ? top : 0; layout_right_padding_ = right >= 0 ? right : 0; layout_bottom_padding_ = bottom >= 0 ? bottom : 0; layout_left_padding_ = left >= 0 ? left : 0; if (view_layout_) { static_cast(view_layout_)->SetPadding(layout_top_padding_, layout_right_padding_, layout_bottom_padding_, layout_left_padding_); } ComputeContentSize(); QueueDraw(); } void Button::SetButtonClipRegion(int top_clip, int right_clip, int bottom_clip, int left_clip) { top_clip_ = top_clip >= 0 ? top_clip : 0; right_clip_ = right_clip >= 0 ? right_clip : 0; bottom_clip_ = bottom_clip >= 0 ? bottom_clip : 0; left_clip_ = left_clip >= 0 ? left_clip : 0; } void Button::BuildLayout(const std::string &str, TextureArea* image) { if (image_ != image) { if (image_) { image_->UnReference(); nuxAssert(image_->GetReferenceCount() == 1); image_ = NULL; } if (image) { image_ = new TextureArea(); image_->Reference(); // WARNING: GetPaintLayer returns a clone and SetPaintLayer makes a copy of the clone // UnReference temp otherwise it will be lost and cause a mem leak. AbstractPaintLayer *temp = image->GetPaintLayer(); image_->SetPaintLayer(temp); delete temp; SetImageMinimumSize(image->GetMinimumWidth(), image->GetMinimumHeight()); SetImageMaximumSize(image->GetMaximumWidth(), image->GetMaximumHeight()); } } bool create_new_text = false; if (static_text_ && (str != static_text_->GetText())) { create_new_text = true; } if ((static_text_ == NULL) && (str != "")) { create_new_text = true; } if (create_new_text) { if (static_text_) { static_text_->UnReference(); nuxAssert(static_text_->GetReferenceCount() == 1); static_text_ = NULL; } if (str != "") { label_ = str; static_text_ = new StaticText(str, NUX_TRACKER_LOCATION); static_text_->Reference(); static_text_->SetTextColor(label_color_); } } RemoveLayout(); LinearLayout *layout = NULL; if (static_text_ && image_) { if ((layout_type_ == HORIZONTAL) && (item_order_ == IMAGE_FIRST)) { layout = new HLayout(NUX_TRACKER_LOCATION); layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->SetHorizontalInternalMargin(space_between_items_); } else if ((layout_type_ == HORIZONTAL) && (item_order_ == LABEL_FIRST)) { layout = new HLayout(NUX_TRACKER_LOCATION); layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->SetHorizontalInternalMargin(space_between_items_); } else if ((layout_type_ == VERTICAL) && (item_order_ == IMAGE_FIRST)) { layout = new VLayout(NUX_TRACKER_LOCATION); layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->SetVerticalInternalMargin(space_between_items_); } else if ((layout_type_ == VERTICAL) && (item_order_ == LABEL_FIRST)) { layout = new VLayout(NUX_TRACKER_LOCATION); layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->SetVerticalInternalMargin(space_between_items_); } // Both image_ and static_text_ have a reference count of 2. nuxAssert(image_->GetReferenceCount() == 2); nuxAssert(static_text_->GetReferenceCount() == 2); } else if (static_text_) { if (layout_type_ == HORIZONTAL) { layout = new HLayout(NUX_TRACKER_LOCATION); layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); } else if (layout_type_ == VERTICAL) { layout = new VLayout(NUX_TRACKER_LOCATION); layout->AddView(static_text_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); } nuxAssert(static_text_->GetReferenceCount() == 2); } else if (image_) { if (layout_type_ == HORIZONTAL) { layout = new HLayout(NUX_TRACKER_LOCATION); layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); } else if (layout_type_ == VERTICAL) { layout = new VLayout(NUX_TRACKER_LOCATION); layout->AddView(image_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); } nuxAssert(image_->GetReferenceCount() == 2); } if (static_text_) { static_text_->SetInputEventSensitivity(false); static_text_->SetTextPointSize(label_font_size_); } if (image_) { image_->SetInputEventSensitivity(false); } if (layout) { switch(distribution_) { case START_OF_LAYOUT: layout->SetContentDistribution(MAJOR_POSITION_LEFT); break; case END_OF_LAYOUT: layout->SetContentDistribution(MAJOR_POSITION_RIGHT); break; case CENTER_OF_LAYOUT: layout->SetContentDistribution(MAJOR_POSITION_CENTER); break; case SPREAD_OVER_LAYOUT: layout->SetContentDistribution(MAJOR_POSITION_SPREAD); break; } } if (layout) { layout->SetHorizontalInternalMargin(space_between_items_); layout->SetPadding(layout_top_padding_, layout_right_padding_, layout_bottom_padding_, layout_left_padding_); } if (layout) { SetLayout(layout); } ComputeContentSize(); QueueDraw(); } void Button::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); UXStyleImageRef ref_style = eIMAGE_STYLE_NONE; if (visual_state_ == VISUAL_STATE_PRESSED) { ref_style = eBUTTON_FOCUS; } else if (visual_state_ == VISUAL_STATE_PRELIGHT) { ref_style = eBUTTON_PRELIGHT; } else { ref_style = eBUTTON_NORMAL; } TexCoordXForm texxform; ROPConfig rop; rop.Blend = true; rop.SrcBlend = GL_ONE; rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; GetPainter().PushDrawSliceScaledTextureLayer(graphics_engine, base, ref_style, color::White, eAllCorners, true, rop); if (GetCompositionLayout()) { GetPainter().PushPaintLayerStack(); { Geometry clip_geo = base; clip_geo.OffsetPosition(left_clip_, top_clip_); clip_geo.OffsetSize(-left_clip_ - right_clip_, -top_clip_ - bottom_clip_); graphics_engine.PushClippingRectangle(clip_geo); GetCompositionLayout()->ProcessDraw(graphics_engine, true); graphics_engine.PopClippingRectangle(); } GetPainter().PopPaintLayerStack(); } GetPainter().PopPaintLayer(); graphics_engine.PopClippingRectangle(); } long Button::ComputeContentSize() { return View::ComputeContentSize(); } void Button::Activate() { if (persistent_active_state_ == false) { return; } if (active_ == true) { // already active return; } active_ = true; state_change.emit(this); QueueDraw(); } void Button::Deactivate() { if (persistent_active_state_ == false) { return; } if (active_ == false) { // already deactivated return; } active_ = false; state_change.emit(this); QueueDraw(); } void Button::RecvClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (persistent_active_state_) { active_ = !active_; } click.emit(this); state_change.emit(this); QueueDraw(); } void Button::SetDistribution(Distribution distribution) { distribution_ = distribution; BuildLayout(label_, image_); } void Button::SetItemOrder(ItemOrder item_order) { item_order_ = item_order; BuildLayout(label_, image_); } void Button::SetLayoutType(LayoutType layout_type) { layout_type_ = layout_type; BuildLayout(label_, image_); } void Button::SetSpaceBetweenItems(int space_between_items) { space_between_items_ = (space_between_items >= 0) ? space_between_items : 0; if (view_layout_) { static_cast(view_layout_)->SetSpaceBetweenChildren(space_between_items_); } ComputeContentSize(); QueueDraw(); } void Button::SetLabelFontSize(int point) { AbstractButton::SetLabelFontSize(point); if (static_text_ == NULL) return; ComputeContentSize(); QueueDraw(); } } nux-4.0.8+18.10.20180623/Nux/Button.h0000644000000000000000000002156313313373365013006 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef BUTTON_H #define BUTTON_H #include "AbstractButton.h" namespace nux { class HLayout; class VLayout; class TextureArea; class StaticText; // Deprecated // Image position with regard to the text enum Position { NUX_POSITION_LEFT, // image on left, text on the right NUX_POSITION_RIGHT, // text on the left, image on right NUX_POSITION_TOP, // image above text NUX_POSITION_BOTTOM // image below text }; //! A Button with styling(image + text) /*! The Button class has a non persistent active state. It returns to a normal state after a mouse click. For a Button is a persistent active state, use the ToggleButton class. This widget is also known as a PushButton. */ class Button: public AbstractButton { NUX_DECLARE_OBJECT_TYPE(Button, View); public: enum LayoutType { HORIZONTAL, VERTICAL, }; enum ItemOrder { IMAGE_FIRST, LABEL_FIRST, }; enum Distribution { START_OF_LAYOUT, END_OF_LAYOUT, CENTER_OF_LAYOUT, SPREAD_OVER_LAYOUT, }; Button(TextureArea *image, NUX_FILE_LINE_PROTO); Button(const std::string& button_label, NUX_FILE_LINE_PROTO); Button(const std::string& button_label, TextureArea *image, NUX_FILE_LINE_PROTO); Button(NUX_FILE_LINE_PROTO); virtual ~Button(); //! Emitted when the button is clicked. sigc::signal click; //! Emitted when the active state changes. /*! Emitted when the active state changes, as a result of a mouse click or an API call.\n \sa Activate, Deactivate. */ sigc::signal state_change; //! Set the label. /*! Set the label of this Button. If the \a label argument is an empty string, then the the Button label is destroyed, and the content of the Button is re-arranged accordingly. @param label The label of the Button. */ void SetLabel(const std::string &button_label); //!Return the label of this Button. /*! Return the label of this Button. @return The Button label string. */ std::string GetLabel() const; //! Set the image. /*! Set the image of this Button. If the \a image argument is NULL and this Button has an image, then the image is destroyed, and the content of the button is re-arranged accordingly.\n This Button make a copy of the \a image argument if it is not NULL. The source image should be destroyed after if it is no longer needed.\n The minimum and maximum size of the internal image are set to the minimum and maximum size of the \a image argument. \sa SetImageMinimumSize, SetImageMaximumSize. @param A TextureArea. */ void SetImage(TextureArea *image); //! Get the image. /*! Returns a new TextureArea with the same content as the internal TextureArea of this Button. The returned TextureArea has a floating reference.\n If the Button doesn't have an image, the function returns NULL. @return A TextureArea. */ TextureArea* GetImage(); //! Set the minimum size of the image in the Button. /*! Set the minimum size of the image in the Button.\n When setting an image into this Button with \a SetImage, the minimum size is set to the one of the \a image argument of \a SetImage. \sa SetImage. @param width Minimum width of the image. @param height Minimum height of the image. */ void SetImageMinimumSize(int width, int height); //! Set the maximum size of the image in the Button. /*! Set the maximum size of the image in the Button.\n When setting an image into this Button with \a SetImage, the maximum size is set to the one of the \a image argument of \a SetImage. \sa SetImage. @param width Maximum width of the image. @param height Maximum height of the image. */ void SetImageMaximumSize(int width, int height); //! Set the padding of the internal layout. /*! Set the padding of the internal layout.\n The default value is 2 for top, right, bottom and left padding. @param top Top padding. @param right Right padding. @param bottom Bottom padding. @param left Left padding. */ void SetLayoutPadding(int top, int right, int bottom, int left); //! Add a clipping rectangle inside the button. /*! Add an internal clipping rectangle inside the button. This will clip the rendering of anything inside the button. The default value is 2 for top, right, bottom and left clipping. @param top Top clipping. @param right Right clipping. @param bottom Bottom clipping. @param left Left clipping. */ void SetButtonClipRegion(int top_clip, int right_clip, int bottom_clip, int left_clip); //! Set the distribution of elements inside the layout. /*! Set how elements are distributed in the layout. The distribution takes effect only if the element don't use all the space available in the layout. In that case, they may be distributed toward the start, middle or end of the layout. @param distribution Distribution of elements inside the layout. */ void SetDistribution(Distribution distribution); //! Set the order of the image and label inside the layout. /*! Set the order of the image and label in the layout. Either the image comes first or the label. This is true in an horizontal or vertical layout configuration. @param item_order Order of the image and label inside the layout. */ void SetItemOrder(ItemOrder item_order); //! Set the layout type. /*! Set the layout type. With an horizontal layout type, the image and the label are arranged horizontally, while with a vertical layout type, they are arranged vertically. You may call SetItemOrder to choose if the image or the label come first in an horizontal(from left to right) or vertical(top to bottom) configuration. @param layout_type The layout type. */ void SetLayoutType(LayoutType layout_type); //! Set the space between the image and the label. /*! Set the space between the image and the label. @param space_between_items The space between the image and the label inside the layout. */ void SetSpaceBetweenItems(int space_between_items); //! Activate the button. /*! Activate the button. If this object is a Button, then it has no persistent state and the function does nothing. */ void Activate(); //! Deactivate the button. /*! Deactivate the button. If this object is a Button, then it has no persistent state and the function does nothing. */ void Deactivate(); virtual void SetLabelFontSize(int point); protected: LayoutType layout_type_; //!< The button layout type. ItemOrder item_order_; //!< Ordering of the text and image. Distribution distribution_; //!< Distribution of the image and text inside the Button layout. int space_between_items_; //!< Space between the Button image and text. bool persistent_active_state_; //!< The button's persistent state flag. int layout_left_padding_; int layout_right_padding_; int layout_top_padding_; int layout_bottom_padding_; int left_clip_; int right_clip_; int top_clip_; int bottom_clip_; bool SetLabelProperty(std::string &value, std::string const &str); void Initialize(const std::string &str, TextureArea* texture_area); void BuildLayout(const std::string &str, TextureArea* texture_area); TextureArea *image_; Size image_minimum_size_; Size image_maximum_size_; virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void RecvClick(int x, int y, unsigned long button_flags, unsigned long key_flags); // virtual void PreLayoutManagement(); // virtual long PostLayoutManagement(long LayoutResult); virtual long ComputeContentSize(); }; //typedef Button ToggleButton; } #endif // BUTTON_H nux-4.0.8+18.10.20180623/Nux/CairoWrapper.cpp0000644000000000000000000001355313313373365014464 0ustar /* * Copyright (C) 2011 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Mirco Müller namespace nux { struct CairoWrapper::Impl { Impl(CairoWrapper* parent, Geometry const& geo, DrawCanvasCallback callback); ~Impl(); bool CreateBitmap (); bool Invalidate (Geometry const& geom); void SetDrawCanvasCallback (DrawCanvasCallback callback); bool DumpToFile (std::string const& filename); bool Recreate (); void DeleteResources(); CairoWrapper* parent_; Geometry geometry_; DrawCanvasCallback draw_canvas_callback_; cairo_t* cr_; cairo_surface_t* surface_; NBitmapData* bitmap_; BaseTexture* texture_; }; CairoWrapper::Impl::Impl(CairoWrapper* parent, Geometry const& geo, DrawCanvasCallback callback) : parent_(parent) , geometry_(geo) , draw_canvas_callback_(callback) , cr_(0) , surface_(0) , bitmap_(0) , texture_(0) { } CairoWrapper::Impl::~Impl() { DeleteResources(); } void CairoWrapper::Impl::DeleteResources() { if (surface_) { cairo_surface_destroy (surface_); surface_ = 0; } if (cr_) { cairo_destroy (cr_); cr_ = 0; } if (bitmap_) { delete bitmap_; bitmap_ = 0; } if (texture_) { texture_->UnReference (); texture_ = 0; } } bool CairoWrapper::Impl::Recreate () { DeleteResources(); surface_ = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, geometry_.width, geometry_.height); if (cairo_surface_status (surface_) != CAIRO_STATUS_SUCCESS) { g_debug ("Could not create image-surface!"); return false; } cr_ = cairo_create (surface_); if (cairo_status (cr_) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (surface_); g_debug ("Could not create cairo-context!"); return false; } if (!draw_canvas_callback_) return false; draw_canvas_callback_ (geometry_, cr_); CreateBitmap (); NBitmapData* bitmap = parent_->GetBitmap (); if (texture_) texture_->UnReference (); if (GetGraphicsDisplay()->GetGraphicsEngine() == 0) return false; texture_ = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); texture_->Update (bitmap); return true; } bool CairoWrapper::Impl::CreateBitmap () { if (geometry_.width < 1 || geometry_.height < 1) { g_debug ("Width or height invalid!"); return false; } if (bitmap_) { delete bitmap_; bitmap_ = 0; } BitmapFormat bitmap_format = BITFMT_B8G8R8A8; bitmap_ = new NTextureData (bitmap_format, geometry_.width, geometry_.height, 1); unsigned char* ptr = cairo_image_surface_get_data (surface_); int stride = cairo_image_surface_get_stride (surface_); if (ptr == 0 || stride == 0) { g_debug ("Invalid surface!"); return false; } for (int j = 0; j < geometry_.height; j++) { Memcpy (bitmap_->GetSurface (0).GetPtrRawData() + j * bitmap_->GetSurface (0).GetPitch(), (const void *) (&ptr[j * stride]), geometry_.width * GPixelFormats[bitmap_format].NumComponents); } return true; } void CairoWrapper::Impl::SetDrawCanvasCallback (DrawCanvasCallback callback) { if (!callback) return; draw_canvas_callback_ = callback; Recreate (); } bool CairoWrapper::Impl::DumpToFile (std::string const& filename) { if (!surface_) Recreate(); cairo_surface_write_to_png (surface_, filename.c_str ()); return true; } bool CairoWrapper::Impl::Invalidate (Geometry const& geom) { if (geometry_.width == geom.width && geometry_.height == geom.height) return false; geometry_.x = geom.x; geometry_.y = geom.y; geometry_.width = geom.width; geometry_.height = geom.height; DeleteResources(); return true; } CairoWrapper::CairoWrapper (Geometry const& geom, DrawCanvasCallback callback) : pimpl(new Impl(this, geom, callback)) { Recreate (); } CairoWrapper::~CairoWrapper () { delete pimpl; } bool CairoWrapper::Invalidate (Geometry const& geom) { return pimpl->Invalidate(geom); } void CairoWrapper::SetDrawCanvasCallback (DrawCanvasCallback callback) { pimpl->SetDrawCanvasCallback(callback); } bool CairoWrapper::DumpToFile (std::string const& filename) { return pimpl->DumpToFile(filename); } bool CairoWrapper::Recreate () { return pimpl->Recreate(); } NBitmapData* CairoWrapper::GetBitmap () const { if (!pimpl->bitmap_) pimpl->Recreate(); return pimpl->bitmap_; } BaseTexture* CairoWrapper::GetTexture () const { if (!pimpl->texture_) pimpl->Recreate(); return pimpl->texture_; } cairo_surface_t* CairoWrapper::GetCairoSurface () const { if (!pimpl->surface_) pimpl->Recreate(); return pimpl->surface_; } cairo_t* CairoWrapper::GetCairoContext () const { if (!pimpl->cr_) pimpl->Recreate(); return pimpl->cr_; } } nux-4.0.8+18.10.20180623/Nux/CairoWrapper.h0000644000000000000000000000277313313373365014133 0ustar /* * Copyright (C) 2011 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Mirco Müller #include "Nux/Nux.h" namespace nux { typedef std::function DrawCanvasCallback; class CairoWrapper { public: CairoWrapper (Geometry const& geom, DrawCanvasCallback callback); ~CairoWrapper (); bool Invalidate (Geometry const& geom); void SetDrawCanvasCallback (DrawCanvasCallback callback); cairo_surface_t* GetCairoSurface () const; cairo_t* GetCairoContext () const; bool DumpToFile (std::string const& filename); BaseTexture* GetTexture () const; NBitmapData* GetBitmap () const; bool Recreate (); private: struct Impl; Impl* pimpl; }; } #endif // CAIRO_WRAPPER_H nux-4.0.8+18.10.20180623/Nux/Canvas.cpp0000644000000000000000000001321613313373365013275 0ustar /* * Copyright (C) 2011 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Mirco Müller UnReference (); } void Canvas::Recreate () { if (_surface) cairo_surface_destroy (_surface); if (_cr) cairo_destroy (_cr); if (_last_width < 1 || _last_height < 1) { g_debug ("Width or height of view invalid!"); return; } _surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, _last_width, _last_height); if (cairo_surface_status (_surface) != CAIRO_STATUS_SUCCESS) { g_debug ("Could not create image-surface!"); return; } _cr = cairo_create (_surface); if (cairo_status (_cr) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (_surface); g_debug ("Could not create cairo-context!"); return; } cairo_set_operator (_cr, CAIRO_OPERATOR_CLEAR); cairo_paint (_cr); _invalid = false; } NBitmapData* Canvas::GetBitmap () { if (_last_width < 1 || _last_height < 1) { g_debug ("Width or height invalid!"); return NULL; } BitmapFormat bitmap_format = BITFMT_B8G8R8A8; NTextureData* bitmap_data = new NTextureData (bitmap_format, _last_width, _last_height, 1); unsigned char* ptr = cairo_image_surface_get_data (_surface); int stride = cairo_image_surface_get_stride (_surface); if (ptr == NULL || stride == 0) { g_debug ("Invalid surface!"); delete bitmap_data; return NULL; } for (int j = 0; j < _last_height; j++) { Memcpy (bitmap_data->GetSurface (0).GetPtrRawData() + j * bitmap_data->GetSurface (0).GetPitch(), (const void *) (&ptr[j * stride]), _last_width * GPixelFormats[bitmap_format].NumComponents); } return bitmap_data; } cairo_surface_t* Canvas::GetCairoSurface () { return _surface; } cairo_t* Canvas::GetCairoContext () { return _cr; } int Canvas::GetLastWidth () { return _last_width; } int Canvas::GetLastHeight () { return _last_height; } // this is really just a stub... Canvas::Paint() being declared as virtual is // meant to be overwritten by a derived class anyway in real-world scenario // whatever needs to be drawn (and adapt to size) happens here in Paint() void Canvas::Paint () { cairo_t* cr = GetCairoContext (); if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) return; cairo_scale (cr, 1.0, 1.0); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_rectangle (cr, 0.0f, 0.0f, (double) GetLastWidth (), (double) GetLastHeight ()); cairo_set_source_rgba (cr, 1.0f, 0.0f, 0.0f, 1.0f); cairo_fill_preserve (cr); cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 1.0f); cairo_stroke (cr); //cairo_surface_write_to_png (GetCairoSurface (), "/tmp/surf-debug.png"); } void Canvas::Draw (GraphicsEngine& graphics_engine, bool /* forceDraw */) { Geometry geom = GetGeometry (); // see if the (cairo-drawn) texture needs to be updated if (_invalid || _last_width != geom.width || _last_height != geom.height) { _last_width = geom.width; _last_height = geom.height; Recreate (); Paint (); NBitmapData* bitmap = GetBitmap (); if (_texture) _texture->UnReference (); _texture = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture (); _texture->Update (bitmap); delete bitmap; } // draw the texture on screen graphics_engine.PushClippingRectangle (geom); GetWindowThread()->GetGraphicsEngine().GetRenderStates().SetBlend (false); TexCoordXForm texxform; texxform.SetWrap(TEXWRAP_CLAMP, TEXWRAP_CLAMP); texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD); graphics_engine.QRP_1Tex(geom.x, geom.y, geom.width, geom.height, _texture->GetDeviceTexture (), texxform, Color (1.0f, 1.0f, 1.0f, 1.0f)); graphics_engine.PopClippingRectangle(); } void Canvas::DrawContent(GraphicsEngine& /* graphics_engine */, bool /* forceDraw */) { } void Canvas::Invalidate() { _invalid = true; } void Canvas::PreLayoutManagement() { View::PreLayoutManagement(); } long Canvas::PostLayoutManagement(long layoutResult) { long result = View::PostLayoutManagement(layoutResult); return result; } } nux-4.0.8+18.10.20180623/Nux/Canvas.h0000644000000000000000000000327313313373365012744 0ustar /* * Copyright (C) 2011 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Mirco Müller #include "Nux/Nux.h" #include "Nux/View.h" namespace nux { class Canvas : public View { public: Canvas (NUX_FILE_LINE_DECL); ~Canvas (); protected: void Draw (GraphicsEngine& graphics_engine, bool forceDraw); void DrawContent (GraphicsEngine& graphics_engine, bool forceDraw); virtual void Paint (); void Invalidate (); cairo_surface_t* GetCairoSurface (); cairo_t* GetCairoContext (); int GetLastWidth (); int GetLastHeight (); private: void PreLayoutManagement (); long PostLayoutManagement (long layoutResult); void Recreate (); NBitmapData* GetBitmap (); private: cairo_t* _cr; cairo_surface_t* _surface; int _last_width; int _last_height; bool _invalid; BaseTexture* _texture; }; } #endif // CANVAS_H nux-4.0.8+18.10.20180623/Nux/CheckBox.cpp0000644000000000000000000000473013313373365013551 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "HLayout.h" #include "CheckBox.h" #include "StaticText.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(CheckBox); CheckBox::CheckBox(const std::string &str, bool state, NUX_FILE_LINE_DECL) : AbstractCheckedButton(str, state, NUX_FILE_LINE_PARAM) { } CheckBox::~CheckBox() { } void CheckBox::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); InteractState is; is.is_on = active_; if (visual_state_ == VISUAL_STATE_PRESSED) { is.is_focus = true; } else if (visual_state_ == VISUAL_STATE_PRELIGHT) { is.is_prelight = true; } else { is.is_focus = false; is.is_prelight = false; } GetPainter().PushPaintLayerStack(); { GetPainter().PaintCheckBox(graphics_engine, check_area_->GetGeometry(), is, Color(0xff000000)); static_text_->ProcessDraw(graphics_engine, true); } GetPainter().PopPaintLayerStack(); graphics_engine.PopClippingRectangle(); } void CheckBox::RecvClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { active_ = !active_; click.emit(this); state_change.emit(this); QueueDraw(); } void CheckBox::Activate() { if (active_ == true) { // already active return; } active_ = true; state_change.emit(this); QueueDraw(); } void CheckBox::Deactivate() { if (active_ == false) return; if (active_ == false) { // already deactivated return; } active_ = false; state_change.emit(this); QueueDraw(); } } nux-4.0.8+18.10.20180623/Nux/CheckBox.h0000644000000000000000000000500013313373365013205 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef CHECKBOX_H #define CHECKBOX_H #include "AbstractCheckedButton.h" namespace nux { class HLayout; class InputArea; class StaticText; //! CheckBox class /*! A CheckBox class.\n The CheckBox class cannot be vertically resized. It can only be resized horizontally. The vertical size is always match the size of the content (check area + label). */ class CheckBox: public AbstractCheckedButton { NUX_DECLARE_OBJECT_TYPE(CheckBox, AbstractCheckedButton); public: CheckBox(const std::string &str, bool state = false, NUX_FILE_LINE_PROTO); virtual ~CheckBox(); //! Emitted when the button is clicked. sigc::signal click; //! Emitted when the active state changes. /*! Emitted when the active state changes, as a result of a mouse click or an API call.\n \sa Activate, Deactivate. */ sigc::signal state_change; //! Activate the check box. /*! Activate the check box. */ virtual void Activate(); //! Deactivate the check box. /*! Deactivate the check box. */ virtual void Deactivate(); protected: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void RecvClick(int x, int y, unsigned long button_flags, unsigned long key_flags); private: //! Override of Area::SetMinimumHeight and made private. /*! Prevent changing the minimum height of the StaticText view. */ virtual void SetMinimumHeight(int h){}; //! Override of Area::SetMaximumHeight and made private. /*! Prevent changing the maximum height of the StaticText view. */ virtual void SetMaximumHeight(int h){}; }; } #endif // CHECKBOX_H nux-4.0.8+18.10.20180623/Nux/ClientArea.cpp0000644000000000000000000001714013313373365014071 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #if defined(NUX_OS_WINDOWS) #include "NuxGraphics/GraphicsDisplay.h" #elif defined(NUX_OS_LINUX) #include "NuxGraphics/GraphicsDisplay.h" #endif #include "NuxGraphics/GraphicsEngine.h" #include "TimerProc.h" #include "ClientArea.h" namespace nux { ClientArea::ClientArea(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { m_IsClientAreaEnabled = false; SetMinimumSize(DEFAULT_WIDGET_WIDTH, 4 * PRACTICAL_WIDGET_HEIGHT); mouse_down.connect(sigc::mem_fun(this, &ClientArea::RecvMouseDown)); mouse_up.connect(sigc::mem_fun(this, &ClientArea::RecvMouseUp)); mouse_drag.connect(sigc::mem_fun(this, &ClientArea::RecvMouseDrag)); mouse_move.connect(sigc::mem_fun(this, &ClientArea::RecvMouseMove)); key_down.connect(sigc::mem_fun(this, &ClientArea::RecvKeyEvent)); } ClientArea::~ClientArea() { } void ClientArea::BeginDraw(GraphicsEngine& graphics_engine, bool force_draw) { // if ((IsRedrawNeeded() == false) && (force_draw == false)) // return; // Save blend states unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); ObjectPtr prev_fbo_ = GetGraphicsDisplay()->GetGpuDevice()->GetCurrentFrameBufferObject(); Geometry prev_viewport_ = graphics_engine.GetViewportRect(); if (GetWindowThread()->GetGraphicsDisplay().HasFrameBufferSupport()) { int width = GetWidth(); int height = GetHeight(); m_ctx.x = GetX(); m_ctx.y = GetY(); m_ctx.width = width; m_ctx.height = height; // A is obtained from graphics_engine. So A dimension's are in relative window coordinates. Rect A = graphics_engine.GetClippingRegion(); Rect B = Rect(m_ctx.x, m_ctx.y, m_ctx.width, m_ctx.height); Rect C = A.Intersect(B); m_ctx.x_clipregion = C.x; m_ctx.y_clipregion = C.y; m_ctx.width_clipregion = C.GetWidth(); m_ctx.height_clipregion = C.GetHeight(); //ObjectPtr prevFBO = GetGraphicsDisplay()->GetGpuDevice()->GetCurrentFrameBufferObject(); if (m_FrameBufferObject.IsNull()) { // Create the fbo before using it for the first time. m_FrameBufferObject = GetGraphicsDisplay()->GetGpuDevice()->CreateFrameBufferObject(); } if (!m_MainColorRT.IsValid() || (m_MainColorRT->GetWidth() != width) || (m_MainColorRT->GetHeight() != height)) { // Create or resize the color and depth textures before using them. m_MainColorRT = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(width, height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); m_MainDepthRT = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(width, height, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); } m_FrameBufferObject->FormatFrameBufferObject(width, height, BITFMT_R8G8B8A8); m_FrameBufferObject->EmptyClippingRegion(); m_FrameBufferObject->SetTextureAttachment(0, m_MainColorRT, 0); m_FrameBufferObject->SetDepthTextureAttachment(m_MainDepthRT, 0); m_FrameBufferObject->Activate(); graphics_engine.SetViewport(0, 0, width, height); ClientDraw(graphics_engine, m_ctx, force_draw); } if (prev_fbo_.IsValid()) { // Restore the previous fbo prev_fbo_->Activate(); prev_fbo_->ApplyClippingRegion(); } // Restore the matrices and the view port. graphics_engine.ApplyModelViewMatrix(); graphics_engine.SetOrthographicProjectionMatrix(prev_viewport_.width, prev_viewport_.height); graphics_engine.SetViewport(prev_viewport_.x, prev_viewport_.y, prev_viewport_.width, prev_viewport_.height); { unsigned int w, h; w = m_MainColorRT->GetWidth(); h = m_MainColorRT->GetHeight(); int x = m_ctx.x; int y = m_ctx.y; TexCoordXForm texxform0; texxform0.uwrap = TEXWRAP_CLAMP; texxform0.vwrap = TEXWRAP_CLAMP; texxform0.FlipVCoord(true); GetGraphicsDisplay()->GetGraphicsEngine()->QRP_1Tex(x, y, w, h, m_MainColorRT, texxform0, Color(color::White)); } // restore blend states graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } void ClientArea::Draw(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { // don't draw here or we risk drawing more than one time. //BeginDraw(graphics_engine, force_draw); } void ClientArea::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { BeginDraw(graphics_engine, force_draw); } void ClientArea::ClientDraw(GraphicsEngine & /* graphics_engine */, DrawAreaContext & /* ctx */, bool /* force_draw */) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); } void ClientArea::SetClientViewport(GraphicsEngine &graphics_engine) { if (GetWindowThread()->GetGraphicsDisplay().HasFrameBufferSupport()) { graphics_engine.SetViewport(0, 0, m_FrameBufferObject->GetWidth(), m_FrameBufferObject->GetHeight()); m_FrameBufferObject->EmptyClippingRegion(); } else { int window_height = graphics_engine.GetViewportHeight(); graphics_engine.SetViewport( m_ctx.x, window_height - m_ctx.y - m_ctx.height, m_ctx.width, m_ctx.height); graphics_engine.SetOpenGLClippingRectangle( m_ctx.x_clipregion, window_height - m_ctx.y_clipregion - m_ctx.height_clipregion, m_ctx.width_clipregion, m_ctx.height_clipregion); } } void ClientArea::Setup2DMode(GraphicsEngine &graphics_engine) { //Restore 2D ViewPort graphics_engine.SetViewport(0, 0, GetBaseWidth(), GetBaseHeight()); graphics_engine.Push2DWindow(GetBaseWidth(), GetBaseHeight()); } void ClientArea::RecvMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { } void ClientArea::RecvMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { } void ClientArea::RecvMouseDrag(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { } void ClientArea::RecvMouseMove(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { } void ClientArea::RecvKeyEvent( unsigned long /* event_type */, /*event type*/ unsigned long /* GetKeySym */, /*event keysym*/ unsigned long /* event_state */, /*event state*/ const char* /* event_char */, /*character*/ unsigned short /* repeat_count */ /*key repeat count*/ ) { } bool ClientArea::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/ClientArea.h0000644000000000000000000000676013313373365013544 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef CLIENTAREA_H #define CLIENTAREA_H #include "InputArea.h" #include "Painter.h" #include "View.h" #include "TimerProc.h" namespace nux { class ClientArea; struct ClientAreaDraw { ClientArea *clientarea; Geometry clipgeometry; }; class ClientArea: public View { public: ClientArea(NUX_FILE_LINE_PROTO); ~ClientArea(); virtual void BeginDraw(GraphicsEngine &graphics_engine, bool force_draw); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); void EnableClientDraw(bool b) { m_IsClientAreaEnabled = b; }; bool IsClientDrawEnabled() const { return m_IsClientAreaEnabled; }; virtual void ClientDraw(GraphicsEngine &graphics_engine, DrawAreaContext &ctx, bool force_draw); virtual void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); virtual void RecvKeyEvent( unsigned long , /*event type*/ unsigned long , /*event keysym*/ unsigned long , /*event state*/ const char* , /*character*/ unsigned short /*key repeat count*/ ); sigc::signal sigClientDraw; void SetClientViewport(GraphicsEngine &graphics_engine); void Setup2DMode(GraphicsEngine &graphics_engine); // Before the client start drawing we set up a framebuffer object. We don't want the client to start messing // up the whole rendering by. If we setup a framebuffer instead, the client can never know the framebuffer // we use fror the whole rendering. all we have to do is to copy the client framebuffer into the main framebuffer // after the client as finished with the draw. ObjectPtr& GetWindowFrameBufferObject() { return m_FrameBufferObject; } ObjectPtr m_FrameBufferObject; protected: virtual bool AcceptKeyNavFocus(); private: // We use Rectangle texture to attach to the framebuffer because some GPU like the Geforce FX 5600 do not // have support for ARB_texture_non_power_of_two. However it does support ARB_texture_recatangle. ObjectPtr m_MainColorRT; ObjectPtr m_MainDepthRT; DrawAreaContext m_ctx; bool m_IsClientAreaEnabled; }; } #endif // CLIENTAREA_H nux-4.0.8+18.10.20180623/Nux/ColorEditor.cpp0000644000000000000000000011162713313373365014314 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/GLSh_ColorPicker.h" #include "VLayout.h" #include "HLayout.h" #include "CheckBox.h" #include "EditTextBox.h" #include "RadioButton.h" #include "RadioButtonGroup.h" #include "ToggleButton.h" #include "Layout.h" #include "ColorEditor.h" namespace nux { Size ColorEditor::picker_area_size = Size(200, 200); int ColorEditor::channel_area_width = 12; static void ThreadColorEditorDialog(NThread *thread, void *InitData) { VLayout *MainLayout(new VLayout(NUX_TRACKER_LOCATION)); ColorEditor *coloreditor(new ColorEditor()); coloreditor->ComputeContentSize(); // necessary so all element of the widget get their rightful size. ColorDialogProxy *coloreditorproxy = static_cast (InitData); if (coloreditorproxy) { coloreditor->SetRGB(coloreditorproxy->GetColor()); coloreditor->SetColorModel(coloreditorproxy->GetColorModel(), coloreditorproxy->GetColorChannel()); coloreditor->sigChange.connect(sigc::mem_fun(coloreditorproxy, &ColorDialogProxy::RecvDialogChange)); } HLayout *ButtonLayout(new HLayout("Dialog Buttons", NUX_TRACKER_LOCATION)); ToggleButton *OkButton(new ToggleButton("OK", NUX_TRACKER_LOCATION)); OkButton->SetMinimumWidth(60); OkButton->SetMinimumHeight(20); ToggleButton *CancelButton(new ToggleButton("Cancel", NUX_TRACKER_LOCATION)); CancelButton->SetMinimumWidth(60); CancelButton->SetMinimumHeight(20); //FIXME - OkButton->sigClick.connect(sigc::mem_fun(static_cast (thread), &WindowThread::TerminateThread)); //FIXME - OkButton->sigClick.connect(sigc::bind(sigc::mem_fun(coloreditorproxy, &ColorDialogProxy::RecvDialogOk), coloreditor)); //FIXME - CancelButton->sigClick.connect(sigc::bind(sigc::mem_fun(coloreditorproxy, &ColorDialogProxy::RecvDialogCancel), coloreditor)); //FIXME - CancelButton->sigClick.connect(sigc::mem_fun(static_cast (thread), &WindowThread::TerminateThread)); ButtonLayout->SetHorizontalInternalMargin(6); ButtonLayout->SetVerticalExternalMargin(2); ButtonLayout->AddView(OkButton, 0); ButtonLayout->AddView(CancelButton, 0); MainLayout->AddView(coloreditor); MainLayout->AddLayout(ButtonLayout, 0); static_cast (thread)->SetLayout(MainLayout); MainLayout->SetBaseWidth(1); MainLayout->SetBaseHeight(1); MainLayout->ComputeContentSize(); static_cast (thread)->SetWindowSize(MainLayout->GetBaseWidth(), MainLayout->GetBaseHeight()); // Call StopThreadMonitoring in case the dialog was close by clicking the window close button. //coloreditorproxy->StopThreadMonitoring(); } ColorDialogProxy::ColorDialogProxy(bool ModalWindow) { m_bDialogChange = false; m_bDialogRunning = false; m_ModalWindow = ModalWindow; m_RGBColor = Color(1.0f, 1.0f, 1.0f, 1.0f); m_ColorModel = color::RGB; color_channel_ = color::RED; } ColorDialogProxy::~ColorDialogProxy() { } void ColorDialogProxy::Start() { m_PreviousRGBColor = m_RGBColor; int Width = 290; int Height = 230; m_Thread = CreateModalWindowThread(WINDOWSTYLE_TOOL, "Color Editor", Width, Height, GetWindowThread(), ThreadColorEditorDialog, this); if (m_Thread) { //todo(jaytaoko): m_DialogThreadID = m_Thread->GetThreadId(); m_Thread->Start(0); } m_bDialogRunning = true; } bool ColorDialogProxy::IsActive() { return (m_Thread && (m_Thread->GetThreadState() != THREADSTOP) && m_bDialogRunning); } void ColorDialogProxy::RecvDialogOk(ColorEditor *coloreditor) { m_RGBColor = coloreditor->GetRGBColor(); m_PreviousRGBColor = m_RGBColor; m_bDialogChange = true; m_bDialogRunning = false; } void ColorDialogProxy::RecvDialogCancel(ColorEditor* /* coloreditor */) { m_RGBColor = m_PreviousRGBColor; m_bDialogChange = true; m_bDialogRunning = false; } void ColorDialogProxy::RecvDialogChange(ColorEditor *coloreditor) { m_RGBColor = coloreditor->GetRGBColor(); m_bDialogChange = true; } void ColorDialogProxy::StopThreadMonitoring() { m_RGBColor = m_PreviousRGBColor; m_bDialogChange = true; m_bDialogRunning = false; m_Thread = 0; m_DialogThreadID = 0; } void ColorDialogProxy::SetColor(Color color) { m_RGBColor = color; } Color ColorDialogProxy::GetColor() { return m_RGBColor; } void ColorDialogProxy::SetPreviousColor(Color color) { m_PreviousRGBColor = color; } Color ColorDialogProxy::GetPreviousColor() { return m_PreviousRGBColor; } void ColorDialogProxy::SetColorModel(color::Model color_model) { m_ColorModel = color_model; } color::Model ColorDialogProxy::GetColorModel() { return m_ColorModel; } void ColorDialogProxy::SetColorChannel(color::Channel color_channel) { color_channel_ = color_channel; } color::Channel ColorDialogProxy::GetColorChannel() { return color_channel_; } ColorEditor::ColorEditor(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , rgb_(1.0f, 1.0f, 0.0f) , hsv_(rgb_) { m_ColorModel = color::RGB; color_channel_ = color::RED; m_MarkerPosition = Point(0, 0); m_VertMarkerPosition = Point(0, 0); m_Validator.SetMinimum(0.0); m_Validator.SetMaximum(1.0); m_Validator.SetDecimals(2); picker_area_ = new BasicView(NUX_TRACKER_LOCATION); channel_area_ = new BasicView(NUX_TRACKER_LOCATION); selected_color_area_ = new BasicView(NUX_TRACKER_LOCATION); m_hlayout = new HLayout(NUX_TRACKER_LOCATION); channel_area_->mouse_down.connect(sigc::mem_fun(this, &ColorEditor::RecvMouseDown)); channel_area_->mouse_up.connect(sigc::mem_fun(this, &ColorEditor::RecvMouseUp)); channel_area_->mouse_drag.connect(sigc::mem_fun(this, &ColorEditor::RecvMouseDrag)); picker_area_->mouse_down.connect(sigc::mem_fun(this, &ColorEditor::RecvPickerMouseDown)); picker_area_->mouse_up.connect(sigc::mem_fun(this, &ColorEditor::RecvPickerMouseUp)); picker_area_->mouse_drag.connect(sigc::mem_fun(this, &ColorEditor::RecvPickerMouseDrag)); selected_color_area_->SetMinMaxSize(62, 32); picker_area_->SetMinMaxSize(picker_area_size.width, picker_area_size.height); channel_area_->SetMaximumHeight(picker_area_size.height); channel_area_->SetMinimumWidth(channel_area_width); channel_area_->SetMaximumWidth(channel_area_width); m_hlayout->AddView(picker_area_, 1); m_hlayout->AddLayout(new SpaceLayout(5, 5, 20, 20), 0); m_hlayout->AddView(channel_area_, 0, eAbove, eFull); SetCompositionLayout(m_hlayout); // RGB { redlayout = new HLayout(NUX_TRACKER_LOCATION); { //FIXME - change to radio button redcheck = new RadioButton("R"); redcheck->SetMinimumWidth(32); redtext = new EditTextBox("", NUX_TRACKER_LOCATION); redtext->SetMinimumWidth(36); redlayout->AddView(redcheck, 0); redlayout->AddView(redtext, 0); redcheck->click.connect(sigc::bind(sigc::bind(sigc::mem_fun(this, &ColorEditor::RecvCheckColorModel0), color::RED), color::RGB)); } greenlayout = new HLayout(NUX_TRACKER_LOCATION); { //FIXME - Change to radio button greencheck = new RadioButton("G"); greencheck->SetMinimumWidth(32); greentext = new EditTextBox("", NUX_TRACKER_LOCATION); greentext->SetMinimumWidth(36); greenlayout->AddView(greencheck, 0); greenlayout->AddView(greentext, 0); greencheck->click.connect(sigc::bind(sigc::bind(sigc::mem_fun(this, &ColorEditor::RecvCheckColorModel0), color::GREEN), color::RGB)); } bluelayout = new HLayout(NUX_TRACKER_LOCATION); { //FIXME - change to radio button bluecheck = new RadioButton("B"); bluecheck->SetMinimumWidth(32); bluetext = new EditTextBox("", NUX_TRACKER_LOCATION); bluetext->SetMinimumWidth(36); bluelayout->AddView(bluecheck, 0); bluelayout->AddView(bluetext, 0); bluecheck->click.connect(sigc::bind(sigc::bind(sigc::mem_fun(this, &ColorEditor::RecvCheckColorModel0), color::BLUE), color::RGB)); } } // HSV { huelayout = new HLayout(NUX_TRACKER_LOCATION); { huecheck = new RadioButton("H"); huecheck->SetMinimumWidth(32); hue_text_entry_ = new EditTextBox("", NUX_TRACKER_LOCATION); hue_text_entry_->SetMinimumWidth(36); huelayout->AddView(huecheck, 0); huelayout->AddView(hue_text_entry_, 0); huecheck->click.connect(sigc::bind(sigc::bind(sigc::mem_fun(this, &ColorEditor::RecvCheckColorModel0), color::HUE), color::HSV )); } saturationlayout = new HLayout(NUX_TRACKER_LOCATION); { saturationcheck = new RadioButton("S"); saturationcheck->SetMinimumWidth(32); saturation_text_entry_ = new EditTextBox("", NUX_TRACKER_LOCATION); saturation_text_entry_->SetMinimumWidth(36); saturationlayout->AddView(saturationcheck, 0); saturationlayout->AddView(saturation_text_entry_, 0); saturationcheck->click.connect(sigc::bind(sigc::bind(sigc::mem_fun(this, &ColorEditor::RecvCheckColorModel0), color::SATURATION), color::HSV )); } valuelayout = new HLayout(NUX_TRACKER_LOCATION); { valuecheck = new RadioButton("V"); valuecheck->SetMinimumWidth(32); value_text_entry_ = new EditTextBox("", NUX_TRACKER_LOCATION); value_text_entry_->SetMinimumWidth(36); valuelayout->AddView(valuecheck, 0); valuelayout->AddView(value_text_entry_, 0); valuecheck->click.connect(sigc::bind(sigc::bind(sigc::mem_fun(this, &ColorEditor::RecvCheckColorModel0), color::VALUE), color::HSV )); } } ctrllayout = new VLayout(NUX_TRACKER_LOCATION); ctrllayout->AddView(selected_color_area_); ctrllayout->AddView(new SpaceLayout(20, 20, 10, 10), 1); ctrllayout->AddLayout(redlayout, 0); ctrllayout->AddLayout(greenlayout, 0); ctrllayout->AddLayout(bluelayout, 0); ctrllayout->AddLayout(new SpaceLayout(10, 10, 10, 10)); ctrllayout->AddLayout(huelayout, 0); ctrllayout->AddLayout(saturationlayout, 0); ctrllayout->AddLayout(valuelayout, 0); ctrllayout->SetHorizontalExternalMargin(2); ctrllayout->SetVerticalInternalMargin(2); m_hlayout->AddLayout(ctrllayout, 0); radiogroup = new RadioButtonGroup(NUX_TRACKER_LOCATION); radiogroup->ConnectButton(redcheck); radiogroup->ConnectButton(greencheck); radiogroup->ConnectButton(bluecheck); radiogroup->ConnectButton(huecheck); radiogroup->ConnectButton(saturationcheck); radiogroup->ConnectButton(valuecheck); m_RedShader = new GLSh_ColorPicker(color::RED); m_GreenShader = new GLSh_ColorPicker(color::GREEN); m_BlueShader = new GLSh_ColorPicker(color::BLUE); m_HueShader = new GLSh_ColorPicker(color::HUE); m_SaturationShader = new GLSh_ColorPicker(color::SATURATION); m_ValueShader = new GLSh_ColorPicker(color::VALUE); redtext->SetText(m_Validator.ToString(255 * rgb_.red)); greentext->SetText(m_Validator.ToString(255 * rgb_.green)); bluetext->SetText(m_Validator.ToString(255 * rgb_.blue)); hue_text_entry_->SetText(m_Validator.ToString(360 * hsv_.hue)); saturation_text_entry_->SetText(m_Validator.ToString(100 * hsv_.saturation)); value_text_entry_->SetText(m_Validator.ToString(100 * hsv_.value)); } ColorEditor::~ColorEditor() { delete m_RedShader; delete m_GreenShader; delete m_BlueShader; delete m_HueShader; delete m_SaturationShader; delete m_ValueShader; radiogroup->UnReference(); } void ColorEditor::PreLayoutManagement() { View::PreLayoutManagement(); if (view_layout_) { // Constrain the vertical expansion of the color picker. view_layout_->SetBaseWidth(1); view_layout_->SetBaseHeight(1); } } void ColorEditor::Draw(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); base.OffsetPosition(1, 1); base.OffsetSize(-2, -2); graphics_engine.PushClippingRectangle(base); GetPainter().PushDrawShapeLayer(graphics_engine, base, eSHAPE_CORNER_ROUND4, Color(0xFF000000), eAllCorners, true); if (m_ColorModel == color::RGB) { DrawRGB(graphics_engine, force_draw); } else { DrawHSV(graphics_engine, force_draw); } GetPainter().PopBackground(); graphics_engine.PopClippingRectangle(); } void ColorEditor::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); GetPainter().PushShapeLayer(graphics_engine, base, eSHAPE_CORNER_ROUND4, Color(0xFF000000), eAllCorners, true); bool force = force_draw || IsFullRedraw(); redcheck->ProcessDraw(graphics_engine, force); redtext->ProcessDraw(graphics_engine, force); greencheck->ProcessDraw(graphics_engine, force); greentext->ProcessDraw(graphics_engine, force); bluecheck->ProcessDraw(graphics_engine, force); bluetext->ProcessDraw(graphics_engine, force); huecheck->ProcessDraw(graphics_engine, force); hue_text_entry_->ProcessDraw(graphics_engine, force); saturationcheck->ProcessDraw(graphics_engine, force); saturation_text_entry_->ProcessDraw(graphics_engine, force); valuecheck->ProcessDraw(graphics_engine, force); value_text_entry_->ProcessDraw(graphics_engine, force); GetPainter().PopBackground(); } // Draw Marker on Base Chanel Area void ColorEditor::DrawBaseChannelMarker(GraphicsEngine &graphics_engine) { int marker_position_x; int marker_position_y; graphics_engine.PushClippingRectangle(channel_area_->GetGeometry()); marker_position_x = channel_area_->GetBaseX(); marker_position_y = channel_area_->GetBaseY() + m_VertMarkerPosition.y; GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x, marker_position_y - 5, marker_position_x + 5, marker_position_y, marker_position_x, marker_position_y + 5, Color(0.0f, 0.0f, 0.0f, 1.0f)); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x, marker_position_y - 4, marker_position_x + 4, marker_position_y, marker_position_x, marker_position_y + 4, Color(0.7f, 0.7f, 0.7f, 1.0f)); marker_position_x = channel_area_->GetBaseX() + channel_area_->GetBaseWidth(); marker_position_y = channel_area_->GetBaseY() + m_VertMarkerPosition.y; GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x, marker_position_y - 5, marker_position_x - 5, marker_position_y, marker_position_x, marker_position_y + 5, Color(0.0f, 0.0f, 0.0f, 1.0f)); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x, marker_position_y - 4, marker_position_x - 4, marker_position_y, marker_position_x, marker_position_y + 4, Color(0.7f, 0.7f, 0.7f, 1.0f)); graphics_engine.PopClippingRectangle(); } void ColorEditor::DrawRGB(GraphicsEngine &graphics_engine, bool /* force_draw */) { if (m_ColorModel == color::RGB) { GetPainter().Paint2DQuadColor(graphics_engine, selected_color_area_->GetGeometry(), Color(rgb_)); Color BaseChannelTop; Color BaseChannelBottom; if (color_channel_ == color::RED) { m_RedShader->SetColor(rgb_.red, rgb_.green, rgb_.blue, 1.0f); m_RedShader->SetScreenPositionOffset(graphics_engine.GetViewportX(), graphics_engine.GetViewportY()); BaseChannelTop = Color(1.0f, rgb_.green, rgb_.blue, 1.0f); BaseChannelBottom = Color(0.0f, rgb_.green, rgb_.blue, 1.0f); m_RedShader->Render( picker_area_->GetBaseX(), picker_area_->GetBaseY(), 0, picker_area_->GetBaseWidth(), picker_area_->GetBaseHeight(), graphics_engine.GetViewportWidth(), graphics_engine.GetViewportHeight() ); } else if (color_channel_ == color::GREEN) { m_GreenShader->SetColor(rgb_.red, rgb_.green, rgb_.blue, 1.0f); m_GreenShader->SetScreenPositionOffset(graphics_engine.GetViewportX(), graphics_engine.GetViewportY()); BaseChannelTop = Color(rgb_.red, 1.0f, rgb_.blue, 1.0f); BaseChannelBottom = Color(rgb_.red, 0.0f, rgb_.blue, 1.0f); m_GreenShader->Render( picker_area_->GetBaseX(), picker_area_->GetBaseY(), 0, picker_area_->GetBaseWidth(), picker_area_->GetBaseHeight(), graphics_engine.GetViewportWidth(), graphics_engine.GetViewportHeight() ); } else if (color_channel_ == color::BLUE) { m_BlueShader->SetColor(rgb_.red, rgb_.green, rgb_.blue, 1.0f); m_BlueShader->SetScreenPositionOffset(graphics_engine.GetViewportX(), graphics_engine.GetViewportY()); BaseChannelTop = Color(rgb_.red, rgb_.green, 1.0f, 1.0f); BaseChannelBottom = Color(rgb_.red, rgb_.green, 0.0f, 1.0f); m_BlueShader->Render( picker_area_->GetBaseX(), picker_area_->GetBaseY(), 0, picker_area_->GetBaseWidth(), picker_area_->GetBaseHeight(), graphics_engine.GetViewportWidth(), graphics_engine.GetViewportHeight() ); } Geometry pickermarker = Geometry(GetBaseX() + m_MarkerPosition.x - 2, GetBaseY() + m_MarkerPosition.y - 2, 5, 5); Color color(rgb_.red, rgb_.green, rgb_.blue); float luma = color::LumaRed * rgb_.red + color::LumaGreen * rgb_.green + color::LumaBlue * rgb_.blue; Color one_minus_luma(1.0f - luma, 1.0f - luma, 1.0f - luma); GetPainter().Paint2DQuadWireframe(graphics_engine, pickermarker, one_minus_luma); GetPainter().Paint2DQuadColor(graphics_engine, channel_area_->GetGeometry(), BaseChannelTop, BaseChannelBottom, BaseChannelBottom, BaseChannelTop); // Draw Marker on Base Chanel Area DrawBaseChannelMarker(graphics_engine); } } void ColorEditor::DrawHSV(GraphicsEngine &graphics_engine, bool /* force_draw */) { if (m_ColorModel == color::HSV) { color::RedGreenBlue rgb(hsv_); GetPainter().Paint2DQuadColor(graphics_engine, selected_color_area_->GetGeometry(), Color(rgb)); Color BaseChannelTop; Color BaseChannelBottom; if (color_channel_ == color::HUE) { m_HueShader->SetColor(hsv_.hue, hsv_.saturation, hsv_.value, 1.0f); m_HueShader->SetScreenPositionOffset(graphics_engine.GetViewportX(), graphics_engine.GetViewportY()); m_HueShader->Render( picker_area_->GetBaseX(), picker_area_->GetBaseY(), 0, picker_area_->GetBaseWidth(), picker_area_->GetBaseHeight(), graphics_engine.GetViewportWidth(), graphics_engine.GetViewportHeight() ); Geometry P = channel_area_->GetGeometry(); float s = 1.0f - 1.0f; float v = 1.0f; float fw = P.GetHeight() / 6; Geometry p = Geometry(P.x, P.y, P.GetWidth(), fw); GetPainter().Paint2DQuadVGradient(graphics_engine, p, Color(1.0f * v, s * v, s * v), Color(1.0f * v, s * v, 1.0f * v)); p.SetY(P.y + fw); GetPainter().Paint2DQuadVGradient(graphics_engine, p, Color(1.0f * v, s * v, 1.0f * v), Color(s * v, s * v, 1.0f * v)); p.SetY(P.y + 2 * fw); GetPainter().Paint2DQuadVGradient(graphics_engine, p, Color(s * v, s * v, 1.0f * v), Color(s * v, 1.0f * v, 1.0f * v)); p.SetY(P.y + 3 * fw); GetPainter().Paint2DQuadVGradient(graphics_engine, p, Color(s * v, 1.0f * v, 1.0f * v), Color(s * v, 1.0f * v, s * v)); p.SetY(P.y + 4 * fw); GetPainter().Paint2DQuadVGradient(graphics_engine, p, Color(s * v, 1.0f * v, s * v), Color(1.0f * v, 1.0f * v, s * v)); p.SetY(P.y + 5 * fw); p.SetHeight(P.GetHeight() - 5 * fw); // correct rounding errors GetPainter().Paint2DQuadVGradient(graphics_engine, p, Color(1.0f * v, 1.0f * v, s * v), Color(1.0f * v, s * v, s * v)); Geometry pickermarker = Geometry(GetBaseX() + m_MarkerPosition.x - 2, GetBaseY() + m_MarkerPosition.y - 2, 5, 5); float luma = color::LumaRed * rgb_.red + color::LumaGreen * rgb_.green + color::LumaBlue * rgb_.blue; Color one_minus_luma(1.0f - luma, 1.0f - luma, 1.0f - luma); GetPainter().Paint2DQuadWireframe(graphics_engine, pickermarker, one_minus_luma); } else if (color_channel_ == color::SATURATION) { float value = hsv_.value; if (value < 0.3f) value = 0.3f; m_SaturationShader->SetColor(hsv_.hue, hsv_.saturation, hsv_.value, 1.0f); m_SaturationShader->SetScreenPositionOffset(graphics_engine.GetViewportX(), graphics_engine.GetViewportY()); BaseChannelTop = Color(color::RedGreenBlue(color::HueSaturationValue(hsv_.hue, 1.0f, value))); BaseChannelBottom = Color(value, value, value, 1.0f); m_SaturationShader->Render( picker_area_->GetBaseX(), picker_area_->GetBaseY(), 0, picker_area_->GetBaseWidth(), picker_area_->GetBaseHeight(), graphics_engine.GetViewportWidth(), graphics_engine.GetViewportHeight() ); //Geometry pickermarker = Geometry(GetX() + x - 2, GetY() + y -2, 5, 5); Geometry pickermarker = Geometry(GetBaseX() + m_MarkerPosition.x - 2, GetBaseY() + m_MarkerPosition.y - 2, 5, 5); float luma = color::LumaRed * rgb_.red + color::LumaGreen * rgb_.green + color::LumaBlue * rgb_.blue; Color one_minus_luma(1.0f - luma, 1.0f - luma, 1.0f - luma); GetPainter().Paint2DQuadWireframe(graphics_engine, pickermarker, one_minus_luma); GetPainter().Paint2DQuadColor(graphics_engine, channel_area_->GetGeometry(), BaseChannelTop, BaseChannelBottom, BaseChannelBottom, BaseChannelTop); } else if (color_channel_ == color::VALUE) { m_ValueShader->SetColor(hsv_.hue, hsv_.saturation, hsv_.value, 1.0f); m_ValueShader->SetScreenPositionOffset(graphics_engine.GetViewportX(), graphics_engine.GetViewportY()); BaseChannelTop = Color(color::RedGreenBlue(color::HueSaturationValue(hsv_.hue, hsv_.saturation, 1.0f))); BaseChannelBottom = Color(color::RedGreenBlue(color::HueSaturationValue(hsv_.hue, hsv_.saturation, 0.0f))); m_ValueShader->Render( picker_area_->GetBaseX(), picker_area_->GetBaseY(), 0, picker_area_->GetBaseWidth(), picker_area_->GetBaseHeight(), graphics_engine.GetViewportWidth(), graphics_engine.GetViewportHeight() ); //Geometry pickermarker = Geometry(GetX() + x - 2, GetY() + y -2, 5, 5); Geometry pickermarker = Geometry(GetBaseX() + m_MarkerPosition.x - 2, GetBaseY() + m_MarkerPosition.y - 2, 5, 5); float luma = color::LumaRed * rgb_.red + color::LumaGreen * rgb_.green + color::LumaBlue * rgb_.blue; Color one_minus_luma(1.0f - luma, 1.0f - luma, 1.0f - luma); GetPainter().Paint2DQuadWireframe(graphics_engine, pickermarker, one_minus_luma); GetPainter().Paint2DQuadColor(graphics_engine, channel_area_->GetGeometry(), BaseChannelTop, BaseChannelBottom, BaseChannelBottom, BaseChannelTop); } // Draw Marker on Base Chanel Area DrawBaseChannelMarker(graphics_engine); } } void ColorEditor::RecvMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { float BaseValue; if (m_ColorModel == color::RGB) { if (y < 0) BaseValue = 1.0f; else if (y > channel_area_->GetBaseHeight()) BaseValue = 0.0f; else BaseValue = 1.0f - (float) y / (float) channel_area_->GetBaseHeight(); if (color_channel_ == color::RED) rgb_.red = BaseValue; else if (color_channel_ == color::GREEN) rgb_.green = BaseValue; else if (color_channel_ == color::BLUE) rgb_.blue = BaseValue; hsv_ = color::HueSaturationValue(rgb_); } if (m_ColorModel == color::HSV) { if (y < 0) BaseValue = 1.0f; else if (y > channel_area_->GetBaseHeight()) BaseValue = 0.0f; else BaseValue = 1.0f - (float) y / (float) channel_area_->GetBaseHeight(); if (color_channel_ == color::HUE) { hsv_.hue = BaseValue; if (hsv_.hue >= 1.0f) hsv_.hue = 0.0f; } else if (color_channel_ == color::SATURATION) hsv_.saturation = BaseValue; else if (color_channel_ == color::VALUE) hsv_.value = BaseValue; rgb_ = color::RedGreenBlue(hsv_); } redtext->SetText(m_Validator.ToString(255 * rgb_.red)); greentext->SetText(m_Validator.ToString(255 * rgb_.green)); bluetext->SetText(m_Validator.ToString(255 * rgb_.blue)); hue_text_entry_->SetText(m_Validator.ToString(360 * hsv_.hue)); saturation_text_entry_->SetText(m_Validator.ToString(100 * hsv_.saturation)); value_text_entry_->SetText(m_Validator.ToString(100 * hsv_.value)); m_VertMarkerPosition = Point(Clamp (x, 0, channel_area_->GetBaseWidth() - 1), Clamp (y, 0, channel_area_->GetBaseHeight() - 1)); sigChange.emit(this); QueueDraw(); } void ColorEditor::RecvMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void ColorEditor::RecvMouseDrag(int x, int y, int /* dx */, int /* dy */, unsigned long button_flags, unsigned long key_flags) { RecvMouseDown(x, y, button_flags, key_flags); } void ColorEditor::RecvPickerMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_ColorModel == color::RGB) { if (color_channel_ == color::RED) { if (y < 0) rgb_.green = 1.0f; else if (y > picker_area_->GetBaseHeight()) rgb_.green = 0.0f; else rgb_.green = 1.0f - (float) y / (float) picker_area_->GetBaseHeight(); if (x < 0) rgb_.blue = 0.0f; else if (x > picker_area_->GetBaseWidth()) rgb_.blue = 1.0f; else rgb_.blue = (float) x / (float) picker_area_->GetBaseWidth(); } if (color_channel_ == color::GREEN) { if (y < 0) rgb_.red = 1.0f; else if (y > picker_area_->GetBaseHeight()) rgb_.red = 0.0f; else rgb_.red = 1.0f - (float) y / (float) picker_area_->GetBaseHeight(); if (x < 0) rgb_.blue = 0.0f; else if (x > picker_area_->GetBaseWidth()) rgb_.blue = 1.0f; else rgb_.blue = (float) x / (float) picker_area_->GetBaseWidth(); } if (color_channel_ == color::BLUE) { if (x < 0) rgb_.red = 0.0f; else if (x > picker_area_->GetBaseWidth()) rgb_.red = 1.0f; else rgb_.red = (float) x / (float) picker_area_->GetBaseWidth(); if (y < 0) rgb_.green = 1.0f; else if (y > picker_area_->GetBaseHeight()) rgb_.green = 0.0f; else rgb_.green = 1.0f - (float) y / (float) picker_area_->GetBaseHeight(); } hsv_ = color::HueSaturationValue(rgb_); m_MarkerPosition = Point(Clamp (x, 0, picker_area_->GetBaseWidth() - 1), Clamp (y, 0, picker_area_->GetBaseHeight() - 1)); } if (m_ColorModel == color::HSV) { if (color_channel_ == color::HUE) { if (y < 0) hsv_.value = 1.0f; else if (y > picker_area_->GetBaseHeight()) hsv_.value = 0.0f; else hsv_.value = 1.0f - (float) y / (float) picker_area_->GetBaseHeight(); if (x < 0) hsv_.saturation = 0.0f; else if (x > picker_area_->GetBaseWidth()) hsv_.saturation = 1.0f; else hsv_.saturation = (float) x / (float) picker_area_->GetBaseWidth(); } if (color_channel_ == color::SATURATION) { if (y < 0) hsv_.value = 1.0f; else if (y > picker_area_->GetBaseHeight()) hsv_.value = 0.0f; else hsv_.value = 1.0f - (float) y / (float) picker_area_->GetBaseHeight(); if (x < 0) hsv_.hue = 0.0f; else if (x >= picker_area_->GetBaseWidth()) hsv_.hue = 0.0f; else hsv_.hue = (float) x / (float) picker_area_->GetBaseWidth(); } if (color_channel_ == color::VALUE) { if (x < 0) hsv_.hue = 0.0f; else if (x >= picker_area_->GetBaseWidth()) hsv_.hue = 0.0f; else hsv_.hue = (float) x / (float) picker_area_->GetBaseWidth(); if (y < 0) hsv_.saturation = 1.0f; else if (y > picker_area_->GetBaseHeight()) hsv_.saturation = 0.0f; else hsv_.saturation = 1.0f - (float) y / (float) picker_area_->GetBaseHeight(); } rgb_ = color::RedGreenBlue(hsv_); m_MarkerPosition = Point(Clamp (x, 0, picker_area_->GetBaseWidth() - 1), Clamp (y, 0, picker_area_->GetBaseHeight() - 1)); } redtext->SetText(m_Validator.ToString(255 * rgb_.red)); greentext->SetText(m_Validator.ToString(255 * rgb_.green)); bluetext->SetText(m_Validator.ToString(255 * rgb_.blue)); hue_text_entry_->SetText(m_Validator.ToString(360 * hsv_.hue)); saturation_text_entry_->SetText(m_Validator.ToString(100 * hsv_.saturation)); value_text_entry_->SetText(m_Validator.ToString(100 * hsv_.value)); sigChange.emit(this); QueueDraw(); } void ColorEditor::RecvPickerMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void ColorEditor::RecvPickerMouseDrag(int x, int y, int /* dx */, int /* dy */, unsigned long button_flags, unsigned long key_flags) { RecvPickerMouseDown(x, y, button_flags, key_flags); } void ColorEditor::RecvCheckColorModel0(AbstractButton * /* button */, color::Model color_mode, color::Channel color_channel) { RecvCheckColorModel(true, color_mode, color_channel); } void ColorEditor::RecvCheckColorModel(bool b, color::Model color_mode, color::Channel color_channel) { if (b) { if ((color_mode == color::HSV) && (m_ColorModel == color::RGB)) { hsv_ = color::HueSaturationValue(rgb_); } if ((color_mode == color::RGB) && (m_ColorModel == color::HSV)) { rgb_ = color::RedGreenBlue(hsv_); } m_ColorModel = color_mode; color_channel_ = color_channel; } if (b && (color_mode == color::RGB)) { int x = 0; int y = 0; int z = 1; if (color_channel_ == color::RED) { z = (1.0f - rgb_.red) * picker_area_->GetBaseHeight(); y = (1.0f - rgb_.green) * picker_area_->GetBaseHeight(); x = rgb_.blue * picker_area_->GetBaseWidth(); } if (color_channel_ == color::GREEN) { z = (1.0f - rgb_.green) * picker_area_->GetBaseHeight(); y = (1.0f - rgb_.red) * picker_area_->GetBaseHeight(); x = rgb_.blue * picker_area_->GetBaseWidth(); } if (color_channel_ == color::BLUE) { z = (1.0f - rgb_.blue) * picker_area_->GetBaseHeight(); y = (1.0f - rgb_.green) * picker_area_->GetBaseHeight(); x = rgb_.red * picker_area_->GetBaseWidth(); } m_VertMarkerPosition = Point(Clamp (0, 0, channel_area_->GetBaseWidth() - 1), Clamp (z, 0, channel_area_->GetBaseHeight() - 1)); m_MarkerPosition = Point(Clamp (x, 0, picker_area_->GetBaseWidth() - 1), Clamp (y, 0, picker_area_->GetBaseHeight() - 1)); redtext->SetText(m_Validator.ToString(255 * rgb_.red)); greentext->SetText(m_Validator.ToString(255 * rgb_.green)); bluetext->SetText(m_Validator.ToString(255 * rgb_.blue)); } if (b && (color_mode == color::HSV)) { int x = 0; int y = 0; int z = 1; if (color_channel_ == color::HUE) { z = (1.0f - hsv_.hue) * picker_area_->GetBaseHeight(); y = (1.0f - hsv_.value) * picker_area_->GetBaseHeight(); x = hsv_.saturation * picker_area_->GetBaseWidth(); } if (color_channel_ == color::SATURATION) { z = (1.0f - hsv_.saturation) * picker_area_->GetBaseHeight(); y = (1.0f - hsv_.value) * picker_area_->GetBaseHeight(); x = hsv_.hue * picker_area_->GetBaseWidth(); } if (color_channel_ == color::VALUE) { z = (1.0f - hsv_.value) * picker_area_->GetBaseHeight(); y = (1.0f - hsv_.saturation) * picker_area_->GetBaseHeight(); x = hsv_.hue * picker_area_->GetBaseWidth(); } m_VertMarkerPosition = Point(Clamp (0, 0, channel_area_->GetBaseWidth() - 1), Clamp (z, 0, channel_area_->GetBaseHeight() - 1)); m_MarkerPosition = Point(Clamp (x, 0, picker_area_->GetBaseWidth() - 1), Clamp (y, 0, picker_area_->GetBaseHeight() - 1)); hue_text_entry_->SetText(m_Validator.ToString(360 * hsv_.hue)); saturation_text_entry_->SetText(m_Validator.ToString(100 * hsv_.saturation)); value_text_entry_->SetText(m_Validator.ToString(100 * hsv_.value)); } QueueDraw(); } Color ColorEditor::GetRGBColor() const { return Color(rgb_); } void ColorEditor::SetRGB(Color const& rgb) { SetRGB(rgb.red, rgb.green, rgb.blue ); } void ColorEditor::SetRGB(double r, double g, double b) { rgb_ = color::RedGreenBlue(Clamp(r, 0.0, 1.0), Clamp(g, 0.0, 1.0), Clamp(b, 0.0, 1.0)); hsv_ = color::HueSaturationValue(rgb_); RecvCheckColorModel(true, m_ColorModel, color_channel_); sigChange.emit(this); } void ColorEditor::SetHSV(double h, double s, double v) { hsv_ = color::HueSaturationValue(Clamp(h, 0.0, 1.0), Clamp(s, 0.0, 1.0), Clamp(v, 0.0, 1.0)); rgb_ = color::RedGreenBlue(hsv_); RecvCheckColorModel(true, m_ColorModel, color_channel_); sigChange.emit(this); } void ColorEditor::SetRed(double red) { SetRGB(red, rgb_.green, rgb_.blue); } void ColorEditor::SetGreen(double green) { SetRGB(rgb_.red, green, rgb_.blue); } void ColorEditor::SetBlue(double blue) { SetRGB(rgb_.red, rgb_.green, blue); } void ColorEditor::SetHue(double hue) { SetHSV(hue, hsv_.saturation, hsv_.value); } void ColorEditor::SetSaturation(double saturation) { SetHSV(hsv_.hue, saturation, hsv_.value); } void ColorEditor::SetValue(double value) { SetHSV(hsv_.hue, hsv_.saturation, value); } void ColorEditor::SetColorModel(color::Model colormodel, color::Channel colorchannel) { if (colormodel == color::HSV) { if ((colorchannel != color::HUE) && (colorchannel != color::SATURATION) && (colorchannel != color::VALUE)) { nuxDebugMsg("[ColorEditor::SetColorModel] The color model(HSV) and the color channel don't match."); return; } } if (colormodel == color::RGB) { if ((colorchannel != color::RED) && (colorchannel != color::GREEN) && (colorchannel != color::BLUE)) { nuxDebugMsg("[ColorEditor::SetColorModel] The color model(RGB) and the color channel don't match."); return; } } m_ColorModel = colormodel; color_channel_ = colorchannel; RecvCheckColorModel(true, m_ColorModel, color_channel_); /*FIXME - disabled because we lost radiogroup if (color_channel_ == color::RED) radiogroup->ActivateButton(redcheck); else if (color_channel_ == color::GREEN) radiogroup->ActivateButton(greencheck); else if (color_channel_ == color::BLUE) radiogroup->ActivateButton(bluecheck); else if (color_channel_ == color::HUE) radiogroup->ActivateButton(huecheck); else if (color_channel_ == color::SATURATION) radiogroup->ActivateButton(saturationcheck); else if (color_channel_ == color::VALUE) radiogroup->ActivateButton(valuecheck); */ } color::Model ColorEditor::GetColorModel() const { return m_ColorModel; } color::Channel ColorEditor::GetColorChannel() const { return color_channel_; } bool ColorEditor::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/ColorEditor.h0000644000000000000000000001373713313373365013764 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef COLOREDITOR_H #define COLOREDITOR_H #include "NuxGraphics/GpuDevice.h" #include "NuxGraphics/GLDeviceObjects.h" #include "NuxGraphics/GLSh_DrawFunction.h" #include "DoubleValidator.h" #include "TimerProc.h" namespace nux { class GLSh_ColorPicker; class HLayout; class VLayout; class EditTextBox; class CheckBox; class AbstractButton; class RadioButton; class RadioButtonGroup; class Button; class ColorEditor; class ColorPreview; class ColorDialogProxy { public: ColorDialogProxy(bool ModalWindow); ~ColorDialogProxy(); void RecvDialogOk(ColorEditor *coloreditor); void RecvDialogCancel(ColorEditor *coloreditor); void RecvDialogChange(ColorEditor *coloreditor); void Start(); bool IsActive(); void StopThreadMonitoring(); void SetColor(Color color); Color GetColor(); void SetPreviousColor(Color color); Color GetPreviousColor(); void SetColorModel(color::Model color_model); color::Model GetColorModel(); void SetColorChannel(color::Channel color_model); color::Channel GetColorChannel(); private: bool m_bDialogChange; bool m_bDialogRunning; unsigned int m_DialogThreadID; Color m_RGBColor; Color m_PreviousRGBColor; color::Model m_ColorModel; color::Channel color_channel_; bool m_ModalWindow; NThread *m_Thread; friend class ColorPreview; }; class ColorEditor : public View { public: ColorEditor(NUX_FILE_LINE_PROTO); ~ColorEditor(); void SetRed(double r); void SetGreen(double g); void SetBlue(double b); void SetHue(double h); void SetSaturation(double s); void SetValue(double v); void SetRGB(double r, double g, double b); void SetHSV(double h, double s, double v); void SetRGB(Color const& rgb); Color GetRGBColor() const; void SetColorModel(color::Model, color::Channel); color::Model GetColorModel() const; color::Channel GetColorChannel() const; void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void RecvPickerMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvPickerMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvPickerMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void RecvCheckColorModel(bool, color::Model, color::Channel); void RecvCheckColorModel0(AbstractButton *button, color::Model color_mode, color::Channel channel); sigc::signal< void, ColorEditor * > sigChange; protected: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual void PreLayoutManagement(); virtual bool AcceptKeyNavFocus(); private: //! Override of Area::SetMinimumHeight and made private. /*! Prevent changing the minimum height of the ColorEditor view. */ virtual void SetMinimumHeight(int h){}; //! Override of Area::SetMaximumHeight and made private. /*! Prevent changing the maximum height of the ColorEditor view. */ virtual void SetMaximumHeight(int h){}; //! Override of Area::SetMinimumWidth and made private. /*! Prevent changing the minimum width of the ColorEditor view. */ virtual void SetMinimumWidth(int w){}; //! Override of Area::SetMaximumWidth and made private. /*! Prevent changing the maximum width of the ColorEditor view. */ virtual void SetMaximumWidth(int w){}; void DrawBaseChannelMarker(GraphicsEngine &graphics_engine); void DrawRGB(GraphicsEngine &graphics_engine, bool force_draw); void DrawHSV(GraphicsEngine &graphics_engine, bool force_draw); color::Channel color_channel_; color::Model m_ColorModel; InputArea *picker_area_; InputArea *channel_area_; InputArea *selected_color_area_; HLayout *m_hlayout; VLayout *ctrllayout; GLSh_ColorPicker *m_RedShader; GLSh_ColorPicker *m_GreenShader; GLSh_ColorPicker *m_BlueShader; GLSh_ColorPicker *m_HueShader; GLSh_ColorPicker *m_SaturationShader; GLSh_ColorPicker *m_ValueShader; Point m_MarkerPosition; Point m_VertMarkerPosition; color::RedGreenBlue rgb_; color::HueSaturationValue hsv_; HLayout *redlayout; HLayout *greenlayout; HLayout *bluelayout; RadioButton *redcheck; EditTextBox *redtext; RadioButton *greencheck; EditTextBox *greentext; RadioButton *bluecheck; EditTextBox *bluetext; HLayout *huelayout; HLayout *saturationlayout; HLayout *valuelayout; RadioButton *huecheck; EditTextBox *hue_text_entry_; RadioButton *saturationcheck; EditTextBox *saturation_text_entry_; RadioButton *valuecheck; EditTextBox *value_text_entry_; RadioButtonGroup *radiogroup; DoubleValidator m_Validator; static Size picker_area_size; static int channel_area_width; }; } #endif // COLOREDITOR_H nux-4.0.8+18.10.20180623/Nux/ColorPickerDialog.cpp0000644000000000000000000000335513313373365015421 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Button.h" #include "ColorPickerDialog.h" namespace nux { static Color DummyColor; ColorPickerDialog::ColorPickerDialog() : m_Color(DummyColor) { SetWindowTitle("Color Picker"); SetWindowSizeMatchLayout(true); m_Vlayout = new VLayout("Color Picker"); m_ColorEditor = new ColorEditor(); m_Vlayout->AddView(m_ColorEditor); m_Vlayout->AddLayout(m_ButtonLayout); m_Vlayout->SetScaleFactor(0); // Set layout for the window SetLayout(m_Vlayout); } ColorPickerDialog::~ColorPickerDialog() { } void ColorPickerDialog::StartDialog(Color &color, color::Model /* ColorModel */, bool StartModal) { Dialog::Start(StartModal); m_Color = color; } void ColorPickerDialog::RecvOk() { m_Color = m_ColorEditor->GetRGBColor(); m_Color = color::Black; ShowWindow(FALSE); } void ColorPickerDialog::RecvCancel() { m_Color = DummyColor; ShowWindow(FALSE); } } nux-4.0.8+18.10.20180623/Nux/ColorPickerDialog.h0000644000000000000000000000251413313373365015062 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef COLORPICKERDIALOG_H #define COLORPICKERDIALOG_H #include "Dialog.h" #include "ColorEditor.h" namespace nux { class HLayout; class VLayout; class ColorPickerDialog : public Dialog { public: ColorPickerDialog(); ~ColorPickerDialog(); virtual void RecvOk(); virtual void RecvCancel(); void StartDialog(Color &color, color::Model ColorModel = color::RGB, bool StartModal = false); private: VLayout *m_Vlayout; ColorEditor *m_ColorEditor; Color &m_Color; }; } #endif // COLORPICKERDIALOG_H nux-4.0.8+18.10.20180623/Nux/ColorPreview.cpp0000644000000000000000000001014513313373365014500 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "ColorPreview.h" #include "ColorEditor.h" #include "HLayout.h" #include "TimerProc.h" #include "StaticTextBox.h" #include #include namespace nux { ColorPreview::ColorPreview(Color const& c, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_Color(c) { //setSize(200, 100); m_hlayout = new HLayout(NUX_TRACKER_LOCATION); m_ColorArea = new BasicView(NUX_TRACKER_LOCATION); m_ColorValue = new StaticTextBox("", NUX_TRACKER_LOCATION); m_DialogThreadProxy = new ColorDialogProxy(true); SetMaximumHeight(18); m_ColorArea->SetMaximumHeight(18); m_ColorArea->SetMinimumWidth(32); m_ColorArea->SetMaximumWidth(32); m_ColorValue->SetTextColor(Color(0xFFFFFFFF)); m_ColorValue->SetFont(GetSysBoldFont()); m_ColorValue->SetMinimumWidth(128); std::stringstream s; s << "[ R:" << (int)(m_Color.red * 255) << ", G:" << (int)(m_Color.green * 255) << ", B:" << (int)(m_Color.blue * 255) << " ]"; m_ColorValue->SetText(s.str()); m_ColorArea->mouse_click.connect(sigc::mem_fun(this, &ColorPreview::RecvClick)); m_hlayout->AddView(m_ColorArea, 0); m_hlayout->AddView(m_ColorValue, 1); m_hlayout->SetHorizontalInternalMargin(4); SetCompositionLayout(m_hlayout); m_ChangeDetectionTimer = new TimerFunctor(); m_ChangeDetectionTimer->tick.connect(sigc::mem_fun(this, &ColorPreview::RecvTimer)); m_ChangeTimerHandler = 0; } ColorPreview::~ColorPreview() { delete m_ChangeDetectionTimer; if (m_ChangeTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_ChangeTimerHandler); delete m_DialogThreadProxy; } void ColorPreview::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); GetPainter().PaintBackground(graphics_engine, base); GetPainter().PaintShape(graphics_engine, m_ColorArea->GetGeometry(), m_Color, eSHAPE_CORNER_ROUND4, false); //GetPainter().Paint2DQuadWireFrameColor(graphics_engine, base, Color(COLOR_BACKGROUND_SECONDARY)); m_ColorValue->QueueDraw(); } void ColorPreview::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { m_ColorValue->ProcessDraw(graphics_engine, force_draw); } void ColorPreview::RecvClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { m_DialogThreadProxy->SetColor(m_Color); m_DialogThreadProxy->Start(); m_ChangeTimerHandler = GetTimer().AddOneShotTimer(33, m_ChangeDetectionTimer, this); } void ColorPreview::RecvTimer(void * /* v */) { if (m_DialogThreadProxy->m_bDialogChange && m_DialogThreadProxy->m_bDialogRunning) { m_DialogThreadProxy->m_bDialogChange = false; m_Color = m_DialogThreadProxy->GetColor(); QueueDraw(); } if (m_DialogThreadProxy->IsActive()) { m_ChangeTimerHandler = GetTimer().AddOneShotTimer(33, m_ChangeDetectionTimer, this); } else { if (m_ChangeTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_ChangeTimerHandler); m_ChangeTimerHandler = 0; m_Color = m_DialogThreadProxy->GetColor(); QueueDraw(); } } Color const& ColorPreview::GetRGBColor() const { return m_Color; } void ColorPreview::SetColor(Color const& color) { m_Color = color; } } nux-4.0.8+18.10.20180623/Nux/ColorPreview.h0000644000000000000000000000367713313373365014161 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef COLORPREVIEW_H #define COLORPREVIEW_H #include "NuxCore/Color.h" #include "NuxGraphics/GpuDevice.h" #include "NuxGraphics/GLDeviceObjects.h" #include "TimerProc.h" namespace nux { class HLayout; class StaticTextBox; class ColorEditor; class TimerHandle; class ColorDialogProxy; class ColorPreview : public View { public: ColorPreview(Color const& c = nux::color::Transparent, NUX_FILE_LINE_PROTO); ~ColorPreview(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); sigc::signal< void, ColorEditor * > sigColorChanged; void SetColor(Color const& rgb); Color const& GetRGBColor() const; private: void RecvTimer(void *v); void RecvClick(int x, int y, unsigned long button_flags, unsigned long key_flags); TimerFunctor *m_ChangeDetectionTimer; TimerHandle m_ChangeTimerHandler; Color m_Color; HLayout *m_hlayout; InputArea *m_ColorArea; StaticTextBox *m_ColorValue; ColorDialogProxy *m_DialogThreadProxy; }; } #endif // COLORPREVIEW_H nux-4.0.8+18.10.20180623/Nux/ComboBoxSimple.cpp0000644000000000000000000002272113313373365014745 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "ComboBoxSimple.h" #include "MenuPage.h" #include "ActionItem.h" #include "StaticText.h" namespace nux { ComboBoxSimple::ComboBoxSimple(NUX_FILE_LINE_DECL) : AbstractComboBox(NUX_FILE_LINE_PARAM) { m_SelectedAction = 0; m_CurrentMenu = 0; m_CurrentMenu = new MenuPage("", NUX_TRACKER_LOCATION); m_CurrentMenu->SinkReference(); m_CurrentMenu->SetParentObject(this); // Set Signals _combo_box_opening_area->mouse_down.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvMouseDown)); _combo_box_opening_area->mouse_up.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvMouseUp)); _combo_box_area->mouse_down.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvMouseDown)); _combo_box_area->mouse_up.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvMouseUp)); //m_Popup.sigPopupStop.connect(sigc::mem_fun(this, &ComboBox::OnPopupStop)); // Set Geometry _combo_box_opening_area->SetGeometry(Geometry(0, 0, 20, DEFAULT_WIDGET_HEIGHT)); //_combo_box_opening_area->SetMaximumSize(20, DEFAULT_WIDGET_HEIGHT); _combo_box_opening_area->SetMinimumSize(20, DEFAULT_WIDGET_HEIGHT); _combo_box_area->SetMinimumSize(2 * DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); _combo_box_area->SetGeometry(Geometry(0, 0, 3 * DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT)); //_pango_static_text->SetClipping(_combo_box_area->GetBaseWidth()); _combo_box_area->geometry_changed.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvGeometryChanged)); //m_CurrentMenu = new MenuPage; m_CurrentMenu->SetParentMenu(0); m_CurrentMenu->sigActionTriggered.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvSigActionTriggered)); m_CurrentMenu->sigTerminateMenuCascade.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvSigTerminateMenuCascade)); m_CurrentMenu->sigClosingMenu.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvClosingMenuSignal)); } ComboBoxSimple::~ComboBoxSimple() { m_CurrentMenu->UnParentObject(); m_CurrentMenu->UnReference(); } Area* ComboBoxSimple::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; NUX_RETURN_VALUE_IF_TRUE(_combo_box_opening_area->TestMousePointerInclusion(mouse_position, event_type), _combo_box_opening_area); NUX_RETURN_VALUE_IF_TRUE(_combo_box_area->TestMousePointerInclusion(mouse_position, event_type), _combo_box_area); if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } void ComboBoxSimple::MoveSelectionUp() { int current_index = GetSelectionIndex(); SetSelectionIndex(current_index - 1); } void ComboBoxSimple::MoveSelectionDown() { int current_index = GetSelectionIndex(); SetSelectionIndex(current_index + 1); } ActionItem *ComboBoxSimple::AddItem(const char *label, int Uservalue) { if (m_CurrentMenu->GetNumItem() == 0) { // The first element added is the element featured on the combo box when it is closed. m_SelectedAction = m_CurrentMenu->AddAction(label, Uservalue); _combo_box_area->SetBaseString(m_SelectedAction->GetLabel()); _pango_static_text->SetText(m_SelectedAction->GetLabel()); return m_SelectedAction; } else { return m_CurrentMenu->AddAction(label, Uservalue); } } void ComboBoxSimple::RemoveItem(ActionItem *item) { } void ComboBoxSimple::RemoveAllItem() { m_CurrentMenu->RemoveAllItem(); } void ComboBoxSimple::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags) { if (m_MenuIsActive == false) { // Open the MenuPage m_MenuIsActive = true; m_IsOpeningMenu = true; Geometry geo = m_CurrentMenu->GetGeometry(); geo.SetX(_combo_box_area->GetAbsoluteX()); geo.SetY(_combo_box_area->GetAbsoluteY() + _combo_box_area->GetBaseHeight()); geo.SetWidth(_combo_box_area->GetBaseWidth()); //m_CurrentMenu->SetMinimumWidth(geo.width); //m_CurrentMenu->SetMaximumWidth(geo.width); m_CurrentMenu->SetGeometry(geo); m_CurrentMenu->ComputeContentSize(); m_CurrentMenu->StartMenu(_combo_box_area->GetAbsoluteX(), _combo_box_area->GetAbsoluteY() + _combo_box_area->GetBaseHeight(), 0, 0); } else { // If the mouse up that follows happen inside the area, then it is going to close the menu. m_IsOpeningMenu = false; } QueueDraw(); } void ComboBoxSimple::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags) { if (m_MenuIsActive) { if (_combo_box_area->IsMouseInside() || _combo_box_opening_area->IsMouseInside()) { if (m_IsOpeningMenu == false) { // close the MenuPage that is Open m_CurrentMenu->StopMenu(0, 0); m_MenuIsActive = false; } else { // The MousePress before this MouseRelease, caused the MenuPage to open. // Set m_IsOpeningMenu so the next mouse release will close the menu. m_IsOpeningMenu = false; m_MenuIsActive = true; } } else { bool hit_inside_a_menu = false; bool b = m_CurrentMenu->TestMouseUp(x, y, button_flags, key_flags, hit_inside_a_menu); if (b || (hit_inside_a_menu == false)) { RecvSigTerminateMenuCascade(); m_MenuIsActive = false; } } } QueueDraw(); } void ComboBoxSimple::RecvSigActionTriggered(MenuPage *menu, ActionItem *action) { m_MenuIsActive = false; m_CurrentMenu->StopMenu(); m_SelectedAction = action; _combo_box_area->SetBaseString(m_SelectedAction->GetLabel()); m_IsOpeningMenu = false; _pango_static_text->SetText(m_SelectedAction->GetLabel()); sigTriggered.emit(this); sigActionTriggered.emit(m_SelectedAction); QueueDraw(); // You can do something if you want with the menu* and the action* } void ComboBoxSimple::RecvSigActionTriggered2(TableCtrl *table, TableItem *item, unsigned int row, unsigned int column) { m_MenuIsActive = false; m_CurrentMenu->StopMenu(); m_IsOpeningMenu = false; QueueDraw(); // You can do something if you want with the menu* and the action* } void ComboBoxSimple::RecvSigTerminateMenuCascade() { //m_MenuIsActive = false; m_CurrentMenu->StopMenu(); m_IsOpeningMenu = false; } void ComboBoxSimple::RecvClosingMenuSignal(MenuPage* menu_page) { nuxAssert(menu_page == m_CurrentMenu); m_IsOpeningMenu = false; m_MenuIsActive = false; // When the menu is closing check if the mouse is still inside the combo box surface // and set the _current_mouse_in flag accordingly. if (!_combo_box_area->TestMousePointerInclusion(GetWindowThread()->GetWindowCompositor().GetMousePosition(), NUX_NO_EVENT)) { _combo_box_area->mouse_in_ = false; } if (!_combo_box_opening_area->TestMousePointerInclusion(GetWindowThread()->GetWindowCompositor().GetMousePosition(), NUX_NO_EVENT)) { _combo_box_opening_area->mouse_in_ = false; } QueueDraw(); } void ComboBoxSimple::RecvGeometryChanged(Area *area, Geometry &geo) { //_pango_static_text->SetClipping(geo.width); } const char *ComboBoxSimple::GetSelectionLabel() const { if (m_SelectedAction) return m_SelectedAction->GetLabel(); return 0; } int ComboBoxSimple::GetSelectionUserValue() const { if (m_SelectedAction) return m_SelectedAction->GetUserValue(); return 0; } int ComboBoxSimple::GetNumItem() const { return m_CurrentMenu->GetNumItem(); } ActionItem *ComboBoxSimple::GetItem(int index) const { return m_CurrentMenu->GetActionItem(index); } int ComboBoxSimple::GetSelectionIndex() const { if (m_SelectedAction) return m_CurrentMenu->GetActionItemIndex(m_SelectedAction); return -1; } void ComboBoxSimple::SetSelectionIndex(int index) { if ((index >= 0) && (index < m_CurrentMenu->GetNumItem())) { m_SelectedAction = m_CurrentMenu->GetActionItem(index); _combo_box_area->SetBaseString(m_SelectedAction->GetLabel()); _pango_static_text->SetText(m_SelectedAction->GetLabel()); QueueDraw(); } else if (m_CurrentMenu->GetNumItem() > 0) { // index is negative m_SelectedAction = m_CurrentMenu->GetActionItem(0); _combo_box_area->SetBaseString(m_SelectedAction->GetLabel()); _pango_static_text->SetText(m_SelectedAction->GetLabel()); QueueDraw(); } else { m_SelectedAction = 0; } } } nux-4.0.8+18.10.20180623/Nux/ComboBoxSimple.h0000644000000000000000000000560513313373365014414 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef COMBOBOX_LOGIC_H #define COMBOBOX_LOGIC_H #include "AbstractComboBox.h" #include "ActionItem.h" namespace nux { class MenuPage; class ActionItem; class TableItem; class TableCtrl; class ComboBoxSimple : public AbstractComboBox { public: ComboBoxSimple(NUX_FILE_LINE_PROTO); ~ComboBoxSimple(); // make the class abstract // virtual void Draw(GraphicsEngine& graphics_engine, bool force_draw); // virtual void DrawContent(GraphicsEngine& graphics_engine, bool force_draw); public: ActionItem *AddItem(const char *label, int Uservalue = 0); void RemoveItem(ActionItem *item); void RemoveAllItem(); // emitters void OnMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnPopupStop(); // signals void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvSigActionTriggered(MenuPage *, ActionItem *); void RecvSigActionTriggered2(TableCtrl *table, TableItem *item, unsigned int row, unsigned int column); void RecvSigTerminateMenuCascade(); void RecvGeometryChanged(Area *area, Geometry &geo); const char *GetSelectionLabel() const; int GetSelectionUserValue() const; int GetNumItem() const; ActionItem *GetItem(int index) const; int GetSelectionIndex() const; void SetSelectionIndex(int index); // moves the currently selected item up/down - just shorthand for SetSelectionIndex void MoveSelectionUp(); void MoveSelectionDown(); MenuPage * GetMenuPage() { return m_CurrentMenu; } sigc::signal sigTriggered; sigc::signal sigActionTriggered; protected: virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); void RecvClosingMenuSignal(MenuPage* menu_page); MenuPage *m_CurrentMenu; ActionItem *m_SelectedAction; }; } #endif // COMBOBOX_LOGIC_H nux-4.0.8+18.10.20180623/Nux/D2DTextRenderer.cpp0000644000000000000000000003316113313373365014770 0ustar #include "D2DTextRenderer.h" // SafeRelease inline function. template inline void SafeRelease(T **ppT) { if (*ppT) { (*ppT)->Release(); *ppT = NULL; } } /****************************************************************** * * * CustomTextRenderer::CustomTextRenderer * * * * The constructor stores the Direct2D factory, the render * * target, and the outline and fill brushes used for drawing the * * glyphs, underlines, and strikethroughs. * * * ******************************************************************/ CustomTextRenderer::CustomTextRenderer( ID2D1Factory* pD2DFactory, ID2D1RenderTarget* pRT, ID2D1SolidColorBrush* pOutlineBrush, ID2D1BitmapBrush* pFillBrush ) : cRefCount_(0), pD2DFactory_(pD2DFactory), pRT_(pRT), pOutlineBrush_(pOutlineBrush), pFillBrush_(pFillBrush) { if (pD2DFactory_) pD2DFactory_->AddRef(); if (pRT_) pRT_->AddRef(); if (pOutlineBrush_) pOutlineBrush_->AddRef(); if (pFillBrush_) pFillBrush_->AddRef(); } /****************************************************************** * * * CustomTextRenderer::~CustomTextRenderer * * * * The destructor releases the member variables * * * ******************************************************************/ CustomTextRenderer::~CustomTextRenderer() { SafeRelease(&pD2DFactory_); SafeRelease(&pRT_); SafeRelease(&pOutlineBrush_); SafeRelease(&pFillBrush_); } /****************************************************************** * * * CustomTextRenderer::DrawGlyphRun * * * * Gets GlyphRun outlines via IDWriteFontFace::GetGlyphRunOutline * * and then draws and fills them using Direct2D path geometries * * * ******************************************************************/ IFACEMETHODIMP CustomTextRenderer::DrawGlyphRun( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, __in DWRITE_GLYPH_RUN const* glyphRun, __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, IUnknown* clientDrawingEffect ) { HRESULT hr = S_OK; // Create the path geometry. ID2D1PathGeometry* pPathGeometry = NULL; hr = pD2DFactory_->CreatePathGeometry(&pPathGeometry); // Write to the path geometry using the geometry sink. ID2D1GeometrySink* pSink = NULL; if (SUCCEEDED(hr)) { hr = pPathGeometry->Open(&pSink); } // Get the glyph run outline geometries back from DirectWrite and place them within the // geometry sink. if (SUCCEEDED(hr)) { hr = glyphRun->fontFace->GetGlyphRunOutline( glyphRun->fontEmSize, glyphRun->glyphIndices, glyphRun->glyphAdvances, glyphRun->glyphOffsets, glyphRun->glyphCount, glyphRun->isSideways, glyphRun->bidiLevel%2, pSink ); } // Close the geometry sink if (SUCCEEDED(hr)) { hr = pSink->Close(); } // Initialize a matrix to translate the origin of the glyph run. D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY); // Create the transformed geometry ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pPathGeometry, &matrix, &pTransformedGeometry); } // Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pOutlineBrush_); SafeRelease(&pPathGeometry); SafeRelease(&pSink); SafeRelease(&pTransformedGeometry); return hr; } /****************************************************************** * * * CustomTextRenderer::DrawUnderline * * * * Draws underlines below the text using a Direct2D rectangle * * geometry * * * ******************************************************************/ IFACEMETHODIMP CustomTextRenderer::DrawUnderline( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, __in DWRITE_UNDERLINE const* underline, IUnknown* clientDrawingEffect ) { HRESULT hr; D2D1_RECT_F rect = D2D1::RectF( 0, underline->offset, underline->width, underline->offset + underline->thickness ); ID2D1RectangleGeometry* pRectangleGeometry = NULL; hr = pD2DFactory_->CreateRectangleGeometry( &rect, &pRectangleGeometry ); // Initialize a matrix to translate the origin of the underline D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY ); ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pRectangleGeometry, &matrix, &pTransformedGeometry ); } // Draw the outline of the rectangle pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the rectangle pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ ); SafeRelease(&pRectangleGeometry); SafeRelease(&pTransformedGeometry); return S_OK; } /****************************************************************** * * * CustomTextRenderer::DrawStrikethrough * * * * Draws strike-through below the text using a Direct2D * * rectangle geometry * * * ******************************************************************/ IFACEMETHODIMP CustomTextRenderer::DrawStrikethrough( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, __in DWRITE_STRIKETHROUGH const* strikethrough, IUnknown* clientDrawingEffect ) { HRESULT hr; D2D1_RECT_F rect = D2D1::RectF( 0, strikethrough->offset, strikethrough->width, strikethrough->offset + strikethrough->thickness ); ID2D1RectangleGeometry* pRectangleGeometry = NULL; hr = pD2DFactory_->CreateRectangleGeometry( &rect, &pRectangleGeometry ); // Initialize a matrix to translate the origin of the strikethrough D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F( 1.0f, 0.0f, 0.0f, 1.0f, baselineOriginX, baselineOriginY ); ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pRectangleGeometry, &matrix, &pTransformedGeometry ); } // Draw the outline of the rectangle pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // // Fill in the rectangle // pRT_->FillGeometry( // pTransformedGeometry, // pOutlineBrush_ // ); SafeRelease(&pRectangleGeometry); SafeRelease(&pTransformedGeometry); return S_OK; } /****************************************************************** * * * CustomTextRenderer::DrawInlineObject * * * * This function is not implemented for the purposes of this * * sample. * * * ******************************************************************/ IFACEMETHODIMP CustomTextRenderer::DrawInlineObject( __maybenull void* clientDrawingContext, FLOAT originX, FLOAT originY, IDWriteInlineObject* inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown* clientDrawingEffect ) { // Not implemented return E_NOTIMPL; } /****************************************************************** * * * CustomTextRenderer::AddRef * * * * Increments the ref count * * * ******************************************************************/ IFACEMETHODIMP_(unsigned long) CustomTextRenderer::AddRef() { return InterlockedIncrement((LONG *)&cRefCount_); } /****************************************************************** * * * CustomTextRenderer::Release * * * * Decrements the ref count and deletes the instance if the ref * * count becomes 0 * * * ******************************************************************/ IFACEMETHODIMP_(unsigned long) CustomTextRenderer::Release() { unsigned long newCount = InterlockedDecrement((LONG *)&cRefCount_); if (newCount == 0) { delete this; return 0; } return newCount; } /****************************************************************** * * * CustomTextRenderer::IsPixelSnappingDisabled * * * * Determines whether pixel snapping is disabled. The recommended * * default is FALSE, unless doing animation that requires * * subpixel vertical placement. * * * ******************************************************************/ IFACEMETHODIMP CustomTextRenderer::IsPixelSnappingDisabled( __maybenull void* clientDrawingContext, __out BOOL* isDisabled ) { *isDisabled = FALSE; return S_OK; } /****************************************************************** * * * CustomTextRenderer::GetCurrentTransform * * * * Returns the current transform applied to the render target.. * * * ******************************************************************/ IFACEMETHODIMP CustomTextRenderer::GetCurrentTransform( __maybenull void* clientDrawingContext, __out DWRITE_MATRIX* transform ) { //forward the render target's transform pRT_->GetTransform(reinterpret_cast(transform)); return S_OK; } /****************************************************************** * * * CustomTextRenderer::GetPixelsPerDip * * * * This returns the number of pixels per DIP. * * * ******************************************************************/ IFACEMETHODIMP CustomTextRenderer::GetPixelsPerDip( __maybenull void* clientDrawingContext, __out FLOAT* pixelsPerDip ) { float x, yUnused; pRT_->GetDpi(&x, &yUnused); *pixelsPerDip = x / 96; return S_OK; } /****************************************************************** * * * CustomTextRenderer::QueryInterface * * * * Query interface implementation * * * ******************************************************************/ IFACEMETHODIMP CustomTextRenderer::QueryInterface( IID const& riid, void** ppvObject ) { if (__uuidof(IDWriteTextRenderer) == riid) { *ppvObject = this; } else if (__uuidof(IDWritePixelSnapping) == riid) { *ppvObject = this; } else if (__uuidof(IUnknown) == riid) { *ppvObject = this; } else { *ppvObject = NULL; return E_FAIL; } this->AddRef(); return S_OK; } nux-4.0.8+18.10.20180623/Nux/D2DTextRenderer.h0000644000000000000000000000612113313373365014431 0ustar #pragma once #include #include #include #include "Wincodec.h" /****************************************************************** * * * CustomTextRenderer * * * * The IDWriteTextRenderer interface is an input parameter to * * IDWriteTextLayout::Draw. This interfaces defines a number of * * callback functions that the client application implements for * * custom text rendering. This sample renderer implementation * * renders text using text outlines and Direct2D. * * A more sophisticated client would also support bitmap * * renderings. * * * ******************************************************************/ class CustomTextRenderer : public IDWriteTextRenderer { public: CustomTextRenderer( ID2D1Factory* pD2DFactory, ID2D1RenderTarget* pRT, ID2D1SolidColorBrush* pOutlineBrush, ID2D1BitmapBrush* pFillBrush ); ~CustomTextRenderer(); IFACEMETHOD(IsPixelSnappingDisabled)( __maybenull void* clientDrawingContext, __out BOOL* isDisabled ); IFACEMETHOD(GetCurrentTransform)( __maybenull void* clientDrawingContext, __out DWRITE_MATRIX* transform ); IFACEMETHOD(GetPixelsPerDip)( __maybenull void* clientDrawingContext, __out FLOAT* pixelsPerDip ); IFACEMETHOD(DrawGlyphRun)( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, __in DWRITE_GLYPH_RUN const* glyphRun, __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, IUnknown* clientDrawingEffect ); IFACEMETHOD(DrawUnderline)( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, __in DWRITE_UNDERLINE const* underline, IUnknown* clientDrawingEffect ); IFACEMETHOD(DrawStrikethrough)( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, __in DWRITE_STRIKETHROUGH const* strikethrough, IUnknown* clientDrawingEffect ); IFACEMETHOD(DrawInlineObject)( __maybenull void* clientDrawingContext, FLOAT originX, FLOAT originY, IDWriteInlineObject* inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown* clientDrawingEffect ); public: IFACEMETHOD_(unsigned long, AddRef) (); IFACEMETHOD_(unsigned long, Release) (); IFACEMETHOD(QueryInterface) ( IID const& riid, void** ppvObject ); private: unsigned long cRefCount_; ID2D1Factory* pD2DFactory_; ID2D1RenderTarget* pRT_; ID2D1SolidColorBrush* pOutlineBrush_; ID2D1BitmapBrush* pFillBrush_; }; nux-4.0.8+18.10.20180623/Nux/Dialog.cpp0000644000000000000000000000366613313373365013271 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "HLayout.h" #include "VLayout.h" #include "Button.h" #include "Validator.h" #include "WindowCompositor.h" #include "Dialog.h" namespace nux { Dialog::Dialog(const char *WindowName /* = "" */) : FloatingWindow(WindowName) { ShowWindow(false); m_ButtonLayout = new HLayout("Dialog Buttons"); m_OkButton = new Button("OK"); m_OkButton->SetMinimumWidth(60); m_OkButton->SetMinimumHeight(20); m_CancelButton = new Button("Cancel"); m_CancelButton->SetMinimumWidth(60); m_CancelButton->SetMinimumHeight(20); //FIXME - m_OkButton->sigClick.connect(sigc::mem_fun(this, &Dialog::RecvOk)); //FIXME - m_CancelButton->sigClick.connect(sigc::mem_fun(this, &Dialog::RecvCancel)); m_ButtonLayout->SetHorizontalInternalMargin(6); m_ButtonLayout->SetVerticalExternalMargin(2); m_ButtonLayout->AddView(m_OkButton, 0); m_ButtonLayout->AddView(m_CancelButton, 0); // NuxNote: m_ButtonLayout should be moved to the places where it is used... For instance ColorPickerDialog. } Dialog::~Dialog() { } void Dialog::Start(bool StartModal) { ShowWindow(true, StartModal); } } nux-4.0.8+18.10.20180623/Nux/Dialog.h0000644000000000000000000000236113313373365012725 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef DIALOG_H #define DIALOG_H #include "FloatingWindow.h" namespace nux { class Button; class Dialog: public FloatingWindow { public: Dialog (const TCHAR *WindowName = TEXT ("") ); virtual ~Dialog(); protected: virtual void RecvOk() = 0; virtual void RecvCancel() = 0; virtual void Start (bool StartModal); Button *m_OkButton; Button *m_CancelButton; HLayout *m_ButtonLayout; }; } #endif // DIALOG_H nux-4.0.8+18.10.20180623/Nux/DoubleValidator.cpp0000644000000000000000000000601113313373365015135 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "DoubleValidator.h" #include #include namespace nux { DoubleValidator::DoubleValidator(double Minimum, double Maximum) : m_Minimum(Minimum) , m_Maximum(Maximum) , m_Decimals(3) { _regexp_str = "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"; InitRegExp(); if (m_Minimum > m_Maximum) { double temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } DoubleValidator::DoubleValidator(const DoubleValidator ©) { m_Minimum = copy.m_Minimum; m_Maximum = copy.m_Maximum; _regexp_str = copy._regexp_str; InitRegExp(); } DoubleValidator &DoubleValidator::operator= (const DoubleValidator &rhs) { if (&rhs != this) { m_Minimum = rhs.m_Minimum; m_Maximum = rhs.m_Maximum; _regexp_str = rhs._regexp_str; InitRegExp(); } return *this; } DoubleValidator::~DoubleValidator() { } Validator *DoubleValidator::Clone() const { return new DoubleValidator(*this); } void DoubleValidator::SetMinimum(double value) { m_Minimum = value; if (m_Minimum > m_Maximum) { double temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } double DoubleValidator::GetMinimum() const { return m_Minimum; } void DoubleValidator::SetMaximum(double value) { m_Maximum = value; if (m_Minimum > m_Maximum) { double temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } double DoubleValidator::GetMaximum() const { return m_Maximum; } double DoubleValidator::GetClampedValue(double d) const { if (d < m_Minimum) return m_Minimum; if (d > m_Maximum) return m_Maximum; return d; } void DoubleValidator::Alternative(const char * /* str */) { } void DoubleValidator::SetDecimals(int dec) { m_Decimals = Clamp (dec, 0, 13); } std::string DoubleValidator::ToString(double d) { std::stringstream s; s << std::setprecision(m_Decimals) << d; return s.str(); } double DoubleValidator::ToDouble(const char *str) { if (Validate(str) == Acceptable) return CharToDouble(str); else return 0.0; } } nux-4.0.8+18.10.20180623/Nux/DoubleValidator.h0000644000000000000000000000336113313373365014607 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef DOUBLEVALIDATOR_H #define DOUBLEVALIDATOR_H #include "Validator.h" namespace nux { class DoubleValidator : public Validator { public: DoubleValidator(double Minimum = -1.7E308, double Maximum = 1.7E308); DoubleValidator(const DoubleValidator &validator); DoubleValidator &operator= (const DoubleValidator &rhs); virtual ~DoubleValidator(); virtual Validator *Clone() const; //Virtual Constructor Idiom /*! @return The input value clamped to the range [m_Minimum, m_Maximum]. */ double GetClampedValue(double d) const; virtual void Alternative(const char *str); void SetDecimals(int dec); void SetMinimum(double value); double GetMinimum() const; void SetMaximum(double value); double GetMaximum() const; std::string ToString(double d); double ToDouble(const char *str); private: double m_Minimum; double m_Maximum; int m_Decimals; }; } #endif // INTEGERVALIDATOR_H nux-4.0.8+18.10.20180623/Nux/EMMetrics.cpp0000644000000000000000000000330113313373365013704 0ustar /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Mirco Müller DisplayWidth(dpy,scr) * 25.4) / (static_cast DisplayWidthMM(dpy,scr))); double yres = ((static_cast DisplayHeight(dpy,scr) * 25.4) / (static_cast DisplayHeightMM(dpy,scr))); dpi = (xres + yres) / 2.0; } // update stored ppe pixels_per_em_ = points * dpi / 72.0; // sanity-check if (pixels_per_em_ == 0.0) pixels_per_em_ = 10.0; // assume points == 10.0, dpi == 96.0 } double EMMetrics::Pixel2EM(int value) { return static_cast (value) / pixels_per_em_; } int EMMetrics::EM2Pixel(double value) { return static_cast (value * pixels_per_em_); } } // nux namespace nux-4.0.8+18.10.20180623/Nux/EMMetrics.h0000644000000000000000000000176513313373365013365 0ustar /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Mirco Müller namespace nux { class EMMetrics { public: EMMetrics(Display* dpy, int scr, double points); double Pixel2EM(int value); int EM2Pixel(double value); private: double pixels_per_em_; }; } #endif // NUX_EMMETRICS_H nux-4.0.8+18.10.20180623/Nux/EditTextBox.cpp0000644000000000000000000003424413313373365014271 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "EditTextBox.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "Validator.h" namespace nux { EditTextBox::EditTextBox(const char *Caption, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { m_Validator = NULL; BlinkCursor = false; m_ScrollTimerHandler = 0; m_BlinkTimerFunctor = 0; m_WriteAlpha = true; m_Prefix = ""; m_Suffix = ""; key_nav_mode_ = false; text_input_mode_ = false; SetGeometry(Geometry(0, 0, 3 * DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); SetGeometry(Geometry(0, 0, 3 * DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); mouse_down.connect(sigc::mem_fun(this, &EditTextBox::RecvMouseDown)); mouse_drag.connect(sigc::mem_fun(this, &EditTextBox::RecvMouseDrag)); mouse_up.connect(sigc::mem_fun(this, &EditTextBox::RecvMouseUp)); mouse_double_click.connect(sigc::mem_fun(this, &EditTextBox::RecvMouseDoubleClick)); key_down.connect(sigc::mem_fun(this, &EditTextBox::RecvKeyEvent)); begin_key_focus.connect(sigc::mem_fun(this, &EditTextBox::RecvStartKeyFocus)); end_key_focus.connect(sigc::mem_fun(this, &EditTextBox::RecvEndKeyFocus)); SetText(Caption); SetTextColor(color::White); m_BackgroundColor = Color(0xFF343434); //COLOR_TEXTEDIT_BACKGROUNG; m_SelectedTextColor = Color(0xFFFAFAFA); m_SelectedTextBackgroundColor = Color(0xFF777777); m_TextBlinkColor = Color(0xFF003D0A); m_CursorColor = Color(0xFFDDDDDD); hlayout = new HLayout(NUX_TRACKER_LOCATION); SetLayout(hlayout); m_BlinkTimerFunctor = new TimerFunctor(); m_BlinkTimerFunctor->tick.connect(sigc::mem_fun(this, &EditTextBox::BlinkCursorTimerInterrupt)); m_ScrollTimerFunctor = new TimerFunctor(); m_ScrollTimerFunctor->tick.connect(sigc::mem_fun(this, &EditTextBox::ScrollTimerInterrupt)); SetAcceptKeyboardEvent(true); EnableDoubleClick(true); } EditTextBox::~EditTextBox() { delete m_BlinkTimerFunctor; delete m_ScrollTimerFunctor; delete m_Validator; if (m_BlinkTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_BlinkTimerHandler); m_BlinkTimerHandler = 0; } void EditTextBox::ScrollTimerInterrupt(void * /* v */) { Geometry base = GetGeometry(); const Event& event = GetGraphicsDisplay()->GetCurrentEvent(); int X = event.x; m_KeyboardHandler.CaretAutoScroll(event.x, event.y, base); if (((X < base.x) && (m_KeyboardHandler.GetCursorPosition() > 0)) || ((X > base.x + base.GetWidth()) && (m_KeyboardHandler.GetCursorPosition() < m_KeyboardHandler.GetLength()))) { m_ScrollTimerHandler = GetTimer().AddOneShotTimer(50, m_ScrollTimerFunctor, this); } else { GetTimer().RemoveTimerHandler(m_BlinkTimerHandler); m_ScrollTimerHandler = 0; } // While the mouse is selecting the text, no blinking of cursor StopBlinkCursor(false); StartBlinkCursor(false); QueueDraw(); } void EditTextBox::BlinkCursorTimerInterrupt(void * /* v */) { GetTimer().RemoveTimerHandler(m_BlinkTimerHandler); m_BlinkTimerHandler = GetTimer().AddOneShotTimer(500, m_BlinkTimerFunctor, this); BlinkCursor = !BlinkCursor; QueueDraw(); } void EditTextBox::StopBlinkCursor(bool BlinkState) { GetTimer().RemoveTimerHandler(m_BlinkTimerHandler); m_BlinkTimerHandler = 0; BlinkCursor = BlinkState; QueueDraw(); } void EditTextBox::StartBlinkCursor(bool BlinkState) { m_BlinkTimerHandler = GetTimer().AddOneShotTimer(500, m_BlinkTimerFunctor, this); BlinkCursor = BlinkState; QueueDraw(); } void EditTextBox::SetValidator(const Validator *validator) { nuxAssert(validator != 0); delete m_Validator; m_Validator = validator->Clone(); } void EditTextBox::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); { graphics_engine.PushClippingRectangle(base); GetPainter().Paint2DQuadColor(graphics_engine, base, Color(m_BackgroundColor)); if (HasKeyboardFocus()) { GetPainter().PaintColorTextLineEdit(graphics_engine, GetGeometry(), m_KeyboardHandler.GetTextLine(), GetTextColor(), m_WriteAlpha, m_SelectedTextColor, m_SelectedTextBackgroundColor, m_TextBlinkColor, m_CursorColor, !BlinkCursor, m_KeyboardHandler.GetCursorPosition(), m_KeyboardHandler.GetPositionX(), m_KeyboardHandler.GetTextSelectionStart(), m_KeyboardHandler.GetTextSelectionEnd() ); } else { GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), GetGeometry(), m_KeyboardHandler.GetTextLine(), GetTextColor()); } } graphics_engine.PopClippingRectangle(); } void EditTextBox::DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void EditTextBox::SetText(const char *Caption) { std::string s(Caption); SetText(s); } void EditTextBox::SetText(const std::string &Caption) { std::string s(Caption); size_t pos = s.find(m_Prefix, 0); if (pos == 0) { s.erase(0, m_Prefix.size()); } pos = s.rfind(m_Suffix); if (pos != std::string::npos && pos == s.size() - m_Suffix.size()) { s.erase(pos); } if (ValidateKeyboardEntry(s.c_str())) { m_Text = (m_Prefix + s) + m_Suffix; m_KeyboardHandler.SetText(m_Text); m_temporary_caption = m_Text; sigSetText.emit(this); } QueueDraw(); } const char *EditTextBox::GetText() const { return m_Text.c_str(); } //! Return a caption string striping out the prefix and the suffix std::string EditTextBox::GetCleanText() const { std::string CleanText(m_Text); size_t pos = CleanText.find(m_Prefix, 0); if (pos == 0) { CleanText.erase(0, m_Prefix.size()); } pos = CleanText.rfind(m_Suffix); if (pos != std::string::npos && pos == CleanText.size() - m_Suffix.size()) { CleanText.erase(pos); } return CleanText; } void EditTextBox::RecvMouseDoubleClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { m_KeyboardHandler.SelectAllText(); QueueDraw(); } void EditTextBox::RecvMouseUp(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { m_KeyboardHandler.MouseUp(x, y); if (m_ScrollTimerHandler.IsValid()) { GetTimer().RemoveTimerHandler(m_ScrollTimerHandler); m_ScrollTimerHandler = 0; } QueueDraw(); } void EditTextBox::RecvMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (HasKeyboardFocus() == false) { // First mouse down m_KeyboardHandler.EnterFocus(); } else { // Second mouse down and more m_KeyboardHandler.UnselectAllText(); m_KeyboardHandler.MouseDown(x, y); // Always make the cursor visible when a mouse down happens. StopBlinkCursor(false); StartBlinkCursor(false); } QueueDraw(); } void EditTextBox::RecvMouseDrag(int x, int y, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { Geometry base = GetGeometry(); int X = x + base.x; if ((!m_ScrollTimerHandler.IsValid()) && ((X < base.x) || (X > base.x + base.GetWidth()))) { m_ScrollTimerHandler = GetTimer().AddOneShotTimer(25, m_ScrollTimerFunctor, this); } else if ((X >= base.x) && (X < base.x + base.GetWidth())) { m_KeyboardHandler.MouseDrag(x, y); // While the mouse is selecting the text, no blinking of cursor StopBlinkCursor(false); StartBlinkCursor(false); } QueueDraw(); } long EditTextBox::PostLayoutManagement(long LayoutResult) { long ret = View::PostLayoutManagement(LayoutResult); m_KeyboardHandler.SetClipRegion(GetGeometry()); return ret; } void EditTextBox::RecvKeyEvent( unsigned long eventType , /*event type*/ unsigned long keysym , /*event keysym*/ unsigned long state , /*event state*/ const char* character , /*character*/ unsigned short /* keyCount */ /*key repeat count*/) { if (eventType == NUX_KEYDOWN) text_input_mode_ = true; m_KeyboardHandler.ProcessKey(eventType, keysym, state, character[0], GetGeometry()); // When a key event happens, show the cursor. StopBlinkCursor(false); // Start a new blink cycle with the cursor originally visible. StartBlinkCursor(false); if (character) { sigCharacter.emit(this, character[0]); sigEditChange.emit(this); } if (keysym == NUX_VK_ENTER || keysym == NUX_KP_ENTER) { std::string str(m_KeyboardHandler.GetTextLine()); size_t pos = str.rfind(m_Suffix); if (pos != std::string::npos && pos == str.size() - m_Suffix.size()) { str.erase(pos); } if (ValidateKeyboardEntry(str.c_str())) { m_Text = m_KeyboardHandler.GetTextLine(); m_temporary_caption = m_Text; sigValidateKeyboardEntry.emit(this, m_Text); sigValidateEntry.emit(this); m_KeyboardHandler.SelectAllText(); } else { m_Text = m_temporary_caption; m_KeyboardHandler.SetText(m_Text); m_KeyboardHandler.SelectAllText(); } } if (keysym == NUX_VK_ESCAPE) { text_input_mode_ = false; } QueueDraw(); } bool EditTextBox::ValidateKeyboardEntry(const char *text) const { if (m_Validator) { if (m_Validator->Validate(text) == Validator::Acceptable) { return true; } else { return false; } } return true; } void EditTextBox::EscapeKeyboardFocus() { // todo(jaytaoko): SetKeyboardFocus(false); // Revert back the caption text m_Text = m_temporary_caption; sigEscapeKeyboardFocus.emit(this); QueueDraw(); } void EditTextBox::EnteringKeyboardFocus() { m_KeyboardHandler.SetText(m_Text); m_KeyboardHandler.SelectAllText(); // Preserve the current caption text. If ESC is pressed while we have keyboard focus then // the previous caption text is restored m_temporary_caption = m_Text; sigStartKeyboardFocus.emit(this); QueueDraw(); } void EditTextBox::QuitingKeyboardFocus() { std::string CleanText(m_KeyboardHandler.GetTextLine()); size_t pos = CleanText.find(m_Prefix, 0); if (pos == 0) { CleanText.erase(0, m_Prefix.size()); } pos = CleanText.rfind(m_Suffix); if (pos != std::string::npos && pos == CleanText.size() - m_Suffix.size()) { CleanText.erase(pos); } if (ValidateKeyboardEntry(CleanText.c_str())) { CleanText = m_Prefix + CleanText; CleanText = CleanText + m_Suffix; m_Text = CleanText; //m_KeyboardHandler.GetTextLine(); m_KeyboardHandler.SetText(CleanText); m_temporary_caption = m_Text; sigValidateKeyboardEntry.emit(this, m_Text); sigValidateEntry.emit(this); } else { m_Text = m_temporary_caption; m_KeyboardHandler.SetText(m_Text); m_KeyboardHandler.SelectAllText(); } QueueDraw(); } void EditTextBox::RecvStartKeyFocus() { key_nav_mode_ = true; text_input_mode_ = false; EnteringKeyboardFocus(); m_BlinkTimerHandler = GetTimer().AddOneShotTimer(500, m_BlinkTimerFunctor, this); } void EditTextBox::RecvEndKeyFocus() { key_nav_mode_ = false; text_input_mode_ = false; QuitingKeyboardFocus(); GetTimer().RemoveTimerHandler(m_BlinkTimerHandler); m_BlinkTimerHandler = 0; BlinkCursor = false; } void EditTextBox::SetDoubleValue(double d) { SetText(std::to_string((long double)d)); } void EditTextBox::SetIntegerValue(int i) { SetText(std::to_string((long long)i)); } void EditTextBox::SetTextBackgroundColor(const Color &color) { m_BackgroundColor = color; QueueDraw(); } Color EditTextBox::GetTextBackgroundColor() const { return m_BackgroundColor; } bool EditTextBox::IsEmpty() { if (m_Text == "") { return true; } return false; } bool EditTextBox::InspectKeyEvent(unsigned int eventType, unsigned int keysym, const char* /* character */) { if ((eventType == NUX_KEYDOWN) && (key_nav_mode_ == true) && (text_input_mode_ == false)) { if (keysym == NUX_VK_ENTER || keysym == NUX_KP_ENTER || keysym == NUX_VK_UP || keysym == NUX_VK_DOWN || keysym == NUX_VK_LEFT || keysym == NUX_VK_RIGHT || keysym == NUX_VK_LEFT_TAB || keysym == NUX_VK_TAB) { return false; } } if ((eventType == NUX_KEYDOWN) && (key_nav_mode_ == false) && (text_input_mode_ == false)) { return false; } return true; } } nux-4.0.8+18.10.20180623/Nux/EditTextBox.h0000644000000000000000000001434413313373365013735 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef EDITTEXTBOX_H #define EDITTEXTBOX_H #include "KeyboardHandler.h" #include "TimerProc.h" namespace nux { class HLayout; class VLayout; class Layout; class BaseKeyboardHandler; class TextLine; class Validator; class EditTextBox : public View { public: EditTextBox(const char *Caption, NUX_FILE_LINE_PROTO); ~EditTextBox(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); //! Return True if the the area knows what to do with the key event. virtual bool InspectKeyEvent(unsigned int eventType, unsigned int keysym, const char* character); void SetText(const char *Caption); void SetText(const std::string &Caption); const char *GetText() const; unsigned int GetTextSize() const { return (unsigned int) m_Text.length(); } void SetDoubleValue(double d); void SetIntegerValue(int i); //! Return a caption string striping out the prefix and the suffix virtual std::string GetCleanText() const; void SetTextBackgroundColor(const Color &color); Color GetTextBackgroundColor() const; void SetSelectedTextColor(Color color) { m_SelectedTextColor = color; } void SetSelectedTextBackgroundColor(Color color) { m_SelectedTextBackgroundColor = color; } void SetTextBlinkColor(Color color) { m_TextBlinkColor = color; } void SetCursorColor(Color color) { m_CursorColor = color; } Color GetSelectedTextColor() const { return m_SelectedTextColor; } Color GetSelectedTextBackgroundColor() const { return m_SelectedTextBackgroundColor; } Color GetTextBlinkColor() const { return m_TextBlinkColor; } Color GetCursorColor() const { return m_CursorColor; } void SetKeyEntryType(BaseKeyboardHandler::eKeyEntryType keytype) { m_KeyboardHandler.SetKeyEntryType(keytype); } BaseKeyboardHandler::eKeyEntryType GetKeyEntryType() { return m_KeyboardHandler.GetKeyEntryType(); } // Receivers void RecvMouseDoubleClick(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void RecvKeyEvent( unsigned long eventType , /*event type*/ unsigned long keysym , /*event keysym*/ unsigned long state , /*event state*/ const char* character , /*character*/ unsigned short keyCount /*key repeat count*/); void RecvStartKeyFocus(); void RecvEndKeyFocus(); void SetPrefix(const char *p) { m_Prefix = p; }; void SetPrefix(const char &p) { m_Prefix = p; }; void SetPrefix(const std::string &p) { m_Prefix = p; }; std::string GetPrefix() const { return m_Prefix; }; void SetSuffix(const char *s) { m_Suffix = s; }; void SetSuffix(const char &s) { m_Suffix = s; }; void SetSuffix(const std::string &s) { m_Suffix = s; }; std::string Getsuffix() const { return m_Suffix; }; void SetValidator(const Validator *validator); sigc::signal< void, EditTextBox *, unsigned int > sigCharacter; // Emitted every time a character typed sigc::signal< void, EditTextBox * > sigEditChange; // Emitted every time a character typed sigc::signal< void, EditTextBox *, const std::string &> sigValidateKeyboardEntry; sigc::signal< void, EditTextBox * > sigValidateEntry; // Emitted when the text is validated sigc::signal< void, EditTextBox * > sigSetText; // Emitted when text is set with setCaption sigc::signal< void, EditTextBox * > sigEscapeKeyboardFocus; sigc::signal< void, EditTextBox * > sigStartKeyboardFocus; sigc::signal< void, EditTextBox * > sigEndKeyboardFocus; bool IsTextSelected() { return m_KeyboardHandler.IsTextSelected(); } bool IsEmpty(); private: bool ValidateKeyboardEntry(const char *text) const; void EscapeKeyboardFocus(); void EnteringKeyboardFocus(); void QuitingKeyboardFocus(); virtual long PostLayoutManagement(long LayoutResult); std::string m_Text; HLayout *hlayout; Color m_BackgroundColor; Color m_SelectedTextColor; Color m_SelectedTextBackgroundColor; Color m_TextBlinkColor; Color m_CursorColor; BaseKeyboardHandler m_KeyboardHandler; std::string m_temporary_caption; BaseKeyboardHandler::eKeyEntryType m_keytype; Validator *m_Validator; std::string m_Suffix; std::string m_Prefix; bool BlinkCursor; void BlinkCursorTimerInterrupt(void *v); void StopBlinkCursor(bool BlinkState = false); void StartBlinkCursor(bool BlinkState = false); TimerFunctor *m_BlinkTimerFunctor; TimerHandle m_BlinkTimerHandler; void ScrollTimerInterrupt(void *v); TimerFunctor *m_ScrollTimerFunctor; TimerHandle m_ScrollTimerHandler; //! If true, blend the characters alpha value with the destination and write the result to the destination buffer. bool m_WriteAlpha; bool text_input_mode_; bool key_nav_mode_; friend class RGBValuator; }; } #endif // EDITTEXTBOX_H nux-4.0.8+18.10.20180623/Nux/Features.h.in0000644000000000000000000000052213313373365013706 0ustar /* This file specifies which optional features are available on this specific build of NUX libraries Generated from Features.h.in by configure. */ #ifndef NUX_FEATURES_H #define NUX_FEATURES_H // Whether NUX was built with gestures support. I.e., whether the gestures // API is available. #define @NUX_GESTURES_SUPPORT@ #endif nux-4.0.8+18.10.20180623/Nux/FileSelector.cpp0000644000000000000000000001036613313373365014445 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "FileSelector.h" #include "EditTextBox.h" #include "HLayout.h" #include "Button.h" namespace nux { Color FILESELECTOR_BUTTON_COLOR = Color(0xFF4D4D4D); Color FILESELECTOR_BUTTON_MOUSEOVER_COLOR = Color(0xFF222222); FileSelector::FileSelector(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { m_hlayout = new HLayout(NUX_TRACKER_LOCATION); m_OpenButton = new Button("", NUX_TRACKER_LOCATION); m_FileEditTextBox = new EditTextBox("", NUX_TRACKER_LOCATION); m_hlayout->AddView(m_FileEditTextBox, 1, eCenter); m_hlayout->AddView(m_OpenButton, 0, eCenter); //m_OpenButton->setCaption("..."); m_OpenButton->SetMinimumWidth(20); m_OpenButton->mouse_enter.connect(sigc::mem_fun(this, &FileSelector::RecvMouseEnter)); m_OpenButton->mouse_leave.connect(sigc::mem_fun(this, &FileSelector::RecvMouseLeave)); m_OpenButton->mouse_click.connect(sigc::mem_fun(this, &FileSelector::RecvOpenButtonClick)); SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); SetLayout(m_hlayout); std::string Path = NUX_FINDRESOURCELOCATION("Icons/Folder-16x16.png"); m_Texture = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); m_Texture->Update(Path.c_str()); } FileSelector::~FileSelector() { m_Texture->UnReference(); } void FileSelector::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); GetPainter().PaintBackground(graphics_engine, base); if (m_OpenButton->IsMouseInside()) { GetPainter().PaintShapeCorner(graphics_engine, m_OpenButton->GetGeometry(), FILESELECTOR_BUTTON_MOUSEOVER_COLOR, eSHAPE_CORNER_ROUND4, eCornerTopRight | eCornerBottomRight, false); } else { GetPainter().PaintShapeCorner(graphics_engine, m_OpenButton->GetGeometry(), FILESELECTOR_BUTTON_COLOR, eSHAPE_CORNER_ROUND4, eCornerTopRight | eCornerBottomRight, false); } GeometryPositioning gp(eHACenter, eVACenter); Geometry TextureGeo = Geometry(0, 0, m_Texture->GetWidth(), m_Texture->GetHeight()); Geometry GeoPo = ComputeGeometryPositioning(m_OpenButton->GetGeometry(), TextureGeo, gp); GetGraphicsDisplay()->GetGraphicsEngine()->GetRenderStates().SetBlend(TRUE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GetGraphicsDisplay()->GetGraphicsEngine()->GetRenderStates().SetColorMask(TRUE, TRUE, TRUE, FALSE); nux::TexCoordXForm texxform; graphics_engine.QRP_1Tex(GeoPo.x, GeoPo.y, GeoPo.width, GeoPo.height, m_Texture->GetDeviceTexture(), texxform, nux::color::White); GetGraphicsDisplay()->GetGraphicsEngine()->GetRenderStates().SetColorMask(TRUE, TRUE, TRUE, TRUE); GetGraphicsDisplay()->GetGraphicsEngine()->GetRenderStates().SetBlend(FALSE); m_FileEditTextBox->QueueDraw(); } void FileSelector::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { m_FileEditTextBox->ProcessDraw(graphics_engine, force_draw); } void FileSelector::RecvMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void FileSelector::RecvMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void FileSelector::RecvOpenButtonClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); sigClick.emit(); } } nux-4.0.8+18.10.20180623/Nux/FileSelector.h0000644000000000000000000000362513313373365014112 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef FILE_SELECTOR_H #define FILE_SELECTOR_H namespace nux { class Button; class EditTextBox; class FileSelector: public View { public: FileSelector(NUX_FILE_LINE_PROTO); ~FileSelector(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); //void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); //void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); //void RecvMouseMove(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvOpenButtonClick(int x, int y, unsigned long button_flags, unsigned long key_flags); sigc::signal sigClick; private: EditTextBox *m_FileEditTextBox; InputArea *m_OpenButton; HLayout *m_hlayout; BaseTexture *m_Texture; }; } #endif // FILE_SELECTOR_H nux-4.0.8+18.10.20180623/Nux/FloatingWindow.cpp0000644000000000000000000003603013313373365015014 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/GLTextureResourceManager.h" #include "HLayout.h" #include "WindowThread.h" #include "WindowCompositor.h" #include "FloatingWindow.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(FloatingWindow); /* Elements inside the Window have coordinates based on the top-left corner of the window. This is true whether we are drawing or computing the layout. When computing the layout, use x_root and y_root to pass the top-left corner position of the window. When drawing, make a similar adjustment. */ FloatingWindow::FloatingWindow(const char *WindowName, NUX_FILE_LINE_DECL) : BaseWindow(WindowName, NUX_FILE_LINE_PARAM) { m_bIsVisible = false; m_bSizeMatchLayout = false; m_bIsModal = false; m_bIsVisibleSizeGrip = true; m_SizeGripDragPositionX = 0; m_SizeGripDragPositionY = 0; m_hasTitleBar = true; _resize_handle_width = 20; _resize_handle_height = 20; _title_bar_height = 20; _minimize_button = new BasicView(NUX_TRACKER_LOCATION); _minimize_button->SetParentObject(this); _resize_handle = new BasicView(NUX_TRACKER_LOCATION); _resize_handle->SinkReference(); _resize_handle->SetParentObject(this); _title_bar = new BasicView(NUX_TRACKER_LOCATION); _title_bar->SinkReference(); _title_bar->SetParentObject(this); _close_button = new BasicView(NUX_TRACKER_LOCATION); _window_title_bar = new StaticTextBox("", NUX_TRACKER_LOCATION); _title_bar_layout = new HLayout(NUX_TRACKER_LOCATION); _title_bar_layout->Reference(); _minimize_button->SetMinMaxSize(20, 20); _minimize_button->SetGeometry(Geometry(0, 0, 20, 20)); _close_button->SetMinimumSize(20, 20); _close_button->SetGeometry(Geometry(0, 0, 20, 20)); _resize_handle->SetMinimumSize(_resize_handle_width, _resize_handle_height); _resize_handle->SetGeometry(Geometry(0, 0, _resize_handle_width, _resize_handle_height)); _title_bar->mouse_down.connect(sigc::mem_fun(this, &FloatingWindow::RecvTitleBarMouseDown)); _title_bar->mouse_drag.connect(sigc::mem_fun(this, &FloatingWindow::RecvTitleBarMouseDrag)); _close_button->mouse_click.connect(sigc::mem_fun(this, &FloatingWindow::RecvCloseButtonClick)); _resize_handle->mouse_drag.connect(sigc::mem_fun(this, &FloatingWindow::OnSizeGrigMouseDrag)); _resize_handle->mouse_down.connect(sigc::mem_fun(this, &FloatingWindow::OnSizeGrigMouseDown)); _title_bar_layout->AddView((_window_title_bar), 1, eCenter, eFix); _title_bar_layout->AddView((_close_button), 0, eCenter, eFix); _title_bar_layout->SetParentObject(this); if (HasTitleBar()) SetTopBorder(24); else SetTopBorder(6); SetBorder(2); SetMinimumSize(32, 32); SetGeometry(Geometry(100, 100, 320, 200)); std::string Path = NUX_FINDRESOURCELOCATION("UITextures/AddButton.png"); MinimizeIcon = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); MinimizeIcon->Update(Path.c_str()); Path = NUX_FINDRESOURCELOCATION("UITextures/CancelButton.png"); CloseIcon = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); CloseIcon->Update(Path.c_str()); SetWindowTitle(WindowName); } FloatingWindow::~FloatingWindow() { m_InterfaceObject.clear(); _resize_handle->UnParentObject(); _resize_handle->UnReference(); _title_bar->UnParentObject(); _title_bar->UnReference(); _minimize_button->UnReference(); CloseIcon->UnReference(); MinimizeIcon->UnReference(); _title_bar_layout->UnParentObject(); _title_bar_layout->UnReference(); } Area* FloatingWindow::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; NUX_RETURN_VALUE_IF_TRUE(_resize_handle->TestMousePointerInclusion(mouse_position, event_type), _resize_handle); NUX_RETURN_VALUE_IF_TRUE(_close_button->TestMousePointerInclusion(mouse_position, event_type), _close_button); if (HasTitleBar()) { NUX_RETURN_VALUE_IF_TRUE(_title_bar->TestMousePointerInclusion(mouse_position, event_type), _title_bar); } // if (_title_bar_layout) // { // nuxAssert(_title_bar_layout->IsLayout()); // Area* found_area = _title_bar_layout->FindAreaUnderMouse(mouse_position, event_type); // if (found_area) // return found_area; // } if (m_layout) { nuxAssert(m_layout->IsLayout()); Area* found_area = m_layout->FindAreaUnderMouse(mouse_position, event_type); if (found_area) return found_area; } if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } void FloatingWindow::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); // The elements position inside the window are referenced to top-left window corner. So bring base to(0, 0). base.SetX(0); base.SetY(0); graphics_engine.PushClippingRectangle(base); GetPainter().PushDrawShapeLayer(graphics_engine, base, eSHAPE_CORNER_ROUND10, Color(0xFF707070), eCornerTopLeft | eCornerTopRight, true); if (HasTitleBar()) { GetPainter().PaintShapeCorner(graphics_engine, Geometry(_title_bar->GetBaseX(), _title_bar->GetBaseY(), _title_bar->GetBaseWidth(), _title_bar->GetBaseHeight()), Color(0xFF2f2f2f), eSHAPE_CORNER_ROUND10, eCornerTopLeft | eCornerTopRight); GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), _window_title_bar->GetGeometry(), _window_title, Color(0xFFFFFFFF), true, eAlignTextCenter); GetPainter().Draw2DTextureAligned(graphics_engine, CloseIcon, _close_button->GetGeometry(), TextureAlignmentStyle(eTACenter, eTACenter)); } GetPainter().PopBackground(); graphics_engine.PopClippingRectangle(); } void FloatingWindow::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); // The elements position inside the window are referenced to top-left window corner. So bring base to(0, 0). base.SetX(0); base.SetY(0); GetPainter().PushShapeLayer(graphics_engine, base, eSHAPE_CORNER_ROUND10, Color(0xFF707070), eCornerTopLeft | eCornerTopRight, true); if (m_layout) { graphics_engine.PushClippingRectangle(base); m_layout->ProcessDraw(graphics_engine, force_draw); graphics_engine.PopClippingRectangle(); } GetPainter().PopBackground(); } void FloatingWindow::EnableTitleBar(bool b) { m_hasTitleBar = b; ComputeContentSize(); } bool FloatingWindow::HasTitleBar() const { return m_hasTitleBar; } void FloatingWindow::OnSizeGrigMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (IsSizeMatchContent()) { return; } // Do not let the _resize_handle test the event because the window is not displaying it; int XGrip = x; int YGrip = y; // We want to false on one half of the size grip square to register a mouse down. This is meant to leave more room // for the scrollbar buttons(if any) at the bottom right of the window. if ((XGrip > 0) && (YGrip > 0) && (XGrip > _resize_handle_height - YGrip)) { // has grip } m_SizeGripDragPositionX = x; m_SizeGripDragPositionY = y; //GetWindowCompositor().SetMouseFocusArea(this); } void FloatingWindow::OnSizeGrigMouseDrag(int x, int y, int dx, int dy, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (IsSizeMatchContent()) { return; } Geometry geo; geo = GetGeometry(); int ddx = 0; int ddy = 0; if ((dx > 0) && (x > m_SizeGripDragPositionX)) { ddx = dx; } if ((dx < 0) && (x < m_SizeGripDragPositionX)) { ddx = dx; } if ((dy > 0) && (y > m_SizeGripDragPositionY)) { ddy = dy; } if ((dy < 0) && (y < m_SizeGripDragPositionY)) { ddy = dy; } geo.OffsetSize(ddx, ddy); SetGeometry(geo); #if defined(USE_X11) if (m_input_window != 0) { //nuxDebugMsg("Resize Input window: %d, %d, %d, %d", geo.x, geo.y, geo.width, geo.height); m_input_window->SetGeometry(GetGeometry()); } #endif GetWindowThread()->QueueObjectLayout(this); QueueDraw(); } void FloatingWindow::RecvTitleBarMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { _title_bar_mouse_down_location = Point(x, y); } void FloatingWindow::RecvTitleBarMouseDrag(int /* x */, int /* y */, int dx, int dy, unsigned long /* button_flags */, unsigned long /* key_flags */) { Geometry geo; geo = GetGeometry(); geo.OffsetPosition(dx, dy); // Set the Window Size and Position Area::SetGeometry(geo); // No need to compute the window layout elements [LayoutWindowElements()]. They haven't changed. // No need to compute the layout [ComputeContentSize()]. It hasn't changed. _title_bar->SetGeometry(Geometry(0, 0, geo.GetWidth(), _title_bar_height)); #if defined(USE_X11) if (m_input_window != 0) { //nuxDebugMsg("Resize Input window: %d, %d, %d, %d", geo.x, geo.y, geo.width, geo.height); m_input_window->SetGeometry(GetGeometry()); } #endif QueueDraw(); } void FloatingWindow::RecvCloseButtonClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { #if defined(USE_X11) // Disable the input window if there is one. EnableInputWindow(false); #endif StopModal(); } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. void FloatingWindow::PreLayoutManagement() { Geometry geo = GetGeometry(); if (m_configure_notify_callback) { (*m_configure_notify_callback) (GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data); if (geo.IsNull()) { nuxDebugMsg("[FloatingWindow::PreLayoutManagement] Received an invalid Geometry."); geo = GetGeometry(); } else { Area::SetGeometry(geo); // Get the geometry adjusted with respect to min and max dimension of this area. geo = GetGeometry(); } } // Drag Bar Geometry if (HasTitleBar()) { _title_bar->SetGeometry(Geometry(0, 0, geo.GetWidth(), _title_bar_height)); } // Size grip Geometry Geometry SizeGripGeometry(geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height, _resize_handle_width, _resize_handle_height); _resize_handle->SetGeometry(SizeGripGeometry); if (m_layout) { Geometry layout_geo = Geometry(m_Border, m_TopBorder, geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder); m_layout->SetGeometry(layout_geo); } } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. long FloatingWindow::PostLayoutManagement(long /* LayoutResult */) { if (IsSizeMatchContent() && m_layout) { Geometry layout_geometry = m_layout->GetGeometry(); Geometry WindowGeometry = Geometry(GetGeometry().x, GetGeometry().y, layout_geometry.GetWidth() + 2 * m_Border, layout_geometry.GetHeight() + m_Border + m_TopBorder); Area::SetGeometry(WindowGeometry); } Geometry geo = GetGeometry(); // Drag Bar Geometry if (HasTitleBar()) { _title_bar->SetGeometry(Geometry(0, 0, geo.GetWidth(), _title_bar_height)); } // Size grip Geometry Geometry temp(geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height, _resize_handle_width, _resize_handle_height); _resize_handle->SetGeometry(temp); // Title Bar _title_bar_layout->SetGeometry(_title_bar->GetGeometry()); GetWindowThread()->ComputeElementLayout(_title_bar_layout); // A FloatingWindow must kill the result of the management and pass it to the parent Layout. return (eCompliantHeight | eCompliantWidth); //return result; } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. void FloatingWindow::ComputeContentPosition(float /* offsetX */, float /* offsetY */) { //ScrollView::ComputeContentPosition(offsetX, offsetY); Geometry geo = GetGeometry(); // Drag Bar Geometry if (HasTitleBar()) { _title_bar->SetGeometry(Geometry(0, 0, geo.GetWidth(), _title_bar_height)); } // Size grip Geometry Geometry temp(geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height, _resize_handle_width, _resize_handle_height); _resize_handle->SetGeometry(temp); // Title Bar _title_bar_layout->SetGeometry(_title_bar->GetGeometry()); GetWindowThread()->ComputeElementLayout(_title_bar_layout); } void FloatingWindow::LayoutWindowElements() { // Define the geometry of some of the component of the window. Otherwise, if the composition layout is not set, // then the component won't be correctly placed after a SetGeometry. This can be redundant if the composition layout is set. Geometry base = GetGeometry(); _title_bar->SetGeometry(Geometry(0, 0, base.GetWidth(), _title_bar_height)); _title_bar_layout->SetGeometry(_title_bar->GetGeometry()); GetWindowThread()->ComputeElementLayout(_title_bar_layout); // Size grip Geometry Geometry temp(base.GetWidth() - _resize_handle_width, base.GetHeight() - _resize_handle_height, _resize_handle_width, _resize_handle_height); _resize_handle->SetGeometry(temp); } void FloatingWindow::SetWindowTitle(const char *title) { NUX_RETURN_IF_NULL(title) _window_title = title; } std::string FloatingWindow::GetWindowTitle() { return _window_title; } } nux-4.0.8+18.10.20180623/Nux/FloatingWindow.h0000644000000000000000000001027713313373365014466 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef FLOATINGWINDOW_H #define FLOATINGWINDOW_H #include "NuxGraphics/Events.h" #include "ScrollView.h" #include "BaseWindow.h" #include "BasicView.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "Validator.h" #include "StaticTextBox.h" namespace nux { class HLayout; class PopUpWindow; class FloatingWindow: public BaseWindow { NUX_DECLARE_OBJECT_TYPE(FloatingWindow, BaseWindow); public: FloatingWindow(const char *WindowName = "", NUX_FILE_LINE_PROTO); ~FloatingWindow(); void SetVisibleSizeGrip(bool b) { if (b && (m_bSizeMatchLayout)) m_bIsVisibleSizeGrip = false; else m_bIsVisibleSizeGrip = b; } bool IsVisibleSizeGrip() { return m_bIsVisibleSizeGrip; } void EnableTitleBar(bool b); bool HasTitleBar() const; void OnSizeGrigMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnSizeGrigMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void RecvCloseButtonClick(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTitleBarMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTitleBarMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void SetWindowTitle(const char *title); std::string GetWindowTitle(); //! Return true if this object can break the layout. /* Return true if this object can break the layout, meaning, the layout can be done on the composition layout only without recomputing the whole window layout. Inherited from View */ virtual bool CanBreakLayout() { if (IsSizeMatchContent()) return false; return true; } protected: virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual void PreLayoutManagement(); virtual long PostLayoutManagement(long LayoutResult); virtual void ComputeContentPosition(float offsetX, float offsetY); //! Layout the window elements. /*! Layout elements such as button on the title bar, and the resize widget according to the current geometry of the window. Also initiate the computation of the child layout if there is one. */ virtual void LayoutWindowElements(); int m_SizeGripDragPositionX; int m_SizeGripDragPositionY; private: int _resize_handle_width; int _resize_handle_height; int _title_bar_height; BasicView *_resize_handle; BasicView *_title_bar; Point _title_bar_mouse_down_location; BasicView *_minimize_button; BasicView *_close_button; StaticTextBox *_window_title_bar; bool m_hasTitleBar; bool m_bIsVisible; bool m_bIsVisibleSizeGrip; bool m_bIsModal; //! If true then the FloatingWindow is resized to match the size of the layout. bool m_bSizeMatchLayout; BaseTexture* CloseIcon; BaseTexture* MinimizeIcon; std::list m_InterfaceObject; HLayout *_title_bar_layout; std::string _window_title; friend class PopUpWindow; friend class ComboBox_Logic_WindowView; friend class ComboBoxComplex; friend class WindowCompositor; }; } #endif // FLOATINGWINDOW_H nux-4.0.8+18.10.20180623/Nux/GeisAdapter.cpp0000644000000000000000000004106113313373365014251 0ustar /* * Copyright 2012 Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada * */ #include #include #include "GeisAdapter.h" #define GEIS_CLASS_UNREF(c) if (c) {geis_gesture_class_unref(c); c = nullptr;} using namespace nux; DECLARE_LOGGER(logger, "nux.geisadapter"); namespace { struct GeisAdapterEventSource { GSource source; GPollFD event_poll_fd; }; static gboolean geis_source_prepare(GSource * /* source */, gint *timeout) { *timeout = -1; return FALSE; } static gboolean geis_source_check(GSource *source) { gboolean retval; GeisAdapterEventSource *event_source = reinterpret_cast(source); if ((event_source->event_poll_fd.revents & G_IO_IN)) { retval = TRUE; } else { retval = FALSE; } return retval; } gboolean geis_source_dispatch(GSource * /* source */, GSourceFunc /* callback */, gpointer user_data) { GeisAdapter *geis_adapter = NUX_STATIC_CAST(GeisAdapter*, user_data); geis_adapter->ProcessGeisEvents(); return TRUE; } static GSourceFuncs geis_source_funcs = { geis_source_prepare, geis_source_check, geis_source_dispatch, NULL, NULL, NULL }; } GeisAdapter::GeisAdapter() : geis_(nullptr) , class_drag_(nullptr) , class_pinch_(nullptr) , class_rotate_(nullptr) , class_tap_(nullptr) , class_touch_(nullptr) , is_init_complete_(false) { geis_ = geis_new(GEIS_INIT_NO_ATOMIC_GESTURES, GEIS_INIT_GRAIL_BACKEND, nullptr); if (!geis_) { LOG_WARNING(logger) << "Couldn't create a Geis instance." " Multitouch gesture support disabled."; } } GeisAdapter::~GeisAdapter() { GEIS_CLASS_UNREF(class_drag_) GEIS_CLASS_UNREF(class_pinch_) GEIS_CLASS_UNREF(class_rotate_) GEIS_CLASS_UNREF(class_tap_) GEIS_CLASS_UNREF(class_touch_) geis_delete(geis_); g_source_remove_by_funcs_user_data(&geis_source_funcs, this); } void GeisAdapter::CreateGSource(GMainContext *context) { GSource *source = g_source_new(&geis_source_funcs, sizeof(GeisAdapterEventSource)); GeisAdapterEventSource *event_source = reinterpret_cast(source); g_source_set_priority(source, G_PRIORITY_DEFAULT); GeisStatus status = geis_get_configuration(geis_, GEIS_CONFIGURATION_FD, &event_source->event_poll_fd.fd); if (status != GEIS_STATUS_SUCCESS) { LOG_WARNING(logger) << "Failed to get geis file descriptor." " Multitouch gesture support disabled."; g_source_destroy(source); return; } event_source->event_poll_fd.events = G_IO_IN; g_source_add_poll(source, &event_source->event_poll_fd); g_source_set_callback(source, 0, this, 0); g_source_attach(source, context); } void GeisAdapter::ProcessGeisEvents() { GeisEvent event = nullptr; GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR; GestureEvent nux_event; status = geis_dispatch_events(geis_); if (status != GEIS_STATUS_SUCCESS) { LOG_WARNING(logger) << "Failed to dispatch events! Status: " << status; } status = geis_next_event(geis_, &event); if (status != GEIS_STATUS_SUCCESS && status != GEIS_STATUS_CONTINUE && status != GEIS_STATUS_EMPTY) { LOG_WARNING(logger) << "Failed to get next event! Status: " << status; } while (status == GEIS_STATUS_CONTINUE || status == GEIS_STATUS_SUCCESS) { switch (geis_event_type(event)) { case GEIS_EVENT_GESTURE_BEGIN: FillNuxEvent(nux_event, event, EVENT_GESTURE_BEGIN); event_ready.emit(nux_event); break; case GEIS_EVENT_GESTURE_UPDATE: FillNuxEvent(nux_event, event, EVENT_GESTURE_UPDATE); if (nux_event.GetGestureClasses() == TAP_GESTURE) { // Geis sends a single Update event for a tap gesture and nothing more, // but it's better to be consistent with the rule that all gestures // must begin and end (with any number of updates in between). // Otherwise code in upper layers will have to add special cases just // for the tap gesture. nuxAssert(!pending_next_event_); SplitUpdateIntoBeginAndEnd(nux_event); nuxAssert(pending_next_event_); event_ready.emit(nux_event); event_ready.emit(*pending_next_event_); pending_next_event_.reset(); } else event_ready.emit(nux_event); break; case GEIS_EVENT_GESTURE_END: FillNuxEvent(nux_event, event, EVENT_GESTURE_END); event_ready.emit(nux_event); break; case GEIS_EVENT_CLASS_AVAILABLE: this->ProcessEventClassAvailable(event); break; case GEIS_EVENT_DEVICE_AVAILABLE: this->ProcessEventDeviceAvailable(event); break; case GEIS_EVENT_DEVICE_UNAVAILABLE: this->ProcessEventDeviceUnavailable(event); break; case GEIS_EVENT_INIT_COMPLETE: this->is_init_complete_ = true; this->init_complete.emit(); break; default: break; } geis_event_delete(event); status = geis_next_event(this->geis_, &event); } } void GeisAdapter::SplitUpdateIntoBeginAndEnd(GestureEvent &nux_event) { nux_event.type = EVENT_GESTURE_BEGIN; // Work around a bug in geis. A very quick gesture (e.g. a quick tap) // will end with its is_construction_finished still set to false. // https://bugs.launchpad.net/grail/+bug/1012315 nux_event.is_construction_finished_ = true; pending_next_event_.reset(new GestureEvent); *pending_next_event_ = nux_event; pending_next_event_->type = EVENT_GESTURE_END; } bool GeisAdapter::ProcessNextEvent(GestureEvent *nux_event) { if (pending_next_event_) { *nux_event = *pending_next_event_; pending_next_event_.reset(); return true; } GeisEvent event = nullptr; GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR; bool filled_nux_event = false; status = geis_dispatch_events(geis_); if (status != GEIS_STATUS_SUCCESS) { LOG_WARNING(logger) << "Failed to dispatch events! Status: " << status; } status = geis_next_event(geis_, &event); if (status != GEIS_STATUS_SUCCESS && status != GEIS_STATUS_CONTINUE && status != GEIS_STATUS_EMPTY) { LOG_WARNING(logger) << "Failed to get next event! Status: " << status; } if (status == GEIS_STATUS_CONTINUE || status == GEIS_STATUS_SUCCESS) { switch (geis_event_type(event)) { case GEIS_EVENT_GESTURE_BEGIN: FillNuxEvent(*nux_event, event, EVENT_GESTURE_BEGIN); filled_nux_event = true; break; case GEIS_EVENT_GESTURE_UPDATE: FillNuxEvent(*nux_event, event, EVENT_GESTURE_UPDATE); if (nux_event->GetGestureClasses() == TAP_GESTURE) { // Geis sends a single Update event for a tap gesture and nothing more, // but it's better to be consistent with the rule that all gestures // must begin and end (with any number of updates in between). // Otherwise code in upper layers will have to add special cases just // for the tap gesture. SplitUpdateIntoBeginAndEnd(*nux_event); } filled_nux_event = true; break; case GEIS_EVENT_GESTURE_END: FillNuxEvent(*nux_event, event, EVENT_GESTURE_END); filled_nux_event = true; break; case GEIS_EVENT_CLASS_AVAILABLE: this->ProcessEventClassAvailable(event); break; case GEIS_EVENT_DEVICE_AVAILABLE: this->ProcessEventDeviceAvailable(event); break; case GEIS_EVENT_DEVICE_UNAVAILABLE: this->ProcessEventDeviceUnavailable(event); break; case GEIS_EVENT_INIT_COMPLETE: this->is_init_complete_ = true; this->init_complete.emit(); break; default: break; } geis_event_delete(event); } if (!filled_nux_event) nux_event->Reset(); return filled_nux_event; } void GeisAdapter::ProcessEventDeviceAvailable(GeisEvent event) { GeisAttr attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_DEVICE); if (!attr) { LOG_WARNING(logger) << "Missing device attr in \"Device Available\" event."; return; } GeisDevice geis_device = static_cast(geis_attr_value_to_pointer(attr)); if (!geis_device) { LOG_WARNING(logger) << "\"Device Available\" event contains a null device"; return; } Device device; attr = geis_device_attr_by_name(geis_device, GEIS_DEVICE_ATTRIBUTE_DIRECT_TOUCH); if (!attr) { LOG_WARNING(logger) << "Missing \"direct touch\" attr in device."; return; } device.direct_touch = geis_attr_value_to_boolean(attr) == GEIS_TRUE; device.id = geis_device_id(geis_device); devices_[device.id] = device; } void GeisAdapter::ProcessEventDeviceUnavailable(GeisEvent event) { GeisAttr attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_DEVICE); if (!attr) { LOG_WARNING(logger) << "Missing device attr in \"Device Available\" event."; return; } GeisDevice geis_device = static_cast(geis_attr_value_to_pointer(attr)); if (!geis_device) { LOG_WARNING(logger) << "\"Device Available\" event contains a null device"; return; } devices_.erase(geis_device_id(geis_device)); } void GeisAdapter::FillNuxEvent(GestureEvent &nux_event, GeisEvent event, EventType nux_event_type) { GeisAttr attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_GROUPSET); GeisGroupSet group_set = static_cast(geis_attr_value_to_pointer(attr)); /* I expect only one group. */ if (geis_groupset_group_count(group_set) != 1) { LOG_WARNING(logger) << "Received a gesture event with " << geis_groupset_group_count(group_set) << " groups"; return; } GeisGroup group = geis_groupset_group(group_set, 0); /* I expect only one frame. */ if (geis_group_frame_count(group) != 1) { LOG_WARNING(logger) << "Received a gesture event with a group containing " << geis_group_frame_count(group) << " frames"; return; } nux_event.Reset(); nux_event.type = nux_event_type; nux_event.geis_ = geis_; nux_event.geis_group_ = group; GeisFrame frame = geis_group_frame(group, 0); FillNuxEventGestureAttributes(nux_event, frame); attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_CONSTRUCTION_FINISHED); nux_event.is_construction_finished_ = geis_attr_value_to_boolean(attr) == GEIS_TRUE; attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_TOUCHSET); GeisTouchSet touch_set = static_cast(geis_attr_value_to_pointer(attr)); FillNuxEventTouches(nux_event, touch_set); // OBS: A gesture may belong to more than one gesture class if (class_drag_ && geis_frame_is_class(frame, class_drag_)) { nux_event.gesture_classes_ |= DRAG_GESTURE; } if (class_pinch_ && geis_frame_is_class(frame, class_pinch_)) { nux_event.gesture_classes_ |= PINCH_GESTURE; } if (class_rotate_ && geis_frame_is_class(frame, class_rotate_)) { nux_event.gesture_classes_ |= ROTATE_GESTURE; } if (class_tap_ && geis_frame_is_class(frame, class_tap_)) { nux_event.gesture_classes_ |= TAP_GESTURE; } if (class_touch_ && geis_frame_is_class(frame, class_touch_)) { nux_event.gesture_classes_ |= TOUCH_GESTURE; } // Work around a bug in geis. A very quick gesture (e.g. a quick tap) // will end with its is_construction_finished still set to false. // https://bugs.launchpad.net/grail/+bug/1012315 if (nux_event_type == EVENT_GESTURE_END) nux_event.is_construction_finished_ = true; } void GeisAdapter::FillNuxEventGestureAttributes(GestureEvent &nux_event, GeisFrame frame) { GeisSize attr_count = geis_frame_attr_count(frame); GeisAttr attr = 0; nux_event.gesture_id_ = geis_frame_id(frame); // Idea: use a hash mapping string attribute names to their correponding // addresses in the GestureEvent class. for (GeisSize i = 0; i < attr_count; ++i) { attr = geis_frame_attr(frame, i); if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_DEVICE_ID)) { int device_id = geis_attr_value_to_integer(attr); nux_event.is_direct_touch_ = devices_[device_id].direct_touch; } else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_TIMESTAMP)) nux_event.timestamp_ = geis_attr_value_to_integer(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_FOCUS_X)) nux_event.focus_.x = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_FOCUS_Y)) nux_event.focus_.y = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_DELTA_X)) nux_event.delta_.x = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_DELTA_Y)) nux_event.delta_.y = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_ANGLE)) nux_event.angle_ = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_ANGLE_DELTA)) nux_event.angle_delta_ = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_ANGULAR_VELOCITY)) nux_event.angular_velocity_ = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_TAP_TIME)) nux_event.tap_duration_ = geis_attr_value_to_integer(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_VELOCITY_X)) nux_event.velocity_.x = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_VELOCITY_Y)) nux_event.velocity_.y = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_RADIUS)) nux_event.radius_ = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_RADIUS_DELTA)) nux_event.radius_delta_ = geis_attr_value_to_float(attr); else if (g_str_equal(geis_attr_name(attr), GEIS_GESTURE_ATTRIBUTE_RADIAL_VELOCITY)) nux_event.radial_velocity_ = geis_attr_value_to_float(attr); } } void GeisAdapter::FillNuxEventTouches(GestureEvent &nux_event, GeisTouchSet touch_set) { GeisSize count = geis_touchset_touch_count(touch_set); TouchPoint point; for (GeisSize i = 0; i < count; ++i) { GeisTouch geis_touch = geis_touchset_touch(touch_set, i); point.id = geis_attr_value_to_integer( geis_touch_attr_by_name(geis_touch, GEIS_TOUCH_ATTRIBUTE_ID)); point.x = geis_attr_value_to_float( geis_touch_attr_by_name(geis_touch, GEIS_TOUCH_ATTRIBUTE_X)); point.y = geis_attr_value_to_float( geis_touch_attr_by_name(geis_touch, GEIS_TOUCH_ATTRIBUTE_Y)); nux_event.touches_.push_back(point); } } void GeisAdapter::ProcessEventClassAvailable(GeisEvent event) { GeisGestureClass gesture_class; GeisAttr attr; attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_CLASS); gesture_class = static_cast(geis_attr_value_to_pointer(attr)); if (strcmp(GEIS_GESTURE_DRAG, geis_gesture_class_name(gesture_class)) == 0) { class_drag_ = gesture_class; geis_gesture_class_ref(gesture_class); } else if (strcmp(GEIS_GESTURE_PINCH, geis_gesture_class_name(gesture_class)) == 0) { class_pinch_ = gesture_class; geis_gesture_class_ref(gesture_class); } else if (strcmp(GEIS_GESTURE_ROTATE, geis_gesture_class_name(gesture_class)) == 0) { class_rotate_ = gesture_class; geis_gesture_class_ref(gesture_class); } else if (strcmp(GEIS_GESTURE_TAP, geis_gesture_class_name(gesture_class)) == 0) { class_tap_ = gesture_class; geis_gesture_class_ref(gesture_class); } else if (strcmp(GEIS_GESTURE_TOUCH, geis_gesture_class_name(gesture_class)) == 0) { class_touch_ = gesture_class; geis_gesture_class_ref(gesture_class); } } nux-4.0.8+18.10.20180623/Nux/GeisAdapter.h0000644000000000000000000000615713313373365013725 0ustar /* * Copyright 2012 Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada * */ #ifndef GEISADAPTER_H #define GEISADAPTER_H #include "Nux/Features.h" #ifdef NUX_GESTURES_SUPPORT #include #include #include #include #include #include "NuxGraphics/GestureEvent.h" namespace nux { /*! This class translates events from geis into native nux::GestureEvents */ class GeisAdapter : public sigc::trackable { public: GeisAdapter(); ~GeisAdapter(); void CreateGSource(GMainContext *context); /* Returns whether initialization is complete. See also: signal init_complete() */ bool IsInitComplete() const {return is_init_complete_;} /* Initialization has finished. Subscriptions can now be filtered and activated. */ sigc::signal init_complete; //! Emitted when a new GestureEvent is ready to be processed sigc::signal event_ready; Geis GetGeisInstance() const {return geis_;} void ProcessGeisEvents(); //! Processes the next pending Geis event, which may yield a GestureEvent /*! Returns true if GestureEvent was filled and false otherwise. */ bool ProcessNextEvent(GestureEvent *event); private: class Device { public: int id; bool direct_touch; }; void ProcessEventDeviceAvailable(GeisEvent event); void ProcessEventDeviceUnavailable(GeisEvent event); void ProcessEventClassAvailable(GeisEvent event); void FillNuxEvent(GestureEvent &nux_event, GeisEvent event, EventType nux_event_type); void FillNuxEventGestureAttributes(GestureEvent &nux_event, GeisFrame frame); void FillNuxEventTouches(GestureEvent &nux_event, GeisTouchSet touch_set); void SplitUpdateIntoBeginAndEnd(GestureEvent &nux_event); Geis geis_; GeisGestureClass class_drag_; GeisGestureClass class_pinch_; GeisGestureClass class_rotate_; GeisGestureClass class_tap_; GeisGestureClass class_touch_; bool is_init_complete_; /* maps a device id to its corresponding device */ std::map devices_; /* Sometimes a single GeisEvent can yield two GestureEvents. When that happens, that second GestureEvent will be temporarily held here until it's consumed. */ std::unique_ptr pending_next_event_; friend class GeisAdapterTest; }; } // namespace nux #endif // NUX_GESTURES_SUPPORT #endif // GEISADAPTER_H nux-4.0.8+18.10.20180623/Nux/Gesture.cpp0000644000000000000000000001740013313373365013477 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #include "Gesture.h" #include "Nux/InputArea.h" using namespace nux; /***************************************************************************** * InputAreaTarget *****************************************************************************/ InputAreaTarget::InputAreaTarget(InputArea *input_area) : input_area_(input_area) { } GestureDeliveryRequest InputAreaTarget::GestureEvent(const nux::GestureEvent &event) { if (input_area_.IsValid()) return input_area_->GestureEvent(event); else return GestureDeliveryRequest::NONE; } bool InputAreaTarget::Equals(const GestureTarget& other) const { const InputAreaTarget *input_area_target = dynamic_cast(&other); if (input_area_target) { return input_area_ == input_area_target->input_area_; } else { return false; } } /***************************************************************************** * Gesture *****************************************************************************/ Gesture::Gesture(const nux::GestureEvent &event) : event_delivery_enabled_(false), acceptance_status_(AcceptanceStatus::UNDECIDED) { queued_events_.reserve(20); queued_events_.push_back(event); } void Gesture::AddTarget(ShPtGestureTarget target) { target_died_connections_[target] = target->died.connect(sigc::mem_fun (this, &Gesture::RemoveTarget)); target_list_.push_back(target); } void Gesture::RemoveTarget(const GestureTarget &target) { auto check_same_target = [&](const ShPtGestureTarget& other_target) { return *other_target == target; }; auto target_iterator = std::find_if(target_list_.begin(), target_list_.end(), check_same_target); if (target_iterator != target_list_.end()) { auto connection_iterator = target_died_connections_.find(*target_iterator); if (connection_iterator != target_died_connections_.end()) connection_iterator->second.disconnect(); target_list_.erase(target_iterator); } if (target_list_.empty()) { /* Reject this gesture if we can no longer accept it */ if (GetAcceptanceStatus() == Gesture::AcceptanceStatus::UNDECIDED) Reject (); lost_all_targets.emit (*this); } } void Gesture::EnableEventDelivery() { if (event_delivery_enabled_) return; event_delivery_enabled_ = true; if (queued_events_.empty()) return; // Deliver all queued events but keep the last one last_event_ = queued_events_[queued_events_.size()-1]; for (auto event : queued_events_) { DeliverEvent(event); } queued_events_.clear(); } void Gesture::Update(const nux::GestureEvent& event) { if (event_delivery_enabled_) { DeliverEvent(event); last_event_ = event; } else { queued_events_.push_back(event); } } void Gesture::DeliverEvent(const GestureEvent &event) { auto it = target_list_.begin(); while (it != target_list_.end()) { GestureDeliveryRequest request = (*it)->GestureEvent(event); switch(request) { case GestureDeliveryRequest::EXCLUSIVITY: ExecuteTargetExclusivityRequest(event, it); break; default: // NONE ++it; } } } void Gesture::ExecuteTargetExclusivityRequest(const GestureEvent &event, std::list::iterator &it_requestor) { // Don't send gesture lost events for a gesture begin. // Targets can't lose a gesture they never knew about. if (event.type != EVENT_GESTURE_BEGIN) { GestureEvent event_lost = event; event_lost.type = EVENT_GESTURE_LOST; auto other_it = target_list_.rbegin(); while (*other_it != *it_requestor) { (*other_it)->GestureEvent(event_lost); ++other_it; } } ++it_requestor; target_list_.erase(it_requestor, target_list_.end()); it_requestor = target_list_.end(); } nux::GestureEvent &Gesture::GetLatestEvent() { if (event_delivery_enabled_) { nuxAssert(queued_events_.size() == 0); return last_event_; } else { nuxAssert(queued_events_.size() > 0); return queued_events_[queued_events_.size()-1]; } } const nux::GestureEvent &Gesture::GetLatestEvent() const { if (event_delivery_enabled_) { nuxAssert(queued_events_.size() == 0); return last_event_; } else { nuxAssert(queued_events_.size() > 0); return queued_events_[queued_events_.size()-1]; } } bool Gesture::IsConstructionFinished() const { return GetLatestEvent().IsConstructionFinished(); } int Gesture::GetId() const { return GetLatestEvent().GetGestureId(); } const std::vector &Gesture::GetTouches() const { return GetLatestEvent().GetTouches(); } bool Gesture::HasTouchesInCommon( const std::shared_ptr &other_gesture) const { const std::vector &my_touches = GetTouches(); const std::vector &other_touches = other_gesture->GetTouches(); for (const auto other_touch : other_touches) { for (const auto my_touch : my_touches) { if (other_touch == my_touch) return true; } } return false; } void Gesture::Reject() { g_assert(acceptance_status_ == AcceptanceStatus::UNDECIDED); GetLatestEvent().Reject(); acceptance_status_ = AcceptanceStatus::REJECTED; } void Gesture::Accept() { g_assert(acceptance_status_ == AcceptanceStatus::UNDECIDED); GetLatestEvent().Accept(); acceptance_status_ = AcceptanceStatus::ACCEPTED; } /***************************************************************************** * GestureSet *****************************************************************************/ void GestureSet::Add(Gesture *gesture) { map_id_to_gesture_[gesture->GetId()] = std::shared_ptr(gesture); } void GestureSet::Add(std::shared_ptr &gesture) { map_id_to_gesture_[gesture->GetId()] = gesture; } std::shared_ptr GestureSet::FindFromGestureId(int gesture_id) { std::map >::iterator it = map_id_to_gesture_.find(gesture_id); if (it != map_id_to_gesture_.end()) return it->second; else return std::shared_ptr(); } std::shared_ptr GestureSet::FindFromTarget(ShPtGestureTarget wanted_target) { for (auto it : map_id_to_gesture_) { std::shared_ptr &gesture = it.second; const std::list &target_list = gesture->GetTargetList(); for (auto target : target_list) { if (*target == *wanted_target) return gesture; } } return nullptr; } std::vector< std::shared_ptr > GestureSet::GetConflictingGestures(std::shared_ptr &gesture) { std::vector< std::shared_ptr > conflicting_gestures; for (auto it : map_id_to_gesture_) { std::shared_ptr &other_gesture = it.second; if (other_gesture == gesture) continue; if (other_gesture->HasTouchesInCommon(gesture)) conflicting_gestures.push_back(other_gesture); } return conflicting_gestures; } void GestureSet::Remove(const Gesture &gesture) { map_id_to_gesture_.erase(gesture.GetId()); } nux-4.0.8+18.10.20180623/Nux/Gesture.h0000644000000000000000000001304513313373365013145 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_GESTURE_H #define NUX_GESTURE_H #include "Nux/Features.h" #ifdef NUX_GESTURES_SUPPORT #include #include "NuxGraphics/GestureEvent.h" /* A collection of helper classes used by WindowCompositor for the task of delivering GestureEvents to their correct target InputAreas and in the decision of whether a gesture should be accepted or rejected. */ namespace nux { class InputArea; /* Interface for gesture targets. */ class GestureTarget { public: /*! Called whenever there's a new gesture event for this target. \param event GestureEvent to be processed by the target. \return A request about the delivery of events for the related gesture. */ virtual GestureDeliveryRequest GestureEvent(const GestureEvent &event) = 0; bool operator ==(const GestureTarget& other) const { return Equals(other); } /*** * We might not have ownership of every single object that we create * implementations of GestureTarget's to wrap around so this signal * indicates to the owner of the GestureTarget that the underlying * object is no longer available, and this target should be removed */ sigc::signal died; private: /*! For some types of target, different instances may wrap the same actual target, in which case reimplementing this method is necessary. */ virtual bool Equals(const GestureTarget& other) const { return this == &other; } }; typedef std::shared_ptr ShPtGestureTarget; class InputAreaTarget : public GestureTarget { public: InputAreaTarget(InputArea *input_area); virtual GestureDeliveryRequest GestureEvent(const nux::GestureEvent &event); private: virtual bool Equals(const GestureTarget& other) const; ObjectWeakPtr input_area_; }; //! A class that relates a multitouch gesture to its target entity /*! It relates a gesture to its target, which can be either a window or unity. It's fed with GestureEvents via Update(). It stores those GestureEvents in a queue until EnableEventDelivery() is called, when all queued events are finally acted upon. After that, further events fed via Update() will have an immediate effect over its target instead of being queued. */ class Gesture { public: Gesture(const GestureEvent &event); void AddTarget(ShPtGestureTarget target); void RemoveTarget(const GestureTarget &target); const std::list &GetTargetList() const {return target_list_;} void EnableEventDelivery(); void Update(const GestureEvent& event); bool IsConstructionFinished() const; bool IsDeliveringEvents() const {return event_delivery_enabled_;} int GetId() const; const std::vector &GetTouches() const; //! Returns whether the given gesture has any touches in common with this one. bool HasTouchesInCommon(const std::shared_ptr &other_gesture) const; //! Rejects the gesture. /* After rejection a gesture is no longer valid */ void Reject(); //! Accepts the gesture void Accept(); enum class AcceptanceStatus { UNDECIDED, ACCEPTED, REJECTED }; AcceptanceStatus GetAcceptanceStatus() const {return acceptance_status_;} /*** * This signal is emitted when a Gesture loses all of its targets and * can no longer be delivered to anything. This might provide a hint * to the owner to stop tracking the gesture */ sigc::signal lost_all_targets; private: const GestureEvent &GetLatestEvent() const; GestureEvent &GetLatestEvent(); void DeliverEvent(const GestureEvent &event); void ExecuteTargetExclusivityRequest(const GestureEvent &event, std::list::iterator &it_requestor); std::list target_list_; std::map target_died_connections_; // events that are waiting to be delivered std::vector queued_events_; // last event delivered GestureEvent last_event_; bool event_delivery_enabled_; AcceptanceStatus acceptance_status_; }; /* Stores information on all curently active gestures. */ class GestureSet { public: void Add(Gesture *gesture); void Add(std::shared_ptr &gesture); std::shared_ptr FindFromGestureId(int gesture_id); std::shared_ptr FindFromTarget(ShPtGestureTarget target); void Remove(const Gesture &gesture); std::vector< std::shared_ptr > GetConflictingGestures(std::shared_ptr &gesture); private: std::map > map_id_to_gesture_; }; } // namespace nux #endif // NUX_GESTURES_SUPPORT #endif // NUX_GESTURE_H nux-4.0.8+18.10.20180623/Nux/GestureBroker.cpp0000644000000000000000000001314713313373365014650 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #include "GestureBroker.h" #include "Gesture.h" using namespace nux; GestureBroker::GestureBroker() { } GestureBroker::~GestureBroker() { } void GestureBroker::ProcessGestureBegin(nux::GestureEvent &event) { std::vector target_list = FindGestureTargets(event); bool gesture_bound_to_target = false; for (auto target : target_list) { bool ok = BindNewGestureToTarget(event, target); gesture_bound_to_target |= ok; } if (!gesture_bound_to_target) event.Reject(); } bool GestureBroker::BindNewGestureToTarget(nux::GestureEvent &event, ShPtGestureTarget target) { bool successful; std::shared_ptr existing_gesture = gesture_set_.FindFromTarget(target); auto create_gesture_for_target = [&]() { std::shared_ptr gesture = gesture_set_.FindFromGestureId(event.GetGestureId()); if (!gesture) { gesture = std::shared_ptr(new Gesture(event)); gesture_lost_all_targets_connections_[gesture] = gesture->lost_all_targets.connect(sigc::mem_fun (&gesture_set_, &GestureSet::Remove)); } gesture->AddTarget(target); gesture_set_.Add(gesture); if (event.IsConstructionFinished()) { gesture->Accept(); gesture->EnableEventDelivery(); } }; if (existing_gesture) { // There's a conflict here. // The target for this new gesture already has a gesture. if (existing_gesture->IsDeliveringEvents()) { // A target can have only one gesture at a time. successful = false; } else { // Since the existing gesture hasn't been delivered to the target yet, // we can choose which will continue. // The rule is that the gesture with the most touches has precedence over // the other. int existing_num_touches = existing_gesture->GetTouches().size(); int new_num_touches = event.GetTouches().size(); if (new_num_touches < existing_num_touches) { successful = false; } else if (new_num_touches == existing_num_touches) { // It means that there are more fingers on the target area // than the target area can handle // (i.e. three fingers over an area that handles only two-fingers' // gestures) existing_gesture->RemoveTarget(*target); successful = false; } else // new_num_touches > existing_num_touches { existing_gesture->RemoveTarget(*target); create_gesture_for_target(); successful = true; } } } else { create_gesture_for_target(); successful = true; } return successful; } void GestureBroker::ProcessGestureUpdate(nux::GestureEvent &event) { std::shared_ptr gesture = gesture_set_.FindFromGestureId(event.GetGestureId()); if (!gesture) { return; } if (event.IsConstructionFinished() && !gesture->IsConstructionFinished()) { // This is the first update for this gesture signaling that // its construction has finished. gesture->Update(event); ResolveBufferedGestureThatFinishedConstruction(gesture); } else { gesture->Update(event); } } void GestureBroker::ProcessGestureEnd(nux::GestureEvent &event) { std::shared_ptr gesture = gesture_set_.FindFromGestureId(event.GetGestureId()); if (!gesture) return; if (event.IsConstructionFinished() && !gesture->IsConstructionFinished()) { // This is the first update for this gesture signaling that // its construction has finished. gesture->Update(event); ResolveBufferedGestureThatFinishedConstruction(gesture); } else { gesture->Update(event); } // We no longer have to keep track of it. auto connection_iterator = gesture_lost_all_targets_connections_.find(gesture); if (connection_iterator != gesture_lost_all_targets_connections_.end()) connection_iterator->second.disconnect(); gesture_set_.Remove(*gesture); // We cannot leave a gesture behing without making a decision on its acceptance. if (gesture->GetAcceptanceStatus() == Gesture::AcceptanceStatus::UNDECIDED) { // This will likely only happen if a geture is ending with its construction unfinished, // which is an odd situation, but just in case... gesture->Reject(); } } void GestureBroker::ResolveBufferedGestureThatFinishedConstruction( std::shared_ptr &gesture) { gesture->Accept(); gesture->EnableEventDelivery(); // will flush all queued events std::vector< std::shared_ptr > conflicting_gestures = gesture_set_.GetConflictingGestures(gesture); if (!conflicting_gestures.empty()) { // That shouldn't happen. All conflicting gestures should have been // dealt with when they begun. for (auto conflicting_gesture : conflicting_gestures) { conflicting_gesture->Reject(); gesture_set_.Remove(*conflicting_gesture); } } } nux-4.0.8+18.10.20180623/Nux/GestureBroker.h0000644000000000000000000000360313313373365014311 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_GESTURE_BROKER_H #define NUX_GESTURE_BROKER_H #include "Nux/Features.h" #ifdef NUX_GESTURES_SUPPORT #include #include "Gesture.h" namespace nux { /*! Receives GestureEvents and delivers them to the appropriate gesture targets. */ class GestureBroker : public sigc::trackable { public: GestureBroker(); virtual ~GestureBroker(); void ProcessGestureBegin(nux::GestureEvent &event); void ProcessGestureUpdate(nux::GestureEvent &event); void ProcessGestureEnd(nux::GestureEvent &event); private: bool BindNewGestureToTarget(nux::GestureEvent &event, ShPtGestureTarget target); void ResolveBufferedGestureThatFinishedConstruction( std::shared_ptr &gesture); /*! Finds the targets of the gesture from the given gesture event. */ std::vector virtual FindGestureTargets(const nux::GestureEvent &event) = 0; GestureSet gesture_set_; std::map , sigc::connection> gesture_lost_all_targets_connections_; }; } // namespace nux #endif // NUX_GESTURES_SUPPORT #endif // NUX_GESTURE_BROKER_H nux-4.0.8+18.10.20180623/Nux/GesturesSubscription.cpp0000644000000000000000000002453713313373365016300 0ustar /* * Copyright 2012 Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada * */ #include "GesturesSubscription.h" #include "Nux.h" #include "NuxCore/Logger.h" #include "Nux/GeisAdapter.h" namespace nux { DECLARE_LOGGER(logger, "nux.gestures_subscription"); GesturesSubscription::GesturesSubscription() : gesture_classes_(DRAG_GESTURE|PINCH_GESTURE|ROTATE_GESTURE), num_touches_(2), #if defined(USE_X11) window_id_(GetWindowThread()->GetGraphicsDisplay().GetWindowHandle()), #else window_id_(0), #endif sub_(nullptr), is_active_(false), drag_threshold_(0.0026f), drag_timeout_(0), pinch_threshold_(1.1f), pinch_timeout_(0), rotate_threshold_(2.0f*3.1415926f/50.0f), rotate_timeout_(0), tap_threshold_(0.0026f), tap_timeout_(300) { } GesturesSubscription::~GesturesSubscription() { if (sub_) geis_subscription_delete(sub_); } void GesturesSubscription::Activate() { if (is_active_) return; is_active_ = true; if (sub_) { GeisStatus status = geis_subscription_activate(sub_); if (status != GEIS_STATUS_SUCCESS) { LOG_ERROR(logger) << "Failed to activate Geis subscription."; } // configuration only works on active subscription (should be fixed in geis) ConfigureGeisSubscription(); } else { CreateGeisSubscriptionWhenPossible(); } } void GesturesSubscription::Deactivate() { if (!is_active_) return; is_active_ = false; if (sub_) { GeisStatus status = geis_subscription_deactivate(sub_); if (status != GEIS_STATUS_SUCCESS) { LOG_ERROR(logger) << "Failed to deactivate Geis subscription."; } } } void GesturesSubscription::SetGestureClasses(int gesture_classes) { SetProperty(gesture_classes_, gesture_classes); #define NUX_ALL_GESTURES (DRAG_GESTURE|PINCH_GESTURE|TAP_GESTURE|TOUCH_GESTURE); unwanted_gesture_classes_ = ~gesture_classes & NUX_ALL_GESTURES; #undef NUX_ALL_GESTURES } void GesturesSubscription::SetNumTouches(unsigned int num_touches) { SetProperty(num_touches_, num_touches); } void GesturesSubscription::SetWindowId(int window_id) { SetProperty(window_id_, window_id); } void GesturesSubscription::SetRecognitionThreshold(GestureClass gesture_class, float threshold) { if (threshold < 0.0f) return; switch(gesture_class) { case DRAG_GESTURE: SetProperty(drag_threshold_, threshold); break; case PINCH_GESTURE: SetProperty(pinch_threshold_, threshold); break; case TAP_GESTURE: SetProperty(tap_threshold_, threshold); break; case ROTATE_GESTURE: SetProperty(rotate_threshold_, threshold); break; default: break; } } void GesturesSubscription::SetRecognitionTimeout(GestureClass gesture_class, int timeout) { if (timeout < 0) return; switch(gesture_class) { case DRAG_GESTURE: SetProperty(drag_timeout_, timeout); break; case PINCH_GESTURE: SetProperty(pinch_timeout_, timeout); break; case TAP_GESTURE: SetProperty(tap_timeout_, timeout); break; case ROTATE_GESTURE: SetProperty(rotate_timeout_, timeout); break; default: break; } } std::vector GesturesSubscription::CreateGeisGestureClasses() { std::vector geis_gesture_classes; #define ADD_GESTURE(name) \ if (gesture_classes_ & name##_GESTURE) \ geis_gesture_classes.push_back(GEIS_GESTURE_##name); ADD_GESTURE(DRAG) ADD_GESTURE(PINCH) ADD_GESTURE(ROTATE) ADD_GESTURE(TAP) ADD_GESTURE(TOUCH) #undef ADD_GESTURE return geis_gesture_classes; } GeisStatus GesturesSubscription::AddGestureClassAndNumTouchesTerm(GeisFilter filter) { GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR; std::vector geis_gesture_classes = CreateGeisGestureClasses(); switch (geis_gesture_classes.size()) { case 1: status = geis_filter_add_term(filter, GEIS_FILTER_CLASS, GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[0], GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_EQ, num_touches_, nullptr); break; case 2: status = geis_filter_add_term(filter, GEIS_FILTER_CLASS, GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[0], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[1], GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_EQ, num_touches_, nullptr); break; case 3: status = geis_filter_add_term(filter, GEIS_FILTER_CLASS, GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[0], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[1], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[2], GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_EQ, num_touches_, nullptr); break; case 4: status = geis_filter_add_term(filter, GEIS_FILTER_CLASS, GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[0], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[1], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[2], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[3], GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_EQ, num_touches_, nullptr); break; case 5: status = geis_filter_add_term(filter, GEIS_FILTER_CLASS, GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[0], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[1], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[2], GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, geis_gesture_classes[4], GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_EQ, num_touches_, nullptr); break; default: status = geis_filter_add_term(filter, GEIS_FILTER_CLASS, GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_EQ, num_touches_, nullptr); break; } return status; } void GesturesSubscription::CreateGeisSubscription() { GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR; GeisFilter filter = nullptr; Geis geis = GetWindowThread()->GetGeisAdapter()->GetGeisInstance(); sub_ = geis_subscription_new(geis, "nux", GEIS_SUBSCRIPTION_NONE); if (!sub_) { LOG_ERROR(logger) << "Failed to create Geis subscription."; goto cleanup; } filter = geis_filter_new(geis, "filter"); if (!filter) { LOG_ERROR(logger) << "Failed to create Geis filter."; goto cleanup; } status = AddGestureClassAndNumTouchesTerm(filter); if (status != GEIS_STATUS_SUCCESS) { LOG_ERROR(logger) << "Failed to add gesture term to Geis filter."; goto cleanup; } status = geis_filter_add_term(filter, GEIS_FILTER_REGION, GEIS_REGION_ATTRIBUTE_WINDOWID, GEIS_FILTER_OP_EQ, window_id_, nullptr); if (status != GEIS_STATUS_SUCCESS) { LOG_ERROR(logger) << "Failed to add region term to Geis filter."; goto cleanup; } status = geis_subscription_add_filter(sub_, filter); if (status != GEIS_STATUS_SUCCESS) { LOG_ERROR(logger) << "Failed to add filter to subscription."; goto cleanup; } filter = nullptr; // it now belongs to the subscription if (is_active_) { status = geis_subscription_activate(sub_); if (status != GEIS_STATUS_SUCCESS) { LOG_ERROR(logger) << "Failed to activate Geis subscription."; goto cleanup; } // configuration only works on active subscription (should be fixed in geis) ConfigureGeisSubscription(); } cleanup: if (status != GEIS_STATUS_SUCCESS) { geis_filter_delete(filter); geis_subscription_delete(sub_); sub_ = nullptr; } } void GesturesSubscription::CreateGeisSubscriptionWhenPossible() { GeisAdapter *geis_adapter = GetWindowThread()->GetGeisAdapter(); if (geis_adapter->IsInitComplete()) CreateGeisSubscription(); else geis_adapter->init_complete.connect( sigc::mem_fun(this, &GesturesSubscription::CreateGeisSubscription)); } void GesturesSubscription::UpdateGeisSubscription() { nuxAssert(sub_ != nullptr); if (is_active_) geis_subscription_deactivate(sub_); geis_subscription_delete(sub_); // Recreate the subscription only once it's active again if (is_active_) CreateGeisSubscription(); } bool GesturesSubscription::MatchesGesture(const GestureEvent &event) const { if (event.GetTouches().size() != num_touches_) return false; if ((event.GetGestureClasses() & gesture_classes_) == 0) return false; if ((event.GetGestureClasses() & unwanted_gesture_classes_) != 0) return false; return true; } void GesturesSubscription::ConfigureGeisSubscription() { nuxAssert(sub_); GeisStatus status; auto setGeisConfig = [&](const char *name, GeisPointer var) { status = geis_subscription_set_configuration(sub_, name, var); if (status != GEIS_STATUS_SUCCESS) { LOG_ERROR(logger) << "Failed to set Geis subscription configuration " << name; } }; setGeisConfig(GEIS_CONFIG_DRAG_THRESHOLD, &drag_threshold_); setGeisConfig(GEIS_CONFIG_DRAG_TIMEOUT, &drag_timeout_); setGeisConfig(GEIS_CONFIG_PINCH_THRESHOLD, &pinch_threshold_); setGeisConfig(GEIS_CONFIG_PINCH_TIMEOUT, &pinch_timeout_); setGeisConfig(GEIS_CONFIG_TAP_THRESHOLD, &tap_threshold_); setGeisConfig(GEIS_CONFIG_TAP_TIMEOUT, &tap_timeout_); setGeisConfig(GEIS_CONFIG_ROTATE_THRESHOLD, &rotate_threshold_); setGeisConfig(GEIS_CONFIG_ROTATE_TIMEOUT, &rotate_timeout_); } } // namespace nux nux-4.0.8+18.10.20180623/Nux/GesturesSubscription.h0000644000000000000000000001355013313373365015736 0ustar /* * Copyright 2012 Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada * */ #ifndef NUX_GESTURES_SUBSCRIPTION_H #define NUX_GESTURES_SUBSCRIPTION_H #include "Nux/Features.h" #ifdef NUX_GESTURES_SUPPORT #include #include // For the GestureClass enumeration. #include "NuxGraphics/GestureEvent.h" namespace nux { //! Represents a subscription to multitouch gestures /*! Typical usage: GesturesSubscription *subscription = new GesturesSubscription; subscription->SetGestureClass(TAP_GESTURE); subscription->SetNumTouches(2); subscription->Activate(); */ /* Wraps all the complexity involved in directly manipulating a GeisSubscription and exposes a simpler, C++, API. */ class GesturesSubscription { public: //! Creates a new, inactive, gestures subscription GesturesSubscription(); //! Destroys this gestures subscription. virtual ~GesturesSubscription(); //! Activates the subscription void Activate(); //! Deactivates the subscription void Deactivate(); //! Returns whether the subscription is active /*! Nux only get gesture events that matches active subscriptions. Subscriptions are inactive by default. */ bool IsActive() const {return is_active_;} //! Sets the classes of gestures this subscription is interested on void SetGestureClasses(int gesture_classes); //! Returns the gesture class that this subscription is interested on /*! By default it's set to DRAG_GESTURE|PINCH_GESTURE|ROTATE_GESTURE */ int GetGestureClasses() const {return gesture_classes_;} //! The subscription will be interested in gestures with the given number of touches void SetNumTouches(unsigned int num_touches); //! Returns the number of touches that this subscription is interested on /*! By default it is set to two touches. */ unsigned int GetNumTouches() const {return num_touches_;} //! Specifies the native window from which touch events will be gathered /*! See also GetWindowId() */ void SetWindowId(int window_id); //! Returns the native window id from which touch events are gathered. /*! By default this is the same native window that Nux uses for rendering. But in cases they differ you should speficy the native window that will provide the touch events with SetWindowId(). */ int GetWindowId() const {return window_id_;} //! Sets the recognition threshold for a given gesture class /*! For the pinch gesture class, the threshold is the current radius divided by the initial radius and should be bigger than one. Its default value is 1.1. For the drag gesture class, the threshold is in meters and represents the minimum amount of movement required for a drag to be recognized. Its default value is 0.0026 For the tap gesture class, the threshold is in meters and represents the maximum amount of movement allowed for a tap to be recognized. Its default value is 0.0026 For the rotate gesture class, the threshold is in radians and represents the mimimum amout of rotation required for a rotation gesture to be recognized. Its default value is (2*PI)/50. It has no effect or meaning for the touch gesture class. */ void SetRecognitionThreshold(GestureClass gesture_class, float threshold); //! Sets the recognition timeout for a given gesture class /*! The timeout is in milliseconds. Setting 0 (zero) means that the recognition never times out. The default timeout for drag, pinch and rotate gesture classes is 0 (zero). Fot taps it's 300. It has no effect or meaning for the touch gesture class. */ void SetRecognitionTimeout(GestureClass gesture_class, int timeout); //! Returns whether the gesture from the given event matches this subscription bool MatchesGesture(const GestureEvent &event) const; private: std::vector CreateGeisGestureClasses(); GeisStatus AddGestureClassAndNumTouchesTerm(GeisFilter filter); void CreateGeisSubscription(); void CreateGeisSubscriptionWhenPossible(); void UpdateGeisSubscription(); void ConfigureGeisSubscription(); template void SetProperty(T& prop, T new_value) { if (prop == new_value) return; prop = new_value; if (sub_) UpdateGeisSubscription(); } int gesture_classes_; int unwanted_gesture_classes_; unsigned int num_touches_; int window_id_; GeisSubscription sub_; bool is_active_; float drag_threshold_; int drag_timeout_; float pinch_threshold_; int pinch_timeout_; float rotate_threshold_; int rotate_timeout_; float tap_threshold_; int tap_timeout_; }; typedef std::shared_ptr ShGesturesSubscription; } // namespace nux #endif // NUX_GESTURES_SUPPORT #endif // NUX_GESTURES_SUBSCRIPTION_H nux-4.0.8+18.10.20180623/Nux/GridHLayout.cpp0000644000000000000000000005211613313373365014257 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "View.h" #include "GridHLayout.h" #include "HLayout.h" #include "VLayout.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(GridHLayout); GridHLayout::GridHLayout(NUX_FILE_LINE_DECL) : Layout(NUX_FILE_LINE_PARAM) { #if DEBUG_LAYOUT m_h_in_margin = 10; left_padding_ = 10; right_padding_ = 10; m_v_in_margin = 10; top_padding_ = 10; bottom_padding_ = 10; #endif m_h_in_margin = 10; m_v_in_margin = 10; filling_order_ = FILL_HORIZONTAL; _children_size = Size(64, 64); _force_children_size = true; _partial_visibility = true; _num_row = 1; _num_column = 1; _dynamic_column = true; match_content_size_ = true; // Start packing the elements from the top. Is the layout has more space than the elements can use, // leave that space at the bottom of the GridHLayout. m_ContentStacking = MAJOR_POSITION_LEFT; SetMinimumSize(32, 32); } GridHLayout::~GridHLayout() { } void GridHLayout::SetSpaceBetweenChildren(int horizontal_space, int vertical_space) { m_h_in_margin = horizontal_space; m_v_in_margin = vertical_space; } int GridHLayout::GetChildPos(Area *child) { int position = 0; std::list::const_iterator it; for (it = GetChildren().begin(); it != GetChildren().end(); it++) { if ((*it) == child) break; ++position; } return position; } Area* GridHLayout::GetChildAtPosition(int pos) { int position = 0; std::list::const_iterator it; for (it = GetChildren().begin(); it != GetChildren().end(); it++) { if (position == pos) return (*it); ++position; } return NULL; } void GridHLayout::EnablePartialVisibility(bool partial_visibility) { _partial_visibility = partial_visibility; } void GridHLayout::SetChildrenSize(int width, int height) { _children_size = Size(width, height); } Size GridHLayout::GetChildrenSize() const { return _children_size; } void GridHLayout::ForceChildrenSize(bool force) { _force_children_size = force; } int GridHLayout::GetNumColumn() const { return _num_column; } int GridHLayout::GetNumRow() const { return _num_row; } void GridHLayout::MatchContentSize(bool match_content) { match_content_size_ = match_content; } bool GridHLayout::IsMatchingContentSize() const { return match_content_size_; } void GridHLayout::GetCompositeList(std::list *ViewList) { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsView()) { View *ic = static_cast(*it); ViewList->push_back(ic); } else if ((*it)->IsLayout()) { Layout *layout = static_cast(*it); layout->GetCompositeList(ViewList); } } } long GridHLayout::ComputeLayoutRowOrder() { std::list elements; if (GetScaleFactor() == 0) { ApplyMinWidth(); } if (_layout_element_list.size() == 0) { return eCompliantHeight | eCompliantWidth; } int num_elements = 0; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsVisible()) { (*it)->SetLayoutDone(false); elements.push_back(*it); num_elements++; } (*it)->SetLayoutDone(false); } int original_height = GetBaseHeight(); // The grid layout goes through the child elements and assign them a size and position. Children are filled in the grid like this: // 0 1 2 3 4 5 // 6 7 8 9 10 11 // 12 13 .. .. .. .. // This is a left to right fill going down. An option can be added the fill the grid from top to bottom and going toward the right. nux::Geometry base = GetGeometry(); it = elements.begin(); int num_row = 0; int num_column = 0; if (num_elements > 0) ++num_row; if (_dynamic_column) { int X = base.x + left_padding_; int Y = base.y + top_padding_; bool first_element_of_row = true; for (int i = 0; i < num_elements; i++) { if (num_row == 1) num_column++; if (first_element_of_row) { first_element_of_row = false; } if (_force_children_size) { (*it)->SetMinimumSize(_children_size.width, _children_size.height); } (*it)->SetGeometry(nux::Geometry(X, Y, _children_size.width, _children_size.height)); (*it)->ComputeContentSize(); X += _children_size.width + m_h_in_margin; it++; if ((!_partial_visibility) && (X + _children_size.width > base.x + base.width)) { X = base.x + left_padding_; Y += _children_size.height + m_v_in_margin; first_element_of_row = true; if (i < num_elements - 1) ++num_row; } else if (X >= base.x + base.width) { X = base.x + left_padding_; Y += _children_size.height + m_v_in_margin; first_element_of_row = true; if (i < num_elements - 1) ++num_row; } } } _num_row = num_row; _num_column = num_column; if ((GetScaleFactor() == 0) || match_content_size_) { int h = num_row * _children_size.height + (top_padding_ + bottom_padding_) + (num_row - 1) * m_v_in_margin; SetMinimumHeight(h); SetBaseHeight(h); } long size_compliance = 0L; { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: GridHLayout Width compliant = " << m_fittingWidth << std::endl; #endif size_compliance |= eCompliantWidth; } // The layout has been resized to tightly pack its content if (GetBaseHeight() > original_height) { #if DEBUG_LAYOUT_COMPUTATION // The layout has been resized larger in height to tightly pack its content. // Or you can say that the layout refuse to be smaller than total HEIGHT of its elements. std::cout << "ComputeContentSize: GridHLayout Height block at " << GetBaseHeight() << std::endl; #endif size_compliance |= eLargerHeight; // need scrollbar } else if (GetBaseHeight() < original_height) { #if DEBUG_LAYOUT_COMPUTATION // The layout is smaller. std::cout << "ComputeContentSize: GridHLayout Height is smaller = " << GetBaseHeight() << std::endl; #endif size_compliance |= eSmallerHeight; } else { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: GridHLayout Height compliant = " << GetBaseHeight() << std::endl; #endif size_compliance |= eCompliantHeight; } // if (GetScaleFactor() == 0) // { // return size_compliance | eForceComply; // } //SetDirty(false); return size_compliance; } long GridHLayout::ComputeLayoutColumnOrder() { std::list elements; if (GetScaleFactor() == 0) { ApplyMinHeight(); } if (_layout_element_list.size() == 0) { return eCompliantHeight | eCompliantWidth; } int num_elements = 0; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsVisible()) { (*it)->SetLayoutDone(false); elements.push_back(*it); num_elements++; } (*it)->SetLayoutDone(false); } int original_width = GetBaseWidth(); nux::Geometry base = GetGeometry(); it = elements.begin(); int num_row = 0; int num_column = 0; if (num_elements > 0) ++num_column; if (_dynamic_column) { int X = base.x + left_padding_; int Y = base.y + top_padding_; bool first_element_of_column = true; for (int i = 0; i < num_elements; i++) { if (num_column == 1) num_row++; if (first_element_of_column) { first_element_of_column = false; } if (_force_children_size) { (*it)->SetMinimumSize(_children_size.width, _children_size.height); } (*it)->SetGeometry(nux::Geometry(X, Y, _children_size.width, _children_size.height)); (*it)->ComputeContentSize(); Y += _children_size.height + m_v_in_margin; it++; if ((!_partial_visibility) && (Y + _children_size.height > base.y + base.height - top_padding_)) { X += _children_size.width + m_h_in_margin; Y = base.y + top_padding_; first_element_of_column = true; if (i < num_elements - 1) ++num_column; } else if (Y >= base.y + base.height) { X += _children_size.width + m_h_in_margin; Y = base.y + top_padding_; first_element_of_column = true; if (i < num_elements - 1) ++num_column; } } } _num_row = num_row; _num_column = num_column; if ((GetScaleFactor() == 0) || match_content_size_) { int w = num_column * _children_size.width + (left_padding_ + right_padding_) + (num_column - 1) * m_h_in_margin; SetMinimumWidth(w); SetBaseWidth(w); } long size_compliance = 0L; if (GetBaseWidth() > original_width) { #if DEBUG_LAYOUT_COMPUTATION // The layout has been resized larger in WIDTH to tightly pack its content. // Or you can say that the layout refuse to be smaller than total WIDTH of its elements. std::cout << "ComputeContentSize: VLayout Width block at " << GetWidth() << std::endl; #endif size_compliance |= eLargerWidth; // need scrollbar } else if (GetBaseWidth() < original_width) { #if DEBUG_LAYOUT_COMPUTATION // The layout is smaller. std::cout << "ComputeContentSize: VLayout Width smaller = " << GetWidth() << std::endl; #endif size_compliance |= eSmallerWidth; } else { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: VLayout Width compliant = " << GetWidth() << std::endl; #endif size_compliance |= eCompliantWidth; } { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: VLayout Height compliant = " << m_fittingHeight << std::endl; #endif size_compliance |= eCompliantHeight; } return size_compliance; } long GridHLayout::ComputeContentSize() { if (filling_order_ == FILL_HORIZONTAL) { return ComputeLayoutRowOrder(); } else { return ComputeLayoutColumnOrder(); } } void GridHLayout::ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw) { if (_layout_element_list.size() == 0) return; std::list elements; std::list::iterator it = _layout_element_list.begin(); graphics_engine.PushModelViewMatrix(Get2DMatrix()); Geometry base = GetGeometry(); Geometry absolute_geometry = GetAbsoluteGeometry(); Geometry parent_geometry = absolute_geometry; Geometry visibility_geometry = absolute_geometry; if (GetToplevel()) { parent_geometry = GetToplevel()->GetAbsoluteGeometry(); } visibility_geometry = parent_geometry.Intersect(absolute_geometry); graphics_engine.PushClippingRectangle(base); it = _layout_element_list.begin(); bool first = false; bool last = false; int JJ = 0; int II = 0; if (filling_order_ == FILL_HORIZONTAL) { JJ = _num_row; II = _num_column; } else { JJ = _num_column; II = _num_row; } for (int j = 0; j < JJ; j++) { for (int i = 0; i < II; i++) { if (it == _layout_element_list.end()) break; if ((*it)->IsVisible() == false) { ++it; continue; } // Test if the element is inside the Grid before rendering. if (visibility_geometry.IsIntersecting((*it)->GetAbsoluteGeometry())) { if (first == false) { first = true; // First invisible child. } int x = 0; int y = 0; if (filling_order_ == FILL_HORIZONTAL) { x = base.x + left_padding_ + i * (_children_size.width + m_h_in_margin); y = base.y + top_padding_ + j * (_children_size.height + m_v_in_margin); } else { x = base.x + left_padding_ + j * (_children_size.width + m_h_in_margin); y = base.y + top_padding_ + i * (_children_size.height + m_v_in_margin); } graphics_engine.PushClippingRectangle(Geometry(x, y, _children_size.width, _children_size.height)); if ((*it)->IsView()) { View *ic = static_cast(*it); ic->ProcessDraw(graphics_engine, force_draw); } else if ((*it)->IsLayout()) { Layout *layout = static_cast(*it); layout->ProcessDraw(graphics_engine, force_draw); } graphics_engine.PopClippingRectangle(); } else { if (first) { // First invisible child. Exit! last = true; } } if (first && last) { // Early exit break; } it++; } if (first && last) break; } graphics_engine.PopClippingRectangle(); graphics_engine.PopModelViewMatrix(); draw_cmd_queued_ = false; } Area* GridHLayout::KeyNavIterationRowOrder(KeyNavDirection direction) { if (_layout_element_list.size() == 0) return NULL; if (IsVisible() == false) return NULL; if (next_object_to_key_focus_area_) { std::list::iterator it; std::list::iterator it_next; it = std::find(_layout_element_list.begin(), _layout_element_list.end(), next_object_to_key_focus_area_); it_next = it; ++it_next; if (it == _layout_element_list.end()) { // Should never happen nuxAssert(0); return NULL; } int position = GetChildPos(*it); // note that(*it) == next_object_to_key_focus_area_ int nun_column = GetNumColumn(); int nun_row = GetNumRow(); if ((direction == KEY_NAV_LEFT) && (it == _layout_element_list.begin())) { // first item return NULL; } if ((direction == KEY_NAV_LEFT) && position % nun_column == 0) { return NULL; } if ((direction == KEY_NAV_RIGHT) && (it_next == _layout_element_list.end())) { // last item return NULL; } if ((direction == KEY_NAV_RIGHT) && position % nun_column == nun_column - 1) { // last item return NULL; } if ((direction == KEY_NAV_UP) && ((position / nun_column) == 0)) { // top edge return NULL; } if ((direction == KEY_NAV_DOWN) && ((position / nun_column) == (nun_row - 1))) { // bottom edge return NULL; } ////// if (direction == KEY_NAV_LEFT) { --it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { int pos = GetChildPos(*it); if (it == _layout_element_list.begin() || ((pos % nun_column) == 0)) break; --it; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_RIGHT) { ++it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { int pos = GetChildPos(*it); if ((it == _layout_element_list.end()) || (pos == (pos / nun_column) * nun_column + (nun_column -1))) break; ++it; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_UP) { for (int i = 0; i < nun_column; ++i) { --it; } if (it != _layout_element_list.end()) return (*it)->KeyNavIteration(direction); } if (direction == KEY_NAV_DOWN) { for (int i = 0; i < nun_column; ++i) { ++it; } if (it != _layout_element_list.end()) return (*it)->KeyNavIteration(direction); } } else { Area* area = NULL; if (direction == KEY_NAV_UP) area = GetChildAtPosition(GetNumColumn() * (GetNumRow() - 1)); else area = _layout_element_list.front(); if (area) return area->KeyNavIteration(direction); } return NULL; } Area* GridHLayout::KeyNavIterationColumnOrder(KeyNavDirection direction) { if (_layout_element_list.size() == 0) return NULL; if (IsVisible() == false) return NULL; if (next_object_to_key_focus_area_) { std::list::iterator it; std::list::iterator it_next; it = std::find(_layout_element_list.begin(), _layout_element_list.end(), next_object_to_key_focus_area_); it_next = it; ++it_next; if (it == _layout_element_list.end()) { // Should never happen nuxAssert(0); return NULL; } int position = GetChildPos(*it); // note that(*it) == next_object_to_key_focus_area_ int nun_column = GetNumColumn(); int nun_row = GetNumRow(); if ((direction == KEY_NAV_UP) && (it == _layout_element_list.begin())) { // first item return NULL; } if ((direction == KEY_NAV_DOWN) && (it_next == _layout_element_list.end())) { // last item return NULL; } if ((direction == KEY_NAV_UP) && ((position % nun_row) == 0)) { // Left edge return NULL; } if ((direction == KEY_NAV_DOWN) && (position == (position / nun_row) * nun_row + (nun_row -1))) { // right edge return NULL; } if ((direction == KEY_NAV_LEFT) && ((position / nun_row) == 0)) { // top edge return NULL; } if ((direction == KEY_NAV_RIGHT) && ((position / nun_row) == nun_column)) { // bottom edge return NULL; } ////// if (direction == KEY_NAV_UP) { --it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { int pos = GetChildPos(*it); if (it == _layout_element_list.begin() || ((pos % nun_row) == 0)) break; --it; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_DOWN) { ++it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; int pos = GetChildPos(*it); if ((it == _layout_element_list.end()) || (pos == (pos / nun_row) * nun_row + (nun_row -1))) break; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_LEFT) { for (int i = 0; i < nun_row; ++i) { --it; } return (*it)->KeyNavIteration(direction); } if (direction == KEY_NAV_RIGHT) { for (int i = 0; i < nun_row; ++i) { ++it; if (it == _layout_element_list.end()) return NULL; } return (*it)->KeyNavIteration(direction); } } else { std::list::iterator it; it = _layout_element_list.begin(); return (*it)->KeyNavIteration(direction); } return NULL; } Area* GridHLayout::KeyNavIteration(KeyNavDirection direction) { if (filling_order_ == FILL_HORIZONTAL) { return KeyNavIterationRowOrder(direction); } else { return KeyNavIterationColumnOrder(direction); } } void GridHLayout::SetFillingOrder(FillingOrder filling_order) { filling_order_ = filling_order; } GridHLayout::FillingOrder GridHLayout::GetFillingOrder() const { return filling_order_; } } nux-4.0.8+18.10.20180623/Nux/GridHLayout.h0000644000000000000000000001122613313373365013721 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef GRIDHLAYOUT_H #define GRIDHLAYOUT_H #include "Layout.h" namespace nux { //! An horizontal grid layout. /*! Fills the grid from left to right and going down. */ class GridHLayout: public Layout { // The grid layout goes through the child elements and assign them a size and position. // 0 1 2 3 4 5 // 6 7 8 9 10 11 // 12 13 .. .. .. .. // This is a left to right fill, going down. NUX_DECLARE_OBJECT_TYPE(GridHLayout, Layout); public: enum FillingOrder { FILL_HORIZONTAL, FILL_VERTICAL }; GridHLayout(NUX_FILE_LINE_PROTO); ~GridHLayout(); virtual void GetCompositeList(std::list *ViewList); //! Control the visibility of elements on the bottom edge. /*! Controls how the layout places the elements at its bottom edge. @param partial_visibility If True, the layout will position elements at its bottom edge even if they are partially visible. */ void EnablePartialVisibility(bool partial_visibility); //! Set the size of the grid element. /*! Set the size of the grid element. @param width Width of elements. @param height Height of elements. */ void SetChildrenSize(int width, int height); //! Get the size of the grid element. /*! @return Size of the grid elements. */ Size GetChildrenSize() const; //! Force the grid elements size. /*! Force the grid elements size to be the one provided by SetChildrenSize. */ void ForceChildrenSize(bool force); //! Get the number of columns in the grid. int GetNumColumn() const; //! Get the number of rows in the grid. int GetNumRow() const; //! Make the grid width match the size of its content. /*! @param match_content If True, force the height of the layout to match the height of the content. This can also be achieve if the stretch factor of this layout is set to 0; */ void MatchContentSize(bool match_content); //! Return True if the grid width match the size of its content. bool IsMatchingContentSize() const; //! Draw Element /*! Draw all elements inside the layout. If force_draw is true then the system requests that all objects redraw themselves completely. @param force_draw @param TraverseInfo @param ProcessEventInfo @return The state of the Process Event. */ virtual void ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw); void SetSpaceBetweenChildren(int horizontal_space, int vertical_space); void SetFillingOrder(FillingOrder order); FillingOrder GetFillingOrder() const; protected: long ComputeLayoutRowOrder(); long ComputeLayoutColumnOrder(); virtual long ComputeContentSize(); int GetChildPos(Area *child); Area* GetChildAtPosition(int pos); Area* KeyNavIterationRowOrder(KeyNavDirection direction); Area* KeyNavIterationColumnOrder(KeyNavDirection direction); virtual Area* KeyNavIteration(KeyNavDirection direction); FillingOrder filling_order_; int m_v_in_margin; int m_h_in_margin; private: Size _children_size; bool _dynamic_column; bool _force_children_size; bool _partial_visibility; bool match_content_size_; //!< If True, for the height of the layout to match the height of the content. int _num_row; int _num_column; // //! Compute the how elements are spread inside the layout // /*! // @param remaining_width Size that remains after subtracting elements width, inner and outer margins from the content width. // @param offset_space The space at the left of all elements. // @param element_margin The margin between elements. // */ // void ComputeStacking(int remaining_width, int &offset_space, int &element_margin); }; } #endif // GRIDHLAYOUT_H nux-4.0.8+18.10.20180623/Nux/GridVLayout.cpp0000644000000000000000000002732013313373365014274 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "View.h" #include "GridVLayout.h" #include "HLayout.h" #include "VLayout.h" namespace nux { static const int VERROR = 0; NUX_IMPLEMENT_OBJECT_TYPE(GridVLayout); GridVLayout::GridVLayout(NUX_FILE_LINE_DECL) : Layout(NUX_FILE_LINE_PARAM) { #if DEBUG_LAYOUT m_h_in_margin = 10; m_h_out_margin = 10; m_v_in_margin = 10; m_v_out_margin = 10; #endif _children_size = Size(64, 64); _force_children_size = true; _partial_visibility = true; _num_row = 1; _num_column = 1; _dynamic_column = true; _width_match_content = true; // Start packing the elements from the top. Is the layout has more space than the elements can use, // leave that space at the bottom of the GridVLayout. m_ContentStacking = eStackLeft; SetMinimumSize(32, 32); } GridVLayout::~GridVLayout() { } int GridVLayout::GetChildPos(Area *child) { int position = 0; std::list::const_iterator it; for (it = GetChildren().begin(); it != GetChildren().end(); it++) { if ((*it) == child) break; } return position; } Area* GridVLayout::GetChildAtPosition(int pos) { int position = 0; std::list::const_iterator it; for (it = GetChildren().begin(); it != GetChildren().end(); it++) { if (position == pos) return (*it); } return NULL; } void GridVLayout::EnablePartialVisibility(bool partial_visibility) { _partial_visibility = partial_visibility; } void GridVLayout::SetChildrenSize(int width, int height) { _children_size = Size(width, height); } Size GridVLayout::GetChildrenSize() const { return _children_size; } void GridVLayout::ForceChildrenSize(bool force) { _force_children_size = force; } int GridVLayout::GetNumColumn() const { return _num_column; } int GridVLayout::GetNumRow() const { return _num_row; } void GridVLayout::SetWidthMatchContent(bool match_content) { _width_match_content = match_content; } bool GridVLayout::GetWidthMatchContent() const { return _width_match_content; } void GridVLayout::GetCompositeList(std::list *ViewList) { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsView()) { View *ic = static_cast(*it); ViewList->push_back(ic); } else if ((*it)->IsLayout()) { Layout *layout = static_cast(*it); layout->GetCompositeList(ViewList); } } } long GridVLayout::ComputeContentSize() { std::list elements; if (GetScaleFactor() == 0) { ApplyMinHeight(); } if (_layout_element_list.size() == 0) { return eCompliantHeight | eCompliantWidth; } int num_elements = 0; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsVisible()) { (*it)->SetLayoutDone(false); elements.push_back(*it); num_elements++; } } int original_width = GetBaseWidth(); nux::Geometry base = GetGeometry(); it = elements.begin(); int num_row = 0; int num_column = 0; if (num_elements > 0) ++num_column; if (_dynamic_column) { int X = base.x + m_h_out_margin; int Y = base.y + m_v_out_margin; bool first_element_of_column = true; for (int i = 0; i < num_elements; i++) { if (num_column == 1) num_row++; if (first_element_of_column) { first_element_of_column = false; } if (_force_children_size) { (*it)->SetMinimumSize(_children_size.width, _children_size.height); } (*it)->SetGeometry(nux::Geometry(X, Y, _children_size.width, _children_size.height)); (*it)->ComputeContentSize(); Y += _children_size.height + m_v_in_margin; it++; if ((!_partial_visibility) && (Y + _children_size.height > base.y + base.height - m_v_out_margin)) { X += _children_size.width + m_h_in_margin; Y = base.y + m_v_out_margin; first_element_of_column = true; if (i < num_elements - 1) ++num_column; } else if (Y >= base.y + base.height) { X += _children_size.width + m_h_in_margin; Y = base.y + m_v_out_margin; first_element_of_column = true; if (i < num_elements - 1) ++num_column; } } } _num_row = num_row; _num_column = num_column; if ((GetScaleFactor() == 0) || _width_match_content) { int w = num_column * _children_size.width + 2 * m_h_out_margin + (num_column - 1) * m_h_in_margin; SetMinimumWidth(w); SetBaseWidth(w); } long size_compliance = 0L; if (GetBaseWidth() > original_width + VERROR) { #if DEBUG_LAYOUT_COMPUTATION // The layout has been resized larger in WIDTH to tightly pack its content. // Or you can say that the layout refuse to be smaller than total WIDTH of its elements. std::cout << "ComputeContentSize: VLayout Width block at " << GetWidth() << std::endl; #endif size_compliance |= eLargerWidth; // need scrollbar } else if (GetBaseWidth() + VERROR < original_width) { #if DEBUG_LAYOUT_COMPUTATION // The layout is smaller. std::cout << "ComputeContentSize: VLayout Width smaller = " << GetWidth() << std::endl; #endif size_compliance |= eSmallerWidth; } else { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: VLayout Width compliant = " << GetWidth() << std::endl; #endif size_compliance |= eCompliantWidth; } { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: VLayout Height compliant = " << m_fittingHeight << std::endl; #endif size_compliance |= eCompliantHeight; } return size_compliance; } void GridVLayout::ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw) { std::list elements; std::list::iterator it = _layout_element_list.begin(); graphics_engine.PushModelViewMatrix(Get2DMatrix()); for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if ((*it)->IsVisible()) elements.push_back(*it); } it = elements.begin(); Geometry base = GetGeometry(); Geometry const& parent_geometry = GetToplevel() ? GetToplevel()->GetAbsoluteGeometry() : GetAbsoluteGeometry(); bool geometry_is_visible = parent_geometry.IsIntersecting(GetAbsoluteGeometry()); graphics_engine.PushClippingRectangle(base); for (int i = 0; i < _num_column; i++) { for (int j = 0; j < _num_row; j++) { if (it == elements.end()) break; // Test if the element is inside the Grid before rendering. if (geometry_is_visible) { int X = base.x + m_h_out_margin + i * (_children_size.width + m_h_in_margin); int Y = base.y + m_v_out_margin + j * (_children_size.height + m_v_in_margin); graphics_engine.PushClippingRectangle(Geometry(X, Y, _children_size.width, _children_size.height)); if ((*it)->IsView()) { View *ic = static_cast(*it); ic->ProcessDraw(graphics_engine, force_draw); } else if ((*it)->IsLayout()) { Layout *layout = static_cast(*it); layout->ProcessDraw(graphics_engine, force_draw); } graphics_engine.PopClippingRectangle(); } it++; } } graphics_engine.PopClippingRectangle(); graphics_engine.PopModelViewMatrix(); draw_cmd_queued_ = false; } Area* GridVLayout::KeyNavIteration(KeyNavDirection direction) { if (_layout_element_list.size() == 0) return NULL; if (IsVisible() == false) return NULL; if (next_object_to_key_focus_area_) { std::list::iterator it; std::list::iterator it_next; it = std::find(_layout_element_list.begin(), _layout_element_list.end(), next_object_to_key_focus_area_); it_next = it; ++it_next; if (it == _layout_element_list.end()) { // Should never happen nuxAssert(0); return NULL; } int position = GetChildPos(*it); // note that(*it) == next_object_to_key_focus_area_ int nun_column = GetNumColumn(); int nun_row = GetNumRow(); if ((direction == KEY_NAV_UP) && (it == _layout_element_list.begin())) { // first item return NULL; } if ((direction == KEY_NAV_DOWN) && (it_next == _layout_element_list.end())) { // last item return NULL; } if ((direction == KEY_NAV_UP) && ((position % nun_row) == 0)) { // Left edge return NULL; } if ((direction == KEY_NAV_DOWN) && (position == (position / nun_row) * nun_row + (nun_row -1))) { // right edge return NULL; } if ((direction == KEY_NAV_LEFT) && ((position / nun_row) == 0)) { // top edge return NULL; } if ((direction == KEY_NAV_RIGHT) && ((position / nun_row) == nun_column)) { // bottom edge return NULL; } ////// if (direction == KEY_NAV_UP) { --it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { int pos = GetChildPos(*it); if (it == _layout_element_list.begin() || ((pos % nun_row) == 0)) break; --it; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_DOWN) { ++it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; int pos = GetChildPos(*it); if ((it == _layout_element_list.end()) || (pos == (pos / nun_row) * nun_row + (nun_row -1))) break; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_LEFT) { for (int i = 0; i < nun_row; ++i) { --it; } return (*it)->KeyNavIteration(direction); } if (direction == KEY_NAV_RIGHT) { for (int i = 0; i < nun_row; ++i) { ++it; if (it == _layout_element_list.end()) return NULL; } return (*it)->KeyNavIteration(direction); } } else { std::list::iterator it; it = _layout_element_list.begin(); return (*it)->KeyNavIteration(direction); } return NULL; } } nux-4.0.8+18.10.20180623/Nux/GridVLayout.h0000644000000000000000000000727213313373365013745 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef GRIDVLAYOUT_H #define GRIDVLAYOUT_H #include "Layout.h" namespace nux { //! A vertical grid layout /*! Fills the grid from top to bottom and going right. */ class GridVLayout: public Layout { // The grid layout goes through the child elements and assign them a size and position. // 0 3 6 9 .. // 1 4 7 10 .. // 2 5 8 .. // This is a top to bottom fill, going right. NUX_DECLARE_OBJECT_TYPE(GridVLayout, Layout); public: GridVLayout(NUX_FILE_LINE_PROTO); ~GridVLayout(); virtual long ComputeContentSize(); virtual void GetCompositeList(std::list *ViewList); //! Control the visibility of elements on the bottom edge. /*! Controls how the layout places the elements at its bottom edge. @param partial_visibility If True, the layout will position elements at its bottom edge even if they are partially visible. */ void EnablePartialVisibility(bool partial_visibility); //! Set the size of the grid element. /*! Set the size of the grid element. @param width Width of elements. @param height Height of elements. */ void SetChildrenSize(int width, int height); //! Get the size of the grid element. /*! @return Size of the grid elements. */ Size GetChildrenSize() const; //! Force the grid elements size. /*! Force the grid elements size to be the one provided by SetChildrenSize. */ void ForceChildrenSize(bool force); //! Get the number of columns in the grid. int GetNumColumn() const; //! Get the number of rows in the grid. int GetNumRow() const; //! Make the grid width match the size of its content. /*! @param match_content If True, force the width of the layout to match the height of the content. This can also be achieve if the stretch factor of this layout is set to 0; */ void SetWidthMatchContent(bool match_content); //! Return True if the grid width match the size of its content. bool GetWidthMatchContent() const; //! Draw Element /*! Draw all elements inside the layout. If force_draw is true then the system requests that all objects redraw themselves completely. @param force_draw @param TraverseInfo @param ProcessEventInfo @return The state of the Process Event. */ virtual void ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw); protected: int GetChildPos(Area *child); Area* GetChildAtPosition(int pos); virtual Area* KeyNavIteration(KeyNavDirection direction); private: Size _children_size; bool _dynamic_column; bool _force_children_size; bool _partial_visibility; bool _width_match_content; //!< If True, for the width of the layout to match the width of the content. int _num_row; int _num_column; }; } #endif // GRIDVLAYOUT_H nux-4.0.8+18.10.20180623/Nux/GroupBox.cpp0000644000000000000000000001175113313373365013631 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #include "GroupBox.h" namespace nux { GroupBox::GroupBox(const char * /* Caption */, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_layout(0) { m_CaptionArea.SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); m_CaptionArea.SetBaseSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); SetMinimumSize(DEFAULT_WIDGET_WIDTH + 5, PRACTICAL_WIDGET_HEIGHT + 5); SetBaseSize(DEFAULT_WIDGET_WIDTH + 5, 2 * PRACTICAL_WIDGET_HEIGHT); SetCaption(""); } GroupBox::~GroupBox() { } void GroupBox::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { graphics_engine.PushClippingRectangle(GetGeometry()); Geometry wireborder_geo = GetGeometry(); wireborder_geo.OffsetPosition(0, 10); wireborder_geo.OffsetSize(0, -10); GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), m_CaptionArea.GetGeometry(), m_CaptionArea.GetBaseString(), GetTextColor(), true, eAlignTextCenter); if (m_layout != 0) { m_layout->QueueDraw(); } graphics_engine.PopClippingRectangle(); } void GroupBox::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { graphics_engine.PushClippingRectangle(GetGeometry()); if (m_layout) { graphics_engine.PushClippingRectangle(m_layout->GetGeometry()); m_layout->ProcessDraw(graphics_engine, force_draw); graphics_engine.PopClippingRectangle(); } graphics_engine.PopClippingRectangle(); } bool GroupBox::SetLayout(Layout *layout) { if (View::SetLayout(layout) == false) { return false; } m_layout = layout; return true; // Geometry geo = GetGeometry(); // Geometry layout_geo = Geometry(geo.x + m_border, geo.y + m_top_border, // geo.GetWidth() - 2*m_border, geo.GetHeight() - m_border - m_top_border); // m_layout->SetGeometry(layout_geo); } void GroupBox::PreLayoutManagement() { // Give the managed layout appropriate size and position.. if (view_layout_) { Geometry layout_geo = GetGeometry(); layout_geo.OffsetPosition(2, 20); layout_geo.OffsetSize(-4, -22); view_layout_->SetGeometry(layout_geo); } } long GroupBox::PostLayoutManagement(long /* LayoutResult */) { // A Group box must tightly group its children. // So it must embrace the size that was compute for the composition layout. // Only the size is change is important here of the GroupBox is important here. long ret = 0; Geometry old_geo = Area::GetGeometry(); if (view_layout_) { Geometry base = view_layout_->GetGeometry(); base.OffsetPosition(-2, -20); base.OffsetSize(4, 22); Area::SetGeometry(base); } Geometry base = GetGeometry(); m_CaptionArea.SetBaseXY(base.x + 6, base.y); if (old_geo.GetWidth() > base.GetWidth()) ret |= eLargerWidth; else if (old_geo.GetWidth() < base.GetWidth()) ret |= eSmallerWidth; else ret |= eCompliantWidth; if (old_geo.GetHeight() > base.GetHeight()) ret |= eLargerHeight; else if (old_geo.GetHeight() < base.GetHeight()) ret |= eSmallerHeight; else ret |= eCompliantHeight; return ret; } void GroupBox::ComputeContentPosition(float offsetX, float offsetY) { if (view_layout_) { view_layout_->SetBaseX(GetBaseX() + 2); view_layout_->SetBaseY(GetBaseY() + 20); view_layout_->ComputeContentPosition(offsetX, offsetY); } Geometry base = GetGeometry(); m_CaptionArea.SetBaseXY(base.x + 6, base.y); } void GroupBox::SetCaption(const char *name) { if ((name == 0) || strlen(name) == 0) { m_CaptionArea.SetBaseString(""); m_CaptionArea.SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); m_CaptionArea.SetBaseSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); } else { m_CaptionArea.SetBaseString(name); m_CaptionArea.SetMinimumSize(4 + GetSysBoldFont()->GetStringWidth(name), PRACTICAL_WIDGET_HEIGHT); m_CaptionArea.SetBaseSize(4 + GetSysBoldFont()->GetStringWidth(name), PRACTICAL_WIDGET_HEIGHT); } } bool GroupBox::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/GroupBox.h0000644000000000000000000000346213313373365013276 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef GROUPBOX_H #define GROUPBOX_H namespace nux { class Layout; /*! A stretch factor of 0 or 1 for the GroupBox has no effect because the GroupBox is designed to tightly adjust to the size of its composition layout. This unlike the Panel widget for instance who does not force itself to adjust to the size of its composition layout. */ class GroupBox : public View { public: GroupBox(const char *Caption = "", NUX_FILE_LINE_PROTO); ~GroupBox(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual bool SetLayout(Layout *layout); void SetCaption(const char *Caption); protected: virtual bool AcceptKeyNavFocus(); private: virtual void PreLayoutManagement(); virtual long PostLayoutManagement(long LayoutResult); virtual void ComputeContentPosition(float offsetX, float offsetY); BasicView m_CaptionArea; Layout *m_layout; }; } #endif // GROUPBOX_H nux-4.0.8+18.10.20180623/Nux/GroupBox2.cpp0000644000000000000000000001514413313373365013713 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #include "GroupBox2.h" namespace nux { int GroupBox2::CAPTION_X_MARGIN = 6; int GroupBox2::X_MARGIN = 4; int GroupBox2::Y_MARGIN = 4; Color GroupBox2::GROUPBOX2_HEADER_BASE_COLOR = Color(0xFF191919); Color GroupBox2::GROUPBOX2_HEADER_TEXT_COLOR = Color(0xFFFFFFFF); int GroupBox2::TOP_HEADER_HEIGHT = 24; GroupBox2::GroupBox2(const char *Caption, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_layout(0) { m_CaptionArea = new BasicView(NUX_TRACKER_LOCATION); SetMinimumSize(DEFAULT_WIDGET_WIDTH + 5, PRACTICAL_WIDGET_HEIGHT + 5); SetBaseSize(DEFAULT_WIDGET_WIDTH + 5, PRACTICAL_WIDGET_HEIGHT + 5); SetCaption(Caption); } GroupBox2::~GroupBox2() { m_CaptionArea->Dispose(); } void GroupBox2::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { graphics_engine.PushClippingRectangle(GetGeometry()); Geometry header = GetGeometry(); header.SetHeight(TOP_HEADER_HEIGHT); Geometry layoutgeomerty = GetGeometry(); layoutgeomerty.OffsetPosition(0, TOP_HEADER_HEIGHT); layoutgeomerty.OffsetSize(0, -TOP_HEADER_HEIGHT); GetPainter().PaintShapeCorner(graphics_engine, header, Color(0xFF000000), eSHAPE_CORNER_ROUND4, eCornerTopLeft | eCornerTopRight, false); GetPainter().PushDrawShapeLayer(graphics_engine, layoutgeomerty, eSHAPE_CORNER_ROUND4, GROUPBOX2_HEADER_BASE_COLOR, eCornerBottomLeft | eCornerBottomRight); GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), m_CaptionArea->GetGeometry(), m_CaptionArea->GetBaseString(), GROUPBOX2_HEADER_TEXT_COLOR); if (m_layout != 0) { m_layout->QueueDraw(); } GetPainter().PopBackground(); graphics_engine.PopClippingRectangle(); } void GroupBox2::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { if (m_layout == 0) return; graphics_engine.PushClippingRectangle(m_layout->GetGeometry()); Geometry layoutgeomerty = GetGeometry(); layoutgeomerty.OffsetPosition(0, TOP_HEADER_HEIGHT); layoutgeomerty.OffsetSize(0, -TOP_HEADER_HEIGHT); if (force_draw) GetPainter().PushDrawShapeLayer(graphics_engine, layoutgeomerty, eSHAPE_CORNER_ROUND4, GROUPBOX2_HEADER_BASE_COLOR, eAllCorners); else GetPainter().PushShapeLayer(graphics_engine, layoutgeomerty, eSHAPE_CORNER_ROUND4, GROUPBOX2_HEADER_BASE_COLOR, eAllCorners); if (m_layout) { graphics_engine.PushClippingRectangle(m_layout->GetGeometry()); m_layout->ProcessDraw(graphics_engine, force_draw); graphics_engine.PopClippingRectangle(); } GetPainter().PopBackground(); graphics_engine.PopClippingRectangle(); } bool GroupBox2::SetLayout(Layout *layout) { if (View::SetLayout(layout) == false) { return false; } m_layout = layout; return true; } void GroupBox2::PreLayoutManagement() { // Give the managed layout appropriate size and position.. if (GetCompositionLayout()) { Geometry layout_geo = GetGeometry(); layout_geo.OffsetPosition(X_MARGIN, TOP_HEADER_HEIGHT + Y_MARGIN); layout_geo.OffsetSize(-2 * X_MARGIN, -TOP_HEADER_HEIGHT - 2 * Y_MARGIN); GetCompositionLayout()->SetGeometry(layout_geo); } } long GroupBox2::PostLayoutManagement(long /* LayoutResult */) { // A Group box must tightly group its children. // So it must embrace the size that was compute for the composition layout. // Only the size is change is important here of the GroupBox2 is important here. long ret = 0; Geometry old_geo = Area::GetGeometry(); if (GetCompositionLayout()) { Geometry base = GetCompositionLayout()->GetGeometry(); base.OffsetPosition(-X_MARGIN, -TOP_HEADER_HEIGHT - Y_MARGIN); base.OffsetSize(2 * X_MARGIN, TOP_HEADER_HEIGHT + 2 * Y_MARGIN); Area::SetGeometry(base); } Geometry base = GetGeometry(); m_CaptionArea->SetBaseXY(base.x + CAPTION_X_MARGIN, base.y + (TOP_HEADER_HEIGHT - m_CaptionArea->GetBaseHeight()) / 2); if (old_geo.GetWidth() > base.GetWidth()) ret |= eLargerWidth; else if (old_geo.GetWidth() < base.GetWidth()) ret |= eSmallerWidth; else ret |= eCompliantWidth; if (old_geo.GetHeight() > base.GetHeight()) ret |= eLargerHeight; else if (old_geo.GetHeight() < base.GetHeight()) ret |= eSmallerHeight; else ret |= eCompliantHeight; return ret; } void GroupBox2::ComputeContentPosition(float offsetX, float offsetY) { if (GetCompositionLayout()) { GetCompositionLayout()->SetBaseX(GetBaseX() + X_MARGIN); GetCompositionLayout()->SetBaseY(GetBaseY() + TOP_HEADER_HEIGHT + Y_MARGIN); GetCompositionLayout()->ComputeContentPosition(offsetX, offsetY); } Geometry base = GetGeometry(); m_CaptionArea->SetBaseXY(base.x + CAPTION_X_MARGIN, base.y + (TOP_HEADER_HEIGHT - m_CaptionArea->GetBaseHeight()) / 2); } void GroupBox2::SetCaption(const char *Caption) { if ((Caption == 0) || (StringLength(Caption) == 0)) { m_CaptionArea->SetBaseString(""); m_CaptionArea->SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); m_CaptionArea->SetBaseSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); } else { m_CaptionArea->SetBaseString(Caption); m_CaptionArea->SetMinimumSize(4 + GetSysBoldFont()->GetStringWidth(Caption), PRACTICAL_WIDGET_HEIGHT); m_CaptionArea->SetBaseSize(4 + GetSysBoldFont()->GetStringWidth(Caption), PRACTICAL_WIDGET_HEIGHT); Size s = GetMinimumSize(); if (s.width < 2 * CAPTION_X_MARGIN + m_CaptionArea->GetBaseWidth()) { SetMinimumSize(2 * CAPTION_X_MARGIN + m_CaptionArea->GetBaseWidth(), s.height); SetBaseSize(2 * CAPTION_X_MARGIN + m_CaptionArea->GetBaseWidth(), s.height); } } } bool GroupBox2::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/GroupBox2.h0000644000000000000000000000402313313373365013352 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef GROUPBOX2_H #define GROUPBOX2_H namespace nux { class Layout; /*! A stretch factor of 0 or 1 for the GroupBox has no effect because the GroupBox is designed to tightly adjust to the size of its composition layout. This unlike the Panel widget for instance who does not force itself to adjust to the size of its composition layout. */ class GroupBox2 : public View { public: GroupBox2(const char *Caption = "", NUX_FILE_LINE_PROTO); ~GroupBox2(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual bool SetLayout(Layout *layout); void SetCaption(const char *Caption); protected: virtual bool AcceptKeyNavFocus(); private: virtual void PreLayoutManagement(); virtual long PostLayoutManagement(long LayoutResult); virtual void ComputeContentPosition(float offsetX, float offsetY); BasicView *m_CaptionArea; Layout *m_layout; static int CAPTION_X_MARGIN; static int X_MARGIN; static int Y_MARGIN; static Color GROUPBOX2_HEADER_BASE_COLOR; static Color GROUPBOX2_HEADER_TEXT_COLOR; static int TOP_HEADER_HEIGHT; }; } #endif // GroupBox2_H nux-4.0.8+18.10.20180623/Nux/HLayout.cpp0000644000000000000000000007266013313373365013457 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "View.h" #include "HLayout.h" #include "VLayout.h" namespace nux { static const int HERROR = 0; NUX_IMPLEMENT_OBJECT_TYPE(HLayout); HLayout::HLayout(NUX_FILE_LINE_DECL) : LinearLayout(NUX_FILE_LINE_PARAM) { #if DEBUG_LAYOUT space_between_children_ = 10; left_padding_ = 10; right_padding_ = 10; m_v_in_margin = 10; top_padding_ = 10; bottom_padding_ = 10; #endif // Start packing the elements from the top. Is the layout has more space than the elements can use, // leave that space at the bottom of the HLayout. m_ContentStacking = eStackLeft; } HLayout::HLayout(std::string name, NUX_FILE_LINE_DECL) : LinearLayout(NUX_FILE_LINE_PARAM) { m_name = name; #if DEBUG_LAYOUT space_between_children_ = 10; left_padding_ = 10; right_padding_ = 10; m_v_in_margin = 10; top_padding_ = 10; bottom_padding_ = 10; #endif m_ContentStacking = eStackLeft; } HLayout::~HLayout() { } void HLayout::GetCompositeList(std::list *ViewList) { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsView()) { View *ic = static_cast(*it); ViewList->push_back(ic); } else if ((*it)->IsLayout()) { Layout *layout = static_cast(*it); layout->GetCompositeList(ViewList); } } } void HLayout::ComputeStacking(int remaining_width, int &offset_space, int &element_margin) { int per_element_space = 0; int total_used_space = 0; int num_elements = 0; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsVisible()) { // gather all the space used by elements total_used_space += (*it)->GetBaseWidth(); num_elements++; } } if (num_elements) { // Compute the space available for each element per_element_space = (remaining_width - total_used_space) / int(num_elements); } if (per_element_space < 0) { per_element_space = 0; } int margin; if (per_element_space > 0) { margin = (per_element_space) / 2; } else { margin = 0; } LayoutContentDistribution stacking = GetContentDistribution(); switch(stacking) { case MAJOR_POSITION_START: { offset_space = 0; element_margin = 0; } break; case MAJOR_POSITION_END: { offset_space = (remaining_width - total_used_space); if (offset_space < 0) offset_space = 0; element_margin = 0; } break; case eStackCenter: { offset_space = (remaining_width - total_used_space) / 2; if (offset_space < 0) offset_space = 0; element_margin = 0; } break; case eStackExpand: default: { offset_space = 0; element_margin = margin; } break; } } long HLayout::ComputeContentSize() { if (_layout_element_list.size() == 0) { return eCompliantHeight | eCompliantWidth; } std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsVisible()) (*it)->SetLayoutDone(false); } int original_height = GetBaseHeight(); if (GetScaleFactor() == 0) { // The size must exactly fit the children. The parent cannot be larger or smaller // than the total width of its children(+ margins). // So set the parent size to Geometry(0,0,1,1) and let the children force it to extend. if (GetParentObject() && GetParentObject()->Type().IsObjectType(HLayout::StaticObjectType)) { // The parent if a HLayout(same type). Then a Stretch factor of 0 means this layout has its width set to 1. Area::SetBaseWidth(1); } else if (GetParentObject() && GetParentObject()->Type().IsObjectType(VLayout::StaticObjectType)) { // The parent if a VLayout. Then a Stretch factor of 0 means this layout has its height set to 1. Area::SetBaseHeight(1); } else { // This is for when a layout is set as a composition layout of an View and its stretch factor is explicitly set to 0. Area::SetBaseWidth(1); Area::SetBaseHeight(1); } //The children will all assume their minimum size. } else { // The total size of the children(+ margins) may be smaller or equal to parent size. } bool unadjusted_layout = false; do { unsigned int num_element = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsVisible()) num_element++; } // Get layout Width and Height int width = GetBaseWidth(); int height = GetBaseHeight(); // Remove the margins. This is the real width and height available to the children. width -= (int) (num_element - 1) * space_between_children_ + (left_padding_ + right_padding_); height -= (top_padding_ + bottom_padding_); // Size the children according to their stretch factor. HLayoutManagement(width, height); // Objects have been resized, now position them. int current_x = GetBaseX() + left_padding_; int current_y = GetBaseY() + top_padding_; int offset_space = 0; int space_after_element = 0; ComputeStacking(width, offset_space, space_after_element); current_x += offset_space; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; current_x += space_after_element; (*it)->SetBaseX(current_x); (*it)->SetBaseY(current_y); MinorDimensionSize extend = (*it)->GetExtend(); MinorDimensionPosition positioning = (*it)->GetPositioning(); float percentage = (*it)->GetPercentage(); // Compute the size of an ellement in the minor dimension(vertical) switch(extend) { case MINOR_SIZE_PERCENTAGE: { // The size of the processed element in the minor dimension is a percentage of layout minor dimension size. // Note that children of the processed element may force it to have a bigger size. int percentage_height = (height * percentage) / 100.0f; (*it)->SetBaseHeight(percentage_height); break; } case MINOR_SIZE_MATCHCONTENT: { // Force the element height to be the minimum has defined with SetMinimumHeight. // The children of this element can force it to get larger. (*it)->ApplyMinHeight(); break; } case eFix: { //do nothing break; } case MINOR_SIZE_FULL: default: { (*it)->SetBaseHeight(height); break; } } // Compute the position of an element in the minor dimension. if ((*it)->GetBaseHeight() < height) { int widget_height = (*it)->GetBaseHeight(); switch(positioning) { case MINOR_POSITION_START: { // do nothing (*it)->SetBaseY(current_y); break; } case MINOR_POSITION_END: { if (widget_height < height) (*it)->SetBaseY(current_y + height - widget_height); else (*it)->SetBaseY(current_y); break; } case MINOR_POSITION_CENTER: default: { if (widget_height < height) (*it)->SetBaseY(current_y + (height - widget_height) / 2); else (*it)->SetBaseY(current_y); } } } current_x += (*it)->GetBaseWidth() + space_after_element + space_between_children_; } // Manage child layout if (num_element == 0) m_fittingWidth = (int) (left_padding_ + right_padding_); else m_fittingWidth = (int) (num_element - 1) * space_between_children_ + (left_padding_ + right_padding_); m_contentHeight = GetBaseHeight() - (top_padding_ + bottom_padding_); // Set to the size of the layout. int element_height = 0; unadjusted_layout = false; // This array is meant to store the sizes of some of the elements height. These elements must have MINOR_SIZE_FULL as extent and // they have not been not been constrained smaller after ComputeContentSize is called. Because the layout may have a stretch factor of 0 // and therefore its size has been set to 1x1 at the start of this function, there is a possibility that some of the elements don't have // the full height of the layout(these elements uses their minimum height because the layout was set to a size 1x1). // We check if that is the case and force a recompute. std::vector FullSizeUnadjusted; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; int ret = 0; if (((*it)->IsLayout() || (*it)->IsView()) /*&& ((*it)->IsLayoutDone() == false)*/ /*&& ((*it)->GetScaleFactor() != 0)*/) { Geometry pre_geo = (*it)->GetGeometry(); ret = (*it)->ComputeContentSize(); Geometry post_geo = (*it)->GetGeometry(); bool larger_width = pre_geo.width < post_geo.width; bool smaller_width = pre_geo.width > post_geo.width; bool larger_height = pre_geo.height < post_geo.height; bool smaller_height = pre_geo.height > post_geo.height; if ((larger_width || smaller_width) && ((*it)->IsLayoutDone() == false)) { // Stop computing the size of this layout. Its size was not convenient to its children. So the children size take priority // over the layout. In ComputeContentSize, the dimension of the layout has been set so it encompasses its children(and the margins). // Now the parent layout cannot be touched again: layout_done_ = true. In VLayoutManagement, it is as if the stretchfactor // of this layout is now 0. // This is the only place where a layout can have layout_done_ set to "true". // If(smaller_width == true) the layout takes less space than anticipated. // Set unadjusted_layout = true, so another pass will allow its sibling to claim more space. { unadjusted_layout = true; (*it)->SetLayoutDone(true); } } if ((smaller_height == false) && ((*it)->GetExtend() == MINOR_SIZE_FULL) && ((*it)->GetBaseHeight() < (*it)->GetMaximumHeight())) { // We catch all object whose size is possibly larger than the layout. We check there size at the end and // recompute the layout if necessary. // For layout elements, make sure that the stretch factor is not 0. If it is, it means it will not use the // size provided by the parent layout. Its size will be adjusted to the minimum size of the layout content. if (! ((*it)->IsLayout() && (*it)->GetScaleFactor() == 0)) FullSizeUnadjusted.push_back((*it)->GetBaseHeight()); } if ((smaller_height || larger_height) && ((*it)->GetExtend() == MINOR_SIZE_MATCHCONTENT)) { (*it)->SetMinimumHeight((*it)->GetBaseHeight()); unadjusted_layout = true; } // Should be reactivate so that if the parent Layout does not call // ComputeContentPosition, at least it is done here to arrange the internal // element of the children. //(*it)->ComputeContentPosition(0,0); } m_fittingWidth += (*it)->GetBaseWidth(); element_height = (*it)->GetBaseHeight(); if ((*it)->IsSpaceLayout() == false) { if ((GetScaleFactor() != 0) && (ret & eSmallerHeight)) { if (m_contentHeight < element_height) { if (m_contentHeight < GetMaximumHeight()) { // An element is larger than the layout height and the layout has not reach its maximum height yet. m_contentHeight = element_height; unadjusted_layout = true; } } } else { if (m_contentHeight <= element_height) { m_contentHeight = element_height; } // else if ((*it)->GetExtend() == MINOR_SIZE_FULL) // { // unadjusted_layout = true; // } } } } // Set the height of the layout to be equal to the largest height it controls. // m_contentHeight is the largest height of an element within this layout. The layout size is then // m_contentHeight + (top_padding_ + bottom_padding_); SetBaseHeight(m_contentHeight + (top_padding_ + bottom_padding_)); // Get back the Height after it has been bounded by [minHeight, maxHeight] in the preceeding call to SetBaseHeight. // Then deduce the height of the content. int temp = GetHeight() - (top_padding_ + bottom_padding_); std::vector::iterator IntIterator = FullSizeUnadjusted.begin(); for (IntIterator = FullSizeUnadjusted.begin(); IntIterator != FullSizeUnadjusted.end(); IntIterator++) { if ((*IntIterator) < temp) { unadjusted_layout = true; } } } while (unadjusted_layout); // m_fittingHeight is sum of the largest element height plus the outer margin. m_fittingHeight = m_contentHeight + (top_padding_ + bottom_padding_); // m_fittingWidth is sum of the element width plus the inner and outer margin. // If the stretch factor is 0 then, the layout height has been set to 1 and need to grow with the elements within. // If the stretch factor is not 0, then the layout height is set to m_fittingHeight only if the its height is less than m_fittingHeight; // This way, if the layout height is greater than m_fittingHeight there is space to compute the content stacking(ComputeStacking). if (GetBaseWidth() < m_fittingWidth) { SetBaseWidth(m_fittingWidth); } m_contentWidth = m_fittingWidth; long size_compliance = 0L; ComputeContentPosition(0, 0); { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: HLayout Width compliant = " << m_fittingWidth << std::endl; #endif size_compliance |= eCompliantWidth; } // The layout has been resized to tightly pack its content if (GetBaseHeight() > original_height + HERROR) { #if DEBUG_LAYOUT_COMPUTATION // The layout has been resized larger in height to tightly pack its content. // Or you can say that the layout refuse to be smaller than total HEIGHT of its elements. std::cout << "ComputeContentSize: HLayout Height block at " << GetBaseHeight() << std::endl; #endif size_compliance |= eLargerHeight; // need scrollbar } else if (GetBaseHeight() + HERROR < original_height) { #if DEBUG_LAYOUT_COMPUTATION // The layout is smaller. std::cout << "ComputeContentSize: HLayout Height is smaller = " << GetBaseHeight() << std::endl; #endif size_compliance |= eSmallerHeight; } else { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: HLayout Height compliant = " << GetBaseHeight() << std::endl; #endif size_compliance |= eCompliantHeight; } return size_compliance; } void HLayout::HLayoutManagement(int width, int /* height */) { bool need_recompute = false; do { need_recompute = false; int available_width = width; unsigned int max_stretchfactor = GetMaxStretchFactor(); std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; if (((*it)->GetScaleFactor() == 0) && ((*it)->IsLayoutDone() != true)) { (*it)->ApplyMinWidth(); } } if (max_stretchfactor == 0) { // It means all object are fixed sized or all re-sizable object have been sized to there max or there min. if (GetScaleFactor() == 0) { // It is unlikely that we get here! int w = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end() && !need_recompute; it++) { if (!(*it)->IsVisible()) continue; w += (*it)->GetBaseWidth(); } SetBaseWidth(w); } return; } for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; if ((*it)->GetScaleFactor() == 0 || (*it)->IsLayoutDone() == true) { available_width -= (*it)->GetBaseWidth(); } } if (available_width <= 2) { for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; if (((*it)->GetScaleFactor() != 0) && (*it)->IsArea()) { // If it is not an object of type eInputArea, do not set layout_done_ to true, // so, the layout management function will later be called on the object. (*it)->ApplyMinWidth(); (*it)->SetLayoutDone(true); } else if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayout()) && ((*it)->IsLayoutDone() == false)) // layout and not fixed by child { // The out of bound must be reset to false. (*it)->ApplyMinWidth(); (*it)->SetLayoutDone(false); } else if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) // layout and not fixed { (*it)->ApplyMinWidth(); // A layout must never have layout_done_ set to true "here" because it must continue // doing the layout of its children and finally resize itself to fit them. // The same way, A layout size factor should never be set to 0. } } return; } float cumul = 0; Area *LastElementThatCanBeResized = 0; int total_distributed_size = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) { float sf = (float) (*it)->GetScaleFactor(); cumul += sf / max_stretchfactor; LastElementThatCanBeResized = (*it); } else { total_distributed_size += (*it)->GetBaseWidth(); } } // ----- // \ factor // Ref_Size * \ ------------ = available_width // / max_factor // / // ----- // all element with stretchfactor != 0 unsigned int ref_width = available_width / cumul; need_recompute = false;; for (it = _layout_element_list.begin(); it != _layout_element_list.end() && !need_recompute; it++) { if (!(*it)->IsVisible()) continue; if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) { unsigned int sf = (*it)->GetScaleFactor(); int new_width; if (sf == max_stretchfactor) { new_width = ref_width; } else { new_width = ref_width * sf / max_stretchfactor; } total_distributed_size += new_width; if (LastElementThatCanBeResized == (*it)) { // Redistribute the remaining size to the last element(at the right). // This is necessary because of imprecision. For instance if available_height = 451 and we have 2 elements // with the same stretch factor than each one will have a size of 225. With is correction, the first element will have a size of // 225 while the second one will have a size of 226. if (available_width - total_distributed_size > 0) { new_width += available_width - total_distributed_size; total_distributed_size = available_width; } } int elemt_max_width = (*it)->GetMaximumSize().width; int elemt_min_width = (*it)->GetMinimumSize().width; // A layout must never have layout_done_ set to true "here" because it must continue // doing the layout of its children and finally resize itself to fit them. // The same way, A layout size factor should never be set to 0. // Q: How about SpaceLayout? Should we treat them the same as layout or widget in this particular case? // A: SapceLayout are treated like widgets in this case if (new_width < elemt_min_width) { // assume the minimum width (*it)->SetBaseWidth(elemt_min_width); if ((*it)->IsLayout() == false || (*it)->IsSpaceLayout()) { (*it)->SetLayoutDone(true); need_recompute = true; } } else if (new_width > elemt_max_width) { // assume the maximum width (*it)->SetBaseWidth(elemt_max_width); if ((*it)->IsLayout() == false || (*it)->IsSpaceLayout()) { (*it)->SetLayoutDone(true); need_recompute = true; } // else // { // // set the extra space back in the pool // total_distributed_size -= (new_width - elemt_max_width); // } } else { (*it)->SetBaseWidth(new_width); } } else { // For fixed element, reset their size to the same so it is checked against // the min and max. This is necessary in case you have set the size of the element first then latter, // you define its MinimumSize and/or MaximumSize size. unsigned int w = (*it)->GetBaseWidth(); unsigned int h = (*it)->GetBaseHeight(); (*it)->SetBaseWidth(w); (*it)->SetBaseHeight(h); } } } while (need_recompute); } unsigned int HLayout::GetMaxStretchFactor() { unsigned int value = 0; unsigned int sf; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; // In the recursive process, make sure we get always the highest stretch factor // of an element that has not been bounded. if ((*it)->IsLayoutDone() == false) { sf = (*it)->GetScaleFactor(); if (sf >= value) { value = sf; } } } return value; } void HLayout::ComputeContentPosition(float offsetX, float offsetY) { std::list::iterator it; { unsigned int num_element = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsVisible()) num_element++; } // Get layout Width and Height int width = GetBaseWidth(); int height = GetBaseHeight(); // remove the margins width -= (int) (num_element - 1) * space_between_children_ + (left_padding_ + right_padding_); height -= (top_padding_ + bottom_padding_); // Objects have been resized, now position them. int current_x = GetBaseX() + left_padding_ + offsetX; // add base offset in X(used for scrolling) int current_y = GetBaseY() + top_padding_ + offsetY; // add base offset in Y(used for scrolling) int offset_space = 0; int element_margin = 0; ComputeStacking(width, offset_space, element_margin); current_x += offset_space; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; current_x += element_margin; (*it)->SetBaseX(current_x); (*it)->SetBaseY(current_y); MinorDimensionPosition positioning = (*it)->GetPositioning(); if ((*it)->GetBaseHeight() < height) { int widget_height = (*it)->GetBaseHeight(); switch(positioning) { case MINOR_POSITION_START: { // do nothing (*it)->SetBaseY(current_y); break; } case MINOR_POSITION_END: { if (widget_height < height) (*it)->SetBaseY(current_y + height - widget_height); else (*it)->SetBaseY(current_y); break; } case MINOR_POSITION_CENTER: default: { if (widget_height < height) (*it)->SetBaseY(current_y + (height - widget_height) / 2); else (*it)->SetBaseY(current_y); } } } current_x += (*it)->GetBaseWidth() + element_margin + space_between_children_; } } for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; if ((*it)->Type().IsDerivedFromType(Layout::StaticObjectType)) { (*it)->ComputeContentPosition(offsetX, offsetY); } else if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) { (*it)->ComputeContentPosition(offsetX, offsetY); } } } Area* HLayout::KeyNavIteration(KeyNavDirection direction) { if (_layout_element_list.size() == 0) return NULL; if (IsVisible() == false) return NULL; if (next_object_to_key_focus_area_) { if ((direction == KEY_NAV_UP) || (direction == KEY_NAV_DOWN)) { // Don't know what to do with this return NULL; } std::list::iterator it; std::list::iterator it_next; it = std::find(_layout_element_list.begin(), _layout_element_list.end(), next_object_to_key_focus_area_); if (it == _layout_element_list.end()) { // Should never happen nuxAssert(0); return NULL; } it_next = it; ++it_next; if ((direction == KEY_NAV_LEFT) && (it == _layout_element_list.begin())) { // can't go further return NULL; } if ((direction == KEY_NAV_RIGHT) && (it_next == _layout_element_list.end())) { // can't go further return NULL; } if (direction == KEY_NAV_LEFT) { --it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { if (it == _layout_element_list.begin()) break; --it; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_RIGHT) { ++it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == _layout_element_list.end()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } } else { Area* key_nav_focus = NULL; if (direction == KEY_NAV_LEFT) { std::list::reverse_iterator it = _layout_element_list.rbegin(); key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == _layout_element_list.rend()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } } else { std::list::iterator it = _layout_element_list.begin(); key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == _layout_element_list.end()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } } return key_nav_focus; } return NULL; } } nux-4.0.8+18.10.20180623/Nux/HLayout.h0000644000000000000000000000355313313373365013117 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef HLAYOUT_H #define HLAYOUT_H #include "LinearLayout.h" namespace nux { class HLayout: public LinearLayout { NUX_DECLARE_OBJECT_TYPE(HLayout, LinearLayout); public: HLayout(NUX_FILE_LINE_PROTO); HLayout(std::string name, NUX_FILE_LINE_PROTO); ~HLayout(); virtual long ComputeContentSize(); virtual void ComputeContentPosition(float offsetX, float offsetY); virtual void HLayoutManagement(int width, int height); virtual unsigned int GetMaxStretchFactor(); virtual void GetCompositeList(std::list *ViewList); //! Compute the how elements are spread inside the layout /*! @param remaining_width Size that remains after subtracting elements width, inner and outer margins from the content width. @param offset_space The space at the left of all elements. @param element_margin The margin between elements. */ void ComputeStacking(int remaining_width, int &offset_space, int &element_margin); protected: virtual Area* KeyNavIteration(KeyNavDirection direction); }; } #endif // HLAYOUT_H nux-4.0.8+18.10.20180623/Nux/HScrollBar.cpp0000644000000000000000000003233213313373365014055 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "HScrollBar.h" namespace nux { const int HSCROLLBAR_WIDTH = 10; const int HSCROLLBAR_HEIGHT = 10; HScrollBar::HScrollBar(NUX_FILE_LINE_DECL) : ScrollBar(NUX_FILE_LINE_PARAM) { content_width_ = 0; content_height_ = 0; container_width_ = 0; container_height_ = 0; m_TrackWidth = 0; m_TrackHeight = 0; m_SlideBarOffsetX = 0; m_SlideBarOffsetY = 0; content_offset_x_ = 0; content_offset_y_ = 0; b_MouseUpTimer = false; b_MouseDownTimer = false; m_color_factor = 1.0f; m_LeftTimerHandler = 0; m_RightTimerHandler = 0; hlayout = new HLayout(NUX_TRACKER_LOCATION); _scroll_left_button = new BasicView(NUX_TRACKER_LOCATION); _track = new BasicView(NUX_TRACKER_LOCATION); _scroll_right_button = new BasicView(NUX_TRACKER_LOCATION); _slider = new BasicView(NUX_TRACKER_LOCATION); _slider->SetParentObject(this); // Set Original State SetMinimumSize(AREA_MIN_WIDTH, HSCROLLBAR_HEIGHT); SetMaximumSize(AREA_MAX_WIDTH, HSCROLLBAR_HEIGHT); // Set Signals _scroll_right_button->mouse_down.connect(sigc::mem_fun(this, &HScrollBar::RecvStartScrollRight)); _scroll_right_button->mouse_up.connect(sigc::mem_fun(this, &HScrollBar::RecvEndScrollRight)); _scroll_left_button->mouse_down.connect(sigc::mem_fun(this, &HScrollBar::RecvStartScrollLeft)); _scroll_left_button->mouse_up.connect(sigc::mem_fun(this, &HScrollBar::RecvEndScrollLeft)); _slider->mouse_down.connect(sigc::mem_fun(this, &HScrollBar::OnSliderMouseDown)); _slider->mouse_up.connect(sigc::mem_fun(this, &HScrollBar::OnSliderMouseUp)); _slider->mouse_drag.connect(sigc::mem_fun(this, &HScrollBar::OnSliderMouseDrag)); _track->mouse_down.connect(sigc::mem_fun(this, &HScrollBar::RecvTrackMouseDown)); _track->mouse_up.connect(sigc::mem_fun(this, &HScrollBar::RecvTrackMouseUp)); _track->mouse_drag.connect(sigc::mem_fun(this, &HScrollBar::RecvTrackMouseDrag)); // Set Geometry _scroll_right_button->SetMinimumSize(HSCROLLBAR_WIDTH, HSCROLLBAR_HEIGHT); _scroll_right_button->SetMaximumSize(HSCROLLBAR_WIDTH, HSCROLLBAR_HEIGHT); _scroll_right_button->SetGeometry(Geometry(0, 0, HSCROLLBAR_WIDTH, HSCROLLBAR_HEIGHT)); _scroll_left_button->SetMinimumSize(HSCROLLBAR_WIDTH, HSCROLLBAR_HEIGHT); _scroll_left_button->SetMaximumSize(HSCROLLBAR_WIDTH, HSCROLLBAR_HEIGHT); _scroll_left_button->SetGeometry(Geometry(0, 0, HSCROLLBAR_WIDTH, HSCROLLBAR_HEIGHT)); hlayout->AddView(_scroll_left_button, 0, eCenter, eFix); hlayout->AddView(_track, 1, eCenter, eFull); hlayout->AddView(_scroll_right_button, 0, eCenter, eFix); callback = new TimerFunctor; callback->tick.connect(sigc::mem_fun(this, &HScrollBar::HScrollBarHandler)); left_callback = new TimerFunctor; left_callback->tick.connect(sigc::mem_fun(this, &HScrollBar::ScrollLeft)); right_callback = new TimerFunctor; right_callback->tick.connect(sigc::mem_fun(this, &HScrollBar::ScrollRight)); trackleft_callback = new TimerFunctor; trackleft_callback->tick.connect(sigc::mem_fun(this, &HScrollBar::TrackLeft)); trackright_callback = new TimerFunctor; trackright_callback->tick.connect(sigc::mem_fun(this, &HScrollBar::TrackRight)); SetLayout(hlayout); SetAcceptMouseWheelEvent(true); } HScrollBar::~HScrollBar() { _slider->UnReference(); delete callback; delete left_callback; delete trackleft_callback; delete right_callback; delete trackright_callback; } void HScrollBar::HScrollBarHandler(void *v) { HScrollBar *scrollbar = static_cast (v); if (scrollbar->b_MouseUpTimer && scrollbar->m_color_factor < 1) { scrollbar->m_color_factor += 0.1f; if (scrollbar->m_color_factor >= 1) { scrollbar->m_color_factor = 1; scrollbar->b_MouseUpTimer = false; } else { scrollbar->QueueDraw(); GetTimer().AddOneShotTimer(10, callback, scrollbar); } } if (scrollbar->b_MouseDownTimer && scrollbar->m_color_factor > 0) { scrollbar->m_color_factor -= 0.09f; if (scrollbar->m_color_factor <= 0) { scrollbar->m_color_factor = 0; scrollbar->b_MouseUpTimer = false; } else { scrollbar->QueueDraw(); GetTimer().AddOneShotTimer(10, callback, scrollbar); } } } void HScrollBar::ScrollRight(void * /* v */) { OnScrollRight.emit(m_ScrollUnit, 1); if (AtMaximum()) RecvEndScrollRight(0, 0, 0, 0); else m_RightTimerHandler = GetTimer().AddOneShotTimer(10, right_callback, this); QueueDraw(); } void HScrollBar::ScrollLeft(void * /* v */) { OnScrollLeft.emit(m_ScrollUnit, 1); if (AtMaximum()) RecvEndScrollLeft(0, 0, 0, 0); else m_LeftTimerHandler = GetTimer().AddOneShotTimer(10, left_callback, this); QueueDraw(); } void HScrollBar::TrackLeft(void * /* v */) { if (m_TrackMouseCoord.x < _slider->GetBaseX() - _track->GetBaseX()) { OnScrollLeft.emit(container_width_, 1); m_TrackLeftTimerHandler = GetTimer().AddOneShotTimer(10, trackleft_callback, this); QueueDraw(); } } void HScrollBar::TrackRight(void * /* v */) { if (m_TrackMouseCoord.x > _slider->GetBaseX() + _slider->GetBaseWidth() - _track->GetBaseX()) { OnScrollRight.emit(container_width_, 1); m_TrackRightTimerHandler = GetTimer().AddOneShotTimer(10, trackright_callback, this); QueueDraw(); } } void HScrollBar::RecvStartScrollLeft(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (!AtMinimum()) ScrollLeft(this); } void HScrollBar::RecvStartScrollRight(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (!AtMaximum()) ScrollRight(this); } void HScrollBar::RecvEndScrollRight(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_RightTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_RightTimerHandler); m_RightTimerHandler = 0; } void HScrollBar::RecvEndScrollLeft(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_LeftTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_LeftTimerHandler); m_LeftTimerHandler = 0; } void HScrollBar::RecvTrackMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { m_TrackMouseCoord = Point(x, y); int X = _slider->GetBaseX() - _track->GetBaseX(); if (x < X) { // move the slide bar up TrackLeft(this); } else { TrackRight(this); // move the slide bar down } } void HScrollBar::RecvTrackMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_TrackLeftTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_TrackLeftTimerHandler); if (m_TrackRightTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_TrackRightTimerHandler); m_TrackLeftTimerHandler = 0; m_TrackRightTimerHandler = 0; } void HScrollBar::RecvTrackMouseDrag(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { } Area* HScrollBar::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; NUX_RETURN_VALUE_IF_TRUE(_scroll_right_button->TestMousePointerInclusion(mouse_position, event_type), _scroll_right_button); NUX_RETURN_VALUE_IF_TRUE(_scroll_left_button->TestMousePointerInclusion(mouse_position, event_type), _scroll_left_button); NUX_RETURN_VALUE_IF_TRUE(_slider->TestMousePointerInclusion(mouse_position, event_type), _slider); NUX_RETURN_VALUE_IF_TRUE(_track->TestMousePointerInclusion(mouse_position, event_type), _track); if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } void HScrollBar::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); GetPainter().PaintBackground(graphics_engine, base); base.OffsetPosition(HSCROLLBAR_WIDTH, 0); base.OffsetSize(-2 * HSCROLLBAR_WIDTH, 0); GetPainter().PaintShape(graphics_engine, base, Color(COLOR_SCROLLBAR_TRACK), eHSCROLLBAR, false); GetPainter().PaintShape(graphics_engine, _scroll_left_button->GetGeometry(), Color(0xFFFFFFFF), eSCROLLBAR_TRIANGLE_LEFT); GetPainter().PaintShape(graphics_engine, _scroll_right_button->GetGeometry(), Color(0xFFFFFFFF), eSCROLLBAR_TRIANGLE_RIGHT); GetPainter().PaintShape(graphics_engine, _slider->GetGeometry(), Color(0.2156 * m_color_factor, 0.2156 * m_color_factor, 0.2156 * m_color_factor, 1.0f), eHSCROLLBAR, true); }; void HScrollBar::SetContainerSize(int /* x */, int /* y */, int w, int h) { // x and y are not needed container_width_ = w; container_height_ = h; ComputeScrolling(); } void HScrollBar::SetContentSize(int /* x */, int /* y */, int w, int h) { // x and y are not needed content_width_ = w; content_height_ = h; ComputeScrolling(); } void HScrollBar::SetContentOffset(float dx, float dy) { content_offset_x_ = dx; content_offset_y_ = dy; ComputeScrolling(); } void HScrollBar::ComputeScrolling() { if (content_width_ == 0) { visibility_percentage_ = 100.0f; } else { visibility_percentage_ = Clamp(100.0f * (float) container_width_ / (float) content_width_, 0.0f, 100.0f); } m_TrackWidth = _track->GetBaseWidth(); int slider_height = _scroll_left_button->GetBaseHeight(); int slider_width = m_TrackWidth * visibility_percentage_ / 100.0f; if (slider_width < 15) { slider_width = 15; } _slider->SetBaseWidth(slider_width); _slider->SetBaseHeight(slider_height); _slider->SetBaseY(_scroll_left_button->GetBaseY()); float pct; if (content_width_ - container_width_ > 0) pct = - (float) content_offset_x_ / (float) (content_width_ - container_width_); else pct = 0; int x = _track->GetBaseX() + pct * (m_TrackWidth - slider_width); _slider->SetBaseX(x); } ///////////////// // RECEIVERS // ///////////////// void HScrollBar::SetValue(float /* value */) { //m_ValueString.setCaption(value); } void HScrollBar::SetParameterName(const char * /* parameter_name */) { //m_ParameterName.setCaption(parameter_name); } //////////////// // EMITTERS // //////////////// void HScrollBar::OnSliderMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { m_SliderDragPositionX = x; m_SliderDragPositionY = y; //sigVScrollBarSliderMouseDown.emit(); b_MouseDownTimer = true; b_MouseUpTimer = false; GetTimer().AddOneShotTimer(10, callback, this); } void HScrollBar::OnSliderMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { b_MouseDownTimer = false; b_MouseUpTimer = true; GetTimer().AddOneShotTimer(10, callback, this); } void HScrollBar::OnSliderMouseDrag(int x, int /* y */, int dx, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (_track->GetBaseWidth() - _slider->GetBaseWidth() > 0) { stepX = (float) (content_width_ - container_width_) / (float) (_track->GetBaseWidth() - _slider->GetBaseWidth()); } else { return; } if ((dx > 0) && (x > m_SliderDragPositionX)) { OnScrollRight.emit(stepX, x - m_SliderDragPositionX); } if ((dx < 0) && (x < m_SliderDragPositionX)) { OnScrollLeft.emit(stepX, m_SliderDragPositionX - x); } } bool HScrollBar::AtMaximum() { if (_slider->GetBaseX() + _slider->GetBaseWidth() == _track->GetBaseX() + _track->GetBaseWidth()) return TRUE; return FALSE; } bool HScrollBar::AtMinimum() { if (_slider->GetBaseX() == _track->GetBaseX()) return TRUE; return FALSE; } long HScrollBar::PostLayoutManagement(long LayoutResult) { long ret = ScrollBar::PostLayoutManagement(LayoutResult); ComputeScrolling(); return ret; } } nux-4.0.8+18.10.20180623/Nux/HScrollBar.h0000644000000000000000000001101713313373365013517 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef HSCROLLBAR_H #define HSCROLLBAR_H #include "TimerProc.h" #include "ScrollBar.h" namespace nux { class HLayout; class HScrollBar : public ScrollBar { public: HScrollBar(NUX_FILE_LINE_PROTO); ~HScrollBar(); void DrawLeftTriangle(GraphicsEngine &graphics_engine, int width, int height, const Geometry &geo, BasePainter &painter); void DrawRightTriangle(GraphicsEngine &graphics_engine, int width, int height, const Geometry &geo, BasePainter &painter); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); private: virtual void DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) {}; void HScrollBarHandler(void *v); void ScrollRight(void *v); void ScrollLeft(void *v); void TrackLeft(void *v); void TrackRight(void *v); public: void SetContainerSize(int x, int y, int w, int h); void SetContentSize(int x, int y, int w, int h); void SetContentOffset(float dx, float dy); void ComputeScrolling(); ///////////////// // RECEIVERS // ///////////////// void SetValue(float value); void SetParameterName(const char *parameter_name); //////////////// // EMITTERS // //////////////// void RecvStartScrollRight(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvStartScrollLeft(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvEndScrollRight(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvEndScrollLeft(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTrackMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTrackMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTrackMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnSliderMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnSliderMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnSliderMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); /////////////// // SIGNALS // /////////////// sigc::signal sigClick; sigc::signal OnScrollLeft; sigc::signal OnScrollRight; sigc::signal sigHScrollBarSliderMouseDown; bool b_MouseDownTimer; bool b_MouseUpTimer; float m_color_factor; protected: // When the Scrollbar is used standalone, it is necessary to call ComputeScrolling at the end of the layout. virtual long PostLayoutManagement(long LayoutResult); virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); bool AtMinimum(); bool AtMaximum(); HLayout *hlayout; BasicView *_slider; BasicView *_scroll_left_button; BasicView *_scroll_right_button; BasicView *_track; int content_width_; int content_height_; float content_offset_x_; float content_offset_y_; int container_width_; int container_height_; int m_TrackWidth; int m_TrackHeight; int m_SlideBarOffsetX; int m_SlideBarOffsetY; float stepX; float stepY; int m_SliderDragPositionX; int m_SliderDragPositionY; TimerFunctor *callback; TimerFunctor *left_callback; TimerFunctor *right_callback; TimerFunctor *trackleft_callback; TimerFunctor *trackright_callback; TimerHandle m_LeftTimerHandler; TimerHandle m_RightTimerHandler; TimerHandle m_TrackLeftTimerHandler; TimerHandle m_TrackRightTimerHandler; Point m_TrackMouseCoord; friend class HLayout; friend class ScrollView; }; } #endif // HSCROLLBAR_H nux-4.0.8+18.10.20180623/Nux/HSplitter.cpp0000644000000000000000000005015713313373365014005 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "HSplitter.h" #include "NuxGraphics/GLTextureResourceManager.h" #include "WindowCompositor.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(HSplitter); static const int HSPLITTERHEIGHT = 5; static const int HSTICK_SIZE = 5; HSplitter::HSplitter(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { new_addition = false; m_initial_config = true; m_focus_splitter_index = -1; m_ResizeOnSplitterRelease = true; mvt_dx = 0; mvt_dy = 0; m_current_x = 0; m_current_y = 0; m_current_width = 200; m_current_height = 200; //SetMinimumSize(200,200); SetGeometry(Geometry(m_current_x, m_current_y, m_current_width, m_current_height)); } HSplitter::~HSplitter() { std::vector< Area* >::iterator it0; for (it0 = m_InterfaceObject.begin(); it0 != m_InterfaceObject.end(); it0++) { (*it0)->UnParentObject(); } m_InterfaceObject.clear(); std::vector< MySplitter* >::iterator it2; for (it2 = m_SplitterObject.begin(); it2 != m_SplitterObject.end(); it2++) { (*it2)->UnParentObject(); } m_SplitterObject.clear(); m_SplitConfig.clear(); } void HSplitter::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { graphics_engine.PushClippingRectangle(GetGeometry()); Geometry base = GetGeometry(); // std::vector::iterator it; // for (it = m_InterfaceObject.begin(); it != m_InterfaceObject.end(); it++) // { // (*it)->ProcessDraw(force_draw); // } GetPainter().PaintBackground(graphics_engine, base); std::vector::iterator it_splitter; for (it_splitter = m_SplitterObject.begin(); it_splitter != m_SplitterObject.end(); it_splitter++) { Geometry geo = (*it_splitter)->GetGeometry(); Geometry grip_geo; int w = 20; if (geo.GetWidth() > w) { grip_geo.SetX(geo.x + (geo.GetWidth() - w) / 2); grip_geo.SetY(geo.y); grip_geo.SetWidth(w); grip_geo.SetHeight(geo.GetHeight()); } else { grip_geo.SetX(geo.x - (w - geo.GetWidth()) / 2); grip_geo.SetY(geo.y); grip_geo.SetWidth(w); grip_geo.SetHeight(geo.GetHeight()); } GetPainter().Draw2DLine(graphics_engine, grip_geo.x, grip_geo.y + 1, grip_geo.x + grip_geo.GetWidth(), grip_geo.y + 1, Color(0xFF111111)); GetPainter().Draw2DLine(graphics_engine, grip_geo.x, grip_geo.y + 3, grip_geo.x + grip_geo.GetWidth(), grip_geo.y + 3, Color(0xFF111111)); } graphics_engine.PopClippingRectangle(); } void HSplitter::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); bool need_redraw = IsRedrawNeeded(); std::vector::iterator it_splitter; std::vector::iterator it; //for(it = m_InterfaceObject.begin(); it != m_InterfaceObject.end(); it++) for (it = m_InterfaceObject.begin(), it_splitter = m_SplitterObject.begin(); it != m_InterfaceObject.end(); it++, it_splitter++) { Geometry sgeo = (*it_splitter)->GetGeometry(); graphics_engine.PushClippingRectangle(Rect( base.x, base.y, base.GetWidth(), sgeo.y - base.y)); base.SetY(sgeo.y + sgeo.GetHeight()); if (force_draw || need_redraw) { if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = static_cast(*it); ic->ProcessDraw(graphics_engine, true); } else if ((*it)->Type().IsObjectType(HLayout::StaticObjectType)) { HLayout *layout = static_cast(*it); layout->ProcessDraw(graphics_engine, true); } else if ((*it)->Type().IsObjectType(VLayout::StaticObjectType)) { VLayout *layout = static_cast(*it); layout->ProcessDraw(graphics_engine, true); } } else { if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = static_cast(*it); ic->ProcessDraw(graphics_engine, false); } else if ((*it)->Type().IsObjectType(HLayout::StaticObjectType)) { HLayout *layout = static_cast(*it); layout->ProcessDraw(graphics_engine, false); } else if ((*it)->Type().IsObjectType(VLayout::StaticObjectType)) { VLayout *layout = static_cast(*it); layout->ProcessDraw(graphics_engine, false); } } graphics_engine.PopClippingRectangle(); } graphics_engine.PopClippingRectangle(); } void HSplitter::OverlayDrawing(GraphicsEngine &graphics_engine) { unsigned int num_element = (unsigned int) m_SplitterObject.size(); Geometry base = GetGeometry(); if (m_focus_splitter_index >= 0) { Geometry geo = m_SplitterObject[m_focus_splitter_index]->GetGeometry(); geo.OffsetPosition(mvt_dx, mvt_dy); if (m_focus_splitter_index == 0 && num_element > 1) { if (geo.y < base.y) { geo.SetY(base.y); } if (geo.y + HSPLITTERHEIGHT > m_SplitterObject[m_focus_splitter_index + 1]->GetGeometry().y) { geo.SetY(m_SplitterObject[m_focus_splitter_index+1]->GetGeometry().y - HSPLITTERHEIGHT); } } if ((m_focus_splitter_index > 0) && (m_focus_splitter_index < (int) num_element - 1)) { if (geo.y < m_SplitterObject[m_focus_splitter_index - 1]->GetGeometry().y + HSPLITTERHEIGHT) { geo.SetY(m_SplitterObject[m_focus_splitter_index - 1]->GetGeometry().y + HSPLITTERHEIGHT); } if (geo.y + HSPLITTERHEIGHT > m_SplitterObject[m_focus_splitter_index + 1]->GetGeometry().y) { geo.SetY(m_SplitterObject[m_focus_splitter_index + 1]->GetGeometry().y - HSPLITTERHEIGHT); } } graphics_engine.GetRenderStates().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); { GetPainter().Paint2DQuadColor(graphics_engine, geo, Color(0xBB868686)); } graphics_engine.GetRenderStates().SetBlend(false); } } void HSplitter::AddWidget(Area *ic, float stretchfactor) { if (ic) { MySplitter *splitter = new MySplitter; splitter->SetParentObject(this); //splitter->SinkReference(); unsigned int no = (unsigned int) m_InterfaceObject.size(); splitter->mouse_down.connect(sigc::bind(sigc::mem_fun(this, &HSplitter::OnSplitterMouseDown), no)); splitter->mouse_drag.connect(sigc::bind(sigc::mem_fun(this, &HSplitter::OnSplitterMouseDrag), no)); splitter->mouse_up.connect(sigc::bind(sigc::mem_fun(this, &HSplitter::OnSplitterMouseUp), no)); ic->SetParentObject(this); m_InterfaceObject.push_back(ic); m_SplitterObject.push_back(splitter); m_SplitConfig.push_back(stretchfactor); new_addition = true; ComputeContentSize(); } } void HSplitter::clearContent() { m_InterfaceObject.clear(); } long HSplitter::ComputeContentSize() { unsigned int num_element = (unsigned int) m_InterfaceObject.size(); int x = GetBaseX(); int y = GetBaseY(); int w = GetBaseWidth(); int h = GetBaseHeight(); if ((w == 0) || (h == 0)) { return eCompliantHeight | eCompliantWidth; } if (num_element < 1) { m_current_height = h; m_current_width = w; m_current_x = x; m_current_y = y; new_addition = false; return eCompliantHeight | eCompliantWidth; } std::vector::iterator it; std::vector::iterator it_splitter; if (new_addition) { ResetSplitConfig(); new_addition = false; } if (m_current_width != w) { for (unsigned int i = 0; i < num_element; i++) { Geometry splitter_geo = m_SplitterObject[i]->GetGeometry(); splitter_geo.SetWidth(w); splitter_geo.SetX(x); m_SplitterObject[i]->SetGeometry(splitter_geo); } } if (m_current_height != h) { int size_to_distribute = h - num_element * HSPLITTERHEIGHT; int previous_spliter_end = m_current_y; int new_spliter_end = y; for (unsigned int i = 0; i < num_element; i++) { Geometry splitter_geo = m_SplitterObject[i]->GetGeometry(); // compute percentage of space occupied by the element i; // width of element i = m_SplitterObject[i]->GetY() - previous_splliter_end int splitter_start = m_SplitterObject[i]->GetBaseY(); float percent = float(splitter_start - previous_spliter_end) / float(m_current_height - num_element * HSPLITTERHEIGHT); if (percent > 1.0f) percent = 1.0f; splitter_geo.SetY(new_spliter_end + size_to_distribute * percent); previous_spliter_end = splitter_start + HSPLITTERHEIGHT; new_spliter_end = new_spliter_end + size_to_distribute * percent + HSPLITTERHEIGHT; m_SplitterObject[i]->SetGeometry(splitter_geo); } if (m_SplitterObject[0]->GetBaseY() < y) { m_SplitterObject[0]->SetBaseY(y); } m_SplitterObject[num_element-1]->SetBaseY(y + h - HSPLITTERHEIGHT); } int accheight = y; for (unsigned int i = 0; i < num_element; i++) { Geometry splitter_geo = m_SplitterObject[i]->GetGeometry(); //m_InterfaceObject[i]->SetGeometry(Geometry(x, accheight, w, splitter_geo.y - accheight)); if (m_InterfaceObject[i]->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = static_cast(m_InterfaceObject[i]); ic->SetGeometry(Geometry(x, accheight, w, splitter_geo.y - accheight)); // if we are already computing the layout from the main window down, we need to call // ComputeElementLayout to force the computing of this element layout. GetWindowThread()->ComputeElementLayout(ic); } else if (m_InterfaceObject[i]->Type().IsDerivedFromType(Layout::StaticObjectType)) { Layout *layout = static_cast(m_InterfaceObject[i]); layout->SetGeometry(Geometry(x, accheight, w, splitter_geo.y - accheight)); // if we are already computing the layout from the main window down, we need to call // ComputeElementLayout to force the computing of this element layout. GetWindowThread()->ComputeElementLayout(layout); } accheight += splitter_geo.y - accheight + HSPLITTERHEIGHT; } m_current_height = h; m_current_width = w; m_current_x = x; m_current_y = y; return eCompliantHeight | eCompliantWidth; } void HSplitter::ResetSplitConfig() { int x = GetBaseX(); int y = GetBaseY(); int w = GetBaseWidth(); int h = GetBaseHeight(); unsigned int num_element = (unsigned int) m_InterfaceObject.size(); if (num_element < 1) { return; } float max_stretch = 0.0f; float stretchfactor; for (unsigned int i = 0; i < (unsigned int) m_SplitConfig.size(); i++) { stretchfactor = m_SplitConfig[i]; if (max_stretch < stretchfactor) { max_stretch = stretchfactor; } } float total = 0; for (unsigned int i = 0; i < (unsigned int) m_SplitConfig.size(); i++) { stretchfactor = m_SplitConfig[i]; total += stretchfactor / max_stretch; } int availableheight = (h - num_element * HSPLITTERHEIGHT); float max_size = float(availableheight) / total; for (unsigned int i = 0; i < (unsigned int) m_SplitConfig.size(); i++) { stretchfactor = m_SplitConfig[i]; y += stretchfactor * max_size / max_stretch; Geometry geo(x, y, w, HSPLITTERHEIGHT); m_SplitterObject[i]->SetGeometry(geo); } m_SplitterObject[num_element-1]->SetBaseX(y + h - HSPLITTERHEIGHT); m_initial_config = true; } void HSplitter::OnSplitterMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */, int header_pos) { m_point = Point(x, y); m_focus_splitter_index = header_pos; GetWindowThread()->GetWindowCompositor().SetWidgetDrawingOverlay(this, GetWindowThread()->GetWindowCompositor().GetProcessingTopView()); // Hint for the window to initiate a redraw GetWindowThread()->RequestRedraw(); } void HSplitter::OnSplitterMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */, int header_pos) { if (mvt_dy) { Geometry geo = m_SplitterObject[header_pos]->GetGeometry(); geo.OffsetPosition(0, mvt_dy); unsigned int num_element = (unsigned int) m_SplitterObject.size(); if (header_pos < (int) num_element - 1) { // Make the splitter bar stick to the next one if the distance between them is less than HSTICK_SIZE. if (m_SplitterObject[header_pos + 1]->GetGeometry().y - geo.y - HSPLITTERHEIGHT < HSTICK_SIZE) geo.SetY( m_SplitterObject[header_pos + 1]->GetGeometry().y - HSPLITTERHEIGHT ); } m_SplitterObject[header_pos]->SetGeometry(geo); ResizeSplitter(header_pos); } m_focus_splitter_index = -1; mvt_dx = 0; mvt_dy = 0; // End overlay drawing; GetWindowThread()->GetWindowCompositor().SetWidgetDrawingOverlay(0, GetWindowThread()->GetWindowCompositor().GetProcessingTopView()); // Hint for the window to initiate a redraw GetWindowThread()->RequestRedraw(); } void HSplitter::OnSplitterMouseDrag(int /* x */, int y, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */, int header_pos) { Geometry geo = m_SplitterObject[header_pos]->GetGeometry(); int num_element = (int) m_SplitterObject.size(); if (header_pos == num_element - 1) { // The last splitter cannot be moved return; } mvt_dx = 0; mvt_dy = (y - m_point.y); if (m_ResizeOnSplitterRelease == false) { // Continuously redraw resize and redraw the 2 parts of the widget. // This is slow. geo.OffsetPosition(mvt_dx, mvt_dy); m_SplitterObject[header_pos]->SetGeometry(geo); ResizeSplitter(header_pos); mvt_dx = 0; mvt_dy = 0; } // Hint for the window to initiate a redraw GetWindowThread()->RequestRedraw(); } void HSplitter::ResizeSplitter(int header_pos) { int num_element = (int) m_SplitterObject.size(); if ((header_pos == 0) && (m_SplitterObject[header_pos]->GetBaseY() < GetBaseY())) { m_SplitterObject[header_pos]->SetBaseY(GetBaseY()); } if ((header_pos == num_element - 1) && (m_SplitterObject[header_pos]->GetBaseY() > GetBaseY() + GetBaseHeight() - HSPLITTERHEIGHT)) { m_SplitterObject[header_pos]->SetBaseY(GetBaseY() + GetBaseHeight() - HSPLITTERHEIGHT); } if (header_pos < (int) num_element - 1) { int posy0, posy1; posy0 = m_SplitterObject[header_pos]->GetBaseY(); posy1 = m_SplitterObject[header_pos + 1]->GetBaseY(); if (posy0 > posy1 - HSPLITTERHEIGHT) { posy0 = posy1 - HSPLITTERHEIGHT; m_SplitterObject[header_pos]->SetBaseY(posy0); } } if (0 < header_pos) { int posy0, posy1; posy0 = m_SplitterObject[header_pos]->GetBaseY(); posy1 = m_SplitterObject[header_pos - 1]->GetBaseY(); if (posy0 < posy1 + HSPLITTERHEIGHT) { posy0 = posy1 + HSPLITTERHEIGHT; m_SplitterObject[header_pos]->SetBaseY(posy0); } } ComputeContentSize(); QueueDraw(); } // HSplitter need to re implement DoneRedraw because it does not // have a m_compositionlayout where its child are located; void HSplitter::DoneRedraw() { std::vector::iterator it; for (it = m_InterfaceObject.begin(); it != m_InterfaceObject.end(); it++) { //(*it)->DoneRedraw(); if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = static_cast(*it); ic->DoneRedraw(); } } } Area* HSplitter::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; std::vector::iterator splitter_it; for (splitter_it = m_SplitterObject.begin(); splitter_it != m_SplitterObject.end(); splitter_it++) { Area* found_area = (*splitter_it)->FindAreaUnderMouse(mouse_position, event_type); if (found_area) return found_area; } std::vector::iterator it; for (it = m_InterfaceObject.begin(); it != m_InterfaceObject.end(); it++) { Area* found_area = (*it)->FindAreaUnderMouse(mouse_position, event_type); if (found_area) return found_area; } if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } bool HSplitter::AcceptKeyNavFocus() { return false; } Area* HSplitter::KeyNavIteration(KeyNavDirection direction) { if (m_InterfaceObject.empty()) return NULL; if (next_object_to_key_focus_area_) { if ((direction == KEY_NAV_LEFT) || (direction == KEY_NAV_RIGHT)) { // Don't know what to do with this return NULL; } std::vector::iterator it; std::vector::iterator it_next; it = std::find(m_InterfaceObject.begin(), m_InterfaceObject.end(), next_object_to_key_focus_area_); if (it == m_InterfaceObject.end()) { // Should never happen nuxAssert(0); return NULL; } it_next = it; ++it_next; if ((direction == KEY_NAV_UP) && (it == m_InterfaceObject.begin())) { // can't go further return NULL; } if ((direction == KEY_NAV_DOWN) && (it_next == m_InterfaceObject.end())) { // can't go further return NULL; } if (direction == KEY_NAV_UP) { --it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { if (it == m_InterfaceObject.begin()) break; --it; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_DOWN) { ++it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == m_InterfaceObject.end()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } } else { Area* key_nav_focus = NULL; if (direction == KEY_NAV_UP) { std::vector::reverse_iterator it = m_InterfaceObject.rbegin(); key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == m_InterfaceObject.rend()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } } else { std::vector::iterator it = m_InterfaceObject.begin(); key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == m_InterfaceObject.end()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } } return key_nav_focus; } return NULL; } } nux-4.0.8+18.10.20180623/Nux/HSplitter.h0000644000000000000000000000602213313373365013442 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef HSPLITTER_H #define HSPLITTER_H namespace nux { class Layout; class HSplitter: public View { NUX_DECLARE_OBJECT_TYPE(HSplitter, View); public: HSplitter(NUX_FILE_LINE_PROTO); ~HSplitter(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); void AddWidget(Area *ic, float stretchfactor); void ResetSplitConfig(); void clearContent(); void OnSplitterMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags, int header_pos); void OnSplitterMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags, int header_pos); void OnSplitterMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags, int header_pos); virtual void OverlayDrawing(GraphicsEngine &graphics_engine); //! Return true if this object can break the layout. /* Return true if this object can break the layout, meaning, the layout can be done on the composition layout only without recomputing the whole window layout. Inherited from Area */ virtual bool CanBreakLayout() { return true; } virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); protected: virtual long ComputeContentSize(); virtual void DoneRedraw(); void ResizeSplitter(int header_pos); //void ContinuousSplitterAdjustment(); void setResizeOnSplitterRelease(bool b) { m_ResizeOnSplitterRelease = b; } bool getResizeOnSplitterRelease() { return m_ResizeOnSplitterRelease; } virtual bool AcceptKeyNavFocus(); virtual Area* KeyNavIteration(KeyNavDirection direction); private: typedef BasicView MySplitter; std::vector m_InterfaceObject; std::vector m_SplitterObject; std::vector m_SplitConfig; Point m_point; bool new_addition; bool m_ResizeOnSplitterRelease; int m_current_width; int m_current_height; int m_current_x; int m_current_y; bool m_initial_config; // splitter bar differential position; int mvt_dx, mvt_dy; int m_focus_splitter_index; }; } #endif // HSPLITTER_H nux-4.0.8+18.10.20180623/Nux/HexRegExpValidator.cpp0000644000000000000000000000550313313373365015567 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "HexRegExpValidator.h" namespace nux { HexRegExpValidator::HexRegExpValidator(int Minimum, int Maximum) : m_Minimum(Minimum) , m_Maximum(Maximum) { _regexp_str = "^(0[xX])*[0-9a-fA-F]+$"; InitRegExp(); if (m_Minimum > m_Maximum) { int temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } HexRegExpValidator::HexRegExpValidator(const HexRegExpValidator ©) { m_Minimum = copy.m_Minimum; m_Maximum = copy.m_Maximum; _regexp_str = copy._regexp_str; InitRegExp(); } HexRegExpValidator &HexRegExpValidator::operator= (const HexRegExpValidator &rhs) { if (&rhs != this) { m_Minimum = rhs.m_Minimum; m_Maximum = rhs.m_Maximum; _regexp_str = rhs._regexp_str; InitRegExp(); } return *this; } HexRegExpValidator::~HexRegExpValidator() { } Validator *HexRegExpValidator::Clone() const { return new HexRegExpValidator(*this); } void HexRegExpValidator::SetMinimum(int value) { m_Minimum = value; if (m_Minimum > m_Maximum) { int temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } int HexRegExpValidator::GetMinimum() const { return m_Minimum; } void HexRegExpValidator::SetMaximum(int value) { m_Maximum = value; if (m_Minimum > m_Maximum) { int temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } int HexRegExpValidator::GetMaximum() const { return m_Maximum; } int HexRegExpValidator::GetClampedValue(int i) const { if (i < m_Minimum) return m_Minimum; if (i > m_Maximum) return m_Maximum; return i; } void HexRegExpValidator::Alternative(const char * /* str */) { } std::string HexRegExpValidator::ToString(int i) { return std::to_string((long long)i); } int HexRegExpValidator::ToInteger(const char *str) { if (Validate(str) == Acceptable) return HexCharToInteger(str); else return 0; } } nux-4.0.8+18.10.20180623/Nux/HexRegExpValidator.h0000644000000000000000000000326613313373365015240 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef HEXREGEXPVALIDATOR_H #define HEXREGEXPVALIDATOR_H #include "Validator.h" namespace nux { class HexRegExpValidator : public Validator { public: HexRegExpValidator(int Minimum = INT_MIN, int Maximum = INT_MAX); HexRegExpValidator(const HexRegExpValidator &validator); HexRegExpValidator &operator= (const HexRegExpValidator &rhs); virtual ~HexRegExpValidator(); virtual Validator *Clone() const; //Virtual Constructor Idiom /*! @return The input value clamped to the range [m_Minimum, m_Maximum]. */ int GetClampedValue(int i) const; virtual void Alternative(const char *str); void SetMinimum(int value); int GetMinimum() const; void SetMaximum(int value); int GetMaximum() const; std::string ToString(int i); int ToInteger(const char *str); private: int m_Minimum; int m_Maximum; }; } #endif // HEXREGEXPVALIDATOR_H nux-4.0.8+18.10.20180623/Nux/InputArea.cpp0000644000000000000000000003261213313373365013753 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include #include #include #include #include "Nux.h" #include "InputArea.h" #include "NuxGraphics/GraphicsEngine.h" #include "WindowCompositor.h" #ifdef NUX_GESTURES_SUPPORT #include "GesturesSubscription.h" #endif namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(InputArea); InputArea::InputArea(NUX_FILE_LINE_DECL) : Area(NUX_FILE_LINE_PARAM) , area_color_(color::Green) , accept_key_nav_focus_on_mouse_down_(true) , accept_key_nav_focus_on_mouse_enter_(false) , is_tracking_child_mouse_events_(false) { SetGeometry(0, 0, 1, 1); mouse_in_ = false; _capture_mouse_down_any_where_else = false; _double_click = false; _dnd_enabled_as_source = false; _dnd_enabled_as_target = false; _dnd_safety_x = 0; _dnd_safety_y = 0; _keyboard_receiver_ignore_mouse_down_outside = false; } InputArea::~InputArea() { while (GetWindowCompositor().GrabPointerRemove(this)); while (GetWindowCompositor().GrabKeyboardRemove(this)); } void InputArea::OnDraw(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { // Draw Nothing! // For debug Only: // graphics_engine.QRP_Color(GetBaseX(), GetBaseY(), GetBaseWidth(), GetBaseHeight(), area_color_); } bool InputArea::HasKeyboardFocus() { return GetWindowThread()->GetWindowCompositor().GetKeyFocusArea() == this; } bool InputArea::IsMouseInside() { return mouse_in_; } // TODO: DEPRECATED bool InputArea::MouseFocusOnOtherArea() { return false; } void InputArea::CaptureMouseDownAnyWhereElse(bool b) { _capture_mouse_down_any_where_else = b; } bool InputArea::IsCaptureMouseDownAnyWhereElse() const { return _capture_mouse_down_any_where_else; } void InputArea::EnableDoubleClick(bool double_click) { _double_click = double_click; } bool InputArea::DoubleClickEnabled() const { return _double_click; } void InputArea::SetKeyboardReceiverIgnoreMouseDownOutside(bool ignore_mouse_down_outside) { _keyboard_receiver_ignore_mouse_down_outside = ignore_mouse_down_outside; } bool InputArea::KeyboardReceiverIgnoreMouseDownOutside() { return _keyboard_receiver_ignore_mouse_down_outside; } void InputArea::HandleDndMove(Event &event) { #if defined(DRAG_AND_DROP_SUPPORTED) std::list mimes; mimes = GetWindowThread()->GetGraphicsDisplay().GetDndMimeTypes(); std::list::iterator it; ProcessDndMove(event.x, event.y, mimes); for (it = mimes.begin(); it != mimes.end(); it++) g_free(*it); #endif } void InputArea::HandleDndDrop(Event &event) { #if defined(DRAG_AND_DROP_SUPPORTED) ProcessDndDrop(event.x, event.y); #endif } #if defined(NUX_OS_LINUX) void InputArea::SendDndStatus(bool accept, DndAction action, Geometry region) { #if defined(DRAG_AND_DROP_SUPPORTED) GetWindowThread()->GetGraphicsDisplay().SendDndStatus(accept, action, Rect(region.x, region.y, region.width, region.height)); #endif } void InputArea::SendDndFinished(bool accepted, DndAction action) { #if defined(DRAG_AND_DROP_SUPPORTED) GetWindowThread()->GetGraphicsDisplay().SendDndFinished(accepted, action); #endif } void InputArea::ProcessDndMove(int x, int y, std::list /* mimes */) { #if defined(DRAG_AND_DROP_SUPPORTED) // must learn to deal with x/y offsets Area *parent = GetToplevel(); if (parent) { x += parent->GetGeometry().x; y += parent->GetGeometry().y; } SendDndStatus(false, DNDACTION_NONE, Geometry(x, y, GetGeometry().width, GetGeometry().height)); #endif } void InputArea::ProcessDndDrop(int /* x */, int /* y */) { #if defined(DRAG_AND_DROP_SUPPORTED) SendDndFinished(false, DNDACTION_NONE); #endif } void InputArea::ProcessDndEnter() { } void InputArea::ProcessDndLeave() { } void InputArea::SetDndEnabled(bool as_source, bool as_target) { #if defined(DRAG_AND_DROP_SUPPORTED) _dnd_enabled_as_source = as_source; _dnd_enabled_as_target = as_target; #endif } bool InputArea::DndSourceDragBegin() { return false; } NBitmapData* InputArea::DndSourceGetDragImage() { return 0; } std::list InputArea::DndSourceGetDragTypes() { std::list types; types.push_back("text/plain;charset=utf-8"); types.push_back("UTF8_STRING"); return types; } const char * InputArea::DndSourceGetDataForType(const char *type, int *size, int *format) { *format = 8; if (g_str_equal(type, "text/plain;charset=utf-8") || g_str_equal(type, "UTF8_STRING")) { *size = (int) strlen("this is just a test"); return "this is just a test"; } *size = 0; return 0; } void InputArea::InnerDndSourceDragFinished(DndAction result, void *data) { #if defined(DRAG_AND_DROP_SUPPORTED) InputArea *self = static_cast (data); self->DndSourceDragFinished(result); #endif } void InputArea::DndSourceDragFinished(DndAction /* result */) { } void InputArea::StartDragAsSource() { #if defined(DRAG_AND_DROP_SUPPORTED) GraphicsDisplay::DndSourceFuncs funcs; funcs.get_drag_image = &InputArea::InnerDndSourceGetDragImage; funcs.get_drag_types = &InputArea::InnerDndSourceGetDragTypes; funcs.get_data_for_type = &InputArea::InnerDndSourceGetDataForType; funcs.drag_finished = &InputArea::InnerDndSourceDragFinished; if (DndSourceDragBegin()) GetWindowThread()->GetGraphicsDisplay().StartDndDrag(funcs, this); #endif } #endif void InputArea::GrabPointer() { GetWindowThread()->GetWindowCompositor().GrabPointerAdd(this); } void InputArea::UnGrabPointer() { GetWindowThread()->GetWindowCompositor().GrabPointerRemove(this); } void InputArea::GrabKeyboard() { GetWindowThread()->GetWindowCompositor().GrabKeyboardAdd(this); } void InputArea::UnGrabKeyboard() { GetWindowThread()->GetWindowCompositor().GrabKeyboardRemove(this); } bool InputArea::OwnsPointerGrab() { return GetWindowThread()->GetWindowCompositor().GetPointerGrabArea() == this; } bool InputArea::OwnsKeyboardGrab() { return GetWindowThread()->GetWindowCompositor().GetKeyboardGrabArea() == this; } bool InputArea::IsMouseOwner() { return (GetWindowThread()->GetWindowCompositor().GetMouseOwnerArea() == this); } // == Signals with 1 to 1 mapping to input device == void InputArea::EmitMouseDownSignal(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_down.emit(x, y, mouse_button_state, special_keys_state); } void InputArea::EmitMouseUpSignal(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_up.emit(x, y, mouse_button_state, special_keys_state); } void InputArea::EmitMouseMoveSignal(int x, int y, int dx, int dy, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_move.emit(x, y, dx, dy, mouse_button_state, special_keys_state); } void InputArea::EmitMouseWheelSignal(int x, int y, int wheel_delta, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_wheel.emit(x, y, wheel_delta, mouse_button_state, special_keys_state); } void InputArea::EmitKeyDownSignal(unsigned int /* key_symbol */, unsigned long /* x11_key_code */, unsigned long /* special_keys_state */) { //OnKeyPressed.emit(key_symbol, x11_key_code, special_keys_state); } void InputArea::EmitKeyUpSignal(unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state) { key_up.emit(key_symbol, x11_key_code, special_keys_state); } void InputArea::EmitKeyEventSignal(unsigned long event_type, unsigned int key_sym, unsigned long special_keys_state, const char* text, int key_repeat_count) { key_down.emit( event_type, key_sym, special_keys_state, text, key_repeat_count); } void InputArea::EmitMouseDragSignal(int x, int y, int dx, int dy, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_drag.emit(x, y, dx, dy, mouse_button_state, special_keys_state); } void InputArea::EmitMouseEnterSignal(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_in_ = true; mouse_enter.emit(x, y, mouse_button_state, special_keys_state); } void InputArea::EmitMouseLeaveSignal(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_in_ = false; mouse_leave.emit(x, y, mouse_button_state, special_keys_state); } void InputArea::EmitMouseClickSignal(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_click.emit(x, y, mouse_button_state, special_keys_state); } void InputArea::EmitMouseDoubleClickSignal(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_double_click.emit(x, y, mouse_button_state, special_keys_state); } void InputArea::EmitMouseDownOutsideArea(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state) { mouse_down_outside_pointer_grab_area.emit(x, y, mouse_button_state, special_keys_state); } void InputArea::EmitMouseCancelSignal() { mouse_cancel.emit(); } Area* InputArea::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { if (TestMousePointerInclusion(mouse_position, event_type)) { return this; } return NULL; } Area* InputArea::FindKeyFocusArea(unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state) { if (has_key_focus_) { return this; } else if (next_object_to_key_focus_area_) { return next_object_to_key_focus_area_->FindKeyFocusArea(key_symbol, x11_key_code, special_keys_state); } return NULL; } bool InputArea::AcceptKeyNavFocus() { return false; } bool InputArea::AcceptKeyNavFocusOnMouseDown() const { return accept_key_nav_focus_on_mouse_down_; } bool InputArea::AcceptKeyNavFocusOnMouseEnter() const { return accept_key_nav_focus_on_mouse_enter_; } void InputArea::SetAcceptKeyNavFocusOnMouseDown(bool accept) { accept_key_nav_focus_on_mouse_down_ = accept; } void InputArea::SetAcceptKeyNavFocusOnMouseEnter(bool accept) { accept_key_nav_focus_on_mouse_enter_ = accept; } bool InputArea::AcceptKeyNavFocus() const { if (GetInputEventSensitivity() == false) return false; return true; } #ifdef NUX_GESTURES_SUPPORT void InputArea::CreateGesturesSubscription(int gesture_classes, unsigned int num_touches) { GesturesSubscription *subscription = new GesturesSubscription; subscription->SetGestureClasses(gesture_classes); subscription->SetNumTouches(num_touches); subscription->Activate(); gestures_subscriptions_.push_back(ShGesturesSubscription(subscription)); } void InputArea::AddGesturesSubscription( std::shared_ptr &subscription) { for (auto sub : gestures_subscriptions_) { if (sub.get() == subscription.get()) return; } gestures_subscriptions_.push_back(subscription); } void InputArea::RemoveGesturesSubscription( std::shared_ptr &subscription) { std::list >::iterator it; for (it = gestures_subscriptions_.begin(); it != gestures_subscriptions_.end(); ++it) { if (it->get() == subscription.get()) { gestures_subscriptions_.erase(it); return; } ++it; } } const std::list& InputArea::GetGesturesSubscriptions() const { return gestures_subscriptions_; } bool InputArea::HasSubscriptionForGesture(const nux::GestureEvent &event) const { for (const auto subscription : gestures_subscriptions_) { if (subscription->MatchesGesture(event)) return true; } return false; } Area* InputArea::GetInputAreaHitByGesture(const nux::GestureEvent &event) { if (!IsVisible()) return nullptr; if (!HasSubscriptionForGesture(event)) return nullptr; if (!IsGestureInsideArea(event)) return nullptr; return this; } #endif // NUX_GESTURES_SUPPORT void InputArea::SetTrackChildMouseEvents(bool enable) { is_tracking_child_mouse_events_ = enable; } bool InputArea::IsTrackingChildMouseEvents() const { return is_tracking_child_mouse_events_; } bool InputArea::ChildMouseEvent(const Event&) { return false; } } // namespace nux nux-4.0.8+18.10.20180623/Nux/InputArea.h0000644000000000000000000004654213313373365013427 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef INPUTAREA_H #define INPUTAREA_H #include "Area.h" #if defined(NUX_OS_WINDOWS) #include "NuxGraphics/Events.h" #elif defined(NUX_OS_LINUX) #include "NuxGraphics/Events.h" #endif #include "NuxGraphics/GraphicsDisplay.h" #ifdef NUX_GESTURES_SUPPORT #include #include #include "Nux/GesturesSubscription.h" #endif namespace nux { #ifdef NUX_GESTURES_SUPPORT class GestureEvent; #endif class WindowCompositor; class InputArea; typedef InputArea CoreArea; class InputArea : public Area { public: NUX_DECLARE_OBJECT_TYPE(InputArea, Area); public: InputArea(NUX_FILE_LINE_PROTO); virtual ~InputArea(); //! Draw InputArea. /*! Draw a colored quad using m_AreaColor. Override this function to define a custom drawing function. If force_draw is true then the system requests that all objects redraw themselves completely. \param force_draw. */ virtual void OnDraw(GraphicsEngine &graphics_engine, bool force_draw); virtual void OverlayDrawing(GraphicsEngine & /* graphics_engine */) {} bool HasKeyboardFocus(); bool MouseFocusOnOtherArea(); void CaptureMouseDownAnyWhereElse(bool b); bool IsCaptureMouseDownAnyWhereElse() const; Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); Area* FindKeyFocusArea(unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state); virtual bool AcceptKeyNavFocus() const; /*! Sets whether this InputArea wants to know about all mouse events sent to a child InputArea. ChildMouseEvent() will be called for every mouse event that a child InputArea receives. \param enable Whether this InputArea should be informed about child mouse events \sa ChildMouseEvent(), IsTrackingChildMouseEvents() */ void SetTrackChildMouseEvents(bool enable); /*! Returns whether this InputArea wants to be informed about child mouse events. This property is false by default. \sa SetTrackChildMouseEvents(), ChildMouseEvent() */ bool IsTrackingChildMouseEvents() const; /*! Called when a mouse event is sent to a child InputArea. If you return true, mouse ownership will be moved to this InputArea and the child InputArea will receive a MOUSE_CANCEL event. If you return false, nothing happens and the child will keep its ownership over the mouse and therefore get further mouse events. The default implementation just returns false; \return Whether you want to take ownership over the mouse. \sa SetTrackChildMouseEvents */ virtual bool ChildMouseEvent(const Event& event); protected: private: bool _dnd_enabled_as_source; bool _dnd_enabled_as_target; public: // Override the virtual methods from Object Base // Here, we get a change to update the text of the keyboard handler. void SetKeyboardReceiverIgnoreMouseDownOutside(bool ignore_mouse_down_outside); void SetAcceptKeyNavFocusOnMouseDown(bool accept); void SetAcceptKeyNavFocusOnMouseEnter(bool accept); bool KeyboardReceiverIgnoreMouseDownOutside(); virtual bool IsArea() const { return true; } void GrabPointer(); void GrabKeyboard(); void UnGrabPointer(); void UnGrabKeyboard(); bool OwnsPointerGrab(); bool OwnsKeyboardGrab(); //! Return true if this Area is the owner of the mouse pointer. /*! The owner of the mouse pointer is the Area that has received a Mouse down event and the mouse button responsible for the event is still pressed. @return True if this Area is the owner of the mouse pointer. */ bool IsMouseOwner(); //! Returns true if the mouse pointer has been determined as inside the this area, following event processing. /*! Returns true if during a call to FindAreaUnderMouse, this area has been determined to be directly under the mouse pointer. Note that this is true only for the first area that is found. There might be other areas that which have the mouse pointer inside of them. \n Call Area::IsMousePointerInside to find out if the mouse pointer is inside an area. @return Return true if the mouse pointer is inside the Area. */ bool IsMouseInside(); //! Enable the double click event signal on this InputArea. void EnableDoubleClick(bool double_click); //! Returns true if the double click signal is enable for this InputArea. bool DoubleClickEnabled() const; bool mouse_in_; #if defined(NUX_OS_LINUX) void HandleDndEnter() {ProcessDndEnter();} void HandleDndLeave() {ProcessDndLeave();} #endif private: //! Event processing in exclusive mode. /*! Bypass OnEvent and performs a simplified event processing mechanism. */ long ProcessEventInExclusiveMode(Event &event, long TraverseInfo, long ProcessEventInfo); void HandleDndMove (Event &event); void HandleDndDrop (Event &event); //! Color of the InputArea /* Color of the InputArea use to draw a colored quad when OnDraw() is called. */ Color area_color_; int _dnd_safety_x; int _dnd_safety_y; protected: bool _capture_mouse_down_any_where_else; bool _double_click; //!< If True, this InputArea can emit the signal mouse_double_click. Default is false. bool _keyboard_receiver_ignore_mouse_down_outside; bool accept_key_nav_focus_on_mouse_down_; bool accept_key_nav_focus_on_mouse_enter_; #if defined(NUX_OS_LINUX) // DnD support // Rather than being implemented with signals, DND support is implemented with protected virtual function. // This ensure that a class and it subclass don't process the same event more than once! virtual void ProcessDndMove (int x, int y, std::listmimes); virtual void ProcessDndDrop (int x, int y); virtual void ProcessDndEnter(); virtual void ProcessDndLeave(); void SendDndStatus(bool accept, DndAction action, Geometry region); void SendDndFinished(bool accepted, DndAction action); void SetDndEnabled(bool as_source, bool as_target); virtual bool DndSourceDragBegin (); virtual NBitmapData * DndSourceGetDragImage (); virtual std::list DndSourceGetDragTypes (); virtual const char * DndSourceGetDataForType(const char *type, int *size, int *format); virtual void DndSourceDragFinished (DndAction result); void StartDragAsSource(); static NBitmapData * InnerDndSourceGetDragImage(void *data) { return static_cast (data)->DndSourceGetDragImage(); } static std::list InnerDndSourceGetDragTypes(void *data) { return static_cast (data)->DndSourceGetDragTypes(); } static void InnerDndSourceDragFinished(DndAction result, void *data); static const char * InnerDndSourceGetDataForType(const char *type, int *size, int *format, void *data) { return static_cast (data)->DndSourceGetDataForType(type, size, format); } #endif public: #ifdef NUX_GESTURES_SUPPORT //! Creates a new gesture subscription for this input area and activates it /* Convenience function. It's the same as doing the following: ShGesturesSubscription sub(new GesturesSubscription); sub->SetGestureClasses(gesture_classes); sub->SetNumTouches(num_touches); sub->Activate(); input_area->AddGesturesSubscription(sub); */ void CreateGesturesSubscription(int gesture_classes, unsigned int num_touches); //! Adds a gestures subscription to this input area. /*! A single subscription can be shared among multiple InputAreas. */ void AddGesturesSubscription(ShGesturesSubscription &subscription); //! Removes a gestures subscription from this input area. void RemoveGesturesSubscription(ShGesturesSubscription &subscription); //! Returns all multitouch gestures subscriptions that this area cares about. /*! An input area will receive GestureEvents for multitouch gestures that hit his area and matches any active subscription present in this list. */ const std::list &GetGesturesSubscriptions() const; //! Returns whether this area has a subscription that matches the gesture event bool HasSubscriptionForGesture(const GestureEvent &event) const; //! Returns the InputArea hit by the given gesture /*! If this area or any of its children is hit by the gesture from the given event, that area will be returned. Otherwise, it returns nullptr. */ virtual Area* GetInputAreaHitByGesture(const GestureEvent &event); private: std::list gestures_subscriptions_; #endif // NUX_GESTURES_SUPPORT public: //! Signal emitted when the Mouse moves over the InputArea surface. sigc::signal mouse_move; // send the current position inside the area //! Signal emitted when the InputArea receives a mouse down event. /*! @param void Return type of the callback hooked to this signal. @param int Mouse X position(1st parameter of the callback). @param int Mouse Y position(2nd parameter of the callback). @param unsigned long Mouse button states(3rd parameter of the callback). @param unsigned long Keyboard special keys states(4th parameter of the callback). */ sigc::signal mouse_down; //! Signal emitted when the InputArea receives a mouse up event. /*! @param void Return type of the callback hooked to this signal. @param int Mouse X position(1st parameter of the callback). @param int Mouse Y position(2nd parameter of the callback). @param unsigned long Mouse button states(3rd parameter of the callback). @param unsigned long Keyboard special keys states(4th parameter of the callback). */ sigc::signal mouse_up; //! Signal emitted when the InputArea receives a mouse enter event. /*! @param void Return type of the callback hooked to this signal. @param int Mouse X position(1st parameter of the callback). @param int Mouse Y position(2nd parameter of the callback). @param unsigned long Mouse button states(3rd parameter of the callback). @param unsigned long Keyboard special keys states(4th parameter of the callback). */ sigc::signal mouse_enter; //! Signal emitted when the InputArea receives a mouse leave event. /*! @param void Return type of the callback hooked to this signal. @param int Mouse X position(1st parameter of the callback). @param int Mouse Y position(2nd parameter of the callback). @param unsigned long Mouse button states(3rd parameter of the callback). @param unsigned long Keyboard special keys states(4th parameter of the callback). */ sigc::signal mouse_leave; //! Signal emitted when the InputArea receives a mouse down followed later by a mouse release over its surface. /*! @param void Return type of the callback hooked to this signal. @param int Mouse X position(1st parameter of the callback). @param int Mouse Y position(2nd parameter of the callback). @param unsigned long Mouse button states(3rd parameter of the callback). @param unsigned long Keyboard special keys states(4th parameter of the callback). */ sigc::signal mouse_click; //! Signal emitted when the InputArea receives a double click event. /*! @param void Return type of the callback hooked to this signal. @param int Mouse X position(1st parameter of the callback). @param int Mouse Y position(2nd parameter of the callback). @param unsigned long Mouse button states(3rd parameter of the callback). @param unsigned long Keyboard special keys states(4th parameter of the callback). */ sigc::signal mouse_double_click; //! Signal emitted when the InputArea receives a mouse down event, followed later by a mouse move event(while the mouse is still pressed). /*! @param void Return type of the callback hooked to this signal. @param int Mouse X position(1st parameter of the callback). @param int Mouse Y position(2nd parameter of the callback). @param int Mouse X delta(3thr parameter of the callback). @param int Mouse Y delta(4th parameter of the callback). @param unsigned long Mouse button states(5th parameter of the callback). @param unsigned long Keyboard special keys states(6th parameter of the callback). */ sigc::signal mouse_drag; // send(current X, current Y, delta X, delta Y) //! Signal emitted when the InputArea receives a mouse wheel event. sigc::signal < void, int, // window x int, // window y int, // mouse wheel delta: +120/-120 correspond to one notch of the wheel unsigned long, // mouse state unsigned long // key state > mouse_wheel; // send(current X, current Y, delta X, delta Y) //! Signal emitted when the InputArea loses ownership over a pressed mouse. /*! Any actions or changes caused by the previous mouse_down should be reverted. */ sigc::signal mouse_cancel; //! Signal emitted when the InputArea receives a key release event. sigc::signal key_up; //! Signal emitted when the area gets the keyboard focus. The is a result of a mouse down event or a call to ForceStartFocus. sigc::signal begin_key_focus; //! Signal emitted when the area looses the keyboard focus. sigc::signal end_key_focus; sigc::signal < void, unsigned long , /*event type*/ unsigned long , /*event keysym*/ unsigned long , /*event state*/ const char* , /*character*/ unsigned short /*key repeat count*/ > key_down; //! Signal emitted when a mouse down event occurs outside of this area /*! If this area is inside the main layout, then the position is relative to the top left corner of the window. If this area is a BaseWindow, then the position is relative to the top left corner of the window. If this area is inside a BaseWindow, then the position is relative to the top left corner of the BaseWIndow. @param int Position of the mouse down event. @param int Position of the mouse down event. @param ulong Mouse button states. @param ulong Keyboard modifiers states. */ sigc::signal mouse_down_outside_pointer_grab_area; sigc::signal start_keyboard_grab; sigc::signal end_keyboard_grab; #ifdef NUX_GESTURES_SUPPORT //! Called whenever a GestureEvent is received /*! You should reimplement this method to handle gestures. Typically you would add code to make this area react to the gestures received. In order to receive events from a given kind of gesture, an area has to have a corresponding gesture subscription. See CreateGesturesSubscription() and AddGesturesSubscription(). This method is called only with gestures that have already been accepted. Therefore you shouldn't call GestureEvent::Accept() or GestureEvent::Reject() from here as there's no point in doing so. Default implementation just returns GestureDeliveryRequest::NONE. */ virtual GestureDeliveryRequest GestureEvent(const GestureEvent & /* event */) { return GestureDeliveryRequest::NONE; } #endif protected: virtual bool AcceptKeyNavFocus(); virtual bool AcceptKeyNavFocusOnMouseDown() const; virtual bool AcceptKeyNavFocusOnMouseEnter() const; // == Signals with 1 to 1 mapping to input device == virtual void EmitMouseDownSignal (int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseUpSignal (int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseMoveSignal (int x, int y, int dx, int dy, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseWheelSignal (int x, int y, int wheel_delta, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitKeyDownSignal (unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state); virtual void EmitKeyUpSignal (unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state); virtual void EmitKeyEventSignal (unsigned long event_type, unsigned int key_symbol, unsigned long special_keys_state, const char* text, int key_repeat_count); // == Interpreted signals == // Mouse down + mouse move on an area virtual void EmitMouseDragSignal (int x, int y, int dx, int dy, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseEnterSignal (int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseLeaveSignal (int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseClickSignal (int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseDoubleClickSignal(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseDownOutsideArea (int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state); virtual void EmitMouseCancelSignal(); friend class WindowCompositor; private: bool is_tracking_child_mouse_events_; }; } #endif // INPUTAREA_H nux-4.0.8+18.10.20180623/Nux/InputAreaProximity.cpp0000644000000000000000000000467613313373365015711 0ustar /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * */ #include "WindowCompositor.h" #include "WindowThread.h" #include "InputAreaProximity.h" #include "NuxCore/Logger.h" namespace nux { DECLARE_LOGGER(logger, "nux.inputarea_proximity"); InputAreaProximity::InputAreaProximity(InputArea* area, unsigned int proximity) : area_(area) , proximity_(proximity) , is_mouse_near_(false) { if(area) GetWindowThread()->GetWindowCompositor().AddAreaInProximityList(this); else LOG_ERROR(logger) << "Error, passing in NULL value for InputArea*"; } InputAreaProximity::~InputAreaProximity() { GetWindowThread()->GetWindowCompositor().RemoveAreaInProximityList(this); } Point GetOffsetFromRect(Rect const& rect, Point const& mouse) { Point offset; if (rect.x > mouse.x) { offset.x = rect.x - mouse.x; } else if (rect.x + rect.width < mouse.x) { offset.x = rect.x + rect.width - mouse.x; } if (rect.y > mouse.y) { offset.y = rect.y - mouse.y; } else if (rect.y + rect.height < mouse.y) { offset.y = rect.y + rect.height - mouse.y; } return offset; } void InputAreaProximity::CheckMousePosition(Point const& mouse) { if (!area_.IsValid()) return; Geometry const& geo = area_->GetAbsoluteGeometry(); Geometry const& expanded = geo.GetExpand(proximity_, proximity_); if (!is_mouse_near_ && expanded.IsInside(mouse)) { is_mouse_near_ = true; mouse_near.emit(mouse); } else if (is_mouse_near_ && !expanded.IsInside(mouse)) { is_mouse_near_ = false; mouse_beyond.emit(mouse); } if (is_mouse_near_ && !geo.IsInside(mouse)) { nux::Point const& offset = GetOffsetFromRect(geo, mouse); mouse_approaching.emit(mouse, offset); } } } nux-4.0.8+18.10.20180623/Nux/InputAreaProximity.h0000644000000000000000000000353613313373365015350 0ustar /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * */ #ifndef NUX_INPUTAREA_PROXIMITY_H #define NUX_INPUTAREA_PROXIMITY_H #include "InputArea.h" namespace nux { class InputAreaProximity { public: InputAreaProximity(InputArea* area, unsigned int proximity); virtual ~InputAreaProximity(); virtual void CheckMousePosition(Point const& mouse); //! Signal emitted when the Mouse is near the input area. /*! @param Point mouse is the current Mouse position. */ sigc::signal mouse_near; //! Signal emitted while the mouse is moving, near, and not yet inside the input area. /*! @param Point mouse is the current Mouse position. @param Point offset is the offset between the mouse and the input area. */ sigc::signal mouse_approaching; //! Signal emitted when the Mouse is moves beyond the input area + proximity. /*! @param Point mouse is the current Mouse position. */ sigc::signal mouse_beyond; protected: ObjectWeakPtr area_; unsigned int proximity_; bool is_mouse_near_; }; } #endif nux-4.0.8+18.10.20180623/Nux/InputMethodIBus.cpp0000644000000000000000000003530413313373365015107 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * Jay Taoko * */ #include "Nux.h" #include "NuxCore/Logger.h" #include "InputMethodIBus.h" namespace nux { namespace { DECLARE_LOGGER(logger, "nux.inputmethod.ibus"); } std::vector IBusIMEContext::hotkeys_; IBusBus* IBusIMEContext::bus_ = NULL; IBusIMEContext::IBusIMEContext(TextEntry* text_entry) : text_entry_(text_entry) , context_(NULL) , cancellable_(g_cancellable_new()) , is_focused_(false) { // init ibus if (!G_OBJECT(bus_)) { ibus_init(); bus_ = ibus_bus_new(); g_object_add_weak_pointer(G_OBJECT(bus_), reinterpret_cast(&bus_)); } else { g_object_ref(bus_); } // connect bus signals g_signal_connect(bus_, "connected", G_CALLBACK(OnConnected_), this); g_signal_connect(bus_, "disconnected", G_CALLBACK(OnDisconnected_), this); if (ibus_bus_is_connected(bus_)) { CreateContext(); } else { LOG_WARN(logger) << "Impossible to connect to connect to ibus"; } } IBusIMEContext::~IBusIMEContext() { DestroyContext(); g_signal_handlers_disconnect_by_data(bus_, this); g_object_unref(cancellable_); g_object_unref(bus_); } void IBusIMEContext::Focus() { if (is_focused_) return; is_focused_ = true; if (context_) ibus_input_context_focus_in(context_); } void IBusIMEContext::Blur() { if (!is_focused_) return; is_focused_ = false; if (context_) ibus_input_context_focus_out(context_); } void IBusIMEContext::Reset() { if (context_) ibus_input_context_reset(context_); } bool IBusIMEContext::FilterKeyEvent(const KeyEvent& event) { guint keyval = event.key_sym(); // todo(jaytaoko): ui::GdkKeyCodeForWindowsKeyCode(event.key_code(), event.IsShiftDown() ^ event.IsCapsLockDown()); if (context_) { guint modifiers = 0; if (event.flags() & IBUS_IGNORED_MASK) return false; if (event.type() == EVENT_KEY_UP) modifiers |= IBUS_RELEASE_MASK; if (event.IsShiftDown()) modifiers |= IBUS_SHIFT_MASK; if (event.IsControlDown()) modifiers |= IBUS_CONTROL_MASK; if (event.IsAltDown()) modifiers |= IBUS_MOD1_MASK; if (event.IsCapsLockDown()) modifiers |= IBUS_LOCK_MASK; ibus_input_context_process_key_event_async(context_, keyval, event.key_code() - 8, modifiers, -1, cancellable_, reinterpret_cast(ProcessKeyEventDone), new ProcessKeyEventData(this, event)); return true; } return false; } void IBusIMEContext::SetSurrounding(const std::wstring& /* text */, int /* cursor_pos */) { // TODO(penghuang) support surrounding } void IBusIMEContext::CreateContext() { nuxAssert(bus_ != NULL); nuxAssert(ibus_bus_is_connected(bus_)); if (!(context_ = ibus_bus_create_input_context(bus_, "nux"))) { LOG_WARN(logger) << "Cannot create InputContext"; return; } g_cancellable_reset(cancellable_); text_entry_->ime_active_ = false; // connect input context signals g_signal_connect(context_, "commit-text", G_CALLBACK(OnCommitText_), this); g_signal_connect(context_, "update-preedit-text", G_CALLBACK(OnUpdatePreeditText_), this); g_signal_connect(context_, "show-preedit-text", G_CALLBACK(OnShowPreeditText_), this); g_signal_connect(context_, "hide-preedit-text", G_CALLBACK(OnHidePreeditText_), this); g_signal_connect(context_, "enabled", G_CALLBACK(OnEnable_), this); g_signal_connect(context_, "disabled", G_CALLBACK(OnDisable_), this); g_signal_connect(context_, "destroy", G_CALLBACK(OnDestroy_), this); guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS; ibus_input_context_set_capabilities(context_, caps); if (is_focused_) ibus_input_context_focus_in(context_); UpdateCursorLocation(); if (IBusConfig* bus_conf = ibus_bus_get_config(bus_)) { g_signal_handlers_disconnect_by_func(bus_conf, reinterpret_cast(OnConfigChanged_), this); g_signal_connect(bus_conf, "value-changed", G_CALLBACK(OnConfigChanged_), this); } UpdateHotkeys(); } void IBusIMEContext::DestroyContext() { LOG_DEBUG(logger) << "Destroy context"; if (ibus_bus_is_connected(bus_)) { if (IBusConfig* bus_conf = ibus_bus_get_config(bus_)) g_signal_handlers_disconnect_by_data(bus_conf, this); } if (!context_) return; text_entry_->ResetPreedit(); ibus_proxy_destroy(reinterpret_cast(context_)); nuxAssert(!context_); } bool IBusIMEContext::IsConnected() const { return context_; } void IBusIMEContext::UpdateCursorLocation() { nux::Rect strong, weak; text_entry_->GetCursorRects(&strong, &weak); // Get the position of the TextEntry in the Window. nux::Geometry geo = text_entry_->GetAbsoluteGeometry(); // Get the Geometry of the window on the display. nux::Geometry window_geo = nux::GetGraphicsDisplay()->GetWindowGeometry(); ibus_input_context_set_cursor_location(context_, geo.x + window_geo.x + strong.x, geo.y + window_geo.y, 0, geo.height); } void IBusIMEContext::OnConnected(IBusBus * /* bus */) { LOG_DEBUG(logger) << "Connected"; if (ibus_bus_is_connected(bus_)) { DestroyContext(); CreateContext(); } } void IBusIMEContext::OnDisconnected(IBusBus * /* bus */) { LOG_DEBUG(logger) << "Disconnected"; hotkeys_.clear(); DestroyContext(); } void IBusIMEContext::OnConfigChanged(IBusConfig* /* config */, gchar* section, gchar* name, GVariant* /* value */) { if (g_strcmp0(section, "general/hotkey") == 0) { if (g_strcmp0(name, "trigger") == 0) UpdateHotkeys(); } } void IBusIMEContext::OnCommitText(IBusInputContext * /* context */, IBusText* text) { LOG_DEBUG(logger) << "Text committed " << text->text; text_entry_->DeleteSelection(); if (text->text) { int cursor = text_entry_->cursor_; std::string new_text(text_entry_->GetText()); std::string commit_text (text->text); new_text.insert (cursor, commit_text); text_entry_->SetText(new_text.c_str()); text_entry_->SetCursor(cursor + commit_text.length()); UpdateCursorLocation(); } } void IBusIMEContext::OnUpdatePreeditText(IBusInputContext* /* context */, IBusText* text, guint /* cursor_pos */, gboolean visible) { LOG_DEBUG(logger) << "Preedit Update"; nuxAssert(IBUS_IS_TEXT(text)); if (text_entry_->preedit_.empty()) UpdateCursorLocation(); if (visible) { IBusAttrList* attrs = text->attrs; if (attrs) { PangoAttrList* preedit_attrs = pango_attr_list_new(); int i = 0; while (1) { IBusAttribute* attr = ibus_attr_list_get(attrs, i++); PangoAttribute* pango_attr; if (!attr) break; switch (attr->type) { case IBUS_ATTR_TYPE_UNDERLINE: pango_attr = pango_attr_underline_new ((PangoUnderline)attr->value); break; case IBUS_ATTR_TYPE_FOREGROUND: pango_attr = pango_attr_foreground_new ( ((attr->value & 0xff0000) >> 8) | 0xff, ((attr->value & 0x00ff00)) | 0xff, ((attr->value & 0x0000ff) << 8) | 0xff); break; case IBUS_ATTR_TYPE_BACKGROUND: pango_attr = pango_attr_background_new ( ((attr->value & 0xff0000) >> 8) | 0xff, ((attr->value & 0x00ff00)) | 0xff, ((attr->value & 0x0000ff) << 8) | 0xff); break; default: continue; } pango_attr->start_index = g_utf8_offset_to_pointer (text->text, attr->start_index) - text->text; pango_attr->end_index = g_utf8_offset_to_pointer (text->text, attr->end_index) - text->text; pango_attr_list_insert (preedit_attrs, pango_attr); } if (text_entry_->preedit_attrs_) { pango_attr_list_unref(text_entry_->preedit_attrs_); text_entry_->preedit_attrs_ = NULL; } text_entry_->preedit_attrs_ = preedit_attrs; } if (text->text) { std::string preedit(text->text); text_entry_->preedit_ = preedit; text_entry_->preedit_cursor_ = preedit.length(); text_entry_->QueueRefresh (true, true); } } else { OnHidePreeditText(context_); } } void IBusIMEContext::OnShowPreeditText(IBusInputContext * /* context */) { LOG_DEBUG(logger) << "Show preedit"; } void IBusIMEContext::OnHidePreeditText(IBusInputContext * /* context */) { LOG_DEBUG(logger) << "Hide preedit"; text_entry_->ResetPreedit(); text_entry_->QueueRefresh (true, true); } void IBusIMEContext::OnEnable(IBusInputContext * /* context */) { LOG_DEBUG(logger) << "On enable"; text_entry_->ime_active_ = true; text_entry_->text_changed.emit(text_entry_); UpdateCursorLocation(); } void IBusIMEContext::OnDisable(IBusInputContext * /* context */) { LOG_DEBUG(logger) << "On disable"; text_entry_->ime_active_ = false; text_entry_->ResetPreedit(); text_entry_->QueueRefresh (true, true); } void IBusIMEContext::OnDestroy(IBusInputContext * /* context */) { LOG_DEBUG(logger) << "On Destroy"; if (!context_) return; g_cancellable_cancel(cancellable_); g_signal_handlers_disconnect_by_data(context_, this); g_object_unref(context_); context_ = NULL; } void IBusIMEContext::ProcessKeyEventDone(IBusInputContext *context, GAsyncResult* res, ProcessKeyEventData *data) { LOG_DEBUG(logger) << "Key event processed"; std::unique_ptr key_ev(data); GError *error = NULL; gboolean processed = ibus_input_context_process_key_event_async_finish(context, res, &error); if (error) { if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { LOG_ERROR(logger) << "Process Key Event failed: " << error->message << "."; } g_error_free(error); return; } nuxAssert(key_ev->context->context_ == context); if (!processed) { key_ev->context->text_entry_->ProcessKeyEvent(key_ev->event.type(), key_ev->event.key_sym(), key_ev->event.flags() | IBUS_IGNORED_MASK, key_ev->event.character().c_str(), 0); } } std::vector IBusIMEContext::ParseIBusHotkeys(const gchar** keybindings) { std::vector hotkeys; for (int i = 0; keybindings && keybindings[i]; ++i) { gchar** binding = g_strsplit (keybindings[i], "+", -1); if (binding) { Event ev; ev.type = EVENT_KEY_DOWN; for (int j = 0; binding && binding[j]; ++j) { if (strcmp(binding[j], "Release") == 0) { ev.type = EVENT_KEY_UP; continue; } KeySym key = XStringToKeysym(binding[j]); bool is_modifier = false; if (key) { switch (key) { case XK_Caps_Lock: case XK_Shift_Lock: case XK_Num_Lock: case XK_Scroll_Lock: is_modifier = true; } } else { // Checking if the current key is a generic modifier key key = XStringToKeysym((std::string(binding[j]) + "_L").c_str()); is_modifier = (key != 0); } if (is_modifier) { switch (key) { case XK_Control_L: case XK_Control_R: ev.key_modifiers |= KEY_MODIFIER_CTRL; break; case XK_Shift_L: case XK_Shift_R: case XK_Shift_Lock: ev.key_modifiers |= KEY_MODIFIER_SHIFT; break; case XK_Alt_L: case XK_Alt_R: ev.key_modifiers |= KEY_MODIFIER_ALT; break; case XK_Super_L: case XK_Super_R: ev.key_modifiers |= KEY_MODIFIER_SUPER; break; case XK_Caps_Lock: ev.key_modifiers |= KEY_MODIFIER_CAPS_LOCK; break; case XK_Num_Lock: ev.key_modifiers |= KEY_MODIFIER_NUMLOCK; break; case XK_Scroll_Lock: ev.key_modifiers |= KEY_MODIFIER_SCROLLLOCK; break; // FIXME add support to Hyper and Meta keys in nux::Event } } if (!is_modifier && key) ev.x11_keysym = key; } if (ev.x11_keysym) { hotkeys.push_back(ev); } g_strfreev(binding); } } return hotkeys; } void IBusIMEContext::UpdateHotkeys() { if (IBusConfig* conf = ibus_bus_get_config(bus_)) { GVariant* val = ibus_config_get_value(conf, "general/hotkey", "triggers"); const gchar** keybindings = g_variant_get_strv(val, NULL); hotkeys_ = ParseIBusHotkeys(keybindings); g_variant_unref(val); g_free(keybindings); } } bool IBusIMEContext::IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const { for (Event const& ev : hotkeys_) { if (ev.x11_keysym == keysym && (ev.type == type || type == EVENT_KEY_DOWN)) { if (ev.type == EVENT_KEY_UP) return (modifiers & ev.key_modifiers); else return (ev.key_modifiers == modifiers); } } return false; } } nux-4.0.8+18.10.20180623/Nux/InputMethodIBus.h0000644000000000000000000001524013313373365014551 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * Jay Taoko * */ #ifndef INPUTMETHODIBUS_H #define INPUTMETHODIBUS_H #include #include namespace nux { class IBusIMEContext; class TextEntry; // FIXME This class should be reworked to replace the mouse_state // with the hardware key_code. class KeyEvent { public: KeyEvent(NuxEventType type, unsigned int key_sym, unsigned int key_code, unsigned int event_flags, const char* character) : type_(type) , key_sym_(key_sym) , key_code_(key_code) , key_modifiers_(event_flags) , character_(character ? character : "") { } NuxEventType type() const {return type_;} unsigned int key_sym() const {return key_sym_;} unsigned int key_code() const {return key_code_;} unsigned int flags() const {return key_modifiers_;} std::string character() const {return character_;} bool IsShiftDown() const { return (key_modifiers_ & KEY_MODIFIER_SHIFT) != 0; } bool IsControlDown() const { return (key_modifiers_ & KEY_MODIFIER_CTRL) != 0; } bool IsCapsLockDown() const { return (key_modifiers_ & KEY_MODIFIER_CAPS_LOCK) != 0; } bool IsAltDown() const { return (key_modifiers_ & KEY_MODIFIER_ALT) != 0; } private: EventType type_; unsigned int key_sym_; unsigned int key_code_; unsigned int key_modifiers_; std::string character_; KeyEvent(const KeyEvent&); void operator = (const KeyEvent&); }; // Used for passing data to ProcessKeyEventDone function() class ProcessKeyEventData { public: ProcessKeyEventData(IBusIMEContext* context, const KeyEvent& event) : context(context) , event(event.type(), event.key_sym(), event.key_code(), event.flags(), event.character().c_str()) { } IBusIMEContext* context; KeyEvent event; }; // Implements IMEContext to integrate ibus input method framework class IBusIMEContext { public: explicit IBusIMEContext(TextEntry* text_entry); virtual ~IBusIMEContext(); // views::IMEContext implementations: virtual void Focus(); virtual void Blur(); virtual void Reset(); virtual bool FilterKeyEvent(const KeyEvent& event); virtual void SetSurrounding(const std::wstring& text, int cursor_pos); bool IsConnected() const; bool IsHotkeyEvent(EventType type, unsigned long keysym, unsigned long modifiers) const; protected: static std::vector ParseIBusHotkeys(const gchar** keybindings); private: void CreateContext(); void DestroyContext(); void UpdateCursorLocation(); static void UpdateHotkeys(); // Event handlers for IBusBus: //CHROMEG_CALLBACK_0(IBusIMEContext, void, OnConnected, IBusBus*); static void OnConnected_(IBusBus* bus, void* data) {nuxDebugMsg("***IBusIMEContext::OnConnected***"); static_cast(data)->OnConnected(bus);} void OnConnected(IBusBus *bus); //CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDisconnected, IBusBus*); static void OnDisconnected_(IBusBus* bus, void* data) {static_cast(data)->OnDisconnected(bus);} void OnDisconnected(IBusBus *bus); static void OnConfigChanged_(IBusConfig* config, gchar* section, gchar* name, GVariant* value, gpointer data) {static_cast(data)->OnConfigChanged(config, section, name, value);} void OnConfigChanged(IBusConfig* config, gchar* section, gchar* name, GVariant* value); // // Event handlers for IBusIMEContext: //CHROMEG_CALLBACK_1(IBusIMEContext, void, OnCommitText, IBusInputContext*, IBusText*); static void OnCommitText_(IBusInputContext* context, IBusText* text, void* data) {static_cast(data)->OnCommitText(context, text);} void OnCommitText(IBusInputContext *context, IBusText* text); //CHROMEG_CALLBACK_3(IBusIMEContext, void, OnUpdatePreeditText, IBusInputContext*, IBusText*, guint, gboolean); static void OnUpdatePreeditText_(IBusInputContext* context, IBusText* text, guint cursor_pos, gboolean visible, void* data) {reinterpret_cast(data)->OnUpdatePreeditText(context, text, cursor_pos, visible);} void OnUpdatePreeditText(IBusInputContext *context, IBusText* text, guint cursor_pos, gboolean visible); //CHROMEG_CALLBACK_0(IBusIMEContext, void, OnShowPreeditText, IBusInputContext*); static void OnShowPreeditText_(IBusInputContext* context, void* data) {static_cast(data)->OnShowPreeditText(context);} void OnShowPreeditText(IBusInputContext *context); // CHROMEG_CALLBACK_0(IBusIMEContext, void, OnHidePreeditText, IBusInputContext*); static void OnHidePreeditText_(IBusInputContext* context, void* data) {static_cast(data)->OnHidePreeditText(context);} void OnHidePreeditText(IBusInputContext *context); // CHROMEG_CALLBACK_0(IBusIMEContext, void, OnEnable, IBusInputContext*); static void OnEnable_(IBusInputContext* context, void* data) {static_cast(data)->OnEnable(context);} void OnEnable(IBusInputContext *context); // CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDisable, IBusInputContext*); static void OnDisable_(IBusInputContext* context, void* data) {static_cast(data)->OnDisable(context);} void OnDisable(IBusInputContext *context); // CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDestroy, IBusInputContext*); static void OnDestroy_(IBusInputContext* context, void* data) {static_cast(data)->OnDestroy(context);} void OnDestroy(IBusInputContext *context); static void ProcessKeyEventDone(IBusInputContext* context, GAsyncResult* res, ProcessKeyEventData* data); TextEntry* text_entry_; IBusInputContext* context_; GCancellable* cancellable_; bool is_focused_; static IBusBus* bus_; static std::vector hotkeys_; IBusIMEContext(const IBusIMEContext&); void operator = (const IBusIMEContext&); }; } #endif // INPUTMETHODIBUS_H nux-4.0.8+18.10.20180623/Nux/IntegerValidator.cpp0000644000000000000000000000542413313373365015327 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "IntegerValidator.h" namespace nux { IntegerValidator::IntegerValidator(int Minimum, int Maximum) : m_Minimum(Minimum) , m_Maximum(Maximum) { _regexp_str = "^[-+]?[0-9]+$"; InitRegExp(); if (m_Minimum > m_Maximum) { int temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } IntegerValidator::IntegerValidator(const IntegerValidator ©) { m_Minimum = copy.m_Minimum; m_Maximum = copy.m_Maximum; _regexp_str = copy._regexp_str; InitRegExp(); } IntegerValidator &IntegerValidator::operator= (const IntegerValidator &rhs) { if (&rhs != this) { m_Minimum = rhs.m_Minimum; m_Maximum = rhs.m_Maximum; _regexp_str = rhs._regexp_str; InitRegExp(); } return *this; } IntegerValidator::~IntegerValidator() { } Validator *IntegerValidator::Clone() const { return new IntegerValidator(*this); } void IntegerValidator::SetMinimum(int value) { m_Minimum = value; if (m_Minimum > m_Maximum) { int temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } int IntegerValidator::GetMinimum() const { return m_Minimum; } void IntegerValidator::SetMaximum(int value) { m_Maximum = value; if (m_Minimum > m_Maximum) { int temp = m_Minimum; m_Minimum = m_Maximum; m_Maximum = temp; } } int IntegerValidator::GetMaximum() const { return m_Maximum; } int IntegerValidator::GetClampedValue(int i) const { if (i < m_Minimum) return m_Minimum; if (i > m_Maximum) return m_Maximum; return i; } void IntegerValidator::Alternative(const char * /* str */) { } std::string IntegerValidator::ToString(int i) { return std::to_string((long long)i); } int IntegerValidator::ToInteger(const char *str) { if (Validate(str) == Acceptable) return CharToInteger(str); else return 0; } } nux-4.0.8+18.10.20180623/Nux/IntegerValidator.h0000644000000000000000000000324013313373365014766 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef INTEGERVALIDATOR_H #define INTEGERVALIDATOR_H #include "Validator.h" namespace nux { class IntegerValidator : public Validator { public: IntegerValidator(int Minimum = INT_MIN, int Maximum = INT_MAX); IntegerValidator(const IntegerValidator &validator); IntegerValidator &operator= (const IntegerValidator &rhs); virtual ~IntegerValidator(); virtual Validator *Clone() const; //Virtual Constructor Idiom /*! @return The input value clamped to the range [m_Minimum, m_Maximum]. */ int GetClampedValue(int i) const; virtual void Alternative(const char *str); void SetMinimum(int value); int GetMinimum() const; void SetMaximum(int value); int GetMaximum() const; std::string ToString(int i); int ToInteger(const char *str); private: int m_Minimum; int m_Maximum; }; } #endif // INTEGERVALIDATOR_H nux-4.0.8+18.10.20180623/Nux/KeyboardHandler.cpp0000644000000000000000000005765413313373365015136 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "KeyboardHandler.h" #include "Utils.h" #include "NuxGraphics/GraphicsEngine.h" #include "NuxCore/Win32Dialogs/NWin32Clipboard.h" namespace nux { int BaseKeyboardHandler::s_jump_offset_at_borders = 60; int BaseKeyboardHandler::s_cursor_width = 4; BaseKeyboardHandler::BaseKeyboardHandler() { m_text_positionx = 0; m_text_positiony = 0; m_previous_cursor_position = 0; m_clip_region = Rect(0, 0, 100, 20); m_KeyType = eAlphaNumeric; m_first_visible_char = 0; m_mouse_drag = false; m_mouse_inside_text_area = true; m_entering_focus = false; m_Font = GetSysFont(); m_caret = m_selection_start = 0; m_insert_mode = true; } BaseKeyboardHandler::~BaseKeyboardHandler() { } void BaseKeyboardHandler::DeleteSelectionText() { int nFirst = Min(m_caret, m_selection_start); int nLast = Max(m_caret, m_selection_start); // Update caret and selection PlaceCaret(nFirst); m_selection_start = m_caret; // Remove the characters for (int i = nFirst; i < nLast; ++i) m_textline.erase(nFirst, 1); } void BaseKeyboardHandler::InsertChar(unsigned int /* character */) { } void BaseKeyboardHandler::ClearText() { m_text_positionx = 0; m_text_positiony = 0; m_caret = 0; m_previous_cursor_position = 0; m_textline.clear(); } void BaseKeyboardHandler::PlaceCaret(unsigned int nCP) { nuxAssert(((int)nCP >= 0) && (nCP <= (unsigned int) m_textline.length())); m_previous_cursor_position = m_caret; m_caret = nCP; } unsigned int BaseKeyboardHandler::NextWordPosition(unsigned int cp) { unsigned int num_char = (unsigned int) m_textline.length(); if (cp == num_char) return cp; unsigned int c = cp + 1; while (c < num_char - 1) { if (( m_textline[c] == char(' ')) && (m_textline[c+1] != char(' '))) return c + 1; c++; } return num_char; } unsigned int BaseKeyboardHandler::PrevWordPosition(unsigned int cp) { if (cp == 0) return 0; unsigned int c = cp - 1; while (c > 1) { if (( m_textline[c] != char(' ')) && (m_textline[c-1] == char(' '))) return c; c--; } return 0; } void BaseKeyboardHandler::MouseDown(int x, int y) { ResolveCaretPosition(x, y); m_mouse_drag = true; m_mouse_inside_text_area = true; m_entering_focus = false; } void BaseKeyboardHandler::MouseUp(int /* x */, int /* y */) { m_mouse_drag = false; m_entering_focus = false; } void BaseKeyboardHandler::MouseDrag(int x, int y) { if (m_entering_focus) return; ResolveCaretPosition(x, y); m_mouse_inside_text_area = true; } void BaseKeyboardHandler::EnterFocus() { m_entering_focus = true; } void BaseKeyboardHandler::ResolveCaretPosition(int x, int /* y */) { if (m_entering_focus) return; if (m_textline.length() == 0) return; unsigned int StrLength = (unsigned int) m_textline.length(); int total = m_text_positionx; unsigned int nCP = StrLength; for (unsigned int i = 0; i < StrLength; i++) { unsigned int cw0 = GetFont()->GetCharWidth(m_textline[i]); unsigned int cw1 = 0; if (i+1 < StrLength) { cw1 = GetFont()->GetCharWidth(m_textline[i+1]); } { if (total == x) { nCP = i; break; } else if (x < total + (int) cw0 / 2) { nCP = i; break; } else if (x < total + (int) cw1 / 2) { // I don't quite understand why we need this??? nCP = i + 1; break; } } total += cw0; } PlaceCaret(nCP); if (!m_mouse_drag) { m_selection_start = m_caret; } } void BaseKeyboardHandler::CaretAutoScroll(int x, int /* y */, Geometry geo) { if (m_entering_focus) return; if (m_textline.length() == 0) return; int StrLength = (int) m_textline.length(); //nuxDebugMsg("[BaseKeyboardHandler::ResolveCaretPosition]"); if (x < geo.x) { if (m_mouse_inside_text_area) { while (m_caret && (GetFont()->GetCharStringWidth(m_textline.c_str(), m_caret) + m_text_positionx > 0)) { --m_caret; //nuxDebugMsg("Group Add: %c", m_textline[m_caret]); } m_mouse_inside_text_area = false; } else if (m_caret) { --m_caret; //nuxDebugMsg("Add Char: %c", m_textline[m_caret]); } else { m_caret = 0; } } else if (x > geo.x + geo.GetWidth()) { if (m_mouse_inside_text_area) { while ((m_caret != StrLength) && (GetFont()->GetCharStringWidth(m_textline.c_str(), m_caret) + m_text_positionx < geo.GetWidth())) { ++m_caret; //nuxDebugMsg("Group Add: %c", m_textline[m_caret-1]); } m_mouse_inside_text_area = false; } else if (m_caret < StrLength) { ++m_caret; //nuxDebugMsg("Group Add: %c", m_textline[m_caret-1]); } else { m_caret = StrLength; } } AdjustCursorAndTextPosition(); } long BaseKeyboardHandler::ProcessKey( unsigned long eventType /*event type*/, unsigned long keysym /*event keysym*/, unsigned long state /*event state*/, char character /*character*/, const Geometry & /* g */) { //if(event.event_type != I_AsciiKey && event.event_type != I_KeyPress && event.event_type != I_KeyRelease) if (eventType != NUX_KEYDOWN) return 0; m_need_redraw = true; //unsigned key = event.ascii_code; unsigned key = 0; if (character != 0) key = character; long virtual_code = keysym; if (key != 0) { switch(m_KeyType) { case eDecimalNumber: { // Check if Key code is in ".0123456789"; // Be careful because WM_KEYDOWN and WM_KEYUP send a key value // that gets here. If key pad 0 is press/released, WM_KEYDOWN/WM_KEYUP will send key = key_kp0. // It is WM_CHAR who send key = 0x30 = '0'. Therefore, do not use strchr(".0123456789", key) to test // if key is a digit character. When using strchr(".0123456789", key_kp0) we get a positive result // and the result is unexpected. if ((key >= char('0') && key <= char('9')) || (key == char('.')) || (key == char('-')) || (key == char('+'))) { if ( m_caret != m_selection_start ) { DeleteSelectionText(); } // '-' and '+' can only be at position 0 of the number if ((key == char('-')) || (key == char('+'))) { if ((m_caret == 0) && (m_textline[0] != char('+')) && (m_textline[0] != char('-'))) { // If we are in overwrite mode and there is already // a char at the caret's position, simply replace it. // Otherwise, we insert the char as normal. if ( !m_insert_mode && m_caret < (int) m_textline.length()) { m_textline[m_caret] = key; PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } else { // Insert the char if ( m_caret <= (int) m_textline.length()) { m_textline.insert(m_caret, 1, key); PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } } } } else { // If we are in overwrite mode and there is already // a char at the caret's position, simply replace it. // Otherwise, we insert the char as normal. if ( !m_insert_mode && m_caret < (int) m_textline.length()) { m_textline[m_caret] = key; PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } else { // Insert the char if ( m_caret <= (int) m_textline.length()) { m_textline.insert(m_caret, 1, key); PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } } } } break; } case eIntegerNumber: { // Check if Key code is in "0123456789"; if ((key >= char('0') && key <= char('9')) || (key == char('-')) || (key == char('+'))) { if ( m_caret != m_selection_start ) { DeleteSelectionText(); } // '-' and '+' can only be at position 0 of the number if ((key == char('-')) || (key == char('+'))) { // If we are in overwrite mode and there is already // a char at the caret's position, simply replace it. // Otherwise, we insert the char as normal. if (!m_insert_mode && (m_caret < (int) m_textline.length())) { m_textline[m_caret] = key; PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } else { // Insert the char if ( m_caret <= (int) m_textline.length()) { m_textline.insert(m_caret, 1, key); PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } } } else { // If we are in overwrite mode and there is already // a char at the caret's position, simply replace it. // Otherwise, we insert the char as normal. if (!m_insert_mode && (m_caret < (int) m_textline.length())) { m_textline[m_caret] = key; PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } else { // Insert the char if (m_caret <= (int) m_textline.length()) { m_textline.insert(m_caret, 1, key); PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } } } } break; } case eHexadecimalNumber: { if ((key >= char('0') && key <= char('9')) || (key >= char('a') && key <= char('f')) || (key >= char('A') && key <= char('F')) || (key == char('-')) || (key == char('+'))) //if(strchr("0123456789abcdefABCDEF", key)) { if (m_caret != m_selection_start) { DeleteSelectionText(); } // If we are in overwrite mode and there is already // a char at the caret's position, simply replace it. // Otherwise, we insert the char as normal. if (!m_insert_mode && (m_caret < (int) m_textline.length())) { m_textline[m_caret] = key; PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } else { // Insert the char if (m_caret <= (int) m_textline.length()) { m_textline.insert(m_caret, 1, key); PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } } } break; } case eBinaryNumber: { //if(strchr("01", key)) if ((key >= char('0') && key <= char('1'))) { if ( m_caret != m_selection_start ) { DeleteSelectionText(); } // If we are in overwrite mode and there is already // a char at the caret's position, simply replace it. // Otherwise, we insert the char as normal. if (!m_insert_mode && (m_caret < (int) m_textline.length())) { m_textline[m_caret] = key; PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } else { // Insert the char if (m_caret <= (int) m_textline.length()) { m_textline.insert(m_caret, 1, key); PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } } } break; } case eAlphaNumeric: default: { if (key > 0x1F && key < 0x7f) { if (m_caret != m_selection_start) { DeleteSelectionText(); } // If we are in overwrite mode and there is already // a char at the caret's position, simply replace it. // Otherwise, we insert the char as normal. if (!m_insert_mode && (m_caret < (int) m_textline.length())) { m_textline[m_caret] = key; PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } else { // Insert the char if (m_caret <= (int) m_textline.length()) { m_textline.insert(m_caret, 1, key); PlaceCaret(m_caret + 1 ); m_selection_start = m_caret; } } } break; } } } // CTRL+C if ((virtual_code == NUX_VK_C) && (state & NUX_STATE_CTRL)) { std::string s = GetSelectedText(); #if defined(NUX_OS_WINDOWS) inlCopyTextToClipboard(s.c_str()); #endif } // CTRL+V if ((virtual_code == NUX_VK_V) && (state & NUX_STATE_CTRL)) { #if defined(NUX_OS_WINDOWS) std::string s = inlReadTextToClipboard(); #elif defined(NUX_OS_LINUX) std::string s = "Paste not implemented yet"; #endif unsigned int start = GetTextSelectionStart(); unsigned int end = GetTextSelectionEnd(); m_textline.replace(start, end - start, s); m_caret = start + (unsigned int) s.length(); UnselectAllText(); } if (virtual_code == NUX_VK_ESCAPE) { // If Text is selected, Unselect UnselectAllText(); } if (virtual_code == NUX_VK_ENTER) { SelectAllText(); } if (virtual_code == NUX_VK_BACKSPACE) { if ( m_caret != m_selection_start ) { DeleteSelectionText(); } else { // Deleting one character if ( m_caret > 0 ) { m_textline.erase(m_caret - 1, 1); PlaceCaret(m_caret - 1 ); m_selection_start = m_caret; } } } else if (virtual_code == NUX_VK_DELETE) { // Check if there is a text selection. if ( m_caret != m_selection_start ) { DeleteSelectionText(); } else { // Deleting one character if (m_caret < (int) m_textline.length()) { m_textline.erase(m_caret, 1); } } } else if (virtual_code == NUX_VK_LEFT) { if (IsTextSelected() && ((state & NUX_STATE_SHIFT) == 0)) { //m_caret = Min(m_caret, m_selection_start); if (m_caret) --m_caret; UnselectAllText(); } else { if ( state & NUX_STATE_CTRL ) { // Control is down. Move the caret to a new item // instead of a character. m_caret = PrevWordPosition( m_caret); PlaceCaret(m_caret ); } else if ( m_caret > 0 ) PlaceCaret(m_caret - 1 ); if ((state & NUX_STATE_SHIFT) == 0) { // Shift is not down. Update selection // start along with the caret. m_selection_start = m_caret; } } } else if (virtual_code == NUX_VK_RIGHT) { if (IsTextSelected() && ((state & NUX_STATE_SHIFT) == 0)) { m_caret = Max(m_caret, m_selection_start); UnselectAllText(); } else { if ( state & NUX_STATE_CTRL) { // Control is down. Move the caret to a new item // instead of a character. m_caret = NextWordPosition( m_caret); PlaceCaret(m_caret ); } else if (m_caret < (int) m_textline.length()) PlaceCaret(m_caret + 1 ); if ((state & NUX_STATE_SHIFT) == 0) { // Shift is not down. Update selection // start along with the caret. m_selection_start = m_caret; } } } else if (virtual_code == NUX_VK_HOME) { if ((state & NUX_STATE_SHIFT) == 0) { PlaceCaret(0); // Shift is not down. Update selection // start along with the caret. m_selection_start = m_caret; } else { PlaceCaret(0 ); } } else if (virtual_code == NUX_VK_END) { if ((state & NUX_STATE_SHIFT) == 0) { PlaceCaret((unsigned int) m_textline.length()); // Shift is not down. Update selection // start along with the caret. m_selection_start = m_caret; } else { PlaceCaret((unsigned int) m_textline.length()); } } else if (virtual_code == NUX_VK_ESCAPE) { return virtual_code; } else if (virtual_code == NUX_VK_ENTER) { return virtual_code; } else { m_need_redraw = false; } if (virtual_code == NUX_VK_HOME) { m_text_positionx = 0; } else if (virtual_code == NUX_VK_END) { unsigned int str_width = GetFont()->GetStringWidth(m_textline.c_str()); if (str_width + s_cursor_width > (unsigned int) m_clip_region.GetWidth()) m_text_positionx = m_clip_region.GetWidth() - (str_width + s_cursor_width); else m_text_positionx = 0; } else if (m_textline.length() != 0) { AdjustCursorAndTextPosition(); m_need_redraw = true; } else if (m_textline.length() == 0) { ClearText(); m_need_redraw = true; } return virtual_code; } void BaseKeyboardHandler::AdjustCursorAndTextPosition() { int str_width = GetFont()->GetStringWidth(m_textline.c_str()); std::string temp0; if (m_caret > 0) temp0 = m_textline.substr(0, m_caret - 1); else temp0 = ""; // 0 1 2 // 01234567|8901234567890123456789 // abcdefgh|ijklmn // // Caret pos = 8 // temp0 = "abcdefg" // temp1 = "abcdefgh" // temp2 = "abcdefghi" std::string temp1 = m_textline.substr(0, m_caret); std::string temp2 = m_textline.substr(0, m_caret + 1); int str_width0 = GetFont()->GetStringWidth(temp0); int str_width1 = GetFont()->GetStringWidth(temp1); int str_width2 = GetFont()->GetStringWidth(temp2); if ((m_text_positionx + str_width1 + s_cursor_width) > m_clip_region.GetWidth()) { // Hitting the end of the text box if (m_caret == (int) m_textline.length()) { m_text_positionx = - (str_width + (int) s_cursor_width - m_clip_region.GetWidth()); } else { int PreviousCharWidth = str_width1 - str_width0; int Offset = Min (s_jump_offset_at_borders, str_width + s_cursor_width - str_width1); while (Offset > m_clip_region.GetWidth()) { Offset /= 2; } if (Offset < PreviousCharWidth) Offset = PreviousCharWidth; m_text_positionx -= Offset; if (m_text_positionx + str_width + s_cursor_width < (int) m_clip_region.GetWidth()) { m_text_positionx = - (str_width + (int) s_cursor_width - m_clip_region.GetWidth()); } } } else if ((m_text_positionx + str_width1) <= 0) { // Hitting the start of the text box if (m_caret == 0) { m_text_positionx = 0; } else { int NextCharWidth = str_width2 - str_width1; int Offset = Min (s_jump_offset_at_borders, str_width1); while (Offset > m_clip_region.GetWidth()) { Offset /= 2; } if (Offset < NextCharWidth) Offset = NextCharWidth; if (Offset > str_width1) { m_text_positionx = 0; return; } m_text_positionx += Offset; if (m_text_positionx > 0) { m_text_positionx = 0; } } } } void BaseKeyboardHandler::MoveCursorAtStart() { m_previous_cursor_position = m_caret; m_caret = 0; } void BaseKeyboardHandler::MoveCursorAtEnd() { unsigned int StrLength = ( unsigned int) m_textline.length(); m_previous_cursor_position = m_caret; m_caret = StrLength; } void BaseKeyboardHandler::SetKeyEntryType(BaseKeyboardHandler::eKeyEntryType keytype) { m_KeyType = keytype; } BaseKeyboardHandler::eKeyEntryType BaseKeyboardHandler::GetKeyEntryType() { return m_KeyType; } void BaseKeyboardHandler::SetText(const char *str) { m_textline = str; // Every time we set the text, we reposition the cursor at the beginning of the text, // and the text position is set to zero with regard to the start of the geometry area. MoveCursorAtStart(); m_selection_start = Min (m_selection_start, (int) StringLength(str)); m_caret = Min (m_caret, (int) StringLength(str)); if (m_caret < m_selection_start) m_selection_start = Max (m_selection_start, (int) StringLength(str)); else if (m_caret > m_selection_start) m_caret = Max (m_caret, (int) StringLength(str)); m_text_positionx = 0; } void BaseKeyboardHandler::SetText(const std::string &s) { SetText(s.c_str()); } void BaseKeyboardHandler::SetClipRegion(const Geometry &g) { m_clip_region = g; } void BaseKeyboardHandler::GetTextSelection(int *start, int *end) const { *start = Min(m_selection_start, m_caret); *end = Max(m_selection_start, m_caret); } int BaseKeyboardHandler::GetTextSelectionStart() const { return Min(m_selection_start, m_caret); } int BaseKeyboardHandler::GetTextSelectionEnd() const { return Max(m_selection_start, m_caret); } void BaseKeyboardHandler::SelectAllText() { m_selection_start = 0; m_caret = (unsigned int) m_textline.length(); AdjustCursorAndTextPosition(); } void BaseKeyboardHandler::UnselectAllText() { m_selection_start = m_caret; } std::string BaseKeyboardHandler::GetSelectedText() const { if (m_selection_start == m_caret) { return std::string(""); } else { std::string s = m_textline.substr(GetTextSelectionStart(), GetTextSelectionEnd() - GetTextSelectionStart()); return s; } } bool BaseKeyboardHandler::IsTextSelected() { if (m_caret != m_selection_start) return true; return false; } void BaseKeyboardHandler::SetFont(ObjectPtr Font) { m_Font = Font; } ObjectPtr BaseKeyboardHandler::GetFont() const { return m_Font; } } nux-4.0.8+18.10.20180623/Nux/KeyboardHandler.h0000644000000000000000000001060413313373365014563 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef KEYBOARDHANDLER_H #define KEYBOARDHANDLER_H #include #include "Utils.h" #include "NuxGraphics/FontTexture.h" #if defined(NUX_OS_WINDOWS) #include "NuxGraphics/Events.h" #elif defined(NUX_OS_LINUX) #include "NuxGraphics/Events.h" #endif #include "NuxCore/Color.h" namespace nux { class GraphicsEngine; class BaseKeyboardHandler { public: enum eKeyEntryType { eAlphaNumeric, eDecimalNumber, eIntegerNumber, eHexadecimalNumber, eBinaryNumber }; BaseKeyboardHandler(); virtual ~BaseKeyboardHandler(); virtual long ProcessKey( unsigned long eventType /*event type*/, unsigned long keysym /*event keysym*/, unsigned long state /*event state*/, char character /*character*/, const Geometry &g); std::string GetTextLine() const { return m_textline; } unsigned int GetLength() const { return (unsigned int) m_textline.length(); } unsigned int GetCursorPosition() const { return m_caret; } bool QueueDraw() const { return m_need_redraw; } int GetPositionX() const { return m_text_positionx; } int GetPositionY() const { return m_text_positiony; } void SetText(const char *str); void SetText(const std::string &s); void ClearText(); void PlaceCaret(unsigned int cp); void MoveCursorAtStart(); void MoveCursorAtEnd(); void SetKeyEntryType(eKeyEntryType keytype); eKeyEntryType GetKeyEntryType(); void SetClipRegion(const Geometry &g); void GetTextSelection(int *start, int *end) const; int GetTextSelectionStart() const; int GetTextSelectionEnd() const; std::string GetSelectedText() const; void SelectAllText(); void UnselectAllText(); bool IsTextSelected(); void SetPrefix(std::string); // 0x865, 25 rad, 25 degree... void SetPostfix(std::string); void EnterFocus(); unsigned int NextWordPosition(unsigned int cp); unsigned int PrevWordPosition(unsigned int cp); void ResolveCaretPosition(int x, int y); void CaretAutoScroll(int x, int y, Geometry geo); void MouseDown(int x, int y); void MouseUp(int x, int y); void MouseDrag(int x, int y); //bool IsMouseDrag(); void SetFont(ObjectPtr Font); ObjectPtr GetFont() const; protected: ObjectPtr m_Font; std::string m_textline; int m_previous_cursor_position; bool m_need_redraw; int m_text_positionx; int m_text_positiony; Geometry m_clip_region; eKeyEntryType m_KeyType; int m_caret; //!< Caret position, in characters bool m_insert_mode; //!< If true, control is in insert mode. Else, overwrite mode. int m_selection_start; //!< Starting position of the selection. The caret marks the end. int m_first_visible_char; //!< First visible character in the edit control void DeleteSelectionText(); void InsertChar(unsigned int character); void AdjustCursorAndTextPosition(); bool m_entering_focus; bool m_mouse_drag; // m_mouse_inside_text_area Detects the fast transition of the mouse from inside the text area to outside bool m_mouse_inside_text_area; /*! When the caret reaches the left or right border of the control and there are more characters to reveals, the caret jumps back in the opposite direction by a number of pixel at the same moment when new characters are revealed. */ static int s_jump_offset_at_borders; static int s_cursor_width; }; } #endif // KEYBOARDHANDLER_H nux-4.0.8+18.10.20180623/Nux/KineticScrollView.cpp0000644000000000000000000001066413313373365015466 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #include #include #include "KineticScrollView.h" using namespace nux; NUX_IMPLEMENT_OBJECT_TYPE(KineticScrollView); KineticScrollView::KineticScrollView(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM), mouse_pressed_on_child_(false), last_child_mouse_position_x_(0), last_child_mouse_position_y_(0) { mouse_down.connect(sigc::mem_fun(this, &KineticScrollView::OnMouseDown)); mouse_up.connect(sigc::mem_fun(this, &KineticScrollView::OnMouseUp)); mouse_drag.connect(sigc::mem_fun(this, &KineticScrollView::OnMouseDrag)); scroller_.content_position_changed.connect( sigc::mem_fun(this, &KineticScrollView::SetLayoutTranslation)); SetTrackChildMouseEvents(true); SetBoundsBehavior(BoundsBehavior::DragAndOvershootBounds); } KineticScrollView::~KineticScrollView() { } void KineticScrollView::SetBoundsBehavior(BoundsBehavior bounds_behavior) { scroller_.SetBoundsBehavior(bounds_behavior); } void KineticScrollView::SetScrollableDirections(ScrollableDirections scrollable_directions) { scroller_.SetScrollableDirections(scrollable_directions); } bool KineticScrollView::ChildMouseEvent(const Event& event) { bool want_mouse_ownership = false; if (event.type == NUX_MOUSE_PRESSED || event.type == NUX_MOUSE_DOUBLECLICK) { mouse_pressed_on_child_ = true; last_child_mouse_position_x_ = event.x; last_child_mouse_position_y_ = event.y; scroller_.ProcessFingerDown(); } else if (event.type == NUX_MOUSE_MOVE) { int dx = event.x - last_child_mouse_position_x_; int dy = event.y - last_child_mouse_position_y_; scroller_.ProcessFingerDrag(dx, dy); if (scroller_.GetHorizontalAxisState() == KineticScrollerAxisStateFollowingFinger || scroller_.GetVerticalAxisState() == KineticScrollerAxisStateFollowingFinger) { want_mouse_ownership = true; } } else if (event.type == NUX_MOUSE_RELEASED) { mouse_pressed_on_child_ = false; scroller_.ProcessFingerUp(); } return want_mouse_ownership; } void KineticScrollView::Draw(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { if (view_layout_) { view_layout_->QueueDraw(); } } void KineticScrollView::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { if (view_layout_) view_layout_->ProcessDraw(graphics_engine, force_draw); } long KineticScrollView::PostLayoutManagement(long /* LayoutResult */) { if (view_layout_) { scroller_.SetContentSize(view_layout_->GetBaseWidth(), view_layout_->GetBaseHeight()); } scroller_.SetViewportSize(GetBaseWidth(), GetBaseHeight()); /* the return value is meaningless and not used for anything. */ return 0; } void KineticScrollView::PostResizeGeometry() { scroller_.SetViewportSize(GetBaseWidth(), GetBaseHeight()); } void KineticScrollView::OnMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { scroller_.ProcessFingerDown(); } void KineticScrollView::OnMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { scroller_.ProcessFingerUp(); } void KineticScrollView::OnMouseDrag(int /* x */, int /* y */, int dx, int dy, unsigned long /* button_flags */, unsigned long /* key_flags */) { scroller_.ProcessFingerDrag(dx, dy); } void KineticScrollView::SetLayoutTranslation(int x, int y) { if (view_layout_) { view_layout_->Set2DTranslation(x, y, 0); QueueDraw(); } } nux-4.0.8+18.10.20180623/Nux/KineticScrollView.h0000644000000000000000000000661413313373365015133 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_KINETIC_SCROLL_VIEW_H #define NUX_KINETIC_SCROLL_VIEW_H #include #include #include namespace nux { /* Used to scroll content that is bigger than the available space to display it. Unlike ScrollView, where scroll bars are used to move the content, here you directly drag the content with a mouse pointer or finger (in case of a touchscreen). Items inside a KineticScrollView should properly handle events of type EVENT_MOUSE_CANCEL. If an item inside a kinetic scroll view is pressed, it gets a EVENT_MOUSE_DOWN as usual. But if the user starts dragging it (instead of releasing it to generete a "click"), the KineticScrollView will get ownership of the mouse and that item will receive an EVENT_MOUSE_CANCEL signalling that it no longer has the mouse and won't get any further events from it. The mouse will then be used for scrolling or flicking the KineticScrollView contents until it's released. Usage example: VLayout *layout = new Layout; for (...) { ... layout->AddView(item ...); } KineticScrollView *kinetic_scroll_view = new KineticScrollView; kinetic_scroll_view->SetLayout(layout); */ class KineticScrollView : public View { NUX_DECLARE_OBJECT_TYPE(KineticScrollView, View); public: KineticScrollView(NUX_FILE_LINE_PROTO); virtual ~KineticScrollView(); void SetScrollableDirections(ScrollableDirections scrollable_directions); /*! Defines what happens when the viewport is about to go beyond content boundaries The default value is DragAndOvershootBounds. */ void SetBoundsBehavior(BoundsBehavior bounds_behavior); /* Reimplemented */ virtual bool ChildMouseEvent(const Event& event); protected: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual long PostLayoutManagement(long LayoutResult); virtual void PostResizeGeometry(); private: void OnMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void SetLayoutTranslation(int x, int y); KineticScroller scroller_; /* Variables used to process events from ChildMouseEven() */ bool mouse_pressed_on_child_; int last_child_mouse_position_x_; int last_child_mouse_position_y_; }; } // namespace nux #endif // NUX_KINETIC_SCROLL_VIEW_H nux-4.0.8+18.10.20180623/Nux/KineticScrolling/0000755000000000000000000000000013313373365014616 5ustar nux-4.0.8+18.10.20180623/Nux/KineticScrolling/AxisDecelerationAnimation.cpp0000644000000000000000000000613313313373365022410 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #include #include "AxisDecelerationAnimation.h" using namespace nux; const float AxisDecelerationAnimation::MINIMUM_VELOCITY = 0.07f; void AxisDecelerationAnimation::SetOvershootBoundsEnabled(bool enable) { overshoot_bounds_ = enable; } void AxisDecelerationAnimation::SetMinimumPosition(float min_pos) { min_pos_ = min_pos; } void AxisDecelerationAnimation::SetMaximumPosition(float max_pos) { max_pos_ = max_pos; } void AxisDecelerationAnimation::SetStartPosition(float position) { start_pos_ = position; } void AxisDecelerationAnimation::SetStartVelocity(float velocity) { start_vel_ = velocity; } void AxisDecelerationAnimation::Start() { decay_constant_ = 0.01f; overshoot_constant_ = 0.007f; pos_ = start_pos_; vel_ = start_vel_; elapsed_time_ = 0; } void AxisDecelerationAnimation::Update(int delta_time) { // Exponential decay elapsed_time_ += delta_time; vel_ = start_vel_ * expf(-(decay_constant_ * elapsed_time_)); pos_ += vel_ * delta_time; if (overshoot_bounds_) { PullBackIfBeyondBoundaries(delta_time); } else { StopIfBeyondBoundaries(); } } void AxisDecelerationAnimation::PullBackIfBeyondBoundaries(int delta_time) { // If we overshot, apply a spring acceleration to bring position // back to its max/min limit. if (pos_ > max_pos_) { float dt = delta_time; float acceleration = -overshoot_constant_ * (pos_ - max_pos_); pos_ += (vel_*dt) + (acceleration*dt*dt/2.0f); vel_ += acceleration*dt; if (fabs(pos_ - max_pos_) < 1.5f) { pos_ = max_pos_; vel_ = 0.0f; } } else if (pos_ < min_pos_) { float dt = delta_time; float acceleration = -overshoot_constant_ * (pos_ - min_pos_); pos_ += (vel_*dt) + (acceleration*dt*dt/2.0f); vel_ += acceleration*dt; if (fabs(pos_ - min_pos_) < 1.5f) { pos_ = min_pos_; vel_ = 0.0f; } } } float AxisDecelerationAnimation::GetPosition() const { return pos_; } bool AxisDecelerationAnimation::IsActive() const { if (pos_ < min_pos_ || pos_ > max_pos_) return true; else return (fabs(vel_) > MINIMUM_VELOCITY); } void AxisDecelerationAnimation::StopIfBeyondBoundaries() { if (pos_ > max_pos_) { pos_ = max_pos_; vel_ = 0.0f; } else if (pos_ < min_pos_) { pos_ = min_pos_; vel_ = 0.0f; } } nux-4.0.8+18.10.20180623/Nux/KineticScrolling/AxisDecelerationAnimation.h0000644000000000000000000000620213313373365022052 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_AXIS_DECELERATION_ANIMATION_H #define NUX_AXIS_DECELERATION_ANIMATION_H namespace nux { /*! Animates the deceleration along an axis until it comes to a halt Usage: 1 - Setup the animation animation.SetMinimumPosition(0.0f); animation.SetMaximumPosition(100.0f); animation.SetStartPosition(34.0f); animation.SetStartVelocity(2.0f); 2 - Start it animation.Start(); 3 - Update it at regular intervals until it finishes animation.Update(delta_time); new_pos = animation.GetPosition(); if (!animation.IsActive()) Stop updating this animation */ class AxisDecelerationAnimation { public: /*! Sets whether position limits can be momentarily overshot */ void SetOvershootBoundsEnabled(bool enable); void SetMinimumPosition(float min_pos); void SetMaximumPosition(float max_pos); void SetStartPosition(float position); /*! \param velocity Initial velocity, in axis units per millisecond. */ void SetStartVelocity(float velocity); /*! Marks the end of the setup phase and sets the animation time to 0. After that, Update() should be called until IsActive() returns false. This method can also be used to restart an ongoing animation. */ void Start(); /*! Moves the animation forward by delta_time milliseconds. After calling this method you will normally want to know the new position (GetPosition()) and whether the animation has finished (IsActive()), meaning that movement along that axis came to a halt. \param delta_time Time elapsed since the last call to Update() */ void Update(int delta_time); /*! Current position along that axis. It changes by every call made to Update() while IsActive() is true. */ float GetPosition() const; /*! Returns whether the animation has finished, meaning that further calls to Update() will no longer change the position. I.e., movement reached a complete halt. */ bool IsActive() const; private: void PullBackIfBeyondBoundaries(int delta_time); void StopIfBeyondBoundaries(); static const float MINIMUM_VELOCITY; float start_pos_; float start_vel_; float pos_; float vel_; float min_pos_; float max_pos_; int elapsed_time_; float decay_constant_; float overshoot_constant_; bool overshoot_bounds_; }; } // namespace nux #endif // NUX_AXIS_DECELERATION_ANIMATION_H nux-4.0.8+18.10.20180623/Nux/KineticScrolling/KineticAxisScroller.cpp0000644000000000000000000001727513313373365021257 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #include #include "KineticAxisScroller.h" #include "AxisDecelerationAnimation.h" #include "VelocityCalculator.h" #include #include "KineticScrollingTickSource.h" using namespace nux; /***************************************************************************** * Private class *****************************************************************************/ class KineticAxisScroller::Private : public sigc::trackable { public: Private(); void CalculateContentPosLimits(); void ProcessFingerDown(); void ProcessFingerUp(); void ProcessFingerDrag(int mov); void ProcessFingerDrag_Pressed(int mov); void ProcessFingerDrag_FollowingFinger(int mov); void UpdateAnimations(int time); int LimitOutOfBoundsMovement(int movement, int position, int min_position) const; float viewport_length_; float content_length_; float content_pos_; float min_content_pos_; BoundsBehavior bounds_behavior_; KineticScrollerAxisState state_; VelocityCalculator velocity_calculator_; AxisDecelerationAnimation deceleration_animation_; int accumulated_movement_; }; KineticAxisScroller::Private::Private() { viewport_length_ = 0.0f; content_length_ = 0.0f; content_pos_ = 0.0f; min_content_pos_ = 0.0f; bounds_behavior_ = DragAndOvershootBounds; state_ = KineticScrollerAxisStateIdle; } void KineticAxisScroller::Private::CalculateContentPosLimits() { if (content_length_ > viewport_length_) min_content_pos_ = -(content_length_ - viewport_length_); else min_content_pos_ = 0.0f; } void KineticAxisScroller::Private::ProcessFingerDown() { switch (state_) { case KineticScrollerAxisStateIdle: state_ = KineticScrollerAxisStatePressed; accumulated_movement_ = 0; break; case KineticScrollerAxisStateMovingByInertia: state_ = KineticScrollerAxisStatePressed; accumulated_movement_ = 0; break; default: /* Ignore it */ break; } } void KineticAxisScroller::Private::ProcessFingerUp() { // consider the elapsed time between the last drag update and now, that the // finger has been lifted (it could have been still for a while). velocity_calculator_.ProcessMovement(0); float velocity = velocity_calculator_.CalculateVelocity(); if (fabs(velocity) < MINIMUM_FLICK_SPEED) velocity = 0.0f; else velocity *= FLICK_BOOST; /* Always run the animation, even if there's no starting speed, as it will pull the content back to a valid position if it was dragged beyond valid boundaries */ deceleration_animation_.SetMinimumPosition(min_content_pos_); deceleration_animation_.SetMaximumPosition(0.0f); deceleration_animation_.SetStartPosition(content_pos_); deceleration_animation_.SetStartVelocity(velocity); deceleration_animation_.Start(); state_ = KineticScrollerAxisStateMovingByInertia; } void KineticAxisScroller::Private::ProcessFingerDrag(int movement) { movement = LimitOutOfBoundsMovement(movement, content_pos_, min_content_pos_); if (movement == 0) return; if (state_ == KineticScrollerAxisStatePressed) { ProcessFingerDrag_Pressed(movement); } else // KineticScrollerAxisState::FollowingFinger { ProcessFingerDrag_FollowingFinger(movement); } } void KineticAxisScroller::Private::ProcessFingerDrag_Pressed(int movement) { accumulated_movement_ += movement; if (abs(accumulated_movement_) > KineticAxisScroller::MOVEMENT_THRESHOLD) { state_ = KineticScrollerAxisStateFollowingFinger; velocity_calculator_.Reset(); ProcessFingerDrag_FollowingFinger(movement); } } void KineticAxisScroller::Private::ProcessFingerDrag_FollowingFinger(int movement) { /* TODO: Filter the input for a smoother movement. E.g.: make the content follow the finger with a small delay instead of exactly following it. That will remove the inherent jitter in input coming from a touchscreen. */ content_pos_ += movement; velocity_calculator_.ProcessMovement(movement); } void KineticAxisScroller::Private::UpdateAnimations(int delta_time) { if (deceleration_animation_.IsActive()) { deceleration_animation_.Update(delta_time); content_pos_ = deceleration_animation_.GetPosition(); if (!deceleration_animation_.IsActive()) state_ = KineticScrollerAxisStateIdle; } else { state_ = KineticScrollerAxisStateIdle; } } int KineticAxisScroller::Private::LimitOutOfBoundsMovement(int movement, int position, int min_position) const { int new_position = position + movement; if (new_position > 0) { if (bounds_behavior_ == StopAtBounds) { return 0 - position; } else { /* hinder movement to hint user that he's dragging content beyound its boundaries*/ return movement / 2; } } else if (new_position < min_position) { if (bounds_behavior_ == StopAtBounds) { return min_position - position; } else { return movement / 2; } } else { /* new_position is still within bounds */ return movement; } } /***************************************************************************** * Public class *****************************************************************************/ const float KineticAxisScroller::MINIMUM_FLICK_SPEED = 0.003f; const float KineticAxisScroller::FLICK_BOOST = 2.0f; KineticAxisScroller::KineticAxisScroller() : p(new Private) { } KineticAxisScroller::~KineticAxisScroller() { delete p; } void KineticAxisScroller::SetViewportLength(int length) { p->viewport_length_ = length; p->CalculateContentPosLimits(); } int KineticAxisScroller::GetViewportLength() const { return p->viewport_length_; } void KineticAxisScroller::SetContentLength(int length) { p->content_length_ = length; p->CalculateContentPosLimits(); } int KineticAxisScroller::GetContentLength() const { return p->content_length_; } void KineticAxisScroller::SetContentPosition(int pos) { p->content_pos_ = pos; } void KineticAxisScroller::SetBoundsBehavior(BoundsBehavior bounds_behavior) { p->bounds_behavior_ = bounds_behavior; p->deceleration_animation_.SetOvershootBoundsEnabled( bounds_behavior != BoundsBehavior::StopAtBounds); } void KineticAxisScroller::ProcessFingerDown() { p->ProcessFingerDown(); } void KineticAxisScroller::ProcessFingerUp() { p->ProcessFingerUp(); } void KineticAxisScroller::ProcessFingerDrag(int movement) { p->ProcessFingerDrag(movement); } void KineticAxisScroller::UpdateTime(int delta_time) { p->UpdateAnimations(delta_time); } bool KineticAxisScroller::NeedTimeUpdates() const { return p->state_ == KineticScrollerAxisStateMovingByInertia && p->deceleration_animation_.IsActive(); } KineticScrollerAxisState KineticAxisScroller::GetState() const { return p->state_; } int KineticAxisScroller::GetContentPosition() const { return p->content_pos_; } nux-4.0.8+18.10.20180623/Nux/KineticScrolling/KineticAxisScroller.h0000644000000000000000000001236513313373365020717 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_KINETIC_AXIS_SCROLLER_H #define NUX_KINETIC_AXIS_SCROLLER_H #include "KineticScrollingEnums.h" namespace nux { namespace kinetic_scrolling { class TickSourceInterface; } /* Drives the scrolling of an entity based on user input, along an axis Given information on user input (e.g. touches and mouse events) it tells how a view/entity/object should react by scrolling in a kinetic fashion. The scroller moves the content and considers the viewport to be fixed. */ class KineticAxisScroller { public: /* Minimum flick speed, in axis units per millisecond. If the flick speed is lower than that there will be no kinetic scrolling. */ static const float MINIMUM_FLICK_SPEED; /* Multiplier for the flick speed, to make flicking more effective. */ static const float FLICK_BOOST; /*! Enumeration that describes the possible states of the kinetic scroller */ enum States { Idle, /*!< It's not pressed and not moving. This is the initial state */ Pressed, /*!< It's pressed but not yet moving. */ FollowingFinger, /*!< It's pressed and moving to follow the user's finger */ MovingByInertia /*!< It's not pressed anymore but it's still moving due to inertia. Reacheable from FollowingFinger. After it loses all its momentum it will stop and therefore move to the Idle state. */ }; /*! Minimum movement of the finger along an axis necessary for the scroller to start following it. I.e. to move from Pressed to FollowingFinger state. */ static const int MOVEMENT_THRESHOLD = 5; KineticAxisScroller(); virtual ~KineticAxisScroller(); /***** Initialization ******/ /*! Specifies the length of the viewport. Any existing momentum or movement is halted. You will usually call this method only during initialization. */ void SetViewportLength(int length); /*! Returns the viewport length set via SetViewportLength() */ int GetViewportLength() const; /*! Specifies the length of the content. Scrolling is only useful when the content is larger than the viewport. Any existing momentum or movement is halted. You will usually call this method only during initialization. */ void SetContentLength(int length); /*! Returns the content length set via SetViewportLength() */ int GetContentLength() const; /*! Sets the content position, relative to viewport's top/left corner. Any existing momentum or movement is halted. You will usually call this method only during initialization. */ void SetContentPosition(int pos); /*! Defines what happens when the viewport is about to be beyond content boundaries The default value is DragAndOvershootBounds. */ void SetBoundsBehavior(BoundsBehavior bounds_behavior); /***** input ******/ /*! Tells the scroller that a finger is touching the scrollable surface The scroller is interested only in single finger interactions. If subsequent fingers hit the surface they shouldn't be informed to the scroller. Thus calling this method twice, without a ProcessFingerUp() in between, is not supported. */ void ProcessFingerDown(); /*! Tells the scroller that a finger has left the scrollable surface \sa ProcessFingerDown() */ void ProcessFingerUp(); /*! Tells the scroller that a finger has moved along the scrollable surface \param movement How far it has moved along the axis. */ void ProcessFingerDrag(int movement); /*! Moves animations forward by delta_time milliseconds. After calling this method you will normally want to know the new position (GetPosition()) and whether the animation has finished (IsActive()), meaning that movement along that axis came to a halt. \param delta_time Time elapsed since the last call to Update() */ void UpdateTime(int delta_time); /***** Scrolling output ******/ int GetContentPosition() const; /*! Whether, in its current state, the scroller needs UpdateTime() to be called That happens in states where content position changes happen due to internal animations and not in direct response to user input like in ProcessFingerDrag() */ bool NeedTimeUpdates() const; /*! Returns the current state of the kinetic scroller. */ KineticScrollerAxisState GetState() const; private: class Private; Private *p; }; } // namespace nux #endif // NUX_KINETIC_AXIS_SCROLLER_H nux-4.0.8+18.10.20180623/Nux/KineticScrolling/KineticScroller.cpp0000644000000000000000000001536513313373365020430 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #include #include "KineticScroller.h" #include "KineticAxisScroller.h" #include "AxisDecelerationAnimation.h" #include "VelocityCalculator.h" #include #include "KineticScrollingTickSource.h" using namespace nux; /***************************************************************************** * Private class *****************************************************************************/ class KineticScroller::Private : public sigc::trackable { public: Private(); Private(kinetic_scrolling::TickSourceInterface *tick_source); void Init(); void SetViewportSize(int width, int height); void SetContentSize(int width, int height); void SetContentPosition(int x, int y); void ProcessFingerDown(); void ProcessFingerUp(); void ProcessFingerDrag(int dx, int dy); void UpdateAnimations(int time); void CheckChangesInContentPosition(); bool CanScrollHorizontally() const; bool CanScrollVertically() const; ScrollableDirections scrollable_directions_; std::unique_ptr tick_source_; sigc::signal *content_position_changed; KineticAxisScroller scroller_x_; KineticAxisScroller scroller_y_; int last_content_pos_x_; int last_content_pos_y_; }; KineticScroller::Private::Private() { tick_source_.reset(new kinetic_scrolling::TimerTickSource); Init(); } KineticScroller::Private::Private(kinetic_scrolling::TickSourceInterface *tick_source) { tick_source_.reset(tick_source); Init(); } void KineticScroller::Private::Init() { scrollable_directions_ = ScrollableDirectionsAuto; tick_source_->tick.connect( sigc::mem_fun(this, &KineticScroller::Private::UpdateAnimations)); } void KineticScroller::Private::SetViewportSize(int width, int height) { scroller_x_.SetViewportLength(width); scroller_y_.SetViewportLength(height); } void KineticScroller::Private::SetContentSize(int width, int height) { scroller_x_.SetContentLength(width); scroller_y_.SetContentLength(height); } void KineticScroller::Private::SetContentPosition(int x, int y) { scroller_x_.SetContentPosition(x); scroller_y_.SetContentPosition(y); last_content_pos_x_ = x; last_content_pos_y_ = y; } void KineticScroller::Private::ProcessFingerDown() { if (CanScrollHorizontally()) scroller_x_.ProcessFingerDown(); if (CanScrollVertically()) scroller_y_.ProcessFingerDown(); tick_source_->Stop(); } void KineticScroller::Private::ProcessFingerUp() { if (CanScrollHorizontally()) scroller_x_.ProcessFingerUp(); if (CanScrollVertically()) scroller_y_.ProcessFingerUp(); if (scroller_x_.NeedTimeUpdates() || scroller_y_.NeedTimeUpdates()) tick_source_->Start(); } void KineticScroller::Private::ProcessFingerDrag(int dx, int dy) { if (CanScrollHorizontally()) scroller_x_.ProcessFingerDrag(dx); if (CanScrollVertically()) scroller_y_.ProcessFingerDrag(dy); CheckChangesInContentPosition(); } void KineticScroller::Private::UpdateAnimations(int delta_time) { if (scroller_x_.NeedTimeUpdates()) scroller_x_.UpdateTime(delta_time); if (scroller_y_.NeedTimeUpdates()) scroller_y_.UpdateTime(delta_time); CheckChangesInContentPosition(); if (!scroller_x_.NeedTimeUpdates() && !scroller_y_.NeedTimeUpdates()) tick_source_->Stop(); } void KineticScroller::Private::CheckChangesInContentPosition() { if (last_content_pos_x_ != scroller_x_.GetContentPosition() || last_content_pos_y_ != scroller_y_.GetContentPosition()) { content_position_changed->emit(scroller_x_.GetContentPosition(), scroller_y_.GetContentPosition()); } last_content_pos_x_ = scroller_x_.GetContentPosition(); last_content_pos_y_ = scroller_y_.GetContentPosition(); } bool KineticScroller::Private::CanScrollHorizontally() const { return scrollable_directions_ == ScrollableDirectionsHorizontal || scrollable_directions_ == ScrollableDirectionsHorizontalAndVertical || (scrollable_directions_ == ScrollableDirectionsAuto && scroller_x_.GetViewportLength() < scroller_x_.GetContentLength()); } bool KineticScroller::Private::CanScrollVertically() const { return scrollable_directions_ == ScrollableDirectionsVertical || scrollable_directions_ == ScrollableDirectionsHorizontalAndVertical || (scrollable_directions_ == ScrollableDirectionsAuto && scroller_y_.GetViewportLength() < scroller_y_.GetContentLength()); } /***************************************************************************** * Public class *****************************************************************************/ KineticScroller::KineticScroller() : p(new Private) { p->content_position_changed = &content_position_changed; } KineticScroller::KineticScroller(kinetic_scrolling::TickSourceInterface *tick_source) : p(new Private(tick_source)) { p->content_position_changed = &content_position_changed; } KineticScroller::~KineticScroller() { delete p; } void KineticScroller::SetViewportSize(int width, int height) { p->SetViewportSize(width, height); } void KineticScroller::SetContentSize(int width, int height) { p->SetContentSize(width, height); } void KineticScroller::SetContentPosition(int x, int y) { p->SetContentPosition(x, y); } void KineticScroller::SetBoundsBehavior(BoundsBehavior bounds_behavior) { p->scroller_x_.SetBoundsBehavior(bounds_behavior); p->scroller_y_.SetBoundsBehavior(bounds_behavior); } void KineticScroller::SetScrollableDirections( ScrollableDirections scrollable_directions) { p->scrollable_directions_ = scrollable_directions; } void KineticScroller::ProcessFingerDown() { p->ProcessFingerDown(); } void KineticScroller::ProcessFingerUp() { p->ProcessFingerUp(); } void KineticScroller::ProcessFingerDrag(int dx, int dy) { p->ProcessFingerDrag(dx, dy); } KineticScrollerAxisState KineticScroller::GetHorizontalAxisState() const { return p->scroller_x_.GetState(); } KineticScrollerAxisState KineticScroller::GetVerticalAxisState() const { return p->scroller_y_.GetState(); } nux-4.0.8+18.10.20180623/Nux/KineticScrolling/KineticScroller.h0000644000000000000000000001042613313373365020066 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_KINETIC_SCROLLER_H #define NUX_KINETIC_SCROLLER_H #include "KineticScrollingEnums.h" namespace nux { namespace kinetic_scrolling { class TickSourceInterface; } /* Drives the scrolling of an entity based on user input Given information on user input (e.g. touches and mouse events) it tells how a view/entity/object should react by scrolling in a kinetic fashion. Thus this class doesn't do anything by itself but must be attached or composed with the object that you want to have kinetic scrolling. The scroller moves the content and considers the viewport to be fixed. */ class KineticScroller { public: /*! Minimum movement of the finger along an axis necessary for the scroller to start following it. I.e. to move from Pressed to FollowingFinger state. */ static const int MOVEMENT_THRESHOLD = 5; KineticScroller(); /*! Constructor useful for testing purposes. When testing you would like to manually drive the animations */ KineticScroller(kinetic_scrolling::TickSourceInterface *tick_source); virtual ~KineticScroller(); /***** Initialization ******/ /*! Specifies the size of the viewport. Any existing momentum or movement is halted. You will usually call this method only during initialization. */ void SetViewportSize(int width, int height); /*! Specifies the size of the content. Scrolling is only useful when the content is larger than the viewport. Any existing momentum or movement is halted. You will usually call this method only during initialization. */ void SetContentSize(int width, int height); /*! Sets the content position, relative to viewport's top-left corner. Any existing momentum or movement is halted. You will usually call this method only during initialization. */ void SetContentPosition(int x, int y); /*! Defines what happens when the viewport is about to be beyond content boundaries The default value is DragAndOvershootBounds. */ void SetBoundsBehavior(BoundsBehavior bounds_behavior); /*! Defines which directions can be scrolled. The default value is Auto. */ void SetScrollableDirections(ScrollableDirections scrollable_directions); /***** input ******/ /*! Tells the scroller that a finger is touching the scrollable surface The scroller is interested only in single finger interactions. If subsequent fingers hit the surface they shouldn't be informed to the scroller. Thus calling this method twice, without a ProcessFingerUp() in between, is not supported. */ void ProcessFingerDown(); /*! Tells the scroller that a finger has left the scrollable surface \sa ProcessFingerDown() */ void ProcessFingerUp(); /*! Tells the scroller that a finger has moved along the scrollable surface \param dx How far it has moved along the X axis. \param dx How far it has moved along the Y axis. */ void ProcessFingerDrag(int dx, int dy); /***** Scrolling output ******/ //! Emitted when the content position changes /*! It won't be emitted due to a call to SetContentPosition(). @param int X coordinate of the new content position. @param int Y coordinate of the new content position. */ sigc::signal content_position_changed; KineticScrollerAxisState GetHorizontalAxisState() const; KineticScrollerAxisState GetVerticalAxisState() const; private: class Private; Private *p; }; } // namespace nux #endif // NUX_KINETIC_SCROLLER_H nux-4.0.8+18.10.20180623/Nux/KineticScrolling/KineticScrollingEnums.h0000644000000000000000000000460713313373365021251 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_KINETIC_SCROLLING_ENUMS_H #define NUX_KINETIC_SCROLLING_ENUMS_H namespace nux { enum BoundsBehavior { StopAtBounds, /*!< content can not be dragged beyond viewport boundaries, and flicks will not overshoot */ DragOverBounds, /*!< content can be dragged beyond viewport boundaries, but flicks will not overshoot. */ DragAndOvershootBounds /*!< content can be dragged beyond viewport boundaries and can overshoot it when flicked. */ }; enum ScrollableDirections { ScrollableDirectionsAuto, ScrollableDirectionsHorizontal, ScrollableDirectionsVertical, ScrollableDirectionsHorizontalAndVertical }; /*! Enumeration that describes the possible states of an axis of the kinetic scroller Kinetic scrolling works for each axis independently. Therefore each axis has its own separate state. */ enum KineticScrollerAxisState { /*!< It's not pressed and not moving. This is the initial state. This is also the state an axis will be if scrolling is not possible or enabled for it. */ KineticScrollerAxisStateIdle, /*!< It's pressed but not yet moving. */ KineticScrollerAxisStatePressed, /*!< It's pressed and moving to follow the user's finger */ KineticScrollerAxisStateFollowingFinger, /*!< It's not pressed anymore but it's still moving due to inertia. Reacheable from FollowingFinger. After it loses all its momentum it will stop and therefore move to the Idle state. */ KineticScrollerAxisStateMovingByInertia }; } // namespace nux #endif // NUX_KINETIC_SCROLLING_ENUMS_H nux-4.0.8+18.10.20180623/Nux/KineticScrolling/KineticScrollingTickSource.cpp0000644000000000000000000000342513313373365022565 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #include #include "KineticScrollingTickSource.h" using namespace nux::kinetic_scrolling; TimerTickSource::TimerTickSource() { timer_functor_.tick.connect(sigc::mem_fun(this, &TimerTickSource::Tick)); timer_functor_.expired.connect(sigc::mem_fun(this, &TimerTickSource::TimerExpired)); } TimerTickSource::~TimerTickSource() { Stop(); } void TimerTickSource::Start() { timer_handle_ = nux::GetTimer().AddDurationTimer(UPDATE_PERIOD, 100000000 /* some arbitrarily long time */, &timer_functor_, NULL); last_elapsed_time_ = 0; } void TimerTickSource::Stop() { if (timer_handle_.IsValid()) { nux::GetTimer().RemoveTimerHandler(timer_handle_); } } void TimerTickSource::Tick(void*) { int delta_time = timer_handle_.GetElapsedTimed() - last_elapsed_time_; last_elapsed_time_ = timer_handle_.GetElapsedTimed(); tick.emit(delta_time); } void TimerTickSource::TimerExpired(void*) { } nux-4.0.8+18.10.20180623/Nux/KineticScrolling/KineticScrollingTickSource.h0000644000000000000000000000425713313373365022236 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_KS_TICK_SOURCE_H #define NUX_KS_TICK_SOURCE_H #include #include /***** * OBS: Would be good have animation::TickSource used instead of this, * but that's not posssible at the moment. ****/ namespace nux { namespace kinetic_scrolling { /*! A class that emits a signal at constant intervals. */ class TickSourceInterface { public: virtual ~TickSourceInterface() {} virtual void Start() = 0; virtual void Stop() = 0; /*! Emitted at a constant frequency. Its parameter is the time elapsed since the previous tick or, if this is the very first tick, since the tick source was started, in milliseconds. */ sigc::signal tick; }; /*! A TickSource implemented using nux::TimerHandler It's way more convenient and testable to use this than nux::TimerHandler if all you want is something that calls you at regular intervals. */ class TimerTickSource : public TickSourceInterface { public: TimerTickSource(); virtual ~TimerTickSource(); virtual void Start(); virtual void Stop(); private: /* update period in milliseconds */ static const int UPDATE_PERIOD = 16 /* 60 fps */; void Tick(void*); void TimerExpired(void*); TimerHandle timer_handle_; TimerFunctor timer_functor_; int64_t last_elapsed_time_; }; } // namespace kinetic_scrolling } // namespace nux #endif // NUX_KS_TICK_SOURCE_H nux-4.0.8+18.10.20180623/Nux/KineticScrolling/VelocityCalculator.cpp0000644000000000000000000000565713313373365021147 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #include "VelocityCalculator.h" #include using namespace nux; VelocityCalculator::VelocityCalculator() { Reset(); } #include void VelocityCalculator::ProcessMovement(int movement) { if (samples_read_ == -1) { samples_read_ = samples_write_; } else if (samples_read_ == samples_write_) { /* the oldest value is going to be overwritten. so now the oldest will be the next one. */ samples_read_ = (samples_read_ + 1) % MAX_SAMPLES; } samples_[samples_write_].mov = movement; samples_[samples_write_].time = g_get_monotonic_time() / 1000; samples_write_ = (samples_write_ + 1) % MAX_SAMPLES; } float VelocityCalculator::CalculateVelocity() const { if (NumSamples() < 2) return 0.0f; int last_index; if (samples_write_ == 0) last_index = MAX_SAMPLES - 1; else last_index = samples_write_ - 1; int64_t curr_time = samples_[last_index].time; int total_time = 0; int total_distance = 0; int sample_index = (samples_read_ + 1) % MAX_SAMPLES; int64_t previous_time = samples_[samples_read_].time; while (sample_index != samples_write_) { // Skip this sample if it's too old if (curr_time - samples_[sample_index].time <= AGE_OLDEST_SAMPLE) { int delta_time = samples_[sample_index].time - previous_time; total_distance += samples_[sample_index].mov; total_time += delta_time; } previous_time = samples_[sample_index].time; sample_index = (sample_index + 1) % MAX_SAMPLES; } return float(total_distance) / float(total_time); } void VelocityCalculator::Reset() { samples_read_ = -1; samples_write_ = 0; } int VelocityCalculator::NumSamples() const { if (samples_read_ == -1) { return 0; } else { if (samples_write_ == 0) { /* consider only what's to the right of samples_read_ (including himself) */ return MAX_SAMPLES - samples_read_; } else if (samples_write_ == samples_read_) return MAX_SAMPLES; /* buffer is full */ else if (samples_write_ < samples_read_) return (MAX_SAMPLES - samples_read_) + samples_write_; else return samples_write_ - samples_read_; } } nux-4.0.8+18.10.20180623/Nux/KineticScrolling/VelocityCalculator.h0000644000000000000000000000444413313373365020605 0ustar /* * Copyright (C) 2012 - Canonical Ltd. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Daniel d'Andrada */ #ifndef NUX_VELOCITY_CALCULATOR_H #define NUX_VELOCITY_CALCULATOR_H #include namespace nux { /* Estimates the current velocity of a finger based on recent movement Taking an estimate from a reasonable number of samples, instead of only from its last movement, removes wild variations in velocity caused by the jitter normally present in input from a touchscreen. */ class VelocityCalculator { public: VelocityCalculator(); /* How much the finger has moved since ProcessMovement() was last called. */ void ProcessMovement(int movement); /* Calculates the finger velocity, in axis units/millisecond */ float CalculateVelocity() const; /* Removes all stored movements from previous calls to ProcessMovement() */ void Reset(); /* Maximum number of movement samples stored */ static const int MAX_SAMPLES = 10; /* Age of the oldest sample considered in the velocity calculations, in milliseconds, compared to the most recent one. */ static const int AGE_OLDEST_SAMPLE = 200; private: int NumSamples() const; class Sample { public: int mov; /* movement distance since last sample */ int64_t time; /* time, in milliseconds */ }; /* a circular buffer of samples */ Sample samples_[MAX_SAMPLES]; int samples_read_; /* index of the oldest sample available. -1 if buffer is empty */ int samples_write_; /* index where the next sample will be written */ }; } // namespace nux #endif // NUX_VELOCITY_CALCULATOR_H nux-4.0.8+18.10.20180623/Nux/LayeredLayout.cpp0000644000000000000000000003620713313373365014652 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Neil Jagdish Patel * */ #include "Nux.h" #include "View.h" #include "LayeredLayout.h" #include namespace nux { LayeredLayout::LayeredChildProperties::LayeredChildProperties(bool expand, int x, int y, int width, int height) : m_expand(expand), m_x(x), m_y(y), m_width(width), m_height(height) {} LayeredLayout::LayeredChildProperties::~LayeredChildProperties() {} void LayeredLayout::LayeredChildProperties::Update(bool expand, int x, int y, int width, int height) { m_expand = expand; m_x = x; m_y = y; m_width = width; m_height = height; } NUX_IMPLEMENT_OBJECT_TYPE(LayeredLayout); LayeredLayout::LayeredLayout(NUX_FILE_LINE_DECL) : Layout(NUX_FILE_LINE_PARAM), m_active_index(0), m_active_area(NULL), m_paint_all(false), m_input_mode(INPUT_MODE_ACTIVE), m_child_draw_queued(false) { m_ContentStacking = eStackLeft; child_queue_draw.connect(sigc::mem_fun(this, &LayeredLayout::ChildQueueDraw)); } LayeredLayout::~LayeredLayout() { } void LayeredLayout::GetCompositeList(std::list *ViewList) { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsView()) { View *ic = NUX_STATIC_CAST(View*, (*it)); ViewList->push_back(ic); } else if ((*it)->IsLayout()) { Layout *layout = NUX_STATIC_CAST(Layout *, (*it)); layout->GetCompositeList(ViewList); } } } long LayeredLayout::ComputeContentSize() { nux::Geometry base = GetGeometry(); std::list::iterator it; int total_max_width = 0; int total_max_height = 0; int ret = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { Area *area = *it; std::shared_ptr props; Geometry geo = base; AreaPropertyMap::iterator prop_it = area_property_map_.find(area); if (prop_it != area_property_map_.end()) { props = prop_it->second; } else { props = 0; } if (props && props->m_expand) { int max_width, max_height; // It wants to expand, however we need to check that it doesn't need at minimum more // space than we have max_width = base.width >= area->GetMinimumWidth() ? base.width : area->GetMinimumWidth(); max_height = base.height >= area->GetMinimumHeight() ? base.height : area->GetMinimumHeight(); geo.width = max_width; geo.height = max_height; total_max_width = total_max_width >= max_width ? total_max_width : max_width; total_max_height = total_max_height >= max_height ? total_max_height : max_height; } else if (props) { geo.x = base.x + props->m_x; geo.y = base.y + props->m_y; geo.width = props->m_width; geo.height = props->m_height; } (*it)->SetGeometry(geo); (*it)->ComputeContentSize(); } SetBaseSize(total_max_width, total_max_height); if (base.width < total_max_width) ret |= eLargerWidth; else ret |= eCompliantWidth; // We don't complain about getting more space if (base.height < total_max_height) ret |= eLargerHeight; else ret |= eCompliantHeight; // Don't complain about getting more space return ret; } void LayeredLayout::PaintOne(Area *_area, GraphicsEngine &graphics_engine, bool force_draw) { if (_area->IsView()) { View *ic = NUX_STATIC_CAST(View *, _area); ic->ProcessDraw(graphics_engine, force_draw); } else if (_area->IsLayout()) { Layout *layout = NUX_STATIC_CAST(Layout *, _area); layout->ProcessDraw(graphics_engine, force_draw); } } void LayeredLayout::ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); if (m_paint_all) { std::list::iterator it, eit = _layout_element_list.end(); unsigned int alpha = 0, src = 0, dest = 0; graphics_engine.GetRenderStates().GetBlend(alpha, src, dest); graphics_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); nux::GetPainter().PaintBackground(graphics_engine, base); nux::GetPainter().PushBackgroundStack(); for (it = _layout_element_list.begin(); it != eit; ++it) { if ((*it)->IsVisible()) PaintOne(static_cast (*it), graphics_engine, true); } nux::GetPainter().PopBackgroundStack(); graphics_engine.GetRenderStates().SetBlend(alpha, src, dest); m_child_draw_queued = false; } else if (m_active_area && m_active_area->IsVisible()) { PaintOne(m_active_area, graphics_engine, force_draw); } graphics_engine.PopClippingRectangle(); draw_cmd_queued_ = false; } Area* LayeredLayout::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { if (m_active_area == NULL) return NULL; bool mouse_inside = m_active_area->TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; if (m_input_mode == INPUT_MODE_ACTIVE) { if (m_active_area && m_active_area->GetInputEventSensitivity() && m_active_area->GetInputEventSensitivity()) return m_active_area->FindAreaUnderMouse(mouse_position, event_type); } else { std::list::reverse_iterator it, eit = _layout_element_list.rend(); for (it = _layout_element_list.rbegin(); it != eit; ++it) { Area *area = (*it); if (area->IsVisible() && area->GetInputEventSensitivity()) { return m_active_area->FindAreaUnderMouse(mouse_position, event_type); } } } return NULL; } void LayeredLayout::AddLayout(Layout *layout, unsigned int /* stretch_factor */, MinorDimensionPosition /* positioning */, MinorDimensionSize /* extend */, float /* percentage */, LayoutPosition /* position */) { AddLayer(layout); } void LayeredLayout::AddView(Area *view, unsigned int /* stretch_factor */, MinorDimensionPosition /* positioning */, MinorDimensionSize /* extend */, float /* percentage */, LayoutPosition /* position */) { AddLayer(view); } void LayeredLayout::RemoveChildObject(Area *area) { RemoveLayer(area); } void LayeredLayout::Clear() { m_active_index = 0; m_active_area = NULL; Layout::Clear(); } void LayeredLayout::ChildQueueDraw(Area * /* area */) { m_child_draw_queued = true; } void LayeredLayout::ChildVisibilityChanged(Area * /* area */, bool /* visible */) { QueueDraw(); } // // LayeredLayout Methods // void LayeredLayout::AddLayer(Area *area, bool expand, int x, int y, int width, int height) { // return if the area is NULL NUX_RETURN_IF_NULL(area); // Return if the area already has a parent NUX_RETURN_IF_NOTNULL(area->GetParentObject()); std::shared_ptr props(new LayeredChildProperties(expand, x, y, width, height)); AreaPropertyMap::iterator it = area_property_map_.find(area); if (it != area_property_map_.end()) { area_property_map_.erase(it); } area_property_map_[area] = props; if (!m_active_area) { m_active_area = area; } props->m_vis_it = area->OnVisibleChanged.connect(sigc::mem_fun(this, &LayeredLayout::ChildVisibilityChanged)); if (area->IsLayout()) Layout::AddLayout(static_cast (area)); else Layout::AddView(area); QueueDraw(); } void LayeredLayout::UpdateLayer(Area *area, bool expand, int x, int y, int width, int height) { std::shared_ptr props; NUX_RETURN_IF_NULL(area); AreaPropertyMap::iterator it = area_property_map_.find(area); if (it != area_property_map_.end()) { props = it->second; } else { props = 0; } if (props == 0) return; props->Update(expand, x, y, width, height); QueueDraw(); } void LayeredLayout::RemoveLayer(Area *area) { if (area == NULL) return; std::shared_ptr props; AreaPropertyMap::iterator prop_it = area_property_map_.find(area); if (prop_it != area_property_map_.end()) { props = prop_it->second; } else { return; } (*props->m_vis_it).disconnect(); area_property_map_.erase(prop_it); if (m_active_area == area) { std::list::iterator it, eit = _layout_element_list.end(); int index = 0; m_active_index = 0; m_active_area = NULL; for (it = _layout_element_list.begin(); it != eit; ++it, ++index) { if (*it != area) { m_active_area = static_cast (*it); m_active_index = index; break; } } } Layout::RemoveChildObject(area); } void LayeredLayout::SetActiveLayerN(int index_) { std::list::iterator it, eit = _layout_element_list.end(); int i = 0; NUX_RETURN_IF_FALSE((unsigned int)index_ < _layout_element_list.size()); if (index_ == m_active_index) return; m_active_index = index_; m_active_area = NULL; for (it = _layout_element_list.begin(); it != eit; ++it) { if (i == m_active_index && !m_active_area) { m_active_area = static_cast (*it); } if ((*it)->IsView()) { static_cast (*it)->QueueDraw(); } else if ((*it)->IsLayout()) { static_cast (*it)->QueueDraw(); } i++; } QueueDraw(); } int LayeredLayout::GetActiveLayerN() { return m_active_index; } void LayeredLayout::SetActiveLayer (Area *area) { std::list::iterator it, eit = _layout_element_list.end(); int i = 0; for (it = _layout_element_list.begin(); it != eit; ++it) { Area *a = static_cast (*it); if (area == a) { SetActiveLayerN(i); return; } i++; } nuxDebugMsg("[LayeredLayout::LowerBottom] Area(%p) is not a child of LayeredLayout(%p)", area, this); } void LayeredLayout::OnLayerGeometryChanged(Area* area, Geometry geo) { // Set the LayeredLayout to the same saize as the active layer; if (area && (area == m_active_area)) { SetGeometry(geo); } } Area * LayeredLayout::GetActiveLayer() { return m_active_area; } void LayeredLayout::SetPaintAll(bool paint_all) { if (m_paint_all == paint_all) return; m_paint_all = paint_all; QueueDraw(); } bool LayeredLayout::GetPaintAll() { return m_paint_all; } void LayeredLayout::SetInputMode(LayeredLayout::InputMode input_mode) { if (m_input_mode == input_mode) return; m_input_mode = input_mode; } LayeredLayout::InputMode LayeredLayout::GetInputMode() { return m_input_mode; } void LayeredLayout::Raise(Area *area, Area *above) { std::list::iterator it, eit = _layout_element_list.end(); std::list::iterator area_it = eit; std::list::iterator above_it = eit; NUX_RETURN_IF_NULL(area); NUX_RETURN_IF_NULL(above); for (it = _layout_element_list.begin(); it != eit; ++it) { if (above == (*it)) above_it = it; else if (area == (*it)) area_it = it; } if (area_it == eit) { nuxDebugMsg("[LayeredLayout::Raise] Area %p is not a valid layer", area); return; } if (above_it == eit) { nuxDebugMsg("[LayeredLayout::Raise] Area %p is not a valid layer", above); return; } _layout_element_list.erase(area_it); _layout_element_list.insert(++above_it, area); } void LayeredLayout::Lower(Area *area, Area *below) { std::list::iterator it, eit = _layout_element_list.end(); std::list::iterator area_it = eit; std::list::iterator below_it = eit; NUX_RETURN_IF_NULL(area); NUX_RETURN_IF_NULL(below); for (it = _layout_element_list.begin(); it != eit; ++it) { if (below == (*it)) below_it = it; else if (area == (*it)) area_it = it; } if (area_it == eit) { nuxDebugMsg("[LayeredLayout::Lower] Area %p is not a valid layer", area); return; } if (below_it == eit) { nuxDebugMsg("[LayeredLayout::Lower] Area %p is not a valid layer", below); return; } _layout_element_list.erase(area_it); _layout_element_list.insert(below_it, area); } void LayeredLayout::RaiseTop(Area *area) { std::list::iterator it, eit = _layout_element_list.end(); std::list::iterator area_it = eit; NUX_RETURN_IF_NULL(area); for (it = _layout_element_list.begin(); it != eit; ++it) { if (area == (*it)) area_it = it; } if (area_it == eit) { nuxDebugMsg("[LayeredLayout::RaiseTop] Area %p is not a valid layer", area); return; } _layout_element_list.erase(area_it); _layout_element_list.insert(eit, area); } void LayeredLayout::LowerBottom(Area *area) { std::list::iterator it, eit = _layout_element_list.end(); std::list::iterator area_it = eit; NUX_RETURN_IF_NULL(area); for (it = _layout_element_list.begin(); it != eit; ++it) { if (area == (*it)) area_it = it; } if (area_it == eit) { nuxDebugMsg("[LayeredLayout::LowerBottom] Area %p is not a valid layer", area); return; } _layout_element_list.erase(area_it); _layout_element_list.insert(_layout_element_list.begin(), area); } Area* LayeredLayout::KeyNavIteration(KeyNavDirection direction) { if (m_active_area == NULL) return NULL; if (m_active_area->IsVisible() == false) return NULL; if (next_object_to_key_focus_area_) { return NULL; } else { return m_active_area->KeyNavIteration(direction); } return NULL; } } nux-4.0.8+18.10.20180623/Nux/LayeredLayout.h0000644000000000000000000002354113313373365014314 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Neil Jagdish Patel * */ #ifndef LAYERED_LAYOUT_H #define LAYERED_LAYOUT_H #include "Layout.h" namespace nux { //! An layered layout. /*! LayeredLayout works either as a bin layout, showing only one layer at a time, or it works as a composite layout, drawing all children in order(and you are able to modify the order). The layout also allows two modes of input. In INPUT_MODE_ACTIVE, the layout will only send events to the active layer, even if in composite drawing mode. In INPUT_MODE_COMPOSITE, the layout will send events to all the layers, in the stacking order from top to bottom. This allows creation of complex widgets more easily than implementing the drawing and input modes manually. */ class LayeredLayout: public Layout { NUX_DECLARE_OBJECT_TYPE(LayeredLayout, Layout); public: class LayeredChildProperties // : public LayeredLayout::LayoutProperties { public: LayeredChildProperties(bool expand, int x, int y, int width, int height); ~LayeredChildProperties(); void Update(bool expand, int x, int y, int width, int height); bool m_expand; int m_x; int m_y; int m_width; int m_height; sigc::signal::iterator m_vis_it; }; typedef enum { INPUT_MODE_ACTIVE = 0, INPUT_MODE_COMPOSITE } InputMode; LayeredLayout(NUX_FILE_LINE_PROTO); ~LayeredLayout(); //! Add a layer to the layout /*! This method will add the layer with layout specific options \param area the Area, Layout or View \param expand area should be expanded to all the available space of the layout. If this is set to false, all the following parameters must be set \param x the horizontal position of the layer, expand must be false \param y the vertical position of the layer, expand must be false \param width the width of the layer inside the layout, expand must be false \param height the height of the layer inside the layout, expand must be false */ void AddLayer (Area *area, bool expand=true, int x=0, int y=0, int width=0, int height=0); //! Update properties of a layer in the layout /*! Allows updating properties of a layer after it has been added to the layout \param area the Area, Layout or View to update \param expand area should be expanded to all the available space of the layout. If this is set to false, all the following parameters must be set \param x the horizontal position of the layer, expand must be false \param y the vertical position of the layer, expand must be false \param width the width of the layer inside the layout, expand must be false \param height the height of the layer inside the layout, expand must be false */ void UpdateLayer(Area *area, bool expand=true, int x=0, int y=0, int width=0, int height=0); //! Remove a layer /*! This method will remove a layer from the layout. It is here for completeness. \param area the Area, Layout or View to remove */ void RemoveLayer(Area *area); //! Set the active layer of the layout /*! The active layer will receives input in the input mode is INPUT_MODE_ACTIVE. \param index_ The index of the layer to make active */ void SetActiveLayerN(int index_); //! Get the active layer of the layout /*! Returns the index of the active layer of the layout. This is only useful if input mode is INPUT_MODE_ACTIVE. \return the index of the active layer */ int GetActiveLayerN(); //! Set the active layer of the layout /*! The active layer will receives input in the input mode is INPUT_MODE_ACTIVE. \param area The area of the layer to make active */ void SetActiveLayer(Area *area); //! Get the active layer of the layout /*! Returns the the active layer of the layout. This is only useful if input mode is INPUT_MODE_ACTIVE. \return the active layer */ Area * GetActiveLayer (); //! Set whether the layout will paint all the layers it contains. Default is false. /*! Normally, the layout will only paint the active layer. However, if you are using the layout in INPUT_COMPOSITE, or have just sized and positioned the layers that you'd like them to be drawn so that they they are composited inside the layout, this should be set to true. \param paint_all whether to paint all the layers in the layout */ void SetPaintAll(bool paint_all); //! Get whether the layout is drawing all the layers it contains /*! Returns whether the layout is drawing all the layers it contains. See SetPaintAll. \return whether the layout is drawing all the layers */ bool GetPaintAll(); //! Sets the input mode of the layout /*! The layout is able to operate in two modes. INPUT_MODE_ACTIVE means that the layout will send events only to the active layout. In INPUT_MODE_COMPOSITE, the layout sends events to all the layouts it contains, starting from the topmost down to the bottom. A layer can stop propagation by returning the appropriate value in ProcessEvent. This can be mixed and matched with SetPaintAll depending on what you want to achieve. For instance, having paint all set to true but input_mode set to INPUT_MODE_ACTIVE allows you to create a composite view with one or many backgrounds, but with only one active view. \param input_mode the input mode */ void SetInputMode(LayeredLayout::InputMode input_mode); //! Raise the paint and input depth of an area /*! Raises the paint and input depth of the area in the layout \param area area to raise \param above area to raise above */ void Raise(Area *area, Area *above); //! Lower the paint and input depth of an area /*! Lowers the paint and input depth of the area in the layout \param area area to raise \param below area to lower below */ void Lower(Area *area, Area *below); //! Raises the paint and input depth of area to the top of the layout /*! Area will be drawn above all other layers and will be the first receive events \param area area to raise */ void RaiseTop(Area *area); //! Lowers the paint and input depth of area to the bottom of the layout /*! Area will be drawn below all other layers and will be the last receive events \param area area to lower */ void LowerBottom(Area *area); //! Get which input mode is set on the layout /*! Returns the current input mode on the layout. \return the current input mode on the layout */ LayeredLayout::InputMode GetInputMode(); // //! Set the layout properties for this area // /*! // Allows the Layout managing this area to store the properties specifc to this area. Layouts // should create a sub-class of LayoutProperties. The LayoutProperties of an area will // be deleted upon destruction. // @param properties the LayoutProperties sub-class associated with this area. Can be NULL to // unset. // */ // void SetLayoutProperties(LayoutProperties *properties); // // //! Get the layout properties for this area // /*! // Retrieves the LayoutProperties sub-class with this area. See SetLayoutProperties // @return LayoutProperties sub-class associated with this area. // */ // LayoutProperties * GetLayoutProperties(); void AddLayout(Layout *layouy, unsigned int stretch_factor = 1, MinorDimensionPosition position = eAbove, MinorDimensionSize extend = eFull, float percentage = 100.0f, LayoutPosition = NUX_LAYOUT_END); void AddView(Area *view, unsigned int stretch_factor = 1, MinorDimensionPosition positioning = eAbove, MinorDimensionSize extend = eFull, float percentage = 100.0f, LayoutPosition = NUX_LAYOUT_END); void RemoveChildObject(Area *area); void Clear(); protected: // // Overrides // long ComputeContentSize(); void GetCompositeList(std::list *ViewList); void ProcessDraw(GraphicsEngine &gfx_context, bool force_draw); Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); virtual Area* KeyNavIteration(KeyNavDirection direction); void OnLayerGeometryChanged(Area* area, Geometry geo); private: void PaintOne(Area *area, GraphicsEngine &graphics_engine, bool force_draw); void ChildQueueDraw(Area *area); void ChildVisibilityChanged(Area *area, bool visible); private: typedef std::map > AreaPropertyMap; AreaPropertyMap area_property_map_; int m_active_index; Area *m_active_area; bool m_paint_all; LayeredLayout::InputMode m_input_mode; bool m_child_draw_queued; }; } #endif // LAYERED_LAYOUT_H nux-4.0.8+18.10.20180623/Nux/Layout.cpp0000644000000000000000000006251013313373365013340 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #include "View.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(Layout); NUX_IMPLEMENT_OBJECT_TYPE(SpaceLayout); Layout::Layout(NUX_FILE_LINE_DECL) : Area(NUX_FILE_LINE_PARAM) { space_between_children_ = 0; left_padding_ = 0; right_padding_ = 0; top_padding_ = 0; bottom_padding_ = 0; m_contentWidth = 0; m_contentHeight = 0; m_ContentStacking = eStackExpand; draw_cmd_queued_ = false; child_draw_cmd_queued_ = false; SetMinimumSize(1, 1); } Layout::~Layout() { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { (*it)->UnParentObject(); } _layout_element_list.clear(); } int Layout::GetLeftPadding() const { return left_padding_; } int Layout::GetRightPadding() const { return right_padding_; } int Layout::GetTopPadding() const { return top_padding_; } int Layout::GetBottomPadding() const { return bottom_padding_; } void Layout::SetLeftAndRightPadding(int padding) { #if DEBUG_LAYOUT return; #endif left_padding_ = padding < 0 ? 0 : padding; right_padding_ = padding < 0 ? 0 : padding; } void Layout::SetLeftAndRightPadding(int left, int right) { #if DEBUG_LAYOUT return; #endif left_padding_ = left < 0 ? 0 : left; right_padding_ = right < 0 ? 0 : right; } void Layout::SetTopAndBottomPadding(int padding) { #if DEBUG_LAYOUT return; #endif top_padding_ = padding < 0 ? 0 : padding; bottom_padding_ = padding < 0 ? 0 : padding; } void Layout::SetTopAndBottomPadding(int top, int bottom) { #if DEBUG_LAYOUT return; #endif top_padding_ = top < 0 ? 0 : top; bottom_padding_ = bottom < 0 ? 0 : bottom; } void Layout::SetPadding(int padding) { top_padding_ = padding < 0 ? 0 : padding; bottom_padding_ = top_padding_; right_padding_ = top_padding_; left_padding_ = top_padding_; } void Layout::SetPadding(int top_bottom_padding, int left_right_padding) { top_padding_ = top_bottom_padding < 0 ? 0 : top_bottom_padding; bottom_padding_ = top_padding_; right_padding_ = left_right_padding < 0 ? 0 : left_right_padding; left_padding_ = right_padding_; } void Layout::SetPadding(int top, int right, int bottom, int left) { top_padding_ = top < 0 ? 0 : top; right_padding_ = right < 0 ? 0 : right; bottom_padding_ = bottom < 0 ? 0 : bottom; left_padding_ = left < 0 ? 0 : left; } //! Deprecated. Use SetLeftAndRightPadding. void Layout::SetHorizontalExternalMargin(int padding) { SetLeftAndRightPadding(padding); } //! Deprecated. Use SetTopAndBottomPadding, void Layout::SetVerticalExternalMargin(int padding) { SetTopAndBottomPadding(padding); } void Layout::RemoveChildObject(Area *bo) { std::list::iterator it; it = std::find(_layout_element_list.begin(), _layout_element_list.end(), bo); if (it != _layout_element_list.end()) { /* we need to emit the signal before the un-parent, just in case one of the callbacks wanted to use this object */ ViewRemoved.emit(this, bo); bo->UnParentObject(); _layout_element_list.erase(it); } } bool Layout::FindWidget(Area *WidgetObject) const { std::list::const_iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it) == WidgetObject) { return true; } } return false; } bool Layout::IsEmpty() const { return (_layout_element_list.size() == 0); } // If(stretchfactor == 0): the WidgetLayout geometry will be set to SetGeometry(0,0,1,1); // and the children will take their natural size by expending WidgetLayout. // If the parent of WidgetLayout offers more space, it won't be used by WidgetLayout. void Layout::AddLayout(Layout *layout, unsigned int stretchFactor, MinorDimensionPosition minor_position, MinorDimensionSize minor_size, float percentage, LayoutPosition index) { nuxAssertMsg(layout != 0, "[Layout::AddView] Invalid parameter."); NUX_RETURN_IF_TRUE(layout == 0); // Should never happen nuxAssertMsg(layout != this, "[Layout::AddLayout] Error: Trying to add a layout to itself."); NUX_RETURN_IF_FALSE(layout != 0); Area *parent = layout->GetParentObject(); nuxAssertMsg(parent == 0, "[Layout::AddLayout] Trying to add an object that already has a parent."); NUX_RETURN_IF_TRUE(parent != 0); nuxAssertMsg(index >= 0, "[Layout::AddLayout] Invalid index position. Adding at the beginning of the list.."); layout->SetScaleFactor(stretchFactor); layout->SetPositioning(minor_position); layout->SetExtend(minor_size); if (percentage < 1.0f) { layout->SetPercentage(1.0f); } else if (percentage > 100.0f) { layout->SetPercentage(100.0f); } else { layout->SetPercentage(percentage); } layout->SetParentObject(this); layout->child_queue_draw.connect(sigc::mem_fun(this, &Layout::ChildQueueDraw)); layout->queue_draw.connect(sigc::mem_fun(this, &Layout::ChildQueueDraw)); if (index < 0) index = NUX_LAYOUT_BEGIN; if (index == NUX_LAYOUT_END || index >= _layout_element_list.size()) { _layout_element_list.push_back(layout); } else { std::list::iterator pos = _layout_element_list.begin(); int idx = index; while (pos != _layout_element_list.end() && idx > 0) { idx--; pos++; } _layout_element_list.insert(pos, layout); } ViewAdded.emit(this, layout); } //! Add an object to the layout. /*! Add an object to the layout. A baseobject minor dimension with respect to a layout object is the dimension opposite to the layout flow. A baseobject major dimension with respect to a layout object is the dimension aligned with the layout flow. A layout object minor dimension is the dimension opposite to the layout flow. A layout object major dimension is the dimension aligned with the layout flow. Add an object to the layout. The added object get its size and position managed by the layout. When a baseobject is added with a stretches factor equal to 0, its major dimension assumes its minimum value. For instance, if the layout is a vertical layout and the added object has a stretch factor equal 0, then during the layout, the added object height will be set to its minimum value using ApplyMinHeight(). The minor_position parameter controls how the layout will place the object within itself. A vertical layout object controls the horizontal positioning of its children baseobjects, While an horizontal layout object controls the vertical positioning of its children baseobjects. The minor_size parameter controls how much size the baseobject minor dimension gets from the layout minor dimension. See MinorDimensionSize. /param baseobject The object that is being added. /param stretchFactor This value controls how the layout object share space between its children baseobject. /param minor_position Controls how the layout position the object. /param minor_size Controls the object minor dimension size. /param percentage Controls the object minor dimension size in percentage of the layout minor dimension size. /param index Controls the object position in the layout children. */ void Layout::AddView(Area *bo, unsigned int stretchFactor, MinorDimensionPosition minor_position, MinorDimensionSize minor_size, float percentage, LayoutPosition index) { nuxAssertMsg(bo != 0, "[Layout::AddView] Invalid parameter."); NUX_RETURN_IF_TRUE(bo == 0); if (!bo->IsView()) return; Area *parent = bo->GetParentObject(); nuxAssertMsg(parent == 0, "[Layout::AddView] Trying to add an object that already has a parent."); NUX_RETURN_IF_TRUE(parent != 0); nuxAssertMsg(index >= 0, "[Layout::AddView] Invalid index position. Adding at the beginning of the list.."); bo->SetScaleFactor(stretchFactor); bo->SetPositioning(minor_position); bo->SetExtend(minor_size); if (percentage < 1.0f) { bo->SetPercentage(1.0f); } else if (percentage > 100.0f) { bo->SetPercentage(100.0f); } else { bo->SetPercentage(percentage); } bo->SetParentObject(this); if (bo->IsView()) { static_cast (bo)->queue_draw.connect(sigc::mem_fun(this, &Layout::ChildQueueDraw)); static_cast (bo)->child_queue_draw.connect(sigc::mem_fun(this, &Layout::ChildQueueDraw)); } //if(HasFocusControl() && HasFocusableEntries() == false) //{ //bo->SetFocused(true); //ChildFocusChanged(this, bo); //} if (index < 0) index = NUX_LAYOUT_BEGIN; if (index == NUX_LAYOUT_END || index >= _layout_element_list.size()) { _layout_element_list.push_back(bo); } else { #if defined(NUX_OS_WINDOWS) && !defined(NUX_VISUAL_STUDIO_2010) std::list::iterator pos = _layout_element_list.begin(); #else auto pos = _layout_element_list.begin(); #endif int idx = index; while (pos != _layout_element_list.end() && idx > 0) { idx--; pos++; } _layout_element_list.insert(pos, bo); } ViewAdded.emit(this, bo); //--->> Removed because it cause problem with The splitter widget: ComputeContentSize(); } void Layout::AddSpace(unsigned int /* width */, unsigned int stretchFactor, LayoutPosition /* index */) { AddLayout(new SpaceLayout(), stretchFactor); } void Layout::Clear() { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { (*it)->UnParentObject(); } _layout_element_list.clear(); } bool Layout::SearchInAllSubNodes(Area *bo) { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it) == bo) { return true; } else if ((*it)->IsLayout()) { Layout *layout = NUX_STATIC_CAST(Layout *, (*it)); if (layout->SearchInAllSubNodes(bo)) { return true; } } } return false; } bool Layout::SearchInFirstSubNodes(Area *bo) { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it) == bo) { return true; } } return false; } unsigned int Layout::GetMaxStretchFactor() { unsigned int value = 0; unsigned int sf; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { sf = (*it)->GetScaleFactor(); if (sf >= value) { value = sf; } } return value; } unsigned int Layout::GetMinStretchFactor() { unsigned int value = 0xFFFFFFFF; unsigned int sf; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { sf = (*it)->GetScaleFactor(); if (sf <= value) { value = sf; } } return value; } unsigned int Layout::GetNumStretchFactor(unsigned int sf) { unsigned int count = 0; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->GetScaleFactor() == sf) { count++; } } return count; } void Layout::DoneRedraw() { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsView()) { View *ic = NUX_STATIC_CAST(View *, (*it)); ic->DoneRedraw(); } } } Area* Layout::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsVisible() && (*it)->GetInputEventSensitivity()) { Area* hit_view = NUX_STATIC_CAST(Area*, (*it)->FindAreaUnderMouse(mouse_position, event_type)); if (hit_view) return hit_view; } } return NULL; } void Layout::ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw) { std::list::iterator it; if (RedirectRenderingToTexture()) { if (update_backup_texture_ || force_draw || draw_cmd_queued_) { GetPainter().PushPaintLayerStack(); BeginBackupTextureRendering(graphics_engine, force_draw); { graphics_engine.PushModelViewMatrix(Get2DMatrix()); for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; if ((*it)->IsView()) { View* view = static_cast(*it); view->ProcessDraw(graphics_engine, force_draw); } else if ((*it)->IsLayout()) { Layout* layout = static_cast(*it); layout->ProcessDraw(graphics_engine, force_draw); } } graphics_engine.PopModelViewMatrix(); } EndBackupTextureRendering(graphics_engine, force_draw); GetPainter().PopPaintLayerStack(); } if (PresentRedirectedView()) { unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; // Be a good citizen, get a copy of the current GPU sates according to Nux graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); TexCoordXForm texxform; //Geometry xform_geo = GetGraphicsDisplay()->GetGraphicsEngine()->ModelViewXFormRect(GetGeometry()); if ((force_draw || draw_cmd_queued_) && background_texture_.IsValid()) { graphics_engine.GetRenderStates().SetBlend(false); texxform.FlipVCoord(true); // Draw the background of this view. GetGraphicsDisplay()->GetGraphicsEngine()->QRP_1Tex(GetX(), GetY(), background_texture_->GetWidth(), background_texture_->GetHeight(), background_texture_, texxform, color::White); } texxform.uwrap = TEXWRAP_CLAMP; texxform.vwrap = TEXWRAP_CLAMP; texxform.FlipVCoord(true); graphics_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); GetGraphicsDisplay()->GetGraphicsEngine()->QRP_1Tex(GetX(), GetY(), GetWidth(), GetHeight(), backup_texture_, texxform, Color(color::White)); // Be a good citizen, restore the Nux blending states. graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } } else { graphics_engine.PushModelViewMatrix(Get2DMatrix()); // Clip against the padding region. Geometry clip_geo = GetGeometry(); clip_geo.OffsetPosition(left_padding_, top_padding_); clip_geo.OffsetSize(-left_padding_ - right_padding_, -top_padding_ - bottom_padding_); graphics_engine.PushClippingRectangle(clip_geo); for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if (!(*it)->IsVisible()) continue; if ((*it)->IsView()) { View* view = static_cast(*it); view->ProcessDraw(graphics_engine, force_draw); } else if ((*it)->IsLayout()) { Layout* layout = static_cast(*it); layout->ProcessDraw(graphics_engine, force_draw); } } graphics_engine.PopClippingRectangle(); graphics_engine.PopModelViewMatrix(); } ResetQueueDraw(); } void Layout::BeginBackupTextureRendering(GraphicsEngine& graphics_engine, bool force_draw) { ObjectPtr active_fbo_texture; if (force_draw || draw_cmd_queued_) { // Get the active fbo color texture active_fbo_texture = GetGraphicsDisplay()->GetGpuDevice()->ActiveFboTextureAttachment(0); } Geometry xform_geo; // Compute position in the active fbo texture. xform_geo = graphics_engine.ModelViewXFormRect(GetGeometry()); // Get the current fbo... prev_fbo_ = GetGraphicsDisplay()->GetGpuDevice()->GetCurrentFrameBufferObject(); // ... and the size of the view port rectangle. prev_viewport_ = graphics_engine.GetViewportRect(); const int width = GetWidth(); const int height = GetHeight(); // Compute intersection with active fbo. Geometry intersection = xform_geo; if (active_fbo_texture.IsValid()) { Geometry active_fbo_geo(0, 0, active_fbo_texture->GetWidth(), active_fbo_texture->GetHeight()); intersection = active_fbo_geo.Intersect(xform_geo); } if (backup_fbo_.IsNull()) { // Create the fbo before using it for the first time. backup_fbo_ = GetGraphicsDisplay()->GetGpuDevice()->CreateFrameBufferObject(); } if (!backup_texture_.IsValid() || (backup_texture_->GetWidth() != width) || (backup_texture_->GetHeight() != height)) { // Create or resize the color and depth textures before using them. backup_texture_ = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(width, height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); backup_depth_texture_ = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(width, height, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); } if (!background_texture_.IsValid() || (background_texture_->GetWidth() != intersection.width) || (background_texture_->GetHeight() != intersection.height)) { background_texture_ = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(intersection.width, intersection.height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); } // Draw the background on the previous fbo texture if ((force_draw || draw_cmd_queued_) && background_texture_.IsValid()) { backup_fbo_->FormatFrameBufferObject(intersection.width, intersection.height, BITFMT_R8G8B8A8); backup_fbo_->EmptyClippingRegion(); graphics_engine.SetViewport(0, 0, intersection.width, intersection.height); graphics_engine.SetOrthographicProjectionMatrix(intersection.width, intersection.height); // Set the background texture in the fbo backup_fbo_->SetTextureAttachment(0, background_texture_, 0); backup_fbo_->SetDepthTextureAttachment(ObjectPtr(0), 0); backup_fbo_->Activate(); graphics_engine.SetViewport(0, 0, background_texture_->GetWidth(), background_texture_->GetHeight()); // Clear surface CHECKGL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); CHECKGL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT)); TexCoordXForm texxform; texxform.uoffset = xform_geo.x / (float) active_fbo_texture->GetWidth(); texxform.voffset = xform_geo.y / (float) active_fbo_texture->GetHeight(); texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD); texxform.flip_v_coord = true; // Temporarily change the model-view matrix to copy the texture background texture. // This way we are not affceted by the regular model-view matrix. graphics_engine.SetModelViewMatrix(Matrix4::IDENTITY()); // Copy the texture from the previous fbo attachment into our background texture. if (copy_previous_fbo_for_background_) { graphics_engine.QRP_1Tex(0, 0, intersection.width, intersection.height, active_fbo_texture, texxform, color::White); } else { graphics_engine.QRP_Color(0, 0, intersection.width, intersection.height, Color(0.0f, 0.0f, 0.0f, 0.0f)); } // Restore the model-view matrix. graphics_engine.ApplyModelViewMatrix(); } backup_fbo_->FormatFrameBufferObject(width, height, BITFMT_R8G8B8A8); backup_fbo_->EmptyClippingRegion(); backup_fbo_->SetTextureAttachment(0, backup_texture_, 0); backup_fbo_->SetDepthTextureAttachment(backup_depth_texture_, 0); backup_fbo_->Activate(); if (force_draw || draw_cmd_queued_) { CHECKGL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); CHECKGL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT)); } graphics_engine.SetViewport(0, 0, width, height); graphics_engine.SetOrthographicProjectionMatrix(width, height); // Transform the geometry of this area through the current model view matrix. This gives the // the position of the view in the active fbo texture. Geometry offset_rect = graphics_engine.ModelViewXFormRect(GetGeometry()); int x_offset = -offset_rect.x; int y_offset = -offset_rect.y; graphics_engine.PushModelViewMatrix(Matrix4::TRANSLATE(x_offset, y_offset, 0)); } void Layout::EndBackupTextureRendering(GraphicsEngine& graphics_engine, bool /* force_draw */) { graphics_engine.PopModelViewMatrix(); if (prev_fbo_.IsValid()) { // Restore the previous fbo prev_fbo_->Activate(); prev_fbo_->ApplyClippingRegion(); } // Release the reference on the previous fbo prev_fbo_.Release(); // Restore the matrices and the view port. graphics_engine.ApplyModelViewMatrix(); graphics_engine.SetOrthographicProjectionMatrix(prev_viewport_.width, prev_viewport_.height); graphics_engine.SetViewport(prev_viewport_.x, prev_viewport_.y, prev_viewport_.width, prev_viewport_.height); } void Layout::QueueDraw() { if (draw_cmd_queued_) { // A draw has already been scheduled. return; } // Report to a parent view with redirect_rendering_to_texture_ set to true that one of its children // needs to be redrawn. PrepareParentRedirectedView(); std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsView()) { View* view = static_cast(*it); view->QueueDraw(); } else if ((*it)->IsLayout()) { Layout* layout = static_cast(*it); layout->QueueDraw(); } } draw_cmd_queued_ = true; queue_draw.emit(this); } bool Layout::IsQueuedForDraw() { return draw_cmd_queued_; } bool Layout::ChildQueuedForDraw() { return child_draw_cmd_queued_; } void Layout::SetContentDistribution(LayoutContentDistribution stacking) { m_ContentStacking = stacking; } LayoutContentDistribution Layout::GetContentDistribution() { return m_ContentStacking; } void Layout::RequestBottomUpLayoutComputation(Area * /* bo_initiator */) { } void Layout::ChildQueueDraw(Area* area) { if (child_draw_cmd_queued_) return; child_draw_cmd_queued_ = true; child_queue_draw.emit(area); } bool Layout::AcceptKeyNavFocus() { return false; } void Layout::ResetQueueDraw() { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) { if ((*it)->IsLayout()) { Layout* layout = NUX_STATIC_CAST(Layout*, (*it)); if (layout->ChildQueuedForDraw()) { layout->ResetQueueDraw(); } } else if ((*it)->IsView()) { View* view = NUX_STATIC_CAST(View*, (*it)); if (view->GetLayout()) { view->GetLayout()->ResetQueueDraw(); view->draw_cmd_queued_ = false; view->child_draw_cmd_queued_ = false; } } } draw_cmd_queued_ = false; child_draw_cmd_queued_ = false; update_backup_texture_ = false; } void Layout::GeometryChangePending(bool /* position_about_to_change */, bool /* size_about_to_change */) { if (IsLayoutDone()) QueueDraw(); } void Layout::GeometryChanged(bool /* position_has_changed */, bool size_has_changed) { if (RedirectedAncestor()) { if (size_has_changed) QueueDraw(); return; } if (IsLayoutDone()) QueueDraw(); } #ifdef NUX_GESTURES_SUPPORT Area* Layout::GetInputAreaHitByGesture(const GestureEvent &event) { if (!IsVisible()) return nullptr; if (!IsGestureInsideArea(event)) return nullptr; for (const auto area : _layout_element_list) { Area *area_hit = area->GetInputAreaHitByGesture(event); if (area_hit) return area_hit; } return nullptr; } #endif } nux-4.0.8+18.10.20180623/Nux/Layout.h0000644000000000000000000003213413313373365013004 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef LAYOUT_H #define LAYOUT_H namespace nux { #define DEBUG_LAYOUT 0 #define DEBUG_LAYOUT_COMPUTATION 0 typedef enum { NUX_LAYOUT_BEGIN = 0, NUX_LAYOUT_END = 0x7fffffff } LayoutPosition; class Layout: public Area { NUX_DECLARE_OBJECT_TYPE(Layout, Area); public: Layout(NUX_FILE_LINE_PROTO); virtual ~Layout(); virtual void AddLayout(Layout *, unsigned int stretchFactor = 1, MinorDimensionPosition = eAbove, MinorDimensionSize extend = eFull, float percentage = 100.0f, LayoutPosition = NUX_LAYOUT_END); //! Add an object to the layout. /*! Add an object to the layout. A baseobject minor dimension with respect to a layout object is the dimension opposite to the layout flow. A baseobject major dimension with respect to a layout object is the dimension aligned with the layout flow. A layout object minor dimension is the dimension opposite to the layout flow. A layout object major dimension is the dimension aligned with the layout flow. Add an object to the layout. The added object get its size and position managed by the layout. When a baseobject is added with a stretches factor equal to 0, its major dimension assumes its minimum value. For instance, if the layout is a vertical layout and the added object has a stretch factor equal 0, then during the layout, the added object height will be set to its minimum value using ApplyMinHeight(). The positioning parameter controls how the layout will place the object within itself. A vertical layout object controls the horizontal positioning of its children baseobject, While an horizontal layout object controls the vertical positioning of its children baseobject. The extend parameter controls how much size the baseobject minor dimension gets from the layout minor dimension. See MinorDimensionSize. /param baseobject The object that is being added. /param stretchFactor This value controls how the layout object share space between its children baseobject. /param positioning Controls how the layout position the object. /param extend Controls the object minor dimension size. /param percentage Controls the object minor dimension size in percentage of the layout minor dimension size. /param index Controls the object position in the layout. */ virtual void AddView(Area *baseobject, unsigned int stretchFactor = 1, MinorDimensionPosition positioning = eAbove, MinorDimensionSize extend = eFull, float percentage = 100.0f, LayoutPosition index = NUX_LAYOUT_END); virtual void AddSpace(unsigned int width, unsigned int stretchFactor = 0, LayoutPosition index = NUX_LAYOUT_END); virtual void Clear(); //! Set the left/right padding with the same value. /*! Set the left/right padding of the layout. \n Valid only for HLayout, VLayouts, HGridLayouts and VGridLayout. @param padding The left/right padding value of the layout. */ void SetLeftAndRightPadding(int padding); //! Set the left/right padding independently. /*! Set the left/right padding of the layout. \n Valid only for HLayout, VLayouts, HGridLayouts and VGridLayout. @param left Left padding value of the layout. @param right Right padding value of the layout. */ void SetLeftAndRightPadding(int left, int right); //! Set the top/bottom padding with the same value. /*! Set the top/bottom padding of the layout. \n Valid only for HLayout, VLayouts, HGridLayouts and VGridLayout. @param padding The top/bottom padding value of the layout. */ void SetTopAndBottomPadding(int padding); //! Set the top/bottom padding independently. /*! Set the top/bottom padding of the layout. \n Valid only for HLayout, VLayouts, HGridLayouts and VGridLayout. @param top Top padding value of the layout. @param bottom Bottom padding value of the layout. */ void SetTopAndBottomPadding(int top, int bottom); //! Set the left/right and top/bottom padding of the layout. /*! Set the left/right and top/bottom padding of the layout. \n Valid only for HLayout, VLayouts, HGridLayouts and VGridLayout. @param top_bottom_padding The top/bottom padding value of the layout. @param left_right_padding The left/right padding value of the layout. */ void SetPadding(int top_bottom_padding, int left_right_padding); virtual unsigned int GetMaxStretchFactor(); unsigned int GetMinStretchFactor(); unsigned int GetNumStretchFactor(unsigned int sf); int GetContentWidth() const { return m_contentWidth; }; int GetContentHeight() const { return m_contentHeight; }; //! Deprecated. Use SetLeftAndRightPadding. void SetHorizontalExternalMargin(int m); //! Deprecated. Use SetTopAndBottomPadding, void SetVerticalExternalMargin(int m); //! Set the left/right/top/bottom padding of the layout. /*! Set the left/right and top/bottom padding of the layout. \n Valid only for HLayout, VLayouts, HGridLayouts and VGridLayout. @param top The top padding value of the layout. @param right The right padding value of the layout. @param bottom The bottom padding value of the layout. @param left The left padding value of the layout. */ void SetPadding(int top, int right, int bottom, int left); //! Set the left/right/top/bottom padding of the layout. /*! Set the left/right/top/bottom padding of the layout. \n Valid only for HLayout, VLayouts, HGridLayouts and VGridLayout. @param padding The top/right/bottom/left padding value of the layout. */ void SetPadding(int padding); int GetLeftPadding() const; int GetRightPadding() const; int GetTopPadding() const; int GetBottomPadding() const; public: virtual void GetCompositeList(std::list * /* ViewList */) { } virtual void Draw() {} void DoneRedraw(); bool SearchInAllSubNodes(Area *bo); bool SearchInFirstSubNodes(Area *bo); Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); //! Draw Element /*! Draw all elements inside the layout. If force_draw is true then the system requests that all objects redraw themselves completely. \param force_draw \param TraverseInfo \param ProcessEventInfo \return The state of the Process Event. */ virtual void ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw); //! Mark all element in the layout as dirty. /*! Mark all element in the layout as dirty. This will also mark all sub elements as dirty. InputArea element are not marked as dirty(they don't have the flags). Emits the signal \i queue_draw. */ virtual void QueueDraw(); //! Return true if a draw has been scheduled for this layout /*! @return True if a draw has been scheduled for this layout. */ bool IsQueuedForDraw(); //! Return true if a draw has been scheduled for a child of this layout /*! @return True if a draw has been scheduled for a child of this layout. */ bool ChildQueuedForDraw(); //! Define how elements are spread out inside the layout. /*! Typically, a layout stacks it elements from left to right(HLayout) or top to bottom(VLayout). When the elements don't uses all the space that is available, the content stacking policy allows alternatives ways to position the elements. This does not affect the elements size, only their position inside the layout. @param stacking_order */ virtual void SetContentDistribution(LayoutContentDistribution stacking_order); virtual LayoutContentDistribution GetContentDistribution(); virtual bool FindWidget(Area *WidgetObject) const; virtual bool IsEmpty() const; /* This function is reimplemented in Layout and View classes they need to perform some special operations. It does nothing for Area classes(this class cannot have children). */ virtual void RemoveChildObject(Area *); //! Request a Layout recompute after a change of size /* When an object size changes, it is necessary for its parent structure to initiate a layout re computation in order preserve the layout structure defined by the user through the API. */ virtual void RequestBottomUpLayoutComputation(Area *bo_initiator); std::list& GetChildren() { return _layout_element_list; } virtual void ChildQueueDraw(Area* area); sigc::signal queue_draw; //!< Signal emitted when a layout is scheduled for a draw. sigc::signal child_queue_draw; sigc::signal ViewAdded; sigc::signal ViewRemoved; #ifdef NUX_GESTURES_SUPPORT virtual Area* GetInputAreaHitByGesture(const GestureEvent &event); #endif /*! When a layout goes through Layout::ProcessDraw, this call isn't necessary. Otherwise, call it to set the value of draw_cmd_queued_ to false. */ virtual void ResetQueueDraw(); protected: void BeginBackupTextureRendering(GraphicsEngine& graphics_engine, bool force_draw); void EndBackupTextureRendering(GraphicsEngine& graphics_engine, bool force_draw); virtual void GeometryChangePending(bool position_about_to_change, bool size_about_to_change); virtual void GeometryChanged(bool position_has_changed, bool size_has_changed); virtual bool AcceptKeyNavFocus(); bool draw_cmd_queued_; // _layout_element_list; std::string m_name; LayoutContentDistribution m_ContentStacking; }; // The Space layout is a layout object that is used to create fixed or re-sizable empty space. class SpaceLayout: public Layout { NUX_DECLARE_OBJECT_TYPE(SpaceLayout, Layout); public: SpaceLayout(NUX_FILE_LINE_PROTO) : Layout(NUX_FILE_LINE_PARAM) { }; SpaceLayout(int minWidth, int maxWidth, int minHeight, int maxHeight, NUX_FILE_LINE_PROTO) : Layout(NUX_FILE_LINE_PARAM) { SetMinimumSize(minWidth, minHeight); SetMaximumSize(maxWidth, maxHeight); }; ~SpaceLayout() { }; virtual bool FindWidget(Area * /* WidgetObject */) const { return false; } virtual bool IsEmpty() const { return true; } virtual void AddLayout(Layout *, unsigned int /* stretchFactor */ = 1, MinorDimensionPosition /* minor_position */ = eAbove, MinorDimensionSize /* minor_size */ = eFull, float /* percentage */ = 100.0f, LayoutPosition /* index */ = NUX_LAYOUT_END) { // Do not allow a WidgetLayout to encapsulate an object of type layout } virtual void AddView(Area * /* baseobject */, unsigned int /* stretchFactor */ = 1, MinorDimensionPosition /* positioning */ = eAbove, MinorDimensionSize /* extend */ = eFull, float /* percentage */ = 100.0f, LayoutPosition /* index */ = NUX_LAYOUT_END) { // the baseObject is provided via the constructor. }; virtual void AddSpace(unsigned int /* width */, unsigned int /* stretchFactor */ = 0, LayoutPosition /* index */ = NUX_LAYOUT_END) { // Do not allow a WidgetLayout to encapsulate an object of type layout } virtual bool CanFocus() { return false; } // Begin: Abstract virtual function member(inherited from class Layout) that must be implemented virtual long ComputeContentSize() { return 0; } virtual void ComputeContentPosition(float /* offsetX */, float /* offsetY */) { } // End: Abstract virtual function member(inherited from class Layout) that must be implemented protected: Area *Find(long handle); }; } #endif // LAYOUT_H nux-4.0.8+18.10.20180623/Nux/LinearLayout.cpp0000644000000000000000000001631213313373365014472 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "LinearLayout.h" #include "View.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(LinearLayout); LinearLayout::LinearLayout(NUX_FILE_LINE_DECL) : Layout(NUX_FILE_LINE_PARAM) { } LinearLayout::~LinearLayout() { } // If(stretchfactor == 0): the WidgetLayout geometry will be set to SetGeometry(0,0,1,1); // and the children will take their natural size by expending WidgetLayout. // If the parent of WidgetLayout offers more space, it won't be used by WidgetLayout. void LinearLayout::AddLayout(Layout *layout, unsigned int stretchFactor, MinorDimensionPosition minor_position, MinorDimensionSize minor_size, float percentage, LayoutPosition index) { nuxAssertMsg(layout != 0, "[Layout::AddView] Invalid parameter."); NUX_RETURN_IF_TRUE(layout == 0); // Should never happen nuxAssertMsg(layout != this, "[Layout::AddLayout] Error: Trying to add a layout to itself."); NUX_RETURN_IF_FALSE(layout != 0); Area *parent = layout->GetParentObject(); nuxAssertMsg(parent == 0, "[Layout::AddLayout] Trying to add an object that already has a parent."); NUX_RETURN_IF_TRUE(parent != 0); nuxAssertMsg(index >= 0, "[Layout::AddLayout] Invalid index position. Adding at the beginning of the list.."); layout->SetScaleFactor(stretchFactor); layout->SetPositioning(minor_position); layout->SetExtend(minor_size); if (percentage < 1.0f) { layout->SetPercentage(1.0f); } else if (percentage > 100.0f) { layout->SetPercentage(100.0f); } else { layout->SetPercentage(percentage); } layout->SetParentObject(this); layout->child_queue_draw.connect(sigc::mem_fun(this, &Layout::ChildQueueDraw)); layout->queue_draw.connect(sigc::mem_fun(this, &Layout::ChildQueueDraw)); if (index < 0) index = NUX_LAYOUT_BEGIN; if (index == NUX_LAYOUT_END || index >= _layout_element_list.size()) { _layout_element_list.push_back(layout); } else { std::list::iterator pos = _layout_element_list.begin(); int idx = index; while (pos != _layout_element_list.end() && idx > 0) { idx--; pos++; } _layout_element_list.insert(pos, layout); } ViewAdded.emit(this, layout); } //! Add an object to the layout. /*! Add an object to the layout. A baseobject minor dimension with respect to a layout object is the dimension opposite to the layout flow. A baseobject major dimension with respect to a layout object is the dimension aligned with the layout flow. A layout object minor dimension is the dimension opposite to the layout flow. A layout object major dimension is the dimension aligned with the layout flow. Add an object to the layout. The added object get its size and position managed by the layout. When a baseobject is added with a stretches factor equal to 0, its major dimension assumes its minimum value. For instance, if the layout is a vertical layout and the added object has a stretch factor equal 0, then during the layout, the added object height will be set to its minimum value using ApplyMinHeight(). The minor_position parameter controls how the layout will place the object within itself. A vertical layout object controls the horizontal positioning of its children baseobjects, While an horizontal layout object controls the vertical positioning of its children baseobjects. The minor_size parameter controls how much size the baseobject minor dimension gets from the layout minor dimension. See MinorDimensionSize. /param baseobject The object that is being added. /param stretchFactor This value controls how the layout object share space between its children baseobject. /param minor_position Controls how the layout position the object. /param minor_size Controls the object minor dimension size. /param percentage Controls the object minor dimension size in percentage of the layout minor dimension size. /param index Controls the object position in the layout children. */ void LinearLayout::AddView(Area *bo, unsigned int stretchFactor, MinorDimensionPosition minor_position, MinorDimensionSize minor_size, float percentage, LayoutPosition index) { nuxAssertMsg(bo != 0, "[Layout::AddView] Invalid parameter."); NUX_RETURN_IF_TRUE(bo == 0); Area *parent = bo->GetParentObject(); nuxAssertMsg(parent == 0, "[Layout::AddView] Trying to add an object that already has a parent."); NUX_RETURN_IF_TRUE(parent != 0); nuxAssertMsg(index >= 0, "[Layout::AddView] Invalid index position. Adding at the beginning of the list.."); bo->SetScaleFactor(stretchFactor); bo->SetPositioning(minor_position); bo->SetExtend(minor_size); if (percentage < 1.0f) { bo->SetPercentage(1.0f); } else if (percentage > 100.0f) { bo->SetPercentage(100.0f); } else { bo->SetPercentage(percentage); } bo->SetParentObject(this); if (bo->IsView()) (static_cast (bo))->queue_draw.connect(sigc::mem_fun(this, &Layout::ChildQueueDraw)); //if(HasFocusControl() && HasFocusableEntries() == false) //{ //bo->SetFocused(true); //ChildFocusChanged(this, bo); //} if (index < 0) index = NUX_LAYOUT_BEGIN; if (index == NUX_LAYOUT_END || index >= _layout_element_list.size()) { _layout_element_list.push_back(bo); } else { #if defined(NUX_OS_WINDOWS) && !defined(NUX_VISUAL_STUDIO_2010) std::list::iterator pos = _layout_element_list.begin(); #else auto pos = _layout_element_list.begin(); #endif int idx = index; while (pos != _layout_element_list.end() && idx > 0) { idx--; pos++; } _layout_element_list.insert(pos, bo); } ViewAdded.emit(this, bo); //--->> Removed because it cause problem with The splitter widget: ComputeContentSize(); } void LinearLayout::AddSpace(unsigned int /* width */, unsigned int stretchFactor, LayoutPosition /* index */) { AddLayout(new SpaceLayout(), stretchFactor); } void LinearLayout::SetHorizontalInternalMargin(int space) { SetSpaceBetweenChildren(space); } void LinearLayout::SetVerticalInternalMargin(int space) { SetSpaceBetweenChildren(space); } void LinearLayout::SetSpaceBetweenChildren(int space) { #if DEBUG_LAYOUT return; #endif space_between_children_ = space >= 0 ? space : 0; } } nux-4.0.8+18.10.20180623/Nux/LinearLayout.h0000644000000000000000000001033113313373365014132 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef LINEARLAYOUT_H #define LINEARLAYOUT_H #include "Layout.h" namespace nux { // The Space layout is a layout object that is used to create fixed or re-sizable empty space. class LinearLayout: public Layout { NUX_DECLARE_OBJECT_TYPE(LinearLayout, Layout); public: virtual void AddLayout(Layout *, unsigned int stretchFactor = 1, MinorDimensionPosition = eAbove, MinorDimensionSize extend = eFull, float percentage = 100.0f, LayoutPosition = NUX_LAYOUT_END); //! Add an object to the layout. /*! Add an object to the layout. A baseobject minor dimension with respect to a layout object is the dimension opposite to the layout flow. A baseobject major dimension with respect to a layout object is the dimension aligned with the layout flow. A layout object minor dimension is the dimension opposite to the layout flow. A layout object major dimension is the dimension aligned with the layout flow. Add an object to the layout. The added object get its size and position managed by the layout. When a baseobject is added with a stretches factor equal to 0, its major dimension assumes its minimum value. For instance, if the layout is a vertical layout and the added object has a stretch factor equal 0, then during the layout, the added object height will be set to its minimum value using ApplyMinHeight(). The positioning parameter controls how the layout will place the object within itself. A vertical layout object controls the horizontal positioning of its children baseobject, While an horizontal layout object controls the vertical positioning of its children baseobject. The extend parameter controls how much size the baseobject minor dimension gets from the layout minor dimension. See MinorDimensionSize. /param baseobject The object that is being added. /param stretchFactor This value controls how the layout object share space between its children baseobject. /param positioning Controls how the layout position the object. /param extend Controls the object minor dimension size. /param percentage Controls the object minor dimension size in percentage of the layout minor dimension size. /param index Controls the object position in the layout. */ virtual void AddView(Area *baseobject, unsigned int stretchFactor = 1, MinorDimensionPosition positioning = eAbove, MinorDimensionSize extend = eFull, float percentage = 100.0f, LayoutPosition index = NUX_LAYOUT_END); virtual void AddSpace(unsigned int width, unsigned int stretchFactor = 0, LayoutPosition index = NUX_LAYOUT_END); //! Deprecated. Use SetSpaceBetweenChildren; void SetHorizontalInternalMargin(int space); //! Deprecated. Use SetSpaceBetweenChildren; void SetVerticalInternalMargin(int space); //! Set the space between the children of a HLayout or VLayout. /*! Set the horizontal space between the children of the layout. In a VLayout, children of the layout are placed horizontally, on after the other, from left to right. This function set the space allowed between the children. Valid only for HLayout and VLayout. @param horizontal_space The horizontal space between the children of the layout. */ void SetSpaceBetweenChildren(int space); protected: LinearLayout(NUX_FILE_LINE_PROTO); virtual ~LinearLayout(); }; } #endif // LINEARLAYOUT_H nux-4.0.8+18.10.20180623/Nux/MainLoopGLib.cpp0000644000000000000000000003260413313373365014340 0ustar #include "Nux.h" #include "Layout.h" #include "NuxGraphics/GraphicsEngine.h" #include "ClientArea.h" #include "WindowCompositor.h" #include "TimerProc.h" #include "SystemThread.h" #include "FloatingWindow.h" #include "WindowThread.h" #include "MainLoopGLib.h" namespace nux { static GMutex *gLibEventMutex = 0; static void nux_glib_threads_lock(void) { if (gLibEventMutex) g_mutex_lock(gLibEventMutex); } static void nux_glib_threads_unlock(void) { if (gLibEventMutex) g_mutex_unlock(gLibEventMutex); } struct NuxEventSource { GSource source; GPollFD event_poll_fd; }; typedef struct { WindowThread *window_thread; unsigned int id; } TimeoutData; Event GetSystemEvent(WindowThread* window_thread) { return window_thread->GetNextEvent(); } gboolean nux_timeout_dispatch(gpointer user_data) { bool repeat = false; TimeoutData* dd = NUX_STATIC_CAST(TimeoutData*, user_data); unsigned int return_code = 1; dd->window_thread->_inside_timer_loop = true; repeat = GetTimer().ExecTimerHandler(dd->id); dd->window_thread->_inside_timer_loop = false; if (dd->window_thread->IsEmbeddedWindow()) { dd->window_thread->RedrawRequested.emit(); } else { Event event = GetSystemEvent(dd->window_thread); return_code = dd->window_thread->ProcessEvent(event); } if ((return_code == 0) && !dd->window_thread->IsEmbeddedWindow()) { g_main_loop_quit(dd->window_thread->main_loop_glib_); } if (!repeat) delete dd; return repeat; } static gboolean nux_event_prepare(GSource * /* source */, gint *timeout) { nux_glib_threads_lock(); gboolean retval; *timeout = -1; #if defined(NUX_OS_WINDOWS) MSG msg; retval = PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE) ? TRUE : FALSE; #elif defined(NUX_OS_LINUX) # if defined(USE_X11) retval = GetGraphicsDisplay()->HasXPendingEvent() ? TRUE : FALSE; # else retval = false; # endif nux_glib_threads_unlock(); return retval; } static gboolean nux_event_check(GSource *source) { nux_glib_threads_lock(); gboolean retval = FALSE; NuxEventSource *event_source = (NuxEventSource*) source; if ((event_source->event_poll_fd.revents & G_IO_IN)) { #if defined(NUX_OS_WINDOWS) MSG msg; retval = PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE) ? TRUE : FALSE; #elif defined(NUX_OS_LINUX) # if defined(USE_X11) retval = GetGraphicsDisplay()->HasXPendingEvent() ? TRUE : FALSE; # endif #else # error Not implemented. #endif } nux_glib_threads_unlock(); return retval; } gboolean nux_event_dispatch(GSource * /* source */, GSourceFunc /* callback */, gpointer user_data) { nux_glib_threads_lock(); WindowThread *window_thread = NUX_STATIC_CAST(WindowThread *, user_data); Event event = GetSystemEvent(window_thread); unsigned int return_code = window_thread->ProcessEvent(event); if (return_code == 0 && !window_thread->IsEmbeddedWindow()) { g_main_loop_quit(window_thread->main_loop_glib_); } nux_glib_threads_unlock(); return return_code || window_thread->IsEmbeddedWindow(); } static GSourceFuncs event_funcs = { nux_event_prepare, nux_event_check, nux_event_dispatch, NULL, NULL, NULL }; // Timeline source functions static gboolean nux_timeline_prepare (GSource * /* source */, gint *timeout) { // right now we are assuming that we are v-synced, so that will handle synchronizations // we could guess how long we have to wait for the next frame but thats rather ugly // ideally we need some more API that ensures that timeline/event/re-layout/draws are all in sync *timeout = 0; return TRUE; } static gboolean nux_timeline_check(GSource * /* source */) { return TRUE; } static gboolean nux_timeline_dispatch(GSource *source, GSourceFunc /* callback */, gpointer user_data) { #if !defined(NUX_MINIMAL) bool has_timelines_left = false; nux_glib_threads_lock(); gint64 micro_secs = g_source_get_time(source); WindowThread *window_thread = NUX_STATIC_CAST(WindowThread *, user_data); // pump the timelines has_timelines_left = window_thread->ProcessTimelines(micro_secs); if (!has_timelines_left) { // no timelines left on the stack so lets go ahead and remove the // master clock, to save on wakeups window_thread->StopMasterClock(); } nux_glib_threads_unlock(); #endif return TRUE; } static GSourceFuncs timeline_funcs = { nux_timeline_prepare, nux_timeline_check, nux_timeline_dispatch, NULL, NULL, NULL }; void WindowThread::InitGlibLoop() { static bool main_context_created = false; if (!IsEmbeddedWindow()) { #if GLIB_MAJOR_VERSION < 2 || GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 32 static bool gthread_initialized = false; if (!gthread_initialized) g_thread_init(NULL); gthread_initialized = true; #endif if (((main_loop_glib_context_ == 0) || (main_loop_glib_ == 0)) && (main_context_created == false)) { //create a context main_loop_glib_context_ = g_main_context_default(); //create a main loop with context main_loop_glib_ = g_main_loop_new(main_loop_glib_context_, TRUE); } else if ((main_loop_glib_context_ == 0) || (main_loop_glib_ == 0)) { // Secondary physical windows goes in here //create a context main_loop_glib_context_ = g_main_context_new(); //create a main loop with context main_loop_glib_ = g_main_loop_new(main_loop_glib_context_, TRUE); } else { return; } } main_context_created = true; gLibEventMutex = 0; //g_mutex_new(); } void WindowThread::RunGlibLoop() { GSource *source = g_source_new(&event_funcs, sizeof(NuxEventSource)); NuxEventSource *event_source = (NuxEventSource*) source; g_source_set_priority(source, G_PRIORITY_DEFAULT); #if defined(NUX_OS_WINDOWS) event_source->event_poll_fd.fd = G_WIN32_MSG_HANDLE; #elif defined(NUX_OS_LINUX) # if defined(USE_X11) event_source->event_poll_fd.fd = ConnectionNumber(GetGraphicsDisplay().GetX11Display()); # endif #else # error Not implemented. #endif event_source->event_poll_fd.events = G_IO_IN; g_source_add_poll(source, &event_source->event_poll_fd); g_source_set_can_recurse(source, TRUE); g_source_set_callback(source, 0, this, 0); if (IsEmbeddedWindow()) g_source_attach(source, NULL); else g_source_attach(source, main_loop_glib_context_); #ifdef NUX_GESTURES_SUPPORT //TODO: Some people say that it's much faster to share a GSource among many // file descriptors than having a separate GSource for each file descriptor. // See if it would be better to have GeisAdapter sharing the same GSource with // WindowThread/Nux/X if (IsEmbeddedWindow()) geis_adapter_->CreateGSource(nullptr); else geis_adapter_->CreateGSource(main_loop_glib_context_); geis_adapter_->event_ready.connect( sigc::mem_fun(this, &WindowThread::ProcessGestureEvent)); #endif #if !defined(NUX_MINIMAL) if (!_Timelines->empty()) StartMasterClock(); #endif if (!IsEmbeddedWindow()) { g_main_loop_run(main_loop_glib_); g_main_loop_unref(main_loop_glib_); } } namespace { typedef struct _ExternalNuxSource { GSource source; GPollFD pfd; } ExternalNuxSource; gboolean ExternalSourcePrepareFunc(GSource *source, gint *timeout) { /* Always block for new events */ *timeout = -1; return FALSE; } gboolean ExternalSourceCheckFunc(GSource *source) { /* Only return true if there are events waiting for us */ ExternalNuxSource *extSource = reinterpret_cast (source); return extSource->pfd.revents == G_IO_IN; } gboolean ExternalSourceDispatchFunc(GSource *source, GSourceFunc callback, gpointer user_data) { return (*callback) (user_data); } static GSourceFuncs externalGLibFuncs = { &ExternalSourcePrepareFunc, &ExternalSourceCheckFunc, &ExternalSourceDispatchFunc, NULL, /* Technically we shouldn't be touching these, but the compiler * will complain if we don't */ 0, 0 }; } gboolean WindowThread::ExternalSourceCallback(gpointer user_data) { WindowThread::ExternalFdData *data = reinterpret_cast (user_data); data->cb (); return TRUE; } void ExternalGLibSources::AddFdToGLibLoop(gint fd, gpointer data, GSourceFunc callback, GMainContext *context) { GSource *source = g_source_new(&externalGLibFuncs, sizeof (ExternalNuxSource)); ExternalNuxSource *extSource = reinterpret_cast (source); extSource->pfd.fd = fd; extSource->pfd.events = G_IO_IN; extSource->pfd.revents = 0; g_source_add_poll (source, &extSource->pfd); g_source_set_callback (source, callback, data, NULL); g_source_attach (source, context); } void ExternalGLibSources::RemoveFdFromGLibLoop(gpointer data) { g_source_remove_by_user_data(data); } void WindowThread::AddFdToGLibLoop(int fd, gpointer data, GSourceFunc callback) { external_glib_sources_->AddFdToGLibLoop(fd, data, callback, main_loop_glib_context_); } void WindowThread::RemoveFdFromGLibLoop(gpointer data) { external_glib_sources_->RemoveFdFromGLibLoop(data); } void WindowThread::CleanupGlibLoop() { g_source_remove_by_funcs_user_data(&event_funcs, this); for (std::list::iterator it = _external_fds.begin(); it != _external_fds.end(); ++it) { gpointer data = reinterpret_cast(&(*it)); external_glib_sources_->RemoveFdFromGLibLoop(data); } } unsigned int WindowThread::AddGLibTimeout(unsigned int duration) { if (IsEmbeddedWindow()) { TimeoutData* dd = new TimeoutData; dd->window_thread = this; dd->id = g_timeout_add(duration, nux_timeout_dispatch, dd); return dd->id; } else { if ((main_loop_glib_context_ == 0) || (main_loop_glib_ == 0)) { //LOG_WARNING(logger) << "Trying to set a timeout before GLib Context is created.\n"; return 0; } GSource* timeout_source; //create a new time-out source timeout_source = g_timeout_source_new(duration); TimeoutData* dd = new TimeoutData; dd->window_thread = this; dd->id = 0; //set the callback for this source g_source_set_callback(timeout_source, nux_timeout_dispatch, dd, NULL); //attach source to context dd->id = g_source_attach(timeout_source, main_loop_glib_context_); return dd->id; } } #if defined(NUX_OS_WINDOWS) bool WindowThread::AddChildWindowGlibLoop(WindowThread* wnd_thread) #else bool WindowThread::AddChildWindowGlibLoop(WindowThread* /* wnd_thread */) #endif { #if defined(NUX_OS_WINDOWS) if (wnd_thread == NULL) { return false; } if (main_loop_glib_context_ == NULL) { InitGlibLoop(); } GSource *source = g_source_new(&event_funcs, sizeof(NuxEventSource)); NuxEventSource *event_source = (NuxEventSource*) source; g_source_set_priority(source, G_PRIORITY_DEFAULT); event_source->event_poll_fd.fd = (int)((int*)wnd_thread->GetThreadHandle()); event_source->event_poll_fd.events = G_IO_IN; g_source_add_poll(source, &event_source->event_poll_fd); g_source_set_can_recurse(source, TRUE); g_source_set_callback(source, 0, this, 0); if (IsEmbeddedWindow()) g_source_attach(source, NULL); else g_source_attach(source, main_loop_glib_context_); #endif return true; } void WindowThread::StartMasterClock() { // if we are not embedded and don't have a context yet if (!IsEmbeddedWindow() && main_loop_glib_context_ == 0) return; if (_MasterClock == NULL) { // make a source for our master clock _MasterClock = g_source_new(&timeline_funcs, sizeof(GSource)); g_source_set_priority(_MasterClock, G_PRIORITY_DEFAULT + 10); g_source_set_callback(_MasterClock, 0, this, 0); g_source_set_can_recurse(_MasterClock, TRUE); if (IsEmbeddedWindow()) g_source_attach(_MasterClock, NULL); else if (main_loop_glib_context_ != 0) g_source_attach(_MasterClock, main_loop_glib_context_); #if !defined(NUX_MINIMAL) gint64 micro_secs = g_source_get_time(_MasterClock); last_timeline_frame_time_sec_ = micro_secs / 1000000; last_timeline_frame_time_usec_ = micro_secs % 1000000; #endif } } void WindowThread::StopMasterClock() { if (_MasterClock) { g_source_remove(g_source_get_id(_MasterClock)); _MasterClock = NULL; } } void WindowThread::StopGLibLoop() { // woo no more main loop! this is prolly bad for nux, so erm // FIXME!! - Jay take a look at this, make sure just quitting the mainloop // is an idea that makes sense(needed for testing) if (!IsEmbeddedWindow()) g_main_loop_quit(main_loop_glib_); } #endif } nux-4.0.8+18.10.20180623/Nux/MainLoopGLib.h0000644000000000000000000000045513313373365014004 0ustar #ifndef _NUX_MAIN_LOOP_GLIB_H #define _NUX_MAIN_LOOP_GLIB_H #include namespace nux { class ExternalGLibSources { public: void AddFdToGLibLoop(gint fd, gpointer data, GSourceFunc callback, GMainContext *context); void RemoveFdFromGLibLoop(gpointer data); }; } #endif nux-4.0.8+18.10.20180623/Nux/Makefile.am0000644000000000000000000001461613313373365013417 0ustar CLEANFILES = DISTCLEANFILES = EXTRA_DIST = lib_LTLIBRARIES = \ libnux-@NUX_API_VERSION@.la libnux_@NUX_API_VERSION@_la_CPPFLAGS= \ -I$(srcdir) \ -I$(top_srcdir) \ -DPREFIX=\""$(prefix)"\" \ -DLIBDIR=\""$(libdir)"\" \ -DDATADIR=\""$(datadir)"\" \ -DPKGDATADIR=\""$(pkgdatadir)/@NUX_API_VERSION@"\" \ -DG_LOG_DOMAIN=\"Nux\" \ $(GCC_FLAGS) \ $(NUX_CFLAGS) \ $(IBUS_CFLAGS) \ $(GEIS_CFLAGS) \ $(MAINTAINER_CFLAGS) \ $(COVERAGE_CFLAGS) libnux_@NUX_API_VERSION@_la_LIBADD = \ $(top_builddir)/NuxCore/libnux-core-@NUX_API_VERSION@.la \ $(top_builddir)/NuxGraphics/libnux-graphics-@NUX_API_VERSION@.la \ $(NUX_LIBS) \ $(IBUS_LIBS) \ $(GEIS_LIBS) libnux_@NUX_API_VERSION@_la_LDFLAGS = \ $(NUX_LT_LDFLAGS) \ $(COVERAGE_LDFLAGS) source_cpp = \ AbstractButton.cpp \ AbstractCheckedButton.cpp \ AbstractComboBox.cpp \ AbstractPaintLayer.cpp \ AbstractThread.cpp \ Area.cpp \ BaseWindow.cpp \ BasicView.cpp \ Button.cpp \ CairoWrapper.cpp \ Canvas.cpp \ CheckBox.cpp \ ClientArea.cpp \ EMMetrics.cpp \ GridHLayout.cpp \ HLayout.cpp \ HSplitter.cpp \ InputArea.cpp \ KeyboardHandler.cpp \ KineticScrolling/AxisDecelerationAnimation.cpp \ KineticScrolling/KineticAxisScroller.cpp \ KineticScrolling/KineticScroller.cpp \ KineticScrolling/KineticScrollingTickSource.cpp \ KineticScrolling/VelocityCalculator.cpp \ KineticScrollView.cpp \ LayeredLayout.cpp \ Layout.cpp \ LinearLayout.cpp \ MainLoopGLib.cpp \ Nux.cpp \ NuxGlobalInitializer.cpp \ Painter.cpp \ PaintLayer.cpp \ StaticText.cpp \ StaticTextBox.cpp \ SystemThread.cpp \ TextEntry.cpp \ TextLoader.cpp \ TextureArea.cpp \ Theme.cpp \ TimerProc.cpp \ Utils.cpp \ VLayout.cpp \ View.cpp \ VSplitter.cpp \ WidgetMetrics.cpp \ WindowCompositor.cpp \ WindowThread.cpp if !NUX_MINIMAL source_cpp += \ ActionItem.cpp \ AnimatedTextureArea.cpp \ ColorEditor.cpp \ ColorPickerDialog.cpp \ ColorPreview.cpp \ Dialog.cpp \ DoubleValidator.cpp \ EditTextBox.cpp \ FileSelector.cpp \ FloatingWindow.cpp \ GroupBox.cpp \ GroupBox2.cpp \ HexRegExpValidator.cpp \ HScrollBar.cpp \ IntegerValidator.cpp \ MenuPage.cpp \ MenuBar.cpp \ MouseAreaCtrl.cpp \ NumericValuator.cpp \ Panel.cpp \ PopUpWindow.cpp \ InputAreaProximity.cpp \ RadioButton.cpp \ RadioButtonGroup.cpp \ RangeValue.cpp \ RangeValueInteger.cpp \ RGBValuator.cpp \ ScrollBar.cpp \ ScrollView.cpp \ SpinBox.cpp \ SpinBoxDouble.cpp \ SpinBox_Logic.cpp \ TabView.cpp \ Timeline.cpp \ TimelineEasings.cpp \ ToggleButton.cpp \ ToolButton.cpp \ Validator.cpp \ VScrollBar.cpp endif if USE_X11 source_cpp += \ InputMethodIBus.cpp \ XICClient.cpp \ XIMCallbacks.cpp \ XIMController.cpp endif if HAVE_GEIS source_cpp += \ GeisAdapter.cpp \ Gesture.cpp \ GestureBroker.cpp \ GesturesSubscription.cpp endif source_h = \ $(builddir)/Features.h \ AbstractButton.h \ AbstractCheckedButton.h \ AbstractComboBox.h \ AbstractPaintLayer.h \ AbstractThread.h \ Area.h \ BaseWindow.h \ BasicView.h \ Button.h \ CairoWrapper.h \ Canvas.h \ CheckBox.h \ ClientArea.h \ EMMetrics.h \ GridHLayout.h \ HLayout.h \ HSplitter.h \ InputArea.h \ KeyboardHandler.h \ KineticScrolling/AxisDecelerationAnimation.h \ KineticScrolling/KineticAxisScroller.h \ KineticScrolling/KineticScroller.h \ KineticScrolling/KineticScrollingEnums.h \ KineticScrolling/KineticScrollingTickSource.h \ KineticScrolling/VelocityCalculator.h \ KineticScrollView.h \ LayeredLayout.h \ Layout.h \ LinearLayout.h \ MainLoopGLib.h \ Nux.h \ NuxGlobalInitializer.h \ Painter.h \ PaintLayer.h \ StaticText.h \ StaticTextBox.h \ SystemThread.h \ TextEntry.h \ TextLoader.h \ TextureArea.h \ Theme.h \ TimerProc.h \ Utils.h \ VLayout.h \ View.h \ VSplitter.h \ WidgetMetrics.h \ WindowCompositor.h \ WindowThread.h if !NUX_MINIMAL source_h += \ $(builddir)/ABI.h \ ActionItem.h \ AnimatedTextureArea.h \ ColorEditor.h \ ColorPickerDialog.h \ ColorPreview.h \ Dialog.h \ DoubleValidator.h \ EditTextBox.h \ FileSelector.h \ FloatingWindow.h \ GroupBox.h \ GroupBox2.h \ HexRegExpValidator.h \ HScrollBar.h \ IntegerValidator.h \ MenuPage.h \ MenuBar.h \ MouseAreaCtrl.h \ NumericValuator.h \ NuxTimerTickSource.h \ Panel.h \ PopUpWindow.h \ InputAreaProximity.h \ RadioButton.h \ RadioButtonGroup.h \ RangeValue.h \ RangeValueInteger.h \ Readme.txt \ RGBValuator.h \ ScrollBar.h \ ScrollView.h \ SpinBox.h \ SpinBoxDouble.h \ SpinBox_Logic.h \ TabView.h \ TextEntryComposeSeqs.h \ Timeline.h \ TimelineEasings.h \ ToolButton.h \ ToggleButton.h \ Validator.h \ VScrollBar.h endif if USE_X11 source_h += \ InputMethodIBus.h \ XICClient.h \ XIMController.h endif if HAVE_GEIS source_h += \ GeisAdapter.h \ Gesture.h \ GestureBroker.h \ GesturesSubscription.h endif nuxprogramframework_cpp = \ ProgramFramework/ProgramTemplate.cpp \ ProgramFramework/TestView.cpp \ ProgramFramework/TestTextEntry.cpp nuxprogramframework_h = \ ProgramFramework/ProgramTemplate.h \ ProgramFramework/TestView.h \ ProgramFramework/TestTextEntry.h libnux_@NUX_API_VERSION@_la_SOURCES = \ $(source_cpp) \ $(source_h) \ $(nuxprogramframework_cpp) \ $(nuxprogramframework_h) nuxdir = $(includedir)/Nux-@NUX_API_VERSION@/Nux nux_HEADERS = $(source_h) nuxprogramframeworkdir = $(includedir)/Nux-@NUX_API_VERSION@/Nux/ProgramFramework nuxprogramframework_HEADERS = $(nuxprogramframework_h) kineticscrolling_h = \ KineticScrolling/AxisDecelerationAnimation.h \ KineticScrolling/KineticAxisScroller.h \ KineticScrolling/KineticScroller.h \ KineticScrolling/KineticScrollingEnums.h \ KineticScrolling/KineticScrollingTickSource.h \ KineticScrolling/VelocityCalculator.h kineticscrollingdir = $(includedir)/Nux-@NUX_API_VERSION@/Nux/KineticScrolling kineticscrolling_HEADERS = $(kineticscrolling_h) # pkg-config file nux-@NUX_API_VERSION@.pc: nux.pc $(AM_V_GEN) cp -f nux.pc nux-@NUX_API_VERSION@.pc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = nux-@NUX_API_VERSION@.pc unused_src = \ ComboBoxSimple.cpp \ ComboBoxSimple.h \ D2DTextRenderer.cpp \ D2DTextRenderer.h \ GridVLayout.cpp \ GridVLayout.h \ PangoText.cpp \ PangoText.h CLEANFILES += nux-@NUX_API_VERSION@.pc DISTCLEANFILES += nux.pc EXTRA_DIST += nux.pc.in ${unused_src} nux-4.0.8+18.10.20180623/Nux/MenuBar.cpp0000644000000000000000000003404413313373365013415 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "WindowCompositor.h" #include "HLayout.h" #include "MenuBar.h" namespace nux { static const unsigned int MENU_MINIMUM_WIDTH = 10; static const unsigned int MENUBAR_ICON_WIDTH = 24; static const unsigned int MENUBAR_ICON_HEIGHT = 24; NUX_IMPLEMENT_ROOT_OBJECT_TYPE(MenuBarItem); NUX_IMPLEMENT_OBJECT_TYPE(MenuBar); MenuBarItem::MenuBarItem(NUX_FILE_LINE_DECL) : Object(true, NUX_FILE_LINE_PARAM) { // This area is added to the layout of the MenuBar. The Menubar will will ref/unref it. area = new BasicView(NUX_TRACKER_LOCATION); icon = 0; } MenuBarItem::~MenuBarItem() { if (menu) menu->UnReference(); if (icon) icon->UnReference(); // The Area is owned by the MenuBar: do nothing for area. } MenuBar::MenuBar(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_MenuIsActive(false) //, m_CurrentMenu(0) , m_IsOpeningMenu(false) { m_CurrentMenu = NULL; m_MenuBarWindow = NULL; m_hlayout = new HLayout(NUX_TRACKER_LOCATION); m_hlayout->SetHorizontalInternalMargin(4); m_hlayout->SetHorizontalExternalMargin(2); SetMinimumSize(24, 24); SetMaximumSize(AREA_MAX_WIDTH, 24); SetGeometry(Geometry(0, 0, 200, 20)); m_hlayout->SetHorizontalInternalMargin(4); m_hlayout->SetVerticalExternalMargin(0); m_hlayout->SetContentDistribution(eStackLeft); SetCompositionLayout(m_hlayout); } MenuBar::~MenuBar() { std::list< MenuBarItem * >::iterator it; for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++) { (*it)->UnReference(); } m_MenuBarItemList.clear(); } void MenuBar::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); Geometry item_geometry; std::list< MenuBarItem * >::iterator it; for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++) { BasicView *area = (*it)->area; item_geometry = area->GetGeometry(); if (area->IsMouseInside()) { GetPainter().PaintBackground(graphics_engine, item_geometry); if (!m_MenuIsActive) { GetPainter().Paint2DQuadColor(graphics_engine, item_geometry, Color(0xFF000000)); //GetPainter().PaintShape(graphics_engine, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2); } else { GetPainter().Paint2DQuadColor(graphics_engine, item_geometry, Color(0xFF000000)); //GetPainter().PaintShapeCorner(graphics_engine, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2, //eCornerTopLeft|eCornerTopRight, false); } if ((*it)->icon) { graphics_engine.GetRenderStates().SetBlend(TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); GetPainter().Draw2DTexture(graphics_engine, (*it)->icon, item_geometry.x, item_geometry.y); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); graphics_engine.GetRenderStates().SetBlend(GL_FALSE); } else { GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), item_geometry, area->GetBaseString(), GetTextColor(), true, eAlignTextCenter); } } else { GetPainter().PaintBackground(graphics_engine, item_geometry); if ((*it)->icon) { graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); graphics_engine.GetRenderStates().SetBlend(TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); GetPainter().Draw2DTexture(graphics_engine, (*it)->icon, item_geometry.x, item_geometry.y); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); graphics_engine.GetRenderStates().SetBlend(GL_FALSE); } else { GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), item_geometry, area->GetBaseString(), GetTextColor(), true, eAlignTextCenter); } } } if (m_MenuIsActive) { BasicView *area = m_CurrentMenu->area; item_geometry = area->GetGeometry(); GetPainter().PaintBackground(graphics_engine, item_geometry); GetPainter().Paint2DQuadColor(graphics_engine, item_geometry, Color(0xFF000000)); //GetPainter().PaintShapeCorner(graphics_engine, item_geometry, Color(0xFF000000), eSHAPE_CORNER_ROUND2, eCornerTopLeft|eCornerTopRight, true); if (m_CurrentMenu->icon) { graphics_engine.GetRenderStates().SetBlend(TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); GetPainter().Draw2DTexture(graphics_engine, m_CurrentMenu->icon, item_geometry.x, item_geometry.y); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); graphics_engine.GetRenderStates().SetBlend(GL_FALSE); } else { GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), item_geometry, area->GetBaseString(), GetTextColor(), true, eAlignTextCenter); } } graphics_engine.PopClippingRectangle(); } void MenuBar::DrawContent(GraphicsEngine &graphics_engine, bool /* force_draw */) { graphics_engine.PushClippingRectangle(GetGeometry()); graphics_engine.PopClippingRectangle(); } void MenuBar::AddMenu(const char *MenuLabel, MenuPage *menu) { NUX_RETURN_IF_NULL(menu); AddMenu(MenuLabel, menu, 0); } void MenuBar::AddMenu(const char *MenuLabel, MenuPage *menu, BaseTexture *icon) { NUX_RETURN_IF_NULL(menu); // MenuBarItem inherits from Object: no need to Sink the reference. MenuBarItem *menubar_item(new MenuBarItem(NUX_TRACKER_LOCATION)); menu->m_IsTopOfMenuChain = true; menubar_item->area->SetBaseString(MenuLabel); menubar_item->menu = menu; if (menubar_item->menu) menubar_item->menu->Reference(); menubar_item->icon = icon; if (menubar_item->icon) menubar_item->icon->Reference(); m_MenuBarItemList.push_back(menubar_item); //menubar_item->area->SetMinimumSize(DEFAULT_WIDGET_WIDTH, 40); if (!icon) { menubar_item->area->SetMinimumSize(Max(MENU_MINIMUM_WIDTH, (unsigned int) (10 + GetFont()->GetStringWidth(MenuLabel))), Max(MENU_MINIMUM_WIDTH, (unsigned int) 16)); } else { menubar_item->area->SetMinMaxSize(MENUBAR_ICON_WIDTH, MENUBAR_ICON_HEIGHT); } menubar_item->area->mouse_enter.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::EmitItemMouseEnter), menubar_item)); menubar_item->area->mouse_leave.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::EmitItemMouseLeave), menubar_item)); menubar_item->area->mouse_down.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::EmitItemMouseDown), menubar_item)); menubar_item->area->mouse_drag.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::RecvItemMouseDrag), menubar_item)); menubar_item->area->mouse_up.connect(sigc::bind(sigc::mem_fun(this, &MenuBar::EmitItemMouseUp), menubar_item)); menubar_item->menu->SetParentMenu(0); menubar_item->menu->sigActionTriggered.connect(sigc::mem_fun(this, &MenuBar::RecvSigActionTriggered)); menubar_item->menu->sigTerminateMenuCascade.connect(sigc::mem_fun(this, &MenuBar::RecvSigTerminateMenuCascade)); menubar_item->menu->sigMouseDownOutsideMenuCascade.connect(sigc::mem_fun(this, &MenuBar::RecvSigMouseDownOutsideMenuCascade)); m_hlayout->AddView(menubar_item->area, 0, eCenter); GetWindowThread()->ComputeElementLayout(m_hlayout); } void MenuBar::EmitItemMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */, MenuBarItem *menubar_item) { if (m_MenuIsActive) { if (m_CurrentMenu && (m_CurrentMenu->menu != menubar_item->menu)) m_CurrentMenu->menu->StopMenu(0, 0); menubar_item->menu->m_MenuWindow = m_MenuBarWindow; menubar_item->menu->StartMenu(menubar_item->area->GetBaseX(), menubar_item->area->GetBaseY() + menubar_item->area->GetBaseHeight(), 0, 0); m_CurrentMenu = menubar_item; m_IsOpeningMenu = true; } QueueDraw(); } void MenuBar::EmitItemMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */, MenuBarItem * /* menubar_item */) { QueueDraw(); } void MenuBar::EmitItemMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */, MenuBarItem *menubar_item) { m_MenuBarWindow = GetWindowThread()->GetWindowCompositor().GetProcessingTopView(); if (m_MenuIsActive == false) { // Open the corresponding MenuPage if (m_CurrentMenu) { // This should never happen nuxAssert(0); m_CurrentMenu->menu->StopMenu(); } m_MenuIsActive = true; m_CurrentMenu = menubar_item; m_CurrentMenu->menu->m_MenuWindow = m_MenuBarWindow; m_IsOpeningMenu = true; m_CurrentMenu->menu->StartMenu(menubar_item->area->GetBaseX(), menubar_item->area->GetBaseY() + menubar_item->area->GetBaseHeight(), 0, 0); } else { // If the mouse up that follows happen inside the area, then it is going to close the menu. m_IsOpeningMenu = false; } QueueDraw(); } void MenuBar::EmitItemMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem * /* menubar_item */) { if (m_MenuIsActive) { if (m_CurrentMenu->area->IsMouseInside()) { if (m_IsOpeningMenu == false) { // close the MenuPage that is Open if (m_CurrentMenu) m_CurrentMenu->menu->StopMenu(0, 0); m_MenuIsActive = false; m_CurrentMenu = 0; } else { // The MousePress before this MouseRelease, caused the MenuPage to open. // Set m_IsOpeningMenu so the next mouse release will close the menu. m_IsOpeningMenu = false; } } else { bool hit_inside_a_menu = false; bool b = m_CurrentMenu->menu->TestMouseUp(x, y, button_flags, key_flags, hit_inside_a_menu); if (b || (hit_inside_a_menu == false)) { RecvSigTerminateMenuCascade(); } } } QueueDraw(); } void MenuBar::RecvItemMouseDrag(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */, MenuBarItem * /* menubar_item */) { // TODO: Port to new event architecture // // Transition between one menu bar item to another // if (GetWindowThread()->GetWindowCompositor().GetMouseFocusArea() == menubar_item->area) // { // if (!menubar_item->area->IsMouseInside()) // can also test GetWindowThread()->GetWindowCompositor().GetMouseOverArea() != &menubar_item->area // { // std::list< MenuBarItem * >::iterator it; // // compute window coordinates x and y; // int winx = menubar_item->area->GetBaseX() + x; // int winy = menubar_item->area->GetBaseY() + y; // // for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++) // { // BasicView *area = (*it)->area; // Geometry geometry = area->GetGeometry(); // // if (geometry.IsPointInside(winx, winy)) // { // // Close the menu below menubar_item(the one that has the focus // menubar_item->area->ForceStopFocus(0, 0); // // // EmitItemMouseEnter is going to open the menu below(*it) // { // EmitItemMouseEnter(winx, winy, button_flags, key_flags, (*it)); // m_IsOpeningMenu = true; // area->ForceStartFocus(0, 0); // // GetWindowThread()->GetWindowCompositor().SetMouseFocusArea(area); // GetWindowThread()->GetWindowCompositor().SetMouseOverArea(area); // } // // break; // } // } // } // } } void MenuBar::RecvSigActionTriggered(MenuPage * /* menu */, ActionItem * /* action */) { m_MenuIsActive = false; if (m_CurrentMenu) { m_CurrentMenu->menu->StopMenu(); QueueDraw(); } m_CurrentMenu = 0; m_IsOpeningMenu = false; // You can do something if you want with the menu* and the action* } void MenuBar::RecvSigTerminateMenuCascade() { m_MenuIsActive = false; if (m_CurrentMenu) { m_CurrentMenu->menu->StopMenu(); } m_CurrentMenu = 0; m_IsOpeningMenu = false; QueueDraw(); } void MenuBar::RecvSigMouseDownOutsideMenuCascade(MenuPage * /* menu */, int x, int y) { Geometry geometry; std::list< MenuBarItem * >::iterator it; bool TerminateMenuCascade = 1; for (it = m_MenuBarItemList.begin(); it != m_MenuBarItemList.end(); it++) { BasicView *area = (*it)->area; geometry = area->GetGeometry(); if (geometry.IsPointInside(x, y)) { // The event landed on one of the MenuBar item. // Do nothing. This will be handled in the ProcessEvent of the MenuBar item where the mouse down landed. TerminateMenuCascade = 0; break; } } if (TerminateMenuCascade) RecvSigTerminateMenuCascade(); } } nux-4.0.8+18.10.20180623/Nux/MenuBar.h0000644000000000000000000000647613313373365013072 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MENUBAR_H #define MENUBAR_H #include "ScrollView.h" #include "ToolButton.h" #include "MenuPage.h" #include "Painter.h" namespace nux { class PopupBox; class BaseWindow; class MenuBar; class HLayout; class MenuBarItem: public Object { public: NUX_DECLARE_OBJECT_TYPE(MenuBarItem, Object); MenuBarItem(NUX_FILE_LINE_PROTO); ~MenuBarItem(); private: BasicView *area; MenuPage *menu; BaseTexture *icon; // should be 24x24 friend class MenuBar; }; class MenuBar: public View { NUX_DECLARE_OBJECT_TYPE(MenuBar, View); public: MenuBar(NUX_FILE_LINE_PROTO); ~MenuBar(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); //void AddActionItem(ActionItem* actionItem); void AddMenu(const char *MenuLabel, MenuPage *popup); void AddMenu(const char *MenuLabel, MenuPage *menu, BaseTexture *icon); ///////////////// // EMITERS // ///////////////// private: void EmitItemMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item); void EmitItemMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item); void EmitItemMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item); void EmitItemMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item); void RecvItemMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags, MenuBarItem *menubar_item); void RecvSigActionTriggered(MenuPage *, ActionItem *); void RecvSigTerminateMenuCascade(); //! Process a mouse down event outside of the menu cascade. /* Process a mouse down event outside of the menu cascade. The menu bar checks if the mouse down happened on one of its menu bar item. If yes, it let the menu bar item process the event. if no, it will initiate the closure of the menu cascade. \param menu menu item \param x coordinate of the mouse down event \param y coordinate of the mouse down event */ void RecvSigMouseDownOutsideMenuCascade(MenuPage *menu, int x, int y); protected: private: std::list< MenuBarItem * > m_MenuBarItemList; HLayout *m_hlayout; bool m_MenuIsActive; MenuBarItem *m_CurrentMenu; bool m_IsOpeningMenu; BaseWindow *m_MenuBarWindow; }; } #endif // MENUBAR_H nux-4.0.8+18.10.20180623/Nux/MenuPage.cpp0000644000000000000000000010300413313373365013556 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "MenuPage.h" #include "WindowCompositor.h" #include "ActionItem.h" #include "VLayout.h" #include "StaticText.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(MenuItem); NUX_IMPLEMENT_OBJECT_TYPE(MenuSeparator); NUX_IMPLEMENT_OBJECT_TYPE(MenuPage); static const int MENU_ICONE_WIDTH = 18; static const int MENU_ITEM_MIN_WIDTH = 90; static const int MENU_ITEM_MIN_HEIGHT = 20; static const int MENU_ITEM_BORDER_TO_ICON_MARGIN = 5; static const int MENU_ITEM_ICON_TO_TEXT_MARGIN = 5; static const int MENU_ITEM_TEXT_TO_BORDER_MARGIN = 5; // Algorithm: // To initiate the menu, the mouse has to hit one of the menu bar item(they hold the name of the menu that are displayed). // When that happens, the menu attached to the MenuBarItem gets the focus and becomes visible. Before the mouse is released, // the flag m_NextMouseUpMeanStop is set to FALSE, meaning that the following mouse up will not be processed by the menu, even if the released happened // outside of any of the menu forming the menu cascade. This way, the menu will remain open. There are exceptions to this however. // After the firs mouse down on the MenuBarItem and before the mouse up event, if the mouse over the the opened menu, // then m_NextMouseUpMeanStop is set to TRUE. If the mouse is released over an active menu item, the menu cascade will close itself. // If the mouse is released outside any of the menu forming the menu cascade, the menu will close itself. // // MenuItem::MenuItem(const char *label, int UserValue, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { _child_menu = 0; _action_item = new ActionItem(label, UserValue, NUX_TRACKER_LOCATION); _pango_static_text = new StaticText(label, NUX_TRACKER_LOCATION); _pango_static_text->SetTextColor(Color(0.0f, 0.0f, 0.0f, 1.0f)); } MenuItem::~MenuItem() { _pango_static_text->Dispose(); if (_action_item) _action_item->UnReference(); if (_child_menu) _child_menu->UnReference(); } void MenuItem::SetChildMenu(MenuPage *menu) { nuxAssert(menu); NUX_RETURN_IF_NULL(menu); if (_child_menu) _child_menu->UnReference(); _child_menu = menu; _child_menu->Reference(); } MenuPage *MenuItem::GetChildMenu() const { return _child_menu; } void MenuItem::SetActionItem(ActionItem *action) { nuxAssertMsg(action != 0, "[MenuItem::SetActionItem] Parameter is Null."); if (action == 0) return; _pango_static_text->Dispose(); if (_action_item) _action_item->UnReference(); _action_item = action; _action_item->Reference(); _pango_static_text = new StaticText(_action_item->GetLabel(), NUX_TRACKER_LOCATION); } ActionItem *MenuItem::GetActionItem() const { return _action_item; } int MenuItem::GetTextWidth() { if (_pango_static_text) { int w, h; _pango_static_text->GetTextLayoutSize(w, h); return w; } return 0; } int MenuItem::GetTextHeight() { if (_pango_static_text) { int w, h; _pango_static_text->GetTextLayoutSize(w, h); return h; } return 0; } //ActionItem* MenuItem::GetActionItem() //{ // return &_action_item; //} void MenuItem::Draw(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void MenuItem::DrawAsMenuItem(GraphicsEngine &graphics_engine, const Color & /* textcolor */, bool is_highlighted, bool /* isFirstItem */, bool /* isLastItem */, bool /* draw_icone */) { Geometry geo = GetGeometry(); Geometry icon_geo(0, 0, 20, 20); Geometry text_geo = geo; text_geo.OffsetPosition(24, 0); text_geo.OffsetSize(2 * 24, 0); icon_geo.SetX(geo.x + 2); icon_geo.SetY(geo.y + 0); const char *label = _action_item->GetLabel(); if (is_highlighted) { /* if (isFirstItem && isLastItem) GetPainter().PaintShape(graphics_engine, geo, COLOR_FOREGROUND_SECONDARY, eSHAPE_CORNER_ROUND4); else if (isFirstItem) GetPainter().PaintShapeCorner(graphics_engine, geo, COLOR_FOREGROUND_SECONDARY, eSHAPE_CORNER_ROUND4, eCornerTopLeft | eCornerTopRight); else if (isLastItem) GetPainter().PaintShapeCorner(graphics_engine, geo, COLOR_FOREGROUND_SECONDARY, eSHAPE_CORNER_ROUND4, eCornerBottomLeft | eCornerBottomRight); else GetPainter().Paint2DQuadColor(graphics_engine, geo, COLOR_FOREGROUND_SECONDARY); */ GetPainter().Paint2DQuadColor(graphics_engine, geo, Color(0x44000000) /*COLOR_FOREGROUND_SECONDARY*/); _pango_static_text->SetTextColor(Color(1.0f, 1.0f, 1.0f, 1.0f)); } else { _pango_static_text->SetTextColor(Color(0.0f, 0.0f, 0.0f, 1.0f)); //GetPainter().Paint2DQuadColor(graphics_engine, geo, Color(0xFF868686)); } //if(m_Icon) { //GetPainter().Draw2DTextureAligned(graphics_engine, &_action_item->GetIcon(), icon_geo, TextureAlignmentStyle(eTACenter, eTACenter)); } if (label) { //GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), text_geo, std::string(label), textcolor, eAlignTextLeft); _pango_static_text->SetGeometry(text_geo); _pango_static_text->ProcessDraw(graphics_engine, true); } } MenuSeparator::MenuSeparator(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { } MenuSeparator::~MenuSeparator() { } void MenuSeparator::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); int y0 = base.y + base.GetHeight() / 2; GetPainter().Draw2DLine(graphics_engine, base.x, y0, base.x + base.GetWidth(), y0, Color(0xFF222222)); GetPainter().Draw2DLine(graphics_engine, base.x, y0 + 1, base.x + base.GetWidth(), y0 + 1, Color(0xFFAAAAAA)); } MenuPage::MenuPage(const char *title, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { m_Parent = 0; m_item_width = MENU_ITEM_MIN_WIDTH; m_item_height = MENU_ITEM_MIN_HEIGHT; m_show_item_icon = true; m_MenuWindow = 0; m_Name = title; m_IsTopOfMenuChain = false; _font_name = g_strdup("Ubuntu 12"); on_closure_continue_with_event_ = false; // Set Original State // Set Signals mouse_move.connect(sigc::mem_fun(this, &MenuPage::EmitMouseMove)); mouse_drag.connect(sigc::mem_fun(this, &MenuPage::EmitMouseDrag)); mouse_down.connect(sigc::mem_fun(this, &MenuPage::EmitMouseDown)); mouse_up.connect(sigc::mem_fun(this, &MenuPage::EmitMouseUp)); mouse_leave.connect(sigc::mem_fun(this, &MenuPage::RecvMouseLeave)); mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &MenuPage::Terminate)); // Set Geometry SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); // Set layout m_numItem = 0; m_HighlightedItem = -1; m_IsActive = false; m_NextMouseUpMeanStop = false; m_SubMenuAction = 0; _vlayout = new VLayout(NUX_TRACKER_LOCATION); // No Need to set a composition layout. // The MenuPage is floating above everything else. SetLayout(_vlayout); SetTextColor(color::Black); } MenuPage::~MenuPage() { // std::vector ::iterator it; // // for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++) // { // (*it)->UnReference(); // } m_MenuItemVector.clear(); m_MenuSeparatorVector.clear(); RemoveLayout(); } //void MenuPage::SetName(const char* name) //{ // m_Name = name; //} // const char *MenuPage::GetName() const { return m_Name.c_str(); } bool MenuPage::CanClose() const { return m_Action_Triggered; } Area* MenuPage::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } void MenuPage::Draw(GraphicsEngine &graphics_engine, bool force_draw) { if (m_IsActive) { Geometry base = GetGeometry(); Geometry shadow; shadow = base; shadow.OffsetPosition(4, 4); //GetPainter().PaintShape(graphics_engine, shadow, Color(0xFF000000), eSHAPE_CORNER_ROUND4_SHADOW); graphics_engine.PushClippingRectangle(base); graphics_engine.GetRenderStates().SetBlend(GL_TRUE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GetPainter().Paint2DQuadColor(graphics_engine, base, Color(0xCCFFFFFF)); graphics_engine.GetRenderStates().SetBlend(GL_FALSE); Geometry text_area; text_area.SetX(base.x); text_area.SetY(base.y); text_area.SetWidth(base.GetWidth()); text_area.SetHeight(PRACTICAL_WIDGET_HEIGHT); int i; std::vector::iterator it; int numItem = (int) m_MenuItemVector.size(); for (it = m_MenuItemVector.begin(), i = 0; it != m_MenuItemVector.end(); it++, i++) { bool is_highlighted = (m_HighlightedItem == i); (*it)->DrawAsMenuItem(graphics_engine, Color(0xFFFFFFFF) /*GetTextColor()*/, is_highlighted, i == 0, i == (numItem - 1), true); } std::vector::iterator separator_iterator; for (separator_iterator = m_MenuSeparatorVector.begin(); separator_iterator != m_MenuSeparatorVector.end(); separator_iterator++) { (*separator_iterator)->Draw(graphics_engine, force_draw); } graphics_engine.PopClippingRectangle(); } } void MenuPage::DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void MenuPage::SetFontName(char *font_name) { std::vector::iterator it; for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); ++it) { (*it)->GetStaticText()->SetFontName(font_name); } g_free(_font_name); _font_name = g_strdup(font_name); } ActionItem *MenuPage::AddAction(const char *label, int UserValue) { // pMenuItem if added to the layout do not sink the Reference. MenuItem *pMenuItem(new MenuItem(label, UserValue, NUX_TRACKER_LOCATION)); pMenuItem->GetStaticText()->SetFontName(_font_name); m_MenuItemVector.push_back(pMenuItem); pMenuItem->SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); int new_item_width = pMenuItem->GetTextWidth(); //GetFont()->GetStringWidth(pMenuItem->GetActionItem()->GetLabel()); if (new_item_width < m_item_width) { std::vector::iterator it; for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++) { if (ShowItemIcon()) { pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN + MENU_ICONE_WIDTH + MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } else { pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } } } else { std::vector::iterator it; for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++) { if (ShowItemIcon()) { (*it)->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN + MENU_ICONE_WIDTH + MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } else { (*it)->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } (*it)->SetBaseSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } m_item_width = new_item_width; // SetBaseWidth(MENU_ITEM_ICON_TO_TEXT_MARGIN // + m_item_width // + MENU_ITEM_TEXT_TO_BORDER_MARGIN); } if (pMenuItem->GetChildMenu() != 0) { pMenuItem->GetChildMenu()->SetParentMenu(this); } m_numItem = (int) m_MenuItemVector.size(); _vlayout->AddView(pMenuItem, 0, eLeft, eFix); ComputeContentSize(); return pMenuItem->GetActionItem(); } //void MenuPage::AddActionItem(ActionItem* actionItem) //{ // nuxAssertMsg(actionItem != 0, "[MenuPage::AddActionItem] Parameter is Null."); // if (actionItem == 0) // return; // // MenuItem* pMenuItem = new MenuItem(actionItem->GetLabel(), actionItem->GetUserValue(), NUX_TRACKER_LOCATION); // pMenuItem->SinkReference(); // pMenuItem->SetActionItem(actionItem); // // m_MenuItemVector.push_back(pMenuItem); // pMenuItem->SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); // // int new_item_width = GetFont()->GetStringWidth(actionItem->GetLabel()); // if (new_item_width < m_item_width) // { // if (ShowItemIcon()) // { // pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN // + MENU_ICONE_WIDTH // + MENU_ITEM_ICON_TO_TEXT_MARGIN // + m_item_width // + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); // } // else // { // pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN // + m_item_width // + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); // } // } // else // { // if (ShowItemIcon()) // { // pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN // + MENU_ICONE_WIDTH // + MENU_ITEM_ICON_TO_TEXT_MARGIN // + new_item_width // + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); // } // else // { // pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN // + new_item_width // + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); // } // // std::vector::iterator it; // for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++) // { // (*it)->setSize(MENU_ITEM_ICON_TO_TEXT_MARGIN // + new_item_width // + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); // } // // m_item_width = new_item_width; // SetWidth(MENU_ITEM_ICON_TO_TEXT_MARGIN // + m_item_width // + MENU_ITEM_TEXT_TO_BORDER_MARGIN); // } // // if (pMenuItem->GetChildMenu() != 0) // { // pMenuItem->GetChildMenu()->SetParentMenu(this); // } // // m_numItem = (int)m_MenuItemVector.size(); // _vlayout->AddView(pMenuItem, 0, eLeft, eFix); // ComputeContentSize(); //} MenuPage *MenuPage::AddMenu(const char *label) { // pMenuItem if added to the layout do not sink the Reference. MenuItem *pMenuItem(new MenuItem(label, 0, NUX_TRACKER_LOCATION)); pMenuItem->SetChildMenu(new MenuPage(label)); //pMenuItem->SetActionItem(new ActionItem()); //pMenuItem->GetActionItem()->SetLabel(label); m_MenuItemVector.push_back(pMenuItem); pMenuItem->SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); int new_item_width = pMenuItem->GetTextWidth(); //GetFont()->GetStringWidth(label); if (new_item_width < m_item_width) { if (ShowItemIcon()) { pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN + MENU_ICONE_WIDTH + MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } else { pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } } else { if (ShowItemIcon()) { pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN + MENU_ICONE_WIDTH + MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } else { pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } std::vector< MenuItem * >::iterator it; for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++) { (*it)->SetBaseSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } m_item_width = new_item_width; SetBaseWidth(MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN); } if (pMenuItem->GetChildMenu() != 0) { pMenuItem->GetChildMenu()->SetParentMenu(this); } m_numItem = (int) m_MenuItemVector.size(); _vlayout->AddView(pMenuItem, 0, eLeft, eFix); ComputeContentSize(); return pMenuItem->GetChildMenu(); } ActionItem *MenuPage::AddSubMenu(const char * /* label */, MenuPage *menu) { menu->m_IsTopOfMenuChain = false; // pMenuItem if added to the layout do not sink the Reference. MenuItem *pMenuItem(new MenuItem(menu->GetName(), 0, NUX_TRACKER_LOCATION)); pMenuItem->SetChildMenu(menu); m_MenuItemVector.push_back(pMenuItem); pMenuItem->SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); int new_item_width = pMenuItem->GetTextWidth(); //GetFont()->GetStringWidth(label); if (new_item_width < m_item_width) { if (ShowItemIcon()) { pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN + MENU_ICONE_WIDTH + MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } else { pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } } else { if (ShowItemIcon()) { pMenuItem->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN + MENU_ICONE_WIDTH + MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } else { pMenuItem->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } std::vector< MenuItem * >::iterator it; for (it = m_MenuItemVector.begin(); it != m_MenuItemVector.end(); it++) { (*it)->SetBaseSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + new_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, m_item_height); } m_item_width = new_item_width; SetBaseWidth(MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN); } if (pMenuItem->GetChildMenu() != 0) { pMenuItem->GetChildMenu()->SetParentMenu(this); } m_numItem = (int) m_MenuItemVector.size(); _vlayout->AddView(pMenuItem, 0, eLeft, eFix); ComputeContentSize(); return pMenuItem->GetActionItem(); } void MenuPage::AddSeparator() { // pMenuSeparator if added to the layout do not sink the Reference. MenuSeparator *pMenuSeparator(new MenuSeparator(NUX_TRACKER_LOCATION)); m_MenuSeparatorVector.push_back(pMenuSeparator); if (ShowItemIcon()) { pMenuSeparator->SetMinMaxSize(MENU_ITEM_BORDER_TO_ICON_MARGIN + MENU_ICONE_WIDTH + MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, 4); } else { pMenuSeparator->SetMinMaxSize(MENU_ITEM_ICON_TO_TEXT_MARGIN + m_item_width + MENU_ITEM_TEXT_TO_BORDER_MARGIN, 4); } _vlayout->AddView(pMenuSeparator, 0, eLeft, eFix); ComputeContentSize(); } void MenuPage::RemoveItem(ActionItem * /* item */) { } void MenuPage::RemoveAllItem() { m_MenuSeparatorVector.clear(); m_MenuItemVector.clear(); m_numItem = 0; _vlayout->Clear(); ComputeContentSize(); //FIXME - Hack to fix a bug with the menu height not being reset after removing items Geometry base = GetGeometry(); base.height = 0; View::SetGeometry(base); } void MenuPage::EmitMouseMove(int /* x */, int y, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (IsMouseInside()) { m_NextMouseUpMeanStop = true; // Find on which item the mouse is std::vector< MenuItem * >::iterator item_iterator; unsigned int i = 0; m_HighlightedItem = -1; for (item_iterator = m_MenuItemVector.begin(), i = 0; item_iterator != m_MenuItemVector.end(); item_iterator++, i++) { int MenuY = GetBaseY(); int py = (*item_iterator)->GetBaseY() - MenuY; int height = (*item_iterator)->GetBaseHeight(); if ((y >= py) && (y < py + height)) { m_HighlightedItem = i; QueueDraw(); break; } } } else { if (m_HighlightedItem != -1) { m_HighlightedItem = -1; QueueDraw(); } } if (m_HighlightedItem >= 0) { MenuItem *selected_action = m_MenuItemVector[m_HighlightedItem]; if ((selected_action->GetChildMenu() != 0) && selected_action->GetActionItem()->isEnabled()) { // This MenuItem has a sub-MenuPage. Start it. Geometry geo = selected_action->GetGeometry(); selected_action->GetChildMenu()->m_MenuWindow = selected_action->GetChildMenu()->GetParentMenu()->m_MenuWindow; selected_action->GetChildMenu()->StartMenu(geo.x + geo.GetWidth() - 5, geo.y, 0, 0); // The current SubMenu is not the same as the new one... if (m_SubMenuAction != selected_action) { // If m_SubMenuAction is not null then stop the sub menu StopActionSubMenu(); // Set the Action that holds the SubMenu. m_SubMenuAction = selected_action; } } else { StopActionSubMenu(); } } } void MenuPage::EmitMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags) { m_NextMouseUpMeanStop = true; EmitMouseMove(x, y, 0, 0, button_flags, key_flags); } void MenuPage::EmitMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags) { if (m_NextMouseUpMeanStop == false) { m_NextMouseUpMeanStop = true; return; } m_Action_Triggered = false; bool hit_inside_a_menu = false; if (m_SubMenuAction) { m_Action_Triggered = m_SubMenuAction->GetChildMenu()->TestMouseUp(x, y, button_flags, key_flags, hit_inside_a_menu); } if (m_Action_Triggered == false) { if (IsMouseInside()) { if (m_SubMenuAction) { m_Action_Triggered = false; } else if (m_HighlightedItem != -1) { if (m_MenuItemVector[m_HighlightedItem]->GetActionItem()->isEnabled() == false) { // Do nothing. We don't want to close the menu when we release the mouse over an action that is not Enabled. m_Action_Triggered = false; } else { m_Action_Triggered = true; // Fire the Action Here ExecuteActionItem(m_MenuItemVector[m_HighlightedItem]); NotifyActionTriggeredToParent(this, m_MenuItemVector[m_HighlightedItem]); } } } else { // Bellow the Mouse, there was no MenuPage when the MouseUp happened. if (hit_inside_a_menu == false) { // Terminate the MenuPage cascade NotifyTerminateMenuCascade(); } } } } bool MenuPage::TestMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags, bool &hit_inside_a_menu) { m_Action_Triggered = false; if (m_SubMenuAction) { m_Action_Triggered = m_SubMenuAction->GetChildMenu()->TestMouseUp(x, y, button_flags, key_flags, hit_inside_a_menu); } if (m_Action_Triggered == false) { if (IsMouseInside()) { hit_inside_a_menu = true; if (m_SubMenuAction) { m_Action_Triggered = false; // Do nothing. We don't want to close the menu when we are above an action that has a submenu. } else if (m_HighlightedItem != -1) { if (m_MenuItemVector[m_HighlightedItem]->GetActionItem()->isEnabled() == false) { // Do nothing. We don't want to close the menu when we release the mouse over an action that is not Enabled. m_Action_Triggered = false; } else { m_Action_Triggered = true; // Fire the Action Here ExecuteActionItem(m_MenuItemVector[m_HighlightedItem]); NotifyActionTriggeredToParent(this, m_MenuItemVector[m_HighlightedItem]); // But Do not emit the Stop //sigPopupStop.emit(); } } } } if (m_Action_Triggered) return true; return false; } bool MenuPage::TestMouseDown() { bool b = false; if (m_SubMenuAction) { b = m_SubMenuAction->GetChildMenu()->TestMouseDown(); } if (b) { return true; } else { return IsMouseInside(); } } void MenuPage::EmitMouseDrag(int x, int y, int /* dx */, int /* dy */, unsigned long button_flags, unsigned long key_flags) { if (IsMouseInside()) EmitMouseMove(x, y, 0, 0, button_flags, key_flags); } void MenuPage::RecvMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { // Cancel selected item when the mouse is out. if (m_HighlightedItem != -1) { MenuItem *item = m_MenuItemVector[m_HighlightedItem]; if (item->GetChildMenu()) { if (!item->GetChildMenu()->IsActive()) { m_HighlightedItem = -1; } } else { m_HighlightedItem = -1; } } QueueDraw(); } void MenuPage::StartMenu(int MenuXPosition, int MenuYPosition, int /* x*/, int /* y */, bool /* OverrideCurrentMenuChain */) { Geometry base = GetGeometry(); base.SetX(MenuXPosition); base.SetY(MenuYPosition); int WindowWidth = GetWindowThread()->GetGraphicsEngine().GetWindowWidth(); int WindowHeight = GetWindowThread()->GetGraphicsEngine().GetWindowHeight(); // Correct the position of the MenuPage if is going out of the screen // The first page of a menu chain has less opportunities to be adjusted than its child pages. // The first page of a menu chain has(GetParentMenu() == 0) return true. int MenuLeft = base.x + base.GetWidth() + 5; if (MenuLeft > WindowWidth) { base.OffsetPosition(WindowWidth - MenuLeft, 0); } int MenuRight = base.x; if ((MenuRight < 0) && (GetParentMenu() != 0)) { base.OffsetPosition(-MenuRight, 0); } int MenuBottom = base.y + base.GetHeight() + 5; if ((MenuBottom > WindowHeight) && (GetParentMenu() != 0)) { base.OffsetPosition(0, WindowHeight - MenuBottom); } int MenuTop = base.y - 5; if ((MenuTop < 0) && (GetParentMenu() != 0)) { base.OffsetPosition(0, -MenuTop); } SetGeometry(base); SetActive(true); // Add the menu to the stack manager popup list. if (GetParentMenu() == 0) { // This is the head of the menu chain m_MenuWindow = GetWindowThread()->GetWindowCompositor().GetProcessingTopView(); } GetWindowThread()->GetWindowCompositor().AddMenu(this, m_MenuWindow/*, OverrideCurrentMenuChain*/); m_NextMouseUpMeanStop = false; StopActionSubMenu(); } void MenuPage::StopMenu(int /* x */, int /* y */) { SetActive(false); // The Stack Manager will remove all popup that are not visible anymore m_NextMouseUpMeanStop = false; m_HighlightedItem = -1; StopActionSubMenu(); // The MenuPage does not need to be redrawn, but in embedded mode, this triggers a dirty Area on // the BaseWindow and it informs the system to update this egion of the screen // (where the menu is about to disappear). QueueDraw(); /*Area *top_area = GetWindowThread()->GetWindowCompositor().GetProcessingTopView(); if (top_area) { if (top_area->IsView()) { NUX_STATIC_CAST(View*, top_area)->QueueDraw(); } if (top_area->IsLayout()) { NUX_STATIC_CAST(Layout*, top_area)->QueueDraw(); } }*/ } // Never call this function directly void MenuPage::Terminate(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { } void MenuPage::StopActionSubMenu() { if (m_SubMenuAction) { if (m_SubMenuAction->GetChildMenu()) { m_SubMenuAction->GetChildMenu()->StopMenu(0, 0); } } m_SubMenuAction = 0; } void MenuPage::ExecuteActionItem(MenuItem *menuItem) { menuItem->GetActionItem()->Trigger(); } void MenuPage::NotifyActionTriggeredToParent(MenuPage *menu, MenuItem *menuItem) { if (m_Parent) { m_Parent->NotifyActionTriggeredToParent(menu, menuItem); } else { sigActionTriggered.emit(menu, menuItem->GetActionItem()); } StopMenu(); } void MenuPage::NotifyTerminateMenuCascade() { if (m_Parent) { m_Parent->NotifyTerminateMenuCascade(); } else { sigTerminateMenuCascade.emit(); } // if (IsActive()) // { // StopMenu(); // } } void MenuPage::NotifyMouseDownOutsideMenuCascade(int x, int y) { if (m_Parent) { m_Parent->NotifyMouseDownOutsideMenuCascade(x, y); } else { // This is the top MenuPage in a menu chain. // If this MenuPage has been registered with a MenuBar, then the MenuBar will intercept this signal // and terminate the menu chain. sigMouseDownOutsideMenuCascade.emit(this, x, y); // It is also possible that this MenuPage is not associated to a MenuBar(called directly for a contextual menu) if (m_IsTopOfMenuChain == false) { // This MenuPage is not attached to a MenuBar if (IsActive()) { //StopMenu(); } } } } void MenuPage::SetParentMenu(MenuPage *parent) { m_Parent = parent; } MenuPage *MenuPage::GetParentMenu() { return m_Parent; } long MenuPage::ComputeContentSize() { return View::ComputeContentSize(); } void MenuPage::SetGeometry(const Geometry &geo) { // The MenuPage widget cannot be resized by the client. The menu widget controls its own size. Geometry base = GetGeometry(); // We are only interested in the position X/Y. The popup figures out its width and height by itself. base.SetX(geo.x); base.SetY(geo.y); base.SetWidth(geo.GetWidth()); base.SetHeight(m_numItem * PRACTICAL_WIDGET_HEIGHT); SetBaseXY(geo.x, geo.y); ComputeContentPosition(0, 0); } ActionItem *MenuPage::GetActionItem(int index) const { nuxAssert(index >= 0); if (index >= (int) m_MenuItemVector.size()) return 0; return m_MenuItemVector[index]->GetActionItem(); } int MenuPage::GetActionItemIndex(ActionItem *action) const { if (action == 0) return -1; for (int i = 0; i < (int) m_MenuItemVector.size(); i++) { if (action == m_MenuItemVector[i]->GetActionItem()) { return i; } } return -1; } Geometry MenuPage::GetAbsoluteGeometry() const { return GetGeometry(); } Geometry MenuPage::GetRootGeometry() const { return GetGeometry(); } void MenuPage::SetOnClosureContinueEventCycle(bool on_closure_continue_with_event) { on_closure_continue_with_event_ = on_closure_continue_with_event; } bool MenuPage::OnClosureContinueEventCycle() const { return on_closure_continue_with_event_; } } nux-4.0.8+18.10.20180623/Nux/MenuPage.h0000644000000000000000000002521013313373365013225 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MENUPAGE_H #define MENUPAGE_H #include "ActionItem.h" #include "FloatingWindow.h" namespace nux { class StaticText; class MenuPage; class VLayout; class MenuBar; class MenuItem: public View { NUX_DECLARE_OBJECT_TYPE(MenuItem, View); public: MenuItem(const char *label, int UserValue, NUX_FILE_LINE_PROTO); ~MenuItem(); void DrawAsMenuItem(GraphicsEngine &graphics_engine, const Color &textcolor, bool is_highlighted, bool isFirstItem, bool isLastItem, bool draw_icone); //const ActionItem& GetItem() const {return m_ActionItem;} ActionItem *GetActionItem() const; //ActionItem* GetActionItem(); int GetTextWidth(); int GetTextHeight(); StaticText * GetStaticText() { return _pango_static_text; } private: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) {}; void SetChildMenu(MenuPage *menu); MenuPage *GetChildMenu() const; void SetActionItem(ActionItem *menu); MenuPage *_child_menu; ActionItem *_action_item; StaticText *_pango_static_text; friend class MenuPage; }; class MenuSeparator: public View { NUX_DECLARE_OBJECT_TYPE(MenuSeparator, View); public: MenuSeparator(NUX_FILE_LINE_PROTO); ~MenuSeparator(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) {}; private: friend class MenuPage; }; class MenuPage: public View { NUX_DECLARE_OBJECT_TYPE(MenuPage, View); public: MenuPage(const char *title = "", NUX_FILE_LINE_PROTO); ~MenuPage(); // void SetName(const char* name); const char *GetName() const; ActionItem *AddAction(const char *label = 0, int UserValue = 0); //void AddActionItem(ActionItem* actionItem); void AddSeparator(); MenuPage *AddMenu(const char *label); ActionItem *AddSubMenu(const char *label, MenuPage *menu); void RemoveItem(ActionItem *item); void RemoveAllItem(); bool CanClose() const; // emitters void EmitMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void EmitMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void EmitMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void EmitMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); //private: //! Start the MenuPage iteration and show it. /* Start the MenuPage iteration and show it. When this function is called, the menu becomes visible and appear at position(MenuXPosition, MenuYPosition). The menu also assumes it has received a mouse down event at coordinates(x, y). \param MenuXPosition: the position of the menu. \param MenuYPosition: the position of the menu. \param x: the simulate position where the mouse down happened on the menu area. \param y: the simulate position where the mouse down happened on the menu area. \param TakeMousefocus: if true, the MenuPage area will take the mouse focus. */ void StartMenu(int MenuXPosition, int MenuYPosition, int x = 0, int y = 0, bool OverrideCurrentMenuChain = true); //! Stop the MenuPage iteration and hide it. /* Stop the MenuPage iteration and hide it. \param x: the simulate position where the mouse down happened on the menu area. \param y: the simulate position where the mouse down happened on the menu area. */ void StopMenu(int x = 0, int y = 0); void SetFontName(char *font_name); //! Let regular widgets process a mouse down event that closes the menu chain without a menu item selection. /*! When a menu chain closes as a result of a mouse down event outside of the menu chain, there is still the possibility to let regular widgets process the event. The flag is tested on the top level MenuPage of the menu chain. @param propagate_when_closing_without_action Set to True to propagate the event to regular widgets if the menu chain closes as a result of a mouse down event outside the menu chain. */ void SetOnClosureContinueEventCycle(bool on_closure_continue_with_event); //! Returns True if a mouse down that closes the menu chain can be processed by regular widgets. /*! When a menu chain closes as a result of a mouse down event outside of the menu chain, there is still the possibility to let regular widgets process the event. The flag is tested on the top level MenuPage of the menu chain. @return True is a mouse down event that closes a menu chain without an item selection, can be passed down the event cycle. */ bool OnClosureContinueEventCycle() const; public: void StopActionSubMenu(); void ExecuteActionItem(MenuItem *menuItem); void NotifyActionTriggeredToParent(MenuPage *, MenuItem *menuItem); void NotifyTerminateMenuCascade(); void NotifyMouseDownOutsideMenuCascade(int x, int y); void SetParentMenu(MenuPage *); MenuPage *GetParentMenu(); void setShowItemIcon(bool b) { m_show_item_icon = b; } bool ShowItemIcon() { return m_show_item_icon; } bool TestMouseDown(); bool TestMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags, bool &hit_inside_a_menu); // Never call this function directly void Terminate(int x, int y, unsigned long button_flags, unsigned long key_flags); // signals sigc::signal sigItemSelected; //! Send an action Signal. /* The MenuPage object sends this signal when an action is triggered. \param MenuPage the menu object sending the signal. \param ActionItem the action object that was triggered in the menu. */ sigc::signal sigActionTriggered; //! Terminate the menu and its sub menu cascade. /* The MenuPage object send this signal to inform that it needs to be close. The receiving object must close the MenuPage by calling the member function StopMenu(). Any object that controls a menu should intercept sigTerminateMenuCascade and sigMouseDownOutsideMenuCascade. */ sigc::signal sigTerminateMenuCascade; //! Notify that a mouse down event happened outside the menu cascade. /* Notify that a mouse down event happened outside the menu cascade. This event is processed by the MenuPage bar. The menu bar checks if the mouse down happened on one of its menu bar item. If yes, it let the menu bar item process the event. if no, it will initiate the closure of the menu cascade. Any object that controls a menu should intercept sigTerminateMenuCascade and sigMouseDownOutsideMenuCascade. */ sigc::signal sigMouseDownOutsideMenuCascade; sigc::signal sigOpeningMenu; sigc::signal sigClosingMenu; void SetActive(bool b) { m_IsActive = b; if (b) /*m_PopupArea.*/CaptureMouseDownAnyWhereElse(true); else /*m_PopupArea.*/CaptureMouseDownAnyWhereElse(false); } bool IsActive() const { return m_IsActive; } /*! Return the number of items in the menu. */ int GetNumItem() const { return m_numItem; } ActionItem *GetActionItem(int i) const; /*! Get the index of and item in the menu. @return the index of the ActionItem in the menu. -1 if the Action Item is not found. */ int GetActionItemIndex(ActionItem *action) const; //! Return the position of this object with regard to its top left corner of the physical window. /*! Return the position of the Area inside the physical window. For the main layout set in WindowThread, The following functions are equivalent: \li GetGeometry() \li GetRootGeometry() \li GetAbsoluteGeometry() */ virtual Geometry GetAbsoluteGeometry() const; //! Return the position of this object with regard to its top level parent(the main layout or a BaseWindow). /*! Return the position of the Area inside the physical window. For the main layout set in WindowThread or for a BaseWindow, GetRootGeometry() is equivalent to GetGeometry(). */ virtual Geometry GetRootGeometry() const; protected: virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); private: bool on_closure_continue_with_event_; int m_numItem; int m_HighlightedItem; bool m_IsActive; VLayout* _vlayout; bool m_NextMouseUpMeanStop; MenuItem *m_SubMenuAction; std::string m_Name; bool m_Action_Triggered; MenuPage *m_Parent; // Set to TRUE if one of the MenuItem processed the mouse event. bool m_MouseEventProcessed; int m_item_width; int m_item_height; bool m_show_item_icon; std::vector m_MenuItemVector; std::vector< MenuSeparator * > m_MenuSeparatorVector; BaseWindow *m_MenuWindow; //! This parameter is True if this MenuPage is at the top of a menu chain attached to a MenuBar. bool m_IsTopOfMenuChain; char *_font_name; public: /////////////////////////////////////////////////////// // AbstractInterfaceObject /////////////////////////////////////////////////////// virtual long ComputeContentSize(); virtual void SetGeometry(const Geometry &geo); friend class MenuBar; friend class WindowCompositor; }; } #endif // MENUPAGE_H nux-4.0.8+18.10.20180623/Nux/MouseAreaCtrl.cpp0000644000000000000000000000553613313373365014576 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "MouseAreaCtrl.h" namespace nux { MouseAreaCtrl::MouseAreaCtrl(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { // Set Original State m_vlayout = new VLayout(NUX_TRACKER_LOCATION); m_Area = new BasicView(NUX_TRACKER_LOCATION); // Set Signals m_Area->mouse_down.connect(sigc::mem_fun(this, &MouseAreaCtrl::MouseDown)); m_Area->mouse_up.connect(sigc::mem_fun(this, &MouseAreaCtrl::MouseUp)); m_Area->mouse_drag.connect(sigc::mem_fun(this, &MouseAreaCtrl::MouseDrag)); // Set Geometry m_Area->SetMinimumSize(100, 100); m_Area->SetGeometry(Geometry(0, 0, 200, 400)); m_vlayout->AddView(m_Area, 1); m_vlayout->SetVerticalExternalMargin(6); m_vlayout->SetHorizontalExternalMargin(6); SetCompositionLayout(m_vlayout); } MouseAreaCtrl::~MouseAreaCtrl() { } void MouseAreaCtrl::Draw(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BACKGROUND_SECONDARY), eSHAPE_CORNER_ROUND10); sigDraw.emit(force_draw); } void MouseAreaCtrl::DrawContent(GraphicsEngine & /* graphics_engine */, bool force_draw) { sigDraw.emit(force_draw); } int MouseAreaCtrl::getAreaPosX() { return m_Area->GetBaseX(); } int MouseAreaCtrl::getAreaPosY() { return m_Area->GetBaseY(); } int MouseAreaCtrl::getAreaWidth() { return m_Area->GetBaseWidth(); } int MouseAreaCtrl::getAreaHeight() { return m_Area->GetBaseHeight(); } ///////////////// // EMITERS // ///////////////// void MouseAreaCtrl::MouseDown(int x, int y, unsigned long button_flags, unsigned long /* key_flags */) { sigMouseDown.emit(x, y, button_flags); } void MouseAreaCtrl::MouseUp(int x, int y, unsigned long button_flags, unsigned long /* key_flags */) { sigMouseUp.emit(x, y, button_flags); } void MouseAreaCtrl::MouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long /* key_flags */) { sigMouseDrag.emit(x, y, dx, dy, button_flags); } } nux-4.0.8+18.10.20180623/Nux/MouseAreaCtrl.h0000644000000000000000000000422713313373365014237 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MOUSEAREACTRL_H #define MOUSEAREACTRL_H #include "EditTextBox.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" namespace nux { //replace MouseAreaCtrl with GfxViewCtrl class MouseAreaCtrl: public View { public: MouseAreaCtrl(NUX_FILE_LINE_PROTO); ~MouseAreaCtrl(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); int getAreaPosY(); int getAreaPosX(); int getAreaWidth(); int getAreaHeight(); ///////////////// // EMITERS // ///////////////// void MouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void MouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void MouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); ///////////////// // SIGNALS // ///////////////// sigc::signal sigMouseDown; sigc::signal sigMouseUp; sigc::signal sigMouseDrag; sigc::signal sigDraw; private: VLayout *m_vlayout; BasicView *m_Area; public: virtual void SetGeometry(const Geometry &geo) { Area::SetGeometry(geo); ComputeContentSize(); } }; } #endif // MOUSEAREACTRL_H nux-4.0.8+18.10.20180623/Nux/NumericValuator.cpp0000644000000000000000000001120613313373365015177 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "HLayout.h" #include "EditTextBox.h" #include "DoubleValidator.h" #include "NumericValuator.h" #include namespace nux { const int BTN_WIDTH = 14; const int BTN_HEIGHT = 14; NumericValuator::NumericValuator() : m_DoubleValidator(0.0, 100.0) , m_Step(0.1f) { InitializeLayout(); InitializeWidgets(); } NumericValuator::~NumericValuator() { } void NumericValuator::InitializeWidgets() { m_EditLine->SetValidator(&m_DoubleValidator); m_EditLine->SetText(std::to_string((long double)m_DoubleValidator.GetMinimum())); m_EditLine->SetMinimumSize(2 * DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); m_EditLine->SetGeometry(Geometry(0, 0, 2 * DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT)); m_SpinnerDownBtn->SetMinimumSize(BTN_WIDTH, BTN_HEIGHT); m_SpinnerDownBtn->SetGeometry(Geometry(0, 0, BTN_WIDTH, BTN_HEIGHT)); m_SpinnerUpBtn->SetMinimumSize(BTN_WIDTH, BTN_HEIGHT); m_SpinnerUpBtn->SetGeometry(Geometry(0, 0, BTN_WIDTH, BTN_HEIGHT)); hlayout->AddView(m_SpinnerDownBtn, 0); hlayout->AddView(m_EditLine, 1); hlayout->AddView(m_SpinnerUpBtn, 0); hlayout->SetContentDistribution(eStackLeft); SetCompositionLayout(hlayout); } void NumericValuator::InitializeLayout() { hlayout = new HLayout(NUX_TRACKER_LOCATION); } void NumericValuator::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { GeometryPositioning gp(eHALeft, eVACenter); Geometry GeoPo = ComputeGeometryPositioning(m_SpinnerUpBtn->GetGeometry(), GetTheme().GetImageGeometry(eTRIANGLE_RIGHT), gp); GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eTRIANGLE_RIGHT); GeoPo = ComputeGeometryPositioning(m_SpinnerDownBtn->GetGeometry(), GetTheme().GetImageGeometry(eTRIANGLE_LEFT), gp); GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eTRIANGLE_LEFT); m_EditLine->QueueDraw(); } void NumericValuator::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { m_EditLine->ProcessDraw(graphics_engine, force_draw); } void NumericValuator::SetValue(float value) { m_fValue = value; if (m_fValue < m_DoubleValidator.GetMinimum()) m_fValue = m_DoubleValidator.GetMinimum(); if (m_fValue > m_DoubleValidator.GetMaximum()) m_fValue = m_DoubleValidator.GetMaximum(); m_EditLine->SetText(std::to_string((long double)m_fValue)); } float NumericValuator::GetValue() const { return m_fValue; } void NumericValuator::SetStep(float f) { m_Step = f; } float NumericValuator::GetStep() { return m_Step; } void NumericValuator::ImplementIncrementBtn() { SetValue(m_fValue + m_Step); sigIncrement.emit(); sigValueChanged.emit(m_fValue); if (m_fValue < m_DoubleValidator.GetMaximum()) { m_UpTimerHandler = GetTimer().AddOneShotTimer(100, m_UpTimerCallback, 0); QueueDraw(); } } void NumericValuator::ImplementDecrementBtn() { SetValue(m_fValue - m_Step); sigDecrement.emit(); sigValueChanged.emit(m_fValue); if (m_fValue > m_DoubleValidator.GetMinimum()) { m_DownTimerHandler = GetTimer().AddOneShotTimer(100, m_DownTimerCallback, 0); QueueDraw(); } } void NumericValuator::ImplementValidateEntry() { double ret = 0; ret = CharToDouble(m_EditLine->GetCleanText().c_str()); { m_fValue = ret; if (m_fValue < m_DoubleValidator.GetMinimum()) { m_fValue = m_DoubleValidator.GetMinimum(); m_EditLine->SetText(std::to_string((long double)m_fValue)); } if (m_fValue > m_DoubleValidator.GetMaximum()) { m_fValue = m_DoubleValidator.GetMaximum(); m_EditLine->SetText(std::to_string((long double)m_fValue)); } } // else // { // m_EditLine->SetText(std::string::Printf("%f", m_fValue)); // } } } nux-4.0.8+18.10.20180623/Nux/NumericValuator.h0000644000000000000000000000336113313373365014647 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUMERICVALUATOR_H #define NUMERICVALUATOR_H #include "SpinBox_Logic.h" namespace nux { class HLayout; class EditTextBox; class NumericValuator : public SpinBox_Logic { public: NumericValuator(); ~NumericValuator(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual void ImplementIncrementBtn(); virtual void ImplementDecrementBtn(); virtual void ImplementValidateEntry(); void SetValue(float value); float GetValue() const; void SetStep(float f); float GetStep(); sigc::signal sigIncrement; sigc::signal sigDecrement; sigc::signal sigValueChanged; protected: void InitializeWidgets(); void InitializeLayout(); private: HLayout *hlayout; DoubleValidator m_DoubleValidator; float m_fValue; float m_Step; }; } #endif // NUMERICVALUATOR_H nux-4.0.8+18.10.20180623/Nux/Nux.cpp0000644000000000000000000002620013313373365012631 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/NuxGraphics.h" namespace nux { static NCriticalSection ThreadArrayLock; std::vector ThreadArray; void NuxInitialize(const char * /* CommandLine */) { nux::NuxCoreInitialize(0); nux::NuxGraphicsInitialize(); // Register a thread local store for the WindowThreads. Each window thread will be able to access its own WindowThread pointer. inlRegisterThreadLocalIndex(0, ThreadLocal_InalogicAppImpl, NULL); } static WindowThread *_CreateModalWindowThread(const char *window_title, int width, int height, WindowThread *parent, ThreadUserInitFunc /* user_init_func */, void * /* data */, bool Modal) { // check that Parent exist WindowThread *w = new WindowThread(window_title, width, height, parent, Modal); if (w == 0) { nuxDebugMsg("[_CreateModalWindowThread] WindowThread creation failed."); return NULL; } return w; } WindowThread *CreateGUIThread(const char *window_title, int width, int height, WindowThread *parent, ThreadUserInitFunc user_init_func, void *data) { return CreateNuxWindow(window_title, width, height, WINDOWSTYLE_NORMAL, parent, false, user_init_func, data); } WindowThread *CreateNuxWindow(const char *window_title, int width, int height, WindowStyle window_border_style, AbstractThread *parent, bool modal, ThreadUserInitFunc user_init_func, void *data) { if (GetWindowThread()) { // An WindowThread already exist for this thread. nuxDebugMsg("[CreateGUIThread] You may have only one Nux window per system thread."); return NULL; } modal = (modal && parent && parent->Type().IsObjectType(WindowThread::StaticObjectType)); if (width <= WindowThread::MINIMUM_WINDOW_WIDTH) { width = WindowThread::MINIMUM_WINDOW_WIDTH; } if (height <= WindowThread::MINIMUM_WINDOW_HEIGHT) { height = WindowThread::MINIMUM_WINDOW_HEIGHT; } WindowThread *w = new WindowThread(window_title, width, height, parent, modal); if (w == NULL) { nuxDebugMsg("[CreateGUIThread] WindowThread creation failed."); return NULL; } w->user_init_func_ = user_init_func; w->user_exit_func_ = 0; w->initialization_data_ = data; w->window_style_ = window_border_style; w->ThreadCtor(); return w; } WindowThread *CreateNuxWindowNewThread(const char *window_title, int width, int height, WindowStyle window_border_style, AbstractThread *parent, bool modal, ThreadUserInitFunc user_init_func, void *data) { modal = (modal && parent && parent->Type().IsObjectType(WindowThread::StaticObjectType)); if (width <= WindowThread::MINIMUM_WINDOW_WIDTH) { width = WindowThread::MINIMUM_WINDOW_WIDTH; } if (height <= WindowThread::MINIMUM_WINDOW_HEIGHT) { height = WindowThread::MINIMUM_WINDOW_HEIGHT; } WindowThread *w = new WindowThread(window_title, width, height, parent, modal); if (w == NULL) { nuxDebugMsg("[CreateNuxWindowNewThread] WindowThread creation failed."); return NULL; } w->user_init_func_ = user_init_func; w->user_exit_func_ = 0; w->initialization_data_ = data; w->window_style_ = window_border_style; // Do not call WindowThread::ThreadCtor(); return w; } #if defined(NUX_OS_WINDOWS) WindowThread* CreateFromForeignWindow(HWND WindowHandle, HDC WindowDCHandle, HGLRC OpenGLRenderingContext, ThreadUserInitFunc user_init_func, void *data) { if (GetWindowThread()) { // An WindowThread already exist for this thread. nuxDebugMsg("[CreateGUIThread] You may have only one Nux window per system thread."); return NULL; } WindowThread *w = new WindowThread("WindowTitle", 400, 300, 0, true); if (w == 0) { nuxDebugMsg("[CreateGUIThread] WindowThread creation failed."); return NULL; } w->user_init_func_ = user_init_func; w->user_exit_func_ = 0; w->initialization_data_ = data; w->window_style_ = WINDOWSTYLE_NORMAL; w->embedded_window_ = true; w->ThreadCtor(WindowHandle, WindowDCHandle, OpenGLRenderingContext); return w; } #elif defined(NO_X11) #elif defined(NUX_OS_LINUX) #ifdef NUX_OPENGLES_20 WindowThread *CreateFromForeignWindow (Window X11Window, EGLContext OpenGLContext, ThreadUserInitFunc user_init_func, void *data) #else WindowThread *CreateFromForeignWindow (Window X11Window, GLXContext OpenGLContext, ThreadUserInitFunc user_init_func, void *data) #endif { if (GetWindowThread()) { // An WindowThread already exist for this thread. nuxDebugMsg("[CreateGUIThread] You may have only one Nux window per system thread."); return 0; } WindowThread *w = new WindowThread("WindowTitle", 400, 300, 0, true); if (w == 0) { nuxDebugMsg("[CreateGUIThread] WindowThread creation failed."); return NULL; } w->user_init_func_ = user_init_func; w->user_exit_func_ = 0; w->initialization_data_ = data; w->window_style_ = WINDOWSTYLE_NORMAL; w->embedded_window_ = true; w->ThreadCtor(NULL, X11Window, OpenGLContext); return w; } #endif // Create a window thread that is a child of the Parent. This thread has a window. WindowThread *CreateWindowThread(WindowStyle WndStyle, const char *window_title, int width, int height, WindowThread *parent, ThreadUserInitFunc user_init_func, void *data) { if (width <= WindowThread::MINIMUM_WINDOW_WIDTH) { width = WindowThread::MINIMUM_WINDOW_WIDTH; } if (height <= WindowThread::MINIMUM_WINDOW_HEIGHT) { height = WindowThread::MINIMUM_WINDOW_HEIGHT; } WindowThread *w = _CreateModalWindowThread(window_title, width, height, parent, user_init_func, data, false); if (w == 0) { nuxDebugMsg("[CreateWindowThread] WindowThread creation failed."); return NULL; } w->user_init_func_ = user_init_func; w->user_exit_func_ = 0; w->initialization_data_ = data; w->window_style_ = WndStyle; return w; } // Create modal graphics thread that is a child of the Parent. This thread has a window. WindowThread *CreateModalWindowThread(WindowStyle WndStyle, const char *window_title, int width, int height, WindowThread *parent, ThreadUserInitFunc user_init_func, void *data) { if (width <= WindowThread::MINIMUM_WINDOW_WIDTH) { width = WindowThread::MINIMUM_WINDOW_WIDTH; } if (height <= WindowThread::MINIMUM_WINDOW_HEIGHT) { height = WindowThread::MINIMUM_WINDOW_HEIGHT; } WindowThread *w = _CreateModalWindowThread(window_title, width, height, parent, user_init_func, data, true); if (w == 0) { nuxDebugMsg("[CreateWindowThread] WindowThread creation failed."); return NULL; } w->user_init_func_ = user_init_func; w->user_exit_func_ = 0; w->initialization_data_ = data; w->window_style_ = WndStyle; return w; } SystemThread *CreateSystemThread(AbstractThread *parent, ThreadUserInitFunc user_init_func, void *data) { SystemThread *system_thread = new SystemThread(parent); if (system_thread == 0) { nuxDebugMsg("[CreateSimpleThread] SystemThread creation failed."); return NULL; } system_thread->user_init_func_ = user_init_func; system_thread->user_exit_func_ = 0; system_thread->initialization_data_ = data; return system_thread; } bool RegisterNuxThread(NThread *ThreadPtr) { nuxAssert(ThreadPtr); NUX_RETURN_VALUE_IF_NULL(ThreadPtr, false); NScopeLock Scope(&ThreadArrayLock); std::vector::iterator it = find(ThreadArray.begin(), ThreadArray.end(), ThreadPtr); if (it == ThreadArray.end()) { ThreadArray.push_back(ThreadPtr); } return true; } void UnregisterNuxThread(NThread *ThreadPtr) { nuxAssert(ThreadPtr); NUX_RETURN_IF_NULL(ThreadPtr); NScopeLock Scope(&ThreadArrayLock); std::vector::iterator it = find(ThreadArray.begin(), ThreadArray.end(), ThreadPtr); if (it != ThreadArray.end()) { ThreadArray.erase(it); } } ObjectPtr GetSysFont() { return GetWindowThread()->GetGraphicsEngine().GetFont(); } ObjectPtr GetSysBoldFont() { return GetWindowThread()->GetGraphicsEngine().GetBoldFont(); } WindowCompositor &GetWindowCompositor() { NThread *thread = GetWindowThread(); if (thread && !thread->Type().IsObjectType(WindowThread::StaticObjectType)) { nuxDebugMsg("[GetWindowCompositor] You can't call GetWindowCompositor on this type of thread: s", thread->Type().name ); PrintOutputDebugString("[GetWindowCompositor] You can't call GetWindowCompositor on this type of thread: s", thread->Type().name ); NUX_HARDWARE_BREAK; } return (static_cast (thread))->GetWindowCompositor(); } WindowThread *GetWindowThread() { return GetThreadNuxWindow(); } WindowThread *GetThreadNuxWindow() { NThread *thread = static_cast (inlGetThreadLocalStorage(ThreadLocal_InalogicAppImpl)); return NUX_STATIC_CAST(WindowThread *, thread); } BasePainter& GetPainter() { NThread *thread = GetWindowThread(); return NUX_STATIC_CAST(WindowThread *, thread)->GetPainter(); } UXTheme& GetTheme() { NThread *thread = GetWindowThread(); return NUX_STATIC_CAST(WindowThread *, thread)->GetTheme(); } TimerHandler& GetTimer() { NThread *thread = GetWindowThread(); return NUX_STATIC_CAST(WindowThread *, thread)->GetTimerHandler(); } } nux-4.0.8+18.10.20180623/Nux/Nux.h0000644000000000000000000002276013313373365012305 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUX_H #define NUX_H #include "NuxCore/NuxCore.h" #include "NuxCore/Error.h" #include "NuxCore/FilePath.h" #include "NuxCore/Color.h" #include "NuxCore/Rect.h" #include "NuxCore/Point.h" #include "NuxCore/Size.h" #include "NuxCore/ObjectPtr.h" #include "NuxCore/Math/Constants.h" #include "NuxCore/Math/Vector3.h" #include "NuxCore/Math/Vector4.h" #include "NuxCore/Math/Matrix3.h" #include "NuxCore/Math/Matrix4.h" #include "NuxCore/Math/Spline.h" #include #include #include #include #include #include #include #if defined(NUX_OS_LINUX) #include "Nux/Features.h" #endif #include "Utils.h" #include "WidgetMetrics.h" #include "Area.h" #include "InputArea.h" #include "Theme.h" #include "Painter.h" #include "View.h" #include "BasicView.h" #include "AbstractThread.h" #include "WindowThread.h" #include "WindowCompositor.h" #if !defined(NUX_MINIMAL) # include "Timeline.h" #endif #include "SystemThread.h" namespace nux { class WindowThread; class SystemThread; class WindowCompositor; class TimerHandler; void NuxInitialize(const char *CommandLine); //! Create a Nux window. /*! Create a Nux window. The window @param window_title The window title. @param width The window width. @param height The window height. @param parent The window height parent. Should be NULL. @param user_init_func Initialization function to be called before starting the window loop. @param data Parameter to the initialization function. */ WindowThread *CreateGUIThread(const char *window_title, int width, int height, WindowThread *parent = NULL, ThreadUserInitFunc user_init_func = NULL, void *data = NULL); //! Create the only Nux window for the current system thread. /*! There can be only one NuxWindow per system thread. This function creates the only Nux window allowed in the current thread. \n The first time this function is called in the current system thread, it returns a valid pointer to a NuxWindow object. The next time it is called, the system detects that a NuxWindow has already been created in the thread and it returns NULL. \n When CreateNuxWindow successfully returns, the NuxWindow internals (GraphicsDisplay, Compositor, Painter, TimerManager) have been initialized. Calling nux::GetThreadNuxWindow() returns a pointer to the NuxWindow that has been successfully created in the current thread. \n To start the main loop of a NuxWindow created with CreateNuxWindow, call NuxWindow::Run(); \n The modal parameter specifies if the window is blocking while it is active. This is valid only if the parent thread is a WindowThread. @param window_title The window title. @param width The window width. @param height The window height. @param window_border_style The window border style. @param parent The window parent. @param modal Modality of the window. @param user_init_func Initialization function to be called before starting the window loop. @param data Parameter to the initialization function. @return A valid pointer to a NuxWindow if the window has been successfully created. NULL otherwise. */ WindowThread *CreateNuxWindow(const char *window_title, int width, int height, WindowStyle window_border_style = WINDOWSTYLE_NORMAL, AbstractThread *parent = NULL, bool modal = false, ThreadUserInitFunc user_init_func = NULL, void *data = NULL); //! Create a Nux window to be run in a new thread. /*! Create a Nux window that will run in a new thread. Unlike CreateNuxWindow, CreateNuxWindowNewThread should always successfully return a valid NuxWindow pointer. However, the internal objects of the NuxWindow (GraphicsDisplay, Compositor, Painter, TimerManager) have not been initialized yet. So, calling NuxWindow::GetWindowCompositor(), NuxWindow::GetGraphicsDisplay() will fail. \n To start the main loop of a NuxWindow created with CreateNuxWindow, call NuxWindow::Run(); \n The modal parameter specifies if the window is blocking its parent window while it is active. This is valid only if the parent thread is a WindowThread. @param window_title The window title. @param width The window width. @param height The window height. @param window_border_style The window border style. @param parent The window parent. @param modal Modality of the window. @param user_init_func Initialization function to be called before starting the window loop. @param data Parameter to the initialization function. @return A valid pointer to a NuxWindow if the window has been successfully created. NULL otherwise. */ WindowThread *CreateNuxWindowNewThread(const char *window_title, int width, int height, WindowStyle window_border_style = WINDOWSTYLE_NORMAL, AbstractThread *parent = NULL, bool modal = false, ThreadUserInitFunc user_init_func = NULL, void *data = NULL); #if defined(NUX_OS_WINDOWS) //! Create a main graphics thread. This thread has a window and no parent window. WindowThread *CreateFromForeignWindow(HWND WindowHandle, HDC WindowDCHandle, HGLRC OpenGLRenderingContext, ThreadUserInitFunc user_init_func, void *data); #elif defined(NO_X11) #elif defined(NUX_OS_LINUX) //! Create a main graphics thread. This thread has a window and no parent window. #ifdef NUX_OPENGLES_20 WindowThread *CreateFromForeignWindow (Window X11Window, EGLContext OpenGLContext, ThreadUserInitFunc user_init_func, void *data); #else WindowThread *CreateFromForeignWindow (Window X11Window, GLXContext OpenGLContext, ThreadUserInitFunc user_init_func, void *data); #endif #endif // Create a window thread that is a child of the Parent. This thread has a window. /*! @param window_style The window style. @param window_title The window title. @param width The window width. @param height The window height. @param parent The window parent. @param user_init_func Initialization function to be called before starting the window loop. @param data Parameter to the initialization function. */ WindowThread *CreateWindowThread(WindowStyle window_style, const char *window_title, int width, int height, WindowThread *parent, ThreadUserInitFunc user_init_func = NULL, void *data = NULL); // Create a Modal window thread that is a child of the Parent. This thread has a window. /*! @param window_style The window style. @param window_title The window title. @param width The window width. @param height The window height. @param parent The window height parent. Should be NULL. @param user_init_func Initialization function to be called before starting the window loop. @param data Parameter to the initialization function. */ WindowThread *CreateModalWindowThread(WindowStyle window_style, const char *window_title, int width, int height, WindowThread *parent, ThreadUserInitFunc user_init_func = NULL, void *data = NULL); // Create a simple thread SystemThread *CreateSystemThread(AbstractThread *parent = NULL, ThreadUserInitFunc user_init_func = NULL, void *data = NULL); /* ThreadState GetThreadState(unsigned int ThreadID);*/ ObjectPtr GetSysFont(); ObjectPtr GetSysBoldFont(); WindowThread *GetWindowThread(); WindowThread *GetThreadNuxWindow(); WindowCompositor &GetWindowCompositor(); BasePainter &GetPainter(); UXTheme &GetTheme(); TimerHandler &GetTimer(); #define gPainter nux::GetPainter() // deprecated #define gTheme nux::GetTheme() // deprecated inlDeclareThreadLocalStorage(NThread *, 0, ThreadLocal_InalogicAppImpl); } #endif // NUX_H nux-4.0.8+18.10.20180623/Nux/NuxGlobalInitializer.cpp0000644000000000000000000000424113313373365016157 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGlobalInitializer.h" namespace nux { static NuxGlobalSingletonInitializer* GNuxGlobalInitializer = 0; static void SystemStart() { static unsigned char StaticBuffer[sizeof(NuxGlobalSingletonInitializer) ]; // Placement new in our reserved buffer. GNuxGlobalInitializer = new(StaticBuffer) NuxGlobalSingletonInitializer(); //GLogDevice.AddOutputDevice( &NUX_GLOBAL_OBJECT_INSTANCE(NOutputLogFile)); //GLogDevice.AddOutputDevice( &NUX_GLOBAL_OBJECT_INSTANCE(NOutputVisualDebugConsole)); } static void SystemShutdown() { // Manually destroy initializer if (GNuxGlobalInitializer) GNuxGlobalInitializer->~NuxGlobalSingletonInitializer(); GNuxGlobalInitializer = 0; } bool NuxGlobalSingletonInitializer::m_NuxGlobalObjectsReady = false; NuxGlobalSingletonInitializer::NuxGlobalSingletonInitializer() { m_NuxGlobalObjectsReady = true; } NuxGlobalSingletonInitializer::~NuxGlobalSingletonInitializer() { m_NuxGlobalObjectsReady = false; } bool NuxGlobalSingletonInitializer::Ready() { return m_NuxGlobalObjectsReady; } int NuxGlobalInitializer::m_Count = 0; NuxGlobalInitializer::NuxGlobalInitializer() { if (m_Count++ == 0) { SystemStart(); } } NuxGlobalInitializer::~NuxGlobalInitializer() { if (--m_Count == 0) { SystemShutdown(); } } } nux-4.0.8+18.10.20180623/Nux/NuxGlobalInitializer.h0000644000000000000000000000444313313373365015630 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUXGLOBALINITIALIZER_H #define NUXGLOBALINITIALIZER_H #define NUX_NUX_GLOBAL_OBJECT_INIT_SEQUENCE() // // NUX_GLOBAL_OBJECT_VARIABLE(RenderingStats); namespace nux { class NuxGlobalSingletonInitializer { NUX_DISABLE_OBJECT_COPY(NuxGlobalSingletonInitializer); NuxGlobalSingletonInitializer *operator & (); const NuxGlobalSingletonInitializer *operator & () const; public: NuxGlobalSingletonInitializer(); ~NuxGlobalSingletonInitializer(); static bool Ready(); private: static bool m_NuxGlobalObjectsReady; NUX_NUX_GLOBAL_OBJECT_INIT_SEQUENCE(); }; // Nifty Counter idiom. See http://www-d0.fnal.gov/KAI/doc/tutorials/static_initialization.html class NuxGlobalInitializer { public: NuxGlobalInitializer(); ~NuxGlobalInitializer(); private: static int m_Count; }; // Every compilation unit that includes this file will have its own instance of sGlobalInitializer. sGlobalInitializer is initialized // before the main function of the program is called. The first time sGlobalInitializer is initialized, it calls SystemStart() to create // our global object singleton. In SystemStart() we have a change to create our singletons in any order we like. // When the program exits, every instance of sGlobalInitializer will be destroyed. The last instance destroyed will call SystemShutdown(). // In SystemShutdown() we can destroy our global objects in any order we like. static NuxGlobalInitializer sNuxGlobalInitializer; } #endif // NUXGLOBALINITIALIZER_H nux-4.0.8+18.10.20180623/Nux/NuxTimerTickSource.h0000644000000000000000000000224613313373365015277 0ustar #ifndef NUX_TIMER_TICK_SOURCE_H #define NUX_TIMER_TICK_SOURCE_H #include "NuxCore/Animation.h" #include "NuxCore/AnimationController.h" #include "Nux/Nux.h" #include "Nux/TimerProc.h" namespace nux { // Everything inline, but should be extracted. class NuxTimerTickSource: public animation::TickSource { public: NuxTimerTickSource() : foo(0) { timer_.tick.connect(sigc::mem_fun(this, &NuxTimerTickSource::Tick)); timer_.expired.connect(sigc::mem_fun(this, &NuxTimerTickSource::TimerExpired)); unsigned int period = 16; // ms int duration = -1; // run forever timer_handle_ = nux::GetTimer().AddDurationTimer(period, duration, &timer_, NULL); } ~NuxTimerTickSource() { if (timer_handle_.Activated()) nux::GetTimer().RemoveTimerHandler(timer_handle_); } private: void Tick(void*) { tick.emit(g_get_monotonic_time()); if (++foo % 60 == 0) { // LOG_WARN(logger) << "tick..."; } } void TimerExpired(void*) { //LOG_WARN(logger) << "Timer expired."; } private: int foo; TimerFunctor timer_; TimerHandle timer_handle_; }; } #endif // NUX_TIMER_TICK_SOURCE_H nux-4.0.8+18.10.20180623/Nux/PaintLayer.cpp0000644000000000000000000003050113313373365014126 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/GraphicsEngine.h" #include "NuxGraphics/RenderingPipe.h" #include "Utils.h" #include "PaintLayer.h" namespace nux { ColorLayer::ColorLayer(const Color& color, bool write_alpha, const ROPConfig& ROP) { _color = color; m_write_alpha = write_alpha; m_rop = ROP; } void ColorLayer::Renderlayer(GraphicsEngine& graphics_engine) { unsigned int current_red_mask; unsigned int current_green_mask; unsigned int current_blue_mask; unsigned int current_alpha_mask; unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; // Get the current color mask and blend states. They will be restored later. graphics_engine.GetRenderStates().GetColorMask(current_red_mask, current_green_mask, current_blue_mask, current_alpha_mask); // Get the current blend states. They will be restored later. graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, m_write_alpha ? GL_TRUE : GL_FALSE); graphics_engine.GetRenderStates().SetBlend(m_rop.Blend, m_rop.SrcBlend, m_rop.DstBlend); graphics_engine.QRP_Color(geometry_.x, geometry_.y, geometry_.GetWidth(), geometry_.GetHeight(), _color); // Restore Color mask and blend states. graphics_engine.GetRenderStates().SetColorMask(current_red_mask, current_green_mask, current_blue_mask, current_alpha_mask); // Restore the blend state graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } AbstractPaintLayer* ColorLayer::Clone() const { return new ColorLayer(*this); } void ColorLayer::SetColor(const Color& color) { _color = color; } Color ColorLayer::GetColor() const { return _color; } ///////////////////////////////////////////////////// ShapeLayer::ShapeLayer(UXStyleImageRef image_style, const Color& color, unsigned long corners, bool write_alpha, const ROPConfig& ROP) { m_image_style = image_style; m_color = color; m_write_alpha = write_alpha; m_rop = ROP; m_rop.Blend = true; m_corners = corners; } void ShapeLayer::Renderlayer(GraphicsEngine& graphics_engine) { unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; // Get the current blend states. They will be restored later. graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); GetPainter().PaintShapeCornerROP(graphics_engine, geometry_, m_color, m_image_style, m_corners, m_write_alpha, m_rop); graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } AbstractPaintLayer* ShapeLayer::Clone() const { return new ShapeLayer(*this); } ///////////////////////////////////////////////////// SliceScaledTextureLayer::SliceScaledTextureLayer(UXStyleImageRef image_style, const Color& color, unsigned long corners, bool write_alpha, const ROPConfig& ROP) { m_image_style = image_style; m_color = color; m_write_alpha = write_alpha; m_rop = ROP; m_corners = corners; } void SliceScaledTextureLayer::Renderlayer(GraphicsEngine& graphics_engine) { unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; // Get the current blend states. They will be restored later. graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); GetPainter().PaintTextureShape(graphics_engine, geometry_, m_image_style); graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } AbstractPaintLayer* SliceScaledTextureLayer::Clone() const { return new SliceScaledTextureLayer(*this); } ///////////////////////////////////////////////////// CompositionLayer::CompositionLayer (ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, ObjectPtr texture1, TexCoordXForm texxform1, const Color& color1, LayerBlendMode layer_blend_mode, bool write_alpha, const ROPConfig& ROP) : m_source_texture(texture0), m_source_texture_color(color0), m_source_texture_texxform(texxform0), m_foreground_texture(texture1), m_foreground_texture_color(color1), m_foreground_texture_texxform(texxform1), m_write_alpha(write_alpha), m_rop(ROP), m_blend_mode(layer_blend_mode) { } CompositionLayer::CompositionLayer (ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, const Color& blend_color, LayerBlendMode layer_blend_mode, bool write_alpha, const ROPConfig& ROP) : m_source_texture(texture0), m_source_texture_color(color0), m_source_texture_texxform(texxform0), m_foreground_color(blend_color), m_write_alpha(write_alpha), m_rop(ROP), m_blend_mode(layer_blend_mode) { } CompositionLayer::CompositionLayer(const Color&base_color, ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, LayerBlendMode layer_blend_mode, bool write_alpha, const ROPConfig& ROP) : m_foreground_texture(texture0), m_foreground_texture_color(color0), m_foreground_texture_texxform(texxform0), m_source_color(base_color), m_write_alpha(write_alpha), m_rop(ROP), m_blend_mode(layer_blend_mode) { } CompositionLayer::CompositionLayer(const Color& base_color, const Color& blend_color, LayerBlendMode layer_blend_mode, bool write_alpha, const ROPConfig& ROP) : m_source_color(base_color), m_foreground_color(blend_color), m_write_alpha(write_alpha), m_rop(ROP), m_blend_mode(layer_blend_mode) { } CompositionLayer::~CompositionLayer () { if (m_foreground_texture.IsValid()) m_foreground_texture.Release(); if (m_source_texture.IsValid()) m_source_texture.Release(); } void CompositionLayer::Renderlayer(GraphicsEngine& graphics_engine) { unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; unsigned int current_red_mask; unsigned int current_green_mask; unsigned int current_blue_mask; unsigned int current_alpha_mask; // Get the current color mask and blend states. They will be restored later. graphics_engine.GetRenderStates().GetColorMask(current_red_mask, current_green_mask, current_blue_mask, current_alpha_mask); graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, m_write_alpha ? GL_TRUE : GL_FALSE); graphics_engine.GetRenderStates().SetBlend(m_rop.Blend, m_rop.SrcBlend, m_rop.DstBlend); if (m_source_texture.IsValid()) { if (m_foreground_texture.IsValid()) { graphics_engine.QRP_GLSL_TextureLayerOverTexture(geometry_.x, geometry_.y, geometry_.GetWidth(), geometry_.GetHeight(), m_source_texture, m_source_texture_texxform, m_source_texture_color, m_foreground_texture, m_foreground_texture_texxform, m_foreground_texture_color, m_blend_mode); } else { graphics_engine.QRP_GLSL_ColorLayerOverTexture(geometry_.x, geometry_.y, geometry_.GetWidth(), geometry_.GetHeight(), m_source_texture, m_source_texture_texxform, m_source_texture_color, m_foreground_color, m_blend_mode); } } else { if (m_foreground_texture.IsValid()) { graphics_engine.QRP_GLSL_TextureLayerOverColor(geometry_.x, geometry_.y, geometry_.GetWidth(), geometry_.GetHeight(), m_source_color, m_foreground_texture, m_foreground_texture_texxform, m_foreground_texture_color, m_blend_mode); } //When both textures aren't valid assume we are blending two colours. else if (m_source_texture.IsValid() == false && m_foreground_texture.IsValid() == false) { graphics_engine.QRP_GLSL_ColorLayerOverColor(geometry_.x, geometry_.y, geometry_.GetWidth(), geometry_.GetHeight(), m_source_color, m_foreground_color, m_blend_mode); } } graphics_engine.GetRenderStates().SetColorMask(current_red_mask, current_green_mask, current_blue_mask, current_alpha_mask); graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } AbstractPaintLayer* CompositionLayer::Clone() const { return new CompositionLayer(*this); } ///////////////////////////////////////////////////// TextureLayer::TextureLayer(ObjectPtr device_texture, TexCoordXForm texxform, const Color& color, bool write_alpha, const ROPConfig& ROP) : m_device_texture(device_texture), m_color(color), m_write_alpha(write_alpha), m_rop(ROP), m_texxform(texxform), m_color_blend_mode(LAYER_BLEND_MODE_LAST) { } TextureLayer::TextureLayer(ObjectPtr device_texture, TexCoordXForm texxform, const Color& color0, bool write_alpha, const ROPConfig& ROP, const Color& blend_color, LayerBlendMode color_blend_mode) : m_device_texture(device_texture), m_color(color0), m_write_alpha(write_alpha), m_rop(ROP), m_texxform(texxform), m_blend_color(blend_color), m_color_blend_mode(color_blend_mode) { } TextureLayer::~TextureLayer() { m_device_texture.Release(); } void TextureLayer::Renderlayer(GraphicsEngine& graphics_engine) { unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; unsigned int current_red_mask; unsigned int current_green_mask; unsigned int current_blue_mask; unsigned int current_alpha_mask; // Get the current color mask and blend states. They will be restored later. graphics_engine.GetRenderStates().GetColorMask(current_red_mask, current_green_mask, current_blue_mask, current_alpha_mask); graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, m_write_alpha ? GL_TRUE : GL_FALSE); graphics_engine.GetRenderStates().SetBlend(m_rop.Blend, m_rop.SrcBlend, m_rop.DstBlend); if (m_color_blend_mode == LAYER_BLEND_MODE_LAST) { graphics_engine.QRP_1Tex(geometry_.x, geometry_.y, geometry_.GetWidth(), geometry_.GetHeight(), m_device_texture, m_texxform, m_color); } else { graphics_engine.QRP_GLSL_ColorLayerOverTexture(geometry_.x, geometry_.y, geometry_.GetWidth(), geometry_.GetHeight(), m_device_texture, m_texxform, m_color, m_blend_color, m_color_blend_mode); } // Restore Color mask and blend states. graphics_engine.GetRenderStates().SetColorMask(current_red_mask, current_green_mask, current_blue_mask, current_alpha_mask); graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } AbstractPaintLayer* TextureLayer::Clone() const { return new TextureLayer(*this); } ObjectPtr< IOpenGLBaseTexture> TextureLayer::GetDeviceTexture() { return m_device_texture; } } nux-4.0.8+18.10.20180623/Nux/PaintLayer.h0000644000000000000000000001201013313373365013566 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef PAINTLAYER_H #define PAINTLAYER_H #include "AbstractPaintLayer.h" #include "NuxGraphics/GraphicsEngine.h" namespace nux { class BaseTexture; class ColorLayer: public AbstractPaintLayer { public: ColorLayer(const Color& color, bool WriteAlpha = false, const ROPConfig& ROP = ROPConfig::Default); void SetColor(const Color& color); Color GetColor() const; virtual void Renderlayer(GraphicsEngine& graphics_engine); virtual AbstractPaintLayer* Clone() const; private: Color _color; bool m_write_alpha; ROPConfig m_rop; }; class ShapeLayer: public AbstractPaintLayer { public: ShapeLayer(UXStyleImageRef imageStyle, const Color& color, unsigned long Corners = eAllCorners, bool WriteAlpha = false, const ROPConfig& ROP = ROPConfig::Default); virtual void Renderlayer(GraphicsEngine& graphics_engine); virtual AbstractPaintLayer* Clone() const; private: UXStyleImageRef m_image_style; Color m_color; bool m_write_alpha; ROPConfig m_rop; unsigned long m_corners; }; class SliceScaledTextureLayer: public AbstractPaintLayer { public: SliceScaledTextureLayer(UXStyleImageRef imageStyle, const Color& color, unsigned long Corners = eAllCorners, bool WriteAlpha = false, const ROPConfig& ROP = ROPConfig::Default); virtual void Renderlayer(GraphicsEngine& graphics_engine); virtual AbstractPaintLayer* Clone() const; private: UXStyleImageRef m_image_style; Color m_color; bool m_write_alpha; ROPConfig m_rop; unsigned long m_corners; }; class CompositionLayer: public AbstractPaintLayer { public: //! Layer blend operation. /*! Blend(texture0*color0, texture1*color1); */ CompositionLayer(ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, ObjectPtr texture1, TexCoordXForm texxform1, const Color& color1, LayerBlendMode layer_blend_mode, bool write_alpha, const ROPConfig& ROP); //! Layer blend operation. /*! Blend(texture0*color0, blend_color); */ CompositionLayer(ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, const Color& blend_color, LayerBlendMode layer_blend_mode, bool write_alpha, const ROPConfig& ROP); //! Layer blend operation. /*! Blend(texture0*color0, color0); */ CompositionLayer(const Color& base_color, ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, LayerBlendMode layer_blend_mode, bool write_alpha, const ROPConfig& ROP); CompositionLayer(const Color& base_color, const Color& blend_color, LayerBlendMode layer_blend_mode, bool write_alpha, const ROPConfig& ROP); virtual ~CompositionLayer(); virtual void Renderlayer(GraphicsEngine& graphics_engine); virtual AbstractPaintLayer* Clone() const; private: ObjectPtr m_source_texture; Color m_source_texture_color; TexCoordXForm m_source_texture_texxform; ObjectPtr m_foreground_texture; Color m_foreground_texture_color; TexCoordXForm m_foreground_texture_texxform; Color m_source_color; Color m_foreground_color; bool m_write_alpha; ROPConfig m_rop; LayerBlendMode m_blend_mode; }; class TextureLayer: public AbstractPaintLayer { public: TextureLayer(ObjectPtr< IOpenGLBaseTexture > device_texture, TexCoordXForm texxform, const Color& color, bool WriteAlpha = false, const ROPConfig& ROP = ROPConfig::Default); TextureLayer(ObjectPtr device_texture, TexCoordXForm texxform, const Color& color0, bool write_alpha, const ROPConfig& ROP, const Color& blend_color, LayerBlendMode color_blend_mode); virtual ~TextureLayer(); virtual void Renderlayer(GraphicsEngine& graphics_engine); virtual AbstractPaintLayer* Clone() const; virtual ObjectPtr< IOpenGLBaseTexture> GetDeviceTexture(); private: ObjectPtr< IOpenGLBaseTexture > m_device_texture; Color m_color; bool m_write_alpha; ROPConfig m_rop; TexCoordXForm m_texxform; Color m_blend_color; LayerBlendMode m_color_blend_mode; }; } #endif // PAINTLAYER_H nux-4.0.8+18.10.20180623/Nux/Painter.cpp0000644000000000000000000012426513313373365013473 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "InputArea.h" #include "Painter.h" #include "NuxGraphics/GLTextureResourceManager.h" namespace nux { GeometryPositioning::GeometryPositioning() { m_stretch_horizontal = true; m_stretch_vertical = true; m_vertical_aligment = eVACenter; m_horizontal_aligment = eHACenter; m_horizontal_margin = 0; m_vertical_margin = 0; } GeometryPositioning::GeometryPositioning( HorizontalAlignment /* horizontal_aligment */, VerticalAlignment /* vertical_aligment */, bool stretch_horizontal, bool stretch_vertical, int horizontal_margin, int vertical_margin) { m_stretch_horizontal = stretch_horizontal; m_stretch_vertical = stretch_vertical; m_vertical_aligment = eVACenter; m_horizontal_aligment = eHACenter; m_horizontal_margin = horizontal_margin; m_vertical_margin = vertical_margin; } GeometryPositioning::~GeometryPositioning() { } Geometry ComputeGeometryPositioning(const Geometry &container_geo, const Geometry &content_geo, GeometryPositioning gctx) { int x_pos, y_pos; int w, h; if (gctx.m_stretch_horizontal) { w = container_geo.GetWidth() - 2 * gctx.m_horizontal_margin; } else { w = content_geo.GetWidth(); } if (gctx.m_stretch_horizontal) { h = container_geo.GetHeight() - 2 * gctx.m_vertical_margin; } else { h = content_geo.GetHeight(); } if (gctx.m_horizontal_aligment == eHACenter) { int offset = (container_geo.GetWidth() - w) / 2.0f; //offset = (offset < 0) ? 0 : offset; x_pos = container_geo.x + offset; } else if (gctx.m_horizontal_aligment == eHALeft) { x_pos = container_geo.x + gctx.m_horizontal_margin; if (x_pos > container_geo.x + container_geo.GetWidth()) x_pos = container_geo.x; } else if (gctx.m_horizontal_aligment == eHARight) { x_pos = container_geo.x + container_geo.GetWidth() - w - gctx.m_horizontal_margin; if (x_pos < container_geo.x) x_pos = container_geo.x; } else { x_pos = container_geo.x + gctx.m_horizontal_margin; } if (gctx.m_vertical_aligment == eVACenter) { int offset = (container_geo.GetHeight() - h) / 2.0f; //offset = (offset < 0) ? 0 : offset; y_pos = container_geo.y + offset; } else if (gctx.m_vertical_aligment == eVATop) { y_pos = container_geo.y + gctx.m_vertical_margin; if (y_pos > container_geo.y + container_geo.GetHeight()) y_pos = container_geo.y; } else if (gctx.m_vertical_aligment == eVABottom) { y_pos = container_geo.y + container_geo.GetHeight() - h - gctx.m_vertical_margin; if (y_pos < container_geo.y) y_pos = container_geo.y; } else { y_pos = container_geo.y + gctx.m_vertical_margin; } return Geometry(x_pos, y_pos, w, h); } InteractState::InteractState() { is_on = false; is_focus = false; is_prelight = false; is_disable = false; } InteractState::InteractState(bool on, bool focus, bool prelight, bool disable) { is_on = on; is_focus = focus; is_prelight = prelight; is_disable = disable; } InteractState::~InteractState() { } BasePainter::BasePainter(WindowThread *window_thread) : window_thread_(window_thread) { } BasePainter::~BasePainter() { EmptyBackgroundStack(); } int BasePainter::PaintColorTextLineEdit(GraphicsEngine &graphics_engine, const Geometry &g, std::string const& Str, Color TextColor, bool WriteAlphaChannel, Color SelectedTextColor, Color SelectedTextBackgroundColor, Color TextBlinkColor, Color CursorColor, bool ShowCursor, unsigned int CursorPosition, int offset, int selection_start, int selection_end) const { PageBBox page; page.xmin = g.x; page.xmax = g.x + g.GetWidth(); page.ymin = g.y; page.ymax = g.y + g.GetHeight(); page.x_margin = DEFAULT_TEXT_X_MARGIN; page.y_margin = DEFAULT_TEXT_Y_MARGIN; return graphics_engine.RenderColorTextLineEdit(GetSysFont(), page, Str, TextColor, WriteAlphaChannel, SelectedTextColor, SelectedTextBackgroundColor, TextBlinkColor, CursorColor, ShowCursor, CursorPosition, offset, selection_start, selection_end); } int BasePainter::PaintTextLineStatic(GraphicsEngine &graphics_engine, ObjectPtr Font, Geometry const& g, std::string const& text_line, Color const& color, bool WriteAlphaChannel, TextAlignment alignment) const { PageBBox page; page.xmin = g.x; page.xmax = g.x + g.GetWidth(); page.ymin = g.y; page.ymax = g.y + g.GetHeight(); page.x_margin = DEFAULT_TEXT_X_MARGIN; page.y_margin = DEFAULT_TEXT_Y_MARGIN; return graphics_engine.RenderColorTextLineStatic(Font, page, text_line, color, WriteAlphaChannel, alignment); } void BasePainter::Draw2DTexture(GraphicsEngine &graphics_engine, BaseTexture *texture, int x, int y) const { float tex_w, tex_h; tex_w = (float) texture->GetWidth(); tex_h = (float) texture->GetHeight(); TexCoordXForm texxform; graphics_engine.QRP_1Tex(x, y, tex_w, tex_h, texture->GetDeviceTexture(), texxform, color::White); } void BasePainter::Draw2DTextureAligned(GraphicsEngine &graphics_engine, BaseTexture *texture, const Geometry &g, TextureAlignmentStyle tex_align) const { int x_pos, y_pos; int tex_w, tex_h; tex_w = (float) texture->GetWidth(); tex_h = (float) texture->GetHeight(); if (tex_align.horz_alignment == eTACenter) { int offset = (g.GetWidth() - tex_w) / 2.0f; offset = (offset < 0) ? 0 : offset; x_pos = g.x + offset; } else if (tex_align.horz_alignment == eTALeft) { x_pos = g.x + tex_align.horizontal_margin; } else if (tex_align.horz_alignment == eTARight) { x_pos = g.x + g.GetWidth() - tex_w - tex_align.horizontal_margin; } else { x_pos = g.x + tex_align.horizontal_margin; } if (tex_align.vert_alignment == eTACenter) { int offset = (g.GetHeight() - tex_h) / 2.0f; offset = (offset < 0) ? 0 : offset; y_pos = g.y + offset; } else if (tex_align.vert_alignment == eTATop) { y_pos = g.y + tex_align.vertical_margin; } else if (tex_align.vert_alignment == eTABottom) { y_pos = g.y + g.GetHeight() - tex_h - tex_align.vertical_margin; } else { y_pos = g.y + tex_align.vertical_margin; } PaintTextureShape(graphics_engine, Geometry(x_pos, y_pos, tex_w, tex_h), texture, 0, 0, 0, 0, 0); } /////////////////// // Draw QUADS // /////////////////// void BasePainter::Paint2DQuadColor(GraphicsEngine &graphics_engine, const Geometry &g, const Color &c0) const { graphics_engine.QRP_Color(g.x, g.y, g.GetWidth(), g.GetHeight(), c0); } void BasePainter::Paint2DQuadColor(GraphicsEngine &graphics_engine, const Geometry &g, const Color &c0_top_left, const Color &c1_bottom_left, const Color &c2_bottom_right, const Color &c3_top_right) const { graphics_engine.QRP_Color(g.x, g.y, g.GetWidth(), g.GetHeight(), c0_top_left, c1_bottom_left, c2_bottom_right, c3_top_right); } void BasePainter::Paint2DQuadColor(GraphicsEngine &graphics_engine, int x, int y, int width, int height, const Color &c0) const { graphics_engine.QRP_Color(x, y, width, height, c0); } void BasePainter::Paint2DQuadColor(GraphicsEngine &graphics_engine, int x, int y, int width, int height, const Color &c0_top_left, const Color &c1_bottom_left, const Color &c2_bottom_right, const Color &c3_top_right) const { graphics_engine.QRP_Color(x, y, width, height, c0_top_left, c1_bottom_left, c2_bottom_right, c3_top_right); } void BasePainter::Paint2DQuadVGradient(GraphicsEngine &graphics_engine, const Geometry &g, Color TopColor, Color BottomColor) const { Paint2DQuadColor(graphics_engine, g, TopColor, BottomColor, BottomColor, TopColor); } void BasePainter::Paint2DQuadHGradient(GraphicsEngine &graphics_engine, const Geometry &g, Color LeftColor, Color RightColor) const { Paint2DQuadColor(graphics_engine, g, LeftColor, LeftColor, RightColor, LeftColor); } ///////////////////////////// // Draw QUADS WIREFRAME // ///////////////////////////// void BasePainter::Paint2DQuadWireframe(GraphicsEngine &graphics_engine, const Geometry &g, Color c0) const { graphics_engine.QRP_QuadWireframe(g.x, g.y, g.GetWidth(), g.GetHeight(), c0, c0, c0, c0); } // void BasePainter::Paint2DQuadWireframe(GraphicsEngine& graphics_engine, const Geometry &g, Color c0_left, Color c1_right) const // { // graphics_engine.QRP_QuadWireframe(g.x, g.y, g.GetWidth(), g.GetHeight(), c0_left, c0_left, c1_right, c1_right); // } void BasePainter::Paint2DQuadWireframe(GraphicsEngine &graphics_engine, const Geometry &g, Color c_top_left, Color c_bottom_left, Color c_bottom_right, Color c_top_right) const { graphics_engine.QRP_QuadWireframe(g.x, g.y, g.GetWidth(), g.GetHeight(), c_top_left, c_bottom_left, c_bottom_right, c_top_right); } void BasePainter::Paint2DQuadWireframe(GraphicsEngine &graphics_engine, int x, int y, int width, int height, Color c0) const { graphics_engine.QRP_QuadWireframe(x, y, width, height, c0, c0, c0, c0); } // void BasePainter::Paint2DQuadWireframe(GraphicsEngine& graphics_engine, int x, int y, int width, int height, Color c0_left, Color c1_right) const // { // graphics_engine.QRP_QuadWireframe(x, y, width, height, c0_left, c0_left, c1_right, c1_right); // } void BasePainter::Paint2DQuadWireframe(GraphicsEngine &graphics_engine, int x, int y, int width, int height, Color c_top_left, Color c_bottom_left, Color c_bottom_right, Color c_top_right) const { graphics_engine.QRP_QuadWireframe(x, y, width, height, c_top_left, c_bottom_left, c_bottom_right, c_top_right); } ////////////////////// // Draw TRIANGLES // ////////////////////// void BasePainter::Draw2DTriangleColor(GraphicsEngine &graphics_engine, int x0, int y0, int x1, int y1, int x2, int y2, Color c0) { graphics_engine.QRP_Triangle(x0, y0, x1, y1, x2, y2, c0); } void BasePainter::Draw2DTriangleColor(GraphicsEngine &graphics_engine, int x0, int y0, int x1, int y1, int x2, int y2, Color c0, Color c1, Color c2) { graphics_engine.QRP_Triangle(x0, y0, x1, y1, x2, y2, c0, c1, c2); } ////////////////////// // DRAW LINES // ////////////////////// void BasePainter::Draw2DLine(GraphicsEngine &graphics_engine, int x0, int y0, int x1, int y1, Color c0) const { graphics_engine.QRP_Line(x0, y0, x1, y1, c0); } void BasePainter::Draw2DLine(GraphicsEngine &graphics_engine, int x0, int y0, int x1, int y1, Color c0, Color c1) const { graphics_engine.QRP_Line(x0, y0, x1, y1, c0, c1); } //////////////////// // Themes // //////////////////// void BasePainter::PaintShape(GraphicsEngine &graphics_engine, const Geometry &geo, const Color &c0, UXStyleImageRef style, bool WriteAlpha) const { ROPConfig ROP; ROP.Blend = true; ROP.SrcBlend = GL_SRC_ALPHA; ROP.DstBlend = GL_ONE_MINUS_SRC_ALPHA; PaintShapeCornerROP(graphics_engine, geo, c0, style, eCornerTopLeft | eCornerTopRight | eCornerBottomLeft | eCornerBottomRight, WriteAlpha, ROP); } void BasePainter::PaintShapeCorner(GraphicsEngine &graphics_engine, const Geometry &geo, const Color &c0, UXStyleImageRef style, long corners, bool WriteAlpha) const { ROPConfig ROP; ROP.Blend = true; ROP.SrcBlend = GL_SRC_ALPHA; ROP.DstBlend = GL_ONE_MINUS_SRC_ALPHA; PaintShapeCornerROP(graphics_engine, geo, c0, style, corners, WriteAlpha, ROP); } void BasePainter::PaintShapeROP(GraphicsEngine &graphics_engine, const Geometry &geo, const Color &c0, UXStyleImageRef style, bool WriteAlpha, const ROPConfig &ROP) const { PaintShapeCornerROP(graphics_engine, geo, c0, style, eCornerTopLeft | eCornerTopRight | eCornerBottomLeft | eCornerBottomRight, WriteAlpha, ROP); } void BasePainter::PaintShapeCornerROP(GraphicsEngine &graphics_engine, const Geometry &geo, const Color &c0, UXStyleImageRef style, long corners, bool WriteAlpha, const ROPConfig &ROP) const { const PainterImage *pimage = GetTheme().GetImage(style); if (pimage == 0) return; BaseTexture *texture = pimage->texture; int border_left = pimage->border_left; int border_right = pimage->border_right; int border_top = pimage->border_top; int border_bottom = pimage->border_bottom; bool draw_borders_only = pimage->draw_borders_only; unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; unsigned int current_red_mask; unsigned int current_green_mask; unsigned int current_blue_mask; unsigned int current_alpha_mask; // Get the current color mask and blend states. They will be restored later. graphics_engine.GetRenderStates().GetColorMask(current_red_mask, current_green_mask, current_blue_mask, current_alpha_mask); graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); graphics_engine.GetRenderStates().SetColorMask(GL_TRUE, GL_TRUE, GL_TRUE, WriteAlpha ? GL_TRUE : GL_FALSE); graphics_engine.GetRenderStates().SetBlend(ROP.Blend, ROP.SrcBlend, ROP.DstBlend); int tex_w = texture->GetWidth(); int tex_h = texture->GetHeight(); int r_x = geo.x; int r_y = geo.y; int r_w = geo.GetWidth(); int r_h = geo.GetHeight(); TexCoordXForm texxform; texxform.SetTexCoordType(TexCoordXForm::UNNORMALIZED_COORD); if (r_w < border_left + border_right) { // Do not apply this correction: just show the drawing as it is; //border_left = border_right = 0; } if (r_h < border_top + border_bottom) { // Do not apply this correction: just show the drawing as it is; //border_top = border_bottom = 0; } // Draw TOP-LEFT CORNER if (corners & eCornerTopLeft) { texxform.u0 = 0; texxform.v0 = 0; texxform.u1 = border_left; texxform.v1 = border_top; graphics_engine.QRP_ColorModTexAlpha(r_x, r_y, border_left, border_top, texture->GetDeviceTexture(), texxform, c0); } else { graphics_engine.QRP_Color(r_x, r_y, border_left, border_top, c0); } // Draw TOP-RIGHT CORNER if (corners & eCornerTopRight) { texxform.u0 = tex_w - border_right; texxform.v0 = 0; texxform.u1 = tex_w; texxform.v1 = border_top; graphics_engine.QRP_ColorModTexAlpha(r_x + r_w - border_right, r_y, border_right, border_top, texture->GetDeviceTexture(), texxform, c0); } else { graphics_engine.QRP_Color(r_x + r_w - border_right, r_y, border_right, border_top, c0); } // Draw BOTTOM-LEFT CORNER if (corners & eCornerBottomLeft) { texxform.u0 = 0; texxform.v0 = tex_h - border_bottom; texxform.u1 = border_left; texxform.v1 = tex_h; graphics_engine.QRP_ColorModTexAlpha(r_x, r_y + r_h - border_bottom, border_left, border_bottom, texture->GetDeviceTexture(), texxform, c0); } else { graphics_engine.QRP_Color(r_x, r_y + r_h - border_bottom, border_left, border_bottom, c0); } // Draw BOTTOM-RIGHT CORNER if (corners & eCornerBottomRight) { texxform.u0 = tex_w - border_right; texxform.v0 = tex_h - border_bottom; texxform.u1 = tex_w; texxform.v1 = tex_h; graphics_engine.QRP_ColorModTexAlpha(r_x + r_w - border_right, r_y + r_h - border_bottom, border_right, border_bottom, texture->GetDeviceTexture(), texxform, c0); } else { graphics_engine.QRP_Color(r_x + r_w - border_right, r_y + r_h - border_bottom, border_right, border_bottom, c0); } texxform.u0 = border_left; texxform.v0 = 0; texxform.u1 = tex_w - border_right; texxform.v1 = border_top; graphics_engine.QRP_ColorModTexAlpha(r_x + border_left, r_y, r_w - border_left - border_right, border_top, texture->GetDeviceTexture(), texxform, c0); // Draw BOTTOM BORDER texxform.u0 = border_left; texxform.v0 = tex_h - border_bottom; texxform.u1 = tex_w - border_right; texxform.v1 = tex_h; graphics_engine.QRP_ColorModTexAlpha(r_x + border_left, r_y + r_h - border_bottom, r_w - border_left - border_right, border_bottom, texture->GetDeviceTexture(), texxform, c0); // Draw LEFT BORDER texxform.u0 = 0; texxform.v0 = border_top; texxform.u1 = border_left; texxform.v1 = tex_h - border_bottom; graphics_engine.QRP_ColorModTexAlpha(r_x, r_y + border_top, border_left, r_h - border_top - border_bottom, texture->GetDeviceTexture(), texxform, c0); // Draw RIGHT BORDER texxform.u0 = tex_w - border_right; texxform.v0 = border_top; texxform.u1 = tex_w; texxform.v1 = tex_h - border_bottom; graphics_engine.QRP_ColorModTexAlpha(r_x + r_w - border_right, r_y + border_top, border_right, r_h - border_top - border_bottom, texture->GetDeviceTexture(), texxform, c0); // Draw CENTER if (draw_borders_only == false) { texxform.u0 = border_left; texxform.v0 = border_top; texxform.u1 = tex_w - border_right; texxform.v1 = tex_h - border_bottom; graphics_engine.QRP_ColorModTexAlpha(r_x + border_left, r_y + border_top, r_w - border_left - border_right, r_h - border_top - border_bottom, texture->GetDeviceTexture(), texxform, c0); } // Restore Color mask and blend states. graphics_engine.GetRenderStates().SetColorMask(current_red_mask, current_green_mask, current_blue_mask, current_alpha_mask); graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } void BasePainter::PaintTextureShape(GraphicsEngine &graphics_engine, const Geometry &geo, UXStyleImageRef style) const { const PainterImage *pimage = GetTheme().GetImage(style); if (pimage == 0) return; BaseTexture *texture = pimage->texture; int border_left = pimage->border_left; int border_right = pimage->border_right; int border_top = pimage->border_top; int border_bottom = pimage->border_bottom; bool draw_borders_only = pimage->draw_borders_only; PaintTextureShape(graphics_engine, geo, texture, border_left, border_right, border_top, border_bottom, draw_borders_only); } void BasePainter::PaintTextureShape(GraphicsEngine &graphics_engine, const Geometry &geo, BaseTexture *texture, int border_left, int border_right, int border_top, int border_bottom, bool draw_borders_only, bool premultiply) const { int tex_w = texture->GetWidth(); int tex_h = texture->GetHeight(); int r_x = geo.x; int r_y = geo.y; int r_w = geo.GetWidth(); int r_h = geo.GetHeight(); if (r_w < border_left + border_right) { border_left = border_right = 0; } if (r_h < border_top + border_bottom) { border_top = border_bottom = 0; } if (premultiply) graphics_engine.GetRenderStates().SetBlend(TRUE, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); else graphics_engine.GetRenderStates().SetBlend(TRUE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); TexCoordXForm texxform; texxform.SetTexCoordType(TexCoordXForm::UNNORMALIZED_COORD); // Draw TOP-LEFT CORNER texxform.u0 = 0; texxform.v0 = 0; texxform.u1 = border_left; texxform.v1 = border_top; graphics_engine.QRP_1Tex(r_x, r_y, border_left, border_top, texture->GetDeviceTexture(), texxform, color::White); // Draw TOP-RIGHT CORNER texxform.u0 = tex_w - border_right; texxform.v0 = 0; texxform.u1 = tex_w; texxform.v1 = border_top; graphics_engine.QRP_1Tex(r_x + r_w - border_right, r_y, border_right, border_top, texture->GetDeviceTexture(), texxform, color::White); // Draw BOTTOM-LEFT CORNER texxform.u0 = 0; texxform.v0 = tex_h - border_bottom; texxform.u1 = border_left; texxform.v1 = tex_h; graphics_engine.QRP_1Tex(r_x, r_y + r_h - border_bottom, border_left, border_bottom, texture->GetDeviceTexture(), texxform, color::White); // Draw BOTTOM-RIGHT CORNER texxform.u0 = tex_w - border_right; texxform.v0 = tex_h - border_bottom; texxform.u1 = tex_w; texxform.v1 = tex_h; graphics_engine.QRP_1Tex(r_x + r_w - border_right, r_y + r_h - border_bottom, border_right, border_bottom, texture->GetDeviceTexture(), texxform, color::White); // Draw TOP BORDER texxform.u0 = border_left; texxform.v0 = 0; texxform.u1 = tex_w - border_right; texxform.v1 = border_top; graphics_engine.QRP_1Tex(r_x + border_left, r_y, r_w - border_left - border_right, border_top, texture->GetDeviceTexture(), texxform, color::White); // Draw BOTTOM BORDER texxform.u0 = border_left; texxform.v0 = tex_h - border_bottom; texxform.u1 = tex_w - border_right; texxform.v1 = tex_h; graphics_engine.QRP_1Tex(r_x + border_left, r_y + r_h - border_bottom, r_w - border_left - border_right, border_bottom, texture->GetDeviceTexture(), texxform, color::White); // Draw LEFT BORDER texxform.u0 = 0; texxform.v0 = border_top; texxform.u1 = border_left; texxform.v1 = tex_h - border_bottom; graphics_engine.QRP_1Tex(r_x, r_y + border_top, border_left, r_h - border_top - border_bottom, texture->GetDeviceTexture(), texxform, color::White); // Draw RIGHT BORDER texxform.u0 = tex_w - border_right; texxform.v0 = border_top; texxform.u1 = tex_w; texxform.v1 = tex_h - border_bottom; graphics_engine.QRP_1Tex(r_x + r_w - border_right, r_y + border_top, border_right, r_h - border_top - border_bottom, texture->GetDeviceTexture(), texxform, color::White); // Draw CENTER if (draw_borders_only == false) { texxform.u0 = border_left; texxform.v0 = border_top; texxform.u1 = tex_w - border_right; texxform.v1 = tex_h - border_bottom; graphics_engine.QRP_1Tex(r_x + border_left, r_y + border_top, r_w - border_left - border_right, r_h - border_top - border_bottom, texture->GetDeviceTexture(), texxform, color::White); } graphics_engine.GetRenderStates().SetBlend(FALSE); } void BasePainter::PaintHorizontalGradientQuad(GraphicsEngine &graphics_engine, const Geometry &geo, int array_size, float *percentage_array, Color *color_array) { for (int i = 0; i < array_size - 1; i++) { float p0 = percentage_array[i] / 100.0f; float p1 = percentage_array[i+1] / 100.0f; Paint2DQuadColor(graphics_engine, geo.x, geo.y + geo.GetHeight() * p0, geo.GetWidth(), geo.GetHeight() * p1 - geo.GetHeight() * p0, color_array[i], color_array[i], color_array[i+1], color_array[i+1]); } } void BasePainter::PaintCheckBox(GraphicsEngine &graphics_engine, const Geometry &geo, const InteractState &interaction_state, Color /* check_mark_color */, Color /* check_box_color */) { GeometryPositioning pctx(eHACenter, eVACenter); pctx.m_stretch_horizontal = false; pctx.m_stretch_vertical = false; const PainterImage *pimage = GetTheme().GetImage(eCHECKBOX_NORMAL_ON); if (pimage == 0) return; BaseTexture *texture = pimage->texture; Geometry content_geo(0, 0, texture->GetWidth(), texture->GetHeight()) ; content_geo = ComputeGeometryPositioning(geo, content_geo, pctx); graphics_engine.GetRenderStates().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (interaction_state.is_focus && interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eCHECKBOX_FOCUS_ON)->texture, content_geo.x, content_geo.y); } else if (interaction_state.is_focus && !interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eCHECKBOX_FOCUS_OFF)->texture, content_geo.x, content_geo.y); } else if (interaction_state.is_prelight && interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eCHECKBOX_PRELIGHT_ON)->texture, content_geo.x, content_geo.y); } else if (interaction_state.is_prelight && !interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eCHECKBOX_PRELIGHT_OFF)->texture, content_geo.x, content_geo.y); } else if (interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eCHECKBOX_NORMAL_ON)->texture, content_geo.x, content_geo.y); } else { Draw2DTexture(graphics_engine, GetTheme().GetImage(eCHECKBOX_NORMAL_OFF)->texture, content_geo.x, content_geo.y); } graphics_engine.GetRenderStates().SetBlend(false); } void BasePainter::PaintRadioButton(GraphicsEngine &graphics_engine, const Geometry &geo, const InteractState &interaction_state, Color /* check_mark_color */, Color /* check_box_color */) { PaintBackground(graphics_engine, geo); GeometryPositioning pctx(eHACenter, eVACenter); pctx.m_stretch_horizontal = false; pctx.m_stretch_vertical = false; const PainterImage *pimage = GetTheme().GetImage(eRADIO_NORMAL_ON); if (pimage == 0) return; BaseTexture *texture = pimage->texture; Geometry content_geo(0, 0, texture->GetWidth(), texture->GetHeight()) ; content_geo = ComputeGeometryPositioning(geo, content_geo, pctx); graphics_engine.GetRenderStates().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (interaction_state.is_focus && interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eRADIO_FOCUS_ON)->texture, content_geo.x, content_geo.y); } else if (interaction_state.is_focus && !interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eRADIO_FOCUS_OFF)->texture, content_geo.x, content_geo.y); } else if (interaction_state.is_prelight && interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eRADIO_PRELIGHT_ON)->texture, content_geo.x, content_geo.y); } else if (interaction_state.is_prelight && !interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eRADIO_PRELIGHT_OFF)->texture, content_geo.x, content_geo.y); } else if (interaction_state.is_on) { Draw2DTexture(graphics_engine, GetTheme().GetImage(eRADIO_NORMAL_ON)->texture, content_geo.x, content_geo.y); } else { Draw2DTexture(graphics_engine, GetTheme().GetImage(eRADIO_NORMAL_OFF)->texture, content_geo.x, content_geo.y); } graphics_engine.GetRenderStates().SetBlend(false); } void BasePainter::PaintActivePaintLayerStack(GraphicsEngine &graphics_engine, const Geometry &geo) { if (active_paint_layer_stack_.empty()) { return; } std::list::const_reverse_iterator rev_it; bool clear_background = false; if (pushed_paint_layer_stack_.empty()) { // This is the first stack of layers. Clear the background clear_background = true; } for (rev_it = active_paint_layer_stack_.rbegin(); rev_it != active_paint_layer_stack_.rend(); rev_it++) { AbstractPaintLayer *layer = (*rev_it); Geometry layer_geo = layer->GetGeometry(); graphics_engine.PushClippingRectangle(geo); graphics_engine.SetModelViewMatrix(layer->GetModelViewMatrix()); if (clear_background) { Paint2DQuadColor(graphics_engine, layer_geo, Color(0x0)); clear_background = false; } RenderSinglePaintLayer(graphics_engine, layer_geo, layer); // restore the model view matrix stack and the clipping rectangle stack. graphics_engine.ApplyModelViewMatrix(); graphics_engine.PopClippingRectangle(); } } void BasePainter::PaintBackground(GraphicsEngine& graphics_engine, const Geometry& geo) { PaintActivePaintLayerStack(graphics_engine, geo); } void BasePainter::PaintAllLayerStack(GraphicsEngine& graphics_engine, const Geometry& geo) { std::list >::const_iterator stack_it; std::list::const_reverse_iterator rev_layer_it; bool clear_background = true; for (stack_it = pushed_paint_layer_stack_.begin(); stack_it != pushed_paint_layer_stack_.end(); stack_it++) { std::list stack = (*stack_it); for (rev_layer_it = stack.rbegin(); rev_layer_it != stack.rend(); rev_layer_it++) { AbstractPaintLayer* layer = (*rev_layer_it); Geometry layer_geo = layer->GetGeometry(); graphics_engine.PushClippingRectangle(geo); if (clear_background) { Paint2DQuadColor(graphics_engine, layer_geo, Color(0x0)); clear_background = false; } RenderSinglePaintLayer(graphics_engine, layer_geo, layer); graphics_engine.PopClippingRectangle(); } } } void BasePainter::RenderSinglePaintLayer(GraphicsEngine &graphics_engine, Geometry /* geo */, AbstractPaintLayer *paint_layer) { paint_layer->Renderlayer(graphics_engine); } void BasePainter::PushLayer(GraphicsEngine & /* graphics_engine */, const Geometry &geo, AbstractPaintLayer *layer) { AbstractPaintLayer *l = layer->Clone(); l->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); l->SetGeometry(geo); active_paint_layer_stack_.push_front(l); } void BasePainter::PushDrawLayer(GraphicsEngine &graphics_engine, const Geometry &geo, AbstractPaintLayer *layer) { PushLayer(graphics_engine, geo, layer); PaintBackground(graphics_engine, geo); } void BasePainter::PushColorLayer(GraphicsEngine & /* graphics_engine */, const Geometry &geo, Color color, bool WriteAlpha, const ROPConfig &ROP) { ColorLayer *cl = new ColorLayer(color, WriteAlpha, ROP); cl->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); cl->SetGeometry(geo); active_paint_layer_stack_.push_front(cl); } void BasePainter::PushDrawColorLayer(GraphicsEngine &graphics_engine, const Geometry &geo, Color color, bool WriteAlpha, const ROPConfig &ROP) { PushColorLayer(graphics_engine, geo, color, WriteAlpha, ROP); PaintBackground(graphics_engine, geo); } void BasePainter::PushShapeLayer(GraphicsEngine & /* graphics_engine */, Geometry geo, UXStyleImageRef imageStyle, const Color &color, unsigned long Corners, bool WriteAlpha, const ROPConfig &ROP) { ShapeLayer *sl = new ShapeLayer(imageStyle, color, Corners, WriteAlpha, ROP); sl->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); sl->SetGeometry(geo); active_paint_layer_stack_.push_front(sl); } void BasePainter::PushDrawShapeLayer(GraphicsEngine &graphics_engine, Geometry geo, UXStyleImageRef imageStyle, const Color &color, unsigned long Corners, bool WriteAlpha, const ROPConfig &ROP) { PushShapeLayer(graphics_engine, geo, imageStyle, color, Corners, WriteAlpha, ROP); PaintBackground(graphics_engine, geo); } void BasePainter::PushSliceScaledTextureLayer(GraphicsEngine & /* graphics_engine */, Geometry geo, UXStyleImageRef imageStyle, const Color &color, unsigned long Corners, bool WriteAlpha, const ROPConfig &ROP) { SliceScaledTextureLayer *sl = new SliceScaledTextureLayer(imageStyle, color, Corners, WriteAlpha, ROP); sl->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); sl->SetGeometry(geo); active_paint_layer_stack_.push_front(sl); } void BasePainter::PushDrawSliceScaledTextureLayer(GraphicsEngine &graphics_engine, Geometry geo, UXStyleImageRef imageStyle, const Color &color, unsigned long Corners, bool WriteAlpha, const ROPConfig &ROP) { PushSliceScaledTextureLayer(graphics_engine, geo, imageStyle, color, Corners, WriteAlpha, ROP); PaintBackground(graphics_engine, geo); } void BasePainter::PushTextureLayer(GraphicsEngine & /* graphics_engine */, Geometry geo, ObjectPtr DeviceTexture, TexCoordXForm texxform, const Color &color, bool WriteAlpha, const ROPConfig &ROP) { TextureLayer *tl = new TextureLayer(DeviceTexture, texxform, color, WriteAlpha, ROP); tl->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); tl->SetGeometry(geo); active_paint_layer_stack_.push_front(tl); } void BasePainter::PushCompositionLayer (GraphicsEngine & /* graphics_engine */, Geometry geo, ObjectPtr texture0, TexCoordXForm texxform0, const Color &color0, ObjectPtr texture1, TexCoordXForm texxform1, const Color &color1, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP) { CompositionLayer *cl = new CompositionLayer (texture0, texxform0, color0, texture1, texxform1, color1, layer_blend_mode, WriteAlpha, ROP); cl->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); cl->SetGeometry(geo); active_paint_layer_stack_.push_front(cl); } void BasePainter::PushCompositionLayer (GraphicsEngine & /* graphics_engine */, Geometry geo, ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, const Color& blend_color, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP) { CompositionLayer *cl = new CompositionLayer (texture0, texxform0, color0, blend_color, layer_blend_mode, WriteAlpha, ROP); cl->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); cl->SetGeometry(geo); active_paint_layer_stack_.push_front(cl); } void BasePainter::PushCompositionLayer (GraphicsEngine & /* graphics_engine */, Geometry geo, const Color& base_color, ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP) { CompositionLayer *cl = new CompositionLayer (base_color, texture0, texxform0, color0, layer_blend_mode, WriteAlpha, ROP); cl->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); cl->SetGeometry(geo); active_paint_layer_stack_.push_front(cl); } void BasePainter::PushDrawCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr texture0, TexCoordXForm texxform0, const Color &color0, const Color& blend_color, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP) { PushCompositionLayer(graphics_engine, geo, texture0, texxform0, color0, blend_color, layer_blend_mode, WriteAlpha, ROP); PaintBackground(graphics_engine, geo); } void BasePainter::PushDrawCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr texture0, TexCoordXForm texxform0, const Color &color0, ObjectPtr texture1, TexCoordXForm texxform1, const Color &color1, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP) { PushCompositionLayer(graphics_engine, geo, texture0, texxform0, color0, texture1, texxform1, color1, layer_blend_mode, WriteAlpha, ROP); PaintBackground(graphics_engine, geo); } void BasePainter::PushDrawCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, const Color& base_color, ObjectPtr texture0, TexCoordXForm texxform0, const Color &color0, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP) { PushCompositionLayer(graphics_engine, geo, base_color, texture0, texxform0, color0, layer_blend_mode, WriteAlpha, ROP); } void BasePainter::PushColorizeTextureLayer(GraphicsEngine & /* graphics_engine */, Geometry geo, ObjectPtr DeviceTexture, TexCoordXForm texxform, const Color &color, bool WriteAlpha, const ROPConfig &ROP, const Color &blend_color, LayerBlendMode layer_blend_mode) { TextureLayer *tl = new TextureLayer(DeviceTexture, texxform, color, WriteAlpha, ROP, blend_color, layer_blend_mode); tl->SetModelViewMatrix(window_thread_->GetGraphicsEngine().GetModelViewMatrix()); tl->SetGeometry(geo); active_paint_layer_stack_.push_front(tl); } void BasePainter::PushDrawTextureLayer(GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr DeviceTexture, TexCoordXForm texxform, const Color &color, bool WriteAlpha, const ROPConfig &ROP) { PushTextureLayer(graphics_engine, geo, DeviceTexture, texxform, color, WriteAlpha, ROP); PaintBackground(graphics_engine, geo); } void BasePainter::PushDrawColorizeTextureLayer(GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr DeviceTexture, TexCoordXForm texxform, const Color &color, bool WriteAlpha, const ROPConfig &ROP, const Color &blend_color, LayerBlendMode layer_blend_mode) { PushColorizeTextureLayer(graphics_engine, geo, DeviceTexture, texxform, color, WriteAlpha, ROP, blend_color, layer_blend_mode); PaintBackground(graphics_engine, geo); } void BasePainter::PopBackground(int level) { PopPaintLayer(level); } void BasePainter::PopPaintLayer(int level) { nuxAssert(level >= 0); while ((level >= 1) && (!active_paint_layer_stack_.empty())) { AbstractPaintLayer *paint_layer = (*active_paint_layer_stack_.begin()); delete paint_layer; active_paint_layer_stack_.pop_front(); level--; } } void BasePainter::EmptyBackgroundStack() { EmptyActivePaintLayerStack(); } void BasePainter::EmptyActivePaintLayerStack() { std::list::iterator background_layer_it; for (background_layer_it = active_paint_layer_stack_.begin(); background_layer_it != active_paint_layer_stack_.end(); ++background_layer_it) { delete(*background_layer_it); } active_paint_layer_stack_.clear(); } void BasePainter::EmptyPushedPaintLayerStack() { std::list >::iterator pushed_paint_layer_it; for (pushed_paint_layer_it = pushed_paint_layer_stack_.begin(); pushed_paint_layer_it != pushed_paint_layer_stack_.end(); ++pushed_paint_layer_it) { std::list paint_layer_stack = *pushed_paint_layer_it; { std::list::iterator paint_layer_it; for (paint_layer_it = paint_layer_stack.begin(); paint_layer_it != paint_layer_stack.end(); ++paint_layer_it) { delete(*paint_layer_it); } paint_layer_stack.clear(); } } active_paint_layer_stack_.clear(); } void BasePainter::PushBackgroundStack() { PushPaintLayerStack(); } void BasePainter::PushPaintLayerStack() { pushed_paint_layer_stack_.push_back(active_paint_layer_stack_); active_paint_layer_stack_.clear(); } void BasePainter::PopBackgroundStack() { PopPaintLayerStack(); } void BasePainter::PopPaintLayerStack() { // clear and delete EmptyActivePaintLayerStack(); active_paint_layer_stack_ = pushed_paint_layer_stack_.back(); pushed_paint_layer_stack_.pop_back(); } } nux-4.0.8+18.10.20180623/Nux/Painter.h0000644000000000000000000005162713313373365013141 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef PAINTER_H #define PAINTER_H #include #include #include #include "Utils.h" #include "NuxGraphics/GraphicsEngine.h" #include "PaintLayer.h" namespace nux { class TextLineRenderer; class BaseTexture; class GeometryPositioning { public: GeometryPositioning(); GeometryPositioning( HorizontalAlignment horizontal_aligment, VerticalAlignment vertical_aligment, bool stretch_horizontal = FALSE, bool stretch_vertical = FALSE, int horizontal_margin = 0, int vertical_margin = 0); ~GeometryPositioning(); bool m_stretch_horizontal; // if TRUE, the content width will be stretched over the width of the container. bool m_stretch_vertical; // if TRUE, the content height will be stretched over the height of the container. void SetAlignment(HorizontalAlignment ha, VerticalAlignment va) { m_vertical_aligment = va; m_horizontal_aligment = ha; } VerticalAlignment m_vertical_aligment; HorizontalAlignment m_horizontal_aligment; int m_horizontal_margin; // Add a margin to the horizontal alignment int m_vertical_margin; // Add a margin to the vertical alignment }; //! Compute the position of one geometry inside an other. /*! Compute the position of one geometry inside an other. @container_geo The container geometry @content_geo The content geometry @GeometryPositioning The parameter to use to compute the position of the content. @return the computed geometry. */ Geometry ComputeGeometryPositioning(const Geometry &container_geo, const Geometry &content_geo, GeometryPositioning gctx); //! State of UI controls /* Class storing the states of User interface controls such button, radio, checkbox, combobox. */ class InteractState { public: /* Default constructor. All states are set to false. */ InteractState(); InteractState(bool on, bool focus, bool prelight, bool disable); ~InteractState(); bool is_on; bool is_focus; bool is_prelight; bool is_disable; }; // enum PainterBackgroundType // { // eColorBackground = 0, // eShapeBackground, // eShapeCornerBackground, // eTextureBackground, // }; class TextureAlignmentStyle { public: TextureAlignmentStyle() { horz_alignment = eTACenter; vert_alignment = eTACenter; horizontal_margin = 0; vertical_margin = 0; }; TextureAlignmentStyle(TextureAlignment horz_align, TextureAlignment vert_align) { horz_alignment = horz_align; vert_alignment = vert_align; horizontal_margin = 0; vertical_margin = 0; }; ~TextureAlignmentStyle() {}; enum TextureAlignment horz_alignment; enum TextureAlignment vert_alignment; int horizontal_margin; int vertical_margin; }; class BasePainter { public: BasePainter(WindowThread *window_thread); virtual ~BasePainter(); int intTest; //! Draw unscaled texture at position(x, y). The size of the quad is the size of the texture. virtual void Draw2DTexture(GraphicsEngine &graphics_engine, BaseTexture *Texture, int x, int y) const; virtual void Draw2DTextureAligned(GraphicsEngine &graphics_engine, BaseTexture *Texture, const Geometry &g, TextureAlignmentStyle tex_align) const; /////////////////// //////////////////// // TEXT PAINTING // //////////////////// virtual int PaintColorTextLineEdit(GraphicsEngine &graphics_engine, const Geometry &g, std::string const& Str, Color TextColor, bool WriteAlphaChannel, Color SelectedTextColor, Color SelectedTextBackgroundColor, Color TextBlinkColor, Color CursorColor, bool ShowCursor, unsigned int CursorPosition, int offset = 0, int selection_start = 0, int selection_end = 0) const; virtual int PaintTextLineStatic(GraphicsEngine &graphics_engine, ObjectPtr Font, Geometry const& g, std::string const& text_line, Color const& color = Color(0.0f, 0.0f, 0.0f, 1.0f), bool WriteAlphaChannel = true, TextAlignment alignment = eAlignTextLeft) const; void Paint2DQuadColor(GraphicsEngine &graphics_engine, const Geometry &g, const Color &c0) const; void Paint2DQuadColor(GraphicsEngine &graphics_engine, const Geometry &g, const Color &c0_top_left, const Color &c1_bottom_left, const Color &c2_bottom_right, const Color &c3_top_right) const; void Paint2DQuadColor(GraphicsEngine &graphics_engine, int x, int y, int width, int height, const Color &c0) const; void Paint2DQuadColor(GraphicsEngine &graphics_engine, int x, int y, int width, int height, const Color &c0_top_left, const Color &c1_bottom_left, const Color &c2_bottom_right, const Color &c3_top_right) const; //! Paint a 2D quad with a gradient color going from Top to Bottom. /*! Paint a 2D quad with a gradient color going from Top to Bottom. @param g Geometry of the quad. @param TopColor color at the top of the quad. @param TopColor color at the bottom of the quad. */ void Paint2DQuadVGradient(GraphicsEngine &graphics_engine, const Geometry &g, Color TopColor, Color BottomColor) const; //! Paint a 2D quad with a gradient color going from Left to Right. /*! Paint a 2D quad with a gradient color going from Left to Right. @param g Geometry of the quad. @param LeftColor color at the top of the quad. @param RightColor color at the bottom of the quad. */ void Paint2DQuadHGradient(GraphicsEngine &graphics_engine, const Geometry &g, Color LeftColor, Color RightColor) const; void Paint2DQuadWireframe(GraphicsEngine &graphics_engine, const Geometry &g, Color c0) const; void Paint2DQuadWireframe(GraphicsEngine &graphics_engine, const Geometry &g, Color c_top_left, Color c_bottom_left, Color c_bottom_right, Color c_top_right) const; void Paint2DQuadWireframe(GraphicsEngine &graphics_engine, int x, int y, int width, int height, Color c0) const; void Paint2DQuadWireframe(GraphicsEngine &graphics_engine, int x, int y, int width, int height, Color c_top_left, Color c_bottom_left, Color c_bottom_right, Color c_top_right) const; void Draw2DTriangleColor(GraphicsEngine &graphics_engine, int x0, int y0, int x1, int y1, int x2, int y2, Color c0); void Draw2DTriangleColor(GraphicsEngine &graphics_engine, int x0, int y0, int x1, int y1, int x2, int y2, Color c0, Color c1, Color c2); ////////////////////// // DRAW LINES // ////////////////////// void Draw2DLine(GraphicsEngine &graphics_engine, int x0, int y0, int x1, int y1, Color c0) const; void Draw2DLine(GraphicsEngine &graphics_engine, int x0, int y0, int x1, int y1, Color c0, Color c1) const; //////////////////// // Themes // //////////////////// void PaintShape(GraphicsEngine &graphics_engine, const Geometry &geo, const Color &c0, UXStyleImageRef style, bool WriteAlpha = true) const; void PaintShapeCorner(GraphicsEngine &graphics_engine, const Geometry &geo, const Color &c0, UXStyleImageRef style, long corners, bool WriteAlpha = true) const; void PaintShapeROP(GraphicsEngine &graphics_engine, const Geometry &geo, const Color &c0, UXStyleImageRef style, bool WriteAlpha = true, const ROPConfig &ROP = ROPConfig::Default) const; void PaintShapeCornerROP(GraphicsEngine &graphics_engine, const Geometry &geo, const Color &c0, UXStyleImageRef style, long corners, bool WriteAlpha = true, const ROPConfig &ROP = ROPConfig::Default) const; void PaintTextureShape(GraphicsEngine &graphics_engine, const Geometry &geo, UXStyleImageRef style) const; void PaintTextureShape(GraphicsEngine &graphics_engine, const Geometry &geo, BaseTexture *Texture, int border_left, int border_right, int border_top, int border_bottom, bool draw_borders_only, bool premultiply = true) const; //! Draw Check Box. /*! Draw a Check box. */ void PaintCheckBox(GraphicsEngine &graphics_engine, const Geometry &geo, const InteractState &interaction_state, Color check_mark_color = Color(0x0), Color check_box_color = Color(0x0)); void PaintRadioButton(GraphicsEngine &graphics_engine, const Geometry &geo, const InteractState &interaction_state, Color check_mark_color = Color(0x0), Color check_box_color = Color(0x0)); void PaintHorizontalGradientQuad(GraphicsEngine &graphics_engine, const Geometry &geo, int num_color, float *percentage_array, Color *color_array); public: void PushColorLayer(GraphicsEngine &graphics_engine, const Geometry &geo, Color color, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default); void PushShapeLayer(GraphicsEngine &graphics_engine, Geometry geo, UXStyleImageRef imageStyle, const Color &color, unsigned long Corners = eAllCorners, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default); void PushSliceScaledTextureLayer(GraphicsEngine &graphics_engine, Geometry geo, UXStyleImageRef imageStyle, const Color &color, unsigned long Corners = eAllCorners, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default); void PushTextureLayer(GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr DeviceTexture, TexCoordXForm texxform, const Color &color, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default); void PushColorizeTextureLayer(GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr DeviceTexture, TexCoordXForm texxform, const Color &color, bool WriteAlpha, const ROPConfig &ROP, const Color &blend_color, LayerBlendMode layer_blend_mode); void PushDrawColorLayer(GraphicsEngine &graphics_engine, const Geometry &geo, Color color, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default); void PushDrawShapeLayer(GraphicsEngine &graphics_engine, Geometry geo, UXStyleImageRef imageStyle, const Color &color, unsigned long Corners = eAllCorners, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default); void PushDrawSliceScaledTextureLayer(GraphicsEngine &graphics_engine, Geometry geo, UXStyleImageRef imageStyle, const Color &color, unsigned long Corners = eAllCorners, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default); void PushDrawTextureLayer(GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr DeviceTexture, TexCoordXForm texxform, const Color &color, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default); void PushDrawColorizeTextureLayer(GraphicsEngine& graphics_engine, Geometry geo, ObjectPtr DeviceTexture, TexCoordXForm texxform, const Color &color, bool WriteAlpha, const ROPConfig &ROP, const Color &blend_color, LayerBlendMode layer_blend_mode); void PushCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr texture0, TexCoordXForm texxform0, const Color &color0, ObjectPtr texture1, TexCoordXForm texxform1, const Color &color1, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP); void PushDrawCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr texture0, TexCoordXForm texxform0, const Color &color0, ObjectPtr texture1, TexCoordXForm texxform1, const Color &color1, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP); void PushCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, const Color& blend_color, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP); void PushDrawCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, ObjectPtr texture0, TexCoordXForm texxform0, const Color &color0, const Color& blend_color, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP); void PushCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, const Color& base_color, ObjectPtr texture0, TexCoordXForm texxform0, const Color& color0, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP); void PushDrawCompositionLayer (GraphicsEngine &graphics_engine, Geometry geo, const Color& base_color, ObjectPtr texture0, TexCoordXForm texxform0, const Color &color0, LayerBlendMode layer_blend_mode, bool WriteAlpha, const ROPConfig &ROP); void PushLayer(GraphicsEngine &graphics_engine, const Geometry &geo, AbstractPaintLayer *layer); void PushDrawLayer(GraphicsEngine &graphics_engine, const Geometry &geo, AbstractPaintLayer *layer); //! Render a paint layer. /*! When calling this function make sure to assign a correct geometry to the paint layer parameter. */ void RenderSinglePaintLayer(GraphicsEngine &graphics_engine, Geometry geo, AbstractPaintLayer *paint_layer); //! Deprecated. Use PopPaintLayer. void PopBackground(int level = 1); //! Pop the top most paint layers from the active paint layer stack. /*! Pop the top most paint layers from the active paint layer stack. @param level The number of layer to pop off. */ void PopPaintLayer(int level = 1); //! Deprecated. Use EmptyActivePaintLayerStack. void EmptyBackgroundStack(); //! Empty the active paint layer stack. /*! Empty the active paint layer stack. All paint layers in the active stack are deleted. */ void EmptyActivePaintLayerStack(); //! Deprecated. Use PaintActivePaintLayerStack. void PaintBackground(GraphicsEngine &graphics_engine, const Geometry &geo); //! Paint all the layers in the active paint layer stack. /*! Paint all the layers in the active paint layer stack. */ void PaintActivePaintLayerStack(GraphicsEngine &graphics_engine, const Geometry &geo); //! Paint all layers in all stacks /* Paint all layers in all stacks with the current model-view and projection matrices. This is useful for redirected rendering to textures. */ void PaintAllLayerStack(GraphicsEngine& graphics_engine, const Geometry& geo); //! Deprecated. Use PushPaintLayerStack. void PushBackgroundStack(); //! Push the current paint layer stack. /*! Push the current paint layer stack. */ void PushPaintLayerStack(); //! Deprecated. Use PopPaintLayerStack. void PopBackgroundStack(); //! Pop a previously pushed paint layer stack. /*! Pop a previously pushed paint layer stack. */ void PopPaintLayerStack(); private: //! Clear all the pushed paint layers. /*! Clear all the pushed paint layers. Each layer in a paint layer stack is deleted. */ void EmptyPushedPaintLayerStack(); std::list active_paint_layer_stack_; std::list > pushed_paint_layer_stack_; WindowThread *window_thread_; //!< The WindowThread to which this object belongs. }; class PushBackgroundScope { public: PushBackgroundScope(BasePainter &painter, GraphicsEngine &graphics_engine, const Geometry &geo, UXStyleImageRef image_style, bool PushAndDraw = false) : m_painter(painter) { if (PushAndDraw) m_painter.PushDrawShapeLayer(graphics_engine, geo, image_style, color::White, eAllCorners); else m_painter.PushShapeLayer(graphics_engine, geo, image_style, color::White, eAllCorners); } ~PushBackgroundScope() { //m_painter.PopBackground(); } private: BasePainter &m_painter; }; class PushShapeBackgroundScope { public: PushShapeBackgroundScope(BasePainter &painter, GraphicsEngine &graphics_engine, const Geometry &geo, UXStyleImageRef image_style, const Color &color, bool PushAndDraw = false, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default) : m_painter(painter) { if (PushAndDraw) m_painter.PushDrawShapeLayer(graphics_engine, geo, image_style, color, eAllCorners, WriteAlpha, ROP); else m_painter.PushShapeLayer(graphics_engine, geo, image_style, color, eAllCorners, WriteAlpha, ROP); } ~PushShapeBackgroundScope() { m_painter.PopBackground(); } private: BasePainter &m_painter; }; class PushShapeCornerBackgroundScope { public: PushShapeCornerBackgroundScope(BasePainter &painter, GraphicsEngine &graphics_engine, const Geometry &geo, UXStyleImageRef image_style, const Color &color, long corners, bool PushAndDraw = false, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default) : m_painter(painter) { if (PushAndDraw) m_painter.PushDrawShapeLayer(graphics_engine, geo, image_style, color, corners, WriteAlpha, ROP); else m_painter.PushShapeLayer(graphics_engine, geo, image_style, color, corners, WriteAlpha, ROP); } ~PushShapeCornerBackgroundScope() { m_painter.PopBackground(); } private: BasePainter &m_painter; }; class PushColorBackgroundScope { public: PushColorBackgroundScope(BasePainter &painter, GraphicsEngine &graphics_engine, const Geometry &geo, const Color &color, bool PushAndDraw = false, bool WriteAlpha = false, const ROPConfig &ROP = ROPConfig::Default) : m_painter(painter) { if (PushAndDraw) m_painter.PushDrawColorLayer(graphics_engine, geo, color, WriteAlpha, ROP); else m_painter.PushColorLayer(graphics_engine, geo, color, WriteAlpha, ROP); } ~PushColorBackgroundScope() { m_painter.PopBackground(); } private: BasePainter &m_painter; }; } #endif // PAINTER_H nux-4.0.8+18.10.20180623/Nux/Panel.cpp0000644000000000000000000001056213313373365013122 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #include "WindowCompositor.h" #include "VScrollBar.h" #include "HScrollBar.h" #include "Panel.h" namespace nux { Panel::Panel(NUX_FILE_LINE_DECL) : ScrollView(NUX_FILE_LINE_PARAM) , m_layout(0) { m_top_border = 0; m_border = 0; } Panel::~Panel() { // Delete all the interface object: This is a problem... The widget should be destroy by there associated parameters //delete vlayout; m_layout = NULL; } void Panel::Draw(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void Panel::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { graphics_engine.PushClippingRectangle(GetGeometry()); graphics_engine.PushClippingRectangle(Rect(m_ViewX, m_ViewY, m_ViewWidth, m_ViewHeight)); if (m_layout) { graphics_engine.PushClippingRectangle(m_layout->GetGeometry()); m_layout->ProcessDraw(graphics_engine, force_draw); graphics_engine.PopClippingRectangle(); } graphics_engine.PopClippingRectangle(); if (m_vertical_scrollbar_enable) { _vscrollbar->ProcessDraw(graphics_engine, force_draw); } if (m_horizontal_scrollbar_enable) { _hscrollbar->ProcessDraw(graphics_engine, force_draw); } graphics_engine.PopClippingRectangle(); } void Panel::AddWidget(View *ic, int stretchfactor) { if (ic && m_layout) { m_layout->AddView(ic, stretchfactor); // if (stretchfactor ==0): the WidgetLayout geometry will be set to SetGeometry(0,0,1,1); // and the children will take their natural size by expending WidgetLayout. // If the parent of WidgetLayout offers more space, it won't be used by WidgetLayout. ComputeContentSize(); } } void Panel::AddWidget(std::list *ViewList) { std::list::iterator it; for (it = ViewList->begin(); it != ViewList->end(); it++) { AddWidget((*it)); } } bool Panel::SetLayout(Layout *layout) { if (View::SetLayout(layout) == false) { return false; } m_layout = view_layout_; FormatContent(); return true; } void Panel::clearContent() { m_layout->Clear(); } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. void Panel::PreLayoutManagement() { ScrollView::PreLayoutManagement(); } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. long Panel::PostLayoutManagement(long LayoutResult) { long result = ScrollView::PostLayoutManagement(LayoutResult); return result; } // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. void Panel::ComputeContentPosition(float offsetX, float offsetY) { ScrollView::ComputeContentPosition(offsetX, offsetY); } void Panel::ScrollLeft(float stepx, int mousedx) { ScrollView::ScrollLeft(stepx, mousedx); ComputeContentSize(); QueueDraw(); } void Panel::ScrollRight(float stepx, int mousedx) { ScrollView::ScrollRight(stepx, mousedx); ComputeContentSize(); QueueDraw(); } void Panel::ScrollUp(float stepy, int mousedy) { ScrollView::ScrollUp(stepy, mousedy); ComputeContentSize(); QueueDraw(); } void Panel::ScrollDown(float stepy, int mousedy) { ScrollView::ScrollDown(stepy, mousedy); ComputeContentSize(); QueueDraw(); } bool Panel::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/Panel.h0000644000000000000000000000436113313373365012567 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef PANEL_H #define PANEL_H #include "ScrollView.h" namespace nux { class Layout; class Panel: public ScrollView { public: Panel(NUX_FILE_LINE_PROTO); ~Panel(); //void AddWidget(View* ic); void AddWidget(View *ic, int stretchfactor = 1); void AddWidget(std::list *ViewList); virtual bool SetLayout(Layout *layout); void clearContent(); // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. virtual void PreLayoutManagement(); // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. virtual long PostLayoutManagement(long LayoutResult); // Get a change to do any work on an element. // Here we need to position the header by hand because it is not under the control of vlayout. virtual void ComputeContentPosition(float offsetX, float offsetY); protected: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual void ScrollLeft(float stepx, int mousedx); virtual void ScrollRight(float stepx, int mousedx); virtual void ScrollUp(float stepy, int mousedy); virtual void ScrollDown(float stepy, int mousedy); virtual bool AcceptKeyNavFocus(); private: Layout *m_layout; }; } #endif // PANEL_H nux-4.0.8+18.10.20180623/Nux/PangoText.cpp0000644000000000000000000003323713313373365014000 0ustar #include "Nux.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "Validator.h" #include "cairo/cairo.h" #include "pango/pango.h" #include "pango/pangocairo.h" #include "NuxGraphics/CairoGraphics.h" #include "PangoText.h" namespace nux { PangoText::PangoText(const char* text, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { _pango_font_map = pango_ft2_font_map_new(); _pango_context = pango_font_map_create_context(PANGO_FONT_MAP(_pango_font_map)); _pango_layout = pango_layout_new(_pango_context); _pango_font_desc = pango_font_description_from_string("Sans, 20"); _size_match_text = true; _textColor = color::White; _texture2D = 0; SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); SetText(text); } PangoText::~PangoText() { if (_cairoGraphics == 0) delete(_cairoGraphics); if (_texture2D == 0) delete(_texture2D); } void PangoText::PreLayoutManagement() { int textWidth = 0; int textHeight = 0; GetTextExtents("Ubuntu", textWidth, textHeight); _pre_layout_width = GetBaseWidth(); _pre_layout_height = GetBaseHeight(); SetBaseSize(textWidth, textHeight); if (_texture2D == 0) { UpdateTextLayout(); } View::PreLayoutManagement(); } long PangoText::PostLayoutManagement(long layoutResult) { // long result = View::PostLayoutManagement(layoutResult); long result = 0; int w = GetBaseWidth(); int h = GetBaseHeight(); if (_pre_layout_width < w) result |= eLargerWidth; else if (_pre_layout_width > w) result |= eSmallerWidth; else result |= eCompliantWidth; if (_pre_layout_height < h) result |= eLargerHeight; else if (_pre_layout_height > h) result |= eSmallerHeight; else result |= eCompliantHeight; return result; } void PangoText::SetSizeMatchText(bool size_match_text) { _size_match_text = size_match_text; } bool PangoText::GetSizeMatchText() const { return _size_match_text; } void PangoText::Draw(GraphicsEngine& gfxContext, bool forceDraw) { Geometry base = GetGeometry(); gfxContext.PushClippingRectangle(base); TexCoordXForm texxform; texxform.SetWrap(TEXWRAP_REPEAT, TEXWRAP_REPEAT); texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD); gfxContext.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); gfxContext.QRP_1Tex(base.x, base.y, base.width, base.height, _texture2D->GetDeviceTexture(), texxform, _textColor); gfxContext.GetRenderStates().SetBlend(false); gfxContext.PopClippingRectangle(); } void PangoText::DrawContent(GraphicsEngine& gfxContext, bool forceDraw) { } void PangoText::SetText(std::string text) { if (_text != text) { _text = text; UpdateTextLayout(); sigTextChanged.emit(this); } } void PangoText::SetTextColor(Color textColor) { if (_textColor != textColor) { _textColor = textColor; sigTextColorChanged.emit(this); } } void PangoText::GetTextExtents(int &width, int &height) { GetTextExtents("Ubuntu", width, height); } void PangoText::GetTextExtents(const char* font, int& width, int& height) { cairo_surface_t* surface = NULL; cairo_t* cr = NULL; PangoLayout* layout = NULL; PangoFontDescription* desc = NULL; PangoContext* pangoCtx = NULL; PangoRectangle logRect = {0, 0, 0, 0}; int dpi = 96; // sanity check if (!font) return; surface = cairo_image_surface_create(CAIRO_FORMAT_A1, 1, 1); cr = cairo_create(surface); CairoFontOptions font_options; cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_DEFAULT); cairo_font_options_set_subpixel_order(font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_DEFAULT); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_set_font_options(cr, font_options); layout = pango_cairo_create_layout(cr); desc = pango_font_description_from_string(font); pango_font_description_set_weight(desc, PANGO_WEIGHT_NORMAL); pango_layout_set_font_description(layout, desc); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); pango_layout_set_text(layout, _text.c_str(), -1); pangoCtx = pango_layout_get_context(layout); // is not ref'ed pango_cairo_context_set_font_options(pangoCtx, font_options); // use some default DPI-value pango_cairo_context_set_resolution(pangoCtx, dpi); pango_layout_context_changed(layout); pango_layout_get_extents(layout, NULL, &logRect); width = logRect.width / PANGO_SCALE; height = logRect.height / PANGO_SCALE; // clean up pango_font_description_free(desc); g_object_unref(layout); cairo_destroy(cr); cairo_surface_destroy(surface); } void PangoText::DrawText(void* cairo_context, int width, int height, Color color) { cairo_t* cr = (cairo_t*) cairo_context; int textWidth = 0; int textHeight = 0; PangoLayout* layout = NULL; PangoFontDescription* desc = NULL; PangoContext* pangoCtx = NULL; int dpi = 0; GetTextExtents("Ubuntu", textWidth, textHeight); CairoFontOptions font_options; cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_DEFAULT); cairo_font_options_set_subpixel_order(font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_DEFAULT); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_set_font_options(cr, font_options); layout = pango_cairo_create_layout(cr); desc = pango_font_description_from_string("Ubuntu"); pango_layout_set_font_description(layout, desc); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); pango_layout_set_text(layout, _text.c_str(), -1); pangoCtx = pango_layout_get_context(layout); pango_cairo_context_set_font_options(pangoCtx, font_options); pango_cairo_context_set_resolution(pangoCtx, dpi); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0.0f, 0.0f, 0.0f, 0.0f); cairo_paint(cr); cairo_set_source_rgba(cr, color.red, color.green, color.blue, color.alpha); pango_layout_context_changed(layout); cairo_move_to(cr, 0.0f, 0.0f); pango_cairo_show_layout(cr, layout); // clean up pango_font_description_free(desc); g_object_unref(layout); } void PangoText::UpdateTextLayout() { pango_layout_set_text(_pango_layout, _text.c_str(), -1); // reset the glyph string if (_glyph_text) delete(_glyph_text); _glyph_text = 0; _glyph_length = 0; int max_g = 0; double pango_to_ink = (1.0/((double) PANGO_SCALE)); PangoLayoutIter* pIter = pango_layout_get_iter(_pango_layout); // and go! do { // typedef struct { // PangoLayout *layout; // gint start_index; // start of line as byte index into layout->text. // gint length; // length of line in bytes. // GSList *runs; // a list containing the runs of the line in visual order. // guint is_paragraph_start : 1; // TRUE if this is the first line of the paragraph. // guint resolved_dir : 3; // Resolved direction of line. // } PangoLayoutLine; PangoLayoutLine* pLine = pango_layout_iter_get_line(pIter); // no need for unref int plOffset = pLine->start_index; // start of the line in the uni32_text PangoRectangle ink_r; PangoRectangle log_r; pango_layout_iter_get_line_extents(pIter, &ink_r, &log_r); double plY = (1.0 / ((double) PANGO_SCALE)) * ((double) log_r.y); // start position of this line of the layout double plX = (1.0 / ((double) PANGO_SCALE)) * ((double) log_r.x); GSList* curR = pLine->runs; // Iterate over the runs of this line while (curR) { // typedef struct { // PangoItem *item; // a PangoItem structure that provides information about a segment of text. // PangoGlyphString *glyphs; // the glyphs obtained by shaping the text corresponding to item. // } PangoLayoutRun, PangoGlyphItem; // // typedef struct { // gint offset; // the offset of the segment from the beginning of the string in bytes. // gint length; // the length of the segment in bytes. // gint num_chars; // the length of the segment in characters. // PangoAnalysis analysis; // the properties of the segment. // } PangoItem; // typedef struct { // gint num_glyphs; // // PangoGlyphInfo *glyphs; // // /* This is a memory inefficient way of representing the information // * here - each value gives the byte index within the text // * corresponding to the glyph string of the start of the cluster to // * which the glyph belongs. // */ // gint *log_clusters; // } PangoGlyphString; PangoLayoutRun* pRun = (PangoLayoutRun*) curR->data; int prOffset = pRun->item->offset; // the offset of the segment from the beginning of the line in bytes if (pRun) { // a run has uniform font/directionality/etc... int o_g_l = _glyph_length; // save the index of the first glyph we'll add for (int i = 0; i < pRun->glyphs->num_glyphs; i++) { // add glyph sequentially, reading them from the run. realloc space for the glyphs if (_glyph_length >= max_g) { max_g = 2 * _glyph_length + 1; pango_glyph* temp = new pango_glyph [max_g + 1]; if (_glyph_length == 0) { _glyph_text = temp; } else { std::memcpy(temp, _glyph_text, _glyph_length * sizeof(pango_glyph)); delete _glyph_text; _glyph_text = temp; } } // fill the glyph info _glyph_text[_glyph_length].font = pRun->item->analysis.font; _glyph_text[_glyph_length].gl = pRun->glyphs->glyphs[i].glyph; _glyph_text[_glyph_length].uni_st = plOffset + prOffset + pRun->glyphs->log_clusters[i]; // depending on the directionality, the last uni32 codepoint for this glyph is the first of the next char // or the first of the previous if (pRun->item->analysis.level == 1) { // rtl if (i < pRun->glyphs->num_glyphs - 1) { _glyph_text[_glyph_length + 1].uni_en = _glyph_text[_glyph_length].uni_st; } _glyph_text[_glyph_length].uni_dir = 1; _glyph_text[_glyph_length + 1].uni_dir = 1; // set the directionality for the next too, so that the last glyph in // the array has the correct direction } else { // ltr if (i > 0) { _glyph_text[_glyph_length - 1].uni_en = _glyph_text[_glyph_length].uni_st; } _glyph_text[_glyph_length].uni_dir = 0; _glyph_text[_glyph_length + 1].uni_dir = 0; } // set the position // the layout is an infinite line _glyph_text[_glyph_length].x = plX + pango_to_ink * ((double) pRun->glyphs->glyphs[i].geometry.x_offset); _glyph_text[_glyph_length].y = plY + pango_to_ink * ((double) pRun->glyphs->glyphs[i].geometry.y_offset); // advance to the next glyph plX += pango_to_ink * ((double) pRun->glyphs->glyphs[i].geometry.width); // and set the next glyph's position, in case it's the terminating glyph _glyph_text[_glyph_length+1].x = plX; _glyph_text[_glyph_length+1].y = plY; _glyph_length++; } // and finish filling the info // notably, the uni_en of the last char in ltr text and the uni_en of the first in rtl are still not set if (pRun->item->analysis.level == 1) { // rtl if (_glyph_length > o_g_l) _glyph_text[o_g_l].uni_en=plOffset+prOffset+pRun->item->length; } else { if (_glyph_length > 0) _glyph_text[_glyph_length-1].uni_en=plOffset+prOffset+pRun->item->length; } // the terminating glyph has glyph_id=0 because it means 'no glyph' _glyph_text[_glyph_length].gl = 0; // and is associated with no text(but you cannot set uni_st=uni_en=0, because the termination // is expected to be the glyph for the termination of the uni32_text) _glyph_text[_glyph_length].uni_st = _glyph_text[_glyph_length].uni_en = plOffset + prOffset + pRun->item->length; } curR = curR->next; } } while ( pango_layout_iter_next_line(pIter)); pango_layout_iter_free(pIter); } void PangoText::ComputeTextLayout() { PangoLayout* layout = NULL; PangoFontDescription* desc = NULL; PangoContext* pangoCtx = NULL; PangoRectangle logRect = {0, 0, 0, 0}; int dpi = 96; } } nux-4.0.8+18.10.20180623/Nux/PangoText.h0000644000000000000000000000666513313373365013452 0ustar #ifndef PANGOTEXT_H #define PANGOTEXT_H #include "pango/pango.h" #include "pango/pango-fontmap.h" #include namespace nux { // taken from inkscape typedef struct { int gl; // glyph_id double x,y; // glyph position in the layout(nominal sizes, in the [0..1] range) bool char_start; // is this glyph the beginning of a letter(rtl is taken in account) bool word_start; // is this glyph the beginning of a word bool para_start; // is this glyph the beginning of a paragraph(for indentation) char uni_dir; // bidi orientation of the run containing this glyph int uni_st,uni_en; // start and end positions of the text corresponding to this glyph: you always have uni_st < uni_en PangoFont* font; // font this glyph uses(for bidi text, you need several fonts) } pango_glyph; class CairoGraphics; class PangoText: public View { public: PangoText(const char* text, NUX_FILE_LINE_PROTO); ~PangoText(); //! Set size of widget according to the text extent. /*! @param size_match_text If true, the widget size is set to match the size of the text on the screen. */ void SetSizeMatchText(bool size_match_text); //! Return true if the widget with changes to match the text width. bool GetSizeMatchText() const; void SetText(std::string text); void SetTextColor(Color textColor); sigc::signal sigTextChanged; sigc::signal sigTextColorChanged; protected: void PreLayoutManagement(); long PostLayoutManagement(long layoutResult); void Draw(GraphicsEngine& gfxContext, bool forceDraw); void DrawContent(GraphicsEngine& gfxContext, bool forceDraw); void GetTextExtents(int &width, int &height); typedef struct { int gl; // glyph_id double x,y; // glyph position in the layout(nominal sizes, in the [0..1] range) bool char_start; // is this glyph the beginning of a letter(rtl is taken in account) bool word_start; // is this glyph the beginning of a word bool para_start; // is this glyph the beginning of a paragraph(for indentation) char uni_dir; // bidi orientation of the run containing this glyph int uni_st,uni_en; // start and end positions of the text corresponding to this glyph // you always have uni_st < uni_en PangoFont* font; // font this glyph uses(for bidi text, you need several fonts) } pango_glyph; std::string _text; Color _textColor; CairoGraphics *_cairoGraphics; BaseTexture *_texture2D; int _pre_layout_width; int _pre_layout_height; bool _size_match_text; PangoLayout* _pango_layout; PangoContext* _pango_context; PangoFontMap* _pango_font_map; PangoFontDescription* _pango_font_desc; pango_glyph* _glyph_text; // glyph string computed for uni32_text int _glyph_length; // number of glyph in the glyph_text array void ComputeTextLayout(); void GetTextExtents(const char* font, int& width, int& height); void DrawText(void* cairo_context, int width, int height, Color color); void UpdateTextLayout(); }; } #endif // PANGOTEXT_H nux-4.0.8+18.10.20180623/Nux/PopUpWindow.cpp0000644000000000000000000000237413313373365014320 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "WindowCompositor.h" #include "PopUpWindow.h" namespace nux { PopUpWindow::PopUpWindow() { EnableTitleBar(false); ShowWindow(false); SetTopBorder(0); SetBorder(0); SetWindowSizeMatchLayout(true); SetMinimumSize(20, 20); } PopUpWindow::~PopUpWindow() { } void PopUpWindow::Show() { //m_Window.ComputeContentSize(); ShowWindow(true); } void PopUpWindow::Hide() { ShowWindow(false); } } nux-4.0.8+18.10.20180623/Nux/PopUpWindow.h0000644000000000000000000000243213313373365013760 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef POPUPWINDOW_H #define POPUPWINDOW_H #include "FloatingWindow.h" namespace nux { class Layout; // This class implements a window without a taskbar. It can contain any can of layout. // The purpose is to implement a window that pop ups with complexe widget inside. // The basic popup widget only displays text options. class PopUpWindow : public FloatingWindow { public: PopUpWindow(); ~PopUpWindow(); void Show(); void Hide(); private: }; } #endif // POPUPWINDOW_H nux-4.0.8+18.10.20180623/Nux/ProgramFramework/0000755000000000000000000000000013313373365014640 5ustar nux-4.0.8+18.10.20180623/Nux/ProgramFramework/ProgramTemplate.cpp0000644000000000000000000001341113313373365020447 0ustar /* * Copyright 2012 Inalogic Inc. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see * * * Authored by: Jay Taoko * */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include "Nux.h" #include "VLayout.h" #include "HLayout.h" #include "WindowThread.h" #include "TextEntry.h" #include "ProgramTemplate.h" namespace { unsigned int MAX_MESSAGE_LEN = 1024; std::string ReadMessageOnFd(int fd) { char buf[MAX_MESSAGE_LEN + 1]; ssize_t bytes = read(fd, reinterpret_cast (buf), MAX_MESSAGE_LEN); if (bytes == -1) throw std::runtime_error(std::string("read: ") + strerror(errno)); buf[bytes] = '\0'; return std::string(buf); } bool CheckForMessageOnFd(int fd, const std::string &msg) { struct pollfd pfd; pfd.events = POLLIN; pfd.revents = 0; pfd.fd = fd; if (poll(&pfd, 1, -1) == -1) throw std::runtime_error(std::string("poll: ") + strerror(errno)); if (ReadMessageOnFd(fd) == msg) return true; else return false; } void WaitForMessageOnFd(int fd, const std::string &msg) { while (!CheckForMessageOnFd(fd, msg)); } void SendMessageToFd(int fd, const std::string &msg) { if (msg.size() > MAX_MESSAGE_LEN) { std::stringstream ss; ss << "Only messages up to " << MAX_MESSAGE_LEN << " chars are supported."; throw std::runtime_error(ss.str ()); } if (write(fd, reinterpret_cast (const_cast(msg.c_str())), msg.size()) == -1) throw std::runtime_error(std::string("write: ") + strerror(errno)); } } ProgramTemplate::ProgramTemplate(const char* program_name, int window_width, int window_height, int program_life_span) { ready_to_go_ = false; window_width_ = window_width; window_height_ = window_height; if (window_width_ < 100) window_width_ = 100; if (window_height_ < 100) window_height_ = 100; timeout_signal_ = NULL; window_thread_ = NULL; program_name_ = program_name; program_life_span_ = program_life_span; if (program_life_span_ > 0 && program_life_span_ < 1000) { // Minimum life span is 1 second. program_life_span_ = 1000; } if (pipe2(test_pipe_, O_CLOEXEC) == -1) throw std::runtime_error(strerror(errno)); if (pipe2(program_pipe_, O_CLOEXEC) == -1) throw std::runtime_error(strerror(errno)); } ProgramTemplate::~ProgramTemplate() { if (window_thread_) delete window_thread_; } void ProgramTemplate::Startup() { nux::NuxInitialize(0); window_thread_ = nux::CreateGUIThread(program_name_.c_str(), window_width_, window_height_, NULL, ProgramTemplate::ThreadInitializer, this); window_thread_->window_configuration.connect(sigc::mem_fun(this, &ProgramTemplate::WaitForConfigureEvent)); } void ProgramTemplate::UserInterfaceSetup() { // nux::VLayout *MainVLayout = new nux::VLayout(NUX_TRACKER_LOCATION); // nux::TextEntry *text_entry_0 = new nux::TextEntry(TEXT("0123456789abcdefghij"), NUX_TRACKER_LOCATION); // MainVLayout->AddView(text_entry_0, 0, nux::eCenter, nux::eFull); // MainVLayout->SetVerticalInternalMargin(10); // MainVLayout->SetContentDistribution(nux::eStackCenter); // nux::GetWindowThread()->SetLayout(MainVLayout); // nux::ColorLayer background(nux::Color(0xFF4D4D4D)); // window_thread_->SetWindowBackgroundPaintLayer(&background); } void ProgramTemplate::Run() { if (window_thread_ == NULL) return; if (program_life_span_ > 0) { timeout_signal_ = new nux::TimeOutSignal(); timeout_signal_->tick.connect(sigc::mem_fun(this, &ProgramTemplate::ProgramExitCall)); window_thread_->GetTimerHandler().AddOneShotTimer(program_life_span_, timeout_signal_, NULL, NULL); } window_thread_->Run(NULL); } void ProgramTemplate::SendMessageToProgram(const std::string &msg) { SendMessageToFd(program_pipe_[1], msg); } void ProgramTemplate::WaitForMessageFromProgram(const std::string &msg) { WaitForMessageOnFd(test_pipe_[0], msg); } void ProgramTemplate::SendMessageToTest(const std::string &msg) { SendMessageToFd(test_pipe_[1], msg); } void ProgramTemplate::MessageReceivedFromTest() { HandleProgramMessage(ReadMessageOnFd(program_pipe_[0])); } void ProgramTemplate::ThreadInitializer(nux::NThread *, void *data) { using namespace std::placeholders; /* Monitor the test-to-app fd for messages */ ProgramTemplate *pt = reinterpret_cast(data); pt->window_thread_->WatchFdForEvents(pt->program_pipe_[0], std::bind(&ProgramTemplate::MessageReceivedFromTest, pt)); } void ProgramTemplate::HandleProgramMessage(const std::string &msg) { } bool ProgramTemplate::ReadyToGo() { return window_thread_; } nux::WindowThread* ProgramTemplate::GetWindowThread() { return window_thread_; } void ProgramTemplate::ProgramExitCall(void * /* data */) { if (window_thread_) window_thread_->ExitMainLoop(); } void ProgramTemplate::WaitForConfigureEvent(int /* x */, int /* y */, int /* width */, int /* height */) { ready_to_go_ = true; } // int main(int argc, char **argv) // { // ProgramTemplate test("Text Entry", 300, 300, 3000); // test.Startup(); // test.UserInterfaceSetup(); // test.Run(); // return 0; // } nux-4.0.8+18.10.20180623/Nux/ProgramFramework/ProgramTemplate.h0000644000000000000000000000503613313373365020120 0ustar /* * Copyright 2012 Inalogic Inc. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see * * * Authored by: Jay Taoko * */ #include "Nux/Nux.h" #include "Nux/VLayout.h" #include "Nux/HLayout.h" #include "Nux/WindowThread.h" #include "Nux/TextEntry.h" #ifndef PROGRAMTEMPLATE_H #define PROGRAMTEMPLATE_H class ProgramTemplate { public: ProgramTemplate(const char* program_name, int window_width, int window_height, int program_life_span); virtual ~ProgramTemplate(); virtual void Startup(); virtual void UserInterfaceSetup(); virtual void Run(); bool ReadyToGo(); //!< Use with caution // // This WindowThread here will be valid, but if you call it from // another thread, and the call has a side-effect of calling // nux::GetWindowThread, it will likely result in undefined behaviour // since nux::GetWindowThread depends on the same thread that // GetWindowThread () here provides being the currently running // thread, as nux::GetWindowThread operates in terms of thread // local storage. nux::WindowThread* GetWindowThread(); //!< Tells the program to do something, depending on the defined protocol // implemented in HandleProgramMessage void SendMessageToProgram (const std::string &msg); void WaitForMessageFromProgram (const std::string &msg); public: std::string program_name_; int program_life_span_; //!< The program will auto-terminate after a delay in milliseconds. nux::TimeOutSignal* timeout_signal_; nux::WindowThread* window_thread_; int window_width_; int window_height_; protected: void SendMessageToTest(const std::string &msg); private: void MessageReceivedFromTest(); static void ThreadInitializer(nux::NThread *, void *); virtual void HandleProgramMessage(const std::string &); void ProgramExitCall(void* data); void WaitForConfigureEvent(int x, int y, int width, int height); bool ready_to_go_; int program_pipe_[2]; int test_pipe_[2]; }; #endif // PROGRAMTEMPLATE_H nux-4.0.8+18.10.20180623/Nux/ProgramFramework/TestTextEntry.cpp0000644000000000000000000001221213313373365020150 0ustar /* * Copyright 2012 Inalogic Inc. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see * * * Authored by: Jay Taoko * */ #include "Nux/Nux.h" #include "TestTextEntry.h" /* TestTextEntry: This class is a Nux view that processes all mouse events that it receives. It is meant for testing simulated mouse events. */ namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(TestTextEntry); TestTextEntry::TestTextEntry(NUX_FILE_LINE_DECL) : nux::TextEntry("", NUX_FILE_LINE_PARAM) { ResetEvents(); ResetKeyFocusEvents(); key_nav_direction_ = nux::KEY_NAV_NONE; has_focus_ = false; mouse_in_ = false; mouse_mouse_drag_ = false; mouse_mouse_down_ = false; mouse_down.connect(sigc::mem_fun(this, &TestTextEntry::OnMouseDown)); mouse_up.connect(sigc::mem_fun(this, &TestTextEntry::OnMouseUp)); mouse_drag.connect(sigc::mem_fun(this, &TestTextEntry::OnMouseDrag)); mouse_click.connect(sigc::mem_fun(this, &TestTextEntry::OnMouseClick)); mouse_double_click.connect(sigc::mem_fun(this, &TestTextEntry::OnMouseDoubleClick)); mouse_move.connect(sigc::mem_fun(this, &TestTextEntry::OnMouseMove)); mouse_enter.connect(sigc::mem_fun(this, &TestTextEntry::OnMouseEnter)); mouse_leave.connect(sigc::mem_fun(this, &TestTextEntry::OnMouseLeave)); key_nav_focus_change.connect(sigc::mem_fun(this, &TestTextEntry::OnKeyNavFocusChange)); begin_key_focus.connect(sigc::mem_fun(this, &TestTextEntry::OnBeginKeyFocus)); end_key_focus.connect(sigc::mem_fun(this, &TestTextEntry::OnEndKeyFocus)); object_destroyed.connect(sigc::mem_fun(this, &TestTextEntry::OnObjectDestroyed)); text_changed.connect(sigc::mem_fun(this, &TestTextEntry::OnTextChanged)); } TestTextEntry::~TestTextEntry() { } void TestTextEntry::ResetEvents() { registered_mouse_down_ = false; registered_mouse_up_ = false; registered_mouse_drag_ = false; registered_mouse_enter_ = false; registered_mouse_leave_ = false; registered_mouse_click_ = false; registered_mouse_double_click_ = false; registered_mouse_move_ = false; registered_mouse_enter_ = false; registered_mouse_leave_ = false; registered_object_destroyed_ = false; registered_text_changed_ = false; } void TestTextEntry::ResetKeyFocusEvents() { registered_begin_keynav_focus_ = false; registered_end_keynav_focus_ = false; } void TestTextEntry::OnMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_down_ = true; mouse_mouse_down_ = true; QueueDraw(); } void TestTextEntry::OnMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_up_ = true; mouse_mouse_down_ = false; mouse_mouse_drag_ = false; QueueDraw(); } void TestTextEntry::OnMouseDrag(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_drag_ = true; mouse_mouse_drag_ = true; QueueDraw(); } void TestTextEntry::OnMouseClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_click_ = true; QueueDraw(); } void TestTextEntry::OnMouseDoubleClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_double_click_ = true; mouse_mouse_down_ = true; QueueDraw(); } void TestTextEntry::OnMouseMove(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_move_ = true; QueueDraw(); } void TestTextEntry::OnMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_enter_ = true; mouse_in_ = true; QueueDraw(); } void TestTextEntry::OnMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_leave_ = true; mouse_in_ = false; QueueDraw(); } void TestTextEntry::OnKeyNavFocusChange(nux::Area* /* area */, bool has_focus, nux::KeyNavDirection direction) { has_focus_ = HasKeyFocus(); has_focus_ = has_focus; key_nav_direction_ = direction; QueueDraw(); } void TestTextEntry::OnBeginKeyFocus() { registered_begin_keynav_focus_ = true; } void TestTextEntry::OnEndKeyFocus() { registered_end_keynav_focus_ = true; } void TestTextEntry::OnObjectDestroyed(nux::Object* /* object */) { registered_object_destroyed_ = true; } void TestTextEntry::OnTextChanged(TextEntry* /* text_entry */) { registered_text_changed_ = true; } } nux-4.0.8+18.10.20180623/Nux/ProgramFramework/TestTextEntry.h0000644000000000000000000000514113313373365017620 0ustar /* * Copyright 2012 Inalogic Inc. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see * * * Authored by: Jay Taoko * */ #ifndef TEST_TEXT_ENTRY_H #define TEST_TEXT_ENTRY_H #include "Nux/TextEntry.h" namespace nux { class TestTextEntry: public nux::TextEntry { NUX_DECLARE_OBJECT_TYPE(TestTextEntry, TextEntry); public: TestTextEntry(NUX_FILE_LINE_PROTO); ~TestTextEntry(); void ResetEvents(); void ResetKeyFocusEvents(); bool has_focus_; bool registered_mouse_down_; bool registered_mouse_up_; bool registered_mouse_drag_; bool registered_mouse_click_; bool registered_mouse_double_click_; bool registered_mouse_move_; bool registered_mouse_enter_; bool registered_mouse_leave_; bool registered_object_destroyed_; bool registered_begin_keynav_focus_; bool registered_end_keynav_focus_; bool registered_text_changed_; nux::KeyNavDirection key_nav_direction_; //!< The key nav direction received when the view obtained the focus. protected: bool mouse_in_; bool mouse_mouse_drag_; bool mouse_mouse_down_; void OnMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnMouseClick(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseDoubleClick(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnKeyNavFocusChange(nux::Area* area, bool has_focus, nux::KeyNavDirection direction); void OnBeginKeyFocus(); void OnEndKeyFocus(); void OnObjectDestroyed(Object* object); void OnTextChanged(TextEntry* text_entry); }; } #endif // TEST_TEXT_ENTRY_H nux-4.0.8+18.10.20180623/Nux/ProgramFramework/TestView.cpp0000644000000000000000000001344113313373365017121 0ustar /* * Copyright 2012 Inalogic Inc. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see * * * Authored by: Jay Taoko * */ #include "Nux/Nux.h" #include "TestView.h" /* TestView: This class is a Nux view that processes all mouse events that it receives. It is meant for testing simulated mouse events. */ namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(TestView); TestView::TestView(NUX_FILE_LINE_DECL) : nux::View(NUX_FILE_LINE_PARAM) , can_focus_(true) , calls_to_queue_draw_(0) { ResetEvents(); ResetKeyFocusEvents(); key_nav_direction_ = nux::KEY_NAV_NONE; normal_color_ = nux::color::Green; mouse_down_color_ = nux::color::Red; mouse_drag_color_ = nux::color::Yellow; mouse_in_color_ = nux::color::Blue; current_color_ = normal_color_; with_key_focus_color_ = nux::color::White; without_key_focus_color_ = normal_color_; has_focus_ = false; mouse_in_ = false; mouse_mouse_drag_ = false; mouse_mouse_down_ = false; mouse_down.connect(sigc::mem_fun(this, &TestView::OnMouseDown)); mouse_up.connect(sigc::mem_fun(this, &TestView::OnMouseUp)); mouse_drag.connect(sigc::mem_fun(this, &TestView::OnMouseDrag)); mouse_click.connect(sigc::mem_fun(this, &TestView::OnMouseClick)); mouse_double_click.connect(sigc::mem_fun(this, &TestView::OnMouseDoubleClick)); mouse_move.connect(sigc::mem_fun(this, &TestView::OnMouseMove)); mouse_enter.connect(sigc::mem_fun(this, &TestView::OnMouseEnter)); mouse_leave.connect(sigc::mem_fun(this, &TestView::OnMouseLeave)); key_nav_focus_change.connect(sigc::mem_fun(this, &TestView::OnKeyNavFocusChange)); begin_key_focus.connect(sigc::mem_fun(this, &TestView::OnBeginKeyFocus)); end_key_focus.connect(sigc::mem_fun(this, &TestView::OnEndKeyFocus)); object_destroyed.connect(sigc::mem_fun(this, &TestView::OnObjectDestroyed)); } TestView::~TestView() { } void TestView::ResetEvents() { registered_mouse_down_ = false; registered_mouse_up_ = false; registered_mouse_drag_ = false; registered_mouse_enter_ = false; registered_mouse_leave_ = false; registered_mouse_click_ = false; registered_mouse_double_click_ = false; registered_mouse_move_ = false; registered_mouse_enter_ = false; registered_mouse_leave_ = false; registered_object_destroyed_ = false; } void TestView::ResetKeyFocusEvents() { registered_begin_keynav_focus_ = false; registered_end_keynav_focus_ = false; } void TestView::QueueDraw() { ++calls_to_queue_draw_; nux::View::QueueDraw(); } nux::Color TestView::GetColor() const { return current_color_; } void TestView::Draw(nux::GraphicsEngine& graphics_engine, bool /* force_draw */) { nux::Geometry geo = GetGeometry(); graphics_engine.QRP_Color(geo.x, geo.y, geo.width, geo.height, current_color_); if (has_focus_) graphics_engine.QRP_Color(geo.x, geo.y, 20, 20, with_key_focus_color_); } void TestView::OnMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_down_ = true; current_color_ = mouse_down_color_; mouse_mouse_down_ = true; QueueDraw(); } void TestView::OnMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_up_ = true; if (mouse_in_) current_color_ = mouse_in_color_; else current_color_ = normal_color_; mouse_mouse_down_ = false; mouse_mouse_drag_ = false; QueueDraw(); } void TestView::OnMouseDrag(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_drag_ = true; current_color_ = mouse_drag_color_; mouse_mouse_drag_ = true; QueueDraw(); } void TestView::OnMouseClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_click_ = true; QueueDraw(); } void TestView::OnMouseDoubleClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_double_click_ = true; current_color_ = mouse_down_color_; mouse_mouse_down_ = true; QueueDraw(); } void TestView::OnMouseMove(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_move_ = true; QueueDraw(); } void TestView::OnMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_enter_ = true; mouse_in_ = true; current_color_ = mouse_in_color_; QueueDraw(); } void TestView::OnMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { registered_mouse_leave_ = true; mouse_in_ = false; current_color_ = normal_color_; QueueDraw(); } void TestView::OnKeyNavFocusChange(nux::Area* /* area */, bool has_focus, nux::KeyNavDirection direction) { has_focus_ = HasKeyFocus(); has_focus_ = has_focus; key_nav_direction_ = direction; QueueDraw(); } void TestView::OnBeginKeyFocus() { registered_begin_keynav_focus_ = true; } void TestView::OnEndKeyFocus() { registered_end_keynav_focus_ = true; } void TestView::OnObjectDestroyed(nux::Object* /* object */) { registered_object_destroyed_ = true; } } nux-4.0.8+18.10.20180623/Nux/ProgramFramework/TestView.h0000644000000000000000000000565713313373365016600 0ustar /* * Copyright 2012 Inalogic Inc. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see * * * Authored by: Jay Taoko * */ #ifndef TEST_VIEW_H #define TEST_VIEW_H #include "Nux/TextureArea.h" namespace nux { class TestView: public nux::View { NUX_DECLARE_OBJECT_TYPE(TestView, View); public: TestView(NUX_FILE_LINE_PROTO); ~TestView(); nux::Color GetColor() const; bool AcceptKeyNavFocus() {return can_focus_;} void ResetEvents(); void ResetKeyFocusEvents(); void QueueDraw(); bool can_focus_; bool has_focus_; bool registered_mouse_down_; bool registered_mouse_up_; bool registered_mouse_drag_; bool registered_mouse_click_; bool registered_mouse_double_click_; bool registered_mouse_move_; bool registered_mouse_enter_; bool registered_mouse_leave_; bool registered_object_destroyed_; bool registered_begin_keynav_focus_; bool registered_end_keynav_focus_; unsigned int calls_to_queue_draw_; nux::KeyNavDirection key_nav_direction_; //!< The key nav direction received when the view obtained the focus. protected: nux::Color current_color_; nux::Color normal_color_; nux::Color mouse_down_color_; nux::Color mouse_drag_color_; nux::Color mouse_in_color_; nux::Color with_key_focus_color_; nux::Color without_key_focus_color_; bool mouse_in_; bool mouse_mouse_drag_; bool mouse_mouse_down_; void OnMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnMouseClick(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseDoubleClick(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnKeyNavFocusChange(nux::Area* area, bool has_focus, nux::KeyNavDirection direction); void OnBeginKeyFocus(); void OnEndKeyFocus(); void OnObjectDestroyed(Object* object); void Draw(nux::GraphicsEngine& graphics_engine, bool force_draw); }; } #endif // TEST_VIEW_H nux-4.0.8+18.10.20180623/Nux/RGBValuator.cpp0000644000000000000000000013725613313373365014225 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/GLTextureResourceManager.h" #include "HLayout.h" #include "VLayout.h" #include "EditTextBox.h" #include "ToggleButton.h" #include "HexRegExpValidator.h" #include "IntegerValidator.h" #include "DoubleValidator.h" #include "RGBValuator.h" #include #include namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(RGBValuator); RGBValuator::RGBValuator(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , rgb_(1, 1, 1) , hsv_(rgb_) , hls_(rgb_) , m_color_model(color::RGB) , m_color_format(color::FLOAT) { InitializeLayout(); SetColorModel(m_color_model); SetColorFormat(m_color_format); SetRGBA(1.0f, 1.0f, 1.0f, 1.0f); InitializeWidgets(); } RGBValuator::RGBValuator(Color const& color, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , rgb_(1, 1, 1) , hsv_(rgb_) , hls_(rgb_) , m_color_model(color::RGB) , m_color_format(color::FLOAT) { InitializeLayout(); SetColorModel(m_color_model); SetColorFormat(m_color_format); SetRGBA(color); InitializeWidgets(); } RGBValuator::RGBValuator(color::Model colorModel, float x, float y, float z, float alpha, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , rgb_(1, 1, 1) , hsv_(rgb_) , hls_(rgb_) , m_color_model(colorModel) , m_color_format(color::FLOAT) { InitializeLayout(); switch(m_color_model) { case color::HSV: { SetColorModel(color::HSV); SetHSV(x, y, z); SetAlpha(alpha); break; } case color::HLS: { SetColorModel(color::HLS); SetHLS(x, y, z); SetAlpha(alpha); break; } default: case color::RGB: { SetColorModel(color::RGB); SetRGBA(x, y, z, alpha); } } SetColorFormat(m_color_format); InitializeWidgets(); } void RGBValuator::InitializeLayout() { hlayout = new HLayout("RGBValuatorLayout", NUX_TRACKER_LOCATION); redlayout = new HLayout("RedLayout", NUX_TRACKER_LOCATION); greenlayout = new HLayout("GreenLayout", NUX_TRACKER_LOCATION); bluelayout = new HLayout("BlueLayout", NUX_TRACKER_LOCATION); alphalayout = new HLayout("AlphaLayout", NUX_TRACKER_LOCATION); vlayout = new VLayout("RGBVLayout", NUX_TRACKER_LOCATION); colormodel_layout = new VLayout("ColorModel", NUX_TRACKER_LOCATION); m_ColorModel = new ToggleButton(); m_ColorFormat = new ToggleButton(); red_caption_ = new EditTextBox("", NUX_TRACKER_LOCATION); green_caption_ = new EditTextBox("", NUX_TRACKER_LOCATION); blue_caption_ = new EditTextBox("", NUX_TRACKER_LOCATION); alpha_caption_ = new EditTextBox("", NUX_TRACKER_LOCATION); red_valuator_ = new BasicView(NUX_TRACKER_LOCATION); green_valuator_ = new BasicView(NUX_TRACKER_LOCATION); blue_valuator_ = new BasicView(NUX_TRACKER_LOCATION); alpha_valuator_ = new BasicView(NUX_TRACKER_LOCATION); color_square_ = new BasicView(NUX_TRACKER_LOCATION); m_ComponentLabel0 = new BasicView(NUX_TRACKER_LOCATION); m_ComponentLabel1 = new BasicView(NUX_TRACKER_LOCATION); m_ComponentLabel2 = new BasicView(NUX_TRACKER_LOCATION); m_ComponentAlpha = new BasicView(NUX_TRACKER_LOCATION); } void RGBValuator::InitializeWidgets() { m_HexRegExp.SetMaximum(255); m_HexRegExp.SetMinimum(0); m_IntRegExp.SetMaximum(255); m_IntRegExp.SetMinimum(0); m_DoubleRegExp.SetMaximum(1.0); m_DoubleRegExp.SetMinimum(0); // Set Signals red_valuator_->mouse_down.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseDown_Red)); green_valuator_->mouse_down.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseDown_Green)); blue_valuator_->mouse_down.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseDown_Blue)); alpha_valuator_->mouse_down.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseDown_Alpha)); red_valuator_->mouse_drag.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseDrag_Red)); green_valuator_->mouse_drag.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseDrag_Green)); blue_valuator_->mouse_drag.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseDrag_Blue)); alpha_valuator_->mouse_drag.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseDrag_Alpha)); m_ColorModel->click.connect(sigc::mem_fun(this, &RGBValuator::OnChangeColorModel)); m_ColorFormat->click.connect(sigc::mem_fun(this, &RGBValuator::OnChangeColorFormat)); m_ColorModel->SetFont(GetSysBoldFont()); m_ColorFormat->SetFont(GetSysBoldFont()); red_valuator_->mouse_up.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseUp_Red)); green_valuator_->mouse_up.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseUp_Green)); blue_valuator_->mouse_up.connect(sigc::mem_fun(this, &RGBValuator::OnReceiveMouseUp_Blue)); red_caption_->sigValidateKeyboardEntry.connect(sigc::bind(sigc::mem_fun(this, &RGBValuator::OnComponentInput), 0)); green_caption_->sigValidateKeyboardEntry.connect(sigc::bind(sigc::mem_fun(this, &RGBValuator::OnComponentInput), 1)); blue_caption_->sigValidateKeyboardEntry.connect(sigc::bind(sigc::mem_fun(this, &RGBValuator::OnComponentInput), 2)); alpha_caption_->sigValidateKeyboardEntry.connect(sigc::bind(sigc::mem_fun(this, &RGBValuator::OnComponentInput), 3)); // Set Geometry red_caption_->SetGeometry(Geometry(0, 0, 42, DEFAULT_WIDGET_HEIGHT)); red_caption_->SetMaximumHeight(15); green_caption_->SetGeometry(Geometry(0, 0, 42, DEFAULT_WIDGET_HEIGHT)); green_caption_->SetMaximumHeight(15); blue_caption_->SetGeometry(Geometry(0, 0, 42, DEFAULT_WIDGET_HEIGHT)); blue_caption_->SetMaximumHeight(15); alpha_caption_->SetGeometry(Geometry(0, 0, 42, DEFAULT_WIDGET_HEIGHT)); alpha_caption_->SetMaximumHeight(15); m_ComponentLabel0->SetMinimumSize(10, DEFAULT_WIDGET_HEIGHT); m_ComponentLabel0->SetMaximumHeight(15); //m_ComponentLabel0->SetGeometry(Geometry(0, 0, 15, DEFAULT_WIDGET_HEIGHT)); m_ComponentLabel1->SetMinimumSize(10, DEFAULT_WIDGET_HEIGHT); m_ComponentLabel1->SetMaximumHeight(15); //m_ComponentLabel1->SetGeometry(Geometry(0, 0, 15, DEFAULT_WIDGET_HEIGHT)); m_ComponentLabel2->SetMinimumSize(10, DEFAULT_WIDGET_HEIGHT); m_ComponentLabel2->SetMaximumHeight(15); //m_ComponentLabel2->SetGeometry(Geometry(0, 0, 15, DEFAULT_WIDGET_HEIGHT)); m_ComponentAlpha->SetMinimumSize(10, DEFAULT_WIDGET_HEIGHT); m_ComponentAlpha->SetMaximumHeight(15); //m_ComponentAlpha->SetGeometry(Geometry(0, 0, 15, DEFAULT_WIDGET_HEIGHT)); red_valuator_->SetMinimumSize(3 * DEFAULT_WIDGET_WIDTH, 15); red_valuator_->SetMaximumHeight(15); red_valuator_->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); green_valuator_->SetMinimumSize(3 * DEFAULT_WIDGET_WIDTH, 15); green_valuator_->SetMaximumHeight(15); green_valuator_->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); blue_valuator_->SetMinimumSize(3 * DEFAULT_WIDGET_WIDTH, 15); blue_valuator_->SetMaximumHeight(15); blue_valuator_->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); alpha_valuator_->SetMinimumSize(3 * DEFAULT_WIDGET_WIDTH, 15); alpha_valuator_->SetMaximumHeight(15); alpha_valuator_->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); color_square_->SetMinimumSize(32, 32); color_square_->SetGeometry(Geometry(0, 0, 32, 32)); m_ColorModel->SetMinimumSize(20, 16); m_ColorModel->SetLayoutPadding(0, 0, 0, 0); m_ColorFormat->SetMinimumSize(20, 16); m_ColorFormat->SetLayoutPadding(0, 0, 0, 0); redlayout->AddView(m_ComponentLabel0, 0, MINOR_POSITION_CENTER, MINOR_SIZE_MATCHCONTENT); redlayout->AddView(red_caption_, 0); redlayout->AddView(red_valuator_, 1); redlayout->SetSpaceBetweenChildren(4); greenlayout->AddView(m_ComponentLabel1, 0, MINOR_POSITION_CENTER, MINOR_SIZE_MATCHCONTENT); greenlayout->AddView(green_caption_, 0); greenlayout->AddView(green_valuator_, 1); greenlayout->SetSpaceBetweenChildren(4); bluelayout->AddView(m_ComponentLabel2, 0, MINOR_POSITION_CENTER, MINOR_SIZE_MATCHCONTENT); bluelayout->AddView(blue_caption_, 0); bluelayout->AddView(blue_valuator_, 1); bluelayout->SetSpaceBetweenChildren(4); alphalayout->AddView(m_ComponentAlpha, 0, MINOR_POSITION_CENTER, MINOR_SIZE_MATCHCONTENT); alphalayout->AddView(alpha_caption_, 0); alphalayout->AddView(alpha_valuator_, 1); alphalayout->SetSpaceBetweenChildren(4); // Set layout colormodel_layout->AddView(color_square_, 0, eCenter, eFix); colormodel_layout->AddView(m_ColorModel, 0, eCenter, eFull); colormodel_layout->AddView(m_ColorFormat, 0, eCenter, eFull); colormodel_layout->SetSpaceBetweenChildren(2); hlayout->AddView(colormodel_layout, 0, MINOR_POSITION_START, MINOR_SIZE_MATCHCONTENT); vlayout->AddLayout(redlayout, 0); vlayout->AddLayout(greenlayout, 0); vlayout->AddLayout(bluelayout, 0); vlayout->AddLayout(alphalayout, 0); vlayout->SetSpaceBetweenChildren(2); vlayout->SetTopAndBottomPadding(4); vlayout->SetLeftAndRightPadding(4); vlayout->SetContentDistribution(MAJOR_POSITION_CENTER); hlayout->AddLayout(vlayout, 1, MINOR_POSITION_CENTER, MINOR_SIZE_FULL); hlayout->SetSpaceBetweenChildren(2); hlayout->SetLeftAndRightPadding(6, 6); hlayout->SetTopAndBottomPadding(0); SetCompositionLayout(hlayout); NTextureData image; MakeCheckBoardImage(image.GetSurface(0), 64, 64, Color(0xff000000), Color(0xff323232), 4, 4); BaseTexture* CheckboardPattern = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); CheckboardPattern->Update(&image); TexCoordXForm texxform; texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD); texxform.SetWrap(TEXWRAP_REPEAT, TEXWRAP_REPEAT); m_CheckboardLayer = new TextureLayer(CheckboardPattern->GetDeviceTexture(), texxform, color::White); CheckboardPattern->UnReference(); } RGBValuator::~RGBValuator() { NUX_SAFE_DELETE(m_CheckboardLayer); } void RGBValuator::DrawRedMarker(GraphicsEngine &graphics_engine) { int marker_position_x; int marker_position_y; float percent = 0.0f; if (m_color_model == color::RGB) percent = rgb_.red; if (m_color_model == color::HSV) percent = hsv_.hue; if (m_color_model == color::HLS) percent = hls_.hue; graphics_engine.PushClippingRectangle(red_valuator_->GetGeometry()); marker_position_x = red_valuator_->GetBaseX() + percent * red_valuator_->GetBaseWidth(); marker_position_y = red_valuator_->GetBaseY() + red_valuator_->GetBaseHeight(); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 5, marker_position_y, marker_position_x, marker_position_y - 5, marker_position_x + 5, marker_position_y, Color(0xFF000000)); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 4, marker_position_y, marker_position_x, marker_position_y - 4, marker_position_x + 4, marker_position_y, Color(0.7f, 0.7f, 0.7f, 1.0f)); graphics_engine.PopClippingRectangle(); } void RGBValuator::DrawGreenMarker(GraphicsEngine &graphics_engine) { int marker_position_x; int marker_position_y; float percent = 0.0f; if (m_color_model == color::RGB) percent = rgb_.green; if (m_color_model == color::HSV) percent = hsv_.saturation; if (m_color_model == color::HLS) percent = hls_.lightness; graphics_engine.PushClippingRectangle(green_valuator_->GetGeometry()); marker_position_x = green_valuator_->GetBaseX() + percent * green_valuator_->GetBaseWidth(); marker_position_y = green_valuator_->GetBaseY() + green_valuator_->GetBaseHeight(); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 5, marker_position_y, marker_position_x, marker_position_y - 5, marker_position_x + 5, marker_position_y, Color(0.0f, 0.0f, 0.0f, 1.0f)); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 4, marker_position_y, marker_position_x, marker_position_y - 4, marker_position_x + 4, marker_position_y, Color(0.7f, 0.7f, 0.7f, 1.0f)); graphics_engine.PopClippingRectangle(); } void RGBValuator::DrawBlueMarker(GraphicsEngine &graphics_engine) { int marker_position_x; int marker_position_y; float percent = 0.0f; if (m_color_model == color::RGB) percent = rgb_.blue; if (m_color_model == color::HSV) percent = hsv_.value; if (m_color_model == color::HLS) percent = hls_.saturation; graphics_engine.PushClippingRectangle(blue_valuator_->GetGeometry()); marker_position_x = blue_valuator_->GetBaseX() + percent * blue_valuator_->GetBaseWidth(); marker_position_y = blue_valuator_->GetBaseY() + blue_valuator_->GetBaseHeight(); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 5, marker_position_y, marker_position_x, marker_position_y - 5, marker_position_x + 5, marker_position_y, Color(0.0f, 0.0f, 0.0f, 1.0f)); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 4, marker_position_y, marker_position_x, marker_position_y - 4, marker_position_x + 4, marker_position_y, Color(0.7f, 0.7f, 0.7f, 1.0f)); graphics_engine.PopClippingRectangle(); } void RGBValuator::DrawAlphaMarker(GraphicsEngine &graphics_engine) { int marker_position_x; int marker_position_y; graphics_engine.PushClippingRectangle(alpha_valuator_->GetGeometry()); marker_position_x = alpha_valuator_->GetBaseX() + alpha_ * alpha_valuator_->GetBaseWidth(); marker_position_y = alpha_valuator_->GetBaseY() + alpha_valuator_->GetBaseHeight(); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 5, marker_position_y, marker_position_x, marker_position_y - 5, marker_position_x + 5, marker_position_y, Color(0.0f, 0.0f, 0.0f, 1.0f)); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 4, marker_position_y, marker_position_x, marker_position_y - 4, marker_position_x + 4, marker_position_y, Color(0.7f, 0.7f, 0.7f, 1.0f)); graphics_engine.PopClippingRectangle(); } void RGBValuator::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); GetPainter().PushDrawShapeLayer(graphics_engine, vlayout->GetGeometry(), eSHAPE_CORNER_ROUND4, Color(0xFF000000), eAllCorners, true); if (m_color_model == color::RGB) { DrawRGB(graphics_engine); } else if (m_color_model == color::HSV) { DrawHSV(graphics_engine); } else if (m_color_model == color::HLS) { DrawHLS(graphics_engine); } GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), m_ComponentLabel0->GetGeometry(), m_ComponentLabel0->GetBaseString(), Color(0xFFFFFFFF)); GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), m_ComponentLabel1->GetGeometry(), m_ComponentLabel1->GetBaseString(), Color(0xFFFFFFFF)); GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), m_ComponentLabel2->GetGeometry(), m_ComponentLabel2->GetBaseString(), Color(0xFFFFFFFF)); GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), m_ComponentAlpha->GetGeometry(), m_ComponentAlpha->GetBaseString(), Color(0xFFFFFFFF)); DrawRedMarker(graphics_engine); DrawGreenMarker(graphics_engine); DrawBlueMarker(graphics_engine); DrawAlphaMarker(graphics_engine); GetPainter().PopBackground(); graphics_engine.PopClippingRectangle(); } void RGBValuator::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); red_caption_->ProcessDraw(graphics_engine, force_draw); green_caption_->ProcessDraw(graphics_engine, force_draw); blue_caption_->ProcessDraw(graphics_engine, force_draw); alpha_caption_->ProcessDraw(graphics_engine, force_draw); m_ColorModel->ProcessDraw(graphics_engine, force_draw); // the button has round corner. That is why we need to push the background. m_ColorFormat->ProcessDraw(graphics_engine, force_draw); // the button has round corner. That is why we need to push the background. graphics_engine.PopClippingRectangle(); } void RGBValuator::DrawRGB(GraphicsEngine &graphics_engine) { // Red Geometry P = red_valuator_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(0.0f, rgb_.green, rgb_.blue), Color(0.0f, rgb_.green, rgb_.blue), Color(1.0f, rgb_.green, rgb_.blue), Color(1.0f, rgb_.green, rgb_.blue)); // Green P = green_valuator_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(rgb_.red, 0.0f, rgb_.blue), Color(rgb_.red, 0.0f, rgb_.blue), Color(rgb_.red, 1.0f, rgb_.blue), Color(rgb_.red, 1.0f, rgb_.blue)); // Blue P = blue_valuator_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(rgb_.red, rgb_.green, 0.0f), Color(rgb_.red, rgb_.green, 0.0f), Color(rgb_.red, rgb_.green, 1.0f), Color(rgb_.red, rgb_.green, 1.0f)); // Alpha P = alpha_valuator_->GetGeometry(); m_CheckboardLayer->SetGeometry(P); m_CheckboardLayer->Renderlayer(graphics_engine); graphics_engine.GetRenderStates().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(0.0f, 0.0f, 0.0f, 0.0f), Color(0.0f, 0.0f, 0.0f, 0.0f), Color(rgb_.red, rgb_.green, rgb_.blue, 1.0f), Color(rgb_.red, rgb_.green, rgb_.blue, 1.0f)); graphics_engine.GetRenderStates().SetBlend(false); P = color_square_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(rgb_.red, rgb_.green, rgb_.blue), Color(rgb_.red, rgb_.green, rgb_.blue), Color(rgb_.red, rgb_.green, rgb_.blue), Color(rgb_.red, rgb_.green, rgb_.blue)); m_ColorModel->ProcessDraw(graphics_engine, true); m_ColorFormat->ProcessDraw(graphics_engine, true); } void RGBValuator::DrawHSV(GraphicsEngine &graphics_engine) { // Red Geometry P = red_valuator_->GetGeometry(); float s = 0; //XSI: 1.0f - hsv_.saturation; float v = 1; //XSI: hsv_.value; float fw = P.GetWidth() / 6; Geometry p = Geometry(P.x, P.y, fw, P.GetHeight()); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(1.0f * v, s * v, s * v), Color(1.0f * v, s * v, s * v), Color(1.0f * v, 1.0f * v, s * v), Color(1.0f * v, 1.0f * v, s * v)); p.SetX(P.x + fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(1.0f * v, 1.0f * v, s * v), Color(1.0f * v, 1.0f * v, s * v), Color(s * v, 1.0f * v, s * v), Color(s * v, 1.0f * v, s * v)); p.SetX(P.x + 2 * fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(s * v, 1.0f * v, s * v), Color(s * v, 1.0f * v, s * v), Color(s * v, 1.0f * v, 1.0f * v), Color(s * v, 1.0f * v, 1.0f * v)); p.SetX(P.x + 3 * fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(s * v, 1.0f * v, 1.0f * v), Color(s * v, 1.0f * v, 1.0f * v), Color(s * v, s * v, 1.0f * v), Color(s * v, s * v, 1.0f * v)); p.SetX(P.x + 4 * fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(s * v, s * v, 1.0f * v), Color(s * v, s * v, 1.0f * v), Color(1.0f * v, s * v, 1.0f * v), Color(1.0f * v, s * v, 1.0f * v)); p.SetX(P.x + 5 * fw); p.SetWidth(P.GetWidth() - 5 * fw); // correct rounding errors GetPainter().Paint2DQuadColor(graphics_engine, p, Color(1.0f * v, s * v, 1.0f * v), Color(1.0f * v, s * v, 1.0f * v), Color(1.0f * v, s * v, s * v), Color(1.0f * v, s * v, s * v)); s = 1.0f - hsv_.saturation; v = hsv_.value; float hue = hsv_.hue; if (hue == 1.0f) hue = 0.0f; color::RedGreenBlue rgb(color::HueSaturationValue(hue, 1, 1)); Color value_gray(v, v, v); Color value_color(Color(rgb) * v); // Green P = green_valuator_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, value_gray, value_gray, value_color, value_color); rgb = color::RedGreenBlue(color::HueSaturationValue(hue, hsv_.saturation, 1)); // Blue P = blue_valuator_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, color::Black, color::Black, Color(rgb), Color(rgb)); rgb = color::RedGreenBlue(color::HueSaturationValue(hue, hsv_.saturation, hsv_.value)); // Alpha P = alpha_valuator_->GetGeometry(); m_CheckboardLayer->SetGeometry(P); m_CheckboardLayer->Renderlayer(graphics_engine); graphics_engine.GetRenderStates().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(0.0f, 0.0f, 0.0f, 0.0f), Color(0.0f, 0.0f, 0.0f, 0.0f), Color(rgb), Color(rgb)); graphics_engine.GetRenderStates().SetBlend(false); P = color_square_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(rgb)); m_ColorModel->ProcessDraw(graphics_engine, true); m_ColorFormat->ProcessDraw(graphics_engine, true); } void RGBValuator::DrawHLS(GraphicsEngine &graphics_engine) { // Red Geometry P = red_valuator_->GetGeometry(); float s = 0; //XSI: 1.0f - hls_.saturation; float l = 1; //XSI: hls_.lightness; float fw = P.GetWidth() / 6; Geometry p = Geometry(P.x, P.y, fw, P.GetHeight()); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(1.0f * l, s * l, s * l), Color(1.0f * l, s * l, s * l), Color(1.0f * l, 1.0f * l, s * l), Color(1.0f * l, 1.0f * l, s * l)); p.SetX(P.x + fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(1.0f * l, 1.0f * l, s * l), Color(1.0f * l, 1.0f * l, s * l), Color(s * l, 1.0f * l, s * l), Color(s * l, 1.0f * l, s * l)); p.SetX(P.x + 2 * fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(s * l, 1.0f * l, s * l), Color(s * l, 1.0f * l, s * l), Color(s * l, 1.0f * l, 1.0f * l), Color(s * l, 1.0f * l, 1.0f * l)); p.SetX(P.x + 3 * fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(s * l, 1.0f * l, 1.0f * l), Color(s * l, 1.0f * l, 1.0f * l), Color(s * l, s * l, 1.0f * l), Color(s * l, s * l, 1.0f * l)); p.SetX(P.x + 4 * fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(s * l, s * l, 1.0f * l), Color(s * l, s * l, 1.0f * l), Color(1.0f * l, s * l, 1.0f * l), Color(1.0f * l, s * l, 1.0f * l)); p.SetX(P.x + 5 * fw); p.SetWidth(P.GetWidth() - 5 * fw); // correct rounding errors GetPainter().Paint2DQuadColor(graphics_engine, p, Color(1.0f * l, s * l, 1.0f * l), Color(1.0f * l, s * l, 1.0f * l), Color(1.0f * l, s * l, s * l), Color(1.0f * l, s * l, s * l)); s = 1.0f - hls_.saturation; l = hls_.lightness; float Hue; if (hls_.hue == 1.0f) Hue = 0.0f; else Hue = hls_.hue; // TODO: Tim Penhey 2011-05-13 // refactor this code to use the same methods as the RGB(A)Property classes. color::RedGreenBlue rgb(color::HueSaturationValue(Hue, 1, 1)); // Need to use HSVtoRGB to compute the color float r = rgb.red; float g = rgb.green; float b = rgb.blue; // Green P = green_valuator_->GetGeometry(); fw = P.GetWidth() / 2; p = Geometry(P.x, P.y, fw, P.GetHeight()); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(0.0f, 0.0f, 0.0f), Color(0.0f, 0.0f, 0.0f), Color(r* (1 - s) + 0.5f * s, g* (1 - s) + 0.5f * s, b* (1 - s) + 0.5f * s), Color(r* (1 - s) + 0.5f * s, g* (1 - s) + 0.5f * s, b* (1 - s) + 0.5f * s)); p.SetX(P.x + fw); GetPainter().Paint2DQuadColor(graphics_engine, p, Color(r* (1 - s) + 0.5f * s, g* (1 - s) + 0.5f * s, b* (1 - s) + 0.5f * s), Color(r* (1 - s) + 0.5f * s, g* (1 - s) + 0.5f * s, b* (1 - s) + 0.5f * s), Color(1.0f, 1.0f, 1.0f), Color(1.0f, 1.0f, 1.0f)); //HLStoRGB(r, g, b, Hue, hsv_.saturation, 1.0f); // Blue float cr, cg, cb; if (l > 0.5) { float factor = (l - 0.5f) / 0.5f; cr = (1 - factor) * r * (1 - s) + 0.5 * s + factor * 1.0f; cg = (1 - factor) * g * (1 - s) + 0.5 * s + factor * 1.0f; cb = (1 - factor) * b * (1 - s) + 0.5 * s + factor * 1.0f; } else { float factor = l / 0.5f; cr = (factor) * r * (1 - s) + 0.5 * s; cg = (factor) * g * (1 - s) + 0.5 * s; cb = (factor) * b * (1 - s) + 0.5 * s; } P = blue_valuator_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(l, l, l), Color(l, l, l), Color(cr, cg, cb), Color(cr, cg, cb)); // TODO: Tim Penhey 2011-05-13 // Can we just use the rgb_ member variable? Check later. rgb = color::RedGreenBlue(hls_); // Alpha P = alpha_valuator_->GetGeometry(); m_CheckboardLayer->SetGeometry(P); m_CheckboardLayer->Renderlayer(graphics_engine); graphics_engine.GetRenderStates().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(0.0f, 0.0f, 0.0f, 0.0f), Color(0.0f, 0.0f, 0.0f, 0.0f), Color(rgb), Color(rgb)); graphics_engine.GetRenderStates().SetBlend(false); P = color_square_->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, Color(rgb)); m_ColorModel->ProcessDraw(graphics_engine, true); m_ColorFormat->ProcessDraw(graphics_engine, true); } void RGBValuator::SetRGBA(Color const& color) { SetRGBA(color.red, color.green, color.blue, color.alpha); } void RGBValuator::SetRGBA(float r, float g, float b, float a) { SetRGB(r, g, b); SetAlpha(a); } void RGBValuator::SetRGB(Color const& color) { SetRGB(color.red, color.green, color.blue); } std::string as_hex(float f) { std::ostringstream s; s << std::hex << (int)f; return s.str(); } std::string as_dec(float f) { std::ostringstream s; s << (int)f; return s.str(); } std::string as_float(float f) { std::ostringstream s; s << std::setprecision(3) << f; return s.str(); } void RGBValuator::SetRGB(float r, float g, float b) { rgb_.red = Clamp(r, 0.0f, 1.0f); rgb_.green = Clamp(g, 0.0f, 1.0f); rgb_.blue = Clamp(b, 0.0f, 1.0f); bool RedEditSelected = red_caption_->IsTextSelected(); bool GreenEditSelected = green_caption_->IsTextSelected(); bool BlueEditSelected = blue_caption_->IsTextSelected(); if (m_color_format == color::HEX) { red_caption_->SetText(as_hex(rgb_.red * 255)); green_caption_->SetText(as_hex(rgb_.green * 255)); blue_caption_->SetText(as_hex(rgb_.blue * 255)); } else if (m_color_format == color::INT) { red_caption_->SetText(as_dec(rgb_.red * 255)); green_caption_->SetText(as_dec(rgb_.green * 255)); blue_caption_->SetText(as_dec(rgb_.blue * 255)); } else { red_caption_->SetText(as_float(rgb_.red)); green_caption_->SetText(as_float(rgb_.green)); blue_caption_->SetText(as_float(rgb_.blue)); } // Restore text selection if necessary. // This solves a problem when an EditTextBox of the widget gets the focus and has its text selected // but another who is losing the focus will cause it to lose the text selection by calling SetRGB. if (RedEditSelected) red_caption_->m_KeyboardHandler.SelectAllText(); if (GreenEditSelected) green_caption_->m_KeyboardHandler.SelectAllText(); if (BlueEditSelected) blue_caption_->m_KeyboardHandler.SelectAllText(); sigColorChanged.emit(rgb_.red, rgb_.green, rgb_.blue, alpha_); } void RGBValuator::SetHSV(float h, float s, float v) { hsv_.hue = Clamp(h, 0.0f, 1.0f); hsv_.saturation = Clamp(s, 0.0f, 1.0f); hsv_.value = Clamp(v, 0.0f, 1.0f); bool RedEditSelected = red_caption_->IsTextSelected(); bool GreenEditSelected = green_caption_->IsTextSelected(); bool BlueEditSelected = blue_caption_->IsTextSelected(); if (m_color_format == color::HEX) { red_caption_->SetText(as_hex(hsv_.hue * 255)); green_caption_->SetText(as_hex(hsv_.saturation * 255)); blue_caption_->SetText(as_hex(hsv_.value * 255)); } else if (m_color_format == color::INT) { red_caption_->SetText(as_dec(hsv_.hue * 255)); green_caption_->SetText(as_dec(hsv_.saturation * 255)); blue_caption_->SetText(as_dec(hsv_.value * 255)); } else { red_caption_->SetText(as_float(hsv_.hue)); green_caption_->SetText(as_float(hsv_.saturation)); blue_caption_->SetText(as_float(hsv_.value)); } if (hsv_.hue >= 1.0f) { hsv_.hue = 1.0f; // XSI: hsv_.hue = 0.0f; } if (RedEditSelected) red_caption_->m_KeyboardHandler.SelectAllText(); if (GreenEditSelected) green_caption_->m_KeyboardHandler.SelectAllText(); if (BlueEditSelected) blue_caption_->m_KeyboardHandler.SelectAllText(); rgb_ = color::RedGreenBlue(hsv_); sigColorChanged.emit(rgb_.red, rgb_.green, rgb_.blue, alpha_); } void RGBValuator::SetHLS(float h, float l, float s) { hls_.hue = Clamp(h, 0.0f, 1.0f); hls_.lightness = Clamp(l, 0.0f, 1.0f); hls_.saturation = Clamp(s, 0.0f, 1.0f); bool RedEditSelected = red_caption_->IsTextSelected(); bool GreenEditSelected = green_caption_->IsTextSelected(); bool BlueEditSelected = blue_caption_->IsTextSelected(); if (m_color_format == color::HEX) { red_caption_->SetText(as_hex(hls_.hue * 255)); green_caption_->SetText(as_hex(hls_.lightness * 255)); blue_caption_->SetText(as_hex(hls_.saturation * 255)); } else if (m_color_format == color::INT) { red_caption_->SetText(as_dec(hls_.hue * 255)); green_caption_->SetText(as_dec(hls_.lightness * 255)); blue_caption_->SetText(as_dec(hls_.saturation * 255)); } else { red_caption_->SetText(as_float(hls_.hue)); green_caption_->SetText(as_float(hls_.lightness)); blue_caption_->SetText(as_float(hls_.saturation)); } if (hls_.hue >= 1.0f) { hls_.hue = 1.0f; // XSI: hls_.hue = 0.0f; } if (RedEditSelected) red_caption_->m_KeyboardHandler.SelectAllText(); if (GreenEditSelected) green_caption_->m_KeyboardHandler.SelectAllText(); if (BlueEditSelected) blue_caption_->m_KeyboardHandler.SelectAllText(); rgb_ = color::RedGreenBlue(hls_); sigColorChanged.emit(rgb_.red, rgb_.green, rgb_.blue, alpha_); } void RGBValuator::SetAlpha(float alpha) { alpha_ = Clamp(alpha, 0.0f, 1.0f); if (m_color_format == color::HEX) { alpha_caption_->SetText(as_hex(alpha_ * 255)); } else if (m_color_format == color::INT) { alpha_caption_->SetText(as_dec(alpha_ * 255)); } else { alpha_caption_->SetText(as_float(alpha_)); } sigColorChanged.emit(rgb_.red, rgb_.green, rgb_.blue, alpha_); } void RGBValuator::OnReceiveMouseDown_Red(int x, int /* y */, unsigned long /* button_flags */, unsigned long key_flags) { if (m_color_model == color::RGB) { if (x < 0) rgb_.red = 0.0f; else if (x > red_valuator_->GetBaseWidth()) rgb_.red = 1.0f; else rgb_.red = (float) x / (float) red_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetRGB(rgb_.red, rgb_.red, rgb_.red); } else { SetRGB(rgb_.red, rgb_.green, rgb_.blue); } } else if (m_color_model == color::HSV) { if (x < 0) hsv_.hue = 0.0f; else if (x > red_valuator_->GetBaseWidth()) hsv_.hue = 1.0f; else hsv_.hue = (float) x / (float) red_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetHSV(hsv_.hue, hsv_.hue, hsv_.hue); } else { SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } } else if (m_color_model == color::HLS) { if (x < 0) hls_.hue = 0.0f; else if (x > red_valuator_->GetBaseWidth()) hls_.hue = 1.0f; else hls_.hue = (float) x / (float) red_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetHLS(hls_.hue, hls_.hue, hls_.hue); } else { SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } } QueueDraw(); } void RGBValuator::OnReceiveMouseDown_Green(int x, int /* y */, unsigned long /* button_flags */, unsigned long key_flags) { if (m_color_model == color::RGB) { if (x < 0) rgb_.green = 0.0f; else if (x > green_valuator_->GetBaseWidth()) rgb_.green = 1.0f; else rgb_.green = (float) x / (float) green_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetRGB(rgb_.green, rgb_.green, rgb_.green); } else { SetRGB(rgb_.red, rgb_.green, rgb_.blue); } } else if (m_color_model == color::HSV) { if (x < 0) hsv_.saturation = 0.0f; else if (x > green_valuator_->GetBaseWidth()) hsv_.saturation = 1.0f; else hsv_.saturation = (float) x / (float) green_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetHSV(hsv_.saturation, hsv_.saturation, hsv_.saturation); } else { SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } } else if (m_color_model == color::HLS) { if (x < 0) hls_.lightness = 0.0f; else if (x > green_valuator_->GetBaseWidth()) hls_.lightness = 1.0f; else hls_.lightness = (float) x / (float) green_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetHLS(hls_.lightness, hls_.lightness, hls_.lightness); } else { SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } } QueueDraw(); } void RGBValuator::OnReceiveMouseDown_Blue(int x, int /* y */, unsigned long /* button_flags */, unsigned long key_flags) { if (m_color_model == color::RGB) { if (x < 0) rgb_.blue = 0.0f; else if (x > blue_valuator_->GetBaseWidth()) rgb_.blue = 1.0f; else rgb_.blue = (float) x / (float) blue_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetRGB(rgb_.blue, rgb_.blue, rgb_.blue); } else { SetRGB(rgb_.red, rgb_.green, rgb_.blue); } } else if (m_color_model == color::HSV) { if (x < 0) hsv_.value = 0.0f; else if (x > blue_valuator_->GetBaseWidth()) hsv_.value = 1.0f; else hsv_.value = (float) x / (float) blue_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetHSV(hsv_.value, hsv_.value, hsv_.value); } else { SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } } else if (m_color_model == color::HLS) { if (x < 0) hls_.saturation = 0.0f; else if (x > blue_valuator_->GetBaseWidth()) hls_.saturation = 1.0f; else hls_.saturation = (float) x / (float) blue_valuator_->GetBaseWidth(); if (key_flags & NUX_STATE_CTRL) { SetHLS(hls_.saturation, hls_.saturation, hls_.saturation); } else { SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } } QueueDraw(); } void RGBValuator::OnReceiveMouseDown_Alpha(int x, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (x < 0) alpha_ = 0.0f; else if (x > alpha_valuator_->GetBaseWidth()) alpha_ = 1.0f; else alpha_ = (float) x / (float) alpha_valuator_->GetBaseWidth(); SetAlpha(alpha_); QueueDraw(); } void RGBValuator::OnReceiveMouseDrag_Red(int x, int y, int /* dx */, int /* dy */, unsigned long button_flags, unsigned long key_flags) { OnReceiveMouseDown_Red(x, y, button_flags, key_flags); } void RGBValuator::OnReceiveMouseDrag_Green(int x, int y, int /* dx */, int /* dy */, unsigned long button_flags, unsigned long key_flags) { OnReceiveMouseDown_Green(x, y, button_flags, key_flags); } void RGBValuator::OnReceiveMouseDrag_Blue(int x, int y, int /* dx */, int /* dy */, unsigned long button_flags, unsigned long key_flags) { OnReceiveMouseDown_Blue(x, y, button_flags, key_flags); } void RGBValuator::OnReceiveMouseDrag_Alpha(int x, int y, int /* dx */, int /* dy */, unsigned long button_flags, unsigned long key_flags) { OnReceiveMouseDown_Alpha(x, y, button_flags, key_flags); } void RGBValuator::OnReceiveMouseUp_Red (int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_color_model == color::HSV) { if (hsv_.hue >= 1.0f) { hsv_.hue = 1.0f; // XSI: hsv_.hue = 0.0f; } if (hsv_.saturation <= 0.0f) { // XSI: hsv_.hue = 0.0f; } if (hsv_.value <= 0.0f) { // XSI: hsv_.hue = 0.0f; // XSI: hsv_.saturation = 0.0f; } SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } if (m_color_model == color::HLS) { if (hls_.hue >= 1.0f) { hls_.hue = 1.0f; // XSI: hls_.hue = 0.0f; } if (hls_.saturation <= 0.0f) { // XSI: hls_.hue = 0.0f; } if (hls_.lightness <= 0.0f || hls_.lightness >= 1.0f) { // XSI: hls_.hue = 0.0f; // XSI: hls_.saturation = 0.0f; } SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } QueueDraw(); } void RGBValuator::OnReceiveMouseUp_Green (int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_color_model == color::HSV) { if (hsv_.hue >= 1.0f) { hsv_.hue = 1.0f; // XSI: hsv_.hue = 0.0f; } if (hsv_.saturation <= 0.0f) { // XSI: hsv_.hue = 0.0f; } if (hsv_.value <= 0.0f) { // XSI: hsv_.hue = 0.0f; // XSI: hsv_.saturation = 0.0f; } SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } if (m_color_model == color::HLS) { if (hls_.hue >= 1.0f) { hls_.hue = 1.0f; // XSI: hls_.hue = 0.0f; } if (hls_.saturation <= 0.0f) { // XSI: hls_.hue = 0.0f; } if (hls_.lightness <= 0.0f || hls_.lightness >= 1.0f) { // XSI: hls_.hue = 0.0f; // XSI: hls_.saturation = 0.0f; } SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } QueueDraw(); } void RGBValuator::OnReceiveMouseUp_Blue(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_color_model == color::HSV) { if (hsv_.hue >= 1.0f) { hsv_.hue = 1.0f; // XSI: hsv_.hue = 0.0f; } if (hsv_.saturation <= 0.0f) { // XSI: hsv_.hue = 0.0f; } if (hsv_.value <= 0.0f) { // XSI: hsv_.hue = 0.0f; // XSI: hsv_.saturation = 0.0f; } SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } if (m_color_model == color::HLS) { if (hls_.hue >= 1.0f) { hls_.hue = 1.0f; // XSI: hls_.hue = 0.0f; } if (hls_.saturation <= 0.0f) { // XSI: hls_.hue = 0.0f; } if (hls_.lightness <= 0.0f || hls_.lightness >= 1.0f) { // XSI: hls_.hue = 0.0f; // XSI: hls_.saturation = 0.0f; } SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } QueueDraw(); } void RGBValuator::RecvMouseDownColorModel(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void RGBValuator::OnChangeColorModel(AbstractButton* /* button */) { if (m_color_model == color::RGB) { SetColorModel(color::HLS); hls_ = color::HueLightnessSaturation(rgb_); SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } else if (m_color_model == color::HLS) { SetColorModel(color::HSV); rgb_ = color::RedGreenBlue(hls_); hsv_ = color::HueSaturationValue(rgb_); SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); if (hsv_.hue == -1.0f) { hsv_.hue = 0; } } else if (m_color_model == color::HSV) { SetColorModel(color::RGB); rgb_ = color::RedGreenBlue(hsv_); SetRGB(rgb_.red, rgb_.green, rgb_.blue); } QueueDraw(); } void RGBValuator::OnChangeColorFormat(AbstractButton* /* button */) { if (m_color_format == color::FLOAT) { SetColorFormat(color::INT); } else if (m_color_format == color::INT) { SetColorFormat(color::HEX); } else if (m_color_format == color::HEX) { SetColorFormat(color::FLOAT); } } void RGBValuator::OnComponentInput(EditTextBox* /* textbox */, const std::string &s, int componentIndex) { float f = 0; if ((m_color_format == color::HEX) && (m_HexRegExp.Validate(s.c_str()) == Validator::Acceptable)) { f = (float) m_HexRegExp.ToInteger(s.c_str()) / 255.0f; } else if ((m_color_format == color::INT) && (m_IntRegExp.Validate(s.c_str()) == Validator::Acceptable)) { f = (float) m_IntRegExp.ToInteger(s.c_str()) / 255.0f; } else { f = (float) m_DoubleRegExp.ToDouble(s.c_str()); } f = Clamp(f, 0.0f, 1.0f); if (componentIndex == 0) { f = Clamp(f, 0.0f, 1.0f); if (m_color_model == color::RGB) { rgb_.red = f; SetRGB(rgb_.red, rgb_.green, rgb_.blue); } else if (m_color_model == color::HSV) { hsv_.hue = f; OnReceiveMouseUp_Red(0, 0, 0, 0); SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } else if (m_color_model == color::HLS) { hls_.hue = f; OnReceiveMouseUp_Red(0, 0, 0, 0); SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } } if (componentIndex == 1) { f = Clamp(f, 0.0f, 1.0f); if (m_color_model == color::RGB) { rgb_.green = f; SetRGB(rgb_.red, rgb_.green, rgb_.blue); } else if (m_color_model == color::HSV) { hsv_.saturation = f; OnReceiveMouseUp_Green(0, 0, 0, 0); SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } else if (m_color_model == color::HLS) { hls_.lightness = f; OnReceiveMouseUp_Green(0, 0, 0, 0); SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } } if (componentIndex == 2) { f = Clamp(f, 0.0f, 1.0f); if (m_color_model == color::RGB) { rgb_.blue = f; SetRGB(rgb_.red, rgb_.green, rgb_.blue); } else if (m_color_model == color::HSV) { hsv_.value = f; OnReceiveMouseUp_Blue(0, 0, 0, 0); SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); } else if (m_color_model == color::HLS) { hls_.saturation = f; OnReceiveMouseUp_Blue(0, 0, 0, 0); SetHLS(hls_.hue, hls_.lightness, hls_.saturation); } } if (componentIndex == 3) { float f = 0; f = CharToDouble(s.c_str()); f = Clamp(f, 0.0f, 1.0f); //if(m_color_model == color::RGB) { alpha_ = f; SetAlpha(alpha_); } } QueueDraw(); } void RGBValuator::SetColorModel(color::Model cm) { if (cm == color::RGB) { m_color_model = color::RGB; m_ColorModel->SetLabel("RGB"); m_ComponentLabel0->SetBaseString("R"); m_ComponentLabel1->SetBaseString("G"); m_ComponentLabel2->SetBaseString("B"); m_ComponentAlpha->SetBaseString("A"); } if (cm == color::HSV) { m_color_model = color::HSV; m_ColorModel->SetLabel("HSV"); m_ComponentLabel0->SetBaseString("H"); m_ComponentLabel1->SetBaseString("S"); m_ComponentLabel2->SetBaseString("V"); m_ComponentAlpha->SetBaseString("A"); } if (cm == color::HLS) { m_color_model = color::HLS; m_ColorModel->SetLabel("HLS"); m_ComponentLabel0->SetBaseString("H"); m_ComponentLabel1->SetBaseString("L"); m_ComponentLabel2->SetBaseString("S"); m_ComponentAlpha->SetBaseString("A"); } if (cm == color::YUV) { m_color_model = color::YUV; m_ColorModel->SetLabel("YUV"); m_ComponentLabel0->SetBaseString("Y"); m_ComponentLabel1->SetBaseString("U"); m_ComponentLabel2->SetBaseString("V"); m_ComponentAlpha->SetBaseString("A"); } } void RGBValuator::SetColorFormat(color::Format cf) { if (cf == color::FLOAT) { m_color_format = color::FLOAT; m_ColorFormat->SetLabel("float"); red_caption_->SetKeyEntryType(BaseKeyboardHandler::eAlphaNumeric); green_caption_->SetKeyEntryType(BaseKeyboardHandler::eAlphaNumeric); blue_caption_->SetKeyEntryType(BaseKeyboardHandler::eAlphaNumeric); red_caption_->SetPrefix(""); green_caption_->SetPrefix(""); blue_caption_->SetPrefix(""); alpha_caption_->SetPrefix(""); } if (cf == color::INT) { m_color_format = color::INT; m_ColorFormat->SetLabel("int"); red_caption_->SetKeyEntryType(BaseKeyboardHandler::eIntegerNumber); green_caption_->SetKeyEntryType(BaseKeyboardHandler::eIntegerNumber); blue_caption_->SetKeyEntryType(BaseKeyboardHandler::eIntegerNumber); red_caption_->SetPrefix(""); green_caption_->SetPrefix(""); blue_caption_->SetPrefix(""); alpha_caption_->SetPrefix(""); } if (cf == color::HEX) { m_color_format = color::HEX; m_ColorFormat->SetLabel("hex"); red_caption_->SetKeyEntryType(BaseKeyboardHandler::eHexadecimalNumber); green_caption_->SetKeyEntryType(BaseKeyboardHandler::eHexadecimalNumber); blue_caption_->SetKeyEntryType(BaseKeyboardHandler::eHexadecimalNumber); red_caption_->SetPrefix("0x"); green_caption_->SetPrefix("0x"); blue_caption_->SetPrefix("0x"); alpha_caption_->SetPrefix("0x"); } if (m_color_model == color::RGB) { SetRGBA(rgb_.red, rgb_.green, rgb_.blue, alpha_); } else if (m_color_model == color::HLS) { SetHLS(hls_.hue, hls_.lightness, hls_.saturation); SetAlpha(alpha_); } else if (m_color_model == color::HSV) { SetHSV(hsv_.hue, hsv_.saturation, hsv_.value); SetAlpha(alpha_); } } void RGBValuator::PreLayoutManagement() { View::PreLayoutManagement(); if (view_layout_) { // Constrain the vertical expansion of the color selector. view_layout_->SetBaseHeight(1); } } Color RGBValuator::GetColor() const { return Color(rgb_, alpha_); } void RGBValuator::EmitColorChangedSignal() { sigColorChanged.emit(rgb_.red, rgb_.green, rgb_.blue, alpha_); } bool RGBValuator::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/RGBValuator.h0000644000000000000000000001450213313373365013656 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef RGBGEVALUATOR_H #define RGBGEVALUATOR_H #include "NuxCore/Color.h" #include "HexRegExpValidator.h" #include "IntegerValidator.h" #include "DoubleValidator.h" namespace nux { class ToggleButton; class VLayout; class HLayout; class EditTextBox; class AbstractButton; class RGBValuator : public View //public ValuatorAbstraction { NUX_DECLARE_OBJECT_TYPE(RGBValuator, View); public: RGBValuator(NUX_FILE_LINE_PROTO); RGBValuator(Color const& color, NUX_FILE_LINE_PROTO); /*! Create an initialize the widget with the appropriate color model and value. @param ColorModel The color model(CM_RGB, CM_HSV, CM_HLS) @param x Red if CM_RGB, Hue if CM_HSV, Hue if CM_HLS @param y Green if CM_RGB, Saturation if CM_HSV, Light if CM_HLS @param z Blue if CM_RGB, Value if CM_HSV, Saturation if CM_HLS @param alpha */ RGBValuator(color::Model colorModel, float x, float y, float z, float alpha, NUX_FILE_LINE_PROTO); ~RGBValuator(); // API void SetColorModel(color::Model cm); void SetColorFormat(color::Format cf); Color GetColor() const; void SetRGB(Color const& color); void SetRGB(float r, float g, float b); void SetAlpha(float alpha); void SetRGBA(Color const& color); void SetRGBA(float r, float g, float b, float a); void SetHSV(float h, float s, float v); void SetHLS(float h, float l, float s); // emitters void OnReceiveMouseDown_Red (int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDown_Green (int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDown_Blue (int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDown_Alpha (int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDrag_Red (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDrag_Green (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDrag_Blue (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDrag_Alpha (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnChangeColorModel(AbstractButton* button); void OnChangeColorFormat(AbstractButton* button); void RecvMouseDownColorModel(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseUp_Red (int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseUp_Green (int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseUp_Blue (int x, int y, unsigned long button_flags, unsigned long key_flags); void OnComponentInput (EditTextBox *textbox, const std::string &s, int componentIndex); void OnChannelKeyboardFocus(); void OnChannelLostKeyboardFocus(); void OnChannelValidateKeyboardEntry(); void OnChannelCharacter(unsigned int character, int componentIndex); //! Cause the widget to emit sigColorChanged signal. /*! Cause the widget to emit sigColorChanged signal. Useful for initialization of the signal receivers. */ void EmitColorChangedSignal(); // signals //sigc::signal sigSetRGB; sigc::signal sigColorChanged; protected: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual void PreLayoutManagement(); void InitializeWidgets(); void InitializeLayout(); virtual bool AcceptKeyNavFocus(); private: //! Override of Area::SetMinimumHeight and made private. /*! Prevent changing the minimum height of the RGBValuator view. */ virtual void SetMinimumHeight(int h){}; //! Override of Area::SetMaximumHeight and made private. /*! Prevent changing the maximum height of the RGBValuator view. */ virtual void SetMaximumHeight(int h){}; void DrawRedMarker(GraphicsEngine &graphics_engine); void DrawGreenMarker(GraphicsEngine &graphics_engine); void DrawBlueMarker(GraphicsEngine &graphics_engine); void DrawAlphaMarker(GraphicsEngine &graphics_engine); void DrawRGB(GraphicsEngine &graphics_engine); void DrawHSV(GraphicsEngine &graphics_engine); void DrawHLS(GraphicsEngine &graphics_engine); HLayout *hlayout; HLayout *redlayout; HLayout *greenlayout; HLayout *bluelayout; HLayout *alphalayout; VLayout *vlayout; VLayout *colormodel_layout; EditTextBox *red_caption_; EditTextBox *green_caption_; EditTextBox *blue_caption_; EditTextBox *alpha_caption_; BasicView *red_valuator_; BasicView *green_valuator_; BasicView *blue_valuator_; BasicView *alpha_valuator_; BasicView *color_square_; BasicView *m_ComponentLabel0; BasicView *m_ComponentLabel1; BasicView *m_ComponentLabel2; BasicView *m_ComponentAlpha; TextureLayer *m_CheckboardLayer; color::RedGreenBlue rgb_; color::HueSaturationValue hsv_; color::HueLightnessSaturation hls_; float alpha_; ToggleButton *m_ColorModel; ToggleButton *m_ColorFormat; color::Model m_color_model; color::Format m_color_format; HexRegExpValidator m_HexRegExp; IntegerValidator m_IntRegExp; DoubleValidator m_DoubleRegExp; }; } #endif // RGBGEVALUATOR_H nux-4.0.8+18.10.20180623/Nux/RadioButton.cpp0000644000000000000000000000767713313373365014332 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "HLayout.h" #include "RadioButton.h" #include "StaticText.h" #include "RadioButtonGroup.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(RadioButton); RadioButton::RadioButton(const std::string& str, bool state, NUX_FILE_LINE_DECL) : AbstractCheckedButton(str, state, NUX_FILE_LINE_PARAM) { block_changed_signal_ = false; radio_group_index_ = -1; } RadioButton::~RadioButton() { if (radio_button_group_.IsValid() && radio_group_index_ != -1) { radio_button_group_->DisconnectButton(this); if (radio_button_group_->GetNumButtons() == 0) { // The last button in the group calls UnReference on the RadioButtonGroup. radio_button_group_->UnReference(); } } } void RadioButton::Draw(GraphicsEngine& graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); InteractState is; is.is_on = active_; if (visual_state_ == VISUAL_STATE_PRESSED) { is.is_focus = true; } else if (visual_state_ == VISUAL_STATE_PRELIGHT) { is.is_prelight = true; } else { is.is_focus = false; is.is_prelight = false; } GetPainter().PushPaintLayerStack(); { GetPainter().PaintRadioButton(graphics_engine, check_area_->GetGeometry(), is, Color(0xff000000)); static_text_->ProcessDraw(graphics_engine, true); } GetPainter().PopPaintLayerStack(); graphics_engine.PopClippingRectangle(); } void RadioButton::RecvClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (radio_button_group_.IsValid()) { block_changed_signal_ = true; radio_button_group_->NotifyClick(this); block_changed_signal_ = false; state_change.emit(this); click.emit(this); } else { active_ = !active_; click.emit(this); } QueueDraw(); } void RadioButton::Activate() { if (radio_button_group_.IsValid()) { radio_button_group_->SetActiveButton(this, true); return; } SetStatePrivate(true); } void RadioButton::Deactivate() { if (radio_button_group_.IsValid()) { // The RadioButton is part of a group. To deactivate it, activate another radio button in that group."; return; } SetStatePrivate(false); } void RadioButton::SetRadioButtonGroup(RadioButtonGroup* radio_button_group) { if (radio_button_group_.IsValid() && radio_button_group_.GetPointer() == radio_button_group) return; if (radio_button_group_.IsValid()) { radio_button_group_.Release(); } if (radio_button_group) { radio_button_group_ = ObjectWeakPtr(radio_button_group); } } ObjectWeakPtr RadioButton::GetRadioButtonGroup() { return radio_button_group_; } void RadioButton::SetStatePrivate(bool state) { active_ = state; QueueDraw(); } void RadioButton::SetStatePrivate(bool state, bool emit_signal) { active_ = state; if (emit_signal && !block_changed_signal_) { state_change.emit(this); } QueueDraw(); } } nux-4.0.8+18.10.20180623/Nux/RadioButton.h0000644000000000000000000000627013313373365013763 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef RADIO_BUTTON_H #define RADIO_BUTTON_H #include "AbstractCheckedButton.h" namespace nux { class HLayout; class InputArea; class StaticText; class RadioButtonGroup; //! RadioButton class /*! A RadioButton class. Work with the RadioButtonGroup to allow "one to many" selection.\n The RadioButton class cannot be vertically resized. It can only be resized horizontally. The vertical size is always match the size of the content (check area + label). */ class RadioButton: public AbstractCheckedButton { NUX_DECLARE_OBJECT_TYPE(RadioButton, AbstractCheckedButton); public: RadioButton(const std::string& str, bool state = false, NUX_FILE_LINE_PROTO); virtual ~RadioButton(); //! Emitted when the button is clicked. sigc::signal click; //! Emitted when the active state changes. /*! Emitted when the active state changes, as a result of a mouse click or an API call.\n \sa Activate, Deactivate. */ sigc::signal state_change; //! Activate the radio button. /*! Activate the radio button. If this radio button is part of a RadioButtonGroup, it will emit the signal state_change. */ virtual void Activate(); //! Deactivate the radio button. /*! Deactivate the radio button. */ virtual void Deactivate(); protected: virtual void Draw(GraphicsEngine& graphics_engine, bool force_draw); virtual void RecvClick(int x, int y, unsigned long button_flags, unsigned long key_flags); bool block_changed_signal_; void SetRadioButtonGroup(RadioButtonGroup* radio_button_group); ObjectWeakPtr GetRadioButtonGroup(); //! Intended for RadioButtonGroup only. void SetStatePrivate(bool state); //! Intended for RadioButtonGroup only. void SetStatePrivate(bool state, bool emit_signal); ObjectWeakPtr radio_button_group_; int radio_group_index_; private: //! Override of Area::SetMinimumHeight and made private. /*! Prevent changing the minimum height of the StaticText view. */ virtual void SetMinimumHeight(int h){}; //! Override of Area::SetMaximumHeight and made private. /*! Prevent changing the maximum height of the StaticText view. */ virtual void SetMaximumHeight(int h){}; friend class RadioButtonGroup; }; } #endif // RADIO_BUTTON_H nux-4.0.8+18.10.20180623/Nux/RadioButtonGroup.cpp0000644000000000000000000001207413313373365015332 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "RadioButton.h" #include "RadioButtonGroup.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(RadioButtonGroup); RadioButtonGroup::RadioButtonGroup(NUX_FILE_LINE_DECL) : InitiallyUnownedObject(NUX_FILE_LINE_PARAM) // RadioButtonGroup is created as un-owned , active_button_index_(0) { } RadioButtonGroup::~RadioButtonGroup() { std::vector >::iterator it; for (it = radio_button_array_.begin(); it != radio_button_array_.end(); it++) { if ((*it).IsValid()) { (*it)->SetRadioButtonGroup(NULL); (*it)->radio_group_index_ = -1; } } } void RadioButtonGroup::ConnectButton(RadioButton* radio) { if (radio == NULL) { return; } if (!radio->Type().IsDerivedFromType(RadioButton::StaticObjectType)) { return; } std::vector >::iterator it; for (it = radio_button_array_.begin(); it != radio_button_array_.end(); it++) { if ((*it).IsValid() && ((*it).GetPointer() == radio)) { // already in return; } } size_t index = (unsigned int) radio_button_array_.size(); if (index == 0) { // Inserting the first radio button if (radio->GetRadioButtonGroup().IsValid()) { // Disconnect from the other selector radio->GetRadioButtonGroup()->DisconnectButton(radio); } radio->SetRadioButtonGroup(this); radio->radio_group_index_ = 0; radio->SetStatePrivate(true); radio_button_array_.push_back(ObjectWeakPtr(radio)); active_button_index_ = 0; } else { if (radio->GetRadioButtonGroup().IsValid()) { // Disconnect from the other selector radio->GetRadioButtonGroup()->DisconnectButton(radio); } radio->SetRadioButtonGroup(this); radio->radio_group_index_ = index; // When a radio button is added to a group that is not empty, its check state is set to false. radio->SetStatePrivate(false); radio_button_array_.push_back(ObjectWeakPtr(radio)); } } void RadioButtonGroup::DisconnectButton(RadioButton* radio) { bool found = false; size_t array_size = (unsigned int) radio_button_array_.size(); std::vector >::iterator it; it = radio_button_array_.begin(); size_t i; for (i = 0; i < array_size; i++, it++) { if (radio_button_array_[i] == radio) { radio->radio_group_index_ = -1; radio->SetStatePrivate(false); radio_button_array_.erase(it); found = true; break; } } if (found && (i - 1 > 0) && (!radio_button_array_.empty())) { // The previous button becomes active radio_button_array_[i]->SetStatePrivate(true); } } int RadioButtonGroup::GetNumButtons() { int count = 0; std::vector >::iterator it; for (it = radio_button_array_.begin(); it != radio_button_array_.end(); ++it) { if ((*it).IsValid()) { ++count; } } return count; } void RadioButtonGroup::NotifyClick(RadioButton* radio) { std::vector >::iterator it; for (it = radio_button_array_.begin(); it != radio_button_array_.end(); ++it) { if ((*it).GetPointer() != radio) { if ((*it).IsValid()) { (*it)->SetStatePrivate(false, true); } } else { if ((*it).IsValid()) { (*it)->SetStatePrivate(true, true); } } } } void RadioButtonGroup::SetActiveButton(RadioButton* radio, bool emit_signal) { std::vector >::iterator it = find(radio_button_array_.begin(), radio_button_array_.end(), radio); if (it == radio_button_array_.end()) return; if ((*it).IsValid() == false) { // The button has been destroyed. // Remove it from the array radio_button_array_.erase(it); return; } for (it = radio_button_array_.begin(); it != radio_button_array_.end(); ++it) { if ((*it).IsValid() && ((*it).GetPointer() != radio)) { (*it)->SetStatePrivate(false, emit_signal); } } radio->SetStatePrivate(true, emit_signal); } } nux-4.0.8+18.10.20180623/Nux/RadioButtonGroup.h0000644000000000000000000000534713313373365015004 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef RADIOBUTTONLOGIC_H #define RADIOBUTTONLOGIC_H namespace nux { class RadioButton; //! RadioButtonGroup select one of many radio button in a group. /*! RadioButtonGroup does not hold a strong reference on radio buttons. */ class RadioButtonGroup: public InitiallyUnownedObject { NUX_DECLARE_OBJECT_TYPE(RadioButtonGroup, InitiallyUnownedObject); public: RadioButtonGroup(NUX_FILE_LINE_PROTO); ~RadioButtonGroup(); //! Add a radio button to the group. /* The first radio button added to the group gets its check state set to true. When a radio button is added to a group that is not empty, its check state is set to false. */ void ConnectButton(RadioButton* radio); //! Remove a radio button from the group. /* When a radio button is removed, the previous button in the group gets its check state set to true; */ void DisconnectButton(RadioButton* radio); //! Set the active radio button. /* Set the active radio button in the group. If \i emit_signal is true, all the button in the group emit their \i state_changed signal.\n If the parameter \i radio is already active and \i emit_signal is true, the \i state_changed signal will be emitted.\n The active button is the last one to emit its \i state_changed signal. @param radio The button to activate. @param emit_signal If true, emit the state_changed signal of all the buttons in the group. */ void SetActiveButton(RadioButton* radio, bool emit_signal = true); private: //! Return the number of buttons in the group. /*! Return the number of buttons in the group. @return The number of buttons in the group. */ int GetNumButtons(); void NotifyClick(RadioButton* radio); std::vector > radio_button_array_; int active_button_index_; friend class RadioButton; }; } #endif // RADIOBUTTONLOGIC_H nux-4.0.8+18.10.20180623/Nux/RangeValue.cpp0000644000000000000000000001747613313373365014127 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "EditTextBox.h" #include "HLayout.h" #include "RangeValue.h" #include #include namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(RangeValue); RangeValue::RangeValue(float Value, float MinValue, float MaxValue, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { m_min = MinValue; m_max = MaxValue; m_StartColor = Color(0xff202020); m_EndColor = Color(0xff202020); m_ProgressColor = Color(0xff606060); m_EnableDrawProgress = true; m_CTRL_KEY = 0; InitializeLayout(); InitializeWidgets(); SetValue(Value); } RangeValue::~RangeValue() { } void RangeValue::InitializeWidgets() { ////////////////// // Set Signals // ////////////////// m_Percentage->mouse_down.connect(sigc::mem_fun(this, &RangeValue::OnReceiveMouseDown)); m_Percentage->mouse_up.connect(sigc::mem_fun(this, &RangeValue::OnReceiveMouseUp)); m_Percentage->mouse_drag.connect(sigc::mem_fun(this, &RangeValue::OnReceiveMouseDrag)); m_ValueString->sigValidateKeyboardEntry.connect(sigc::mem_fun(this, &RangeValue::OnValidateKeyboardEntry)); ////////////////// // Set Geometry // ////////////////// m_ValueString->SetMinimumSize(DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT); m_ValueString->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT)); m_Percentage->SetMinimumSize(2 * DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT); m_Percentage->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT)); // Set the minimum size of this widget. // This is use by RangeValuePropertyItem::GetItemBestHeight SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); hlayout->AddView(m_ValueString, 0, eCenter, eFull); hlayout->AddView(m_Percentage, 4, eCenter, eFull); //hlayout->AddLayout(&vlayout, 4); hlayout->SetHorizontalExternalMargin(0); hlayout->SetHorizontalInternalMargin(2); hlayout->SetVerticalExternalMargin(0); SetCompositionLayout(hlayout); } void RangeValue::InitializeLayout() { hlayout = new HLayout(NUX_TRACKER_LOCATION); m_Percentage = new BasicView(NUX_TRACKER_LOCATION); m_ValueString = new EditTextBox("", NUX_TRACKER_LOCATION); } void RangeValue::DrawMarker(GraphicsEngine &graphics_engine) { int marker_position_x; int marker_position_y; graphics_engine.PushClippingRectangle(m_Percentage->GetGeometry()); marker_position_x = m_Percentage->GetBaseX() + (m_Value - m_min) * m_Percentage->GetBaseWidth() * 1 / (m_max - m_min); marker_position_y = m_Percentage->GetBaseY() + m_Percentage->GetBaseHeight(); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 5, marker_position_y, marker_position_x, marker_position_y - 5, marker_position_x + 5, marker_position_y, Color(0.0f, 0.0f, 0.0f, 1.0f)); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 4, marker_position_y, marker_position_x, marker_position_y - 4, marker_position_x + 4, marker_position_y, Color(0.7f, 0.7f, 0.7f, 1.0f)); graphics_engine.PopClippingRectangle(); } void RangeValue::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { // Percentage Geometry P = m_Percentage->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, m_StartColor, m_StartColor, m_EndColor, m_EndColor); if (m_EnableDrawProgress) { P.SetWidth((m_Value - m_min) * (float) P.GetWidth() / (m_max - m_min)); GetPainter().Paint2DQuadColor(graphics_engine, P, m_ProgressColor); } m_ValueString->ProcessDraw(graphics_engine, true); DrawMarker(graphics_engine); } void RangeValue::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { m_ValueString->ProcessDraw(graphics_engine, force_draw); } ///////////////// // RECEIVERS // ///////////////// void RangeValue::SetRange(float min_value, float max_value) { if (min_value < max_value) { m_min = min_value; m_max = max_value; } else { m_min = max_value; m_max = min_value; } if (m_Value < m_min) m_Value = m_min; else if (m_Value > m_max) m_Value = m_max; SetValue(m_Value); } void RangeValue::SetValue(float value) { if (value < m_min) m_Value = m_min; else if (value > m_max) m_Value = m_max; else m_Value = value; m_ValueString->SetText(std::to_string((long double)m_Value)); QueueDraw(); } float RangeValue::GetValue() const { return m_Value; } //////////////// // EMITTERS // //////////////// void RangeValue::OnReceiveMouseDown(int x, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (x < 0) m_Value = m_min; else if (x > m_Percentage->GetBaseWidth()) m_Value = m_max; else m_Value = m_min + (m_max - m_min) * (float) x / (float) m_Percentage->GetBaseWidth(); m_ValueString->SetText(std::to_string((long double)m_Value)); sigValueChanged.emit(this); sigFloatChanged.emit(m_Value); sigMouseDown.emit(m_Value); QueueDraw(); } void RangeValue::OnReceiveMouseUp(int x, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (x < 0) m_Value = m_min; else if (x > m_Percentage->GetBaseWidth()) m_Value = m_max; else m_Value = m_min + (m_max - m_min) * (float) x / (float) m_Percentage->GetBaseWidth(); std::stringstream s; s << std::setprecision(3) << m_Value; m_ValueString->SetText(s.str()); sigValueChanged.emit(this); sigFloatChanged.emit(m_Value); sigMouseUp.emit(m_Value); QueueDraw(); } void RangeValue::OnReceiveMouseDrag(int x, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (x < 0) m_Value = m_min; else if (x > m_Percentage->GetBaseWidth()) m_Value = m_max; else m_Value = m_min + (m_max - m_min) * (float) x / (float) m_Percentage->GetBaseWidth(); std::stringstream s; s << std::setprecision(3) << m_Value; m_ValueString->SetText(s.str()); sigValueChanged.emit(this); sigFloatChanged.emit(m_Value); sigMouseDrag.emit(m_Value); QueueDraw(); } void RangeValue::OnKeyboardFocus() { } void RangeValue::OnLostKeyboardFocus() { } void RangeValue::OnValidateKeyboardEntry(EditTextBox* /* textbox */, const std::string &text) { float f; f = CharToDouble(text.c_str()); SetValue(f); sigValueChanged.emit(this); sigFloatChanged.emit(m_Value); sigSetTypedValue.emit(f); QueueDraw(); } void RangeValue::EmitFloatChangedSignal() { sigFloatChanged.emit(m_Value); } void RangeValue::SetBackgroundColor(const Color &color) { m_ValueString->SetTextBackgroundColor(color); } const Color RangeValue::GetBackgroundColor() const { return m_ValueString->GetTextBackgroundColor(); } } nux-4.0.8+18.10.20180623/Nux/RangeValue.h0000644000000000000000000000675713313373365013574 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef RANGEVALUE_H #define RANGEVALUE_H namespace nux { class HLayout; class EditTextBox; class RangeValue : public View { NUX_DECLARE_OBJECT_TYPE(RangeValue, View); public: RangeValue(float Value = 0, float MinValue = 0.0f, float MaxValue = 1.0f, NUX_FILE_LINE_PROTO); virtual ~RangeValue(); void DrawMarker(GraphicsEngine &graphics_engine); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); ///////////////// // RECEIVERS // ///////////////// void SetRange(float min_value, float max_value); void SetValue(float value); float GetValue() const; float GetMinValue() const { return m_min; } float GetMaxValue() const { return m_max; } void SetBackgroundColor(const Color &color); const Color GetBackgroundColor() const; void setStartToEndColor(Color color_start, Color color_end) { m_StartColor = color_start; m_EndColor = color_end; } void setStartColor(Color color) { m_StartColor = color; } void setEndColor(Color color) { m_EndColor = color; } void setProgressColor(Color color) { m_ProgressColor = color; } void EnableDrawProgress(bool b) { m_EnableDrawProgress = b; } //////////////// // EMITTERS // //////////////// void OnReceiveMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnKeyboardFocus(); void OnLostKeyboardFocus(); void OnValidateKeyboardEntry(EditTextBox *textbox, const std::string &text); bool IsCtrlKeyPressed() const { return m_CTRL_KEY; } // signals sigc::signal sigValueChanged; sigc::signal sigFloatChanged; sigc::signal sigMouseDown; sigc::signal sigMouseUp; sigc::signal sigMouseDrag; sigc::signal sigSetTypedValue; //sigc::signal sigValidateKeyboarEntry; void EmitFloatChangedSignal(); protected: void InitializeWidgets(); void InitializeLayout(); protected: HLayout *hlayout; EditTextBox *m_ValueString; BasicView *m_Percentage; Color m_StartColor; Color m_EndColor; Color m_ProgressColor; Color m_BackgroundColor; bool m_EnableDrawProgress; long m_CTRL_KEY; float m_Value; float m_min, m_max; }; } #endif // RANGEVALUE_H nux-4.0.8+18.10.20180623/Nux/RangeValueInteger.cpp0000644000000000000000000002035213313373365015430 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "EditTextBox.h" #include "HLayout.h" #include "RangeValueInteger.h" namespace nux { RangeValueInteger::RangeValueInteger(int Value, int MinValue, int MaxValue, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { m_min = MinValue; m_max = MaxValue; m_StartColor = Color(0xff202020); m_EndColor = Color(0xff202020); m_ProgressColor = Color(0xff606060); m_EnableDrawProgress = true; m_CTRL_KEY = 0; m_MarkerPosition = 0; InitializeLayout(); InitializeWidgets(); SetValue(Value); } RangeValueInteger::~RangeValueInteger() { } void RangeValueInteger::InitializeWidgets() { ////////////////// // Set Signals // ////////////////// m_Percentage->mouse_down.connect(sigc::mem_fun(this, &RangeValueInteger::OnReceiveMouseDown)); m_Percentage->mouse_up.connect(sigc::mem_fun(this, &RangeValueInteger::OnReceiveMouseUp)); m_Percentage->mouse_drag.connect(sigc::mem_fun(this, &RangeValueInteger::OnReceiveMouseDrag)); m_ValueString->sigValidateKeyboardEntry.connect(sigc::mem_fun(this, &RangeValueInteger::OnValidateKeyboardEntry)); ////////////////// // Set Geometry // ////////////////// m_ValueString->SetMinimumSize(DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT); m_ValueString->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT)); m_Percentage->SetMinimumSize(2 * DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT); m_Percentage->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT)); // Set the minimum size of this widget. // This is use by RangeValuePropertyItem::GetItemBestHeight SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); hlayout->AddView(m_ValueString, 0, eCenter, eFull); hlayout->AddView(m_Percentage, 4, eCenter, eFull); //hlayout->AddLayout(&vlayout, 4); hlayout->SetHorizontalExternalMargin(0); hlayout->SetHorizontalInternalMargin(2); hlayout->SetVerticalExternalMargin(0); SetCompositionLayout(hlayout); } void RangeValueInteger::InitializeLayout() { hlayout = new HLayout(NUX_TRACKER_LOCATION); m_Percentage = new BasicView(NUX_TRACKER_LOCATION); m_ValueString = new EditTextBox("", NUX_TRACKER_LOCATION); } void RangeValueInteger::DrawMarker(GraphicsEngine &graphics_engine) { int marker_position_x; int marker_position_y; graphics_engine.PushClippingRectangle(m_Percentage->GetGeometry()); marker_position_x = m_Percentage->GetBaseX() + (m_MarkerPosition - m_min) * m_Percentage->GetBaseWidth() * 1 / (m_max - m_min); marker_position_y = m_Percentage->GetBaseY() + m_Percentage->GetBaseHeight(); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 5, marker_position_y, marker_position_x, marker_position_y - 5, marker_position_x + 5, marker_position_y, Color(0.0f, 0.0f, 0.0f, 1.0f)); GetPainter().Draw2DTriangleColor(graphics_engine, marker_position_x - 4, marker_position_y, marker_position_x, marker_position_y - 4, marker_position_x + 4, marker_position_y, Color(0.7f, 0.7f, 0.7f, 1.0f)); graphics_engine.PopClippingRectangle(); } void RangeValueInteger::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { // Percentage Geometry P = m_Percentage->GetGeometry(); GetPainter().Paint2DQuadColor(graphics_engine, P, m_StartColor, m_StartColor, m_EndColor, m_EndColor); if (m_EnableDrawProgress) { P.SetWidth((m_MarkerPosition - m_min) * (float) P.GetWidth() / (m_max - m_min)); GetPainter().Paint2DQuadColor(graphics_engine, P, m_ProgressColor); } DrawMarker(graphics_engine); } void RangeValueInteger::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { m_ValueString->ProcessDraw(graphics_engine, force_draw); } void RangeValueInteger::SetRange(int min_value, int max_value) { if (min_value < max_value) { m_min = min_value; m_max = max_value; } else { m_min = max_value; m_max = min_value; } if (m_Value < m_min) m_Value = m_min; else if (m_Value > m_max) m_Value = m_max; SetValue(m_Value); } void RangeValueInteger::SetValue(int value) { if (value < m_min) m_Value = m_min; else if (value > m_max) m_Value = m_max; else m_Value = value; m_MarkerPosition = m_Value; m_ValueString->SetText(std::to_string((long long)m_Value)); QueueDraw(); } int RangeValueInteger::GetValue() const { return m_Value; } //////////////// // EMITTERS // //////////////// void RangeValueInteger::OnReceiveMouseDown(int x, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (x < 0) { m_Value = m_min; m_MarkerPosition = m_Value; } else if (x > m_Percentage->GetBaseWidth()) { m_Value = m_max; m_MarkerPosition = m_Value; } else { m_Value = m_min + (m_max - m_min) * (float) x / (float) m_Percentage->GetBaseWidth(); m_MarkerPosition = m_min + (m_max - m_min) * (float) x / (float) m_Percentage->GetBaseWidth(); if (m_MarkerPosition - m_Value > 0.5f) m_Value++; } m_ValueString->SetText(std::to_string((long long)m_Value)); sigValueChanged.emit(this); sigMouseDown.emit(m_Value); sigValueChanged2.emit(m_Value); QueueDraw(); } void RangeValueInteger::OnReceiveMouseUp(int x, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (x < 0) m_Value = m_min; else if (x > m_Percentage->GetBaseWidth()) m_Value = m_max; else { m_Value = m_min + (m_max - m_min) * (float) x / (float) m_Percentage->GetBaseWidth(); if (m_MarkerPosition - m_Value > 0.5f) m_Value++; } m_MarkerPosition = m_Value; m_ValueString->SetText(std::to_string((long long)m_Value)); sigValueChanged.emit(this); sigMouseUp.emit(m_Value); sigValueChanged2.emit(m_Value); QueueDraw(); } void RangeValueInteger::OnReceiveMouseDrag(int x, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (x < 0) { m_Value = m_min; m_MarkerPosition = m_Value; } else if (x > m_Percentage->GetBaseWidth()) { m_Value = m_max; m_MarkerPosition = m_Value; } else { m_Value = m_min + (m_max - m_min) * (float) x / (float) m_Percentage->GetBaseWidth(); m_MarkerPosition = m_min + (m_max - m_min) * (float) x / (float) m_Percentage->GetBaseWidth(); if (m_MarkerPosition - m_Value > 0.5f) m_Value++; } m_ValueString->SetText(std::to_string((long long)m_Value)); sigValueChanged.emit(this); sigMouseDrag.emit(m_Value); sigValueChanged2.emit(m_Value); QueueDraw(); } void RangeValueInteger::OnKeyboardFocus() { } void RangeValueInteger::OnLostKeyboardFocus() { } void RangeValueInteger::OnValidateKeyboardEntry(EditTextBox* /* textbox */, const std::string &text) { int i; i = CharToInteger(text.c_str()); SetValue(i); sigValueChanged.emit(this); sigSetTypedValue.emit(i); sigValueChanged2.emit(m_Value); QueueDraw(); } void RangeValueInteger::BroadcastValue() { sigValueChanged2.emit(m_Value); } } nux-4.0.8+18.10.20180623/Nux/RangeValueInteger.h0000644000000000000000000000713113313373365015075 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef RANGEVALUEINTEGER_H #define RANGEVALUEINTEGER_H namespace nux { class HLayout; class EditTextBox; class RangeValueInteger : public View { public: RangeValueInteger(int Value = 0, int MinValue = 0, int MaxValue = 100, NUX_FILE_LINE_PROTO); ~RangeValueInteger(); void DrawMarker(GraphicsEngine &graphics_engine); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); ///////////////// // RECEIVERS // ///////////////// void SetRange(int min_value, int max_value); void SetValue(int value); int GetValue() const; int GetMinValue() const { return m_min; } int GetMaxValue() const { return m_max; } void SetBackgroundColor(const Color &color) { m_ValueString->SetTextBackgroundColor(color); } const Color GetBackgroundColor() const { return m_ValueString->GetTextBackgroundColor(); } void setStartToEndColor(Color color_start, Color color_end) { m_StartColor = color_start; m_EndColor = color_end; } void setStartColor(Color color) { m_StartColor = color; } void setEndColor(Color color) { m_EndColor = color; } void setProgressColor(Color color) { m_ProgressColor = color; } void EnableDrawProgress(bool b) { m_EnableDrawProgress = b; } //////////////// // EMITTERS // //////////////// void OnReceiveMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnReceiveMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnKeyboardFocus(); void OnLostKeyboardFocus(); void OnValidateKeyboardEntry(EditTextBox *textbox, const std::string &text); bool IsCtrlKeyPressed() const { return m_CTRL_KEY; } // signals sigc::signal sigValueChanged; sigc::signal sigMouseDown; sigc::signal sigMouseUp; sigc::signal sigMouseDrag; sigc::signal sigSetTypedValue; sigc::signal sigValueChanged2; //sigc::signal sigValidateKeyboarEntry; void BroadcastValue(); protected: void InitializeWidgets(); void InitializeLayout(); protected: HLayout *hlayout; EditTextBox *m_ValueString; BasicView *m_Percentage; Color m_StartColor; Color m_EndColor; Color m_ProgressColor; Color m_BackgroundColor; bool m_EnableDrawProgress; long m_CTRL_KEY; float m_MarkerPosition; int m_Value; int m_min, m_max; }; } #endif // RANGEVALUEINTEGER_H nux-4.0.8+18.10.20180623/Nux/Readme.txt0000644000000000000000000001151413313373365013313 0ustar Wednesday, May 10, 2006 -------------------------- Implemented RTTI with ObjectType. class InterfaceControl now inherits from BaseArea. remove m_BackgroundArea from InterfaceControl. Tuesday, November 23, 2005 -------------------------- I have reach a milestone. I am no longer concern about the feasibility of the GUI. For the most part, it is completed. Many things have been implemented: - file menu - status bar - modal window dialog - ... At this stage, I am cleaning the project in order to package the GUI in a library. From there, I will start designing some applications. Monday, August 1, 2005 ---------------------- The ComboBox is done. For that purpose, the third parameter of OnEvent and ProcessEvent was designed: ProcessEventInfo. ProcessEventInfo allow each base area OnEvent function to receive the event but not to process it. Previously if a mouse down was not inside a window, that window wouldn't propagate the event. Now, the event is propagated up to the OnEvent function and this one won't process the event if ProcessEventInfo = eDoNotProcess. If ProcessEventInfo = eDoNotProcess, only some check about m_CaptureMouseDownAnyWhereElse are done if needed. This feature can also be use to update timer on dynamic drawing objet attached to the widget (progressive appearance or dissapearance of a popup window for instance). If a BaseArea object has m_CaptureMouseDownAnyWhereElse = true, then that object want to receive notification every time a mouse down happens outside of its geometry. PushButton is working. ToolButton is on the way. Friday, july 15, 2005 -------------------- Rearranged the the OpenGL window Client (moved to OpenGLEngine) and GfxServer. New Table widget (later list box, tree list) Added DevIL as the texture file reader. Replace the FreeType code with Font.cpp and Fonts.hpp. This solution is more efficient and better regarding performance. Various clean Up Friday, may 20, 2005 -------------------- Fixed some text entry inconsistencies. Cleanup of signals. Added Signals and Functions for keyboard entry focus. Sunday, May 15, 2005 -------------------- Vertical and Horizontal scrollbars are working. Some minor inconsistencies still remain, but they will be fixed. Added debug feature for layout: - fixed margins - drawing of layouts borders with #define DEBUG_LAYOUT Friday, May 13, 2005 --------------------- Integers and Scrollbar don't fit together. All coordinates and width/height will be converted to float. Wednesday, May 11, 2005 ----------------------- - Addd vertical and horizontal scrollbar. 2005-05-07 ------------ - Added Drawing clipping region stack. This is a feature that clips a region against its parent before the region is drawn. This is needed for the GUI interface. The GUI Areas are stacked inside other Areas. At the highest level, a window set the clipping region to its size. And area inside the Window will then set the clipping region to its own side before it is drawn(PushClippingRectangle). What the clipping features does is, it clips the new region against the previous one and pushes the resulting region on the stack and uses it to set glScissor. If the result of the intersection is null, the clipping region is set to a null rectangle (nothing is drawn). After drawing the area, call PopClippingRectangle to pop the current clipping region and restore the previous clipping region. PushClippingRectangle - If(there is a current clipping region on the stack) compute the intersection between the input region and the region on the stack. Else clip the input region against the full window size. - If(the intersection is not null) set the glScissor to the size and position of the intersection region. Else set glScissor(0, 0, 0, 00 (nothing is drawn) PushClippingRectangle - If(there is a current clipping region on the stack) - pop it - If(the stack is not empty) set the clipping region to the size and position of the region on top of the stack Else set glScissor to the full window size. - The original generic template design provided by Loki is no longer par of the design. It has been replaced by a more classic architecture featuring inheritance and virtual functions. Also, A new layout design has been implemented. It took some time and effort before a suitable design could be achieved. I call this design "Follow, Rebel then Lead" or FRL. A design document is definitely needed here. At least so I can remember what I did latter. Some new widget have been implemented, most notably, the RGB color selector. 2005-04-05 ------------ I am getting ride of the generic interface for BaseArea. I don't think I need it anymore. BaseArea as enough functionality and I can handle it directly to composite widget. The free List feature comming with template is not tht useful since there are only few BaseArea that compose a widget. I will refactor the ValuatorImpl first.nux-4.0.8+18.10.20180623/Nux/ScrollBar.cpp0000644000000000000000000000250313313373365013742 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "ScrollBar.h" namespace nux { ScrollBar::ScrollBar(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { m_visible = 1; m_ScrollUnit = 5; visibility_percentage_ = 0.0f; } ScrollBar::~ScrollBar() { } void ScrollBar::SetScrollUnit(int unit) { nuxAssert(unit > 0); m_ScrollUnit = unit; if (m_ScrollUnit <= 0) m_ScrollUnit = 5; } int ScrollBar::GetScrollUnit() const { return m_ScrollUnit; } bool ScrollBar::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/ScrollBar.h0000644000000000000000000000326513313373365013415 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef SCROLLBAR_H #define SCROLLBAR_H namespace nux { class ScrollView; class ScrollBar : public View //public ValuatorAbstraction { public: ScrollBar(NUX_FILE_LINE_PROTO); ~ScrollBar(); private: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw) = 0; virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw) = 0; public: int visible() const { return m_visible; } void clear_visible() { m_visible = 0; } void set_visible() { m_visible = 1; } void resize(int x, int y, int w, int h) { SetGeometry(Geometry(x, y, w, h)); } void SetScrollUnit(int unit); int GetScrollUnit() const; protected: virtual bool AcceptKeyNavFocus(); int m_ScrollUnit; int m_visible; float visibility_percentage_; friend class ScrollView; }; } #endif // SCROLLBAR_H nux-4.0.8+18.10.20180623/Nux/ScrollView.cpp0000644000000000000000000005407313313373365014161 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2010-2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "HScrollBar.h" #include "VScrollBar.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "ScrollView.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(ScrollView); ScrollView::ScrollView(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_MouseWheelScrollSize(32) // TODO: these should really be Rects. , m_ViewContentX(0) , m_ViewContentY(0) , m_ViewContentWidth(0) , m_ViewContentHeight(0) , m_ViewX(0) , m_ViewY(0) , m_ViewWidth(0) , m_ViewHeight(0) , m_TextureIndex(0) , m_ReformatTexture(true) , m_horizontal_scrollbar_enable(true) , m_vertical_scrollbar_enable(true) , m_top_border(0) , m_border(0) , _delta_x(0) , _delta_y(0) , m_bSizeMatchContent(false) , m_ViewContentLeftMargin(0) , m_ViewContentRightMargin(0) , m_ViewContentTopMargin(0) , m_ViewContentBottomMargin(0) { _hscrollbar = new HScrollBar(NUX_TRACKER_LOCATION); _vscrollbar = new VScrollBar(NUX_TRACKER_LOCATION); // _hscrollbar and _vscrollbar have to be parented so they are correctly // rendered and so that GetRootGeometry/GetAbsoluteGeometry returns the // correct Geometry. This is necessary in embedded mode. _hscrollbar->SetParentObject(this); _vscrollbar->SetParentObject(this); _hscrollbar->SetReconfigureParentLayoutOnGeometryChange(false); _vscrollbar->SetReconfigureParentLayoutOnGeometryChange(false); SetMinimumSize(30, 30); SetGeometry(Geometry(0, 0, 400, 200)); _hscrollbar->OnScrollLeft.connect(sigc::mem_fun(this, &ScrollView::ScrollLeft)); _hscrollbar->OnScrollRight.connect(sigc::mem_fun(this, &ScrollView::ScrollRight)); _vscrollbar->OnScrollUp.connect(sigc::mem_fun(this, &ScrollView::ScrollUp)); _vscrollbar->OnScrollDown.connect(sigc::mem_fun(this, &ScrollView::ScrollDown)); mouse_wheel.connect(sigc::mem_fun(this, &ScrollView::RecvMouseWheel)); _vscrollbar->mouse_wheel.connect(sigc::mem_fun(this, &ScrollView::RecvMouseWheel)); FormatContent(); SetAcceptMouseWheelEvent(true); } // customization for Unity void ScrollView::SetVScrollBar(VScrollBar* newVScrollBar) { if (_vscrollbar) { // disconnect old _vscrollbar _vscrollbar->OnScrollUp.connect(sigc::mem_fun(this, &ScrollView::ScrollUp)); _vscrollbar->OnScrollDown.connect(sigc::mem_fun(this, &ScrollView::ScrollDown)); _vscrollbar->mouse_wheel.connect(sigc::mem_fun(this, &ScrollView::RecvMouseWheel)); _vscrollbar->UnReference(); } _vscrollbar = newVScrollBar; _vscrollbar->SetParentObject(this); _vscrollbar->SetReconfigureParentLayoutOnGeometryChange(false); // connect new _vscrollbar _vscrollbar->OnScrollUp.connect(sigc::mem_fun(this, &ScrollView::ScrollUp)); _vscrollbar->OnScrollDown.connect(sigc::mem_fun(this, &ScrollView::ScrollDown)); _vscrollbar->mouse_wheel.connect(sigc::mem_fun(this, &ScrollView::RecvMouseWheel)); } ScrollView::~ScrollView() { // Delete all the interface object: This is a problem... The widget should be destroy by there associated parameters _hscrollbar->UnReference(); _vscrollbar->UnReference(); } Area* ScrollView::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { // Test if the mouse is inside the ScrollView. // The last parameter of TestMousePointerInclusion is a boolean used to test if the case // of mouse wheel events. If that boolean value is true, then TestMousePointerInclusion // returns true only if the mouse pointer is over this area and the the area accepts // mouse wheel events(see Area::SetAcceptMouseWheelEvent) bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) { // The mouse pointer is not over this Area. return NULL. return NULL; } Area* found_area; // Recursively go over the ui element that are managed by this ScrollView and look // for the area that is below the mouse. // Test the vertical scrollbar if (m_vertical_scrollbar_enable) { found_area = _vscrollbar->FindAreaUnderMouse(mouse_position, event_type); NUX_RETURN_VALUE_IF_NOTNULL(found_area, found_area); } // Test the horizontal scrollbar if (m_horizontal_scrollbar_enable) { found_area = _hscrollbar->FindAreaUnderMouse(mouse_position, event_type); NUX_RETURN_VALUE_IF_NOTNULL(found_area, found_area); } // If the code gets here, it means that no area has been found yet. // Test the layout of the ScrollView return View::FindAreaUnderMouse(mouse_position, event_type); } bool ScrollView::SetLayout(Layout *layout) { if (View::SetLayout(layout) == false) { return false; } FormatContent(); return true; } void ScrollView::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { graphics_engine.PushClippingRectangle(GetGeometry()); Geometry base = GetGeometry(); GetPainter().PaintBackground(graphics_engine, base); if (m_vertical_scrollbar_enable) { _vscrollbar->QueueDraw(); } if (m_horizontal_scrollbar_enable) { _hscrollbar->QueueDraw(); } graphics_engine.PopClippingRectangle(); } void ScrollView::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { if (IsFullRedraw()) GetPainter().PushBackgroundStack(); graphics_engine.PushClippingRectangle(GetGeometry()); graphics_engine.PushClippingRectangle(Rect(m_ViewX, m_ViewY, m_ViewWidth, m_ViewHeight)); if (view_layout_) view_layout_->ProcessDraw(graphics_engine, force_draw); graphics_engine.PopClippingRectangle(); if (m_vertical_scrollbar_enable) { _vscrollbar->ProcessDraw(graphics_engine, force_draw); } if (m_horizontal_scrollbar_enable) { _hscrollbar->ProcessDraw(graphics_engine, force_draw); } graphics_engine.PopClippingRectangle(); if (IsFullRedraw()) GetPainter().PopBackgroundStack(); } ///////// // API // ///////// void ScrollView::EnableVerticalScrollBar(bool b) { if (b == m_vertical_scrollbar_enable) return; m_vertical_scrollbar_enable = b; ComputeContentSize(); } void ScrollView::EnableHorizontalScrollBar(bool b) { if (m_horizontal_scrollbar_enable == b) return; m_horizontal_scrollbar_enable = b; ComputeContentSize(); } /////////////////////// // Internal function // /////////////////////// void ScrollView::FormatContent() { Geometry geo; geo = GetGeometry(); ComputeContentSize(); } void ScrollView::PreLayoutManagement() { // Give the managed layout the same size and position as the Control. Geometry geo = GetGeometry(); int ScrollBarWidth = _vscrollbar->GetBaseWidth(); int ScrollBarHeight = _hscrollbar->GetBaseHeight(); nuxAssertMsg(ScrollBarWidth > 0, "[ScrollView::PreLayoutManagement] Invalid scrollbar width: %d", ScrollBarWidth); nuxAssertMsg(ScrollBarHeight > 0, "[ScrollView::PreLayoutManagement] Invalid scrollbar height: %d", ScrollBarHeight); m_ViewX = GetBaseX() + m_border + m_ViewContentLeftMargin; m_ViewY = GetBaseY() + m_top_border + m_ViewContentTopMargin; m_ViewWidth = GetBaseWidth() - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin; nuxAssertMsg(m_ViewWidth > 0, "[ScrollView::PreLayoutManagement] Invalid view width: %d", m_ViewWidth); m_ViewHeight = GetBaseHeight() - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin; nuxAssertMsg(m_ViewHeight > 0, "[ScrollView::PreLayoutManagement] Invalid view height: %d", m_ViewHeight); if (m_ViewX + _delta_x + m_ViewContentWidth < m_ViewX + m_ViewWidth) { // The position of the end of the content is smaller than the view right border position // Compute _delta_x so the end of the content match exactly the view right border position _delta_x = - (m_ViewContentWidth > m_ViewWidth ? m_ViewContentWidth - m_ViewWidth : 0); nuxAssert(_delta_x <= 0); } if (m_ViewY + _delta_y + m_ViewContentHeight < m_ViewY + m_ViewHeight) { // The position of the end of the content is smaller than the view right border position // Compute _delta_y so the end of the content match exactly the view right border position _delta_y = - (m_ViewContentHeight > m_ViewHeight ? m_ViewContentHeight - m_ViewHeight : 0); nuxAssert(_delta_y <= 0); } if (view_layout_) { // Set the composition layout to the size of the view area and offset it by(_delta_x, _delta_y) if (view_layout_->GetScaleFactor() != 0) { view_layout_->SetGeometry( m_ViewX, m_ViewY, m_ViewWidth, m_ViewHeight); } view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); } // Horizontal scrollbar Geometry if (m_horizontal_scrollbar_enable) { if (m_vertical_scrollbar_enable == false) { // If there is no vertical scrollbar, take all the width available. _hscrollbar->SetBaseWidth(GetBaseWidth() - 2 * m_border); } else _hscrollbar->SetBaseWidth(GetBaseWidth() - ScrollBarWidth - 2 * m_border); _hscrollbar->SetBaseX(geo.x + m_border); _hscrollbar->SetBaseY(geo.y + geo.GetHeight() - _hscrollbar->GetBaseHeight() - m_border); _hscrollbar->ComputeContentSize(); } else { // The horizontal scrollbar won't be visible but give it a proper size anyway. _hscrollbar->SetBaseWidth(GetBaseWidth() - ScrollBarWidth - 2 * m_border); _hscrollbar->SetBaseX(geo.x + m_border); _hscrollbar->SetBaseY(geo.y + geo.GetHeight() - _hscrollbar->GetBaseHeight() - m_border); _hscrollbar->ComputeContentSize(); } // Vertical scrollbar Geometry if (m_vertical_scrollbar_enable) { if (m_horizontal_scrollbar_enable == false) { // If there is no horizontal scrollbar, take all the width available. _vscrollbar->SetBaseHeight(GetBaseHeight() - m_top_border - m_border); } else _vscrollbar->SetBaseHeight(GetBaseHeight() - ScrollBarHeight - m_top_border - m_border); _vscrollbar->SetBaseX(geo.x + geo.GetWidth() - ScrollBarWidth - m_border); _vscrollbar->SetBaseY(geo.y + m_top_border); _vscrollbar->ComputeContentSize(); } else { // The vertical scrollbar won't be visible but give it a proper size anyway. _vscrollbar->SetBaseHeight(GetBaseHeight() - ScrollBarHeight - m_top_border - m_border); _vscrollbar->SetBaseX(geo.x + geo.GetWidth() - ScrollBarWidth - m_border); _vscrollbar->SetBaseY(geo.y + m_top_border); _vscrollbar->ComputeContentSize(); } } long ScrollView::PostLayoutManagement(long LayoutResult) { if (view_layout_) { m_ViewContentX = view_layout_->GetBaseX(); m_ViewContentY = view_layout_->GetBaseY(); m_ViewContentWidth = view_layout_->GetBaseWidth(); m_ViewContentHeight = view_layout_->GetBaseHeight(); } _hscrollbar->SetContainerSize(GetBaseX() + m_border + m_ViewContentLeftMargin, GetBaseY() + m_top_border + m_ViewContentTopMargin, GetBaseWidth() - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin, GetBaseHeight() - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin); if (m_horizontal_scrollbar_enable) { if (view_layout_) { _hscrollbar->SetContentSize(view_layout_->GetBaseX(), view_layout_->GetBaseY(), view_layout_->GetBaseWidth(), view_layout_->GetBaseHeight()); } else { _hscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin, GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0); } _hscrollbar->SetContentOffset(_delta_x, _delta_y); } else { _hscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin, GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0); _hscrollbar->SetContentOffset(0, 0); } _vscrollbar->SetContainerSize(GetBaseX() + m_border + m_ViewContentLeftMargin, GetBaseY() + m_top_border + m_ViewContentTopMargin, GetBaseWidth() - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin, GetBaseHeight() - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin); if (m_vertical_scrollbar_enable) { if (view_layout_) { _vscrollbar->SetContentSize(view_layout_->GetBaseX(), view_layout_->GetBaseY(), view_layout_->GetBaseWidth(), view_layout_->GetBaseHeight()); } else { _vscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin, GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0); } _vscrollbar->SetContentOffset(_delta_x, _delta_y); } else { _vscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin, GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0); _vscrollbar->SetContentOffset(0, 0); } // I may not be necessary to call this function here since ComputeContentPosition was called on ComputeContentPosition // during the layout process. if (view_layout_) view_layout_->ComputeContentPosition(0, 0); // The ScrollView always returns complient width and height to its parent layout. return (eCompliantHeight | eCompliantWidth); } // When the ScrollView is in a Layout object, and that layout call View::ComputeContentPosition // the ScrollView must call its own ComputeContentPosition so it can properly do the positioning of the inner object. // Otherwise, view_layout_->ComputeContentPosition is called but it doesn't know that it may not contain all the // object of the ScrollView. Which result in incorrect positioning. // Here we touch only the position. Do not touch the width or height of object. // This function is called when the ScrollView is embedded within a Layout. void ScrollView::ComputeContentPosition(float /* offsetX */, float /* offsetY */) { Geometry geo = GetGeometry(); int w = 0; int h = 0; w = _vscrollbar->GetBaseWidth(); h = _hscrollbar->GetBaseHeight(); m_ViewX = GetBaseX() + m_border + m_ViewContentLeftMargin; m_ViewY = GetBaseY() + m_top_border + m_ViewContentTopMargin; m_ViewWidth = GetBaseWidth() - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin; m_ViewHeight = GetBaseHeight() - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin; if (m_ViewX + _delta_x + m_ViewContentWidth < m_ViewX + m_ViewWidth) { _delta_x = - (m_ViewContentWidth > m_ViewWidth ? m_ViewContentWidth - m_ViewWidth : 0); } if (m_ViewY + _delta_y + m_ViewContentHeight < m_ViewY + m_ViewHeight) { _delta_y = - (m_ViewContentHeight > m_ViewHeight ? m_ViewContentHeight - m_ViewHeight : 0); } if (view_layout_) { view_layout_->SetBaseX(m_ViewX); view_layout_->SetBaseY(m_ViewY); } // Horizontal scrollbar Geometry if (m_horizontal_scrollbar_enable) { if (m_vertical_scrollbar_enable == false) _hscrollbar->SetBaseWidth(GetBaseWidth() - 2 * m_border); else _hscrollbar->SetBaseWidth(GetBaseWidth() - w - 2 * m_border); _hscrollbar->SetBaseX(geo.x + m_border); _hscrollbar->SetBaseY(geo.y + geo.GetHeight() - _hscrollbar->GetBaseHeight() - m_border); _hscrollbar->ComputeContentSize(); } // Vertical scrollbar Geometry if (m_vertical_scrollbar_enable) { if (m_horizontal_scrollbar_enable == false) _vscrollbar->SetBaseHeight(GetBaseHeight() - m_top_border - m_border); else _vscrollbar->SetBaseHeight(GetBaseHeight() - h - m_top_border - m_border); _vscrollbar->SetBaseX(geo.x + geo.GetWidth() - w - m_border); _vscrollbar->SetBaseY(geo.y + m_top_border); _vscrollbar->ComputeContentSize(); } if (view_layout_) { m_ViewContentX = view_layout_->GetBaseX(); m_ViewContentY = view_layout_->GetBaseY(); } else { m_ViewContentX = m_ViewX; m_ViewContentY = m_ViewY; } _vscrollbar->SetContentOffset(_delta_x, _delta_y); _hscrollbar->SetContentOffset(_delta_x, _delta_y); if (view_layout_) { view_layout_->ComputeContentPosition(0, 0); } } void ScrollView::ScrollLeft(float stepx, int mousedx) { if (view_layout_) { _delta_x += (float) stepx * (float) mousedx;; if (_delta_x > 0) { _delta_x = 0; } view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); scrolling.emit(_delta_x, _delta_y); } if (view_layout_) { _hscrollbar->SetContentOffset(_delta_x, _delta_y); _hscrollbar->QueueDraw(); } QueueDraw(); } void ScrollView::ScrollRight(float stepx, int mousedx) { if (view_layout_) { _delta_x -= (float) stepx * (float) mousedx; if (m_ViewX + _delta_x + m_ViewContentWidth < m_ViewX + m_ViewWidth) { _delta_x = - (m_ViewContentWidth > m_ViewWidth ? m_ViewContentWidth - m_ViewWidth : 0); } view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); scrolling.emit(_delta_x, _delta_y); } if (view_layout_) { _hscrollbar->SetContentOffset(_delta_x, _delta_y); _hscrollbar->QueueDraw(); } QueueDraw(); } void ScrollView::ScrollUp(float stepy, int mousedy) { if (m_ViewContentHeight <= m_ViewHeight) return; if (view_layout_) { int last_delta_y = _delta_y; _delta_y += stepy * mousedy; if (_delta_y > 0) { _delta_y = 0; } if (last_delta_y != _delta_y) { QueueDraw(); _vscrollbar->QueueDraw(); } view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); _vscrollbar->SetContentOffset(_delta_x, _delta_y); scrolling.emit(_delta_x, _delta_y); } } void ScrollView::ScrollDown(float stepy, int mousedy) { if (m_ViewContentHeight <= m_ViewHeight) return; if (view_layout_) { int last_delta_y = _delta_y; _delta_y -= stepy * mousedy; if (m_ViewY + _delta_y + m_ViewContentHeight < m_ViewY + m_ViewHeight) { _delta_y = - (m_ViewContentHeight > m_ViewHeight ? m_ViewContentHeight - m_ViewHeight : 0); } if (last_delta_y != _delta_y) { QueueDraw(); _vscrollbar->QueueDraw(); } view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); _vscrollbar->SetContentOffset(_delta_x, _delta_y); scrolling.emit(_delta_x, _delta_y); } } void ScrollView::ResetScrollToLeft() { _delta_x = 0; if (view_layout_) view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); _hscrollbar->SetContentOffset(_delta_x, _delta_y); _hscrollbar->QueueDraw(); QueueDraw(); } void ScrollView::ResetScrollToRight() { if (view_layout_) { _delta_x = - (m_ViewContentWidth > m_ViewWidth ? m_ViewContentWidth - m_ViewWidth : 0); view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); } else { _delta_x = 0; } _hscrollbar->SetContentOffset(_delta_x, _delta_y); _hscrollbar->QueueDraw(); QueueDraw(); } void ScrollView::ResetScrollToUp() { _delta_y = 0; if (view_layout_) view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); _vscrollbar->SetContentOffset(_delta_x, _delta_y); _vscrollbar->QueueDraw(); QueueDraw(); } void ScrollView::ResetScrollToDown() { if (view_layout_) { _delta_y = - (m_ViewContentHeight > m_ViewHeight ? m_ViewContentHeight - m_ViewHeight : 0); view_layout_->Set2DTranslation(_delta_x, _delta_y, 0); } else { _delta_y = 0; } _vscrollbar->SetContentOffset(_delta_x, _delta_y); _vscrollbar->QueueDraw(); QueueDraw(); } void ScrollView::RecvMouseWheel(int /* x */, int /* y */, int wheel_delta, long /* button_flags */, unsigned long /* key_flags */) { // nux can't tell the difference between horizontal and vertical mouse wheel events // so we are only going to support vertical if (abs(wheel_delta) == NUX_MOUSEWHEEL_DELTA) { // Vertical Scrolling if (wheel_delta < 0) { ScrollDown(1, m_MouseWheelScrollSize); } else { ScrollUp(1, m_MouseWheelScrollSize); } } else if (abs(wheel_delta) == (NUX_MOUSEWHEEL_DELTA ^ 2)) { // Horizontal Scrolling if (wheel_delta < 0) { ScrollRight(1, m_MouseWheelScrollSize); } else { ScrollLeft(1, m_MouseWheelScrollSize); } } } bool ScrollView::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/ScrollView.h0000644000000000000000000001360013313373365013615 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2010-2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef SCROLLVIEW_H #define SCROLLVIEW_H #include "Nux.h" #include "View.h" namespace nux { class HScrollBar; class VScrollBar; // Rename it to ScrollArea or ScrollWindow class ScrollView: public View { NUX_DECLARE_OBJECT_TYPE(ScrollView, View); public: ScrollView(NUX_FILE_LINE_PROTO); virtual ~ScrollView(); // API void EnableVerticalScrollBar(bool b); void EnableHorizontalScrollBar(bool b); virtual bool SetLayout(Layout *layout); ///////////////// // EMITERS // ///////////////// void OnSizeGrigMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnSizeGrigMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void EmitMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); //void EmitInternalResize(int x, int y, int w, int h); ///////////////// // RECEIVERS // ///////////////// virtual void ScrollLeft(float stepx, int mousedx); virtual void ScrollRight(float stepx, int mousedx); virtual void ScrollUp(float stepy, int mousedy); virtual void ScrollDown(float stepy, int mousedy); virtual void ResetScrollToLeft(); virtual void ResetScrollToRight(); virtual void ResetScrollToUp(); virtual void ResetScrollToDown(); // amount to scroll by for each mouse wheel event int m_MouseWheelScrollSize; // Geometry of the layout that encompass the child layouts. //! X Position of the content int m_ViewContentX; //! Y Position of the content int m_ViewContentY; //! Width of content int m_ViewContentWidth; //! Height of content int m_ViewContentHeight; //Client View Area //! X position of the scroll view content area int m_ViewX; //! Y position of the scroll view content area int m_ViewY; //! Width of the scroll view content area int m_ViewWidth; //! Height of the scroll view content area int m_ViewHeight; Geometry m_ViewGeometry; Geometry m_ContentGeometry; // signals /*! Emitted when scrolling happens. the parameters to the signals are: int: value of the horizontal translation of the layout. int: value of the vertical translation of the layout. This signal is emitted only if the scroll view has a layout. */ sigc::signal scrolling; public: void SetViewContentLeftMargin(int margin) { m_ViewContentLeftMargin = margin; } int GetViewContentLeftMargin() const { return m_ViewContentLeftMargin; } void SetViewContentRightMargin(int margin) { m_ViewContentRightMargin = margin; } int GetViewContentRightMargin() const { return m_ViewContentRightMargin; } void SetViewContentTopMargin(int margin) { m_ViewContentTopMargin = margin; } int GetViewContentTopMargin() const { return m_ViewContentTopMargin; } void SetViewContentBottomMargin(int margin) { m_ViewContentBottomMargin = margin; } int GetViewContentBottomMargin() const { return m_ViewContentBottomMargin; } protected: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); void RecvMouseWheel(int x, int y, int wheel_delta, long button_flags, unsigned long key_flags); //! Change Vertical Scrollbar in the ScrollView. /*! For styling purpose, allow the classes that inherit from ScrollView to change the vertical scrollbar. */ void SetVScrollBar(VScrollBar* newVScrollBar); // Backup texture to speed up scrolling ObjectPtr m_FrameBufferObject; void SwapTextureIndex() { m_TextureIndex = (m_TextureIndex == 0) ? 1 : 0; } void SetTextureIndex(int index) { m_TextureIndex = index; } int GetTextureIndex() { return m_TextureIndex; } int m_TextureIndex; bool m_ReformatTexture; // ScrollBars HScrollBar *_hscrollbar; VScrollBar *_vscrollbar; bool m_horizontal_scrollbar_enable; bool m_vertical_scrollbar_enable; int m_top_border; int m_border; //! Horizontal scrollbar offsets. int _delta_x; //! Vertical scrollbar offsets. int _delta_y; void FormatContent(); virtual void PreLayoutManagement(); virtual long PostLayoutManagement(long LayoutResult); virtual void ComputeContentPosition(float offsetX, float offsetY); private: virtual bool AcceptKeyNavFocus(); /** If True, the scrollbar size will be adjusted to match the size of the content. This is useful for the ComboBoxComplex widget. */ bool m_bSizeMatchContent; int m_ViewContentLeftMargin; int m_ViewContentRightMargin; int m_ViewContentTopMargin; int m_ViewContentBottomMargin; }; } #endif // SCROLLVIEW_H nux-4.0.8+18.10.20180623/Nux/SpinBox.cpp0000644000000000000000000001616313313373365013450 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "TimerProc.h" #include "HLayout.h" #include "VLayout.h" #include "IntegerValidator.h" #include "SpinBox.h" namespace nux { const Color SPINBOX_BUTTON_COLOR = Color(0xFF4D4D4D); const Color SPINBOX_BUTTON_MOUSEOVER_COLOR = Color(0xFF222222); SpinBox::SpinBox(int Value, int Step, int MinValue, int MaxValue, NUX_FILE_LINE_DECL) : SpinBox_Logic(NUX_FILE_LINE_PARAM) , m_IntValidator(MinValue, MaxValue) , m_Step(Step) { hlayout = new HLayout(NUX_TRACKER_LOCATION); vlayout = new VLayout(NUX_TRACKER_LOCATION); m_EditLine->SetValidator(&m_IntValidator); m_EditLine->SetSuffix(""); m_EditLine->SetPrefix(""); m_EditLine->SetText(std::to_string((long long)m_IntValidator.GetMinimum())); m_EditLine->SetMinimumSize(1.5 * DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT); m_EditLine->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); m_SpinnerUpBtn->SetMinimumSize(15, 10); m_SpinnerUpBtn->SetGeometry(Geometry(0, 0, 15, 10)); m_SpinnerDownBtn->SetMinimumSize(15, 10); m_SpinnerDownBtn->SetGeometry(Geometry(0, 0, 15, 10)); // Set the minimum size of this widget. // This is use by TextLineEditPropertyItem::GetItemBestHeight SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); hlayout->AddView(m_EditLine, 1); vlayout->AddView(m_SpinnerUpBtn, 1); vlayout->AddView(m_SpinnerDownBtn, 1); hlayout->AddLayout(vlayout, 0); SetLayout(hlayout); SetValue(Value); } SpinBox::~SpinBox() { } void SpinBox::InitializeWidgets() { } void SpinBox::InitializeLayout() { } void SpinBox::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); GetPainter().PaintBackground(graphics_engine, base); if (m_EditLine->IsMouseInside() || m_SpinnerUpBtn->IsMouseInside() || m_SpinnerDownBtn->IsMouseInside()) { GetPainter().PaintShapeCorner(graphics_engine, m_SpinnerUpBtn->GetGeometry(), SPINBOX_BUTTON_MOUSEOVER_COLOR, eSHAPE_CORNER_ROUND4, eCornerTopRight, false); GetPainter().PaintShapeCorner(graphics_engine, m_SpinnerDownBtn->GetGeometry(), SPINBOX_BUTTON_MOUSEOVER_COLOR, eSHAPE_CORNER_ROUND4, eCornerBottomRight, false); } else { GetPainter().PaintShapeCorner(graphics_engine, m_SpinnerUpBtn->GetGeometry(), SPINBOX_BUTTON_COLOR, eSHAPE_CORNER_ROUND4, eCornerTopRight, false); GetPainter().PaintShapeCorner(graphics_engine, m_SpinnerDownBtn->GetGeometry(), SPINBOX_BUTTON_COLOR, eSHAPE_CORNER_ROUND4, eCornerBottomRight, false); } GeometryPositioning gp(eHACenter, eVACenter); Geometry GeoPo = ComputeGeometryPositioning(m_SpinnerUpBtn->GetGeometry(), GetTheme().GetImageGeometry(eSPINER_UP), gp); if (m_SpinnerUpBtn->IsMouseInside()) GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eSPINER_UP); else GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eSPINER_UP); gp.SetAlignment(eHACenter, eVACenter); GeoPo = ComputeGeometryPositioning(m_SpinnerDownBtn->GetGeometry(), GetTheme().GetImageGeometry(eSPINER_DOWN), gp); if (m_SpinnerDownBtn->IsMouseInside()) GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eSPINER_DOWN); else GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eSPINER_DOWN); m_EditLine->QueueDraw(); } void SpinBox::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { m_EditLine->ProcessDraw(graphics_engine, force_draw); } void SpinBox::SetValue(int value) { m_iValue = m_IntValidator.GetClampedValue(value); m_EditLine->SetText(std::to_string((long long)m_iValue)); sigValueChanged.emit(this); sigValue.emit(m_iValue); QueueDraw(); } int SpinBox::GetValue() const { return m_iValue; } void SpinBox::SetStep(int i) { m_Step = i; if (m_Step <= 0) m_Step = 1; QueueDraw(); } int SpinBox::GetStep() const { return m_Step; } int SpinBox::GetMinValue() const { return m_IntValidator.GetMinimum(); } int SpinBox::GetMaxValue() const { return m_IntValidator.GetMaximum(); } void SpinBox::SetRange(int MinValue, int Maxvalue) { m_IntValidator.SetMinimum(MinValue); m_IntValidator.SetMaximum(Maxvalue); m_iValue = m_IntValidator.GetClampedValue(m_iValue); sigValueChanged.emit(this); sigValue.emit(m_iValue); QueueDraw(); } void SpinBox::ImplementIncrementBtn() { SetValue(m_iValue + m_Step); if (m_iValue < m_IntValidator.GetMaximum()) { if (m_UpTimerHandler.IsValid()) m_UpTimerHandler = GetTimer().AddOneShotTimer(100, m_UpTimerCallback, 0); else m_UpTimerHandler = GetTimer().AddOneShotTimer(800, m_UpTimerCallback, 0); QueueDraw(); } sigValueChanged.emit(this); sigIncrement.emit(this); sigValue.emit(m_iValue); } void SpinBox::ImplementDecrementBtn() { SetValue(m_iValue - m_Step); if (m_iValue > m_IntValidator.GetMinimum()) { if (m_DownTimerHandler.IsValid()) m_DownTimerHandler = GetTimer().AddOneShotTimer(100, m_DownTimerCallback, 0); else m_DownTimerHandler = GetTimer().AddOneShotTimer(800, m_DownTimerCallback, 0); QueueDraw(); } sigValueChanged.emit(this); sigDecrement.emit(this); sigValue.emit(m_iValue); } void SpinBox::ImplementValidateEntry() { double ret = 0; ret = CharToDouble(m_EditLine->GetCleanText().c_str()); { m_iValue = m_IntValidator.GetClampedValue(ret); m_EditLine->SetText(std::to_string((long long)m_iValue)); sigValueChanged.emit(this); sigValue.emit(m_iValue); // // if (m_iValue < m_IntValidator.GetMinimum()) // { // m_iValue = m_IntValidator.GetMinimum(); // m_EditLine->SetText(std::string::Printf("%d", m_iValue)); // } // if (m_iValue > m_IntValidator.GetMaximum()) // { // m_iValue = m_IntValidator.GetMaximum(); // m_EditLine->SetText(std::string::Printf("%d", m_iValue)); // } } // else // { // m_EditLine->SetText(std::string::Printf("%d", m_iValue)); // sigValueChanged.emit(this); // sigValue.emit(m_iValue); // } } } nux-4.0.8+18.10.20180623/Nux/SpinBox.h0000644000000000000000000000371613313373365013115 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef SPINBOX_H #define SPINBOX_H #include "IntegerValidator.h" #include "SpinBox_Logic.h" namespace nux { class SpinBox: public SpinBox_Logic { public: SpinBox(int Value = 0, int Step = 1, int MinValue = 0, int MaxValue = 100, NUX_FILE_LINE_PROTO); virtual ~SpinBox(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual void ImplementIncrementBtn(); virtual void ImplementDecrementBtn(); virtual void ImplementValidateEntry(); void SetValue(int value); int GetValue() const; void SetStep(int i); int GetStep() const; int GetMinValue() const; int GetMaxValue() const; void SetRange(int MinValue, int Maxvalue); sigc::signal sigIncrement; sigc::signal sigDecrement; sigc::signal sigValueChanged; sigc::signal sigValue; protected: void InitializeWidgets(); void InitializeLayout(); private: HLayout *hlayout; VLayout *vlayout; IntegerValidator m_IntValidator; int m_iValue; int m_Step; }; } #endif // SPINBOX_H nux-4.0.8+18.10.20180623/Nux/SpinBoxDouble.cpp0000644000000000000000000001721713313373365014604 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "TimerProc.h" #include "HLayout.h" #include "VLayout.h" #include "DoubleValidator.h" #include "SpinBox_Logic.h" #include "SpinBoxDouble.h" namespace nux { const Color SPINBOX_DOUBLE_BUTTON_COLOR = Color(0xFF4D4D4D); const Color SPINBOX_DOUBLE_BUTTON_MOUSEOVER_COLOR = Color(0xFF222222); SpinBoxDouble::SpinBoxDouble(double Value, double Step, double MinValue, double MaxValue, NUX_FILE_LINE_DECL) : SpinBox_Logic(NUX_FILE_LINE_PARAM) , m_DoubleValidator(MinValue, MaxValue) , m_Step(Step) { InitializeLayout(); InitializeWidgets(); SetValue(Value); } SpinBoxDouble::~SpinBoxDouble() { } void SpinBoxDouble::InitializeWidgets() { m_EditLine->SetValidator(&m_DoubleValidator); m_EditLine->SetSuffix(""); m_EditLine->SetPrefix(""); m_EditLine->SetText(std::to_string((long double)m_DoubleValidator.GetMinimum())); m_EditLine->SetMinimumSize(1.5 * DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT); m_EditLine->SetGeometry(Geometry(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); m_SpinnerUpBtn->SetMinimumSize(15, 10); m_SpinnerUpBtn->SetGeometry(Geometry(0, 0, 15, 10)); m_SpinnerDownBtn->SetMinimumSize(15, 10); m_SpinnerDownBtn->SetGeometry(Geometry(0, 0, 15, 10)); // Set the minimum size of this widget. // This is use by TextLineEditPropertyItem::GetItemBestHeight SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); m_hlayout->AddView(m_EditLine, 1); m_vlayout->AddView(m_SpinnerUpBtn, 1); m_vlayout->AddView(m_SpinnerDownBtn, 1); m_hlayout->AddLayout(m_vlayout, 0); SetCompositionLayout(m_hlayout); } void SpinBoxDouble::InitializeLayout() { m_hlayout = new HLayout(NUX_TRACKER_LOCATION); m_vlayout = new VLayout(NUX_TRACKER_LOCATION); } void SpinBoxDouble::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); GetPainter().PaintBackground(graphics_engine, base); if (m_EditLine->IsMouseInside() || m_SpinnerUpBtn->IsMouseInside() || m_SpinnerDownBtn->IsMouseInside()) { GetPainter().PaintShapeCorner(graphics_engine, m_SpinnerUpBtn->GetGeometry(), SPINBOX_DOUBLE_BUTTON_MOUSEOVER_COLOR, eSHAPE_CORNER_ROUND4, eCornerTopRight, false); GetPainter().PaintShapeCorner(graphics_engine, m_SpinnerDownBtn->GetGeometry(), SPINBOX_DOUBLE_BUTTON_MOUSEOVER_COLOR, eSHAPE_CORNER_ROUND4, eCornerBottomRight, false); } else { GetPainter().PaintShapeCorner(graphics_engine, m_SpinnerUpBtn->GetGeometry(), SPINBOX_DOUBLE_BUTTON_COLOR, eSHAPE_CORNER_ROUND4, eCornerTopRight, false); GetPainter().PaintShapeCorner(graphics_engine, m_SpinnerDownBtn->GetGeometry(), SPINBOX_DOUBLE_BUTTON_COLOR, eSHAPE_CORNER_ROUND4, eCornerBottomRight, false); } GeometryPositioning gp(eHACenter, eVACenter); Geometry GeoPo = ComputeGeometryPositioning(m_SpinnerUpBtn->GetGeometry(), GetTheme().GetImageGeometry(eSPINER_UP), gp); if (m_SpinnerUpBtn->IsMouseInside()) GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eSPINER_UP); else GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eSPINER_UP); gp.SetAlignment(eHACenter, eVACenter); GeoPo = ComputeGeometryPositioning(m_SpinnerDownBtn->GetGeometry(), GetTheme().GetImageGeometry(eSPINER_DOWN), gp); if (m_SpinnerDownBtn->IsMouseInside()) GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eSPINER_DOWN); else GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eSPINER_DOWN); m_EditLine->QueueDraw(); } void SpinBoxDouble::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { m_EditLine->ProcessDraw(graphics_engine, force_draw); } void SpinBoxDouble::SetValue(double value) { m_Value = m_DoubleValidator.GetClampedValue(value); // if (m_Value < m_DoubleValidator.GetMinimum()) // m_Value = m_DoubleValidator.GetMinimum(); // if (m_Value > m_DoubleValidator.GetMaximum()) // m_Value = m_DoubleValidator.GetMaximum(); m_EditLine->SetText(std::to_string((long double)m_Value)); sigValueChanged.emit(this); sigValue.emit(m_Value); QueueDraw(); } double SpinBoxDouble::GetValue() const { return m_Value; } void SpinBoxDouble::SetStep(double d) { m_Step = d; if (m_Step <= 0) m_Step = 1.0; QueueDraw(); } double SpinBoxDouble::GetStep() const { return m_Step; } double SpinBoxDouble::GetMinValue() const { return m_DoubleValidator.GetMinimum(); } double SpinBoxDouble::GetMaxValue() const { return m_DoubleValidator.GetMaximum(); } void SpinBoxDouble::SetRange(double MinValue, double Maxvalue) { m_DoubleValidator.SetMinimum(MinValue); m_DoubleValidator.SetMaximum(Maxvalue); m_Value = m_DoubleValidator.GetClampedValue(m_Value); sigValueChanged.emit(this); sigValue.emit(m_Value); QueueDraw(); } void SpinBoxDouble::ImplementIncrementBtn() { SetValue(m_Value + m_Step); if (m_Value < m_DoubleValidator.GetMaximum()) { if (m_UpTimerHandler.IsValid()) m_UpTimerHandler = GetTimer().AddOneShotTimer(100, m_UpTimerCallback, 0); else m_UpTimerHandler = GetTimer().AddOneShotTimer(800, m_UpTimerCallback, 0); QueueDraw(); } sigValueChanged.emit(this); sigIncrement.emit(this); sigValue.emit(m_Value); } void SpinBoxDouble::ImplementDecrementBtn() { SetValue(m_Value - m_Step); if (m_Value > m_DoubleValidator.GetMinimum()) { if (m_DownTimerHandler.IsValid()) m_DownTimerHandler = GetTimer().AddOneShotTimer(100, m_DownTimerCallback, 0); else m_DownTimerHandler = GetTimer().AddOneShotTimer(800, m_DownTimerCallback, 0); QueueDraw(); } sigValueChanged.emit(this); sigDecrement.emit(this); sigValue.emit(m_Value); } void SpinBoxDouble::ImplementValidateEntry() { double ret = 0; ret = CharToDouble(m_EditLine->GetCleanText().c_str()); { m_Value = m_DoubleValidator.GetClampedValue(ret); m_EditLine->SetText(std::to_string((long double)m_Value)); sigValueChanged.emit(this); sigValue.emit(m_Value); // // if (m_Value < m_DoubleValidator.GetMinimum()) // { // m_Value = m_DoubleValidator.GetMinimum(); // m_EditLine->SetText(std::string::Printf("%.3f", m_Value)); // } // if (m_Value > m_DoubleValidator.GetMaximum()) // { // m_Value = m_DoubleValidator.GetMaximum(); // m_EditLine->SetText(std::string::Printf("%.3f", m_Value)); // } } // else // { // m_EditLine->SetText(std::string::Printf("%.3f", m_Value)); // sigValueChanged.emit(this); // sigValue.emit(m_Value); // } } } nux-4.0.8+18.10.20180623/Nux/SpinBoxDouble.h0000644000000000000000000000403513313373365014243 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef SPINBOXDOUBLE_H #define SPINBOXDOUBLE_H #include "EditTextBox.h" namespace nux { class SpinBoxDouble: public SpinBox_Logic { public: SpinBoxDouble(double Value = 0, double Step = 1, double MinValue = 0, double MaxValue = 100, NUX_FILE_LINE_PROTO); virtual ~SpinBoxDouble(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual void ImplementIncrementBtn(); virtual void ImplementDecrementBtn(); virtual void ImplementValidateEntry(); void SetValue(double value); double GetValue() const; void SetStep(double i); double GetStep() const; double GetMinValue() const; double GetMaxValue() const; void SetRange(double MinValue, double Maxvalue); sigc::signal sigIncrement; sigc::signal sigDecrement; sigc::signal sigValueChanged; sigc::signal sigValue; protected: void InitializeWidgets(); void InitializeLayout(); private: HLayout *m_hlayout; VLayout *m_vlayout; DoubleValidator m_DoubleValidator; double m_Value; double m_Step; }; } #endif // SPINBOXDOUBLE_H nux-4.0.8+18.10.20180623/Nux/SpinBox_Logic.cpp0000644000000000000000000001436613313373365014570 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "TimerProc.h" #include "SpinBox_Logic.h" namespace nux { SpinBox_Logic::SpinBox_Logic(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_UpTimerHandler(0) , m_DownTimerHandler(0) { m_SpinnerUpBtn = new BasicView(NUX_TRACKER_LOCATION); m_SpinnerDownBtn = new BasicView(NUX_TRACKER_LOCATION); m_EditLine = new EditTextBox("", NUX_TRACKER_LOCATION); // Set Original State m_EditLine->SetSuffix(""); m_EditLine->SetPrefix(""); // Set Signals m_SpinnerUpBtn->mouse_down.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvIncrement)); m_SpinnerUpBtn->mouse_double_click.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvIncrement)); m_SpinnerUpBtn->mouse_up.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvSpinnerMouseUp)); m_SpinnerUpBtn->mouse_click.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvSpinnerMouseUp)); m_SpinnerUpBtn->mouse_enter.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvMouseEnter)); m_SpinnerUpBtn->mouse_leave.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvMouseLeave)); m_SpinnerDownBtn->mouse_down.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvDecrement)); m_SpinnerDownBtn->mouse_double_click.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvDecrement)); m_SpinnerDownBtn->mouse_up.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvSpinnerMouseUp)); m_SpinnerDownBtn->mouse_click.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvSpinnerMouseUp)); m_SpinnerDownBtn->mouse_enter.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvMouseEnter)); m_SpinnerDownBtn->mouse_leave.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvMouseLeave)); m_EditLine->sigValidateEntry.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvValidateEntry)); m_EditLine->sigStartKeyboardFocus.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvStartKeyboardFocus)); m_EditLine->sigEndKeyboardFocus.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvEndKeyboardFocus)); m_EditLine->sigEscapeKeyboardFocus.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvEscapeKeyboardFocus)); m_EditLine->sigEditChange.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvEditChange)); m_EditLine->mouse_enter.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvMouseEnter)); m_EditLine->mouse_leave.connect(sigc::mem_fun(this, &SpinBox_Logic::RecvMouseLeave)); m_UpTimerCallback = new TimerFunctor; m_UpTimerCallback->tick.connect(sigc::mem_fun(this, &SpinBox_Logic::TimerSpinUpBtn)); m_DownTimerCallback = new TimerFunctor; m_DownTimerCallback->tick.connect(sigc::mem_fun(this, &SpinBox_Logic::TimerSpinDownBtn)); } SpinBox_Logic::~SpinBox_Logic() { delete m_UpTimerCallback; delete m_DownTimerCallback; // m_SpinnerUpBtn->Dispose(); // m_SpinnerDownBtn->Dispose(); // m_EditLine->Dispose(); } void SpinBox_Logic::RecvIncrement(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { TimerSpinUpBtn(0); } void SpinBox_Logic::RecvSpinnerMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_UpTimerHandler.IsValid()) { GetTimer().RemoveTimerHandler(m_UpTimerHandler); m_UpTimerHandler = 0; } if (m_DownTimerHandler.IsValid()) { GetTimer().RemoveTimerHandler(m_DownTimerHandler); m_DownTimerHandler = 0; } QueueDraw(); } void SpinBox_Logic::RecvDecrement(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { TimerSpinDownBtn(0); } void SpinBox_Logic::TimerSpinUpBtn(void * /* v */) { ImplementIncrementBtn(); } void SpinBox_Logic::TimerSpinDownBtn(void * /* v */) { ImplementDecrementBtn(); } void SpinBox_Logic::RecvStartKeyboardFocus(EditTextBox * /* textbox */) { QueueDraw(); } void SpinBox_Logic::RecvEndKeyboardFocus(EditTextBox * /* textbox */) { QueueDraw(); } void SpinBox_Logic::RecvEscapeKeyboardFocus(EditTextBox * /* textbox */) { QueueDraw(); } void SpinBox_Logic::RecvMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void SpinBox_Logic::RecvMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void SpinBox_Logic::RecvMouseMove(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void SpinBox_Logic::RecvMouseDrag(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void SpinBox_Logic::RecvEditChange(EditTextBox * /* textbox */) { QueueDraw(); } void SpinBox_Logic::RecvValidateEntry(EditTextBox * /* textbox */) { ImplementValidateEntry(); // int ret = 0; // if (inlCharToInteger(m_EditLine->GetCleanCaption().GetTChar(), ret)) // { // m_iValue = ret; // if (m_iValue < m_IntValidator.GetMinimum()) // { // m_iValue = m_IntValidator.GetMinimum(); // m_EditLine->setCaption(std::string::Printf("%d", m_iValue)); // } // if (m_iValue > m_IntValidator.GetMaximum()) // { // m_iValue = m_IntValidator.GetMaximum(); // m_EditLine->setCaption(std::string::Printf("%d", m_iValue)); // } // } // else // { // m_EditLine->setCaption(std::string::Printf("%d", m_iValue)); // } } } nux-4.0.8+18.10.20180623/Nux/SpinBox_Logic.h0000644000000000000000000000602613313373365014227 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef SPINBOX_LOGIC_H #define SPINBOX_LOGIC_H #include "EditTextBox.h" #include "View.h" namespace nux { class SpinBox_Logic: public View { public: SpinBox_Logic(NUX_FILE_LINE_PROTO); virtual ~SpinBox_Logic(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw) = 0; virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw) = 0; // RECEIVERS void RecvMouseMove(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvIncrement(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvDecrement(int x, int y, unsigned long button_flags, unsigned long key_flags); void TimerSpinUpBtn(void *v); void TimerSpinDownBtn(void *v); void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); /* The spinner buttons need to be redrawn when they are released. Their color may have changed when the mouse down was initiated. This receiver is going to initiate the redraw of the whole SpinBox_Logic. */ void RecvSpinnerMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvStartKeyboardFocus(EditTextBox *textbox); void RecvEndKeyboardFocus(EditTextBox *textbox); void RecvEscapeKeyboardFocus(EditTextBox *textbox); void RecvEditChange(EditTextBox *textbox); void RecvValidateEntry(EditTextBox *textbox); virtual void ImplementIncrementBtn() = 0; virtual void ImplementDecrementBtn() = 0; virtual void ImplementValidateEntry() = 0; // SIGNALS sigc::signal sigClick; sigc::signal sigIncrement; sigc::signal sigDecrement; sigc::signal sigValueChanged; sigc::signal sigIntValueChanged; protected: EditTextBox *m_EditLine; BasicView *m_SpinnerUpBtn; BasicView *m_SpinnerDownBtn; TimerFunctor *m_UpTimerCallback; TimerFunctor *m_DownTimerCallback; TimerHandle m_UpTimerHandler; TimerHandle m_DownTimerHandler; }; } #endif // SPINBOX_LOGIC_H nux-4.0.8+18.10.20180623/Nux/StaticText.cpp0000644000000000000000000006102113313373365014153 0ustar /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "Validator.h" #include "cairo/cairo.h" #include "pango/pango.h" #include "pango/pangocairo.h" #include "NuxGraphics/CairoGraphics.h" #include "NuxGraphics/GraphicsDisplay.h" #include "StaticText.h" #if defined(NUX_OS_WINDOWS) #include "D2DTextRenderer.h" #endif namespace nux { // DIP = Device Independent Pixel unit // 1 DIP = 1/96 inch. // 1 inch = 72 points. float ConvertPointSizeToDIP(float points) { return points; //return (points/72.0f)*96.0f; } NUX_IMPLEMENT_OBJECT_TYPE(StaticText); StaticText::StaticText(const std::string& text, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , text_width_(0) , text_height_(0) { padding_x_ = 0; padding_y_ = 0; update_text_rendering_ = true; text_alignment_ = ALIGN_CENTER; #if defined(NUX_STATIC_TEXT_USE_DIRECT_WRITE) layout_left_ = 0; layout_top_ = 0; GetGraphicsDisplay()->GetDirect2DFactory()->GetDesktopDpi(&dpi_scale_x, &dpi_scale_y); dpi_scale_x /= 96.0f; dpi_scale_y /= 96.0f; // 1 DIP = (1/96) inch; 1 inch = 96 DIP // PixelToDIP = (pixels/dpi)*96.0f font_size_ = 12; font_name_ = "Tahoma"; #elif defined(NUX_STATIC_TEXT_USE_CAIRO) cairo_graphics_ = NULL; font_size_ = 10; font_name_ = "Ubuntu"; std::ostringstream os; os << font_name_ << " " << font_size_; pango_font_name_ = std::string(os.str()); dpy_ = 96.0f; #endif size_match_text_ = true; text_color_ = color::White; clip_to_width_ = 0; SetMinimumSize(1, 1); SetText(text); } StaticText::~StaticText() { #if defined(NUX_STATIC_TEXT_USE_CAIRO) if (cairo_graphics_ != 0) delete(cairo_graphics_); #endif if (dw_texture_.IsValid()) dw_texture_.Release(); } void StaticText::ApplyMinWidth() { Size sz = GetTextSizeNoClip(); if ((sz.width <= GetMaximumWidth()) && (sz.width >= GetMinimumWidth())) { SetBaseWidth(sz.width); } else if (sz.width >= GetMaximumWidth()) { View::ApplyMaxWidth(); } else { View::ApplyMinWidth(); } } long StaticText::ComputeContentSize() { int pre_layout_width = GetBaseWidth(); int pre_layout_height = GetBaseHeight(); Size sz = GetTextSizeNoClip(); // The height of the StaticText is the height of the text itself. SetBaseHeight(sz.height); if ((sz.width >= GetMinimumWidth()) && (sz.width <= GetMaximumWidth())) { // The text size is within the bounds of the view. SetBaseWidth(sz.width); } else if (sz.width > GetMaximumWidth()) { // The text is bigger than the available size. ApplyMaxWidth(); } else if (sz.width < GetMinimumWidth()) { // The text size is smaller than the minimum width of the view. View::ApplyMinWidth(); } // Get the width size of this area. int width = GetBaseWidth(); int height = GetBaseHeight(); if (sz.width > width) { // The text is too large to fit. // There will be ellipsis at the end of the text. SetClipping(width); } else { // The text fits inside the view. SetClipping(0); } long result = 0; if (pre_layout_width < width) result |= eLargerWidth; else if (pre_layout_width > width) result |= eSmallerWidth; else result |= eCompliantWidth; if (pre_layout_height < height) result |= eLargerHeight; else if (pre_layout_height > height) result |= eSmallerHeight; else result |= eCompliantHeight; return result; } void StaticText::SetSizeMatchText(bool size_match_text) { size_match_text_ = size_match_text; } bool StaticText::GetSizeMatchText() const { return size_match_text_; } void StaticText::SetClipping(int clipping) { if (clip_to_width_ == clipping) return; clip_to_width_ = clipping; if (clip_to_width_ < 0) clip_to_width_ = 0; ComputeTextSize(); update_text_rendering_ = true; } int StaticText::GetClipping() const { return clip_to_width_; } void StaticText::Draw(GraphicsEngine& graphics_engine, bool /* forceDraw */) { if (update_text_rendering_) { UpdateTextRendering(); } // Draw background texture here. if (!dw_texture_.IsValid()) return; Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); nux::GetPainter().PaintBackground(graphics_engine, base); // Get the current blend states. They will be restored later. unsigned int alpha = 0, src = 0, dest = 0; graphics_engine.GetRenderStates().GetBlend(alpha, src, dest); graphics_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); TexCoordXForm texxform; texxform.SetWrap(TEXWRAP_CLAMP, TEXWRAP_CLAMP); texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD); // Compute and y coordinate centered on the view int y = base.y + (base.height - dw_texture_->GetHeight()) / 2; int x = base.x; //Special case: In the horizontal direction, if the width of the text is smaller than the // width of the view, then center the text horizontally. if (dw_texture_->GetWidth() < base.width) { if (text_alignment_ == ALIGN_CENTER) { x = base.x + (base.width - dw_texture_->GetWidth()) / 2; } else if (text_alignment_ == ALIGN_LEFT) { x = base.x; } else if (text_alignment_ == ALIGN_RIGHT) { x = base.x + base.width - dw_texture_->GetWidth(); } } graphics_engine.QRP_1Tex(x, y, dw_texture_->GetWidth(), dw_texture_->GetHeight(), dw_texture_, texxform, text_color_); graphics_engine.GetRenderStates().SetBlend(alpha, src, dest); graphics_engine.PopClippingRectangle(); } void StaticText::SetFontSize(int font_size) { if (font_size <= 0) return; #if defined(NUX_STATIC_TEXT_USE_DIRECT_WRITE) font_size_ = font_size; #elif defined(NUX_STATIC_TEXT_USE_CAIRO) font_size_ = font_size; std::ostringstream os; os << font_name_ << " " << font_size_; pango_font_name_ = std::string(os.str()); #endif // reset cache no_clip_size_.width = 0; no_clip_size_.height = 0; // Changing the font can cause the StaticView to resize itself. Size sz = GetTextSizeNoClip(); // Calling SetBaseSize will trigger a layout request of this view and all of its parents. SetBaseSize(sz.width, sz.height); } void StaticText::SetTextPointSize(int font_size) { SetFontSize(font_size); } int StaticText::GetFontSize() const { return font_size_; } int StaticText::GetTextPointSize() const { return GetFontSize(); } void StaticText::SetText(const std::string& text) { if (text_ == text) return; text_ = text; // reset cache no_clip_size_.width = 0; no_clip_size_.height = 0; // Changing the font can cause the StaticView to resize itself. Size sz = GetTextSizeNoClip(); // Calling SetBaseSize will trigger a layout request of this view and all of its parents. SetBaseSize(sz.width, sz.height); update_text_rendering_ = true; text_changed.emit(this); QueueDraw(); } std::string StaticText::GetText() const { return text_; } void StaticText::SetTextColor(const Color& text_color) { text_color_ = text_color; QueueDraw(); } Color StaticText::GetTextColor() const { return text_color_; } void StaticText::SetFontName(const std::string& font_name) { if (font_name_ == font_name) return; font_name_ = font_name; #if defined(NUX_OS_LINUX) std::ostringstream os; os << font_name_ << " " << font_size_; pango_font_name_ = std::string(os.str()); #endif // reset cache no_clip_size_.width = 0; no_clip_size_.height = 0; // Changing the font can cause the StaticView to resize itself. Size sz = GetTextSizeNoClip(); // Calling SetBaseSize will trigger a layout request of this view and all of its parents. SetBaseSize(sz.width, sz.height); QueueDraw(); } std::string StaticText::GetFontName() const { return font_name_; } void StaticText::GetTextLayoutSize(int& width, int& height) const { if (text_ == "") { width = 0; height = 0; return; } width = text_width_; height = text_height_; } Size StaticText::GetTextLayoutSize() const { Size sz; GetTextLayoutSize(sz.width, sz.height); return sz; } void StaticText::SetTextAlignment(TextAlignment alignment) { text_alignment_ = alignment; } StaticText::TextAlignment StaticText::GetTextAlignment() const { return text_alignment_; } ObjectPtr StaticText::GetTextTexture() { if (update_text_rendering_) { // If the text rendering needs to be updated, do it here. UpdateTextRendering(); } return dw_texture_; } Size StaticText::GetTextSizeNoClip() { if (no_clip_size_.width == 0) no_clip_size_ = ComputeTextSize(false, false); return no_clip_size_; } #if defined(NUX_STATIC_TEXT_USE_DIRECT_WRITE) Size StaticText::ComputeTextSize(bool assign, bool with_clipping) { HRESULT hr; IDWriteFactory* pDWriteFactory = GetGraphicsDisplay()->GetDirectWriteFactory(); ID2D1RenderTarget* pRT = NULL; IDWriteTextFormat* pTextFormat = NULL; hr = pDWriteFactory->CreateTextFormat( ANSICHAR_TO_UNICHAR(font_name_.c_str()), // Font family name. NULL, // Font collection(NULL sets it to use the system font collection). DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, ConvertPointSizeToDIP(font_size_), L"en-us", &pTextFormat); // Center align(horizontally) the text. if (SUCCEEDED(hr)) { hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); } if (SUCCEEDED(hr)) { hr = pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); } if (SUCCEEDED(hr)) { hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); } IDWriteTextLayout* pTextLayout_; hr = pDWriteFactory->CreateTextLayout( TCHAR_TO_UNICHAR(text_.c_str()), // The string to be laid out and formatted. text_.length(), // The length of the string. pTextFormat, // The text format to apply to the string(contains font information, etc). 1, // The width of the layout box. 1, // The height of the layout box. &pTextLayout_ // The IDWriteTextLayout interface pointer. ); DWRITE_TEXT_METRICS metrics; pTextLayout_->GetMetrics(&metrics); int text_width = std::ceil(metrics.widthIncludingTrailingWhitespace * dpi_scale_x); int text_height = std::ceil(metrics.height * dpi_scale_y); if (assign) { text_width_ = text_width; text_height_ = text_height; padding_x_ = text_width_ - metrics.widthIncludingTrailingWhitespace * dpi_scale_x; padding_y_ = text_height_ - metrics.height * dpi_scale_y; if (with_clipping && (clip_to_width_ > 0)) { text_width_ = text_width_ <= clip_to_width_ ? text_width_ : clip_to_width_; } text_width = text_width_; text_height = text_height_; } layout_top_ = metrics.top * dpi_scale_x; layout_left_ = metrics.left * dpi_scale_y; if (pTextLayout_) { pTextLayout_->Release(); pTextLayout_ = NULL; } if (pTextFormat) { pTextFormat->Release(); pTextFormat = NULL; } return Size(text_width, text_height); } void StaticText::RasterizeText(Color color) { if ((text_width_ <=0) || (text_height_ <= 0)) { dw_texture_.Release(); return; } HRESULT hr; ID2D1Factory* pD2DFactory = GetGraphicsDisplay()->GetDirect2DFactory(); IDWriteFactory* pDWriteFactory = GetGraphicsDisplay()->GetDirectWriteFactory(); IWICImagingFactory* pWICFactory = GetGraphicsDisplay()->GetWICFactory(); ID2D1RenderTarget* pRT = NULL; IDWriteTextFormat* pTextFormat = NULL; hr = pDWriteFactory->CreateTextFormat( ANSICHAR_TO_UNICHAR(font_name_.c_str()), // Font family name. NULL, // Font collection(NULL sets it to use the system font collection). DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, ConvertPointSizeToDIP(font_size_), L"en-us", &pTextFormat); // Center align(horizontally) the text. if (SUCCEEDED(hr)) { hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); } if (SUCCEEDED(hr)) { hr = pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); } if (SUCCEEDED(hr)) { hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); } IDWriteTextLayout* pTextLayout_ = NULL; hr = pDWriteFactory->CreateTextLayout( TCHAR_TO_UNICHAR(text_.c_str()), // The string to be laid out and formatted. text_.length(), // The length of the string. pTextFormat, // The text format to apply to the string(contains font information, etc). text_width_ / dpi_scale_x, // The width of the layout box. text_height_ / dpi_scale_y, // The height of the layout box. &pTextLayout_ // The IDWriteTextLayout interface pointer. ); IDWriteInlineObject* inlineObject = NULL; if (SUCCEEDED(hr)) { pDWriteFactory->CreateEllipsisTrimmingSign( pTextLayout_, &inlineObject); } DWRITE_TRIMMING trimming = {DWRITE_TRIMMING_GRANULARITY_CHARACTER, 0, 0}; hr = pTextLayout_->SetTrimming(&trimming, inlineObject); IWICBitmap* pWICBitmap = NULL; if (SUCCEEDED(hr)) { hr = pWICFactory->CreateBitmap( text_width_ / dpi_scale_x, text_height_ / dpi_scale_y, GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnLoad, &pWICBitmap); } // Set the render target type to D2D1_RENDER_TARGET_TYPE_DEFAULT to use software rendering. if (SUCCEEDED(hr)) { D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties; renderTargetProperties.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; renderTargetProperties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; renderTargetProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; renderTargetProperties.dpiX = 0.0; renderTargetProperties.dpiY = 0.0; renderTargetProperties.usage = D2D1_RENDER_TARGET_USAGE_NONE; renderTargetProperties.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; hr = pD2DFactory->CreateWicBitmapRenderTarget( pWICBitmap, renderTargetProperties, //D2D1::RenderTargetProperties(), &pRT); } ID2D1SolidColorBrush* pBrush; hr = pRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF(color.red, color.green, color.blue, color.alpha)), &pBrush); // Create the text renderer CustomTextRenderer* pTextRenderer_ = new (std::nothrow) CustomTextRenderer( pD2DFactory, pRT, pBrush, NULL); D2D1_POINT_2F origin = D2D1::Point2F(static_cast(padding_x_ / dpi_scale_x), static_cast(padding_y_ / dpi_scale_y)); if (0) { if (SUCCEEDED(hr)) { pRT->BeginDraw(); pRT->SetTransform(D2D1::IdentityMatrix()); pRT->Clear(D2D1::ColorF(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f))); // Call the DrawText method of this class. hr = pTextLayout_->Draw( NULL, pTextRenderer_, // Custom text renderer. origin.x, origin.y ); hr = pRT->EndDraw(); } } else { if (SUCCEEDED(hr)) { pRT->BeginDraw(); pRT->SetTransform(D2D1::IdentityMatrix()); pRT->Clear(D2D1::ColorF(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f))); // Call the DrawText method of this class. pRT->DrawTextLayout( origin, pTextLayout_, pBrush); hr = pRT->EndDraw(); } } { unsigned int width, height; pWICBitmap->GetSize(&width, &height); dw_texture_ = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture(width, height, 1, nux::BITFMT_B8G8R8A8, NUX_TRACKER_LOCATION); nux::SURFACE_LOCKED_RECT lock_rect; dw_texture_->LockRect(0, &lock_rect, NULL); pWICBitmap->CopyPixels(NULL, lock_rect.Pitch, 4*width*height, (BYTE*) lock_rect.pBits); dw_texture_->UnlockRect(0); } if (pTextRenderer_) delete pTextRenderer_; if (pBrush) { pBrush->Release(); pBrush = NULL; } if (pRT) { pRT->Release(); pRT = NULL; } if (pWICBitmap) { pWICBitmap->Release(); pWICBitmap = NULL; } if (pTextLayout_) { pTextLayout_->Release(); pTextLayout_ = NULL; } if (pTextFormat) { pTextFormat->Release(); pTextFormat = NULL; } } void StaticText::UpdateTextRendering() { Size sz = ComputeTextSize(); if (sz.width == 0 || sz.height == 0) { // Nothing to render if (dw_texture_.IsValid()) { dw_texture_.Release(); } return; } RasterizeText(color::White); update_text_rendering_ = false; } #elif defined(NUX_STATIC_TEXT_USE_CAIRO) Size StaticText::ComputeTextSize(bool assign, bool with_clipping) { cairo_surface_t* pango_surface = NULL; cairo_t* cairo_ctx = NULL; PangoLayout* pango_layout = NULL; PangoFontDescription* font_desc = NULL; PangoContext* pango_ctx = NULL; PangoRectangle ink_rect = {0, 0, 0, 0}; PangoRectangle logical_rect = {0, 0, 0, 0}; int dpi = 96; // Create Cairo surface. pango_surface = cairo_image_surface_create(CAIRO_FORMAT_A1, 1, 1); // Create Cairo context. cairo_ctx = cairo_create(pango_surface); // Create layout. pango_layout = pango_cairo_create_layout(cairo_ctx); { pango_layout_set_wrap (pango_layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_ellipsize(pango_layout, PANGO_ELLIPSIZE_END); pango_layout_set_markup (pango_layout, text_.c_str(), -1); } // Create font description: "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]" font_desc = pango_font_description_from_string(pango_font_name_.c_str()); { pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL); pango_layout_set_font_description(pango_layout, font_desc); } // Get Pango context pango_ctx = pango_layout_get_context(pango_layout); // is not ref'ed // Set font options CairoFontOptions font_options; { cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_DEFAULT); cairo_font_options_set_subpixel_order(font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_DEFAULT); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_set_font_options(cairo_ctx, font_options); pango_cairo_context_set_font_options(pango_ctx, font_options); } // use some default DPI-value pango_cairo_context_set_resolution(pango_ctx, dpi); pango_layout_context_changed(pango_layout); pango_layout_get_extents(pango_layout, &ink_rect, &logical_rect); int text_width = std::ceil((float)logical_rect.width / PANGO_SCALE); int text_height = std::ceil((float)logical_rect.height / PANGO_SCALE); if (assign) { text_width_ = text_width; text_height_ = text_height; padding_x_ = text_width_ - logical_rect.width / PANGO_SCALE; padding_y_ = text_height_ - logical_rect.height / PANGO_SCALE; if (with_clipping && (clip_to_width_ > 0)) { text_width_ = text_width_ <= clip_to_width_ ? text_width_ : clip_to_width_; } text_width = text_width_; text_height = text_height_; } // clean up pango_font_description_free(font_desc); g_object_unref(pango_layout); cairo_destroy(cairo_ctx); cairo_surface_destroy(pango_surface); return Size(text_width, text_height); } void StaticText::RasterizeText(void* cairo_context, Color /* color */) { cairo_t* cairo_ctx = (cairo_t*) cairo_context; PangoLayout* pango_layout = NULL; PangoFontDescription* font_desc = NULL; PangoContext* pango_ctx = NULL; int dpi = 96; // Create layout. pango_layout = pango_cairo_create_layout(cairo_ctx); { pango_layout_set_wrap (pango_layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_ellipsize(pango_layout, PANGO_ELLIPSIZE_END); pango_layout_set_markup (pango_layout, text_.c_str(), -1); // Sets the width to which the lines of the PangoLayout should wrap or ellipsized. The default value is -1: no width set. pango_layout_set_width(pango_layout, (clip_to_width_ ? clip_to_width_ : text_width_) * PANGO_SCALE); } // Create font description: "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]" font_desc = pango_font_description_from_string(pango_font_name_.c_str()); { pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL); pango_layout_set_font_description(pango_layout, font_desc); } // Get Pango context pango_ctx = pango_layout_get_context(pango_layout); // is not ref'ed // Set font options CairoFontOptions font_options; { cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_DEFAULT); cairo_font_options_set_subpixel_order (font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_DEFAULT); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_set_font_options(cairo_ctx, font_options); pango_cairo_context_set_font_options(pango_ctx, font_options); } pango_cairo_context_set_resolution(pango_ctx, dpi); cairo_set_source_rgba(cairo_ctx, 1.0, 1.0, 1.0, 1.0); pango_layout_context_changed(pango_layout); cairo_move_to(cairo_ctx, padding_x_, padding_y_); pango_cairo_show_layout(cairo_ctx, pango_layout); // clean up pango_font_description_free(font_desc); g_object_unref(pango_layout); } void StaticText::UpdateTextRendering() { Size sz = ComputeTextSize(); if (sz.width == 0 || sz.height == 0) { // Nothing to render if (dw_texture_.IsValid()) { dw_texture_.Release(); } return; } cairo_graphics_ = new CairoGraphics(CAIRO_FORMAT_ARGB32, sz.width, sz.height); cairo_t* cairo_ctx = cairo_graphics_->GetContext(); cairo_set_operator(cairo_ctx, CAIRO_OPERATOR_CLEAR); cairo_paint(cairo_ctx); cairo_set_operator(cairo_ctx, CAIRO_OPERATOR_OVER); RasterizeText(cairo_ctx, text_color_); NBitmapData* bitmap = cairo_graphics_->GetBitmap(); // NTexture2D is the high level representation of an image that is backed by // an actual opengl texture. BaseTexture* rasterized_text_texture = NULL; rasterized_text_texture = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); rasterized_text_texture->Update(bitmap); dw_texture_ = rasterized_text_texture->GetDeviceTexture(); rasterized_text_texture->UnReference(); rasterized_text_texture = NULL; delete bitmap; cairo_destroy(cairo_ctx); delete cairo_graphics_; cairo_graphics_ = NULL; update_text_rendering_ = false; } #endif } nux-4.0.8+18.10.20180623/Nux/StaticText.h0000644000000000000000000001414013313373365013620 0ustar /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef STATICTEXT_H #define STATICTEXT_H #include "NuxCore/Size.h" #if defined(NUX_OS_WINDOWS) #define NUX_STATIC_TEXT_USE_DIRECT_WRITE #elif defined(NUX_OS_LINUX) #define NUX_STATIC_TEXT_USE_CAIRO #else #error Not implemented. #endif namespace nux { class CairoGraphics; /*! A View that renders as static text. */ class StaticText: public View { NUX_DECLARE_OBJECT_TYPE(StaticText, View); public: //! Text alignment inside the view. /*! When the text width is smaller than the view width, the text may be aligned inside the view. The options are: Left Right Center The default alignment is centered. */ enum TextAlignment { ALIGN_CENTER = 0, ALIGN_LEFT, ALIGN_RIGHT, }; StaticText(const std::string& text, NUX_FILE_LINE_PROTO); virtual ~StaticText(); //! Set size of widget according to the text extent. /*! @param size_match_text If true, the widget size is set to match the size of the text on the screen. */ void SetSizeMatchText(bool size_match_text); //! Return true if the widget with changes to match the text width. bool GetSizeMatchText() const; //! Set the text string. void SetText(const std::string& text); //! Get the text string. std::string GetText() const; //! Set text color. /*! Set the text color. The default color is white. @param text_color The text color. */ void SetTextColor(const Color& text_color); //! Get text color. /*! Get the text color. @return The text color. */ Color GetTextColor() const; //! Set the font name. /*! Set the font name. On Ubuntu, the default is "Ubuntu". @param font_name The font name. */ void SetFontName(const std::string& font_name); //! Get the font name. /*! Get the font name. @return The font name. */ std::string GetFontName() const; //! Set text point size. /* Set the text point size. The value should be greater than 0. Otherwise, the text point size is not changed. \n The default value is 10. @param size The text point size. */ void SetFontSize(int size); void SetTextPointSize(int size); //deprecated: use SetFontSize //! Get text point size. int GetFontSize() const; int GetTextPointSize() const; //deprecated: use GetFontSize void GetTextLayoutSize(int& width, int& height) const; Size GetTextLayoutSize() const; //! Set text alignment inside the view. /*! @param alignment The text alignment inside the view. */ void SetTextAlignment(TextAlignment alignment); //! Return the text alignment /*! @return The text alignment inside the view. */ TextAlignment GetTextAlignment() const; //! Returns the device texture for the text. /*! Returns the device texture for the text. The device texture may be used \n for direct rendering. @return A smart point for the device texture. */ ObjectPtr GetTextTexture(); sigc::signal text_changed; protected: virtual void ApplyMinWidth(); virtual long ComputeContentSize(); virtual void Draw(GraphicsEngine& graphics_engine, bool forceDraw); int text_width_; //!< Rasterized text width. int text_height_; //!< Rasterized text height. std::string text_; Color text_color_; BaseTexture* rasterized_text_texture_; bool size_match_text_; int clip_to_width_; //!< Wrapping of line. float font_size_; std::string font_name_; bool update_text_rendering_; ObjectPtr dw_texture_; TextAlignment text_alignment_; void SetClipping(int clipping); int GetClipping() const; #if defined(NUX_STATIC_TEXT_USE_DIRECT_WRITE) Size ComputeTextSize(bool assign = true, bool with_clipping = true); void RasterizeText(Color color); void UpdateTextRendering(); float layout_left_; float layout_top_; float dpi_scale_x; float dpi_scale_y; #elif defined (NUX_STATIC_TEXT_USE_CAIRO) float dpy_; std::string pango_font_name_; //!< Input to pango_font_description_from_string. Size ComputeTextSize(bool assign = true, bool with_clipping = true); void RasterizeText(void* cairo_context, Color color); void UpdateTextRendering(); CairoGraphics* cairo_graphics_; #endif private: //! Override of Area::SetMinimumHeight and made private. /*! Prevent changing the minimum height of the StaticText view. */ virtual void SetMinimumHeight(int h){}; //! Override of Area::SetMaximumHeight and made private. /*! Prevent changing the maximum height of the StaticText view. */ virtual void SetMaximumHeight(int h){}; //! Compute the full text size. /*! Compute the full text size, but do not change the parameters of this class. @return The full text size. */ Size GetTextSizeNoClip(); float padding_x_; //!< Adds a padding around the entire text box. float padding_y_; //!< Adds a padding around the entire text box. Size no_clip_size_; //! Cache of the GetTextSizeNoClip results so we don't recompute them constantly. }; } #endif // STATICTEXT_H nux-4.0.8+18.10.20180623/Nux/StaticTextBox.cpp0000644000000000000000000000733213313373365014631 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "Validator.h" #include "StaticTextBox.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(StaticTextBox); StaticTextBox::StaticTextBox(const char *Caption, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_TextAlignment(eAlignTextLeft) , m_bMinimumWidthMatchText(true) , m_bDrawBackground(false) , m_WriteAlpha(true) { m_BackgroundColor = Color(0xFF343434); m_TextColor = Color(1.0f, 1.0f, 1.0f, 1.0f); // First, set the default minimum size. SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); // The width size of the text is computed in SetText and set as the minimum for the widget. // If the text is null or empty, then the default minimum widtth set above remains. SetText(Caption); SetGeometry(Geometry(0, 0, 3 * DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT)); // This widget does not use a layout! m_Background = 0; } StaticTextBox::~StaticTextBox() { delete m_Background; } void StaticTextBox::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); { graphics_engine.PushClippingRectangle(base); if (m_bDrawBackground) { GetPainter().PushDrawLayer(graphics_engine, base, m_Background); GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), GetGeometry(), m_Text, m_TextColor, m_WriteAlpha, m_TextAlignment); GetPainter().PopBackground(); } else { //GetPainter().PaintBackground(graphics_engine, base); GetPainter().PaintTextLineStatic(graphics_engine, GetFont(), GetGeometry(), m_Text, m_TextColor, m_WriteAlpha, m_TextAlignment); } graphics_engine.PopClippingRectangle(); } } void StaticTextBox::DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void StaticTextBox::SetText(const char *Caption) { std::string s(Caption); SetText(s); } void StaticTextBox::SetText(const std::string &Caption) { m_Text = Caption; if (GetMinWidthMatchText()) AdjustMinWidthToMatchText(); QueueDraw(); } void StaticTextBox::SetMinWidthMatchText(bool b) { m_bMinimumWidthMatchText = b; if (m_bMinimumWidthMatchText) AdjustMinWidthToMatchText(); } bool StaticTextBox::GetMinWidthMatchText() const { return m_bMinimumWidthMatchText; } void StaticTextBox::AdjustMinWidthToMatchText() { if (m_Text.size() == 0) return; SetMinimumWidth(/*4 + */GetFont()->GetStringWidth(m_Text)); } void StaticTextBox::SetFont(ObjectPtr Font) { View::SetFont(Font); if (GetMinWidthMatchText()) AdjustMinWidthToMatchText(); } void StaticTextBox::SetBackground(AbstractPaintLayer *layer) { delete m_Background; m_Background = layer->Clone(); } bool StaticTextBox::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/StaticTextBox.h0000644000000000000000000000632213313373365014274 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef STATICTEXTBOX_H #define STATICTEXTBOX_H namespace nux { class Validator; class StaticTextBox : public View //public InputArea { NUX_DECLARE_OBJECT_TYPE(StaticTextBox, View); public: StaticTextBox(const char *Caption, NUX_FILE_LINE_PROTO); ~StaticTextBox(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); // API void SetText(const char *Caption); void SetText(const std::string &Caption); const char *GetText() const; unsigned int GetTextSize() const { return (unsigned int) m_Text.length(); } //! Change the widget minimum width whenever the text is set. /*! Change the widget minimum width whenever the text is set. @param b If true, the widget minimum width is set to match the size of the text */ void SetMinWidthMatchText(bool b); //! Return true if the widget with changes to match the text width. bool GetMinWidthMatchText() const; void SetTextColor(const Color &color) { m_TextColor = color; }; Color GetTextColor() const { return m_TextColor; }; void SetTextBackgroundColor(const Color &color) { m_BackgroundColor = color; } Color GetTextBackgroundColor() const { return m_BackgroundColor; } void SetTextAlignment(TextAlignment alignment) { m_TextAlignment = alignment; } TextAlignment GetTextAlignment() { return m_TextAlignment; } void SetDrawBackground(bool b) { m_bDrawBackground = b; } void SetBackground(AbstractPaintLayer *bkg); ///////////////// // SIGNALS // ///////////////// virtual void SetFont(ObjectPtr Font); protected: virtual bool AcceptKeyNavFocus(); void AdjustMinWidthToMatchText(); std::string m_Text; Color m_TextColor; Color m_BackgroundColor; tstring m_temporary_caption; Validator *m_validator; TextAlignment m_TextAlignment; AbstractPaintLayer *m_Background; bool m_bMinimumWidthMatchText; bool m_bDrawBackground; //! If true, blend the characters alpha value with the destination and write the result to the destination buffer. bool m_WriteAlpha; public: virtual void SetGeometry(const Geometry &geo) { Area::SetGeometry(geo); ComputeContentSize(); } }; } #endif // STATICTEXTBOX_H nux-4.0.8+18.10.20180623/Nux/SystemThread.cpp0000644000000000000000000000775113313373365014505 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #if defined(NUX_OS_WINDOWS) #include "NuxGraphics/GraphicsDisplay.h" #elif defined(NUX_OS_LINUX) #include "NuxGraphics/GraphicsDisplay.h" #endif #include "NuxGraphics/GraphicsEngine.h" #include "ClientArea.h" #include "WindowCompositor.h" #include "TimerProc.h" #include "WindowCompositor.h" #include "WindowThread.h" #include "SystemThread.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(SystemThread); SystemThread::SystemThread(AbstractThread *Parent/* = 0*/) : AbstractThread(Parent) { } SystemThread::~SystemThread() { } ThreadState SystemThread::Start(void * /* arg */) { if (!parent_) { return NThread::Start(); } else { if (parent_->Type().IsObjectType(SystemThread::StaticObjectType)) return static_cast (parent_)->StartChildThread(this, true); if (parent_->Type().IsObjectType(WindowThread::StaticObjectType)) return static_cast (parent_)->StartChildThread(this, true); nuxAssertMsg(0, "[WindowThread::Start] This should not happen."); return THREAD_START_ERROR; } } int SystemThread::Run(void * /* arg */) { if (user_init_func_) { (*user_init_func_) (this, initialization_data_); } if (parent_) { if (parent_->Type().IsObjectType(SystemThread::StaticObjectType)) static_cast (parent_)->ChildHasFinished(this); if (parent_->Type().IsObjectType(WindowThread::StaticObjectType)) static_cast (parent_)->ChildHasFinished(this); } SetThreadState(THREADSTOP); TerminateChildThreads(); return 0; } ThreadState SystemThread::StartChildThread(AbstractThread *thread, bool /* Modal */) { ThreadState state = thread->NThread::Start(); //if(state == THREADRUNNING) AddChildThread(thread); return state; } void SystemThread::AddChildThread(AbstractThread *thread) { nuxAssert(thread); std::list::iterator it; it = find(children_thread_list_.begin(), children_thread_list_.end(), thread); if (it == children_thread_list_.end()) { children_thread_list_.push_back(thread); } } void SystemThread::RemoveChildThread(AbstractThread *window) { nuxAssert(window); std::list::iterator it; it = find(children_thread_list_.begin(), children_thread_list_.end(), window); if (it != children_thread_list_.end()) { children_thread_list_.erase(it); } } void SystemThread::ChildHasFinished(AbstractThread *thread) { RemoveChildThread(thread); if (thread->Type().IsObjectType(WindowThread::StaticObjectType)) { //SuspendChildGraphics(static_cast(thread)); } thread->SetThreadState(THREADSTOP); } void SystemThread::TerminateChildThreads() { std::list::iterator it; for (it = children_thread_list_.begin(); it != children_thread_list_.end(); it++) { (*it)->SetThreadState(THREADSTOP); } children_thread_list_.clear(); } bool SystemThread::ThreadCtor() { SetThreadState(THREADRUNNING); return true; } bool SystemThread::ThreadDtor() { return true; } } nux-4.0.8+18.10.20180623/Nux/SystemThread.h0000644000000000000000000000532513313373365014145 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef SYSTEMTHREAD_H #define SYSTEMTHREAD_H namespace nux { class WindowCompositor; class WindowThread; class SystemThread: public AbstractThread { NUX_DECLARE_OBJECT_TYPE(SystemThread, AbstractThread); public: SystemThread(AbstractThread *Parent = 0); ~SystemThread(); virtual ThreadState Start(void *arg); protected: virtual int Run(void *arg); virtual ThreadState StartChildThread(AbstractThread *thread, bool Modal); virtual void AddChildThread(AbstractThread *); virtual void RemoveChildThread(AbstractThread *); virtual void ChildHasFinished(AbstractThread *app); virtual void TerminateChildThreads(); // std::list m_ChildThread; // SystemThread* m_Parent; // ThreadUserInitFunc m_UserInitFunc; // ThreadUserExitFunc m_UserExitFunc; /*! Info: Constructor-like function. Will be called by EntryPoint before executing the thread body. Override this function to provide your extra initialization. NOTE: do not confuse it with the classes constructor */ virtual bool ThreadCtor(); /*! Info: Destructor-like function. Will be called by EntryPoint after executing the thread body. Override this function to provide your extra destruction. NOTE: do not confuse it with the classes constructor */ virtual bool ThreadDtor(); /*! This pointer maybe set by the user in ThreadInitFunc and reused in ThreadExitFunc */ private: SystemThread(const SystemThread &); // Does not make sense for a singleton. This is a self assignment. SystemThread &operator= (const SystemThread &); // Declare operator adress-of as private SystemThread *operator &(); std::string m_ThreadName; friend SystemThread *CreateSystemThread(AbstractThread *Parent, ThreadUserInitFunc UserInitFunc, void *InitData); friend class WindowThread; }; } #endif // SYSTEMTHREAD_H nux-4.0.8+18.10.20180623/Nux/TabView.cpp0000644000000000000000000004317413313373365013431 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "TabView.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" namespace nux { int TabView::TAB_BUTTON_WIDTH = 12; int TabView::TAB_BUTTON_HEIGHT = 20; int TabView::TAB_HEIGHT = 24; int TabView::TAB_X_BORDER = 4; int TabView::TAB_Y_BORDER = 4; Color TabView::TAB_HEADER_BACKGROUND_COLOR = Color(0xFF000000); Color TabView::TAB_BACKGROUND_COLOR = Color(0xFF191919); Color TabView::TAB_HEADER_COLOR = Color(0xFF333333); Color TabView::TAB_HEADER_FOCUS_COLOR = Color(0xFF5D5D5D); TabView::TabElement::TabElement(std::string TabName, Layout *TabLayout) { _index = 0; _tab_name = TabName; _tab_content_layout = TabLayout; _tab_area = new BasicView(NUX_TRACKER_LOCATION); _tab_content_layout->Reference(); _tab_area->Reference(); } TabView::TabElement::~TabElement() { _index = 0; _tab_content_layout->UnReference(); _tab_area->UnReference(); } void TabView::TabElement::SetIndex(int index) { _index = index; } int TabView::TabElement::GetIndex() const { return _index; } void TabView::TabElement::SetGeometry(const Geometry &geo) { _tab_area->SetGeometry(geo); } Geometry const& TabView::TabElement::GetGeometry() const { return _tab_area->GetGeometry(); } const std::string &TabView::TabElement::GetName() const { return _tab_name; } TabView::TabView(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { _scroll_right = NULL; _scroll_left = NULL; _visible_tab_content_layout = NULL; _tabview_heads_layout = NULL; _tabview_scroll_button_layout = NULL; m_FocusTabIndex = 0; m_TabPositionOffset = 0; m_DrawBackgroundOnPreviousGeometry = false; _tabview_heads_layout = new HLayout(NUX_TRACKER_LOCATION); //_tabview_heads_layout->SetParentObject(this); _tabview_scroll_button_layout = new HLayout(NUX_TRACKER_LOCATION); _tabview_scroll_button_layout->SetParentObject(this); _scroll_right = new BasicView(NUX_TRACKER_LOCATION); _scroll_left = new BasicView(NUX_TRACKER_LOCATION); _scroll_right->SetMinimumSize(TAB_BUTTON_WIDTH, TAB_BUTTON_HEIGHT); _scroll_left->SetMinimumSize(TAB_BUTTON_WIDTH, TAB_BUTTON_HEIGHT); _scroll_right->SetMaximumSize(TAB_BUTTON_WIDTH, TAB_BUTTON_HEIGHT); _scroll_left->SetMaximumSize(TAB_BUTTON_WIDTH, TAB_BUTTON_HEIGHT); _scroll_right->mouse_enter.connect(sigc::mem_fun(this, &TabView::RecvMouseEnter)); _scroll_right->mouse_leave.connect(sigc::mem_fun(this, &TabView::RecvMouseLeave)); _scroll_left->mouse_enter.connect(sigc::mem_fun(this, &TabView::RecvMouseEnter)); _scroll_left->mouse_leave.connect(sigc::mem_fun(this, &TabView::RecvMouseLeave)); _scroll_right->mouse_down.connect(sigc::mem_fun(this, &TabView::RecvTabRightMouseDown)); _scroll_left->mouse_down.connect(sigc::mem_fun(this, &TabView::RecvTabLeftMouseDown)); _scroll_right->mouse_up.connect(sigc::mem_fun(this, &TabView::RecvTabButtonMouseUp)); _scroll_left->mouse_up.connect(sigc::mem_fun(this, &TabView::RecvTabButtonMouseUp)); _tabview_scroll_button_layout->AddView(_scroll_left, 1, eCenter); _tabview_scroll_button_layout->AddView(_scroll_right, 1, eCenter); tabright_callback = new TimerFunctor; tabright_callback->tick.connect(sigc::mem_fun(this, &TabView::RecvTabRightTimerExpired)); tableft_callback = new TimerFunctor; tableft_callback->tick.connect(sigc::mem_fun(this, &TabView::RecvTabLeftTimerExpired)); } TabView::~TabView() { _tabview_heads_layout->UnReference(); _tabview_scroll_button_layout->UnReference(); RemoveCompositionLayout(); delete(tabright_callback); delete(tableft_callback); std::vector::iterator it; for (it = _tab_array.begin(); it != _tab_array.end(); it++) { (*it)->_tab_area->UnParentObject(); (*it)->_tab_content_layout->UnParentObject(); delete(*it); } _tab_array.clear(); } Area* TabView::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; NUX_RETURN_VALUE_IF_TRUE(_scroll_right->TestMousePointerInclusion(mouse_position, event_type), _scroll_right); NUX_RETURN_VALUE_IF_TRUE(_scroll_left->TestMousePointerInclusion(mouse_position, event_type), _scroll_left); unsigned int vector_size = (unsigned int) _tab_array.size(); for (unsigned int i = 0; i < vector_size; i++) { NUX_RETURN_VALUE_IF_TRUE(_tab_array[i]->_tab_area->TestMousePointerInclusion(mouse_position, event_type), _tab_array[i]->_tab_area); } if (_visible_tab_content_layout) { nuxAssert(_visible_tab_content_layout->IsLayout()); Area* found_area = _visible_tab_content_layout->FindAreaUnderMouse(mouse_position, event_type); if (found_area) return found_area; } return this; } void TabView::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { if (m_DrawBackgroundOnPreviousGeometry) { GetPainter().PaintBackground(graphics_engine, m_PreviousGeometry); m_DrawBackgroundOnPreviousGeometry = false; } graphics_engine.PushClippingRectangle(GetGeometry()); Geometry base = GetGeometry(); GetPainter().PushDrawShapeLayer(graphics_engine, Geometry(base.x, base.y, base.GetWidth(), TAB_HEIGHT), eSHAPE_CORNER_ROUND4, TAB_HEADER_BACKGROUND_COLOR, eCornerTopLeft | eCornerTopRight); if (_visible_tab_content_layout) _visible_tab_content_layout->QueueDraw(); unsigned int vector_size = (unsigned int) _tab_array.size(); Geometry geo = GetGeometry(); Geometry clip_geo; clip_geo.SetX(geo.x); clip_geo.SetY(geo.y); clip_geo.SetWidth(geo.GetWidth() - 2 * TAB_BUTTON_WIDTH); clip_geo.SetHeight(_tabview_heads_layout->GetBaseHeight()); graphics_engine.PushClippingRectangle(clip_geo); for (unsigned int i = 0; i < vector_size; i++) { Geometry tab_geo = _tab_array[i]->_tab_area->GetGeometry(); const char *tab_text = _tab_array[i]->GetName().c_str(); if (_tab_array[i]->_index == m_FocusTabIndex) { tab_geo.OffsetSize(-2, 0); GetPainter().PaintShapeCorner(graphics_engine, tab_geo, TAB_HEADER_FOCUS_COLOR, eSHAPE_CORNER_ROUND4, eCornerTopLeft | eCornerTopRight, false); GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), tab_geo, tab_text, Color(0xFFFFFFFF), true, eAlignTextCenter); } else { tab_geo.OffsetSize(-2, 0); GetPainter().PaintShapeCorner(graphics_engine, tab_geo, TAB_HEADER_COLOR, eSHAPE_CORNER_ROUND4, eCornerTopLeft | eCornerTopRight, false); GetPainter().PaintTextLineStatic(graphics_engine, GetSysBoldFont(), tab_geo, tab_text, Color(0xFF000000), true, eAlignTextCenter); } } graphics_engine.PopClippingRectangle(); GetPainter().PaintShapeCorner(graphics_engine, Geometry(base.x, base.y + TAB_HEIGHT, base.GetWidth(), base.GetHeight() - TAB_HEIGHT), TAB_BACKGROUND_COLOR, eSHAPE_CORNER_ROUND4, eCornerBottomLeft | eCornerBottomRight, false); GetPainter().Paint2DQuadColor(graphics_engine, _scroll_right->GetGeometry(), TAB_HEADER_BACKGROUND_COLOR); GeometryPositioning gp(eHACenter, eVACenter); Geometry GeoPo = ComputeGeometryPositioning(_scroll_right->GetGeometry(), GetTheme().GetImageGeometry(eTAB_RIGHT), gp); if (_scroll_right->IsMouseInside()) GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eTAB_RIGHT); else GetPainter().PaintShape(graphics_engine, GeoPo, TAB_HEADER_FOCUS_COLOR, eTAB_RIGHT); GetPainter().Paint2DQuadColor(graphics_engine, _scroll_left->GetGeometry(), TAB_HEADER_BACKGROUND_COLOR); gp.SetAlignment(eHACenter, eVACenter); GeoPo = ComputeGeometryPositioning(_scroll_left->GetGeometry(), GetTheme().GetImageGeometry(eTAB_LEFT), gp); if (_scroll_left->IsMouseInside()) GetPainter().PaintShape(graphics_engine, GeoPo, Color(0xFFFFFFFF), eTAB_LEFT); else GetPainter().PaintShape(graphics_engine, GeoPo, TAB_HEADER_FOCUS_COLOR, eTAB_LEFT); GetPainter().PopBackground(); graphics_engine.PopClippingRectangle(); } void TabView::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(GetGeometry()); GetPainter().PushShapeLayer(graphics_engine, Geometry(base.x, base.y + TAB_HEIGHT, base.GetWidth(), base.GetHeight() - TAB_HEIGHT), eSHAPE_CORNER_ROUND4, TAB_BACKGROUND_COLOR, eCornerBottomLeft | eCornerBottomRight); if (_visible_tab_content_layout) { graphics_engine.PushClippingRectangle(_visible_tab_content_layout->GetGeometry()); _visible_tab_content_layout->ProcessDraw(graphics_engine, force_draw); graphics_engine.PopClippingRectangle(); } GetPainter().PopBackground(); graphics_engine.PopClippingRectangle(); } void TabView::PreLayoutManagement() { // Give the managed layout appropriate size and position.. if (view_layout_) { Geometry layout_geo = GetGeometry(); layout_geo.OffsetPosition(TAB_X_BORDER, TAB_HEIGHT); layout_geo.OffsetSize(-2 * TAB_X_BORDER, - (TAB_HEIGHT) - TAB_Y_BORDER); view_layout_->SetGeometry(layout_geo); } } long TabView::PostLayoutManagement(long LayoutResult) { // Set the geometry of the control to be the same as the managed layout. // Only the size is changed. The position of the composition layout hasn't // been changed by ComputeContentSize. if (view_layout_) { Geometry base = view_layout_->GetGeometry(); base.OffsetPosition(-TAB_X_BORDER, -TAB_HEIGHT); base.OffsetSize(2 * TAB_X_BORDER, TAB_HEIGHT + TAB_Y_BORDER); Area::SetGeometry(base); } Geometry base = GetGeometry(); int tab_x = view_layout_->GetGeometry().x + view_layout_->GetGeometry().GetWidth() - 2 * TAB_BUTTON_WIDTH; int tab_y = base.y; _scroll_left->SetBaseXY(tab_x, tab_y); _scroll_left->SetBaseSize(TAB_BUTTON_WIDTH, TAB_BUTTON_HEIGHT); _scroll_right->SetBaseXY(tab_x + TAB_BUTTON_WIDTH, tab_y); _scroll_right->SetBaseSize(TAB_BUTTON_WIDTH, TAB_BUTTON_HEIGHT); _tabview_heads_layout->SetBaseY(tab_y); _tabview_heads_layout->SetBaseHeight(TAB_HEIGHT); TranslateTabLayout(0); _tabview_scroll_button_layout->SetBaseXY(tab_x, tab_y); _tabview_scroll_button_layout->SetBaseSize(2 * TAB_BUTTON_WIDTH, TAB_HEIGHT); GetWindowThread()->ComputeElementLayout(_tabview_scroll_button_layout); if (_visible_tab_content_layout) { // _visible_tab_content_layout->SetGeometry(view_layout_->GetGeometry()); // GetWindowThread()->ComputeElementLayout(_visible_tab_content_layout); _visible_tab_content_layout->QueueDraw(); } return LayoutResult; } void TabView::ComputeContentPosition(float offsetX, float offsetY) { if (view_layout_) { view_layout_->SetBaseX(GetBaseX() + TAB_X_BORDER); view_layout_->SetBaseY(GetBaseY() + TAB_HEIGHT); view_layout_->ComputeContentPosition(offsetX, offsetY); } } void TabView::AddTab(const char *tab_name, Layout *tab_layout) { if (tab_layout == 0) return; TabElement *Tab = new TabElement(tab_name, tab_layout); Tab->SetIndex(_tab_array.size()); if (Tab->GetIndex() == 0) { m_FocusTabIndex = 0; _visible_tab_content_layout = Tab->_tab_content_layout; //_visible_tab_content_layout->SetGeometry(view_layout_->GetGeometry()); SetCompositionLayout(_visible_tab_content_layout); GetWindowThread()->ComputeElementLayout(this); } Tab->_tab_area->SetMinimumSize(6 + GetSysBoldFont()->GetStringWidth(tab_name), PRACTICAL_WIDGET_HEIGHT); Tab->_tab_area->SetMaximumSize(6 + GetSysBoldFont()->GetStringWidth(tab_name), PRACTICAL_WIDGET_HEIGHT); Tab->_tab_area->mouse_down.connect(sigc::bind(sigc::mem_fun(this, &TabView::RecvTabMouseDown), Tab)); Tab->_tab_area->mouse_up.connect(sigc::bind(sigc::mem_fun(this, &TabView::RecvTabMouseUp), Tab)); _tabview_heads_layout->AddView(Tab->_tab_area, 1, eCenter); GetWindowThread()->ComputeElementLayout(_tabview_heads_layout); _tab_array.push_back(Tab); } void TabView::SetActiveTad(int index) { if (index >= (int) _tab_array.size()) { m_FocusTabIndex = (int) _tab_array.size() - 1; } else { m_FocusTabIndex = index; } _visible_tab_content_layout = _tab_array[m_FocusTabIndex]->_tab_content_layout; if (_visible_tab_content_layout) SetCompositionLayout(_visible_tab_content_layout); GetWindowThread()->ComputeElementLayout(this); sigTabChanged(this); sigTabIndexChanged(m_FocusTabIndex); QueueDraw(); } void TabView::TranslateLeft(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { TranslateTabLayout(-5); } void TabView::TranslateRight(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { TranslateTabLayout(5); } void TabView::TranslateTabLayout(int offset) { // if ((m_TabPositionOffset == 0) && (offset > 0)) // return; m_TabPositionOffset += offset; int lx = view_layout_->GetBaseX() + m_TabPositionOffset; if (lx > view_layout_->GetBaseX()) { // end of scroll left; m_TabPositionOffset = 0; lx = view_layout_->GetBaseX() + m_TabPositionOffset; } if (lx + _tabview_heads_layout->GetBaseWidth() < view_layout_->GetBaseX() + view_layout_->GetBaseWidth() - 2 * TAB_BUTTON_WIDTH) { lx = (view_layout_->GetBaseX() + view_layout_->GetBaseWidth() - 2 * TAB_BUTTON_WIDTH) - _tabview_heads_layout->GetBaseWidth(); if (lx > view_layout_->GetBaseX()) { m_TabPositionOffset = 0; lx = view_layout_->GetBaseX() + m_TabPositionOffset; } else m_TabPositionOffset = - (view_layout_->GetBaseX() - lx); } _tabview_heads_layout->SetBaseX(lx); GetWindowThread()->ComputeElementLayout(_tabview_heads_layout); QueueDraw(); } void TabView::RecvTabMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */, TabElement *tab) { m_FocusTabIndex = tab->_index; _visible_tab_content_layout = tab->_tab_content_layout; if (_visible_tab_content_layout) { SetCompositionLayout(_visible_tab_content_layout); } //_visible_tab_content_layout->SetGeometry(view_layout_->GetGeometry()); m_PreviousGeometry = GetGeometry(); int PrevWidth = GetBaseWidth(); int PrevHeight = GetBaseHeight(); GetWindowThread()->ComputeElementLayout(this, true); int NewWidth = GetBaseWidth(); int NewHeight = GetBaseHeight(); if ((NewWidth != PrevWidth) || (NewHeight != PrevHeight)) { // We need to draw the background on the previous size of the Table if its // size is set to match the content(IsSizeMatchContent) and an item is close. //m_PreviousGeometry; m_DrawBackgroundOnPreviousGeometry = true; } m_DrawBackgroundOnPreviousGeometry = true; sigTabChanged(this); sigTabIndexChanged(m_FocusTabIndex); QueueDraw(); } void TabView::RecvTabMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */, TabElement * /* tab */) { } void TabView::RecvMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void TabView::RecvMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void TabView::RecvTabRightMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { RecvTabRightTimerExpired(tabright_callback); } void TabView::RecvTabLeftMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { RecvTabLeftTimerExpired(tableft_callback); } void TabView::RecvTabButtonMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_TabRightTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_TabRightTimerHandler); if (m_TabLeftTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_TabLeftTimerHandler); m_TabRightTimerHandler = 0; m_TabLeftTimerHandler = 0; } void TabView::RecvTabRightTimerExpired(void * /* v */) { TranslateTabLayout(-10); m_TabRightTimerHandler = GetTimer().AddOneShotTimer(10, tabright_callback, this); } void TabView::RecvTabLeftTimerExpired(void * /* v */) { TranslateTabLayout(10); m_TabLeftTimerHandler = GetTimer().AddOneShotTimer(10, tableft_callback, this); } bool TabView::AcceptKeyNavFocus() { return false; } } nux-4.0.8+18.10.20180623/Nux/TabView.h0000644000000000000000000001071313313373365013067 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef TABVIEW_H #define TABVIEW_H #include "Nux.h" #include "View.h" #include "TimerProc.h" #include "HLayout.h" namespace nux { class TabView : public View { public: TabView(NUX_FILE_LINE_PROTO); ~TabView(); virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); void AddTab(const char *tab_name, Layout *tab_layout); void SetActiveTad(int index); //! Return true if this object can break the layout. /* Return true if this object can break the layout, meaning, the layout can be done on the composition layout only without recomputing the whole window layout. Inherited from View */ virtual bool CanBreakLayout() { return false; } sigc::signal< void, TabView * > sigTabChanged; sigc::signal< void, int > sigTabIndexChanged; private: class TabElement { public: TabElement(std::string TabName, Layout *TabLayout); ~TabElement(); void SetIndex(int index); int GetIndex() const; void SetGeometry(const Geometry &geo); Geometry const& GetGeometry() const; const std::string &GetName() const; std::string _tab_name; Layout *_tab_content_layout; BasicView *_tab_area; int _index; }; public: void RecvTabMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags, TabElement *); void RecvTabMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags, TabElement *); void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); protected: virtual bool AcceptKeyNavFocus(); private: void RecvTabRightTimerExpired(void *v); void RecvTabLeftTimerExpired(void *v); void RecvTabRightMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTabLeftMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTabButtonMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void PreLayoutManagement(); virtual long PostLayoutManagement(long LayoutResult); virtual void ComputeContentPosition(float offsetX, float offsetY); void TranslateLeft(int x, int y, unsigned long button_flags, unsigned long key_flags); void TranslateRight(int x, int y, unsigned long button_flags, unsigned long key_flags); void TranslateTabLayout(int offset); BasicView *_scroll_right; BasicView *_scroll_left; Layout *_visible_tab_content_layout; HLayout *_tabview_heads_layout; HLayout *_tabview_scroll_button_layout; int m_TabPositionOffset; int m_FocusTabIndex; TimerFunctor *tabright_callback; TimerFunctor *tableft_callback; TimerHandle m_TabRightTimerHandler; TimerHandle m_TabLeftTimerHandler; std::vector _tab_array; static Color TAB_HEADER_BACKGROUND_COLOR; static Color TAB_BACKGROUND_COLOR; static Color TAB_HEADER_COLOR; static Color TAB_HEADER_FOCUS_COLOR; static int TAB_BUTTON_WIDTH; static int TAB_BUTTON_HEIGHT; static int TAB_HEIGHT; static int TAB_X_BORDER; static int TAB_Y_BORDER; // We need to draw the background on the previous size of the Table if its // size is set to match the content(IsSizeMatchContent) and an item is close. Geometry m_PreviousGeometry; bool m_DrawBackgroundOnPreviousGeometry; }; } #endif // TABVIEW_H nux-4.0.8+18.10.20180623/Nux/TextEntry.cpp0000644000000000000000000022264413313373365014037 0ustar /* * Copyright 2011-2013 Canonical Ltd. * Copyright 2010 Inalogic Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0(the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Nux.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "Validator.h" #include "cairo/cairo.h" #include "pango/pango.h" #include "pango/pangocairo.h" #include "NuxGraphics/CairoGraphics.h" #include "TextEntry.h" #if defined(NUX_OS_LINUX) # include "TextEntryComposeSeqs.h" # if defined(USE_X11) # include # include "InputMethodIBus.h" # endif #endif namespace nux { static const int kInnerBorderX = 2; static const int kInnerBorderY = 0; //1; static const int kCursorBlinkTimeout = 400; static const double kStrongCursorLineWidth = 1; static const double kStrongCursorBarWidth = 1; static const double kWeakCursorLineWidth = 3; static const double kWeakCursorBarWidth = 3; static const Color kStrongCursorColor(0.9f, 0.9f, 0.9f, 1.0f); static const Color kWeakCursorColor(1.0f, 1.0f, 1.0f, 0.5f); static const Color kDefaultTextColor(0, 0, 0, 1.0f); static const Color kDefaultBackgroundColor(1, 1, 1, 1.0f); static const Color kDefaultSelectionBackgroundColor(0.5, 0.5, 0.5, 1.0f); static const Color kDefaultSelectionTextColor(1, 1, 1, 1.0f); static const unsigned long long kTripleClickTimeout = 500; static const std::string kDefaultFontName = "Ubuntu"; static unsigned long long GetCurrentTime() { gint64 micro_secs = g_get_real_time(); return static_cast(micro_secs / 1000); } static std::string CleanupLineBreaks(const char *source) { nuxAssert(source); std::string result; while (*source) { if (*source == '\r') { result += ' '; if (source[1] == '\n') source++; } else if (*source == '\n') { result += ' '; } else { result += *source; } source++; } return result; } // Calculate pixel size based on the Windows DPI of 96 for compatibility // reasons. CairoFont::CairoFont(const std::string &family, /*PangoFontDescription *font,*/ double pt_size, Style style, Weight weight) : font_(pango_font_description_new()) , size_(pt_size * PANGO_SCALE * 96 / 72) , style_(style) , weight_(weight) { pango_font_description_set_family(font_, family.c_str()); pango_font_description_set_absolute_size(font_, size_); if (weight_ == CairoFont::WEIGHT_BOLD) { pango_font_description_set_weight(font_, PANGO_WEIGHT_BOLD); } if (style_ == CairoFont::STYLE_ITALIC) { pango_font_description_set_style(font_, PANGO_STYLE_ITALIC); } } CairoFont::~CairoFont() { pango_font_description_free(font_); } NUX_IMPLEMENT_OBJECT_TYPE(TextEntry); TextEntry::TextEntry(const char* text, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , _size_match_text(true) , _texture2D(nullptr) , canvas_(nullptr) , cached_layout_(nullptr) , preedit_attrs_(nullptr) , completion_color_(color::Gray) , last_dblclick_time_(0) , cursor_(0) , preedit_cursor_(0) , selection_bound_(0) , scroll_offset_x_(0) , scroll_offset_y_(0) , cursor_blink_timer_(0) , cursor_blink_status_(0) , visible_(true) , focused_(false) , need_im_reset_(false) , overwrite_(false) , select_words_(false) , select_lines_(false) , button_(false) , bold_(false) , underline_(false) , strikeout_(false) , italic_(false) , multiline_(false) , wrap_(false) , cursor_visible_(false) , readonly_(false) , content_modified_(false) , selection_changed_(false) , cursor_moved_(false) , update_canvas_(true) , font_family_("Ubuntu") , font_size_(12) , font_options_(cairo_font_options_create()) , font_dpi_(96.0) , _text_color(color::White) , align_(CairoGraphics::ALIGN_LEFT) #if defined(USE_X11) , caret_cursor_(None) , ime_(new IBusIMEContext(this)) #endif , ime_active_(false) , text_input_mode_(false) , key_nav_mode_(false) , lose_key_focus_on_key_nav_direction_up_(true) , lose_key_focus_on_key_nav_direction_down_(true) , cursor_visible_on_key_focus_only_(false) { cairo_font_options_set_antialias(font_options_, CAIRO_ANTIALIAS_SUBPIXEL); cairo_font_options_set_hint_style(font_options_, CAIRO_HINT_STYLE_FULL); cairo_font_options_set_hint_metrics(font_options_, CAIRO_HINT_METRICS_ON); cairo_font_options_set_subpixel_order(font_options_, CAIRO_SUBPIXEL_ORDER_RGB); mouse_down.connect(sigc::mem_fun(this, &TextEntry::RecvMouseDown)); mouse_drag.connect(sigc::mem_fun(this, &TextEntry::RecvMouseDrag)); mouse_up.connect(sigc::mem_fun(this, &TextEntry::RecvMouseUp)); mouse_double_click.connect(sigc::mem_fun(this, &TextEntry::RecvMouseDoubleClick)); mouse_enter.connect(sigc::mem_fun(this, &TextEntry::RecvMouseEnter)); mouse_leave.connect(sigc::mem_fun(this, &TextEntry::RecvMouseLeave)); key_down.connect(sigc::mem_fun(this, &TextEntry::RecvKeyEvent)); key_up.connect([this] (unsigned int keysym, unsigned long, unsigned long state) { RecvKeyEvent(NUX_KEYUP, keysym, state, nullptr, 0); }); geometry_changed.connect([this] (Area* /*area*/, Geometry& /*geo*/) { QueueRefresh(true, false); }); begin_key_focus.connect(sigc::mem_fun(this, &TextEntry::RecvStartKeyFocus)); end_key_focus.connect(sigc::mem_fun(this, &TextEntry::RecvEndKeyFocus)); SetMinimumSize(DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); SetText(text); SetAcceptKeyboardEvent(true); EnableDoubleClick(true); SetPasswordChar("*"); } TextEntry::~TextEntry() { if (cursor_blink_timer_) g_source_remove(cursor_blink_timer_); cairo_font_options_destroy(font_options_); if (_texture2D) _texture2D->UnReference(); #if defined(USE_X11) if (ime_) delete ime_; #endif delete canvas_; ResetLayout(); } void TextEntry::PreLayoutManagement() { View::PreLayoutManagement(); } long TextEntry::PostLayoutManagement(long layoutResult) { long result = View::PostLayoutManagement(layoutResult); MainDraw(); return result; } void TextEntry::GeometryChanged(bool /*position_has_changed*/, bool /*size_has_changed*/) { update_canvas_ = true; View::GeometryChanged(true, true); } Area* TextEntry::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { Area* area = View::FindAreaUnderMouse(mouse_position, event_type); return area; } void TextEntry::ProcessMouseEvent(int event_type, int x, int y, int /* dx */, int /* dy */, unsigned long button_flags, unsigned long key_flags) { int X = static_cast(x /*round(event.GetX())*/) - kInnerBorderX - scroll_offset_x_; int Y = static_cast(y /*round(event.GetY())*/) - kInnerBorderY - scroll_offset_y_; int index = XYToTextIndex(X, Y); MouseButton button = GetEventButton(button_flags); if (event_type == NUX_MOUSE_PRESSED && (button == 2 || button == 3)) { SetCursor(index); #if defined(NUX_OS_LINUX) if (button == 2) PastePrimaryClipboard(); #endif QueueRefresh(false, true); return; } if (button != 1 && event_type != NUX_MOUSE_MOVE) return; int sel_start, sel_end; GetSelectionBounds(&sel_start, &sel_end); unsigned long long current_time = GetCurrentTime(); if ((event_type == NUX_MOUSE_PRESSED) && (current_time - last_dblclick_time_ <= kTripleClickTimeout)) { SelectLine(); } else if (event_type == NUX_MOUSE_DOUBLECLICK && !ime_active_) { SelectWord(); last_dblclick_time_ = current_time; } else if (event_type == NUX_MOUSE_PRESSED) { if (key_flags & NUX_STATE_SHIFT) { // If current click position is inside the selection range, then just // cancel the selection. if (index > sel_start && index < sel_end) SetCursor(index); else if (index <= sel_start) SetSelectionBounds(sel_end, index); else if (index >= sel_end) SetSelectionBounds(sel_start, index); } else { SetCursor(index); } } else if (event_type == NUX_MOUSE_MOVE) { SetSelectionBounds(selection_bound_, index); } QueueRefresh(false, true); //return EVENT_RESULT_HANDLED; } void TextEntry::ProcessKeyEvent( unsigned long event_type, /*event type*/ unsigned long keysym , /*event keysym*/ unsigned long state , /*event state*/ const char* character , /*character*/ unsigned short /* keyCount */ /*key repeat count*/) { #if defined(USE_X11) if (im_running()) { // FIXME Have to get the x11_keycode for ibus-hangul/korean input KeyCode keycode = XKeysymToKeycode(GetGraphicsDisplay()->GetX11Display(), keysym); KeyEvent event(static_cast(event_type), keysym, keycode, state, character); if (ime_->FilterKeyEvent(event)) return; } #endif /* Ignore all the keyup events to make Composition and Dead keys to work, * as no one (IBus a part) needs them */ if (event_type == NUX_KEYUP) return; #if !defined(NO_X11) if (IsInCompositionMode() || IsInitialCompositionKeySym(keysym)) { if (HandleComposition(keysym)) return; } #endif if (event_type == NUX_KEYDOWN) text_input_mode_ = true; cursor_blink_status_ = 4; if ((!multiline_) && (!lose_key_focus_on_key_nav_direction_up_) && (keysym == NUX_VK_UP)) { // Ignore key navigation direction 'up' if we are not in multi-line. return; } if ((!multiline_) && (!lose_key_focus_on_key_nav_direction_up_) && (keysym == NUX_VK_DOWN)) { // Ignore key navigation direction 'down' if we are not in multi-line. return; } // we need to ignore some characters if (keysym == NUX_VK_TAB) return; if ((keysym == NUX_VK_ENTER || keysym == NUX_KP_ENTER)) { activated.emit(); return; } unsigned int keyval = keysym; bool shift = (state & NUX_STATE_SHIFT); bool ctrl = (state & NUX_STATE_CTRL); bool handled = false; // DLOG("TextEntry::key_down(%d, shift:%d ctrl:%d)", keyval, shift, ctrl); if (event_type == NUX_KEYDOWN) { if (keyval == NUX_VK_LEFT) { if (!ctrl) MoveCursor(VISUALLY, -1, shift); else MoveCursor(WORDS, -1, shift); handled = true; } else if (keyval == NUX_VK_RIGHT) { if (!ctrl) MoveCursor(VISUALLY, 1, shift); else MoveCursor(WORDS, 1, shift); handled = true; } else if (keyval == NUX_VK_UP) { // move cursor to start of line MoveCursor(DISPLAY_LINES, -1, shift); handled = true; } else if (keyval == NUX_VK_DOWN) { // move cursor to end of line MoveCursor(DISPLAY_LINES, 1, shift); handled = true; } else if (keyval == NUX_VK_HOME) { if (!ctrl) MoveCursor(DISPLAY_LINE_ENDS, -1, shift); else MoveCursor(BUFFER, -1, shift); handled = true; } else if (keyval == NUX_VK_END) { if (!ctrl) MoveCursor(DISPLAY_LINE_ENDS, 1, shift); else MoveCursor(BUFFER, 1, shift); handled = true; } else if (keyval == NUX_VK_PAGE_UP) { if (!ctrl) MoveCursor(PAGES, -1, shift); else MoveCursor(BUFFER, -1, shift); handled = true; } else if (keyval == NUX_VK_PAGE_DOWN) { if (!ctrl) MoveCursor(PAGES, 1, shift); else MoveCursor(BUFFER, 1, shift); handled = true; } else if (((keyval == NUX_VK_x || keyval == NUX_VK_X) && ctrl && !shift) || ((keyval == NUX_VK_DELETE) && shift && !ctrl)) { CutClipboard(); handled = true; } else if (((keyval == NUX_VK_c || keyval == NUX_VK_C) && ctrl && !shift) || ((keyval == NUX_VK_INSERT) && ctrl && !shift)) { CopyClipboard(); handled = true; } else if (((keyval == NUX_VK_v || keyval == NUX_VK_V) && ctrl && !shift) || ((keyval == NUX_VK_INSERT) && shift && !ctrl)) { PasteClipboard(); handled = true; } else if ((keyval == NUX_VK_a || keyval == NUX_VK_A) && ctrl) { SelectAll(); handled = true; } else if (keyval == NUX_VK_BACKSPACE) { if (!ctrl) BackSpace(VISUALLY); else BackSpace(WORDS); handled = true; } else if ((keyval == NUX_VK_DELETE) && (!shift)) { if (!ctrl) Delete(VISUALLY); else Delete(WORDS); handled = true; } else if ((keyval == NUX_VK_INSERT) && (!shift) && (!ctrl)) { ToggleOverwrite(); handled = true; } // else // { // return EVENT_RESULT_UNHANDLED; // } } else { // EVENT_KEY_PRESS // if (keyval == GDK_Return || keyval == GDK_KP_Enter) // { // // If multiline_ is unset, just ignore new_line. // if (multiline_) // EnterText("\n"); // else // return; // } // else // { // return; // } } if (!handled && character) { unsigned int utf_char = g_utf8_get_char(character); if (g_unichar_isprint(utf_char)) EnterText(character); } QueueRefresh(false, true); } void TextEntry::RecvMouseDoubleClick(int x, int y, unsigned long button_flags, unsigned long key_flags) { ProcessMouseEvent(NUX_MOUSE_DOUBLECLICK, x, y, 0, 0, button_flags, key_flags); } void TextEntry::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags) { ProcessMouseEvent(NUX_MOUSE_RELEASED, x, y, 0, 0, button_flags, key_flags); } void TextEntry::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags) { ProcessMouseEvent(NUX_MOUSE_PRESSED, x, y, 0, 0, button_flags, key_flags); } void TextEntry::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) { ProcessMouseEvent(NUX_MOUSE_MOVE, x, y, dx, dy, button_flags, key_flags); } void TextEntry::RecvMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { #if defined(USE_X11) if (caret_cursor_ == None) { Display* display = nux::GetGraphicsDisplay()->GetX11Display(); nux::BaseWindow* window = static_cast(GetTopLevelViewWindow()); if (display && window) { caret_cursor_ = XCreateFontCursor(display, XC_xterm); XDefineCursor(display, window->GetInputWindowId(), caret_cursor_); } } #endif } void TextEntry::RecvMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { #if defined(USE_X11) if (caret_cursor_ != None) { Display* display = nux::GetGraphicsDisplay()->GetX11Display(); nux::BaseWindow* window = static_cast(GetTopLevelViewWindow()); if (display && window) { XUndefineCursor(display, window->GetInputWindowId()); XFreeCursor(display, caret_cursor_); caret_cursor_ = None; } } #endif } void TextEntry::RecvKeyEvent( unsigned long eventType , /*event type*/ unsigned long keysym , /*event keysym*/ unsigned long state , /*event state*/ const char* character , /*character*/ unsigned short keyCount /*key repeat count*/) { ProcessKeyEvent(eventType, keysym, state, character, keyCount); } void TextEntry::RecvStartKeyFocus() { key_nav_mode_ = true; text_input_mode_ = false; composition_list_.clear(); FocusInx(); } void TextEntry::RecvEndKeyFocus() { key_nav_mode_ = false; text_input_mode_ = false; composition_list_.clear(); FocusOutx(); } void TextEntry::Draw(GraphicsEngine& gfxContext, bool /* forceDraw */) { MainDraw(); Geometry base = GetGeometry(); gfxContext.PushClippingRectangle(base); nux::GetPainter().PaintBackground(gfxContext, base); Color col = color::Black; col.alpha = 0; gfxContext.QRP_Color(base.x, base.y, base.width, base.height, col); TexCoordXForm texxform; texxform.SetWrap(TEXWRAP_REPEAT, TEXWRAP_REPEAT); texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD); gfxContext.QRP_1Tex(base.x, base.y, base.width, base.height, _texture2D->GetDeviceTexture(), texxform, _text_color); gfxContext.PopClippingRectangle(); } void TextEntry::DrawContent(GraphicsEngine& /* gfxContext */, bool /* forceDraw */) { //MainDraw(); } TextEntry::SearchState TextEntry::GetCompositionForList(std::vector const& input, std::string& composition) { SearchState search_state = SearchState::NO_MATCH; #if defined(NUX_OS_LINUX) if (input.size() >= ComposeSequence::MAX_SYMBOLS) return search_state; for (unsigned i = 0; i < COMPOSE_SEQUENCES_SIZE; ++i) { int j = 0; bool valid_seq = false; ComposeSequence const& seq = COMPOSE_SEQUENCES[i]; for (auto key : input) { if (key != seq.symbols[j]) { if (seq.symbols[j] != XK_VoidSymbol) valid_seq = false; break; } valid_seq = true; ++j; } if (valid_seq) { if (seq.symbols[j] == XK_VoidSymbol) { search_state = SearchState::MATCH; composition = seq.result; return search_state; } else { search_state = SearchState::PARTIAL; } } } #endif return search_state; } bool TextEntry::IsInCompositionMode() const { return !composition_list_.empty(); } bool TextEntry::IsInitialCompositionKeySym(unsigned long keysym) const { #if defined(USE_X11) /* Checks if a keysym is a valid initial composition key */ if (keysym == XK_Multi_key || (keysym >= XK_dead_grave && keysym <= XK_dead_currency) || keysym == XK_Greek_accentdieresis) { return true; } #endif return false; } bool TextEntry::HandleComposition(unsigned long keysym) { #if defined(USE_X11) bool composition_mode = IsInCompositionMode(); if (composition_mode && IsModifierKey(keysym)) return true; composition_list_.push_back(keysym); std::string composition_match; auto match = GetCompositionForList(composition_list_, composition_match); if (match == SearchState::PARTIAL) { return true; } else if (match == SearchState::MATCH) { EnterText(composition_match.c_str()); composition_list_.clear(); QueueRefresh(false, true); return true; } else { composition_list_.clear(); return composition_mode; } #endif return false; } void TextEntry::SetText(const char* text) { const char* end = NULL; g_utf8_validate(text, -1, &end); std::string txt((text && *text && end > text) ? std::string(text, end) : ""); if (txt == text_) return; // prevent some redraws text_ = multiline_ ? txt : CleanupLineBreaks(txt.c_str()); cursor_ = 0; selection_bound_ = 0; need_im_reset_ = true; //ResetImContext(); text_input_mode_ = true; QueueRefresh(true, true); text_changed.emit(this); } std::string const& TextEntry::GetText() const { return text_; } std::string TextEntry::GetTextSelection() const { if (text_.size() == 0) { return std::string(""); } int selection_start = 0; int selection_end = 0; if (GetSelectionBounds(&selection_start, &selection_end)) { return text_.substr(selection_start, selection_end); } else { return std::string(""); } } void TextEntry::SetCompletion(const char* text) { const char* end = NULL; g_utf8_validate(text, -1, &end); std::string txt((text && *text && end > text) ? std::string(text, end) : ""); if (txt == completion_) return; completion_ = txt; QueueRefresh(true, true); } std::string const& TextEntry::GetCompletion() const { return completion_; } void TextEntry::SetCompletionColor(const Color &color) { completion_color_ = color; QueueRefresh(true, true); } Color const& TextEntry::GetCompletionColor() const { return completion_color_; } void TextEntry::SetTextColor(const Color &text_color) { if (_text_color != text_color) { _text_color = text_color; QueueRefresh(true, true); } } Color TextEntry::GetTextColor() const { return _text_color; } void TextEntry::MainDraw() { CairoGraphics* edit_canvas = EnsureCanvas(); if (update_canvas_ || !last_selection_region_.empty() || !selection_region_.empty()) { edit_canvas->PushState(); DrawText(edit_canvas); edit_canvas->PopState(); } // if (background_) // background_->Draw(canvas, 0, 0, GetBaseWidth, GetBaseHeight); CairoGraphics* final_canvas = new CairoGraphics(CAIRO_FORMAT_ARGB32, edit_canvas->GetWidth(), edit_canvas->GetHeight()); final_canvas->PushState(); final_canvas->IntersectRectClipRegion(kInnerBorderX, kInnerBorderY, GetBaseWidth() - kInnerBorderX, GetBaseHeight() - kInnerBorderY); final_canvas->DrawCanvas(0, 0, edit_canvas); final_canvas->PopState(); DrawCursor(final_canvas); update_canvas_ = false; last_selection_region_ = selection_region_; last_cursor_region_ = cursor_region_; NBitmapData* bitmap = final_canvas->GetBitmap(); delete final_canvas; if (!_texture2D || _texture2D->GetWidth() != bitmap->GetWidth() || _texture2D->GetHeight() != bitmap->GetHeight()) { if (_texture2D) _texture2D->UnReference(); _texture2D = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); } _texture2D->Update(bitmap); delete bitmap; } void TextEntry::FocusInx() { if (!focused_) { focused_ = true; if (!readonly_ /*&& im_context_*/) { need_im_reset_ = true; #if defined(USE_X11) ime_->Focus(); nux::GetWindowThread()->XICFocus(this); #endif //gtk_im_context_focus_in(im_context_); //UpdateIMCursorLocation(); } cursor_visible_ = true; // show cursor when getting focus selection_changed_ = true; cursor_moved_ = true; // Don't adjust scroll. QueueRefresh(true, false); } } void TextEntry::FocusOutx() { if (focused_) { focused_ = false; if (!readonly_ /*&& im_context_*/) { need_im_reset_ = true; #if defined(USE_X11) ime_->Blur(); nux::GetWindowThread()->XICUnFocus(); #endif //gtk_im_context_focus_out(im_context_); } cursor_visible_ = false; // hide cursor when losing focus selection_changed_ = true; cursor_moved_ = true; if (cursor_visible_on_key_focus_only_ && cursor_blink_timer_) { g_source_remove(cursor_blink_timer_); cursor_blink_timer_ = 0; } // Don't adjust scroll. QueueRefresh(true, false); } } CairoGraphics* TextEntry::EnsureCanvas() { if (canvas_) { if ((GetBaseWidth() == canvas_->GetWidth()) && (GetBaseHeight() == canvas_->GetHeight())) { return canvas_; } else { nuxDebugMsg("[TextEntry::EnsureCanvas] Recreate canvas"); delete canvas_; canvas_ = NULL; } } canvas_ = new CairoGraphics(CAIRO_FORMAT_ARGB32, GetBaseWidth(), GetBaseHeight()); nuxAssert(canvas_); return canvas_; } void TextEntry::AdjustScroll() { int old_offset_x = scroll_offset_x_; int old_offset_y = scroll_offset_y_; int display_width = GetBaseWidth() - kInnerBorderX * 2; int display_height = GetBaseHeight() - kInnerBorderY * 2; PangoLayout* layout = EnsureLayout(); int text_width, text_height; pango_layout_get_pixel_size(layout, &text_width, &text_height); int strong_x, strong_y, strong_height; int weak_x, weak_y, weak_height; GetCursorLocationInLayout(&strong_x, &strong_y, &strong_height, &weak_x, &weak_y, &weak_height); if (!wrap_ && display_width > text_width) { PangoAlignment align = pango_layout_get_alignment(layout); if (align == PANGO_ALIGN_RIGHT) scroll_offset_x_ = display_width - text_width; else if (align == PANGO_ALIGN_CENTER) scroll_offset_x_ = (display_width - text_width) / 2; else scroll_offset_x_ = 0; } else { if (scroll_offset_x_ + strong_x < 0) scroll_offset_x_ = -strong_x; else if (scroll_offset_x_ + strong_x > display_width) scroll_offset_x_ = display_width - strong_x; if (std::abs(weak_x - strong_x) < display_width) { if (scroll_offset_x_ + weak_x < 0) scroll_offset_x_ = - weak_x; else if (scroll_offset_x_ + weak_x > display_width) scroll_offset_x_ = display_width - weak_x; } } if (display_height > text_height) { scroll_offset_y_ = 0; } else { if (scroll_offset_y_ + strong_y + strong_height > display_height) scroll_offset_y_ = display_height - strong_y - strong_height; if (scroll_offset_y_ + strong_y < 0) scroll_offset_y_ = -strong_y; } if (old_offset_x != scroll_offset_x_ || old_offset_y != scroll_offset_y_) content_modified_ = true; } void TextEntry::QueueRefresh(bool relayout, bool adjust_scroll) { if (relayout) ResetLayout(); if (adjust_scroll) AdjustScroll(); QueueTextDraw(); QueueCursorBlink(); } void TextEntry::ResetImContext() { if (need_im_reset_) { need_im_reset_ = false; // if (im_context_) // gtk_im_context_reset(im_context_); ResetPreedit(); } } void TextEntry::ResetPreedit() { // Reset layout if there were some content in preedit string if (preedit_.length()) ResetLayout(); preedit_.clear(); preedit_cursor_ = 0; if (preedit_attrs_) { pango_attr_list_unref(preedit_attrs_); preedit_attrs_ = NULL; } } void TextEntry::PreeditStarted() { ime_active_ = true; } void TextEntry::UpdatePreedit(std::string const& preedit, int cursor) { preedit_ = preedit; preedit_cursor_ = cursor; QueueRefresh(true, true); } void TextEntry::UpdatePreeditAttribs(PangoAttrList* list) { if (preedit_attrs_) { pango_attr_list_unref(preedit_attrs_); preedit_attrs_ = NULL; } preedit_attrs_ = list; } void TextEntry::ClearPreedit() { ResetPreedit(); QueueRefresh(true, true); } void TextEntry::DrawText(CairoGraphics *canvas) { PangoLayout *layout = EnsureLayout(); bool redraw_text = false; if (update_canvas_) { canvas->ClearCanvas(); canvas->PushState(); redraw_text = true; } else if (!last_selection_region_.empty()) { //last_selection_region_.Integerize(); canvas->PushState(); canvas->IntersectGeneralClipRegion(last_selection_region_); canvas->ClearRect(0, 0, GetBaseWidth(), GetBaseHeight()); redraw_text = true; } if (redraw_text) { cairo_set_source_rgb(canvas->GetInternalContext(), _text_color.red, _text_color.green, _text_color.blue); cairo_move_to(canvas->GetInternalContext(), scroll_offset_x_ + kInnerBorderX, scroll_offset_y_ + kInnerBorderY); pango_cairo_show_layout(canvas->GetInternalContext(), layout); canvas->PopState(); } // Draw selection background. // Selection in a single line may be not continual, so we use pango to // get the x-ranges of each selection range in one line, and draw them // separately. if (!selection_region_.empty()) { canvas->PushState(); //selection_region_.Integerize(); canvas->IntersectGeneralClipRegion(selection_region_); Color selection_color = GetSelectionBackgroundColor(); Color text_color = GetSelectionTextColor(); cairo_set_source_rgb(canvas->GetInternalContext(), selection_color.red, selection_color.green, selection_color.blue); cairo_paint(canvas->GetInternalContext()); cairo_move_to(canvas->GetInternalContext(), scroll_offset_x_ + kInnerBorderX, scroll_offset_y_ + kInnerBorderY); cairo_set_source_rgb(canvas->GetInternalContext(), text_color.red, text_color.green, text_color.blue); pango_cairo_show_layout(canvas->GetInternalContext(), layout); canvas->PopState(); } } bool TextEntry::CursorBlinkCallback(TextEntry *self) { if (self->cursor_blink_status_) self->ShowCursor(); else self->HideCursor(); if (--self->cursor_blink_status_ < 0) self->cursor_blink_status_ = 2; return true; } void TextEntry::QueueCursorBlink() { if (cursor_visible_on_key_focus_only_ && !focused_) return; if (!cursor_blink_timer_) cursor_blink_timer_ = g_timeout_add(kCursorBlinkTimeout, (GSourceFunc)&CursorBlinkCallback, this); } void TextEntry::ShowCursor() { if (!cursor_visible_) { cursor_visible_ = true; if (focused_ && !readonly_) { cursor_moved_ = true; QueueRefresh(false, false); } } } void TextEntry::HideCursor() { if (cursor_visible_) { cursor_visible_ = false; if (focused_ && !readonly_) { cursor_moved_ = true; QueueRefresh(false, false); } } } void TextEntry::GetCursorRects(Rect *strong, Rect *weak) { int strong_x, strong_y, strong_height; int weak_x, weak_y, weak_height; GetCursorLocationInLayout(&strong_x, &strong_y, &strong_height, &weak_x, &weak_y, &weak_height); strong->x = strong_x + kInnerBorderX + scroll_offset_x_ - kStrongCursorBarWidth; strong->width = kStrongCursorBarWidth * 2; strong->y = strong_y + kInnerBorderY + scroll_offset_y_; strong->height = strong_height; if (weak_x != strong_x) { weak->x = weak_x+ kInnerBorderX + scroll_offset_x_ - kWeakCursorBarWidth; weak->width = kWeakCursorBarWidth * 2; weak->y = weak_y+ kInnerBorderY + scroll_offset_y_; weak->height = weak_height; } else { *weak = *strong; } } void TextEntry::UpdateCursorRegion() { cursor_region_.clear(); Rect strong, weak; GetCursorRects(&strong, &weak); cursor_region_.push_back(strong); cursor_region_.push_back(weak); } void TextEntry::DrawCursor(CairoGraphics *canvas) { if (!cursor_visible_) return; int strong_x, strong_y, strong_height; int weak_x, weak_y, weak_height; GetCursorLocationInLayout(&strong_x, &strong_y, &strong_height, &weak_x, &weak_y, &weak_height); // Draw strong cursor. // 0.5 is for cairo drawing between the grid canvas->DrawLine(strong_x + kInnerBorderX + scroll_offset_x_ + 0.5, strong_y + kInnerBorderY + scroll_offset_y_, strong_x + kInnerBorderX + scroll_offset_x_ + 0.5, strong_y + strong_height + kInnerBorderY + scroll_offset_y_, kStrongCursorLineWidth, kStrongCursorColor); // Draw a small arror towards weak cursor if (strong_x > weak_x) { canvas->DrawLine( strong_x + kInnerBorderX + scroll_offset_x_ - kStrongCursorBarWidth, strong_y + kInnerBorderY + scroll_offset_y_ + kStrongCursorLineWidth, strong_x + kInnerBorderX + scroll_offset_x_, strong_y + kInnerBorderY + scroll_offset_y_ + kStrongCursorLineWidth, kStrongCursorLineWidth, kStrongCursorColor); } else if (strong_x < weak_x) { canvas->DrawLine( strong_x + kInnerBorderX + scroll_offset_x_, strong_y + kInnerBorderY + scroll_offset_y_ + kStrongCursorLineWidth, strong_x + kInnerBorderX + scroll_offset_x_ + kStrongCursorBarWidth, strong_y + kInnerBorderY + scroll_offset_y_ + kStrongCursorLineWidth, kStrongCursorLineWidth, kStrongCursorColor); } if (strong_x != weak_x ) { // Draw weak cursor. canvas->DrawLine(weak_x + kInnerBorderX + scroll_offset_x_, weak_y + kInnerBorderY + scroll_offset_y_, weak_x + kInnerBorderX + scroll_offset_x_, weak_y + weak_height + kInnerBorderY + scroll_offset_y_, kWeakCursorLineWidth, kWeakCursorColor); // Draw a small arror towards strong cursor if (weak_x > strong_x) { canvas->DrawLine( weak_x + kInnerBorderX + scroll_offset_x_ - kWeakCursorBarWidth, weak_y + kInnerBorderY + scroll_offset_y_ + kWeakCursorLineWidth, weak_x + kInnerBorderX + scroll_offset_x_, weak_y + kInnerBorderY + scroll_offset_y_ + kWeakCursorLineWidth, kWeakCursorLineWidth, kWeakCursorColor); } else { canvas->DrawLine( weak_x + kInnerBorderX + scroll_offset_x_, weak_y + kInnerBorderY + scroll_offset_y_ + kWeakCursorLineWidth, weak_x + kInnerBorderX + scroll_offset_x_ + kWeakCursorBarWidth, weak_y + kInnerBorderY + scroll_offset_y_ + kWeakCursorLineWidth, kWeakCursorLineWidth, kWeakCursorColor); } } } Color TextEntry::GetSelectionBackgroundColor() { return kDefaultSelectionBackgroundColor; } Color TextEntry::GetSelectionTextColor() { return kDefaultSelectionTextColor; } void TextEntry::GetCursorLocationInLayout(int *strong_x, int *strong_y, int *strong_height, int *weak_x, int *weak_y, int *weak_height) { PangoLayout *layout = EnsureLayout(); int cursor_index = TextIndexToLayoutIndex(cursor_, true); PangoRectangle strong, weak; pango_layout_get_cursor_pos(layout, cursor_index, &strong, &weak); if (strong_x) *strong_x = PANGO_PIXELS(strong.x); if (strong_y) *strong_y = PANGO_PIXELS(strong.y); if (strong_height) *strong_height = PANGO_PIXELS(strong.height); if (weak_x) *weak_x = PANGO_PIXELS(weak.x); if (weak_y) *weak_y = PANGO_PIXELS(weak.y); if (weak_height) *weak_height = PANGO_PIXELS(weak.height); } PangoLayout* TextEntry::EnsureLayout() { if (!cached_layout_) { cached_layout_ = CreateLayout(); } return cached_layout_; } void TextEntry::QueueTextDraw() { if (content_modified_) { UpdateSelectionRegion(); UpdateCursorRegion(); QueueDraw(); //owner->QueueDraw(); content_modified_ = false; update_canvas_ = true; } else { if (selection_changed_) { UpdateSelectionRegion(); if (!last_selection_region_.empty()) QueueDraw(); //owner_->QueueDrawRegion(last_selection_region_); if (!selection_region_.empty()) QueueDraw(); //owner_->QueueDrawRegion(selection_region_); selection_changed_ = false; } if (cursor_moved_) { UpdateCursorRegion(); if (!last_cursor_region_.empty()) QueueDraw(); //owner_->QueueDrawRegion(last_cursor_region_); if (!cursor_region_.empty()) QueueDraw(); //owner_->QueueDrawRegion(cursor_region_); cursor_moved_ = false; } } } void TextEntry::ResetLayout() { if (cached_layout_) { g_object_unref(cached_layout_); cached_layout_ = NULL; content_modified_ = true; } } PangoLayout* TextEntry::CreateLayout() { // Creates the pango layout with a temporary canvas that is not zoomed. CairoGraphics *canvas = new CairoGraphics(CAIRO_FORMAT_ARGB32, 1, 1); PangoLayout *layout = pango_cairo_create_layout(canvas->GetInternalContext()); delete canvas; PangoAttrList *tmp_attrs = pango_attr_list_new(); std::string tmp_string; /* Set necessary parameters */ pango_cairo_context_set_font_options(pango_layout_get_context(layout), font_options_); pango_cairo_context_set_resolution(pango_layout_get_context(layout), font_dpi_); if (wrap_) { pango_layout_set_width(layout, (GetBaseWidth() - kInnerBorderX * 2) * PANGO_SCALE); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); } else { pango_layout_set_width(layout, -1); } pango_layout_set_single_paragraph_mode(layout, !multiline_); if (preedit_.length()) { size_t cursor_index = static_cast(cursor_); size_t text_length = text_.length(); size_t preedit_length = preedit_.length(); if (visible_) { tmp_string = text_; tmp_string.insert(cursor_index, preedit_); } else { size_t nchars = g_utf8_strlen(text_.c_str(), text_length); size_t preedit_nchars = g_utf8_strlen(preedit_.c_str(), preedit_length); nchars += preedit_nchars; tmp_string.reserve(password_char_.length() * nchars); for (size_t i = 0; i < nchars; ++i) tmp_string.append(password_char_); size_t cursor_offset = g_utf8_pointer_to_offset(text_.c_str(), text_.c_str() + cursor_index); /* Fix cursor index and preedit_length */ cursor_index = cursor_offset * password_char_.length(); preedit_length = preedit_nchars * password_char_.length(); } if (preedit_attrs_) pango_attr_list_splice(tmp_attrs, preedit_attrs_, static_cast(cursor_index), static_cast(preedit_length)); } else { if (visible_) { tmp_string = text_; } else { size_t nchars = g_utf8_strlen(text_.c_str(), text_.length()); tmp_string.reserve(password_char_.length() * nchars); for (size_t i = 0; i < nchars; ++i) tmp_string.append(password_char_); } } int pre_completion_length = tmp_string.length(); if (!completion_.empty() && !wrap_ && preedit_.empty()) { tmp_string = text_ + completion_; } pango_layout_set_text(layout, tmp_string.c_str(), static_cast(tmp_string.length())); /* Set necessary attributes */ PangoAttribute *attr; if (underline_) { attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr->start_index = 0; attr->end_index = static_cast(pre_completion_length); pango_attr_list_insert(tmp_attrs, attr); } if (strikeout_) { attr = pango_attr_strikethrough_new(TRUE); attr->start_index = 0; attr->end_index = static_cast(pre_completion_length); pango_attr_list_insert(tmp_attrs, attr); } if (!completion_.empty() && !wrap_) { attr = pango_attr_foreground_new(65535 * completion_color_.red, 65535 * completion_color_.green, 65535 * completion_color_.blue); attr->start_index = static_cast(pre_completion_length); attr->end_index = static_cast(tmp_string.length()); pango_attr_list_insert(tmp_attrs, attr); } /* Set font desc */ { /* safe to down_cast here, because we know the actual implementation. */ CairoFont *font = new CairoFont( font_family_.empty() ? kDefaultFontName : font_family_.c_str(), font_size_, italic_ ? CairoFont::STYLE_ITALIC : CairoFont::STYLE_NORMAL, bold_ ? CairoFont::WEIGHT_BOLD : CairoFont::WEIGHT_NORMAL); nuxAssert(font); attr = pango_attr_font_desc_new(font->GetFontDescription()); attr->start_index = 0; attr->end_index = static_cast(tmp_string.length()); pango_attr_list_insert(tmp_attrs, attr); pango_layout_set_font_description(layout, font->GetFontDescription()); font->Destroy(); } pango_layout_set_attributes(layout, tmp_attrs); pango_attr_list_unref(tmp_attrs); /* Set alignment according to text direction. Only set layout's alignment * when it's not wrapped and in single line mode. */ if (!wrap_ && pango_layout_get_line_count(layout) <= 1 && align_ != CairoGraphics::ALIGN_CENTER) { PangoDirection dir; if (visible_) dir = pango_find_base_dir(tmp_string.c_str(), static_cast(tmp_string.length())); else dir = PANGO_DIRECTION_NEUTRAL; if (dir == PANGO_DIRECTION_NEUTRAL) { // GtkWidget *widget = GetWidgetAndCursorLocation(NULL); // if (widget && gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL) // dir = PANGO_DIRECTION_RTL; // else // dir = PANGO_DIRECTION_LTR; dir = PANGO_DIRECTION_LTR; } // If wordWrap is false then "justify" alignment has no effect. PangoAlignment pango_align = (align_ == CairoGraphics::ALIGN_RIGHT ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT); // Invert the alignment if text direction is right to left. if (dir == PANGO_DIRECTION_RTL) { pango_align = (align_ == CairoGraphics::ALIGN_RIGHT ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT); } pango_layout_set_alignment(layout, pango_align); pango_layout_set_justify(layout, FALSE); } else if (align_ == CairoGraphics::ALIGN_JUSTIFY) { pango_layout_set_justify(layout, TRUE); pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); } else if (align_ == CairoGraphics::ALIGN_RIGHT) { pango_layout_set_justify(layout, FALSE); pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT); } else if (align_ == CairoGraphics::ALIGN_CENTER) { pango_layout_set_justify(layout, FALSE); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); } else { pango_layout_set_justify(layout, FALSE); pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); } { PangoContext *context; PangoFontMetrics *metrics; int ascent, descent; context = pango_layout_get_context(layout); metrics = pango_context_get_metrics(context, pango_layout_get_font_description(layout), pango_context_get_language(context)); ascent = pango_font_metrics_get_ascent(metrics); descent = pango_font_metrics_get_descent(metrics); int full_height = PANGO_PIXELS(ascent + descent) + (kInnerBorderY * 2); SetMinimumHeight(full_height); pango_font_metrics_unref(metrics); } return layout; } int TextEntry::TextIndexToLayoutIndex(int text_index, bool consider_preedit_cursor) { if (visible_) { if (text_index < cursor_) return text_index; if (text_index == cursor_ && consider_preedit_cursor) return text_index + preedit_cursor_; return text_index + static_cast(preedit_.length()); } const char *text = text_.c_str(); int offset = static_cast( g_utf8_pointer_to_offset(text, text + text_index)); int preedit_offset = 0; int preedit_chars = 0; if (preedit_.length()) { const char *preedit_text = preedit_.c_str(); preedit_offset = static_cast(g_utf8_pointer_to_offset( preedit_text, preedit_text + preedit_cursor_)); preedit_chars = static_cast(g_utf8_strlen( preedit_text, preedit_.length())); } int password_char_length = static_cast(password_char_.length()); if (text_index < cursor_) return offset * password_char_length; if (text_index == cursor_ && consider_preedit_cursor) return (offset + preedit_offset) * password_char_length; return (offset + preedit_chars) * password_char_length; } int TextEntry::LayoutIndexToTextIndex(int layout_index) { if (visible_) { if (layout_index < cursor_) return layout_index; int preedit_length = static_cast(preedit_.length()); if (layout_index >= cursor_ + preedit_length) return layout_index - preedit_length; return cursor_; } int password_char_length = static_cast(password_char_.length()); nuxAssert(layout_index % password_char_length == 0); int offset = layout_index / password_char_length; const char *text = text_.c_str(); int cursor_offset = static_cast( g_utf8_pointer_to_offset(text, text + cursor_)); int preedit_chars = static_cast( g_utf8_strlen(preedit_.c_str(), preedit_.length())); if (offset < cursor_offset) return static_cast(g_utf8_offset_to_pointer(text, offset) - text); if (offset >= cursor_offset + preedit_chars) return static_cast( g_utf8_offset_to_pointer(text, offset - preedit_chars) - text); return cursor_; } int TextEntry::GetCharLength(int index) { const char *text = text_.c_str(); const char *ptr = text + index; const char *end = text + text_.length(); const char *next = g_utf8_find_next_char(ptr, end); return static_cast(next ? static_cast(next - ptr) : end - ptr); } int TextEntry::GetPrevCharLength(int index) { const char *text = text_.c_str(); const char *ptr = text + index; const char *prev = g_utf8_find_prev_char(text, ptr); return static_cast(prev ? static_cast(ptr - prev) : ptr - text); } void TextEntry::EnterText(const char *str) { if (readonly_ || !str || !*str) return; if (GetSelectionBounds(NULL, NULL)) { DeleteSelection(); } else if (overwrite_ && cursor_ != static_cast(text_.length())) { DeleteText(cursor_, cursor_ + GetCharLength(cursor_)); } std::string tmp_text; if (!multiline_) { tmp_text = CleanupLineBreaks(str); str = tmp_text.c_str(); } const char *end = NULL; g_utf8_validate(str, -1, &end); if (end > str) { size_t len = end - str; text_.insert(cursor_, str, len); cursor_ += static_cast(len); selection_bound_ += static_cast(len); } ResetLayout(); text_input_mode_ = true; text_changed.emit(this); } void TextEntry::DeleteText(int start, int end) { if (readonly_) return; int text_length = static_cast(text_.length()); if (start < 0) start = 0; else if (start > text_length) start = text_length; if (end < 0) end = 0; else if (end > text_length) end = text_length; if (start > end) std::swap(start, end); else if (start == end) return; text_.erase(start, end - start); if (cursor_ >= end) cursor_ -= (end - start); if (selection_bound_ >= end) selection_bound_ -= (end - start); ResetLayout(); text_input_mode_ = true; text_changed.emit(this); } void TextEntry::SelectWord() { int selection_bound = MoveWords(cursor_, -1); int cursor = MoveWords(selection_bound, 1); SetSelectionBounds(selection_bound, cursor); } void TextEntry::SelectLine() { int selection_bound = MoveLineEnds(cursor_, -1); int cursor = MoveLineEnds(selection_bound, 1); SetSelectionBounds(selection_bound, cursor); } void TextEntry::Select(int start, int end) { int text_length = static_cast(text_.length()); if (start == -1) start = text_length; if (end == -1) end = text_length; start = Clamp(start, 0, text_length); end = Clamp(end, 0, text_length); SetSelectionBounds(start, end); QueueRefresh(false, true); } void TextEntry::SelectAll() { SetSelectionBounds(0, static_cast(text_.length())); QueueRefresh(false, true); } CairoGraphics::Alignment TextEntry::GetAlign() const { return align_; } void TextEntry::SetAlign(CairoGraphics::Alignment align) { align_ = align; QueueRefresh(true, true); } bool TextEntry::im_active() { return ime_active_; } bool TextEntry::im_running() { #if defined(USE_X11) return ime_->IsConnected(); #else return false; #endif } void TextEntry::DeleteSelection() { int start, end; if (GetSelectionBounds(&start, &end)) DeleteText(start, end); } void TextEntry::CopyClipboard() { // int start, end; // if (GetSelectionBounds(&start, &end)) // { // GtkWidget *widget = GetWidgetAndCursorLocation(NULL); // if (widget) // { // if (visible_) // { // gtk_clipboard_set_text( // gtk_widget_get_clipboard(widget, GDK_SELECTION_CLIPBOARD), // text_.c_str() + start, end - start); // } // else // { // // Don't copy real content if it's in invisible. // std::string content; // int nchars = static_cast( // g_utf8_strlen(text_.c_str() + start, end - start)); // for (int i = 0; i < nchars; ++i) // content.append(password_char_); // gtk_clipboard_set_text( // gtk_widget_get_clipboard(widget, GDK_SELECTION_CLIPBOARD), // content.c_str(), static_cast(content.length())); // } // } // } } void TextEntry::CutClipboard() { CopyClipboard(); DeleteSelection(); QueueRefresh(true, true); } void TextEntry::PasteClipboard() { // GtkWidget *widget = GetWidgetAndCursorLocation(NULL); // if (widget) // { // gtk_clipboard_request_text( // gtk_widget_get_clipboard(widget, GDK_SELECTION_CLIPBOARD), // PasteCallback, this); // } } #if defined(NUX_OS_LINUX) void TextEntry::PastePrimaryClipboard() { // TODO } #endif void TextEntry::BackSpace(MovementStep step) { if (GetSelectionBounds(NULL, NULL)) { DeleteSelection(); } else { if (cursor_ == 0) return; if (step == VISUALLY) { DeleteText(cursor_ - GetPrevCharLength(cursor_), cursor_); } else if (step == WORDS) { int new_cursor; new_cursor = MoveWords(cursor_, -1); DeleteText(new_cursor, cursor_); } } } void TextEntry::Delete(MovementStep step) { if (GetSelectionBounds(NULL, NULL)) { DeleteSelection(); } else { if (cursor_ == static_cast(text_.length())) return; if (step == VISUALLY) { DeleteText(cursor_, cursor_ + GetCharLength(cursor_)); } else if (step == WORDS) { int new_cursor; new_cursor = MoveWords(cursor_, 1); DeleteText(cursor_, new_cursor); } } } void TextEntry::ToggleOverwrite() { overwrite_ = !overwrite_; } void TextEntry::UpdateSelectionRegion() { selection_region_.clear(); // Selection in a single line may be not continual, so we use pango to // get the x-ranges of each selection range in one line, and draw them // separately. int start_index, end_index; if (GetSelectionBounds(&start_index, &end_index)) { PangoLayout *layout = EnsureLayout(); PangoRectangle line_extents, pos; int draw_start, draw_end; int *ranges; int n_ranges; int n_lines = pango_layout_get_line_count(layout); start_index = TextIndexToLayoutIndex(start_index, false); end_index = TextIndexToLayoutIndex(end_index, false); for (int line_index = 0; line_index < n_lines; ++line_index) { #if PANGO_VERSION_CHECK(1,16,0) PangoLayoutLine *line = pango_layout_get_line_readonly(layout, line_index); #else PangoLayoutLine *line = pango_layout_get_line(layout, line_index); #endif if (line->start_index + line->length < start_index) continue; if (end_index < line->start_index) break; draw_start = std::max(start_index, line->start_index); draw_end = std::min(end_index, line->start_index + line->length); pango_layout_line_get_x_ranges(line, draw_start, draw_end, &ranges, &n_ranges); pango_layout_line_get_pixel_extents(line, NULL, &line_extents); pango_layout_index_to_pos(layout, line->start_index, &pos); for (int i = 0; i < n_ranges; ++i) { selection_region_.push_back(Rect( kInnerBorderX + scroll_offset_x_ + PANGO_PIXELS(ranges[i * 2]), kInnerBorderY + scroll_offset_y_ + PANGO_PIXELS(pos.y), PANGO_PIXELS(ranges[i * 2 + 1] - ranges[i * 2]), line_extents.height)); } g_free(ranges); } } } void TextEntry::MoveCursor(MovementStep step, int count, bool extend_selection) { ResetImContext(); int new_cursor = 0; // Clear selection first if not extend it. if (!extend_selection) { selection_changed_ = true; cursor_moved_ = true; selection_bound_ = cursor_; cursor_moved.emit(cursor_); } // Calculate the new offset after motion. switch(step) { case VISUALLY: new_cursor = MoveVisually(cursor_, count); break; case WORDS: new_cursor = MoveWords(cursor_, count); break; case DISPLAY_LINES: new_cursor = MoveDisplayLines(cursor_, count); break; case DISPLAY_LINE_ENDS: new_cursor = MoveLineEnds(cursor_, count); break; case PAGES: new_cursor = MovePages(cursor_, count); break; case BUFFER: nuxAssert(count == -1 || count == 1); new_cursor = static_cast(count == -1 ? 0 : text_.length()); break; } if (extend_selection) SetSelectionBounds(selection_bound_, new_cursor); else SetCursor(new_cursor); QueueRefresh(true, true); } int TextEntry::MoveVisually(int current_index, int count) { nuxAssert(current_index >= 0 && current_index <= static_cast(text_.length())); nuxAssert(count); nuxAssert(preedit_.length() == 0); PangoLayout* layout = EnsureLayout(); const char* text = pango_layout_get_text(layout); int index = TextIndexToLayoutIndex(current_index, false); int new_index = 0; int new_trailing = 0; while (count != 0) { if (count > 0) { --count; pango_layout_move_cursor_visually(layout, true, index, 0, 1, &new_index, &new_trailing); } else if (count < 0) { ++count; pango_layout_move_cursor_visually(layout, true, index, 0, -1, &new_index, &new_trailing); } index = new_index; if (index < 0 || index == G_MAXINT) return current_index; index = static_cast(g_utf8_offset_to_pointer(text + index, new_trailing) - text); } return LayoutIndexToTextIndex(index); } int TextEntry::MoveWords(int current_index, int count) { nuxAssert(current_index >= 0 && current_index <= static_cast(text_.length())); nuxAssert(count); nuxAssert(preedit_.length() == 0); if (!visible_) { return static_cast(count > 0 ? text_.length() : 0); } // The cursor movement direction shall be determined by the direction of // current text line. PangoLayout* layout = EnsureLayout(); int n_log_attrs; PangoLogAttr* log_attrs; pango_layout_get_log_attrs(layout, &log_attrs, &n_log_attrs); const char* text = pango_layout_get_text(layout); int index = TextIndexToLayoutIndex(current_index, false); int line_index; pango_layout_index_to_line_x(layout, index, FALSE, &line_index, NULL); // Weird bug: line_index here may be >= than line count? int line_count = pango_layout_get_line_count(layout); if (line_index >= line_count) { line_index = line_count - 1; } #if PANGO_VERSION_CHECK(1,16,0) PangoLayoutLine* line = pango_layout_get_line_readonly(layout, line_index); #else PangoLayoutLine* line = pango_layout_get_line(layout, line_index); #endif bool rtl = (line->resolved_dir == PANGO_DIRECTION_RTL); const char* ptr = text + index; int offset = static_cast(g_utf8_pointer_to_offset(text, ptr)); while (count != 0) { if (((rtl && count < 0) || (!rtl && count > 0)) && *ptr) { if (log_attrs[offset].is_white) { while (ptr && *ptr && log_attrs[offset].is_white) { ptr = g_utf8_find_next_char(ptr, NULL); ++offset; } } else { if (ptr && *ptr) { ptr = g_utf8_find_next_char(ptr, NULL); ++offset; } } while (ptr && *ptr) { ptr = g_utf8_find_next_char(ptr, NULL); ++offset; if (log_attrs[offset].is_word_start || log_attrs[offset].is_word_end) break; } if (!ptr) { ptr = text; while (*ptr) ++ptr; } } else if (((rtl && count > 0) || (!rtl && count < 0)) && (ptr > text)) { if (offset > 0 && log_attrs[offset - 1].is_white) { while (ptr && offset > 0 && log_attrs[offset - 1].is_white) { ptr = g_utf8_find_prev_char(text, ptr); --offset; } } else { if (ptr) { ptr = g_utf8_find_prev_char(text, ptr); --offset; } } while (ptr /*&& *ptr*/) //fix: when at the end of the string, allow ctrl+left arrow to move backward to the start/end of the previous word. { ptr = g_utf8_find_prev_char(text, ptr); --offset; if (log_attrs[offset].is_word_start || log_attrs[offset].is_word_end) break; } if (!ptr) ptr = text; } else { break; } if (count > 0) --count; else ++count; } return LayoutIndexToTextIndex(static_cast(ptr - text)); } int TextEntry::MoveDisplayLines(int current_index, int count) { nuxAssert(current_index >= 0 && current_index <= static_cast(text_.length())); nuxAssert(count); nuxAssert(preedit_.length() == 0); PangoLayout *layout = EnsureLayout(); const char *text = pango_layout_get_text(layout); int index = TextIndexToLayoutIndex(current_index, false); int n_lines = pango_layout_get_line_count(layout); int line_index = 0; int x_off = 0; PangoRectangle rect; // Find the current cursor X position in layout pango_layout_index_to_line_x(layout, index, FALSE, &line_index, &x_off); // Weird bug: line_index here may be >= than line count? if (line_index >= n_lines) { line_index = n_lines - 1; } pango_layout_get_cursor_pos(layout, index, &rect, NULL); x_off = rect.x; line_index += count; if (line_index < 0) { return 0; } else if (line_index >= n_lines) { return static_cast(text_.length()); } int trailing; #if PANGO_VERSION_CHECK(1,16,0) PangoLayoutLine *line = pango_layout_get_line_readonly(layout, line_index); #else PangoLayoutLine *line = pango_layout_get_line(layout, line_index); #endif // Find out the cursor x offset related to the new line position. if (line->resolved_dir == PANGO_DIRECTION_RTL) { pango_layout_get_cursor_pos(layout, line->start_index + line->length, &rect, NULL); } else { pango_layout_get_cursor_pos(layout, line->start_index, &rect, NULL); } // rect.x is the left edge position of the line in the layout x_off -= rect.x; if (x_off < 0) x_off = 0; pango_layout_line_x_to_index(line, x_off, &index, &trailing); index = static_cast(g_utf8_offset_to_pointer(text + index, trailing) - text); return LayoutIndexToTextIndex(index); } int TextEntry::MovePages(int current_index, int count) { nuxAssert(current_index >= 0 && current_index <= static_cast(text_.length())); nuxAssert(count); nuxAssert(preedit_.length() == 0); // Transfer pages to display lines. PangoLayout *layout = EnsureLayout(); int layout_height; pango_layout_get_pixel_size(layout, NULL, &layout_height); int n_lines = pango_layout_get_line_count(layout); int line_height = layout_height / n_lines; int page_lines = (GetBaseHeight() - kInnerBorderY * 2) / line_height; return MoveDisplayLines(current_index, count * page_lines); } int TextEntry::MoveLineEnds(int current_index, int count) { nuxAssert(current_index >= 0 && current_index <= static_cast(text_.length())); nuxAssert(count); nuxAssert(preedit_.length() == 0); PangoLayout *layout = EnsureLayout(); int index = TextIndexToLayoutIndex(current_index, false); int line_index = 0; // Find current line pango_layout_index_to_line_x(layout, index, FALSE, &line_index, NULL); // Weird bug: line_index here may be >= than line count? int line_count = pango_layout_get_line_count(layout); if (line_index >= line_count) { line_index = line_count - 1; } // #if PANGO_VERSION_CHECK(1,16,0) // PangoLayoutLine *line = pango_layout_get_line_readonly(layout, line_index); // #else PangoLayoutLine *line = pango_layout_get_line(layout, line_index); // #endif if (line->length == 0) return current_index; if ((line->resolved_dir == PANGO_DIRECTION_RTL && count < 0) || (line->resolved_dir != PANGO_DIRECTION_RTL && count > 0)) { index = line->start_index + line->length; } else { index = line->start_index; } return LayoutIndexToTextIndex(index); } void TextEntry::SetCursor(int cursor) { if (cursor != cursor_) { ResetImContext(); // If there was a selection range, then the selection range will be cleared. // Then content_modified_ shall be set to true to force redrawing the text. if (cursor_ != selection_bound_) selection_changed_ = true; cursor_ = cursor; selection_bound_ = cursor; cursor_moved_ = true; cursor_moved.emit(cursor); } } int TextEntry::XYToTextIndex(int x, int y) { int width, height; PangoLayout *layout = EnsureLayout(); const char *text = pango_layout_get_text(layout); pango_layout_get_pixel_size(layout, &width, &height); if (y < 0) { return 0; } else if (y >= height) { return static_cast(text_.length()); } int trailing; int index; pango_layout_xy_to_index(layout, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing); index = static_cast( g_utf8_offset_to_pointer(text + index, trailing) - text); index = LayoutIndexToTextIndex(index); // Adjust the offset if preedit is not empty and if the offset is after // current cursor. int preedit_length = static_cast(preedit_.length()); if (preedit_length && index > cursor_) { if (index >= cursor_ + preedit_length) index -= preedit_length; else index = cursor_; } return Clamp(index, 0, static_cast(text_.length())); } bool TextEntry::GetSelectionBounds(int* start, int* end) const { if (start) { *start = std::min(selection_bound_, cursor_); } if (end) { *end = std::max(selection_bound_, cursor_); } return (selection_bound_ != cursor_); } void TextEntry::SetSelectionBounds(int selection_bound, int cursor) { if (selection_bound_ != selection_bound || cursor_ != cursor) { selection_changed_ = true; selection_bound_ = selection_bound; if (cursor_ != cursor) { cursor_ = cursor; cursor_moved_ = true; cursor_moved.emit(cursor); } //ResetImContext(); } } void TextEntry::SetFontFamily(const char *font) { font_family_ = font; QueueRefresh(true, true); } void TextEntry::SetFontSize(double font_size) { font_size_ = font_size; QueueRefresh(true, true); } void TextEntry::SetFontOptions(const cairo_font_options_t *options) { g_return_if_fail(options); cairo_font_options_destroy(font_options_); font_options_ = cairo_font_options_copy(options); QueueRefresh(true, true); } bool TextEntry::InspectKeyEvent(unsigned int /* eventType */, unsigned int /* key_sym */, const char* /* character */) { nux::Event const& cur_event = GetGraphicsDisplay()->GetCurrentEvent(); return InspectKeyEvent(cur_event); } bool TextEntry::InspectKeyEvent(nux::Event const& event) { unsigned int eventType = event.type; unsigned int key_sym = event.GetKeySym(); #if defined(USE_X11) if (im_running()) { // Always allow IBus hotkey events if (ime_->IsHotkeyEvent(static_cast(eventType), key_sym, event.key_modifiers)) return true; } #endif // Ignore events when Alt or Super are pressed if (event.GetKeyModifierState(KEY_MODIFIER_SUPER) || event.GetKeyModifierState(KEY_MODIFIER_ALT)) return false; if ((eventType == NUX_KEYDOWN) && (key_nav_mode_ == true) && (text_input_mode_ == false) && (ime_active_ == false)) { if (key_sym == NUX_VK_ENTER || key_sym == NUX_KP_ENTER || key_sym == NUX_VK_UP || key_sym == NUX_VK_DOWN || key_sym == NUX_VK_LEFT || key_sym == NUX_VK_RIGHT || key_sym == NUX_VK_LEFT_TAB || key_sym == NUX_VK_TAB || key_sym == NUX_VK_ESCAPE) { if (key_sym == NUX_VK_LEFT || key_sym == NUX_VK_RIGHT || key_sym == NUX_VK_ENTER || key_sym == NUX_KP_ENTER) { return true; } if (multiline_ && (key_sym == NUX_VK_UP)) { // Navigate between the lines of the text entry. // This will move the cursor one line up. return true; } if (multiline_ && (key_sym == NUX_VK_DOWN)) { // Navigate between the lines of the text entry. // This will move the cursor one line down. return true; } if ((!multiline_) && (!lose_key_focus_on_key_nav_direction_up_) && (key_sym == NUX_VK_UP)) { // By returning true, the text entry signals that it want to receive the signal for this event. // Otherwise, the parent view of the text entry would be looking for another view to receive keynav focus to. return true; } if ((!multiline_) && (!lose_key_focus_on_key_nav_direction_down_) && (key_sym == NUX_VK_DOWN)) { // By returning true, the text entry signals that it want to receive the signal for this event. // Otherwise, the parent view of the text entry would be looking for another view to receive keynav focus to. return true; } return false; } } if ((eventType == NUX_KEYDOWN) && (key_nav_mode_ == true) && (text_input_mode_ == true) && (ime_active_ == false)) { // Enable to exit the TextEntry when in write mode(hack for unity dash) if (key_sym == NUX_VK_UP || key_sym == NUX_VK_DOWN || key_sym == NUX_VK_ESCAPE) { if ((!multiline_) && (!lose_key_focus_on_key_nav_direction_up_) && NUX_VK_UP) { // By returning true, the text entry signals that it want to receive the signal for this event. // Otherwise, the parent view of the text entry would be looking for another view to receive keynav focus to. return true; } if ((!multiline_) && (!lose_key_focus_on_key_nav_direction_down_) && NUX_VK_DOWN) { // By returning true, the text entry signals that it want to receive the signal for this event. // Otherwise, the parent view of the text entry would be looking for another view to receive keynav focus to. return true; } return false; } } if ((eventType == NUX_KEYDOWN) && (key_nav_mode_ == false) && (text_input_mode_ == false)) { return false; } return true; } /// Public API void TextEntry::MoveCursorToLineStart() { MoveCursor(DISPLAY_LINE_ENDS, -1, 0); } void TextEntry::MoveCursorToLineEnd() { MoveCursor(DISPLAY_LINE_ENDS, 1, 0); } void TextEntry::SetLoseKeyFocusOnKeyNavDirectionUp(bool b) { lose_key_focus_on_key_nav_direction_up_ = b; } bool TextEntry::GetLoseKeyFocusOnKeyNavDirectionUp() const { return lose_key_focus_on_key_nav_direction_up_; } void TextEntry::SetLoseKeyFocusOnKeyNavDirectionDown(bool b) { lose_key_focus_on_key_nav_direction_down_ = b; } bool TextEntry::GetLoseKeyFocusOnKeyNavDirectionDown() const { return lose_key_focus_on_key_nav_direction_down_; } void TextEntry::SetToggleCursorVisibilityOnKeyFocus(bool b) { if (cursor_visible_on_key_focus_only_ == b) return; cursor_visible_on_key_focus_only_ = b; if (cursor_visible_on_key_focus_only_) { if (!focused_) { if (cursor_blink_timer_) { g_source_remove(cursor_blink_timer_); cursor_blink_timer_ = 0; } cursor_visible_ = false; QueueDraw(); } } else { if (!focused_) { QueueCursorBlink(); } } } bool TextEntry::GetToggleCursorVisibilityOnKeyFocus() const { return cursor_visible_on_key_focus_only_; } bool TextEntry::IsInTextInputMode() const { return text_input_mode_; } void TextEntry::SetVisibility(bool visible) { if (visible_ != visible) { visible_ = visible; if (!readonly_) { if (focused_) { //gtk_im_context_focus_out(im_context_); } //InitImContext(); ResetPreedit(); if (focused_) { //gtk_im_context_focus_in(im_context_); } } ResetLayout(); } } typedef unsigned short UTF16Char; typedef unsigned int UTF32Char; typedef unsigned char UTF8Char; static const UTF8Char kTrailingBytesForUTF8[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; // http://google-gadgets-for-linux.googlecode.com/svn-history/r97/trunk/ggadget/unicode_utils.cc size_t GetUTF8CharLength(const char *src) { return src ? (kTrailingBytesForUTF8[static_cast(*src)] + 1) : 0; } bool IsLegalUTF8Char(const char *src, size_t length) { if (!src || !length) return false; const UTF8Char *srcptr = reinterpret_cast(src); UTF8Char a; UTF8Char ch = *srcptr; srcptr += length; switch (length) { default: return false; // Everything else falls through when "true"... case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; [[gnu::fallthrough]]; case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; [[gnu::fallthrough]]; case 2: if ((a = (*--srcptr)) > 0xBF) return false; switch (ch) { // No fall-through in this inner switch case 0xE0: if (a < 0xA0) return false; break; case 0xED: if (a > 0x9F) return false; break; case 0xF0: if (a < 0x90) return false; break; case 0xF4: if (a > 0x8F) return false; break; default: if (a < 0x80) return false; } [[gnu::fallthrough]]; case 1: if (ch >= 0x80 && ch < 0xC2) return false; [[gnu::fallthrough]]; } if (ch > 0xF4) return false; return true; } void TextEntry::SetPasswordChar(const char* c) { if (c == NULL || *c == 0 || !IsLegalUTF8Char(c, GetUTF8CharLength(c))) { password_char_.clear(); } else { password_char_.assign(c, GetUTF8CharLength(c)); } QueueRefresh(true, true); } std::string TextEntry::GetPasswordChar() { return password_char_; } void TextEntry::SetPasswordMode(bool visible) { SetVisibility(!visible); } bool TextEntry::PasswordMode() const { return !visible_; } } nux-4.0.8+18.10.20180623/Nux/TextEntry.h0000644000000000000000000004276313313373365013506 0ustar #ifndef TEXTENTRY_H #define TEXTENTRY_H // Heavily inspired from google gadget code /* * Copyright 2011-2013 Canonical Ltd. * Copyright 2010 Inalogic Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0(the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "cairo/cairo.h" #include "pango/pango.h" #include "pango/pangocairo.h" #include "NuxGraphics/CairoGraphics.h" namespace nux { class CairoGraphics; class IBusIMEContext; class CairoFont { public: enum Style { STYLE_NORMAL, STYLE_ITALIC }; /** * Enum used to specify font weight. */ enum Weight { WEIGHT_NORMAL, WEIGHT_BOLD }; /** * Constructor for CairoFont. Takes a PangoFontDescription object and its * ownership. Will free the PangoFontDescription object on destruction. */ CairoFont(const std::string &family, /*PangoFontDescription *font,*/ double size, Style style, Weight weight); virtual ~CairoFont(); virtual Style GetStyle() const {return style_;} virtual Weight GetWeight() const {return weight_;} virtual double GetPointSize() const {return size_;} virtual void Destroy() {delete this;} const PangoFontDescription *GetFontDescription() const {return font_;} private: PangoFontDescription *font_; double size_; Style style_; Weight weight_; }; class TextEntry: public View { NUX_DECLARE_OBJECT_TYPE(TextEntry, View); public: TextEntry(const char* text, NUX_FILE_LINE_PROTO); ~TextEntry(); Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); virtual void Draw(GraphicsEngine& graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine& graphics_engine, bool force_draw); void PreLayoutManagement(); long PostLayoutManagement(long layoutResult); // Receivers void RecvMouseDoubleClick(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvKeyEvent( unsigned long eventType , /*event type*/ unsigned long keysym , /*event keysym*/ unsigned long state , /*event state*/ const char* character , /*character*/ unsigned short keyCount /*key repeat count*/); void RecvStartKeyFocus(); void RecvEndKeyFocus(); bool _size_match_text; BaseTexture *_texture2D; void MainDraw(); void ProcessMouseEvent(int event_type, int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void ProcessKeyEvent ( unsigned long eventType , /*event type*/ unsigned long keysym , /*event keysym*/ unsigned long state , /*event state*/ const char* character , /*character*/ unsigned short keyCount /*key repeat count*/); void FocusInx(); void FocusOutx(); //! Text changed signal /*! This signal is emitted when the text has changed. */ sigc::signal text_changed; sigc::signal activated; sigc::signal cursor_moved; void SetText(const char* text); std::string const& GetText() const; std::string GetTextSelection() const; void SetCompletion(const char* text); // Should use std::string, does not for consistancy std::string const& GetCompletion() const; void SetCompletionColor(const Color& color); Color const& GetCompletionColor() const; void SetTextColor(const Color& color); Color GetTextColor() const; void SetFontFamily(const char* font); void SetFontSize(double font_size); void SetFontOptions(const cairo_font_options_t* options); /** Select text between start and end. */ void Select(int start, int end); /** Select all text */ void SelectAll(); CairoGraphics::Alignment GetAlign() const; void SetAlign(CairoGraphics::Alignment align); bool im_active(); bool im_running(); void MoveCursorToLineStart(); void MoveCursorToLineEnd(); void SetToggleCursorVisibilityOnKeyFocus(bool b); bool GetToggleCursorVisibilityOnKeyFocus() const; /*! When the text entry is in single line mode, the keyboard arrow up/down may be used to navigate to another view. If the parameter of this function is set to true then the text entry returns false on NUX_VK_UP in InspectKeyEvent(). This allows the parent of the text entry to look for another view that can receive the keyboard focus. The default value is true.\n In multi-line mode, keyboard arrow up/down are used to navigate in the text. @param b True to allow the key navigation to move away from the text entry on NUX_VK_UP. */ void SetLoseKeyFocusOnKeyNavDirectionUp(bool b); bool GetLoseKeyFocusOnKeyNavDirectionUp() const; /*! When the text entry is in single line mode, the keyboard arrow up/down may be used to navigate to another view. If the parameter of this function is set to true then the text entry returns false on NUX_VK_DOWN in InspectKeyEvent(). This allows the parent of the text entry to look for another view that can receive the keyboard focus. The default value is true.\n In multi-line mode, keyboard arrow up/down are used to navigate in the text. @param b True to allow the key navigation to move away from the text entry on NUX_VK_DOWN. */ void SetLoseKeyFocusOnKeyNavDirectionDown(bool b); bool GetLoseKeyFocusOnKeyNavDirectionDown() const; /*! Return True if the text has been modified after the text entry has received the keyboard focus.\n If the text entry already has characters typed in and it gets the keyboard focus, this function return false while the text has not been modified. The text can be modified either by typing new characters or addind text through TextEntry::SetText, TextEntry::EnterText, TextEntry::DeleteText. If this text entry does not have the keyboard focus, this function returns false. @return True after the text entry has received the keyboard focus and text has been typed in. */ bool IsInTextInputMode() const; /*! Insert text at current caret position. */ void EnterText(const char* str); /*! Delete text in a specified range, in number of characters. */ void DeleteText(int start, int end); void SetPasswordMode(bool visible); void SetVisibility(bool visible); void SetPasswordChar(const char* c); bool PasswordMode() const; std::string GetPasswordChar(); void PreeditStarted(); void UpdatePreedit(std::string const& preedit, int cursor); void UpdatePreeditAttribs(PangoAttrList* list); void ClearPreedit(); protected: bool _block_focus; // used to selectively ignore focus keyevents virtual void GeometryChanged(bool position_has_changed, bool size_has_changed); /** * Enum used to specify different motion types. */ enum MovementStep { VISUALLY, WORDS, DISPLAY_LINES, DISPLAY_LINE_ENDS, PAGES, BUFFER }; /** * Enum used for the search state of the compose list */ enum SearchState { NO_MATCH, PARTIAL, MATCH }; /** Checks for possible composition sequences */ bool IsInitialCompositionKeySym(unsigned long keysym) const; bool IsInCompositionMode() const; bool HandleComposition(unsigned long keysym); SearchState GetCompositionForList(std::vector const& input, std::string& composition); void QueueTextDraw(); /** Remove the cached layout. */ void ResetLayout(); /** * Create pango layout on-demand. If the layout is not changed, return the * cached one. */ PangoLayout* EnsureLayout(); /** Create a new layout containning current edit content */ PangoLayout* CreateLayout(); /** Create cairo canvas on-demand. */ CairoGraphics* EnsureCanvas(); /** Adjust the scroll information */ void AdjustScroll(); /** * Send out a request to refresh all informations of the edit control * and queue a draw request. * If @c relayout is true then the layout will be regenerated. * */ void QueueRefresh(bool relayout, bool adjust_scroll); /** Reset the input method context */ void ResetImContext(); /** Reset preedit text */ void ResetPreedit(); /** Send out a request to blink the cursor if necessary */ void QueueCursorBlink(); static bool CursorBlinkCallback(TextEntry* data); void ShowCursor(); void HideCursor(); /** Draw the Cursor to the canvas */ void DrawCursor(CairoGraphics* canvas); /** Draw the text to the canvas */ virtual void DrawText(CairoGraphics* canvas); void GetCursorRects(Rect* strong, Rect* weak); void UpdateCursorRegion(); void UpdateSelectionRegion(); /** Move cursor */ void MoveCursor(MovementStep step, int count, bool extend_selection); /** Move cursor visually, meaning left or right */ int MoveVisually(int current_pos, int count); /** Move cursor in words */ int MoveWords(int current_pos, int count); /** Move cursor in display lines */ int MoveDisplayLines(int current_pos, int count); /** Move cursor in pages */ int MovePages(int current_pos, int count); /** Move cursor to the beginning or end of a display line */ int MoveLineEnds(int current_pos, int count); /** Set the current cursor offset, in number of characters. */ void SetCursor(int cursor); /** Get the most reasonable character offset according to the pixel * coordinate in the layout */ int XYToTextIndex(int x, int y); /** Get the offset range that is currently selected,in number of characters.*/ bool GetSelectionBounds(int* start, int* end) const; /** Set the offest range that should be selected, in number of characters. */ void SetSelectionBounds(int selection_bound, int cursor); /** Convert index in text_ into index in layout text. */ int TextIndexToLayoutIndex(int text_index, bool consider_preedit_cursor); /** Convert index in layout text into index in text_. */ int LayoutIndexToTextIndex(int layout_index); /** Get char length at index, in number of bytes. */ int GetCharLength(int index); /** Get previous char length before index, in number of bytes. */ int GetPrevCharLength(int index); /** Select the current word under cursor */ void SelectWord(); /** Select the current display line under cursor */ void SelectLine(); /** Delete the text that is currently selected */ void DeleteSelection(); /** Cut the current selected text to the clipboard */ virtual void CutClipboard(); /** Copy the current selected text to the clipboard */ virtual void CopyClipboard(); /** Paste the text in the clipboard to current offset */ virtual void PasteClipboard(); #if defined(NUX_OS_LINUX) /** Paste the text in the primary clipboard to current offset */ virtual void PastePrimaryClipboard(); #endif /** Delete a character before the offset of the cursor */ void BackSpace(MovementStep step); /** Delete a character at the offset of the cursor */ void Delete(MovementStep step); /** Switch between the overwrite mode and the insert mode*/ void ToggleOverwrite(); /** Gets the color of selection background. */ Color GetSelectionBackgroundColor(); /** Gets the color of selection text. */ Color GetSelectionTextColor(); /** * Gets the cursor location in pango layout. The unit is pixel. */ void GetCursorLocationInLayout(int* strong_x, int* strong_y, int* strong_height, int* weak_x, int* weak_y, int* weak_height); /** The CairoCanvas which hold cairo_t inside */ CairoGraphics* canvas_; /** The cached Pango Layout */ PangoLayout* cached_layout_; /** The text content of the edit control */ std::string text_; /** The preedit text of the edit control */ std::string preedit_; /** Attribute list of the preedit text */ PangoAttrList* preedit_attrs_; /** * The character that should be displayed in invisible mode. * If this is empty, then the edit control is visible */ std::string password_char_; /** The completion string */ std::string completion_; /** The completion colour */ Color completion_color_; /** Last time of mouse double click event. */ unsigned long long last_dblclick_time_; /** The current cursor position in number of bytes. */ int cursor_; /** * The preedit cursor position within the preedit string, * in number of bytes. */ int preedit_cursor_; /** * The current selection bound in number of bytes, * range between cursor_ and selection_bound_ are selected. */ int selection_bound_; /** X offset of current scroll, in pixels */ int scroll_offset_x_; /** Y offset of current scroll, in pixels */ int scroll_offset_y_; /** Timer id of cursor blink callback */ int cursor_blink_timer_; /** * Indicates the status of cursor blinking, * 0 means hide cursor * otherwise means show cursor. * The maximum value would be 2, and decrased by one in each cursor blink * callback, then there would be 2/3 visible time and 1/3 invisible time. */ int cursor_blink_status_; /*! Whether the text is visible, or its characters are masked by a default char (password mode). */ bool visible_; /** Whether the edit control is focused */ bool focused_; /** Whether the input method should be reset */ bool need_im_reset_; /** Whether the keyboard in overwrite mode */ bool overwrite_; /** Whether the button click should select words */ bool select_words_; /** Whether the button click should select lines */ bool select_lines_; /** Whether the left button is pressed */ bool button_; /** Whether the text should be bold */ bool bold_; /** Whether the text should be underlined */ bool underline_; /** Whether the text should be struck-out */ bool strikeout_; /** Whether the text should be italic */ bool italic_; /** Whether the text could be shown in multilines */ bool multiline_; /** Whether the text should be wrapped */ bool wrap_; /** whether the cursor should be displayed */ bool cursor_visible_; /** whether the edit control is readonly */ bool readonly_; /** * Indicates if the content of the edit control has been modified * since last draw */ bool content_modified_; /** Indicates if the selection region has been changed since last draw. */ bool selection_changed_; /** Indicates if the cursor position has been moved since last draw. */ bool cursor_moved_; /** Indicates if the canvas cache needs updating. */ bool update_canvas_; /** The font family of the text */ std::string font_family_; /** The font size of the text */ double font_size_; cairo_font_options_t* font_options_; double font_dpi_; /** The text color of the edit control */ Color _text_color; CairoGraphics::Alignment align_; #if defined(USE_X11) Cursor caret_cursor_; #endif std::list last_selection_region_; std::list selection_region_; std::list last_cursor_region_; std::list cursor_region_; #if defined(USE_X11) IBusIMEContext* ime_; friend class IBusIMEContext; #endif bool ime_active_; bool text_input_mode_; //!< Transient state of the TextEntry. \sa IsInTextInputMode. bool key_nav_mode_; bool lose_key_focus_on_key_nav_direction_up_; bool lose_key_focus_on_key_nav_direction_down_; bool cursor_visible_on_key_focus_only_; std::vector composition_list_; virtual bool InspectKeyEvent(Event const& event); virtual bool InspectKeyEvent(unsigned int eventType, unsigned int keysym, const char* character); }; } #endif // TEXTENTRY_H nux-4.0.8+18.10.20180623/Nux/TextEntryComposeSeqs.h0000644000000000000000000131750013313373365015663 0ustar /* * Copyright 2010-2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * Jay Taoko * Marco Trevisan * */ #ifndef TEXT_ENTRY_COMPOSE_SEQS_H #define TEXT_ENTRY_COMPOSE_SEQS_H namespace nux { /* This list has been generated using the script ./tools/compose_key_list_generator.py * with this file as input: * http://cgit.freedesktop.org/xorg/lib/libX11/plain/nls/en_US.UTF-8/Compose.pre */ struct ComposeSequence { const static unsigned int MAX_SYMBOLS = 8; KeySym symbols[MAX_SYMBOLS]; const char* result; }; static const size_t COMPOSE_SEQUENCES_SIZE = 4444; static const ComposeSequence COMPOSE_SEQUENCES[] = { {{XK_dead_hook, XK_B, XK_VoidSymbol}, "Ɓ"}, // U0181 | LATIN CAPITAL LETTER B WITH HOOK {{XK_Multi_key, XK_f, XK_l, XK_VoidSymbol}, "fl"}, // Ufb02 | LATIN SMALL LIGATURE FL {{XK_dead_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, // U1F85 | GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾅ"}, {{XK_dead_belowdot, XK_B, XK_VoidSymbol}, "Ḅ"}, // U1E04 | LATIN CAPITAL LETTER B WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_B, XK_VoidSymbol}, "Ḅ"}, {{XK_dead_acute, XK_C, XK_VoidSymbol}, "Ć"}, // U0106 | LATIN CAPITAL LETTER C WITH ACUTE {{XK_Multi_key, XK_acute, XK_C, XK_VoidSymbol}, "Ć"}, {{XK_Multi_key, XK_apostrophe, XK_C, XK_VoidSymbol}, "Ć"}, {{XK_Multi_key, XK_C, XK_apostrophe, XK_VoidSymbol}, "Ć"}, {{XK_dead_caron, XK_minus, XK_VoidSymbol}, "₋"}, // U208B | SUBSCRIPT MINUS {{XK_dead_grave, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἂ"}, // U1F0A | GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἂ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἂ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἂ"}, {{XK_dead_doublegrave, XK_O, XK_VoidSymbol}, "Ȍ"}, // U020C | LATIN CAPITAL LETTER O WITH DOUBLE GRAVE {{XK_dead_abovedot, XK_y, XK_VoidSymbol}, "ẏ"}, // U1E8F | LATIN SMALL LETTER Y WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_y, XK_VoidSymbol}, "ẏ"}, {{XK_Multi_key, XK_C, XK_equal, XK_VoidSymbol}, "€"}, // EuroSign | EURO SIGN {{XK_Multi_key, XK_equal, XK_C, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_c, XK_equal, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_equal, XK_c, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_E, XK_equal, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_equal, XK_E, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_e, XK_equal, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_equal, XK_e, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_Cyrillic_ES, XK_equal, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_equal, XK_Cyrillic_ES, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_Cyrillic_IE, XK_equal, XK_VoidSymbol}, "€"}, {{XK_Multi_key, XK_equal, XK_Cyrillic_IE, XK_VoidSymbol}, "€"}, {{XK_dead_currency, XK_e, XK_VoidSymbol}, "€"}, {{XK_dead_hook, XK_F, XK_VoidSymbol}, "Ƒ"}, // U0191 | LATIN CAPITAL LETTER F WITH HOOK {{XK_dead_voiced_sound, XK_kana_HE, XK_VoidSymbol}, "ベ"}, // U30D9 | KATAKANA LETTER BE {{XK_Multi_key, XK_slash, XK_Cyrillic_ghe, XK_VoidSymbol}, "ғ"}, // U0493 | CYRILLIC SMALL LETTER GHE WITH STROKE {{XK_Multi_key, XK_KP_Divide, XK_Cyrillic_ghe, XK_VoidSymbol}, "ғ"}, {{XK_Multi_key, XK_parenleft, XK_L, XK_parenright, XK_VoidSymbol}, "Ⓛ"}, // U24C1 | CIRCLED LATIN CAPITAL LETTER L {{XK_dead_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, // U1F95 | GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾕ"}, {{XK_dead_grave, XK_Emacron, XK_VoidSymbol}, "Ḕ"}, // U1E14 | LATIN CAPITAL LETTER E WITH MACRON AND GRAVE {{XK_Multi_key, XK_grave, XK_Emacron, XK_VoidSymbol}, "Ḕ"}, {{XK_dead_grave, XK_dead_macron, XK_E, XK_VoidSymbol}, "Ḕ"}, {{XK_dead_grave, XK_Multi_key, XK_macron, XK_E, XK_VoidSymbol}, "Ḕ"}, {{XK_dead_grave, XK_Multi_key, XK_underscore, XK_E, XK_VoidSymbol}, "Ḕ"}, {{XK_Multi_key, XK_grave, XK_dead_macron, XK_E, XK_VoidSymbol}, "Ḕ"}, {{XK_Multi_key, XK_grave, XK_macron, XK_E, XK_VoidSymbol}, "Ḕ"}, {{XK_Multi_key, XK_grave, XK_underscore, XK_E, XK_VoidSymbol}, "Ḕ"}, {{XK_dead_macron, XK_Egrave, XK_VoidSymbol}, "Ḕ"}, {{XK_dead_macron, XK_dead_grave, XK_E, XK_VoidSymbol}, "Ḕ"}, {{XK_Multi_key, XK_N, XK_o, XK_VoidSymbol}, "№"}, // numerosign | NUMERO SIGN {{XK_Multi_key, XK_N, XK_O, XK_VoidSymbol}, "№"}, {{XK_Multi_key, XK_Cyrillic_EN, XK_Cyrillic_o, XK_VoidSymbol}, "№"}, {{XK_Multi_key, XK_Cyrillic_EN, XK_Cyrillic_O, XK_VoidSymbol}, "№"}, {{XK_dead_acute, XK_nobreakspace, XK_VoidSymbol}, "́"}, // U0301 | COMBINING ACUTE ACCENT {{XK_dead_grave, XK_dead_psili, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἒ"}, // U1F1A | GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἒ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἒ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἒ"}, {{XK_dead_macron, XK_Cyrillic_O, XK_VoidSymbol}, "О̄"}, // CYRILLIC CAPITAL LETTER O WITH COMBINING MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_O, XK_VoidSymbol}, "О̄"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_O, XK_VoidSymbol}, "О̄"}, {{XK_dead_horn, XK_o, XK_VoidSymbol}, "ơ"}, // U01A1 | LATIN SMALL LETTER O WITH HORN {{XK_Multi_key, XK_plus, XK_o, XK_VoidSymbol}, "ơ"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_0, XK_parenright, XK_VoidSymbol}, "㉚"}, // U325A | CIRCLED NUMBER THIRTY {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_0, XK_parenright, XK_VoidSymbol}, "㉚"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_0, XK_parenright, XK_VoidSymbol}, "㉚"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_0, XK_parenright, XK_VoidSymbol}, "㉚"}, {{XK_dead_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, // U1FA5 | GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾥ"}, {{XK_dead_belowdot, XK_H, XK_VoidSymbol}, "Ḥ"}, // U1E24 | LATIN CAPITAL LETTER H WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_H, XK_VoidSymbol}, "Ḥ"}, {{XK_dead_stroke, XK_H, XK_VoidSymbol}, "Ħ"}, // U0126 | LATIN CAPITAL LETTER H WITH STROKE {{XK_Multi_key, XK_slash, XK_H, XK_VoidSymbol}, "Ħ"}, {{XK_Multi_key, XK_KP_Divide, XK_H, XK_VoidSymbol}, "Ħ"}, {{XK_Multi_key, XK_parenleft, XK_kana_SE, XK_parenright, XK_VoidSymbol}, "㋝"}, // U32DD | CIRCLED KATAKANA SE {{XK_Multi_key, XK_d, XK_equal, XK_VoidSymbol}, "₫"}, // U20ab | DONG SIGN {{XK_Multi_key, XK_equal, XK_d, XK_VoidSymbol}, "₫"}, {{XK_dead_currency, XK_d, XK_VoidSymbol}, "₫"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "Ἢ"}, // U1F2A | GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "Ἢ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "Ἢ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "Ἢ"}, {{XK_dead_acute, XK_Greek_epsilon, XK_VoidSymbol}, "έ"}, // U03AD | GREEK SMALL LETTER EPSILON WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_epsilon, XK_VoidSymbol}, "έ"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_epsilon, XK_VoidSymbol}, "έ"}, {{XK_Multi_key, XK_Greek_epsilon, XK_apostrophe, XK_VoidSymbol}, "έ"}, {{XK_dead_macron, XK_Otilde, XK_VoidSymbol}, "Ȭ"}, // U022C | LATIN CAPITAL LETTER O WITH TILDE AND MACRON {{XK_Multi_key, XK_macron, XK_Otilde, XK_VoidSymbol}, "Ȭ"}, {{XK_Multi_key, XK_underscore, XK_Otilde, XK_VoidSymbol}, "Ȭ"}, {{XK_dead_macron, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ȭ"}, {{XK_dead_macron, XK_Multi_key, XK_asciitilde, XK_O, XK_VoidSymbol}, "Ȭ"}, {{XK_Multi_key, XK_macron, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ȭ"}, {{XK_Multi_key, XK_macron, XK_asciitilde, XK_O, XK_VoidSymbol}, "Ȭ"}, {{XK_Multi_key, XK_underscore, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ȭ"}, {{XK_Multi_key, XK_underscore, XK_asciitilde, XK_O, XK_VoidSymbol}, "Ȭ"}, {{XK_dead_tilde, XK_Omacron, XK_VoidSymbol}, "Ȭ"}, {{XK_dead_tilde, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ȭ"}, {{XK_dead_acute, XK_abreve, XK_VoidSymbol}, "ắ"}, // U1EAF | LATIN SMALL LETTER A WITH BREVE AND ACUTE {{XK_Multi_key, XK_acute, XK_abreve, XK_VoidSymbol}, "ắ"}, {{XK_Multi_key, XK_apostrophe, XK_abreve, XK_VoidSymbol}, "ắ"}, {{XK_dead_acute, XK_dead_breve, XK_a, XK_VoidSymbol}, "ắ"}, {{XK_dead_acute, XK_Multi_key, XK_U, XK_a, XK_VoidSymbol}, "ắ"}, {{XK_dead_acute, XK_Multi_key, XK_b, XK_a, XK_VoidSymbol}, "ắ"}, {{XK_Multi_key, XK_acute, XK_dead_breve, XK_a, XK_VoidSymbol}, "ắ"}, {{XK_Multi_key, XK_acute, XK_b, XK_a, XK_VoidSymbol}, "ắ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_breve, XK_a, XK_VoidSymbol}, "ắ"}, {{XK_Multi_key, XK_apostrophe, XK_b, XK_a, XK_VoidSymbol}, "ắ"}, {{XK_dead_breve, XK_aacute, XK_VoidSymbol}, "ắ"}, {{XK_dead_breve, XK_dead_acute, XK_a, XK_VoidSymbol}, "ắ"}, {{XK_dead_stroke, XK_U, XK_VoidSymbol}, "Ʉ"}, // U0244 | LATIN CAPITAL LETTER U BAR {{XK_Multi_key, XK_percent, XK_o, XK_VoidSymbol}, "‰"}, // U2030 | PER MILLE SIGN {{XK_dead_belowmacron, XK_K, XK_VoidSymbol}, "Ḵ"}, // U1E34 | LATIN CAPITAL LETTER K WITH LINE BELOW {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_w, XK_VoidSymbol}, "ʷ"}, // U02B7 | MODIFIER LETTER SMALL W {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_w, XK_VoidSymbol}, "ʷ"}, {{XK_dead_cedilla, XK_K, XK_VoidSymbol}, "Ķ"}, // U0136 | LATIN CAPITAL LETTER K WITH CEDILLA {{XK_Multi_key, XK_comma, XK_K, XK_VoidSymbol}, "Ķ"}, {{XK_Multi_key, XK_K, XK_comma, XK_VoidSymbol}, "Ķ"}, {{XK_Multi_key, XK_cedilla, XK_K, XK_VoidSymbol}, "Ķ"}, {{XK_dead_acute, XK_Cyrillic_u, XK_VoidSymbol}, "у́"}, // CYRILLIC SMALL LETTER U WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_u, XK_VoidSymbol}, "у́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_u, XK_VoidSymbol}, "у́"}, {{XK_Multi_key, XK_greater, XK_greater, XK_VoidSymbol}, "»"}, // guillemotright | RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK {{XK_dead_grave, XK_dead_psili, XK_Greek_IOTA, XK_VoidSymbol}, "Ἲ"}, // U1F3A | GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_IOTA, XK_VoidSymbol}, "Ἲ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_IOTA, XK_VoidSymbol}, "Ἲ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_IOTA, XK_VoidSymbol}, "Ἲ"}, {{XK_dead_stroke, XK_c, XK_VoidSymbol}, "ȼ"}, // U023C | LATIN SMALL LETTER C WITH STROKE {{XK_dead_acute, XK_ecircumflex, XK_VoidSymbol}, "ế"}, // U1EBF | LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE {{XK_Multi_key, XK_acute, XK_ecircumflex, XK_VoidSymbol}, "ế"}, {{XK_Multi_key, XK_apostrophe, XK_ecircumflex, XK_VoidSymbol}, "ế"}, {{XK_dead_acute, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ế"}, {{XK_dead_acute, XK_Multi_key, XK_asciicircum, XK_e, XK_VoidSymbol}, "ế"}, {{XK_Multi_key, XK_acute, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ế"}, {{XK_Multi_key, XK_acute, XK_asciicircum, XK_e, XK_VoidSymbol}, "ế"}, {{XK_Multi_key, XK_apostrophe, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ế"}, {{XK_Multi_key, XK_apostrophe, XK_asciicircum, XK_e, XK_VoidSymbol}, "ế"}, {{XK_dead_circumflex, XK_eacute, XK_VoidSymbol}, "ế"}, {{XK_dead_circumflex, XK_dead_acute, XK_e, XK_VoidSymbol}, "ế"}, {{XK_dead_voiced_sound, XK_kana_KO, XK_VoidSymbol}, "ゴ"}, // U30B4 | KATAKANA LETTER GO {{XK_Multi_key, XK_A, XK_T, XK_VoidSymbol}, "@"}, // at | COMMERCIAL AT {{XK_Multi_key, XK_parenleft, XK_N, XK_parenright, XK_VoidSymbol}, "Ⓝ"}, // U24C3 | CIRCLED LATIN CAPITAL LETTER N {{XK_dead_abovering, XK_nobreakspace, XK_VoidSymbol}, "̊"}, // U030A | COMBINING RING ABOVE {{XK_dead_abovedot, XK_N, XK_VoidSymbol}, "Ṅ"}, // U1E44 | LATIN CAPITAL LETTER N WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_N, XK_VoidSymbol}, "Ṅ"}, {{XK_dead_caron, XK_space, XK_VoidSymbol}, "ˇ"}, // caron | CARON {{XK_dead_caron, XK_dead_caron, XK_VoidSymbol}, "ˇ"}, {{XK_Multi_key, XK_space, XK_less, XK_VoidSymbol}, "ˇ"}, {{XK_Multi_key, XK_less, XK_space, XK_VoidSymbol}, "ˇ"}, {{XK_dead_cedilla, XK_n, XK_VoidSymbol}, "ņ"}, // U0146 | LATIN SMALL LETTER N WITH CEDILLA {{XK_Multi_key, XK_comma, XK_n, XK_VoidSymbol}, "ņ"}, {{XK_Multi_key, XK_n, XK_comma, XK_VoidSymbol}, "ņ"}, {{XK_Multi_key, XK_cedilla, XK_n, XK_VoidSymbol}, "ņ"}, {{XK_dead_diaeresis, XK_E, XK_VoidSymbol}, "Ë"}, // Ediaeresis | LATIN CAPITAL LETTER E WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_E, XK_VoidSymbol}, "Ë"}, {{XK_Multi_key, XK_E, XK_quotedbl, XK_VoidSymbol}, "Ë"}, {{XK_Multi_key, XK_diaeresis, XK_E, XK_VoidSymbol}, "Ë"}, {{XK_Multi_key, XK_E, XK_diaeresis, XK_VoidSymbol}, "Ë"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὂ"}, // U1F4A | GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὂ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὂ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὂ"}, {{XK_dead_acute, XK_Greek_upsilon, XK_VoidSymbol}, "ύ"}, // U03CD | GREEK SMALL LETTER UPSILON WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_upsilon, XK_VoidSymbol}, "ύ"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_upsilon, XK_VoidSymbol}, "ύ"}, {{XK_Multi_key, XK_Greek_upsilon, XK_apostrophe, XK_VoidSymbol}, "ύ"}, {{XK_dead_grave, XK_nobreakspace, XK_VoidSymbol}, "̀"}, // U0300 | COMBINING GRAVE ACCENT {{XK_dead_hook, XK_o, XK_VoidSymbol}, "ỏ"}, // U1ECF | LATIN SMALL LETTER O WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_o, XK_VoidSymbol}, "ỏ"}, {{XK_dead_caron, XK_O, XK_VoidSymbol}, "Ǒ"}, // U01D1 | LATIN CAPITAL LETTER O WITH CARON {{XK_Multi_key, XK_c, XK_O, XK_VoidSymbol}, "Ǒ"}, {{XK_dead_diaeresis, XK_Cyrillic_a, XK_VoidSymbol}, "ӓ"}, // U04D3 | CYRILLIC SMALL LETTER A WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_a, XK_VoidSymbol}, "ӓ"}, {{XK_dead_acute, XK_P, XK_VoidSymbol}, "Ṕ"}, // U1E54 | LATIN CAPITAL LETTER P WITH ACUTE {{XK_Multi_key, XK_acute, XK_P, XK_VoidSymbol}, "Ṕ"}, {{XK_Multi_key, XK_apostrophe, XK_P, XK_VoidSymbol}, "Ṕ"}, {{XK_Multi_key, XK_parenleft, XK_kana_KU, XK_parenright, XK_VoidSymbol}, "㋗"}, // U32D7 | CIRCLED KATAKANA KU {{XK_dead_cedilla, XK_R, XK_VoidSymbol}, "Ŗ"}, // U0156 | LATIN CAPITAL LETTER R WITH CEDILLA {{XK_Multi_key, XK_comma, XK_R, XK_VoidSymbol}, "Ŗ"}, {{XK_Multi_key, XK_R, XK_comma, XK_VoidSymbol}, "Ŗ"}, {{XK_Multi_key, XK_cedilla, XK_R, XK_VoidSymbol}, "Ŗ"}, {{XK_dead_circumflex, XK_U, XK_VoidSymbol}, "Û"}, // Ucircumflex | LATIN CAPITAL LETTER U WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_U, XK_VoidSymbol}, "Û"}, {{XK_Multi_key, XK_U, XK_asciicircum, XK_VoidSymbol}, "Û"}, {{XK_Multi_key, XK_greater, XK_U, XK_VoidSymbol}, "Û"}, {{XK_Multi_key, XK_U, XK_greater, XK_VoidSymbol}, "Û"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_2, XK_parenright, XK_VoidSymbol}, "㉜"}, // U325C | CIRCLED NUMBER THIRTY TWO {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "㉜"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_2, XK_parenright, XK_VoidSymbol}, "㉜"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_2, XK_parenright, XK_VoidSymbol}, "㉜"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "㉜"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_2, XK_parenright, XK_VoidSymbol}, "㉜"}, {{XK_dead_hook, XK_ohorn, XK_VoidSymbol}, "ở"}, // U1EDF | LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_ohorn, XK_VoidSymbol}, "ở"}, {{XK_dead_hook, XK_dead_horn, XK_o, XK_VoidSymbol}, "ở"}, {{XK_dead_hook, XK_Multi_key, XK_plus, XK_o, XK_VoidSymbol}, "ở"}, {{XK_Multi_key, XK_question, XK_dead_horn, XK_o, XK_VoidSymbol}, "ở"}, {{XK_Multi_key, XK_question, XK_plus, XK_o, XK_VoidSymbol}, "ở"}, {{XK_dead_horn, XK_ohook, XK_VoidSymbol}, "ở"}, {{XK_dead_horn, XK_dead_hook, XK_o, XK_VoidSymbol}, "ở"}, {{XK_dead_macron, XK_dead_abovedot, XK_a, XK_VoidSymbol}, "ǡ"}, // U01E1 | LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON {{XK_dead_macron, XK_Multi_key, XK_period, XK_a, XK_VoidSymbol}, "ǡ"}, {{XK_Multi_key, XK_macron, XK_dead_abovedot, XK_a, XK_VoidSymbol}, "ǡ"}, {{XK_Multi_key, XK_macron, XK_period, XK_a, XK_VoidSymbol}, "ǡ"}, {{XK_Multi_key, XK_underscore, XK_dead_abovedot, XK_a, XK_VoidSymbol}, "ǡ"}, {{XK_Multi_key, XK_underscore, XK_period, XK_a, XK_VoidSymbol}, "ǡ"}, {{XK_dead_abovedot, XK_amacron, XK_VoidSymbol}, "ǡ"}, {{XK_dead_abovedot, XK_dead_macron, XK_a, XK_VoidSymbol}, "ǡ"}, {{XK_dead_grave, XK_space, XK_VoidSymbol}, "`"}, // grave | GRAVE ACCENT {{XK_dead_grave, XK_dead_grave, XK_VoidSymbol}, "`"}, {{XK_Multi_key, XK_grave, XK_space, XK_VoidSymbol}, "`"}, {{XK_Multi_key, XK_space, XK_grave, XK_VoidSymbol}, "`"}, {{XK_dead_macron, XK_Cyrillic_i, XK_VoidSymbol}, "ӣ"}, // U04E3 | CYRILLIC SMALL LETTER I WITH MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_i, XK_VoidSymbol}, "ӣ"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_i, XK_VoidSymbol}, "ӣ"}, {{XK_dead_dasia, XK_Greek_rho, XK_VoidSymbol}, "ῥ"}, // U1FE5 | GREEK SMALL LETTER RHO WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_rho, XK_VoidSymbol}, "ῥ"}, {{XK_dead_abovedot, XK_Sacute, XK_VoidSymbol}, "Ṥ"}, // U1E64 | LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE {{XK_Multi_key, XK_period, XK_Sacute, XK_VoidSymbol}, "Ṥ"}, {{XK_dead_abovedot, XK_dead_acute, XK_S, XK_VoidSymbol}, "Ṥ"}, {{XK_dead_abovedot, XK_Multi_key, XK_acute, XK_S, XK_VoidSymbol}, "Ṥ"}, {{XK_dead_abovedot, XK_Multi_key, XK_apostrophe, XK_S, XK_VoidSymbol}, "Ṥ"}, {{XK_Multi_key, XK_period, XK_dead_acute, XK_S, XK_VoidSymbol}, "Ṥ"}, {{XK_Multi_key, XK_period, XK_acute, XK_S, XK_VoidSymbol}, "Ṥ"}, {{XK_Multi_key, XK_period, XK_apostrophe, XK_S, XK_VoidSymbol}, "Ṥ"}, {{XK_dead_acute, XK_Sabovedot, XK_VoidSymbol}, "Ṥ"}, {{XK_dead_acute, XK_dead_abovedot, XK_S, XK_VoidSymbol}, "Ṥ"}, {{XK_Multi_key, XK_parenleft, XK_kana_NE, XK_parenright, XK_VoidSymbol}, "㋧"}, // U32E7 | CIRCLED KATAKANA NE {{XK_dead_stroke, XK_T, XK_VoidSymbol}, "Ŧ"}, // U0166 | LATIN CAPITAL LETTER T WITH STROKE {{XK_Multi_key, XK_slash, XK_T, XK_VoidSymbol}, "Ŧ"}, {{XK_Multi_key, XK_KP_Divide, XK_T, XK_VoidSymbol}, "Ŧ"}, {{XK_Multi_key, XK_T, XK_slash, XK_VoidSymbol}, "Ŧ"}, {{XK_Multi_key, XK_T, XK_minus, XK_VoidSymbol}, "Ŧ"}, {{XK_Multi_key, XK_parenleft, XK_9, XK_parenright, XK_VoidSymbol}, "⑨"}, // U2468 | CIRCLED DIGIT NINE {{XK_Multi_key, XK_parenleft, XK_KP_9, XK_parenright, XK_VoidSymbol}, "⑨"}, {{XK_dead_diaeresis, XK_e, XK_VoidSymbol}, "ë"}, // ediaeresis | LATIN SMALL LETTER E WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_e, XK_VoidSymbol}, "ë"}, {{XK_Multi_key, XK_e, XK_quotedbl, XK_VoidSymbol}, "ë"}, {{XK_Multi_key, XK_diaeresis, XK_e, XK_VoidSymbol}, "ë"}, {{XK_Multi_key, XK_e, XK_diaeresis, XK_VoidSymbol}, "ë"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὢ"}, // U1F6A | GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὢ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὢ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὢ"}, {{XK_dead_tilde, XK_uhorn, XK_VoidSymbol}, "ữ"}, // U1EEF | LATIN SMALL LETTER U WITH HORN AND TILDE {{XK_Multi_key, XK_asciitilde, XK_uhorn, XK_VoidSymbol}, "ữ"}, {{XK_dead_tilde, XK_dead_horn, XK_u, XK_VoidSymbol}, "ữ"}, {{XK_dead_tilde, XK_Multi_key, XK_plus, XK_u, XK_VoidSymbol}, "ữ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_horn, XK_u, XK_VoidSymbol}, "ữ"}, {{XK_Multi_key, XK_asciitilde, XK_plus, XK_u, XK_VoidSymbol}, "ữ"}, {{XK_dead_horn, XK_utilde, XK_VoidSymbol}, "ữ"}, {{XK_dead_horn, XK_dead_tilde, XK_u, XK_VoidSymbol}, "ữ"}, {{XK_dead_voiced_sound, XK_kana_SE, XK_VoidSymbol}, "ゼ"}, // U30BC | KATAKANA LETTER ZE {{XK_dead_circumflex, XK_0, XK_VoidSymbol}, "⁰"}, // U2070 | SUPERSCRIPT ZERO {{XK_Multi_key, XK_asciicircum, XK_0, XK_VoidSymbol}, "⁰"}, {{XK_dead_circumflex, XK_KP_0, XK_VoidSymbol}, "⁰"}, {{XK_Multi_key, XK_asciicircum, XK_KP_0, XK_VoidSymbol}, "⁰"}, {{XK_dead_doubleacute, XK_Cyrillic_u, XK_VoidSymbol}, "ӳ"}, // U04F3 | CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE {{XK_Multi_key, XK_equal, XK_Cyrillic_u, XK_VoidSymbol}, "ӳ"}, {{XK_Multi_key, XK_parenleft, XK_kana_NA, XK_parenright, XK_VoidSymbol}, "㋤"}, // U32E4 | CIRCLED KATAKANA NA {{XK_dead_belowtilde, XK_U, XK_VoidSymbol}, "Ṵ"}, // U1E74 | LATIN CAPITAL LETTER U WITH TILDE BELOW {{XK_Multi_key, XK_parenleft, XK_kana_RI, XK_parenright, XK_VoidSymbol}, "㋷"}, // U32F7 | CIRCLED KATAKANA RI {{XK_dead_circumflex, XK_Y, XK_VoidSymbol}, "Ŷ"}, // U0176 | LATIN CAPITAL LETTER Y WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_Y, XK_VoidSymbol}, "Ŷ"}, {{XK_Multi_key, XK_Y, XK_asciicircum, XK_VoidSymbol}, "Ŷ"}, {{XK_dead_circumflex, XK_u, XK_VoidSymbol}, "û"}, // ucircumflex | LATIN SMALL LETTER U WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_u, XK_VoidSymbol}, "û"}, {{XK_Multi_key, XK_u, XK_asciicircum, XK_VoidSymbol}, "û"}, {{XK_Multi_key, XK_greater, XK_u, XK_VoidSymbol}, "û"}, {{XK_Multi_key, XK_u, XK_greater, XK_VoidSymbol}, "û"}, {{XK_dead_grave, XK_Greek_upsilon, XK_VoidSymbol}, "ὺ"}, // U1F7A | GREEK SMALL LETTER UPSILON WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_upsilon, XK_VoidSymbol}, "ὺ"}, {{XK_dead_hook, XK_r, XK_VoidSymbol}, "ɼ"}, // U027C | LATIN SMALL LETTER R WITH LONG LEG {{XK_dead_currency, XK_U, XK_VoidSymbol}, "圓"}, // U5713 | YUAN / WEN {{XK_dead_macron, XK_a, XK_VoidSymbol}, "ā"}, // U0101 | LATIN SMALL LETTER A WITH MACRON {{XK_Multi_key, XK_macron, XK_a, XK_VoidSymbol}, "ā"}, {{XK_Multi_key, XK_underscore, XK_a, XK_VoidSymbol}, "ā"}, {{XK_Multi_key, XK_a, XK_underscore, XK_VoidSymbol}, "ā"}, {{XK_Multi_key, XK_minus, XK_a, XK_VoidSymbol}, "ā"}, {{XK_Multi_key, XK_a, XK_minus, XK_VoidSymbol}, "ā"}, {{XK_Multi_key, XK_underscore, XK_0, XK_VoidSymbol}, "₀"}, // U2080 | SUBSCRIPT ZERO {{XK_Multi_key, XK_underscore, XK_KP_0, XK_VoidSymbol}, "₀"}, {{XK_dead_caron, XK_0, XK_VoidSymbol}, "₀"}, {{XK_dead_acute, XK_Cyrillic_GHE, XK_VoidSymbol}, "Ѓ"}, // U0403 | CYRILLIC CAPITAL LETTER GJE {{XK_Multi_key, XK_acute, XK_Cyrillic_GHE, XK_VoidSymbol}, "Ѓ"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_GHE, XK_VoidSymbol}, "Ѓ"}, {{XK_dead_abovedot, XK_T, XK_VoidSymbol}, "Ṫ"}, // U1E6A | LATIN CAPITAL LETTER T WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_T, XK_VoidSymbol}, "Ṫ"}, {{XK_Multi_key, XK_T, XK_period, XK_VoidSymbol}, "Ṫ"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ἅ"}, // U1F05 | GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ἅ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ἅ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ἅ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ἅ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ἅ"}, {{XK_dead_diaeresis, XK_W, XK_VoidSymbol}, "Ẅ"}, // U1E84 | LATIN CAPITAL LETTER W WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_W, XK_VoidSymbol}, "Ẅ"}, {{XK_dead_invertedbreve, XK_e, XK_VoidSymbol}, "ȇ"}, // U0207 | LATIN SMALL LETTER E WITH INVERTED BREVE {{XK_dead_grave, XK_Ecircumflex, XK_VoidSymbol}, "Ề"}, // U1EC0 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE {{XK_Multi_key, XK_grave, XK_Ecircumflex, XK_VoidSymbol}, "Ề"}, {{XK_dead_grave, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ề"}, {{XK_dead_grave, XK_Multi_key, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ề"}, {{XK_Multi_key, XK_grave, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ề"}, {{XK_Multi_key, XK_grave, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ề"}, {{XK_dead_circumflex, XK_Egrave, XK_VoidSymbol}, "Ề"}, {{XK_dead_circumflex, XK_dead_grave, XK_E, XK_VoidSymbol}, "Ề"}, {{XK_dead_abovedot, XK_E, XK_VoidSymbol}, "Ė"}, // U0116 | LATIN CAPITAL LETTER E WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_E, XK_VoidSymbol}, "Ė"}, {{XK_Multi_key, XK_E, XK_period, XK_VoidSymbol}, "Ė"}, {{XK_dead_tilde, XK_equal, XK_VoidSymbol}, "≃"}, // similarequal | ASYMPTOTICALLY EQUAL TO {{XK_dead_belowmacron, XK_d, XK_VoidSymbol}, "ḏ"}, // U1E0F | LATIN SMALL LETTER D WITH LINE BELOW {{XK_dead_stroke, XK_d, XK_VoidSymbol}, "đ"}, // dstroke | LATIN SMALL LETTER D WITH STROKE {{XK_Multi_key, XK_minus, XK_d, XK_VoidSymbol}, "đ"}, {{XK_Multi_key, XK_d, XK_minus, XK_VoidSymbol}, "đ"}, {{XK_Multi_key, XK_slash, XK_d, XK_VoidSymbol}, "đ"}, {{XK_Multi_key, XK_KP_Divide, XK_d, XK_VoidSymbol}, "đ"}, {{XK_dead_voiced_sound, XK_kana_WA, XK_VoidSymbol}, "ヷ"}, // U30F7 | KATAKANA LETTER VA {{XK_dead_acute, XK_dead_dasia, XK_Greek_epsilon, XK_VoidSymbol}, "ἕ"}, // U1F15 | GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_epsilon, XK_VoidSymbol}, "ἕ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_epsilon, XK_VoidSymbol}, "ἕ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_epsilon, XK_VoidSymbol}, "ἕ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_epsilon, XK_VoidSymbol}, "ἕ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_epsilon, XK_VoidSymbol}, "ἕ"}, {{XK_dead_belowmacron, XK_Z, XK_VoidSymbol}, "Ẕ"}, // U1E94 | LATIN CAPITAL LETTER Z WITH LINE BELOW {{XK_dead_invertedbreve, XK_u, XK_VoidSymbol}, "ȗ"}, // U0217 | LATIN SMALL LETTER U WITH INVERTED BREVE {{XK_dead_iota, XK_dead_grave, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾚ"}, // U1F9A | GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾚ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾚ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾚ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾚ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾚ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾚ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾚ"}, {{XK_dead_abovedot, XK_f, XK_VoidSymbol}, "ḟ"}, // U1E1F | LATIN SMALL LETTER F WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_f, XK_VoidSymbol}, "ḟ"}, {{XK_Multi_key, XK_f, XK_period, XK_VoidSymbol}, "ḟ"}, {{XK_dead_abovedot, XK_g, XK_VoidSymbol}, "ġ"}, // U0121 | LATIN SMALL LETTER G WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_g, XK_VoidSymbol}, "ġ"}, {{XK_Multi_key, XK_g, XK_period, XK_VoidSymbol}, "ġ"}, {{XK_Multi_key, XK_space, XK_space, XK_VoidSymbol}, " "}, // nobreakspace | NO-BREAK SPACE {{XK_dead_acute, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ἥ"}, // U1F25 | GREEK SMALL LETTER ETA WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ἥ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ἥ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ἥ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ἥ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ἥ"}, {{XK_dead_acute, XK_Acircumflex, XK_VoidSymbol}, "Ấ"}, // U1EA4 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE {{XK_Multi_key, XK_acute, XK_Acircumflex, XK_VoidSymbol}, "Ấ"}, {{XK_Multi_key, XK_apostrophe, XK_Acircumflex, XK_VoidSymbol}, "Ấ"}, {{XK_dead_acute, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ấ"}, {{XK_dead_acute, XK_Multi_key, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ấ"}, {{XK_Multi_key, XK_acute, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ấ"}, {{XK_Multi_key, XK_acute, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ấ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ấ"}, {{XK_Multi_key, XK_apostrophe, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ấ"}, {{XK_dead_circumflex, XK_Aacute, XK_VoidSymbol}, "Ấ"}, {{XK_dead_circumflex, XK_dead_acute, XK_A, XK_VoidSymbol}, "Ấ"}, {{XK_dead_abovedot, XK_a, XK_VoidSymbol}, "ȧ"}, // U0227 | LATIN SMALL LETTER A WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_a, XK_VoidSymbol}, "ȧ"}, {{XK_dead_iota, XK_dead_grave, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾪ"}, // U1FAA | GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾪ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾪ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾪ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾪ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾪ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾪ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾪ"}, {{XK_dead_acute, XK_idiaeresis, XK_VoidSymbol}, "ḯ"}, // U1E2F | LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE {{XK_Multi_key, XK_acute, XK_idiaeresis, XK_VoidSymbol}, "ḯ"}, {{XK_Multi_key, XK_apostrophe, XK_idiaeresis, XK_VoidSymbol}, "ḯ"}, {{XK_dead_acute, XK_dead_diaeresis, XK_i, XK_VoidSymbol}, "ḯ"}, {{XK_dead_acute, XK_Multi_key, XK_quotedbl, XK_i, XK_VoidSymbol}, "ḯ"}, {{XK_Multi_key, XK_acute, XK_dead_diaeresis, XK_i, XK_VoidSymbol}, "ḯ"}, {{XK_Multi_key, XK_acute, XK_quotedbl, XK_i, XK_VoidSymbol}, "ḯ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_diaeresis, XK_i, XK_VoidSymbol}, "ḯ"}, {{XK_Multi_key, XK_apostrophe, XK_quotedbl, XK_i, XK_VoidSymbol}, "ḯ"}, {{XK_dead_diaeresis, XK_iacute, XK_VoidSymbol}, "ḯ"}, {{XK_dead_diaeresis, XK_dead_acute, XK_i, XK_VoidSymbol}, "ḯ"}, {{XK_dead_abovedot, XK_i, XK_VoidSymbol}, "ı"}, // U0131 | LATIN SMALL LETTER DOTLESS I {{XK_Multi_key, XK_i, XK_period, XK_VoidSymbol}, "ı"}, {{XK_Multi_key, XK_period, XK_i, XK_VoidSymbol}, "ı"}, {{XK_dead_abovering, XK_space, XK_VoidSymbol}, "°"}, // degree | DEGREE SIGN {{XK_dead_abovering, XK_dead_abovering, XK_VoidSymbol}, "°"}, {{XK_Multi_key, XK_o, XK_o, XK_VoidSymbol}, "°"}, {{XK_Multi_key, XK_asterisk, XK_0, XK_VoidSymbol}, "°"}, {{XK_Multi_key, XK_0, XK_asterisk, XK_VoidSymbol}, "°"}, {{XK_dead_acute, XK_Cyrillic_ie, XK_VoidSymbol}, "е́"}, // CYRILLIC SMALL LETTER IE WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_ie, XK_VoidSymbol}, "е́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_ie, XK_VoidSymbol}, "е́"}, {{XK_dead_tilde, XK_less, XK_VoidSymbol}, "≲"}, // U2272 | LESS-THAN OR EQUIVALENT TO {{XK_dead_acute, XK_dead_dasia, XK_Greek_iota, XK_VoidSymbol}, "ἵ"}, // U1F35 | GREEK SMALL LETTER IOTA WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_iota, XK_VoidSymbol}, "ἵ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_iota, XK_VoidSymbol}, "ἵ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_iota, XK_VoidSymbol}, "ἵ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_iota, XK_VoidSymbol}, "ἵ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_iota, XK_VoidSymbol}, "ἵ"}, {{XK_dead_tilde, XK_Abreve, XK_VoidSymbol}, "Ẵ"}, // U1EB4 | LATIN CAPITAL LETTER A WITH BREVE AND TILDE {{XK_Multi_key, XK_asciitilde, XK_Abreve, XK_VoidSymbol}, "Ẵ"}, {{XK_dead_tilde, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ẵ"}, {{XK_dead_tilde, XK_Multi_key, XK_U, XK_A, XK_VoidSymbol}, "Ẵ"}, {{XK_dead_tilde, XK_Multi_key, XK_b, XK_A, XK_VoidSymbol}, "Ẵ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ẵ"}, {{XK_Multi_key, XK_asciitilde, XK_b, XK_A, XK_VoidSymbol}, "Ẵ"}, {{XK_dead_breve, XK_Atilde, XK_VoidSymbol}, "Ẵ"}, {{XK_dead_breve, XK_dead_tilde, XK_A, XK_VoidSymbol}, "Ẵ"}, {{XK_dead_grave, XK_Omacron, XK_VoidSymbol}, "Ṑ"}, // U1E50 | LATIN CAPITAL LETTER O WITH MACRON AND GRAVE {{XK_Multi_key, XK_grave, XK_Omacron, XK_VoidSymbol}, "Ṑ"}, {{XK_dead_grave, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ṑ"}, {{XK_dead_grave, XK_Multi_key, XK_macron, XK_O, XK_VoidSymbol}, "Ṑ"}, {{XK_dead_grave, XK_Multi_key, XK_underscore, XK_O, XK_VoidSymbol}, "Ṑ"}, {{XK_Multi_key, XK_grave, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ṑ"}, {{XK_Multi_key, XK_grave, XK_macron, XK_O, XK_VoidSymbol}, "Ṑ"}, {{XK_Multi_key, XK_grave, XK_underscore, XK_O, XK_VoidSymbol}, "Ṑ"}, {{XK_dead_macron, XK_Ograve, XK_VoidSymbol}, "Ṑ"}, {{XK_dead_macron, XK_dead_grave, XK_O, XK_VoidSymbol}, "Ṑ"}, {{XK_dead_stroke, XK_z, XK_VoidSymbol}, "ƶ"}, // U01B6 | LATIN SMALL LETTER Z WITH STROKE {{XK_Multi_key, XK_slash, XK_z, XK_VoidSymbol}, "ƶ"}, {{XK_Multi_key, XK_KP_Divide, XK_z, XK_VoidSymbol}, "ƶ"}, {{XK_Multi_key, XK_parenleft, XK_C, XK_parenright, XK_VoidSymbol}, "Ⓒ"}, // U24B8 | CIRCLED LATIN CAPITAL LETTER C {{XK_dead_grave, XK_Greek_ALPHA, XK_VoidSymbol}, "Ὰ"}, // U1FBA | GREEK CAPITAL LETTER ALPHA WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_ALPHA, XK_VoidSymbol}, "Ὰ"}, {{XK_Multi_key, XK_parenleft, XK_4, XK_7, XK_parenright, XK_VoidSymbol}, "㊼"}, // U32BC | CIRCLED NUMBER FORTY SEVEN {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_7, XK_parenright, XK_VoidSymbol}, "㊼"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_7, XK_parenright, XK_VoidSymbol}, "㊼"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_7, XK_parenright, XK_VoidSymbol}, "㊼"}, {{XK_dead_acute, XK_m, XK_VoidSymbol}, "ḿ"}, // U1E3F | LATIN SMALL LETTER M WITH ACUTE {{XK_Multi_key, XK_acute, XK_m, XK_VoidSymbol}, "ḿ"}, {{XK_Multi_key, XK_apostrophe, XK_m, XK_VoidSymbol}, "ḿ"}, {{XK_dead_stroke, XK_L, XK_VoidSymbol}, "Ł"}, // U0141 | LATIN CAPITAL LETTER L WITH STROKE {{XK_Multi_key, XK_slash, XK_L, XK_VoidSymbol}, "Ł"}, {{XK_Multi_key, XK_L, XK_slash, XK_VoidSymbol}, "Ł"}, {{XK_Multi_key, XK_KP_Divide, XK_L, XK_VoidSymbol}, "Ł"}, {{XK_dead_grave, XK_A, XK_VoidSymbol}, "À"}, // Agrave | LATIN CAPITAL LETTER A WITH GRAVE {{XK_Multi_key, XK_grave, XK_A, XK_VoidSymbol}, "À"}, {{XK_Multi_key, XK_A, XK_grave, XK_VoidSymbol}, "À"}, {{XK_dead_belowcircumflex, XK_E, XK_VoidSymbol}, "Ḙ"}, // U1E18 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW {{XK_dead_tilde, XK_Ecircumflex, XK_VoidSymbol}, "Ễ"}, // U1EC4 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE {{XK_Multi_key, XK_asciitilde, XK_Ecircumflex, XK_VoidSymbol}, "Ễ"}, {{XK_dead_tilde, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ễ"}, {{XK_dead_tilde, XK_Multi_key, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ễ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ễ"}, {{XK_Multi_key, XK_asciitilde, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ễ"}, {{XK_dead_circumflex, XK_Etilde, XK_VoidSymbol}, "Ễ"}, {{XK_dead_circumflex, XK_dead_tilde, XK_E, XK_VoidSymbol}, "Ễ"}, {{XK_dead_voiced_sound, XK_kana_FU, XK_VoidSymbol}, "ブ"}, // U30D6 | KATAKANA LETTER BU {{XK_Multi_key, XK_parenleft, XK_S, XK_parenright, XK_VoidSymbol}, "Ⓢ"}, // U24C8 | CIRCLED LATIN CAPITAL LETTER S {{XK_dead_voiced_sound, XK_kana_HA, XK_VoidSymbol}, "バ"}, // U30D0 | KATAKANA LETTER BA {{XK_dead_grave, XK_Greek_ETA, XK_VoidSymbol}, "Ὴ"}, // U1FCA | GREEK CAPITAL LETTER ETA WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_ETA, XK_VoidSymbol}, "Ὴ"}, {{XK_Multi_key, XK_F, XK_r, XK_VoidSymbol}, "₣"}, // U20a3 | FRENCH FRANC SIGN {{XK_dead_currency, XK_F, XK_VoidSymbol}, "₣"}, {{XK_dead_diaeresis, XK_otilde, XK_VoidSymbol}, "ṏ"}, // U1E4F | LATIN SMALL LETTER O WITH TILDE AND DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_otilde, XK_VoidSymbol}, "ṏ"}, {{XK_dead_diaeresis, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ṏ"}, {{XK_dead_diaeresis, XK_Multi_key, XK_asciitilde, XK_o, XK_VoidSymbol}, "ṏ"}, {{XK_Multi_key, XK_quotedbl, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ṏ"}, {{XK_Multi_key, XK_quotedbl, XK_asciitilde, XK_o, XK_VoidSymbol}, "ṏ"}, {{XK_dead_tilde, XK_odiaeresis, XK_VoidSymbol}, "ṏ"}, {{XK_dead_tilde, XK_dead_diaeresis, XK_o, XK_VoidSymbol}, "ṏ"}, {{XK_dead_grave, XK_Cyrillic_u, XK_VoidSymbol}, "у̀"}, // CYRILLIC SMALL LETTER U WITH COMBINING GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_Cyrillic_u, XK_VoidSymbol}, "у̀"}, {{XK_dead_doubleacute, XK_o, XK_VoidSymbol}, "ő"}, // U0151 | LATIN SMALL LETTER O WITH DOUBLE ACUTE {{XK_Multi_key, XK_equal, XK_o, XK_VoidSymbol}, "ő"}, {{XK_Multi_key, XK_D, XK_H, XK_VoidSymbol}, "Ð"}, // ETH | LATIN CAPITAL LETTER ETH {{XK_dead_acute, XK_Cyrillic_ghe, XK_VoidSymbol}, "ѓ"}, // U0453 | CYRILLIC SMALL LETTER GJE {{XK_Multi_key, XK_acute, XK_Cyrillic_ghe, XK_VoidSymbol}, "ѓ"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_ghe, XK_VoidSymbol}, "ѓ"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_9, XK_parenright, XK_VoidSymbol}, "㉙"}, // U3259 | CIRCLED NUMBER TWENTY NINE {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_9, XK_parenright, XK_VoidSymbol}, "㉙"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_9, XK_parenright, XK_VoidSymbol}, "㉙"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_9, XK_parenright, XK_VoidSymbol}, "㉙"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_9, XK_parenright, XK_VoidSymbol}, "㉙"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_9, XK_parenright, XK_VoidSymbol}, "㉙"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_upsilon, XK_VoidSymbol}, "ὕ"}, // U1F55 | GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_upsilon, XK_VoidSymbol}, "ὕ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_upsilon, XK_VoidSymbol}, "ὕ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_upsilon, XK_VoidSymbol}, "ὕ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_upsilon, XK_VoidSymbol}, "ὕ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_upsilon, XK_VoidSymbol}, "ὕ"}, {{XK_dead_hook, XK_Ocircumflex, XK_VoidSymbol}, "Ổ"}, // U1ED4 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_Ocircumflex, XK_VoidSymbol}, "Ổ"}, {{XK_dead_hook, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ổ"}, {{XK_dead_hook, XK_Multi_key, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ổ"}, {{XK_Multi_key, XK_question, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ổ"}, {{XK_Multi_key, XK_question, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ổ"}, {{XK_dead_circumflex, XK_Ohook, XK_VoidSymbol}, "Ổ"}, {{XK_dead_circumflex, XK_dead_hook, XK_O, XK_VoidSymbol}, "Ổ"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_7, XK_parenright, XK_VoidSymbol}, "㉗"}, // U3257 | CIRCLED NUMBER TWENTY SEVEN {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_7, XK_parenright, XK_VoidSymbol}, "㉗"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_7, XK_parenright, XK_VoidSymbol}, "㉗"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_7, XK_parenright, XK_VoidSymbol}, "㉗"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_7, XK_parenright, XK_VoidSymbol}, "㉗"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_7, XK_parenright, XK_VoidSymbol}, "㉗"}, {{XK_dead_macron, XK_udiaeresis, XK_VoidSymbol}, "ǖ"}, // U01D6 | LATIN SMALL LETTER U WITH DIAERESIS AND MACRON {{XK_Multi_key, XK_macron, XK_udiaeresis, XK_VoidSymbol}, "ǖ"}, {{XK_Multi_key, XK_underscore, XK_udiaeresis, XK_VoidSymbol}, "ǖ"}, {{XK_dead_macron, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǖ"}, {{XK_dead_macron, XK_Multi_key, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǖ"}, {{XK_Multi_key, XK_macron, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǖ"}, {{XK_Multi_key, XK_macron, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǖ"}, {{XK_Multi_key, XK_underscore, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǖ"}, {{XK_Multi_key, XK_underscore, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǖ"}, {{XK_dead_macron, XK_v, XK_VoidSymbol}, "ǖ"}, {{XK_dead_invertedbreve, XK_Cyrillic_i, XK_VoidSymbol}, "и̑"}, // CYRILLIC SMALL LETTER I WITH COMBINING INVERTED BREVE {{XK_Multi_key, XK_parenleft, XK_i, XK_parenright, XK_VoidSymbol}, "ⓘ"}, // U24D8 | CIRCLED LATIN SMALL LETTER I {{XK_Multi_key, XK_parenleft, XK_parenleft, XK_VoidSymbol}, "["}, // bracketleft | LEFT SQUARE BRACKET {{XK_dead_grave, XK_Greek_IOTA, XK_VoidSymbol}, "Ὶ"}, // U1FDA | GREEK CAPITAL LETTER IOTA WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_IOTA, XK_VoidSymbol}, "Ὶ"}, {{XK_Multi_key, XK_parenleft, XK_kana_SU, XK_parenright, XK_VoidSymbol}, "㋜"}, // U32DC | CIRCLED KATAKANA SU {{XK_dead_belowmacron, XK_r, XK_VoidSymbol}, "ṟ"}, // U1E5F | LATIN SMALL LETTER R WITH LINE BELOW {{XK_dead_caron, XK_s, XK_VoidSymbol}, "š"}, // U0161 | LATIN SMALL LETTER S WITH CARON {{XK_Multi_key, XK_c, XK_s, XK_VoidSymbol}, "š"}, {{XK_Multi_key, XK_less, XK_s, XK_VoidSymbol}, "š"}, {{XK_Multi_key, XK_s, XK_less, XK_VoidSymbol}, "š"}, {{XK_dead_grave, XK_a, XK_VoidSymbol}, "à"}, // agrave | LATIN SMALL LETTER A WITH GRAVE {{XK_Multi_key, XK_grave, XK_a, XK_VoidSymbol}, "à"}, {{XK_Multi_key, XK_a, XK_grave, XK_VoidSymbol}, "à"}, {{XK_Multi_key, XK_parenleft, XK_4, XK_parenright, XK_VoidSymbol}, "④"}, // U2463 | CIRCLED DIGIT FOUR {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_parenright, XK_VoidSymbol}, "④"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ὥ"}, // U1F65 | GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ὥ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ὥ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ὥ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ὥ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ὥ"}, {{XK_dead_belowdot, XK_U, XK_VoidSymbol}, "Ụ"}, // U1EE4 | LATIN CAPITAL LETTER U WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_U, XK_VoidSymbol}, "Ụ"}, {{XK_dead_caron, XK_G, XK_VoidSymbol}, "Ǧ"}, // U01E6 | LATIN CAPITAL LETTER G WITH CARON {{XK_Multi_key, XK_c, XK_G, XK_VoidSymbol}, "Ǧ"}, {{XK_Multi_key, XK_parenleft, XK_y, XK_parenright, XK_VoidSymbol}, "ⓨ"}, // U24E8 | CIRCLED LATIN SMALL LETTER Y {{XK_dead_grave, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὺ"}, // U1FEA | GREEK CAPITAL LETTER UPSILON WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὺ"}, {{XK_Multi_key, XK_bar, XK_asciitilde, XK_VoidSymbol}, "⍭"}, // U236d | | ~ APL FUNCTIONAL SYMBOL STILE TILDE {{XK_Multi_key, XK_asciitilde, XK_bar, XK_VoidSymbol}, "⍭"}, {{XK_Multi_key, XK_parenleft, XK_kana_HE, XK_parenright, XK_VoidSymbol}, "㋬"}, // U32EC | CIRCLED KATAKANA HE {{XK_Multi_key, XK_numbersign, XK_numbersign, XK_VoidSymbol}, "♯"}, // U266f | MUSIC SHARP SIGN {{XK_dead_doubleacute, XK_u, XK_VoidSymbol}, "ű"}, // U0171 | LATIN SMALL LETTER U WITH DOUBLE ACUTE {{XK_Multi_key, XK_equal, XK_u, XK_VoidSymbol}, "ű"}, {{XK_Multi_key, XK_d, XK_h, XK_VoidSymbol}, "ð"}, // eth | LATIN SMALL LETTER ETH {{XK_Multi_key, XK_parenleft, XK_2, XK_0, XK_parenright, XK_VoidSymbol}, "⑳"}, // U2473 | CIRCLED NUMBER TWENTY {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_0, XK_parenright, XK_VoidSymbol}, "⑳"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_0, XK_parenright, XK_VoidSymbol}, "⑳"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_0, XK_parenright, XK_VoidSymbol}, "⑳"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_0, XK_parenright, XK_VoidSymbol}, "⑳"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_0, XK_parenright, XK_VoidSymbol}, "⑳"}, {{XK_Multi_key, XK_equal, XK_greater, XK_VoidSymbol}, "⇒"}, // U21D2 | RIGHTWARDS DOUBLE ARROW {{XK_dead_belowdot, XK_Y, XK_VoidSymbol}, "Ỵ"}, // U1EF4 | LATIN CAPITAL LETTER Y WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_Y, XK_VoidSymbol}, "Ỵ"}, {{XK_dead_diaeresis, XK_dead_belowdiaeresis, XK_equal, XK_VoidSymbol}, "⩷"}, // U2A77 | EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW {{XK_dead_belowdiaeresis, XK_dead_diaeresis, XK_equal, XK_VoidSymbol}, "⩷"}, {{XK_dead_invertedbreve, XK_Cyrillic_o, XK_VoidSymbol}, "о̑"}, // CYRILLIC SMALL LETTER O WITH COMBINING INVERTED BREVE {{XK_dead_diaeresis, XK_Cyrillic_YERU, XK_VoidSymbol}, "Ӹ"}, // U04F8 | CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_YERU, XK_VoidSymbol}, "Ӹ"}, {{XK_Multi_key, XK_parenleft, XK_minus, XK_VoidSymbol}, "{"}, // braceleft | LEFT CURLY BRACKET {{XK_Multi_key, XK_minus, XK_parenleft, XK_VoidSymbol}, "{"}, {{XK_dead_grave, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὼ"}, // U1FFA | GREEK CAPITAL LETTER OMEGA WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὼ"}, {{XK_Multi_key, XK_less, XK_less, XK_VoidSymbol}, "«"}, // guillemotleft | LEFT-POINTING DOUBLE ANGLE QUOTATION MARK {{XK_dead_belowdot, XK_v, XK_VoidSymbol}, "ṿ"}, // U1E7F | LATIN SMALL LETTER V WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_v, XK_VoidSymbol}, "ṿ"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_3, XK_parenright, XK_VoidSymbol}, "⑬"}, // U246C | CIRCLED NUMBER THIRTEEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_3, XK_parenright, XK_VoidSymbol}, "⑬"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_3, XK_parenright, XK_VoidSymbol}, "⑬"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_3, XK_parenright, XK_VoidSymbol}, "⑬"}, {{XK_Multi_key, XK_underscore, XK_1, XK_VoidSymbol}, "₁"}, // U2081 | SUBSCRIPT ONE {{XK_Multi_key, XK_underscore, XK_KP_1, XK_VoidSymbol}, "₁"}, {{XK_dead_caron, XK_1, XK_VoidSymbol}, "₁"}, {{XK_dead_macron, XK_A, XK_VoidSymbol}, "Ā"}, // U0100 | LATIN CAPITAL LETTER A WITH MACRON {{XK_Multi_key, XK_macron, XK_A, XK_VoidSymbol}, "Ā"}, {{XK_Multi_key, XK_underscore, XK_A, XK_VoidSymbol}, "Ā"}, {{XK_Multi_key, XK_A, XK_underscore, XK_VoidSymbol}, "Ā"}, {{XK_Multi_key, XK_minus, XK_A, XK_VoidSymbol}, "Ā"}, {{XK_Multi_key, XK_A, XK_minus, XK_VoidSymbol}, "Ā"}, {{XK_dead_invertedbreve, XK_A, XK_VoidSymbol}, "Ȃ"}, // U0202 | LATIN CAPITAL LETTER A WITH INVERTED BREVE {{XK_dead_diaeresis, XK_w, XK_VoidSymbol}, "ẅ"}, // U1E85 | LATIN SMALL LETTER W WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_w, XK_VoidSymbol}, "ẅ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ἄ"}, // U1F04 | GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ἄ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ἄ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ἄ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ἄ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ἄ"}, {{XK_dead_abovedot, XK_D, XK_VoidSymbol}, "Ḋ"}, // U1E0A | LATIN CAPITAL LETTER D WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_D, XK_VoidSymbol}, "Ḋ"}, {{XK_Multi_key, XK_D, XK_period, XK_VoidSymbol}, "Ḋ"}, {{XK_dead_caron, XK_nobreakspace, XK_VoidSymbol}, "̌"}, // U030C | COMBINING CARON {{XK_dead_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾏ"}, // U1F8F | GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾏ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾏ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾏ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾏ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾏ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾏ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾏ"}, {{XK_dead_breve, XK_Cyrillic_U, XK_VoidSymbol}, "Ў"}, // U040E | CYRILLIC CAPITAL LETTER SHORT U {{XK_Multi_key, XK_U, XK_Cyrillic_U, XK_VoidSymbol}, "Ў"}, {{XK_Multi_key, XK_b, XK_Cyrillic_U, XK_VoidSymbol}, "Ў"}, {{XK_dead_stroke, XK_D, XK_VoidSymbol}, "Đ"}, // Dstroke | LATIN CAPITAL LETTER D WITH STROKE {{XK_Multi_key, XK_minus, XK_D, XK_VoidSymbol}, "Đ"}, {{XK_Multi_key, XK_D, XK_minus, XK_VoidSymbol}, "Đ"}, {{XK_Multi_key, XK_slash, XK_D, XK_VoidSymbol}, "Đ"}, {{XK_Multi_key, XK_KP_Divide, XK_D, XK_VoidSymbol}, "Đ"}, {{XK_dead_invertedbreve, XK_R, XK_VoidSymbol}, "Ȓ"}, // U0212 | LATIN CAPITAL LETTER R WITH INVERTED BREVE {{XK_dead_belowmacron, XK_z, XK_VoidSymbol}, "ẕ"}, // U1E95 | LATIN SMALL LETTER Z WITH LINE BELOW {{XK_dead_acute, XK_dead_psili, XK_Greek_epsilon, XK_VoidSymbol}, "ἔ"}, // U1F14 | GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_epsilon, XK_VoidSymbol}, "ἔ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_epsilon, XK_VoidSymbol}, "ἔ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_epsilon, XK_VoidSymbol}, "ἔ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_epsilon, XK_VoidSymbol}, "ἔ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_epsilon, XK_VoidSymbol}, "ἔ"}, {{XK_dead_circumflex, XK_dead_belowdot, XK_O, XK_VoidSymbol}, "Ộ"}, // U1ED8 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW {{XK_dead_circumflex, XK_Multi_key, XK_exclam, XK_O, XK_VoidSymbol}, "Ộ"}, {{XK_Multi_key, XK_asciicircum, XK_dead_belowdot, XK_O, XK_VoidSymbol}, "Ộ"}, {{XK_Multi_key, XK_asciicircum, XK_exclam, XK_O, XK_VoidSymbol}, "Ộ"}, {{XK_dead_belowdot, XK_Ocircumflex, XK_VoidSymbol}, "Ộ"}, {{XK_dead_belowdot, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ộ"}, {{XK_Multi_key, XK_braceleft, XK_braceright, XK_VoidSymbol}, "∅"}, // U2205 | EMPTY SET {{XK_dead_belowtilde, XK_E, XK_VoidSymbol}, "Ḛ"}, // U1E1A | LATIN CAPITAL LETTER E WITH TILDE BELOW {{XK_dead_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾟ"}, // U1F9F | GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾟ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾟ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾟ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾟ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾟ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾟ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾟ"}, {{XK_Multi_key, XK_C, XK_slash, XK_VoidSymbol}, "₡"}, // U20a1 | COLON SIGN {{XK_Multi_key, XK_slash, XK_C, XK_VoidSymbol}, "₡"}, {{XK_dead_currency, XK_C, XK_VoidSymbol}, "₡"}, {{XK_dead_abovedot, XK_G, XK_VoidSymbol}, "Ġ"}, // U0120 | LATIN CAPITAL LETTER G WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_G, XK_VoidSymbol}, "Ġ"}, {{XK_Multi_key, XK_G, XK_period, XK_VoidSymbol}, "Ġ"}, {{XK_dead_acute, XK_acircumflex, XK_VoidSymbol}, "ấ"}, // U1EA5 | LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE {{XK_Multi_key, XK_acute, XK_acircumflex, XK_VoidSymbol}, "ấ"}, {{XK_Multi_key, XK_apostrophe, XK_acircumflex, XK_VoidSymbol}, "ấ"}, {{XK_dead_acute, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ấ"}, {{XK_dead_acute, XK_Multi_key, XK_asciicircum, XK_a, XK_VoidSymbol}, "ấ"}, {{XK_Multi_key, XK_acute, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ấ"}, {{XK_Multi_key, XK_acute, XK_asciicircum, XK_a, XK_VoidSymbol}, "ấ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ấ"}, {{XK_Multi_key, XK_apostrophe, XK_asciicircum, XK_a, XK_VoidSymbol}, "ấ"}, {{XK_dead_circumflex, XK_aacute, XK_VoidSymbol}, "ấ"}, {{XK_dead_circumflex, XK_dead_acute, XK_a, XK_VoidSymbol}, "ấ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ἤ"}, // U1F24 | GREEK SMALL LETTER ETA WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ἤ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ἤ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ἤ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ἤ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ἤ"}, {{XK_Multi_key, XK_period, XK_period, XK_VoidSymbol}, "…"}, // ellipsis | HORIZONTAL ELLIPSIS {{XK_Multi_key, XK_5, XK_8, XK_VoidSymbol}, "⅝"}, // U215D | VULGAR FRACTION FIVE EIGHTHS {{XK_Multi_key, XK_parenleft, XK_kana_KE, XK_parenright, XK_VoidSymbol}, "㋘"}, // U32D8 | CIRCLED KATAKANA KE {{XK_dead_belowbreve, XK_H, XK_VoidSymbol}, "Ḫ"}, // U1E2A | LATIN CAPITAL LETTER H WITH BREVE BELOW {{XK_dead_currency, XK_A, XK_VoidSymbol}, "₳"}, // U20B3 | AUSTRAL SIGN {{XK_dead_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾯ"}, // U1FAF | GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾯ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾯ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾯ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾯ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾯ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾯ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾯ"}, {{XK_Multi_key, XK_parenleft, XK_D, XK_parenright, XK_VoidSymbol}, "Ⓓ"}, // U24B9 | CIRCLED LATIN CAPITAL LETTER D {{XK_Multi_key, XK_plus, XK_minus, XK_VoidSymbol}, "±"}, // plusminus | PLUS-MINUS SIGN {{XK_Multi_key, XK_minus, XK_plus, XK_VoidSymbol}, "±"}, {{XK_dead_abovedot, XK_I, XK_VoidSymbol}, "İ"}, // U0130 | LATIN CAPITAL LETTER I WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_I, XK_VoidSymbol}, "İ"}, {{XK_Multi_key, XK_I, XK_period, XK_VoidSymbol}, "İ"}, {{XK_dead_macron, XK_Y, XK_VoidSymbol}, "Ȳ"}, // U0232 | LATIN CAPITAL LETTER Y WITH MACRON {{XK_Multi_key, XK_macron, XK_Y, XK_VoidSymbol}, "Ȳ"}, {{XK_Multi_key, XK_underscore, XK_Y, XK_VoidSymbol}, "Ȳ"}, {{XK_dead_tilde, XK_abreve, XK_VoidSymbol}, "ẵ"}, // U1EB5 | LATIN SMALL LETTER A WITH BREVE AND TILDE {{XK_Multi_key, XK_asciitilde, XK_abreve, XK_VoidSymbol}, "ẵ"}, {{XK_dead_tilde, XK_dead_breve, XK_a, XK_VoidSymbol}, "ẵ"}, {{XK_dead_tilde, XK_Multi_key, XK_U, XK_a, XK_VoidSymbol}, "ẵ"}, {{XK_dead_tilde, XK_Multi_key, XK_b, XK_a, XK_VoidSymbol}, "ẵ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_breve, XK_a, XK_VoidSymbol}, "ẵ"}, {{XK_Multi_key, XK_asciitilde, XK_b, XK_a, XK_VoidSymbol}, "ẵ"}, {{XK_dead_breve, XK_atilde, XK_VoidSymbol}, "ẵ"}, {{XK_dead_breve, XK_dead_tilde, XK_a, XK_VoidSymbol}, "ẵ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_iota, XK_VoidSymbol}, "ἴ"}, // U1F34 | GREEK SMALL LETTER IOTA WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_iota, XK_VoidSymbol}, "ἴ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_iota, XK_VoidSymbol}, "ἴ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_iota, XK_VoidSymbol}, "ἴ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_iota, XK_VoidSymbol}, "ἴ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_iota, XK_VoidSymbol}, "ἴ"}, {{XK_Multi_key, XK_3, XK_5, XK_VoidSymbol}, "⅗"}, // U2157 | VULGAR FRACTION THREE FIFTHS {{XK_dead_stroke, XK_2, XK_VoidSymbol}, "ƻ"}, // U01BB | LATIN LETTER TWO WITH STROKE {{XK_Multi_key, XK_colon, XK_parenright, XK_VoidSymbol}, "☺"}, // U263A | WHITE SMILING FACE {{XK_Multi_key, XK_parenleft, XK_4, XK_8, XK_parenright, XK_VoidSymbol}, "㊽"}, // U32BD | CIRCLED NUMBER FORTY EIGHT {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_8, XK_parenright, XK_VoidSymbol}, "㊽"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_8, XK_parenright, XK_VoidSymbol}, "㊽"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_8, XK_parenright, XK_VoidSymbol}, "㊽"}, {{XK_dead_acute, XK_A, XK_VoidSymbol}, "Á"}, // Aacute | LATIN CAPITAL LETTER A WITH ACUTE {{XK_Multi_key, XK_acute, XK_A, XK_VoidSymbol}, "Á"}, {{XK_Multi_key, XK_A, XK_acute, XK_VoidSymbol}, "Á"}, {{XK_Multi_key, XK_apostrophe, XK_A, XK_VoidSymbol}, "Á"}, {{XK_Multi_key, XK_A, XK_apostrophe, XK_VoidSymbol}, "Á"}, {{XK_dead_abovedot, XK_l, XK_VoidSymbol}, "ŀ"}, // U0140 | LATIN SMALL LETTER L WITH MIDDLE DOT {{XK_dead_tilde, XK_ecircumflex, XK_VoidSymbol}, "ễ"}, // U1EC5 | LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE {{XK_Multi_key, XK_asciitilde, XK_ecircumflex, XK_VoidSymbol}, "ễ"}, {{XK_dead_tilde, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ễ"}, {{XK_dead_tilde, XK_Multi_key, XK_asciicircum, XK_e, XK_VoidSymbol}, "ễ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ễ"}, {{XK_Multi_key, XK_asciitilde, XK_asciicircum, XK_e, XK_VoidSymbol}, "ễ"}, {{XK_dead_circumflex, XK_etilde, XK_VoidSymbol}, "ễ"}, {{XK_dead_circumflex, XK_dead_tilde, XK_e, XK_VoidSymbol}, "ễ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_omicron, XK_VoidSymbol}, "ὄ"}, // U1F44 | GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_omicron, XK_VoidSymbol}, "ὄ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_omicron, XK_VoidSymbol}, "ὄ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_omicron, XK_VoidSymbol}, "ὄ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_omicron, XK_VoidSymbol}, "ὄ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_omicron, XK_VoidSymbol}, "ὄ"}, {{XK_Multi_key, XK_parenleft, XK_T, XK_parenright, XK_VoidSymbol}, "Ⓣ"}, // U24C9 | CIRCLED LATIN CAPITAL LETTER T {{XK_dead_stroke, XK_P, XK_VoidSymbol}, "Ᵽ"}, // U2C63 | LATIN CAPITAL LETTER P WITH STROKE {{XK_dead_belowcircumflex, XK_N, XK_VoidSymbol}, "Ṋ"}, // U1E4A | LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW {{XK_dead_invertedbreve, XK_Cyrillic_ie, XK_VoidSymbol}, "е̑"}, // CYRILLIC SMALL LETTER IE WITH COMBINING INVERTED BREVE {{XK_dead_tilde, XK_N, XK_VoidSymbol}, "Ñ"}, // Ntilde | LATIN CAPITAL LETTER N WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_N, XK_VoidSymbol}, "Ñ"}, {{XK_Multi_key, XK_N, XK_asciitilde, XK_VoidSymbol}, "Ñ"}, {{XK_dead_doubleacute, XK_O, XK_VoidSymbol}, "Ő"}, // U0150 | LATIN CAPITAL LETTER O WITH DOUBLE ACUTE {{XK_Multi_key, XK_equal, XK_O, XK_VoidSymbol}, "Ő"}, {{XK_dead_doublegrave, XK_Cyrillic_ie, XK_VoidSymbol}, "е̏"}, // CYRILLIC SMALL LETTER IE WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_ie, XK_VoidSymbol}, "е̏"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_2, XK_parenright, XK_VoidSymbol}, "㉒"}, // U3252 | CIRCLED NUMBER TWENTY TWO {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "㉒"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_2, XK_parenright, XK_VoidSymbol}, "㉒"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_2, XK_parenright, XK_VoidSymbol}, "㉒"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "㉒"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_2, XK_parenright, XK_VoidSymbol}, "㉒"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_2, XK_parenright, XK_VoidSymbol}, "㉒"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "㉒"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_2, XK_parenright, XK_VoidSymbol}, "㉒"}, {{XK_dead_hook, XK_ocircumflex, XK_VoidSymbol}, "ổ"}, // U1ED5 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_ocircumflex, XK_VoidSymbol}, "ổ"}, {{XK_dead_hook, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ổ"}, {{XK_dead_hook, XK_Multi_key, XK_asciicircum, XK_o, XK_VoidSymbol}, "ổ"}, {{XK_Multi_key, XK_question, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ổ"}, {{XK_Multi_key, XK_question, XK_asciicircum, XK_o, XK_VoidSymbol}, "ổ"}, {{XK_dead_circumflex, XK_ohook, XK_VoidSymbol}, "ổ"}, {{XK_dead_circumflex, XK_dead_hook, XK_o, XK_VoidSymbol}, "ổ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_upsilon, XK_VoidSymbol}, "ὔ"}, // U1F54 | GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_upsilon, XK_VoidSymbol}, "ὔ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_upsilon, XK_VoidSymbol}, "ὔ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_upsilon, XK_VoidSymbol}, "ὔ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_upsilon, XK_VoidSymbol}, "ὔ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_upsilon, XK_VoidSymbol}, "ὔ"}, {{XK_dead_acute, XK_Cyrillic_o, XK_VoidSymbol}, "о́"}, // CYRILLIC SMALL LETTER O WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_o, XK_VoidSymbol}, "о́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_o, XK_VoidSymbol}, "о́"}, {{XK_Multi_key, XK_parenleft, XK_j, XK_parenright, XK_VoidSymbol}, "ⓙ"}, // U24D9 | CIRCLED LATIN SMALL LETTER J {{XK_dead_macron, XK_Cyrillic_ie, XK_VoidSymbol}, "е̄"}, // CYRILLIC SMALL LETTER IE WITH COMBINING MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_ie, XK_VoidSymbol}, "е̄"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_ie, XK_VoidSymbol}, "е̄"}, {{XK_dead_grave, XK_Udiaeresis, XK_VoidSymbol}, "Ǜ"}, // U01DB | LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE {{XK_Multi_key, XK_grave, XK_Udiaeresis, XK_VoidSymbol}, "Ǜ"}, {{XK_dead_grave, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǜ"}, {{XK_dead_grave, XK_Multi_key, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǜ"}, {{XK_Multi_key, XK_grave, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǜ"}, {{XK_Multi_key, XK_grave, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǜ"}, {{XK_dead_diaeresis, XK_Ugrave, XK_VoidSymbol}, "Ǜ"}, {{XK_dead_grave, XK_V, XK_VoidSymbol}, "Ǜ"}, {{XK_dead_diaeresis, XK_dead_grave, XK_U, XK_VoidSymbol}, "Ǜ"}, {{XK_dead_belowdot, XK_R, XK_VoidSymbol}, "Ṛ"}, // U1E5A | LATIN CAPITAL LETTER R WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_R, XK_VoidSymbol}, "Ṛ"}, {{XK_dead_doubleacute, XK_space, XK_VoidSymbol}, "˝"}, // U2dd | DOUBLE ACUTE ACCENT {{XK_dead_doubleacute, XK_dead_doubleacute, XK_VoidSymbol}, "˝"}, {{XK_dead_circumflex, XK_Cyrillic_o, XK_VoidSymbol}, "о̂"}, // CYRILLIC SMALL LETTER O WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_o, XK_VoidSymbol}, "о̂"}, {{XK_dead_breve, XK_Cyrillic_u, XK_VoidSymbol}, "ў"}, // U045E | CYRILLIC SMALL LETTER SHORT U {{XK_Multi_key, XK_U, XK_Cyrillic_u, XK_VoidSymbol}, "ў"}, {{XK_Multi_key, XK_b, XK_Cyrillic_u, XK_VoidSymbol}, "ў"}, {{XK_dead_acute, XK_a, XK_VoidSymbol}, "á"}, // aacute | LATIN SMALL LETTER A WITH ACUTE {{XK_Multi_key, XK_acute, XK_a, XK_VoidSymbol}, "á"}, {{XK_Multi_key, XK_a, XK_acute, XK_VoidSymbol}, "á"}, {{XK_Multi_key, XK_apostrophe, XK_a, XK_VoidSymbol}, "á"}, {{XK_Multi_key, XK_a, XK_apostrophe, XK_VoidSymbol}, "á"}, {{XK_dead_caron, XK_S, XK_VoidSymbol}, "Š"}, // U0160 | LATIN CAPITAL LETTER S WITH CARON {{XK_Multi_key, XK_c, XK_S, XK_VoidSymbol}, "Š"}, {{XK_Multi_key, XK_less, XK_S, XK_VoidSymbol}, "Š"}, {{XK_Multi_key, XK_S, XK_less, XK_VoidSymbol}, "Š"}, {{XK_dead_belowdot, XK_u, XK_VoidSymbol}, "ụ"}, // U1EE5 | LATIN SMALL LETTER U WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_u, XK_VoidSymbol}, "ụ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ὤ"}, // U1F64 | GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ὤ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ὤ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ὤ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ὤ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ὤ"}, {{XK_Multi_key, XK_parenleft, XK_z, XK_parenright, XK_VoidSymbol}, "ⓩ"}, // U24E9 | CIRCLED LATIN SMALL LETTER Z {{XK_dead_ogonek, XK_o, XK_VoidSymbol}, "ǫ"}, // U01EB | LATIN SMALL LETTER O WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_o, XK_VoidSymbol}, "ǫ"}, {{XK_Multi_key, XK_o, XK_semicolon, XK_VoidSymbol}, "ǫ"}, {{XK_Multi_key, XK_comma, XK_o, XK_VoidSymbol}, "ǫ"}, {{XK_Multi_key, XK_o, XK_comma, XK_VoidSymbol}, "ǫ"}, {{XK_Multi_key, XK_numbersign, XK_e, XK_VoidSymbol}, "♪"}, // U266a | EIGHTH NOTE {{XK_Multi_key, XK_parenleft, XK_kana_HO, XK_parenright, XK_VoidSymbol}, "㋭"}, // U32ED | CIRCLED KATAKANA HO {{XK_Multi_key, XK_0, XK_asciitilde, XK_VoidSymbol}, "⍬"}, // U236c | 0 ~ APL FUNCTIONAL SYMBOL ZILDE {{XK_Multi_key, XK_asciitilde, XK_0, XK_VoidSymbol}, "⍬"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_5, XK_parenright, XK_VoidSymbol}, "⑮"}, // U246E | CIRCLED NUMBER FIFTEEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_5, XK_parenright, XK_VoidSymbol}, "⑮"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_5, XK_parenright, XK_VoidSymbol}, "⑮"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_5, XK_parenright, XK_VoidSymbol}, "⑮"}, {{XK_dead_tilde, XK_n, XK_VoidSymbol}, "ñ"}, // ntilde | LATIN SMALL LETTER N WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_n, XK_VoidSymbol}, "ñ"}, {{XK_Multi_key, XK_n, XK_asciitilde, XK_VoidSymbol}, "ñ"}, {{XK_dead_doubleacute, XK_U, XK_VoidSymbol}, "Ű"}, // U0170 | LATIN CAPITAL LETTER U WITH DOUBLE ACUTE {{XK_Multi_key, XK_equal, XK_U, XK_VoidSymbol}, "Ű"}, {{XK_dead_semivoiced_sound, XK_kana_HI, XK_VoidSymbol}, "ピ"}, // U30D4 | KATAKANA LETTER PI {{XK_dead_hook, XK_n, XK_VoidSymbol}, "ɲ"}, // U0272 | LATIN SMALL LETTER N WITH LEFT HOOK {{XK_dead_belowdot, XK_y, XK_VoidSymbol}, "ỵ"}, // U1EF5 | LATIN SMALL LETTER Y WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_y, XK_VoidSymbol}, "ỵ"}, {{XK_dead_grave, XK_Greek_eta, XK_VoidSymbol}, "ὴ"}, // U1F74 | GREEK SMALL LETTER ETA WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_eta, XK_VoidSymbol}, "ὴ"}, {{XK_dead_circumflex, XK_6, XK_VoidSymbol}, "⁶"}, // U2076 | SUPERSCRIPT SIX {{XK_Multi_key, XK_asciicircum, XK_6, XK_VoidSymbol}, "⁶"}, {{XK_dead_circumflex, XK_KP_6, XK_VoidSymbol}, "⁶"}, {{XK_Multi_key, XK_asciicircum, XK_KP_6, XK_VoidSymbol}, "⁶"}, {{XK_dead_diaeresis, XK_Cyrillic_yeru, XK_VoidSymbol}, "ӹ"}, // U04F9 | CYRILLIC SMALL LETTER YERU WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_yeru, XK_VoidSymbol}, "ӹ"}, {{XK_dead_acute, XK_aring, XK_VoidSymbol}, "ǻ"}, // U01FB | LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE {{XK_Multi_key, XK_acute, XK_aring, XK_VoidSymbol}, "ǻ"}, {{XK_Multi_key, XK_apostrophe, XK_aring, XK_VoidSymbol}, "ǻ"}, {{XK_dead_acute, XK_dead_abovering, XK_a, XK_VoidSymbol}, "ǻ"}, {{XK_dead_acute, XK_Multi_key, XK_o, XK_a, XK_VoidSymbol}, "ǻ"}, {{XK_Multi_key, XK_acute, XK_dead_abovering, XK_a, XK_VoidSymbol}, "ǻ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_abovering, XK_a, XK_VoidSymbol}, "ǻ"}, {{XK_Multi_key, XK_asterisk, XK_apostrophe, XK_a, XK_VoidSymbol}, "ǻ"}, {{XK_dead_abovering, XK_aacute, XK_VoidSymbol}, "ǻ"}, {{XK_dead_abovering, XK_dead_acute, XK_a, XK_VoidSymbol}, "ǻ"}, {{XK_dead_diaeresis, XK_Umacron, XK_VoidSymbol}, "Ṻ"}, // U1E7A | LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Umacron, XK_VoidSymbol}, "Ṻ"}, {{XK_dead_diaeresis, XK_dead_macron, XK_U, XK_VoidSymbol}, "Ṻ"}, {{XK_dead_diaeresis, XK_Multi_key, XK_macron, XK_U, XK_VoidSymbol}, "Ṻ"}, {{XK_dead_diaeresis, XK_Multi_key, XK_underscore, XK_U, XK_VoidSymbol}, "Ṻ"}, {{XK_Multi_key, XK_quotedbl, XK_dead_macron, XK_U, XK_VoidSymbol}, "Ṻ"}, {{XK_Multi_key, XK_quotedbl, XK_macron, XK_U, XK_VoidSymbol}, "Ṻ"}, {{XK_Multi_key, XK_quotedbl, XK_underscore, XK_U, XK_VoidSymbol}, "Ṻ"}, {{XK_Multi_key, XK_parenleft, XK_w, XK_parenright, XK_VoidSymbol}, "ⓦ"}, // U24E6 | CIRCLED LATIN SMALL LETTER W {{XK_dead_abovedot, XK_t, XK_VoidSymbol}, "ṫ"}, // U1E6B | LATIN SMALL LETTER T WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_t, XK_VoidSymbol}, "ṫ"}, {{XK_Multi_key, XK_t, XK_period, XK_VoidSymbol}, "ṫ"}, {{XK_dead_stroke, XK_b, XK_VoidSymbol}, "ƀ"}, // U0180 | LATIN SMALL LETTER B WITH STROKE {{XK_Multi_key, XK_slash, XK_b, XK_VoidSymbol}, "ƀ"}, {{XK_Multi_key, XK_KP_Divide, XK_b, XK_VoidSymbol}, "ƀ"}, {{XK_dead_hook, XK_s, XK_VoidSymbol}, "ʂ"}, // U0282 | LATIN SMALL LETTER S WITH HOOK {{XK_dead_belowdot, XK_b, XK_VoidSymbol}, "ḅ"}, // U1E05 | LATIN SMALL LETTER B WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_b, XK_VoidSymbol}, "ḅ"}, {{XK_dead_iota, XK_dead_acute, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, // U1F84 | GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾄ"}, {{XK_dead_abovedot, XK_nobreakspace, XK_VoidSymbol}, "̇"}, // U0307 | COMBINING DOT ABOVE {{XK_Multi_key, XK_underscore, XK_6, XK_VoidSymbol}, "₆"}, // U2086 | SUBSCRIPT SIX {{XK_Multi_key, XK_underscore, XK_KP_6, XK_VoidSymbol}, "₆"}, {{XK_dead_caron, XK_6, XK_VoidSymbol}, "₆"}, {{XK_dead_invertedbreve, XK_Cyrillic_IE, XK_VoidSymbol}, "Е̑"}, // CYRILLIC CAPITAL LETTER IE WITH COMBINING INVERTED BREVE {{XK_dead_abovedot, XK_c, XK_VoidSymbol}, "ċ"}, // U010B | LATIN SMALL LETTER C WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_c, XK_VoidSymbol}, "ċ"}, {{XK_Multi_key, XK_c, XK_period, XK_VoidSymbol}, "ċ"}, {{XK_dead_abovedot, XK_X, XK_VoidSymbol}, "Ẋ"}, // U1E8A | LATIN CAPITAL LETTER X WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_X, XK_VoidSymbol}, "Ẋ"}, {{XK_dead_doublegrave, XK_o, XK_VoidSymbol}, "ȍ"}, // U020D | LATIN SMALL LETTER O WITH DOUBLE GRAVE {{XK_dead_acute, XK_Greek_OMICRON, XK_VoidSymbol}, "Ό"}, // U038C | GREEK CAPITAL LETTER OMICRON WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_OMICRON, XK_VoidSymbol}, "Ό"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_OMICRON, XK_VoidSymbol}, "Ό"}, {{XK_Multi_key, XK_Greek_OMICRON, XK_apostrophe, XK_VoidSymbol}, "Ό"}, {{XK_dead_tilde, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἇ"}, // U1F0F | GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἇ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἇ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἇ"}, {{XK_Multi_key, XK_less, XK_minus, XK_VoidSymbol}, "←"}, // U2190 | LEFTWARDS ARROW {{XK_dead_grave, XK_emacron, XK_VoidSymbol}, "ḕ"}, // U1E15 | LATIN SMALL LETTER E WITH MACRON AND GRAVE {{XK_Multi_key, XK_grave, XK_emacron, XK_VoidSymbol}, "ḕ"}, {{XK_dead_grave, XK_dead_macron, XK_e, XK_VoidSymbol}, "ḕ"}, {{XK_dead_grave, XK_Multi_key, XK_macron, XK_e, XK_VoidSymbol}, "ḕ"}, {{XK_dead_grave, XK_Multi_key, XK_underscore, XK_e, XK_VoidSymbol}, "ḕ"}, {{XK_Multi_key, XK_grave, XK_dead_macron, XK_e, XK_VoidSymbol}, "ḕ"}, {{XK_Multi_key, XK_grave, XK_macron, XK_e, XK_VoidSymbol}, "ḕ"}, {{XK_Multi_key, XK_grave, XK_underscore, XK_e, XK_VoidSymbol}, "ḕ"}, {{XK_dead_macron, XK_egrave, XK_VoidSymbol}, "ḕ"}, {{XK_dead_macron, XK_dead_grave, XK_e, XK_VoidSymbol}, "ḕ"}, {{XK_dead_iota, XK_dead_acute, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, // U1F94 | GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾔ"}, {{XK_dead_currency, XK_THORN, XK_VoidSymbol}, "৲"}, // U09F2 | BENGALI RUPEE MARK {{XK_dead_currency, XK_thorn, XK_VoidSymbol}, "৲"}, {{XK_dead_breve, XK_Cyrillic_I, XK_VoidSymbol}, "Й"}, // U0419 | CYRILLIC CAPITAL LETTER SHORT I {{XK_Multi_key, XK_U, XK_Cyrillic_I, XK_VoidSymbol}, "Й"}, {{XK_Multi_key, XK_b, XK_Cyrillic_I, XK_VoidSymbol}, "Й"}, {{XK_dead_caron, XK_e, XK_VoidSymbol}, "ě"}, // U011B | LATIN SMALL LETTER E WITH CARON {{XK_Multi_key, XK_c, XK_e, XK_VoidSymbol}, "ě"}, {{XK_Multi_key, XK_less, XK_e, XK_VoidSymbol}, "ě"}, {{XK_Multi_key, XK_e, XK_less, XK_VoidSymbol}, "ě"}, {{XK_Multi_key, XK_4, XK_5, XK_VoidSymbol}, "⅘"}, // U2158 | VULGAR FRACTION FOUR FIFTHS {{XK_Multi_key, XK_slash, XK_Cyrillic_KA, XK_VoidSymbol}, "Ҟ"}, // U049E | CYRILLIC CAPITAL LETTER KA WITH STROKE {{XK_Multi_key, XK_KP_Divide, XK_Cyrillic_KA, XK_VoidSymbol}, "Ҟ"}, {{XK_dead_horn, XK_O, XK_VoidSymbol}, "Ơ"}, // U01A0 | LATIN CAPITAL LETTER O WITH HORN {{XK_Multi_key, XK_plus, XK_O, XK_VoidSymbol}, "Ơ"}, {{XK_dead_belowdot, XK_h, XK_VoidSymbol}, "ḥ"}, // U1E25 | LATIN SMALL LETTER H WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_h, XK_VoidSymbol}, "ḥ"}, {{XK_dead_iota, XK_dead_acute, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, // U1FA4 | GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾤ"}, {{XK_dead_cedilla, XK_nobreakspace, XK_VoidSymbol}, "̧"}, // U0327 | COMBINING CEDILLA {{XK_Multi_key, XK_N, XK_equal, XK_VoidSymbol}, "₦"}, // U20a6 | NAIRA SIGN {{XK_Multi_key, XK_equal, XK_N, XK_VoidSymbol}, "₦"}, {{XK_dead_currency, XK_N, XK_VoidSymbol}, "₦"}, {{XK_dead_currency, XK_n, XK_VoidSymbol}, "₦"}, {{XK_dead_macron, XK_i, XK_VoidSymbol}, "ī"}, // U012B | LATIN SMALL LETTER I WITH MACRON {{XK_Multi_key, XK_macron, XK_i, XK_VoidSymbol}, "ī"}, {{XK_Multi_key, XK_underscore, XK_i, XK_VoidSymbol}, "ī"}, {{XK_Multi_key, XK_i, XK_underscore, XK_VoidSymbol}, "ī"}, {{XK_Multi_key, XK_minus, XK_i, XK_VoidSymbol}, "ī"}, {{XK_Multi_key, XK_i, XK_minus, XK_VoidSymbol}, "ī"}, {{XK_dead_tilde, XK_Acircumflex, XK_VoidSymbol}, "Ẫ"}, // U1EAA | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE {{XK_Multi_key, XK_asciitilde, XK_Acircumflex, XK_VoidSymbol}, "Ẫ"}, {{XK_dead_tilde, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ẫ"}, {{XK_dead_tilde, XK_Multi_key, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ẫ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ẫ"}, {{XK_Multi_key, XK_asciitilde, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ẫ"}, {{XK_dead_circumflex, XK_Atilde, XK_VoidSymbol}, "Ẫ"}, {{XK_dead_circumflex, XK_dead_tilde, XK_A, XK_VoidSymbol}, "Ẫ"}, {{XK_dead_macron, XK_otilde, XK_VoidSymbol}, "ȭ"}, // U022D | LATIN SMALL LETTER O WITH TILDE AND MACRON {{XK_Multi_key, XK_macron, XK_otilde, XK_VoidSymbol}, "ȭ"}, {{XK_Multi_key, XK_underscore, XK_otilde, XK_VoidSymbol}, "ȭ"}, {{XK_dead_macron, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ȭ"}, {{XK_dead_macron, XK_Multi_key, XK_asciitilde, XK_o, XK_VoidSymbol}, "ȭ"}, {{XK_Multi_key, XK_macron, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ȭ"}, {{XK_Multi_key, XK_macron, XK_asciitilde, XK_o, XK_VoidSymbol}, "ȭ"}, {{XK_Multi_key, XK_underscore, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ȭ"}, {{XK_Multi_key, XK_underscore, XK_asciitilde, XK_o, XK_VoidSymbol}, "ȭ"}, {{XK_dead_tilde, XK_omacron, XK_VoidSymbol}, "ȭ"}, {{XK_dead_tilde, XK_dead_macron, XK_o, XK_VoidSymbol}, "ȭ"}, {{XK_dead_acute, XK_Greek_alpha, XK_VoidSymbol}, "ά"}, // U03AC | GREEK SMALL LETTER ALPHA WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_alpha, XK_VoidSymbol}, "ά"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_alpha, XK_VoidSymbol}, "ά"}, {{XK_Multi_key, XK_Greek_alpha, XK_apostrophe, XK_VoidSymbol}, "ά"}, {{XK_dead_tilde, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "Ἧ"}, // U1F2F | GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "Ἧ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "Ἧ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "Ἧ"}, {{XK_dead_horn, XK_u, XK_VoidSymbol}, "ư"}, // U01B0 | LATIN SMALL LETTER U WITH HORN {{XK_Multi_key, XK_plus, XK_u, XK_VoidSymbol}, "ư"}, {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_j, XK_VoidSymbol}, "ʲ"}, // U02B2 | MODIFIER LETTER SMALL J {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_j, XK_VoidSymbol}, "ʲ"}, {{XK_dead_belowmacron, XK_k, XK_VoidSymbol}, "ḵ"}, // U1E35 | LATIN SMALL LETTER K WITH LINE BELOW {{XK_dead_iota, XK_Greek_alphaaccent, XK_VoidSymbol}, "ᾴ"}, // U1FB4 | GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_alphaaccent, XK_VoidSymbol}, "ᾴ"}, {{XK_dead_iota, XK_dead_acute, XK_Greek_alpha, XK_VoidSymbol}, "ᾴ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_Greek_alpha, XK_VoidSymbol}, "ᾴ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_Greek_alpha, XK_VoidSymbol}, "ᾴ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_Greek_alpha, XK_VoidSymbol}, "ᾴ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_Greek_alpha, XK_VoidSymbol}, "ᾴ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_Greek_alpha, XK_VoidSymbol}, "ᾴ"}, {{XK_Multi_key, XK_bracketleft, XK_bracketright, XK_VoidSymbol}, "⌷"}, // U2337 | [ ] APL FUNCTIONAL SYMBOL SQUISH QUAD {{XK_Multi_key, XK_bracketright, XK_bracketleft, XK_VoidSymbol}, "⌷"}, {{XK_Multi_key, XK_p, XK_exclam, XK_VoidSymbol}, "¶"}, // paragraph | PILCROW SIGN {{XK_Multi_key, XK_P, XK_exclam, XK_VoidSymbol}, "¶"}, {{XK_Multi_key, XK_P, XK_P, XK_VoidSymbol}, "¶"}, {{XK_dead_breve, XK_Cyrillic_i, XK_VoidSymbol}, "й"}, // U0439 | CYRILLIC SMALL LETTER SHORT I {{XK_Multi_key, XK_U, XK_Cyrillic_i, XK_VoidSymbol}, "й"}, {{XK_Multi_key, XK_b, XK_Cyrillic_i, XK_VoidSymbol}, "й"}, {{XK_dead_diaeresis, XK_space, XK_VoidSymbol}, "\""}, // quotedbl | REVERSE SOLIDUS {{XK_dead_cedilla, XK_L, XK_VoidSymbol}, "Ļ"}, // U013B | LATIN CAPITAL LETTER L WITH CEDILLA {{XK_Multi_key, XK_comma, XK_L, XK_VoidSymbol}, "Ļ"}, {{XK_Multi_key, XK_L, XK_comma, XK_VoidSymbol}, "Ļ"}, {{XK_Multi_key, XK_cedilla, XK_L, XK_VoidSymbol}, "Ļ"}, {{XK_dead_hook, XK_E, XK_VoidSymbol}, "Ẻ"}, // U1EBA | LATIN CAPITAL LETTER E WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_E, XK_VoidSymbol}, "Ẻ"}, {{XK_dead_tilde, XK_dead_dasia, XK_Greek_IOTA, XK_VoidSymbol}, "Ἷ"}, // U1F3F | GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_IOTA, XK_VoidSymbol}, "Ἷ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_IOTA, XK_VoidSymbol}, "Ἷ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_IOTA, XK_VoidSymbol}, "Ἷ"}, {{XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ô"}, // ocircumflex | LATIN SMALL LETTER O WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_o, XK_VoidSymbol}, "ô"}, {{XK_Multi_key, XK_o, XK_asciicircum, XK_VoidSymbol}, "ô"}, {{XK_Multi_key, XK_greater, XK_o, XK_VoidSymbol}, "ô"}, {{XK_Multi_key, XK_o, XK_greater, XK_VoidSymbol}, "ô"}, {{XK_dead_hook, XK_W, XK_VoidSymbol}, "Ⱳ"}, // U2C72 | LATIN CAPITAL LETTER W WITH HOOK {{XK_dead_abovedot, XK_n, XK_VoidSymbol}, "ṅ"}, // U1E45 | LATIN SMALL LETTER N WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_n, XK_VoidSymbol}, "ṅ"}, {{XK_dead_iota, XK_Greek_etaaccent, XK_VoidSymbol}, "ῄ"}, // U1FC4 | GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_etaaccent, XK_VoidSymbol}, "ῄ"}, {{XK_dead_iota, XK_dead_acute, XK_Greek_eta, XK_VoidSymbol}, "ῄ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_Greek_eta, XK_VoidSymbol}, "ῄ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_Greek_eta, XK_VoidSymbol}, "ῄ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_Greek_eta, XK_VoidSymbol}, "ῄ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_Greek_eta, XK_VoidSymbol}, "ῄ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_Greek_eta, XK_VoidSymbol}, "ῄ"}, {{XK_Multi_key, XK_A, XK_E, XK_VoidSymbol}, "Æ"}, // AE | LATIN CAPITAL LETTER AE {{XK_Multi_key, XK_3, XK_8, XK_VoidSymbol}, "⅜"}, // U215C | VULGAR FRACTION THREE EIGHTHS {{XK_Multi_key, XK_n, XK_g, XK_VoidSymbol}, "ŋ"}, // U014B | LATIN SMALL LETTER ENG {{XK_dead_belowdot, XK_I, XK_VoidSymbol}, "Ị"}, // U1ECA | LATIN CAPITAL LETTER I WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_I, XK_VoidSymbol}, "Ị"}, {{XK_dead_stroke, XK_r, XK_VoidSymbol}, "ɍ"}, // U024D | LATIN SMALL LETTER R WITH STROKE {{XK_dead_acute, XK_Greek_omicron, XK_VoidSymbol}, "ό"}, // U03CC | GREEK SMALL LETTER OMICRON WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_omicron, XK_VoidSymbol}, "ό"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_omicron, XK_VoidSymbol}, "ό"}, {{XK_Multi_key, XK_Greek_omicron, XK_apostrophe, XK_VoidSymbol}, "ό"}, {{XK_dead_acute, XK_Otilde, XK_VoidSymbol}, "Ṍ"}, // U1E4C | LATIN CAPITAL LETTER O WITH TILDE AND ACUTE {{XK_Multi_key, XK_acute, XK_Otilde, XK_VoidSymbol}, "Ṍ"}, {{XK_Multi_key, XK_apostrophe, XK_Otilde, XK_VoidSymbol}, "Ṍ"}, {{XK_dead_acute, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ṍ"}, {{XK_dead_acute, XK_Multi_key, XK_asciitilde, XK_O, XK_VoidSymbol}, "Ṍ"}, {{XK_Multi_key, XK_acute, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ṍ"}, {{XK_Multi_key, XK_acute, XK_asciitilde, XK_O, XK_VoidSymbol}, "Ṍ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ṍ"}, {{XK_Multi_key, XK_apostrophe, XK_asciitilde, XK_O, XK_VoidSymbol}, "Ṍ"}, {{XK_dead_tilde, XK_Oacute, XK_VoidSymbol}, "Ṍ"}, {{XK_dead_tilde, XK_dead_acute, XK_O, XK_VoidSymbol}, "Ṍ"}, {{XK_dead_caron, XK_i, XK_VoidSymbol}, "ǐ"}, // U01D0 | LATIN SMALL LETTER I WITH CARON {{XK_Multi_key, XK_c, XK_i, XK_VoidSymbol}, "ǐ"}, {{XK_Multi_key, XK_parenleft, XK_kana_U, XK_parenright, XK_VoidSymbol}, "㋒"}, // U32D2 | CIRCLED KATAKANA U {{XK_dead_acute, XK_p, XK_VoidSymbol}, "ṕ"}, // U1E55 | LATIN SMALL LETTER P WITH ACUTE {{XK_Multi_key, XK_acute, XK_p, XK_VoidSymbol}, "ṕ"}, {{XK_Multi_key, XK_apostrophe, XK_p, XK_VoidSymbol}, "ṕ"}, {{XK_dead_diaeresis, XK_O, XK_VoidSymbol}, "Ö"}, // Odiaeresis | LATIN CAPITAL LETTER O WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_O, XK_VoidSymbol}, "Ö"}, {{XK_Multi_key, XK_O, XK_quotedbl, XK_VoidSymbol}, "Ö"}, {{XK_Multi_key, XK_diaeresis, XK_O, XK_VoidSymbol}, "Ö"}, {{XK_Multi_key, XK_O, XK_diaeresis, XK_VoidSymbol}, "Ö"}, {{XK_dead_hook, XK_z, XK_VoidSymbol}, "ȥ"}, // U0225 | LATIN SMALL LETTER Z WITH HOOK {{XK_dead_acute, XK_s, XK_VoidSymbol}, "ś"}, // U015B | LATIN SMALL LETTER S WITH ACUTE {{XK_Multi_key, XK_acute, XK_s, XK_VoidSymbol}, "ś"}, {{XK_Multi_key, XK_apostrophe, XK_s, XK_VoidSymbol}, "ś"}, {{XK_Multi_key, XK_s, XK_apostrophe, XK_VoidSymbol}, "ś"}, {{XK_dead_acute, XK_Ohorn, XK_VoidSymbol}, "Ớ"}, // U1EDA | LATIN CAPITAL LETTER O WITH HORN AND ACUTE {{XK_Multi_key, XK_acute, XK_Ohorn, XK_VoidSymbol}, "Ớ"}, {{XK_Multi_key, XK_apostrophe, XK_Ohorn, XK_VoidSymbol}, "Ớ"}, {{XK_dead_acute, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ớ"}, {{XK_dead_acute, XK_Multi_key, XK_plus, XK_O, XK_VoidSymbol}, "Ớ"}, {{XK_Multi_key, XK_acute, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ớ"}, {{XK_Multi_key, XK_acute, XK_plus, XK_O, XK_VoidSymbol}, "Ớ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ớ"}, {{XK_Multi_key, XK_apostrophe, XK_plus, XK_O, XK_VoidSymbol}, "Ớ"}, {{XK_dead_horn, XK_Oacute, XK_VoidSymbol}, "Ớ"}, {{XK_dead_horn, XK_dead_acute, XK_O, XK_VoidSymbol}, "Ớ"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_3, XK_parenright, XK_VoidSymbol}, "㉝"}, // U325D | CIRCLED NUMBER THIRTY THREE {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_3, XK_parenright, XK_VoidSymbol}, "㉝"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_3, XK_parenright, XK_VoidSymbol}, "㉝"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_3, XK_parenright, XK_VoidSymbol}, "㉝"}, {{XK_dead_tilde, XK_dead_dasia, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὗ"}, // U1F5F | GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὗ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὗ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὗ"}, {{XK_dead_diaeresis, XK_Cyrillic_ZE, XK_VoidSymbol}, "Ӟ"}, // U04DE | CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_ZE, XK_VoidSymbol}, "Ӟ"}, {{XK_Multi_key, XK_1, XK_8, XK_VoidSymbol}, "⅛"}, // U215B | VULGAR FRACTION ONE EIGHTH {{XK_dead_macron, XK_dead_abovedot, XK_A, XK_VoidSymbol}, "Ǡ"}, // U01E0 | LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON {{XK_dead_macron, XK_Multi_key, XK_period, XK_A, XK_VoidSymbol}, "Ǡ"}, {{XK_Multi_key, XK_macron, XK_dead_abovedot, XK_A, XK_VoidSymbol}, "Ǡ"}, {{XK_Multi_key, XK_macron, XK_period, XK_A, XK_VoidSymbol}, "Ǡ"}, {{XK_Multi_key, XK_underscore, XK_dead_abovedot, XK_A, XK_VoidSymbol}, "Ǡ"}, {{XK_Multi_key, XK_underscore, XK_period, XK_A, XK_VoidSymbol}, "Ǡ"}, {{XK_dead_abovedot, XK_Amacron, XK_VoidSymbol}, "Ǡ"}, {{XK_dead_abovedot, XK_dead_macron, XK_A, XK_VoidSymbol}, "Ǡ"}, {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_s, XK_VoidSymbol}, "ˢ"}, // U02E2 | MODIFIER LETTER SMALL S {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_s, XK_VoidSymbol}, "ˢ"}, {{XK_Multi_key, XK_less, XK_3, XK_VoidSymbol}, "♥"}, // U2665 | BLACK HEART SUIT {{XK_dead_psili, XK_Greek_rho, XK_VoidSymbol}, "ῤ"}, // U1FE4 | GREEK SMALL LETTER RHO WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_rho, XK_VoidSymbol}, "ῤ"}, {{XK_Multi_key, XK_a, XK_e, XK_VoidSymbol}, "æ"}, // ae | LATIN SMALL LETTER AE {{XK_Multi_key, XK_parenleft, XK_1, XK_0, XK_parenright, XK_VoidSymbol}, "⑩"}, // U2469 | CIRCLED NUMBER TEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_0, XK_parenright, XK_VoidSymbol}, "⑩"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_0, XK_parenright, XK_VoidSymbol}, "⑩"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_0, XK_parenright, XK_VoidSymbol}, "⑩"}, {{XK_dead_acute, XK_Cyrillic_IE, XK_VoidSymbol}, "Е́"}, // CYRILLIC CAPITAL LETTER IE WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_IE, XK_VoidSymbol}, "Е́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_IE, XK_VoidSymbol}, "Е́"}, {{XK_dead_macron, XK_u, XK_VoidSymbol}, "ū"}, // U016B | LATIN SMALL LETTER U WITH MACRON {{XK_Multi_key, XK_macron, XK_u, XK_VoidSymbol}, "ū"}, {{XK_Multi_key, XK_underscore, XK_u, XK_VoidSymbol}, "ū"}, {{XK_Multi_key, XK_u, XK_underscore, XK_VoidSymbol}, "ū"}, {{XK_Multi_key, XK_minus, XK_u, XK_VoidSymbol}, "ū"}, {{XK_Multi_key, XK_u, XK_minus, XK_VoidSymbol}, "ū"}, {{XK_Multi_key, XK_exclam, XK_asciicircum, XK_VoidSymbol}, "¦"}, // brokenbar | BROKEN BAR {{XK_Multi_key, XK_parenleft, XK_d, XK_parenright, XK_VoidSymbol}, "ⓓ"}, // U24D3 | CIRCLED LATIN SMALL LETTER D {{XK_dead_tilde, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὧ"}, // U1F6F | GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὧ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὧ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὧ"}, {{XK_dead_macron, XK_Cyrillic_U, XK_VoidSymbol}, "Ӯ"}, // U04EE | CYRILLIC CAPITAL LETTER U WITH MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_U, XK_VoidSymbol}, "Ӯ"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_U, XK_VoidSymbol}, "Ӯ"}, {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_i, XK_VoidSymbol}, "ⁱ"}, // U2071 | SUPERSCRIPT LATIN SMALL LETTER I {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_i, XK_VoidSymbol}, "ⁱ"}, {{XK_dead_caron, XK_j, XK_VoidSymbol}, "ǰ"}, // U01F0 | LATIN SMALL LETTER J WITH CARON {{XK_Multi_key, XK_c, XK_j, XK_VoidSymbol}, "ǰ"}, {{XK_Multi_key, XK_parenleft, XK_kana_MO, XK_parenright, XK_VoidSymbol}, "㋲"}, // U32F2 | CIRCLED KATAKANA MO {{XK_dead_belowtilde, XK_u, XK_VoidSymbol}, "ṵ"}, // U1E75 | LATIN SMALL LETTER U WITH TILDE BELOW {{XK_dead_iota, XK_Greek_omegaaccent, XK_VoidSymbol}, "ῴ"}, // U1FF4 | GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_omegaaccent, XK_VoidSymbol}, "ῴ"}, {{XK_dead_iota, XK_dead_acute, XK_Greek_omega, XK_VoidSymbol}, "ῴ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_Greek_omega, XK_VoidSymbol}, "ῴ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_Greek_omega, XK_VoidSymbol}, "ῴ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_Greek_omega, XK_VoidSymbol}, "ῴ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_Greek_omega, XK_VoidSymbol}, "ῴ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_Greek_omega, XK_VoidSymbol}, "ῴ"}, {{XK_dead_diaeresis, XK_o, XK_VoidSymbol}, "ö"}, // odiaeresis | LATIN SMALL LETTER O WITH DIAERESIS {{XK_Multi_key, XK_o, XK_diaeresis, XK_VoidSymbol}, "ö"}, {{XK_Multi_key, XK_diaeresis, XK_o, XK_VoidSymbol}, "ö"}, {{XK_Multi_key, XK_quotedbl, XK_o, XK_VoidSymbol}, "ö"}, {{XK_Multi_key, XK_o, XK_quotedbl, XK_VoidSymbol}, "ö"}, {{XK_dead_invertedbreve, XK_Cyrillic_A, XK_VoidSymbol}, "А̑"}, // CYRILLIC CAPITAL LETTER A WITH COMBINING INVERTED BREVE {{XK_dead_abovedot, XK_Z, XK_VoidSymbol}, "Ż"}, // U017B | LATIN CAPITAL LETTER Z WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_Z, XK_VoidSymbol}, "Ż"}, {{XK_Multi_key, XK_Z, XK_period, XK_VoidSymbol}, "Ż"}, {{XK_dead_doublegrave, XK_A, XK_VoidSymbol}, "Ȁ"}, // U0200 | LATIN CAPITAL LETTER A WITH DOUBLE GRAVE {{XK_dead_acute, XK_w, XK_VoidSymbol}, "ẃ"}, // U1E83 | LATIN SMALL LETTER W WITH ACUTE {{XK_Multi_key, XK_acute, XK_w, XK_VoidSymbol}, "ẃ"}, {{XK_Multi_key, XK_apostrophe, XK_w, XK_VoidSymbol}, "ẃ"}, {{XK_dead_breve, XK_A, XK_VoidSymbol}, "Ă"}, // U0102 | LATIN CAPITAL LETTER A WITH BREVE {{XK_Multi_key, XK_U, XK_A, XK_VoidSymbol}, "Ă"}, {{XK_Multi_key, XK_u, XK_A, XK_VoidSymbol}, "Ă"}, {{XK_Multi_key, XK_b, XK_A, XK_VoidSymbol}, "Ă"}, {{XK_Multi_key, XK_A, XK_parenleft, XK_VoidSymbol}, "Ă"}, {{XK_dead_doublegrave, XK_Cyrillic_u, XK_VoidSymbol}, "у̏"}, // CYRILLIC SMALL LETTER U WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_u, XK_VoidSymbol}, "у̏"}, {{XK_Multi_key, XK_underscore, XK_7, XK_VoidSymbol}, "₇"}, // U2087 | SUBSCRIPT SEVEN {{XK_Multi_key, XK_underscore, XK_KP_7, XK_VoidSymbol}, "₇"}, {{XK_dead_caron, XK_7, XK_VoidSymbol}, "₇"}, {{XK_Multi_key, XK_d, XK_i, XK_VoidSymbol}, "⌀"}, // U2300 | DIAMETER SIGN {{XK_dead_iota, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾉ"}, // U1F89 | GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾉ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾉ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾉ"}, {{XK_dead_acute, XK_Ccedilla, XK_VoidSymbol}, "Ḉ"}, // U1E08 | LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE {{XK_Multi_key, XK_acute, XK_Ccedilla, XK_VoidSymbol}, "Ḉ"}, {{XK_Multi_key, XK_apostrophe, XK_Ccedilla, XK_VoidSymbol}, "Ḉ"}, {{XK_dead_acute, XK_dead_cedilla, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_dead_acute, XK_Multi_key, XK_comma, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_dead_acute, XK_Multi_key, XK_cedilla, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_Multi_key, XK_acute, XK_dead_cedilla, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_Multi_key, XK_acute, XK_comma, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_Multi_key, XK_acute, XK_cedilla, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_cedilla, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_Multi_key, XK_apostrophe, XK_cedilla, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_dead_cedilla, XK_Cacute, XK_VoidSymbol}, "Ḉ"}, {{XK_dead_cedilla, XK_dead_acute, XK_C, XK_VoidSymbol}, "Ḉ"}, {{XK_dead_hook, XK_v, XK_VoidSymbol}, "ʋ"}, // U028B | LATIN SMALL LETTER V WITH HOOK {{XK_Multi_key, XK_2, XK_5, XK_VoidSymbol}, "⅖"}, // U2156 | VULGAR FRACTION TWO FIFTHS {{XK_dead_tilde, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἆ"}, // U1F0E | GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἆ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἆ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἆ"}, {{XK_dead_doublegrave, XK_R, XK_VoidSymbol}, "Ȑ"}, // U0210 | LATIN CAPITAL LETTER R WITH DOUBLE GRAVE {{XK_dead_belowdot, XK_z, XK_VoidSymbol}, "ẓ"}, // U1E93 | LATIN SMALL LETTER Z WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_z, XK_VoidSymbol}, "ẓ"}, {{XK_dead_macron, XK_E, XK_VoidSymbol}, "Ē"}, // U0112 | LATIN CAPITAL LETTER E WITH MACRON {{XK_Multi_key, XK_macron, XK_E, XK_VoidSymbol}, "Ē"}, {{XK_Multi_key, XK_underscore, XK_E, XK_VoidSymbol}, "Ē"}, {{XK_Multi_key, XK_E, XK_underscore, XK_VoidSymbol}, "Ē"}, {{XK_Multi_key, XK_minus, XK_E, XK_VoidSymbol}, "Ē"}, {{XK_Multi_key, XK_E, XK_minus, XK_VoidSymbol}, "Ē"}, {{XK_Multi_key, XK_F, XK_U, XK_VoidSymbol}, "🖕"}, // U1F595 | REVERSED HAND WITH MIDDLE FINGER EXTENDED {{XK_dead_iota, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾙ"}, // U1F99 | GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾙ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾙ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾙ"}, {{XK_Multi_key, XK_question, XK_exclam, XK_VoidSymbol}, "⸘"}, // U2E18 | INVERTED INTERROBANG {{XK_dead_invertedbreve, XK_Cyrillic_u, XK_VoidSymbol}, "у̑"}, // CYRILLIC SMALL LETTER U WITH COMBINING INVERTED BREVE {{XK_dead_belowtilde, XK_i, XK_VoidSymbol}, "ḭ"}, // U1E2D | LATIN SMALL LETTER I WITH TILDE BELOW {{XK_Multi_key, XK_1, XK_7, XK_VoidSymbol}, "⅐"}, // U2150 | VULGAR FRACTION ONE SEVENTH {{XK_Multi_key, XK_less, XK_quotedbl, XK_VoidSymbol}, "“"}, // U201c | LEFT DOUBLE QUOTATION MARK {{XK_Multi_key, XK_quotedbl, XK_less, XK_VoidSymbol}, "“"}, {{XK_Multi_key, XK_slash, XK_Cyrillic_ka, XK_VoidSymbol}, "ҟ"}, // U049F | CYRILLIC SMALL LETTER KA WITH STROKE {{XK_Multi_key, XK_KP_Divide, XK_Cyrillic_ka, XK_VoidSymbol}, "ҟ"}, {{XK_dead_hook, XK_a, XK_VoidSymbol}, "ả"}, // U1EA3 | LATIN SMALL LETTER A WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_a, XK_VoidSymbol}, "ả"}, {{XK_dead_cedilla, XK_G, XK_VoidSymbol}, "Ģ"}, // U0122 | LATIN CAPITAL LETTER G WITH CEDILLA {{XK_Multi_key, XK_comma, XK_G, XK_VoidSymbol}, "Ģ"}, {{XK_Multi_key, XK_G, XK_comma, XK_VoidSymbol}, "Ģ"}, {{XK_Multi_key, XK_cedilla, XK_G, XK_VoidSymbol}, "Ģ"}, {{XK_Multi_key, XK_P, XK_t, XK_VoidSymbol}, "₧"}, // U20a7 | PESETA SIGN {{XK_dead_currency, XK_P, XK_VoidSymbol}, "₧"}, {{XK_dead_belowcomma, XK_nobreakspace, XK_VoidSymbol}, "̦"}, // U0326 | COMBINING COMMA BELOW {{XK_dead_iota, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾩ"}, // U1FA9 | GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾩ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾩ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾩ"}, {{XK_dead_cedilla, XK_H, XK_VoidSymbol}, "Ḩ"}, // U1E28 | LATIN CAPITAL LETTER H WITH CEDILLA {{XK_Multi_key, XK_comma, XK_H, XK_VoidSymbol}, "Ḩ"}, {{XK_Multi_key, XK_H, XK_comma, XK_VoidSymbol}, "Ḩ"}, {{XK_Multi_key, XK_cedilla, XK_H, XK_VoidSymbol}, "Ḩ"}, {{XK_dead_currency, XK_G, XK_VoidSymbol}, "₲"}, // U20B2 | GUARANI SIGN {{XK_dead_currency, XK_g, XK_VoidSymbol}, "₲"}, {{XK_dead_belowcomma, XK_dead_belowcomma, XK_VoidSymbol}, ","}, // comma | COMMA {{XK_dead_belowcomma, XK_space, XK_VoidSymbol}, ","}, {{XK_dead_tilde, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "Ἦ"}, // U1F2E | GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "Ἦ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "Ἦ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "Ἦ"}, {{XK_dead_hook, XK_b, XK_VoidSymbol}, "ɓ"}, // U0253 | LATIN SMALL LETTER B WITH HOOK {{XK_dead_macron, XK_dead_abovedot, XK_O, XK_VoidSymbol}, "Ȱ"}, // U0230 | LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON {{XK_dead_macron, XK_Multi_key, XK_period, XK_O, XK_VoidSymbol}, "Ȱ"}, {{XK_Multi_key, XK_macron, XK_dead_abovedot, XK_O, XK_VoidSymbol}, "Ȱ"}, {{XK_Multi_key, XK_macron, XK_period, XK_O, XK_VoidSymbol}, "Ȱ"}, {{XK_Multi_key, XK_underscore, XK_dead_abovedot, XK_O, XK_VoidSymbol}, "Ȱ"}, {{XK_Multi_key, XK_underscore, XK_period, XK_O, XK_VoidSymbol}, "Ȱ"}, {{XK_dead_abovedot, XK_Omacron, XK_VoidSymbol}, "Ȱ"}, {{XK_dead_abovedot, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ȱ"}, {{XK_dead_hook, XK_abreve, XK_VoidSymbol}, "ẳ"}, // U1EB3 | LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_abreve, XK_VoidSymbol}, "ẳ"}, {{XK_dead_hook, XK_dead_breve, XK_a, XK_VoidSymbol}, "ẳ"}, {{XK_dead_hook, XK_Multi_key, XK_U, XK_a, XK_VoidSymbol}, "ẳ"}, {{XK_dead_hook, XK_Multi_key, XK_b, XK_a, XK_VoidSymbol}, "ẳ"}, {{XK_Multi_key, XK_question, XK_dead_breve, XK_a, XK_VoidSymbol}, "ẳ"}, {{XK_Multi_key, XK_question, XK_b, XK_a, XK_VoidSymbol}, "ẳ"}, {{XK_dead_breve, XK_ahook, XK_VoidSymbol}, "ẳ"}, {{XK_dead_breve, XK_dead_hook, XK_a, XK_VoidSymbol}, "ẳ"}, {{XK_Multi_key, XK_I, XK_J, XK_VoidSymbol}, "IJ"}, // U0132 | LATIN CAPITAL LIGATURE IJ {{XK_Multi_key, XK_I, XK_j, XK_VoidSymbol}, "IJ"}, {{XK_dead_voiced_sound, XK_kana_KI, XK_VoidSymbol}, "ギ"}, // U30AE | KATAKANA LETTER GI {{XK_Multi_key, XK_period, XK_minus, XK_VoidSymbol}, "·"}, // periodcentered | MIDDLE DOT {{XK_Multi_key, XK_period, XK_asciicircum, XK_VoidSymbol}, "·"}, {{XK_Multi_key, XK_asciicircum, XK_period, XK_VoidSymbol}, "·"}, {{XK_dead_macron, XK_Greek_ALPHA, XK_VoidSymbol}, "Ᾱ"}, // U1FB9 | GREEK CAPITAL LETTER ALPHA WITH MACRON {{XK_Multi_key, XK_macron, XK_Greek_ALPHA, XK_VoidSymbol}, "Ᾱ"}, {{XK_Multi_key, XK_underscore, XK_Greek_ALPHA, XK_VoidSymbol}, "Ᾱ"}, {{XK_dead_macron, XK_dead_belowdot, XK_L, XK_VoidSymbol}, "Ḹ"}, // U1E38 | LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON {{XK_dead_macron, XK_Multi_key, XK_exclam, XK_L, XK_VoidSymbol}, "Ḹ"}, {{XK_Multi_key, XK_macron, XK_dead_belowdot, XK_L, XK_VoidSymbol}, "Ḹ"}, {{XK_Multi_key, XK_macron, XK_exclam, XK_L, XK_VoidSymbol}, "Ḹ"}, {{XK_Multi_key, XK_underscore, XK_dead_belowdot, XK_L, XK_VoidSymbol}, "Ḹ"}, {{XK_Multi_key, XK_underscore, XK_exclam, XK_L, XK_VoidSymbol}, "Ḹ"}, {{XK_dead_belowdot, XK_dead_macron, XK_L, XK_VoidSymbol}, "Ḹ"}, {{XK_Multi_key, XK_parenleft, XK_4, XK_6, XK_parenright, XK_VoidSymbol}, "㊻"}, // U32BB | CIRCLED NUMBER FORTY SIX {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_6, XK_parenright, XK_VoidSymbol}, "㊻"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_6, XK_parenright, XK_VoidSymbol}, "㊻"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_6, XK_parenright, XK_VoidSymbol}, "㊻"}, {{XK_Multi_key, XK_7, XK_8, XK_VoidSymbol}, "⅞"}, // U215E | VULGAR FRACTION SEVEN EIGHTHS {{XK_Multi_key, XK_parenleft, XK_J, XK_parenright, XK_VoidSymbol}, "Ⓙ"}, // U24BF | CIRCLED LATIN CAPITAL LETTER J {{XK_dead_tilde, XK_dead_psili, XK_Greek_IOTA, XK_VoidSymbol}, "Ἶ"}, // U1F3E | GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_IOTA, XK_VoidSymbol}, "Ἶ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_IOTA, XK_VoidSymbol}, "Ἶ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_IOTA, XK_VoidSymbol}, "Ἶ"}, {{XK_dead_hook, XK_ecircumflex, XK_VoidSymbol}, "ể"}, // U1EC3 | LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_ecircumflex, XK_VoidSymbol}, "ể"}, {{XK_dead_hook, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ể"}, {{XK_dead_hook, XK_Multi_key, XK_asciicircum, XK_e, XK_VoidSymbol}, "ể"}, {{XK_Multi_key, XK_question, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ể"}, {{XK_Multi_key, XK_question, XK_asciicircum, XK_e, XK_VoidSymbol}, "ể"}, {{XK_dead_circumflex, XK_ehook, XK_VoidSymbol}, "ể"}, {{XK_dead_circumflex, XK_dead_hook, XK_e, XK_VoidSymbol}, "ể"}, {{XK_dead_stroke, XK_l, XK_VoidSymbol}, "ł"}, // U0142 | LATIN SMALL LETTER L WITH STROKE {{XK_Multi_key, XK_slash, XK_l, XK_VoidSymbol}, "ł"}, {{XK_Multi_key, XK_l, XK_slash, XK_VoidSymbol}, "ł"}, {{XK_Multi_key, XK_KP_Divide, XK_l, XK_VoidSymbol}, "ł"}, {{XK_dead_cedilla, XK_C, XK_VoidSymbol}, "Ç"}, // Ccedilla | LATIN CAPITAL LETTER C WITH CEDILLA {{XK_Multi_key, XK_comma, XK_C, XK_VoidSymbol}, "Ç"}, {{XK_Multi_key, XK_C, XK_comma, XK_VoidSymbol}, "Ç"}, {{XK_Multi_key, XK_cedilla, XK_C, XK_VoidSymbol}, "Ç"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_parenright, XK_VoidSymbol}, "①"}, // U2460 | CIRCLED DIGIT ONE {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_parenright, XK_VoidSymbol}, "①"}, {{XK_dead_belowmacron, XK_N, XK_VoidSymbol}, "Ṉ"}, // U1E48 | LATIN CAPITAL LETTER N WITH LINE BELOW {{XK_dead_voiced_sound, XK_kana_SA, XK_VoidSymbol}, "ザ"}, // U30B6 | KATAKANA LETTER ZA {{XK_dead_caron, XK_A, XK_VoidSymbol}, "Ǎ"}, // U01CD | LATIN CAPITAL LETTER A WITH CARON {{XK_Multi_key, XK_c, XK_A, XK_VoidSymbol}, "Ǎ"}, {{XK_Multi_key, XK_parenleft, XK_t, XK_parenright, XK_VoidSymbol}, "ⓣ"}, // U24E3 | CIRCLED LATIN SMALL LETTER T {{XK_Multi_key, XK_parenleft, XK_Z, XK_parenright, XK_VoidSymbol}, "Ⓩ"}, // U24CF | CIRCLED LATIN CAPITAL LETTER Z {{XK_dead_grave, XK_ocircumflex, XK_VoidSymbol}, "ồ"}, // U1ED3 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE {{XK_Multi_key, XK_grave, XK_ocircumflex, XK_VoidSymbol}, "ồ"}, {{XK_dead_grave, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ồ"}, {{XK_dead_grave, XK_Multi_key, XK_asciicircum, XK_o, XK_VoidSymbol}, "ồ"}, {{XK_Multi_key, XK_grave, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ồ"}, {{XK_Multi_key, XK_grave, XK_asciicircum, XK_o, XK_VoidSymbol}, "ồ"}, {{XK_dead_circumflex, XK_ograve, XK_VoidSymbol}, "ồ"}, {{XK_dead_circumflex, XK_dead_grave, XK_o, XK_VoidSymbol}, "ồ"}, {{XK_Multi_key, XK_O, XK_E, XK_VoidSymbol}, "Œ"}, // OE | LATIN CAPITAL LIGATURE OE {{XK_Multi_key, XK_x, XK_x, XK_VoidSymbol}, "×"}, // multiply | MULTIPLICATION SIGN {{XK_dead_macron, XK_Greek_IOTA, XK_VoidSymbol}, "Ῑ"}, // U1FD9 | GREEK CAPITAL LETTER IOTA WITH MACRON {{XK_Multi_key, XK_macron, XK_Greek_IOTA, XK_VoidSymbol}, "Ῑ"}, {{XK_Multi_key, XK_underscore, XK_Greek_IOTA, XK_VoidSymbol}, "Ῑ"}, {{XK_dead_abovedot, XK_R, XK_VoidSymbol}, "Ṙ"}, // U1E58 | LATIN CAPITAL LETTER R WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_R, XK_VoidSymbol}, "Ṙ"}, {{XK_dead_ogonek, XK_space, XK_VoidSymbol}, "˛"}, // ogonek | OGONEK {{XK_dead_ogonek, XK_dead_ogonek, XK_VoidSymbol}, "˛"}, {{XK_Multi_key, XK_slash, XK_slash, XK_VoidSymbol}, "\\"}, // backslash | REVERSE SOLIDUS {{XK_Multi_key, XK_slash, XK_less, XK_VoidSymbol}, "\\"}, {{XK_Multi_key, XK_less, XK_slash, XK_VoidSymbol}, "\\"}, {{XK_dead_diaeresis, XK_Cyrillic_ze, XK_VoidSymbol}, "ӟ"}, // U04DF | CYRILLIC SMALL LETTER ZE WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_ze, XK_VoidSymbol}, "ӟ"}, {{XK_dead_voiced_sound, XK_kana_TO, XK_VoidSymbol}, "ド"}, // U30C9 | KATAKANA LETTER DO {{XK_Multi_key, XK_slash, XK_equal, XK_VoidSymbol}, "≠"}, // U2260 | NOT EQUAL TO {{XK_Multi_key, XK_equal, XK_slash, XK_VoidSymbol}, "≠"}, {{XK_dead_stroke, XK_equal, XK_VoidSymbol}, "≠"}, {{XK_dead_belowdot, XK_ohorn, XK_VoidSymbol}, "ợ"}, // U1EE3 | LATIN SMALL LETTER O WITH HORN AND DOT BELOW {{XK_Multi_key, XK_exclam, XK_ohorn, XK_VoidSymbol}, "ợ"}, {{XK_dead_belowdot, XK_dead_horn, XK_o, XK_VoidSymbol}, "ợ"}, {{XK_dead_belowdot, XK_Multi_key, XK_plus, XK_o, XK_VoidSymbol}, "ợ"}, {{XK_Multi_key, XK_exclam, XK_dead_horn, XK_o, XK_VoidSymbol}, "ợ"}, {{XK_Multi_key, XK_exclam, XK_plus, XK_o, XK_VoidSymbol}, "ợ"}, {{XK_dead_horn, XK_obelowdot, XK_VoidSymbol}, "ợ"}, {{XK_dead_horn, XK_dead_belowdot, XK_o, XK_VoidSymbol}, "ợ"}, {{XK_dead_cedilla, XK_T, XK_VoidSymbol}, "Ţ"}, // U0162 | LATIN CAPITAL LETTER T WITH CEDILLA {{XK_Multi_key, XK_comma, XK_T, XK_VoidSymbol}, "Ţ"}, {{XK_Multi_key, XK_T, XK_comma, XK_VoidSymbol}, "Ţ"}, {{XK_Multi_key, XK_cedilla, XK_T, XK_VoidSymbol}, "Ţ"}, {{XK_Multi_key, XK_parenleft, XK_5, XK_parenright, XK_VoidSymbol}, "⑤"}, // U2464 | CIRCLED DIGIT FIVE {{XK_Multi_key, XK_parenleft, XK_KP_5, XK_parenright, XK_VoidSymbol}, "⑤"}, {{XK_dead_cedilla, XK_c, XK_VoidSymbol}, "ç"}, // ccedilla | LATIN SMALL LETTER C WITH CEDILLA {{XK_Multi_key, XK_comma, XK_c, XK_VoidSymbol}, "ç"}, {{XK_Multi_key, XK_c, XK_comma, XK_VoidSymbol}, "ç"}, {{XK_Multi_key, XK_cedilla, XK_c, XK_VoidSymbol}, "ç"}, {{XK_dead_macron, XK_Greek_UPSILON, XK_VoidSymbol}, "Ῡ"}, // U1FE9 | GREEK CAPITAL LETTER UPSILON WITH MACRON {{XK_Multi_key, XK_macron, XK_Greek_UPSILON, XK_VoidSymbol}, "Ῡ"}, {{XK_Multi_key, XK_underscore, XK_Greek_UPSILON, XK_VoidSymbol}, "Ῡ"}, {{XK_dead_abovedot, XK_dead_belowdot, XK_S, XK_VoidSymbol}, "Ṩ"}, // U1E68 | LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE {{XK_dead_abovedot, XK_Multi_key, XK_exclam, XK_S, XK_VoidSymbol}, "Ṩ"}, {{XK_Multi_key, XK_period, XK_dead_belowdot, XK_S, XK_VoidSymbol}, "Ṩ"}, {{XK_Multi_key, XK_period, XK_exclam, XK_S, XK_VoidSymbol}, "Ṩ"}, {{XK_dead_belowdot, XK_Sabovedot, XK_VoidSymbol}, "Ṩ"}, {{XK_dead_belowdot, XK_dead_abovedot, XK_S, XK_VoidSymbol}, "Ṩ"}, {{XK_Multi_key, XK_parenleft, XK_kana_FU, XK_parenright, XK_VoidSymbol}, "㋫"}, // U32EB | CIRCLED KATAKANA HU {{XK_dead_macron, XK_dead_ogonek, XK_o, XK_VoidSymbol}, "ǭ"}, // U01ED | LATIN SMALL LETTER O WITH OGONEK AND MACRON {{XK_dead_macron, XK_Multi_key, XK_semicolon, XK_o, XK_VoidSymbol}, "ǭ"}, {{XK_Multi_key, XK_macron, XK_dead_ogonek, XK_o, XK_VoidSymbol}, "ǭ"}, {{XK_Multi_key, XK_macron, XK_semicolon, XK_o, XK_VoidSymbol}, "ǭ"}, {{XK_Multi_key, XK_underscore, XK_dead_ogonek, XK_o, XK_VoidSymbol}, "ǭ"}, {{XK_Multi_key, XK_underscore, XK_semicolon, XK_o, XK_VoidSymbol}, "ǭ"}, {{XK_dead_ogonek, XK_omacron, XK_VoidSymbol}, "ǭ"}, {{XK_dead_ogonek, XK_dead_macron, XK_o, XK_VoidSymbol}, "ǭ"}, {{XK_dead_macron, XK_Cyrillic_u, XK_VoidSymbol}, "ӯ"}, // U04EF | CYRILLIC SMALL LETTER U WITH MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_u, XK_VoidSymbol}, "ӯ"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_u, XK_VoidSymbol}, "ӯ"}, {{XK_dead_tilde, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὦ"}, // U1F6E | GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὦ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὦ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὦ"}, {{XK_dead_grave, XK_y, XK_VoidSymbol}, "ỳ"}, // U1EF3 | LATIN SMALL LETTER Y WITH GRAVE {{XK_Multi_key, XK_grave, XK_y, XK_VoidSymbol}, "ỳ"}, {{XK_dead_ogonek, XK_U, XK_VoidSymbol}, "Ų"}, // U0172 | LATIN CAPITAL LETTER U WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_U, XK_VoidSymbol}, "Ų"}, {{XK_Multi_key, XK_U, XK_semicolon, XK_VoidSymbol}, "Ų"}, {{XK_Multi_key, XK_comma, XK_U, XK_VoidSymbol}, "Ų"}, {{XK_Multi_key, XK_U, XK_comma, XK_VoidSymbol}, "Ų"}, {{XK_Multi_key, XK_slash, XK_minus, XK_VoidSymbol}, "⌿"}, // U233f | / - APL FUNCTIONAL SYMBOL SLASH BAR {{XK_Multi_key, XK_minus, XK_slash, XK_VoidSymbol}, "⌿"}, {{XK_Multi_key, XK_colon, XK_minus, XK_VoidSymbol}, "÷"}, // division | DIVISION SIGN {{XK_Multi_key, XK_minus, XK_colon, XK_VoidSymbol}, "÷"}, {{XK_dead_acute, XK_Utilde, XK_VoidSymbol}, "Ṹ"}, // U1E78 | LATIN CAPITAL LETTER U WITH TILDE AND ACUTE {{XK_Multi_key, XK_acute, XK_Utilde, XK_VoidSymbol}, "Ṹ"}, {{XK_Multi_key, XK_apostrophe, XK_Utilde, XK_VoidSymbol}, "Ṹ"}, {{XK_dead_acute, XK_dead_tilde, XK_U, XK_VoidSymbol}, "Ṹ"}, {{XK_dead_acute, XK_Multi_key, XK_asciitilde, XK_U, XK_VoidSymbol}, "Ṹ"}, {{XK_Multi_key, XK_acute, XK_dead_tilde, XK_U, XK_VoidSymbol}, "Ṹ"}, {{XK_Multi_key, XK_acute, XK_asciitilde, XK_U, XK_VoidSymbol}, "Ṹ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_tilde, XK_U, XK_VoidSymbol}, "Ṹ"}, {{XK_Multi_key, XK_apostrophe, XK_asciitilde, XK_U, XK_VoidSymbol}, "Ṹ"}, {{XK_dead_tilde, XK_Uacute, XK_VoidSymbol}, "Ṹ"}, {{XK_dead_tilde, XK_dead_acute, XK_U, XK_VoidSymbol}, "Ṹ"}, {{XK_Multi_key, XK_parenleft, XK_kana_WA, XK_parenright, XK_VoidSymbol}, "㋻"}, // U32FB | CIRCLED KATAKANA WA {{XK_Multi_key, XK_parenleft, XK_I, XK_parenright, XK_VoidSymbol}, "Ⓘ"}, // U24BE | CIRCLED LATIN CAPITAL LETTER I {{XK_dead_acute, XK_ae, XK_VoidSymbol}, "ǽ"}, // U01FD | LATIN SMALL LETTER AE WITH ACUTE {{XK_Multi_key, XK_acute, XK_ae, XK_VoidSymbol}, "ǽ"}, {{XK_Multi_key, XK_apostrophe, XK_ae, XK_VoidSymbol}, "ǽ"}, {{XK_Multi_key, XK_slash, XK_asciicircum, XK_VoidSymbol}, "|"}, // bar | VERTICAL LINE {{XK_Multi_key, XK_asciicircum, XK_slash, XK_VoidSymbol}, "|"}, {{XK_Multi_key, XK_V, XK_L, XK_VoidSymbol}, "|"}, {{XK_Multi_key, XK_L, XK_V, XK_VoidSymbol}, "|"}, {{XK_Multi_key, XK_v, XK_l, XK_VoidSymbol}, "|"}, {{XK_Multi_key, XK_l, XK_v, XK_VoidSymbol}, "|"}, {{XK_dead_invertedbreve, XK_Cyrillic_a, XK_VoidSymbol}, "а̑"}, // CYRILLIC SMALL LETTER A WITH COMBINING INVERTED BREVE {{XK_Multi_key, XK_f, XK_i, XK_VoidSymbol}, "fi"}, // Ufb01 | LATIN SMALL LIGATURE FI {{XK_dead_abovedot, XK_b, XK_VoidSymbol}, "ḃ"}, // U1E03 | LATIN SMALL LETTER B WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_b, XK_VoidSymbol}, "ḃ"}, {{XK_Multi_key, XK_b, XK_period, XK_VoidSymbol}, "ḃ"}, {{XK_dead_acute, XK_Greek_ALPHA, XK_VoidSymbol}, "Ά"}, // U0386 | GREEK CAPITAL LETTER ALPHA WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_ALPHA, XK_VoidSymbol}, "Ά"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_ALPHA, XK_VoidSymbol}, "Ά"}, {{XK_Multi_key, XK_Greek_ALPHA, XK_apostrophe, XK_VoidSymbol}, "Ά"}, {{XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἁ"}, // U1F09 | GREEK CAPITAL LETTER ALPHA WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἁ"}, {{XK_dead_belowdot, XK_W, XK_VoidSymbol}, "Ẉ"}, // U1E88 | LATIN CAPITAL LETTER W WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_W, XK_VoidSymbol}, "Ẉ"}, {{XK_dead_invertedbreve, XK_i, XK_VoidSymbol}, "ȋ"}, // U020B | LATIN SMALL LETTER I WITH INVERTED BREVE {{XK_dead_caron, XK_c, XK_VoidSymbol}, "č"}, // U010D | LATIN SMALL LETTER C WITH CARON {{XK_Multi_key, XK_c, XK_c, XK_VoidSymbol}, "č"}, {{XK_Multi_key, XK_less, XK_c, XK_VoidSymbol}, "č"}, {{XK_Multi_key, XK_c, XK_less, XK_VoidSymbol}, "č"}, {{XK_Multi_key, XK_underscore, XK_equal, XK_VoidSymbol}, "₌"}, // U208C | SUBSCRIPT EQUALS SIGN {{XK_Multi_key, XK_underscore, XK_KP_Equal, XK_VoidSymbol}, "₌"}, {{XK_dead_caron, XK_equal, XK_VoidSymbol}, "₌"}, {{XK_dead_belowdot, XK_T, XK_VoidSymbol}, "Ṭ"}, // U1E6C | LATIN CAPITAL LETTER T WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_T, XK_VoidSymbol}, "Ṭ"}, {{XK_Multi_key, XK_1, XK_3, XK_VoidSymbol}, "⅓"}, // U2153 | VULGAR FRACTION ONE THIRD {{XK_dead_belowcircumflex, XK_d, XK_VoidSymbol}, "ḓ"}, // U1E13 | LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW {{XK_Multi_key, XK_minus, XK_greater, XK_VoidSymbol}, "→"}, // U2192 | RIGHTWARDS ARROW {{XK_dead_dasia, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἑ"}, // U1F19 | GREEK CAPITAL LETTER EPSILON WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἑ"}, {{XK_dead_abovering, XK_w, XK_VoidSymbol}, "ẘ"}, // U1E98 | LATIN SMALL LETTER W WITH RING ABOVE {{XK_Multi_key, XK_o, XK_w, XK_VoidSymbol}, "ẘ"}, {{XK_dead_belowcomma, XK_t, XK_VoidSymbol}, "ț"}, // U021B | LATIN SMALL LETTER T WITH COMMA BELOW {{XK_Multi_key, XK_semicolon, XK_t, XK_VoidSymbol}, "ț"}, {{XK_Multi_key, XK_t, XK_semicolon, XK_VoidSymbol}, "ț"}, {{XK_dead_circumflex, XK_g, XK_VoidSymbol}, "ĝ"}, // U011D | LATIN SMALL LETTER G WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_g, XK_VoidSymbol}, "ĝ"}, {{XK_dead_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾞ"}, // U1F9E | GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾞ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾞ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾞ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾞ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾞ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾞ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾞ"}, {{XK_dead_hook, XK_q, XK_VoidSymbol}, "ʠ"}, // U02A0 | LATIN SMALL LETTER Q WITH HOOK {{XK_dead_abovedot, XK_h, XK_VoidSymbol}, "ḣ"}, // U1E23 | LATIN SMALL LETTER H WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_h, XK_VoidSymbol}, "ḣ"}, {{XK_dead_acute, XK_space, XK_VoidSymbol}, "'"}, // apostrophe | APOSTROPHE {{XK_Multi_key, XK_apostrophe, XK_space, XK_VoidSymbol}, "'"}, {{XK_Multi_key, XK_space, XK_apostrophe, XK_VoidSymbol}, "'"}, {{XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "Ἡ"}, // U1F29 | GREEK CAPITAL LETTER ETA WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "Ἡ"}, {{XK_dead_hook, XK_Acircumflex, XK_VoidSymbol}, "Ẩ"}, // U1EA8 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_Acircumflex, XK_VoidSymbol}, "Ẩ"}, {{XK_dead_hook, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ẩ"}, {{XK_dead_hook, XK_Multi_key, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ẩ"}, {{XK_Multi_key, XK_question, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ẩ"}, {{XK_Multi_key, XK_question, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ẩ"}, {{XK_dead_circumflex, XK_Ahook, XK_VoidSymbol}, "Ẩ"}, {{XK_dead_circumflex, XK_dead_hook, XK_A, XK_VoidSymbol}, "Ẩ"}, {{XK_dead_macron, XK_odiaeresis, XK_VoidSymbol}, "ȫ"}, // U022B | LATIN SMALL LETTER O WITH DIAERESIS AND MACRON {{XK_Multi_key, XK_macron, XK_odiaeresis, XK_VoidSymbol}, "ȫ"}, {{XK_Multi_key, XK_underscore, XK_odiaeresis, XK_VoidSymbol}, "ȫ"}, {{XK_dead_macron, XK_dead_diaeresis, XK_o, XK_VoidSymbol}, "ȫ"}, {{XK_dead_macron, XK_Multi_key, XK_quotedbl, XK_o, XK_VoidSymbol}, "ȫ"}, {{XK_Multi_key, XK_macron, XK_dead_diaeresis, XK_o, XK_VoidSymbol}, "ȫ"}, {{XK_Multi_key, XK_macron, XK_quotedbl, XK_o, XK_VoidSymbol}, "ȫ"}, {{XK_Multi_key, XK_underscore, XK_dead_diaeresis, XK_o, XK_VoidSymbol}, "ȫ"}, {{XK_Multi_key, XK_underscore, XK_quotedbl, XK_o, XK_VoidSymbol}, "ȫ"}, {{XK_dead_diaeresis, XK_omacron, XK_VoidSymbol}, "ȫ"}, {{XK_dead_diaeresis, XK_dead_macron, XK_o, XK_VoidSymbol}, "ȫ"}, {{XK_dead_breve, XK_i, XK_VoidSymbol}, "ĭ"}, // U012D | LATIN SMALL LETTER I WITH BREVE {{XK_Multi_key, XK_U, XK_i, XK_VoidSymbol}, "ĭ"}, {{XK_Multi_key, XK_b, XK_i, XK_VoidSymbol}, "ĭ"}, {{XK_Multi_key, XK_comma, XK_minus, XK_VoidSymbol}, "¬"}, // notsign | NOT SIGN {{XK_Multi_key, XK_minus, XK_comma, XK_VoidSymbol}, "¬"}, {{XK_dead_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾮ"}, // U1FAE | GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾮ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾮ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾮ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾮ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾮ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾮ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾮ"}, {{XK_dead_semivoiced_sound, XK_kana_HA, XK_VoidSymbol}, "パ"}, // U30D1 | KATAKANA LETTER PA {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_h, XK_VoidSymbol}, "ʰ"}, // U02B0 | MODIFIER LETTER SMALL H {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_h, XK_VoidSymbol}, "ʰ"}, {{XK_dead_belowdot, XK_k, XK_VoidSymbol}, "ḳ"}, // U1E33 | LATIN SMALL LETTER K WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_k, XK_VoidSymbol}, "ḳ"}, {{XK_dead_hook, XK_V, XK_VoidSymbol}, "Ʋ"}, // U01B2 | LATIN CAPITAL LETTER V WITH HOOK {{XK_dead_doublegrave, XK_Cyrillic_IE, XK_VoidSymbol}, "Е̏"}, // CYRILLIC CAPITAL LETTER IE WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_IE, XK_VoidSymbol}, "Е̏"}, {{XK_dead_hook, XK_w, XK_VoidSymbol}, "ⱳ"}, // U2C73 | LATIN SMALL LETTER W WITH HOOK {{XK_dead_dasia, XK_Greek_IOTA, XK_VoidSymbol}, "Ἱ"}, // U1F39 | GREEK CAPITAL LETTER IOTA WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_IOTA, XK_VoidSymbol}, "Ἱ"}, {{XK_dead_belowdot, XK_E, XK_VoidSymbol}, "Ẹ"}, // U1EB8 | LATIN CAPITAL LETTER E WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_E, XK_VoidSymbol}, "Ẹ"}, {{XK_dead_stroke, XK_C, XK_VoidSymbol}, "Ȼ"}, // U023B | LATIN CAPITAL LETTER C WITH STROKE {{XK_Multi_key, XK_8, XK_8, XK_VoidSymbol}, "∞"}, // U221e | 8 8 INFINITY {{XK_dead_caron, XK_L, XK_VoidSymbol}, "Ľ"}, // U013D | LATIN CAPITAL LETTER L WITH CARON {{XK_Multi_key, XK_c, XK_L, XK_VoidSymbol}, "Ľ"}, {{XK_Multi_key, XK_less, XK_L, XK_VoidSymbol}, "Ľ"}, {{XK_Multi_key, XK_L, XK_less, XK_VoidSymbol}, "Ľ"}, {{XK_Multi_key, XK_1, XK_4, XK_VoidSymbol}, "¼"}, // onequarter | VULGAR FRACTION ONE QUARTER {{XK_dead_semivoiced_sound, XK_kana_HO, XK_VoidSymbol}, "ポ"}, // U30DD | KATAKANA LETTER PO {{XK_dead_belowdot, XK_m, XK_VoidSymbol}, "ṃ"}, // U1E43 | LATIN SMALL LETTER M WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_m, XK_VoidSymbol}, "ṃ"}, {{XK_Multi_key, XK_parenleft, XK_O, XK_parenright, XK_VoidSymbol}, "Ⓞ"}, // U24C4 | CIRCLED LATIN CAPITAL LETTER O {{XK_dead_dasia, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὁ"}, // U1F49 | GREEK CAPITAL LETTER OMICRON WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὁ"}, {{XK_dead_hook, XK_I, XK_VoidSymbol}, "Ỉ"}, // U1EC8 | LATIN CAPITAL LETTER I WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_I, XK_VoidSymbol}, "Ỉ"}, {{XK_dead_macron, XK_o, XK_VoidSymbol}, "ō"}, // U014D | LATIN SMALL LETTER O WITH MACRON {{XK_Multi_key, XK_macron, XK_o, XK_VoidSymbol}, "ō"}, {{XK_Multi_key, XK_underscore, XK_o, XK_VoidSymbol}, "ō"}, {{XK_Multi_key, XK_o, XK_underscore, XK_VoidSymbol}, "ō"}, {{XK_Multi_key, XK_minus, XK_o, XK_VoidSymbol}, "ō"}, {{XK_Multi_key, XK_o, XK_minus, XK_VoidSymbol}, "ō"}, {{XK_dead_grave, XK_I, XK_VoidSymbol}, "Ì"}, // Igrave | LATIN CAPITAL LETTER I WITH GRAVE {{XK_Multi_key, XK_grave, XK_I, XK_VoidSymbol}, "Ì"}, {{XK_Multi_key, XK_I, XK_grave, XK_VoidSymbol}, "Ì"}, {{XK_Multi_key, XK_parenleft, XK_kana_A, XK_parenright, XK_VoidSymbol}, "㋐"}, // U32D0 | CIRCLED KATAKANA A {{XK_dead_acute, XK_omacron, XK_VoidSymbol}, "ṓ"}, // U1E53 | LATIN SMALL LETTER O WITH MACRON AND ACUTE {{XK_Multi_key, XK_acute, XK_omacron, XK_VoidSymbol}, "ṓ"}, {{XK_Multi_key, XK_apostrophe, XK_omacron, XK_VoidSymbol}, "ṓ"}, {{XK_dead_acute, XK_dead_macron, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_dead_acute, XK_Multi_key, XK_macron, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_dead_acute, XK_Multi_key, XK_underscore, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_Multi_key, XK_acute, XK_dead_macron, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_Multi_key, XK_acute, XK_macron, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_Multi_key, XK_acute, XK_underscore, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_macron, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_Multi_key, XK_apostrophe, XK_macron, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_Multi_key, XK_apostrophe, XK_underscore, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_dead_macron, XK_oacute, XK_VoidSymbol}, "ṓ"}, {{XK_dead_macron, XK_dead_acute, XK_o, XK_VoidSymbol}, "ṓ"}, {{XK_dead_caron, XK_o, XK_VoidSymbol}, "ǒ"}, // U01D2 | LATIN SMALL LETTER O WITH CARON {{XK_Multi_key, XK_c, XK_o, XK_VoidSymbol}, "ǒ"}, {{XK_Multi_key, XK_1, XK_5, XK_VoidSymbol}, "⅕"}, // U2155 | VULGAR FRACTION ONE FIFTH {{XK_Multi_key, XK_parenleft, XK_e, XK_parenright, XK_VoidSymbol}, "ⓔ"}, // U24D4 | CIRCLED LATIN SMALL LETTER E {{XK_dead_dasia, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὑ"}, // U1F59 | GREEK CAPITAL LETTER UPSILON WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὑ"}, {{XK_Multi_key, XK_m, XK_slash, XK_VoidSymbol}, "₥"}, // U20a5 | MILL SIGN {{XK_Multi_key, XK_slash, XK_m, XK_VoidSymbol}, "₥"}, {{XK_dead_currency, XK_m, XK_VoidSymbol}, "₥"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_1, XK_parenright, XK_VoidSymbol}, "㉛"}, // U325B | CIRCLED NUMBER THIRTY ONE {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_1, XK_parenright, XK_VoidSymbol}, "㉛"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_1, XK_parenright, XK_VoidSymbol}, "㉛"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_1, XK_parenright, XK_VoidSymbol}, "㉛"}, {{XK_Multi_key, XK_parenleft, XK_Y, XK_parenright, XK_VoidSymbol}, "Ⓨ"}, // U24CE | CIRCLED LATIN CAPITAL LETTER Y {{XK_dead_circumflex, XK_s, XK_VoidSymbol}, "ŝ"}, // U015D | LATIN SMALL LETTER S WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_s, XK_VoidSymbol}, "ŝ"}, {{XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ü"}, // Udiaeresis | LATIN CAPITAL LETTER U WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ü"}, {{XK_Multi_key, XK_U, XK_quotedbl, XK_VoidSymbol}, "Ü"}, {{XK_Multi_key, XK_diaeresis, XK_U, XK_VoidSymbol}, "Ü"}, {{XK_Multi_key, XK_U, XK_diaeresis, XK_VoidSymbol}, "Ü"}, {{XK_Multi_key, XK_parenleft, XK_kana_CHI, XK_parenright, XK_VoidSymbol}, "㋠"}, // U32E0 | CIRCLED KATAKANA TI {{XK_dead_belowdot, XK_s, XK_VoidSymbol}, "ṣ"}, // U1E63 | LATIN SMALL LETTER S WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_s, XK_VoidSymbol}, "ṣ"}, {{XK_dead_macron, XK_AE, XK_VoidSymbol}, "Ǣ"}, // U01E2 | LATIN CAPITAL LETTER AE WITH MACRON {{XK_Multi_key, XK_macron, XK_AE, XK_VoidSymbol}, "Ǣ"}, {{XK_Multi_key, XK_underscore, XK_AE, XK_VoidSymbol}, "Ǣ"}, {{XK_dead_circumflex, XK_Cyrillic_u, XK_VoidSymbol}, "у̂"}, // CYRILLIC SMALL LETTER U WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_u, XK_VoidSymbol}, "у̂"}, {{XK_dead_diaeresis, XK_Cyrillic_I, XK_VoidSymbol}, "Ӥ"}, // U04E4 | CYRILLIC CAPITAL LETTER I WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_I, XK_VoidSymbol}, "Ӥ"}, {{XK_dead_invertedbreve, XK_Cyrillic_er, XK_VoidSymbol}, "р̑"}, // CYRILLIC SMALL LETTER ER WITH COMBINING INVERTED BREVE {{XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὡ"}, // U1F69 | GREEK CAPITAL LETTER OMEGA WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὡ"}, {{XK_dead_acute, XK_Uhorn, XK_VoidSymbol}, "Ứ"}, // U1EE8 | LATIN CAPITAL LETTER U WITH HORN AND ACUTE {{XK_Multi_key, XK_acute, XK_Uhorn, XK_VoidSymbol}, "Ứ"}, {{XK_Multi_key, XK_apostrophe, XK_Uhorn, XK_VoidSymbol}, "Ứ"}, {{XK_dead_acute, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ứ"}, {{XK_dead_acute, XK_Multi_key, XK_plus, XK_U, XK_VoidSymbol}, "Ứ"}, {{XK_Multi_key, XK_acute, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ứ"}, {{XK_Multi_key, XK_acute, XK_plus, XK_U, XK_VoidSymbol}, "Ứ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ứ"}, {{XK_Multi_key, XK_apostrophe, XK_plus, XK_U, XK_VoidSymbol}, "Ứ"}, {{XK_dead_horn, XK_Uacute, XK_VoidSymbol}, "Ứ"}, {{XK_dead_horn, XK_dead_acute, XK_U, XK_VoidSymbol}, "Ứ"}, {{XK_dead_currency, XK_u, XK_VoidSymbol}, "元"}, // U5143 | YUAN / WEN {{XK_dead_belowtilde, XK_plus, XK_VoidSymbol}, "⨦"}, // U2A26 | PLUS SIGN WITH TILDE BELOW {{XK_dead_breve, XK_u, XK_VoidSymbol}, "ŭ"}, // U016D | LATIN SMALL LETTER U WITH BREVE {{XK_Multi_key, XK_U, XK_u, XK_VoidSymbol}, "ŭ"}, {{XK_Multi_key, XK_u, XK_u, XK_VoidSymbol}, "ŭ"}, {{XK_Multi_key, XK_b, XK_u, XK_VoidSymbol}, "ŭ"}, {{XK_dead_grave, XK_i, XK_VoidSymbol}, "ì"}, // igrave | LATIN SMALL LETTER I WITH GRAVE {{XK_Multi_key, XK_grave, XK_i, XK_VoidSymbol}, "ì"}, {{XK_Multi_key, XK_i, XK_grave, XK_VoidSymbol}, "ì"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_6, XK_parenright, XK_VoidSymbol}, "⑯"}, // U246F | CIRCLED NUMBER SIXTEEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_6, XK_parenright, XK_VoidSymbol}, "⑯"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_6, XK_parenright, XK_VoidSymbol}, "⑯"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_6, XK_parenright, XK_VoidSymbol}, "⑯"}, {{XK_dead_belowring, XK_bar, XK_VoidSymbol}, "⫰"}, // U2AF0 | VERTICAL LINE WITH CIRCLE BELOW {{XK_dead_belowdiaeresis, XK_u, XK_VoidSymbol}, "ṳ"}, // U1E73 | LATIN SMALL LETTER U WITH DIAERESIS BELOW {{XK_dead_grave, XK_Ocircumflex, XK_VoidSymbol}, "Ồ"}, // U1ED2 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE {{XK_Multi_key, XK_grave, XK_Ocircumflex, XK_VoidSymbol}, "Ồ"}, {{XK_dead_grave, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ồ"}, {{XK_dead_grave, XK_Multi_key, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ồ"}, {{XK_Multi_key, XK_grave, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ồ"}, {{XK_Multi_key, XK_grave, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ồ"}, {{XK_dead_circumflex, XK_Ograve, XK_VoidSymbol}, "Ồ"}, {{XK_dead_circumflex, XK_dead_grave, XK_O, XK_VoidSymbol}, "Ồ"}, {{XK_dead_diaeresis, XK_Cyrillic_CHE, XK_VoidSymbol}, "Ӵ"}, // U04F4 | CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_CHE, XK_VoidSymbol}, "Ӵ"}, {{XK_dead_circumflex, XK_7, XK_VoidSymbol}, "⁷"}, // U2077 | SUPERSCRIPT SEVEN {{XK_Multi_key, XK_asciicircum, XK_7, XK_VoidSymbol}, "⁷"}, {{XK_dead_circumflex, XK_KP_7, XK_VoidSymbol}, "⁷"}, {{XK_Multi_key, XK_asciicircum, XK_KP_7, XK_VoidSymbol}, "⁷"}, {{XK_dead_tilde, XK_Y, XK_VoidSymbol}, "Ỹ"}, // U1EF8 | LATIN CAPITAL LETTER Y WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_Y, XK_VoidSymbol}, "Ỹ"}, {{XK_dead_voiced_sound, XK_kana_HO, XK_VoidSymbol}, "ボ"}, // U30DC | KATAKANA LETTER BO {{XK_dead_caron, XK_Z, XK_VoidSymbol}, "Ž"}, // U017D | LATIN CAPITAL LETTER Z WITH CARON {{XK_Multi_key, XK_c, XK_Z, XK_VoidSymbol}, "Ž"}, {{XK_Multi_key, XK_v, XK_Z, XK_VoidSymbol}, "Ž"}, {{XK_Multi_key, XK_less, XK_Z, XK_VoidSymbol}, "Ž"}, {{XK_Multi_key, XK_Z, XK_less, XK_VoidSymbol}, "Ž"}, {{XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ü"}, // udiaeresis | LATIN SMALL LETTER U WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_u, XK_VoidSymbol}, "ü"}, {{XK_Multi_key, XK_u, XK_quotedbl, XK_VoidSymbol}, "ü"}, {{XK_Multi_key, XK_diaeresis, XK_u, XK_VoidSymbol}, "ü"}, {{XK_Multi_key, XK_u, XK_diaeresis, XK_VoidSymbol}, "ü"}, {{XK_dead_circumflex, XK_Cyrillic_IE, XK_VoidSymbol}, "Е̂"}, // CYRILLIC CAPITAL LETTER IE WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_IE, XK_VoidSymbol}, "Е̂"}, {{XK_Multi_key, XK_f, XK_f, XK_VoidSymbol}, "ff"}, // Ufb00 | LATIN SMALL LIGATURE FF {{XK_dead_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾃ"}, // U1F83 | GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾃ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾃ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾃ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾃ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾃ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾃ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾃ"}, {{XK_dead_hook, XK_C, XK_VoidSymbol}, "Ƈ"}, // U0187 | LATIN CAPITAL LETTER C WITH HOOK {{XK_dead_invertedbreve, XK_E, XK_VoidSymbol}, "Ȇ"}, // U0206 | LATIN CAPITAL LETTER E WITH INVERTED BREVE {{XK_dead_belowdot, XK_w, XK_VoidSymbol}, "ẉ"}, // U1E89 | LATIN SMALL LETTER W WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_w, XK_VoidSymbol}, "ẉ"}, {{XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἀ"}, // U1F08 | GREEK CAPITAL LETTER ALPHA WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἀ"}, {{XK_Multi_key, XK_parenleft, XK_g, XK_parenright, XK_VoidSymbol}, "ⓖ"}, // U24D6 | CIRCLED LATIN SMALL LETTER G {{XK_Multi_key, XK_underscore, XK_parenleft, XK_VoidSymbol}, "₍"}, // U208D | SUBSCRIPT LEFT PARENTHESIS {{XK_dead_caron, XK_parenleft, XK_VoidSymbol}, "₍"}, {{XK_dead_caron, XK_C, XK_VoidSymbol}, "Č"}, // U010C | LATIN CAPITAL LETTER C WITH CARON {{XK_Multi_key, XK_c, XK_C, XK_VoidSymbol}, "Č"}, {{XK_Multi_key, XK_less, XK_C, XK_VoidSymbol}, "Č"}, {{XK_Multi_key, XK_C, XK_less, XK_VoidSymbol}, "Č"}, {{XK_dead_belowmacron, XK_D, XK_VoidSymbol}, "Ḏ"}, // U1E0E | LATIN CAPITAL LETTER D WITH LINE BELOW {{XK_dead_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾓ"}, // U1F93 | GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾓ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾓ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾓ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾓ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾓ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾓ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾓ"}, {{XK_dead_stroke, XK_I, XK_VoidSymbol}, "Ɨ"}, // U0197 | LATIN CAPITAL LETTER I WITH STROKE {{XK_Multi_key, XK_slash, XK_I, XK_VoidSymbol}, "Ɨ"}, {{XK_Multi_key, XK_KP_Divide, XK_I, XK_VoidSymbol}, "Ɨ"}, {{XK_dead_invertedbreve, XK_U, XK_VoidSymbol}, "Ȗ"}, // U0216 | LATIN CAPITAL LETTER U WITH INVERTED BREVE {{XK_dead_abovering, XK_y, XK_VoidSymbol}, "ẙ"}, // U1E99 | LATIN SMALL LETTER Y WITH RING ABOVE {{XK_Multi_key, XK_o, XK_y, XK_VoidSymbol}, "ẙ"}, {{XK_dead_psili, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἐ"}, // U1F18 | GREEK CAPITAL LETTER EPSILON WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἐ"}, {{XK_Multi_key, XK_parenleft, XK_kana_MU, XK_parenright, XK_VoidSymbol}, "㋰"}, // U32F0 | CIRCLED KATAKANA MU {{XK_dead_circumflex, XK_G, XK_VoidSymbol}, "Ĝ"}, // U011C | LATIN CAPITAL LETTER G WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_G, XK_VoidSymbol}, "Ĝ"}, {{XK_dead_abovedot, XK_F, XK_VoidSymbol}, "Ḟ"}, // U1E1E | LATIN CAPITAL LETTER F WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_F, XK_VoidSymbol}, "Ḟ"}, {{XK_Multi_key, XK_F, XK_period, XK_VoidSymbol}, "Ḟ"}, {{XK_dead_circumflex, XK_Cyrillic_I, XK_VoidSymbol}, "И̂"}, // CYRILLIC CAPITAL LETTER I WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_I, XK_VoidSymbol}, "И̂"}, {{XK_dead_circumflex, XK_Cyrillic_A, XK_VoidSymbol}, "А̂"}, // CYRILLIC CAPITAL LETTER A WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_A, XK_VoidSymbol}, "А̂"}, {{XK_dead_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾣ"}, // U1FA3 | GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾣ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾣ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾣ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾣ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾣ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾣ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾣ"}, {{XK_Multi_key, XK_period, XK_equal, XK_VoidSymbol}, "•"}, // enfilledcircbullet | BULLET {{XK_dead_abovedot, XK_A, XK_VoidSymbol}, "Ȧ"}, // U0226 | LATIN CAPITAL LETTER A WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_A, XK_VoidSymbol}, "Ȧ"}, {{XK_dead_hook, XK_acircumflex, XK_VoidSymbol}, "ẩ"}, // U1EA9 | LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_acircumflex, XK_VoidSymbol}, "ẩ"}, {{XK_dead_hook, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ẩ"}, {{XK_dead_hook, XK_Multi_key, XK_asciicircum, XK_a, XK_VoidSymbol}, "ẩ"}, {{XK_Multi_key, XK_question, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ẩ"}, {{XK_Multi_key, XK_question, XK_asciicircum, XK_a, XK_VoidSymbol}, "ẩ"}, {{XK_dead_circumflex, XK_ahook, XK_VoidSymbol}, "ẩ"}, {{XK_dead_circumflex, XK_dead_hook, XK_a, XK_VoidSymbol}, "ẩ"}, {{XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "Ἠ"}, // U1F28 | GREEK CAPITAL LETTER ETA WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "Ἠ"}, {{XK_dead_diaeresis, XK_Greek_UPSILON, XK_VoidSymbol}, "Ϋ"}, // U03AB | GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA {{XK_Multi_key, XK_quotedbl, XK_Greek_UPSILON, XK_VoidSymbol}, "Ϋ"}, {{XK_Multi_key, XK_Greek_UPSILON, XK_quotedbl, XK_VoidSymbol}, "Ϋ"}, {{XK_dead_currency, XK_Y, XK_VoidSymbol}, "円"}, // U5186 | YEN {{XK_Multi_key, XK_minus, XK_minus, XK_space, XK_VoidSymbol}, "­"}, // U00ad | SOFT HYPHEN {{XK_dead_breve, XK_I, XK_VoidSymbol}, "Ĭ"}, // U012C | LATIN CAPITAL LETTER I WITH BREVE {{XK_Multi_key, XK_U, XK_I, XK_VoidSymbol}, "Ĭ"}, {{XK_Multi_key, XK_b, XK_I, XK_VoidSymbol}, "Ĭ"}, {{XK_dead_acute, XK_Idiaeresis, XK_VoidSymbol}, "Ḯ"}, // U1E2E | LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE {{XK_Multi_key, XK_acute, XK_Idiaeresis, XK_VoidSymbol}, "Ḯ"}, {{XK_Multi_key, XK_apostrophe, XK_Idiaeresis, XK_VoidSymbol}, "Ḯ"}, {{XK_dead_acute, XK_dead_diaeresis, XK_I, XK_VoidSymbol}, "Ḯ"}, {{XK_dead_acute, XK_Multi_key, XK_quotedbl, XK_I, XK_VoidSymbol}, "Ḯ"}, {{XK_Multi_key, XK_acute, XK_dead_diaeresis, XK_I, XK_VoidSymbol}, "Ḯ"}, {{XK_Multi_key, XK_acute, XK_quotedbl, XK_I, XK_VoidSymbol}, "Ḯ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_diaeresis, XK_I, XK_VoidSymbol}, "Ḯ"}, {{XK_Multi_key, XK_apostrophe, XK_quotedbl, XK_I, XK_VoidSymbol}, "Ḯ"}, {{XK_dead_diaeresis, XK_Iacute, XK_VoidSymbol}, "Ḯ"}, {{XK_dead_diaeresis, XK_dead_acute, XK_I, XK_VoidSymbol}, "Ḯ"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_6, XK_parenright, XK_VoidSymbol}, "㊱"}, // U32B1 | CIRCLED NUMBER THIRTY SIX {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_6, XK_parenright, XK_VoidSymbol}, "㊱"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_6, XK_parenright, XK_VoidSymbol}, "㊱"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_6, XK_parenright, XK_VoidSymbol}, "㊱"}, {{XK_dead_iota, XK_Greek_alpha, XK_VoidSymbol}, "ᾳ"}, // U1FB3 | GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_alpha, XK_VoidSymbol}, "ᾳ"}, {{XK_dead_acute, XK_Cyrillic_A, XK_VoidSymbol}, "А́"}, // CYRILLIC CAPITAL LETTER A WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_A, XK_VoidSymbol}, "А́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_A, XK_VoidSymbol}, "А́"}, {{XK_dead_macron, XK_Cyrillic_A, XK_VoidSymbol}, "А̄"}, // CYRILLIC CAPITAL LETTER A WITH COMBINING MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_A, XK_VoidSymbol}, "А̄"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_A, XK_VoidSymbol}, "А̄"}, {{XK_dead_belowdot, XK_e, XK_VoidSymbol}, "ẹ"}, // U1EB9 | LATIN SMALL LETTER E WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_e, XK_VoidSymbol}, "ẹ"}, {{XK_dead_psili, XK_Greek_IOTA, XK_VoidSymbol}, "Ἰ"}, // U1F38 | GREEK CAPITAL LETTER IOTA WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_IOTA, XK_VoidSymbol}, "Ἰ"}, {{XK_Multi_key, XK_parenleft, XK_o, XK_parenright, XK_VoidSymbol}, "ⓞ"}, // U24DE | CIRCLED LATIN SMALL LETTER O {{XK_Multi_key, XK_1, XK_2, XK_VoidSymbol}, "½"}, // onehalf | VULGAR FRACTION ONE HALF {{XK_dead_cedilla, XK_l, XK_VoidSymbol}, "ļ"}, // U013C | LATIN SMALL LETTER L WITH CEDILLA {{XK_Multi_key, XK_comma, XK_l, XK_VoidSymbol}, "ļ"}, {{XK_Multi_key, XK_l, XK_comma, XK_VoidSymbol}, "ļ"}, {{XK_Multi_key, XK_cedilla, XK_l, XK_VoidSymbol}, "ļ"}, {{XK_dead_acute, XK_M, XK_VoidSymbol}, "Ḿ"}, // U1E3E | LATIN CAPITAL LETTER M WITH ACUTE {{XK_Multi_key, XK_acute, XK_M, XK_VoidSymbol}, "Ḿ"}, {{XK_Multi_key, XK_apostrophe, XK_M, XK_VoidSymbol}, "Ḿ"}, {{XK_Multi_key, XK_backslash, XK_minus, XK_VoidSymbol}, "⍀"}, // U2340 | \ - APL FUNCTIONAL SYMBOL BACKSLASH BAR {{XK_Multi_key, XK_minus, XK_backslash, XK_VoidSymbol}, "⍀"}, {{XK_dead_iota, XK_Greek_eta, XK_VoidSymbol}, "ῃ"}, // U1FC3 | GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_eta, XK_VoidSymbol}, "ῃ"}, {{XK_dead_iota, XK_dead_grave, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾊ"}, // U1F8A | GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾊ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾊ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾊ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾊ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾊ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾊ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾊ"}, {{XK_Multi_key, XK_parenleft, XK_P, XK_parenright, XK_VoidSymbol}, "Ⓟ"}, // U24C5 | CIRCLED LATIN CAPITAL LETTER P {{XK_dead_currency, XK_K, XK_VoidSymbol}, "₭"}, // U20AD | KIP SIGN {{XK_dead_currency, XK_k, XK_VoidSymbol}, "₭"}, {{XK_dead_hook, XK_i, XK_VoidSymbol}, "ỉ"}, // U1EC9 | LATIN SMALL LETTER I WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_i, XK_VoidSymbol}, "ỉ"}, {{XK_dead_psili, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὀ"}, // U1F48 | GREEK CAPITAL LETTER OMICRON WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὀ"}, {{XK_dead_diaeresis, XK_Greek_upsilon, XK_VoidSymbol}, "ϋ"}, // U03CB | GREEK SMALL LETTER UPSILON WITH DIALYTIKA {{XK_Multi_key, XK_quotedbl, XK_Greek_upsilon, XK_VoidSymbol}, "ϋ"}, {{XK_Multi_key, XK_Greek_upsilon, XK_quotedbl, XK_VoidSymbol}, "ϋ"}, {{XK_dead_acute, XK_I, XK_VoidSymbol}, "Í"}, // Iacute | LATIN CAPITAL LETTER I WITH ACUTE {{XK_Multi_key, XK_acute, XK_I, XK_VoidSymbol}, "Í"}, {{XK_Multi_key, XK_I, XK_acute, XK_VoidSymbol}, "Í"}, {{XK_Multi_key, XK_apostrophe, XK_I, XK_VoidSymbol}, "Í"}, {{XK_Multi_key, XK_I, XK_apostrophe, XK_VoidSymbol}, "Í"}, {{XK_dead_macron, XK_O, XK_VoidSymbol}, "Ō"}, // U014C | LATIN CAPITAL LETTER O WITH MACRON {{XK_Multi_key, XK_macron, XK_O, XK_VoidSymbol}, "Ō"}, {{XK_Multi_key, XK_underscore, XK_O, XK_VoidSymbol}, "Ō"}, {{XK_Multi_key, XK_O, XK_underscore, XK_VoidSymbol}, "Ō"}, {{XK_Multi_key, XK_minus, XK_O, XK_VoidSymbol}, "Ō"}, {{XK_Multi_key, XK_O, XK_minus, XK_VoidSymbol}, "Ō"}, {{XK_dead_diaeresis, XK_Otilde, XK_VoidSymbol}, "Ṏ"}, // U1E4E | LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Otilde, XK_VoidSymbol}, "Ṏ"}, {{XK_dead_diaeresis, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ṏ"}, {{XK_dead_diaeresis, XK_Multi_key, XK_asciitilde, XK_O, XK_VoidSymbol}, "Ṏ"}, {{XK_Multi_key, XK_quotedbl, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ṏ"}, {{XK_Multi_key, XK_quotedbl, XK_asciitilde, XK_O, XK_VoidSymbol}, "Ṏ"}, {{XK_dead_tilde, XK_Odiaeresis, XK_VoidSymbol}, "Ṏ"}, {{XK_dead_tilde, XK_dead_diaeresis, XK_O, XK_VoidSymbol}, "Ṏ"}, {{XK_Multi_key, XK_parenleft, XK_b, XK_parenright, XK_VoidSymbol}, "ⓑ"}, // U24D1 | CIRCLED LATIN SMALL LETTER B {{XK_Multi_key, XK_parenleft, XK_kana_TE, XK_parenright, XK_VoidSymbol}, "㋢"}, // U32E2 | CIRCLED KATAKANA TE {{XK_Multi_key, XK_parenleft, XK_f, XK_parenright, XK_VoidSymbol}, "ⓕ"}, // U24D5 | CIRCLED LATIN SMALL LETTER F {{XK_dead_acute, XK_Udiaeresis, XK_VoidSymbol}, "Ǘ"}, // U01D7 | LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE {{XK_Multi_key, XK_acute, XK_Udiaeresis, XK_VoidSymbol}, "Ǘ"}, {{XK_Multi_key, XK_apostrophe, XK_Udiaeresis, XK_VoidSymbol}, "Ǘ"}, {{XK_dead_acute, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǘ"}, {{XK_dead_acute, XK_Multi_key, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǘ"}, {{XK_Multi_key, XK_acute, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǘ"}, {{XK_Multi_key, XK_acute, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǘ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǘ"}, {{XK_Multi_key, XK_apostrophe, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǘ"}, {{XK_dead_acute, XK_V, XK_VoidSymbol}, "Ǘ"}, {{XK_dead_diaeresis, XK_Uacute, XK_VoidSymbol}, "Ǘ"}, {{XK_dead_diaeresis, XK_dead_acute, XK_U, XK_VoidSymbol}, "Ǘ"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_6, XK_parenright, XK_VoidSymbol}, "㉖"}, // U3256 | CIRCLED NUMBER TWENTY SIX {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_6, XK_parenright, XK_VoidSymbol}, "㉖"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_6, XK_parenright, XK_VoidSymbol}, "㉖"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_6, XK_parenright, XK_VoidSymbol}, "㉖"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_6, XK_parenright, XK_VoidSymbol}, "㉖"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_6, XK_parenright, XK_VoidSymbol}, "㉖"}, {{XK_dead_circumflex, XK_dead_belowdot, XK_o, XK_VoidSymbol}, "ộ"}, // U1ED9 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW {{XK_dead_circumflex, XK_Multi_key, XK_exclam, XK_o, XK_VoidSymbol}, "ộ"}, {{XK_Multi_key, XK_asciicircum, XK_dead_belowdot, XK_o, XK_VoidSymbol}, "ộ"}, {{XK_Multi_key, XK_asciicircum, XK_exclam, XK_o, XK_VoidSymbol}, "ộ"}, {{XK_dead_belowdot, XK_ocircumflex, XK_VoidSymbol}, "ộ"}, {{XK_dead_belowdot, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ộ"}, {{XK_dead_abovedot, XK_sacute, XK_VoidSymbol}, "ṥ"}, // U1E65 | LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE {{XK_Multi_key, XK_period, XK_sacute, XK_VoidSymbol}, "ṥ"}, {{XK_dead_abovedot, XK_dead_acute, XK_s, XK_VoidSymbol}, "ṥ"}, {{XK_dead_abovedot, XK_Multi_key, XK_acute, XK_s, XK_VoidSymbol}, "ṥ"}, {{XK_dead_abovedot, XK_Multi_key, XK_apostrophe, XK_s, XK_VoidSymbol}, "ṥ"}, {{XK_Multi_key, XK_period, XK_dead_acute, XK_s, XK_VoidSymbol}, "ṥ"}, {{XK_Multi_key, XK_period, XK_acute, XK_s, XK_VoidSymbol}, "ṥ"}, {{XK_Multi_key, XK_period, XK_apostrophe, XK_s, XK_VoidSymbol}, "ṥ"}, {{XK_dead_acute, XK_sabovedot, XK_VoidSymbol}, "ṥ"}, {{XK_dead_acute, XK_dead_abovedot, XK_s, XK_VoidSymbol}, "ṥ"}, {{XK_dead_acute, XK_Y, XK_VoidSymbol}, "Ý"}, // Yacute | LATIN CAPITAL LETTER Y WITH ACUTE {{XK_Multi_key, XK_acute, XK_Y, XK_VoidSymbol}, "Ý"}, {{XK_Multi_key, XK_Y, XK_acute, XK_VoidSymbol}, "Ý"}, {{XK_Multi_key, XK_apostrophe, XK_Y, XK_VoidSymbol}, "Ý"}, {{XK_Multi_key, XK_Y, XK_apostrophe, XK_VoidSymbol}, "Ý"}, {{XK_dead_circumflex, XK_S, XK_VoidSymbol}, "Ŝ"}, // U015C | LATIN CAPITAL LETTER S WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_S, XK_VoidSymbol}, "Ŝ"}, {{XK_dead_belowmacron, XK_R, XK_VoidSymbol}, "Ṟ"}, // U1E5E | LATIN CAPITAL LETTER R WITH LINE BELOW {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_l, XK_VoidSymbol}, "ˡ"}, // U02E1 | MODIFIER LETTER SMALL L {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_l, XK_VoidSymbol}, "ˡ"}, {{XK_dead_diaeresis, XK_Cyrillic_i, XK_VoidSymbol}, "ӥ"}, // U04E5 | CYRILLIC SMALL LETTER I WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_i, XK_VoidSymbol}, "ӥ"}, {{XK_dead_caron, XK_g, XK_VoidSymbol}, "ǧ"}, // U01E7 | LATIN SMALL LETTER G WITH CARON {{XK_Multi_key, XK_c, XK_g, XK_VoidSymbol}, "ǧ"}, {{XK_dead_belowdot, XK_equal, XK_VoidSymbol}, "⩦"}, // U2A66 | EQUALS SIGN WITH DOT BELOW {{XK_dead_acute, XK_uhorn, XK_VoidSymbol}, "ứ"}, // U1EE9 | LATIN SMALL LETTER U WITH HORN AND ACUTE {{XK_Multi_key, XK_acute, XK_uhorn, XK_VoidSymbol}, "ứ"}, {{XK_Multi_key, XK_apostrophe, XK_uhorn, XK_VoidSymbol}, "ứ"}, {{XK_dead_acute, XK_dead_horn, XK_u, XK_VoidSymbol}, "ứ"}, {{XK_dead_acute, XK_Multi_key, XK_plus, XK_u, XK_VoidSymbol}, "ứ"}, {{XK_Multi_key, XK_acute, XK_dead_horn, XK_u, XK_VoidSymbol}, "ứ"}, {{XK_Multi_key, XK_acute, XK_plus, XK_u, XK_VoidSymbol}, "ứ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_horn, XK_u, XK_VoidSymbol}, "ứ"}, {{XK_Multi_key, XK_apostrophe, XK_plus, XK_u, XK_VoidSymbol}, "ứ"}, {{XK_dead_horn, XK_uacute, XK_VoidSymbol}, "ứ"}, {{XK_dead_horn, XK_dead_acute, XK_u, XK_VoidSymbol}, "ứ"}, {{XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὠ"}, // U1F68 | GREEK CAPITAL LETTER OMEGA WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὠ"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_1, XK_parenright, XK_VoidSymbol}, "⑪"}, // U246A | CIRCLED NUMBER ELEVEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_1, XK_parenright, XK_VoidSymbol}, "⑪"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_1, XK_parenright, XK_VoidSymbol}, "⑪"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_1, XK_parenright, XK_VoidSymbol}, "⑪"}, {{XK_dead_acute, XK_i, XK_VoidSymbol}, "í"}, // iacute | LATIN SMALL LETTER I WITH ACUTE {{XK_Multi_key, XK_acute, XK_i, XK_VoidSymbol}, "í"}, {{XK_Multi_key, XK_i, XK_acute, XK_VoidSymbol}, "í"}, {{XK_Multi_key, XK_apostrophe, XK_i, XK_VoidSymbol}, "í"}, {{XK_Multi_key, XK_i, XK_apostrophe, XK_VoidSymbol}, "í"}, {{XK_dead_breve, XK_U, XK_VoidSymbol}, "Ŭ"}, // U016C | LATIN CAPITAL LETTER U WITH BREVE {{XK_Multi_key, XK_U, XK_U, XK_VoidSymbol}, "Ŭ"}, {{XK_Multi_key, XK_u, XK_U, XK_VoidSymbol}, "Ŭ"}, {{XK_Multi_key, XK_b, XK_U, XK_VoidSymbol}, "Ŭ"}, {{XK_Multi_key, XK_numbersign, XK_f, XK_VoidSymbol}, "♮"}, // U266e | MUSIC NATURAL SIGN {{XK_Multi_key, XK_parenleft, XK_kana_ME, XK_parenright, XK_VoidSymbol}, "㋱"}, // U32F1 | CIRCLED KATAKANA ME {{XK_dead_iota, XK_Greek_omega, XK_VoidSymbol}, "ῳ"}, // U1FF3 | GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_omega, XK_VoidSymbol}, "ῳ"}, {{XK_dead_diaeresis, XK_Cyrillic_che, XK_VoidSymbol}, "ӵ"}, // U04F5 | CYRILLIC SMALL LETTER CHE WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_che, XK_VoidSymbol}, "ӵ"}, {{XK_dead_tilde, XK_y, XK_VoidSymbol}, "ỹ"}, // U1EF9 | LATIN SMALL LETTER Y WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_y, XK_VoidSymbol}, "ỹ"}, {{XK_dead_grave, XK_Greek_omicron, XK_VoidSymbol}, "ὸ"}, // U1F78 | GREEK SMALL LETTER OMICRON WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_omicron, XK_VoidSymbol}, "ὸ"}, {{XK_dead_acute, XK_Cyrillic_I, XK_VoidSymbol}, "И́"}, // CYRILLIC CAPITAL LETTER I WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_I, XK_VoidSymbol}, "И́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_I, XK_VoidSymbol}, "И́"}, {{XK_dead_acute, XK_y, XK_VoidSymbol}, "ý"}, // yacute | LATIN SMALL LETTER Y WITH ACUTE {{XK_Multi_key, XK_acute, XK_y, XK_VoidSymbol}, "ý"}, {{XK_Multi_key, XK_y, XK_acute, XK_VoidSymbol}, "ý"}, {{XK_Multi_key, XK_apostrophe, XK_y, XK_VoidSymbol}, "ý"}, {{XK_Multi_key, XK_y, XK_apostrophe, XK_VoidSymbol}, "ý"}, {{XK_dead_abovedot, XK_z, XK_VoidSymbol}, "ż"}, // U017C | LATIN SMALL LETTER Z WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_z, XK_VoidSymbol}, "ż"}, {{XK_Multi_key, XK_z, XK_period, XK_VoidSymbol}, "ż"}, {{XK_dead_voiced_sound, XK_kana_CHI, XK_VoidSymbol}, "ヂ"}, // U30C2 | KATAKANA LETTER DI {{XK_dead_belowdot, XK_V, XK_VoidSymbol}, "Ṿ"}, // U1E7E | LATIN CAPITAL LETTER V WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_V, XK_VoidSymbol}, "Ṿ"}, {{XK_dead_doublegrave, XK_a, XK_VoidSymbol}, "ȁ"}, // U0201 | LATIN SMALL LETTER A WITH DOUBLE GRAVE {{XK_dead_grave, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ἃ"}, // U1F03 | GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ἃ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ἃ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ἃ"}, {{XK_dead_grave, XK_Uhorn, XK_VoidSymbol}, "Ừ"}, // U1EEA | LATIN CAPITAL LETTER U WITH HORN AND GRAVE {{XK_Multi_key, XK_grave, XK_Uhorn, XK_VoidSymbol}, "Ừ"}, {{XK_dead_grave, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ừ"}, {{XK_dead_grave, XK_Multi_key, XK_plus, XK_U, XK_VoidSymbol}, "Ừ"}, {{XK_Multi_key, XK_grave, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ừ"}, {{XK_Multi_key, XK_grave, XK_plus, XK_U, XK_VoidSymbol}, "Ừ"}, {{XK_dead_horn, XK_Ugrave, XK_VoidSymbol}, "Ừ"}, {{XK_dead_horn, XK_dead_grave, XK_U, XK_VoidSymbol}, "Ừ"}, {{XK_dead_acute, XK_c, XK_VoidSymbol}, "ć"}, // U0107 | LATIN SMALL LETTER C WITH ACUTE {{XK_Multi_key, XK_acute, XK_c, XK_VoidSymbol}, "ć"}, {{XK_Multi_key, XK_apostrophe, XK_c, XK_VoidSymbol}, "ć"}, {{XK_Multi_key, XK_c, XK_apostrophe, XK_VoidSymbol}, "ć"}, {{XK_dead_acute, XK_ccedilla, XK_VoidSymbol}, "ḉ"}, // U1E09 | LATIN SMALL LETTER C WITH CEDILLA AND ACUTE {{XK_Multi_key, XK_acute, XK_ccedilla, XK_VoidSymbol}, "ḉ"}, {{XK_Multi_key, XK_apostrophe, XK_ccedilla, XK_VoidSymbol}, "ḉ"}, {{XK_dead_acute, XK_dead_cedilla, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_dead_acute, XK_Multi_key, XK_comma, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_dead_acute, XK_Multi_key, XK_cedilla, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_Multi_key, XK_acute, XK_dead_cedilla, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_Multi_key, XK_acute, XK_comma, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_Multi_key, XK_acute, XK_cedilla, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_cedilla, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_Multi_key, XK_apostrophe, XK_cedilla, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_dead_cedilla, XK_cacute, XK_VoidSymbol}, "ḉ"}, {{XK_dead_cedilla, XK_dead_acute, XK_c, XK_VoidSymbol}, "ḉ"}, {{XK_dead_belowdot, XK_t, XK_VoidSymbol}, "ṭ"}, // U1E6D | LATIN SMALL LETTER T WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_t, XK_VoidSymbol}, "ṭ"}, {{XK_dead_doubleacute, XK_nobreakspace, XK_VoidSymbol}, "̋"}, // U030B | COMBINING DOUBLE ACUTE ACCENT {{XK_dead_abovedot, XK_Y, XK_VoidSymbol}, "Ẏ"}, // U1E8E | LATIN CAPITAL LETTER Y WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_Y, XK_VoidSymbol}, "Ẏ"}, {{XK_dead_doublegrave, XK_r, XK_VoidSymbol}, "ȑ"}, // U0211 | LATIN SMALL LETTER R WITH DOUBLE GRAVE {{XK_dead_acute, XK_Greek_iotadieresis, XK_VoidSymbol}, "ΐ"}, // U0390 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS {{XK_Multi_key, XK_acute, XK_Greek_iotadieresis, XK_VoidSymbol}, "ΐ"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_iotadieresis, XK_VoidSymbol}, "ΐ"}, {{XK_dead_acute, XK_dead_diaeresis, XK_Greek_iota, XK_VoidSymbol}, "ΐ"}, {{XK_dead_diaeresis, XK_dead_acute, XK_Greek_iota, XK_VoidSymbol}, "ΐ"}, {{XK_dead_acute, XK_Multi_key, XK_quotedbl, XK_Greek_iota, XK_VoidSymbol}, "ΐ"}, {{XK_Multi_key, XK_acute, XK_dead_diaeresis, XK_Greek_iota, XK_VoidSymbol}, "ΐ"}, {{XK_Multi_key, XK_acute, XK_quotedbl, XK_Greek_iota, XK_VoidSymbol}, "ΐ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_diaeresis, XK_Greek_iota, XK_VoidSymbol}, "ΐ"}, {{XK_Multi_key, XK_apostrophe, XK_quotedbl, XK_Greek_iota, XK_VoidSymbol}, "ΐ"}, {{XK_Greek_accentdieresis, XK_Greek_iota, XK_VoidSymbol}, "ΐ"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_epsilon, XK_VoidSymbol}, "ἓ"}, // U1F13 | GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_epsilon, XK_VoidSymbol}, "ἓ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_epsilon, XK_VoidSymbol}, "ἓ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_epsilon, XK_VoidSymbol}, "ἓ"}, {{XK_dead_acute, XK_Cyrillic_a, XK_VoidSymbol}, "а́"}, // CYRILLIC SMALL LETTER A WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_a, XK_VoidSymbol}, "а́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_a, XK_VoidSymbol}, "а́"}, {{XK_dead_grave, XK_Cyrillic_A, XK_VoidSymbol}, "А̀"}, // CYRILLIC CAPITAL LETTER A WITH COMBINING GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_Cyrillic_A, XK_VoidSymbol}, "А̀"}, {{XK_dead_abovedot, XK_e, XK_VoidSymbol}, "ė"}, // U0117 | LATIN SMALL LETTER E WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_e, XK_VoidSymbol}, "ė"}, {{XK_Multi_key, XK_e, XK_period, XK_VoidSymbol}, "ė"}, {{XK_dead_belowcircumflex, XK_e, XK_VoidSymbol}, "ḙ"}, // U1E19 | LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW {{XK_dead_iota, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾘ"}, // U1F98 | GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾘ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾘ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾘ"}, {{XK_dead_horn, XK_dead_horn, XK_VoidSymbol}, "̛"}, // U031B | COMBINING HORN {{XK_dead_horn, XK_nobreakspace, XK_VoidSymbol}, "̛"}, {{XK_dead_horn, XK_space, XK_VoidSymbol}, "̛"}, {{XK_Multi_key, XK_greater, XK_quotedbl, XK_VoidSymbol}, "”"}, // U201d | RIGHT DOUBLE QUOTATION MARK {{XK_Multi_key, XK_quotedbl, XK_greater, XK_VoidSymbol}, "”"}, {{XK_dead_doublegrave, XK_Cyrillic_a, XK_VoidSymbol}, "а̏"}, // CYRILLIC SMALL LETTER A WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_a, XK_VoidSymbol}, "а̏"}, {{XK_Multi_key, XK_S, XK_S, XK_VoidSymbol}, "ẞ"}, // U1e9e | LATIN CAPITAL LETTER SHARP S {{XK_dead_grave, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ἣ"}, // U1F23 | GREEK SMALL LETTER ETA WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ἣ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ἣ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ἣ"}, {{XK_Multi_key, XK_C, XK_bar, XK_VoidSymbol}, "¢"}, // cent | CENT SIGN {{XK_Multi_key, XK_bar, XK_C, XK_VoidSymbol}, "¢"}, {{XK_Multi_key, XK_c, XK_bar, XK_VoidSymbol}, "¢"}, {{XK_Multi_key, XK_bar, XK_c, XK_VoidSymbol}, "¢"}, {{XK_Multi_key, XK_c, XK_slash, XK_VoidSymbol}, "¢"}, {{XK_Multi_key, XK_slash, XK_c, XK_VoidSymbol}, "¢"}, {{XK_dead_currency, XK_c, XK_VoidSymbol}, "¢"}, {{XK_dead_doublegrave, XK_Cyrillic_U, XK_VoidSymbol}, "У̏"}, // CYRILLIC CAPITAL LETTER U WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_U, XK_VoidSymbol}, "У̏"}, {{XK_dead_stroke, XK_h, XK_VoidSymbol}, "ħ"}, // U0127 | LATIN SMALL LETTER H WITH STROKE {{XK_Multi_key, XK_slash, XK_h, XK_VoidSymbol}, "ħ"}, {{XK_Multi_key, XK_KP_Divide, XK_h, XK_VoidSymbol}, "ħ"}, {{XK_dead_cedilla, XK_h, XK_VoidSymbol}, "ḩ"}, // U1E29 | LATIN SMALL LETTER H WITH CEDILLA {{XK_Multi_key, XK_comma, XK_h, XK_VoidSymbol}, "ḩ"}, {{XK_Multi_key, XK_h, XK_comma, XK_VoidSymbol}, "ḩ"}, {{XK_Multi_key, XK_cedilla, XK_h, XK_VoidSymbol}, "ḩ"}, {{XK_dead_iota, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾨ"}, // U1FA8 | GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾨ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾨ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾨ"}, {{XK_dead_acute, XK_Cyrillic_U, XK_VoidSymbol}, "У́"}, // CYRILLIC CAPITAL LETTER U WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_U, XK_VoidSymbol}, "У́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_U, XK_VoidSymbol}, "У́"}, {{XK_dead_stroke, XK_E, XK_VoidSymbol}, "Ɇ"}, // U0246 | LATIN CAPITAL LETTER E WITH STROKE {{XK_Multi_key, XK_parenleft, XK_3, XK_7, XK_parenright, XK_VoidSymbol}, "㊲"}, // U32B2 | CIRCLED NUMBER THIRTY SEVEN {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_7, XK_parenright, XK_VoidSymbol}, "㊲"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_7, XK_parenright, XK_VoidSymbol}, "㊲"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_7, XK_parenright, XK_VoidSymbol}, "㊲"}, {{XK_dead_hook, XK_T, XK_VoidSymbol}, "Ƭ"}, // U01AC | LATIN CAPITAL LETTER T WITH HOOK {{XK_dead_acute, XK_Abreve, XK_VoidSymbol}, "Ắ"}, // U1EAE | LATIN CAPITAL LETTER A WITH BREVE AND ACUTE {{XK_Multi_key, XK_acute, XK_Abreve, XK_VoidSymbol}, "Ắ"}, {{XK_Multi_key, XK_apostrophe, XK_Abreve, XK_VoidSymbol}, "Ắ"}, {{XK_dead_acute, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ắ"}, {{XK_dead_acute, XK_Multi_key, XK_U, XK_A, XK_VoidSymbol}, "Ắ"}, {{XK_dead_acute, XK_Multi_key, XK_b, XK_A, XK_VoidSymbol}, "Ắ"}, {{XK_Multi_key, XK_acute, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ắ"}, {{XK_Multi_key, XK_acute, XK_b, XK_A, XK_VoidSymbol}, "Ắ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ắ"}, {{XK_Multi_key, XK_apostrophe, XK_b, XK_A, XK_VoidSymbol}, "Ắ"}, {{XK_dead_breve, XK_Aacute, XK_VoidSymbol}, "Ắ"}, {{XK_dead_breve, XK_dead_acute, XK_A, XK_VoidSymbol}, "Ắ"}, {{XK_dead_macron, XK_dead_abovedot, XK_o, XK_VoidSymbol}, "ȱ"}, // U0231 | LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON {{XK_dead_macron, XK_Multi_key, XK_period, XK_o, XK_VoidSymbol}, "ȱ"}, {{XK_Multi_key, XK_macron, XK_dead_abovedot, XK_o, XK_VoidSymbol}, "ȱ"}, {{XK_Multi_key, XK_macron, XK_period, XK_o, XK_VoidSymbol}, "ȱ"}, {{XK_Multi_key, XK_underscore, XK_dead_abovedot, XK_o, XK_VoidSymbol}, "ȱ"}, {{XK_Multi_key, XK_underscore, XK_period, XK_o, XK_VoidSymbol}, "ȱ"}, {{XK_dead_abovedot, XK_omacron, XK_VoidSymbol}, "ȱ"}, {{XK_dead_abovedot, XK_dead_macron, XK_o, XK_VoidSymbol}, "ȱ"}, {{XK_dead_acute, XK_Greek_upsilondieresis, XK_VoidSymbol}, "ΰ"}, // U03B0 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS {{XK_Multi_key, XK_acute, XK_Greek_upsilondieresis, XK_VoidSymbol}, "ΰ"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_upsilondieresis, XK_VoidSymbol}, "ΰ"}, {{XK_dead_acute, XK_dead_diaeresis, XK_Greek_upsilon, XK_VoidSymbol}, "ΰ"}, {{XK_dead_acute, XK_Multi_key, XK_quotedbl, XK_Greek_upsilon, XK_VoidSymbol}, "ΰ"}, {{XK_Multi_key, XK_acute, XK_dead_diaeresis, XK_Greek_upsilon, XK_VoidSymbol}, "ΰ"}, {{XK_Multi_key, XK_acute, XK_quotedbl, XK_Greek_upsilon, XK_VoidSymbol}, "ΰ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_diaeresis, XK_Greek_upsilon, XK_VoidSymbol}, "ΰ"}, {{XK_Multi_key, XK_apostrophe, XK_quotedbl, XK_Greek_upsilon, XK_VoidSymbol}, "ΰ"}, {{XK_dead_diaeresis, XK_dead_acute, XK_Greek_upsilon, XK_VoidSymbol}, "ΰ"}, {{XK_Greek_accentdieresis, XK_Greek_upsilon, XK_VoidSymbol}, "ΰ"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_iota, XK_VoidSymbol}, "ἳ"}, // U1F33 | GREEK SMALL LETTER IOTA WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_iota, XK_VoidSymbol}, "ἳ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_iota, XK_VoidSymbol}, "ἳ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_iota, XK_VoidSymbol}, "ἳ"}, {{XK_dead_circumflex, XK_2, XK_VoidSymbol}, "²"}, // twosuperior | SUPERSCRIPT TWO {{XK_Multi_key, XK_asciicircum, XK_2, XK_VoidSymbol}, "²"}, {{XK_Multi_key, XK_2, XK_asciicircum, XK_VoidSymbol}, "²"}, {{XK_dead_circumflex, XK_KP_Space, XK_VoidSymbol}, "²"}, {{XK_Multi_key, XK_asciicircum, XK_KP_Space, XK_VoidSymbol}, "²"}, {{XK_dead_circumflex, XK_KP_2, XK_VoidSymbol}, "²"}, {{XK_Multi_key, XK_asciicircum, XK_KP_2, XK_VoidSymbol}, "²"}, {{XK_Multi_key, XK_parenleft, XK_kana_RA, XK_parenright, XK_VoidSymbol}, "㋶"}, // U32F6 | CIRCLED KATAKANA RA {{XK_dead_cedilla, XK_k, XK_VoidSymbol}, "ķ"}, // U0137 | LATIN SMALL LETTER K WITH CEDILLA {{XK_Multi_key, XK_comma, XK_k, XK_VoidSymbol}, "ķ"}, {{XK_Multi_key, XK_k, XK_comma, XK_VoidSymbol}, "ķ"}, {{XK_Multi_key, XK_cedilla, XK_k, XK_VoidSymbol}, "ķ"}, {{XK_Multi_key, XK_parenleft, XK_4, XK_1, XK_parenright, XK_VoidSymbol}, "㊶"}, // U32B6 | CIRCLED NUMBER FORTY ONE {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_1, XK_parenright, XK_VoidSymbol}, "㊶"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_1, XK_parenright, XK_VoidSymbol}, "㊶"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_1, XK_parenright, XK_VoidSymbol}, "㊶"}, {{XK_Multi_key, XK_colon, XK_parenleft, XK_VoidSymbol}, "☹"}, // U2639 | WHITE FROWNING FACE {{XK_dead_breve, XK_Greek_ALPHA, XK_VoidSymbol}, "Ᾰ"}, // U1FB8 | GREEK CAPITAL LETTER ALPHA WITH VRACHY {{XK_Multi_key, XK_U, XK_Greek_ALPHA, XK_VoidSymbol}, "Ᾰ"}, {{XK_Multi_key, XK_b, XK_Greek_ALPHA, XK_VoidSymbol}, "Ᾰ"}, {{XK_dead_invertedbreve, XK_Cyrillic_U, XK_VoidSymbol}, "У̑"}, // CYRILLIC CAPITAL LETTER U WITH COMBINING INVERTED BREVE {{XK_Multi_key, XK_parenleft, XK_E, XK_parenright, XK_VoidSymbol}, "Ⓔ"}, // U24BA | CIRCLED LATIN CAPITAL LETTER E {{XK_Multi_key, XK_exclam, XK_question, XK_VoidSymbol}, "‽"}, // U203D | INTERROBANG {{XK_dead_acute, XK_Ecircumflex, XK_VoidSymbol}, "Ế"}, // U1EBE | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE {{XK_Multi_key, XK_acute, XK_Ecircumflex, XK_VoidSymbol}, "Ế"}, {{XK_Multi_key, XK_apostrophe, XK_Ecircumflex, XK_VoidSymbol}, "Ế"}, {{XK_dead_acute, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ế"}, {{XK_dead_acute, XK_Multi_key, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ế"}, {{XK_Multi_key, XK_acute, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ế"}, {{XK_Multi_key, XK_acute, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ế"}, {{XK_Multi_key, XK_apostrophe, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ế"}, {{XK_Multi_key, XK_apostrophe, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ế"}, {{XK_dead_circumflex, XK_Eacute, XK_VoidSymbol}, "Ế"}, {{XK_dead_circumflex, XK_dead_acute, XK_E, XK_VoidSymbol}, "Ế"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_omicron, XK_VoidSymbol}, "ὃ"}, // U1F43 | GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_omicron, XK_VoidSymbol}, "ὃ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_omicron, XK_VoidSymbol}, "ὃ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_omicron, XK_VoidSymbol}, "ὃ"}, {{XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Â"}, // Acircumflex | LATIN CAPITAL LETTER A WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_A, XK_VoidSymbol}, "Â"}, {{XK_Multi_key, XK_A, XK_asciicircum, XK_VoidSymbol}, "Â"}, {{XK_Multi_key, XK_greater, XK_A, XK_VoidSymbol}, "Â"}, {{XK_Multi_key, XK_A, XK_greater, XK_VoidSymbol}, "Â"}, {{XK_dead_caron, XK_N, XK_VoidSymbol}, "Ň"}, // U0147 | LATIN CAPITAL LETTER N WITH CARON {{XK_Multi_key, XK_c, XK_N, XK_VoidSymbol}, "Ň"}, {{XK_Multi_key, XK_less, XK_N, XK_VoidSymbol}, "Ň"}, {{XK_Multi_key, XK_N, XK_less, XK_VoidSymbol}, "Ň"}, {{XK_Multi_key, XK_C, XK_E, XK_VoidSymbol}, "₠"}, // U20a0 | EURO-CURRENCY SIGN {{XK_dead_currency, XK_E, XK_VoidSymbol}, "₠"}, {{XK_dead_belowmacron, XK_n, XK_VoidSymbol}, "ṉ"}, // U1E49 | LATIN SMALL LETTER N WITH LINE BELOW {{XK_dead_grave, XK_Greek_EPSILON, XK_VoidSymbol}, "Ὲ"}, // U1FC8 | GREEK CAPITAL LETTER EPSILON WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_EPSILON, XK_VoidSymbol}, "Ὲ"}, {{XK_Multi_key, XK_parenleft, XK_U, XK_parenright, XK_VoidSymbol}, "Ⓤ"}, // U24CA | CIRCLED LATIN CAPITAL LETTER U {{XK_dead_hook, XK_O, XK_VoidSymbol}, "Ỏ"}, // U1ECE | LATIN CAPITAL LETTER O WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_O, XK_VoidSymbol}, "Ỏ"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_1, XK_parenright, XK_VoidSymbol}, "㉑"}, // U3251 | CIRCLED NUMBER TWENTY ONE {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_1, XK_parenright, XK_VoidSymbol}, "㉑"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_1, XK_parenright, XK_VoidSymbol}, "㉑"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_1, XK_parenright, XK_VoidSymbol}, "㉑"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_1, XK_parenright, XK_VoidSymbol}, "㉑"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_1, XK_parenright, XK_VoidSymbol}, "㉑"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_upsilon, XK_VoidSymbol}, "ὓ"}, // U1F53 | GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_upsilon, XK_VoidSymbol}, "ὓ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_upsilon, XK_VoidSymbol}, "ὓ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_upsilon, XK_VoidSymbol}, "ὓ"}, {{XK_dead_grave, XK_O, XK_VoidSymbol}, "Ò"}, // Ograve | LATIN CAPITAL LETTER O WITH GRAVE {{XK_Multi_key, XK_grave, XK_O, XK_VoidSymbol}, "Ò"}, {{XK_Multi_key, XK_O, XK_grave, XK_VoidSymbol}, "Ò"}, {{XK_dead_voiced_sound, XK_kana_SO, XK_VoidSymbol}, "ゾ"}, // U30BE | KATAKANA LETTER ZO {{XK_dead_cedilla, XK_r, XK_VoidSymbol}, "ŗ"}, // U0157 | LATIN SMALL LETTER R WITH CEDILLA {{XK_Multi_key, XK_comma, XK_r, XK_VoidSymbol}, "ŗ"}, {{XK_Multi_key, XK_r, XK_comma, XK_VoidSymbol}, "ŗ"}, {{XK_Multi_key, XK_cedilla, XK_r, XK_VoidSymbol}, "ŗ"}, {{XK_Multi_key, XK_parenleft, XK_kana_KI, XK_parenright, XK_VoidSymbol}, "㋖"}, // U32D6 | CIRCLED KATAKANA KI {{XK_dead_abovedot, XK_r, XK_VoidSymbol}, "ṙ"}, // U1E59 | LATIN SMALL LETTER R WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_r, XK_VoidSymbol}, "ṙ"}, {{XK_dead_breve, XK_Greek_IOTA, XK_VoidSymbol}, "Ῐ"}, // U1FD8 | GREEK CAPITAL LETTER IOTA WITH VRACHY {{XK_Multi_key, XK_U, XK_Greek_IOTA, XK_VoidSymbol}, "Ῐ"}, {{XK_Multi_key, XK_b, XK_Greek_IOTA, XK_VoidSymbol}, "Ῐ"}, {{XK_Multi_key, XK_parenleft, XK_k, XK_parenright, XK_VoidSymbol}, "ⓚ"}, // U24DA | CIRCLED LATIN SMALL LETTER K {{XK_Multi_key, XK_parenright, XK_parenright, XK_VoidSymbol}, "]"}, // bracketright | RIGHT SQUARE BRACKET {{XK_dead_grave, XK_udiaeresis, XK_VoidSymbol}, "ǜ"}, // U01DC | LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE {{XK_Multi_key, XK_grave, XK_udiaeresis, XK_VoidSymbol}, "ǜ"}, {{XK_dead_grave, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǜ"}, {{XK_dead_grave, XK_Multi_key, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǜ"}, {{XK_Multi_key, XK_grave, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǜ"}, {{XK_Multi_key, XK_grave, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǜ"}, {{XK_dead_diaeresis, XK_ugrave, XK_VoidSymbol}, "ǜ"}, {{XK_dead_grave, XK_v, XK_VoidSymbol}, "ǜ"}, {{XK_dead_diaeresis, XK_dead_grave, XK_u, XK_VoidSymbol}, "ǜ"}, {{XK_dead_hook, XK_Ohorn, XK_VoidSymbol}, "Ở"}, // U1EDE | LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_Ohorn, XK_VoidSymbol}, "Ở"}, {{XK_dead_hook, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ở"}, {{XK_dead_hook, XK_Multi_key, XK_plus, XK_O, XK_VoidSymbol}, "Ở"}, {{XK_Multi_key, XK_question, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ở"}, {{XK_Multi_key, XK_question, XK_plus, XK_O, XK_VoidSymbol}, "Ở"}, {{XK_dead_horn, XK_Ohook, XK_VoidSymbol}, "Ở"}, {{XK_dead_horn, XK_dead_hook, XK_O, XK_VoidSymbol}, "Ở"}, {{XK_Multi_key, XK_equal, XK_underscore, XK_VoidSymbol}, "≡"}, // U2261 | = _ IDENTICAL TO {{XK_Multi_key, XK_parenleft, XK_kana_I, XK_parenright, XK_VoidSymbol}, "㋑"}, // U32D1 | CIRCLED KATAKANA I {{XK_dead_grave, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ὣ"}, // U1F63 | GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ὣ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ὣ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ὣ"}, {{XK_dead_circumflex, XK_a, XK_VoidSymbol}, "â"}, // acircumflex | LATIN SMALL LETTER A WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_a, XK_VoidSymbol}, "â"}, {{XK_Multi_key, XK_a, XK_asciicircum, XK_VoidSymbol}, "â"}, {{XK_Multi_key, XK_greater, XK_a, XK_VoidSymbol}, "â"}, {{XK_Multi_key, XK_a, XK_greater, XK_VoidSymbol}, "â"}, {{XK_Multi_key, XK_parenleft, XK_6, XK_parenright, XK_VoidSymbol}, "⑥"}, // U2465 | CIRCLED DIGIT SIX {{XK_Multi_key, XK_parenleft, XK_KP_6, XK_parenright, XK_VoidSymbol}, "⑥"}, {{XK_dead_stroke, XK_t, XK_VoidSymbol}, "ŧ"}, // U0167 | LATIN SMALL LETTER T WITH STROKE {{XK_Multi_key, XK_slash, XK_t, XK_VoidSymbol}, "ŧ"}, {{XK_Multi_key, XK_KP_Divide, XK_t, XK_VoidSymbol}, "ŧ"}, {{XK_Multi_key, XK_t, XK_slash, XK_VoidSymbol}, "ŧ"}, {{XK_Multi_key, XK_t, XK_minus, XK_VoidSymbol}, "ŧ"}, {{XK_dead_psili, XK_Greek_upsilon, XK_VoidSymbol}, "ὐ"}, // U1F50 | GREEK SMALL LETTER UPSILON WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_upsilon, XK_VoidSymbol}, "ὐ"}, {{XK_Multi_key, XK_numbersign, XK_q, XK_VoidSymbol}, "♩"}, // U2669 | QUARTER NOTE {{XK_dead_breve, XK_Greek_UPSILON, XK_VoidSymbol}, "Ῠ"}, // U1FE8 | GREEK CAPITAL LETTER UPSILON WITH VRACHY {{XK_Multi_key, XK_U, XK_Greek_UPSILON, XK_VoidSymbol}, "Ῠ"}, {{XK_Multi_key, XK_b, XK_Greek_UPSILON, XK_VoidSymbol}, "Ῠ"}, {{XK_Multi_key, XK_parenleft, XK_0, XK_parenright, XK_VoidSymbol}, "⓪"}, // U24EA | CIRCLED DIGIT ZERO {{XK_Multi_key, XK_parenleft, XK_KP_0, XK_parenright, XK_VoidSymbol}, "⓪"}, {{XK_dead_macron, XK_dead_ogonek, XK_O, XK_VoidSymbol}, "Ǭ"}, // U01EC | LATIN CAPITAL LETTER O WITH OGONEK AND MACRON {{XK_dead_macron, XK_Multi_key, XK_semicolon, XK_O, XK_VoidSymbol}, "Ǭ"}, {{XK_Multi_key, XK_macron, XK_dead_ogonek, XK_O, XK_VoidSymbol}, "Ǭ"}, {{XK_Multi_key, XK_macron, XK_semicolon, XK_O, XK_VoidSymbol}, "Ǭ"}, {{XK_Multi_key, XK_underscore, XK_dead_ogonek, XK_O, XK_VoidSymbol}, "Ǭ"}, {{XK_Multi_key, XK_underscore, XK_semicolon, XK_O, XK_VoidSymbol}, "Ǭ"}, {{XK_dead_ogonek, XK_Omacron, XK_VoidSymbol}, "Ǭ"}, {{XK_dead_ogonek, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ǭ"}, {{XK_dead_voiced_sound, XK_kana_HI, XK_VoidSymbol}, "ビ"}, // U30D3 | KATAKANA LETTER BI {{XK_dead_tilde, XK_Uhorn, XK_VoidSymbol}, "Ữ"}, // U1EEE | LATIN CAPITAL LETTER U WITH HORN AND TILDE {{XK_Multi_key, XK_asciitilde, XK_Uhorn, XK_VoidSymbol}, "Ữ"}, {{XK_dead_tilde, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ữ"}, {{XK_dead_tilde, XK_Multi_key, XK_plus, XK_U, XK_VoidSymbol}, "Ữ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ữ"}, {{XK_Multi_key, XK_asciitilde, XK_plus, XK_U, XK_VoidSymbol}, "Ữ"}, {{XK_dead_horn, XK_Utilde, XK_VoidSymbol}, "Ữ"}, {{XK_dead_horn, XK_dead_tilde, XK_U, XK_VoidSymbol}, "Ữ"}, {{XK_dead_hook, XK_m, XK_VoidSymbol}, "ɱ"}, // U0271 | LATIN SMALL LETTER M WITH HOOK {{XK_dead_currency, XK_M, XK_VoidSymbol}, "ℳ"}, // U2133 | SCRIPT CAPITAL M {{XK_dead_circumflex, XK_Cyrillic_ie, XK_VoidSymbol}, "е̂"}, // CYRILLIC SMALL LETTER IE WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_ie, XK_VoidSymbol}, "е̂"}, {{XK_dead_grave, XK_o, XK_VoidSymbol}, "ò"}, // ograve | LATIN SMALL LETTER O WITH GRAVE {{XK_Multi_key, XK_grave, XK_o, XK_VoidSymbol}, "ò"}, {{XK_Multi_key, XK_o, XK_grave, XK_VoidSymbol}, "ò"}, {{XK_dead_circumflex, XK_y, XK_VoidSymbol}, "ŷ"}, // U0177 | LATIN SMALL LETTER Y WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_y, XK_VoidSymbol}, "ŷ"}, {{XK_Multi_key, XK_y, XK_asciicircum, XK_VoidSymbol}, "ŷ"}, {{XK_Multi_key, XK_R, XK_s, XK_VoidSymbol}, "₨"}, // U20a8 | RUPEE SIGN {{XK_dead_currency, XK_R, XK_VoidSymbol}, "₨"}, {{XK_dead_acute, XK_utilde, XK_VoidSymbol}, "ṹ"}, // U1E79 | LATIN SMALL LETTER U WITH TILDE AND ACUTE {{XK_Multi_key, XK_acute, XK_utilde, XK_VoidSymbol}, "ṹ"}, {{XK_Multi_key, XK_apostrophe, XK_utilde, XK_VoidSymbol}, "ṹ"}, {{XK_dead_acute, XK_dead_tilde, XK_u, XK_VoidSymbol}, "ṹ"}, {{XK_dead_acute, XK_Multi_key, XK_asciitilde, XK_u, XK_VoidSymbol}, "ṹ"}, {{XK_Multi_key, XK_acute, XK_dead_tilde, XK_u, XK_VoidSymbol}, "ṹ"}, {{XK_Multi_key, XK_acute, XK_asciitilde, XK_u, XK_VoidSymbol}, "ṹ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_tilde, XK_u, XK_VoidSymbol}, "ṹ"}, {{XK_Multi_key, XK_apostrophe, XK_asciitilde, XK_u, XK_VoidSymbol}, "ṹ"}, {{XK_dead_tilde, XK_uacute, XK_VoidSymbol}, "ṹ"}, {{XK_dead_tilde, XK_dead_acute, XK_u, XK_VoidSymbol}, "ṹ"}, {{XK_dead_grave, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὸ"}, // U1FF8 | GREEK CAPITAL LETTER OMICRON WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὸ"}, {{XK_dead_belowdot, XK_Uhorn, XK_VoidSymbol}, "Ự"}, // U1EF0 | LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW {{XK_Multi_key, XK_exclam, XK_Uhorn, XK_VoidSymbol}, "Ự"}, {{XK_dead_belowdot, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ự"}, {{XK_dead_belowdot, XK_Multi_key, XK_plus, XK_U, XK_VoidSymbol}, "Ự"}, {{XK_Multi_key, XK_exclam, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ự"}, {{XK_Multi_key, XK_exclam, XK_plus, XK_U, XK_VoidSymbol}, "Ự"}, {{XK_dead_horn, XK_Ubelowdot, XK_VoidSymbol}, "Ự"}, {{XK_dead_horn, XK_dead_belowdot, XK_U, XK_VoidSymbol}, "Ự"}, {{XK_Multi_key, XK_parenright, XK_minus, XK_VoidSymbol}, "}"}, // braceright | RIGHT CURLY BRACKET {{XK_Multi_key, XK_minus, XK_parenright, XK_VoidSymbol}, "}"}, {{XK_dead_acute, XK_AE, XK_VoidSymbol}, "Ǽ"}, // U01FC | LATIN CAPITAL LETTER AE WITH ACUTE {{XK_Multi_key, XK_acute, XK_AE, XK_VoidSymbol}, "Ǽ"}, {{XK_Multi_key, XK_apostrophe, XK_AE, XK_VoidSymbol}, "Ǽ"}, {{XK_Multi_key, XK_2, XK_3, XK_VoidSymbol}, "⅔"}, // U2154 | VULGAR FRACTION TWO THIRDS {{XK_dead_grave, XK_Cyrillic_IE, XK_VoidSymbol}, "Ѐ"}, // U0400 | CYRILLIC CAPITAL LETTER IE WITH GRAVE {{XK_Multi_key, XK_grave, XK_Cyrillic_IE, XK_VoidSymbol}, "Ѐ"}, {{XK_Multi_key, XK_underscore, XK_3, XK_VoidSymbol}, "₃"}, // U2083 | SUBSCRIPT THREE {{XK_Multi_key, XK_underscore, XK_KP_3, XK_VoidSymbol}, "₃"}, {{XK_dead_caron, XK_3, XK_VoidSymbol}, "₃"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ἂ"}, // U1F02 | GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ἂ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ἂ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ἂ"}, {{XK_dead_acute, XK_dead_diaeresis, XK_space, XK_VoidSymbol}, "΅"}, // U0385 | GREEK DIALYTIKA TONOS {{XK_dead_diaeresis, XK_dead_acute, XK_space, XK_VoidSymbol}, "΅"}, {{XK_Multi_key, XK_diaeresis, XK_dead_acute, XK_VoidSymbol}, "΅"}, {{XK_Multi_key, XK_diaeresis, XK_acute, XK_VoidSymbol}, "΅"}, {{XK_Multi_key, XK_diaeresis, XK_apostrophe, XK_VoidSymbol}, "΅"}, {{XK_Multi_key, XK_apostrophe, XK_quotedbl, XK_space, XK_VoidSymbol}, "΅"}, {{XK_dead_doublegrave, XK_E, XK_VoidSymbol}, "Ȅ"}, // U0204 | LATIN CAPITAL LETTER E WITH DOUBLE GRAVE {{XK_dead_abovedot, XK_w, XK_VoidSymbol}, "ẇ"}, // U1E87 | LATIN SMALL LETTER W WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_w, XK_VoidSymbol}, "ẇ"}, {{XK_Multi_key, XK_0, XK_3, XK_VoidSymbol}, "↉"}, // U2189 | VULGAR FRACTION ZERO THIRDS {{XK_Multi_key, XK_space, XK_period, XK_VoidSymbol}, " "}, // U2008 | PUNCTUATION SPACE {{XK_dead_grave, XK_Cyrillic_U, XK_VoidSymbol}, "У̀"}, // CYRILLIC CAPITAL LETTER U WITH COMBINING GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_Cyrillic_U, XK_VoidSymbol}, "У̀"}, {{XK_dead_currency, XK_f, XK_VoidSymbol}, "ƒ"}, // function | LATIN SMALL LETTER F WITH HOOK {{XK_dead_hook, XK_f, XK_VoidSymbol}, "ƒ"}, {{XK_dead_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, // U1F8D | GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾍ"}, {{XK_dead_belowdot, XK_D, XK_VoidSymbol}, "Ḍ"}, // U1E0C | LATIN CAPITAL LETTER D WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_D, XK_VoidSymbol}, "Ḍ"}, {{XK_dead_caron, XK_D, XK_VoidSymbol}, "Ď"}, // U010E | LATIN CAPITAL LETTER D WITH CARON {{XK_Multi_key, XK_c, XK_D, XK_VoidSymbol}, "Ď"}, {{XK_Multi_key, XK_less, XK_D, XK_VoidSymbol}, "Ď"}, {{XK_Multi_key, XK_D, XK_less, XK_VoidSymbol}, "Ď"}, {{XK_Multi_key, XK_parenleft, XK_kana_KO, XK_parenright, XK_VoidSymbol}, "㋙"}, // U32D9 | CIRCLED KATAKANA KO {{XK_dead_grave, XK_dead_psili, XK_Greek_epsilon, XK_VoidSymbol}, "ἒ"}, // U1F12 | GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_epsilon, XK_VoidSymbol}, "ἒ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_epsilon, XK_VoidSymbol}, "ἒ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_epsilon, XK_VoidSymbol}, "ἒ"}, {{XK_dead_doublegrave, XK_U, XK_VoidSymbol}, "Ȕ"}, // U0214 | LATIN CAPITAL LETTER U WITH DOUBLE GRAVE {{XK_dead_diaeresis, XK_t, XK_VoidSymbol}, "ẗ"}, // U1E97 | LATIN SMALL LETTER T WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_t, XK_VoidSymbol}, "ẗ"}, {{XK_Multi_key, XK_underscore, XK_apostrophe, XK_VoidSymbol}, "⍘"}, // U2358 | _ ' APL FUNCTIONAL SYMBOL QUOTE UNDERBAR {{XK_dead_hook, XK_k, XK_VoidSymbol}, "ƙ"}, // U0199 | LATIN SMALL LETTER K WITH HOOK {{XK_Multi_key, XK_less, XK_apostrophe, XK_VoidSymbol}, "‘"}, // U2018 | LEFT SINGLE QUOTATION MARK {{XK_Multi_key, XK_apostrophe, XK_less, XK_VoidSymbol}, "‘"}, {{XK_dead_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, // U1F9D | GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾝ"}, {{XK_dead_breve, XK_dead_cedilla, XK_E, XK_VoidSymbol}, "Ḝ"}, // U1E1C | LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE {{XK_dead_breve, XK_Multi_key, XK_comma, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_dead_breve, XK_Multi_key, XK_cedilla, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_Multi_key, XK_U, XK_dead_cedilla, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_Multi_key, XK_U, XK_space, XK_comma, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_Multi_key, XK_U, XK_cedilla, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_Multi_key, XK_b, XK_dead_cedilla, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_Multi_key, XK_b, XK_comma, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_Multi_key, XK_b, XK_cedilla, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_dead_cedilla, XK_dead_breve, XK_E, XK_VoidSymbol}, "Ḝ"}, {{XK_dead_breve, XK_G, XK_VoidSymbol}, "Ğ"}, // U011E | LATIN CAPITAL LETTER G WITH BREVE {{XK_Multi_key, XK_U, XK_G, XK_VoidSymbol}, "Ğ"}, {{XK_Multi_key, XK_G, XK_U, XK_VoidSymbol}, "Ğ"}, {{XK_Multi_key, XK_b, XK_G, XK_VoidSymbol}, "Ğ"}, {{XK_Multi_key, XK_breve, XK_G, XK_VoidSymbol}, "Ğ"}, {{XK_Multi_key, XK_G, XK_breve, XK_VoidSymbol}, "Ğ"}, {{XK_Multi_key, XK_G, XK_parenleft, XK_VoidSymbol}, "Ğ"}, {{XK_dead_hook, XK_d, XK_VoidSymbol}, "ɗ"}, // U0257 | LATIN SMALL LETTER D WITH HOOK {{XK_Multi_key, XK_L, XK_minus, XK_VoidSymbol}, "£"}, // sterling | POUND SIGN {{XK_Multi_key, XK_minus, XK_L, XK_VoidSymbol}, "£"}, {{XK_Multi_key, XK_l, XK_minus, XK_VoidSymbol}, "£"}, {{XK_Multi_key, XK_minus, XK_l, XK_VoidSymbol}, "£"}, {{XK_dead_currency, XK_l, XK_VoidSymbol}, "£"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ἢ"}, // U1F22 | GREEK SMALL LETTER ETA WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ἢ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ἢ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ἢ"}, {{XK_dead_hook, XK_N, XK_VoidSymbol}, "Ɲ"}, // U019D | LATIN CAPITAL LETTER N WITH LEFT HOOK {{XK_dead_hook, XK_Z, XK_VoidSymbol}, "Ȥ"}, // U0224 | LATIN CAPITAL LETTER Z WITH HOOK {{XK_dead_grave, XK_acircumflex, XK_VoidSymbol}, "ầ"}, // U1EA7 | LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE {{XK_Multi_key, XK_grave, XK_acircumflex, XK_VoidSymbol}, "ầ"}, {{XK_dead_grave, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ầ"}, {{XK_dead_grave, XK_Multi_key, XK_asciicircum, XK_a, XK_VoidSymbol}, "ầ"}, {{XK_Multi_key, XK_grave, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ầ"}, {{XK_Multi_key, XK_grave, XK_asciicircum, XK_a, XK_VoidSymbol}, "ầ"}, {{XK_dead_circumflex, XK_agrave, XK_VoidSymbol}, "ầ"}, {{XK_dead_circumflex, XK_dead_grave, XK_a, XK_VoidSymbol}, "ầ"}, {{XK_dead_voiced_sound, XK_kana_KU, XK_VoidSymbol}, "グ"}, // U30B0 | KATAKANA LETTER GU {{XK_Multi_key, XK_parenleft, XK_n, XK_parenright, XK_VoidSymbol}, "ⓝ"}, // U24DD | CIRCLED LATIN SMALL LETTER N {{XK_dead_breve, XK_nobreakspace, XK_VoidSymbol}, "̆"}, // U0306 | COMBINING BREVE {{XK_dead_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, // U1FAD | GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾭ"}, {{XK_dead_belowtilde, XK_I, XK_VoidSymbol}, "Ḭ"}, // U1E2C | LATIN CAPITAL LETTER I WITH TILDE BELOW {{XK_dead_ogonek, XK_I, XK_VoidSymbol}, "Į"}, // U012E | LATIN CAPITAL LETTER I WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_I, XK_VoidSymbol}, "Į"}, {{XK_Multi_key, XK_I, XK_semicolon, XK_VoidSymbol}, "Į"}, {{XK_Multi_key, XK_comma, XK_I, XK_VoidSymbol}, "Į"}, {{XK_Multi_key, XK_I, XK_comma, XK_VoidSymbol}, "Į"}, {{XK_dead_circumflex, XK_3, XK_VoidSymbol}, "³"}, // threesuperior | SUPERSCRIPT THREE {{XK_Multi_key, XK_asciicircum, XK_3, XK_VoidSymbol}, "³"}, {{XK_Multi_key, XK_3, XK_asciicircum, XK_VoidSymbol}, "³"}, {{XK_dead_circumflex, XK_KP_3, XK_VoidSymbol}, "³"}, {{XK_Multi_key, XK_asciicircum, XK_KP_3, XK_VoidSymbol}, "³"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_iota, XK_VoidSymbol}, "ἲ"}, // U1F32 | GREEK SMALL LETTER IOTA WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_iota, XK_VoidSymbol}, "ἲ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_iota, XK_VoidSymbol}, "ἲ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_iota, XK_VoidSymbol}, "ἲ"}, {{XK_Multi_key, XK_colon, XK_period, XK_VoidSymbol}, "∴"}, // therefore | : . THEREFORE {{XK_dead_breve, XK_dead_belowdot, XK_a, XK_VoidSymbol}, "ặ"}, // U1EB7 | LATIN SMALL LETTER A WITH BREVE AND DOT BELOW {{XK_dead_breve, XK_Multi_key, XK_exclam, XK_a, XK_VoidSymbol}, "ặ"}, {{XK_Multi_key, XK_U, XK_dead_belowdot, XK_a, XK_VoidSymbol}, "ặ"}, {{XK_Multi_key, XK_U, XK_exclam, XK_a, XK_VoidSymbol}, "ặ"}, {{XK_Multi_key, XK_b, XK_dead_belowdot, XK_a, XK_VoidSymbol}, "ặ"}, {{XK_Multi_key, XK_b, XK_exclam, XK_a, XK_VoidSymbol}, "ặ"}, {{XK_dead_belowdot, XK_abreve, XK_VoidSymbol}, "ặ"}, {{XK_dead_belowdot, XK_dead_breve, XK_a, XK_VoidSymbol}, "ặ"}, {{XK_dead_doublegrave, XK_Cyrillic_o, XK_VoidSymbol}, "о̏"}, // CYRILLIC SMALL LETTER O WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_o, XK_VoidSymbol}, "о̏"}, {{XK_dead_grave, XK_Cyrillic_o, XK_VoidSymbol}, "о̀"}, // CYRILLIC SMALL LETTER O WITH COMBINING GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_Cyrillic_o, XK_VoidSymbol}, "о̀"}, {{XK_dead_currency, XK_T, XK_VoidSymbol}, "₮"}, // U20AE | TUGRIK SIGN {{XK_Multi_key, XK_parenleft, XK_F, XK_parenright, XK_VoidSymbol}, "Ⓕ"}, // U24BB | CIRCLED LATIN CAPITAL LETTER F {{XK_dead_macron, XK_Cyrillic_o, XK_VoidSymbol}, "о̄"}, // CYRILLIC SMALL LETTER O WITH COMBINING MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_o, XK_VoidSymbol}, "о̄"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_o, XK_VoidSymbol}, "о̄"}, {{XK_dead_belowcircumflex, XK_L, XK_VoidSymbol}, "Ḽ"}, // U1E3C | LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW {{XK_Multi_key, XK_parenleft, XK_5, XK_0, XK_parenright, XK_VoidSymbol}, "㊿"}, // U32BF | CIRCLED NUMBER FIFTY {{XK_Multi_key, XK_parenleft, XK_5, XK_KP_0, XK_parenright, XK_VoidSymbol}, "㊿"}, {{XK_Multi_key, XK_parenleft, XK_KP_5, XK_0, XK_parenright, XK_VoidSymbol}, "㊿"}, {{XK_Multi_key, XK_parenleft, XK_KP_5, XK_KP_0, XK_parenright, XK_VoidSymbol}, "㊿"}, {{XK_dead_caron, XK_l, XK_VoidSymbol}, "ľ"}, // U013E | LATIN SMALL LETTER L WITH CARON {{XK_Multi_key, XK_c, XK_l, XK_VoidSymbol}, "ľ"}, {{XK_Multi_key, XK_less, XK_l, XK_VoidSymbol}, "ľ"}, {{XK_Multi_key, XK_l, XK_less, XK_VoidSymbol}, "ľ"}, {{XK_Multi_key, XK_parenleft, XK_kana_TSU, XK_parenright, XK_VoidSymbol}, "㋡"}, // U32E1 | CIRCLED KATAKANA TU {{XK_dead_tilde, XK_A, XK_VoidSymbol}, "Ã"}, // Atilde | LATIN CAPITAL LETTER A WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_A, XK_VoidSymbol}, "Ã"}, {{XK_Multi_key, XK_A, XK_asciitilde, XK_VoidSymbol}, "Ã"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_omicron, XK_VoidSymbol}, "ὂ"}, // U1F42 | GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_omicron, XK_VoidSymbol}, "ὂ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_omicron, XK_VoidSymbol}, "ὂ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_omicron, XK_VoidSymbol}, "ὂ"}, {{XK_dead_abovedot, XK_j, XK_VoidSymbol}, "ȷ"}, // U0237 | LATIN SMALL LETTER DOTLESS J {{XK_dead_circumflex, XK_dead_belowdot, XK_e, XK_VoidSymbol}, "ệ"}, // U1EC7 | LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW {{XK_dead_circumflex, XK_Multi_key, XK_exclam, XK_e, XK_VoidSymbol}, "ệ"}, {{XK_Multi_key, XK_asciicircum, XK_dead_belowdot, XK_e, XK_VoidSymbol}, "ệ"}, {{XK_Multi_key, XK_asciicircum, XK_exclam, XK_e, XK_VoidSymbol}, "ệ"}, {{XK_dead_belowdot, XK_ecircumflex, XK_VoidSymbol}, "ệ"}, {{XK_dead_belowdot, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ệ"}, {{XK_Multi_key, XK_parenleft, XK_V, XK_parenright, XK_VoidSymbol}, "Ⓥ"}, // U24CB | CIRCLED LATIN CAPITAL LETTER V {{XK_Multi_key, XK_backslash, XK_o, XK_slash, XK_VoidSymbol}, "🙌"}, // PERSON RAISING BOTH HANDS IN CELEBRATION {{XK_dead_breve, XK_O, XK_VoidSymbol}, "Ŏ"}, // U014E | LATIN CAPITAL LETTER O WITH BREVE {{XK_Multi_key, XK_U, XK_O, XK_VoidSymbol}, "Ŏ"}, {{XK_Multi_key, XK_b, XK_O, XK_VoidSymbol}, "Ŏ"}, {{XK_dead_grave, XK_Cyrillic_ie, XK_VoidSymbol}, "ѐ"}, // U0450 | CYRILLIC SMALL LETTER IE WITH GRAVE {{XK_Multi_key, XK_grave, XK_Cyrillic_ie, XK_VoidSymbol}, "ѐ"}, {{XK_dead_acute, XK_O, XK_VoidSymbol}, "Ó"}, // Oacute | LATIN CAPITAL LETTER O WITH ACUTE {{XK_Multi_key, XK_acute, XK_O, XK_VoidSymbol}, "Ó"}, {{XK_Multi_key, XK_O, XK_acute, XK_VoidSymbol}, "Ó"}, {{XK_Multi_key, XK_apostrophe, XK_O, XK_VoidSymbol}, "Ó"}, {{XK_Multi_key, XK_O, XK_apostrophe, XK_VoidSymbol}, "Ó"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_upsilon, XK_VoidSymbol}, "ὒ"}, // U1F52 | GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_upsilon, XK_VoidSymbol}, "ὒ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_upsilon, XK_VoidSymbol}, "ὒ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_upsilon, XK_VoidSymbol}, "ὒ"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_4, XK_parenright, XK_VoidSymbol}, "㉔"}, // U3254 | CIRCLED NUMBER TWENTY FOUR {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_4, XK_parenright, XK_VoidSymbol}, "㉔"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_4, XK_parenright, XK_VoidSymbol}, "㉔"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_4, XK_parenright, XK_VoidSymbol}, "㉔"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_4, XK_parenright, XK_VoidSymbol}, "㉔"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_4, XK_parenright, XK_VoidSymbol}, "㉔"}, {{XK_dead_tilde, XK_ocircumflex, XK_VoidSymbol}, "ỗ"}, // U1ED7 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE {{XK_Multi_key, XK_asciitilde, XK_ocircumflex, XK_VoidSymbol}, "ỗ"}, {{XK_dead_tilde, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ỗ"}, {{XK_dead_tilde, XK_Multi_key, XK_asciicircum, XK_o, XK_VoidSymbol}, "ỗ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ỗ"}, {{XK_Multi_key, XK_asciitilde, XK_asciicircum, XK_o, XK_VoidSymbol}, "ỗ"}, {{XK_dead_circumflex, XK_otilde, XK_VoidSymbol}, "ỗ"}, {{XK_dead_circumflex, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ỗ"}, {{XK_dead_voiced_sound, XK_kana_SHI, XK_VoidSymbol}, "ジ"}, // U30B8 | KATAKANA LETTER ZI {{XK_dead_caron, XK_Udiaeresis, XK_VoidSymbol}, "Ǚ"}, // U01D9 | LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON {{XK_Multi_key, XK_c, XK_Udiaeresis, XK_VoidSymbol}, "Ǚ"}, {{XK_dead_caron, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǚ"}, {{XK_dead_caron, XK_Multi_key, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǚ"}, {{XK_Multi_key, XK_c, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǚ"}, {{XK_Multi_key, XK_c, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǚ"}, {{XK_dead_caron, XK_V, XK_VoidSymbol}, "Ǚ"}, {{XK_dead_diaeresis, XK_dead_caron, XK_U, XK_VoidSymbol}, "Ǚ"}, {{XK_Multi_key, XK_parenleft, XK_v, XK_parenright, XK_VoidSymbol}, "ⓥ"}, // U24E5 | CIRCLED LATIN SMALL LETTER V {{XK_Multi_key, XK_parenleft, XK_l, XK_parenright, XK_VoidSymbol}, "ⓛ"}, // U24DB | CIRCLED LATIN SMALL LETTER L {{XK_Multi_key, XK_parenleft, XK_4, XK_2, XK_parenright, XK_VoidSymbol}, "㊷"}, // U32B7 | CIRCLED NUMBER FORTY TWO {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "㊷"}, {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_2, XK_parenright, XK_VoidSymbol}, "㊷"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_2, XK_parenright, XK_VoidSymbol}, "㊷"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "㊷"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_2, XK_parenright, XK_VoidSymbol}, "㊷"}, {{XK_dead_macron, XK_dead_belowdot, XK_R, XK_VoidSymbol}, "Ṝ"}, // U1E5C | LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON {{XK_dead_macron, XK_Multi_key, XK_exclam, XK_R, XK_VoidSymbol}, "Ṝ"}, {{XK_Multi_key, XK_macron, XK_dead_belowdot, XK_R, XK_VoidSymbol}, "Ṝ"}, {{XK_Multi_key, XK_macron, XK_exclam, XK_R, XK_VoidSymbol}, "Ṝ"}, {{XK_Multi_key, XK_underscore, XK_dead_belowdot, XK_R, XK_VoidSymbol}, "Ṝ"}, {{XK_Multi_key, XK_underscore, XK_exclam, XK_R, XK_VoidSymbol}, "Ṝ"}, {{XK_dead_belowdot, XK_dead_macron, XK_R, XK_VoidSymbol}, "Ṝ"}, {{XK_Multi_key, XK_parenleft, XK_kana_TA, XK_parenright, XK_VoidSymbol}, "㋟"}, // U32DF | CIRCLED KATAKANA TA {{XK_dead_cedilla, XK_S, XK_VoidSymbol}, "Ş"}, // U015E | LATIN CAPITAL LETTER S WITH CEDILLA {{XK_Multi_key, XK_comma, XK_S, XK_VoidSymbol}, "Ş"}, {{XK_Multi_key, XK_S, XK_comma, XK_VoidSymbol}, "Ş"}, {{XK_Multi_key, XK_cedilla, XK_S, XK_VoidSymbol}, "Ş"}, {{XK_Multi_key, XK_1, XK_1, XK_0, XK_VoidSymbol}, "⅒"}, // U2152 | VULGAR FRACTION ONE TENTH {{XK_dead_tilde, XK_a, XK_VoidSymbol}, "ã"}, // atilde | LATIN SMALL LETTER A WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_a, XK_VoidSymbol}, "ã"}, {{XK_Multi_key, XK_a, XK_asciitilde, XK_VoidSymbol}, "ã"}, {{XK_dead_grave, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ὢ"}, // U1F62 | GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ὢ"}, {{XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ὢ"}, {{XK_Multi_key, XK_grave, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ὢ"}, {{XK_Multi_key, XK_less, XK_equal, XK_VoidSymbol}, "≤"}, // U2264 | LESS-THAN OR EQUAL TO {{XK_Multi_key, XK_less, XK_underscore, XK_VoidSymbol}, "≤"}, {{XK_Multi_key, XK_underscore, XK_less, XK_VoidSymbol}, "≤"}, {{XK_dead_hook, XK_u, XK_VoidSymbol}, "ủ"}, // U1EE7 | LATIN SMALL LETTER U WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_u, XK_VoidSymbol}, "ủ"}, {{XK_dead_caron, XK_k, XK_VoidSymbol}, "ǩ"}, // U01E9 | LATIN SMALL LETTER K WITH CARON {{XK_Multi_key, XK_c, XK_k, XK_VoidSymbol}, "ǩ"}, {{XK_dead_stroke, XK_R, XK_VoidSymbol}, "Ɍ"}, // U024C | LATIN CAPITAL LETTER R WITH STROKE {{XK_dead_hook, XK_h, XK_VoidSymbol}, "ɦ"}, // U0266 | LATIN SMALL LETTER H WITH HOOK {{XK_Multi_key, XK_diaeresis, XK_dead_grave, XK_VoidSymbol}, "῭"}, // U1FED | GREEK DIALYTIKA AND VARIA {{XK_Multi_key, XK_diaeresis, XK_grave, XK_VoidSymbol}, "῭"}, {{XK_Multi_key, XK_numbersign, XK_S, XK_VoidSymbol}, "♬"}, // U266c | BEAMED SIXTEENTH NOTES {{XK_Multi_key, XK_parenleft, XK_kana_MI, XK_parenright, XK_VoidSymbol}, "㋯"}, // U32EF | CIRCLED KATAKANA MI {{XK_dead_abovering, XK_U, XK_VoidSymbol}, "Ů"}, // U016E | LATIN CAPITAL LETTER U WITH RING ABOVE {{XK_Multi_key, XK_o, XK_U, XK_VoidSymbol}, "Ů"}, {{XK_Multi_key, XK_asterisk, XK_U, XK_VoidSymbol}, "Ů"}, {{XK_Multi_key, XK_U, XK_asterisk, XK_VoidSymbol}, "Ů"}, {{XK_dead_tilde, XK_nobreakspace, XK_VoidSymbol}, "̃"}, // U0303 | COMBINING TILDE {{XK_Multi_key, XK_parenleft, XK_1, XK_7, XK_parenright, XK_VoidSymbol}, "⑰"}, // U2470 | CIRCLED NUMBER SEVENTEEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_7, XK_parenright, XK_VoidSymbol}, "⑰"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_7, XK_parenright, XK_VoidSymbol}, "⑰"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_7, XK_parenright, XK_VoidSymbol}, "⑰"}, {{XK_dead_acute, XK_o, XK_VoidSymbol}, "ó"}, // oacute | LATIN SMALL LETTER O WITH ACUTE {{XK_Multi_key, XK_acute, XK_o, XK_VoidSymbol}, "ó"}, {{XK_Multi_key, XK_o, XK_acute, XK_VoidSymbol}, "ó"}, {{XK_Multi_key, XK_apostrophe, XK_o, XK_VoidSymbol}, "ó"}, {{XK_Multi_key, XK_o, XK_apostrophe, XK_VoidSymbol}, "ó"}, {{XK_dead_grave, XK_Greek_epsilon, XK_VoidSymbol}, "ὲ"}, // U1F72 | GREEK SMALL LETTER EPSILON WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_epsilon, XK_VoidSymbol}, "ὲ"}, {{XK_dead_hook, XK_schwa, XK_VoidSymbol}, "ɚ"}, // U025A | LATIN SMALL LETTER SCHWA WITH HOOK {{XK_dead_currency, XK_b, XK_VoidSymbol}, "฿"}, // Thai_baht | THAI CURRENCY SYMBOL BAHT {{XK_dead_hook, XK_y, XK_VoidSymbol}, "ỷ"}, // U1EF7 | LATIN SMALL LETTER Y WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_y, XK_VoidSymbol}, "ỷ"}, {{XK_dead_grave, XK_n, XK_VoidSymbol}, "ǹ"}, // U01F9 | LATIN SMALL LETTER N WITH GRAVE {{XK_Multi_key, XK_grave, XK_n, XK_VoidSymbol}, "ǹ"}, {{XK_dead_circumflex, XK_8, XK_VoidSymbol}, "⁸"}, // U2078 | SUPERSCRIPT EIGHT {{XK_Multi_key, XK_asciicircum, XK_8, XK_VoidSymbol}, "⁸"}, {{XK_dead_circumflex, XK_KP_8, XK_VoidSymbol}, "⁸"}, {{XK_Multi_key, XK_asciicircum, XK_KP_8, XK_VoidSymbol}, "⁸"}, {{XK_dead_iota, XK_space, XK_VoidSymbol}, "ͺ"}, // U37a | GREEK YPOGEGRAMMENI {{XK_dead_iota, XK_dead_iota, XK_VoidSymbol}, "ͺ"}, {{XK_dead_tilde, XK_V, XK_VoidSymbol}, "Ṽ"}, // U1E7C | LATIN CAPITAL LETTER V WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_V, XK_VoidSymbol}, "Ṽ"}, {{XK_dead_caron, XK_z, XK_VoidSymbol}, "ž"}, // U017E | LATIN SMALL LETTER Z WITH CARON {{XK_Multi_key, XK_c, XK_z, XK_VoidSymbol}, "ž"}, {{XK_Multi_key, XK_v, XK_z, XK_VoidSymbol}, "ž"}, {{XK_Multi_key, XK_less, XK_z, XK_VoidSymbol}, "ž"}, {{XK_Multi_key, XK_z, XK_less, XK_VoidSymbol}, "ž"}, {{XK_dead_circumflex, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̂"}, // CYRILLIC CAPITAL LETTER ER WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̂"}, {{XK_dead_iota, XK_dead_grave, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾂ"}, // U1F82 | GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾂ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾂ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾂ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾂ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾂ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾂ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾂ"}, {{XK_dead_hook, XK_t, XK_VoidSymbol}, "ƭ"}, // U01AD | LATIN SMALL LETTER T WITH HOOK {{XK_dead_belowmacron, XK_b, XK_VoidSymbol}, "ḇ"}, // U1E07 | LATIN SMALL LETTER B WITH LINE BELOW {{XK_dead_voiced_sound, XK_kana_TA, XK_VoidSymbol}, "ダ"}, // U30C0 | KATAKANA LETTER DA {{XK_dead_circumflex, XK_c, XK_VoidSymbol}, "ĉ"}, // U0109 | LATIN SMALL LETTER C WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_c, XK_VoidSymbol}, "ĉ"}, {{XK_Multi_key, XK_underscore, XK_8, XK_VoidSymbol}, "₈"}, // U2088 | SUBSCRIPT EIGHT {{XK_Multi_key, XK_underscore, XK_KP_8, XK_VoidSymbol}, "₈"}, {{XK_dead_caron, XK_8, XK_VoidSymbol}, "₈"}, {{XK_dead_acute, XK_Greek_IOTA, XK_VoidSymbol}, "Ί"}, // U038A | GREEK CAPITAL LETTER IOTA WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_IOTA, XK_VoidSymbol}, "Ί"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_IOTA, XK_VoidSymbol}, "Ί"}, {{XK_Multi_key, XK_Greek_IOTA, XK_apostrophe, XK_VoidSymbol}, "Ί"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἅ"}, // U1F0D | GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἅ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἅ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἅ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἅ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἅ"}, {{XK_dead_diaeresis, XK_X, XK_VoidSymbol}, "Ẍ"}, // U1E8C | LATIN CAPITAL LETTER X WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_X, XK_VoidSymbol}, "Ẍ"}, {{XK_dead_invertedbreve, XK_o, XK_VoidSymbol}, "ȏ"}, // U020F | LATIN SMALL LETTER O WITH INVERTED BREVE {{XK_dead_circumflex, XK_parenright, XK_VoidSymbol}, "⁾"}, // U207E | SUPERSCRIPT RIGHT PARENTHESIS {{XK_Multi_key, XK_asciicircum, XK_parenright, XK_VoidSymbol}, "⁾"}, {{XK_Multi_key, XK_minus, XK_minus, XK_period, XK_VoidSymbol}, "–"}, // U2013 | EN DASH {{XK_dead_iota, XK_dead_grave, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾒ"}, // U1F92 | GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾒ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾒ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾒ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾒ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾒ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾒ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾒ"}, {{XK_dead_acute, XK_emacron, XK_VoidSymbol}, "ḗ"}, // U1E17 | LATIN SMALL LETTER E WITH MACRON AND ACUTE {{XK_Multi_key, XK_acute, XK_emacron, XK_VoidSymbol}, "ḗ"}, {{XK_Multi_key, XK_apostrophe, XK_emacron, XK_VoidSymbol}, "ḗ"}, {{XK_dead_acute, XK_dead_macron, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_dead_acute, XK_Multi_key, XK_macron, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_dead_acute, XK_Multi_key, XK_underscore, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_Multi_key, XK_acute, XK_dead_macron, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_Multi_key, XK_acute, XK_macron, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_Multi_key, XK_acute, XK_underscore, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_macron, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_Multi_key, XK_apostrophe, XK_macron, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_Multi_key, XK_apostrophe, XK_underscore, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_dead_macron, XK_eacute, XK_VoidSymbol}, "ḗ"}, {{XK_dead_macron, XK_dead_acute, XK_e, XK_VoidSymbol}, "ḗ"}, {{XK_Multi_key, XK_L, XK_L, XK_A, XK_P, XK_VoidSymbol}, "🖖"}, // U1F596 | RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS {{XK_dead_ogonek, XK_e, XK_VoidSymbol}, "ę"}, // U0119 | LATIN SMALL LETTER E WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_e, XK_VoidSymbol}, "ę"}, {{XK_Multi_key, XK_e, XK_semicolon, XK_VoidSymbol}, "ę"}, {{XK_Multi_key, XK_comma, XK_e, XK_VoidSymbol}, "ę"}, {{XK_Multi_key, XK_e, XK_comma, XK_VoidSymbol}, "ę"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_omicron, XK_VoidSymbol}, "ὅ"}, // U1F45 | GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_omicron, XK_VoidSymbol}, "ὅ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_omicron, XK_VoidSymbol}, "ὅ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_omicron, XK_VoidSymbol}, "ὅ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_omicron, XK_VoidSymbol}, "ὅ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_omicron, XK_VoidSymbol}, "ὅ"}, {{XK_dead_belowmacron, XK_T, XK_VoidSymbol}, "Ṯ"}, // U1E6E | LATIN CAPITAL LETTER T WITH LINE BELOW {{XK_dead_acute, XK_dead_dasia, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἕ"}, // U1F1D | GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἕ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἕ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἕ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἕ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἕ"}, {{XK_dead_caron, XK_h, XK_VoidSymbol}, "ȟ"}, // U021F | LATIN SMALL LETTER H WITH CARON {{XK_Multi_key, XK_c, XK_h, XK_VoidSymbol}, "ȟ"}, {{XK_dead_currency, XK_O, XK_VoidSymbol}, "૱"}, // U0AF1 | GUJARATI RUPEE SIGN {{XK_Multi_key, XK_plus, XK_plus, XK_VoidSymbol}, "#"}, // numbersign | NUMBER SIGN {{XK_dead_iota, XK_dead_grave, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾢ"}, // U1FA2 | GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾢ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾢ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾢ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾢ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾢ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾢ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾢ"}, {{XK_dead_stroke, XK_e, XK_VoidSymbol}, "ɇ"}, // U0247 | LATIN SMALL LETTER E WITH STROKE {{XK_dead_diaeresis, XK_h, XK_VoidSymbol}, "ḧ"}, // U1E27 | LATIN SMALL LETTER H WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_h, XK_VoidSymbol}, "ḧ"}, {{XK_dead_grave, XK_Greek_alpha, XK_VoidSymbol}, "ὰ"}, // U1F70 | GREEK SMALL LETTER ALPHA WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_alpha, XK_VoidSymbol}, "ὰ"}, {{XK_dead_tilde, XK_i, XK_VoidSymbol}, "ĩ"}, // U0129 | LATIN SMALL LETTER I WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_i, XK_VoidSymbol}, "ĩ"}, {{XK_Multi_key, XK_i, XK_asciitilde, XK_VoidSymbol}, "ĩ"}, {{XK_dead_diaeresis, XK_dead_diaeresis, XK_VoidSymbol}, "¨"}, // diaeresis | DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_quotedbl, XK_VoidSymbol}, "¨"}, {{XK_dead_diaeresis, XK_Greek_IOTA, XK_VoidSymbol}, "Ϊ"}, // U03AA | GREEK CAPITAL LETTER IOTA WITH DIALYTIKA {{XK_Multi_key, XK_quotedbl, XK_Greek_IOTA, XK_VoidSymbol}, "Ϊ"}, {{XK_Multi_key, XK_Greek_IOTA, XK_quotedbl, XK_VoidSymbol}, "Ϊ"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "Ἥ"}, // U1F2D | GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "Ἥ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "Ἥ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "Ἥ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "Ἥ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "Ἥ"}, {{XK_dead_circumflex, XK_dead_belowdot, XK_A, XK_VoidSymbol}, "Ậ"}, // U1EAC | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW {{XK_dead_circumflex, XK_Multi_key, XK_exclam, XK_A, XK_VoidSymbol}, "Ậ"}, {{XK_Multi_key, XK_asciicircum, XK_dead_belowdot, XK_A, XK_VoidSymbol}, "Ậ"}, {{XK_Multi_key, XK_asciicircum, XK_exclam, XK_A, XK_VoidSymbol}, "Ậ"}, {{XK_dead_belowdot, XK_Acircumflex, XK_VoidSymbol}, "Ậ"}, {{XK_dead_belowdot, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ậ"}, {{XK_dead_abovedot, XK_o, XK_VoidSymbol}, "ȯ"}, // U022F | LATIN SMALL LETTER O WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_o, XK_VoidSymbol}, "ȯ"}, {{XK_dead_iota, XK_dead_grave, XK_Greek_alpha, XK_VoidSymbol}, "ᾲ"}, // U1FB2 | GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_grave, XK_Greek_alpha, XK_VoidSymbol}, "ᾲ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_Greek_alpha, XK_VoidSymbol}, "ᾲ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_Greek_alpha, XK_VoidSymbol}, "ᾲ"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_9, XK_parenright, XK_VoidSymbol}, "㊴"}, // U32B4 | CIRCLED NUMBER THIRTY NINE {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_9, XK_parenright, XK_VoidSymbol}, "㊴"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_9, XK_parenright, XK_VoidSymbol}, "㊴"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_9, XK_parenright, XK_VoidSymbol}, "㊴"}, {{XK_dead_belowdot, XK_l, XK_VoidSymbol}, "ḷ"}, // U1E37 | LATIN SMALL LETTER L WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_l, XK_VoidSymbol}, "ḷ"}, {{XK_dead_acute, XK_L, XK_VoidSymbol}, "Ĺ"}, // U0139 | LATIN CAPITAL LETTER L WITH ACUTE {{XK_Multi_key, XK_acute, XK_L, XK_VoidSymbol}, "Ĺ"}, {{XK_Multi_key, XK_apostrophe, XK_L, XK_VoidSymbol}, "Ĺ"}, {{XK_Multi_key, XK_L, XK_apostrophe, XK_VoidSymbol}, "Ĺ"}, {{XK_dead_cedilla, XK_space, XK_VoidSymbol}, "¸"}, // cedilla | CEDILLA {{XK_dead_cedilla, XK_dead_cedilla, XK_VoidSymbol}, "¸"}, {{XK_Multi_key, XK_comma, XK_space, XK_VoidSymbol}, "¸"}, {{XK_Multi_key, XK_space, XK_comma, XK_VoidSymbol}, "¸"}, {{XK_Multi_key, XK_comma, XK_comma, XK_VoidSymbol}, "¸"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_IOTA, XK_VoidSymbol}, "Ἵ"}, // U1F3D | GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_IOTA, XK_VoidSymbol}, "Ἵ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_IOTA, XK_VoidSymbol}, "Ἵ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_IOTA, XK_VoidSymbol}, "Ἵ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_IOTA, XK_VoidSymbol}, "Ἵ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_IOTA, XK_VoidSymbol}, "Ἵ"}, {{XK_dead_tilde, XK_E, XK_VoidSymbol}, "Ẽ"}, // U1EBC | LATIN CAPITAL LETTER E WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_E, XK_VoidSymbol}, "Ẽ"}, {{XK_Multi_key, XK_parenleft, XK_K, XK_parenright, XK_VoidSymbol}, "Ⓚ"}, // U24C0 | CIRCLED LATIN CAPITAL LETTER K {{XK_dead_iota, XK_dead_grave, XK_Greek_eta, XK_VoidSymbol}, "ῂ"}, // U1FC2 | GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_grave, XK_Greek_eta, XK_VoidSymbol}, "ῂ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_Greek_eta, XK_VoidSymbol}, "ῂ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_Greek_eta, XK_VoidSymbol}, "ῂ"}, {{XK_Multi_key, XK_less, XK_greater, XK_VoidSymbol}, "⋄"}, // U22c4 | < > DIAMOND OPERATOR {{XK_Multi_key, XK_greater, XK_less, XK_VoidSymbol}, "⋄"}, {{XK_dead_belowdot, XK_n, XK_VoidSymbol}, "ṇ"}, // U1E47 | LATIN SMALL LETTER N WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_n, XK_VoidSymbol}, "ṇ"}, {{XK_dead_grave, XK_E, XK_VoidSymbol}, "È"}, // Egrave | LATIN CAPITAL LETTER E WITH GRAVE {{XK_Multi_key, XK_grave, XK_E, XK_VoidSymbol}, "È"}, {{XK_Multi_key, XK_E, XK_grave, XK_VoidSymbol}, "È"}, {{XK_dead_diaeresis, XK_Greek_iota, XK_VoidSymbol}, "ϊ"}, // U03CA | GREEK SMALL LETTER IOTA WITH DIALYTIKA {{XK_Multi_key, XK_quotedbl, XK_Greek_iota, XK_VoidSymbol}, "ϊ"}, {{XK_Multi_key, XK_Greek_iota, XK_quotedbl, XK_VoidSymbol}, "ϊ"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὅ"}, // U1F4D | GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὅ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὅ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὅ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὅ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὅ"}, {{XK_dead_belowdot, XK_O, XK_VoidSymbol}, "Ọ"}, // U1ECC | LATIN CAPITAL LETTER O WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_O, XK_VoidSymbol}, "Ọ"}, {{XK_dead_stroke, XK_y, XK_VoidSymbol}, "ɏ"}, // U024F | LATIN SMALL LETTER Y WITH STROKE {{XK_dead_caron, XK_a, XK_VoidSymbol}, "ǎ"}, // U01CE | LATIN SMALL LETTER A WITH CARON {{XK_Multi_key, XK_c, XK_a, XK_VoidSymbol}, "ǎ"}, {{XK_dead_breve, XK_Cyrillic_A, XK_VoidSymbol}, "Ӑ"}, // U04D0 | CYRILLIC CAPITAL LETTER A WITH BREVE {{XK_Multi_key, XK_U, XK_Cyrillic_A, XK_VoidSymbol}, "Ӑ"}, {{XK_Multi_key, XK_b, XK_Cyrillic_A, XK_VoidSymbol}, "Ӑ"}, {{XK_dead_grave, XK_Greek_iotadieresis, XK_VoidSymbol}, "ῒ"}, // U1FD2 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA {{XK_Multi_key, XK_grave, XK_Greek_iotadieresis, XK_VoidSymbol}, "ῒ"}, {{XK_dead_grave, XK_dead_diaeresis, XK_Greek_iota, XK_VoidSymbol}, "ῒ"}, {{XK_dead_grave, XK_Multi_key, XK_quotedbl, XK_Greek_iota, XK_VoidSymbol}, "ῒ"}, {{XK_Multi_key, XK_grave, XK_dead_diaeresis, XK_Greek_iota, XK_VoidSymbol}, "ῒ"}, {{XK_Multi_key, XK_grave, XK_quotedbl, XK_Greek_iota, XK_VoidSymbol}, "ῒ"}, {{XK_Multi_key, XK_parenleft, XK_kana_O, XK_parenright, XK_VoidSymbol}, "㋔"}, // U32D4 | CIRCLED KATAKANA O {{XK_dead_abovedot, XK_p, XK_VoidSymbol}, "ṗ"}, // U1E57 | LATIN SMALL LETTER P WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_p, XK_VoidSymbol}, "ṗ"}, {{XK_Multi_key, XK_p, XK_period, XK_VoidSymbol}, "ṗ"}, {{XK_dead_caron, XK_r, XK_VoidSymbol}, "ř"}, // U0159 | LATIN SMALL LETTER R WITH CARON {{XK_Multi_key, XK_c, XK_r, XK_VoidSymbol}, "ř"}, {{XK_Multi_key, XK_less, XK_r, XK_VoidSymbol}, "ř"}, {{XK_Multi_key, XK_r, XK_less, XK_VoidSymbol}, "ř"}, {{XK_dead_stroke, XK_O, XK_VoidSymbol}, "Ø"}, // Oslash | LATIN CAPITAL LETTER O WITH STROKE {{XK_Multi_key, XK_slash, XK_O, XK_VoidSymbol}, "Ø"}, {{XK_Multi_key, XK_O, XK_slash, XK_VoidSymbol}, "Ø"}, {{XK_Multi_key, XK_KP_Divide, XK_O, XK_VoidSymbol}, "Ø"}, {{XK_dead_acute, XK_Cyrillic_ER, XK_VoidSymbol}, "Р́"}, // CYRILLIC CAPITAL LETTER ER WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_ER, XK_VoidSymbol}, "Р́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_ER, XK_VoidSymbol}, "Р́"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὕ"}, // U1F5D | GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὕ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὕ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὕ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὕ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὕ"}, {{XK_dead_grave, XK_Ohorn, XK_VoidSymbol}, "Ờ"}, // U1EDC | LATIN CAPITAL LETTER O WITH HORN AND GRAVE {{XK_Multi_key, XK_grave, XK_Ohorn, XK_VoidSymbol}, "Ờ"}, {{XK_dead_grave, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ờ"}, {{XK_dead_grave, XK_Multi_key, XK_plus, XK_O, XK_VoidSymbol}, "Ờ"}, {{XK_Multi_key, XK_grave, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ờ"}, {{XK_Multi_key, XK_grave, XK_plus, XK_O, XK_VoidSymbol}, "Ờ"}, {{XK_dead_horn, XK_Ograve, XK_VoidSymbol}, "Ờ"}, {{XK_dead_horn, XK_dead_grave, XK_O, XK_VoidSymbol}, "Ờ"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_5, XK_parenright, XK_VoidSymbol}, "㉟"}, // U325F | CIRCLED NUMBER THIRTY FIVE {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_5, XK_parenright, XK_VoidSymbol}, "㉟"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_5, XK_parenright, XK_VoidSymbol}, "㉟"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_5, XK_parenright, XK_VoidSymbol}, "㉟"}, {{XK_dead_macron, XK_Adiaeresis, XK_VoidSymbol}, "Ǟ"}, // U01DE | LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON {{XK_Multi_key, XK_macron, XK_Adiaeresis, XK_VoidSymbol}, "Ǟ"}, {{XK_Multi_key, XK_underscore, XK_Adiaeresis, XK_VoidSymbol}, "Ǟ"}, {{XK_dead_macron, XK_dead_diaeresis, XK_A, XK_VoidSymbol}, "Ǟ"}, {{XK_dead_macron, XK_Multi_key, XK_quotedbl, XK_A, XK_VoidSymbol}, "Ǟ"}, {{XK_Multi_key, XK_macron, XK_dead_diaeresis, XK_A, XK_VoidSymbol}, "Ǟ"}, {{XK_Multi_key, XK_macron, XK_quotedbl, XK_A, XK_VoidSymbol}, "Ǟ"}, {{XK_Multi_key, XK_underscore, XK_dead_diaeresis, XK_A, XK_VoidSymbol}, "Ǟ"}, {{XK_Multi_key, XK_underscore, XK_quotedbl, XK_A, XK_VoidSymbol}, "Ǟ"}, {{XK_dead_diaeresis, XK_Amacron, XK_VoidSymbol}, "Ǟ"}, {{XK_dead_diaeresis, XK_dead_macron, XK_A, XK_VoidSymbol}, "Ǟ"}, {{XK_Multi_key, XK_1, XK_9, XK_VoidSymbol}, "⅑"}, // U2151 | VULGAR FRACTION ONE NINTH {{XK_dead_grave, XK_Greek_upsilondieresis, XK_VoidSymbol}, "ῢ"}, // U1FE2 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA {{XK_Multi_key, XK_grave, XK_Greek_upsilondieresis, XK_VoidSymbol}, "ῢ"}, {{XK_dead_grave, XK_dead_diaeresis, XK_Greek_upsilon, XK_VoidSymbol}, "ῢ"}, {{XK_dead_grave, XK_Multi_key, XK_quotedbl, XK_Greek_upsilon, XK_VoidSymbol}, "ῢ"}, {{XK_Multi_key, XK_grave, XK_dead_diaeresis, XK_Greek_upsilon, XK_VoidSymbol}, "ῢ"}, {{XK_Multi_key, XK_grave, XK_quotedbl, XK_Greek_upsilon, XK_VoidSymbol}, "ῢ"}, {{XK_Multi_key, XK_s, XK_o, XK_VoidSymbol}, "§"}, // section | SECTION SIGN {{XK_Multi_key, XK_o, XK_s, XK_VoidSymbol}, "§"}, {{XK_Multi_key, XK_S, XK_O, XK_VoidSymbol}, "§"}, {{XK_Multi_key, XK_O, XK_S, XK_VoidSymbol}, "§"}, {{XK_Multi_key, XK_s, XK_exclam, XK_VoidSymbol}, "§"}, {{XK_Multi_key, XK_S, XK_exclam, XK_VoidSymbol}, "§"}, {{XK_Multi_key, XK_Cyrillic_pe, XK_Cyrillic_a, XK_VoidSymbol}, "§"}, {{XK_dead_abovedot, XK_scaron, XK_VoidSymbol}, "ṧ"}, // U1E67 | LATIN SMALL LETTER S WITH CARON AND DOT ABOVE {{XK_Multi_key, XK_period, XK_scaron, XK_VoidSymbol}, "ṧ"}, {{XK_dead_abovedot, XK_dead_caron, XK_s, XK_VoidSymbol}, "ṧ"}, {{XK_dead_abovedot, XK_Multi_key, XK_c, XK_s, XK_VoidSymbol}, "ṧ"}, {{XK_Multi_key, XK_period, XK_dead_caron, XK_s, XK_VoidSymbol}, "ṧ"}, {{XK_dead_caron, XK_sabovedot, XK_VoidSymbol}, "ṧ"}, {{XK_dead_caron, XK_dead_abovedot, XK_s, XK_VoidSymbol}, "ṧ"}, {{XK_Multi_key, XK_parenleft, XK_a, XK_parenright, XK_VoidSymbol}, "ⓐ"}, // U24D0 | CIRCLED LATIN SMALL LETTER A {{XK_dead_tilde, XK_u, XK_VoidSymbol}, "ũ"}, // U0169 | LATIN SMALL LETTER U WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_u, XK_VoidSymbol}, "ũ"}, {{XK_Multi_key, XK_u, XK_asciitilde, XK_VoidSymbol}, "ũ"}, {{XK_dead_grave, XK_e, XK_VoidSymbol}, "è"}, // egrave | LATIN SMALL LETTER E WITH GRAVE {{XK_Multi_key, XK_grave, XK_e, XK_VoidSymbol}, "è"}, {{XK_Multi_key, XK_e, XK_grave, XK_VoidSymbol}, "è"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_2, XK_parenright, XK_VoidSymbol}, "⑫"}, // U246B | CIRCLED NUMBER TWELVE {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "⑫"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_2, XK_parenright, XK_VoidSymbol}, "⑫"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_2, XK_parenright, XK_VoidSymbol}, "⑫"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "⑫"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_2, XK_parenright, XK_VoidSymbol}, "⑫"}, {{XK_dead_acute, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὥ"}, // U1F6D | GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὥ"}, {{XK_Multi_key, XK_acute, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὥ"}, {{XK_Multi_key, XK_acute, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὥ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὥ"}, {{XK_Multi_key, XK_apostrophe, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὥ"}, {{XK_dead_hook, XK_Uhorn, XK_VoidSymbol}, "Ử"}, // U1EEC | LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_Uhorn, XK_VoidSymbol}, "Ử"}, {{XK_dead_hook, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ử"}, {{XK_dead_hook, XK_Multi_key, XK_plus, XK_U, XK_VoidSymbol}, "Ử"}, {{XK_Multi_key, XK_question, XK_dead_horn, XK_U, XK_VoidSymbol}, "Ử"}, {{XK_Multi_key, XK_question, XK_plus, XK_U, XK_VoidSymbol}, "Ử"}, {{XK_dead_horn, XK_Uhook, XK_VoidSymbol}, "Ử"}, {{XK_dead_horn, XK_dead_hook, XK_U, XK_VoidSymbol}, "Ử"}, {{XK_dead_stroke, XK_greater, XK_VoidSymbol}, "≯"}, // U226F | NOT GREATER-THAN {{XK_dead_diaeresis, XK_Cyrillic_U, XK_VoidSymbol}, "Ӱ"}, // U04F0 | CYRILLIC CAPITAL LETTER U WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_U, XK_VoidSymbol}, "Ӱ"}, {{XK_dead_iota, XK_dead_grave, XK_Greek_omega, XK_VoidSymbol}, "ῲ"}, // U1FF2 | GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_grave, XK_Greek_omega, XK_VoidSymbol}, "ῲ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_Greek_omega, XK_VoidSymbol}, "ῲ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_Greek_omega, XK_VoidSymbol}, "ῲ"}, {{XK_Multi_key, XK_parenleft, XK_kana_YU, XK_parenright, XK_VoidSymbol}, "㋴"}, // U32F4 | CIRCLED KATAKANA YU {{XK_dead_belowcircumflex, XK_u, XK_VoidSymbol}, "ṷ"}, // U1E77 | LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW {{XK_dead_hook, XK_M, XK_VoidSymbol}, "Ɱ"}, // U2C6E | LATIN CAPITAL LETTER M WITH HOOK {{XK_dead_acute, XK_Z, XK_VoidSymbol}, "Ź"}, // U0179 | LATIN CAPITAL LETTER Z WITH ACUTE {{XK_Multi_key, XK_acute, XK_Z, XK_VoidSymbol}, "Ź"}, {{XK_Multi_key, XK_apostrophe, XK_Z, XK_VoidSymbol}, "Ź"}, {{XK_Multi_key, XK_Z, XK_apostrophe, XK_VoidSymbol}, "Ź"}, {{XK_dead_stroke, XK_o, XK_VoidSymbol}, "ø"}, // oslash | LATIN SMALL LETTER O WITH STROKE {{XK_Multi_key, XK_slash, XK_o, XK_VoidSymbol}, "ø"}, {{XK_Multi_key, XK_o, XK_slash, XK_VoidSymbol}, "ø"}, {{XK_Multi_key, XK_KP_Divide, XK_o, XK_VoidSymbol}, "ø"}, {{XK_dead_acute, XK_Ooblique, XK_VoidSymbol}, "Ǿ"}, // U01FE | LATIN CAPITAL LETTER O WITH STROKE AND ACUTE {{XK_Multi_key, XK_acute, XK_Ooblique, XK_VoidSymbol}, "Ǿ"}, {{XK_Multi_key, XK_apostrophe, XK_Ooblique, XK_VoidSymbol}, "Ǿ"}, {{XK_dead_acute, XK_dead_stroke, XK_O, XK_VoidSymbol}, "Ǿ"}, {{XK_dead_acute, XK_Multi_key, XK_slash, XK_O, XK_VoidSymbol}, "Ǿ"}, {{XK_Multi_key, XK_acute, XK_slash, XK_O, XK_VoidSymbol}, "Ǿ"}, {{XK_Multi_key, XK_apostrophe, XK_slash, XK_O, XK_VoidSymbol}, "Ǿ"}, {{XK_dead_acute, XK_Multi_key, XK_KP_Divide, XK_O, XK_VoidSymbol}, "Ǿ"}, {{XK_Multi_key, XK_acute, XK_KP_Divide, XK_O, XK_VoidSymbol}, "Ǿ"}, {{XK_Multi_key, XK_apostrophe, XK_KP_Divide, XK_O, XK_VoidSymbol}, "Ǿ"}, {{XK_dead_stroke, XK_dead_acute, XK_O, XK_VoidSymbol}, "Ǿ"}, {{XK_dead_stroke, XK_Oacute, XK_VoidSymbol}, "Ǿ"}, {{XK_dead_abovedot, XK_B, XK_VoidSymbol}, "Ḃ"}, // U1E02 | LATIN CAPITAL LETTER B WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_B, XK_VoidSymbol}, "Ḃ"}, {{XK_Multi_key, XK_B, XK_period, XK_VoidSymbol}, "Ḃ"}, {{XK_Multi_key, XK_F, XK_l, XK_VoidSymbol}, "ffl"}, // Ufb04 | LATIN SMALL LIGATURE FFL {{XK_dead_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾇ"}, // U1F87 | GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾇ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾇ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾇ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾇ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾇ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾇ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾇ"}, {{XK_Multi_key, XK_underscore, XK_9, XK_VoidSymbol}, "₉"}, // U2089 | SUBSCRIPT NINE {{XK_Multi_key, XK_underscore, XK_KP_9, XK_VoidSymbol}, "₉"}, {{XK_dead_caron, XK_9, XK_VoidSymbol}, "₉"}, {{XK_dead_circumflex, XK_C, XK_VoidSymbol}, "Ĉ"}, // U0108 | LATIN CAPITAL LETTER C WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_C, XK_VoidSymbol}, "Ĉ"}, {{XK_dead_invertedbreve, XK_I, XK_VoidSymbol}, "Ȋ"}, // U020A | LATIN CAPITAL LETTER I WITH INVERTED BREVE {{XK_dead_diaeresis, XK_x, XK_VoidSymbol}, "ẍ"}, // U1E8D | LATIN SMALL LETTER X WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_x, XK_VoidSymbol}, "ẍ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἄ"}, // U1F0C | GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἄ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἄ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἄ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἄ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἄ"}, {{XK_dead_acute, XK_Greek_OMEGA, XK_VoidSymbol}, "Ώ"}, // U038F | GREEK CAPITAL LETTER OMEGA WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_OMEGA, XK_VoidSymbol}, "Ώ"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_OMEGA, XK_VoidSymbol}, "Ώ"}, {{XK_Multi_key, XK_Greek_OMEGA, XK_apostrophe, XK_VoidSymbol}, "Ώ"}, {{XK_Multi_key, XK_1, XK_6, XK_VoidSymbol}, "⅙"}, // U2159 | VULGAR FRACTION ONE SIXTH {{XK_dead_hook, XK_G, XK_VoidSymbol}, "Ɠ"}, // U0193 | LATIN CAPITAL LETTER G WITH HOOK {{XK_dead_belowcircumflex, XK_D, XK_VoidSymbol}, "Ḓ"}, // U1E12 | LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW {{XK_dead_currency, XK_D, XK_VoidSymbol}, "₯"}, // U20AF | DRACHMA SIGN {{XK_dead_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾗ"}, // U1F97 | GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾗ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾗ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾗ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾗ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾗ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾗ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾗ"}, {{XK_dead_ogonek, XK_E, XK_VoidSymbol}, "Ę"}, // U0118 | LATIN CAPITAL LETTER E WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_E, XK_VoidSymbol}, "Ę"}, {{XK_Multi_key, XK_E, XK_semicolon, XK_VoidSymbol}, "Ę"}, {{XK_Multi_key, XK_comma, XK_E, XK_VoidSymbol}, "Ę"}, {{XK_Multi_key, XK_E, XK_comma, XK_VoidSymbol}, "Ę"}, {{XK_dead_belowcomma, XK_T, XK_VoidSymbol}, "Ț"}, // U021A | LATIN CAPITAL LETTER T WITH COMMA BELOW {{XK_Multi_key, XK_semicolon, XK_T, XK_VoidSymbol}, "Ț"}, {{XK_Multi_key, XK_T, XK_semicolon, XK_VoidSymbol}, "Ț"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἔ"}, // U1F1C | GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἔ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἔ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἔ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἔ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἔ"}, {{XK_Multi_key, XK_comma, XK_quotedbl, XK_VoidSymbol}, "„"}, // U201e | DOUBLE LOW-9 QUOTATION MARK {{XK_Multi_key, XK_quotedbl, XK_comma, XK_VoidSymbol}, "„"}, {{XK_dead_abovedot, XK_H, XK_VoidSymbol}, "Ḣ"}, // U1E22 | LATIN CAPITAL LETTER H WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_H, XK_VoidSymbol}, "Ḣ"}, {{XK_dead_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾧ"}, // U1FA7 | GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾧ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾧ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾧ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾧ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾧ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾧ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾧ"}, {{XK_Multi_key, XK_W, XK_equal, XK_VoidSymbol}, "₩"}, // U20a9 | WON SIGN {{XK_Multi_key, XK_equal, XK_W, XK_VoidSymbol}, "₩"}, {{XK_dead_currency, XK_W, XK_VoidSymbol}, "₩"}, {{XK_dead_currency, XK_w, XK_VoidSymbol}, "₩"}, {{XK_dead_tilde, XK_I, XK_VoidSymbol}, "Ĩ"}, // U0128 | LATIN CAPITAL LETTER I WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_I, XK_VoidSymbol}, "Ĩ"}, {{XK_Multi_key, XK_I, XK_asciitilde, XK_VoidSymbol}, "Ĩ"}, {{XK_dead_macron, XK_Odiaeresis, XK_VoidSymbol}, "Ȫ"}, // U022A | LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON {{XK_Multi_key, XK_macron, XK_Odiaeresis, XK_VoidSymbol}, "Ȫ"}, {{XK_Multi_key, XK_underscore, XK_Odiaeresis, XK_VoidSymbol}, "Ȫ"}, {{XK_dead_macron, XK_dead_diaeresis, XK_O, XK_VoidSymbol}, "Ȫ"}, {{XK_dead_macron, XK_Multi_key, XK_quotedbl, XK_O, XK_VoidSymbol}, "Ȫ"}, {{XK_Multi_key, XK_macron, XK_dead_diaeresis, XK_O, XK_VoidSymbol}, "Ȫ"}, {{XK_Multi_key, XK_macron, XK_quotedbl, XK_O, XK_VoidSymbol}, "Ȫ"}, {{XK_Multi_key, XK_underscore, XK_dead_diaeresis, XK_O, XK_VoidSymbol}, "Ȫ"}, {{XK_Multi_key, XK_underscore, XK_quotedbl, XK_O, XK_VoidSymbol}, "Ȫ"}, {{XK_dead_diaeresis, XK_Omacron, XK_VoidSymbol}, "Ȫ"}, {{XK_dead_diaeresis, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ȫ"}, {{XK_dead_circumflex, XK_dead_belowdot, XK_a, XK_VoidSymbol}, "ậ"}, // U1EAD | LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW {{XK_dead_circumflex, XK_Multi_key, XK_exclam, XK_a, XK_VoidSymbol}, "ậ"}, {{XK_Multi_key, XK_asciicircum, XK_dead_belowdot, XK_a, XK_VoidSymbol}, "ậ"}, {{XK_Multi_key, XK_asciicircum, XK_exclam, XK_a, XK_VoidSymbol}, "ậ"}, {{XK_dead_belowdot, XK_acircumflex, XK_VoidSymbol}, "ậ"}, {{XK_dead_belowdot, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ậ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "Ἤ"}, // U1F2C | GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "Ἤ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "Ἤ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "Ἤ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "Ἤ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "Ἤ"}, {{XK_dead_acute, XK_Greek_iota, XK_VoidSymbol}, "ί"}, // U03AF | GREEK SMALL LETTER IOTA WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_iota, XK_VoidSymbol}, "ί"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_iota, XK_VoidSymbol}, "ί"}, {{XK_dead_belowdot, XK_K, XK_VoidSymbol}, "Ḳ"}, // U1E32 | LATIN CAPITAL LETTER K WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_K, XK_VoidSymbol}, "Ḳ"}, {{XK_Multi_key, XK_parenleft, XK_4, XK_0, XK_parenright, XK_VoidSymbol}, "㊵"}, // U32B5 | CIRCLED NUMBER FORTY {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_0, XK_parenright, XK_VoidSymbol}, "㊵"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_0, XK_parenright, XK_VoidSymbol}, "㊵"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_0, XK_parenright, XK_VoidSymbol}, "㊵"}, {{XK_Multi_key, XK_underscore, XK_2, XK_VoidSymbol}, "₂"}, // U2082 | SUBSCRIPT TWO {{XK_Multi_key, XK_underscore, XK_KP_Space, XK_VoidSymbol}, "₂"}, {{XK_Multi_key, XK_underscore, XK_KP_2, XK_VoidSymbol}, "₂"}, {{XK_dead_caron, XK_2, XK_VoidSymbol}, "₂"}, {{XK_dead_iota, XK_dead_tilde, XK_Greek_alpha, XK_VoidSymbol}, "ᾷ"}, // U1FB7 | GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_Greek_alpha, XK_VoidSymbol}, "ᾷ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_Greek_alpha, XK_VoidSymbol}, "ᾷ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_Greek_alpha, XK_VoidSymbol}, "ᾷ"}, {{XK_dead_iota, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾈ"}, // U1F88 | GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾈ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾈ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾈ"}, {{XK_Multi_key, XK_R, XK_equal, XK_VoidSymbol}, "₹"}, // U20b9 | INDIAN RUPEE SIGN {{XK_Multi_key, XK_equal, XK_R, XK_VoidSymbol}, "₹"}, {{XK_Multi_key, XK_r, XK_equal, XK_VoidSymbol}, "₹"}, {{XK_Multi_key, XK_equal, XK_r, XK_VoidSymbol}, "₹"}, {{XK_Multi_key, XK_k, XK_k, XK_VoidSymbol}, "ĸ"}, // U0138 | LATIN SMALL LETTER KRA {{XK_dead_stroke, XK_A, XK_VoidSymbol}, "Ⱥ"}, // U023A | LATIN CAPITAL LETTER A WITH STROKE {{XK_dead_tilde, XK_e, XK_VoidSymbol}, "ẽ"}, // U1EBD | LATIN SMALL LETTER E WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_e, XK_VoidSymbol}, "ẽ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_IOTA, XK_VoidSymbol}, "Ἴ"}, // U1F3C | GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_IOTA, XK_VoidSymbol}, "Ἴ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_IOTA, XK_VoidSymbol}, "Ἴ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_IOTA, XK_VoidSymbol}, "Ἴ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_IOTA, XK_VoidSymbol}, "Ἴ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_IOTA, XK_VoidSymbol}, "Ἴ"}, {{XK_dead_breve, XK_Cyrillic_ZHE, XK_VoidSymbol}, "Ӂ"}, // U04C1 | CYRILLIC CAPITAL LETTER ZHE WITH BREVE {{XK_Multi_key, XK_U, XK_Cyrillic_ZHE, XK_VoidSymbol}, "Ӂ"}, {{XK_Multi_key, XK_b, XK_Cyrillic_ZHE, XK_VoidSymbol}, "Ӂ"}, {{XK_dead_belowdot, XK_M, XK_VoidSymbol}, "Ṃ"}, // U1E42 | LATIN CAPITAL LETTER M WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_M, XK_VoidSymbol}, "Ṃ"}, {{XK_dead_diaeresis, XK_acute, XK_VoidSymbol}, "̈́"}, // U0344 | COMBINING GREEK DIALYTIKA TONOS {{XK_dead_diaeresis, XK_apostrophe, XK_VoidSymbol}, "̈́"}, {{XK_Multi_key, XK_quotedbl, XK_dead_acute, XK_VoidSymbol}, "̈́"}, {{XK_Multi_key, XK_quotedbl, XK_acute, XK_VoidSymbol}, "̈́"}, {{XK_Multi_key, XK_quotedbl, XK_apostrophe, XK_VoidSymbol}, "̈́"}, {{XK_dead_iota, XK_dead_tilde, XK_Greek_eta, XK_VoidSymbol}, "ῇ"}, // U1FC7 | GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_Greek_eta, XK_VoidSymbol}, "ῇ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_Greek_eta, XK_VoidSymbol}, "ῇ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_Greek_eta, XK_VoidSymbol}, "ῇ"}, {{XK_Multi_key, XK_parenleft, XK_q, XK_parenright, XK_VoidSymbol}, "ⓠ"}, // U24E0 | CIRCLED LATIN SMALL LETTER Q {{XK_dead_acute, XK_E, XK_VoidSymbol}, "É"}, // Eacute | LATIN CAPITAL LETTER E WITH ACUTE {{XK_Multi_key, XK_acute, XK_E, XK_VoidSymbol}, "É"}, {{XK_Multi_key, XK_E, XK_acute, XK_VoidSymbol}, "É"}, {{XK_Multi_key, XK_apostrophe, XK_E, XK_VoidSymbol}, "É"}, {{XK_Multi_key, XK_E, XK_apostrophe, XK_VoidSymbol}, "É"}, {{XK_dead_caron, XK_n, XK_VoidSymbol}, "ň"}, // U0148 | LATIN SMALL LETTER N WITH CARON {{XK_Multi_key, XK_c, XK_n, XK_VoidSymbol}, "ň"}, {{XK_Multi_key, XK_less, XK_n, XK_VoidSymbol}, "ň"}, {{XK_Multi_key, XK_n, XK_less, XK_VoidSymbol}, "ň"}, {{XK_dead_macron, XK_Cyrillic_IE, XK_VoidSymbol}, "Е̄"}, // CYRILLIC CAPITAL LETTER IE WITH COMBINING MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_IE, XK_VoidSymbol}, "Е̄"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_IE, XK_VoidSymbol}, "Е̄"}, {{XK_dead_belowdot, XK_o, XK_VoidSymbol}, "ọ"}, // U1ECD | LATIN SMALL LETTER O WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_o, XK_VoidSymbol}, "ọ"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὄ"}, // U1F4C | GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὄ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὄ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὄ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὄ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὄ"}, {{XK_dead_breve, XK_Cyrillic_a, XK_VoidSymbol}, "ӑ"}, // U04D1 | CYRILLIC SMALL LETTER A WITH BREVE {{XK_Multi_key, XK_U, XK_Cyrillic_a, XK_VoidSymbol}, "ӑ"}, {{XK_Multi_key, XK_b, XK_Cyrillic_a, XK_VoidSymbol}, "ӑ"}, {{XK_dead_caron, XK_U, XK_VoidSymbol}, "Ǔ"}, // U01D3 | LATIN CAPITAL LETTER U WITH CARON {{XK_Multi_key, XK_c, XK_U, XK_VoidSymbol}, "Ǔ"}, {{XK_dead_acute, XK_Omacron, XK_VoidSymbol}, "Ṓ"}, // U1E52 | LATIN CAPITAL LETTER O WITH MACRON AND ACUTE {{XK_Multi_key, XK_acute, XK_Omacron, XK_VoidSymbol}, "Ṓ"}, {{XK_Multi_key, XK_apostrophe, XK_Omacron, XK_VoidSymbol}, "Ṓ"}, {{XK_dead_acute, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_dead_acute, XK_Multi_key, XK_macron, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_dead_acute, XK_Multi_key, XK_underscore, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_Multi_key, XK_acute, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_Multi_key, XK_acute, XK_macron, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_Multi_key, XK_acute, XK_underscore, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_macron, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_Multi_key, XK_apostrophe, XK_macron, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_Multi_key, XK_apostrophe, XK_underscore, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_dead_macron, XK_Oacute, XK_VoidSymbol}, "Ṓ"}, {{XK_dead_macron, XK_dead_acute, XK_O, XK_VoidSymbol}, "Ṓ"}, {{XK_Multi_key, XK_parenleft, XK_kana_KA, XK_parenright, XK_VoidSymbol}, "㋕"}, // U32D5 | CIRCLED KATAKANA KA {{XK_dead_tilde, XK_Greek_iotadieresis, XK_VoidSymbol}, "ῗ"}, // U1FD7 | GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI {{XK_Multi_key, XK_asciitilde, XK_Greek_iotadieresis, XK_VoidSymbol}, "ῗ"}, {{XK_dead_tilde, XK_dead_diaeresis, XK_Greek_iota, XK_VoidSymbol}, "ῗ"}, {{XK_dead_tilde, XK_Multi_key, XK_quotedbl, XK_Greek_iota, XK_VoidSymbol}, "ῗ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_diaeresis, XK_Greek_iota, XK_VoidSymbol}, "ῗ"}, {{XK_Multi_key, XK_asciitilde, XK_quotedbl, XK_Greek_iota, XK_VoidSymbol}, "ῗ"}, {{XK_Multi_key, XK_parenleft, XK_4, XK_3, XK_parenright, XK_VoidSymbol}, "㊸"}, // U32B8 | CIRCLED NUMBER FORTY THREE {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_3, XK_parenright, XK_VoidSymbol}, "㊸"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_3, XK_parenright, XK_VoidSymbol}, "㊸"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_3, XK_parenright, XK_VoidSymbol}, "㊸"}, {{XK_dead_grave, XK_U, XK_VoidSymbol}, "Ù"}, // Ugrave | LATIN CAPITAL LETTER U WITH GRAVE {{XK_Multi_key, XK_grave, XK_U, XK_VoidSymbol}, "Ù"}, {{XK_Multi_key, XK_U, XK_grave, XK_VoidSymbol}, "Ù"}, {{XK_dead_caron, XK_R, XK_VoidSymbol}, "Ř"}, // U0158 | LATIN CAPITAL LETTER R WITH CARON {{XK_Multi_key, XK_c, XK_R, XK_VoidSymbol}, "Ř"}, {{XK_Multi_key, XK_less, XK_R, XK_VoidSymbol}, "Ř"}, {{XK_Multi_key, XK_R, XK_less, XK_VoidSymbol}, "Ř"}, {{XK_dead_invertedbreve, XK_Cyrillic_I, XK_VoidSymbol}, "И̑"}, // CYRILLIC CAPITAL LETTER I WITH COMBINING INVERTED BREVE {{XK_Multi_key, XK_parenleft, XK_3, XK_parenright, XK_VoidSymbol}, "③"}, // U2462 | CIRCLED DIGIT THREE {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_parenright, XK_VoidSymbol}, "③"}, {{XK_dead_grave, XK_ohorn, XK_VoidSymbol}, "ờ"}, // U1EDD | LATIN SMALL LETTER O WITH HORN AND GRAVE {{XK_Multi_key, XK_grave, XK_ohorn, XK_VoidSymbol}, "ờ"}, {{XK_dead_grave, XK_dead_horn, XK_o, XK_VoidSymbol}, "ờ"}, {{XK_dead_grave, XK_Multi_key, XK_plus, XK_o, XK_VoidSymbol}, "ờ"}, {{XK_Multi_key, XK_grave, XK_dead_horn, XK_o, XK_VoidSymbol}, "ờ"}, {{XK_Multi_key, XK_grave, XK_plus, XK_o, XK_VoidSymbol}, "ờ"}, {{XK_dead_horn, XK_ograve, XK_VoidSymbol}, "ờ"}, {{XK_dead_horn, XK_dead_grave, XK_o, XK_VoidSymbol}, "ờ"}, {{XK_dead_circumflex, XK_space, XK_VoidSymbol}, "^"}, // asciicircum | CIRCUMFLEX ACCENT {{XK_dead_circumflex, XK_dead_circumflex, XK_VoidSymbol}, "^"}, {{XK_Multi_key, XK_asciicircum, XK_space, XK_VoidSymbol}, "^"}, {{XK_Multi_key, XK_space, XK_asciicircum, XK_VoidSymbol}, "^"}, {{XK_Multi_key, XK_greater, XK_space, XK_VoidSymbol}, "^"}, {{XK_Multi_key, XK_space, XK_greater, XK_VoidSymbol}, "^"}, {{XK_Multi_key, XK_parenleft, XK_r, XK_parenright, XK_VoidSymbol}, "ⓡ"}, // U24E1 | CIRCLED LATIN SMALL LETTER R {{XK_dead_circumflex, XK_Cyrillic_a, XK_VoidSymbol}, "а̂"}, // CYRILLIC SMALL LETTER A WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_a, XK_VoidSymbol}, "а̂"}, {{XK_dead_macron, XK_ae, XK_VoidSymbol}, "ǣ"}, // U01E3 | LATIN SMALL LETTER AE WITH MACRON {{XK_Multi_key, XK_macron, XK_ae, XK_VoidSymbol}, "ǣ"}, {{XK_Multi_key, XK_underscore, XK_ae, XK_VoidSymbol}, "ǣ"}, {{XK_dead_belowdot, XK_S, XK_VoidSymbol}, "Ṣ"}, // U1E62 | LATIN CAPITAL LETTER S WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_S, XK_VoidSymbol}, "Ṣ"}, {{XK_Multi_key, XK_parenleft, XK_kana_NI, XK_parenright, XK_VoidSymbol}, "㋥"}, // U32E5 | CIRCLED KATAKANA NI {{XK_dead_tilde, XK_Greek_upsilondieresis, XK_VoidSymbol}, "ῧ"}, // U1FE7 | GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI {{XK_Multi_key, XK_asciitilde, XK_Greek_upsilondieresis, XK_VoidSymbol}, "ῧ"}, {{XK_dead_tilde, XK_dead_diaeresis, XK_Greek_upsilon, XK_VoidSymbol}, "ῧ"}, {{XK_dead_tilde, XK_Multi_key, XK_quotedbl, XK_Greek_upsilon, XK_VoidSymbol}, "ῧ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_diaeresis, XK_Greek_upsilon, XK_VoidSymbol}, "ῧ"}, {{XK_Multi_key, XK_asciitilde, XK_quotedbl, XK_Greek_upsilon, XK_VoidSymbol}, "ῧ"}, {{XK_Multi_key, XK_parenleft, XK_7, XK_parenright, XK_VoidSymbol}, "⑦"}, // U2466 | CIRCLED DIGIT SEVEN {{XK_Multi_key, XK_parenleft, XK_KP_7, XK_parenright, XK_VoidSymbol}, "⑦"}, {{XK_dead_acute, XK_e, XK_VoidSymbol}, "é"}, // eacute | LATIN SMALL LETTER E WITH ACUTE {{XK_Multi_key, XK_acute, XK_e, XK_VoidSymbol}, "é"}, {{XK_Multi_key, XK_e, XK_acute, XK_VoidSymbol}, "é"}, {{XK_Multi_key, XK_apostrophe, XK_e, XK_VoidSymbol}, "é"}, {{XK_Multi_key, XK_e, XK_apostrophe, XK_VoidSymbol}, "é"}, {{XK_dead_tilde, XK_U, XK_VoidSymbol}, "Ũ"}, // U0168 | LATIN CAPITAL LETTER U WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_U, XK_VoidSymbol}, "Ũ"}, {{XK_Multi_key, XK_U, XK_asciitilde, XK_VoidSymbol}, "Ũ"}, {{XK_dead_hook, XK_uhorn, XK_VoidSymbol}, "ử"}, // U1EED | LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_uhorn, XK_VoidSymbol}, "ử"}, {{XK_dead_hook, XK_dead_horn, XK_u, XK_VoidSymbol}, "ử"}, {{XK_dead_hook, XK_Multi_key, XK_plus, XK_u, XK_VoidSymbol}, "ử"}, {{XK_Multi_key, XK_question, XK_dead_horn, XK_u, XK_VoidSymbol}, "ử"}, {{XK_Multi_key, XK_question, XK_plus, XK_u, XK_VoidSymbol}, "ử"}, {{XK_dead_horn, XK_uhook, XK_VoidSymbol}, "ử"}, {{XK_dead_horn, XK_dead_hook, XK_u, XK_VoidSymbol}, "ử"}, {{XK_dead_acute, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὤ"}, // U1F6C | GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA {{XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὤ"}, {{XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὤ"}, {{XK_Multi_key, XK_acute, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὤ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὤ"}, {{XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὤ"}, {{XK_dead_diaeresis, XK_Cyrillic_u, XK_VoidSymbol}, "ӱ"}, // U04F1 | CYRILLIC SMALL LETTER U WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_u, XK_VoidSymbol}, "ӱ"}, {{XK_dead_currency, XK_t, XK_VoidSymbol}, "৳"}, // U09F3 | BENGALI RUPEE SIGN {{XK_dead_belowdiaeresis, XK_U, XK_VoidSymbol}, "Ṳ"}, // U1E72 | LATIN CAPITAL LETTER U WITH DIAERESIS BELOW {{XK_Multi_key, XK_parenleft, XK_kana_YO, XK_parenright, XK_VoidSymbol}, "㋵"}, // U32F5 | CIRCLED KATAKANA YO {{XK_dead_iota, XK_dead_tilde, XK_Greek_omega, XK_VoidSymbol}, "ῷ"}, // U1FF7 | GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_Greek_omega, XK_VoidSymbol}, "ῷ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_Greek_omega, XK_VoidSymbol}, "ῷ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_Greek_omega, XK_VoidSymbol}, "ῷ"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_8, XK_parenright, XK_VoidSymbol}, "㊳"}, // U32B3 | CIRCLED NUMBER THIRTY EIGHT {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_8, XK_parenright, XK_VoidSymbol}, "㊳"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_8, XK_parenright, XK_VoidSymbol}, "㊳"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_8, XK_parenright, XK_VoidSymbol}, "㊳"}, {{XK_dead_grave, XK_u, XK_VoidSymbol}, "ù"}, // ugrave | LATIN SMALL LETTER U WITH GRAVE {{XK_Multi_key, XK_grave, XK_u, XK_VoidSymbol}, "ù"}, {{XK_Multi_key, XK_u, XK_grave, XK_VoidSymbol}, "ù"}, {{XK_dead_diaeresis, XK_Y, XK_VoidSymbol}, "Ÿ"}, // U0178 | LATIN CAPITAL LETTER Y WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Y, XK_VoidSymbol}, "Ÿ"}, {{XK_Multi_key, XK_Y, XK_quotedbl, XK_VoidSymbol}, "Ÿ"}, {{XK_Multi_key, XK_diaeresis, XK_Y, XK_VoidSymbol}, "Ÿ"}, {{XK_Multi_key, XK_Y, XK_diaeresis, XK_VoidSymbol}, "Ÿ"}, {{XK_dead_grave, XK_Greek_omega, XK_VoidSymbol}, "ὼ"}, // U1F7C | GREEK SMALL LETTER OMEGA WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_omega, XK_VoidSymbol}, "ὼ"}, {{XK_dead_tilde, XK_space, XK_VoidSymbol}, "~"}, // asciitilde | TILDE {{XK_dead_tilde, XK_dead_tilde, XK_VoidSymbol}, "~"}, {{XK_Multi_key, XK_asciitilde, XK_space, XK_VoidSymbol}, "~"}, {{XK_Multi_key, XK_space, XK_asciitilde, XK_VoidSymbol}, "~"}, {{XK_Multi_key, XK_minus, XK_space, XK_VoidSymbol}, "~"}, {{XK_Multi_key, XK_space, XK_minus, XK_VoidSymbol}, "~"}, {{XK_dead_diaeresis, XK_Cyrillic_IE, XK_VoidSymbol}, "Ё"}, // U0401 | CYRILLIC CAPITAL LETTER IO {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_IE, XK_VoidSymbol}, "Ё"}, {{XK_dead_breve, XK_a, XK_VoidSymbol}, "ă"}, // U0103 | LATIN SMALL LETTER A WITH BREVE {{XK_Multi_key, XK_U, XK_a, XK_VoidSymbol}, "ă"}, {{XK_Multi_key, XK_u, XK_a, XK_VoidSymbol}, "ă"}, {{XK_Multi_key, XK_b, XK_a, XK_VoidSymbol}, "ă"}, {{XK_Multi_key, XK_a, XK_parenleft, XK_VoidSymbol}, "ă"}, {{XK_dead_acute, XK_W, XK_VoidSymbol}, "Ẃ"}, // U1E82 | LATIN CAPITAL LETTER W WITH ACUTE {{XK_Multi_key, XK_acute, XK_W, XK_VoidSymbol}, "Ẃ"}, {{XK_Multi_key, XK_apostrophe, XK_W, XK_VoidSymbol}, "Ẃ"}, {{XK_dead_doublegrave, XK_e, XK_VoidSymbol}, "ȅ"}, // U0205 | LATIN SMALL LETTER E WITH DOUBLE GRAVE {{XK_dead_macron, XK_Cyrillic_a, XK_VoidSymbol}, "а̄"}, // CYRILLIC SMALL LETTER A WITH COMBINING MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_a, XK_VoidSymbol}, "а̄"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_a, XK_VoidSymbol}, "а̄"}, {{XK_dead_tilde, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ἇ"}, // U1F07 | GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ἇ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ἇ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ἇ"}, {{XK_dead_hook, XK_c, XK_VoidSymbol}, "ƈ"}, // U0188 | LATIN SMALL LETTER C WITH HOOK {{XK_dead_belowdot, XK_d, XK_VoidSymbol}, "ḍ"}, // U1E0D | LATIN SMALL LETTER D WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_d, XK_VoidSymbol}, "ḍ"}, {{XK_dead_iota, XK_dead_acute, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, // U1F8C | GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾌ"}, {{XK_Multi_key, XK_underscore, XK_parenright, XK_VoidSymbol}, "₎"}, // U208E | SUBSCRIPT RIGHT PARENTHESIS {{XK_dead_caron, XK_parenright, XK_VoidSymbol}, "₎"}, {{XK_dead_macron, XK_e, XK_VoidSymbol}, "ē"}, // U0113 | LATIN SMALL LETTER E WITH MACRON {{XK_Multi_key, XK_macron, XK_e, XK_VoidSymbol}, "ē"}, {{XK_Multi_key, XK_underscore, XK_e, XK_VoidSymbol}, "ē"}, {{XK_Multi_key, XK_e, XK_underscore, XK_VoidSymbol}, "ē"}, {{XK_Multi_key, XK_minus, XK_e, XK_VoidSymbol}, "ē"}, {{XK_Multi_key, XK_e, XK_minus, XK_VoidSymbol}, "ē"}, {{XK_dead_belowdot, XK_Z, XK_VoidSymbol}, "Ẓ"}, // U1E92 | LATIN CAPITAL LETTER Z WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_Z, XK_VoidSymbol}, "Ẓ"}, {{XK_dead_doublegrave, XK_u, XK_VoidSymbol}, "ȕ"}, // U0215 | LATIN SMALL LETTER U WITH DOUBLE GRAVE {{XK_dead_belowmacron, XK_t, XK_VoidSymbol}, "ṯ"}, // U1E6F | LATIN SMALL LETTER T WITH LINE BELOW {{XK_dead_currency, XK_B, XK_VoidSymbol}, "₱"}, // U20B1 | PESO SIGN {{XK_Multi_key, XK_greater, XK_apostrophe, XK_VoidSymbol}, "’"}, // U2019 | RIGHT SINGLE QUOTATION MARK {{XK_Multi_key, XK_apostrophe, XK_greater, XK_VoidSymbol}, "’"}, {{XK_dead_hook, XK_K, XK_VoidSymbol}, "Ƙ"}, // U0198 | LATIN CAPITAL LETTER K WITH HOOK {{XK_dead_breve, XK_dead_cedilla, XK_e, XK_VoidSymbol}, "ḝ"}, // U1E1D | LATIN SMALL LETTER E WITH CEDILLA AND BREVE {{XK_dead_breve, XK_Multi_key, XK_comma, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_dead_breve, XK_Multi_key, XK_cedilla, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_Multi_key, XK_U, XK_dead_cedilla, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_Multi_key, XK_U, XK_space, XK_comma, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_Multi_key, XK_U, XK_cedilla, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_Multi_key, XK_b, XK_dead_cedilla, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_Multi_key, XK_b, XK_comma, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_Multi_key, XK_b, XK_cedilla, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_dead_cedilla, XK_dead_breve, XK_e, XK_VoidSymbol}, "ḝ"}, {{XK_dead_iota, XK_dead_acute, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, // U1F9C | GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_psili, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenright, XK_Greek_ETA, XK_VoidSymbol}, "ᾜ"}, {{XK_dead_cedilla, XK_g, XK_VoidSymbol}, "ģ"}, // U0123 | LATIN SMALL LETTER G WITH CEDILLA {{XK_Multi_key, XK_comma, XK_g, XK_VoidSymbol}, "ģ"}, {{XK_Multi_key, XK_g, XK_comma, XK_VoidSymbol}, "ģ"}, {{XK_Multi_key, XK_cedilla, XK_g, XK_VoidSymbol}, "ģ"}, {{XK_dead_hook, XK_A, XK_VoidSymbol}, "Ả"}, // U1EA2 | LATIN CAPITAL LETTER A WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_A, XK_VoidSymbol}, "Ả"}, {{XK_dead_belowdot, XK_plus, XK_VoidSymbol}, "⨥"}, // U2A25 | PLUS SIGN WITH DOT BELOW {{XK_dead_voiced_sound, XK_kana_TE, XK_VoidSymbol}, "デ"}, // U30C7 | KATAKANA LETTER DE {{XK_dead_tilde, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ἧ"}, // U1F27 | GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ἧ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ἧ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ἧ"}, {{XK_dead_circumflex, XK_Cyrillic_i, XK_VoidSymbol}, "и̂"}, // CYRILLIC SMALL LETTER I WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_i, XK_VoidSymbol}, "и̂"}, {{XK_dead_acute, XK_Cyrillic_i, XK_VoidSymbol}, "и́"}, // CYRILLIC SMALL LETTER I WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_i, XK_VoidSymbol}, "и́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_i, XK_VoidSymbol}, "и́"}, {{XK_Multi_key, XK_C, XK_C, XK_C, XK_P, XK_VoidSymbol}, "☭"}, // U262D | HAMMER AND SICKLE {{XK_dead_iota, XK_dead_acute, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, // U1FAC | GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_acute, XK_Multi_key, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_dead_iota, XK_Multi_key, XK_acute, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_dead_iota, XK_Multi_key, XK_apostrophe, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_acute, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_Multi_key, XK_Greek_iota, XK_acute, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_dead_psili, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_Multi_key, XK_Greek_iota, XK_apostrophe, XK_parenright, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾬ"}, {{XK_Multi_key, XK_o, XK_r, XK_VoidSymbol}, "®"}, // registered | REGISTERED SIGN {{XK_Multi_key, XK_o, XK_R, XK_VoidSymbol}, "®"}, {{XK_Multi_key, XK_O, XK_r, XK_VoidSymbol}, "®"}, {{XK_Multi_key, XK_O, XK_R, XK_VoidSymbol}, "®"}, {{XK_Multi_key, XK_R, XK_o, XK_VoidSymbol}, "®"}, {{XK_Multi_key, XK_R, XK_O, XK_VoidSymbol}, "®"}, {{XK_Multi_key, XK_i, XK_j, XK_VoidSymbol}, "ij"}, // U0133 | LATIN SMALL LIGATURE IJ {{XK_dead_hook, XK_Abreve, XK_VoidSymbol}, "Ẳ"}, // U1EB2 | LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_Abreve, XK_VoidSymbol}, "Ẳ"}, {{XK_dead_hook, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ẳ"}, {{XK_dead_hook, XK_Multi_key, XK_U, XK_A, XK_VoidSymbol}, "Ẳ"}, {{XK_dead_hook, XK_Multi_key, XK_b, XK_A, XK_VoidSymbol}, "Ẳ"}, {{XK_Multi_key, XK_question, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ẳ"}, {{XK_Multi_key, XK_question, XK_b, XK_A, XK_VoidSymbol}, "Ẳ"}, {{XK_dead_breve, XK_Ahook, XK_VoidSymbol}, "Ẳ"}, {{XK_dead_breve, XK_dead_hook, XK_A, XK_VoidSymbol}, "Ẳ"}, {{XK_Multi_key, XK_period, XK_colon, XK_VoidSymbol}, "∵"}, // because | . : BECAUSE {{XK_dead_tilde, XK_dead_dasia, XK_Greek_iota, XK_VoidSymbol}, "ἷ"}, // U1F37 | GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_iota, XK_VoidSymbol}, "ἷ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_iota, XK_VoidSymbol}, "ἷ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_iota, XK_VoidSymbol}, "ἷ"}, {{XK_Multi_key, XK_O, XK_A, XK_VoidSymbol}, "Ⓐ"}, // U24B6 | CIRCLED LATIN CAPITAL LETTER A {{XK_Multi_key, XK_parenleft, XK_A, XK_parenright, XK_VoidSymbol}, "Ⓐ"}, {{XK_Multi_key, XK_period, XK_less, XK_VoidSymbol}, "‹"}, // U2039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK {{XK_Multi_key, XK_parenleft, XK_4, XK_5, XK_parenright, XK_VoidSymbol}, "㊺"}, // U32BA | CIRCLED NUMBER FORTY FIVE {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_5, XK_parenright, XK_VoidSymbol}, "㊺"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_5, XK_parenright, XK_VoidSymbol}, "㊺"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_5, XK_parenright, XK_VoidSymbol}, "㊺"}, {{XK_dead_belowcircumflex, XK_l, XK_VoidSymbol}, "ḽ"}, // U1E3D | LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW {{XK_dead_iota, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾼ"}, // U1FBC | GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾼ"}, {{XK_dead_grave, XK_Cyrillic_a, XK_VoidSymbol}, "а̀"}, // CYRILLIC SMALL LETTER A WITH COMBINING GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_Cyrillic_a, XK_VoidSymbol}, "а̀"}, {{XK_Multi_key, XK_3, XK_4, XK_VoidSymbol}, "¾"}, // threequarters | VULGAR FRACTION THREE QUARTERS {{XK_dead_acute, XK_N, XK_VoidSymbol}, "Ń"}, // U0143 | LATIN CAPITAL LETTER N WITH ACUTE {{XK_Multi_key, XK_acute, XK_N, XK_VoidSymbol}, "Ń"}, {{XK_Multi_key, XK_apostrophe, XK_N, XK_VoidSymbol}, "Ń"}, {{XK_Multi_key, XK_N, XK_apostrophe, XK_VoidSymbol}, "Ń"}, {{XK_dead_hook, XK_Ecircumflex, XK_VoidSymbol}, "Ể"}, // U1EC2 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE {{XK_Multi_key, XK_question, XK_Ecircumflex, XK_VoidSymbol}, "Ể"}, {{XK_dead_hook, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ể"}, {{XK_dead_hook, XK_Multi_key, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ể"}, {{XK_Multi_key, XK_question, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ể"}, {{XK_Multi_key, XK_question, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ể"}, {{XK_dead_circumflex, XK_Ehook, XK_VoidSymbol}, "Ể"}, {{XK_dead_circumflex, XK_dead_hook, XK_E, XK_VoidSymbol}, "Ể"}, {{XK_Multi_key, XK_parenleft, XK_Q, XK_parenright, XK_VoidSymbol}, "Ⓠ"}, // U24C6 | CIRCLED LATIN CAPITAL LETTER Q {{XK_dead_invertedbreve, XK_Cyrillic_O, XK_VoidSymbol}, "О̑"}, // CYRILLIC CAPITAL LETTER O WITH COMBINING INVERTED BREVE {{XK_dead_acute, XK_otilde, XK_VoidSymbol}, "ṍ"}, // U1E4D | LATIN SMALL LETTER O WITH TILDE AND ACUTE {{XK_Multi_key, XK_acute, XK_otilde, XK_VoidSymbol}, "ṍ"}, {{XK_Multi_key, XK_apostrophe, XK_otilde, XK_VoidSymbol}, "ṍ"}, {{XK_dead_acute, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ṍ"}, {{XK_dead_acute, XK_Multi_key, XK_asciitilde, XK_o, XK_VoidSymbol}, "ṍ"}, {{XK_Multi_key, XK_acute, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ṍ"}, {{XK_Multi_key, XK_acute, XK_asciitilde, XK_o, XK_VoidSymbol}, "ṍ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ṍ"}, {{XK_Multi_key, XK_apostrophe, XK_asciitilde, XK_o, XK_VoidSymbol}, "ṍ"}, {{XK_dead_tilde, XK_oacute, XK_VoidSymbol}, "ṍ"}, {{XK_dead_tilde, XK_dead_acute, XK_o, XK_VoidSymbol}, "ṍ"}, {{XK_dead_iota, XK_Greek_ETA, XK_VoidSymbol}, "ῌ"}, // U1FCC | GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_ETA, XK_VoidSymbol}, "ῌ"}, {{XK_dead_circumflex, XK_I, XK_VoidSymbol}, "Î"}, // Icircumflex | LATIN CAPITAL LETTER I WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_I, XK_VoidSymbol}, "Î"}, {{XK_Multi_key, XK_I, XK_asciicircum, XK_VoidSymbol}, "Î"}, {{XK_Multi_key, XK_greater, XK_I, XK_VoidSymbol}, "Î"}, {{XK_Multi_key, XK_I, XK_greater, XK_VoidSymbol}, "Î"}, {{XK_dead_diaeresis, XK_Cyrillic_ie, XK_VoidSymbol}, "ё"}, // U0451 | CYRILLIC SMALL LETTER IO {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_ie, XK_VoidSymbol}, "ё"}, {{XK_Multi_key, XK_o, XK_e, XK_VoidSymbol}, "œ"}, // oe | LATIN SMALL LIGATURE OE {{XK_Multi_key, XK_C, XK_r, XK_VoidSymbol}, "₢"}, // U20a2 | CRUZEIRO SIGN {{XK_dead_currency, XK_r, XK_VoidSymbol}, "₢"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_5, XK_parenright, XK_VoidSymbol}, "㉕"}, // U3255 | CIRCLED NUMBER TWENTY FIVE {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_5, XK_parenright, XK_VoidSymbol}, "㉕"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_5, XK_parenright, XK_VoidSymbol}, "㉕"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_5, XK_parenright, XK_VoidSymbol}, "㉕"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_5, XK_parenright, XK_VoidSymbol}, "㉕"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_5, XK_parenright, XK_VoidSymbol}, "㉕"}, {{XK_dead_tilde, XK_dead_dasia, XK_Greek_upsilon, XK_VoidSymbol}, "ὗ"}, // U1F57 | GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_upsilon, XK_VoidSymbol}, "ὗ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_upsilon, XK_VoidSymbol}, "ὗ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_upsilon, XK_VoidSymbol}, "ὗ"}, {{XK_dead_breve, XK_Cyrillic_IE, XK_VoidSymbol}, "Ӗ"}, // U04D6 | CYRILLIC CAPITAL LETTER IE WITH BREVE {{XK_Multi_key, XK_U, XK_Cyrillic_IE, XK_VoidSymbol}, "Ӗ"}, {{XK_Multi_key, XK_b, XK_Cyrillic_IE, XK_VoidSymbol}, "Ӗ"}, {{XK_dead_grave, XK_Cyrillic_O, XK_VoidSymbol}, "О̀"}, // CYRILLIC CAPITAL LETTER O WITH COMBINING GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_Cyrillic_O, XK_VoidSymbol}, "О̀"}, {{XK_dead_acute, XK_udiaeresis, XK_VoidSymbol}, "ǘ"}, // U01D8 | LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE {{XK_Multi_key, XK_acute, XK_udiaeresis, XK_VoidSymbol}, "ǘ"}, {{XK_Multi_key, XK_apostrophe, XK_udiaeresis, XK_VoidSymbol}, "ǘ"}, {{XK_dead_acute, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǘ"}, {{XK_dead_acute, XK_Multi_key, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǘ"}, {{XK_Multi_key, XK_acute, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǘ"}, {{XK_Multi_key, XK_acute, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǘ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǘ"}, {{XK_Multi_key, XK_apostrophe, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǘ"}, {{XK_dead_acute, XK_v, XK_VoidSymbol}, "ǘ"}, {{XK_dead_diaeresis, XK_uacute, XK_VoidSymbol}, "ǘ"}, {{XK_dead_diaeresis, XK_dead_acute, XK_u, XK_VoidSymbol}, "ǘ"}, {{XK_dead_circumflex, XK_Cyrillic_O, XK_VoidSymbol}, "О̂"}, // CYRILLIC CAPITAL LETTER O WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_O, XK_VoidSymbol}, "О̂"}, {{XK_Multi_key, XK_parenleft, XK_kana_SA, XK_parenright, XK_VoidSymbol}, "㋚"}, // U32DA | CIRCLED KATAKANA SA {{XK_dead_macron, XK_dead_belowdot, XK_r, XK_VoidSymbol}, "ṝ"}, // U1E5D | LATIN SMALL LETTER R WITH DOT BELOW AND MACRON {{XK_dead_macron, XK_Multi_key, XK_exclam, XK_r, XK_VoidSymbol}, "ṝ"}, {{XK_Multi_key, XK_macron, XK_dead_belowdot, XK_r, XK_VoidSymbol}, "ṝ"}, {{XK_Multi_key, XK_macron, XK_exclam, XK_r, XK_VoidSymbol}, "ṝ"}, {{XK_Multi_key, XK_underscore, XK_dead_belowdot, XK_r, XK_VoidSymbol}, "ṝ"}, {{XK_Multi_key, XK_underscore, XK_exclam, XK_r, XK_VoidSymbol}, "ṝ"}, {{XK_dead_belowdot, XK_dead_macron, XK_r, XK_VoidSymbol}, "ṝ"}, {{XK_dead_circumflex, XK_minus, XK_VoidSymbol}, "⁻"}, // U207B | SUPERSCRIPT MINUS {{XK_Multi_key, XK_T, XK_H, XK_VoidSymbol}, "Þ"}, // THORN | LATIN CAPITAL LETTER THORN {{XK_Multi_key, XK_parenleft, XK_2, XK_parenright, XK_VoidSymbol}, "②"}, // U2461 | CIRCLED DIGIT TWO {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_parenright, XK_VoidSymbol}, "②"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_parenright, XK_VoidSymbol}, "②"}, {{XK_dead_voiced_sound, XK_kana_KA, XK_VoidSymbol}, "ガ"}, // U30AC | KATAKANA LETTER GA {{XK_dead_cedilla, XK_t, XK_VoidSymbol}, "ţ"}, // U0163 | LATIN SMALL LETTER T WITH CEDILLA {{XK_Multi_key, XK_comma, XK_t, XK_VoidSymbol}, "ţ"}, {{XK_Multi_key, XK_t, XK_comma, XK_VoidSymbol}, "ţ"}, {{XK_Multi_key, XK_cedilla, XK_t, XK_VoidSymbol}, "ţ"}, {{XK_dead_belowdot, XK_Ohorn, XK_VoidSymbol}, "Ợ"}, // U1EE2 | LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW {{XK_Multi_key, XK_exclam, XK_Ohorn, XK_VoidSymbol}, "Ợ"}, {{XK_dead_belowdot, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ợ"}, {{XK_dead_belowdot, XK_Multi_key, XK_plus, XK_O, XK_VoidSymbol}, "Ợ"}, {{XK_Multi_key, XK_exclam, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ợ"}, {{XK_Multi_key, XK_exclam, XK_plus, XK_O, XK_VoidSymbol}, "Ợ"}, {{XK_dead_horn, XK_Obelowdot, XK_VoidSymbol}, "Ợ"}, {{XK_dead_horn, XK_dead_belowdot, XK_O, XK_VoidSymbol}, "Ợ"}, {{XK_Multi_key, XK_greater, XK_equal, XK_VoidSymbol}, "≥"}, // U2265 | GREATER-THAN OR EQUAL TO {{XK_Multi_key, XK_greater, XK_underscore, XK_VoidSymbol}, "≥"}, {{XK_Multi_key, XK_underscore, XK_greater, XK_VoidSymbol}, "≥"}, {{XK_dead_tilde, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ὧ"}, // U1F67 | GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ὧ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ὧ"}, {{XK_Multi_key, XK_asciitilde, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ὧ"}, {{XK_dead_diaeresis, XK_Cyrillic_O, XK_VoidSymbol}, "Ӧ"}, // U04E6 | CYRILLIC CAPITAL LETTER O WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_O, XK_VoidSymbol}, "Ӧ"}, {{XK_dead_caron, XK_K, XK_VoidSymbol}, "Ǩ"}, // U01E8 | LATIN CAPITAL LETTER K WITH CARON {{XK_Multi_key, XK_c, XK_K, XK_VoidSymbol}, "Ǩ"}, {{XK_Multi_key, XK_parenleft, XK_kana_HI, XK_parenright, XK_VoidSymbol}, "㋪"}, // U32EA | CIRCLED KATAKANA HI {{XK_Multi_key, XK_numbersign, XK_b, XK_VoidSymbol}, "♭"}, // U266d | MUSIC FLAT SIGN {{XK_dead_dasia, XK_Greek_RHO, XK_VoidSymbol}, "Ῥ"}, // U1FEC | GREEK CAPITAL LETTER RHO WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_RHO, XK_VoidSymbol}, "Ῥ"}, {{XK_dead_circumflex, XK_i, XK_VoidSymbol}, "î"}, // icircumflex | LATIN SMALL LETTER I WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_i, XK_VoidSymbol}, "î"}, {{XK_Multi_key, XK_i, XK_asciicircum, XK_VoidSymbol}, "î"}, {{XK_Multi_key, XK_greater, XK_i, XK_VoidSymbol}, "î"}, {{XK_Multi_key, XK_i, XK_greater, XK_VoidSymbol}, "î"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_8, XK_parenright, XK_VoidSymbol}, "⑱"}, // U2471 | CIRCLED NUMBER EIGHTEEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_8, XK_parenright, XK_VoidSymbol}, "⑱"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_8, XK_parenright, XK_VoidSymbol}, "⑱"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_8, XK_parenright, XK_VoidSymbol}, "⑱"}, {{XK_dead_ogonek, XK_u, XK_VoidSymbol}, "ų"}, // U0173 | LATIN SMALL LETTER U WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_u, XK_VoidSymbol}, "ų"}, {{XK_Multi_key, XK_u, XK_semicolon, XK_VoidSymbol}, "ų"}, {{XK_Multi_key, XK_comma, XK_u, XK_VoidSymbol}, "ų"}, {{XK_Multi_key, XK_u, XK_comma, XK_VoidSymbol}, "ų"}, {{XK_dead_grave, XK_Y, XK_VoidSymbol}, "Ỳ"}, // U1EF2 | LATIN CAPITAL LETTER Y WITH GRAVE {{XK_Multi_key, XK_grave, XK_Y, XK_VoidSymbol}, "Ỳ"}, {{XK_dead_circumflex, XK_Cyrillic_U, XK_VoidSymbol}, "У̂"}, // CYRILLIC CAPITAL LETTER U WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_U, XK_VoidSymbol}, "У̂"}, {{XK_dead_circumflex, XK_9, XK_VoidSymbol}, "⁹"}, // U2079 | SUPERSCRIPT NINE {{XK_Multi_key, XK_asciicircum, XK_9, XK_VoidSymbol}, "⁹"}, {{XK_dead_circumflex, XK_KP_9, XK_VoidSymbol}, "⁹"}, {{XK_Multi_key, XK_asciicircum, XK_KP_9, XK_VoidSymbol}, "⁹"}, {{XK_dead_grave, XK_N, XK_VoidSymbol}, "Ǹ"}, // U01F8 | LATIN CAPITAL LETTER N WITH GRAVE {{XK_Multi_key, XK_grave, XK_N, XK_VoidSymbol}, "Ǹ"}, {{XK_Multi_key, XK_parenleft, XK_kana_RO, XK_parenright, XK_VoidSymbol}, "㋺"}, // U32FA | CIRCLED KATAKANA RO {{XK_dead_tilde, XK_v, XK_VoidSymbol}, "ṽ"}, // U1E7D | LATIN SMALL LETTER V WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_v, XK_VoidSymbol}, "ṽ"}, {{XK_dead_iota, XK_Greek_OMEGA, XK_VoidSymbol}, "ῼ"}, // U1FFC | GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI {{XK_Multi_key, XK_Greek_iota, XK_Greek_OMEGA, XK_VoidSymbol}, "ῼ"}, {{XK_Multi_key, XK_t, XK_h, XK_VoidSymbol}, "þ"}, // thorn | LATIN SMALL LETTER THORN {{XK_dead_iota, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾁ"}, // U1F81 | GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾁ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ᾁ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ᾁ"}, {{XK_dead_belowring, XK_A, XK_VoidSymbol}, "Ḁ"}, // U1E00 | LATIN CAPITAL LETTER A WITH RING BELOW {{XK_dead_currency, XK_s, XK_VoidSymbol}, "₪"}, // NewSheqelSign | NEW SHEQEL SIGN {{XK_Multi_key, XK_parenleft, XK_h, XK_parenright, XK_VoidSymbol}, "ⓗ"}, // U24D7 | CIRCLED LATIN SMALL LETTER H {{XK_dead_tilde, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ἆ"}, // U1F06 | GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ἆ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ἆ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ἆ"}, {{XK_dead_acute, XK_Greek_ETA, XK_VoidSymbol}, "Ή"}, // U0389 | GREEK CAPITAL LETTER ETA WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_ETA, XK_VoidSymbol}, "Ή"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_ETA, XK_VoidSymbol}, "Ή"}, {{XK_Multi_key, XK_Greek_ETA, XK_apostrophe, XK_VoidSymbol}, "Ή"}, {{XK_dead_doublegrave, XK_I, XK_VoidSymbol}, "Ȉ"}, // U0208 | LATIN CAPITAL LETTER I WITH DOUBLE GRAVE {{XK_dead_abovedot, XK_x, XK_VoidSymbol}, "ẋ"}, // U1E8B | LATIN SMALL LETTER X WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_x, XK_VoidSymbol}, "ẋ"}, {{XK_dead_abovedot, XK_C, XK_VoidSymbol}, "Ċ"}, // U010A | LATIN CAPITAL LETTER C WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_C, XK_VoidSymbol}, "Ċ"}, {{XK_Multi_key, XK_C, XK_period, XK_VoidSymbol}, "Ċ"}, {{XK_dead_acute, XK_Cyrillic_KA, XK_VoidSymbol}, "Ќ"}, // U040C | CYRILLIC CAPITAL LETTER KJE {{XK_Multi_key, XK_acute, XK_Cyrillic_KA, XK_VoidSymbol}, "Ќ"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_KA, XK_VoidSymbol}, "Ќ"}, {{XK_dead_circumflex, XK_Cyrillic_er, XK_VoidSymbol}, "р̂"}, // CYRILLIC SMALL LETTER ER WITH COMBINING CIRCUMFLEX ACCENT {{XK_Multi_key, XK_asciicircum, XK_Cyrillic_er, XK_VoidSymbol}, "р̂"}, {{XK_dead_iota, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾑ"}, // U1F91 | GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾑ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ᾑ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ᾑ"}, {{XK_dead_cedilla, XK_D, XK_VoidSymbol}, "Ḑ"}, // U1E10 | LATIN CAPITAL LETTER D WITH CEDILLA {{XK_Multi_key, XK_comma, XK_D, XK_VoidSymbol}, "Ḑ"}, {{XK_Multi_key, XK_D, XK_comma, XK_VoidSymbol}, "Ḑ"}, {{XK_Multi_key, XK_cedilla, XK_D, XK_VoidSymbol}, "Ḑ"}, {{XK_Multi_key, XK_minus, XK_minus, XK_minus, XK_VoidSymbol}, "—"}, // U2014 | EM DASH {{XK_dead_cedilla, XK_ColonSign, XK_VoidSymbol}, "₵"}, // U20B5 | CEDI SIGN {{XK_dead_cedilla, XK_cent, XK_VoidSymbol}, "₵"}, {{XK_dead_currency, XK_Ccedilla, XK_VoidSymbol}, "₵"}, {{XK_dead_currency, XK_ccedilla, XK_VoidSymbol}, "₵"}, {{XK_dead_cedilla, XK_dead_currency, XK_C, XK_VoidSymbol}, "₵"}, {{XK_dead_currency, XK_dead_cedilla, XK_C, XK_VoidSymbol}, "₵"}, {{XK_dead_cedilla, XK_dead_currency, XK_c, XK_VoidSymbol}, "₵"}, {{XK_dead_currency, XK_dead_cedilla, XK_c, XK_VoidSymbol}, "₵"}, {{XK_dead_belowcomma, XK_S, XK_VoidSymbol}, "Ș"}, // U0218 | LATIN CAPITAL LETTER S WITH COMMA BELOW {{XK_Multi_key, XK_semicolon, XK_S, XK_VoidSymbol}, "Ș"}, {{XK_Multi_key, XK_S, XK_semicolon, XK_VoidSymbol}, "Ș"}, {{XK_dead_abovedot, XK_Multi_key, XK_f, XK_s, XK_VoidSymbol}, "ẛ"}, // U1e9b | LATIN SMALL LETTER LONG S WITH DOT ABOVE {{XK_Multi_key, XK_dead_abovedot, XK_f, XK_s, XK_VoidSymbol}, "ẛ"}, {{XK_dead_caron, XK_E, XK_VoidSymbol}, "Ě"}, // U011A | LATIN CAPITAL LETTER E WITH CARON {{XK_Multi_key, XK_c, XK_E, XK_VoidSymbol}, "Ě"}, {{XK_Multi_key, XK_less, XK_E, XK_VoidSymbol}, "Ě"}, {{XK_Multi_key, XK_E, XK_less, XK_VoidSymbol}, "Ě"}, {{XK_Multi_key, XK_parenleft, XK_kana_SHI, XK_parenright, XK_VoidSymbol}, "㋛"}, // U32DB | CIRCLED KATAKANA SI {{XK_dead_macron, XK_nobreakspace, XK_VoidSymbol}, "̄"}, // U0304 | COMBINING MACRON {{XK_dead_iota, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾡ"}, // U1FA1 | GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾡ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ᾡ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ᾡ"}, {{XK_dead_macron, XK_G, XK_VoidSymbol}, "Ḡ"}, // U1E20 | LATIN CAPITAL LETTER G WITH MACRON {{XK_Multi_key, XK_macron, XK_G, XK_VoidSymbol}, "Ḡ"}, {{XK_Multi_key, XK_underscore, XK_G, XK_VoidSymbol}, "Ḡ"}, {{XK_Multi_key, XK_5, XK_6, XK_VoidSymbol}, "⅚"}, // U215A | VULGAR FRACTION FIVE SIXTHS {{XK_dead_hook, XK_p, XK_VoidSymbol}, "ƥ"}, // U01A5 | LATIN SMALL LETTER P WITH HOOK {{XK_dead_currency, XK_S, XK_VoidSymbol}, "$"}, // dollar | DOLLAR SIGN {{XK_Multi_key, XK_parenleft, XK_kana_SO, XK_parenright, XK_VoidSymbol}, "㋞"}, // U32DE | CIRCLED KATAKANA SO {{XK_dead_tilde, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ἦ"}, // U1F26 | GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ἦ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ἦ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ἦ"}, {{XK_dead_cedilla, XK_E, XK_VoidSymbol}, "Ȩ"}, // U0228 | LATIN CAPITAL LETTER E WITH CEDILLA {{XK_Multi_key, XK_cedilla, XK_E, XK_VoidSymbol}, "Ȩ"}, {{XK_dead_tilde, XK_acircumflex, XK_VoidSymbol}, "ẫ"}, // U1EAB | LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE {{XK_Multi_key, XK_asciitilde, XK_acircumflex, XK_VoidSymbol}, "ẫ"}, {{XK_dead_tilde, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ẫ"}, {{XK_dead_tilde, XK_Multi_key, XK_asciicircum, XK_a, XK_VoidSymbol}, "ẫ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_circumflex, XK_a, XK_VoidSymbol}, "ẫ"}, {{XK_Multi_key, XK_asciitilde, XK_asciicircum, XK_a, XK_VoidSymbol}, "ẫ"}, {{XK_dead_circumflex, XK_atilde, XK_VoidSymbol}, "ẫ"}, {{XK_dead_circumflex, XK_dead_tilde, XK_a, XK_VoidSymbol}, "ẫ"}, {{XK_dead_macron, XK_I, XK_VoidSymbol}, "Ī"}, // U012A | LATIN CAPITAL LETTER I WITH MACRON {{XK_Multi_key, XK_macron, XK_I, XK_VoidSymbol}, "Ī"}, {{XK_Multi_key, XK_underscore, XK_I, XK_VoidSymbol}, "Ī"}, {{XK_Multi_key, XK_I, XK_underscore, XK_VoidSymbol}, "Ī"}, {{XK_Multi_key, XK_minus, XK_I, XK_VoidSymbol}, "Ī"}, {{XK_Multi_key, XK_I, XK_minus, XK_VoidSymbol}, "Ī"}, {{XK_dead_macron, XK_space, XK_VoidSymbol}, "¯"}, // macron | MACRON {{XK_dead_macron, XK_dead_macron, XK_VoidSymbol}, "¯"}, {{XK_Multi_key, XK_minus, XK_asciicircum, XK_VoidSymbol}, "¯"}, {{XK_Multi_key, XK_asciicircum, XK_minus, XK_VoidSymbol}, "¯"}, {{XK_Multi_key, XK_underscore, XK_underscore, XK_VoidSymbol}, "¯"}, {{XK_Multi_key, XK_underscore, XK_asciicircum, XK_VoidSymbol}, "¯"}, {{XK_dead_macron, XK_Greek_alpha, XK_VoidSymbol}, "ᾱ"}, // U1FB1 | GREEK SMALL LETTER ALPHA WITH MACRON {{XK_Multi_key, XK_macron, XK_Greek_alpha, XK_VoidSymbol}, "ᾱ"}, {{XK_Multi_key, XK_underscore, XK_Greek_alpha, XK_VoidSymbol}, "ᾱ"}, {{XK_dead_acute, XK_K, XK_VoidSymbol}, "Ḱ"}, // U1E30 | LATIN CAPITAL LETTER K WITH ACUTE {{XK_Multi_key, XK_acute, XK_K, XK_VoidSymbol}, "Ḱ"}, {{XK_Multi_key, XK_apostrophe, XK_K, XK_VoidSymbol}, "Ḱ"}, {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_r, XK_VoidSymbol}, "ʳ"}, // U02B3 | MODIFIER LETTER SMALL R {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_r, XK_VoidSymbol}, "ʳ"}, {{XK_dead_voiced_sound, XK_kana_KE, XK_VoidSymbol}, "ゲ"}, // U30B2 | KATAKANA LETTER GE {{XK_dead_stroke, XK_Z, XK_VoidSymbol}, "Ƶ"}, // U01B5 | LATIN CAPITAL LETTER Z WITH STROKE {{XK_Multi_key, XK_slash, XK_Z, XK_VoidSymbol}, "Ƶ"}, {{XK_Multi_key, XK_KP_Divide, XK_Z, XK_VoidSymbol}, "Ƶ"}, {{XK_Multi_key, XK_parenleft, XK_p, XK_parenright, XK_VoidSymbol}, "ⓟ"}, // U24DF | CIRCLED LATIN SMALL LETTER P {{XK_Multi_key, XK_parenleft, XK_B, XK_parenright, XK_VoidSymbol}, "Ⓑ"}, // U24B7 | CIRCLED LATIN CAPITAL LETTER B {{XK_dead_tilde, XK_dead_psili, XK_Greek_iota, XK_VoidSymbol}, "ἶ"}, // U1F36 | GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_iota, XK_VoidSymbol}, "ἶ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_iota, XK_VoidSymbol}, "ἶ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_iota, XK_VoidSymbol}, "ἶ"}, {{XK_dead_hook, XK_e, XK_VoidSymbol}, "ẻ"}, // U1EBB | LATIN SMALL LETTER E WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_e, XK_VoidSymbol}, "ẻ"}, {{XK_dead_acute, XK_l, XK_VoidSymbol}, "ĺ"}, // U013A | LATIN SMALL LETTER L WITH ACUTE {{XK_Multi_key, XK_acute, XK_l, XK_VoidSymbol}, "ĺ"}, {{XK_Multi_key, XK_apostrophe, XK_l, XK_VoidSymbol}, "ĺ"}, {{XK_Multi_key, XK_l, XK_apostrophe, XK_VoidSymbol}, "ĺ"}, {{XK_dead_voiced_sound, XK_kana_TSU, XK_VoidSymbol}, "ヅ"}, // U30C5 | KATAKANA LETTER DU {{XK_Multi_key, XK_question, XK_question, XK_VoidSymbol}, "¿"}, // questiondown | INVERTED QUESTION MARK {{XK_Multi_key, XK_diaeresis, XK_dead_tilde, XK_VoidSymbol}, "῁"}, // U1FC1 | GREEK DIALYTIKA AND PERISPOMENI {{XK_Multi_key, XK_diaeresis, XK_asciitilde, XK_VoidSymbol}, "῁"}, {{XK_dead_abovedot, XK_M, XK_VoidSymbol}, "Ṁ"}, // U1E40 | LATIN CAPITAL LETTER M WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_M, XK_VoidSymbol}, "Ṁ"}, {{XK_Multi_key, XK_M, XK_period, XK_VoidSymbol}, "Ṁ"}, {{XK_Multi_key, XK_parenleft, XK_R, XK_parenright, XK_VoidSymbol}, "Ⓡ"}, // U24C7 | CIRCLED LATIN CAPITAL LETTER R {{XK_dead_hook, XK_g, XK_VoidSymbol}, "ɠ"}, // U0260 | LATIN SMALL LETTER G WITH HOOK {{XK_dead_stroke, XK_J, XK_VoidSymbol}, "Ɉ"}, // U0248 | LATIN CAPITAL LETTER J WITH STROKE {{XK_dead_belowdot, XK_i, XK_VoidSymbol}, "ị"}, // U1ECB | LATIN SMALL LETTER I WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_i, XK_VoidSymbol}, "ị"}, {{XK_Multi_key, XK_N, XK_G, XK_VoidSymbol}, "Ŋ"}, // U014A | LATIN CAPITAL LETTER ENG {{XK_Multi_key, XK_parenleft, XK_kana_TO, XK_parenright, XK_VoidSymbol}, "㋣"}, // U32E3 | CIRCLED KATAKANA TO {{XK_dead_diaeresis, XK_I, XK_VoidSymbol}, "Ï"}, // Idiaeresis | LATIN CAPITAL LETTER I WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_I, XK_VoidSymbol}, "Ï"}, {{XK_Multi_key, XK_I, XK_quotedbl, XK_VoidSymbol}, "Ï"}, {{XK_Multi_key, XK_diaeresis, XK_I, XK_VoidSymbol}, "Ï"}, {{XK_Multi_key, XK_I, XK_diaeresis, XK_VoidSymbol}, "Ï"}, {{XK_dead_macron, XK_Greek_iota, XK_VoidSymbol}, "ῑ"}, // U1FD1 | GREEK SMALL LETTER IOTA WITH MACRON {{XK_Multi_key, XK_macron, XK_Greek_iota, XK_VoidSymbol}, "ῑ"}, {{XK_Multi_key, XK_underscore, XK_Greek_iota, XK_VoidSymbol}, "ῑ"}, {{XK_dead_macron, XK_dead_belowdot, XK_l, XK_VoidSymbol}, "ḹ"}, // U1E39 | LATIN SMALL LETTER L WITH DOT BELOW AND MACRON {{XK_dead_macron, XK_Multi_key, XK_exclam, XK_l, XK_VoidSymbol}, "ḹ"}, {{XK_Multi_key, XK_macron, XK_dead_belowdot, XK_l, XK_VoidSymbol}, "ḹ"}, {{XK_Multi_key, XK_macron, XK_exclam, XK_l, XK_VoidSymbol}, "ḹ"}, {{XK_Multi_key, XK_underscore, XK_dead_belowdot, XK_l, XK_VoidSymbol}, "ḹ"}, {{XK_Multi_key, XK_underscore, XK_exclam, XK_l, XK_VoidSymbol}, "ḹ"}, {{XK_dead_belowdot, XK_dead_macron, XK_l, XK_VoidSymbol}, "ḹ"}, {{XK_Multi_key, XK_parenleft, XK_kana_E, XK_parenright, XK_VoidSymbol}, "㋓"}, // U32D3 | CIRCLED KATAKANA E {{XK_dead_macron, XK_Udiaeresis, XK_VoidSymbol}, "Ǖ"}, // U01D5 | LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON {{XK_Multi_key, XK_macron, XK_Udiaeresis, XK_VoidSymbol}, "Ǖ"}, {{XK_Multi_key, XK_underscore, XK_Udiaeresis, XK_VoidSymbol}, "Ǖ"}, {{XK_dead_macron, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǖ"}, {{XK_dead_macron, XK_Multi_key, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǖ"}, {{XK_Multi_key, XK_macron, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǖ"}, {{XK_Multi_key, XK_macron, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǖ"}, {{XK_Multi_key, XK_underscore, XK_dead_diaeresis, XK_U, XK_VoidSymbol}, "Ǖ"}, {{XK_Multi_key, XK_underscore, XK_quotedbl, XK_U, XK_VoidSymbol}, "Ǖ"}, {{XK_dead_macron, XK_V, XK_VoidSymbol}, "Ǖ"}, {{XK_dead_breve, XK_Cyrillic_ie, XK_VoidSymbol}, "ӗ"}, // U04D7 | CYRILLIC SMALL LETTER IE WITH BREVE {{XK_Multi_key, XK_U, XK_Cyrillic_ie, XK_VoidSymbol}, "ӗ"}, {{XK_Multi_key, XK_b, XK_Cyrillic_ie, XK_VoidSymbol}, "ӗ"}, {{XK_dead_tilde, XK_dead_psili, XK_Greek_upsilon, XK_VoidSymbol}, "ὖ"}, // U1F56 | GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_upsilon, XK_VoidSymbol}, "ὖ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_upsilon, XK_VoidSymbol}, "ὖ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_upsilon, XK_VoidSymbol}, "ὖ"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_8, XK_parenright, XK_VoidSymbol}, "㉘"}, // U3258 | CIRCLED NUMBER TWENTY EIGHT {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_8, XK_parenright, XK_VoidSymbol}, "㉘"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_8, XK_parenright, XK_VoidSymbol}, "㉘"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_8, XK_parenright, XK_VoidSymbol}, "㉘"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_8, XK_parenright, XK_VoidSymbol}, "㉘"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_8, XK_parenright, XK_VoidSymbol}, "㉘"}, {{XK_dead_acute, XK_ohorn, XK_VoidSymbol}, "ớ"}, // U1EDB | LATIN SMALL LETTER O WITH HORN AND ACUTE {{XK_Multi_key, XK_acute, XK_ohorn, XK_VoidSymbol}, "ớ"}, {{XK_Multi_key, XK_apostrophe, XK_ohorn, XK_VoidSymbol}, "ớ"}, {{XK_dead_acute, XK_dead_horn, XK_o, XK_VoidSymbol}, "ớ"}, {{XK_dead_acute, XK_Multi_key, XK_plus, XK_o, XK_VoidSymbol}, "ớ"}, {{XK_Multi_key, XK_acute, XK_dead_horn, XK_o, XK_VoidSymbol}, "ớ"}, {{XK_Multi_key, XK_acute, XK_plus, XK_o, XK_VoidSymbol}, "ớ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_horn, XK_o, XK_VoidSymbol}, "ớ"}, {{XK_Multi_key, XK_apostrophe, XK_plus, XK_o, XK_VoidSymbol}, "ớ"}, {{XK_dead_horn, XK_oacute, XK_VoidSymbol}, "ớ"}, {{XK_dead_horn, XK_dead_acute, XK_o, XK_VoidSymbol}, "ớ"}, {{XK_dead_acute, XK_S, XK_VoidSymbol}, "Ś"}, // U015A | LATIN CAPITAL LETTER S WITH ACUTE {{XK_Multi_key, XK_acute, XK_S, XK_VoidSymbol}, "Ś"}, {{XK_Multi_key, XK_apostrophe, XK_S, XK_VoidSymbol}, "Ś"}, {{XK_Multi_key, XK_S, XK_apostrophe, XK_VoidSymbol}, "Ś"}, {{XK_dead_acute, XK_Cyrillic_ka, XK_VoidSymbol}, "ќ"}, // U045C | CYRILLIC SMALL LETTER KJE {{XK_Multi_key, XK_acute, XK_Cyrillic_ka, XK_VoidSymbol}, "ќ"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_ka, XK_VoidSymbol}, "ќ"}, {{XK_Multi_key, XK_s, XK_s, XK_VoidSymbol}, "ß"}, // ssharp | LATIN SMALL LETTER SHARP S {{XK_dead_macron, XK_Greek_upsilon, XK_VoidSymbol}, "ῡ"}, // U1FE1 | GREEK SMALL LETTER UPSILON WITH MACRON {{XK_Multi_key, XK_macron, XK_Greek_upsilon, XK_VoidSymbol}, "ῡ"}, {{XK_Multi_key, XK_underscore, XK_Greek_upsilon, XK_VoidSymbol}, "ῡ"}, {{XK_dead_abovedot, XK_S, XK_VoidSymbol}, "Ṡ"}, // U1E60 | LATIN CAPITAL LETTER S WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_S, XK_VoidSymbol}, "Ṡ"}, {{XK_Multi_key, XK_S, XK_period, XK_VoidSymbol}, "Ṡ"}, {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_x, XK_VoidSymbol}, "ˣ"}, // U02E3 | MODIFIER LETTER SMALL X {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_x, XK_VoidSymbol}, "ˣ"}, {{XK_dead_voiced_sound, XK_kana_SU, XK_VoidSymbol}, "ズ"}, // U30BA | KATAKANA LETTER ZU {{XK_dead_stroke, XK_g, XK_VoidSymbol}, "ǥ"}, // U01E5 | LATIN SMALL LETTER G WITH STROKE {{XK_Multi_key, XK_slash, XK_g, XK_VoidSymbol}, "ǥ"}, {{XK_Multi_key, XK_KP_Divide, XK_g, XK_VoidSymbol}, "ǥ"}, {{XK_Multi_key, XK_parenleft, XK_x, XK_parenright, XK_VoidSymbol}, "ⓧ"}, // U24E7 | CIRCLED LATIN SMALL LETTER X {{XK_dead_diaeresis, XK_Cyrillic_o, XK_VoidSymbol}, "ӧ"}, // U04E7 | CYRILLIC SMALL LETTER O WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_o, XK_VoidSymbol}, "ӧ"}, {{XK_dead_tilde, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ὦ"}, // U1F66 | GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI {{XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ὦ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ὦ"}, {{XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ὦ"}, {{XK_dead_stroke, XK_i, XK_VoidSymbol}, "ɨ"}, // U0268 | LATIN SMALL LETTER I WITH STROKE {{XK_Multi_key, XK_slash, XK_i, XK_VoidSymbol}, "ɨ"}, {{XK_Multi_key, XK_KP_Divide, XK_i, XK_VoidSymbol}, "ɨ"}, {{XK_dead_grave, XK_uhorn, XK_VoidSymbol}, "ừ"}, // U1EEB | LATIN SMALL LETTER U WITH HORN AND GRAVE {{XK_Multi_key, XK_grave, XK_uhorn, XK_VoidSymbol}, "ừ"}, {{XK_dead_grave, XK_dead_horn, XK_u, XK_VoidSymbol}, "ừ"}, {{XK_dead_grave, XK_Multi_key, XK_plus, XK_u, XK_VoidSymbol}, "ừ"}, {{XK_Multi_key, XK_grave, XK_dead_horn, XK_u, XK_VoidSymbol}, "ừ"}, {{XK_Multi_key, XK_grave, XK_plus, XK_u, XK_VoidSymbol}, "ừ"}, {{XK_dead_horn, XK_ugrave, XK_VoidSymbol}, "ừ"}, {{XK_dead_horn, XK_dead_grave, XK_u, XK_VoidSymbol}, "ừ"}, {{XK_dead_macron, XK_U, XK_VoidSymbol}, "Ū"}, // U016A | LATIN CAPITAL LETTER U WITH MACRON {{XK_Multi_key, XK_macron, XK_U, XK_VoidSymbol}, "Ū"}, {{XK_Multi_key, XK_underscore, XK_U, XK_VoidSymbol}, "Ū"}, {{XK_Multi_key, XK_U, XK_underscore, XK_VoidSymbol}, "Ū"}, {{XK_Multi_key, XK_minus, XK_U, XK_VoidSymbol}, "Ū"}, {{XK_Multi_key, XK_U, XK_minus, XK_VoidSymbol}, "Ū"}, {{XK_dead_circumflex, XK_Multi_key, XK_S, XK_M, XK_VoidSymbol}, "℠"}, // U2120 | SERVICE MARK {{XK_Multi_key, XK_S, XK_M, XK_VoidSymbol}, "℠"}, {{XK_dead_circumflex, XK_Multi_key, XK_s, XK_M, XK_VoidSymbol}, "℠"}, {{XK_Multi_key, XK_s, XK_M, XK_VoidSymbol}, "℠"}, {{XK_dead_circumflex, XK_Multi_key, XK_S, XK_m, XK_VoidSymbol}, "℠"}, {{XK_Multi_key, XK_S, XK_m, XK_VoidSymbol}, "℠"}, {{XK_dead_circumflex, XK_Multi_key, XK_s, XK_m, XK_VoidSymbol}, "℠"}, {{XK_Multi_key, XK_s, XK_m, XK_VoidSymbol}, "℠"}, {{XK_dead_diaeresis, XK_i, XK_VoidSymbol}, "ï"}, // idiaeresis | LATIN SMALL LETTER I WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_i, XK_VoidSymbol}, "ï"}, {{XK_Multi_key, XK_i, XK_quotedbl, XK_VoidSymbol}, "ï"}, {{XK_Multi_key, XK_diaeresis, XK_i, XK_VoidSymbol}, "ï"}, {{XK_Multi_key, XK_i, XK_diaeresis, XK_VoidSymbol}, "ï"}, {{XK_Multi_key, XK_semicolon, XK_underscore, XK_VoidSymbol}, "⍮"}, // U236e | ; _ APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR {{XK_dead_belowcircumflex, XK_T, XK_VoidSymbol}, "Ṱ"}, // U1E70 | LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW {{XK_Multi_key, XK_parenleft, XK_kana_YA, XK_parenright, XK_VoidSymbol}, "㋳"}, // U32F3 | CIRCLED KATAKANA YA {{XK_Multi_key, XK_parenleft, XK_u, XK_parenright, XK_VoidSymbol}, "ⓤ"}, // U24E4 | CIRCLED LATIN SMALL LETTER U {{XK_dead_acute, XK_g, XK_VoidSymbol}, "ǵ"}, // U01F5 | LATIN SMALL LETTER G WITH ACUTE {{XK_Multi_key, XK_acute, XK_g, XK_VoidSymbol}, "ǵ"}, {{XK_Multi_key, XK_apostrophe, XK_g, XK_VoidSymbol}, "ǵ"}, {{XK_dead_circumflex, XK_4, XK_VoidSymbol}, "⁴"}, // U2074 | SUPERSCRIPT FOUR {{XK_Multi_key, XK_asciicircum, XK_4, XK_VoidSymbol}, "⁴"}, {{XK_dead_circumflex, XK_KP_4, XK_VoidSymbol}, "⁴"}, {{XK_Multi_key, XK_asciicircum, XK_KP_4, XK_VoidSymbol}, "⁴"}, {{XK_dead_grave, XK_Greek_iota, XK_VoidSymbol}, "ὶ"}, // U1F76 | GREEK SMALL LETTER IOTA WITH VARIA {{XK_Multi_key, XK_grave, XK_Greek_iota, XK_VoidSymbol}, "ὶ"}, {{XK_dead_currency, XK_o, XK_VoidSymbol}, "௹"}, // U0BF9 | TAMIL RUPEE SIGN {{XK_dead_acute, XK_z, XK_VoidSymbol}, "ź"}, // U017A | LATIN SMALL LETTER Z WITH ACUTE {{XK_Multi_key, XK_acute, XK_z, XK_VoidSymbol}, "ź"}, {{XK_Multi_key, XK_apostrophe, XK_z, XK_VoidSymbol}, "ź"}, {{XK_Multi_key, XK_z, XK_apostrophe, XK_VoidSymbol}, "ź"}, {{XK_dead_diaeresis, XK_y, XK_VoidSymbol}, "ÿ"}, // ydiaeresis | LATIN SMALL LETTER Y WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_y, XK_VoidSymbol}, "ÿ"}, {{XK_Multi_key, XK_y, XK_quotedbl, XK_VoidSymbol}, "ÿ"}, {{XK_Multi_key, XK_diaeresis, XK_y, XK_VoidSymbol}, "ÿ"}, {{XK_Multi_key, XK_y, XK_diaeresis, XK_VoidSymbol}, "ÿ"}, {{XK_dead_dasia, XK_Greek_alpha, XK_VoidSymbol}, "ἁ"}, // U1F01 | GREEK SMALL LETTER ALPHA WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_alpha, XK_VoidSymbol}, "ἁ"}, {{XK_dead_grave, XK_W, XK_VoidSymbol}, "Ẁ"}, // U1E80 | LATIN CAPITAL LETTER W WITH GRAVE {{XK_Multi_key, XK_grave, XK_W, XK_VoidSymbol}, "Ẁ"}, {{XK_dead_invertedbreve, XK_a, XK_VoidSymbol}, "ȃ"}, // U0203 | LATIN SMALL LETTER A WITH INVERTED BREVE {{XK_dead_ogonek, XK_a, XK_VoidSymbol}, "ą"}, // U0105 | LATIN SMALL LETTER A WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_a, XK_VoidSymbol}, "ą"}, {{XK_Multi_key, XK_a, XK_semicolon, XK_VoidSymbol}, "ą"}, {{XK_Multi_key, XK_comma, XK_a, XK_VoidSymbol}, "ą"}, {{XK_Multi_key, XK_a, XK_comma, XK_VoidSymbol}, "ą"}, {{XK_Multi_key, XK_underscore, XK_4, XK_VoidSymbol}, "₄"}, // U2084 | SUBSCRIPT FOUR {{XK_Multi_key, XK_underscore, XK_KP_4, XK_VoidSymbol}, "₄"}, {{XK_dead_caron, XK_4, XK_VoidSymbol}, "₄"}, {{XK_dead_diaeresis, XK_Ukrainian_I, XK_VoidSymbol}, "Ї"}, // U0407 | CYRILLIC CAPITAL LETTER YI {{XK_Multi_key, XK_quotedbl, XK_Ukrainian_I, XK_VoidSymbol}, "Ї"}, {{XK_dead_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾆ"}, // U1F86 | GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾆ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾆ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾆ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾆ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾆ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾆ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾆ"}, {{XK_dead_hook, XK_dead_hook, XK_VoidSymbol}, "̉"}, // U0309 | COMBINING HOOK ABOVE {{XK_dead_hook, XK_nobreakspace, XK_VoidSymbol}, "̉"}, {{XK_dead_hook, XK_space, XK_VoidSymbol}, "̉"}, {{XK_dead_doublegrave, XK_Cyrillic_i, XK_VoidSymbol}, "и̏"}, // CYRILLIC SMALL LETTER I WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_i, XK_VoidSymbol}, "и̏"}, {{XK_dead_abovedot, XK_d, XK_VoidSymbol}, "ḋ"}, // U1E0B | LATIN SMALL LETTER D WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_d, XK_VoidSymbol}, "ḋ"}, {{XK_Multi_key, XK_d, XK_period, XK_VoidSymbol}, "ḋ"}, {{XK_dead_hook, XK_D, XK_VoidSymbol}, "Ɗ"}, // U018A | LATIN CAPITAL LETTER D WITH HOOK {{XK_dead_acute, XK_Greek_UPSILON, XK_VoidSymbol}, "Ύ"}, // U038E | GREEK CAPITAL LETTER UPSILON WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_UPSILON, XK_VoidSymbol}, "Ύ"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_UPSILON, XK_VoidSymbol}, "Ύ"}, {{XK_Multi_key, XK_Greek_UPSILON, XK_apostrophe, XK_VoidSymbol}, "Ύ"}, {{XK_dead_dasia, XK_Greek_epsilon, XK_VoidSymbol}, "ἑ"}, // U1F11 | GREEK SMALL LETTER EPSILON WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_epsilon, XK_VoidSymbol}, "ἑ"}, {{XK_dead_circumflex, XK_Z, XK_VoidSymbol}, "Ẑ"}, // U1E90 | LATIN CAPITAL LETTER Z WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_Z, XK_VoidSymbol}, "Ẑ"}, {{XK_dead_invertedbreve, XK_r, XK_VoidSymbol}, "ȓ"}, // U0213 | LATIN SMALL LETTER R WITH INVERTED BREVE {{XK_Multi_key, XK_parenleft, XK_M, XK_parenright, XK_VoidSymbol}, "Ⓜ"}, // U24C2 | CIRCLED LATIN CAPITAL LETTER M {{XK_dead_breve, XK_e, XK_VoidSymbol}, "ĕ"}, // U0115 | LATIN SMALL LETTER E WITH BREVE {{XK_Multi_key, XK_U, XK_e, XK_VoidSymbol}, "ĕ"}, {{XK_Multi_key, XK_b, XK_e, XK_VoidSymbol}, "ĕ"}, {{XK_dead_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾖ"}, // U1F96 | GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾖ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾖ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾖ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾖ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾖ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾖ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾖ"}, {{XK_dead_belowtilde, XK_e, XK_VoidSymbol}, "ḛ"}, // U1E1B | LATIN SMALL LETTER E WITH TILDE BELOW {{XK_dead_dasia, XK_Greek_eta, XK_VoidSymbol}, "ἡ"}, // U1F21 | GREEK SMALL LETTER ETA WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_eta, XK_VoidSymbol}, "ἡ"}, {{XK_dead_belowdot, XK_A, XK_VoidSymbol}, "Ạ"}, // U1EA0 | LATIN CAPITAL LETTER A WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_A, XK_VoidSymbol}, "Ạ"}, {{XK_Multi_key, XK_v, XK_slash, XK_VoidSymbol}, "√"}, // U221a | v / SQUARE ROOT {{XK_Multi_key, XK_slash, XK_v, XK_VoidSymbol}, "√"}, {{XK_dead_circumflex, XK_h, XK_VoidSymbol}, "ĥ"}, // U0125 | LATIN SMALL LETTER H WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_h, XK_VoidSymbol}, "ĥ"}, {{XK_Multi_key, XK_L, XK_equal, XK_VoidSymbol}, "₤"}, // U20a4 | LIRA SIGN {{XK_Multi_key, XK_equal, XK_L, XK_VoidSymbol}, "₤"}, {{XK_dead_currency, XK_L, XK_VoidSymbol}, "₤"}, {{XK_Multi_key, XK_parenleft, XK_m, XK_parenright, XK_VoidSymbol}, "ⓜ"}, // U24DC | CIRCLED LATIN SMALL LETTER M {{XK_dead_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾦ"}, // U1FA6 | GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾦ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾦ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾦ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾦ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾦ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾦ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾦ"}, {{XK_dead_belowbreve, XK_h, XK_VoidSymbol}, "ḫ"}, // U1E2B | LATIN SMALL LETTER H WITH BREVE BELOW {{XK_dead_semivoiced_sound, XK_kana_FU, XK_VoidSymbol}, "プ"}, // U30D7 | KATAKANA LETTER PU {{XK_dead_stroke, XK_dead_stroke, XK_VoidSymbol}, "/"}, // slash | SOLIDUS {{XK_dead_stroke, XK_space, XK_VoidSymbol}, "/"}, {{XK_dead_acute, XK_Greek_eta, XK_VoidSymbol}, "ή"}, // U03AE | GREEK SMALL LETTER ETA WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_eta, XK_VoidSymbol}, "ή"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_eta, XK_VoidSymbol}, "ή"}, {{XK_Multi_key, XK_Greek_eta, XK_apostrophe, XK_VoidSymbol}, "ή"}, {{XK_dead_dasia, XK_Greek_iota, XK_VoidSymbol}, "ἱ"}, // U1F31 | GREEK SMALL LETTER IOTA WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_iota, XK_VoidSymbol}, "ἱ"}, {{XK_dead_grave, XK_Abreve, XK_VoidSymbol}, "Ằ"}, // U1EB0 | LATIN CAPITAL LETTER A WITH BREVE AND GRAVE {{XK_Multi_key, XK_grave, XK_Abreve, XK_VoidSymbol}, "Ằ"}, {{XK_dead_grave, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ằ"}, {{XK_dead_grave, XK_Multi_key, XK_U, XK_A, XK_VoidSymbol}, "Ằ"}, {{XK_dead_grave, XK_Multi_key, XK_b, XK_A, XK_VoidSymbol}, "Ằ"}, {{XK_Multi_key, XK_grave, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ằ"}, {{XK_Multi_key, XK_grave, XK_b, XK_A, XK_VoidSymbol}, "Ằ"}, {{XK_dead_breve, XK_Agrave, XK_VoidSymbol}, "Ằ"}, {{XK_dead_breve, XK_dead_grave, XK_A, XK_VoidSymbol}, "Ằ"}, {{XK_dead_macron, XK_y, XK_VoidSymbol}, "ȳ"}, // U0233 | LATIN SMALL LETTER Y WITH MACRON {{XK_Multi_key, XK_macron, XK_y, XK_VoidSymbol}, "ȳ"}, {{XK_Multi_key, XK_underscore, XK_y, XK_VoidSymbol}, "ȳ"}, {{XK_dead_circumflex, XK_j, XK_VoidSymbol}, "ĵ"}, // U0135 | LATIN SMALL LETTER J WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_j, XK_VoidSymbol}, "ĵ"}, {{XK_dead_acute, XK_dead_acute, XK_VoidSymbol}, "´"}, // acute | ACUTE ACCENT {{XK_Multi_key, XK_apostrophe, XK_apostrophe, XK_VoidSymbol}, "´"}, {{XK_dead_tilde, XK_Greek_alpha, XK_VoidSymbol}, "ᾶ"}, // U1FB6 | GREEK SMALL LETTER ALPHA WITH PERISPOMENI {{XK_Multi_key, XK_asciitilde, XK_Greek_alpha, XK_VoidSymbol}, "ᾶ"}, {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_y, XK_VoidSymbol}, "ʸ"}, // U02B8 | MODIFIER LETTER SMALL Y {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_y, XK_VoidSymbol}, "ʸ"}, {{XK_dead_belowmacron, XK_l, XK_VoidSymbol}, "ḻ"}, // U1E3B | LATIN SMALL LETTER L WITH LINE BELOW {{XK_dead_invertedbreve, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̑"}, // CYRILLIC CAPITAL LETTER ER WITH COMBINING INVERTED BREVE {{XK_Multi_key, XK_parenleft, XK_G, XK_parenright, XK_VoidSymbol}, "Ⓖ"}, // U24BC | CIRCLED LATIN CAPITAL LETTER G {{XK_dead_dasia, XK_Greek_omicron, XK_VoidSymbol}, "ὁ"}, // U1F41 | GREEK SMALL LETTER OMICRON WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_omicron, XK_VoidSymbol}, "ὁ"}, {{XK_Multi_key, XK_exclam, XK_exclam, XK_VoidSymbol}, "¡"}, // exclamdown | INVERTED EXCLAMATION MARK {{XK_dead_stroke, XK_B, XK_VoidSymbol}, "Ƀ"}, // U0243 | LATIN CAPITAL LETTER B WITH STROKE {{XK_dead_cedilla, XK_N, XK_VoidSymbol}, "Ņ"}, // U0145 | LATIN CAPITAL LETTER N WITH CEDILLA {{XK_Multi_key, XK_comma, XK_N, XK_VoidSymbol}, "Ņ"}, {{XK_Multi_key, XK_N, XK_comma, XK_VoidSymbol}, "Ņ"}, {{XK_Multi_key, XK_cedilla, XK_N, XK_VoidSymbol}, "Ņ"}, {{XK_dead_diaeresis, XK_A, XK_VoidSymbol}, "Ä"}, // Adiaeresis | LATIN CAPITAL LETTER A WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_A, XK_VoidSymbol}, "Ä"}, {{XK_Multi_key, XK_A, XK_quotedbl, XK_VoidSymbol}, "Ä"}, {{XK_Multi_key, XK_diaeresis, XK_A, XK_VoidSymbol}, "Ä"}, {{XK_Multi_key, XK_A, XK_diaeresis, XK_VoidSymbol}, "Ä"}, {{XK_dead_tilde, XK_Greek_eta, XK_VoidSymbol}, "ῆ"}, // U1FC6 | GREEK SMALL LETTER ETA WITH PERISPOMENI {{XK_Multi_key, XK_asciitilde, XK_Greek_eta, XK_VoidSymbol}, "ῆ"}, {{XK_dead_belowcircumflex, XK_n, XK_VoidSymbol}, "ṋ"}, // U1E4B | LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW {{XK_dead_abovedot, XK_dead_stroke, XK_j, XK_VoidSymbol}, "ɟ"}, // U025F | LATIN SMALL LETTER DOTLESS J WITH STROKE {{XK_dead_stroke, XK_dead_abovedot, XK_j, XK_VoidSymbol}, "ɟ"}, {{XK_Multi_key, XK_parenleft, XK_W, XK_parenright, XK_VoidSymbol}, "Ⓦ"}, // U24CC | CIRCLED LATIN CAPITAL LETTER W {{XK_dead_currency, XK_H, XK_VoidSymbol}, "₴"}, // U20B4 | HRYVNIA SIGN {{XK_dead_currency, XK_h, XK_VoidSymbol}, "₴"}, {{XK_dead_acute, XK_Greek_omega, XK_VoidSymbol}, "ώ"}, // U03CE | GREEK SMALL LETTER OMEGA WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_omega, XK_VoidSymbol}, "ώ"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_omega, XK_VoidSymbol}, "ώ"}, {{XK_Multi_key, XK_Greek_omega, XK_apostrophe, XK_VoidSymbol}, "ώ"}, {{XK_dead_dasia, XK_Greek_upsilon, XK_VoidSymbol}, "ὑ"}, // U1F51 | GREEK SMALL LETTER UPSILON WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_upsilon, XK_VoidSymbol}, "ὑ"}, {{XK_dead_acute, XK_Ocircumflex, XK_VoidSymbol}, "Ố"}, // U1ED0 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE {{XK_Multi_key, XK_acute, XK_Ocircumflex, XK_VoidSymbol}, "Ố"}, {{XK_Multi_key, XK_apostrophe, XK_Ocircumflex, XK_VoidSymbol}, "Ố"}, {{XK_dead_acute, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ố"}, {{XK_dead_acute, XK_Multi_key, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ố"}, {{XK_Multi_key, XK_acute, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ố"}, {{XK_Multi_key, XK_acute, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ố"}, {{XK_Multi_key, XK_apostrophe, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ố"}, {{XK_Multi_key, XK_apostrophe, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ố"}, {{XK_dead_circumflex, XK_Oacute, XK_VoidSymbol}, "Ố"}, {{XK_dead_circumflex, XK_dead_acute, XK_O, XK_VoidSymbol}, "Ố"}, {{XK_Multi_key, XK_parenleft, XK_2, XK_3, XK_parenright, XK_VoidSymbol}, "㉓"}, // U3253 | CIRCLED NUMBER TWENTY THREE {{XK_Multi_key, XK_parenleft, XK_2, XK_KP_3, XK_parenright, XK_VoidSymbol}, "㉓"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_3, XK_parenright, XK_VoidSymbol}, "㉓"}, {{XK_Multi_key, XK_parenleft, XK_KP_Space, XK_KP_3, XK_parenright, XK_VoidSymbol}, "㉓"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_3, XK_parenright, XK_VoidSymbol}, "㉓"}, {{XK_Multi_key, XK_parenleft, XK_KP_2, XK_KP_3, XK_parenright, XK_VoidSymbol}, "㉓"}, {{XK_dead_acute, XK_r, XK_VoidSymbol}, "ŕ"}, // U0155 | LATIN SMALL LETTER R WITH ACUTE {{XK_Multi_key, XK_acute, XK_r, XK_VoidSymbol}, "ŕ"}, {{XK_Multi_key, XK_apostrophe, XK_r, XK_VoidSymbol}, "ŕ"}, {{XK_Multi_key, XK_r, XK_apostrophe, XK_VoidSymbol}, "ŕ"}, {{XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ô"}, // Ocircumflex | LATIN CAPITAL LETTER O WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ô"}, {{XK_Multi_key, XK_O, XK_asciicircum, XK_VoidSymbol}, "Ô"}, {{XK_Multi_key, XK_greater, XK_O, XK_VoidSymbol}, "Ô"}, {{XK_Multi_key, XK_O, XK_greater, XK_VoidSymbol}, "Ô"}, {{XK_dead_diaeresis, XK_Ukrainian_i, XK_VoidSymbol}, "ї"}, // U0457 | CYRILLIC SMALL LETTER YI {{XK_Multi_key, XK_quotedbl, XK_Ukrainian_i, XK_VoidSymbol}, "ї"}, {{XK_dead_tilde, XK_Greek_iota, XK_VoidSymbol}, "ῖ"}, // U1FD6 | GREEK SMALL LETTER IOTA WITH PERISPOMENI {{XK_Multi_key, XK_asciitilde, XK_Greek_iota, XK_VoidSymbol}, "ῖ"}, {{XK_dead_breve, XK_space, XK_VoidSymbol}, "˘"}, // breve | BREVE {{XK_dead_breve, XK_dead_breve, XK_VoidSymbol}, "˘"}, {{XK_Multi_key, XK_space, XK_parenleft, XK_VoidSymbol}, "˘"}, {{XK_Multi_key, XK_parenleft, XK_space, XK_VoidSymbol}, "˘"}, {{XK_dead_belowdot, XK_r, XK_VoidSymbol}, "ṛ"}, // U1E5B | LATIN SMALL LETTER R WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_r, XK_VoidSymbol}, "ṛ"}, {{XK_dead_caron, XK_udiaeresis, XK_VoidSymbol}, "ǚ"}, // U01DA | LATIN SMALL LETTER U WITH DIAERESIS AND CARON {{XK_Multi_key, XK_c, XK_udiaeresis, XK_VoidSymbol}, "ǚ"}, {{XK_dead_caron, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǚ"}, {{XK_dead_caron, XK_Multi_key, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǚ"}, {{XK_Multi_key, XK_c, XK_dead_diaeresis, XK_u, XK_VoidSymbol}, "ǚ"}, {{XK_Multi_key, XK_c, XK_quotedbl, XK_u, XK_VoidSymbol}, "ǚ"}, {{XK_dead_caron, XK_v, XK_VoidSymbol}, "ǚ"}, {{XK_dead_diaeresis, XK_dead_caron, XK_u, XK_VoidSymbol}, "ǚ"}, {{XK_dead_diaeresis, XK_Cyrillic_ZHE, XK_VoidSymbol}, "Ӝ"}, // U04DC | CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_ZHE, XK_VoidSymbol}, "Ӝ"}, {{XK_dead_acute, XK_Cyrillic_er, XK_VoidSymbol}, "р́"}, // CYRILLIC SMALL LETTER ER WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_er, XK_VoidSymbol}, "р́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_er, XK_VoidSymbol}, "р́"}, {{XK_dead_dasia, XK_Greek_omega, XK_VoidSymbol}, "ὡ"}, // U1F61 | GREEK SMALL LETTER OMEGA WITH DASIA {{XK_Multi_key, XK_parenleft, XK_Greek_omega, XK_VoidSymbol}, "ὡ"}, {{XK_dead_tilde, XK_Ohorn, XK_VoidSymbol}, "Ỡ"}, // U1EE0 | LATIN CAPITAL LETTER O WITH HORN AND TILDE {{XK_Multi_key, XK_asciitilde, XK_Ohorn, XK_VoidSymbol}, "Ỡ"}, {{XK_dead_tilde, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ỡ"}, {{XK_dead_tilde, XK_Multi_key, XK_plus, XK_O, XK_VoidSymbol}, "Ỡ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_horn, XK_O, XK_VoidSymbol}, "Ỡ"}, {{XK_Multi_key, XK_asciitilde, XK_plus, XK_O, XK_VoidSymbol}, "Ỡ"}, {{XK_dead_horn, XK_Otilde, XK_VoidSymbol}, "Ỡ"}, {{XK_dead_horn, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ỡ"}, {{XK_dead_caron, XK_t, XK_VoidSymbol}, "ť"}, // U0165 | LATIN SMALL LETTER T WITH CARON {{XK_Multi_key, XK_c, XK_t, XK_VoidSymbol}, "ť"}, {{XK_Multi_key, XK_less, XK_t, XK_VoidSymbol}, "ť"}, {{XK_Multi_key, XK_t, XK_less, XK_VoidSymbol}, "ť"}, {{XK_dead_diaeresis, XK_a, XK_VoidSymbol}, "ä"}, // adiaeresis | LATIN SMALL LETTER A WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_a, XK_VoidSymbol}, "ä"}, {{XK_Multi_key, XK_a, XK_quotedbl, XK_VoidSymbol}, "ä"}, {{XK_Multi_key, XK_diaeresis, XK_a, XK_VoidSymbol}, "ä"}, {{XK_Multi_key, XK_a, XK_diaeresis, XK_VoidSymbol}, "ä"}, {{XK_Multi_key, XK_parenleft, XK_8, XK_parenright, XK_VoidSymbol}, "⑧"}, // U2467 | CIRCLED DIGIT EIGHT {{XK_Multi_key, XK_parenleft, XK_KP_8, XK_parenright, XK_VoidSymbol}, "⑧"}, {{XK_dead_tilde, XK_Greek_upsilon, XK_VoidSymbol}, "ῦ"}, // U1FE6 | GREEK SMALL LETTER UPSILON WITH PERISPOMENI {{XK_Multi_key, XK_asciitilde, XK_Greek_upsilon, XK_VoidSymbol}, "ῦ"}, {{XK_Multi_key, XK_diaeresis, XK_greater, XK_VoidSymbol}, "⍩"}, // U2369 | ¨ > APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS {{XK_Multi_key, XK_greater, XK_diaeresis, XK_VoidSymbol}, "⍩"}, {{XK_Multi_key, XK_parenleft, XK_kana_NO, XK_parenright, XK_VoidSymbol}, "㋨"}, // U32E8 | CIRCLED KATAKANA NO {{XK_Multi_key, XK_numbersign, XK_E, XK_VoidSymbol}, "♫"}, // U266b | BEAMED EIGHTH NOTES {{XK_dead_ogonek, XK_O, XK_VoidSymbol}, "Ǫ"}, // U01EA | LATIN CAPITAL LETTER O WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_O, XK_VoidSymbol}, "Ǫ"}, {{XK_Multi_key, XK_O, XK_semicolon, XK_VoidSymbol}, "Ǫ"}, {{XK_Multi_key, XK_comma, XK_O, XK_VoidSymbol}, "Ǫ"}, {{XK_Multi_key, XK_O, XK_comma, XK_VoidSymbol}, "Ǫ"}, {{XK_dead_diaeresis, XK_Cyrillic_E, XK_VoidSymbol}, "Ӭ"}, // U04EC | CYRILLIC CAPITAL LETTER E WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_E, XK_VoidSymbol}, "Ӭ"}, {{XK_dead_circumflex, XK_equal, XK_VoidSymbol}, "⁼"}, // U207C | SUPERSCRIPT EQUALS SIGN {{XK_Multi_key, XK_asciicircum, XK_equal, XK_VoidSymbol}, "⁼"}, {{XK_dead_circumflex, XK_KP_Equal, XK_VoidSymbol}, "⁼"}, {{XK_Multi_key, XK_asciicircum, XK_KP_Equal, XK_VoidSymbol}, "⁼"}, {{XK_Multi_key, XK_o, XK_c, XK_VoidSymbol}, "©"}, // copyright | COPYRIGHT SIGN {{XK_Multi_key, XK_o, XK_C, XK_VoidSymbol}, "©"}, {{XK_Multi_key, XK_O, XK_c, XK_VoidSymbol}, "©"}, {{XK_Multi_key, XK_O, XK_C, XK_VoidSymbol}, "©"}, {{XK_Multi_key, XK_C, XK_o, XK_VoidSymbol}, "©"}, {{XK_Multi_key, XK_C, XK_O, XK_VoidSymbol}, "©"}, {{XK_dead_tilde, XK_greater, XK_VoidSymbol}, "≳"}, // U2273 | GREATER-THAN OR EQUIVALENT TO {{XK_Multi_key, XK_parenleft, XK_c, XK_parenright, XK_VoidSymbol}, "ⓒ"}, // U24D2 | CIRCLED LATIN SMALL LETTER C {{XK_dead_circumflex, XK_w, XK_VoidSymbol}, "ŵ"}, // U0175 | LATIN SMALL LETTER W WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_w, XK_VoidSymbol}, "ŵ"}, {{XK_Multi_key, XK_w, XK_asciicircum, XK_VoidSymbol}, "ŵ"}, {{XK_Multi_key, XK_u, XK_b, XK_u, XK_n, XK_t, XK_u, XK_VoidSymbol}, ""}, // UBUNTU CIRCLE {{XK_Multi_key, XK_U, XK_B, XK_U, XK_N, XK_T, XK_U, XK_VoidSymbol}, ""}, {{XK_dead_tilde, XK_Greek_omega, XK_VoidSymbol}, "ῶ"}, // U1FF6 | GREEK SMALL LETTER OMEGA WITH PERISPOMENI {{XK_Multi_key, XK_asciitilde, XK_Greek_omega, XK_VoidSymbol}, "ῶ"}, {{XK_Multi_key, XK_parenleft, XK_kana_RU, XK_parenright, XK_VoidSymbol}, "㋸"}, // U32F8 | CIRCLED KATAKANA RU {{XK_dead_diaeresis, XK_umacron, XK_VoidSymbol}, "ṻ"}, // U1E7B | LATIN SMALL LETTER U WITH MACRON AND DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_umacron, XK_VoidSymbol}, "ṻ"}, {{XK_dead_diaeresis, XK_dead_macron, XK_u, XK_VoidSymbol}, "ṻ"}, {{XK_dead_diaeresis, XK_Multi_key, XK_macron, XK_u, XK_VoidSymbol}, "ṻ"}, {{XK_dead_diaeresis, XK_Multi_key, XK_underscore, XK_u, XK_VoidSymbol}, "ṻ"}, {{XK_Multi_key, XK_quotedbl, XK_dead_macron, XK_u, XK_VoidSymbol}, "ṻ"}, {{XK_Multi_key, XK_quotedbl, XK_macron, XK_u, XK_VoidSymbol}, "ṻ"}, {{XK_Multi_key, XK_quotedbl, XK_underscore, XK_u, XK_VoidSymbol}, "ṻ"}, {{XK_dead_acute, XK_Aring, XK_VoidSymbol}, "Ǻ"}, // U01FA | LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE {{XK_Multi_key, XK_acute, XK_Aring, XK_VoidSymbol}, "Ǻ"}, {{XK_Multi_key, XK_apostrophe, XK_Aring, XK_VoidSymbol}, "Ǻ"}, {{XK_dead_acute, XK_dead_abovering, XK_A, XK_VoidSymbol}, "Ǻ"}, {{XK_dead_acute, XK_Multi_key, XK_o, XK_A, XK_VoidSymbol}, "Ǻ"}, {{XK_Multi_key, XK_acute, XK_dead_abovering, XK_A, XK_VoidSymbol}, "Ǻ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_abovering, XK_A, XK_VoidSymbol}, "Ǻ"}, {{XK_Multi_key, XK_asterisk, XK_apostrophe, XK_A, XK_VoidSymbol}, "Ǻ"}, {{XK_dead_abovering, XK_Aacute, XK_VoidSymbol}, "Ǻ"}, {{XK_dead_abovering, XK_dead_acute, XK_A, XK_VoidSymbol}, "Ǻ"}, {{XK_dead_stroke, XK_p, XK_VoidSymbol}, "ᵽ"}, // U1D7D | LATIN SMALL LETTER P WITH STROKE {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_n, XK_VoidSymbol}, "ⁿ"}, // U207F | SUPERSCRIPT LATIN SMALL LETTER N {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_n, XK_VoidSymbol}, "ⁿ"}, {{XK_dead_grave, XK_w, XK_VoidSymbol}, "ẁ"}, // U1E81 | LATIN SMALL LETTER W WITH GRAVE {{XK_Multi_key, XK_grave, XK_w, XK_VoidSymbol}, "ẁ"}, {{XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ἀ"}, // U1F00 | GREEK SMALL LETTER ALPHA WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ἀ"}, {{XK_dead_belowdot, XK_minus, XK_VoidSymbol}, "⨪"}, // U2A2A | MINUS SIGN WITH DOT BELOW {{XK_Multi_key, XK_underscore, XK_5, XK_VoidSymbol}, "₅"}, // U2085 | SUBSCRIPT FIVE {{XK_Multi_key, XK_underscore, XK_KP_5, XK_VoidSymbol}, "₅"}, {{XK_dead_caron, XK_5, XK_VoidSymbol}, "₅"}, {{XK_dead_ogonek, XK_A, XK_VoidSymbol}, "Ą"}, // U0104 | LATIN CAPITAL LETTER A WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_A, XK_VoidSymbol}, "Ą"}, {{XK_Multi_key, XK_A, XK_semicolon, XK_VoidSymbol}, "Ą"}, {{XK_Multi_key, XK_comma, XK_A, XK_VoidSymbol}, "Ą"}, {{XK_Multi_key, XK_A, XK_comma, XK_VoidSymbol}, "Ą"}, {{XK_dead_belowmacron, XK_B, XK_VoidSymbol}, "Ḇ"}, // U1E06 | LATIN CAPITAL LETTER B WITH LINE BELOW {{XK_dead_stroke, XK_u, XK_VoidSymbol}, "ʉ"}, // U0289 | LATIN SMALL LETTER U BAR {{XK_dead_diaeresis, XK_nobreakspace, XK_VoidSymbol}, "̈"}, // U0308 | COMBINING DIAERESIS {{XK_dead_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾋ"}, // U1F8B | GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾋ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾋ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾋ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾋ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾋ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾋ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾋ"}, {{XK_dead_invertedbreve, XK_O, XK_VoidSymbol}, "Ȏ"}, // U020E | LATIN CAPITAL LETTER O WITH INVERTED BREVE {{XK_dead_circumflex, XK_z, XK_VoidSymbol}, "ẑ"}, // U1E91 | LATIN SMALL LETTER Z WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_z, XK_VoidSymbol}, "ẑ"}, {{XK_dead_psili, XK_Greek_epsilon, XK_VoidSymbol}, "ἐ"}, // U1F10 | GREEK SMALL LETTER EPSILON WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_epsilon, XK_VoidSymbol}, "ἐ"}, {{XK_dead_currency, XK_p, XK_VoidSymbol}, "₰"}, // U20B0 | GERMAN PENNY SIGN {{XK_dead_breve, XK_E, XK_VoidSymbol}, "Ĕ"}, // U0114 | LATIN CAPITAL LETTER E WITH BREVE {{XK_Multi_key, XK_U, XK_E, XK_VoidSymbol}, "Ĕ"}, {{XK_Multi_key, XK_b, XK_E, XK_VoidSymbol}, "Ĕ"}, {{XK_dead_acute, XK_Emacron, XK_VoidSymbol}, "Ḗ"}, // U1E16 | LATIN CAPITAL LETTER E WITH MACRON AND ACUTE {{XK_Multi_key, XK_acute, XK_Emacron, XK_VoidSymbol}, "Ḗ"}, {{XK_Multi_key, XK_apostrophe, XK_Emacron, XK_VoidSymbol}, "Ḗ"}, {{XK_dead_acute, XK_dead_macron, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_dead_acute, XK_Multi_key, XK_macron, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_dead_acute, XK_Multi_key, XK_underscore, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_Multi_key, XK_acute, XK_dead_macron, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_Multi_key, XK_acute, XK_macron, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_Multi_key, XK_acute, XK_underscore, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_Multi_key, XK_apostrophe, XK_dead_macron, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_Multi_key, XK_apostrophe, XK_macron, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_Multi_key, XK_apostrophe, XK_underscore, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_dead_macron, XK_Eacute, XK_VoidSymbol}, "Ḗ"}, {{XK_dead_macron, XK_dead_acute, XK_E, XK_VoidSymbol}, "Ḗ"}, {{XK_dead_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾛ"}, // U1F9B | GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾛ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾛ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾛ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾛ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾛ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "ᾛ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "ᾛ"}, {{XK_Multi_key, XK_comma, XK_apostrophe, XK_VoidSymbol}, "‚"}, // U201a | SINGLE LOW-9 QUOTATION MARK {{XK_Multi_key, XK_apostrophe, XK_comma, XK_VoidSymbol}, "‚"}, {{XK_dead_caron, XK_H, XK_VoidSymbol}, "Ȟ"}, // U021E | LATIN CAPITAL LETTER H WITH CARON {{XK_Multi_key, XK_c, XK_H, XK_VoidSymbol}, "Ȟ"}, {{XK_dead_belowdot, XK_a, XK_VoidSymbol}, "ạ"}, // U1EA1 | LATIN SMALL LETTER A WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_a, XK_VoidSymbol}, "ạ"}, {{XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ἠ"}, // U1F20 | GREEK SMALL LETTER ETA WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ἠ"}, {{XK_dead_semivoiced_sound, XK_kana_HE, XK_VoidSymbol}, "ペ"}, // U30DA | KATAKANA LETTER PE {{XK_Multi_key, XK_Y, XK_equal, XK_VoidSymbol}, "¥"}, // yen | YEN SIGN {{XK_Multi_key, XK_equal, XK_Y, XK_VoidSymbol}, "¥"}, {{XK_Multi_key, XK_y, XK_equal, XK_VoidSymbol}, "¥"}, {{XK_Multi_key, XK_equal, XK_y, XK_VoidSymbol}, "¥"}, {{XK_Multi_key, XK_Y, XK_minus, XK_VoidSymbol}, "¥"}, {{XK_Multi_key, XK_minus, XK_Y, XK_VoidSymbol}, "¥"}, {{XK_Multi_key, XK_y, XK_minus, XK_VoidSymbol}, "¥"}, {{XK_Multi_key, XK_minus, XK_y, XK_VoidSymbol}, "¥"}, {{XK_dead_currency, XK_y, XK_VoidSymbol}, "¥"}, {{XK_dead_circumflex, XK_H, XK_VoidSymbol}, "Ĥ"}, // U0124 | LATIN CAPITAL LETTER H WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_H, XK_VoidSymbol}, "Ĥ"}, {{XK_dead_diaeresis, XK_H, XK_VoidSymbol}, "Ḧ"}, // U1E26 | LATIN CAPITAL LETTER H WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_H, XK_VoidSymbol}, "Ḧ"}, {{XK_dead_ogonek, XK_nobreakspace, XK_VoidSymbol}, "̨"}, // U0328 | COMBINING OGONEK {{XK_dead_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾫ"}, // U1FAB | GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾫ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾫ"}, {{XK_dead_iota, XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾫ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾫ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_grave, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾫ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾫ"}, {{XK_Multi_key, XK_Greek_iota, XK_grave, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "ᾫ"}, {{XK_dead_horn, XK_U, XK_VoidSymbol}, "Ư"}, // U01AF | LATIN CAPITAL LETTER U WITH HORN {{XK_Multi_key, XK_plus, XK_U, XK_VoidSymbol}, "Ư"}, {{XK_dead_abovedot, XK_O, XK_VoidSymbol}, "Ȯ"}, // U022E | LATIN CAPITAL LETTER O WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_O, XK_VoidSymbol}, "Ȯ"}, {{XK_dead_grave, XK_abreve, XK_VoidSymbol}, "ằ"}, // U1EB1 | LATIN SMALL LETTER A WITH BREVE AND GRAVE {{XK_Multi_key, XK_grave, XK_abreve, XK_VoidSymbol}, "ằ"}, {{XK_dead_grave, XK_dead_breve, XK_a, XK_VoidSymbol}, "ằ"}, {{XK_dead_grave, XK_Multi_key, XK_U, XK_a, XK_VoidSymbol}, "ằ"}, {{XK_dead_grave, XK_Multi_key, XK_b, XK_a, XK_VoidSymbol}, "ằ"}, {{XK_Multi_key, XK_grave, XK_dead_breve, XK_a, XK_VoidSymbol}, "ằ"}, {{XK_Multi_key, XK_grave, XK_b, XK_a, XK_VoidSymbol}, "ằ"}, {{XK_dead_breve, XK_agrave, XK_VoidSymbol}, "ằ"}, {{XK_dead_breve, XK_dead_grave, XK_a, XK_VoidSymbol}, "ằ"}, {{XK_dead_psili, XK_Greek_iota, XK_VoidSymbol}, "ἰ"}, // U1F30 | GREEK SMALL LETTER IOTA WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_iota, XK_VoidSymbol}, "ἰ"}, {{XK_Multi_key, XK_m, XK_u, XK_VoidSymbol}, "µ"}, // mu | MICRO SIGN {{XK_Multi_key, XK_slash, XK_u, XK_VoidSymbol}, "µ"}, {{XK_Multi_key, XK_u, XK_slash, XK_VoidSymbol}, "µ"}, {{XK_dead_circumflex, XK_J, XK_VoidSymbol}, "Ĵ"}, // U0134 | LATIN CAPITAL LETTER J WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_J, XK_VoidSymbol}, "Ĵ"}, {{XK_dead_belowdot, XK_L, XK_VoidSymbol}, "Ḷ"}, // U1E36 | LATIN CAPITAL LETTER L WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_L, XK_VoidSymbol}, "Ḷ"}, {{XK_Multi_key, XK_parenleft, XK_4, XK_4, XK_parenright, XK_VoidSymbol}, "㊹"}, // U32B9 | CIRCLED NUMBER FORTY FOUR {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_4, XK_parenright, XK_VoidSymbol}, "㊹"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_4, XK_parenright, XK_VoidSymbol}, "㊹"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_4, XK_parenright, XK_VoidSymbol}, "㊹"}, {{XK_dead_stroke, XK_nobreakspace, XK_VoidSymbol}, "̸"}, // U0338 | COMBINING LONG SOLIDUS OVERLAY {{XK_Multi_key, XK_period, XK_greater, XK_VoidSymbol}, "›"}, // U203a | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK {{XK_Multi_key, XK_parenleft, XK_H, XK_parenright, XK_VoidSymbol}, "Ⓗ"}, // U24BD | CIRCLED LATIN CAPITAL LETTER H {{XK_dead_currency, XK_a, XK_VoidSymbol}, "؋"}, // U060B | AFGHANI SIGN {{XK_dead_voiced_sound, XK_kana_WO, XK_VoidSymbol}, "ヺ"}, // U30FA | KATAKANA LETTER VO {{XK_dead_grave, XK_ecircumflex, XK_VoidSymbol}, "ề"}, // U1EC1 | LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE {{XK_Multi_key, XK_grave, XK_ecircumflex, XK_VoidSymbol}, "ề"}, {{XK_dead_grave, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ề"}, {{XK_dead_grave, XK_Multi_key, XK_asciicircum, XK_e, XK_VoidSymbol}, "ề"}, {{XK_Multi_key, XK_grave, XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ề"}, {{XK_Multi_key, XK_grave, XK_asciicircum, XK_e, XK_VoidSymbol}, "ề"}, {{XK_dead_circumflex, XK_egrave, XK_VoidSymbol}, "ề"}, {{XK_dead_circumflex, XK_dead_grave, XK_e, XK_VoidSymbol}, "ề"}, {{XK_dead_psili, XK_Greek_omicron, XK_VoidSymbol}, "ὀ"}, // U1F40 | GREEK SMALL LETTER OMICRON WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_omicron, XK_VoidSymbol}, "ὀ"}, {{XK_dead_abovering, XK_A, XK_VoidSymbol}, "Å"}, // Aring | LATIN CAPITAL LETTER A WITH RING ABOVE {{XK_Multi_key, XK_o, XK_A, XK_VoidSymbol}, "Å"}, {{XK_Multi_key, XK_asterisk, XK_A, XK_VoidSymbol}, "Å"}, {{XK_Multi_key, XK_A, XK_asterisk, XK_VoidSymbol}, "Å"}, {{XK_Multi_key, XK_A, XK_A, XK_VoidSymbol}, "Å"}, {{XK_dead_acute, XK_n, XK_VoidSymbol}, "ń"}, // U0144 | LATIN SMALL LETTER N WITH ACUTE {{XK_Multi_key, XK_acute, XK_n, XK_VoidSymbol}, "ń"}, {{XK_Multi_key, XK_apostrophe, XK_n, XK_VoidSymbol}, "ń"}, {{XK_Multi_key, XK_n, XK_apostrophe, XK_VoidSymbol}, "ń"}, {{XK_dead_belowdot, XK_N, XK_VoidSymbol}, "Ṇ"}, // U1E46 | LATIN CAPITAL LETTER N WITH DOT BELOW {{XK_Multi_key, XK_exclam, XK_N, XK_VoidSymbol}, "Ṇ"}, {{XK_Multi_key, XK_parenleft, XK_X, XK_parenright, XK_VoidSymbol}, "Ⓧ"}, // U24CD | CIRCLED LATIN CAPITAL LETTER X {{XK_dead_caron, XK_I, XK_VoidSymbol}, "Ǐ"}, // U01CF | LATIN CAPITAL LETTER I WITH CARON {{XK_Multi_key, XK_c, XK_I, XK_VoidSymbol}, "Ǐ"}, {{XK_dead_stroke, XK_Y, XK_VoidSymbol}, "Ɏ"}, // U024E | LATIN CAPITAL LETTER Y WITH STROKE {{XK_dead_acute, XK_ocircumflex, XK_VoidSymbol}, "ố"}, // U1ED1 | LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE {{XK_Multi_key, XK_acute, XK_ocircumflex, XK_VoidSymbol}, "ố"}, {{XK_Multi_key, XK_apostrophe, XK_ocircumflex, XK_VoidSymbol}, "ố"}, {{XK_dead_acute, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ố"}, {{XK_dead_acute, XK_Multi_key, XK_asciicircum, XK_o, XK_VoidSymbol}, "ố"}, {{XK_Multi_key, XK_acute, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ố"}, {{XK_Multi_key, XK_acute, XK_asciicircum, XK_o, XK_VoidSymbol}, "ố"}, {{XK_Multi_key, XK_apostrophe, XK_dead_circumflex, XK_o, XK_VoidSymbol}, "ố"}, {{XK_Multi_key, XK_apostrophe, XK_asciicircum, XK_o, XK_VoidSymbol}, "ố"}, {{XK_dead_circumflex, XK_oacute, XK_VoidSymbol}, "ố"}, {{XK_dead_circumflex, XK_dead_acute, XK_o, XK_VoidSymbol}, "ố"}, {{XK_dead_circumflex, XK_1, XK_VoidSymbol}, "¹"}, // onesuperior | SUPERSCRIPT ONE {{XK_Multi_key, XK_asciicircum, XK_1, XK_VoidSymbol}, "¹"}, {{XK_Multi_key, XK_1, XK_asciicircum, XK_VoidSymbol}, "¹"}, {{XK_dead_circumflex, XK_KP_1, XK_VoidSymbol}, "¹"}, {{XK_Multi_key, XK_asciicircum, XK_KP_1, XK_VoidSymbol}, "¹"}, {{XK_Multi_key, XK_parenleft, XK_s, XK_parenright, XK_VoidSymbol}, "ⓢ"}, // U24E2 | CIRCLED LATIN SMALL LETTER S {{XK_dead_tilde, XK_O, XK_VoidSymbol}, "Õ"}, // Otilde | LATIN CAPITAL LETTER O WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_O, XK_VoidSymbol}, "Õ"}, {{XK_Multi_key, XK_O, XK_asciitilde, XK_VoidSymbol}, "Õ"}, {{XK_dead_acute, XK_R, XK_VoidSymbol}, "Ŕ"}, // U0154 | LATIN CAPITAL LETTER R WITH ACUTE {{XK_Multi_key, XK_acute, XK_R, XK_VoidSymbol}, "Ŕ"}, {{XK_Multi_key, XK_apostrophe, XK_R, XK_VoidSymbol}, "Ŕ"}, {{XK_Multi_key, XK_R, XK_apostrophe, XK_VoidSymbol}, "Ŕ"}, {{XK_dead_abovedot, XK_P, XK_VoidSymbol}, "Ṗ"}, // U1E56 | LATIN CAPITAL LETTER P WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_P, XK_VoidSymbol}, "Ṗ"}, {{XK_Multi_key, XK_P, XK_period, XK_VoidSymbol}, "Ṗ"}, {{XK_dead_abovedot, XK_space, XK_VoidSymbol}, "˙"}, // abovedot | DOT ABOVE {{XK_dead_abovedot, XK_dead_abovedot, XK_VoidSymbol}, "˙"}, {{XK_dead_stroke, XK_a, XK_VoidSymbol}, "ⱥ"}, // U2C65 | LATIN SMALL LETTER A WITH STROKE {{XK_dead_currency, XK_I, XK_VoidSymbol}, "៛"}, // U17DB | KHMER CURRENCY SYMBOL RIEL {{XK_dead_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾎ"}, // U1F8E | GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI {{XK_dead_iota, XK_dead_tilde, XK_Multi_key, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾎ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾎ"}, {{XK_dead_iota, XK_Multi_key, XK_asciitilde, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾎ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾎ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_tilde, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾎ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_dead_psili, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾎ"}, {{XK_Multi_key, XK_Greek_iota, XK_asciitilde, XK_parenright, XK_Greek_ALPHA, XK_VoidSymbol}, "ᾎ"}, {{XK_dead_diaeresis, XK_Cyrillic_zhe, XK_VoidSymbol}, "ӝ"}, // U04DD | CYRILLIC SMALL LETTER ZHE WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_zhe, XK_VoidSymbol}, "ӝ"}, {{XK_dead_acute, XK_J, XK_VoidSymbol}, "J́"}, // LATIN CAPITAL LETTER J U004A with COMBINING ACUTE ACCENT U0301 {{XK_Multi_key, XK_apostrophe, XK_J, XK_VoidSymbol}, "J́"}, {{XK_Multi_key, XK_J, XK_apostrophe, XK_VoidSymbol}, "J́"}, {{XK_Multi_key, XK_acute, XK_J, XK_VoidSymbol}, "J́"}, {{XK_Multi_key, XK_J, XK_acute, XK_VoidSymbol}, "J́"}, {{XK_dead_macron, XK_adiaeresis, XK_VoidSymbol}, "ǟ"}, // U01DF | LATIN SMALL LETTER A WITH DIAERESIS AND MACRON {{XK_Multi_key, XK_macron, XK_adiaeresis, XK_VoidSymbol}, "ǟ"}, {{XK_Multi_key, XK_underscore, XK_adiaeresis, XK_VoidSymbol}, "ǟ"}, {{XK_dead_macron, XK_dead_diaeresis, XK_a, XK_VoidSymbol}, "ǟ"}, {{XK_dead_macron, XK_Multi_key, XK_quotedbl, XK_a, XK_VoidSymbol}, "ǟ"}, {{XK_Multi_key, XK_macron, XK_dead_diaeresis, XK_a, XK_VoidSymbol}, "ǟ"}, {{XK_Multi_key, XK_macron, XK_quotedbl, XK_a, XK_VoidSymbol}, "ǟ"}, {{XK_Multi_key, XK_underscore, XK_dead_diaeresis, XK_a, XK_VoidSymbol}, "ǟ"}, {{XK_Multi_key, XK_underscore, XK_quotedbl, XK_a, XK_VoidSymbol}, "ǟ"}, {{XK_dead_diaeresis, XK_amacron, XK_VoidSymbol}, "ǟ"}, {{XK_dead_diaeresis, XK_dead_macron, XK_a, XK_VoidSymbol}, "ǟ"}, {{XK_Multi_key, XK_parenleft, XK_3, XK_4, XK_parenright, XK_VoidSymbol}, "㉞"}, // U325E | CIRCLED NUMBER THIRTY FOUR {{XK_Multi_key, XK_parenleft, XK_3, XK_KP_4, XK_parenright, XK_VoidSymbol}, "㉞"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_4, XK_parenright, XK_VoidSymbol}, "㉞"}, {{XK_Multi_key, XK_parenleft, XK_KP_3, XK_KP_4, XK_parenright, XK_VoidSymbol}, "㉞"}, {{XK_dead_tilde, XK_ohorn, XK_VoidSymbol}, "ỡ"}, // U1EE1 | LATIN SMALL LETTER O WITH HORN AND TILDE {{XK_Multi_key, XK_asciitilde, XK_ohorn, XK_VoidSymbol}, "ỡ"}, {{XK_dead_tilde, XK_dead_horn, XK_o, XK_VoidSymbol}, "ỡ"}, {{XK_dead_tilde, XK_Multi_key, XK_plus, XK_o, XK_VoidSymbol}, "ỡ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_horn, XK_o, XK_VoidSymbol}, "ỡ"}, {{XK_Multi_key, XK_asciitilde, XK_plus, XK_o, XK_VoidSymbol}, "ỡ"}, {{XK_dead_horn, XK_otilde, XK_VoidSymbol}, "ỡ"}, {{XK_dead_horn, XK_dead_tilde, XK_o, XK_VoidSymbol}, "ỡ"}, {{XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ὠ"}, // U1F60 | GREEK SMALL LETTER OMEGA WITH PSILI {{XK_Multi_key, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ὠ"}, {{XK_dead_grave, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̀"}, // CYRILLIC CAPITAL LETTER ER WITH COMBINING GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̀"}, {{XK_dead_belowmacron, XK_L, XK_VoidSymbol}, "Ḻ"}, // U1E3A | LATIN CAPITAL LETTER L WITH LINE BELOW {{XK_dead_abovering, XK_a, XK_VoidSymbol}, "å"}, // aring | LATIN SMALL LETTER A WITH RING ABOVE {{XK_Multi_key, XK_o, XK_a, XK_VoidSymbol}, "å"}, {{XK_Multi_key, XK_asterisk, XK_a, XK_VoidSymbol}, "å"}, {{XK_Multi_key, XK_a, XK_asterisk, XK_VoidSymbol}, "å"}, {{XK_Multi_key, XK_a, XK_a, XK_VoidSymbol}, "å"}, {{XK_dead_caron, XK_T, XK_VoidSymbol}, "Ť"}, // U0164 | LATIN CAPITAL LETTER T WITH CARON {{XK_Multi_key, XK_c, XK_T, XK_VoidSymbol}, "Ť"}, {{XK_Multi_key, XK_less, XK_T, XK_VoidSymbol}, "Ť"}, {{XK_Multi_key, XK_T, XK_less, XK_VoidSymbol}, "Ť"}, {{XK_dead_macron, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̄"}, // CYRILLIC CAPITAL LETTER ER WITH COMBINING MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̄"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̄"}, {{XK_dead_abovedot, XK_Scaron, XK_VoidSymbol}, "Ṧ"}, // U1E66 | LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE {{XK_Multi_key, XK_period, XK_Scaron, XK_VoidSymbol}, "Ṧ"}, {{XK_dead_abovedot, XK_dead_caron, XK_S, XK_VoidSymbol}, "Ṧ"}, {{XK_dead_abovedot, XK_Multi_key, XK_c, XK_S, XK_VoidSymbol}, "Ṧ"}, {{XK_Multi_key, XK_period, XK_dead_caron, XK_S, XK_VoidSymbol}, "Ṧ"}, {{XK_dead_caron, XK_Sabovedot, XK_VoidSymbol}, "Ṧ"}, {{XK_dead_caron, XK_dead_abovedot, XK_S, XK_VoidSymbol}, "Ṧ"}, {{XK_Multi_key, XK_parenleft, XK_kana_HA, XK_parenright, XK_VoidSymbol}, "㋩"}, // U32E9 | CIRCLED KATAKANA HA {{XK_Multi_key, XK_asciitilde, XK_diaeresis, XK_VoidSymbol}, "⍨"}, // U2368 | ~ ¨ APL FUNCTIONAL SYMBOL TILDE DIAERESIS {{XK_dead_circumflex, XK_Multi_key, XK_T, XK_M, XK_VoidSymbol}, "™"}, // U2122 | TRADE MARK SIGN {{XK_Multi_key, XK_T, XK_M, XK_VoidSymbol}, "™"}, {{XK_dead_circumflex, XK_Multi_key, XK_t, XK_M, XK_VoidSymbol}, "™"}, {{XK_Multi_key, XK_t, XK_M, XK_VoidSymbol}, "™"}, {{XK_dead_circumflex, XK_Multi_key, XK_T, XK_m, XK_VoidSymbol}, "™"}, {{XK_Multi_key, XK_T, XK_m, XK_VoidSymbol}, "™"}, {{XK_dead_circumflex, XK_Multi_key, XK_t, XK_m, XK_VoidSymbol}, "™"}, {{XK_Multi_key, XK_t, XK_m, XK_VoidSymbol}, "™"}, {{XK_Multi_key, XK_parenleft, XK_kana_NU, XK_parenright, XK_VoidSymbol}, "㋦"}, // U32E6 | CIRCLED KATAKANA NU {{XK_dead_diaeresis, XK_Cyrillic_e, XK_VoidSymbol}, "ӭ"}, // U04ED | CYRILLIC SMALL LETTER E WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_e, XK_VoidSymbol}, "ӭ"}, {{XK_dead_doublegrave, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̏"}, // CYRILLIC CAPITAL LETTER ER WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_ER, XK_VoidSymbol}, "Р̏"}, {{XK_dead_stroke, XK_less, XK_VoidSymbol}, "≮"}, // U226E | NOT LESS-THAN {{XK_dead_belowdot, XK_uhorn, XK_VoidSymbol}, "ự"}, // U1EF1 | LATIN SMALL LETTER U WITH HORN AND DOT BELOW {{XK_Multi_key, XK_exclam, XK_uhorn, XK_VoidSymbol}, "ự"}, {{XK_dead_belowdot, XK_dead_horn, XK_u, XK_VoidSymbol}, "ự"}, {{XK_dead_belowdot, XK_Multi_key, XK_plus, XK_u, XK_VoidSymbol}, "ự"}, {{XK_Multi_key, XK_exclam, XK_dead_horn, XK_u, XK_VoidSymbol}, "ự"}, {{XK_Multi_key, XK_exclam, XK_plus, XK_u, XK_VoidSymbol}, "ự"}, {{XK_dead_horn, XK_ubelowdot, XK_VoidSymbol}, "ự"}, {{XK_dead_horn, XK_dead_belowdot, XK_u, XK_VoidSymbol}, "ự"}, {{XK_dead_abovedot, XK_dead_belowdot, XK_s, XK_VoidSymbol}, "ṩ"}, // U1E69 | LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE {{XK_dead_abovedot, XK_Multi_key, XK_exclam, XK_s, XK_VoidSymbol}, "ṩ"}, {{XK_Multi_key, XK_period, XK_dead_belowdot, XK_s, XK_VoidSymbol}, "ṩ"}, {{XK_Multi_key, XK_period, XK_exclam, XK_s, XK_VoidSymbol}, "ṩ"}, {{XK_dead_belowdot, XK_sabovedot, XK_VoidSymbol}, "ṩ"}, {{XK_dead_belowdot, XK_dead_abovedot, XK_s, XK_VoidSymbol}, "ṩ"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_9, XK_parenright, XK_VoidSymbol}, "⑲"}, // U2472 | CIRCLED NUMBER NINETEEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_9, XK_parenright, XK_VoidSymbol}, "⑲"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_9, XK_parenright, XK_VoidSymbol}, "⑲"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_9, XK_parenright, XK_VoidSymbol}, "⑲"}, {{XK_dead_tilde, XK_o, XK_VoidSymbol}, "õ"}, // otilde | LATIN SMALL LETTER O WITH TILDE {{XK_Multi_key, XK_asciitilde, XK_o, XK_VoidSymbol}, "õ"}, {{XK_Multi_key, XK_o, XK_asciitilde, XK_VoidSymbol}, "õ"}, {{XK_dead_circumflex, XK_W, XK_VoidSymbol}, "Ŵ"}, // U0174 | LATIN CAPITAL LETTER W WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_W, XK_VoidSymbol}, "Ŵ"}, {{XK_Multi_key, XK_W, XK_asciicircum, XK_VoidSymbol}, "Ŵ"}, {{XK_dead_belowcircumflex, XK_U, XK_VoidSymbol}, "Ṷ"}, // U1E76 | LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW {{XK_Multi_key, XK_parenleft, XK_kana_RE, XK_parenright, XK_VoidSymbol}, "㋹"}, // U32F9 | CIRCLED KATAKANA RE {{XK_dead_circumflex, XK_plus, XK_VoidSymbol}, "⁺"}, // U207A | SUPERSCRIPT PLUS SIGN {{XK_Multi_key, XK_asciicircum, XK_plus, XK_VoidSymbol}, "⁺"}, {{XK_dead_circumflex, XK_KP_Add, XK_VoidSymbol}, "⁺"}, {{XK_Multi_key, XK_asciicircum, XK_KP_Add, XK_VoidSymbol}, "⁺"}, {{XK_dead_acute, XK_oslash, XK_VoidSymbol}, "ǿ"}, // U01FF | LATIN SMALL LETTER O WITH STROKE AND ACUTE {{XK_Multi_key, XK_acute, XK_oslash, XK_VoidSymbol}, "ǿ"}, {{XK_Multi_key, XK_apostrophe, XK_oslash, XK_VoidSymbol}, "ǿ"}, {{XK_dead_acute, XK_dead_stroke, XK_o, XK_VoidSymbol}, "ǿ"}, {{XK_dead_acute, XK_Multi_key, XK_slash, XK_o, XK_VoidSymbol}, "ǿ"}, {{XK_Multi_key, XK_acute, XK_slash, XK_o, XK_VoidSymbol}, "ǿ"}, {{XK_Multi_key, XK_apostrophe, XK_slash, XK_o, XK_VoidSymbol}, "ǿ"}, {{XK_dead_acute, XK_Multi_key, XK_KP_Divide, XK_o, XK_VoidSymbol}, "ǿ"}, {{XK_Multi_key, XK_acute, XK_KP_Divide, XK_o, XK_VoidSymbol}, "ǿ"}, {{XK_Multi_key, XK_apostrophe, XK_KP_Divide, XK_o, XK_VoidSymbol}, "ǿ"}, {{XK_dead_stroke, XK_dead_acute, XK_o, XK_VoidSymbol}, "ǿ"}, {{XK_dead_stroke, XK_oacute, XK_VoidSymbol}, "ǿ"}, {{XK_dead_belowring, XK_a, XK_VoidSymbol}, "ḁ"}, // U1E01 | LATIN SMALL LETTER A WITH RING BELOW {{XK_dead_iota, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾀ"}, // U1F80 | GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾀ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_psili, XK_Greek_alpha, XK_VoidSymbol}, "ᾀ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenright, XK_Greek_alpha, XK_VoidSymbol}, "ᾀ"}, {{XK_Multi_key, XK_F, XK_i, XK_VoidSymbol}, "ffi"}, // Ufb03 | LATIN SMALL LIGATURE FFI {{XK_dead_abovedot, XK_W, XK_VoidSymbol}, "Ẇ"}, // U1E86 | LATIN CAPITAL LETTER W WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_W, XK_VoidSymbol}, "Ẇ"}, {{XK_dead_doublegrave, XK_i, XK_VoidSymbol}, "ȉ"}, // U0209 | LATIN SMALL LETTER I WITH DOUBLE GRAVE {{XK_dead_acute, XK_Greek_EPSILON, XK_VoidSymbol}, "Έ"}, // U0388 | GREEK CAPITAL LETTER EPSILON WITH TONOS {{XK_Multi_key, XK_acute, XK_Greek_EPSILON, XK_VoidSymbol}, "Έ"}, {{XK_Multi_key, XK_apostrophe, XK_Greek_EPSILON, XK_VoidSymbol}, "Έ"}, {{XK_Multi_key, XK_Greek_EPSILON, XK_apostrophe, XK_VoidSymbol}, "Έ"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἃ"}, // U1F0B | GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἃ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἃ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_ALPHA, XK_VoidSymbol}, "Ἃ"}, {{XK_Multi_key, XK_underscore, XK_plus, XK_VoidSymbol}, "₊"}, // U208A | SUBSCRIPT PLUS SIGN {{XK_Multi_key, XK_underscore, XK_KP_Add, XK_VoidSymbol}, "₊"}, {{XK_dead_caron, XK_plus, XK_VoidSymbol}, "₊"}, {{XK_dead_grave, XK_Cyrillic_I, XK_VoidSymbol}, "Ѝ"}, // U040D | CYRILLIC CAPITAL LETTER I WITH GRAVE {{XK_Multi_key, XK_grave, XK_Cyrillic_I, XK_VoidSymbol}, "Ѝ"}, {{XK_dead_caron, XK_d, XK_VoidSymbol}, "ď"}, // U010F | LATIN SMALL LETTER D WITH CARON {{XK_Multi_key, XK_c, XK_d, XK_VoidSymbol}, "ď"}, {{XK_Multi_key, XK_less, XK_d, XK_VoidSymbol}, "ď"}, {{XK_Multi_key, XK_d, XK_less, XK_VoidSymbol}, "ď"}, {{XK_dead_cedilla, XK_d, XK_VoidSymbol}, "ḑ"}, // U1E11 | LATIN SMALL LETTER D WITH CEDILLA {{XK_Multi_key, XK_comma, XK_d, XK_VoidSymbol}, "ḑ"}, {{XK_Multi_key, XK_d, XK_comma, XK_VoidSymbol}, "ḑ"}, {{XK_Multi_key, XK_cedilla, XK_d, XK_VoidSymbol}, "ḑ"}, {{XK_dead_iota, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾐ"}, // U1F90 | GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾐ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_psili, XK_Greek_eta, XK_VoidSymbol}, "ᾐ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenright, XK_Greek_eta, XK_VoidSymbol}, "ᾐ"}, {{XK_Multi_key, XK_slash, XK_Cyrillic_GHE, XK_VoidSymbol}, "Ғ"}, // U0492 | CYRILLIC CAPITAL LETTER GHE WITH STROKE {{XK_Multi_key, XK_KP_Divide, XK_Cyrillic_GHE, XK_VoidSymbol}, "Ғ"}, {{XK_dead_belowmacron, XK_h, XK_VoidSymbol}, "ẖ"}, // U1E96 | LATIN SMALL LETTER H WITH LINE BELOW {{XK_dead_belowcomma, XK_s, XK_VoidSymbol}, "ș"}, // U0219 | LATIN SMALL LETTER S WITH COMMA BELOW {{XK_Multi_key, XK_semicolon, XK_s, XK_VoidSymbol}, "ș"}, {{XK_Multi_key, XK_s, XK_semicolon, XK_VoidSymbol}, "ș"}, {{XK_dead_acute, XK_Cyrillic_O, XK_VoidSymbol}, "О́"}, // CYRILLIC CAPITAL LETTER O WITH COMBINING ACUTE ACCENT {{XK_Multi_key, XK_acute, XK_Cyrillic_O, XK_VoidSymbol}, "О́"}, {{XK_Multi_key, XK_apostrophe, XK_Cyrillic_O, XK_VoidSymbol}, "О́"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἓ"}, // U1F1B | GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἓ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἓ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_EPSILON, XK_VoidSymbol}, "Ἓ"}, {{XK_dead_breve, XK_g, XK_VoidSymbol}, "ğ"}, // U011F | LATIN SMALL LETTER G WITH BREVE {{XK_Multi_key, XK_U, XK_g, XK_VoidSymbol}, "ğ"}, {{XK_Multi_key, XK_g, XK_U, XK_VoidSymbol}, "ğ"}, {{XK_Multi_key, XK_b, XK_g, XK_VoidSymbol}, "ğ"}, {{XK_Multi_key, XK_breve, XK_g, XK_VoidSymbol}, "ğ"}, {{XK_Multi_key, XK_g, XK_breve, XK_VoidSymbol}, "ğ"}, {{XK_Multi_key, XK_g, XK_parenleft, XK_VoidSymbol}, "ğ"}, {{XK_dead_doublegrave, XK_Cyrillic_I, XK_VoidSymbol}, "И̏"}, // CYRILLIC CAPITAL LETTER I WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_I, XK_VoidSymbol}, "И̏"}, {{XK_dead_macron, XK_g, XK_VoidSymbol}, "ḡ"}, // U1E21 | LATIN SMALL LETTER G WITH MACRON {{XK_Multi_key, XK_macron, XK_g, XK_VoidSymbol}, "ḡ"}, {{XK_Multi_key, XK_underscore, XK_g, XK_VoidSymbol}, "ḡ"}, {{XK_dead_iota, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾠ"}, // U1FA0 | GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI {{XK_dead_iota, XK_Multi_key, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾠ"}, {{XK_Multi_key, XK_Greek_iota, XK_dead_psili, XK_Greek_omega, XK_VoidSymbol}, "ᾠ"}, {{XK_Multi_key, XK_Greek_iota, XK_parenright, XK_Greek_omega, XK_VoidSymbol}, "ᾠ"}, {{XK_dead_belowdot, XK_dead_belowdot, XK_VoidSymbol}, "̣"}, // U0323 | COMBINING DOT BELOW {{XK_dead_belowdot, XK_nobreakspace, XK_VoidSymbol}, "̣"}, {{XK_dead_belowdot, XK_space, XK_VoidSymbol}, "̣"}, {{XK_dead_hook, XK_P, XK_VoidSymbol}, "Ƥ"}, // U01A4 | LATIN CAPITAL LETTER P WITH HOOK {{XK_dead_grave, XK_Acircumflex, XK_VoidSymbol}, "Ầ"}, // U1EA6 | LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE {{XK_Multi_key, XK_grave, XK_Acircumflex, XK_VoidSymbol}, "Ầ"}, {{XK_dead_grave, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ầ"}, {{XK_dead_grave, XK_Multi_key, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ầ"}, {{XK_Multi_key, XK_grave, XK_dead_circumflex, XK_A, XK_VoidSymbol}, "Ầ"}, {{XK_Multi_key, XK_grave, XK_asciicircum, XK_A, XK_VoidSymbol}, "Ầ"}, {{XK_dead_circumflex, XK_Agrave, XK_VoidSymbol}, "Ầ"}, {{XK_dead_circumflex, XK_dead_grave, XK_A, XK_VoidSymbol}, "Ầ"}, {{XK_dead_cedilla, XK_e, XK_VoidSymbol}, "ȩ"}, // U0229 | LATIN SMALL LETTER E WITH CEDILLA {{XK_Multi_key, XK_cedilla, XK_e, XK_VoidSymbol}, "ȩ"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "Ἣ"}, // U1F2B | GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "Ἣ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_ETA, XK_VoidSymbol}, "Ἣ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_ETA, XK_VoidSymbol}, "Ἣ"}, {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_a, XK_VoidSymbol}, "ª"}, // ordfeminine | FEMININE ORDINAL INDICATOR {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_a, XK_VoidSymbol}, "ª"}, {{XK_dead_ogonek, XK_i, XK_VoidSymbol}, "į"}, // U012F | LATIN SMALL LETTER I WITH OGONEK {{XK_Multi_key, XK_semicolon, XK_i, XK_VoidSymbol}, "į"}, {{XK_Multi_key, XK_i, XK_semicolon, XK_VoidSymbol}, "į"}, {{XK_Multi_key, XK_comma, XK_i, XK_VoidSymbol}, "į"}, {{XK_Multi_key, XK_i, XK_comma, XK_VoidSymbol}, "į"}, {{XK_dead_acute, XK_k, XK_VoidSymbol}, "ḱ"}, // U1E31 | LATIN SMALL LETTER K WITH ACUTE {{XK_Multi_key, XK_acute, XK_k, XK_VoidSymbol}, "ḱ"}, {{XK_Multi_key, XK_apostrophe, XK_k, XK_VoidSymbol}, "ḱ"}, {{XK_dead_breve, XK_Greek_alpha, XK_VoidSymbol}, "ᾰ"}, // U1FB0 | GREEK SMALL LETTER ALPHA WITH VRACHY {{XK_Multi_key, XK_U, XK_Greek_alpha, XK_VoidSymbol}, "ᾰ"}, {{XK_Multi_key, XK_b, XK_Greek_alpha, XK_VoidSymbol}, "ᾰ"}, {{XK_dead_voiced_sound, XK_kana_U, XK_VoidSymbol}, "ヴ"}, // U30F4 | KATAKANA LETTER VU {{XK_dead_breve, XK_dead_belowdot, XK_A, XK_VoidSymbol}, "Ặ"}, // U1EB6 | LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW {{XK_dead_breve, XK_Multi_key, XK_exclam, XK_A, XK_VoidSymbol}, "Ặ"}, {{XK_Multi_key, XK_U, XK_dead_belowdot, XK_A, XK_VoidSymbol}, "Ặ"}, {{XK_Multi_key, XK_U, XK_exclam, XK_A, XK_VoidSymbol}, "Ặ"}, {{XK_Multi_key, XK_b, XK_dead_belowdot, XK_A, XK_VoidSymbol}, "Ặ"}, {{XK_Multi_key, XK_b, XK_exclam, XK_A, XK_VoidSymbol}, "Ặ"}, {{XK_dead_belowdot, XK_Abreve, XK_VoidSymbol}, "Ặ"}, {{XK_dead_belowdot, XK_dead_breve, XK_A, XK_VoidSymbol}, "Ặ"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_IOTA, XK_VoidSymbol}, "Ἳ"}, // U1F3B | GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_IOTA, XK_VoidSymbol}, "Ἳ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_IOTA, XK_VoidSymbol}, "Ἳ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_IOTA, XK_VoidSymbol}, "Ἳ"}, {{XK_dead_circumflex, XK_Multi_key, XK_underscore, XK_o, XK_VoidSymbol}, "º"}, // masculine | MASCULINE ORDINAL INDICATOR {{XK_Multi_key, XK_asciicircum, XK_underscore, XK_o, XK_VoidSymbol}, "º"}, {{XK_dead_circumflex, XK_nobreakspace, XK_VoidSymbol}, "̂"}, // U0302 | COMBINING CIRCUMFLEX ACCENT {{XK_dead_acute, XK_j, XK_VoidSymbol}, "j́"}, // LATIN SMALL LETTER J U006A with COMBINING ACUTE ACCENT U0301 {{XK_Multi_key, XK_apostrophe, XK_j, XK_VoidSymbol}, "j́"}, {{XK_Multi_key, XK_j, XK_apostrophe, XK_VoidSymbol}, "j́"}, {{XK_Multi_key, XK_acute, XK_j, XK_VoidSymbol}, "j́"}, {{XK_Multi_key, XK_j, XK_acute, XK_VoidSymbol}, "j́"}, {{XK_dead_abovedot, XK_L, XK_VoidSymbol}, "Ŀ"}, // U013F | LATIN CAPITAL LETTER L WITH MIDDLE DOT {{XK_Multi_key, XK_parenleft, XK_4, XK_9, XK_parenright, XK_VoidSymbol}, "㊾"}, // U32BE | CIRCLED NUMBER FORTY NINE {{XK_Multi_key, XK_parenleft, XK_4, XK_KP_9, XK_parenright, XK_VoidSymbol}, "㊾"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_9, XK_parenright, XK_VoidSymbol}, "㊾"}, {{XK_Multi_key, XK_parenleft, XK_KP_4, XK_KP_9, XK_parenright, XK_VoidSymbol}, "㊾"}, {{XK_dead_abovedot, XK_m, XK_VoidSymbol}, "ṁ"}, // U1E41 | LATIN SMALL LETTER M WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_m, XK_VoidSymbol}, "ṁ"}, {{XK_Multi_key, XK_m, XK_period, XK_VoidSymbol}, "ṁ"}, {{XK_dead_grave, XK_Cyrillic_er, XK_VoidSymbol}, "р̀"}, // CYRILLIC SMALL LETTER ER WITH COMBINING GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_Cyrillic_er, XK_VoidSymbol}, "р̀"}, {{XK_dead_breve, XK_Cyrillic_zhe, XK_VoidSymbol}, "ӂ"}, // U04C2 | CYRILLIC SMALL LETTER ZHE WITH BREVE {{XK_Multi_key, XK_U, XK_Cyrillic_zhe, XK_VoidSymbol}, "ӂ"}, {{XK_Multi_key, XK_b, XK_Cyrillic_zhe, XK_VoidSymbol}, "ӂ"}, {{XK_dead_doublegrave, XK_Cyrillic_O, XK_VoidSymbol}, "О̏"}, // CYRILLIC CAPITAL LETTER O WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_O, XK_VoidSymbol}, "О̏"}, {{XK_dead_macron, XK_Cyrillic_er, XK_VoidSymbol}, "р̄"}, // CYRILLIC SMALL LETTER ER WITH COMBINING MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_er, XK_VoidSymbol}, "р̄"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_er, XK_VoidSymbol}, "р̄"}, {{XK_dead_circumflex, XK_dead_belowdot, XK_E, XK_VoidSymbol}, "Ệ"}, // U1EC6 | LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW {{XK_dead_circumflex, XK_Multi_key, XK_exclam, XK_E, XK_VoidSymbol}, "Ệ"}, {{XK_Multi_key, XK_asciicircum, XK_dead_belowdot, XK_E, XK_VoidSymbol}, "Ệ"}, {{XK_Multi_key, XK_asciicircum, XK_exclam, XK_E, XK_VoidSymbol}, "Ệ"}, {{XK_dead_belowdot, XK_Ecircumflex, XK_VoidSymbol}, "Ệ"}, {{XK_dead_belowdot, XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ệ"}, {{XK_dead_stroke, XK_j, XK_VoidSymbol}, "ɉ"}, // U0249 | LATIN SMALL LETTER J WITH STROKE {{XK_dead_grave, XK_dead_dasia, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὃ"}, // U1F4B | GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὃ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὃ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_OMICRON, XK_VoidSymbol}, "Ὃ"}, {{XK_dead_circumflex, XK_E, XK_VoidSymbol}, "Ê"}, // Ecircumflex | LATIN CAPITAL LETTER E WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_E, XK_VoidSymbol}, "Ê"}, {{XK_Multi_key, XK_E, XK_asciicircum, XK_VoidSymbol}, "Ê"}, {{XK_Multi_key, XK_greater, XK_E, XK_VoidSymbol}, "Ê"}, {{XK_Multi_key, XK_E, XK_greater, XK_VoidSymbol}, "Ê"}, {{XK_dead_doublegrave, XK_Cyrillic_er, XK_VoidSymbol}, "р̏"}, // CYRILLIC SMALL LETTER ER WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_er, XK_VoidSymbol}, "р̏"}, {{XK_dead_breve, XK_o, XK_VoidSymbol}, "ŏ"}, // U014F | LATIN SMALL LETTER O WITH BREVE {{XK_Multi_key, XK_U, XK_o, XK_VoidSymbol}, "ŏ"}, {{XK_Multi_key, XK_b, XK_o, XK_VoidSymbol}, "ŏ"}, {{XK_dead_grave, XK_omacron, XK_VoidSymbol}, "ṑ"}, // U1E51 | LATIN SMALL LETTER O WITH MACRON AND GRAVE {{XK_Multi_key, XK_grave, XK_omacron, XK_VoidSymbol}, "ṑ"}, {{XK_dead_grave, XK_dead_macron, XK_o, XK_VoidSymbol}, "ṑ"}, {{XK_dead_grave, XK_Multi_key, XK_macron, XK_o, XK_VoidSymbol}, "ṑ"}, {{XK_dead_grave, XK_Multi_key, XK_underscore, XK_o, XK_VoidSymbol}, "ṑ"}, {{XK_Multi_key, XK_grave, XK_dead_macron, XK_o, XK_VoidSymbol}, "ṑ"}, {{XK_Multi_key, XK_grave, XK_macron, XK_o, XK_VoidSymbol}, "ṑ"}, {{XK_Multi_key, XK_grave, XK_underscore, XK_o, XK_VoidSymbol}, "ṑ"}, {{XK_dead_macron, XK_ograve, XK_VoidSymbol}, "ṑ"}, {{XK_dead_macron, XK_dead_grave, XK_o, XK_VoidSymbol}, "ṑ"}, {{XK_dead_breve, XK_Greek_iota, XK_VoidSymbol}, "ῐ"}, // U1FD0 | GREEK SMALL LETTER IOTA WITH VRACHY {{XK_Multi_key, XK_U, XK_Greek_iota, XK_VoidSymbol}, "ῐ"}, {{XK_Multi_key, XK_b, XK_Greek_iota, XK_VoidSymbol}, "ῐ"}, {{XK_dead_diaeresis, XK_Cyrillic_A, XK_VoidSymbol}, "Ӓ"}, // U04D2 | CYRILLIC CAPITAL LETTER A WITH DIAERESIS {{XK_Multi_key, XK_quotedbl, XK_Cyrillic_A, XK_VoidSymbol}, "Ӓ"}, {{XK_dead_caron, XK_u, XK_VoidSymbol}, "ǔ"}, // U01D4 | LATIN SMALL LETTER U WITH CARON {{XK_Multi_key, XK_c, XK_u, XK_VoidSymbol}, "ǔ"}, {{XK_dead_tilde, XK_Ocircumflex, XK_VoidSymbol}, "Ỗ"}, // U1ED6 | LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE {{XK_Multi_key, XK_asciitilde, XK_Ocircumflex, XK_VoidSymbol}, "Ỗ"}, {{XK_dead_tilde, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ỗ"}, {{XK_dead_tilde, XK_Multi_key, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ỗ"}, {{XK_Multi_key, XK_asciitilde, XK_dead_circumflex, XK_O, XK_VoidSymbol}, "Ỗ"}, {{XK_Multi_key, XK_asciitilde, XK_asciicircum, XK_O, XK_VoidSymbol}, "Ỗ"}, {{XK_dead_circumflex, XK_Otilde, XK_VoidSymbol}, "Ỗ"}, {{XK_dead_circumflex, XK_dead_tilde, XK_O, XK_VoidSymbol}, "Ỗ"}, {{XK_Multi_key, XK_e, XK_e, XK_VoidSymbol}, "ə"}, // U0259 | LATIN SMALL LETTER SCHWA {{XK_dead_grave, XK_dead_dasia, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὓ"}, // U1F5B | GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὓ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὓ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_UPSILON, XK_VoidSymbol}, "Ὓ"}, {{XK_dead_acute, XK_U, XK_VoidSymbol}, "Ú"}, // Uacute | LATIN CAPITAL LETTER U WITH ACUTE {{XK_Multi_key, XK_acute, XK_U, XK_VoidSymbol}, "Ú"}, {{XK_Multi_key, XK_U, XK_acute, XK_VoidSymbol}, "Ú"}, {{XK_Multi_key, XK_apostrophe, XK_U, XK_VoidSymbol}, "Ú"}, {{XK_Multi_key, XK_U, XK_apostrophe, XK_VoidSymbol}, "Ú"}, {{XK_dead_grave, XK_Cyrillic_i, XK_VoidSymbol}, "ѝ"}, // U045D | CYRILLIC SMALL LETTER I WITH GRAVE {{XK_Multi_key, XK_grave, XK_Cyrillic_i, XK_VoidSymbol}, "ѝ"}, {{XK_dead_cedilla, XK_s, XK_VoidSymbol}, "ş"}, // U015F | LATIN SMALL LETTER S WITH CEDILLA {{XK_Multi_key, XK_comma, XK_s, XK_VoidSymbol}, "ş"}, {{XK_Multi_key, XK_s, XK_comma, XK_VoidSymbol}, "ş"}, {{XK_Multi_key, XK_cedilla, XK_s, XK_VoidSymbol}, "ş"}, {{XK_Multi_key, XK_s, XK_cedilla, XK_VoidSymbol}, "ş"}, {{XK_Multi_key, XK_o, XK_x, XK_VoidSymbol}, "¤"}, // currency | CURRENCY SIGN {{XK_Multi_key, XK_x, XK_o, XK_VoidSymbol}, "¤"}, {{XK_Multi_key, XK_o, XK_X, XK_VoidSymbol}, "¤"}, {{XK_Multi_key, XK_X, XK_o, XK_VoidSymbol}, "¤"}, {{XK_Multi_key, XK_O, XK_X, XK_VoidSymbol}, "¤"}, {{XK_Multi_key, XK_X, XK_O, XK_VoidSymbol}, "¤"}, {{XK_Multi_key, XK_O, XK_x, XK_VoidSymbol}, "¤"}, {{XK_Multi_key, XK_x, XK_O, XK_VoidSymbol}, "¤"}, {{XK_dead_currency, XK_dead_currency, XK_VoidSymbol}, "¤"}, {{XK_dead_currency, XK_nobreakspace, XK_VoidSymbol}, "¤"}, {{XK_dead_currency, XK_space, XK_VoidSymbol}, "¤"}, {{XK_dead_abovedot, XK_s, XK_VoidSymbol}, "ṡ"}, // U1E61 | LATIN SMALL LETTER S WITH DOT ABOVE {{XK_Multi_key, XK_period, XK_s, XK_VoidSymbol}, "ṡ"}, {{XK_Multi_key, XK_s, XK_period, XK_VoidSymbol}, "ṡ"}, {{XK_dead_breve, XK_Greek_upsilon, XK_VoidSymbol}, "ῠ"}, // U1FE0 | GREEK SMALL LETTER UPSILON WITH VRACHY {{XK_Multi_key, XK_U, XK_Greek_upsilon, XK_VoidSymbol}, "ῠ"}, {{XK_Multi_key, XK_b, XK_Greek_upsilon, XK_VoidSymbol}, "ῠ"}, {{XK_Multi_key, XK_asterisk, XK_diaeresis, XK_VoidSymbol}, "⍣"}, // U2363 | * ¨ APL FUNCTIONAL SYMBOL STAR DIAERESIS {{XK_Multi_key, XK_diaeresis, XK_asterisk, XK_VoidSymbol}, "⍣"}, {{XK_dead_macron, XK_Cyrillic_I, XK_VoidSymbol}, "Ӣ"}, // U04E2 | CYRILLIC CAPITAL LETTER I WITH MACRON {{XK_Multi_key, XK_macron, XK_Cyrillic_I, XK_VoidSymbol}, "Ӣ"}, {{XK_Multi_key, XK_underscore, XK_Cyrillic_I, XK_VoidSymbol}, "Ӣ"}, {{XK_dead_stroke, XK_G, XK_VoidSymbol}, "Ǥ"}, // U01E4 | LATIN CAPITAL LETTER G WITH STROKE {{XK_Multi_key, XK_slash, XK_G, XK_VoidSymbol}, "Ǥ"}, {{XK_Multi_key, XK_KP_Divide, XK_G, XK_VoidSymbol}, "Ǥ"}, {{XK_dead_hook, XK_U, XK_VoidSymbol}, "Ủ"}, // U1EE6 | LATIN CAPITAL LETTER U WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_U, XK_VoidSymbol}, "Ủ"}, {{XK_dead_circumflex, XK_parenleft, XK_VoidSymbol}, "⁽"}, // U207D | SUPERSCRIPT LEFT PARENTHESIS {{XK_Multi_key, XK_asciicircum, XK_parenleft, XK_VoidSymbol}, "⁽"}, {{XK_dead_grave, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὣ"}, // U1F6B | GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA {{XK_dead_grave, XK_Multi_key, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὣ"}, {{XK_Multi_key, XK_grave, XK_dead_dasia, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὣ"}, {{XK_Multi_key, XK_grave, XK_parenleft, XK_Greek_OMEGA, XK_VoidSymbol}, "Ὣ"}, {{XK_dead_circumflex, XK_e, XK_VoidSymbol}, "ê"}, // ecircumflex | LATIN SMALL LETTER E WITH CIRCUMFLEX {{XK_Multi_key, XK_asciicircum, XK_e, XK_VoidSymbol}, "ê"}, {{XK_Multi_key, XK_e, XK_asciicircum, XK_VoidSymbol}, "ê"}, {{XK_Multi_key, XK_greater, XK_e, XK_VoidSymbol}, "ê"}, {{XK_Multi_key, XK_e, XK_greater, XK_VoidSymbol}, "ê"}, {{XK_Multi_key, XK_parenleft, XK_1, XK_4, XK_parenright, XK_VoidSymbol}, "⑭"}, // U246D | CIRCLED NUMBER FOURTEEN {{XK_Multi_key, XK_parenleft, XK_1, XK_KP_4, XK_parenright, XK_VoidSymbol}, "⑭"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_4, XK_parenright, XK_VoidSymbol}, "⑭"}, {{XK_Multi_key, XK_parenleft, XK_KP_1, XK_KP_4, XK_parenright, XK_VoidSymbol}, "⑭"}, {{XK_dead_abovering, XK_u, XK_VoidSymbol}, "ů"}, // U016F | LATIN SMALL LETTER U WITH RING ABOVE {{XK_Multi_key, XK_o, XK_u, XK_VoidSymbol}, "ů"}, {{XK_Multi_key, XK_asterisk, XK_u, XK_VoidSymbol}, "ů"}, {{XK_Multi_key, XK_u, XK_asterisk, XK_VoidSymbol}, "ů"}, {{XK_Multi_key, XK_parenleft, XK_kana_MA, XK_parenright, XK_VoidSymbol}, "㋮"}, // U32EE | CIRCLED KATAKANA MA {{XK_dead_belowcircumflex, XK_t, XK_VoidSymbol}, "ṱ"}, // U1E71 | LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW {{XK_dead_doubleacute, XK_Cyrillic_U, XK_VoidSymbol}, "Ӳ"}, // U04F2 | CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE {{XK_Multi_key, XK_equal, XK_Cyrillic_U, XK_VoidSymbol}, "Ӳ"}, {{XK_dead_circumflex, XK_5, XK_VoidSymbol}, "⁵"}, // U2075 | SUPERSCRIPT FIVE {{XK_Multi_key, XK_asciicircum, XK_5, XK_VoidSymbol}, "⁵"}, {{XK_dead_circumflex, XK_KP_5, XK_VoidSymbol}, "⁵"}, {{XK_Multi_key, XK_asciicircum, XK_KP_5, XK_VoidSymbol}, "⁵"}, {{XK_dead_acute, XK_G, XK_VoidSymbol}, "Ǵ"}, // U01F4 | LATIN CAPITAL LETTER G WITH ACUTE {{XK_Multi_key, XK_acute, XK_G, XK_VoidSymbol}, "Ǵ"}, {{XK_Multi_key, XK_apostrophe, XK_G, XK_VoidSymbol}, "Ǵ"}, {{XK_dead_hook, XK_Y, XK_VoidSymbol}, "Ỷ"}, // U1EF6 | LATIN CAPITAL LETTER Y WITH HOOK ABOVE {{XK_Multi_key, XK_question, XK_Y, XK_VoidSymbol}, "Ỷ"}, {{XK_dead_doublegrave, XK_Cyrillic_A, XK_VoidSymbol}, "А̏"}, // CYRILLIC CAPITAL LETTER A WITH COMBINING DOUBLE GRAVE ACCENT {{XK_Multi_key, XK_grave, XK_grave, XK_Cyrillic_A, XK_VoidSymbol}, "А̏"}, {{XK_dead_acute, XK_u, XK_VoidSymbol}, "ú"}, // uacute | LATIN SMALL LETTER U WITH ACUTE {{XK_Multi_key, XK_acute, XK_u, XK_VoidSymbol}, "ú"}, {{XK_Multi_key, XK_u, XK_acute, XK_VoidSymbol}, "ú"}, {{XK_Multi_key, XK_apostrophe, XK_u, XK_VoidSymbol}, "ú"}, {{XK_Multi_key, XK_u, XK_apostrophe, XK_VoidSymbol}, "ú"}, {{XK_dead_currency, XK_i, XK_VoidSymbol}, "﷼"}, // UFDFC | RIAL SIGN {{XK_Multi_key, XK_f, XK_s, XK_VoidSymbol}, "ſ"}, // U017f | LATIN SMALL LETTER LONG S {{XK_Multi_key, XK_f, XK_S, XK_VoidSymbol}, "ſ"}, {{XK_Multi_key, XK_parenleft, XK_kana_WO, XK_parenright, XK_VoidSymbol}, "㋾"}, // U32FE | CIRCLED KATAKANA WO }; } //namespace #endif nux-4.0.8+18.10.20180623/Nux/TextLoader.cpp0000644000000000000000000001744113313373365014141 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Jason Smith */ #include "TextLoader.h" #include "NuxGraphics/CairoGraphics.h" #include #include #include namespace nux { struct TextLoader::Impl { Impl(TextLoader* parent); ~Impl(); void RasterizeText(void* cairo_context, Color color); Size ComputeTextSize(); std::string GetPangoFontName(); TextLoader* parent_; float padding_x_; float padding_y_; }; TextLoader::Impl::Impl(TextLoader* parent) : parent_(parent) , padding_x_(0) , padding_y_(0) { } TextLoader::Impl::~Impl() { } std::string TextLoader::Impl::GetPangoFontName() { std::ostringstream os; os << parent_->font_name() << " " << parent_->font_size(); return std::string(os.str()); } Size TextLoader::Impl::ComputeTextSize() { cairo_surface_t* pango_surface = NULL; cairo_t* cairo_ctx = NULL; PangoLayout* pango_layout = NULL; PangoFontDescription* font_desc = NULL; PangoContext* pango_ctx = NULL; PangoRectangle ink_rect = {0, 0, 0, 0}; PangoRectangle logical_rect = {0, 0, 0, 0}; int dpi = 96; std::string pango_font_name = GetPangoFontName(); // Create Cairo surface. pango_surface = cairo_image_surface_create(CAIRO_FORMAT_A1, 1, 1); // Create Cairo context. cairo_ctx = cairo_create(pango_surface); // Create layout. pango_layout = pango_cairo_create_layout(cairo_ctx); { pango_layout_set_wrap (pango_layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_ellipsize(pango_layout, PANGO_ELLIPSIZE_END); pango_layout_set_markup (pango_layout, parent_->text().c_str(), -1); pango_layout_set_height (pango_layout, -parent_->lines()); // Sets the width to which the lines of the PangoLayout should wrap or ellipsized. The default value is -1: no width set. pango_layout_set_width(pango_layout, parent_->width * PANGO_SCALE); } // Create font description: "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]" font_desc = pango_font_description_from_string(pango_font_name.c_str()); { pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL); pango_layout_set_font_description(pango_layout, font_desc); } // Get Pango context pango_ctx = pango_layout_get_context(pango_layout); // is not ref'ed // Set font options CairoFontOptions font_options; { cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_DEFAULT); cairo_font_options_set_subpixel_order(font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_DEFAULT); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_set_font_options(cairo_ctx, font_options); pango_cairo_context_set_font_options(pango_ctx, font_options); } // use some default DPI-value pango_cairo_context_set_resolution(pango_ctx, dpi); pango_layout_context_changed(pango_layout); pango_layout_get_extents(pango_layout, &ink_rect, &logical_rect); int text_width = std::ceil((float)logical_rect.width / PANGO_SCALE); int text_height = std::ceil((float)logical_rect.height / PANGO_SCALE); padding_x_ = text_width - logical_rect.width / PANGO_SCALE; padding_y_ = text_height - logical_rect.height / PANGO_SCALE; text_width = std::min(text_width, parent_->width()); // clean up pango_font_description_free(font_desc); g_object_unref(pango_layout); cairo_destroy(cairo_ctx); cairo_surface_destroy(pango_surface); return Size(text_width, text_height); } void TextLoader::Impl::RasterizeText(void* cairo_context, Color /* color */) { cairo_t* cairo_ctx = (cairo_t*) cairo_context; PangoLayout* pango_layout = NULL; PangoFontDescription* font_desc = NULL; PangoContext* pango_ctx = NULL; int dpi = 96; // Create layout. pango_layout = pango_cairo_create_layout(cairo_ctx); { pango_layout_set_wrap (pango_layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_ellipsize(pango_layout, PANGO_ELLIPSIZE_END); pango_layout_set_alignment(pango_layout, (PangoAlignment)parent_->alignment()); pango_layout_set_markup (pango_layout, parent_->text().c_str(), -1); pango_layout_set_height (pango_layout, -parent_->lines()); // Sets the width to which the lines of the PangoLayout should wrap or ellipsized. The default value is -1: no width set. pango_layout_set_width(pango_layout, parent_->width * PANGO_SCALE); } // Create font description: "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]" font_desc = pango_font_description_from_string(GetPangoFontName().c_str()); { pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL); pango_layout_set_font_description(pango_layout, font_desc); } // Get Pango context pango_ctx = pango_layout_get_context(pango_layout); // is not ref'ed // Set font options CairoFontOptions font_options; { cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_DEFAULT); cairo_font_options_set_subpixel_order (font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_DEFAULT); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_set_font_options(cairo_ctx, font_options); pango_cairo_context_set_font_options(pango_ctx, font_options); } pango_cairo_context_set_resolution(pango_ctx, dpi); cairo_set_source_rgba(cairo_ctx, 1.0, 1.0, 1.0, 1.0); pango_layout_context_changed(pango_layout); cairo_move_to(cairo_ctx, padding_x_, padding_y_); pango_cairo_show_layout(cairo_ctx, pango_layout); // clean up pango_font_description_free(font_desc); g_object_unref(pango_layout); } TextLoader::TextLoader() : alignment(TextAlignment::ALIGN_CENTER) , font_name("Ubuntu") , font_size(10) , width(-1) , minimum_width(0) , lines(1) , pimpl(new TextLoader::Impl(this)) { } TextLoader::~TextLoader() { delete pimpl; } ObjectPtr TextLoader::CreateTexture() { ObjectPtr result; Size sz = pimpl->ComputeTextSize(); if (sz.width == 0 || sz.height == 0) return result; CairoGraphics* cairo_graphics = new CairoGraphics(CAIRO_FORMAT_ARGB32, std::max(sz.width, minimum_width()), sz.height); cairo_t* cairo_ctx = cairo_graphics->GetContext(); cairo_set_operator(cairo_ctx, CAIRO_OPERATOR_CLEAR); cairo_paint(cairo_ctx); cairo_set_operator(cairo_ctx, CAIRO_OPERATOR_OVER); pimpl->RasterizeText(cairo_ctx, color); NBitmapData* bitmap = cairo_graphics->GetBitmap(); // NTexture2D is the high level representation of an image that is backed by // an actual opengl texture. BaseTexture* rasterized_text_texture = NULL; rasterized_text_texture = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); rasterized_text_texture->Update(bitmap); result = rasterized_text_texture; rasterized_text_texture->UnReference(); // get rid of our ref so the owner is the only one who gets it rasterized_text_texture = NULL; delete bitmap; cairo_destroy(cairo_ctx); delete cairo_graphics; cairo_graphics = NULL; return result; } } nux-4.0.8+18.10.20180623/Nux/TextLoader.h0000644000000000000000000000245313313373365013603 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright (C) 2012 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Jason Smith */ #ifndef NUX_TEXTLOADER_H #define NUX_TEXTLOADER_H #include // FIXME namespace nux { class TextLoader { public: enum TextAlignment { ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, }; TextLoader(); ~TextLoader(); Property alignment; Property color; Property font_name; Property text; Property font_size; Property width; Property minimum_width; Property lines; ObjectPtr CreateTexture(); private: struct Impl; Impl* pimpl; }; } #endifnux-4.0.8+18.10.20180623/Nux/TextureArea.cpp0000644000000000000000000001232413313373365014312 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "TextureArea.h" #include "NuxGraphics/ImageSurface.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(TextureArea); TextureArea::TextureArea(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { mouse_down.connect(sigc::mem_fun(this, &TextureArea::RecvMouseDown)); mouse_up.connect(sigc::mem_fun(this, &TextureArea::RecvMouseUp)); mouse_enter.connect(sigc::mem_fun(this, &TextureArea::RecvMouseEnter)); mouse_leave.connect(sigc::mem_fun(this, &TextureArea::RecvMouseLeave)); mouse_click.connect(sigc::mem_fun(this, &TextureArea::RecvMouseClick)); mouse_drag.connect(sigc::mem_fun(this, &TextureArea::RecvMouseDrag)); paint_layer_ = new ColorLayer(nux::color::Black); rotation_2d_.Identity(); } TextureArea::~TextureArea() { if (paint_layer_) delete paint_layer_; } void TextureArea::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { // Ability to rotate the widget around its center graphics_engine.PushModelViewMatrix(Matrix4::TRANSLATE(-GetBaseX() - GetBaseWidth() / 2, -GetBaseY() - GetBaseHeight() / 2, 0)); graphics_engine.PushModelViewMatrix(Get2DRotation()); graphics_engine.PushModelViewMatrix(Matrix4::TRANSLATE(GetBaseX() + GetBaseWidth() / 2, GetBaseY() + GetBaseHeight() / 2, 0)); // The TextureArea should not render the accumulated background. That is left to the caller. // GetPainter().PaintBackground(graphics_engine, GetGeometry()); if (paint_layer_) { paint_layer_->SetGeometry(GetGeometry()); GetPainter().RenderSinglePaintLayer(graphics_engine, GetGeometry(), paint_layer_); } graphics_engine.PopModelViewMatrix(); graphics_engine.PopModelViewMatrix(); graphics_engine.PopModelViewMatrix(); } void TextureArea::DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void TextureArea::SetTexture(BaseTexture *texture) { NUX_RETURN_IF_NULL(texture); delete paint_layer_; TexCoordXForm texxform; texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD); texxform.SetWrap(TEXWRAP_REPEAT, TEXWRAP_REPEAT); paint_layer_ = new TextureLayer(texture->GetDeviceTexture(), texxform, color::White); QueueDraw(); } void TextureArea::SetColor(const Color &color) { delete paint_layer_; paint_layer_ = new ColorLayer(color); QueueDraw(); } void TextureArea::LoadImageFile(const std::string &filename) { if (paint_layer_) { delete paint_layer_; paint_layer_ = NULL; } BaseTexture *texture = LoadTextureFromFile(filename); if (texture) { TexCoordXForm texxform; ROPConfig rop; rop.Blend = true; rop.SrcBlend = GL_SRC_ALPHA; rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; paint_layer_ = new TextureLayer(texture->GetDeviceTexture(), texxform, color::White, true, rop); texture->UnReference(); } else { paint_layer_ = new ColorLayer(nux::color::Black); } } void TextureArea::SetPaintLayer(AbstractPaintLayer *layer) { NUX_SAFE_DELETE(paint_layer_); paint_layer_ = layer->Clone(); QueueDraw(); } AbstractPaintLayer* TextureArea::GetPaintLayer() const { if (paint_layer_ == NULL) return NULL; return paint_layer_->Clone(); } // void TextureArea::SetTexture(const char* TextureFilename) // { // // Who should delete the texture? This class or the user? // m_UserTexture = CreateTextureFromFile(TextureFilename); // QueueDraw(); // } void TextureArea::RecvMouseDown(int x, int y, long /* button_flags */, long /* key_flags */) { sigMouseDown.emit(x, y); QueueDraw(); } void TextureArea::RecvMouseClick(int /* x */, int /* y */, long /* button_flags */, long /* key_flags */) { } void TextureArea::RecvMouseUp(int /* x */, int /* y */, long /* button_flags */, long /* key_flags */) { QueueDraw(); } void TextureArea::RecvMouseEnter(int /* x */, int /* y */, long /* button_flags */, long /* key_flags */) { } void TextureArea::RecvMouseLeave(int /* x */, int /* y */, long /* button_flags */, long /* key_flags */) { } void TextureArea::RecvMouseDrag(int x, int y, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { sigMouseDrag.emit(x, y); } void TextureArea::Set2DRotation(float angle) { rotation_2d_.Rotate_z(angle); QueueDraw(); } Matrix4 TextureArea::Get2DRotation() const { return rotation_2d_; } } nux-4.0.8+18.10.20180623/Nux/TextureArea.h0000644000000000000000000000735213313373365013764 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef TEXTUREAREA_H #define TEXTUREAREA_H #include "NuxGraphics/GraphicsEngine.h" namespace nux { //! Represent a rectangular area painted with a color or a texture layer. /*! By default TextureArea contains a ColorLayer with the color set to Black. */ class TextureArea: public View { NUX_DECLARE_OBJECT_TYPE(TextureArea, View); public: TextureArea(NUX_FILE_LINE_PROTO); virtual ~TextureArea(); /*! Use the provided BaseTexture to create a TextureLayer. The current layer is destroyed. If the \a texture argument is invalid the function returns without changing this object. @param texture Pointer to a BaseTexture class. */ void SetTexture(BaseTexture *texture); /*! Use the provided \a color argument to create a ColorLayer. The current layer is destroyed. @param texture Pointer to a BaseTexture class. */ void SetColor(const Color &color); /*! Set the paint layer of this area. The layer argument to this function is cloned. \sa AbstractPaintLayer, ColorLayer, ShapeLayer, SliceScaledTextureLayer, TextureLayer; @param layer A pointer to a concrete class that inherit from AbstractPaintLayer. */ void SetPaintLayer(AbstractPaintLayer *layer); void LoadImageFile(const std::string &filename); /*! Get a copy of the paint layer of this area. The layer must be destroyed with delete when it is no longer needed. \sa AbstractPaintLayer, ColorLayer, ShapeLayer, SliceScaledTextureLayer, TextureLayer; @return A copy of the layer inside this object. */ AbstractPaintLayer* GetPaintLayer() const; //! Convenience function to set a 2D rotation when rendering the area. /*! The rotation is only used for rendering. It should not be used for something else. */ void Set2DRotation(float angle); Matrix4 Get2DRotation() const; sigc::signal sigMouseDown; //!< Signal emmitted when a mouse button is pressed over this area. sigc::signal sigMouseDrag; //!< Signal emmitted when the mouse is dragged over this area. protected: virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); void RecvMouseDown(int x, int y, long button_flags, long key_flags); void RecvMouseUp(int x, int y, long button_flags, long key_flags); void RecvMouseEnter(int x, int y, long button_flags, long key_flags); void RecvMouseLeave(int x, int y, long button_flags, long key_flags); void RecvMouseClick(int x, int y, long button_flags, long key_flags); void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); private: AbstractPaintLayer *paint_layer_; Matrix4 rotation_2d_; //!< 2D rotation matrix for this area. Used for rendering only. }; typedef TextureArea Image; } #endif // TEXTUREAREA_H nux-4.0.8+18.10.20180623/Nux/Theme.cpp0000644000000000000000000002563613313373365013135 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Theme.h" #if defined(NUX_OS_WINDOWS) #include "tinyxml/tinyxml.h" #endif namespace nux { #define INT_TO_ENUM_ELEMENT(a) {a, #a} // --->>> {a, "a"} typedef struct { UXStyleImageRef value; const char *style; } UXStyle; UXStyle UXStyleArray [] = { INT_TO_ENUM_ELEMENT(eIMAGE_STYLE_NONE), INT_TO_ENUM_ELEMENT(eSTROKE_CORNER_SQUARE), INT_TO_ENUM_ELEMENT(eSTROKE_CORNER_ROUND1), INT_TO_ENUM_ELEMENT(eSTROKE_CORNER_ROUND2), INT_TO_ENUM_ELEMENT(eSTROKE_CORNER_ROUND4), INT_TO_ENUM_ELEMENT(eSTROKE_CORNER_ROUND10), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_ROUND1), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_ROUND2), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_ROUND4), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_ROUND5), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_ROUND6), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_ROUND10), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_ROUND10_SHADOW), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_ROUND4_SHADOW), INT_TO_ENUM_ELEMENT(eSHAPE_CORNER_SHADOW), INT_TO_ENUM_ELEMENT(eTRIANGLE_UP), INT_TO_ENUM_ELEMENT(eTRIANGLE_DOWN), INT_TO_ENUM_ELEMENT(eTRIANGLE_LEFT), INT_TO_ENUM_ELEMENT(eTRIANGLE_RIGHT), INT_TO_ENUM_ELEMENT(eWINDOW_SIZEGRIP), INT_TO_ENUM_ELEMENT(eSHAPE_CHECK_MARK), INT_TO_ENUM_ELEMENT(eSHAPE_CHECK_BOX), INT_TO_ENUM_ELEMENT(eCHECKBOX_NORMAL_ON), INT_TO_ENUM_ELEMENT(eCHECKBOX_NORMAL_OFF), INT_TO_ENUM_ELEMENT(eCHECKBOX_FOCUS_ON), INT_TO_ENUM_ELEMENT(eCHECKBOX_FOCUS_OFF), INT_TO_ENUM_ELEMENT(eCHECKBOX_PRELIGHT_ON), INT_TO_ENUM_ELEMENT(eCHECKBOX_PRELIGHT_OFF), INT_TO_ENUM_ELEMENT(eRADIO_NORMAL_ON), INT_TO_ENUM_ELEMENT(eRADIO_NORMAL_OFF), INT_TO_ENUM_ELEMENT(eRADIO_FOCUS_ON), INT_TO_ENUM_ELEMENT(eRADIO_FOCUS_OFF), INT_TO_ENUM_ELEMENT(eRADIO_PRELIGHT_ON), INT_TO_ENUM_ELEMENT(eRADIO_PRELIGHT_OFF), INT_TO_ENUM_ELEMENT(eBUTTON_NORMAL), INT_TO_ENUM_ELEMENT(eBUTTON_FOCUS), INT_TO_ENUM_ELEMENT(eBUTTON_PRELIGHT), INT_TO_ENUM_ELEMENT(eSPINNERUP), INT_TO_ENUM_ELEMENT(eSPINNERDOWN), INT_TO_ENUM_ELEMENT(eCOMBOBOX_OPEN_BUTTON), INT_TO_ENUM_ELEMENT(eTAB_LEFT), INT_TO_ENUM_ELEMENT(eTAB_RIGHT), INT_TO_ENUM_ELEMENT(eSPINER_UP), INT_TO_ENUM_ELEMENT(eSPINER_DOWN), INT_TO_ENUM_ELEMENT(eTREE_NODE_OPEN), INT_TO_ENUM_ELEMENT(eTREE_NODE_CLOSE), INT_TO_ENUM_ELEMENT(eSCROLLBAR_TRIANGLE_UP), INT_TO_ENUM_ELEMENT(eSCROLLBAR_TRIANGLE_DOWN), INT_TO_ENUM_ELEMENT(eSCROLLBAR_TRIANGLE_LEFT), INT_TO_ENUM_ELEMENT(eSCROLLBAR_TRIANGLE_RIGHT), INT_TO_ENUM_ELEMENT(eVALUATORVERTICALMOVE), INT_TO_ENUM_ELEMENT(eVALUATORHORIZONTALMOVE), INT_TO_ENUM_ELEMENT(eVALUATORMOVE), INT_TO_ENUM_ELEMENT(eVECTORXLABEL), INT_TO_ENUM_ELEMENT(eVECTORYLABEL), INT_TO_ENUM_ELEMENT(eVECTORZLABEL), INT_TO_ENUM_ELEMENT(eVECTORWLABEL), INT_TO_ENUM_ELEMENT(eHSCROLLBAR), INT_TO_ENUM_ELEMENT(eVSCROLLBAR), INT_TO_ENUM_ELEMENT(eMATRIX3PREVIEW), INT_TO_ENUM_ELEMENT(eMATRIX4PREVIEW), INT_TO_ENUM_ELEMENT(eDOT6x6), INT_TO_ENUM_ELEMENT(eGraphIcon), INT_TO_ENUM_ELEMENT(eGraphBarIcon), INT_TO_ENUM_ELEMENT(eWindowCloseButton), {eIMAGE_STYLE_NONE, 0} }; static UXStyleImageRef GetStyleImageRef(const char *style_name) { int i = 0; while (UXStyleArray[i].style != 0) { if (strcmp(UXStyleArray[i].style, style_name) == 0) { return UXStyleArray[i].value; } i++; } return eIMAGE_STYLE_NONE; } UXTheme::UXTheme() { LoadPainterImages(); } UXTheme::~UXTheme() { std::list::iterator it; for (it = painter_image_list_.begin(); it != painter_image_list_.end(); it++) { if ((*it)->texture) { (*it)->texture->UnReference(); } delete(*it); } painter_image_list_.clear(); } #if defined(NUX_OS_LINUX) void UXTheme::ParseStartImage(GMarkupParseContext* /* context */, const gchar* element_name, const gchar** attribute_names, const gchar** attribute_values, gpointer user_data, GError** /* error */) { if (strcmp(element_name, "Image") != 0) { return; } const gchar** name_cursor = attribute_names; const gchar** value_cursor = attribute_values; UXTheme* theme = static_cast(user_data); PainterImage* pimage = new PainterImage; while (*name_cursor) { if (strcmp(*name_cursor, "style") == 0) { pimage->style = GetStyleImageRef(*value_cursor); } if (strcmp(*name_cursor, "border_left") == 0) { pimage->border_left = CharToInteger(*value_cursor); } if (strcmp(*name_cursor, "border_right") == 0) { pimage->border_right = CharToInteger(*value_cursor); } if (strcmp(*name_cursor, "border_top") == 0) { pimage->border_top = CharToInteger(*value_cursor); } if (strcmp(*name_cursor, "border_bottom") == 0) { pimage->border_bottom = CharToInteger(*value_cursor); } if (strcmp(*name_cursor, "Name") == 0) { BaseTexture* device_texture; std::string texture_filename = NUX_FIND_RESOURCE_LOCATION_NOFAIL(*value_cursor); device_texture = theme->Load2DTextureFile(texture_filename.c_str()); pimage->texture = device_texture; } name_cursor++; value_cursor++; } theme->painter_image_list_.push_back(pimage); } void UXTheme::ParseEndImage(GMarkupParseContext* /* context */, const gchar* /* element_name */, gpointer /* user_data */, GError** /* error */) { } #endif void UXTheme::LoadPainterImages() { std::string file_search = "Painter.xml"; std::string painter_filename = NUX_FIND_RESOURCE_LOCATION_NOFAIL(file_search.c_str()); if (painter_filename == "") { nuxCriticalMsg("[GraphicsEngine::LoadPainterImages] Can't find Painter.xml file."); return; } #if defined(NUX_OS_LINUX) /* The list of what handler does what. */ GMarkupParser parser = { UXTheme::ParseStartImage, UXTheme::ParseEndImage, NULL, NULL, NULL }; GMarkupParseContext* context = g_markup_parse_context_new ( &parser, G_MARKUP_TREAT_CDATA_AS_TEXT, this, NULL); std::string str; LoadFileToString(str, painter_filename.c_str()); if (g_markup_parse_context_parse(context, str.c_str(), str.length(), NULL) == FALSE) { nuxCriticalMsg("[GraphicsEngine::LoadPainterImages] Failed to parse data."); return; } #else TiXmlDocument doc(painter_filename.c_str()); doc.LoadFile(); TiXmlHandle docHandle( &doc ); TiXmlElement *data = docHandle.FirstChild(TCHARToUTF8("PaintData")).Element(); TiXmlElement *image = 0; for (image = data->FirstChildElement(TCHARToUTF8("Image")); image; image = image->NextSiblingElement(TCHARToUTF8("Image"))) { PainterImage* pimage = new PainterImage; Memset(pimage, 0, sizeof(PainterImage)); std::string style = image->Attribute(TCHARToUTF8("style")); pimage->style = GetStyleImageRef(style.c_str()); // If the attributes border_left, border_right, border_top, border_bottom are not present, assume they are equal to 0; pimage->border_left = pimage->border_right = pimage->border_top = pimage->border_bottom = 0; image->Attribute(TCHARToUTF8("border_left"), &pimage->border_left); image->Attribute(TCHARToUTF8("border_right"), &pimage->border_right); image->Attribute(TCHARToUTF8("border_top"), &pimage->border_top); image->Attribute(TCHARToUTF8("border_bottom"), &pimage->border_bottom); const char *draw_borders_only = image->Attribute(TCHARToUTF8("border_only")); if (draw_borders_only == 0) { pimage->draw_borders_only = true; } else { if (strcmp(TCHARToUTF8("false"), draw_borders_only) == 0) { pimage->draw_borders_only = false; } else { pimage->draw_borders_only = true; } } if (1) { std::string filename = image->Attribute(TCHARToUTF8("Name")); std::string texture_filename = NUX_FIND_RESOURCE_LOCATION_NOFAIL(filename.c_str()); pimage->texture = 0; pimage->filename = texture_filename; } else { std::string filename = image->Attribute(TCHARToUTF8("Name")); std::string texture_filename = NUX_FIND_RESOURCE_LOCATION_NOFAIL(filename.c_str()); pimage->texture = Load2DTextureFile(texture_filename.c_str()); } painter_image_list_.push_back(pimage); } #endif } const PainterImage *UXTheme::GetImage(UXStyleImageRef style) { std::list::iterator it; for (it = painter_image_list_.begin(); it != painter_image_list_.end(); it++) { if (!(*it)->texture) { BaseTexture* device_texture = Load2DTextureFile((*it)->filename.c_str()); (*it)->texture = device_texture; } if ((*it)->style == style) { return (*it); } } return 0; } Rect UXTheme::GetImageGeometry(UXStyleImageRef style) { std::list::iterator it; for (it = painter_image_list_.begin(); it != painter_image_list_.end(); it++) { if (!(*it)->texture) { BaseTexture* device_texture = Load2DTextureFile((*it)->filename.c_str()); (*it)->texture = device_texture; } if ((*it)->style == style) { unsigned int width = (*it)->texture->GetWidth(); unsigned int height = (*it)->texture->GetHeight(); return Rect(0, 0, width, height); } } nuxDebugMsg("[GraphicsEngine::GetImageGeometry] Cannot find UXStyleImageRef"); return Rect(0, 0, 0, 0); } BaseTexture *UXTheme::Load2DTextureFile(const char *filename) { BaseTexture* texture2D = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); NBitmapData *BitmapData = LoadImageFile(filename); if (BitmapData) { texture2D->Update(BitmapData); delete BitmapData; } return texture2D; } BaseTexture *UXTheme::Load2DTextureFileGenerateAlpha(const char * /* filename */, int /* red */, int /* green */, int /* blue */) { return 0; } } nux-4.0.8+18.10.20180623/Nux/Theme.h0000644000000000000000000000727713313373365012603 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef UXTHEME_H #define UXTHEME_H namespace nux { enum UXStyleImageRef { eIMAGE_STYLE_NONE = 0, eSTROKE_CORNER_SQUARE, eSTROKE_CORNER_ROUND1, eSTROKE_CORNER_ROUND2, eSTROKE_CORNER_ROUND4, eSTROKE_CORNER_ROUND10, eSHAPE_CORNER_SQUARE, eSHAPE_CORNER_ROUND1, eSHAPE_CORNER_ROUND2, eSHAPE_CORNER_ROUND4, eSHAPE_CORNER_ROUND5, eSHAPE_CORNER_ROUND6, eSHAPE_CORNER_ROUND10, eSHAPE_CORNER_ROUND10_SHADOW, eSHAPE_CORNER_ROUND4_SHADOW, eSHAPE_CORNER_SHADOW, eTRIANGLE_UP, eTRIANGLE_DOWN, eTRIANGLE_LEFT, eTRIANGLE_RIGHT, eWINDOW_SIZEGRIP, eSHAPE_CHECK_MARK, eSHAPE_CHECK_BOX_FOCUS, eSHAPE_CHECK_BOX_PRELIGHT, eSHAPE_CHECK_BOX, eCHECKBOX_NORMAL_ON, eCHECKBOX_NORMAL_OFF, eCHECKBOX_FOCUS_ON, eCHECKBOX_FOCUS_OFF, eCHECKBOX_PRELIGHT_ON, eCHECKBOX_PRELIGHT_OFF, eRADIO_NORMAL_ON, eRADIO_NORMAL_OFF, eRADIO_FOCUS_ON, eRADIO_FOCUS_OFF, eRADIO_PRELIGHT_ON, eRADIO_PRELIGHT_OFF, eBUTTON_NORMAL, eBUTTON_FOCUS, eBUTTON_PRELIGHT, eSPINNERUP, eSPINNERDOWN, eCOMBOBOX_OPEN_BUTTON, eTAB_LEFT, eTAB_RIGHT, eSPINER_UP, eSPINER_DOWN, eTREE_NODE_OPEN, eTREE_NODE_CLOSE, eSCROLLBAR_TRIANGLE_UP, eSCROLLBAR_TRIANGLE_DOWN, eSCROLLBAR_TRIANGLE_LEFT, eSCROLLBAR_TRIANGLE_RIGHT, eVECTORXLABEL, eVECTORYLABEL, eVECTORZLABEL, eVECTORWLABEL, eVALUATORVERTICALMOVE, eVALUATORHORIZONTALMOVE, eVALUATORMOVE, eHSCROLLBAR, eVSCROLLBAR, eMATRIX3PREVIEW, eMATRIX4PREVIEW, eDOT6x6, eGraphIcon, eGraphBarIcon, eWindowCloseButton, }; struct PainterImage { BaseTexture* texture; UXStyleImageRef style; int border_left; int border_right; int border_top; int border_bottom; bool draw_borders_only; std::string filename; PainterImage() { texture = NULL; } }; //! Load textures and other data for user interface rendering. /*! Load textures and other data for user interface rendering. */ class UXTheme { public: UXTheme(); ~UXTheme(); const PainterImage *GetImage(UXStyleImageRef style); Rect GetImageGeometry(UXStyleImageRef style); private: #if defined(NUX_OS_LINUX) static void ParseStartImage(GMarkupParseContext* context, const gchar* element_name, const gchar** attribute_names, const gchar** attribute_values, gpointer user_data, GError** error); static void ParseEndImage(GMarkupParseContext* context, const gchar* element_name, gpointer user_data, GError** error); #endif void LoadPainterImages(); BaseTexture* Load2DTextureFile(const char* filename); BaseTexture* Load2DTextureFileGenerateAlpha(const char* filename, int red, int green, int blue); std::list painter_image_list_; }; } #endif // UXTHEME_H nux-4.0.8+18.10.20180623/Nux/Timeline.cpp0000644000000000000000000000421513313373365013627 0ustar /* * Copyright 2010 Inalogic Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by Gordon Allott * */ #include "Nux.h" #include "Timeline.h" namespace nux { Timeline::Timeline(unsigned int msecs, const char * /* Caption */, NUX_FILE_LINE_DECL) : Object(true, NUX_FILE_LINE_PARAM) { Looping = false; IsPlaying = false; Duration = msecs; Rewind(); SinkReference(); // get rid of our floating reference nux::GetWindowThread()->AddTimeline(this); } Timeline::~Timeline() { } void Timeline::Stop() { Pause(); Rewind(); } void Timeline::Start() { IsPlaying = true; Started.emit(); } void Timeline::Pause() { IsPlaying = false; Paused.emit(); } void Timeline::Rewind() { _ElapsedTime = 0; } double Timeline::GetProgress() { return (float)_ElapsedTime / Duration; } double Timeline::GetEasing() { // no easing for the base class return GetProgress(); } void Timeline::DoTick(unsigned long msecs) { if (msecs < 1) return; _ElapsedTime += msecs; if (Looping) _ElapsedTime %= Duration; unsigned long remainder = 0; if (_ElapsedTime > Duration) { remainder = _ElapsedTime - Duration; _ElapsedTime = Duration; } NewFrame.emit(msecs); if (remainder > 0) { nux::GetWindowThread()->RemoveTimeline(this); IsPlaying = false; Completed.emit(); UnReference(); } } } nux-4.0.8+18.10.20180623/Nux/Timeline.h0000644000000000000000000000711513313373365013276 0ustar /* * Copyright (C) 2010 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License * version 3.0 as published by the Free Software Foundation. * * 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 version 3.0 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . * * Authored by Gordon Allott */ #ifndef TIMELINE_H #define TIMELINE_H namespace nux { class Timeline : public Object { public: Timeline(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL); ~Timeline(); void Stop(); void Start(); void Pause(); void Rewind(); double GetProgress(); //ranges from 0.0 -> 1.0 virtual double GetEasing(); // override to provide easing values void DoTick(unsigned long msecs); // If you use this, you make baby kittens cry bool Looping; unsigned long Duration; bool IsPlaying; sigc::signal NewFrame; sigc::signal Completed; sigc::signal Started; sigc::signal Paused; protected: unsigned long _ElapsedTime; }; // template // class PropertyAnimationContainer // { // }; // class AnimatedPropertyBase // { // public: // AnimatedPropertyBase(){}; // virtual void Animate(float t){}; // }; // // Explicit specialization. The explicit type could be float, int, Color.... // template <> // class PropertyAnimationContainer : public AnimatedPropertyBase // { // public: // PropertyAnimationContainer(Property& prop, float start_value, float end_value) // : prop_(prop) // { // start_value_ = start_value; // end_value_ = end_value; // } // virtual void Animate(float t) // { // float value = (1.0f - t) * start_value_ + t * end_value_; // prop_.set(value); // } // Property& prop_; // float start_value_; // float end_value_; // }; // template <> // class PropertyAnimationContainer : public AnimatedPropertyBase // { // public: // PropertyAnimationContainer(Property& prop, Color start_value, Color end_value) // : prop_(prop) // { // start_value_ = start_value; // end_value_ = end_value; // } // virtual void Animate(float t) // { // Color value = (1.0f - t) * start_value_ + t * end_value_; // prop_.set(value); // } // Property& prop_; // Color start_value_; // Color end_value_; // }; // class AnimationTimeline : public Object // { // public: // AnimationTimeline() {}; // template // void AddProperty(Property& prop, T start_value, T end_value) // { // PropertyAnimationContainer* a = new PropertyAnimationContainer (prop, start_value, end_value); // animated_properties_.push_back(a); // } // void Animate(float t) // { // std::list::iterator it; // // Go through all the properties and update them. // for (it = animated_properties_.begin(); it != animated_properties_.end(); ++it) // { // (*it)->Animate(t); // } // } // std::list animated_properties_; // }; } #endif // TIMELINE_H nux-4.0.8+18.10.20180623/Nux/TimelineEasings.cpp0000644000000000000000000000401313313373365015135 0ustar #include "Nux.h" #include "Timeline.h" #include "TimelineEasings.h" namespace nux { TimelineEaseInOutQuad::TimelineEaseInOutQuad(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL) : Timeline(msecs, Caption, NUX_FILE_LINE_PARAM) { } double TimelineEaseInOutQuad::GetEasing() { double prog = GetProgress(); prog *= 2.0; if (prog < 1) { return (prog * prog) * 0.5; } prog -= 1.0; return -0.5 * (prog * (prog - 2) - 1); } TimelineEaseInQuad::TimelineEaseInQuad(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL) : Timeline(msecs, Caption, NUX_FILE_LINE_PARAM) { } double TimelineEaseInQuad::GetEasing() { double prog = GetProgress(); return prog * prog; } TimelineEaseOutQuad::TimelineEaseOutQuad(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL) : Timeline(msecs, Caption, NUX_FILE_LINE_PARAM) { } double TimelineEaseOutQuad::GetEasing() { double prog = GetProgress(); return -1.0 * prog * (prog - 2); } TimelineEaseInOutCubic::TimelineEaseInOutCubic(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL) : Timeline(msecs, Caption, NUX_FILE_LINE_PARAM) { } double TimelineEaseInOutCubic::GetEasing() { double prog = GetProgress(); prog *= 2.0; if (prog < 1) { return (prog * prog * prog) * 0.5; } prog -= 2.0; return 0.5 * (prog * prog * prog + 2.0); } TimelineEaseInCubic::TimelineEaseInCubic(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL) : Timeline(msecs, Caption, NUX_FILE_LINE_PARAM) { } double TimelineEaseInCubic::GetEasing() { double prog = GetProgress(); return prog * prog * prog; } TimelineEaseOutCubic::TimelineEaseOutCubic(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL) : Timeline(msecs, Caption, NUX_FILE_LINE_PARAM) { } double TimelineEaseOutCubic::GetEasing() { double prog = GetProgress(); prog -= 1.0; return prog * prog * prog + 1.0; } } nux-4.0.8+18.10.20180623/Nux/TimelineEasings.h0000644000000000000000000000221713313373365014606 0ustar #ifndef TIMELINEEASINGS_H #define TIMELINEEASINGS_H namespace nux { class TimelineEaseInOutQuad : public Timeline { public: TimelineEaseInOutQuad(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL); double GetEasing(); }; class TimelineEaseInQuad : public Timeline { public: TimelineEaseInQuad(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL); double GetEasing(); }; class TimelineEaseOutQuad : public Timeline { public: TimelineEaseOutQuad(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL); double GetEasing(); }; class TimelineEaseInOutCubic : public Timeline { public: TimelineEaseInOutCubic(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL); double GetEasing(); }; class TimelineEaseInCubic : public Timeline { public: TimelineEaseInCubic(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL); double GetEasing(); }; class TimelineEaseOutCubic : public Timeline { public: TimelineEaseOutCubic(unsigned int msecs, const char *Caption, NUX_FILE_LINE_DECL); double GetEasing(); }; }; #endif // TIMELINEEASINGS_H nux-4.0.8+18.10.20180623/Nux/TimerProc.cpp0000644000000000000000000004626613313373365014001 0ustar /* * Copyright 2010-2013 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * Marco Trevisan * */ #include "Nux.h" #include "TimerProc.h" #include "WindowCompositor.h" #include "WindowThread.h" class BaseWindow; namespace nux { typedef struct { long sec; // seconds long usec; // and microseconds } TimeStruct; /** Return true if t1 is a time reference that will happen after time t2 has expired. */ static bool TimeIsGreater(TimeStruct t1, TimeStruct t2); static void TimeRightNow(TimeStruct *tv); //static unsigned int TimeDiff(TimeStruct t1, TimeStruct t2); static NThreadSafeCounter TimerUID = 0x01234567; class TimerObject { public: TimerObject(); bool operator == (const TimerObject &timer_object); //! Delay before the callback expires TimeStruct when; int Type; gint64 ms_time; // milliseconds void *CallbackData; TimeOutSignal *timeout_signal; //! time progression factor between [0.0, 1.0] float Param; float ProgressDelta; int Period; //!< The periode of the timer interuption(in milliseconds). int Duration; //!< How long the timer will be running from start to finish(in milliseconds); int ElapsedTime; //!< Elapsed time during execution(in milliseconds). int ScheduledIteration; //!< The number of scheduled iterations. int ProgressIterationCount; //!< Number of times the timer has been executed. bool marked_for_removal_; BaseWindow *Window; //!< BaseWindow from where the timer was created. unsigned int glibid; unsigned int uid; TimerHandler::TimerState state_; }; TimerObject::TimerObject() : Type(0) , ms_time(0) , CallbackData(nullptr) , timeout_signal(nullptr) , Param(0) , ProgressDelta(0) , Period(0) , Duration(0) , ElapsedTime(0) , ScheduledIteration(0) , ProgressIterationCount(0) , marked_for_removal_(0) , Window(nullptr) , glibid(0) , uid(0) , state_(TimerHandler::TIMER_STATE_STOPED) {} TimerHandle::TimerHandle() {} TimerHandle::TimerHandle(TimerObject *timer_object) : m_d(timer_object) {} TimerHandle::TimerHandle(const TimerHandle &timer_handle) : m_d(timer_handle.m_d) {} TimerHandle& TimerHandle::operator = (const TimerHandle &timer_handle) { TimerHandle copy(timer_handle); std::swap(m_d, copy.m_d); return *this; } std::shared_ptr const& TimerHandle::operator->() const { return m_d; } bool TimerHandle::operator==(TimerHandle const& h) const { bool equal = (m_d == h.m_d); if (equal && m_d) equal = (m_d->uid == h.m_d->uid); return equal; } bool TimerHandle::IsValid() const { return Activated(); } bool TimerHandle::Activated() const { return m_d != nullptr; } float TimerHandle::GetProgress() const { if (m_d) return m_d->Param; return 0.0f; } float TimerHandle::GetProgressDelta() const { if (m_d) return m_d->ProgressDelta; return 0; } int TimerHandle::GetScheduledIterationCount() const { if (m_d) return m_d->ScheduledIteration; return 0; } int TimerHandle::GetProgressIterationCount() const { if (m_d) return m_d->ProgressIterationCount; return 0; } int TimerHandle::GetElapsedTimed() const { if (m_d) return m_d->ElapsedTime; return 0; } //////////////////////////////////////////////////// TimerHandler::TimerHandler(WindowThread* window_thread) : window_thread_(window_thread) , is_processing_timers_(false) {} void TimerHandler::StartEarlyTimerObjects() { for (auto const& timer_object : early_timer_handlers_) { timer_object->ms_time = g_get_monotonic_time() / 1000; timer_object->glibid = GetWindowThread()->AddTimeout(timer_object->Period); } early_timer_handlers_.clear(); } TimerHandle TimerHandler::AddOneShotTimer(unsigned int Period, TimeOutSignal* timeout_signal, void* Data, WindowThread* window_thread) { TimerHandle timer_object(new TimerObject); timer_object->ms_time = g_get_monotonic_time() / 1000; timer_object->CallbackData = Data; timer_object->timeout_signal = timeout_signal; timer_object->Period = Period; timer_object->Type = TIMERTYPE_PERIODIC; timer_object->state_ = TimerHandler::TIMER_STATE_RUNNING; if (window_thread) timer_object->Window = window_thread->GetWindowCompositor().GetProcessingTopView(); else timer_object->Window = GetWindowThread()->GetWindowCompositor().GetProcessingTopView(); AddHandle(timer_object); { if (window_thread) timer_object->glibid = window_thread->AddTimeout(Period); else timer_object->glibid = GetWindowThread()->AddTimeout(Period); if (timer_object->glibid == 0) { early_timer_handlers_.push_back(timer_object); // Probably trying to set a timeout before Glib main context and loop have been created. // Sometimes later, this timer will be examined when ExecTimerHandler is called. // This happens when trying to set a callback before the main loop has been initialized. } //nuxDebugMsg("[TimerHandler::AddOneShotTimer] Adding Timeout ID: %d", timer_object->glibid); } return timer_object; } TimerHandle TimerHandler::AddDurationTimer(unsigned int Period, int Duration, TimeOutSignal *timeout_signal, void *Data) { TimerHandle timer_object(new TimerObject); timer_object->ms_time = g_get_monotonic_time() / 1000; timer_object->CallbackData = Data; timer_object->timeout_signal = timeout_signal; timer_object->Period = Period; timer_object->Duration = (Duration < 0) ? -1 : Duration; timer_object->Type = TIMERTYPE_DURATION; timer_object->state_ = TimerHandler::TIMER_STATE_RUNNING; AddHandle(timer_object); { timer_object->glibid = GetWindowThread()->AddTimeout(Period); if (timer_object->glibid == 0) { early_timer_handlers_.push_back(timer_object); // Probably trying to set a timeout before Glib main context and loop have been created. // Sometimes later, this timer will be examined when ExecTimerHandler is called. // This happens when trying to set a callback before the mainloop has been initialized. } //nuxDebugMsg("[TimerHandler::AddOneShotTimer] Adding Timeout ID: %d", timer_object->glibid); } return timer_object; } TimerHandle TimerHandler::AddIterativeTimer(unsigned int Period, int NumberOfIterations, TimeOutSignal *timeout_signal, void *Data) { TimerHandle timer_object(new TimerObject); timer_object->ms_time = g_get_monotonic_time() / 1000; timer_object->CallbackData = Data; timer_object->timeout_signal = timeout_signal; timer_object->Period = Period; timer_object->ScheduledIteration = (NumberOfIterations < 0) ? -1 : NumberOfIterations; timer_object->Type = TIMERTYPE_ITERATION; timer_object->state_ = TimerHandler::TIMER_STATE_RUNNING; AddHandle(timer_object); { timer_object->glibid = GetWindowThread()->AddTimeout(Period); if (timer_object->glibid == 0) { early_timer_handlers_.push_back(timer_object); // Probably trying to set a timeout before Glib main context and loop have been created. // Sometimes later, this timer will be examined when ExecTimerHandler is called. // This happens when trying to set a callback before the mainloop has been initialized. } //nuxDebugMsg("[TimerHandler::AddOneShotTimer] Adding Timeout ID: %d", timer_object->glibid); } return timer_object; } // Sort timers and add them to the queue void TimerHandler::AddHandle(TimerHandle const& timer_handle) { if (!timer_handle.Activated()) return; // Give the Timer a unique ID; timer_handle->uid = TimerUID.GetValue(); TimerUID.Increment(); auto tmp = timer_handler_queue_.begin(); while (tmp != timer_handler_queue_.end() && timer_handle->ms_time >= (*tmp)->ms_time) ++tmp; timer_handler_queue_.insert(tmp, timer_handle); } unsigned int TimerHandler::GetNumPendingHandler() { return timer_handler_queue_.size(); } bool TimerHandler::RemoveTimerHandler(TimerHandle &handle) { if (!handle.Activated() || timer_handler_queue_.empty()) return false; for (auto it = timer_handler_queue_.begin(); it != timer_handler_queue_.end(); ++it) { if (*it == handle) { if (!is_processing_timers_) { handle = nullptr; timer_handler_queue_.erase(it); return true; } else { handle->marked_for_removal_ = true; } } } return false; } bool TimerHandler::PauseTimer(TimerHandle& handle) { if (!handle.Activated() || timer_handler_queue_.empty()) return false; if (handle->state_ != TimerHandler::TIMER_STATE_RUNNING) return false; for (auto const& h : timer_handler_queue_) { if (h == handle) { handle->state_ = TimerHandler::TIMER_STATE_PAUSED; if (!is_processing_timers_) { gint64 ms_time_now = g_get_monotonic_time() / 1000; if (handle->Type == TIMERTYPE_PERIODIC) { handle->ElapsedTime += (ms_time_now - handle->ms_time); handle->ProgressDelta = float(handle->ElapsedTime) / float(handle->Period); if (handle->Param + handle->ProgressDelta > 1.0f) handle->ProgressDelta = 1.0f - handle->Param; handle->Param = float(handle->ElapsedTime) / float(handle->Period); } } return true; } } return false; } bool TimerHandler::ResumeTimer(TimerHandle& handle) { if (handle.Activated() || timer_handler_queue_.empty()) return false; if (handle->state_ != TimerHandler::TIMER_STATE_PAUSED) return false; for (auto const& h : timer_handler_queue_) { if (h == handle) { handle->state_ = TimerHandler::TIMER_STATE_RUNNING; if (handle->Type == TIMERTYPE_PERIODIC) { handle->glibid = GetWindowThread()->AddTimeout(handle->Period * (1.0f - handle->Param)); } else { handle->glibid = GetWindowThread()->AddTimeout(handle->Period); } handle->ms_time = g_get_monotonic_time() / 1000; if (handle->glibid == 0) early_timer_handlers_.push_back(handle); return true; } } return false; } int TimerHandler::ExecTimerHandler(unsigned int timer_id) { if (timer_handler_queue_.empty()) return 0; bool repeat = false; is_processing_timers_ = true; for (auto it = timer_handler_queue_.begin(); it != timer_handler_queue_.end(); ++it) { auto const& timer_object = *it; if (timer_object->glibid == timer_id && !timer_object->marked_for_removal_) { if (timer_object->state_ != TIMER_STATE_RUNNING) { return false; } // Find the first timer object that timer_object->ElapsedTime += timer_object->Period; if (timer_object->Type == TIMERTYPE_PERIODIC) { timer_object->ProgressDelta = float(timer_object->ElapsedTime) / float(timer_object->Period) - timer_object->Param; // Clamp progress delta so(timer_object->Param + timer_object->ProgressDelta) <= 1.0f if (timer_object->Param + timer_object->ProgressDelta > 1.0f) timer_object->ProgressDelta = 1.0f - timer_object->Param; timer_object->Param = float(timer_object->ElapsedTime) / float(timer_object->Period); } else if (timer_object->Type == TIMERTYPE_DURATION) { timer_object->ProgressDelta = float(timer_object->ElapsedTime) / float(timer_object->Duration) - timer_object->Param; // Clamp progress delta so(timer_object->Param + timer_object->ProgressDelta) <= 1.0f if (timer_object->Param + timer_object->ProgressDelta > 1.0f) timer_object->ProgressDelta = 1.0f - timer_object->Param; if (timer_object->ProgressDelta < 0.0f) timer_object->ProgressDelta = 0.0f; timer_object->Param = float(timer_object->ElapsedTime) / float(timer_object->Duration); } else if (timer_object->Type == TIMERTYPE_ITERATION) { timer_object->ProgressIterationCount += 1; int duration = timer_object->Period * timer_object->ScheduledIteration; timer_object->ProgressDelta = float(timer_object->ElapsedTime) / float(duration) - timer_object->Param; // Clamp progress delta so(timer_object->Param + timer_object->ProgressDelta) <= 1.0f if (timer_object->Param + timer_object->ProgressDelta > 1.0f) timer_object->ProgressDelta = 1.0f - timer_object->Param; timer_object->Param = float(timer_object->ElapsedTime) / float(duration); } else { nuxAssertMsg(0, "[TimerHandler::ExecTimerHandler] Unknown timer type."); } if (timer_object->Param > 1.0f) { // correction. timer_object->Param = 1.0f; } timer_object->marked_for_removal_ = false; if (timer_object->timeout_signal) { // Execute the signal GetWindowThread()->GetWindowCompositor().SetProcessingTopView(timer_object->Window); timer_object->timeout_signal->tick.emit(timer_object->CallbackData); GetWindowThread()->GetWindowCompositor().SetProcessingTopView(NULL); // Reset glibid to 0. glibid is not null, if this element ever happened to be at the head of the queue // and we set a timer for it. //nuxDebugMsg("[TimerHandler::ExecTimerHandler] Executed Timeout ID: %d", timer_object->glibid); //timer_object->glibid = 0; } bool expired_handler = false; if (timer_object->marked_for_removal_) { // RemoveTimerHandler was called during the callback execution expired_handler = true; } else if (timer_object->Type == TIMERTYPE_PERIODIC) { // A one shot timer expires after the first execution. expired_handler = true; } else if ((timer_object->Type == TIMERTYPE_DURATION) && (timer_object->Param >= 1.0f)) { // A timer delay timer expires after the duration of the timer as expired. expired_handler = true; } else if ((timer_object->Type == TIMERTYPE_ITERATION) && (timer_object->ProgressIterationCount >= timer_object->ScheduledIteration)) { // An iterative timer expires after the timer as been executedN times. expired_handler = true; } if (!expired_handler && (timer_object->state_ == TIMER_STATE_PAUSED)) { // The state has been changed to "paused". return false; } if (expired_handler) { if (timer_object->timeout_signal) { GetWindowThread()->GetWindowCompositor().SetProcessingTopView(timer_object->Window); timer_object->timeout_signal->expired.emit(timer_object->CallbackData); GetWindowThread()->GetWindowCompositor().SetProcessingTopView(NULL); } timer_object->state_ = TIMER_STATE_STOPED; timer_handler_queue_.erase(it); } else { repeat = true; } break; } } // Purge handles that have been marked for removal for (auto it = timer_handler_queue_.begin(); it != timer_handler_queue_.end();) { auto const& timer_object = *it; if (timer_object->marked_for_removal_) { it = timer_handler_queue_.erase(it); continue; } ++it; } is_processing_timers_ = false; return repeat; } bool TimerHandler::FindTimerHandle(TimerHandle &timer_object) { auto it = std::find(timer_handler_queue_.begin(), timer_handler_queue_.end(), timer_object); return (it != timer_handler_queue_.end()); } //---------------------------------------------------------------------------- int TimerHandler::DelayUntilNextTimerExpires() { if (timer_handler_queue_.empty()) return 0; TimeStruct now; TimeStruct delay; TimeRightNow(&now); auto const& first = timer_handler_queue_.front(); if (TimeIsGreater(now, first->when)) { return 0; } else { delay.sec = first->when.sec - now.sec; delay.usec = first->when.usec - now.usec; // make sure that usec cannot be less than -1000000 before applying this code if (delay.usec < 0) { delay.usec += 1000000; delay.sec--; } return (delay.sec * 1000000 + delay.usec) / 1000; // return delay in milliseconds } } /*unsigned int TimeDiff( TimeStruct t1, TimeStruct t2) { int sec; int usec; if (t1.sec >= t2.sec) { sec = t1.sec - t2.sec; usec = t1.usec - t2.usec; while ((usec < 0) && (sec > 0)) { usec += 1000000; sec -= 1; } if (usec < 0) usec = -usec; } if (t1.sec < t2.sec) { sec = t2.sec - t1.sec; usec = t2.usec - t1.usec; while ((usec < 0) && (sec > 0)) { usec += 1000000; sec -= 1; } if (usec < 0) usec = -usec; } return sec*1000 + usec/1000; // time diff is millisecond }*/ bool TimeIsGreater( TimeStruct t1, TimeStruct t2) { if ((t1.sec > t2.sec) || ((t1.sec == t2.sec) && (t1.usec > t2.usec))) return true; if ((t1.sec == t2.sec) && (t1.usec == t2.usec)) return true; return false; } void TimeRightNow(TimeStruct *tv) { #if defined(NUX_OS_WINDOWS) struct _timeb timebuffer; // Time in seconds since midnight(00:00:00), January 1, 1970, coordinated universal time(UTC). _ftime(&timebuffer); tv->sec = timebuffer.time; tv->usec = timebuffer.millitm * 1000; #elif defined(NUX_OS_LINUX) timeval unix_timeval; gettimeofday(&unix_timeval, NULL); tv->sec = unix_timeval.tv_sec; tv->usec = unix_timeval.tv_usec; #else #error TimeRightNow is not implemented for this platform. #endif } } nux-4.0.8+18.10.20180623/Nux/TimerProc.h0000644000000000000000000001471613313373365013441 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef TIMERPROC_H #define TIMERPROC_H #include namespace nux { class TimerHandler; class WindowThread; //! A timeout callback. Fires a signal when a timer expires. class TimeOutSignal : public sigc::trackable { public: sigc::signal tick; sigc::signal expired; }; typedef TimeOutSignal TimerFunctor; class TimerObject; class TimerHandle { public: TimerHandle(); TimerHandle(TimerObject *timer_object); TimerHandle(const TimerHandle &); TimerHandle &operator = (const TimerHandle &); std::shared_ptr const& operator->() const; bool operator==(TimerHandle const& h) const; bool IsValid() const; //! m_d; }; //! A timer manager class created by WindowThread. class TimerHandler { public: enum { TIMERTYPE_UNKNONW = 0L, TIMERTYPE_PERIODIC, TIMERTYPE_DURATION, TIMERTYPE_ITERATION, }; typedef enum { TIMER_STATE_STOPED, TIMER_STATE_PAUSED, TIMER_STATE_RUNNING, } TimerState; TimerHandler(WindowThread *window_thread); //! Add a timer callback. /*! Add a timer callback to the timer manager. When the timer expires, the callback function is executed. The returned TimerObject should not be deleted by the caller. @param Milliseconds period Time before the timer ticks. The timer ticks only once and then it expires. @param timeout_signal The callback to execute when the timer expires. @param Data The callback data @param window_thread Thread safety measure. Pass the WindowThread associated to this TimerHandler if it is called from a different thread than the one where the main thread was created. @return A handle to the timer. */ TimerHandle AddOneShotTimer(unsigned int period, TimeOutSignal *timeout_signal, void *Data, WindowThread* window_thread = NULL); //! Add a periodic timer callback. /*! Add a timer callback to the timer manager. Every time the timer expires, the callback function is executed. The returned TimerHandle should not be deleted by the caller. @param Milliseconds period Time between the timer ticks. The timer will tick 'NumberOfIteration' times. @param Duration The duration over which the timer is repeated. @param timeout_signal The callback to execute when the timer expires. @param Data The callback data @return A handle to the timer. */ TimerHandle AddDurationTimer(unsigned int period, int Duration, TimeOutSignal *timeout_signal, void *Data); //! Add a timer callback to be called a finite number of time. /*! Add a timer callback to the timer manager. The timer callback will be call N times exactly. Every time the timer expires, the callback function is executed. The returned TimerHandle should not be deleted by the caller. @param Milliseconds period Time between the timer ticks. The timer will tick 'NumberOfIteration' times. @param NumberOfIteration The number of time to repeat the wait period. @param timeout_signal The callback to execute when the timer expires. @param Data The callback data @return A handle to the timer. */ TimerHandle AddIterativeTimer(unsigned int period, int NumberOfIteration, TimeOutSignal *timeout_signal, void *Data); //! Search for a timer handle. /*! Search for a timer handle in the timer handle queue. Return true if the timer is found. @param handle Timer handle to search. @return Return true if the timer is found; false otherwise. */ bool FindTimerHandle(TimerHandle& handle); //! Remove a timer; /*! This call stops the timer. @param handle Timer handle to search. @return Return True if the timer is found. */ bool RemoveTimerHandler(TimerHandle& handle); //! Pause a timer. /*! This call pauses a timer. @param handle Timer handle to look for. @return True if the timer is paused. */ bool PauseTimer(TimerHandle& handle); //! Resume the execution of a timer. /*! This call resumes the execution of a timer. @param handle Timer handle to look for. @return True if the timer execution has resumed.. */ bool ResumeTimer(TimerHandle& handle); //! Return the delay until the next timer expires. /*! @return Delay to next timer expiration in milliseconds. */ int DelayUntilNextTimerExpires(); int ExecTimerHandler (unsigned int timer_id); //! Start the timers that were sett before the system was fully initialized. void StartEarlyTimerObjects(); private: // Prevent copy constructor. TimerHandler(const TimerHandler&); // Prevent assignment operator. TimerHandler& operator = (const TimerHandler&); WindowThread *window_thread_; //!< The WindowThread to which this object belongs. bool is_processing_timers_; void AddHandle(TimerHandle const&); unsigned int GetNumPendingHandler(); std::deque timer_handler_queue_; std::list early_timer_handlers_; //!< timer objects that couldn't be started because the main loop is not runing yet. }; } #endif // TIMERPROC_H nux-4.0.8+18.10.20180623/Nux/ToggleButton.cpp0000644000000000000000000000306713313373365014502 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * Gordon Allott * */ #include "Nux.h" #include "ToggleButton.h" #include "HLayout.h" namespace nux { ToggleButton::ToggleButton(TextureArea *image, NUX_FILE_LINE_DECL) : Button(image, NUX_FILE_LINE_PARAM) { persistent_active_state_ = true; } ToggleButton::ToggleButton(const std::string label, NUX_FILE_LINE_DECL) : Button(label, NUX_FILE_LINE_PARAM) { persistent_active_state_ = true; } ToggleButton::ToggleButton(const std::string label, TextureArea *image, NUX_FILE_LINE_DECL) : Button(label, image, NUX_FILE_LINE_PARAM) { persistent_active_state_ = true; } ToggleButton::ToggleButton(NUX_FILE_LINE_DECL) : Button(NUX_FILE_LINE_PARAM) { persistent_active_state_ = true; } ToggleButton::~ToggleButton() { } } nux-4.0.8+18.10.20180623/Nux/ToggleButton.h0000644000000000000000000000263413313373365014146 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef TOGGLEBUTTON_H #define TOGGLEBUTTON_H #include "Button.h" namespace nux { class HLayout; //! A Button with a persistent activate state. /*! The ToggleButton class has a persistent active state. When it is active, it is visually different from its normal state. */ class ToggleButton: public Button { public: ToggleButton(TextureArea *image, NUX_FILE_LINE_PROTO); ToggleButton(const std::string label, NUX_FILE_LINE_PROTO); ToggleButton(const std::string label, TextureArea *image, NUX_FILE_LINE_PROTO); ToggleButton(NUX_FILE_LINE_PROTO); ~ToggleButton(); }; } #endif // TOGGLEBUTTON_H nux-4.0.8+18.10.20180623/Nux/ToolButton.cpp0000644000000000000000000001021713313373365014171 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "NuxGraphics/GLTextureResourceManager.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "ActionItem.h" #include "ToolButton.h" namespace nux { ToolButton::ToolButton(const char *BitmapFilename, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , m_ActionItem(0) { m_Texture = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture(); if (BitmapFilename) m_Texture->Update(BitmapFilename); // Set Original State SetBaseString("ToolButton"); // Set Signals mouse_click.connect(sigc::mem_fun(this, &ToolButton::EmitClick)); mouse_double_click.connect(sigc::mem_fun(this, &ToolButton::RecvMouseDoubleClick)); mouse_down.connect(sigc::mem_fun(this, &ToolButton::RecvMouseDown)); mouse_up.connect(sigc::mem_fun(this, &ToolButton::RecvMouseUp)); mouse_enter.connect(sigc::mem_fun(this, &ToolButton::RecvMouseEnter)); mouse_leave.connect(sigc::mem_fun(this, &ToolButton::RecvMouseLeave)); SetMinimumSize(28, 28); SetGeometry(Geometry(0, 0, 24, 24)); } ToolButton::~ToolButton() { m_Texture->UnReference(); } void ToolButton::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); if (IsMouseInside() && !IsMouseOwner()) { GetPainter().PaintBackground(graphics_engine, base); GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BACKGROUND_SECONDARY), eSHAPE_CORNER_ROUND2); } else if (IsMouseOwner()) { GetPainter().PaintBackground(graphics_engine, base); GetPainter().PaintShape(graphics_engine, base, Color(0xFF2A2A2A), eSHAPE_CORNER_ROUND2); } else { GetPainter().PaintBackground(graphics_engine, base); GetPainter().PaintShape(graphics_engine, base, Color(COLOR_BACKGROUND_PRIMARY), eSHAPE_CORNER_ROUND2); } if (m_Texture) GetPainter().Draw2DTextureAligned(graphics_engine, m_Texture, base, TextureAlignmentStyle(eTACenter, eTACenter)); } void ToolButton::DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void ToolButton::SetState(bool /* b */) { } void ToolButton::SetBitmap(const BaseTexture* Texture) { nuxAssert(Texture); NUX_RETURN_IF_NULL(Texture); if (m_Texture) m_Texture->UnReference(); m_Texture = Texture->Clone(); } void ToolButton::EmitClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { sigClick.emit(); if (m_ActionItem) m_ActionItem->Trigger(); } void ToolButton::RecvMouseDoubleClick(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void ToolButton::RecvMouseDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void ToolButton::RecvMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void ToolButton::RecvMouseEnter(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void ToolButton::RecvMouseLeave(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { QueueDraw(); } void ToolButton::SetAction(ActionItem *action) { m_ActionItem = action; } } nux-4.0.8+18.10.20180623/Nux/ToolButton.h0000644000000000000000000000400513313373365013634 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef TOOLBUTTON_H #define TOOLBUTTON_H #include "ActionItem.h" namespace nux { class HLayout; class ActionItem; class ToolButton : public View { public: ToolButton(const char *BitmapFilename = 0, NUX_FILE_LINE_PROTO); ~ToolButton(); void SetAction(ActionItem *action); void SetState(bool b); void SetBitmap(const BaseTexture* Texture); // emitters void EmitClick(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseDoubleClick (int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseUp (int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags); // signals sigc::signal sigClick; protected: virtual void Draw(GraphicsEngine &GfxContext, bool force_draw); virtual void DrawContent(GraphicsEngine &GfxContext, bool force_draw); private: ActionItem *m_ActionItem; BaseTexture *m_Texture; }; } #endif // TOOLBUTTON_H nux-4.0.8+18.10.20180623/Nux/Utils.cpp0000644000000000000000000000202013313373365013151 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Utils.h" namespace nux { // bool gMouseOwned = false; // // bool IsMouseOwned() // { // if (gMouseOwned) // { // return true; // } // else // { // return false; // } // } } nux-4.0.8+18.10.20180623/Nux/Utils.h0000644000000000000000000000560613313373365012633 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef UTILS_H #define UTILS_H // check if a value lies within a closed interval #ifndef IN_BOUNDS #define IN_BOUNDS( x, lo, hi ) ((x) >= (lo) && (x) <= (hi)) #endif //check if a 2D point lies within a 2D box #ifndef PT_IN_BOX #define PT_IN_BOX( x, y, lo_x, hi_x, lo_y, hi_y ) ( IN_BOUNDS(x,lo_x,hi_x) && IN_BOUNDS(y,lo_y,hi_y)) #endif namespace nux { typedef enum { eSolveNone = (0L), eMouseEventSolved = (1L), eKeyEventSolved = (1L) << 1, eDoNotProcess = (1L) << 2, EVENT_CYCLE_EXCLUSIVE = (1L) << 3, //!< Value of ProcessEventInfo when processing the event cycle of the input area that has the exclusivity. EVENT_CYCLE_EXCLUSIVE_CONTINUE = (1L) << 4, //!< Return value of the cycle of the exclusive input area. If it is returned, allow other areas to process the event. EVENT_CYCLE_SOLVED = (1L) << 5, EVENT_CYCLE_DO_NOT_PROCESS = (1L) << 6, EVENT_CYCLE_RESET_AREA_STATE = (1L) << 7, //!< Reset the mouse event processor of an InputArea. } EventCycleStatus; enum PositionPolicy { ePositionLeft, ePositionRight, ePositionCenter, ePositionFull, ePositionProportional, }; enum SizePolicy { eSizeFixed, eSizeResizeable, }; typedef enum /*RectangleShapeCorners*/ { eCornerNone = 0, eCornerTopLeft = (1L), eCornerTopRight = (1L << 1), eCornerBottomLeft = (1L << 2), eCornerBottomRight = (1L << 3), eAllCorners = eCornerTopLeft | eCornerTopRight | eCornerBottomLeft | eCornerBottomRight, } ShapeCornerType; enum TextureAlignment { eTACenter, eTALeft, eTARight, eTATop, eTABottom }; enum VerticalAlignment { eVACenter, eVATop, eVABottom }; enum HorizontalAlignment { eHACenter, eHALeft, eHARight, }; typedef struct { int x; int y; int width; int height; int x_clipregion; int y_clipregion; int width_clipregion; int height_clipregion; } DrawAreaContext; bool IsMouseOwned(); } #endif // UTILS_H nux-4.0.8+18.10.20180623/Nux/VLayout.cpp0000644000000000000000000007302613313373365013472 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "View.h" #include "VLayout.h" #include "HLayout.h" namespace nux { static const int VERROR = 0; NUX_IMPLEMENT_OBJECT_TYPE(VLayout); VLayout::VLayout(NUX_FILE_LINE_DECL) : LinearLayout(NUX_FILE_LINE_PARAM) { #if DEBUG_LAYOUT m_h_in_margin = 10; left_padding_ = 10; right_padding_ = 10; space_between_children_ = 10; top_padding_ = 10; bottom_padding_ = 10; #endif // Start packing the elements from the left size. Is the layout has more space than the elements can use, // leave that space on the right side of the VLayout. m_ContentStacking = eStackTop; } VLayout::VLayout(std::string name, NUX_FILE_LINE_DECL) : LinearLayout(NUX_FILE_LINE_PARAM) { m_name = name; #if DEBUG_LAYOUT m_h_in_margin = 10; left_padding_ = 10; right_padding_ = 10; space_between_children_ = 10; top_padding_ = 10; bottom_padding_ = 10; #endif m_ContentStacking = eStackTop; } VLayout::~VLayout() { } void VLayout::GetCompositeList(std::list *ViewList) { std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if ((*it)->IsView()) { View *ic = NUX_STATIC_CAST(View *, (*it)); ViewList->push_back(ic); } else if ((*it)->IsLayout()) { Layout *layout = NUX_STATIC_CAST(Layout *, (*it)); layout->GetCompositeList(ViewList); } } } //! Compute the how elements are spread inside the layout /*! @param remaining_height Height that remains after subtracting elements height, inner and outer margins from the content height. @param offset_space The space at the top of all elements. @param element_margin The margin between elements. */ void VLayout::ComputeStacking(int remaining_height, int &offset_space, int &element_margin) { int per_element_space = 0; int total_used_space = 0; int n_elements = 0; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { // gather all the space used by elements if ((*it)->IsVisible()) { total_used_space += (*it)->GetBaseHeight(); n_elements++; } } if (n_elements != 0) { // Compute the space available for each element per_element_space = (remaining_height - total_used_space) / int(n_elements); } if (per_element_space < 0) { per_element_space = 0; } int margin; if (per_element_space > 0) { margin = (per_element_space) / 2; } else { margin = 0; } LayoutContentDistribution stacking = GetContentDistribution(); switch(stacking) { case MAJOR_POSITION_START: { offset_space = 0; element_margin = 0; } break; case MAJOR_POSITION_END: { offset_space = (remaining_height - total_used_space); if (offset_space < 0) offset_space = 0; element_margin = 0; } break; case eStackCenter: { offset_space = (remaining_height - total_used_space) / 2; if (offset_space < 0) offset_space = 0; element_margin = 0; } break; case eStackExpand: default: { offset_space = 0; element_margin = margin; } break; } } long VLayout::ComputeContentSize() { if (_layout_element_list.size() == 0) { return eCompliantHeight | eCompliantWidth; } std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { (*it)->SetLayoutDone(false); } int original_width = GetBaseWidth(); if (GetScaleFactor() == 0) { // The size must exactly fit the children. The parent cannot be larger or smaller // than the total height of its children(+ margins). // So set the parent size to Geometry(0,0,1,1) and let the children force it to extend. if (GetParentObject() && GetParentObject()->Type().IsObjectType(HLayout::StaticObjectType)) { // The parent if a HLayout. Then a Stretch factor of 0 means this layout has its width set to 1. Area::SetBaseWidth(1); } else if (GetParentObject() && GetParentObject()->Type().IsObjectType(VLayout::StaticObjectType)) { // The parent if a VLayout(same type). Then a Stretch factor of 0 means this layout has its height set to 1. Area::SetBaseHeight(1); } else { // This is for when a layout is set as a composition layout of an View and its stretch factor is explicitly set to 0. Area::SetBaseWidth(1); Area::SetBaseHeight(1); } //The children will all assume their minimum size. } else { // The total size of the children(+ margins) may be smaller or equal to parent size. } bool unadjusted_layout = false; size_t num_element = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if ((*it)->IsVisible()) num_element++; } do { // Get layout Width and Height int width = GetBaseWidth(); int height = GetBaseHeight(); // Remove the margins. This is the real width and height available to the children. width -= (left_padding_ + right_padding_); height -= (int) (num_element - 1) * space_between_children_ + (top_padding_ + bottom_padding_); // Size the children according to their stretch factor. VLayoutManagement(width, height); // Objects have been resized, now position them. int current_x = GetBaseX() + left_padding_; int current_y = GetBaseY() + top_padding_; //int per_element_space = 0; //int total_used_space = 0; int offset_space = 0; int space_after_element = 0; ComputeStacking(height, offset_space, space_after_element); current_y += offset_space; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; current_y += space_after_element; (*it)->SetBaseX(current_x); (*it)->SetBaseY(current_y); MinorDimensionSize extend = (*it)->GetExtend(); MinorDimensionPosition positioning = (*it)->GetPositioning(); float percentage = (*it)->GetPercentage(); // Compute the size of an element in the minor dimension(horizontal) switch(extend) { case MINOR_SIZE_PERCENTAGE: { // The size of the element in the minor dimension is a percentage of layout minor dimension size. // Note that children of the processed element may force it to have a bigger size. int percentage_width = (width * percentage) / 100.0f; (*it)->SetBaseWidth(percentage_width); break; } case MINOR_SIZE_MATCHCONTENT: { // Force the element width to be the minimum has defined with SetMinimumWidth. // The children of this element can force it to get larger. (*it)->ApplyMinWidth(); break; } case eFix: { //do nothing break; } case MINOR_SIZE_FULL: default: { (*it)->SetBaseWidth(width); break; } } // Compute the position of an element in the minor dimension. if ((*it)->GetBaseWidth() < width) { int widget_width = (*it)->GetBaseWidth(); switch(positioning) { case MINOR_POSITION_START: { // do nothing (*it)->SetBaseX(current_x); break; } case MINOR_POSITION_END: { if (widget_width < width) (*it)->SetBaseX(current_x + width - widget_width); else (*it)->SetBaseX(current_x); break; } case MINOR_POSITION_CENTER: default: { if (widget_width < width) (*it)->SetBaseX(current_x + (width - widget_width) / 2); else (*it)->SetBaseX(current_x); } } } current_y += (*it)->GetBaseHeight() + space_after_element + space_between_children_; } // Manage child layout m_contentWidth = GetBaseWidth() - (left_padding_ + right_padding_); // Set to the size of the layout. if (num_element == 0) m_fittingHeight = (int) (top_padding_ + bottom_padding_); else m_fittingHeight = (int) (num_element - 1) * space_between_children_ + (top_padding_ + bottom_padding_); int element_width; unadjusted_layout = false; // This array is meant to store the sizes of some of the elements width. These elements must have MINOR_SIZE_FULL as extent and // they have not been not been constrained smaller after ComputeContentSize is called. Because the layout may have a stretch factor of 0 // and therefore its size has been set to 1x1 at the start of this function, there is a possibility that some of the elements don't have // the full width of the layout(these elements uses their minimum width because the layout was set to a size 1x1). // We check if that is the case and force a recompute. std::vector FullSizeUnadjusted; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; int ret = 0; if (((*it)->IsLayout() || (*it)->IsView()) /*&& ((*it)->IsLayoutDone() == false)*/ /*&& ((*it)->GetScaleFactor() != 0)*/) { Geometry pre_geo = (*it)->GetGeometry(); ret = (*it)->ComputeContentSize(); Geometry post_geo = (*it)->GetGeometry(); bool larger_width = pre_geo.width < post_geo.width; bool smaller_width = pre_geo.width > post_geo.width; bool larger_height = pre_geo.height < post_geo.height; bool smaller_height = pre_geo.height > post_geo.height; if ((larger_height || smaller_height) && ((*it)->IsLayoutDone() == false)) { // Stop computing the size of this layout. Its size was not convenient to its children. So the children size take priority // over the layout. In ComputeContentSize, the dimension of the layout has been set so it encompasses its children(and the margins). // Now the parent layout cannot be touched again: layout_done_ = true. In VLayoutManagement, it is as if the stretchfactor // of this layout is now 0. // This is the only place where a layout can have layout_done_ set to "true". // If(smaller_height == true) the layout takes less space than anticipated. // Set unadjusted_layout = true, so another pass will allow its sibling to claim more space. { unadjusted_layout = true; (*it)->SetLayoutDone(true); } } if ((smaller_width == false) && ((*it)->GetExtend() == MINOR_SIZE_FULL) && ((*it)->GetBaseWidth() < (*it)->GetMaximumWidth())) { // Catch all object whose size is possibly larger than the layout. Check their size at the end and // recompute the layout if necessary. // For layout elements, make sure that the stretch factor is not 0. If it is, it means it will not use the // size provided by the parent layout. Its size will be adjusted to the minimum size of the layout content. if (!((*it)->IsLayout() && (*it)->GetScaleFactor() == 0)) FullSizeUnadjusted.push_back((*it)->GetBaseWidth()); } if ((smaller_width || larger_width) && ((*it)->GetExtend() == MINOR_SIZE_MATCHCONTENT)) { (*it)->SetMinimumWidth((*it)->GetBaseWidth()); unadjusted_layout = true; } // Should be reactivate so that if the parent Layout does not call // ComputeContentPosition, at least it is done here to arrange the internal // element of the children. //(*it)->ComputeContentPosition(0,0); } m_fittingHeight += (*it)->GetBaseHeight(); element_width = (*it)->GetBaseWidth(); if ((*it)->IsSpaceLayout() == false) { if ((GetScaleFactor() != 0) && (ret & eSmallerWidth)) { if (m_contentWidth < element_width) { if (m_contentWidth < GetMaximumWidth()) { // An element is larger than the layout width and the layout has not reach its maximum width yet. m_contentWidth = element_width; unadjusted_layout = true; } } } else { if (m_contentWidth <= element_width) { m_contentWidth = element_width; } // else if ((*it)->GetExtend() == MINOR_SIZE_FULL) // { // unadjusted_layout = true; // } } } } // Set the width of the layout to be equal to the largest width it controls. // m_contentWidth is the largest width of an element within this layout. The layout size is then // m_contentWidth + (left_padding_ + right_padding_); SetBaseWidth(m_contentWidth + (left_padding_ + right_padding_)); // Get back the Width after it has been bounded by [minWidth, maxWidth] in the preceeding call to SetBaseWidth. // Then deduce the width of the content. int temp = GetWidth() - (left_padding_ + right_padding_); std::vector::iterator IntIterator = FullSizeUnadjusted.begin(); for (IntIterator = FullSizeUnadjusted.begin(); IntIterator != FullSizeUnadjusted.end(); ++IntIterator) { if ((*IntIterator) < temp) { unadjusted_layout = true; } } } while (unadjusted_layout); // m_fittingWidth is sum of the largest element width plus the outer margin. m_fittingWidth = m_contentWidth + (left_padding_ + right_padding_); // m_fittingHeight is sum of the element height plus the inner and outer margin. // If the stretch factor is 0 then, the layout height has been set to 1 and need to grow with the elements within. // If the stretch factor is not 0, then the layout height is set to m_fittingHeight only if the its height is less than m_fittingHeight; // This way, if the layout height is greater than m_fittingHeight there is space to compute the content stacking(ComputeStacking). if (GetBaseHeight() < m_fittingHeight) { SetBaseHeight(m_fittingHeight); } m_contentHeight = m_fittingHeight; long size_compliance = 0L; ComputeContentPosition(0, 0); if (GetBaseWidth() > original_width + VERROR) { #if DEBUG_LAYOUT_COMPUTATION // The layout has been resized larger in WIDTH to tightly pack its content. // Or you can say that the layout refuse to be smaller than total WIDTH of its elements. std::cout << "ComputeContentSize: VLayout Width block at " << GetWidth() << std::endl; #endif size_compliance |= eLargerWidth; // need scrollbar } else if (GetBaseWidth() + VERROR < original_width) { #if DEBUG_LAYOUT_COMPUTATION // The layout is smaller. std::cout << "ComputeContentSize: VLayout Width smaller = " << GetWidth() << std::endl; #endif size_compliance |= eSmallerWidth; } else { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: VLayout Width compliant = " << GetWidth() << std::endl; #endif size_compliance |= eCompliantWidth; } { #if DEBUG_LAYOUT_COMPUTATION // The layout and its content resized together without trouble. std::cout << "ComputeContentSize: VLayout Height compliant = " << m_fittingHeight << std::endl; #endif size_compliance |= eCompliantHeight; } return size_compliance; } void VLayout::VLayoutManagement(int /* width */, int height) { bool need_recompute = false; do { int available_height = height; int max_stretchfactor = GetMaxStretchFactor(); std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; if (((*it)->GetScaleFactor() == 0) && ((*it)->IsLayoutDone() != true)) { (*it)->ApplyMinHeight(); } } if (max_stretchfactor == 0) { // It means all object are fixed sized or all re-sizable object have been sized to there max or there min. if (GetScaleFactor() == 0) { // It is unlikely that we get here! int h = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end() && !need_recompute; ++it) { if (!(*it)->IsVisible()) continue; h += (*it)->GetBaseHeight(); } SetBaseHeight(h); } return; } for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; if ((*it)->GetScaleFactor() == 0 || (*it)->IsLayoutDone() == true) { available_height -= (*it)->GetBaseHeight(); } } if (available_height <= 2) { for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; if (((*it)->GetScaleFactor() != 0) && (*it)->IsArea()) { // If it is not an object of type eInputArea, do not set layout_done_ to true, // so, the layout management function will later be called on the object. (*it)->ApplyMinHeight(); (*it)->SetLayoutDone(true); } else if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayout()) && ((*it)->IsLayoutDone() == false)) { // The out of bound must be reset to false. (*it)->ApplyMinHeight(); (*it)->SetLayoutDone(false); } else if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) { (*it)->ApplyMinHeight(); // A layout must never have layout_done_ set to true "here" because it must continue // doing the layout of its children and finally resize itself to fit them. // The same way, A layout size factor should never be set to 0. } } return; } float cumul = 0; Area *LastElementThatCanBeResized = 0; int total_distributed_size = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) { float sf = (float) (*it)->GetScaleFactor(); cumul += sf / max_stretchfactor; LastElementThatCanBeResized = (*it); } else { total_distributed_size += (*it)->GetBaseWidth(); } } // -- // \ factor // Ref_Size * \ ------------ = available_height // / max_factor // / // -- // all element with stretchfactor != 0 int ref_height = available_height / cumul; // need_recompute = false;; for (it = _layout_element_list.begin(); it != _layout_element_list.end() && !need_recompute; ++it) { if (!(*it)->IsVisible()) continue; if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) { int sf = (*it)->GetScaleFactor(); int new_height; if (sf == max_stretchfactor) { new_height = ref_height; } else { new_height = ref_height * sf / max_stretchfactor; } total_distributed_size += new_height; if (LastElementThatCanBeResized == (*it)) { // Redistribute the remaining size to the last element(at the bottom). // This is necessary because of imprecision. For instance if available_height = 451 and we have 2 elements // with the same stretch factor than each one will have a size of 225. With is correction, the first element will have a size of // 225 while the second one will have a size of 226. if (available_height - total_distributed_size > 0) { new_height += available_height - total_distributed_size; total_distributed_size = available_height; } } int elemt_max_height = (*it)->GetMaximumSize().height; int elemt_min_height = (*it)->GetMinimumSize().height; // A layout must never have layout_done_ set to true "here" because it must continue // doing the layout of its children and finally resize itself to fit them. // The same way, A layout size factor should never be set to 0. // Q: How about SpaceLayout? Should we treat them the same as layout or widget in this particular case? // A: SapceLayout are treated like widgets in this case if (new_height < elemt_min_height) { // assume the minimum width (*it)->SetBaseHeight(elemt_min_height); if (((*it)->IsLayout() == false) || (*it)->IsSpaceLayout()) { (*it)->SetLayoutDone(true); need_recompute = true; } } else if (new_height > elemt_max_height) { // assume the maximum width (*it)->SetBaseHeight(elemt_max_height); if (((*it)->IsLayout() == false) || (*it)->IsSpaceLayout()) { (*it)->SetLayoutDone(true); need_recompute = true; } // else // { // // set the extra space back in the pool // total_distributed_size -= (new_height - elemt_max_height); // } } else { (*it)->SetBaseHeight(new_height); } } else { // For fixed element, reset their size to the same so it is checked against // the min and max. This is necessary in case you have set the size of the element first then latter, // you define its MinimumSize and/or MaximumSize size. unsigned int w = (*it)->GetBaseWidth(); unsigned int h = (*it)->GetBaseHeight(); (*it)->SetBaseWidth(w); (*it)->SetBaseHeight(h); } } } while (need_recompute); } unsigned int VLayout::GetMaxStretchFactor() { unsigned int value = 0; unsigned int sf; std::list::iterator it; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; // In the recursive process, make sure we get always the highest stretch factor // of an element that has not been bounded. if ((*it)->IsLayoutDone() == false) { sf = (*it)->GetScaleFactor(); if (sf >= value) { value = sf; } } } return value; } void VLayout::ComputeContentPosition(float offsetX, float offsetY) { std::list::iterator it; { unsigned int num_element = 0; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if ((*it)->IsVisible()) num_element++; } // Get layout Width and Height int width = GetBaseWidth(); int height = GetBaseHeight(); // remove the margins width -= (left_padding_ + right_padding_); height -= (int) (num_element - 1) * space_between_children_ + (top_padding_ + bottom_padding_); // Objects have been resized, now position them. int current_x = GetBaseX() + left_padding_ + offsetX; // add base offset in X(used for scrolling) int current_y = GetBaseY() + top_padding_ + offsetY; // add base offset in Y(used for scrolling) int offset_space = 0; int element_margin = 0; ComputeStacking(height, offset_space, element_margin); current_y += offset_space; for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; current_y += element_margin; (*it)->SetBaseX(current_x); (*it)->SetBaseY(current_y); MinorDimensionPosition positioning = (*it)->GetPositioning(); if ((*it)->GetBaseWidth() < width) { int widget_width = (*it)->GetBaseWidth(); switch(positioning) { case MINOR_POSITION_START: { // do nothing (*it)->SetBaseX(current_x); break; } case MINOR_POSITION_END: { if (widget_width < width) (*it)->SetBaseX(current_x + width - widget_width); else (*it)->SetBaseX(current_x); break; } case MINOR_POSITION_CENTER: default: { if (widget_width < width) (*it)->SetBaseX(current_x + (width - widget_width) / 2); else (*it)->SetBaseX(current_x); } } } current_y += (*it)->GetBaseHeight() + element_margin + space_between_children_; } } for (it = _layout_element_list.begin(); it != _layout_element_list.end(); ++it) { if (!(*it)->IsVisible()) continue; if ((*it)->Type().IsDerivedFromType(Layout::StaticObjectType)) { (*it)->ComputeContentPosition(offsetX, offsetY); } else if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) { (*it)->ComputeContentPosition(offsetX, offsetY); } } } Area* VLayout::KeyNavIteration(KeyNavDirection direction) { if (_layout_element_list.size() == 0) return NULL; if (IsVisible() == false) return NULL; if (next_object_to_key_focus_area_) { if ((direction == KEY_NAV_LEFT) || (direction == KEY_NAV_RIGHT)) { // Don't know what to do with this return NULL; } std::list::iterator it; std::list::iterator it_next; it = std::find(_layout_element_list.begin(), _layout_element_list.end(), next_object_to_key_focus_area_); if (it == _layout_element_list.end()) { // Should never happen nuxAssert(0); return NULL; } it_next = it; ++it_next; if ((direction == KEY_NAV_UP) && (it == _layout_element_list.begin())) { // can't go further return NULL; } if ((direction == KEY_NAV_DOWN) && (it_next == _layout_element_list.end())) { // can't go further return NULL; } if (direction == KEY_NAV_UP) { --it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { if (it == _layout_element_list.begin()) break; --it; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_DOWN) { ++it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == _layout_element_list.end()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } } else { Area* key_nav_focus = NULL; if (direction == KEY_NAV_UP) { std::list::reverse_iterator it = _layout_element_list.rbegin(); key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == _layout_element_list.rend()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } } else { std::list::iterator it = _layout_element_list.begin(); key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == _layout_element_list.end()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } } return key_nav_focus; } return NULL; } } nux-4.0.8+18.10.20180623/Nux/VLayout.h0000644000000000000000000000354313313373365013134 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef VLAYOUT_H #define VLAYOUT_H #include "LinearLayout.h" namespace nux { class VLayout: public LinearLayout { NUX_DECLARE_OBJECT_TYPE(VLayout, LinearLayout); public: VLayout(NUX_FILE_LINE_PROTO); VLayout(std::string name, NUX_FILE_LINE_PROTO); ~VLayout(); virtual long ComputeContentSize(); virtual void ComputeContentPosition(float offsetX, float offsetY); virtual void VLayoutManagement(int width, int height); virtual unsigned int GetMaxStretchFactor(); virtual void GetCompositeList(std::list *ViewList); //! Compute the how elements are spread inside the layout /*! @param remaining_height Size that remains after subtracting elements height, inner and outer margins from the content height. @param offset_space The space at the top of all elements. @param element_margin The margin between elements. */ void ComputeStacking(int length, int &offset_space, int &element_margin); protected: virtual Area* KeyNavIteration(KeyNavDirection direction); }; } #endif // VLAYOUT_H nux-4.0.8+18.10.20180623/Nux/VScrollBar.cpp0000644000000000000000000003375313313373365014103 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" #include "VScrollBar.h" namespace nux { const int VSCROLLBAR_WIDTH = 5; const int VSCROLLBAR_HEIGHT = 10; VScrollBar::VScrollBar(NUX_FILE_LINE_DECL) : ScrollBar(NUX_FILE_LINE_PARAM) { content_width_ = 0; content_height_ = 0; container_width_ = 0; container_height_ = 0; m_TrackWidth = 0; m_TrackHeight = 0; m_SlideBarOffsetX = 0; m_SlideBarOffsetY = 0; content_offset_x_ = 0; content_offset_y_ = 0; b_MouseUpTimer = false; b_MouseDownTimer = false; m_color_factor = 1.0f; m_UpTimerHandler = 0; m_DownTimerHandler = 0; vlayout = new VLayout(NUX_TRACKER_LOCATION); _scroll_up_button = new BasicView(NUX_TRACKER_LOCATION); _track = new BasicView(NUX_TRACKER_LOCATION); _scroll_down_button = new BasicView(NUX_TRACKER_LOCATION); _slider = new BasicView(NUX_TRACKER_LOCATION); _slider->SetParentObject(this); // Set Original State SetMinimumSize(VSCROLLBAR_WIDTH, AREA_MIN_HEIGHT); SetMaximumSize(VSCROLLBAR_WIDTH, AREA_MAX_HEIGHT); // Set Signals //_scroll_down_button->mouse_down.connect(sigc::mem_fun(this, &VScrollBar::RecvStartScrollDown)); //_scroll_down_button->mouse_up.connect(sigc::mem_fun(this, &VScrollBar::RecvEndScrollDown)); //_scroll_up_button->mouse_down.connect(sigc::mem_fun(this, &VScrollBar::RecvStartScrollUp)); //_scroll_up_button->mouse_up.connect(sigc::mem_fun(this, &VScrollBar::RecvEndScrollUp)); _slider->mouse_down.connect(sigc::mem_fun(this, &VScrollBar::OnSliderMouseDown)); _slider->mouse_up.connect(sigc::mem_fun(this, &VScrollBar::OnSliderMouseUp)); _slider->mouse_drag.connect(sigc::mem_fun(this, &VScrollBar::OnSliderMouseDrag)); _track->mouse_down.connect(sigc::mem_fun(this, &VScrollBar::RecvTrackMouseDown)); _track->mouse_up.connect(sigc::mem_fun(this, &VScrollBar::RecvTrackMouseUp)); _track->mouse_drag.connect(sigc::mem_fun(this, &VScrollBar::RecvTrackMouseDrag)); //_track->mouse_down.connect(sigc::mem_fun(this, &VScrollBar::OnSliderMouseDown)); // Set Geometry _scroll_down_button->SetMinimumSize(VSCROLLBAR_WIDTH, VSCROLLBAR_HEIGHT); _scroll_down_button->SetMaximumSize(VSCROLLBAR_WIDTH, VSCROLLBAR_HEIGHT); _scroll_down_button->SetGeometry(Geometry(0, 0, VSCROLLBAR_WIDTH, VSCROLLBAR_HEIGHT)); _scroll_up_button->SetMinimumSize(VSCROLLBAR_WIDTH, VSCROLLBAR_HEIGHT); _scroll_up_button->SetMaximumSize(VSCROLLBAR_WIDTH, VSCROLLBAR_HEIGHT); _scroll_up_button->SetGeometry(Geometry(0, 0, VSCROLLBAR_WIDTH, VSCROLLBAR_HEIGHT)); vlayout->AddView(_scroll_up_button, 0, eCenter, eFix); vlayout->AddView(_track, 1, eCenter, eFull); vlayout->AddView(_scroll_down_button, 0, eCenter, eFix); callback = new TimerFunctor; callback->tick.connect(sigc::mem_fun(this, &VScrollBar::VScrollBarHandler)); up_callback = new TimerFunctor; up_callback->tick.connect(sigc::mem_fun(this, &VScrollBar::ScrollUp)); down_callback = new TimerFunctor; down_callback->tick.connect(sigc::mem_fun(this, &VScrollBar::ScrollDown)); trackup_callback = new TimerFunctor; trackup_callback->tick.connect(sigc::mem_fun(this, &VScrollBar::TrackUp)); trackdown_callback = new TimerFunctor; trackdown_callback->tick.connect(sigc::mem_fun(this, &VScrollBar::TrackDown)); SetLayout(vlayout); SetAcceptMouseWheelEvent(true); } VScrollBar::~VScrollBar() { _slider->UnReference(); delete callback; delete up_callback; delete trackup_callback; delete down_callback; delete trackdown_callback; } void VScrollBar::VScrollBarHandler(void *v) { VScrollBar *scrollbar = static_cast (v); if (scrollbar->b_MouseUpTimer && scrollbar->m_color_factor < 1) { scrollbar->m_color_factor += 0.1f; if (scrollbar->m_color_factor >= 1) { scrollbar->m_color_factor = 1; scrollbar->b_MouseUpTimer = false; } else { scrollbar->QueueDraw(); GetTimer().AddOneShotTimer(10, callback, scrollbar); } } if (scrollbar->b_MouseDownTimer && scrollbar->m_color_factor > 0) { scrollbar->m_color_factor -= 0.09f; if (scrollbar->m_color_factor <= 0) { scrollbar->m_color_factor = 0; scrollbar->b_MouseUpTimer = false; } else { scrollbar->QueueDraw(); GetTimer().AddOneShotTimer(10, callback, scrollbar); } } QueueDraw(); } void VScrollBar::ScrollDown(void * /* v */) { OnScrollDown.emit(m_ScrollUnit, 1); if (AtMaximum()) RecvEndScrollDown(0, 0, 0, 0); else m_DownTimerHandler = GetTimer().AddOneShotTimer(10, down_callback, this); QueueDraw(); } void VScrollBar::ScrollUp(void * /* v */) { OnScrollUp.emit(m_ScrollUnit, 1); if (AtMaximum()) RecvEndScrollUp(0, 0, 0, 0); else m_UpTimerHandler = GetTimer().AddOneShotTimer(10, up_callback, this); QueueDraw(); } void VScrollBar::TrackUp(void * /* v */) { if (m_TrackMouseCoord.y < _slider->GetBaseY() - _track->GetBaseY()) { OnScrollUp.emit(container_height_, 1); m_TrackUpTimerHandler = GetTimer().AddOneShotTimer(10, trackup_callback, this); QueueDraw(); } } void VScrollBar::TrackDown(void * /* v */) { if (m_TrackMouseCoord.y > _slider->GetBaseY() + _slider->GetBaseHeight() - _track->GetBaseY()) { OnScrollDown.emit(container_height_, 1); m_TrackDownTimerHandler = GetTimer().AddOneShotTimer(10, trackdown_callback, this); QueueDraw(); } } void VScrollBar::RecvStartScrollUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (!AtMinimum()) ScrollUp(this); } void VScrollBar::RecvEndScrollUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_UpTimerHandler.IsValid()) { GetTimer().RemoveTimerHandler(m_UpTimerHandler); m_UpTimerHandler = 0; } } void VScrollBar::RecvStartScrollDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (!AtMaximum()) ScrollDown(this); } void VScrollBar::RecvEndScrollDown(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_DownTimerHandler.IsValid()) { GetTimer().RemoveTimerHandler(m_DownTimerHandler); m_DownTimerHandler = 0; } } void VScrollBar::RecvTrackMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { m_TrackMouseCoord = Point(x, y); int Y = _slider->GetBaseY() - _track->GetBaseY(); if (y < Y) { // move the slide bar up TrackUp(this); } else { TrackDown(this); // move the slide bar down } } void VScrollBar::RecvTrackMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (m_TrackUpTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_TrackUpTimerHandler); if (m_TrackDownTimerHandler.IsValid()) GetTimer().RemoveTimerHandler(m_TrackDownTimerHandler); m_TrackUpTimerHandler = 0; m_TrackDownTimerHandler = 0; } void VScrollBar::RecvTrackMouseDrag(int /* x */, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */) { } Area* VScrollBar::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; NUX_RETURN_VALUE_IF_TRUE(_scroll_down_button->TestMousePointerInclusion(mouse_position, event_type), _scroll_down_button); NUX_RETURN_VALUE_IF_TRUE(_scroll_up_button->TestMousePointerInclusion(mouse_position, event_type), _scroll_up_button); NUX_RETURN_VALUE_IF_TRUE(_slider->TestMousePointerInclusion(mouse_position, event_type), _slider); NUX_RETURN_VALUE_IF_TRUE(_track->TestMousePointerInclusion(mouse_position, event_type), _track); if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } void VScrollBar::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); GetPainter().PaintBackground(graphics_engine, base); base.OffsetPosition(0, VSCROLLBAR_HEIGHT); base.OffsetSize(0, -2 * VSCROLLBAR_HEIGHT); //GetPainter().PaintShape(graphics_engine, base, Color(COLOR_SCROLLBAR_TRACK), eVSCROLLBAR, false); //graphics_engine.QRP_Color(base.x, base.y, base.width, base.height, Color(COLOR_SCROLLBAR_TRACK)); //GetPainter().PaintShape(graphics_engine, _scroll_up_button->GetGeometry(), Color(0xFFFFFFFF), eSCROLLBAR_TRIANGLE_UP); //GetPainter().PaintShape(graphics_engine, _scroll_down_button->GetGeometry(), Color(0xFFFFFFFF), eSCROLLBAR_TRIANGLE_DOWN); /*GetPainter().PaintShape(graphics_engine, _slider->GetGeometry(), Color(0.2156 * m_color_factor, 0.2156 * m_color_factor, 0.2156 * m_color_factor, 1.0f), eVSCROLLBAR, true);*/ if (content_height_ > container_height_) { Geometry slider_geo = _slider->GetGeometry(); graphics_engine.QRP_Color(slider_geo.x, slider_geo.y, slider_geo.width, slider_geo.height, Color(1.0f, 1.0f, 1.0f, 0.8f)); } //Color(0.2156 * m_color_factor, 0.2156 * m_color_factor, 0.2156 * m_color_factor, 1.0f)); } void VScrollBar::SetContainerSize(int /* x */, int /* y */, int w, int h) { container_width_ = w; container_height_ = h; ComputeScrolling(); } void VScrollBar::SetContentSize(int /* x */, int /* y */, int w, int h) { // x and y are not needed content_width_ = w; content_height_ = h; ComputeScrolling(); } void VScrollBar::SetContentOffset(float dx, float dy) { content_offset_x_ = dx; content_offset_y_ = dy; ComputeScrolling(); } void VScrollBar::ComputeScrolling() { if (content_height_ == 0) { visibility_percentage_ = 100.0f; } else { visibility_percentage_ = Clamp(100.0f * (float) container_height_ / (float) content_height_, 0.0f, 100.0f); } m_TrackHeight = _track->GetBaseHeight(); int slider_width = _scroll_up_button->GetBaseWidth(); int slider_height = m_TrackHeight * visibility_percentage_ / 100.0f; if (slider_height < 15) { slider_height = 15; } _slider->SetBaseWidth(slider_width); _slider->SetBaseHeight(slider_height); _slider->SetBaseX(_scroll_up_button->GetBaseX()); float pct; if (content_height_ - container_height_ > 0) pct = - (float) content_offset_y_ / (float) (content_height_ - container_height_); else pct = 0; int y = _track->GetBaseY() + pct * (m_TrackHeight - slider_height); _slider->SetBaseY(y); } ///////////////// // RECEIVERS // ///////////////// void VScrollBar::SetValue(float /* value */) { //m_ValueString.setCaption(value); } void VScrollBar::SetParameterName(const char * /* parameter_name */) { //m_ParameterName.setCaption(parameter_name); } //////////////// // EMITTERS // //////////////// //void VScrollBar::EmitScrollUp(int x, int y, unsigned long button_flags, unsigned long key_flags) //{ // OnScrollUp.emit(m_ScrollUnit, 1); //} //void VScrollBar::EmitScrollDown(int x, int y, unsigned long button_flags, unsigned long key_flags) //{ // OnScrollDown.emit(m_ScrollUnit, 1); //} void VScrollBar::OnSliderMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */) { m_SliderDragPositionX = x; m_SliderDragPositionY = y; //sigVScrollBarSliderMouseDown.emit(); b_MouseDownTimer = true; b_MouseUpTimer = false; GetTimer().AddOneShotTimer(10, callback, this); } void VScrollBar::OnSliderMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */) { b_MouseDownTimer = false; b_MouseUpTimer = true; GetTimer().AddOneShotTimer(10, callback, this); } void VScrollBar::OnSliderMouseDrag(int /* x */, int y, int /* dx */, int dy, unsigned long /* button_flags */, unsigned long /* key_flags */) { if (_track->GetBaseHeight() - _slider->GetBaseHeight() > 0) { stepY = (float) (content_height_ - container_height_) / (float) (_track->GetBaseHeight() - _slider->GetBaseHeight()); } else { return; } if ((dy > 0) && (y > m_SliderDragPositionY)) { OnScrollDown.emit(stepY, y - m_SliderDragPositionY); } if ((dy < 0) && (y < m_SliderDragPositionY)) { OnScrollUp.emit(stepY, m_SliderDragPositionY - y); } QueueDraw(); } bool VScrollBar::AtMaximum() { if (_slider->GetBaseY() + _slider->GetBaseHeight() == _track->GetBaseY() + _track->GetBaseHeight()) return TRUE; return FALSE; } bool VScrollBar::AtMinimum() { if (_slider->GetBaseY() == _track->GetBaseY()) return TRUE; return FALSE; } long VScrollBar::PostLayoutManagement(long LayoutResult) { long ret = ScrollBar::PostLayoutManagement(LayoutResult); ComputeScrolling(); return ret; } } nux-4.0.8+18.10.20180623/Nux/VScrollBar.h0000644000000000000000000001076113313373365013542 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef VSCROLLBAR_H #define VSCROLLBAR_H #include "TimerProc.h" #include "ScrollBar.h" namespace nux { class VLayout; class VScrollBar: public ScrollBar { public: VScrollBar(NUX_FILE_LINE_PROTO); ~VScrollBar(); virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); void DrawDownTriangle(GraphicsEngine &graphics_engine, int width, int height, const Geometry &geo, BasePainter &painter); void DrawUpTriangle(GraphicsEngine &graphics_engine, int width, int height, const Geometry &geo, BasePainter &painter); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); private: virtual void DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) {}; void VScrollBarHandler(void *v); void ScrollDown(void *v); void ScrollUp(void *v); void TrackUp(void *v); void TrackDown(void *v); public: void SetContainerSize(int x, int y, int w, int h); void SetContentSize(int x, int y, int w, int h); void SetContentOffset(float dx, float dy); void ComputeScrolling(); ///////////////// // RECEIVERS // ///////////////// void SetValue(float value); void SetParameterName(const char *parameter_name); //////////////// // EMITTERS // //////////////// void RecvStartScrollDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvStartScrollUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvEndScrollDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvEndScrollUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTrackMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTrackMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void RecvTrackMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void OnSliderMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnSliderMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); void OnSliderMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); /////////////// // SIGNALS // /////////////// sigc::signal sigClick; sigc::signal OnScrollUp; sigc::signal OnScrollDown; sigc::signal sigVScrollBarSliderMouseDown; bool b_MouseDownTimer; bool b_MouseUpTimer; float m_color_factor; protected: // When the Scrollbar is used standalone, it is necessary to call ComputeScrolling at the end of the layout. virtual long PostLayoutManagement(long LayoutResult); bool AtMinimum(); bool AtMaximum(); VLayout *vlayout; BasicView *_slider; BasicView *_scroll_up_button; BasicView *_scroll_down_button; BasicView *_track; int content_width_; int content_height_; float content_offset_x_; float content_offset_y_; int container_width_; int container_height_; int m_TrackWidth; int m_TrackHeight; int m_SlideBarOffsetX; int m_SlideBarOffsetY; float stepX; float stepY; int m_SliderDragPositionX; int m_SliderDragPositionY; TimerFunctor *callback; TimerFunctor *up_callback; TimerFunctor *down_callback; TimerFunctor *trackup_callback; TimerFunctor *trackdown_callback; TimerHandle m_UpTimerHandler; TimerHandle m_DownTimerHandler; TimerHandle m_TrackUpTimerHandler; TimerHandle m_TrackDownTimerHandler; Point m_TrackMouseCoord; friend class VLayout; friend class ScrollView; }; } #endif // HSCROLLBAR_H nux-4.0.8+18.10.20180623/Nux/VSplitter.cpp0000644000000000000000000005012213313373365014013 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "VSplitter.h" #include "NuxGraphics/GLTextureResourceManager.h" #include "WindowCompositor.h" #include "Layout.h" #include "HLayout.h" #include "VLayout.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(VSplitter); static const int VSPLITTERWIDTH = 5; static const int VSTICK_SIZE = 5; VSplitter::VSplitter(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { new_addition = false; m_initial_config = true; m_focus_splitter_index = -1; m_ResizeOnSplitterRelease = true; mvt_dx = 0; mvt_dy = 0; m_current_x = 0; m_current_y = 0; m_current_width = 100; m_current_height = 100; //SetMinimumSize(m_current_width, m_current_height); SetGeometry(Geometry(m_current_x, m_current_y, m_current_width, m_current_height)); } VSplitter::~VSplitter() { // Delete all the interface object: This is a problem... The widget should be destroy by there associated parameters //delete vlayout; std::vector< Area* >::iterator it0; for (it0 = m_InterfaceObject.begin(); it0 != m_InterfaceObject.end(); ++it0) { (*it0)->UnParentObject(); } m_InterfaceObject.clear(); std::vector< MySplitter* >::iterator it2; for (it2 = m_SplitterObject.begin(); it2 != m_SplitterObject.end(); ++it2) { (*it2)->UnParentObject(); } m_SplitterObject.clear(); m_SplitConfig.clear(); } void VSplitter::Draw(GraphicsEngine &graphics_engine, bool /* force_draw */) { Geometry base = GetGeometry(); graphics_engine.PushClippingRectangle(base); std::vector::iterator it; GetPainter().PaintBackground(graphics_engine, base); std::vector::iterator it_splitter; for (it_splitter = m_SplitterObject.begin(); it_splitter != m_SplitterObject.end(); ++it_splitter) { Geometry geo = (*it_splitter)->GetGeometry(); Geometry grip_geo; int h = 20; if (geo.GetHeight() > h) { grip_geo.SetX(geo.x); grip_geo.SetY(geo.y + (geo.GetHeight() - h) / 2); grip_geo.SetWidth(geo.GetWidth()); grip_geo.SetHeight(h); } else { grip_geo.SetX(geo.x); grip_geo.SetY(geo.y + (h - geo.GetHeight()) / 2); grip_geo.SetWidth(geo.GetWidth()); grip_geo.SetHeight(h); } GetPainter().Draw2DLine(graphics_engine, grip_geo.x + 1, grip_geo.y, grip_geo.x + 1, grip_geo.y + grip_geo.GetHeight(), Color(0xFF111111)); GetPainter().Draw2DLine(graphics_engine, grip_geo.x + 3, grip_geo.y, grip_geo.x + 3, grip_geo.y + grip_geo.GetHeight(), Color(0xFF111111)); } graphics_engine.PopClippingRectangle(); } void VSplitter::DrawContent(GraphicsEngine &graphics_engine, bool force_draw) { graphics_engine.PushClippingRectangle(GetGeometry()); Geometry base = GetGeometry(); bool need_redraw = IsRedrawNeeded(); std::vector::iterator it_splitter; std::vector::iterator it; for (it = m_InterfaceObject.begin(), it_splitter = m_SplitterObject.begin(); it != m_InterfaceObject.end(); ++it, ++it_splitter) { Geometry sgeo = (*it_splitter)->GetGeometry(); graphics_engine.PushClippingRectangle(Rect( base.x, base.y, sgeo.x - base.x, base.GetHeight())); base.SetX(sgeo.x + sgeo.GetWidth()); if (force_draw || need_redraw) { if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = NUX_STATIC_CAST(View *, (*it)); ic->ProcessDraw(graphics_engine, true); } else if ((*it)->Type().IsObjectType(HLayout::StaticObjectType)) { HLayout *layout = NUX_STATIC_CAST(HLayout *, (*it)); layout->ProcessDraw(graphics_engine, true); } else if ((*it)->Type().IsObjectType(VLayout::StaticObjectType)) { VLayout *layout = NUX_STATIC_CAST(VLayout *, (*it)); layout->ProcessDraw(graphics_engine, true); } } else { if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = NUX_STATIC_CAST(View *, (*it)); ic->ProcessDraw(graphics_engine, false); } else if ((*it)->Type().IsObjectType(HLayout::StaticObjectType)) { HLayout *layout = NUX_STATIC_CAST(HLayout *, (*it)); layout->ProcessDraw(graphics_engine, false); } else if ((*it)->Type().IsObjectType(VLayout::StaticObjectType)) { VLayout *layout = NUX_STATIC_CAST(VLayout *, (*it)); layout->ProcessDraw(graphics_engine, false); } } graphics_engine.PopClippingRectangle(); } graphics_engine.PopClippingRectangle(); } void VSplitter::OverlayDrawing(GraphicsEngine &graphics_engine) { unsigned int num_element = (unsigned int) m_SplitterObject.size(); Geometry base = GetGeometry(); if (m_focus_splitter_index >= 0) { Geometry geo = m_SplitterObject[m_focus_splitter_index]->GetGeometry(); geo.OffsetPosition(mvt_dx, mvt_dy); if (m_focus_splitter_index == 0 && num_element > 1) { if (geo.x < base.x) { geo.SetX(base.x); } if (geo.x + VSPLITTERWIDTH > m_SplitterObject[m_focus_splitter_index + 1]->GetGeometry().x) { geo.SetX(m_SplitterObject[m_focus_splitter_index+1]->GetGeometry().x - VSPLITTERWIDTH); } } if ((m_focus_splitter_index > 0) && m_focus_splitter_index < (int) num_element - 1) { if (geo.x < m_SplitterObject[m_focus_splitter_index - 1]->GetGeometry().x + VSPLITTERWIDTH) { geo.SetX(m_SplitterObject[m_focus_splitter_index - 1]->GetGeometry().x + VSPLITTERWIDTH); } if (geo.x + VSPLITTERWIDTH > m_SplitterObject[m_focus_splitter_index + 1]->GetGeometry().x) { geo.SetX(m_SplitterObject[m_focus_splitter_index + 1]->GetGeometry().x - VSPLITTERWIDTH); } } graphics_engine.GetRenderStates().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); { GetPainter().Paint2DQuadColor(graphics_engine, geo, Color(0xBB868686)); } graphics_engine.GetRenderStates().SetBlend(false); } } void VSplitter::AddWidget(Area *ic, float stretchfactor) { if (ic) { MySplitter* splitter = new MySplitter; splitter->SetParentObject(this); //splitter->SinkReference(); unsigned int no = (unsigned int) m_InterfaceObject.size(); splitter->mouse_down.connect(sigc::bind(sigc::mem_fun(this, &VSplitter::OnSplitterMouseDown), no)); splitter->mouse_up.connect(sigc::bind(sigc::mem_fun(this, &VSplitter::OnSplitterMouseUp), no)); splitter->mouse_drag.connect(sigc::bind(sigc::mem_fun(this, &VSplitter::OnSplitterMouseDrag), no)); ic->SetParentObject(this); m_InterfaceObject.push_back(ic); m_SplitterObject.push_back(splitter); m_SplitConfig.push_back(stretchfactor); new_addition = true; ComputeContentSize(); } } void VSplitter::clearContent() { m_InterfaceObject.clear(); } long VSplitter::ComputeContentSize() { unsigned int num_element = (unsigned int) m_InterfaceObject.size(); int x = GetBaseX(); int y = GetBaseY(); int w = GetBaseWidth(); int h = GetBaseHeight(); if ((w == 0) || (h == 0)) { return eCompliantHeight | eCompliantWidth; } if (num_element < 1) { m_current_height = h; m_current_width = w; m_current_x = x; m_current_y = y; new_addition = false; return eCompliantHeight | eCompliantWidth; } std::vector::iterator it; std::vector::iterator it_splitter; if (new_addition) { ResetSplitConfig(); new_addition = false; } if (m_current_height != h) { for (unsigned int i = 0; i < num_element; i++) { Geometry splitter_geo = m_SplitterObject[i]->GetGeometry(); splitter_geo.SetHeight(h); splitter_geo.SetY(y); m_SplitterObject[i]->SetGeometry(splitter_geo); } } if (m_current_width != w) { int size_to_distribute = w - num_element * VSPLITTERWIDTH; int previous_spliter_end = m_current_x; int new_spliter_end = x; for (unsigned int i = 0; i < num_element; i++) { Geometry splitter_geo = m_SplitterObject[i]->GetGeometry(); // compute percentage of space occupied by the element i; // width of element i = m_SplitterObject[i]->GetX() - previous_splliter_end int splitter_start = m_SplitterObject[i]->GetBaseX(); float percent = float(splitter_start - previous_spliter_end) / float(m_current_width - num_element * VSPLITTERWIDTH); if (percent > 1.0f) percent = 1.0f; splitter_geo.SetX(new_spliter_end + size_to_distribute * percent); previous_spliter_end = splitter_start + VSPLITTERWIDTH; new_spliter_end = new_spliter_end + size_to_distribute * percent + VSPLITTERWIDTH; m_SplitterObject[i]->SetGeometry(splitter_geo); } if (m_SplitterObject[0]->GetBaseX() < x) { m_SplitterObject[0]->SetBaseX(x); } m_SplitterObject[num_element-1]->SetBaseX(x + w - VSPLITTERWIDTH); } int accwidth = x; for (unsigned int i = 0; i < num_element; i++) { Geometry splitter_geo = m_SplitterObject[i]->GetGeometry(); //m_InterfaceObject[i]->SetGeometry(Geometry(accwidth, y, splitter_geo.x - accwidth, h)); if (m_InterfaceObject[i]->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = NUX_STATIC_CAST(View *, m_InterfaceObject[i]); ic->SetGeometry(Geometry(accwidth, y, splitter_geo.x - accwidth, h)); // if we are already computing the layout from the main window down, we need to call // ComputeElementLayout to force the computing of this element layout. GetWindowThread()->ComputeElementLayout(ic); } else if (m_InterfaceObject[i]->Type().IsDerivedFromType(Layout::StaticObjectType)) { Layout *layout = NUX_STATIC_CAST(Layout *, m_InterfaceObject[i]); layout->SetGeometry(Geometry(accwidth, y, splitter_geo.x - accwidth, h)); // if we are already computing the layout from the main window down, we need to call // ComputeElementLayout to force the computing of this element layout. GetWindowThread()->ComputeElementLayout(layout); } accwidth += splitter_geo.x - accwidth + VSPLITTERWIDTH; } m_current_height = h; m_current_width = w; m_current_x = x; m_current_y = y; return eCompliantHeight | eCompliantWidth; } void VSplitter::ResetSplitConfig() { int x = GetBaseX(); int y = GetBaseY(); int w = GetBaseWidth(); int h = GetBaseHeight(); unsigned int num_element = (unsigned int) m_InterfaceObject.size(); if (num_element < 1) { return; } float max_stretch = 0.0f; float stretchfactor; for (unsigned int i = 0; i < (unsigned int) m_SplitConfig.size(); i++) { stretchfactor = m_SplitConfig[i]; if (max_stretch < stretchfactor) { max_stretch = stretchfactor; } } float total = 0; for (unsigned int i = 0; i < (unsigned int) m_SplitConfig.size(); i++) { stretchfactor = m_SplitConfig[i]; total += stretchfactor / max_stretch; } int availableheight = (w - num_element * VSPLITTERWIDTH); float max_size = float(availableheight) / total; for (unsigned int i = 0; i < (unsigned int) m_SplitConfig.size(); i++) { stretchfactor = m_SplitConfig[i]; x += stretchfactor * max_size / max_stretch; Geometry geo(x, y, VSPLITTERWIDTH, h); m_SplitterObject[i]->SetGeometry(geo); } m_SplitterObject[num_element-1]->SetBaseX(x + w - VSPLITTERWIDTH); m_initial_config = true; } void VSplitter::OnSplitterMouseDown(int x, int y, unsigned long /* button_flags */, unsigned long /* key_flags */, int header_pos) { m_point = Point(x, y); m_focus_splitter_index = header_pos; GetWindowThread()->GetWindowCompositor().SetWidgetDrawingOverlay(this, GetWindowThread()->GetWindowCompositor().GetProcessingTopView()); // Hint for the window to initiate a redraw GetWindowThread()->RequestRedraw(); } void VSplitter::OnSplitterMouseUp(int /* x */, int /* y */, unsigned long /* button_flags */, unsigned long /* key_flags */, int header_pos) { if (mvt_dx) { Geometry geo = m_SplitterObject[header_pos]->GetGeometry(); geo.OffsetPosition(mvt_dx, 0); unsigned int num_element = (unsigned int) m_SplitterObject.size(); if (header_pos < (int) num_element - 1) { // Make the splitter bar stick to the next one if the distance between them is less than VSTICK_SIZE if (m_SplitterObject[header_pos + 1]->GetGeometry().x - geo.x - VSPLITTERWIDTH < VSTICK_SIZE) geo.SetX( m_SplitterObject[header_pos + 1]->GetGeometry().x - VSPLITTERWIDTH ); } m_SplitterObject[header_pos]->SetGeometry(geo); ResizeSplitter(header_pos); } m_focus_splitter_index = -1; mvt_dx = 0; mvt_dy = 0; // End overlay drawing; GetWindowThread()->GetWindowCompositor().SetWidgetDrawingOverlay(0, GetWindowThread()->GetWindowCompositor().GetProcessingTopView()); // Hint for the window to initiate a redraw GetWindowThread()->RequestRedraw(); } void VSplitter::OnSplitterMouseDrag(int x, int /* y */, int /* dx */, int /* dy */, unsigned long /* button_flags */, unsigned long /* key_flags */, int header_pos) { Geometry geo = m_SplitterObject[header_pos]->GetGeometry(); int num_element = (int) m_SplitterObject.size(); if (header_pos == num_element - 1) { // The last splitter cannot be moved return; } mvt_dx = x - m_point.x; mvt_dy = 0; if (m_ResizeOnSplitterRelease == false) { // Continuously redraw resize and redraw the 2 parts of the widget. // This is slow. geo.OffsetPosition(mvt_dx, mvt_dy); m_SplitterObject[header_pos]->SetGeometry(geo); ResizeSplitter(header_pos); mvt_dx = 0; mvt_dy = 0; } // Hint for the window to initiate a redraw GetWindowThread()->RequestRedraw(); } void VSplitter::ResizeSplitter(int header_pos) { int num_element = (int) m_SplitterObject.size(); if ((header_pos == 0) && (m_SplitterObject[header_pos]->GetBaseX() < GetBaseX())) { m_SplitterObject[header_pos]->SetBaseX(GetBaseX()); } if ((header_pos == num_element - 1) && (m_SplitterObject[header_pos]->GetBaseX() > GetBaseX() + GetBaseWidth() - VSPLITTERWIDTH)) { m_SplitterObject[header_pos]->SetBaseX(GetBaseX() + GetBaseWidth() - VSPLITTERWIDTH); } if (header_pos < (int) num_element - 1) { int posx0, posx1; posx0 = m_SplitterObject[header_pos]->GetBaseX(); posx1 = m_SplitterObject[header_pos + 1]->GetBaseX(); if (posx0 > posx1 - VSPLITTERWIDTH) { posx0 = posx1 - VSPLITTERWIDTH; m_SplitterObject[header_pos]->SetBaseX(posx0); } } if (0 < header_pos) { int posx0, posx1; posx0 = m_SplitterObject[header_pos]->GetBaseX(); posx1 = m_SplitterObject[header_pos - 1]->GetBaseX(); if (posx0 < posx1 + VSPLITTERWIDTH) { posx0 = posx1 + VSPLITTERWIDTH; m_SplitterObject[header_pos]->SetBaseX(posx0); } } m_initial_config = false; ComputeContentSize(); QueueDraw(); } // VSplitter need to re implement DoneRedraw because it does not // have a m_compositionlayout where its child are located; void VSplitter::DoneRedraw() { std::vector::iterator it; for (it = m_InterfaceObject.begin(); it != m_InterfaceObject.end(); ++it) { //(*it)->DoneRedraw(); if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = NUX_STATIC_CAST(View *, (*it)); ic->DoneRedraw(); } } } Area* VSplitter::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; std::vector::iterator splitter_it; for (splitter_it = m_SplitterObject.begin(); splitter_it != m_SplitterObject.end(); ++splitter_it) { Area* found_area = (*splitter_it)->FindAreaUnderMouse(mouse_position, event_type); if (found_area) return found_area; } std::vector::iterator it; for (it = m_InterfaceObject.begin(); it != m_InterfaceObject.end(); ++it) { Area* found_area = (*it)->FindAreaUnderMouse(mouse_position, event_type); if (found_area) return found_area; } if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } bool VSplitter::AcceptKeyNavFocus() { return false; } Area* VSplitter::KeyNavIteration(KeyNavDirection direction) { if (m_InterfaceObject.empty()) return NULL; if (next_object_to_key_focus_area_) { if ((direction == KEY_NAV_UP) || (direction == KEY_NAV_DOWN)) { // Don't know what to do with this return NULL; } std::vector::iterator it; std::vector::iterator it_next; it = std::find(m_InterfaceObject.begin(), m_InterfaceObject.end(), next_object_to_key_focus_area_); if (it == m_InterfaceObject.end()) { // Should never happen nuxAssert(0); return NULL; } it_next = it; ++it_next; if ((direction == KEY_NAV_LEFT) && (it == m_InterfaceObject.begin())) { // can't go further return NULL; } if ((direction == KEY_NAV_RIGHT) && (it_next == m_InterfaceObject.end())) { // can't go further return NULL; } if (direction == KEY_NAV_LEFT) { --it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { if (it == m_InterfaceObject.begin()) break; --it; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } if (direction == KEY_NAV_RIGHT) { ++it; Area* key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == m_InterfaceObject.end()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } return key_nav_focus; } } else { Area* key_nav_focus = NULL; if (direction == KEY_NAV_LEFT) { std::vector::reverse_iterator it = m_InterfaceObject.rbegin(); key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == m_InterfaceObject.rend()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } } else { std::vector::iterator it = m_InterfaceObject.begin(); key_nav_focus = (*it)->KeyNavIteration(direction); while (key_nav_focus == NULL) { ++it; if (it == m_InterfaceObject.end()) break; key_nav_focus = (*it)->KeyNavIteration(direction); } } return key_nav_focus; } return NULL; } } nux-4.0.8+18.10.20180623/Nux/VSplitter.h0000644000000000000000000000600613313373365013462 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef VSPLITTER_H #define VSPLITTER_H namespace nux { class layout; class VSplitter: public View { NUX_DECLARE_OBJECT_TYPE(VSplitter, View); public: VSplitter(NUX_FILE_LINE_PROTO); ~VSplitter(); virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw); virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); void AddWidget(Area *ic, float stretchfactor); void ResetSplitConfig(); void clearContent(); void OnSplitterMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags, int header_pos); void OnSplitterMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags, int header_pos); void OnSplitterMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags, int header_pos); virtual void OverlayDrawing(GraphicsEngine &graphics_engine); //! Return true if this object can break the layout. /* Return true if this object can break the layout, meaning, the layout can be done on the composition layout only without recomputing the whole window layout. Inherited from Area */ virtual bool CanBreakLayout() { return true; } virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); protected: virtual long ComputeContentSize(); virtual void DoneRedraw(); void ResizeSplitter(int header_pos); //void ContinuousSplitterAdjustment(); void setResizeOnSplitterRelease(bool b) { m_ResizeOnSplitterRelease = b; } bool getResizeOnSplitterRelease() { return m_ResizeOnSplitterRelease; } virtual bool AcceptKeyNavFocus(); virtual Area* KeyNavIteration(KeyNavDirection direction); private: typedef BasicView MySplitter; std::vector m_InterfaceObject; std::vector m_SplitterObject; std::vector m_SplitConfig; Point m_point; bool new_addition; bool m_ResizeOnSplitterRelease; int m_current_width; int m_current_height; int m_current_x; int m_current_y; bool m_initial_config; // splitter bar differential position; int mvt_dx, mvt_dy; int m_focus_splitter_index; }; } #endif // VSPLITTER_H nux-4.0.8+18.10.20180623/Nux/Validator.cpp0000644000000000000000000000460013313373365014004 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "Validator.h" namespace nux { Validator::Validator() { } Validator::~Validator() { } bool Validator::InitRegExp() { #if defined(NUX_OS_WINDOWS) regex_ = _regexp_str.c_str(); return true; #else const char *error; int erroffset; _regexp = pcre_compile( _regexp_str.c_str(), /* the pattern */ PCRE_MULTILINE, &error, /* for error message */ &erroffset, /* for error offset */ 0); /* use default character tables */ if (!_regexp) { nuxDebugMsg("[IntegerValidator::IntegerValidator] Invalid regular expression: %s", _regexp_str.c_str()); return false; } return true; #endif } Validator::State Validator::Validate(const char* str) const { #if defined(NUX_OS_WINDOWS) if (str == NULL) return Validator::Invalid; std::string search_string = str; if (std::regex_match(search_string.begin(), search_string.end(), regex_)) { return Validator::Acceptable; } return Validator::Acceptable; #else if (_regexp == 0) return Validator::Invalid; int out_vector [10]; unsigned int offset = 0; int len = (int) strlen(str); // See the "PCRE DISCUSSION OF STACK USAGE" and why it maybe necessary to limit the stack usage. pcre_extra extra; extra.flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION; extra.match_limit_recursion = 2000; int rc = pcre_exec(_regexp, &extra, str, len, offset, 0, out_vector, 10); if (rc <= -1) { return Validator::Invalid; } return Validator::Acceptable; #endif } } nux-4.0.8+18.10.20180623/Nux/Validator.h0000644000000000000000000000270313313373365013453 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef VALIDATOR_H #define VALIDATOR_H #if defined(NUX_OS_WINDOWS) #include #else #include #endif namespace nux { class Validator { public: enum State { Invalid = 0, Intermediate, Acceptable }; Validator(); virtual ~Validator(); virtual Validator *Clone() const = 0; //Virtual Constructor Idiom virtual Validator::State Validate(const char *str) const; virtual void Alternative(const char * /* str */) {} protected: bool InitRegExp(); std::string _regexp_str; #if defined(NUX_OS_WINDOWS) std::regex regex_; #else pcre *_regexp; #endif }; } #endif // VALIDATOR_H nux-4.0.8+18.10.20180623/Nux/View.cpp0000644000000000000000000004756113313373365013006 0ustar /* * Copyright 2010, 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "WindowCompositor.h" #include "Layout.h" #include "View.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE(View); View::View(NUX_FILE_LINE_DECL) : InputArea(NUX_FILE_LINE_PARAM) , m_TextColor(1.0f, 1.0f, 1.0f, 1.0f) , view_layout_(nullptr) , draw_cmd_queued_(false) , child_draw_cmd_queued_(false) { } View::~View() { backup_fbo_.Release(); backup_texture_.Release(); backup_depth_texture_.Release(); background_texture_.Release(); RemoveLayout(); } long View::ComputeContentSize() { if (view_layout_) { PreLayoutManagement(); int PreWidth = GetBaseWidth(); int PreHeight = GetBaseHeight(); long ret = view_layout_->ComputeContentSize(); PostLayoutManagement(ret); int PostWidth = GetBaseWidth(); int PostHeight = GetBaseHeight(); long size_compliance = 0; // The layout has been resized to tightly pack its content if (PostWidth > PreWidth) { size_compliance |= eLargerWidth; // need scrollbar } else if (PostWidth < PreWidth) { size_compliance |= eSmallerWidth; } else { size_compliance |= eCompliantWidth; } // The layout has been resized to tightly pack its content if (PostHeight > PreHeight) { size_compliance |= eLargerHeight; // need scrollbar } else if (PostHeight < PreHeight) { size_compliance |= eSmallerHeight; } else { size_compliance |= eCompliantHeight; } return size_compliance; } else { PreLayoutManagement(); int ret = PostLayoutManagement(eCompliantHeight | eCompliantWidth); return ret; } return 0; } void View::ComputeContentPosition(float offsetX, float offsetY) { if (view_layout_) { view_layout_->SetBaseX(GetBaseX()); view_layout_->SetBaseY(GetBaseY()); view_layout_->ComputeContentPosition(offsetX, offsetY); } } void View::PreLayoutManagement() { // Give the managed layout the same size and position as the Control. if (view_layout_) view_layout_->SetGeometry(GetGeometry()); } long View::PostLayoutManagement(long LayoutResult) { // Set the geometry of the control to be the same as the managed layout. // Only the size is changed. The position of the composition layout hasn't // been changed by ComputeContentSize. if (view_layout_) { // If The layout is empty, do not change the size of the parent element. if (!view_layout_->IsEmpty()) Area::SetGeometry(view_layout_->GetGeometry()); } return LayoutResult; } void View::PreResizeGeometry() { } void View::PostResizeGeometry() { } void View::ProcessDraw(GraphicsEngine& graphics_engine, bool force_draw) { full_view_draw_cmd_ = false; if (RedirectRenderingToTexture()) { if (update_backup_texture_ || force_draw || draw_cmd_queued_) { GetPainter().PushPaintLayerStack(); BeginBackupTextureRendering(graphics_engine, force_draw); { graphics_engine.PushModelViewMatrix(Get2DMatrix()); if (force_draw) { draw_cmd_queued_ = true; full_view_draw_cmd_ = true; Draw(graphics_engine, force_draw); DrawContent(graphics_engine, force_draw); } else { if (draw_cmd_queued_) { full_view_draw_cmd_ = true; Draw(graphics_engine, false); DrawContent(graphics_engine, false); } else if (update_backup_texture_) { DrawContent(graphics_engine, false); } } graphics_engine.PopModelViewMatrix(); } EndBackupTextureRendering(graphics_engine, force_draw); GetPainter().PopPaintLayerStack(); } if (PresentRedirectedView()) { unsigned int current_alpha_blend; unsigned int current_src_blend_factor; unsigned int current_dest_blend_factor; // Be a good citizen, get a copy of the current GPU sates according to Nux graphics_engine.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); TexCoordXForm texxform; if ((force_draw || draw_cmd_queued_) && (background_texture_.IsValid())) { graphics_engine.GetRenderStates().SetBlend(false); texxform.FlipVCoord(true); // Draw the background of this view. GetGraphicsDisplay()->GetGraphicsEngine()->QRP_1Tex(GetX(), GetY(), background_texture_->GetWidth(), background_texture_->GetHeight(), background_texture_, texxform, color::White); } texxform.uwrap = TEXWRAP_CLAMP; texxform.vwrap = TEXWRAP_CLAMP; texxform.FlipVCoord(true); graphics_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); GetGraphicsDisplay()->GetGraphicsEngine()->QRP_1Tex(GetX(), GetY(), GetWidth(), GetHeight(), backup_texture_, texxform, Color(color::White)); // Be a good citizen, restore the Nux blending states. graphics_engine.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); } } else { graphics_engine.PushModelViewMatrix(Get2DMatrix()); if (force_draw) { GetPainter().PaintBackground(graphics_engine, GetGeometry()); GetPainter().PushPaintLayerStack(); draw_cmd_queued_ = true; full_view_draw_cmd_ = true; Draw(graphics_engine, force_draw); DrawContent(graphics_engine, force_draw); GetPainter().PopPaintLayerStack(); } else { if (draw_cmd_queued_) { GetPainter().PaintBackground(graphics_engine, GetGeometry()); GetPainter().PushPaintLayerStack(); full_view_draw_cmd_ = true; Draw(graphics_engine, false); DrawContent(graphics_engine, false); GetPainter().PopPaintLayerStack(); } else { DrawContent(graphics_engine, false); } } graphics_engine.PopModelViewMatrix(); } if (view_layout_) { view_layout_->ResetQueueDraw(); } draw_cmd_queued_ = false; child_draw_cmd_queued_ = false; full_view_draw_cmd_ = false; update_backup_texture_ = false; } void View::BeginBackupTextureRendering(GraphicsEngine& graphics_engine, bool force_draw) { ObjectPtr active_fbo_texture; if (force_draw || draw_cmd_queued_) { // Get the active fbo color texture active_fbo_texture = GetGraphicsDisplay()->GetGpuDevice()->ActiveFboTextureAttachment(0); } Geometry xform_geo; // Compute position in the active fbo texture. xform_geo = graphics_engine.ModelViewXFormRect(GetGeometry()); // Get the active fbo... prev_fbo_ = GetGraphicsDisplay()->GetGpuDevice()->GetCurrentFrameBufferObject(); // ... and the size of the view port rectangle. prev_viewport_ = graphics_engine.GetViewportRect(); const int width = GetWidth(); const int height = GetHeight(); // Compute intersection with active fbo. Geometry intersection = xform_geo; if (active_fbo_texture.IsValid()) { Geometry active_fbo_geo(0, 0, active_fbo_texture->GetWidth(), active_fbo_texture->GetHeight()); intersection = active_fbo_geo.Intersect(xform_geo); } if (backup_fbo_.IsNull()) { // Create the fbo before using it for the first time. backup_fbo_ = GetGraphicsDisplay()->GetGpuDevice()->CreateFrameBufferObject(); } if (!backup_texture_.IsValid() || (backup_texture_->GetWidth() != width) || (backup_texture_->GetHeight() != height)) { // Create or resize the color and depth textures before using them. backup_texture_ = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(width, height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); backup_depth_texture_ = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(width, height, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); } if (!background_texture_.IsValid() || (background_texture_->GetWidth() != intersection.width) || (background_texture_->GetHeight() != intersection.height)) { background_texture_ = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(intersection.width, intersection.height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); } backup_fbo_->FormatFrameBufferObject(width, height, BITFMT_R8G8B8A8); backup_fbo_->EmptyClippingRegion(); graphics_engine.SetViewport(0, 0, width, height); graphics_engine.SetOrthographicProjectionMatrix(width, height); // Draw the background on the previous fbo texture if ((force_draw || draw_cmd_queued_) && background_texture_.IsValid()) { backup_fbo_->FormatFrameBufferObject(intersection.width, intersection.height, BITFMT_R8G8B8A8); backup_fbo_->EmptyClippingRegion(); graphics_engine.SetViewport(0, 0, intersection.width, intersection.height); graphics_engine.SetOrthographicProjectionMatrix(intersection.width, intersection.height); // Set the background texture in the fbo backup_fbo_->SetTextureAttachment(0, background_texture_, 0); backup_fbo_->SetDepthTextureAttachment(ObjectPtr(0), 0); backup_fbo_->Activate(); graphics_engine.SetViewport(0, 0, background_texture_->GetWidth(), background_texture_->GetHeight()); // Clear surface // Clear surface CHECKGL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); CHECKGL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT)); TexCoordXForm texxform; texxform.uoffset = xform_geo.x / (float) active_fbo_texture->GetWidth(); texxform.voffset = xform_geo.y / (float) active_fbo_texture->GetHeight(); texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD); texxform.flip_v_coord = true; // Temporarily change the model-view matrix to copy the texture background texture. // This way we are not affceted by the regular model-view matrix. graphics_engine.SetModelViewMatrix(Matrix4::IDENTITY()); // Copy the texture from the previous fbo attachment into our background texture. if (copy_previous_fbo_for_background_) { graphics_engine.QRP_1Tex(0, 0, intersection.width, intersection.height, active_fbo_texture, texxform, color::White); } else { graphics_engine.QRP_Color(0, 0, intersection.width, intersection.height, Color(0.0f, 0.0f, 0.0f, 0.0f)); } // Restore the model-view matrix. graphics_engine.ApplyModelViewMatrix(); } backup_fbo_->FormatFrameBufferObject(width, height, BITFMT_R8G8B8A8); backup_fbo_->EmptyClippingRegion(); backup_fbo_->SetTextureAttachment(0, backup_texture_, 0); backup_fbo_->SetDepthTextureAttachment(backup_depth_texture_, 0); backup_fbo_->Activate(); if (force_draw || draw_cmd_queued_) { CHECKGL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); CHECKGL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT)); } graphics_engine.SetViewport(0, 0, width, height); graphics_engine.SetOrthographicProjectionMatrix(width, height); // Transform the geometry of this area through the current model view matrix. This gives the // the position of the view in the active fbo texture. Geometry offset_rect = graphics_engine.ModelViewXFormRect(GetGeometry()); int x_offset = -offset_rect.x; int y_offset = -offset_rect.y; graphics_engine.PushModelViewMatrix(Matrix4::TRANSLATE(x_offset, y_offset, 0)); } void View::EndBackupTextureRendering(GraphicsEngine& graphics_engine, bool /* force_draw */) { graphics_engine.PopModelViewMatrix(); if (prev_fbo_.IsValid()) { // Restore the previous fbo prev_fbo_->Activate(); prev_fbo_->ApplyClippingRegion(); } // Release the reference on the previous fbo prev_fbo_.Release(); // Restore the matrices and the view port. graphics_engine.ApplyModelViewMatrix(); graphics_engine.SetOrthographicProjectionMatrix(prev_viewport_.width, prev_viewport_.height); graphics_engine.SetViewport(prev_viewport_.x, prev_viewport_.y, prev_viewport_.width, prev_viewport_.height); } void View::Draw(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void View::DrawContent(GraphicsEngine & /* graphics_engine */, bool /* force_draw */) { } void View::QueueDraw() { // Report to a parent view with redirect_rendering_to_texture_ set to true that one of its children // needs to be redrawn. // // We should always do this, as the conditions for parent rendering may have // changed between child QueueDraw calls (eg window visibility) PrepareParentRedirectedView(); if (draw_cmd_queued_) return; WindowThread* application = GetWindowThread(); if (application) { application->AddToDrawList(this); application->RequestRedraw(); } if (view_layout_) { // If this view has requested a draw, then all of it children in the view_layout_ // need to be redrawn as well. view_layout_->QueueDraw(); } draw_cmd_queued_ = true; queue_draw.emit(this); } void View::NeedSoftRedraw() { //GetWindowCompositor()..AddToDrawList(this); WindowThread* application = GetWindowThread(); if (application) { application->AddToDrawList(this); application->RequestRedraw(); } //draw_cmd_queued_ = false; } bool View::IsRedrawNeeded() { return draw_cmd_queued_; } bool View::IsFullRedraw() const { return full_view_draw_cmd_; } void View::DoneRedraw() { draw_cmd_queued_ = false; if (view_layout_) { view_layout_->DoneRedraw(); } } Layout* View::GetLayout() { return view_layout_; } Layout *View::GetCompositionLayout() { return GetLayout(); } bool View::SetLayout(Layout *layout) { NUX_RETURN_VALUE_IF_NULL(layout, false); nuxAssert(layout->IsLayout()); NUX_RETURN_VALUE_IF_TRUE(view_layout_ == layout, true); Area *parent = layout->GetParentObject(); if (parent == this) { nuxAssert(view_layout_ == layout); return false; } else if (parent != 0) { nuxDebugMsg(0, "[View::SetCompositionLayout] Object already has a parent. You must UnParent the object before you can parenting again."); return false; } if (view_layout_) { /* we need to emit the signal before the unparent, just in case one of the callbacks wanted to use this object */ LayoutRemoved.emit(this, view_layout_); view_layout_->UnParentObject(); } layout->SetParentObject(this); view_layout_ = layout; GetWindowThread()->QueueObjectLayout(this); LayoutAdded.emit(this, view_layout_); view_layout_->queue_draw.connect(sigc::mem_fun(this, &View::ChildViewQueuedDraw)); view_layout_->child_queue_draw.connect(sigc::mem_fun(this, &View::ChildViewQueuedDraw)); return true; } void View::ChildViewQueuedDraw(Area* area) { if (child_draw_cmd_queued_) return; child_draw_cmd_queued_ = true; child_queue_draw.emit(area); } void View::OnChildFocusChanged(/*Area *parent,*/ Area *child) { ChildFocusChanged.emit(/*parent,*/ child); } bool View::SetCompositionLayout(Layout *layout) { return SetLayout(layout); } void View::RemoveLayout() { NUX_RETURN_IF_NULL(view_layout_); if (view_layout_) view_layout_->UnParentObject(); view_layout_ = 0; } void View::RemoveCompositionLayout() { RemoveLayout(); } bool View::SearchInAllSubNodes(Area *bo) { if (view_layout_) return view_layout_->SearchInAllSubNodes(bo); return false; } bool View::SearchInFirstSubNodes(Area *bo) { if (view_layout_) return view_layout_->SearchInFirstSubNodes(bo); return false; } // void View::SetGeometry(int x, int y, int w, int h) // { // Area::SetGeometry(x, y, w, h); // ComputeContentSize(); // PostResizeGeometry(); // } void View::SetGeometry(const Geometry& geo) { Area::SetGeometry(geo.x, geo.y, geo.width, geo.height); ComputeContentSize(); PostResizeGeometry(); } void View::SetFont(ObjectPtr font) { _font = font; } ObjectPtr View::GetFont() { if (!_font.IsValid()) _font = GetSysFont(); return _font; } void View::SetTextColor(const Color &color) { m_TextColor = color; } Color View::GetTextColor() const { return m_TextColor; } void View::EnableView() { view_enabled_ = true; } void View::DisableView() { view_enabled_ = false; } void View::SetEnableView(bool enable) { if (enable) { EnableView(); } else { DisableView(); } } bool View::IsViewEnabled() const { return view_enabled_; } void View::GeometryChangePending(bool /* position_about_to_change */, bool /* size_about_to_change */) { if (IsLayoutDone()) QueueDraw(); } void View::GeometryChanged(bool /* position_has_changed */, bool size_has_changed) { if (RedirectedAncestor()) { if (size_has_changed) QueueDraw(); return; } if (IsLayoutDone()) QueueDraw(); } Area* View::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) { bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); if (mouse_inside == false) return NULL; if (view_layout_) { Area* view = view_layout_->FindAreaUnderMouse(mouse_position, event_type); if (view) return view; } if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) return NULL; return this; } Area* View::FindKeyFocusArea(unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state) { if (has_key_focus_) { return this; } else if (next_object_to_key_focus_area_) { return next_object_to_key_focus_area_->FindKeyFocusArea(key_symbol, x11_key_code, special_keys_state); } return NULL; } Area* View::KeyNavIteration(KeyNavDirection direction) { if (next_object_to_key_focus_area_) { return NULL; } if (IsVisible() == false) return NULL; if (AcceptKeyNavFocus()) { QueueDraw(); return this; } else if (view_layout_) { return view_layout_->KeyNavIteration(direction); } return NULL; } bool View::AcceptKeyNavFocus() { return true; } #ifdef NUX_GESTURES_SUPPORT Area* View::GetInputAreaHitByGesture(const nux::GestureEvent &event) { if (!IsVisible()) return nullptr; if (!IsGestureInsideArea(event)) return nullptr; if (view_layout_) { Area *area = view_layout_->GetInputAreaHitByGesture(event); if (area) return area; } if (HasSubscriptionForGesture(event)) return this; else return nullptr; } #endif } nux-4.0.8+18.10.20180623/Nux/View.h0000644000000000000000000001604513313373365012444 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ABSTRACTOBJECTBASE_H #define ABSTRACTOBJECTBASE_H #include "Nux.h" #include "NuxCore/Property.h" #define NeedRedraw QueueDraw namespace nux { class Layout; #ifdef NUX_GESTURES_SUPPORT class GestureEvent; #endif class View: public InputArea { NUX_DECLARE_OBJECT_TYPE(View, InputArea); public: View(NUX_FILE_LINE_DECL); virtual ~View(); public: /* If ComputeContentSize is called while outside of the layout process (\sa IsInsideLayoutCycle) then the parents of this object maybe added to the layout queue if this view size changes. \sa Area::ReconfigureParentLayout. */ virtual long ComputeContentSize(); virtual void ComputeContentPosition(float offsetX, float offsetY); //! Enable a View. /*! Enable the view. The view cannot receive events. As for the rendering, each view handle its own rendering while is enabled state. */ virtual void EnableView(); //! Disable a View. /*! Disable the view. The view cannot receive input events(keyboard, mouse, touch). As for the rendering, each view handle its own rendering while is disabled state. */ virtual void DisableView(); //! Set the enable state of the view. /*! Set the enable state of the view. @param enable. The state of the view to be set. */ virtual void SetEnableView(bool enable); //! Gets the enable state of the View. /*! @return True if the view is active. */ bool IsViewEnabled() const; public: virtual void ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw); //! Causes a redraw. The widget parameter draw_cmd_queued_ is set to true. The widget Draw() and DrawContent() are called. /*! Emits the signal \i queue_draw. */ virtual void QueueDraw(); //! Causes a soft redraw. The widget parameter draw_cmd_queued_ is set to false. The widget DrawContent() is called. virtual void NeedSoftRedraw(); virtual bool IsRedrawNeeded(); virtual void DoneRedraw(); virtual void OverlayDrawing(GraphicsEngine & /* graphics_engine */) {} //Layout Bridge bool SearchInAllSubNodes(Area *bo); bool SearchInFirstSubNodes(Area *bo); /* void SetGeometry(int x, int y, int w, int h);*/ //! Set Geometry /* Set the Geometry of the View and the geometry of the Default Background Area. For simple interface control UI classes(RGBValuator...), this is enough. For others, they have to overwrite the function and do the appropriate computations for their component. */ virtual void SetGeometry(const Geometry &geo); //! Return true if this object can break the layout. /* Return true if this object can break the layout, meaning, the layout can be done on the composition layout only without recomputing the whole window layout. */ virtual bool CanBreakLayout() { return false; } virtual void SetTextColor(const Color &color); virtual Color GetTextColor() const; //! Get the default layout of this view. /*! Get the default layout of this view. @return The default layout of this view. */ virtual Layout* GetLayout(); //! Set the default layout for this view. /*! Set the default layout for this view. Assigns a scale factor of 1 to the layout. @param layout A Layout object. */ virtual bool SetLayout(Layout *layout); sigc::signal LayoutAdded; sigc::signal LayoutRemoved; void SetFont(ObjectPtr font); ObjectPtr GetFont(); sigc::signal queue_draw; //!< Signal emitted when a view is scheduled for a draw. sigc::signal child_queue_draw; //!< Signal emitted when a child of this view is scheduled for a draw. virtual Area* KeyNavIteration(KeyNavDirection direction); virtual bool AcceptKeyNavFocus(); virtual Area* FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type); virtual Area* FindKeyFocusArea(unsigned int key_symbol, unsigned long x11_key_code, unsigned long special_keys_state); #ifdef NUX_GESTURES_SUPPORT virtual Area* GetInputAreaHitByGesture(const nux::GestureEvent &event); #endif protected: virtual void ChildViewQueuedDraw(Area* area); void BeginBackupTextureRendering(GraphicsEngine& graphics_engine, bool force_draw); void EndBackupTextureRendering(GraphicsEngine& graphics_engine, bool force_draw); void OnChildFocusChanged(/*Area *parent,*/ Area *child); sigc::connection _on_focus_changed_handler; virtual void Draw(GraphicsEngine &graphics_engine, bool force_draw) = 0; virtual void DrawContent(GraphicsEngine &graphics_engine, bool force_draw); virtual void PreLayoutManagement(); virtual long PostLayoutManagement(long LayoutResult); virtual void PreResizeGeometry(); virtual void PostResizeGeometry(); void InitializeWidgets(); void InitializeLayout(); Color m_TextColor; //! Deprecated. Use GetLayout(); virtual Layout* GetCompositionLayout(); //! Deprecated. Use SetLayout(); virtual bool SetCompositionLayout(Layout *layout); void RemoveLayout(); void RemoveCompositionLayout(); /*! Accessed inside ContentDraw() to help determine if some parts needs to be rendered. Do not use it elsewhere. @return True if Draw() was called before ContentDraw(). */ bool IsFullRedraw() const; virtual void GeometryChangePending(bool position_about_to_change, bool size_about_to_change); virtual void GeometryChanged(bool position_has_changed, bool size_has_changed); Layout *view_layout_; bool draw_cmd_queued_; // _font; friend class WindowCompositor; friend class Layout; friend class Area; friend class LayeredLayout; friend class Canvas; friend class VSplitter; friend class HSplitter; }; } #endif // ABSTRACTOBJECTBASE_H nux-4.0.8+18.10.20180623/Nux/WidgetMetrics.cpp0000644000000000000000000000517513313373365014641 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "WidgetMetrics.h" namespace nux { const Color COLOR_BLACK = Color(0xFF000000); const Color COLOR_RED = Color(0xFFFF0000); const Color COLOR_GREEN = Color(0xFF00FF00); const Color COLOR_BLUE = Color(0xFF0000FF); const Color COLOR_WHITE = Color(0xFFFFFFFF); const Color COLOR_BACKGROUND_PRIMARY = Color(0xFF4D4D4D); const Color COLOR_BACKGROUND_SECONDARY = Color(0xFF868686); const Color COLOR_FOREGROUND_PRIMARY = Color(0xFF424242); //0xFFCFCFCF; const Color COLOR_FOREGROUND_SECONDARY = Color(0xFFEFEFEF); const Color COLOR_SELECTION_SECONDARY = Color(0xFFAAAAAA); // Text color const Color COLOR_TEXTEDIT_BACKGROUNG = Color(0xFF9F9F9F); const Color COLOR_TEXTSTATIC_BACKGROUNG = Color(0xFF909090); // General background color const Color COLOR_WIDGET_BACKGROUND = Color(0xFF6E6E6E); const Color COLOR_WIDGET_MOUSEOVER = Color(0xFF969664); const Color COLOR_WINDOW_BACKGROUND = Color(0xFFa0a0a0); // Widget control background color const Color COLOR_PRIMARY_LEFT = Color(0xFFC0C0C0); const Color COLOR_PRIMARY_RIGHT = Color(0xFF7D7D7D); // ScrollBar color const Color COLOR_SCROLLBAR_TRACK = Color(0xFF636363); const Color COLOR_SCROLLBAR_SLIDER = Color(0xFF373737); const Color COLOR_DARK_0 = Color(0xFF575757); const Color COLOR_LIGHT_0 = Color(0xFF737373); const int AREA_MIN_WIDTH = 1; const int AREA_MAX_WIDTH = 0x7FFFFFFF; const int AREA_MIN_HEIGHT = 1; const int AREA_MAX_HEIGHT = 0x7FFFFFFF; const int DEFAULT_WIDGET_HEIGHT = 8; const int PRACTICAL_WIDGET_HEIGHT = 18; const int DEFAULT_WIDGET_WIDTH = 32; const int PRACTICAL_WIDGET_WIDTH = 32; const int DEFAULT_TEXT_X_MARGIN = 0; const int DEFAULT_TEXT_Y_MARGIN = 0; const float DEFAULT_REPEAT_DELAY = 150; //milliseconds } nux-4.0.8+18.10.20180623/Nux/WidgetMetrics.h0000644000000000000000000000446213313373365014304 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef WIDGETMETRICS_H #define WIDGETMETRICS_H namespace nux { extern const Color COLOR_BLACK ; extern const Color COLOR_RED; extern const Color COLOR_GREEN;; extern const Color COLOR_BLUE; extern const Color COLOR_WHITE; extern const Color COLOR_BACKGROUND_PRIMARY; extern const Color COLOR_BACKGROUND_SECONDARY; extern const Color COLOR_FOREGROUND_PRIMARY; extern const Color COLOR_FOREGROUND_SECONDARY; extern const Color COLOR_SELECTION_SECONDARY; // Text color extern const Color COLOR_TEXTEDIT_BACKGROUNG; extern const Color COLOR_TEXTSTATIC_BACKGROUNG; // General background color extern const Color COLOR_WIDGET_BACKGROUND; extern const Color COLOR_WIDGET_MOUSEOVER; extern const Color COLOR_WINDOW_BACKGROUND; // Widget control background color extern const Color COLOR_PRIMARY_LEFT; extern const Color COLOR_PRIMARY_RIGHT; // ScrollBar color extern const Color COLOR_SCROLLBAR_TRACK; extern const Color COLOR_SCROLLBAR_SLIDER; extern const Color COLOR_DARK_0; extern const Color COLOR_LIGHT_0; extern const int AREA_MIN_WIDTH; extern const int AREA_MAX_WIDTH; extern const int AREA_MIN_HEIGHT; extern const int AREA_MAX_HEIGHT; extern const int DEFAULT_WIDGET_HEIGHT; extern const int PRACTICAL_WIDGET_HEIGHT; extern const int DEFAULT_WIDGET_WIDTH; extern const int PRACTICAL_WIDGET_WIDTH; extern const int DEFAULT_TEXT_X_MARGIN; extern const int DEFAULT_TEXT_Y_MARGIN; extern const float DEFAULT_REPEAT_DELAY; } #endif // WIDGETMETRICS_H nux-4.0.8+18.10.20180623/Nux/WindowCompositor.cpp0000644000000000000000000026566213313373365015426 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2010,2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Nux.h" #include "WindowCompositor.h" #include "NuxCore/Logger.h" #include "NuxGraphics/GLError.h" #include "WindowThread.h" #include "BaseWindow.h" #include "InputAreaProximity.h" #if !defined(NUX_MINIMAL) #include "MenuPage.h" #endif #include "PaintLayer.h" #include "Painter.h" #include "Layout.h" #include "NuxGraphics/FontTexture.h" namespace nux { DECLARE_LOGGER(logger, "nux.window"); WindowCompositor::WindowCompositor(WindowThread* window_thread) : draw_reference_fbo_(0) , read_reference_fbo_(0) , window_thread_(window_thread) , currently_rendering_windows_(nullptr) , current_global_clip_rect_(nullptr) { m_OverlayWindow = NULL; _tooltip_window = NULL; m_TooltipArea = NULL; m_Background = NULL; _tooltip_window = NULL; OverlayDrawingCommand = NULL; m_CurrentWindow = NULL; m_MenuWindow = NULL; _always_on_front_window = NULL; inside_event_cycle_ = false; inside_rendering_cycle_ = false; _dnd_area = NULL; _starting_menu_event_cycle = false; _menu_is_active = false; on_menu_closure_continue_with_event_ = false; _mouse_position_on_owner = Point(0, 0); platform_support_for_depth_texture_ = GetGraphicsDisplay()->GetGpuDevice()->GetGpuInfo().Support_Depth_Buffer(); m_FrameBufferObject = GetGraphicsDisplay()->GetGpuDevice()->CreateFrameBufferObject(); // Do not leave the Fbo binded. Deactivate it. m_FrameBufferObject->Deactivate(); // At this stage, the size of the window may not be known yet. // FormatRenderTargets will be called the first time runtime gets into WindowThread::ExecutionLoop m_MainColorRT = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(2, 2, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); if (platform_support_for_depth_texture_) { m_MainDepthRT = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(2, 2, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); } #if !defined(NUX_MINIMAL) _mouse_over_menu_page = NULL; _mouse_owner_menu_page = NULL; _menu_chain = NULL; _menu_chain = new std::list; #endif m_MenuRemoved = false; m_Background = new ColorLayer(Color(0xFF4D4D4D)); #ifdef NUX_GESTURES_SUPPORT gesture_broker_.reset(new DefaultGestureBroker(this)); #endif } void WindowCompositor::BeforeDestructor() { key_focus_area_ = NULL; } WindowCompositor::~WindowCompositor() { _window_to_texture_map.clear(); m_FrameBufferObject.Release(); m_MainColorRT.Release(); m_MainDepthRT.Release(); _view_window_list.clear(); _modal_view_window_list.clear(); #if !defined(NUX_MINIMAL) _menu_chain->clear(); delete _menu_chain; #endif delete m_Background; } WindowCompositor::RenderTargetTextures& WindowCompositor::GetWindowBuffer(BaseWindow* window) { static RenderTargetTextures invalid; std::map< BaseWindow*, RenderTargetTextures>::iterator it = _window_to_texture_map.find(window); if (it != _window_to_texture_map.end()) { return it->second; } LOG_WARN(logger) << "No RenderTargetTextures for window."; return invalid; } void WindowCompositor::RegisterWindow(BaseWindow* window) { LOG_DEBUG_BLOCK(logger); if (!window) return; WindowList::iterator it = find(_view_window_list.begin(), _view_window_list.end(), window); if (it == _view_window_list.end()) { _view_window_list.push_front(WeakBaseWindowPtr(window)); RenderTargetTextures rt; // Don't size the texture to the dimension of the window yet. this will be done later. auto device = GetGraphicsDisplay()->GetGpuDevice(); rt.color_rt = device->CreateSystemCapableDeviceTexture(2, 2, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); rt.depth_rt = device->CreateSystemCapableDeviceTexture(2, 2, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); _window_to_texture_map[window] = rt; window->object_destroyed.connect(sigc::mem_fun(this, &WindowCompositor::UnRegisterWindow)); } } void WindowCompositor::UnRegisterWindow(Object* obj) { LOG_DEBUG_BLOCK(logger); WeakBaseWindowPtr window(obj); if (window.IsNull()) return; WindowList::iterator it = find(_view_window_list.begin(), _view_window_list.end(), window); if (it == _view_window_list.end()) { // look for a weak pointer that has been cleared out. it = find(_view_window_list.begin(), _view_window_list.end(), WeakBaseWindowPtr()); } if (it != _view_window_list.end()) _view_window_list.erase(it); _window_to_texture_map.erase(window.GetPointer()); } //! Get Mouse position relative to the top left corner of the window. Point WindowCompositor::GetMousePosition() { return _mouse_position; } void WindowCompositor::ResetMousePointerAreas() { mouse_over_area_ = NULL; SetMouseOwnerArea(NULL); #if !defined(NUX_MINIMAL) _mouse_over_menu_page = NULL; _mouse_owner_menu_page = NULL; #endif } void WindowCompositor::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type, ObjectWeakPtr& area_under_mouse_pointer) { WeakBaseWindowPtr window; GetAreaUnderMouse(mouse_position, event_type, area_under_mouse_pointer, window); } void WindowCompositor::GetAreaUnderMouse(const Point& mouse_position, NuxEventType event_type, ObjectWeakPtr& area_under_mouse_pointer, WeakBaseWindowPtr& window) { window = NULL; area_under_mouse_pointer = NULL; // Go through the list of BaseWindo and find the first area over which the // mouse pointer is. for (auto const& window_it : _view_window_list) { // Since the mouse is really an input-level thing, we want to know // if the underlying input window is enabled or if the window is // visible if (!window_it.IsValid()) continue; if (window_it->InputWindowEnabled() || window_it->IsVisible()) { Area* area = window_it->FindAreaUnderMouse(mouse_position, event_type); if (area) { area_under_mouse_pointer = static_cast(area); window = window_it; return; } } } // If area_under_mouse_pointer is NULL, then the mouse pointer is not over // any of the BaseWindow. Try the main window layout. if (!area_under_mouse_pointer.IsValid()) { Layout* main_window_layout = window_thread_->GetLayout(); if (main_window_layout) area_under_mouse_pointer = static_cast(main_window_layout->FindAreaUnderMouse(mouse_position, event_type)); } } void WindowCompositor::SetMouseOwnerArea(InputArea* area) { if (mouse_owner_area_ == area) return; auto* old_owner = mouse_owner_area_.GetPointer(); mouse_owner_area_ = area; dnd_safety_x_ = 0; dnd_safety_y_ = 0; if (old_owner) old_owner->EmitMouseCancelSignal(); } ObjectWeakPtr const& WindowCompositor::GetMouseOwnerArea() const { return mouse_owner_area_; } void WindowCompositor::DndEventCycle(Event& event) { if (event.type == NUX_DND_MOVE) { ObjectWeakPtr hit_area; FindAreaUnderMouse(Point(event.x, event.y), event.type, hit_area); if (hit_area.IsValid()) { SetDnDArea(hit_area.GetPointer()); hit_area->HandleDndMove(event); } else { ResetDnDArea(); } } else if (event.type == NUX_DND_ENTER_WINDOW) { // do nothing for now } else if (event.type == NUX_DND_LEAVE_WINDOW) { ResetDnDArea(); } else if (event.type == NUX_DND_DROP) { if (_dnd_area && _dnd_area->GetAbsoluteGeometry().IsPointInside(event.x - event.x_root, event.y - event.y_root)) _dnd_area->HandleDndDrop(event); } } void WindowCompositor::UpdateKeyNavFocusOnMouseDown() { /* In the case of a mouse down event, if there is currently a keyboard event receiver and it is different from the area returned by FindAreaUnderMouse, then stop that receiver from receiving anymore keyboard events and switch make mouse_over_area_ the new receiver(if it accept keyboard events). */ if (mouse_over_area_.IsValid() && mouse_over_area_ != GetKeyFocusArea() && mouse_over_area_->AcceptKeyNavFocusOnMouseDown()) { InputArea* grab_area = GetKeyboardGrabArea(); if (grab_area) { if (mouse_over_area_->IsChildOf(grab_area) /*&& mouse_over_area_->AcceptKeyboardEvent()*/) { SetKeyFocusArea(mouse_over_area_.GetPointer()); } else { SetKeyFocusArea(grab_area); } } else { SetKeyFocusArea(mouse_over_area_.GetPointer()); } } } void WindowCompositor::TrackMouseMovement(const Event &event, bool area_under_mouse_changed) { if (!mouse_owner_area_.IsValid()) { if (mouse_over_area_.IsValid()) { if (event.type == NUX_MOUSE_MOVE) { Geometry hit_view_geo = mouse_over_area_->GetAbsoluteGeometry(); int hit_view_x = event.x - hit_view_geo.x; int hit_view_y = event.y - hit_view_geo.y; int dx = event.x - _mouse_position.x; int dy = event.y - _mouse_position.y; mouse_over_area_->EmitMouseMoveSignal(hit_view_x, hit_view_y, area_under_mouse_changed ? 0 : dx, area_under_mouse_changed ? 0 : dy, event.GetMouseState(), event.GetKeyState()); } } } else { if (event.type == NUX_MOUSE_PRESSED || event.type == NUX_MOUSE_DOUBLECLICK) { // We just got a new mouse owner. Let's update the mouse position on him. Geometry const& mouse_owner_geo = mouse_owner_area_->GetAbsoluteGeometry(); int mouse_owner_x = event.x - mouse_owner_geo.x; int mouse_owner_y = event.y - mouse_owner_geo.y; _mouse_position_on_owner = Point(mouse_owner_x, mouse_owner_y); } else if (event.type == NUX_MOUSE_MOVE) { Geometry const& mouse_owner_geo = mouse_owner_area_->GetAbsoluteGeometry(); int mouse_owner_x = event.x - mouse_owner_geo.x; int mouse_owner_y = event.y - mouse_owner_geo.y; int dx = mouse_owner_x - _mouse_position_on_owner.x; int dy = mouse_owner_y - _mouse_position_on_owner.y; if (mouse_owner_area_->_dnd_enabled_as_source) { dnd_safety_x_ += dx; dnd_safety_y_ += dy; if (abs(dnd_safety_y_) > 30 || abs(dnd_safety_x_) > 30) { #if defined(DRAG_AND_DROP_SUPPORTED) mouse_owner_area_->StartDragAsSource(); #endif ResetMousePointerAreas(); return; } } else { mouse_owner_area_->EmitMouseDragSignal(mouse_owner_x, mouse_owner_y, dx, dy, event.GetMouseState(), event.GetKeyState()); } _mouse_position_on_owner = Point(mouse_owner_x, mouse_owner_y); } else if (event.type == NUX_MOUSE_RELEASED) { _mouse_position_on_owner = Point(0, 0); } } _mouse_position = Point(event.x, event.y); } bool WindowCompositor::UpdateWhatAreaIsUnderMouse(const Event& event) { ObjectWeakPtr new_area_under_mouse; ObjectWeakPtr old_mouse_over_area = mouse_over_area_; if (mouse_owner_area_.IsValid()) { FindAreaUnderMouse(Point(event.x, event.y), event.type, new_area_under_mouse); } else { // Look for the area below the mouse pointer in the BaseWindow. Area* pointer_grab_area = GetPointerGrabArea(); if (pointer_grab_area) { // If there is a pending mouse pointer grab, test that area only new_area_under_mouse = NUX_STATIC_CAST(InputArea*, pointer_grab_area->FindAreaUnderMouse(Point(event.x, event.y), event.type)); } else { FindAreaUnderMouse(Point(event.x, event.y), event.type, new_area_under_mouse); } } if (!mouse_owner_area_.IsValid()) { if (event.type == NUX_WINDOW_MOUSELEAVE) { if (mouse_over_area_.IsValid()) { // The area where the mouse was in the previous cycle and the area // returned by GetAreaUnderMouse are different. // The area from the previous cycle receive a "mouse leave signal". Geometry const& geo = mouse_over_area_->GetAbsoluteGeometry(); int x = event.x - geo.x; int y = event.y - geo.y; mouse_over_area_->EmitMouseLeaveSignal(x, y, event.GetMouseState(), event.GetKeyState()); mouse_over_area_ = NULL; } } if (new_area_under_mouse.IsValid()) { if (new_area_under_mouse != mouse_over_area_) { if (mouse_over_area_.IsValid()) { // The area where the mouse was in the previous cycle and the area // returned by FindAreaUnderMouse are different. // The area from the previous cycle receive a "mouse leave signal". Geometry const& geo = mouse_over_area_->GetAbsoluteGeometry(); int x = event.x - geo.x; int y = event.y - geo.y; mouse_over_area_->EmitMouseLeaveSignal(x, y, event.GetMouseState(), event.GetKeyState()); } // The area we found under the mouse pointer receives a "mouse enter signal". mouse_over_area_ = new_area_under_mouse; if (mouse_over_area_.IsValid() && mouse_over_area_ != GetKeyFocusArea() && mouse_over_area_->AcceptKeyNavFocusOnMouseEnter()) { SetKeyFocusArea(mouse_over_area_.GetPointer()); } Geometry hit_view_geo = new_area_under_mouse->GetAbsoluteGeometry(); int hit_view_x = event.x - hit_view_geo.x; int hit_view_y = event.y - hit_view_geo.y; mouse_over_area_->EmitMouseEnterSignal(hit_view_x, hit_view_y, event.GetMouseState(), event.GetKeyState()); } } else { if (mouse_over_area_.IsValid()) { // Mouse wheel events are stationary. The mouse can remain inside an // area while the mouse wheel is spinning. // This shouldn't qualify as a mouse leave event. if (event.type != NUX_MOUSE_WHEEL) { Geometry const& geo = mouse_over_area_->GetAbsoluteGeometry(); int x = event.x - geo.x; int y = event.y - geo.y; mouse_over_area_->EmitMouseLeaveSignal(x, y, event.GetMouseState(), event.GetKeyState()); } } mouse_over_area_ = NULL; } } else { // Context: The left mouse button down over an area. All events goes to // that area. Geometry const& mouse_owner_geo = mouse_owner_area_->GetAbsoluteGeometry(); int mouse_owner_x = event.x - mouse_owner_geo.x; int mouse_owner_y = event.y - mouse_owner_geo.y; if (event.type == NUX_MOUSE_MOVE) { if (mouse_over_area_ == mouse_owner_area_ && new_area_under_mouse != mouse_owner_area_) { mouse_owner_area_->EmitMouseLeaveSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); mouse_over_area_ = new_area_under_mouse; } else if (mouse_over_area_ != mouse_owner_area_ && new_area_under_mouse == mouse_owner_area_) { mouse_owner_area_->EmitMouseEnterSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); mouse_over_area_ = new_area_under_mouse; } } else if (event.type == NUX_MOUSE_RELEASED) { if (new_area_under_mouse != mouse_over_area_) { if (mouse_over_area_ == mouse_owner_area_) { mouse_owner_area_->EmitMouseLeaveSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); } mouse_over_area_ = new_area_under_mouse; if (mouse_over_area_.IsValid()) { auto const& over_geo = mouse_over_area_->GetAbsoluteGeometry(); mouse_over_area_->EmitMouseEnterSignal(event.x - over_geo.x, event.y - over_geo.y, event.GetMouseState(), event.GetKeyState()); } } } } return mouse_over_area_ != old_mouse_over_area; } void WindowCompositor::ProcessMouseWheelEvent(Event& event) { if (mouse_over_area_.IsValid()) { Geometry hit_view_geo = mouse_over_area_->GetAbsoluteGeometry(); int hit_view_x = event.x - hit_view_geo.x; int hit_view_y = event.y - hit_view_geo.y; mouse_over_area_->EmitMouseWheelSignal(hit_view_x, hit_view_y, event.wheel_delta, event.GetMouseState(), event.GetKeyState()); } } void WindowCompositor::UpdateMouseOwner(const Event& event, bool area_under_mouse_changed) { if (!mouse_owner_area_.IsValid()) { if (mouse_over_area_.IsValid()) { Geometry hit_view_geo = mouse_over_area_->GetAbsoluteGeometry(); int hit_view_x = event.x - hit_view_geo.x; int hit_view_y = event.y - hit_view_geo.y; if (event.type == NUX_MOUSE_PRESSED || event.type == NUX_MOUSE_DOUBLECLICK) { SetMouseOwnerArea(mouse_over_area_.GetPointer()); UpdateKeyNavFocusOnMouseDown(); if (event.type == NUX_MOUSE_DOUBLECLICK && mouse_over_area_->DoubleClickEnabled() && !area_under_mouse_changed) { mouse_over_area_->EmitMouseDoubleClickSignal(hit_view_x, hit_view_y, event.GetMouseState(), event.GetKeyState()); } else { mouse_over_area_->EmitMouseDownSignal(hit_view_x, hit_view_y, event.GetMouseState(), event.GetKeyState()); } } else if (event.type == NUX_MOUSE_RELEASED) { // We only get a NUX_MOUSE_RELEASED event when the mouse was pressed // over another area and released here. There are a few situations that // can cause mouse_owner_area_ to be NULL on a NUX_MOUSE_RELEASED event: // - The mouse down event happens on a area. That area is set into // mouse_owner_area_ // Then the area is destroyed, before the mouse is released // - The mouse down event happens. Then a call to AddGrabPointer triggers // a call to ResetMousePointerAreas. mouse_owner_area_ is then set to // NULL. mouse_over_area_->EmitMouseUpSignal(hit_view_x, hit_view_y, event.GetMouseState(), event.GetKeyState()); } } else { Area* pointer_grab_area = GetPointerGrabArea(); if (event.type == NUX_MOUSE_PRESSED && pointer_grab_area) { Geometry geo = pointer_grab_area->GetAbsoluteGeometry(); int x = event.x - geo.x; int y = event.y - geo.y; NUX_STATIC_CAST(InputArea*, pointer_grab_area)-> EmitMouseDownOutsideArea(x, y, event.GetMouseState(), event.GetKeyState()); } } } else { if (event.type == NUX_MOUSE_RELEASED) { Geometry const& mouse_owner_geo = mouse_owner_area_->GetAbsoluteGeometry(); int mouse_owner_x = event.x - mouse_owner_geo.x; int mouse_owner_y = event.y - mouse_owner_geo.y; auto* old_mouse_owner_area = mouse_owner_area_.GetPointer(); SetMouseOwnerArea(NULL); old_mouse_owner_area->EmitMouseUpSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); if (mouse_over_area_ == old_mouse_owner_area && (!mouse_over_area_->DoubleClickEnabled() || (event.mouse_state & NUX_STATE_FIRST_EVENT) != 0)) { old_mouse_owner_area->EmitMouseClickSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); } } } } void WindowCompositor::FindAncestorInterestedInChildMouseEvents(Area *area) { if (!area) return; Area *parent = area->GetParentObject(); if (!parent) return; if (parent->IsInputArea()) { InputArea *parent_input_area = static_cast(parent); if (parent_input_area->IsTrackingChildMouseEvents()) interested_mouse_owner_ancestor_ = parent_input_area; } if (!interested_mouse_owner_ancestor_.IsValid()) { // Keep searching... FindAncestorInterestedInChildMouseEvents(parent); } } void WindowCompositor::UpdateEventTrackingByMouseOwnerAncestor(const Event& event) { if (event.type == NUX_MOUSE_PRESSED || event.type == NUX_MOUSE_DOUBLECLICK) FindAncestorInterestedInChildMouseEvents(mouse_owner_area_.GetPointer()); if (!interested_mouse_owner_ancestor_.IsValid()) return; bool wants_ownership = interested_mouse_owner_ancestor_->ChildMouseEvent(event); if (wants_ownership) { mouse_owner_area_->EmitMouseCancelSignal(); SetMouseOwnerArea(interested_mouse_owner_ancestor_.GetPointer()); _mouse_position_on_owner = Point(event.x - mouse_owner_area_->GetAbsoluteX(), event.y - mouse_owner_area_->GetAbsoluteY()); interested_mouse_owner_ancestor_ = NULL; } if (event.type == NUX_MOUSE_RELEASED) interested_mouse_owner_ancestor_ = NULL; } void WindowCompositor::MouseEventCycle(Event& event) { // Checks the area_proximities_ list for any mouse near/beyond signals if (event.type == NUX_MOUSE_MOVE || event.type == NUX_WINDOW_MOUSELEAVE) { CheckMouseNearArea(event); } // Updates mouse_over_area_ and emits mouse_enter and mouse_leave signals // accordingly. bool area_under_mouse_changed = UpdateWhatAreaIsUnderMouse(event); // Updates mouse_owner_area_ and emits mouse_down, mouse_up, // mouse_click and mouse_double_click accordingly. UpdateMouseOwner(event, area_under_mouse_changed); // Keeps track of mouse movement and emits mouse_move and mouse_drag // accordingly. TrackMouseMovement(event, area_under_mouse_changed); if (event.type == NUX_MOUSE_WHEEL) ProcessMouseWheelEvent(event); // Feed the appropriate InputArea::ChildMouseEvent() and switch mouse // ownership (including the emission of mouse_cancel) if asked to. UpdateEventTrackingByMouseOwnerAncestor(event); } #if !defined(NUX_MINIMAL) void WindowCompositor::MenuEventCycle(Event& event) { // _mouse_owner_menu_page: the menu page that has the mouse down // _mouse_over_menu_page: the menu page that is directly below the mouse pointer _mouse_position = Point(event.x, event.y); if (_mouse_owner_menu_page == NULL) { if ((event.type == NUX_MOUSE_PRESSED) || (event.type == NUX_MOUSE_RELEASED) || (event.type == NUX_MOUSE_MOVE) || (event.type == NUX_MOUSE_DOUBLECLICK) || (event.type == NUX_MOUSE_WHEEL)) { // Find the MenuPage under the mouse MenuPage* hit_menu_page = NULL; std::list::iterator menu_it; for (menu_it = _menu_chain->begin(); menu_it != _menu_chain->end(); ++menu_it) { // The leaf of the menu chain is in the front of the list. hit_menu_page = NUX_STATIC_CAST(MenuPage*, (*menu_it)->FindAreaUnderMouse(Point(event.x, event.y), event.type)); if (hit_menu_page) { break; } } Geometry hit_menu_page_geo; int hit_menu_page_x = 0; int hit_menu_page_y = 0; if (hit_menu_page) { hit_menu_page_geo = hit_menu_page->GetAbsoluteGeometry(); hit_menu_page_x = event.x - hit_menu_page_geo.x; hit_menu_page_y = event.y - hit_menu_page_geo.y; } if (hit_menu_page && (event.type == NUX_MOUSE_RELEASED)) { hit_menu_page->EmitMouseUpSignal(hit_menu_page_x, hit_menu_page_y, event.GetMouseState(), event.GetKeyState()); (*_menu_chain->begin())->sigClosingMenu(*_menu_chain->begin()); (*_menu_chain->begin())->StopMenu(); } else if (hit_menu_page && (event.type == NUX_MOUSE_MOVE)) { if (hit_menu_page != _mouse_over_menu_page) { if (_mouse_over_menu_page != 0) { Geometry geo = _mouse_over_menu_page->GetAbsoluteGeometry(); int x = event.x - geo.x; int y = event.y - geo.y; _mouse_over_menu_page->EmitMouseLeaveSignal(x, y, event.GetMouseState(), event.GetKeyState()); } _mouse_over_menu_page = hit_menu_page; _mouse_over_menu_page->EmitMouseEnterSignal(hit_menu_page_x, hit_menu_page_y, event.GetMouseState(), event.GetKeyState()); } _mouse_over_menu_page->EmitMouseMoveSignal(hit_menu_page_x, hit_menu_page_y, event.dx, event.dy, event.GetMouseState(), event.GetKeyState()); } else if (hit_menu_page && ((event.type == NUX_MOUSE_PRESSED) || (event.type == NUX_MOUSE_DOUBLECLICK))) { if (!hit_menu_page->DoubleClickEnabled()) { } if (_mouse_over_menu_page && (hit_menu_page != _mouse_over_menu_page)) { Geometry geo = _mouse_over_menu_page->GetAbsoluteGeometry(); int x = event.x - geo.x; int y = event.y - geo.y; _mouse_over_menu_page->EmitMouseLeaveSignal(x, y, event.GetMouseState(), event.GetKeyState()); } _mouse_over_menu_page = hit_menu_page; _mouse_owner_menu_page = hit_menu_page; _mouse_position_on_owner = Point(hit_menu_page_x, hit_menu_page_y); if (_mouse_over_menu_page != GetKeyFocusArea()) { if (_mouse_over_menu_page->AcceptKeyboardEvent()) SetKeyFocusArea(_mouse_over_menu_page); } _mouse_over_menu_page->EmitMouseDownSignal(hit_menu_page_x, hit_menu_page_y, event.GetMouseState(), event.GetKeyState()); } else if (hit_menu_page && (event.type == NUX_MOUSE_WHEEL)) { hit_menu_page->EmitMouseWheelSignal(hit_menu_page_x, hit_menu_page_y, event.wheel_delta, event.GetMouseState(), event.GetKeyState()); } else if (hit_menu_page == NULL) { if (_mouse_over_menu_page) { Geometry geo = _mouse_over_menu_page->GetAbsoluteGeometry(); int x = event.x - geo.x; int y = event.y - geo.y; _mouse_over_menu_page->EmitMouseLeaveSignal(x, y, event.GetMouseState(), event.GetKeyState()); } if (event.type == NUX_MOUSE_PRESSED || event.type == NUX_MOUSE_DOUBLECLICK) { (*_menu_chain->begin())->sigClosingMenu(*_menu_chain->begin()); (*_menu_chain->begin())->StopMenu(); on_menu_closure_continue_with_event_ = (*_menu_chain->begin())->OnClosureContinueEventCycle(); } _mouse_over_menu_page = 0; } } } else { // We should never get here for a NUX_MOUSE_PRESSED event. MenuPage* hit_menu_page = NULL; std::list::iterator menu_it; for (menu_it = _menu_chain->begin(); menu_it != _menu_chain->end(); ++menu_it) { // The leaf of the menu chain is in the front of the list. hit_menu_page = NUX_STATIC_CAST(MenuPage*, (*menu_it)->FindAreaUnderMouse(Point(event.x, event.y), event.type)); if (hit_menu_page) { break; } } Geometry mouse_owner_geo = _mouse_owner_menu_page->GetAbsoluteGeometry(); int mouse_owner_x = event.x - mouse_owner_geo.x; int mouse_owner_y = event.y - mouse_owner_geo.y; // the mouse is down over a view if (event.type == NUX_MOUSE_MOVE) { int dx = mouse_owner_x - _mouse_position_on_owner.x; int dy = mouse_owner_y - _mouse_position_on_owner.y; _mouse_owner_menu_page->EmitMouseDragSignal(mouse_owner_x, mouse_owner_y, dx, dy, event.GetMouseState(), event.GetKeyState()); if ((_mouse_over_menu_page == _mouse_owner_menu_page) && (hit_menu_page != _mouse_owner_menu_page)) { _mouse_owner_menu_page->EmitMouseLeaveSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); _mouse_over_menu_page = hit_menu_page; } else if ((_mouse_over_menu_page != _mouse_owner_menu_page) && (hit_menu_page == _mouse_owner_menu_page)) { _mouse_owner_menu_page->EmitMouseEnterSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); _mouse_over_menu_page = _mouse_owner_menu_page; } _mouse_position_on_owner = Point(mouse_owner_x, mouse_owner_y); } else if (event.type == NUX_MOUSE_RELEASED) { _mouse_owner_menu_page->EmitMouseUpSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); if (hit_menu_page == _mouse_owner_menu_page) { _mouse_owner_menu_page->EmitMouseClickSignal(mouse_owner_x, mouse_owner_y, event.GetMouseState(), event.GetKeyState()); _mouse_over_menu_page = _mouse_owner_menu_page; } else { _mouse_over_menu_page = hit_menu_page; } (*_menu_chain->begin())->sigClosingMenu(*_menu_chain->begin()); (*_menu_chain->begin())->StopMenu(); _mouse_owner_menu_page = NULL; _mouse_position_on_owner = Point(0, 0); } } } #endif void WindowCompositor::FindKeyFocusArea(NuxEventType event_type, unsigned int key_symbol, unsigned int special_keys_state, ObjectWeakPtr& key_focus_area, WeakBaseWindowPtr& window) { key_focus_area = NULL; window = NULL; // Go through the list of BaseWindos and find the first area over which the mouse pointer is. for (auto const& window_it : _view_window_list) { if (window_it.IsValid() && window_it->IsVisible()) { key_focus_area = NUX_STATIC_CAST(InputArea*, window_it->FindKeyFocusArea(event_type, key_symbol, special_keys_state)); if (key_focus_area.IsValid()) { // We have found an area. We are going to exit the while loop. window = window_it; break; } } } // If key_focus_area is NULL, then try the main window layout. if (!key_focus_area.IsValid()) { Layout* main_window_layout = window_thread_->GetLayout(); if (main_window_layout) { key_focus_area = NUX_STATIC_CAST(InputArea*, main_window_layout->FindKeyFocusArea(event_type, key_symbol, special_keys_state)); } } } void WindowCompositor::FindKeyFocusAreaFrom(NuxEventType event_type, unsigned int key_symbol, unsigned int special_keys_state, InputArea* root_search_area, ObjectWeakPtr& key_focus_area, WeakBaseWindowPtr& window) { key_focus_area = NULL; window = NULL; if (root_search_area == NULL) { return; } key_focus_area = NUX_STATIC_CAST(InputArea*, root_search_area->FindKeyFocusArea(event_type, key_symbol, special_keys_state)); if (key_focus_area.IsValid()) { window = NUX_STATIC_CAST(BaseWindow*, root_search_area->GetTopLevelViewWindow()); } } void WindowCompositor::SendKeyEvent(InputArea* input_area, NuxEventType event_type, unsigned int key_sym, unsigned long x11_key_code, unsigned long special_keys_state, const char* text, int key_repeat_count) { if (input_area == NULL) return; if (event_type == NUX_KEYDOWN) { input_area->EmitKeyEventSignal(event_type, key_sym, special_keys_state, text, key_repeat_count); } else if (event_type == NUX_KEYUP) { input_area->EmitKeyUpSignal(key_sym, x11_key_code, special_keys_state); } } void WindowCompositor::KeyboardEventCycle(Event& event) { InputArea* keyboard_event_grab_view = GetKeyboardGrabArea(); ObjectWeakPtr focus_area; // The view under the mouse WeakBaseWindowPtr base_window; // The BaseWindow below the mouse pointer. if (keyboard_event_grab_view) { // There is a keyboard grab. // Find the key focus area, under the keyboard grab area. That is to say, the key focus area is in the widget tree // whose root is the keyboard grab area. This phase is known as the capture phase. FindKeyFocusAreaFrom(event.type, event.GetKeySym(), event.GetKeyState(), keyboard_event_grab_view, focus_area, base_window); } else { FindKeyFocusArea(event.type, event.GetKeySym(), event.GetKeyState(), focus_area, base_window); } KeyNavDirection direction = KEY_NAV_NONE; if (event.type == EVENT_KEY_DOWN) { switch(event.GetKeySym()) { case NUX_VK_UP: direction = KEY_NAV_UP; break; case NUX_VK_DOWN: direction = KEY_NAV_DOWN; break; case NUX_VK_LEFT: direction = KEY_NAV_LEFT; break; case NUX_VK_RIGHT: direction = KEY_NAV_RIGHT; break; case NUX_VK_LEFT_TAB: direction = KEY_NAV_TAB_PREVIOUS; break; case NUX_VK_TAB: direction = KEY_NAV_TAB_NEXT; break; case NUX_VK_ENTER: case NUX_KP_ENTER: // Not sure if Enter should be a navigation key direction = KEY_NAV_ENTER; break; default: direction = KEY_NAV_NONE; break; } } if (focus_area.IsValid()) { SetKeyFocusArea(focus_area.GetPointer(), direction); } else { SetKeyFocusArea(NULL, KEY_NAV_NONE); } if (key_focus_area_.IsValid()) { if (key_focus_area_->InspectKeyEvent(event.type, event.GetKeySym(), event.GetText())) { SendKeyEvent(key_focus_area_.GetPointer(), event.type, event.GetKeySym(), #if defined(NUX_OS_WINDOWS) event.win32_keycode, #elif defined(USE_X11) event.x11_keycode, #else 0, #endif event.GetKeyState(), event.GetText(), event.GetKeyRepeatCount()); } else if (direction == KEY_NAV_NONE) { Area* parent = key_focus_area_->GetParentObject(); while (parent && !parent->InspectKeyEvent(event.type, event.GetKeySym(), event.GetText())) { parent = parent->GetParentObject(); } if (parent) { SendKeyEvent(static_cast(parent), event.type, event.GetKeySym(), #if defined(NUX_OS_WINDOWS) event.win32_keycode, #elif defined(USE_X11) event.x11_keycode, #else 0, #endif event.GetKeyState(), event.GetText(), event.GetKeyRepeatCount()); } } else if (event.type == NUX_KEYDOWN) { if (direction == KEY_NAV_ENTER) { if (key_focus_area_.IsValid() && key_focus_area_->Type().IsDerivedFromType(InputArea::StaticObjectType)) { // Signal emitted from the WindowCompositor. key_nav_focus_activate.emit(key_focus_area_.GetPointer()); // Signal emitted from the area itsel. key_focus_area_->key_nav_focus_activate.emit(key_focus_area_.GetPointer()); } } else { InputArea* key_nav_focus = NULL; Area* parent = key_focus_area_->GetParentObject(); if (parent) key_nav_focus = NUX_STATIC_CAST(InputArea*, parent->KeyNavIteration(direction)); while (key_nav_focus == NULL && parent != NULL) { parent = parent->GetParentObject(); if (parent) key_nav_focus = NUX_STATIC_CAST(InputArea*, parent->KeyNavIteration(direction)); } if (key_nav_focus) { SetKeyFocusArea(key_nav_focus, direction); } } } } else { // The event is for the Application itself } } // NUXTODO: rename as EventCycle void WindowCompositor::ProcessEvent(Event& event) { inside_event_cycle_ = true; if (((event.type >= NUX_MOUSE_PRESSED) && (event.type <= NUX_MOUSE_WHEEL)) || (event.type == NUX_WINDOW_MOUSELEAVE)) { #if !defined(NUX_MINIMAL) bool menu_active = false; if (!_menu_chain->empty()) { menu_active = true; MenuEventCycle(event); CleanMenu(); } if ((menu_active && on_menu_closure_continue_with_event_) || !(menu_active)) #endif { MouseEventCycle(event); } on_menu_closure_continue_with_event_ = false; if (_starting_menu_event_cycle) { _starting_menu_event_cycle = false; } } else if ((event.type >= NUX_KEYDOWN) && (event.type <= NUX_KEYUP)) { KeyboardEventCycle(event); } else if ((event.type >= NUX_DND_MOVE) && (event.type <= NUX_DND_LEAVE_WINDOW)) { DndEventCycle(event); } #ifdef NUX_GESTURES_SUPPORT else if (event.type == EVENT_GESTURE_BEGIN) { gesture_broker_->ProcessGestureBegin(static_cast(event)); } else if (event.type == EVENT_GESTURE_UPDATE) { gesture_broker_->ProcessGestureUpdate(static_cast(event)); } else if (event.type == EVENT_GESTURE_END) { gesture_broker_->ProcessGestureEnd(static_cast(event)); } #endif inside_event_cycle_ = false; } void WindowCompositor::StartModalWindow(WeakBaseWindowPtr window) { if (window == 0) return; WindowList::iterator it = find(_modal_view_window_list.begin(), _modal_view_window_list.end(), window); if (it == _modal_view_window_list.end()) { _modal_view_window_list.push_front(window); } } void WindowCompositor::StopModalWindow(WeakBaseWindowPtr window) { if (!_modal_view_window_list.empty()) { if (*_modal_view_window_list.begin() == window) _modal_view_window_list.pop_front(); } } //! Push a floating view at the top of the stack. void WindowCompositor::PushToFront(BaseWindow* window) { if (window == 0) return; WindowList::iterator it = find(_view_window_list.begin(), _view_window_list.end(), window); if (it != _view_window_list.end()) { _view_window_list.erase(it); _view_window_list.push_front(WeakBaseWindowPtr(window)); } EnsureAlwaysOnFrontWindow(); } //! Push a floating view at the bottom of the stack. void WindowCompositor::PushToBack(BaseWindow* window) { if (window == 0) return; if (window == _always_on_front_window) return; WindowList::iterator it = find(_view_window_list.begin(), _view_window_list.end(), window); if (it != _view_window_list.end()) { _view_window_list.erase(it); _view_window_list.push_back(WeakBaseWindowPtr(window)); } EnsureAlwaysOnFrontWindow(); } //! Push a floating view just above another floating view. void WindowCompositor::PushHigher(BaseWindow* top_floating_view, BaseWindow* bottom_floating_view, bool strict) { NUX_RETURN_IF_NULL(bottom_floating_view); NUX_RETURN_IF_NULL(top_floating_view); NUX_RETURN_IF_FALSE(bottom_floating_view != top_floating_view) WindowList::iterator it; WindowList::iterator it_top; WindowList::iterator it_bot; int i = 0; int top_pos = -1; int bot_pos = -1; for (it_top = _view_window_list.begin(), i = 0; it_top != _view_window_list.end(); ++it_top, ++i) { if (*it == bottom_floating_view) { it_bot = it; bot_pos = i; } if (*it == top_floating_view) { it_top = it; top_pos = i; } if ((top_pos >= 0) && (bot_pos >= 0)) break; } if ((it_top == _view_window_list.end()) || (it_bot == _view_window_list.end())) { return; } if ((top_pos < bot_pos) && (strict == false)) { _view_window_list.erase(it_top); _view_window_list.insert(it_bot, WeakBaseWindowPtr(top_floating_view)); } EnsureAlwaysOnFrontWindow(); } void WindowCompositor::SetAlwaysOnFrontWindow(BaseWindow* window) { _always_on_front_window = WeakBaseWindowPtr(window); EnsureAlwaysOnFrontWindow(); } void WindowCompositor::EnsureAlwaysOnFrontWindow() { // Do not re-order while we are traversing the list of BaseWindow. if (inside_event_cycle_) return; if (_always_on_front_window == NULL) return; WindowList::iterator always_top_it = find(_view_window_list.begin(), _view_window_list.end(), _always_on_front_window); if ((always_top_it != _view_window_list.end()) && (always_top_it != _view_window_list.begin()) && _always_on_front_window.IsValid()) { _view_window_list.erase(always_top_it); _view_window_list.push_front(_always_on_front_window); } } int WindowCompositor::GetProximityListSize() const { return area_proximities_.size(); } void WindowCompositor::AddAreaInProximityList(InputAreaProximity* prox_area) { if (prox_area) { area_proximities_.push_back(prox_area); } else { LOG_ERROR(logger) << "Error, attempted to add a NULL InputAreaProximity to the list."; } } void WindowCompositor::RemoveAreaInProximityList(InputAreaProximity* prox_area) { if (prox_area) { area_proximities_.remove(prox_area); } } void WindowCompositor::CheckMouseNearArea(Event const& event) { for (auto area : area_proximities_) { if (area) { area->CheckMousePosition(Point(event.x, event.y)); } } } void WindowCompositor::ForEachBaseWindow(ForEachBaseWindowFunc const& func) { for (auto const& window : _view_window_list) { if (window.IsValid()) func(window); } for (auto const& window : _modal_view_window_list) { if (window.IsValid()) func(window); } if (m_MenuWindow.IsValid()) func(m_MenuWindow); if (_tooltip_window.IsValid()) func(_tooltip_window); if (m_OverlayWindow.IsValid()) func(m_OverlayWindow); } void WindowCompositor::Draw(bool SizeConfigurationEvent, bool force_draw) { inside_rendering_cycle_ = true; if (!window_thread_->GetGraphicsDisplay().isWindowMinimized()) { //int w, h; window_thread_->GetGraphicsEngine().GetContextSize(m_Width, m_Height); window_thread_->GetGraphicsEngine().SetViewport(0, 0, m_Width, m_Height); // Reset the Model view Matrix and the projection matrix window_thread_->GetGraphicsEngine().ResetProjectionMatrix(); window_thread_->GetGraphicsEngine().ResetModelViewMatrixStack(); window_thread_->GetGraphicsEngine().Push2DTranslationModelViewMatrix(0.0f, 0.0f, 0.0f); if (force_draw || SizeConfigurationEvent) { // We fall here after something dramatic has happen to the window such as a resizing. In this case // everything must be rendered. This is very costly and should happen rarely. if (!window_thread_->IsEmbeddedWindow()) RenderMainWindowComposition(true); { RenderTopViews(true, _view_window_list, false); RenderTopViews(true, _modal_view_window_list, true); DrawMenu(true); DrawTooltip(true); DrawOverlay(true); } } else if (m_MenuRemoved) { // A popup removed cause the whole window to be dirty(at least some part of it). // So exchange DrawList with a real Draw. if (!window_thread_->IsEmbeddedWindow()) RenderMainWindowComposition(false); { RenderTopViews(false, _view_window_list, false); RenderTopViews(false, _modal_view_window_list, true); DrawMenu(true); DrawTooltip(true); DrawOverlay(true); } } else { if (!window_thread_->IsEmbeddedWindow()) RenderMainWindowComposition(false); { RenderTopViews(false, _view_window_list, false); RenderTopViews(false, _modal_view_window_list, true); DrawMenu(true); DrawTooltip(true); DrawOverlay(true); } } m_MenuRemoved = false; window_thread_->GetGraphicsEngine().Pop2DWindow(); } inside_rendering_cycle_ = false; } void WindowCompositor::DrawMenu(bool force_draw) { #if !defined(NUX_MINIMAL) WeakBaseWindowPtr window(m_MenuWindow); if (window.IsValid()) { //window_thread_->GetGraphicsEngine().SetContext(x, y, buffer_width, buffer_height); window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(window_thread_->GetGraphicsEngine().GetWindowWidth(), window_thread_->GetGraphicsEngine().GetWindowHeight()); window_thread_->GetGraphicsEngine().EmptyClippingRegion(); } else { window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(window_thread_->GetGraphicsEngine().GetWindowWidth(), window_thread_->GetGraphicsEngine().GetWindowHeight()); window_thread_->GetGraphicsEngine().EmptyClippingRegion(); } std::list::reverse_iterator rev_it_menu; for (rev_it_menu = _menu_chain->rbegin(); rev_it_menu != _menu_chain->rend( ); ++rev_it_menu) { SetProcessingTopView(m_MenuWindow.GetPointer()); (*rev_it_menu)->ProcessDraw(window_thread_->GetGraphicsEngine(), force_draw); SetProcessingTopView(NULL); } #endif } void WindowCompositor::DrawOverlay(bool /* force_draw */) { int buffer_width = window_thread_->GetGraphicsEngine().GetWindowWidth(); int buffer_height = window_thread_->GetGraphicsEngine().GetWindowHeight(); if (m_OverlayWindow.IsValid()) { //window_thread_->GetGraphicsEngine().SetContext(x, y, buffer_width, buffer_height); window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(buffer_width, buffer_height); window_thread_->GetGraphicsEngine().EmptyClippingRegion(); } else window_thread_->GetGraphicsEngine().SetOpenGLClippingRectangle(0, 0, buffer_width, buffer_height); if (OverlayDrawingCommand) { SetProcessingTopView(m_OverlayWindow.GetPointer()); OverlayDrawingCommand->OverlayDrawing(window_thread_->GetGraphicsEngine()); SetProcessingTopView(NULL); } //GetGraphicsDisplay()->GetGraphicsEngine()->SetContext(0, 0, buffer_width, buffer_height); } void WindowCompositor::DrawTooltip(bool /* force_draw */) { int buffer_width = window_thread_->GetGraphicsEngine().GetWindowWidth(); int buffer_height = window_thread_->GetGraphicsEngine().GetWindowHeight(); if (_tooltip_window.IsValid()) { //window_thread_->GetGraphicsEngine().SetContext(x, y, buffer_width, buffer_height); window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(buffer_width, buffer_height); window_thread_->GetGraphicsEngine().EmptyClippingRegion(); } else window_thread_->GetGraphicsEngine().SetOpenGLClippingRectangle(0, 0, buffer_width, buffer_height); if (m_TooltipText.size()) { //SetProcessingTopView(_tooltip_window); GetPainter().PaintShape(window_thread_->GetGraphicsEngine(), _tooltip_geometry, Color(0xA0000000), eSHAPE_CORNER_ROUND10, true); GetPainter().PaintTextLineStatic(window_thread_->GetGraphicsEngine(), GetSysBoldFont(), _tooltip_text_geometry, m_TooltipText, Color(0xFFFFFFFF)); //SetProcessingTopView(NULL); } //GetGraphicsDisplay()->GetGraphicsEngine()->SetContext(0, 0, buffer_width, buffer_height); } void WindowCompositor::RenderTopViewContent(BaseWindow* window, bool force_draw) { GetPainter().EmptyBackgroundStack(); SetProcessingTopView(window); window->ProcessDraw(window_thread_->GetGraphicsEngine(), force_draw || window->IsRedrawNeeded()); SetProcessingTopView(NULL); GetPainter().EmptyBackgroundStack(); } void WindowCompositor::PresentAnyReadyWindows() { if (!currently_rendering_windows_ || !current_global_clip_rect_) return; GraphicsEngine& graphics_engine = window_thread_->GetGraphicsEngine(); // Present all buffers to the screen graphics_engine.ApplyClippingRectangle(); CHECKGL(glDepthMask(GL_FALSE)); WindowList &windows = *currently_rendering_windows_; Geometry &global_clip_rect = *current_global_clip_rect_; for (auto const& window_ptr : windows) { if (window_ptr.IsNull()) continue; BaseWindow* window = window_ptr.GetPointer(); if (window->IsVisible()) { auto const& win_geo = window->GetGeometry(); if (!global_clip_rect.IsIntersecting(win_geo)) { // The global clipping area can be seen as a per monitor clipping // region. It is mostly used in embedded mode with compiz. If we // get here, it means that the BaseWindow we want to render is not // in area of the monitor that compiz is currently rendering. So // skip it. continue; } RenderTargetTextures& rt = GetWindowBuffer(window); if (rt.color_rt.IsValid()) { /* Already been presented */ if (!window->_contents_ready_for_presentation) continue; /* Caller doesn't want us to render this yet */ if (window_thread_->IsEmbeddedWindow() && !window->AllowPresentationInEmbeddedMode()) continue; // Nux is done rendering a BaseWindow into a texture. The previous call to Deactivate // has cancelled any opengl framebuffer object that was set. PresentBufferToScreen(rt.color_rt, win_geo.x, win_geo.y, false, false, window->GetOpacity(), window->premultiply()); window->_contents_ready_for_presentation = false; } } } } void WindowCompositor::RenderTopViews(bool force_draw, WindowList& windows_to_render, bool drawModal) { // Before anything, deactivate the current frame buffer, set the viewport // to the size of the display and call EmptyClippingRegion(). // Then call GetScissorRect() to get the size of the global clipping area. // This is is hack until we implement SetGlobalClippingRectangle() (the opposite of SetGlobalClippingRectangle). GraphicsEngine& graphics_engine = window_thread_->GetGraphicsEngine(); unsigned int window_width = graphics_engine.GetWindowWidth(); unsigned int window_height = graphics_engine.GetWindowHeight(); graphics_engine.SetViewport(0, 0, window_width, window_height); graphics_engine.EmptyClippingRegion(); Geometry global_clip_rect = graphics_engine.GetScissorRect(); global_clip_rect.y = window_height - global_clip_rect.y - global_clip_rect.height; current_global_clip_rect_ = &global_clip_rect; // We don't need to restore framebuffers if we didn't update any windows bool updated_any_windows = false; // Always make a copy of the windows to render. We have no control over // the windows we are actually drawing. It has been observed that some // windows modify the windows stack during the draw process. // // So... we take a copy of the window list. As much as I'd love to just // have BaseWindow* in the container, again, we have no control over the // windows we are drawing and one may just decide to unregister or destroy // another window mid-render. Since we are contructing a copy of the // list, lets reverse it as we are constructing, as we want to draw the // windows from back to front. WindowList windows(windows_to_render.rbegin(), windows_to_render.rend()); currently_rendering_windows_ = &windows; for (auto const& window_ptr : windows) { if (window_ptr.IsNull()) continue; BaseWindow* window = window_ptr.GetPointer(); if (!drawModal && window->IsModal()) continue; if (window->IsVisible()) { auto const& win_geo = window->GetGeometry(); if (!global_clip_rect.IsIntersecting(win_geo)) { // The global clipping area can be seen as a per monitor clipping // region. It is mostly used in embedded mode with compiz. If we // get here, it means that the BaseWindow we want to render is not // in area of the monitor that compiz is currently rendering. So // skip it. continue; } RenderTargetTextures& rt = GetWindowBuffer(window); // Based on the areas that requested a rendering inside the // BaseWindow, render the BaseWindow or just use its cache. if (force_draw || window->IsRedrawNeeded() || window->ChildNeedsRedraw()) { if (rt.color_rt.IsValid() /*&& rt.depth_rt.IsValid()*/) { int buffer_width = window->GetBaseWidth(); int buffer_height = window->GetBaseHeight(); if ((rt.color_rt->GetWidth() != buffer_width) || (rt.color_rt->GetHeight() != buffer_height)) { rt.color_rt = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(buffer_width, buffer_height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); rt.depth_rt = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(buffer_width, buffer_height, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); } m_FrameBufferObject->FormatFrameBufferObject(buffer_width, buffer_height, BITFMT_R8G8B8A8); m_FrameBufferObject->SetTextureAttachment(0, rt.color_rt, 0); m_FrameBufferObject->SetDepthTextureAttachment(rt.depth_rt, 0); m_FrameBufferObject->Activate(); graphics_engine.SetViewport(0, 0, buffer_width, buffer_height); graphics_engine.SetOrthographicProjectionMatrix(buffer_width, buffer_height); graphics_engine.EmptyClippingRegion(); graphics_engine.SetOpenGLClippingRectangle(0, 0, buffer_width, buffer_height); CHECKGL( glClearColor(0, 0, 0, 0)); GLuint clear_color_buffer_bit = (force_draw || window->IsRedrawNeeded()) ? GL_COLOR_BUFFER_BIT : 0; CHECKGL( glClear(clear_color_buffer_bit | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); } else { Matrix4 mat; mat.Translate(win_geo.x, win_geo.y, 0); graphics_engine.SetOrthographicProjectionMatrix(window_width, window_height); } RenderTopViewContent(window, force_draw); m_FrameBufferObject->Deactivate(); CHECKGL(glDepthMask(GL_TRUE)); graphics_engine.GetRenderStates().SetBlend(false); updated_any_windows = true; } window->_child_need_redraw = false; window->_contents_ready_for_presentation = true; } else { // Invisible window, nothing to draw. window->_child_need_redraw = false; window->DoneRedraw(); } } /* If any windows were updated, then we need to rebind our * reference framebuffer */ if (updated_any_windows) { if (GetWindowThread()->IsEmbeddedWindow()) { // Restore the reference framebuffer if (!RestoreReferenceFramebuffer()) { LOG_DEBUG(logger) << "RenderTopViews: Setting the Reference fbo has failed."; } } else { GetGraphicsDisplay()->GetGpuDevice()->DeactivateFrameBuffer(); } } /* Present any windows which haven't yet been presented */ PresentAnyReadyWindows(); currently_rendering_windows_ = nullptr; current_global_clip_rect_ = nullptr; } void WindowCompositor::RenderMainWindowComposition(bool force_draw) { int buffer_width, buffer_height; buffer_width = window_thread_->GetGraphicsEngine().GetWindowWidth(); buffer_height = window_thread_->GetGraphicsEngine().GetWindowHeight(); if ((!m_MainColorRT.IsValid()) || (m_MainColorRT->GetWidth() != buffer_width) || (m_MainColorRT->GetHeight() != buffer_height)) { m_MainColorRT = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(buffer_width, buffer_height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); } if (platform_support_for_depth_texture_) { if ((!m_MainDepthRT.IsValid()) || (m_MainDepthRT->GetWidth() != buffer_width) || (m_MainDepthRT->GetHeight() != buffer_height)) { m_MainDepthRT = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(buffer_width, buffer_height, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); } } m_FrameBufferObject->FormatFrameBufferObject(buffer_width, buffer_height, BITFMT_R8G8B8A8); m_FrameBufferObject->SetTextureAttachment(0, m_MainColorRT, 0); m_FrameBufferObject->SetDepthTextureAttachment(m_MainDepthRT, 0); m_FrameBufferObject->Activate(); window_thread_->GetGraphicsEngine().EmptyClippingRegion(); window_thread_->GetGraphicsEngine().SetOpenGLClippingRectangle(0, 0, buffer_width, buffer_height); window_thread_->GetGraphicsEngine().SetViewport(0, 0, buffer_width, buffer_height); window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(buffer_width, buffer_height); { CHECKGL(glClear(/*GL_COLOR_BUFFER_BIT |*/ GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); //Begin 2D Drawing { if (force_draw) { GetPainter().PushDrawLayer(window_thread_->GetGraphicsEngine(), Geometry(0, 0, buffer_width, buffer_height), m_Background); //GetPainter().PushBackground(window_thread_->GetGraphicsEngine(), Geometry(0, 0, buffer_width, buffer_height), m_Background, true); window_thread_->ProcessDraw(window_thread_->GetGraphicsEngine(), true); nuxAssert(window_thread_->GetGraphicsEngine().GetNumberOfClippingRegions() == 0); GetPainter().PopBackground(); GetPainter().EmptyBackgroundStack(); } else { GetPainter().PushLayer(window_thread_->GetGraphicsEngine(), Geometry(0, 0, buffer_width, buffer_height), m_Background); //GetPainter().PushBackground(window_thread_->GetGraphicsEngine(), Geometry(0, 0, buffer_width, buffer_height), m_Background, false); window_thread_->ProcessDraw(window_thread_->GetGraphicsEngine(), false); nuxAssert(window_thread_->GetGraphicsEngine().GetNumberOfClippingRegions() == 0); GetPainter().PopBackground(); GetPainter().EmptyBackgroundStack(); } } // End 2D Drawing } window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(buffer_width, buffer_height); m_FrameBufferObject->Deactivate(); unsigned int window_width, window_height; window_width = window_thread_->GetGraphicsEngine().GetWindowWidth(); window_height = window_thread_->GetGraphicsEngine().GetWindowHeight(); window_thread_->GetGraphicsEngine().EmptyClippingRegion(); window_thread_->GetGraphicsEngine().SetOpenGLClippingRectangle(0, 0, window_width, window_height); window_thread_->GetGraphicsEngine().SetViewport(0, 0, window_width, window_height); window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(window_width, window_height); PresentBufferToScreen(m_MainColorRT, 0, 0, false); } void WindowCompositor::PresentBufferToScreen(ObjectPtr HWTexture, int x, int y, bool RenderToMainTexture, bool /* BluredBackground */, float opacity, bool premultiply) { nuxAssert(HWTexture.IsValid()); if (HWTexture.IsNull()) return; int window_width, window_height; window_width = window_thread_->GetGraphicsEngine().GetWindowWidth(); window_height = window_thread_->GetGraphicsEngine().GetWindowHeight(); if (RenderToMainTexture && (HWTexture != m_MainColorRT)) { nuxAssert(m_MainColorRT->GetWidth() == window_width); nuxAssert(m_MainColorRT->GetHeight() == window_height); m_FrameBufferObject->FormatFrameBufferObject(window_width, window_height, BITFMT_R8G8B8A8); m_FrameBufferObject->SetTextureAttachment(0, m_MainColorRT, 0); m_FrameBufferObject->SetDepthTextureAttachment(m_MainDepthRT, 0); m_FrameBufferObject->Activate(); } // Reference framebuffer is already restored window_thread_->GetGraphicsEngine().EmptyClippingRegion(); window_thread_->GetGraphicsEngine().SetOpenGLClippingRectangle(0, 0, window_width, window_height); window_thread_->GetGraphicsEngine().SetViewport(0, 0, window_width, window_height); window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(window_width, window_height); // Render the MAINFBO { int src_width, src_height; src_width = HWTexture->GetWidth(); src_height = HWTexture->GetHeight(); TexCoordXForm texxform0; texxform0.FlipVCoord(true); if (premultiply) { window_thread_->GetGraphicsEngine().GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); GetGraphicsDisplay()->GetGraphicsEngine()->QRP_1Tex(x, y, src_width, src_height, HWTexture, texxform0, Color(opacity, opacity, opacity, opacity)); } else { window_thread_->GetGraphicsEngine().GetRenderStates().SetBlend(false); GetGraphicsDisplay()->GetGraphicsEngine()->QRP_1Tex(x, y, src_width, src_height, HWTexture, texxform0, Color(1.0f, 1.0f, 1.0f, opacity)); } window_thread_->GetGraphicsEngine().GetRenderStates().SetBlend(false); } } #if !defined(NUX_MINIMAL) void WindowCompositor::AddMenu(MenuPage* menu, BaseWindow* window, bool OverrideCurrentMenuChain) { if (_menu_chain->empty()) { // A menu is opening. _starting_menu_event_cycle = true; _menu_is_active = true; } std::list::iterator it = find(_menu_chain->begin(), _menu_chain->end(), menu); if (it == _menu_chain->end()) { // When adding a MenuPage, make sure that it is a child of the MenuPage in _menu_chain->begin(). if (!_menu_chain->empty()) { if (menu->GetParentMenu() != (*_menu_chain->begin())) { if (OverrideCurrentMenuChain) { // Remove the current menu chain for (it = _menu_chain->begin(); it != _menu_chain->end(); ++it) { // Stop all pages (*it)->StopMenu(); } _menu_chain->clear(); } else { // The MenuPage argument is not a descendent of the current menu chain. return; } } } m_MenuWindow = window; // The deepest menu is added in front of the list and tested first for events. _menu_chain->push_front(menu); } } // Be careful never call this function while you are iterating through the elements of _menu_chain. void WindowCompositor::RemoveMenu(MenuPage* menu) { std::list::iterator it = find(_menu_chain->begin(), _menu_chain->end(), menu); if (it == _menu_chain->end()) { return; } _menu_chain->erase(it); m_MenuRemoved = true; if (_menu_is_active && (_menu_chain->empty())) { // The menu is closed _menu_is_active = false; ResetMousePointerAreas(); m_MenuWindow = NULL; } } void WindowCompositor::CleanMenu() { if (_menu_chain->empty()) return; std::list::iterator menu_it = _menu_chain->begin(); while (menu_it != _menu_chain->end()) { if ((*menu_it)->IsActive() == false) { menu_it = _menu_chain->erase(menu_it); m_MenuRemoved = true; } else { ++menu_it; } } if (_menu_is_active && (_menu_chain->empty())) { _menu_is_active = false; ResetMousePointerAreas(); m_MenuWindow = NULL; } } #endif void WindowCompositor::SetWidgetDrawingOverlay(InputArea* ic, BaseWindow* OverlayWindow) { OverlayDrawingCommand = ic; m_OverlayWindow = OverlayWindow; } InputArea* WindowCompositor::GetWidgetDrawingOverlay() { return OverlayDrawingCommand; } void WindowCompositor::SetTooltip(InputArea* TooltipArea, const char* TooltipText, int x, int y) { _tooltip_window = GetProcessingTopView(); m_TooltipArea = TooltipArea; m_TooltipText = TooltipText; m_TooltipX = x; m_TooltipY = y; if (m_TooltipText.size()) { int w = GetSysBoldFont()->GetCharStringWidth(m_TooltipText.c_str()); int h = GetSysBoldFont()->GetFontHeight(); _tooltip_text_geometry = Geometry( m_TooltipX + 10, m_TooltipY - h/2 - 2, w, h + 4); _tooltip_geometry = _tooltip_text_geometry; _tooltip_geometry.OffsetSize(20, 8); _tooltip_geometry.OffsetPosition(-10, -4); _tooltip_mainwindow_geometry = _tooltip_geometry; if (_tooltip_window.IsValid()) { _tooltip_mainwindow_geometry.OffsetPosition(_tooltip_window->GetBaseX(), _tooltip_window->GetBaseY()); } } else { _tooltip_mainwindow_geometry = _tooltip_geometry = _tooltip_text_geometry = Geometry(0, 0, 0, 0); } } Geometry WindowCompositor::GetTooltipGeometry() const { return _tooltip_geometry; } Geometry WindowCompositor::GetTooltipMainWindowGeometry() const { return _tooltip_mainwindow_geometry; } void WindowCompositor::CancelTooltip() { _tooltip_window = NULL; m_TooltipArea = NULL; m_TooltipText = ""; } bool WindowCompositor::ValidateMouseInsideTooltipArea(int x, int y) { NUX_RETURN_VALUE_IF_FALSE(m_TooltipArea, false); NUX_RETURN_VALUE_IF_FALSE(_tooltip_window.IsValid(), false); Geometry geo = m_TooltipArea->GetGeometry(); geo.OffsetPosition(_tooltip_window->GetBaseX(), _tooltip_window->GetBaseY()); return geo.IsPointInside(x, y); } bool WindowCompositor::IsTooltipActive() { NUX_RETURN_VALUE_IF_FALSE(m_TooltipArea, false); return true; } bool WindowCompositor::SetKeyFocusArea(InputArea* area, KeyNavDirection direction) { InputArea* keyboard_grab_area = GetKeyboardGrabArea(); if (keyboard_grab_area && area && (area != keyboard_grab_area) && (!area->IsChildOf(keyboard_grab_area))) { // There is a keyboard grab pending. Only an area that is a child of the area that has // the keyboard grab can be set to receive keyboard events. LOG_DEBUG(logger) << "SetKeyFocusArea: There is a keyboard grab pending. Cannot change the keyboard event receiver."; return false; } if (key_focus_area_ == area) { // Already has the keyboard focus. return true; } if (area && (area->AcceptKeyNavFocus() == false)) { // Area does not want the keyboard focus. return false; } if (key_focus_area_.IsValid()) { // This is the area that has the keyboard focus. Emit the signal 'end_key_focus'. key_focus_area_->end_key_focus.emit(); // From the area that has the keyboard focus to the top level parent, delete the path that // leads to the keyboard focus area. key_focus_area_->ResetUpwardPathToKeyFocusArea(); if (key_focus_area_->Type().IsDerivedFromType(InputArea::StaticObjectType)) { // Signal emitted from the WindowCompositor. key_nav_focus_change.emit(key_focus_area_.GetPointer(), false, direction); // Signal emitted from the area itself. key_focus_area_->key_nav_focus_change.emit(key_focus_area_.GetPointer(), false, direction); // nuxDebugMsg("[WindowCompositor::SetKeyFocusArea] Area type '%s' named '%s': Lost key nav focus.", // key_focus_area_->Type().name, // key_focus_area_->GetBaseString().c_str()); } if (key_focus_area_->Type().IsDerivedFromType(View::StaticObjectType)) { static_cast(key_focus_area_.GetPointer())->QueueDraw(); } } if (area) { key_focus_area_ = area; // From the area that has the keyboard focus to the top level parent, mark the path that // leads to the keyboard focus area. key_focus_area_->SetPathToKeyFocusArea(); // Emit the signal 'begin_key_focus'. key_focus_area_->begin_key_focus.emit(); if (key_focus_area_->Type().IsDerivedFromType(InputArea::StaticObjectType)) { // Signal emitted from the WindowCompositor. key_nav_focus_change.emit(key_focus_area_.GetPointer(), true, direction); // Signal emitted from the area itself. key_focus_area_->key_nav_focus_change.emit(key_focus_area_.GetPointer(), true, direction); // nuxDebugMsg("[WindowCompositor::SetKeyFocusArea] Area type '%s' named '%s': Has key nav focus.", // key_focus_area_->Type().name, // key_focus_area_->GetBaseString().c_str()); } if (key_focus_area_->Type().IsDerivedFromType(View::StaticObjectType)) { static_cast(key_focus_area_.GetPointer())->QueueDraw(); } key_focus_area_->ChildFocusChanged.emit(key_focus_area_.GetPointer()); } else { key_focus_area_ = NULL; // Signal emitted from the area itself. key_nav_focus_change.emit(NULL, false, direction); } return key_focus_area_.IsValid(); } InputArea* WindowCompositor::GetKeyFocusArea() { return key_focus_area_.GetPointer(); } void WindowCompositor::SetBackgroundPaintLayer(AbstractPaintLayer* bkg) { NUX_SAFE_DELETE(m_Background); m_Background = bkg->Clone(); } void WindowCompositor::FloatingAreaConfigureNotify(int Width, int Height) { WindowList::iterator it; for (auto const& win : _view_window_list) { if (!win.IsValid()) continue; if (win->IsVisible()) win->NotifyConfigurationChange(Width, Height); } } void WindowCompositor::FormatRenderTargets(int /* width */, int /* height */) { int buffer_width = window_thread_->GetGraphicsEngine().GetWindowWidth(); int buffer_height = window_thread_->GetGraphicsEngine().GetWindowHeight(); nuxAssert(buffer_width >= 1); nuxAssert(buffer_height >= 1); m_MainColorRT = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(buffer_width, buffer_height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); if (platform_support_for_depth_texture_) { m_MainDepthRT = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(buffer_width, buffer_height, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); } // Clear the buffer the first time... m_FrameBufferObject->FormatFrameBufferObject(buffer_width, buffer_height, BITFMT_R8G8B8A8); m_FrameBufferObject->SetTextureAttachment(0, m_MainColorRT, 0); m_FrameBufferObject->SetDepthTextureAttachment(m_MainDepthRT, 0); m_FrameBufferObject->Activate(); CHECKGL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); CHECKGL(glClearDepth(1.0f)); CHECKGL(glClearStencil(0)); CHECKGL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); m_FrameBufferObject->Deactivate(); CHECKGL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); CHECKGL(glClearDepth(1.0f)); CHECKGL(glClearStencil(0)); CHECKGL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); // m_BlurTexture = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(Max(buffer_width, 1), Max(buffer_height, 1), 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); // m_FullSceneMip0 = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(Max(buffer_width / 2, 1), Max(buffer_height / 2, 1), 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); // m_FullSceneMip1 = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(Max(buffer_width / 4, 1), Max(buffer_height / 4, 1), 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); // m_FullSceneMip2 = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(Max(buffer_width / 8, 1), Max(buffer_height / 8, 1), 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); } void WindowCompositor::RestoreRenderingSurface() { BaseWindow* top_view = GetProcessingTopView(); if (top_view && inside_rendering_cycle_) { nuxAssert(top_view->Type().IsDerivedFromType(BaseWindow::StaticObjectType)); RenderTargetTextures rt = GetWindowBuffer(top_view); int buffer_width = top_view->GetBaseWidth(); int buffer_height = top_view->GetBaseHeight(); nuxAssert(buffer_width >= 1); nuxAssert(buffer_height >= 1); if ((rt.color_rt->GetWidth() != buffer_width) || (rt.color_rt->GetHeight() != buffer_height)) { rt.color_rt = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(buffer_width, buffer_height, 1, BITFMT_R8G8B8A8, NUX_TRACKER_LOCATION); } if (platform_support_for_depth_texture_) { if ((rt.depth_rt->GetWidth() != buffer_width) || (rt.depth_rt->GetHeight() != buffer_height)) { rt.depth_rt = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(buffer_width, buffer_height, 1, BITFMT_D24S8, NUX_TRACKER_LOCATION); } } m_FrameBufferObject->FormatFrameBufferObject(buffer_width, buffer_height, BITFMT_R8G8B8A8); m_FrameBufferObject->SetTextureAttachment(0, rt.color_rt, 0); m_FrameBufferObject->SetDepthTextureAttachment(rt.depth_rt, 0); m_FrameBufferObject->Activate(); window_thread_->GetGraphicsEngine().SetViewport(0, 0, buffer_width, buffer_height); window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(buffer_width, buffer_height); window_thread_->GetGraphicsEngine().ApplyClippingRectangle(); //window_thread_->GetGraphicsEngine().ApplyModelViewMatrix(); ??? } else { int buffer_width = window_thread_->GetGraphicsEngine().GetWindowWidth(); int buffer_height = window_thread_->GetGraphicsEngine().GetWindowHeight(); nuxAssert(buffer_width >= 1); nuxAssert(buffer_height >= 1); // Restore Main Frame Buffer if not in embedded mode if (!GetWindowThread()->IsEmbeddedWindow()) { m_FrameBufferObject->FormatFrameBufferObject(buffer_width, buffer_height, BITFMT_R8G8B8A8); m_FrameBufferObject->SetTextureAttachment(0, m_MainColorRT, 0); m_FrameBufferObject->SetDepthTextureAttachment(m_MainDepthRT, 0); m_FrameBufferObject->Activate(); } else { // Restore reference framebuffer RestoreReferenceFramebuffer(); // Present any ready windows PresentAnyReadyWindows(); } window_thread_->GetGraphicsEngine().SetViewport(0, 0, buffer_width, buffer_height); window_thread_->GetGraphicsEngine().SetOrthographicProjectionMatrix(buffer_width, buffer_height); window_thread_->GetGraphicsEngine().ApplyClippingRectangle(); //window_thread_->GetGraphicsEngine().ApplyModelViewMatrix(); ??? } } void* WindowCompositor::GetBackupTextureData(BaseWindow* base_window, int& width, int& height, int& format) { width = height = format = 0; NUX_RETURN_VALUE_IF_NULL(base_window, 0); std::map::iterator it; it = _window_to_texture_map.find(base_window); if (it == _window_to_texture_map.end()) { return 0; } if ((*it).second.color_rt.IsNull()) { return 0; } return (*it).second.color_rt->GetSurfaceData(0, width, height, format); } void WindowCompositor::ResetDnDArea() { SetDnDArea(NULL); } void WindowCompositor::SetDnDArea(InputArea* area) { #if defined(DRAG_AND_DROP_SUPPORTED) if (_dnd_area == area) return; if (_dnd_area) { _dnd_area->HandleDndLeave(); _dnd_area->UnReference(); } _dnd_area = area; if (_dnd_area) { _dnd_area->Reference(); _dnd_area->HandleDndEnter(); } #endif } InputArea* WindowCompositor::GetDnDArea() { return _dnd_area; } bool WindowCompositor::GrabPointerAdd(InputArea* area) { NUX_RETURN_VALUE_IF_NULL(area, false); bool result = true; if (GetPointerGrabArea() == area) { LOG_DEBUG(logger) << "GrabPointerAdd: The area already has the grab"; return result; } if (window_thread_->GetGraphicsDisplay().PointerGrabData() != this) result = window_thread_->GetGraphicsDisplay().GrabPointer(NULL, this, true); if (result) pointer_grab_stack_.push_front(area); // reset the mouse pointers areas. ResetMousePointerAreas(); return result; } bool WindowCompositor::GrabPointerRemove(InputArea* area) { NUX_RETURN_VALUE_IF_NULL(area, false); std::list::iterator it; // find the first instance of the area pointer in the stack it = find(pointer_grab_stack_.begin(), pointer_grab_stack_.end(), area); if (it == pointer_grab_stack_.end()) return false; pointer_grab_stack_.erase(it); if (pointer_grab_stack_.empty()) window_thread_->GetGraphicsDisplay().UngrabPointer(this); // reset the mouse pointers areas. ResetMousePointerAreas(); return true; } bool WindowCompositor::IsInPointerGrabStack(InputArea* area) { NUX_RETURN_VALUE_IF_NULL(area, false); std::list::iterator it; it = find(pointer_grab_stack_.begin(), pointer_grab_stack_.end(), area); if (it == pointer_grab_stack_.end()) return false; return true; } InputArea* WindowCompositor::GetPointerGrabArea() { if (pointer_grab_stack_.empty()) return NULL; return (*pointer_grab_stack_.begin()); } bool WindowCompositor::GrabKeyboardAdd(InputArea* area) { NUX_RETURN_VALUE_IF_NULL(area, false); bool result = true; if (GetKeyboardGrabArea() == area) { LOG_DEBUG(logger) << "GrabKeyboardAdd: The area already has the grab"; return result; } if (window_thread_->GetGraphicsDisplay().KeyboardGrabData() != this) { result = window_thread_->GetGraphicsDisplay().GrabKeyboard(NULL, this, true); } if (result) { InputArea* current_keyboard_grab = GetKeyboardGrabArea(); if (current_keyboard_grab) current_keyboard_grab->end_keyboard_grab.emit(current_keyboard_grab); keyboard_grab_stack_.push_front(area); // If there is any area with the key focus, cancel it. if (key_focus_area_.IsValid()) { key_focus_area_->end_key_focus.emit(); key_focus_area_->ResetUpwardPathToKeyFocusArea(); if (key_focus_area_->Type().IsDerivedFromType(InputArea::StaticObjectType)) { // Signal emitted from the WindowCompositor. key_nav_focus_change.emit(key_focus_area_.GetPointer(), false, KEY_NAV_NONE); // Signal emitted from the area itself. key_focus_area_->key_nav_focus_change.emit(key_focus_area_.GetPointer(), false, KEY_NAV_NONE); // nuxDebugMsg("[WindowCompositor::GrabKeyboardAdd] Area type '%s' named '%s': Lost key nav focus.", // key_focus_area_->Type().name, // key_focus_area_->GetBaseString().c_str()); } if (key_focus_area_->Type().IsDerivedFromType(View::StaticObjectType)) { static_cast(key_focus_area_.GetPointer())->QueueDraw(); } key_focus_area_ = NULL; } // Must be called only after the area has been added to the front of keyboard_grab_stack_. SetKeyFocusArea(area); area->start_keyboard_grab.emit(area); } return result; } bool WindowCompositor::GrabKeyboardRemove(InputArea* area) { NUX_RETURN_VALUE_IF_NULL(area, false); std::list::iterator it; // find the first instance of the area keyboard in the stack it = find(keyboard_grab_stack_.begin(), keyboard_grab_stack_.end(), area); if (it == keyboard_grab_stack_.end()) return false; InputArea* current_keyboard_grab = (*it); bool has_grab = false; if (it == keyboard_grab_stack_.begin()) { // At the top of the keyboard_grab_stack_. Means it has the keyboard grab. has_grab = true; } // First remove the area from the grab list keyboard_grab_stack_.erase(it); // Then emit end_keyboard_grab if the area had the keyboard grab if (has_grab && current_keyboard_grab) { current_keyboard_grab->end_keyboard_grab.emit(current_keyboard_grab); } if (keyboard_grab_stack_.empty()) { window_thread_->GetGraphicsDisplay().UngrabKeyboard(this); } // Must be called only after the area has been added to the front of keyboard_grab_stack_. if (keyboard_grab_stack_.empty()) { SetKeyFocusArea(NULL); } else { // If there is any area with the key focus, cancel it. if (key_focus_area_.IsValid()) { key_focus_area_->end_key_focus.emit(); key_focus_area_->ResetUpwardPathToKeyFocusArea(); if (key_focus_area_->Type().IsDerivedFromType(InputArea::StaticObjectType)) { // Signal emitted from the WindowCompositor. key_nav_focus_change.emit(key_focus_area_.GetPointer(), false, KEY_NAV_NONE); // Signal emitted from the area itself. key_focus_area_->key_nav_focus_change.emit(key_focus_area_.GetPointer(), false, KEY_NAV_NONE); // nuxDebugMsg("[WindowCompositor::GrabKeyboardRemove] Area type '%s' named '%s': Lost key nav focus.", // key_focus_area_->Type().name, // key_focus_area_->GetBaseString().c_str()); } if (key_focus_area_->Type().IsDerivedFromType(View::StaticObjectType)) { static_cast(key_focus_area_.GetPointer())->QueueDraw(); } key_focus_area_ = NULL; } it = keyboard_grab_stack_.begin(); SetKeyFocusArea(*it); InputArea* new_keyboard_grab = (*it); new_keyboard_grab->start_keyboard_grab.emit(new_keyboard_grab); } return true; } bool WindowCompositor::IsInKeyboardGrabStack(InputArea* area) { NUX_RETURN_VALUE_IF_NULL(area, false); std::list::iterator it; it = find(keyboard_grab_stack_.begin(), keyboard_grab_stack_.end(), area); if (it == keyboard_grab_stack_.end()) return false; return true; } InputArea* WindowCompositor::GetKeyboardGrabArea() { if (keyboard_grab_stack_.empty()) return NULL; return (*keyboard_grab_stack_.begin()); } void WindowCompositor::SetReferenceFramebuffer(unsigned int draw_fbo_object, unsigned int read_fbo_object, Geometry const& fbo_geometry) { draw_reference_fbo_ = draw_fbo_object; read_reference_fbo_ = read_fbo_object; reference_fbo_geometry_ = fbo_geometry; } namespace { bool CheckExternalFramebufferStatus (GLenum binding) { bool ok = false; // Nux does some sanity checks to make sure that the FBO is in good condition. GLenum status; status = glCheckFramebufferStatusEXT(binding); CHECKGL_MSG(glCheckFramebufferStatusEXT); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: // Everything's OK ok = true; break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT"); ok = false; break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT"); ok = false; break; // See issue(87) of http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt // case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: // nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT"); // ok = false; // break; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT"); ok = false; break; #ifndef NUX_OPENGLES_20 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT"); ok = false; break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT"); ok = false; break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT"); ok = false; break; #endif // case GL_FRAMEBUFFER_STATUS_ERROR_EXT: // nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_STATUS_ERROR_EXT"); // ok = false; // break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: nuxError("[GLFramebufferObject::IsValid] GL_FRAMEBUFFER_UNSUPPORTED_EXT"); ok = false; break; default: nuxError("[GLFramebufferObject::IsValid] Unknown ERROR"); ok = false; } return ok; } void SetReferenceFramebufferViewport(const nux::Geometry &reference_fbo_geometry_) { CHECKGL(glViewport(reference_fbo_geometry_.x, reference_fbo_geometry_.y, reference_fbo_geometry_.width, reference_fbo_geometry_.height)); } } bool WindowCompositor::RestoreReferenceFramebuffer() { // It is assumed that the reference fbo contains valid textures. // Nux does the following: // - Bind the reference fbo (reference_fbo_) // - Call glDrawBuffer with GL_COLOR_ATTACHMENT0 // - Set the opengl viewport size (reference_fbo_geometry_) #ifndef NUX_OPENGLES_20 CHECKGL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, draw_reference_fbo_)); CHECKGL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, read_reference_fbo_)); if (draw_reference_fbo_) { CHECKGL(glDrawBuffer(GL_COLOR_ATTACHMENT0)); } else { CHECKGL(glDrawBuffer(GL_BACK)); } if (read_reference_fbo_) { CHECKGL(glReadBuffer(GL_COLOR_ATTACHMENT0)); } else { CHECKGL(glReadBuffer(GL_BACK)); } #else nuxAssertMsg(draw_reference_fbo_ == read_reference_fbo_, "[WindowCompositor::RestoreReferenceFramebuffer]: OpenGL|ES does not"\ " support separate draw and read framebuffer bindings, using the supplied"\ " draw binding"); CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER, draw_reference_fbo_)); #endif SetReferenceFramebufferViewport(reference_fbo_geometry_); #ifndef NUX_OPENGLES_20 int restore_status = (!draw_reference_fbo_ || CheckExternalFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT)) && (!read_reference_fbo_ || CheckExternalFramebufferStatus(GL_READ_FRAMEBUFFER_EXT)); #else int restore_status = CheckExternalFramebufferStatus(GL_FRAMEBUFFER); #endif return restore_status; } void WindowCompositor::RestoreMainFramebuffer() { // This is a bit inefficient as we unbind and then rebind nux::GetGraphicsDisplay()->GetGpuDevice()->DeactivateFrameBuffer (); RestoreReferenceFramebuffer (); /* Present any ready windows after restoring * the reference framebuffer. This ensures that if * we need to restore the reference framebuffer to * get access to its contents through glCopyTexSubImage2D * that it will also have any rendered views in it too */ PresentAnyReadyWindows(); } #ifdef NUX_GESTURES_SUPPORT void WindowCompositor::SetGestureBroker(std::unique_ptr gesture_broker) { gesture_broker_ = std::move(gesture_broker); } InputArea *WindowCompositor::LocateGestureTarget(const GestureEvent &event) { InputArea *input_area = nullptr; for (auto const& window : _view_window_list) { if (!window.IsValid()) continue; input_area = static_cast(window->GetInputAreaHitByGesture(event)); if (input_area) break; } // If a target InputArea wasn't found in any of the BaseWindows, then check // the InputAreas in the layout of the main window. if (!input_area) { Layout* main_window_layout = window_thread_->GetLayout(); if (main_window_layout) input_area = static_cast( main_window_layout->GetInputAreaHitByGesture(event)); } return input_area; } DefaultGestureBroker::DefaultGestureBroker(WindowCompositor *window_compositor) : window_compositor_(window_compositor) { } std::vector DefaultGestureBroker::FindGestureTargets(const nux::GestureEvent &event) { std::vector targets; InputArea *target_area = window_compositor_->LocateGestureTarget(event); if (target_area) targets.push_back(ShPtGestureTarget(new InputAreaTarget(target_area))); return targets; } #endif } nux-4.0.8+18.10.20180623/Nux/WindowCompositor.h0000644000000000000000000005532013313373365015057 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef WINDOWCOMPOSITOR_H #define WINDOWCOMPOSITOR_H #include #include "BaseWindow.h" #include #include #include #ifdef NUX_GESTURES_SUPPORT #include #include "Gesture.h" #include "GestureBroker.h" #endif namespace nux { class MenuPage; class PBuffer; class WindowThread; class View; class InputArea; class InputAreaProximity; class Area; class PaintLayer; class Event; //! A user interface composition class created by WindowThread. class WindowCompositor : public sigc::trackable { public: typedef ObjectWeakPtr WeakBaseWindowPtr; typedef std::function ForEachBaseWindowFunc; WindowCompositor(WindowThread* window_thread); ~WindowCompositor(); //! Get the Geometry of the tooltip based on the BaseWindow that initiated it. Geometry GetTooltipGeometry() const; //! Get the Geometry of the tooltip based on the MainWindow. Geometry GetTooltipMainWindowGeometry() const; // bool MouseDown(Point pt); // // bool MouseMove(Point pt); // bool MouseUp(Point pt); void ProcessEvent(Event& event); //==================================== void MouseEventCycle(Event& event); void DndEventCycle(Event& event); Point _mouse_position_on_owner; Point _mouse_position; //! Get Mouse position relative to the top left corner of the window. Point GetMousePosition(); int GetProximityListSize() const; void AddAreaInProximityList(InputAreaProximity* area_prox); void RemoveAreaInProximityList(InputAreaProximity* area_prox); void KeyboardEventCycle(Event& event); #if !defined(NUX_MINIMAL) void MenuEventCycle(Event& event); MenuPage* _mouse_owner_menu_page; MenuPage* _mouse_over_menu_page; #endif bool _starting_menu_event_cycle; bool _menu_is_active; //! Set the area that has the keyboard focus. /*! Set the area that has the keyboard focus. If the \i area parameter is NULL, \n the area that has the keyboard focus looses it and the function returns false. @param The area that that gets the keyboard focus. @param The key nav direction that initiated the focus to the provided area. @return True if the area succeeded to get the keyboard focus or it already has it. */ bool SetKeyFocusArea(InputArea* area, KeyNavDirection direction = KEY_NAV_NONE); //! Return the area that has the keyboard focus. /*! Return the area that has the keyboard focus. @return The area that has the keyboard focus. */ InputArea* GetKeyFocusArea(); void ForEachBaseWindow(ForEachBaseWindowFunc const&); //! Signal emitted when a BaseWindow becomes visible. /*! This signal is emitted after the BaseWindow has emitted it own sigVisible signal. */ sigc::signal sigVisibleViewWindow; //!< Signal emitted when the BaseWindow becomes visible. //! Signal emitted when a BaseWindow becomes hidden. /*! This signal is emitted after the BaseWindow has emitted it own sigHidden signal. */ sigc::signal sigHiddenViewWindow; //!< Signal emitted when the BaseWindow becomes hidden. private: /*** Helper functions for MouseEventCycle() ***/ void UpdateKeyNavFocusOnMouseDown(); /* Keeps track of mouse movement and emits mouse_move and mouse_drag accordingly. */ void TrackMouseMovement(const Event &event, bool area_under_mouse_changed); /* Updates mouse_over_area_ and emits mouse_enter and mouse_leave signals accordingly. Returns whether mouse_over_area_ has changed */ bool UpdateWhatAreaIsUnderMouse(const Event& event); /* Processes NUX_MOUSEWHEEL events */ void ProcessMouseWheelEvent(Event& event); /* Updates mouse_owner_area_ and emits mouse_down, mouse_up, mouse_click and mouse_double_click accordingly. */ void UpdateMouseOwner(const Event& event, bool area_under_mouse_changed); /* Feed the appropriate InputArea::ChildMouseEvent() and switch mouse ownership (including the emission of mouse_cancel) if asked to. */ void UpdateEventTrackingByMouseOwnerAncestor(const Event& event); void FindAncestorInterestedInChildMouseEvents(Area *area); //! Traverse the widget tree and found the area that is right below the mouse pointer. void FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type, ObjectWeakPtr& area_under_mouse_pointer); void GetAreaUnderMouse(const Point& mouse_position, NuxEventType event_type, ObjectWeakPtr& area_under_mouse_pointer, WeakBaseWindowPtr& window); //! Traverse the widget tree and found the area has the key focus. void FindKeyFocusArea(NuxEventType event_type, unsigned int key_symbol, unsigned int special_keys_state, ObjectWeakPtr& key_focus_area, WeakBaseWindowPtr& window); //! Traverse the widget tree and found the area has the key focus, but start from a specified widget. void FindKeyFocusAreaFrom(NuxEventType event_type, unsigned int key_symbol, unsigned int special_keys_state, InputArea* root_search_area, ObjectWeakPtr& key_focus_area, WeakBaseWindowPtr& window); void ResetMousePointerAreas(); //! Get the area upon which the mouse button is currently down. ObjectWeakPtr const& GetMouseOwnerArea() const; //! Set the area upon which the mouse button is currently down. void SetMouseOwnerArea(InputArea* area); //! Set the area that is right below the mouse pointer. void SetMouseOverArea(InputArea* area); void SendKeyEvent(InputArea* input_area, NuxEventType event_type, unsigned int key_sym, unsigned long x11_key_code, unsigned long special_keys_state, const char* text, int key_repeat_count); //! Checks the list of porximities to see if the mouse is near any areas. void CheckMouseNearArea(Event const& event); //! The InputArea that has the keyboard navigation focus. /*! The InputArea that has the mouse focus also has the keyboard focus. That is if _mouse_focus_area is not Null then _mouse_focus_area is equal to _mouse_focus_area; */ ObjectWeakPtr key_focus_area_; ObjectWeakPtr mouse_owner_area_; ObjectWeakPtr mouse_over_area_; /* An ancestor of the current mouse owner area that wants to be notified about all mouse events that a descendant receives and optionally take ownership over the mouse at any given moment. \sa InputArea::ChildMouseEvent() */ /* TODO: Make it a list/vector once the need for nested trackers. */ ObjectWeakPtr interested_mouse_owner_ancestor_; int dnd_safety_x_; int dnd_safety_y_; public: /*! This signal is similar to Area::key_nav_focus_change. It is emitted from the WindowCompositor. The user only needs to listen to this signal to find out the area that has received the keyboard focus.\n The signal is received whether the area receiving or loosing the keyboard focus.\n If the second parameter is true, it means the area is receiving the focus.\n The third parameter of this signal indicates the keyboard action that triggered this area \n to receive or loose the keyboard focus. */ sigc::signal key_nav_focus_change; /*! This signal is similar to Area::key_nav_focus_activate. It is emitted from the WindowCompositor. The user only needs to listen to this signal to find out the area that has has been activated through the keyboard (ENTER key has been pressed).\n */ sigc::signal key_nav_focus_activate; //==================================== public: /*! Set and external fbo to draw Nux BaseWindow into. This external fbo will be restored after Nux completes it rendering. The external fbo is used only in embedded mode. \n If the fbo_object parameter 0, then the reference fbo is invalid and will not be used. @param draw_fbo_object The opengl index of the GL_DRAW_FRAMEBUFFER_EXT. @param read_fbo_object The opengl index of the GL_READ_FRAMEBUFFER_EXT. @param fbo_geometry The geometry of the fbo. */ void SetReferenceFramebuffer(unsigned int draw_fbo_object, unsigned int read_fbo_object, const Geometry &fbo_geometry); /*! Bind the reference opengl framebuffer object. @return True if no error was detected. */ bool RestoreReferenceFramebuffer(); void RestoreMainFramebuffer(); ObjectPtr& GetWindowFrameBufferObject() { return m_FrameBufferObject; } ObjectPtr m_FrameBufferObject; void StartModalWindow(WeakBaseWindowPtr); void StopModalWindow(WeakBaseWindowPtr); #if !defined(NUX_MINIMAL) void AddMenu(MenuPage* menu, BaseWindow* window, bool OverrideCurrentMenuChain = true); void RemoveMenu(MenuPage* menu); void CleanMenu(); #endif void PushModalWindow(WeakBaseWindowPtr window); void SetWidgetDrawingOverlay(InputArea* ic, BaseWindow* OverlayWindow); InputArea* GetWidgetDrawingOverlay(); void SetTooltip(InputArea* TooltipArea, const char* TooltipText, int x, int y); /*! Return true if the mouse is still inside the area that initiated the tooltip; @param x The mouse x coordinate on screen. @param y The mouse y coordinate on screen. @return Return true is the mouse is still inside the area. */ bool ValidateMouseInsideTooltipArea(int x, int y); /*! Return true if there is a valid tooltip active. @return Return true if there is a valid tooltip active. */ bool IsTooltipActive(); void CancelTooltip(); void SetBackgroundPaintLayer(AbstractPaintLayer* bkg); /*! A special BaseWindow that is always on top of all other BaseWindow. It is even above the BaseWindow that is selected. */ void SetAlwaysOnFrontWindow(BaseWindow* window); //! Set the rendering surface for the current rendering. /*! This function is used to restore the rendering surface according to the system state. This is necessary after using a custom frame buffer object. */ void RestoreRenderingSurface(); //! Get the backup texture data of this BaseWindow, void* GetBackupTextureData(BaseWindow* base_window, int& width, int& height, int& format); //! Reset the DND focus area /*! Set the DND focus area to NULL. \sa _dnd_area; */ void ResetDnDArea(); // SetDnDArea is declared as private. //void SetDnDArea(InputArea* area); InputArea* GetDnDArea(); //! Get the top view that is being processed(event or rendering). /*! Get the active ViewWindow during and event processing or rendering. */ BaseWindow* GetProcessingTopView() { return m_CurrentWindow.GetPointer(); } // Pointer Grab API //! Add an area at the top of the pointer grab stack /*! Add an area at the top of the pointer grab stack. The area at the top of the pointer grab stack has the exclusivity on the pointer events. And area can be added multiple times to the stack but not successively. @param area The area to put at the top of the pointer grab stack. @return True if the Area was successfully added at the top of the pointer grab stack. */ bool GrabPointerAdd(InputArea* area); //! Remove an area from the pointer grab stack /*! If the Area was added multiple time to the pointer grab stack then the top most instance of the parameter area is removed. @param area The area to remove from the top of the pointer grab stack. @return True if the Area was successfully removed. */ bool GrabPointerRemove(InputArea* area); //! Returns True if the area parameter is inside the pointer grab stack. bool IsInPointerGrabStack(InputArea* area); //! Returns the area at the top of the pointer grab stack. InputArea* GetPointerGrabArea(); // Keyboard Grab API //! Add an area at the top of the keyboard grab stack /*! Add an area at the top of the keyboard grab stack. The area at the top of the keyboard grab stack has the exclusivity on the keyboard events. And area can be added multiple times to the stack but not successively. @param area The area to put at the top of the keyboard grab stack. @return True if the Area was successfully added at the top of the keyboard grab stack. */ bool GrabKeyboardAdd(InputArea* area); //! Remove an area from the keyboard grab stack /*! If the Area was added multiple time to the keyboard grab stack then the top most instance of the parameter area is removed. @param area The area to remove from the top of the keyboard grab stack. @return True if the Area was successfully removed. */ bool GrabKeyboardRemove(InputArea* area); //! Returns True if the area parameter is inside the keyboard grab stack. bool IsInKeyboardGrabStack(InputArea* area); //! Returns the area at the top of the keyboard grab stack. InputArea* GetKeyboardGrabArea(); // We use Rectangle texture to attach to the frame-buffer because some GPU like the Geforce FX 5600 do not // have support for ARB_texture_non_power_of_two. However it does support ARB_texture_recatangle. struct RenderTargetTextures { ObjectPtr color_rt; ObjectPtr depth_rt; }; //! Return the RenderTargetTextures structure of a BaseWindow. /*! Return the color and depth texture of a BaseWindow. @param window The BaseWindow. @return A structure that contains the color and depth texture of a BaseWindow. */ RenderTargetTextures& GetWindowBuffer(BaseWindow* window); #ifdef NUX_GESTURES_SUPPORT InputArea *LocateGestureTarget(const GestureEvent &event); void SetGestureBroker(std::unique_ptr gesture_broker); #endif private: typedef std::list WindowList; //! Render the interface. void Draw(bool SizeConfigurationEvent, bool force_draw); void DrawPopup(bool force_draw); void DrawMenu(bool force_draw); void DrawOverlay(bool force_draw); void DrawTooltip(bool force_draw); //! Render all top views. /*! @force_draw True if the entire surface of the backup rendering mush flushed. @WindowList The list of top views. @draw_modal True if the top view that is modal is to be rendered. */ void RenderTopViews(bool force_draw, WindowList&, bool draw_modal); void PresentAnyReadyWindows(); //! Render the content of a top view. void RenderTopViewContent(BaseWindow* window, bool force_draw); void RenderMainWindowComposition(bool force_draw); /*! Render a textured quad the quad has the size of the texture. The texture maybe the main window texture or a BaseWindow texture. @param HWTexture Texture to render. @param x Coordinates of the top left corner of the quad. @param y Coordinates of the top left corner of the quad. @param RenderToMainTexture If true, render to the main window texture. If false, render to the default back buffer. @param BluredBackground If true, the texture is blended with the blurred version of the main window texture. */ void PresentBufferToScreen(ObjectPtr HWTexture, int x, int y, bool RenderToMainTexture, bool BluredBackground = false, float opacity=1.0f, bool premultiply = false); //! Push a floating view just above another floating view. /*! Note that only the top_floating_view is moving. The overall position of the reference view is not changing. @param top_floating_view The view to place above bottom_floating_view. @param top_floating_view The reference view that will be below top_floating_view. @param strict If true and top_floating_view is already above bottom_floating_view, then bring top_floating_view lower so that it is strictly above bottom_floating_view. */ void PushHigher(BaseWindow* top_floating_view, BaseWindow* bottom_floating_view, bool strict = false); //! Push a floating view at the top of the stack. void PushToFront(BaseWindow* bottom_floating_view); //! Push a floating view at the bottom of the stack. void PushToBack(BaseWindow* bottom_floating_view); //! Set the top view that is about to be processed(event or rendering). /*! Before event processing or rendering, this should be called to set the ViewWindow that is about to be processed. This function is used internally by the system. */ void SetProcessingTopView(BaseWindow* window) { m_CurrentWindow = window; } private: void EnsureAlwaysOnFrontWindow(); void FormatRenderTargets(int width, int height); //void UpdatePostProcessRT(); /*! Floating Area need to be informed when the main window has been resized. @param Width New width of the window. @param Height New height of the window. */ void FloatingAreaConfigureNotify(int Width, int Height); void RegisterWindow(BaseWindow*); // UnRegister is called via the object destroyed event, hence the Object*. void UnRegisterWindow(Object*); ObjectPtr m_MainColorRT; ObjectPtr m_MainDepthRT; WeakBaseWindowPtr m_CurrentWindow; //!< BaseWindow where event processing or rendering is happening. WeakBaseWindowPtr m_MenuWindow; //!< The BaseWindow that owns the menu being displayed; void SetDnDArea(InputArea* area); // DnD support InputArea* _dnd_area; //!< the area where the mouse is located during a DND action. //! True while events are being processed inside ProcessEvent(). bool inside_event_cycle_; //! True while inside the rendering cycle. bool inside_rendering_cycle_; InputArea* OverlayDrawingCommand; WeakBaseWindowPtr m_OverlayWindow; //!< The window that owns the overlay; WeakBaseWindowPtr _tooltip_window; //!< The window that owns the tooltip; Geometry _tooltip_geometry; //!< The geometry of the entire tooltip It includes the decoration surrounding the text such as round corners. Geometry _tooltip_mainwindow_geometry; //!< Same as _tooltip_geometry but based on the entire physical window of the application. Geometry _tooltip_text_geometry; //!< The geometry of the text area of the tooltip. bool on_menu_closure_continue_with_event_; AbstractPaintLayer* m_Background; WindowList _view_window_list; WindowList _modal_view_window_list; WeakBaseWindowPtr _always_on_front_window; //!< Floating view that always remains on top. #if !defined(NUX_MINIMAL) std::list* _menu_chain; #endif std::map _window_to_texture_map; bool m_MenuRemoved; // Window Geometry int m_Width; int m_Height; std::string m_TooltipText; InputArea* m_TooltipArea; int m_TooltipX; int m_TooltipY; //! The fbo to restore after Nux rendering in embedded mode. unsigned int draw_reference_fbo_; unsigned int read_reference_fbo_; Geometry reference_fbo_geometry_; //! True if the platform has support for depth textures. bool platform_support_for_depth_texture_; //! Pointer grab stack. /*! The head of the list is the top of the stack. \sa GrabPointerAdd, GrabPointerRemove. */ std::list pointer_grab_stack_; //! Keyboard grab stack. /*! The head of the list is the top of the stack. \sa GrabKeyboardAdd, GrabKeyboardRemove. */ std::list keyboard_grab_stack_; //! List of views that will get checked for the mouse_near signal /*! A list of views that will be checked if \near the mouse. Must add views to this \list to be checked. */ std::list area_proximities_; private: WindowThread* window_thread_; //!< The WindowThread to which this object belongs. #ifdef NUX_GESTURES_SUPPORT std::unique_ptr gesture_broker_; #endif WindowList* currently_rendering_windows_; Geometry* current_global_clip_rect_; //! Perform some action before destruction. /*! Perform some action before destruction. This function should only be called from WindowThread::ThreadDtor(). It will invalidate the area that currently has the keyboard focus. */ void BeforeDestructor(); WindowCompositor(const WindowCompositor&); // Does not make sense for a singleton. This is a self assignment. WindowCompositor& operator= (const WindowCompositor&); // Declare operator address-of as private WindowCompositor* operator & (); friend class InputArea; friend class WindowThread; friend class TimerHandler; friend class MenuBar; friend class MenuPage; friend class BaseWindow; friend class HSplitter; friend class VSplitter; friend class TableCtrl; friend class View; friend class TestWindowCompositor; }; #ifdef NUX_GESTURES_SUPPORT class DefaultGestureBroker : public GestureBroker { public: DefaultGestureBroker(WindowCompositor *window_compositor); private: std::vector virtual FindGestureTargets(const nux::GestureEvent &event); WindowCompositor *window_compositor_; }; #endif } #endif // WINDOWCOMPOSITOR_H nux-4.0.8+18.10.20180623/Nux/WindowThread.cpp0000644000000000000000000014100713313373365014461 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include #include "Nux.h" #include "Layout.h" #include "NuxCore/Logger.h" #include "NuxGraphics/GraphicsEngine.h" #include "ClientArea.h" #include "WindowCompositor.h" #include "TimerProc.h" #include "SystemThread.h" #include "FloatingWindow.h" #include "WindowThread.h" #include "MainLoopGLib.h" namespace nux { DECLARE_LOGGER(logger, "nux.windows.thread"); TimerFunctor *m_ScrollTimerFunctor; TimerHandle m_ScrollTimerHandler; // Thread registration call. Hidden from the users. Implemented in Nux.cpp bool RegisterNuxThread(NThread *ThreadPtr); void UnregisterNuxThread(NThread *ThreadPtr); const int WindowThread::MINIMUM_WINDOW_WIDTH = 1; const int WindowThread::MINIMUM_WINDOW_HEIGHT = 1; NUX_IMPLEMENT_OBJECT_TYPE(WindowThread); WindowThread::WindowThread(const char *WindowTitle, int width, int height, AbstractThread *Parent, bool Modal) : AbstractThread(Parent) , foreign_frame_frozen_(false) , window_initial_width_(width) , window_initial_height_(height) , window_title_(WindowTitle) , m_WidgetInitialized(false) , window_style_(WINDOWSTYLE_NORMAL) , embedded_window_(false) , window_size_configuration_event_(false) , force_rendering_(false) , external_glib_sources_(new ExternalGLibSources) #ifdef NUX_GESTURES_SUPPORT , geis_adapter_(new GeisAdapter) #endif { // Thread specific objects graphics_display_ = NULL; window_compositor_ = NULL; painter_ = NULL; timer_manager_ = NULL; theme_ = NULL; main_layout_ = NULL; queue_main_layout_ = false; // Protection for ThreadCtor and ThreadDtor; thread_ctor_called_ = false; thread_dtor_called_ = false; // wait_for_modal_window_ = false; modal_window_thread_ = 0; is_modal_window_ = Modal; _inside_layout_cycle = 0; _draw_requested_to_host_wm = false; first_pass_ = true; #if !defined(NUX_MINIMAL) _Timelines = new std::list (); gint64 micro_secs = g_get_real_time(); last_timeline_frame_time_sec_ = micro_secs / 1000000; last_timeline_frame_time_usec_ = micro_secs % 1000000; #endif _MasterClock = NULL; main_loop_glib_ = 0; main_loop_glib_context_ = 0; #if defined(USE_X11) x11display_ = NULL; ownx11display_ = false; #endif _pending_wake_up_timer = false; _inside_main_loop = false; _inside_timer_loop = false; async_wake_up_signal_ = new TimerFunctor(); async_wake_up_signal_->tick.connect(sigc::mem_fun(this, &WindowThread::AsyncWakeUpCallback)); } WindowThread::~WindowThread() { xim_controller_.reset(); CleanupGlibLoop(); ThreadDtor(); #if !defined(NUX_MINIMAL) std::list::iterator li; for (li=_Timelines->begin(); li!=_Timelines->end(); ++li) { (*li)->UnReference(); } delete _Timelines; #endif delete async_wake_up_signal_; #if defined(USE_X11) if (x11display_ && ownx11display_) { XCloseDisplay(x11display_); } #endif } void WindowThread::ExitMainLoop() { StopGLibLoop(); } unsigned int WindowThread::AddTimeout(unsigned int timeout_delay) { return AddGLibTimeout(timeout_delay); } TimerHandle WindowThread::SetAsyncTimerCallback(int time_ms, TimeOutSignal* timeout_signal, void *user_data) { if (timeout_signal == NULL) return TimerHandle(); // Use "this->" because if called from a different thread, GetTimer and GetWindowThread are invalid. TimerHandle handle = this->GetTimerHandler().AddOneShotTimer(time_ms, timeout_signal, user_data, this); return handle; } void WindowThread::AsyncWakeUpCallback(void* /* data */) { this->GetTimerHandler().RemoveTimerHandler(async_wake_up_timer_handle_); _pending_wake_up_timer = false; } void WindowThread::ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw) { if (main_layout_) { bool dirty = main_layout_->IsQueuedForDraw(); if (dirty) { // A main layout re computation has happen. It was not initiated physically by resizing the window. We need to draw the background to // clean any dirty region. int buffer_width = graphics_engine.GetWindowWidth(); int buffer_height = graphics_engine.GetWindowHeight(); GetPainter().PaintBackground(graphics_engine, Geometry(0, 0, buffer_width, buffer_height)); } main_layout_->ProcessDraw(graphics_engine, force_draw || dirty); } } void WindowThread::RequestRedraw() { _draw_requested_to_host_wm = true; RedrawRequested.emit(); if (!IsEmbeddedWindow()) { // If the system is not in embedded mode and an asynchronous request for a Draw is made, // and the system is not in a timer processing cycle(always followed by a draw cycle) // or not in the event processing cycle(also followed by a draw cycle), then we set a 0 delay // timer that will wake up the system and initiate a draw cycle. if ((_inside_main_loop == false) && (_inside_timer_loop == false) && (_pending_wake_up_timer == false)) { _pending_wake_up_timer = true; async_wake_up_timer_handle_ = this->GetTimerHandler().AddOneShotTimer(0, async_wake_up_signal_, this); } } } void WindowThread::ClearRedrawFlag() { _draw_requested_to_host_wm = false; } bool WindowThread::IsRedrawNeeded() const { return _draw_requested_to_host_wm; } void WindowThread::SetLayout(Layout *layout) { main_layout_ = layout; if (main_layout_) { int w = graphics_display_->GetGraphicsEngine()->GetContextWidth(); int h = graphics_display_->GetGraphicsEngine()->GetContextHeight(); main_layout_->Reference(); main_layout_->SetScaleFactor(1); StartLayoutCycle(); main_layout_->SetGeometry(0, 0, w, h); main_layout_->ComputeContentSize(); main_layout_->ComputeContentPosition(0, 0); StopLayoutCycle(); RemoveQueuedLayout(); } } Layout* WindowThread::GetLayout() { return main_layout_; } void WindowThread::QueueLayout() { queue_main_layout_ = true; RequestRedraw(); } void WindowThread::ReconfigureLayout() { int w = graphics_display_->GetGraphicsEngine()->GetWindowWidth(); int h = graphics_display_->GetGraphicsEngine()->GetWindowHeight(); if (main_layout_) { StartLayoutCycle(); main_layout_->SetGeometry(0, 0, w, h); main_layout_->ComputeContentSize(); main_layout_->ComputeContentPosition(0, 0); StopLayoutCycle(); } RemoveQueuedLayout(); queue_main_layout_ = false; } bool WindowThread::QueueObjectLayout(Area *area) { NUX_RETURN_VALUE_IF_NULL(area, false); std::list::iterator it; it = find(_queued_layout_list.begin(), _queued_layout_list.end(), area); if (it == _queued_layout_list.end()) { _queued_layout_list.push_back(area); } return true; } bool WindowThread::RemoveObjectFromLayoutQueue(Area *area) { NUX_RETURN_VALUE_IF_NULL(area, false); std::list::iterator it; it = find(_queued_layout_list.begin(), _queued_layout_list.end(), area); if (it != _queued_layout_list.end()) { _queued_layout_list.erase(it); return true; } return false; } void WindowThread::RemoveQueuedLayout() { _queued_layout_list.clear(); } void WindowThread::ComputeQueuedLayout() { StartLayoutCycle(); std::list::iterator it; for (it = _queued_layout_list.begin(); it != _queued_layout_list.end(); ++it) { Area *area = *it; if (area->Type().IsDerivedFromType(View::StaticObjectType)) { View *view = NUX_STATIC_CAST(View *, area); if (!view->CanBreakLayout()) view->QueueDraw(); } else if (area->Type().IsDerivedFromType(Layout::StaticObjectType)) { Layout *layout = NUX_STATIC_CAST(Layout *, area); layout->QueueDraw(); } else { continue; } (*it)->ComputeContentSize(); } StopLayoutCycle(); RemoveQueuedLayout(); } void WindowThread::StartLayoutCycle() { _inside_layout_cycle = true; } void WindowThread::StopLayoutCycle() { _inside_layout_cycle = false; } bool WindowThread::IsInsideLayoutCycle() const { return _inside_layout_cycle; } void WindowThread::ComputeElementLayout(Area *area, bool recurse_to_top_level_layout) { NUX_RETURN_IF_NULL(area); bool alreadyComputingLayout = IsInsideLayoutCycle(); if ((!alreadyComputingLayout) && (!recurse_to_top_level_layout)) { // When computing the layout, setting the size of widgets may cause the system to recurse // upward an look for the up most container which size is affected by its this area. // This happens in Area::InitiateResizeLayout(); // The search upward is not done if we are already in a layout cycle. StartLayoutCycle(); } if (area->Type().IsDerivedFromType(View::StaticObjectType)) { View *ic = NUX_STATIC_CAST(View *, area); ic->QueueDraw(); } else if (area->Type().IsDerivedFromType(Layout::StaticObjectType)) { Layout *layout = NUX_STATIC_CAST(Layout *, area); layout->QueueDraw(); } area->ComputeContentSize(); if (!alreadyComputingLayout) StopLayoutCycle(); } #if !defined(NUX_MINIMAL) void WindowThread::AddTimeline(Timeline *timeline) { _Timelines->push_back(timeline); _Timelines->unique(); StartMasterClock(); } void WindowThread::RemoveTimeline(Timeline *timeline) { _Timelines->remove(timeline); if (_Timelines->empty()) { StopMasterClock(); } } #endif int WindowThread::Run(void * /* ptr */) { if (GetWindowThread() != this) { nuxDebugMsg("Cannot run a several WindowThreads in the same window."); return 1; } if (!IsEmbeddedWindow() && (thread_ctor_called_ == false)) { nuxDebugMsg("Call WindowThread::Start to run this window in its own thread."); return 1; } // Setup the main loop first, so that user_init_func can add new sources // before running it SetupMainLoop(); if (user_init_func_ && (m_WidgetInitialized == false)) { (*user_init_func_) (this, initialization_data_); m_WidgetInitialized = true; } return MainLoop(); } void WindowThread::SetupMainLoop() { if (IsEmbeddedWindow()) { window_compositor_->FormatRenderTargets(graphics_display_->GetWindowWidth(), graphics_display_->GetWindowHeight()); InitGlibLoop(); } else { InitGlibLoop(); } // Called the first time so we can initialize the size of the render targets // At this stage, the size of the window is known. window_compositor_->FormatRenderTargets(graphics_display_->GetWindowWidth(), graphics_display_->GetWindowHeight()); } int WindowThread::MainLoop() { if (IsEmbeddedWindow()) { RunGlibLoop(); return 0; } else { graphics_display_->ShowWindow(); } while (GetThreadState() != THREADSTOP) { if (GetThreadState() == THREADRUNNING) { RunGlibLoop(); if (parent_) { if (parent_->Type().IsObjectType(SystemThread::StaticObjectType)) static_cast (parent_)->ChildHasFinished(this); if (parent_->Type().IsObjectType(WindowThread::StaticObjectType)) static_cast (parent_)->ChildHasFinished(this); { SetThreadState(THREADSTOP); // All children window must be terminated. TerminateChildWindows(); JoinChildThreads(); std::list::iterator it; for (it = children_thread_list_.begin(); it != children_thread_list_.end(); ++it) { delete (*it); } children_thread_list_.clear(); } } else { SetThreadState(THREADSTOP); // All child window must be terminated. TerminateChildWindows(); JoinChildThreads(); std::list::iterator it; for (it = children_thread_list_.begin(); it != children_thread_list_.end(); ++it) { delete (*it); } children_thread_list_.clear(); } } else { // Do not sleep. Just return and let the GraphicsDisplay::SwapBuffer do the sleep if necessary. } } return 0; } extern EventToNameStruct EventToName[]; Event WindowThread::GetNextEvent() { Event event; graphics_display_->GetSystemEvent(&event); #if defined(NUX_OS_LINUX) && defined(USE_X11) // Make sure the current xic is synced up with the current event window if ((event.type == KeyPress || event.type == KeyRelease) && event.x11_window && xim_controller_->GetCurrentWindow() != event.x11_window) { xim_controller_->SetFocusedWindow(event.x11_window); graphics_display_->SetCurrentXIC(xim_controller_->GetXIC()); } #endif return event; } unsigned int WindowThread::ProcessEvent(Event &event) { if (!IsEmbeddedWindow() && graphics_display_->IsPauseThreadGraphicsRendering()) { // Do not sleep. Just return and let the GraphicsDisplay::SwapBuffer do the sleep if necessary. return 0; } return DoProcessEvent(event); } unsigned int WindowThread::DoProcessEvent(Event &event) { _inside_main_loop = true; if (first_pass_) { // Reset the timers that were called before the mainloop got initialized. GetTimer().StartEarlyTimerObjects(); } if ((event.type == NUX_DND_ENTER_WINDOW) || (event.type == NUX_DND_LEAVE_WINDOW)) { GetWindowCompositor().ResetDnDArea(); } // Call event inspectors. bool event_discarded = CallEventInspectors(&event); if (event_discarded) { return 1; } if ((event.type == NUX_TERMINATE_APP) || (this->GetThreadState() == THREADSTOP)) { return 0; } if (event.type == NUX_SIZE_CONFIGURATION) { window_size_configuration_event_ = true; Rect r = graphics_display_->GetWindowGeometry(); window_configuration.emit(r.x, r.y, r.width, r.height); } int w, h; // Call gGfx_OpenGL.getWindowSize after the gGfx_OpenGL.get_event. // Otherwise, w and h may not be correct for the current frame if a resizing happened. graphics_display_->GetWindowSize(w, h); if ((event.type == NUX_MOUSE_PRESSED) || (event.type == NUX_MOUSE_RELEASED) || (event.type == NUX_MOUSE_DOUBLECLICK) || (event.type == NUX_MOUSE_MOVE) || (event.type == NUX_SIZE_CONFIGURATION) || (event.type == NUX_KEYDOWN) || (event.type == NUX_KEYUP) || (event.type == NUX_NC_WINDOW_CONFIGURATION) || (event.type == NUX_WINDOW_ENTER_FOCUS) || (event.type == NUX_WINDOW_EXIT_FOCUS) || (event.type == NUX_WINDOW_MOUSELEAVE) || (event.type == NUX_DND_MOVE) || (event.type == NUX_DND_DROP) || (event.type == NUX_DND_ENTER) || (event.type == NUX_DND_LEAVE) || (event.type == NUX_MOUSE_WHEEL) || event.type == EVENT_GESTURE_BEGIN || event.type == EVENT_GESTURE_UPDATE || event.type == EVENT_GESTURE_END) { //DISPATCH EVENT HERE //event.Application = Application; window_compositor_->ProcessEvent(event); } if (event.type == NUX_SIZE_CONFIGURATION) { if (!graphics_display_->isWindowMinimized()) { graphics_display_->SetViewPort(0, 0, event.width, event.height); ReconfigureLayout(); window_compositor_->FormatRenderTargets(event.width, event.height); } window_compositor_->FloatingAreaConfigureNotify(event.width, event.height); window_size_configuration_event_ = true; } // Some action may have caused layouts and areas to request a recompute. // Process them here before the Draw section. if (!graphics_display_->isWindowMinimized() && !IsEmbeddedWindow()) { if (queue_main_layout_) { ReconfigureLayout(); } else { // Compute the layouts that have been queued. ComputeQueuedLayout(); } } _inside_main_loop = false; if (!graphics_display_->IsPauseThreadGraphicsRendering() || IsEmbeddedWindow()) { bool SwapGLBuffer = false; // Warn the host window manager to initiate a draw cycle. bool request_draw_cycle_to_host_wm = false; if (first_pass_) { if (IsEmbeddedWindow()) { request_draw_cycle_to_host_wm = true; force_rendering_ = true; } else { window_compositor_->Draw(window_size_configuration_event_, true); } first_pass_ = false; } else { bool b = (event.type == NUX_MOUSE_PRESSED) || (event.type == NUX_MOUSE_RELEASED) || (event.type == NUX_MOUSE_DOUBLECLICK) || //(event.type == NUX_MOUSE_MOVE) || (event.type == NUX_SIZE_CONFIGURATION) || (event.type == NUX_KEYDOWN) || (event.type == NUX_KEYUP) || (event.type == NUX_NC_WINDOW_CONFIGURATION) || (event.type == NUX_WINDOW_ENTER_FOCUS) || (event.type == NUX_WINDOW_EXIT_FOCUS) || (event.type == NUX_WINDOW_DIRTY); if (b && window_compositor_->IsTooltipActive()) { // Cancel the tooltip since an event that should cause the tooltip to disappear has occurred. window_compositor_->CancelTooltip(); b |= true; } if (!window_compositor_->ValidateMouseInsideTooltipArea(event.x, event.y) && window_compositor_->IsTooltipActive()) { // Cancel the tooltip since an event that should cause the tooltip to disappear has occurred. window_compositor_->CancelTooltip(); b |= true; } if (b || IsRedrawNeeded()) { if (IsEmbeddedWindow()) { request_draw_cycle_to_host_wm = true; } else { window_compositor_->Draw(window_size_configuration_event_, false); } SwapGLBuffer = true; } else if (window_compositor_->GetWidgetDrawingOverlay() != 0) { if (IsEmbeddedWindow()) { request_draw_cycle_to_host_wm = true; } else { window_compositor_->Draw(window_size_configuration_event_, false); } SwapGLBuffer = false; } } if (!IsEmbeddedWindow()) { if (SwapGLBuffer) { // Something was rendered! Swap the rendering buffer! graphics_display_->SwapBuffer(true); } ClearRedrawFlag(); GetWindowThread()->GetGraphicsEngine().ResetStats(); } else if (IsEmbeddedWindow() && (_draw_requested_to_host_wm == false) && request_draw_cycle_to_host_wm) { RequestRedraw(); } window_size_configuration_event_ = false; } return 1; } unsigned int SpawnThread(NThread & /* thread */) { return 0; } bool WindowThread::IsWaitingforModalWindow() const { return wait_for_modal_window_; } bool WindowThread::IsModalWindow() const { return is_modal_window_; } void WindowThread::AddChildThread(AbstractThread *window) { if (window == NULL) return; std::list::iterator it; it = find(children_thread_list_.begin(), children_thread_list_.end(), window); if (it == children_thread_list_.end()) { children_thread_list_.push_back(window); } } void WindowThread::RemoveChildThread(AbstractThread *window) { nuxAssert(window); std::list::iterator it; it = find(children_thread_list_.begin(), children_thread_list_.end(), window); if (it != children_thread_list_.end()) { children_thread_list_.erase(it); } } void WindowThread::ChildHasFinished(AbstractThread *thread) { RemoveChildThread(thread); if (thread->Type().IsObjectType(WindowThread::StaticObjectType)) { SuspendChildGraphics(static_cast (thread)); } thread->SetThreadState(THREADSTOP); } void WindowThread::TerminateChildThreads() { std::list::iterator it; for (it = children_thread_list_.begin(); it != children_thread_list_.end(); ++it) { (*it)->SetThreadState(THREADSTOP); if ((*it)->Type().IsObjectType(WindowThread::StaticObjectType)) { // Terminate by shutting down the main loop static_cast(*it)->ExitMainLoop(); } if ((*it)->Type().IsObjectType(SystemThread::StaticObjectType)) { // Just kill the thread static_cast(*it)->Stop(true); } } } ThreadState WindowThread::Start(void * /* ptr */) { if (!parent_) { return NThread::Start(); } else { if (parent_->Type().IsObjectType(SystemThread::StaticObjectType)) { return static_cast (parent_)->StartChildThread(this, true); } else if (parent_->Type().IsObjectType(WindowThread::StaticObjectType)) { return static_cast (parent_)->StartChildThread(this, true); } nuxAssertMsg(0, "[WindowThread::Start] This should not happen."); return THREAD_START_ERROR; } } ThreadState WindowThread::StartChildThread(AbstractThread *thread, bool /* Modal */) { if (wait_for_modal_window_) { // This window is already waiting for a modal window. It cannot start another windows. return thread->GetThreadState(); } ThreadState state = thread->NThread::Start(); //if(state == THREADRUNNING) { if (thread->Type().IsObjectType(WindowThread::StaticObjectType)) { // While the child window is being created, the rendering is paused. // This is necessary to active OpenGL objects context sharing. // Cancel the pause by sending the message NUX_THREADMSG_START_RENDERING to this thread. //graphics_display_->PauseThreadGraphicsRendering(); if (static_cast (thread)->is_modal_window_) { DisableMouseKeyboardInput(); modal_window_thread_ = static_cast (thread); // std::list::iterator it; // for (it = children_thread_list_.begin(); it != children_thread_list_.end(); it++) // { // static_cast(*it)->wait_for_modal_window_ = true; // // WIN32: Disable Mouse and Keyboard inputs for all windows child of this window // ::EnableWindow(static_cast(*it)->graphics_display_->GetWindowHandle(), FALSE); // } // // WIN32 // ::EnableWindow(graphics_display_->GetWindowHandle(), FALSE); // wait_for_modal_window_ = true; } static_cast (thread)->wait_for_modal_window_ = false; AddChildThread(thread); } } return state; } ThreadState WindowThread::SuspendChildGraphics(WindowThread *thread) { if (wait_for_modal_window_) { if (modal_window_thread_ != thread) { nuxAssertMsg(0, "[WindowThread::SuspendChildGraphics] cannot supend thread that is not the modal window."); return thread->GetThreadState(); } } ThreadState state = thread->GetThreadState(); if (wait_for_modal_window_) { modal_window_thread_ = 0; EnableMouseKeyboardInput(); // std::list::iterator it; // for (it = children_thread_list_.begin(); it != children_thread_list_.end(); it++) // { // static_cast(*it)->wait_for_modal_window_ = false; // // // WIN32 // ::EnableWindow(static_cast(*it)->graphics_display_->GetWindowHandle(), TRUE); // } } // WIN32 #if defined(NUX_OS_WINDOWS) ::EnableWindow(graphics_display_->GetWindowHandle(), TRUE); #elif defined(NUX_OS_LINUX) #endif return state; } #if !defined(NUX_MINIMAL) bool WindowThread::ProcessTimelines(gint64 micro_secs) { // go through our timelines and tick them // return true if we still have active timelines long msecs; msecs = (micro_secs / 1000000 - last_timeline_frame_time_sec_) * 1000 + (micro_secs % 1000000 - last_timeline_frame_time_usec_) / 1000; if (msecs < 0) { last_timeline_frame_time_sec_ = micro_secs / 1000000; last_timeline_frame_time_usec_ = micro_secs % 1000000; return true; } if (msecs > 0) { last_timeline_frame_time_sec_ += msecs / 1000; last_timeline_frame_time_usec_ += msecs * 1000; } std::list::iterator li; std::list timelines_copy; for (li=_Timelines->begin(); li!=_Timelines->end(); ++li) { (*li)->Reference(); timelines_copy.push_back((*li)); } for(li=timelines_copy.begin(); li!=timelines_copy.end(); ++li) { (*li)->DoTick(msecs); } // unreference again for (li=timelines_copy.begin(); li!=timelines_copy.end(); ++li) (*li)->UnReference(); // return if we have any timelines left return (_Timelines->size() != 0); } #endif void WindowThread::EnableMouseKeyboardInput() { std::list::iterator it; for (it = children_thread_list_.begin(); it != children_thread_list_.end(); ++it) { if (NUX_STATIC_CAST(WindowThread *, *it)->Type().IsObjectType(WindowThread::StaticObjectType)) { NUX_STATIC_CAST(WindowThread *, *it)->EnableMouseKeyboardInput(); } } // WIN32: Enable Mouse and Keyboard inputs for all windows child of this window #if defined(NUX_OS_WINDOWS) ::EnableWindow(graphics_display_->GetWindowHandle(), TRUE); #elif defined(NUX_OS_LINUX) #endif wait_for_modal_window_ = false; } void WindowThread::DisableMouseKeyboardInput() { std::list::iterator it; for (it = children_thread_list_.begin(); it != children_thread_list_.end(); ++it) { if (NUX_STATIC_CAST(WindowThread *, *it)->Type().IsObjectType(WindowThread::StaticObjectType)) { NUX_STATIC_CAST(WindowThread *, *it)->DisableMouseKeyboardInput(); } } // WIN32: Disable Mouse and Keyboard inputs for all windows child of this window #if defined(NUX_OS_WINDOWS) ::EnableWindow(graphics_display_->GetWindowHandle(), FALSE); #elif defined(NUX_OS_LINUX) #endif wait_for_modal_window_ = true; } bool WindowThread::ThreadCtor() { if(thread_ctor_called_) { nuxDebugMsg("[WindowThread::ThreadCtor] ThreadCtor should not be entered more than once per WindowThread."); return true; } #if defined(NUX_OS_WINDOWS) SetWin32ThreadName(GetThreadId(), window_title_.c_str()); #endif if (RegisterNuxThread(this) == FALSE) { nuxDebugMsg("[WindowThread::ThreadCtor] Failed to register the WindowThread."); return false; } inlSetThreadLocalStorage(ThreadLocal_InalogicAppImpl, this); GraphicsDisplay *parent_window = NULL; if (parent_ && static_cast (parent_)->Type().IsObjectType(WindowThread::StaticObjectType)) { parent_window = &static_cast (parent_)->GetGraphicsDisplay(); } else { parent_window = NULL; } graphics_display_ = gGLWindowManager.CreateGLWindow(window_title_.c_str(), window_initial_width_, window_initial_height_, window_style_, parent_window, false); if (graphics_display_ == NULL) { nuxDebugMsg("[WindowThread::ThreadCtor] Failed to create the window."); return false; } if (parent_ && parent_->Type().IsObjectType(WindowThread::StaticObjectType)) { // Cancel the effect of PauseThreadGraphicsRendering on the parent window. //PostThreadMessage(parent_->GetThreadId(), NUX_THREADMSG_START_RENDERING, (UINT_PTR)((void*)this), 0); } painter_ = new BasePainter(this); timer_manager_ = new TimerHandler(this); window_compositor_ = new WindowCompositor(this); xim_controller_ = std::make_shared(graphics_display_->GetX11Display()); SetThreadState(THREADRUNNING); thread_ctor_called_ = true; return true; } #if defined(NUX_OS_WINDOWS) bool WindowThread::ThreadCtor(HWND WindowHandle, HDC WindowDCHandle, HGLRC OpenGLRenderingContext) { nuxAssertMsg(thread_ctor_called_ == false, "[WindowThread::ThreadCtor] ThreadCtor should not be entered more than once per WindowThread."); if(thread_ctor_called_) { return true; } SetWin32ThreadName(GetThreadId(), window_title_.c_str()); if (RegisterNuxThread(this) == FALSE) { nuxDebugMsg("[WindowThread::ThreadCtor] Failed to register the WindowThread."); return false; } inlSetThreadLocalStorage(ThreadLocal_InalogicAppImpl, this); GraphicsDisplay *ParentWindow = 0; if (parent_ && static_cast (parent_)->Type().IsObjectType(WindowThread::StaticObjectType)) { ParentWindow = &static_cast (parent_)->GetGraphicsDisplay(); } else { ParentWindow = 0; } graphics_display_ = gGLWindowManager.CreateFromForeignWindow(WindowHandle, WindowDCHandle, OpenGLRenderingContext); if (graphics_display_ == 0) { nuxDebugMsg("[WindowThread::ThreadCtor] Failed to create the window."); return false; } if (parent_ && parent_->Type().IsObjectType(WindowThread::StaticObjectType)) { // Cancel the effect of PauseThreadGraphicsRendering on the parent window. //PostThreadMessage(parent_->GetThreadId(), NUX_THREADMSG_START_RENDERING, (UINT_PTR)((void*)this), 0); } painter_ = new BasePainter(this); timer_manager_ = new TimerHandler(this); window_compositor_ = new WindowCompositor(this); SetThreadState(THREADRUNNING); thread_ctor_called_ = true; // Set initial states int w = graphics_display_->GetWindowWidth(); int h = graphics_display_->GetWindowHeight(); graphics_display_->SetViewPort(0, 0, w, h); window_compositor_->FormatRenderTargets(w, h); window_compositor_->FloatingAreaConfigureNotify(w, h); return true; } #elif defined(NO_X11) #elif defined(NUX_OS_LINUX) #ifdef NUX_OPENGLES_20 bool WindowThread::ThreadCtor(Display *X11Display, Window X11Window, EGLContext OpenGLContext) #else bool WindowThread::ThreadCtor(Display *X11Display, Window X11Window, GLXContext OpenGLContext) #endif { nuxAssertMsg(thread_ctor_called_ == false, "[WindowThread::ThreadCtor] ThreadCtor should not be entered more than once per WindowThread."); if(thread_ctor_called_) { return true; } if (RegisterNuxThread(this) == FALSE) { nuxDebugMsg("[WindowThread::ThreadCtor] Failed to register the WindowThread."); return false; } inlSetThreadLocalStorage(ThreadLocal_InalogicAppImpl, this); if (X11Display) { x11display_ = X11Display; ownx11display_ = false; } else { x11display_ = XOpenDisplay(NULL); ownx11display_ = true; } graphics_display_ = gGLWindowManager.CreateFromForeignWindow(x11display_, X11Window, OpenGLContext); if (graphics_display_ == 0) { nuxDebugMsg("[WindowThread::ThreadCtor] Failed to create the window."); return false; } if (parent_ && parent_->Type().IsObjectType(WindowThread::StaticObjectType)) { // Cancel the effect of PauseThreadGraphicsRendering on the parent window. //PostThreadMessage(parent_->GetThreadId(), NUX_THREADMSG_START_RENDERING, (UINT_PTR)((void*)this), 0); } painter_ = new BasePainter(this); timer_manager_ = new TimerHandler(this); window_compositor_ = new WindowCompositor(this); xim_controller_ = std::make_shared(graphics_display_->GetX11Display()); SetThreadState(THREADRUNNING); thread_ctor_called_ = true; // Set initial states int w = graphics_display_->GetWindowWidth(); int h = graphics_display_->GetWindowHeight(); graphics_display_->SetViewPort(0, 0, w, h); window_compositor_->FormatRenderTargets(w, h); window_compositor_->FloatingAreaConfigureNotify(w, h); return true; } #endif bool WindowThread::ThreadDtor() { if(thread_dtor_called_) { return true; } // Cleanup RemoveQueuedLayout(); window_compositor_->BeforeDestructor(); if (main_layout_) { main_layout_->UnReference(); } NUX_SAFE_DELETE(window_compositor_); NUX_SAFE_DELETE(timer_manager_); NUX_SAFE_DELETE(painter_); NUX_SAFE_DELETE(theme_); NUX_SAFE_DELETE(graphics_display_); #if defined(NUX_OS_WINDOWS) PostThreadMessage(NUX_GLOBAL_OBJECT_INSTANCE(NProcess).GetMainThreadID(), NUX_THREADMSG_THREAD_TERMINATED, NUX_GLOBAL_OBJECT_INSTANCE(NProcess).GetCurrentThreadID(), 0); #elif defined(NUX_OS_LINUX) #else #error PostThreadMessage not implemented for this platform. #endif inlSetThreadLocalStorage(ThreadLocal_InalogicAppImpl, 0); UnregisterNuxThread(this); thread_dtor_called_ = true; return true; } void WindowThread::SetWindowSize(int width, int height) { if (graphics_display_) { if (IsEmbeddedWindow()) { // This is a passive way to set the window size through out the NuxGraphics system. This call gets the // current window size and sets its accordingly to all sub-system. graphics_display_->ResetWindowSize(); } else { graphics_display_->SetWindowSize(width, height); ReconfigureLayout(); } } } void WindowThread::SetWindowBackgroundPaintLayer(AbstractPaintLayer *background_layer) { if (background_layer == NULL) return; if (window_compositor_) { window_compositor_->SetBackgroundPaintLayer(background_layer); if (main_layout_) { main_layout_->QueueDraw(); } } } void WindowThread::AddToDrawList(View *view) { Area *parent; Geometry const& geo = view->GetAbsoluteGeometry(); parent = view->GetToplevel(); if (parent && (view != parent)) { // pgeo = parent->GetGeometry(); // geo.x += pgeo.x; // geo.y += pgeo.y; if (parent->Type().IsDerivedFromType(BaseWindow::StaticObjectType)) { BaseWindow* window = NUX_STATIC_CAST(BaseWindow*, parent); window->_child_need_redraw = true; } } if (view->Type().IsDerivedFromType(BaseWindow::StaticObjectType)) { // If the view is a BaseWindow, allow it to mark itself for redraw, as if it was its own child. BaseWindow* window = NUX_STATIC_CAST(BaseWindow*, view); window->_child_need_redraw = true; } dirty_areas_.push_back(geo); } void WindowThread::ClearDrawList() { dirty_areas_.clear(); } std::vector const& WindowThread::GetDrawList() const { return dirty_areas_; } bool WindowThread::AddToPresentationList(BaseWindow* bw, bool force) { if (!bw) return false; RequestRedraw(); bool force_or_not_frozen = (force || !foreign_frame_frozen_); std::vector& target_list = force_or_not_frozen ? presentation_list_embedded_ : presentation_list_embedded_next_frame_; if (std::find(target_list.begin(), target_list.end(), bw) != target_list.end()) return force_or_not_frozen; target_list.push_back(WeakBaseWindowPtr(bw)); return force_or_not_frozen; } std::vector WindowThread::GetPresentationListGeometries() const { std::vector presentation_geometries; for (auto const& base_window : presentation_list_embedded_) { if (base_window.IsValid()) { nux::Geometry const& abs_geom = base_window->GetAbsoluteGeometry(); nux::Geometry const& last_geom = base_window->LastPresentedGeometryInEmbeddedMode(); presentation_geometries.push_back(abs_geom); if (abs_geom != last_geom) { if (!last_geom.IsNull()) presentation_geometries.push_back(last_geom); } } } return presentation_geometries; } bool WindowThread::IsEmbeddedWindow() const { return embedded_window_; } #if defined(NUX_OS_WINDOWS) bool WindowThread::ProcessForeignEvent(HWND hWnd, MSG msg, WPARAM wParam, LPARAM lParam, void *data) #elif defined(USE_X11) bool WindowThread::ProcessForeignEvent(XEvent *xevent, void * /* data */) #else bool WindowThread::ProcessForeignEvent() #endif { if (graphics_display_->IsPauseThreadGraphicsRendering()) { return false; } Event nux_event; memset(&nux_event, 0, sizeof(Event)); #if defined(NUX_OS_WINDOWS) graphics_display_->ProcessForeignWin32Event(hWnd, msg, wParam, lParam, &nux_event); #elif defined(USE_X11) graphics_display_->ProcessForeignX11Event(xevent, &nux_event); #endif if (nux_event.type == NUX_TERMINATE_APP || (this->GetThreadState() == THREADSTOP)) { return false; } if (nux_event.type == NUX_SIZE_CONFIGURATION) { window_size_configuration_event_ = true; } int w, h; // Call gGfx_OpenGL.getWindowSize after the gGfx_OpenGL.get_event. // Otherwise, w and h may not be correct for the current frame if a resizing happened. graphics_display_->GetWindowSize(w, h); if (nux_event.type == NUX_MOUSE_PRESSED || (nux_event.type == NUX_MOUSE_RELEASED) || (nux_event.type == NUX_MOUSE_DOUBLECLICK) || (nux_event.type == NUX_MOUSE_MOVE) || (nux_event.type == NUX_SIZE_CONFIGURATION) || (nux_event.type == NUX_KEYDOWN) || (nux_event.type == NUX_KEYUP) || (nux_event.type == NUX_NC_WINDOW_CONFIGURATION) || (nux_event.type == NUX_WINDOW_ENTER_FOCUS) || (nux_event.type == NUX_WINDOW_EXIT_FOCUS) || (nux_event.type == NUX_WINDOW_MOUSELEAVE) || (nux_event.type == NUX_MOUSE_WHEEL)) { //DISPATCH EVENT HERE //nux_event.Application = Application; window_compositor_->ProcessEvent(nux_event); } if (nux_event.type == NUX_SIZE_CONFIGURATION) { if (!graphics_display_->isWindowMinimized()) { graphics_display_->SetViewPort(0, 0, nux_event.width, nux_event.height); ReconfigureLayout(); window_compositor_->FormatRenderTargets(nux_event.width, nux_event.height); } window_compositor_->FloatingAreaConfigureNotify(nux_event.width, nux_event.height); window_size_configuration_event_ = true; } // Some action may have caused layouts and areas to request a recompute. // Process them here before the Draw section. if (!graphics_display_->isWindowMinimized()) { if (queue_main_layout_) { ReconfigureLayout(); } else { // Compute the layouts that have been queued. ComputeQueuedLayout(); } } // Warn the host window manager to initiate a draw cycle. bool request_draw_cycle_to_host_wm = false; if (this->first_pass_) { request_draw_cycle_to_host_wm = true; force_rendering_ = true; //window_compositor_->Draw(window_size_configuration_event_, true); this->first_pass_ = false; } else { bool b = (nux_event.type == NUX_MOUSE_PRESSED) || (nux_event.type == NUX_MOUSE_RELEASED) || (nux_event.type == NUX_MOUSE_DOUBLECLICK) || //(event.type == NUX_MOUSE_MOVE) || (nux_event.type == NUX_SIZE_CONFIGURATION) || (nux_event.type == NUX_KEYDOWN) || (nux_event.type == NUX_KEYUP) || (nux_event.type == NUX_NC_WINDOW_CONFIGURATION) || (nux_event.type == NUX_WINDOW_ENTER_FOCUS) || (nux_event.type == NUX_WINDOW_EXIT_FOCUS) || (nux_event.type == NUX_WINDOW_DIRTY); if (b && window_compositor_->IsTooltipActive()) { // Cancel the tooltip since an event that should cause the tooltip to disappear has occurred. window_compositor_->CancelTooltip(); b |= true; } if (!window_compositor_->ValidateMouseInsideTooltipArea(nux_event.x, nux_event.y) && window_compositor_->IsTooltipActive()) { // Cancel the tooltip since an event that should cause the tooltip to disappear has occurred. window_compositor_->CancelTooltip(); b |= true; } if (b || IsRedrawNeeded()) { request_draw_cycle_to_host_wm = true; } else if (window_compositor_->GetWidgetDrawingOverlay() != 0) { request_draw_cycle_to_host_wm = true; } } if (!_draw_requested_to_host_wm && request_draw_cycle_to_host_wm) RequestRedraw(); return request_draw_cycle_to_host_wm; } void WindowThread::PresentWindowsIntersectingGeometryOnThisFrame(Geometry const& rect) { nuxAssertMsg(IsEmbeddedWindow(), "[WindowThread::PresentWindowIntersectingGeometryOnThisFrame] " "can only be called inside an embedded window"); window_compositor_->ForEachBaseWindow([&rect] (WeakBaseWindowPtr const& w) { if (rect.IsIntersecting(w->GetAbsoluteGeometry())) w->PresentInEmbeddedModeOnThisFrame(true); }); } void WindowThread::RenderInterfaceFromForeignCmd(Geometry const& clip) { nuxAssertMsg(IsEmbeddedWindow() == true, "[WindowThread::RenderInterfaceFromForeignCmd] You can only call RenderInterfaceFromForeignCmd if the window was created with CreateFromForeignWindow."); if (!IsEmbeddedWindow()) return; IOpenGLShaderProgram::SetShaderTracking(true); // Set Nux opengl states. The other plugin in compiz have changed the GPU opengl states. // Nux keep tracks of its own opengl states and restore them before doing any drawing. GetWindowThread()->GetGraphicsEngine().GetRenderStates().SubmitChangeStates(); GetWindowThread()->GetGraphicsEngine().SetOpenGLClippingRectangle(0, 0, GetWindowThread()->GetGraphicsEngine().GetWindowWidth(), GetWindowThread()->GetGraphicsEngine().GetWindowHeight()); if (!graphics_display_->IsPauseThreadGraphicsRendering()) { ComputeQueuedLayout(); GetWindowThread()->GetGraphicsEngine().SetGlobalClippingRectangle(clip); window_compositor_->Draw(window_size_configuration_event_, force_rendering_); GetWindowThread()->GetGraphicsEngine().DisableGlobalClippingRectangle(); // When rendering in embedded mode, nux does not attempt to measure the frame rate... // Cleanup GetWindowThread()->GetGraphicsEngine().ResetStats(); ClearRedrawFlag(); window_size_configuration_event_ = false; force_rendering_ = false; } CHECKGL( glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)); IOpenGLShaderProgram::SetShaderTracking(false); } void WindowThread::ForeignFrameEnded() { nuxAssertMsg(IsEmbeddedWindow(), "[WindowThread::ForeignFrameEnded] " "can only be called inside an embedded window"); window_compositor_->ForEachBaseWindow([] (WeakBaseWindowPtr const& w) { w->MarkPresentedInEmbeddedMode(); }); presentation_list_embedded_.clear(); foreign_frame_frozen_ = false; /* Move all the BaseWindows in presentation_list_embedded_next_frame_ * to presentation_list_embedded_ and mark them for presentation */ for (auto const& win : presentation_list_embedded_next_frame_) { if (win.IsValid()) win->PresentInEmbeddedModeOnThisFrame(); } presentation_list_embedded_next_frame_.clear(); } void WindowThread::ForeignFrameCutoff() { foreign_frame_frozen_ = true; } int WindowThread::InstallEventInspector(EventInspector function, void* data) { NUX_RETURN_VALUE_IF_NULL(function, 0); std::map < int, EventInspectorStorage >::iterator it; for (it = _event_inspectors_map.begin(); it != _event_inspectors_map.end(); ++it) { if ((*it).second._function == function) { // The inspector has already been added. Return its unique id return (*it).second._uid; } } // This is a new Event Inspector EventInspectorStorage new_inspector; new_inspector._function = function; new_inspector._data = data; new_inspector._uid = NUX_GLOBAL_OBJECT_INSTANCE(UniqueIndex).GetUniqueIndex(); _event_inspectors_map [new_inspector._uid] = new_inspector; return new_inspector._uid; } bool WindowThread::RemoveEventInspector(int event_inspector_id) { NUX_RETURN_VALUE_IF_NULL(event_inspector_id, false); std::map < int, EventInspectorStorage >::iterator it; for (it = _event_inspectors_map.begin(); it != _event_inspectors_map.end(); ++it) { if ((*it).second._uid == event_inspector_id) { _event_inspectors_map.erase(it); return true; } } return false; } bool WindowThread::RemoveEventInspector(EventInspector function) { NUX_RETURN_VALUE_IF_NULL(function, false); std::map < int, EventInspectorStorage >::iterator it; for (it = _event_inspectors_map.begin(); it != _event_inspectors_map.end(); ++it) { if ((*it).second._function == function) { _event_inspectors_map.erase(it); return true; } } return false; } bool WindowThread::CallEventInspectors(Event* event) { int n = _event_inspectors_map.size(); if (n == 0) { // No event inspector installed. return false; } bool discard_event = false; std::map < int, EventInspectorStorage >::iterator it; for (it = _event_inspectors_map.begin(); it != _event_inspectors_map.end(); ++it) { EventInspector callback = (*it).second._function; if (callback == 0) continue; int ret = callback(0, event, (*it).second._data); if (ret) { discard_event = true; } } return discard_event; } bool WindowThread::FindDataByFd(const WindowThread::ExternalFdData &data, int fd) { return data.fd == fd; } void WindowThread::WatchFdForEvents(int fd, const WindowThread::FdWatchCallback &cb) { ExternalFdData data; data.fd = fd; data.cb = cb; _external_fds.push_back(data); AddFdToGLibLoop(fd, reinterpret_cast (&_external_fds.back()), WindowThread::ExternalSourceCallback); } void WindowThread::UnwatchFd(int fd) { using namespace std::placeholders; std::list::iterator it = std::find_if (_external_fds.begin(), _external_fds.end(), std::bind(FindDataByFd, _1, fd)); if (it != _external_fds.end()) { RemoveFdFromGLibLoop(&(*it)); _external_fds.erase (it); } } #if defined(NUX_OS_LINUX) && defined(USE_X11) void WindowThread::XICFocus(TextEntry* text_entry) { xim_controller_->FocusInXIC(); xim_controller_->SetCurrentTextEntry(text_entry); graphics_display_->SetCurrentXIC(xim_controller_->GetXIC()); } void WindowThread::XICUnFocus() { xim_controller_->FocusOutXIC(); } #endif GraphicsDisplay& WindowThread::GetGraphicsDisplay() const { return *graphics_display_; } GraphicsEngine& WindowThread::GetGraphicsEngine() const { return *graphics_display_->GetGraphicsEngine(); } WindowCompositor& WindowThread::GetWindowCompositor() const { return *window_compositor_; } BasePainter& WindowThread::GetPainter() const { return *painter_; } TimerHandler& WindowThread::GetTimerHandler() const { return *timer_manager_; } UXTheme& WindowThread::GetTheme() const { if (!theme_) { LOG_INFO(logger) << "Lazily creating nux::UXTheme"; const_cast(this)->theme_ = new UXTheme(); } return *theme_; } std::string WindowThread::GetWindowTitle() const { return window_title_; } } nux-4.0.8+18.10.20180623/Nux/WindowThread.h0000644000000000000000000006361413313373365014135 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef WINDOWTHREAD_H #define WINDOWTHREAD_H #include "TimerProc.h" #ifdef NUX_GESTURES_SUPPORT #include "GeisAdapter.h" #endif #if defined(NUX_OS_LINUX) && defined(USE_X11) #include "XIMController.h" #endif namespace nux { class BaseWindow; class WindowThread; class Layout; class HLayout; class GraphicsDisplay; class ClientArea; class WindowCompositor; class AbstractThread; class SystemThread; class UXTheme; class TimerHandler; #if !defined(NUX_MINIMAL) class Timeline; #endif class Event; class Area; struct ClientAreaDraw; class ExternalGLibSources; gboolean nux_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data); gboolean nux_timeout_dispatch(gpointer user_data); //! Event Inspector function prototype. /*! If an event inspector return true, then the event is discarded. */ typedef int(*EventInspector) (Area* area, Event* event, void* data); //! Main class of a Nux window app. /*! Each WindowThread runs in its own loop. There cannot be more than one WindowThread per system thread. */ class WindowThread: public AbstractThread { NUX_DECLARE_OBJECT_TYPE(WindowThread, AbstractThread); public: WindowThread(const char *WindowTitle, int width, int height, AbstractThread *Parent, bool Modal); virtual ~WindowThread(); //! Start the WindowThread in the current Thread. /*! Run the main loop of the window. \n; The function blocks until the the main loop is stopped. @param ptr Reserved. */ virtual int Run(void *ptr = NULL); /*! Start the user interface Window in it own thread. Start return immediately after the thread is created. @param ptr Reserved. */ virtual ThreadState Start(void *ptr = NULL); //! Exit from the WindowThread loop. /*! Exit the WindowThread loop. */ void ExitMainLoop(); //! Set window size. /*! Set window size. @param width Window width. @param height Window height. */ void SetWindowSize(int width, int height); //! Set the background for the window. /*! Set the background for the window. @param background_layer background layer. */ void SetWindowBackgroundPaintLayer(AbstractPaintLayer *background_layer); /*! Get the graphics display (this is the physical window of this thread). @return The graphics display. */ GraphicsDisplay &GetGraphicsDisplay() const; /*! Get the graphics engine (this is the object that renders the graphics primitives). @return The graphics display. */ GraphicsEngine &GetGraphicsEngine() const; /*! Get the UI compositor (this is processes events and renders ui objects). @return The UI compositor. */ WindowCompositor& GetWindowCompositor() const; /*! Get the painter object. @return The painter object. */ BasePainter &GetPainter() const; /*! Get the timer manager. @return The timer manager. */ TimerHandler &GetTimerHandler() const; /*! Get the UI resource manager (load textures and other data for user interface rendering). @param The ui resource manager. */ UXTheme &GetTheme() const; //! Set the layout for this window thread. /*! @param layout The layout of the user interface. */ void SetLayout(Layout *layout); //! Get the layout of this window. /*! @return The layout of this window. */ Layout* GetLayout(); //! Return true if the process is inside a layout cycle. /*! @return True if the process is inside a layout cycle. */ bool IsInsideLayoutCycle() const; //! Deprecated. Replace with IsInsideLayoutCycle. bool IsComputingLayout() const { return IsInsideLayoutCycle(); } //! Schedule a size computation cycle on an area before the rendering is performed. /*! This list contains the area whose size need to be computed. @param area The object that will perform a size computation cycle. \sa ComputeQueuedLayout. @return True if the object was succefully queued. */ bool QueueObjectLayout(Area *area); //! Compute the layout of a specific element /*! Immediate size negotiation for a View or a layout. */ void ComputeElementLayout(Area* bo, bool recurse_to_top_level_layout = false); //! Remove an area from the list of object whose size was scheduled to be computed before the rendering cycle. /*! @param area The object to remove form the list. @return True if the object was in the _queued_layout_list and has been removed. \sa ComputeQueuedLayout, QueueObjectLayout. */ bool RemoveObjectFromLayoutQueue(Area *area); /*! Return \i true while waiting for a modal window to return. @return \i True while waiting for a modal window to return. */ bool IsWaitingforModalWindow() const; /*! Return \i true if this window is modal. @return \i True if this window is modal. */ bool IsModalWindow() const; /*! Return true if this windowThread is embedded inside Compiz. @return True if embedded inside Compiz. */ bool IsEmbeddedWindow() const; #if defined(NUX_OS_WINDOWS) bool ProcessForeignEvent(HWND hWnd, MSG msg, WPARAM wParam, LPARAM lParam, void *data); #elif defined(USE_X11) bool ProcessForeignEvent(XEvent *event, void *data); #else bool ProcessForeignEvent(); #endif /*! In embedded mode, allow presentation on any windows intersecting this rect. The effect of this is culmulative for the frame, so it can be called multiple times with many different rects until RenderInterfaceFromForeignCmd is called. \sa IsEmbeddedWindow @param rect Region of the display to consider for presenting windows */ void PresentWindowsIntersectingGeometryOnThisFrame(Geometry const& rect); /*! Render the interface. This command is send from the pluging when the window thread is embedded. The clip region matches the surface of one single monitor screen, or a region inside that screen. \sa IsEmbeddedWindow. @param clip Region of the display to render. */ void RenderInterfaceFromForeignCmd(Geometry const& clip); /*! Used to mark the end of the foreign frame. All calls to PresentInEmbeddedModeOnThisFrame are now redirected to this upcoming frame where we will be called next. */ void ForeignFrameEnded(); /*! Used to mark the cutoff point where all calls to PresentInEmbeddedModeOnThisFrame should be effective on the next frame, and not this one, because the parent context has stopped tracking damage events for this frame */ void ForeignFrameCutoff(); #if !defined(NUX_MINIMAL) /*! Add a timeline to our window */ void AddTimeline(Timeline* timeline); void RemoveTimeline(Timeline* timeline); bool ProcessTimelines(gint64 micro_secs); long last_timeline_frame_time_sec_; long last_timeline_frame_time_usec_; #endif void StartMasterClock(); void StopMasterClock(); sigc::signal RedrawRequested; sigc::signal window_configuration; //!< emmitted when the window Geometry changes. //! Set an event inspector function. /*! Inspect all events and returns the action to be taken for the event(process or discard). If \a function as already been added, return its unique id.\n If \a function is null, return 0.\n @param function Event inspector function callback. @param data User defined data. @return Unique id for the event inspector callback. */ int InstallEventInspector(EventInspector function, void* data); //! Remove an event inspector. /*! Remove the event inspector identified by the provided unique id. @param event_inspector_id Unique id for the event inspector. @return True If the event inspector exists and has been removed. */ bool RemoveEventInspector(int event_inspector_id); //! Remove an event inspector. /*! Remove the event inspector identified by the provided function. @param function Event inspector function callback. @return True If the event inspector exists and has been removed. */ bool RemoveEventInspector(EventInspector function); //! Call event inspectors. /*! Call event inspectors to have a look at the event. @return True if the event should be discarded. */ bool CallEventInspectors(Event* event); //! Sets a timer from a different thread. /*! Sets a timer and a callback. When the timer expires, the callback is executed. This function is meant to be called from a different thread. This function very carefully avoid calling any thread specific objects (TLS). @param time_ms Timer delay in milliseconds. @param timeout_signal Pointer to a TimeOutSignal. @param user_data Pointer to user data. @return A timer handle. */ TimerHandle SetAsyncTimerCallback(int time_ms, TimeOutSignal* timeout_signal, void *user_data); /*! Return the Window title. @return The window title. */ std::string GetWindowTitle() const; void ProcessDraw(GraphicsEngine &graphics_engine, bool force_draw); void RequestRedraw(); void ClearRedrawFlag(); bool IsRedrawNeeded() const; // DrawList - this is a maintained list of areas that will // be completely redraw on the next frame void AddToDrawList(View *view); void ClearDrawList(); std::vector const& GetDrawList() const; // PresentationList - this is a maintained list of areas that // will be presented to the reference framebuffer or backbuffer // in embedded mode on the next frame bool AddToPresentationList(nux::BaseWindow*, bool force); std::vector GetPresentationListGeometries() const; Event GetNextEvent(); #ifdef NUX_GESTURES_SUPPORT /*! Simple wrapper for ProcessEvent for connection with GeisAdapter::event_ready */ void ProcessGestureEvent(GestureEvent &event) { ProcessEvent(event); } GeisAdapter *GetGeisAdapter() const {return geis_adapter_.get();} #endif typedef std::function FdWatchCallback; void WatchFdForEvents(int fd, const FdWatchCallback &); void UnwatchFd(int fd); #if defined(NUX_OS_LINUX) && defined(USE_X11) void XICFocus(TextEntry* text_entry); void XICUnFocus(); #endif protected: /*! Constructor-like function for the thread. Will be called by EntryPoint before executing the thread body. For the main window, ThreadCtor is called in nux::CreateMainWindow. ThreadCtor creates and initialize the following elements: - Graphics Window - Timer - Painter - Compositor - Theme engine After ThreadCtor is called, thread_ctor_called_ is set to true; */ virtual bool ThreadCtor(); #if defined(NUX_OS_WINDOWS) /*! Constructor-like function for the thread. Will be called by EntryPoint before executing the thread body. For the main window, ThreadCtor is called in nux::CreateMainWindow. ThreadCtor creates and initialize the following elements: - Graphics Window(from the externally created window) - Timer - Painter - Compositor - Theme engine After ThreadCtor is called, thread_ctor_called_ is set to true; This function is called when Nux is embedded. \sa IsEmbeddedWindow. */ virtual bool ThreadCtor(HWND WindowHandle, HDC WindowDCHandle, HGLRC OpenGLRenderingContext); #elif defined(USE_X11) #ifdef NUX_OPENGLES_20 /*! Constructor-like function for the thread. Will be called by EntryPoint before executing the thread body. For the main window, ThreadCtor is called in nux::CreateMainWindow. ThreadCtor creates and initialize the following elements: - Graphics Window(from the externally created window) - Timer - Painter - Compositor - Theme engine After ThreadCtor is called, thread_ctor_called_ is set to true; This function is called when Nux is embedded. \sa IsEmbeddedWindow. */ virtual bool ThreadCtor(Display *X11Display, Window X11Window, EGLContext OpenGLContext); #else /*! Constructor-like function for the thread. Will be called by EntryPoint before executing the thread body. For the main window, ThreadCtor is called in nux::CreateMainWindow. ThreadCtor creates and initialize the following elements: - Graphics Window(from the externally created window) - Timer - Painter - Compositor - Theme engine After ThreadCtor is called, thread_ctor_called_ is set to true; This function is called when Nux is embedded. \sa IsEmbeddedWindow. */ virtual bool ThreadCtor(Display *X11Display, Window X11Window, GLXContext OpenGLContext); #endif Display *x11display_; bool ownx11display_; #endif /*! Destructor-like function for the thread. Will be called by EntryPoint after executing the thread body. After ThreadDtor is called, thread_dtor_called_ is set to true. ThreadDtor is also called in the destructor of the WindowThread but is protected by thread_dtor_called_ so it is not called twice. In the case of the main window, ThreadDtor is called in the destructor of WindowThread. */ virtual bool ThreadDtor(); //! Causes the Main layout to be recomputed. /*! Causes the main layout to be recomputed. This will happen just before the next draw cycle. */ void QueueLayout(); //! Empty the queue of objects set for layout computation. /*! The queue was filled with calls to QueueObjectLayout. */ void RemoveQueuedLayout(); //! Compute the layout of this window thread. /*! Reconfigure the layout of this window. Start by setting the size of the layout to the size of this window. ReconfigureLayout is executed following an event of type NUX_SIZE_CONFIGURATION or a call to QueueMainLayout. \sa QueueMainLayout. */ void ReconfigureLayout(); /*! Suspend Win32 Mouse and Keyboard inputs for this window thread and its child thread that are also window (not SystemThread). */ void EnableMouseKeyboardInput(); /*! Enable Win32 Mouse and Keyboard inputs for this window thread and its child thread that are also window (not SystemThread). */ void DisableMouseKeyboardInput(); /*! It does the following: * processes the input events * resizes views * draw the frame This function is called when there is an input event, a gesture event or when a timer has expired. */ unsigned int ProcessEvent(Event &event); virtual ThreadState StartChildThread(AbstractThread *thread, bool Modal); virtual void AddChildThread(AbstractThread *); virtual void RemoveChildThread(AbstractThread *); virtual void ChildHasFinished(AbstractThread *app); virtual void TerminateChildThreads(); virtual ThreadState SuspendChildGraphics(WindowThread *app); bool is_modal_window_; bool wait_for_modal_window_; WindowThread *modal_window_thread_; private: /*! Internally called by ProcessEvent end ExecutionLopp after early return check. */ unsigned int DoProcessEvent(Event &event); void SetupMainLoop(); //! Execute the main loop of this thread. /*! Execute the main loop of this thread. @return And exit code. 0 if there was no error. */ int MainLoop(); //! Custom callback to wake up the main thread and start the execution loop. /*! This function is executed when \i async_wake_up_signal_ expires. It doesn't do anything when called, but the main thread will wake up and start the execution loop. \sa async_wake_up_signal_ @param user_ptr Pointer to user data. */ void AsyncWakeUpCallback(void *user_ptr); TimeOutSignal *async_wake_up_signal_; TimerHandle async_wake_up_timer_handle_; //! Informs the system of the start of a layout cycle. /*! This call merely sets a flag to true or false. This flag is used to decided if some actions should be performed or not. Used by the system only. */ void StartLayoutCycle(); //! Informs the system of the end of a layout cycle. /*! This call merely sets a flag to true or false. This flag is used to decided if some actions should be performed or not. Used by the system only. */ void StopLayoutCycle(); //! Execute the size computation cycle on objects. /* The objects whose size is to be computed are added to a list with a call to QueueObjectLayout. Size computation is performed just before the rendering cycle. \sa QueueObjectLayout */ void ComputeQueuedLayout(); GSource *_MasterClock; WindowThread(const WindowThread &); // Does not make sense for a singleton. This is a self assignment. WindowThread& operator = (const WindowThread &); // Declare operator address-of as private WindowThread* operator & (); bool _inside_main_loop; bool _inside_timer_loop; bool _pending_wake_up_timer; //! This list contains the layout that need to be recomputed following the resizing of one of the sub element. /*! This list contains the layout that need to be recomputed following the resizing of one of the sub element. */ std::list _queued_layout_list; std::vector dirty_areas_; typedef nux::ObjectWeakPtr WeakBaseWindowPtr; std::vector presentation_list_embedded_; /*! This list contains al lthe windows which will be presented on the next frame (eg, after ForeignFrameEnded they are moved into presentation_list_embedded_ and marked for presentation) */ std::vector presentation_list_embedded_next_frame_; /*! Whether or not the current frame is "frozen" because the host WM has stopped tracking damage events. If so we should put all presentation requests on the next frame instead of this one */ bool foreign_frame_frozen_; //! This variable is true while we are computing the layout the starting from the outmost layout(the Main Layout); bool _inside_layout_cycle; //! Set to true to schedule a compute cycle on the main layout. bool queue_main_layout_; #if !defined(NUX_MINIMAL) std::list *_Timelines; #endif bool first_pass_; //!< True when going through the ExecutionLoop for the first time. unsigned int window_initial_width_; //!< Window height at startup. unsigned int window_initial_height_; //!< Window width at startup. std::string window_title_; //!< Window title. bool _draw_requested_to_host_wm; //!< Flags signaling that a draw cycle has been requested to the host window manager. Layout *main_layout_; UXTheme *theme_; BasePainter *painter_; TimerHandler *timer_manager_; //bool created_own_thread_; //!< If true, create a system thread and run the window in it. GraphicsDisplay *graphics_display_; WindowCompositor *window_compositor_; bool m_WidgetInitialized; WindowStyle window_style_; /*! True if the thread constructor has been called. This is a form of per-WindowThread reentry protection. */ bool thread_ctor_called_; /*! True if the thread destructor has been called. This is a form of per-WindowThread reentry protection. */ bool thread_dtor_called_; /*! True when running Ubuntu Unity+Nux has a plugin of Compiz. */ bool embedded_window_; /*! Record if there was a configuration nux_event(NUX_SIZE_CONFIGURATION) that requires a full redraw. Used in the case where event processing and rendering are decoupled(with foreign windows). */ bool window_size_configuration_event_; bool force_rendering_; typedef struct _EventInspectorStorage { _EventInspectorStorage() { _function = 0; _data = 0; _uid = 0; } EventInspector _function; void* _data; int _uid; } EventInspectorStorage; //! Map of events inspectors /*! Events inspectors get to examine events before they are processed. They may also stop an event from being processed if they return true. */ std::map _event_inspectors_map; //!< map of events inspectors typedef struct _ExternalFdData { int fd; FdWatchCallback cb; } ExternalFdData; //! List of external sources. This might make more sense as a map, // but providing a struct provides us much nicer GLib integration std::list _external_fds; static bool FindDataByFd(const WindowThread::ExternalFdData &data, int fd); GMainLoop *main_loop_glib_; GMainContext *main_loop_glib_context_; friend gboolean nux_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data); friend gboolean nux_timeout_dispatch(gpointer user_data); std::list child_window_list_; std::unique_ptr external_glib_sources_; void InitGlibLoop(); void RunGlibLoop(); void StopGLibLoop(); void CleanupGlibLoop(); void AddFdToGLibLoop(int, gpointer, GSourceFunc); void RemoveFdFromGLibLoop(gpointer); bool AddChildWindowGlibLoop(WindowThread* wnd_thread); static gboolean ExternalSourceCallback(gpointer user_data); unsigned int AddGLibTimeout(unsigned int duration); #ifdef NUX_GESTURES_SUPPORT std::unique_ptr geis_adapter_; #endif #if defined(NUX_OS_LINUX) && defined(USE_X11) std::shared_ptr xim_controller_; #endif /*! Add a timeout and return the timeout index. This function is used internally by Nux. @param timeout_delay Time laps before the timeout is fired. @return An index for the timeout. */ unsigned int AddTimeout(unsigned int timeout_delay); static const int MINIMUM_WINDOW_WIDTH; //!< Minimum width allowed for a window. static const int MINIMUM_WINDOW_HEIGHT; //!< Minimum height allowed for a window. friend class TimerHandler; friend class BasePainter; friend class SystemThread; friend WindowThread *CreateGUIThread(const char *WindowTitle, int width, int height, WindowThread *Parent, ThreadUserInitFunc UserInitFunc, void *InitData); friend WindowThread *CreateNuxWindow(const char *WindowTitle, int width, int height, ThreadUserInitFunc UserInitFunc, void *InitData); friend WindowThread *CreateNuxWindow(const char *window_title, int width, int height, WindowStyle window_border_style, AbstractThread *parent, bool modal, ThreadUserInitFunc user_init_func, void *data); friend WindowThread *CreateNuxWindowNewThread(const char *window_title, int width, int height, WindowStyle window_border_style, AbstractThread *parent, bool modal, ThreadUserInitFunc user_init_func, void *data); friend WindowThread *CreateWindowThread(WindowStyle WndStyle, const char *WindowTitle, int width, int height, WindowThread *Parent, ThreadUserInitFunc UserInitFunc, void *InitData); friend WindowThread *CreateModalWindowThread(WindowStyle WndStyle, const char *WindowTitle, int width, int height, WindowThread *Parent, ThreadUserInitFunc UserInitFunc, void *InitData); #if defined(NUX_OS_WINDOWS) friend WindowThread *CreateFromForeignWindow(HWND WindowHandle, HDC WindowDCHandle, HGLRC OpenGLRenderingContext, ThreadUserInitFunc UserInitFunc, void *InitData); #elif defined(USE_X11) # ifdef NUX_OPENGLES_20 friend WindowThread *CreateFromForeignWindow (Window X11Window, EGLContext OpenGLContext, ThreadUserInitFunc UserInitFunc, void *InitData); # else friend WindowThread *CreateFromForeignWindow (Window X11Window, GLXContext OpenGLContext, ThreadUserInitFunc UserInitFunc, void *InitData); # endif #elif defined(NO_X11) friend WindowThread *CreateFromForeignWindow (EGLDisplay disp, EGLContext OpenGLContext, ThreadUserInitFunc UserInitFunc, void *InitData); #endif friend SystemThread *CreateSystemThread(AbstractThread *Parent, ThreadUserInitFunc UserInitFunc, void *InitData); }; } #endif // WINDOWTHREAD_H nux-4.0.8+18.10.20180623/Nux/XICClient.cpp0000644000000000000000000001650113313373365013644 0ustar /* * Copyright 2012-2013 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * */ #include "XICClient.h" namespace nux { XICClient::XICClient() : xic_(nullptr) , xim_style_(0) , focused_(false) { } void XICClient::ResetXIC(XIM xim, Window window, Display* display) { if (!xim_style_) SetupXIMStyle(xim); SetupXIC(xim, window, display); } void XICClient::SetCurrentTextEntry(TextEntry* text_entry) { text_entry_ = text_entry; } static int preedit_caret_callback(XIC xic, XPointer clientdata, XIMPreeditCaretCallbackStruct* call_data) { return 0; } static int status_start_callback(XIC xic, XPointer clientdata, XIMPreeditDrawCallbackStruct* call_data) { return 0; } static void status_draw_callback(XIC xic, XPointer clientdata, XPointer* call_data) { } static void status_done_callback(XIC xic, XPointer clientdata, XPointer* call_data) { } XVaNestedList XICClient::GetPreeditCallbacks() { preedit_start_cb_.callback = (XIMProc)XICClient::PreeditStartCallback; preedit_start_cb_.client_data = nullptr; preedit_done_cb_.callback = (XIMProc)XICClient::PreeditDoneCallback; preedit_done_cb_.client_data = (XPointer)text_entry_; preedit_draw_cb_.callback = (XIMProc)XICClient::PreeditDrawCallback; preedit_draw_cb_.client_data = (XPointer)text_entry_; preedit_caret_cb_.callback = (XIMProc)preedit_caret_callback; preedit_caret_cb_.client_data = nullptr; XVaNestedList p_list = nullptr; p_list = XVaCreateNestedList(0, XNPreeditStartCallback, &preedit_start_cb_, XNPreeditDoneCallback, &preedit_done_cb_, XNPreeditDrawCallback, &preedit_draw_cb_, XNPreeditCaretCallback, &preedit_caret_cb_, nullptr); return p_list; } XVaNestedList XICClient::GetStatusCallbacks() { status_start_cb_.callback = (XIMProc)status_start_callback; status_start_cb_.client_data = nullptr; status_done_cb_.callback = (XIMProc)status_done_callback; status_done_cb_.client_data = nullptr; status_draw_cb_.callback = (XIMProc)status_draw_callback; status_draw_cb_.client_data = nullptr; XVaNestedList s_list = nullptr; s_list = XVaCreateNestedList(0, XNStatusStartCallback, &status_start_callback, XNStatusDoneCallback, &status_done_callback, XNStatusDrawCallback, &status_draw_callback, nullptr); return s_list; } XIMStyle XICClient::FilterXIMStyle() { XIMStyle style = 0; if (xim_style_ & XIMPreeditCallbacks) { style |= XIMPreeditCallbacks; } else if (xim_style_ & XIMPreeditNone) { style |= XIMPreeditNone; } else { style |= XIMPreeditNothing; } if (xim_style_ & XIMStatusCallbacks) { style |= XIMStatusCallbacks; } else if (xim_style_ & XIMStatusNone) { style |= XIMStatusNone; } else { style |= XIMStatusNothing; } return style; } void XICClient::SetupXIC(XIM xim, Window window, Display* display) { if (xic_) DestroyXIC(); XIMStyle style = FilterXIMStyle(); const char* p_name = nullptr; XVaNestedList p_list = nullptr; if (style & XIMPreeditCallbacks) { p_list = GetPreeditCallbacks(); p_name = XNPreeditAttributes; } const char* s_name = nullptr; XVaNestedList s_list = nullptr; if (style & XIMStatusCallbacks) { s_list = GetStatusCallbacks(); s_name = XNStatusAttributes; } xic_ = XCreateIC(xim, XNInputStyle, style, XNClientWindow, window, p_name, p_list, s_name, s_list, nullptr); if (p_list) XFree(p_list); if (s_list) XFree(s_list); xim_style_ = style; } XIMStyle ChooseBetterStyle(XIMStyle style1, XIMStyle style2) { XIMStyle s,t; XIMStyle preedit = XIMPreeditArea | XIMPreeditCallbacks | XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone; XIMStyle status = XIMStatusArea | XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone; if (style1 == 0) return style2; if (style2 == 0) return style1; if ((style1 & (preedit | status)) == (style2 & (preedit | status))) return style1; s = style1 & preedit; t = style2 & preedit; if (s != t) { if (s | t | XIMPreeditCallbacks) return (s == XIMPreeditCallbacks) ? style1 : style2; else if (s | t | XIMPreeditPosition) return (s == XIMPreeditPosition) ? style1 : style2; else if (s | t | XIMPreeditArea) return (s == XIMPreeditArea) ? style1 : style2; else if (s | t | XIMPreeditNothing) return (s == XIMPreeditNothing) ? style1 : style2; else /*if (s | t | XIMPreeditNone)*/ return (s == XIMPreeditNone) ? style1 : style2; } else { s = style1 & status; t = style2 & status; if (s | t | XIMStatusCallbacks) return (s == XIMStatusCallbacks) ? style1 : style2; else if (s | t | XIMStatusArea) return (s == XIMStatusArea) ? style1 : style2; else if (s | t | XIMStatusNothing) return (s == XIMStatusNothing) ? style1 : style2; else /*if (s | t | XIMStatusNone)*/ return (s == XIMStatusNone) ? style1 : style2; } } void XICClient::SetupXIMStyle(XIM xim) { int i; XIMStyles *xim_styles = nullptr; XIMStyle prefered_style = XIMPreeditCallbacks | XIMStatusCallbacks; XGetIMValues(xim, XNQueryInputStyle, &xim_styles, nullptr); XIMStyle best = 0, style = 0; for (i = 0; i < xim_styles->count_styles; ++i) { style = xim_styles->supported_styles[i]; if ((style & prefered_style) == style) { best = ChooseBetterStyle(style, best); break; } else { best = ChooseBetterStyle(style, best); } } xim_style_ = best; XFree(xim_styles); } bool XICClient::HasXIC() const { return xic_ != nullptr; } XIC XICClient::GetXIC() const { return xic_; } void XICClient::Reinitialize() { xic_ = nullptr; xim_style_ = 0; focused_ = false; } void XICClient::FocusInXIC() { if (xic_ && !focused_) { XSetICFocus(xic_); focused_ = true; } } void XICClient::FocusOutXIC() { if (xic_ && focused_) { XUnsetICFocus(xic_); focused_ = false; } } bool XICClient::IsFocused() const { return focused_; } void XICClient::DestroyXIC() { if (xic_) { XDestroyIC(xic_); xic_ = nullptr; } } } //namespace nux nux-4.0.8+18.10.20180623/Nux/XICClient.h0000644000000000000000000000415113313373365013307 0ustar /* * Copyright 2012-2013 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * */ #ifndef XICCLIENT_H #define XICCLIENT_H /* Xlib.h is the default header that is included and has the core functionallity */ #include namespace nux { class TextEntry; class XICClient { public: XICClient(); void ResetXIC(XIM xim, Window window, Display* display); void SetCurrentTextEntry(TextEntry* text_entry_); bool HasXIC() const; XIC GetXIC() const; void Reinitialize(); void FocusInXIC(); void FocusOutXIC(); bool IsFocused() const; void DestroyXIC(); private: void SetupXIC(XIM xim, Window window, Display* display); void SetupXIMStyle(XIM xim); XVaNestedList GetPreeditCallbacks(); XVaNestedList GetStatusCallbacks(); XIMStyle FilterXIMStyle(); static int PreeditStartCallback(XIC xic, XPointer clientdata, XPointer data); static int PreeditDoneCallback(XIC xic, XPointer clientdata, XPointer data); static int PreeditDrawCallback(XIC xic, XPointer clientdata, XIMPreeditDrawCallbackStruct* call_data); TextEntry* text_entry_; XIC xic_; XIMStyle xim_style_; XIMCallback preedit_start_cb_; XIMCallback preedit_done_cb_; XIMCallback preedit_draw_cb_; XIMCallback preedit_caret_cb_; XIMCallback status_start_cb_; XIMCallback status_done_cb_; XIMCallback status_draw_cb_; bool focused_; }; } //namespace nux #endif // XICClient.h nux-4.0.8+18.10.20180623/Nux/XIMCallbacks.cpp0000644000000000000000000001126213313373365014316 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2013 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * */ #include "Nux.h" #include "TextEntry.h" #include "XICClient.h" #include #include "NuxCore/Logger.h" DECLARE_LOGGER(logger, "xim.callbacks"); using namespace std; namespace nux { int const FEEDBACK_MASK = (XIMUnderline | XIMReverse); int XICClient::PreeditStartCallback(XIC xic, XPointer clientdata, XPointer call_data) { TextEntry* text_entry = (TextEntry*)clientdata; if (text_entry) { text_entry->PreeditStarted(); } return 0; } int XICClient::PreeditDoneCallback(XIC xic, XPointer clientdata, XPointer call_data) { TextEntry* text_entry = (TextEntry*)clientdata; if (text_entry) { text_entry->ClearPreedit(); } return 0; } void add_feedback_attr(PangoAttrList* attrs, char const* str, XIMFeedback feedback, int start, int end) { PangoAttribute* attr; int start_index = g_utf8_offset_to_pointer(str, start) - str; int end_index = g_utf8_offset_to_pointer(str, end) - str; if (feedback & XIMUnderline) { attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert (attrs, attr); } if (feedback & XIMReverse) { attr = pango_attr_foreground_new(0xFFFF, 0xFFFF, 0xFFFF); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert (attrs, attr); attr = pango_attr_background_new(0x0, 0x0, 0x0); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert (attrs, attr); } if (feedback & ~FEEDBACK_MASK) { LOG_WARN(logger) << "Unrenderer feedback: " << (feedback & ~FEEDBACK_MASK); } } void feedback_to_pango_list(PangoAttrList** attrs, char const* str, int nfeedbacks, XIMFeedback* feedbacks) { XIMFeedback last_feedback = 0; int start = -1; int i = 0; if (attrs) { *attrs = pango_attr_list_new(); for (i = 0; i < nfeedbacks; ++i) { XIMFeedback new_feedback = (feedbacks[i] & FEEDBACK_MASK); if (new_feedback != last_feedback) { last_feedback = new_feedback; start = i; } else { PangoAttribute* attr; int start_index = g_utf8_offset_to_pointer(str, start) - str; int end_index = g_utf8_offset_to_pointer(str, i) - str; attr = pango_attr_foreground_new(0x0, 0x0, 0x0); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert (*attrs, attr); attr = pango_attr_background_new(0xFFFF, 0xFFFF, 0xFFFF); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert (*attrs, attr); } } if (start >= 0) add_feedback_attr(*attrs, str, last_feedback, start, i); } } int XICClient::PreeditDrawCallback(XIC xic, XPointer clientdata, XIMPreeditDrawCallbackStruct* call_data) { TextEntry* text_entry = (TextEntry*)clientdata; if (call_data->text && text_entry) { string preedit; // TODO Actually handle this correctly... if (call_data->text->encoding_is_wchar) { preedit = string(""); } else { preedit = string(call_data->text->string.multi_byte); } PangoAttrList* preedit_attr; feedback_to_pango_list(&preedit_attr, preedit.c_str(), call_data->text->length, call_data->text->feedback); text_entry->UpdatePreeditAttribs(preedit_attr); text_entry->UpdatePreedit(preedit, call_data->caret); } return 0; } } nux-4.0.8+18.10.20180623/Nux/XIMController.cpp0000644000000000000000000000736413313373365014572 0ustar /* * Copyright 2012-2013 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * */ #include #include "XIMController.h" #include "NuxCore/Logger.h" DECLARE_LOGGER(logger, "xim.controller"); namespace nux { XIMController::XIMController(Display* display) : display_(display) , window_(0) , xim_(nullptr) { InitXIMCallback(); } XIMController::~XIMController() { // The XIC must be destroyed before the XIM xic_client_.DestroyXIC(); if (xim_) XCloseIM(xim_); } void XIMController::SetFocusedWindow(Window window) { window_ = window; if (xim_) xic_client_.ResetXIC(xim_, window, display_); } void XIMController::SetCurrentTextEntry(TextEntry* text_entry) { xic_client_.SetCurrentTextEntry(text_entry); if (xim_) xic_client_.ResetXIC(xim_, window_, display_); } void XIMController::RemoveFocusedWindow() { window_ = 0; xic_client_.DestroyXIC(); } bool XIMController::IsXICValid() const { return xic_client_.HasXIC(); } XIC XIMController::GetXIC() const { return xic_client_.GetXIC(); } void XIMController::FocusInXIC() { xic_client_.FocusInXIC(); } void XIMController::FocusOutXIC() { xic_client_.FocusOutXIC(); xic_client_.SetCurrentTextEntry(nullptr); } Window XIMController::GetCurrentWindow() const { return window_; } void XIMController::InitXIMCallback() { char* const xmodifier = getenv("XMODIFIERS"); if (xmodifier && strstr(xmodifier,"ibus") != NULL) { LOG_WARN(logger) << "IBus natively supported."; return; } if (setlocale(LC_ALL, "") == NULL) { LOG_WARN(logger) << "Cannot setlocale."; } if (XSupportsLocale()) { if (XSetLocaleModifiers("") == NULL) { LOG_WARN(logger) << "XSetLocalModifiers Failed."; } XRegisterIMInstantiateCallback(display_, NULL, NULL, NULL, XIMController::SetupXIMClientCallback, (XPointer)this); } } void XIMController::SetupXIMClientCallback(Display* dpy, XPointer client_data, XPointer call_data) { XIMController* self = (XIMController*)client_data; self->SetupXIM(); } void XIMController::EndXIMClientCallback(Display* dpy, XPointer client_data, XPointer call_data) { XIMController* self = (XIMController*)client_data; self->xim_ = NULL; self->xic_client_.Reinitialize(); self->InitXIMCallback(); } void XIMController::SetupXIM() { xim_ = XOpenIM(display_, NULL, NULL, NULL); if (xim_) { SetupXIMDestroyedCallback(); if (window_) xic_client_.ResetXIC(xim_, window_, display_); XUnregisterIMInstantiateCallback (display_, NULL, NULL, NULL, XIMController::SetupXIMClientCallback, (XPointer)this); } else { LOG_WARN(logger) << "Failed to open IM."; } } void XIMController::SetupXIMDestroyedCallback() { XIMCallback destroy_callback; destroy_callback.callback = (XIMProc)XIMController::EndXIMClientCallback; destroy_callback.client_data = (XPointer)this; XSetIMValues (xim_, XNDestroyCallback, &destroy_callback, NULL); } } //namespace nux nux-4.0.8+18.10.20180623/Nux/XIMController.h0000644000000000000000000000333413313373365014230 0ustar /* * Copyright 2012-2013 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Brandon Schaefer * */ #ifndef XIMCONTROLLER_H #define XIMCONTROLLER_H #include "XICClient.h" /* Xlib.h is the default header that is included and has the core functionallity */ #include namespace nux { class TextEntry; class XIMController { public: XIMController(Display* display); ~XIMController(); void SetFocusedWindow(Window window); void SetCurrentTextEntry(TextEntry* text_entry_); void RemoveFocusedWindow(); bool IsXICValid() const; XIC GetXIC() const; void FocusInXIC(); void FocusOutXIC(); Window GetCurrentWindow() const; private: void InitXIMCallback(); static void SetupXIMClientCallback(Display* dpy, XPointer client_data, XPointer call_data); static void EndXIMClientCallback(Display* dpy, XPointer client_data, XPointer call_data); void SetupXIM(); void SetupXIMDestroyedCallback(); Display* display_; Window window_; XIM xim_; XICClient xic_client_; }; } //namespace nux #endif // XIMController.h nux-4.0.8+18.10.20180623/Nux/nux.pc.in0000644000000000000000000000052213313373365013115 0ustar prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: Nux Description: Nux OpenGL Toolkit Version: @VERSION@ Libs: -L${libdir} -lnux-@NUX_API_VERSION@ Cflags: -I${includedir}/Nux-@NUX_API_VERSION@ Requires: glib-2.0 nux-core-@NUX_API_VERSION@ nux-graphics-@NUX_API_VERSION@ @GL_PKGS@ sigc++-2.0 libpcre nux-4.0.8+18.10.20180623/NuxCore/0000755000000000000000000000000013313373365012164 5ustar nux-4.0.8+18.10.20180623/NuxCore/Animation-inl.h0000644000000000000000000001023013313373365015030 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUX_CORE_ANIMATION_INL_H #define NUX_CORE_ANIMATION_INL_H namespace nux { namespace animation { template AnimateValue::AnimateValue() : msec_current_(0) , msec_duration_(0) , start_value_(VALUE_TYPE()) , finish_value_(VALUE_TYPE()) , current_value_(start_value_) {} template AnimateValue::AnimateValue(int msec_duration) : msec_current_(0) , msec_duration_(msec_duration) , start_value_(VALUE_TYPE()) , finish_value_(VALUE_TYPE()) , current_value_(start_value_) {} template AnimateValue::AnimateValue(VALUE_TYPE const& start, VALUE_TYPE const& finish, int msec_duration) : msec_current_(0) , msec_duration_(msec_duration) , start_value_(start) , finish_value_(finish) , current_value_(start_value_) {} template AnimateValue& AnimateValue::SetStartValue(VALUE_TYPE const& start) { start_value_ = start; return *this; } template AnimateValue& AnimateValue::SetFinishValue(VALUE_TYPE const& finish) { finish_value_ = finish; return *this; } template AnimateValue& AnimateValue::SetDuration(int msecs) { msec_duration_ = msecs; return *this; } template AnimateValue& AnimateValue::SetEasingCurve(EasingCurve const& curve) { easing_curve_ = curve; return *this; } template int AnimateValue::Duration() const { return msec_duration_; } template int AnimateValue::CurrentTimePosition() const { return msec_current_; } template VALUE_TYPE const& AnimateValue::GetStartValue() const { return start_value_; } template VALUE_TYPE const& AnimateValue::GetFinishValue() const { return finish_value_; } template VALUE_TYPE const& AnimateValue::GetCurrentValue() const { return current_value_; } template void AnimateValue::Advance(int msec) { if (CurrentState() != Running) return; msec_current_ += msec; if (msec_current_ >= msec_duration_) { msec_current_ = msec_duration_; current_value_ = finish_value_; updated.emit(current_value_); Stop(); } else { double progress = msec_current_ / static_cast(msec_duration_); double value = easing_curve_.ValueForProgress(progress); // These operators work for most if not all the property types we care // about. Should we need more, we'll reevaluate then. VALUE_TYPE new_value = start_value_ + ((finish_value_ - start_value_) * value); if (new_value != current_value_) { current_value_ = new_value; updated.emit(current_value_); } } } template void AnimateValue::Restart() { msec_current_ = 0; current_value_ = start_value_; updated.emit(current_value_); } template void AnimateValue::Reverse() { std::swap(start_value_, finish_value_); if (CurrentState() != Stopped) { msec_current_ = msec_duration_ - msec_current_; } } }} #endif nux-4.0.8+18.10.20180623/NuxCore/Animation.cpp0000644000000000000000000000352013313373365014607 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #include "NuxCore.h" #include "Animation.h" #include "AnimationController.h" namespace na = nux::animation; na::Animation::Animation() : state_(Stopped) {} na::Animation::~Animation() { if (state_ != Stopped) { if (Controller* controller = Controller::Instance()) controller->RemoveAnimation(this); } } void na::Animation::Pause() { if (state_ == Running) { state_ = Paused; } } void na::Animation::Resume() { if (state_ == Paused) { state_ = Running; } } void na::Animation::Start() { if (state_ == Stopped) { state_ = Running; Restart(); Controller* controller = Controller::Instance(); if (controller) controller->AddAnimation(this); } } void na::Animation::Stop() { if (state_ != Stopped) { state_ = Stopped; finished.emit(); Controller* controller = Controller::Instance(); if (controller) controller->RemoveAnimation(this); } } na::Animation::State na::Animation::CurrentState() const { return state_; } nux-4.0.8+18.10.20180623/NuxCore/Animation.h0000644000000000000000000000510513313373365014255 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUX_CORE_ANIMATION_H #define NUX_CORE_ANIMATION_H #include #include #include "EasingCurve.h" namespace nux { namespace animation { class Animation : boost::noncopyable { public: enum State { Stopped, Paused, Running, }; Animation(); virtual ~Animation(); virtual int Duration() const = 0; virtual int CurrentTimePosition() const = 0; void Start(); void Stop(); void Pause(); void Resume(); State CurrentState() const; sigc::signal finished; // Move the animation on so many milliseconds. virtual void Advance(int msec) = 0; protected: virtual void Restart() = 0; private: State state_; }; template class AnimateValue : public Animation { public: AnimateValue(); AnimateValue(int msec_duration); AnimateValue(VALUE_TYPE const& start, VALUE_TYPE const& finish, int msec_duration); AnimateValue& SetStartValue(VALUE_TYPE const& start); AnimateValue& SetFinishValue(VALUE_TYPE const& finish); AnimateValue& SetDuration(int msecs); AnimateValue& SetEasingCurve(EasingCurve const& curve); void Reverse(); virtual int Duration() const; virtual int CurrentTimePosition() const; sigc::signal updated; VALUE_TYPE const& GetStartValue() const; VALUE_TYPE const& GetFinishValue() const; VALUE_TYPE const& GetCurrentValue() const; // Move the animation on so many milliseconds. virtual void Advance(int msec); protected: virtual void Restart(); private: int msec_current_; int msec_duration_; VALUE_TYPE start_value_; VALUE_TYPE finish_value_; VALUE_TYPE current_value_; EasingCurve easing_curve_; }; }} #include "Animation-inl.h" #endif nux-4.0.8+18.10.20180623/NuxCore/AnimationController.cpp0000644000000000000000000001076613313373365016665 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #include "NuxCore.h" #include "AnimationController.h" #include "Animation.h" #include "Logger.h" #include namespace na = nux::animation; namespace nl = nux::logging; namespace { // Yes I know the compiler does that, but can't help being explicit. na::Controller* controller_instance = nullptr; nl::Logger logger("nux.animation"); } na::TickSource::~TickSource() {} na::Controller* na::Controller::Instance() { return controller_instance; } na::Controller::Controller() { if (controller_instance) { LOG_WARNING(logger) << "Multiple animation controllers created."; } else { controller_instance = this; } } na::Controller::~Controller() { if (controller_instance == this) { controller_instance = nullptr; } } struct na::AnimationController::Impl { Impl() : last_tick_(0) , ticking_(false) {} void Add(Animation* anim) { // never add the same twice Animations::iterator end = animations_.end(); Animations::iterator i = std::find(animations_.begin(), end, anim); if (i == end) { animations_.push_back(anim); } } void Remove(Animation* anim) { // never add the same twice Animations::iterator end = animations_.end(); Animations::iterator i = std::find(animations_.begin(), end, anim); if (i != end) { animations_.erase(i); } } bool HasRunningAnimations() const { Animations::const_iterator end = animations_.end(); Animations::const_iterator it = std::find_if(animations_.begin(), end, [](Animations::value_type item) { return item->CurrentState() == Animation::Running; }); return it != end; } void Tick(long long tick) { ticking_ = true; int ms_since_last_tick = static_cast((tick - last_tick_) / 1000); last_tick_ = tick; for (Animations::iterator i = animations_.begin(), end = animations_.end(); i != end; ++i) { // only if it isn't pending. if (do_not_tick_.empty() || do_not_tick_.find((*i)) == do_not_tick_.end()) { (*i)->Advance(ms_since_last_tick); } } ticking_ = false; for (AnimationActions::iterator i = pending_.begin(), end = pending_.end(); i != end; ++i) { if (i->second) Add(i->first); else Remove(i->first); } pending_.clear(); do_not_tick_.clear(); } long long last_tick_; typedef std::vector Animations; Animations animations_; typedef std::vector> AnimationActions; AnimationActions pending_; bool ticking_; typedef std::set DoNotTickActions; DoNotTickActions do_not_tick_; }; na::AnimationController::AnimationController(na::TickSource& tick_source) : pimpl(new Impl) { tick_source.tick.connect(sigc::mem_fun(this, &na::AnimationController::OnTick)); } na::AnimationController::~AnimationController() { delete pimpl; } // tick is expected to be ever increasing void na::AnimationController::OnTick(long long tick) { pimpl->Tick(tick); } void na::AnimationController::AddAnimation(na::Animation* animation) { if (pimpl->ticking_) { pimpl->pending_.push_back(std::make_pair(animation, true)); } else { pimpl->Add(animation); } } void na::AnimationController::RemoveAnimation(na::Animation* animation) { if (pimpl->ticking_) { pimpl->pending_.push_back(std::make_pair(animation, false)); pimpl->do_not_tick_.insert(animation); } else { pimpl->Remove(animation); } } bool na::AnimationController::HasRunningAnimations() const { return pimpl->HasRunningAnimations(); } nux-4.0.8+18.10.20180623/NuxCore/AnimationController.h0000644000000000000000000000470113313373365016322 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUX_CORE_ANIMATION_CONTROLLER_H #define NUX_CORE_ANIMATION_CONTROLLER_H #include namespace nux { namespace animation { class Animation; class TickSource { public: virtual ~TickSource(); // tick value is in microseconds sigc::signal tick; }; /** * The Animation Controller is responsible for updating running animations. * * The controller is constructed with a tick source, and operates as a * pseudo-singleton. A controller must be created somewhere, and once it is, * it set as the default controller. It is expected that there is only one * animation controller. */ class Controller { public: static Controller* Instance(); Controller(); virtual ~Controller(); virtual void AddAnimation(Animation* animation) = 0; virtual void RemoveAnimation(Animation* animation) = 0; virtual bool HasRunningAnimations() const = 0; private: #if defined(NUX_OS_WINDOWS) && !defined(NUX_VISUAL_STUDIO_VC11) Controller(Controller const&); Controller& operator = (Controller const&); #else Controller(Controller const&) = delete; Controller& operator = (Controller const&) = delete; #endif }; class AnimationController : public Controller, public sigc::trackable { public: AnimationController(TickSource& tick_source); virtual ~AnimationController(); // tick is expected to be ever increasing virtual void OnTick(long long tick); virtual void AddAnimation(Animation* animation); virtual void RemoveAnimation(Animation* animation); virtual bool HasRunningAnimations() const; private: struct Impl; Impl* pimpl; }; }} // close namespaces #endif nux-4.0.8+18.10.20180623/NuxCore/AsyncFileWriter.cpp0000644000000000000000000001610413313373365015744 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #include "NuxCore.h" #include "AsyncFileWriter.h" #include #include #include namespace nux { /** * CAUTION: right now this class is not thread aware. It assumes that all the * write calls are coming from a single thread. Perhaps we need to fix this? */ class AsyncFileWriter::Impl { public: Impl(AsyncFileWriter* owner, std::string const& filename); ~Impl(); void Write(std::string const& data); void Close(); void ProcessAsync(); static void AppendAsyncCallback(GFile* source, GAsyncResult* res, Impl* impl); static void WriteAsyncCallback(GOutputStream* source, GAsyncResult* res, Impl* impl); static void CloseAsyncCallback(GOutputStream* source, GAsyncResult* res, Impl* impl); AsyncFileWriter* owner_; GCancellable* cancel_; GFile* file_; GFileOutputStream* output_stream_; bool close_pending_; bool pending_async_call_; std::stringstream pending_content_; std::string data_to_write_; }; AsyncFileWriter::Impl::Impl(AsyncFileWriter* owner, std::string const& filename) : owner_(owner) , cancel_(g_cancellable_new()) , file_(g_file_new_for_path(filename.c_str())) , output_stream_(0) , close_pending_(false) , pending_async_call_(true) { g_file_append_to_async(file_, G_FILE_CREATE_NONE, G_PRIORITY_DEFAULT, cancel_, (GAsyncReadyCallback)&AsyncFileWriter::Impl::AppendAsyncCallback, this); } AsyncFileWriter::Impl::~Impl() { if (pending_async_call_) { g_cancellable_cancel(cancel_); } // make sure the file is closed. if (output_stream_) { // If we had an output stream, sync write any pending content. if (pending_content_.tellp()) { std::string data(pending_content_.str()); gsize bytes_written; g_output_stream_write_all((GOutputStream*)output_stream_, data.c_str(), data.size(), &bytes_written, NULL, NULL); } owner_->closed.emit(); g_object_unref(output_stream_); } g_object_unref(file_); g_object_unref(cancel_); } void AsyncFileWriter::Impl::AppendAsyncCallback(GFile* source, GAsyncResult* res, Impl* impl) { GError* error = NULL; GFileOutputStream* stream = g_file_append_to_finish(source, res, &error); if (error) { // Cancelled callbacks call back, but have a cancelled error code. if (error->code != G_IO_ERROR_CANCELLED) { std::cerr << error->message << "\n"; } g_error_free(error); return; } impl->output_stream_ = stream; impl->pending_async_call_ = false; impl->owner_->opened.emit(); impl->ProcessAsync(); } void AsyncFileWriter::Impl::Write(std::string const& data) { if (close_pending_) return; // TODO: lock the pending_content_ access pending_content_ << data; ProcessAsync(); } void AsyncFileWriter::Impl::ProcessAsync() { if (output_stream_ == NULL || pending_async_call_) return; if (pending_content_.tellp()) { // TODO: lock the pending_content_ access data_to_write_ = pending_content_.str(); g_output_stream_write_async((GOutputStream*)output_stream_, data_to_write_.c_str(), data_to_write_.size(), G_PRIORITY_DEFAULT, cancel_, (GAsyncReadyCallback)&AsyncFileWriter::Impl::WriteAsyncCallback, this); pending_async_call_ = true; } else if (close_pending_) { g_output_stream_close_async((GOutputStream*)output_stream_, G_PRIORITY_DEFAULT, cancel_, (GAsyncReadyCallback)&AsyncFileWriter::Impl::CloseAsyncCallback, this); pending_async_call_ = true; } } void AsyncFileWriter::Impl::WriteAsyncCallback(GOutputStream* source, GAsyncResult* res, Impl* impl) { GError* error = NULL; gssize g_bytes_written = g_output_stream_write_finish(source, res, &error); if (error) { // Cancelled callbacks call back, but have a cancelled error code. if (error->code != G_IO_ERROR_CANCELLED) { std::cerr << error->message << "\n"; } g_error_free(error); return; } // g_bytes_written is signed from gio, but only negative if there is an error. // The error should be set too if there was an error, so no negative bytes // written get past here. std::size_t bytes_written = g_bytes_written; impl->pending_async_call_ = false; // TODO: lock the pending_content_ access std::string data = impl->pending_content_.str(); if (bytes_written >= data.size()) { // There should be no reason why bytes_written should be greater than the // number of bytes in the stream, but this is paranoia. impl->pending_content_.str(""); } else { impl->pending_content_.str(data.substr(bytes_written)); } impl->ProcessAsync(); } void AsyncFileWriter::Impl::Close() { close_pending_ = true; ProcessAsync(); } void AsyncFileWriter::Impl::CloseAsyncCallback(GOutputStream* source, GAsyncResult* res, Impl* impl) { GError* error = NULL; g_output_stream_close_finish(source, res, &error); if (error) { // Cancelled callbacks call back, but have a cancelled error code. if (error->code != G_IO_ERROR_CANCELLED) { std::cerr << error->message << "\n"; } g_error_free(error); return; } g_object_unref(impl->output_stream_); impl->output_stream_ = 0; impl->owner_->closed.emit(); } AsyncFileWriter::AsyncFileWriter(std::string const& filename) : pimpl(new Impl(this, filename)) {} AsyncFileWriter::~AsyncFileWriter() { delete pimpl; } void AsyncFileWriter::Write(std::string const& data) { pimpl->Write(data); } void AsyncFileWriter::Close() { pimpl->Close(); } bool AsyncFileWriter::IsClosing() const { return pimpl->close_pending_; } } // namespace nux nux-4.0.8+18.10.20180623/NuxCore/AsyncFileWriter.h0000644000000000000000000000322013313373365015404 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUXCORE_ASYNC_FILE_WRITER_H #define NUXCORE_ASYNC_FILE_WRITER_H #include #include namespace nux { /** * Write to a file asynchronously. * * This uses the GIO async functions, and as such depend on the gobject main * loop. */ class AsyncFileWriter { public: AsyncFileWriter(std::string const& filename); // Destructor kills any pending async requests, and close the file // synchronously if it is open. ~AsyncFileWriter(); // Queue the data for writing. It'll happen some time. void Write(std::string const& data); // Close the file asynchronously. When the file is closed, the closed // signal is emitted. void Close(); bool IsClosing() const; sigc::signal opened; sigc::signal closed; private: class Impl; Impl* pimpl; }; } #endif nux-4.0.8+18.10.20180623/NuxCore/Character/0000755000000000000000000000000013313373365014060 5ustar nux-4.0.8+18.10.20180623/NuxCore/Character/NAscii.cpp0000644000000000000000000000564513313373365015744 0ustar /* * Copyright 2010 Inalogic Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "NAscii.h" namespace nux { // Windows-1252 code page t_uchar GAscii[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0xFF, '', 0x81, '', '', '', '', '', '', '', '', '', '', '', 0x8d, '', 0x8f, 0x90, '', '', '', '', '', '', '', 0x98, '', '', '', '', 0x9d, '', '', 0xa0, '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '' }; } nux-4.0.8+18.10.20180623/NuxCore/Character/NAscii.h0000644000000000000000000000164613313373365015406 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NTASCII_H #define NTASCII_H namespace nux { extern t_uchar GAscii[]; extern t_uchar GAsciiCP437[]; } #endif // NTASCII_H nux-4.0.8+18.10.20180623/NuxCore/Character/NTChar.h0000644000000000000000000000423713313373365015356 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NTCHAR_H #define NTCHAR_H namespace nux { inline TCHAR ToUpperCase ( TCHAR c ) { return (c < TEXT ('a') || c > TEXT ('z') ) ? (c) : (c + TEXT ('A') - TEXT ('a') ); } inline TCHAR ToLowerCase ( TCHAR c ) { return (c < TEXT ('A') || c > TEXT ('Z') ) ? (c) : (c + TEXT ('a') - TEXT ('A') ); } inline bool IsUpperCase ( TCHAR c ) { return (c >= TEXT ('A') && c <= TEXT ('Z') ); } inline bool IsLowerCase ( TCHAR c ) { return (c >= TEXT ('a') && c <= TEXT ('z') ); } inline bool IsAlphaChar ( TCHAR c ) { return (c >= TEXT ('a') && c <= TEXT ('z') ) || (c >= TEXT ('A') && c <= TEXT ('Z') ); } inline bool IsDigitChar ( TCHAR c ) { return c >= TEXT ('0') && c <= TEXT ('9'); } inline bool IsAlphanumericChar ( TCHAR c ) { return (c >= TEXT ('a') && c <= TEXT ('z') ) || (c >= TEXT ('A') && c <= TEXT ('Z') ) || (c >= TEXT ('0') && c <= TEXT ('9') ); } inline bool IsWhitespaceChar ( TCHAR c ) { return c == TEXT (' ') || c == TEXT ('\t'); } inline bool IsLinebreakChar ( TCHAR c ) { //@todo - support for language-specific line break characters return c == TEXT ('\n'); } /** Returns nonzero if character is a space character. */ inline bool IsSpaceChar ( TCHAR c ) { #ifdef NUX_UNICODE return ( std::iswspace (c) != 0 ); #else return ( std::isspace (c) != 0 ); #endif } } #endif // NTCHAR_H nux-4.0.8+18.10.20180623/NuxCore/Character/NUTF.cpp0000644000000000000000000002360313313373365015344 0ustar /* * Copyright 2010 Inalogic Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "NUTF.h" namespace nux { NUTF8::NUTF8 (const UNICHAR *Source) { Convert (Source); } NUTF8::NUTF8 (const std::wstring &Source) { Convert (NUX_REINTERPRET_CAST (UNICHAR *, NUX_CONST_CAST (wchar_t *, Source.c_str() ) ) ); } void NUTF8::Convert (const UNICHAR *Source) { int NumBytes = 0; // *6 each UTF16 char can translate to up to 6 bytes in UTF8 // +1 for NULL char size_t Size = wcslen ( (wchar_t *) Source) * 6 + 1; utf8 = new char[Size]; memset (utf8, 0, Size); unsigned char TwoBytes[2]; TwoBytes[0] = '\0'; TwoBytes[1] = '\0'; utf8[0] = '\0'; // U-00000000 U-0000007F: 0xxxxxxx // U-00000080 U-000007FF: 110xxxxx 10xxxxxx // U-00000800 U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx // U-00010000 U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // U-00200000 U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // U-04000000 U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // The original specification of UTF-8 allowed for sequences of up to six bytes covering numbers up to 31 bits // (the original limit of the universal character set). However, UTF-8 was restricted by RFC 3629 to use only // the area covered by the formal Unicode definition, U+0000 to U+10FFFF, in November 2003. So UTF-8 code point is at most 4 bytes. for (size_t n = 0; Source[n] != 0; n++) { if (Source[n] <= 0x7F) { TwoBytes[0] = (char) Source[n]; STRCAT_S (utf8, Size, (const char *) &TwoBytes[0]); } else { // 11 valid bits 2 bytes if (Source[n] <= 0x7FF) { // Extract the 5 highest bits TwoBytes[0] = (char) (0xC0 + (Source[n] >> 6) ); NumBytes = 2; } // 16 valid bits 3 bytes else if (Source[n] <= 0xFFFF) { // Extract the highest 4 bits TwoBytes[0] = (char) (0xE0 + (Source[n] >> 12) ); NumBytes = 3; } // Unichar is only 16 bits. Do no continue because (Source[n] >> 18) does not make sense. // 21 valid bits 4 bytes else if (Source[n] <= 0x1FFFFF) { // Extract the highest 3 bits TwoBytes[0] = (char) (0xF0 + (Source[n] >> 18) ); NumBytes = 4; } // Split a 26 bit character into 5 bytes else if (Source[n] <= 0x3FFFFFF) { // Extract the highest 2 bits TwoBytes[0] = (char) (0xF8 + (Source[n] >> 24) ); NumBytes = 5; } // Split a 31 bit character into 6 bytes else if (Source[n] <= 0x7FFFFFFF) { // Extract the highest bit TwoBytes[0] = (char) (0xFC + (Source[n] >> 30) ); NumBytes = 6; } STRCAT_S (utf8, Size, (const char *) &TwoBytes[0]); // Extract the remaining bits - 6 bits at a time for (int i = 1, shift = (NumBytes - 2) * 6; shift >= 0; i++, shift -= 6) { TwoBytes[0] = (char) (0x80 + ( (Source[n] >> shift) & 0x3F) ); STRCAT_S (utf8, Size, (const char *) &TwoBytes[0]); } } } } // void NUTF8::Convert(const t_UTF32* Source) // { // int NumBytes = 0; // // int Size = 0; // while(Source[Size] != 0) // { // ++Size; // } // // *6: each UTF16 char can translate to up to 6 bytes in UTF8 // // +1: for NULL char // Size = Size * 6 + 1; // utf8 = new char[Size*sizeof(t_UTF32)]; // memset(utf8, 0, Size*sizeof(t_UTF32)); // // unsigned char TwoBytes[2]; // TwoBytes[0] = '\0'; TwoBytes[1] = '\0'; // // utf8[0] = '\0'; // // // U-00000000 U-0000007F: 0xxxxxxx // // U-00000080 U-000007FF: 110xxxxx 10xxxxxx // // U-00000800 U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx // // U-00010000 U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // // U-00200000 U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // // U-04000000 U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // // The original specification of UTF-8 allowed for sequences of up to six bytes covering numbers up to 31 bits // // (the original limit of the universal character set). However, UTF-8 was restricted by RFC 3629 to use only // // the area covered by the formal Unicode definition, U+0000 to U+10FFFF, in November 2003. So UTF-8 code point is at most 4 bytes. // // for(size_t n = 0; Source[n] != 0; n++) // { // if (Source[n] <= 0x7F) // { // TwoBytes[0] = (char)Source[n]; // STRCAT_S(utf8, Size, (const char*)&TwoBytes[0]); // } // else // { // // 11 valid bits 2 bytes // if (Source[n] <= 0x7FF) // { // // Extract the 5 highest bits // TwoBytes[0] = (char)(0xC0 + (Source[n] >> 6)); // NumBytes = 2; // } // // 16 valid bits 3 bytes // else if (Source[n] <= 0xFFFF) // { // // Extract the highest 4 bits // TwoBytes[0] = (char)(0xE0 + (Source[n] >> 12)); // NumBytes = 3; // } // // 21 valid bits 4 bytes // else if (Source[n] <= 0x1FFFFF) // { // // Extract the highest 3 bits // TwoBytes[0] = (char)(0xF0 + (Source[n] >> 18)); // NumBytes = 4; // } // // Split a 26 bit character into 5 bytes // else if (Source[n] <= 0x3FFFFFF) // { // // Extract the highest 2 bits // TwoBytes[0] = (char)(0xF8 + (Source[n] >> 24)); // NumBytes = 5; // } // // Split a 31 bit character into 6 bytes // else if (Source[n] <= 0x7FFFFFFF) // { // // Extract the highest bit // TwoBytes[0] = (char)(0xFC + (Source[n] >> 30)); // NumBytes = 6; // } // // STRCAT_S(utf8, Size, (const char*)&TwoBytes[0]); // // // Extract the remaining bits - 6 bits at a time // for(int i = 1, shift = (NumBytes-2)*6; shift >= 0; i++, shift -= 6) // { // TwoBytes[0] = (char)(0x80 + ((Source[n] >> shift) & 0x3F)); // STRCAT_S(utf8, Size, (const char*)&TwoBytes[0]); // } // } // } // } NUTF8::~NUTF8() { delete [] utf8; } NUTF8::operator const char* () { return utf8; } /////////////////////////////////////////////////////////////////////////////// // Convert each unicode character in the source to UTF-8 NUTF16::NUTF16 (const char *Source) { Convert (Source); } NUTF16::NUTF16 (const std::string &Source) { Convert (Source.c_str() ); } void NUTF16::Convert (const char *Source) { // U-00000000 U-0000007F: 0xxxxxxx // U-00000080 U-000007FF: 110xxxxx 10xxxxxx // U-00000800 U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx // U-00010000 U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // U-00200000 U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx // U-04000000 U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx unsigned char MSB; int temp = 0; int numbytes = 0; // Number of bytes used to represent the unicode char int pos = 0; size_t len = strlen (Source) + 1; // +1 for NULL char unicode = new UNICHAR[len*6]; // Loop through the characters in the string and decode them for (size_t n = 0; n < len; ++n) { // Find the hexadecimal number following the equals sign MSB = Source[n]; if (MSB <= 0x7F) { unicode[pos++] = (UNICHAR) MSB; } else { // 2 bytes if (MSB >= 0xC0 && MSB <= 0xDF) { temp = (MSB - 0xC0) << 6; numbytes = 2; } // 3 bytes else if (MSB >= 0xE0 && MSB <= 0xEF) { temp = (MSB - 0xE0) << 12; numbytes = 3; } // 4 bytes else if (MSB >= 0xF0 && MSB <= 0xF7) { temp = (MSB - 0xF0) << 18; numbytes = 4; } // 5 bytes else if (MSB >= 0xF8 && MSB <= 0xFB) { temp = (MSB - 0xF8) << 24; numbytes = 5; } // 6 bytes else if (MSB >= 0xFC && MSB <= 0xFD) { temp = (MSB - 0xFC) << 30; numbytes = 6; } // Loop through the remaining hexadecimal numbers representing the next unicode character for (int i = 0, shift = (numbytes - 2) * 6; shift >= 0; i++, shift -= 6) { int nVal = ( ( (unsigned char) Source[n+1+i]) - 0x80 ) << shift; temp += nVal; } // Add the unicode character to the final string unicode[pos++] = (UNICHAR) temp; // Move the character index in the source to the next unicode character n += (numbytes - 1); } } } NUTF16::~NUTF16() { delete [] unicode; } NUTF16::operator const UNICHAR* () { return unicode; } } nux-4.0.8+18.10.20180623/NuxCore/Character/NUTF.h0000644000000000000000000000733213313373365015012 0ustar /* * Copyright 2010 Inalogic Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUTF_H #define NUTF_H // http://en.wikipedia.org/wiki/UTF-16 // In computing, UTF-16 (16-bit Unicode Transformation Format) is a variable-length character encoding // for Unicode, capable of encoding the entire Unicode repertoire. The encoding form maps code points // (characters) into a sequence of 16-bit words, called code units. For characters in the Basic // Multilingual Plane (BMP) the resulting encoding is a single 16-bit word. For characters in the other // planes, the encoding will result in a pair of 16-bit words, together called a surrogate pair. All possible // code points from U+0000 through U+10FFFF, except for the surrogate code points U+D800U+DFFF // (which are not characters), are uniquely mapped by UTF-16 regardless of the code point's current or // future character assignment or use. // // As many uses in computing require units of bytes (octets) there are three related encoding schemes // which map to octet sequences instead of words: namely UTF-16, UTF-16BE, and UTF-16LE. They // differ only in the byte order chosen to represent each 16-bit unit and whether they make use of a // Byte Order Mark. All of the schemes will result in either a 2 or 4-byte sequence for any given character. // // UTF-16 is officially defined in Annex Q of the international standard ISO/IEC 10646-1. It is also // described in The Unicode Standard version 3.0 and higher, as well as in the IETF's RFC 2781. // // UCS-2 (2-byte Universal Character Set) is an obsolete character encoding which is a predecessor // to UTF-16. The UCS-2 encoding form is nearly identical to that of UTF-16, except that it does not // support surrogate pairs and therefore can only encode characters in the BMP range U+0000 through // U+FFFF. As a consequence it is a fixed-length encoding that always encodes characters into a // single 16-bit value. As with UTF-16, there are three related encoding schemes (UCS-2, UCS-2BE, UCS-2LE) // that map characters to a specific byte sequence. // // Because of the technical similarities and upwards compatibility from UCS-2 to UTF-16, the two // encodings are often erroneously conflated and used as if interchangeable, so that strings encoded // in UTF-16 are sometimes misidentified as being encoded in UCS-2. namespace nux { //! Convert UTF-16 to UTF-8 class NUTF8 { // UTF-8 encoded characters may theoretically be up to six bytes long, however 16-bit BMP characters are only up to three bytes long. public: explicit NUTF8 (const UNICHAR *Source); explicit NUTF8 (const std::wstring &Source); ~NUTF8(); operator const char* (); private: void Convert (const UNICHAR *); //void Convert(const t_UTF32*); char *utf8; }; //! Convert UTF-8 to UTF-16 class NUTF16 { public: explicit NUTF16 (const char *Source); explicit NUTF16 (const std::string &Source); ~NUTF16(); operator const UNICHAR* (); private: void Convert (const char *); UNICHAR *unicode; }; } #endif // NUTF_H nux-4.0.8+18.10.20180623/NuxCore/Character/NUni.cpp0000644000000000000000000006246113313373365015446 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ /* * Copyright 2001-2004 Unicode, Inc. * * Disclaimer * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine * applicability of information provided. If this file has been * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. * * Limitations on Rights to Redistribute This Code * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. */ /* --------------------------------------------------------------------- Conversions between UTF32, UTF-16, and UTF-8. Source code file. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Sept 2001: fixed const & error conditions per mods suggested by S. Parent & A. Lillich. June 2002: Tim Dodd added detection and handling of incomplete source sequences, enhanced error detection, added casts to eliminate compiler warnings. July 2003: slight mods to back out aggressive FFFE detection. Jan 2004: updated switches in from-UTF8 conversions. Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. May 2006: updated isLegalUTF8Sequence. See the header file "ConvertUTF.h" for complete documentation. ------------------------------------------------------------------------ */ #include "NuxCore.h" //#include "NUni.h" namespace nux { static const int halfShift = 10; /* used for shifting by 10 bits */ static const unsigned int halfBase = 0x0010000UL; static const unsigned int halfMask = 0x3FFUL; #define UNI_SUR_HIGH_START (unsigned int)0xD800 #define UNI_SUR_HIGH_END (unsigned int)0xDBFF #define UNI_SUR_LOW_START (unsigned int)0xDC00 #define UNI_SUR_LOW_END (unsigned int)0xDFFF ConversionResult ConvertUTF32toUTF16 (const unsigned int **sourceStart, const unsigned int *sourceEnd, wchar_t **targetStart, wchar_t *targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const unsigned int *source = *sourceStart; wchar_t *target = *targetStart; while (source < sourceEnd) { unsigned int ch; if (target >= targetEnd) { result = targetExhausted; break; } ch = *source++; if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */ { /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = (wchar_t) ch; /* normal case */ } } else if (ch > UNI_MAX_LEGAL_UTF32) { if (flags == strictConversion) { result = sourceIllegal; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { /* target is a character in range 0xFFFF - 0x10FFFF. */ if (target + 1 >= targetEnd) { --source; /* Back up source pointer! */ result = targetExhausted; break; } ch -= halfBase; *target++ = (wchar_t) ( (ch >> halfShift) + UNI_SUR_HIGH_START); *target++ = (wchar_t) ( (ch & halfMask) + UNI_SUR_LOW_START); } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF32 (const wchar_t **sourceStart, const wchar_t *sourceEnd, unsigned int **targetStart, unsigned int *targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const wchar_t *source = *sourceStart; unsigned int *target = *targetStart; unsigned int ch, ch2; while (source < sourceEnd) { const wchar_t *oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { /* If the 16 bits following the high surrogate are in the source buffer... */ if (source < sourceEnd) { ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { ch = ( (ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; ++source; } else if (flags == strictConversion) /* it's an unpaired high surrogate */ { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } else /* We don't have the 16 bits following the high surrogate. */ { --source; /* return to the high surrogate */ result = sourceExhausted; break; } } else if (flags == strictConversion) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } if (target >= targetEnd) { source = oldSource; /* Back up source pointer! */ result = targetExhausted; break; } *target++ = ch; } *sourceStart = source; *targetStart = target; #ifdef CVTUTF_DEBUG if (result == sourceIllegal) { fprintf (stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); fflush (stderr); } #endif return result; } /* --------------------------------------------------------------------- */ /* * Index into the table below with the first byte of a UTF-8 sequence to * get the number of trailing bytes that are supposed to follow it. * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is * left as-is for anyone who may want to do such conversion, which was * allowed in earlier algorithms. */ static const char trailingBytesForUTF8[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 }; /* * Magic values subtracted from a buffer value during UTF8 conversion. * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ static const unsigned int offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; /* * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed * into the first byte, depending on how many bytes follow. There are * as many entries in this table as there are UTF-8 sequence types. * (I.e., one byte sequence, two byte... etc.). Remember that sequencs * for *legal* UTF-8 will be 4 or fewer bytes total. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; /* --------------------------------------------------------------------- */ /* The interface converts a whole buffer to avoid function-call overhead. * Constants have been gathered. Loops & conditionals have been removed as * much as possible for efficiency, in favor of drop-through switches. * (See "Note A" at the bottom of the file for equivalent code.) * If your compiler supports it, the "isLegalUTF8" call can be turned * into an inline function. */ /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF8 (const wchar_t **sourceStart, const wchar_t *sourceEnd, unsigned char **targetStart, unsigned char *targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const wchar_t *source = *sourceStart; unsigned char *target = *targetStart; while (source < sourceEnd) { unsigned int ch; unsigned short bytesToWrite = 0; const unsigned int byteMask = 0xBF; const unsigned int byteMark = 0x80; const wchar_t *oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { /* If the 16 bits following the high surrogate are in the source buffer... */ if (source < sourceEnd) { unsigned int ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { ch = ( (ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; ++source; } else if (flags == strictConversion) /* it's an unpaired high surrogate */ { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } else /* We don't have the 16 bits following the high surrogate. */ { --source; /* return to the high surrogate */ result = sourceExhausted; break; } } else if (flags == strictConversion) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } /* Figure out how many bytes the result will require */ if (ch < (unsigned int) 0x80) { bytesToWrite = 1; } else if (ch < (unsigned int) 0x800) { bytesToWrite = 2; } else if (ch < (unsigned int) 0x10000) { bytesToWrite = 3; } else if (ch < (unsigned int) 0x110000) { bytesToWrite = 4; } else { bytesToWrite = 3; ch = UNI_REPLACEMENT_CHAR; } target += bytesToWrite; if (target > targetEnd) { source = oldSource; /* Back up source pointer! */ target -= bytesToWrite; result = targetExhausted; break; } switch (bytesToWrite) /* note: everything falls through. */ { case 4: *--target = (unsigned char) ( (ch | byteMark) & byteMask); ch >>= 6; [[gnu::fallthrough]]; case 3: *--target = (unsigned char) ( (ch | byteMark) & byteMask); ch >>= 6; [[gnu::fallthrough]]; case 2: *--target = (unsigned char) ( (ch | byteMark) & byteMask); ch >>= 6; [[gnu::fallthrough]]; case 1: *--target = (unsigned char) (ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ /* * Utility routine to tell whether a sequence of bytes is legal UTF-8. * This must be called with the length pre-determined by the first byte. * If not calling this from ConvertUTF8to*, then the length can be set by: * length = trailingBytesForUTF8[*source]+1; * and the sequence is illegal right away if there aren't that many bytes * available. * If presented with a length > 4, this returns false. The Unicode * definition of UTF-8 goes up to 4-byte sequences. */ static bool isLegalUTF8 (const unsigned char *source, int length) { unsigned char a; const unsigned char *srcptr = source + length; switch (length) { default: return false; /* Everything else falls through when "true"... */ case 4: if ( (a = (*--srcptr) ) < 0x80 || a > 0xBF) return false; [[gnu::fallthrough]]; case 3: if ( (a = (*--srcptr) ) < 0x80 || a > 0xBF) return false; [[gnu::fallthrough]]; case 2: if ( (a = (*--srcptr) ) > 0xBF) return false; switch (*source) { /* no fall-through in this inner switch */ case 0xE0: if (a < 0xA0) return false; break; case 0xED: if ( (a < 0x80) || (a > 0x9F) ) return false; break; case 0xF0: if (a < 0x90) return false; break; case 0xF4: if (a > 0x8F) return false; break; default: if (a < 0x80) return false; } [[gnu::fallthrough]]; case 1: if (*source >= 0x80 && *source < 0xC2) return false; [[gnu::fallthrough]]; } if (*source > 0xF4) return false; return true; } /* --------------------------------------------------------------------- */ /* * Exported function to return whether a UTF-8 sequence is legal or not. * This is not used here; it's just exported. */ bool isLegalUTF8Sequence (const unsigned char *source, const unsigned char *sourceEnd) { int length; if (source == sourceEnd) { return true; } while (true) { length = trailingBytesForUTF8[*source] + 1; if (source + length > sourceEnd) { return false; } if (!isLegalUTF8 (source, length) ) { return false; } source += length; if (source >= sourceEnd) { return true; } } return true; } /** * This is a variation of isLegalUTF8Sequence() that behaves like g_utf8_validate(). * In addition to knowing if the sequence is legal, it also tells you the last good character. */ bool tr_utf8_validate ( const char *str, int max_len, const char **end ) { const unsigned char *source = (const unsigned char *) str; const unsigned char *sourceEnd; if ( max_len == 0 ) return true; if ( str == NULL ) return false; sourceEnd = source + ( (max_len < 0) ? strlen (str) : (size_t) max_len); if ( source == sourceEnd ) { if ( end != NULL ) *end = (const char *) source; return true; } for ( ;; ) { const int length = trailingBytesForUTF8[*source] + 1; if (source + length > sourceEnd) { if ( end != NULL ) *end = (const char *) source; return false; } if (!isLegalUTF8 (source, length) ) { if ( end != NULL ) *end = (const char *) source; return false; } source += length; if (source >= sourceEnd) { if ( end != NULL ) *end = (const char *) source; return true; } } return true; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF16 (const unsigned char **sourceStart, const unsigned char *sourceEnd, wchar_t **targetStart, wchar_t *targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const unsigned char *source = *sourceStart; wchar_t *target = *targetStart; while (source < sourceEnd) { unsigned int ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { result = sourceExhausted; break; } /* Do this check whether lenient or strict */ if (! isLegalUTF8 (source, extraBytesToRead + 1) ) { result = sourceIllegal; break; } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ [[gnu::fallthrough]]; case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ [[gnu::fallthrough]]; case 3: ch += *source++; ch <<= 6; [[gnu::fallthrough]]; case 2: ch += *source++; ch <<= 6; [[gnu::fallthrough]]; case 1: ch += *source++; ch <<= 6; [[gnu::fallthrough]]; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { source -= (extraBytesToRead + 1); /* Back up source pointer! */ result = targetExhausted; break; } if (ch <= UNI_MAX_BMP) /* Target is a character <= 0xFFFF */ { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { source -= (extraBytesToRead + 1); /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = (wchar_t) ch; /* normal case */ } } else if (ch > UNI_MAX_UTF16) { if (flags == strictConversion) { result = sourceIllegal; source -= (extraBytesToRead + 1); /* return to the start */ break; /* Bail out; shouldn't continue */ } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { /* target is a character in range 0xFFFF - 0x10FFFF. */ if (target + 1 >= targetEnd) { source -= (extraBytesToRead + 1); /* Back up source pointer! */ result = targetExhausted; break; } ch -= halfBase; *target++ = (wchar_t) ( (ch >> halfShift) + UNI_SUR_HIGH_START); *target++ = (wchar_t) ( (ch & halfMask) + UNI_SUR_LOW_START); } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF8 ( const unsigned int **sourceStart, const unsigned int *sourceEnd, unsigned char **targetStart, unsigned char *targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const unsigned int *source = *sourceStart; unsigned char *target = *targetStart; while (source < sourceEnd) { unsigned int ch; unsigned short bytesToWrite = 0; const unsigned int byteMask = 0xBF; const unsigned int byteMark = 0x80; ch = *source++; if (flags == strictConversion ) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; } } /* * Figure out how many bytes the result will require. Turn any * illegally large UTF32 things (> Plane 17) into replacement chars. */ if (ch < (unsigned int) 0x80) { bytesToWrite = 1; } else if (ch < (unsigned int) 0x800) { bytesToWrite = 2; } else if (ch < (unsigned int) 0x10000) { bytesToWrite = 3; } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; } else { bytesToWrite = 3; ch = UNI_REPLACEMENT_CHAR; result = sourceIllegal; } target += bytesToWrite; if (target > targetEnd) { --source; /* Back up source pointer! */ target -= bytesToWrite; result = targetExhausted; break; } switch (bytesToWrite) /* note: everything falls through. */ { case 4: *--target = (unsigned char) ( (ch | byteMark) & byteMask); ch >>= 6; [[gnu::fallthrough]]; case 3: *--target = (unsigned char) ( (ch | byteMark) & byteMask); ch >>= 6; [[gnu::fallthrough]]; case 2: *--target = (unsigned char) ( (ch | byteMark) & byteMask); ch >>= 6; [[gnu::fallthrough]]; case 1: *--target = (unsigned char) (ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF32 ( const unsigned char **sourceStart, const unsigned char *sourceEnd, unsigned int **targetStart, unsigned int *targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const unsigned char *source = *sourceStart; unsigned int *target = *targetStart; while (source < sourceEnd) { unsigned int ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { result = sourceExhausted; break; } /* Do this check whether lenient or strict */ if (! isLegalUTF8 (source, extraBytesToRead + 1) ) { result = sourceIllegal; break; } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { case 5: ch += *source++; ch <<= 6; [[gnu::fallthrough]]; case 4: ch += *source++; ch <<= 6; [[gnu::fallthrough]]; case 3: ch += *source++; ch <<= 6; [[gnu::fallthrough]]; case 2: ch += *source++; ch <<= 6; [[gnu::fallthrough]]; case 1: ch += *source++; ch <<= 6; [[gnu::fallthrough]]; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { source -= (extraBytesToRead + 1); /* Back up the source pointer! */ result = targetExhausted; break; } if (ch <= UNI_MAX_LEGAL_UTF32) { /* * UTF-16 surrogate values are illegal in UTF-32, and anything * over Plane 17 (> 0x10FFFF) is illegal. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { source -= (extraBytesToRead + 1); /* return to the illegal value itself */ result = sourceIllegal; break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = ch; } } else /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ { result = sourceIllegal; *target++ = UNI_REPLACEMENT_CHAR; } } *sourceStart = source; *targetStart = target; return result; } /* --------------------------------------------------------------------- Note A. The fall-through switches in UTF-8 reading code save a temp variable, some decrements & conditionals. The switches are equivalent to the following loop: { int tmpBytesToRead = extraBytesToRead+1; do { ch += *source++; --tmpBytesToRead; if (tmpBytesToRead) ch <<= 6; [[gnu::fallthrough]]; } while (tmpBytesToRead > 0); } In UTF-8 writing code, the switches on "bytesToWrite" are similarly unrolled loops. --------------------------------------------------------------------- */ } nux-4.0.8+18.10.20180623/NuxCore/Character/NUni.h0000644000000000000000000001602013313373365015101 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUNI_H #define NUNI_H /* * Copyright 2001-2004 Unicode, Inc. * * Disclaimer * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine * applicability of information provided. If this file has been * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. * * Limitations on Rights to Redistribute This Code * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. */ /* --------------------------------------------------------------------- Conversions between UTF32, UTF-16, and UTF-8. Header file. Several funtions are included here, forming a complete set of conversions between the three formats. UTF-7 is not included here, but is handled in a separate source file. Each of these routines takes pointers to input buffers and output buffers. The input buffers are const. Each routine converts the text between *sourceStart and sourceEnd, putting the result into the buffer between *targetStart and targetEnd. Note: the end pointers are *after* the last item: e.g. *(sourceEnd - 1) is the last item. The return result indicates whether the conversion was successful, and if not, whether the problem was in the source or target buffers. (Only the first encountered problem is indicated.) After the conversion, *sourceStart and *targetStart are both updated to point to the end of last text successfully converted in the respective buffers. Input parameters: sourceStart - pointer to a pointer to the source buffer. The contents of this are modified on return so that it points at the next thing to be converted. targetStart - similarly, pointer to pointer to the target buffer. sourceEnd, targetEnd - respectively pointers to the ends of the two buffers, for overflow checking only. These conversion functions take a ConversionFlags argument. When this flag is set to strict, both irregular sequences and isolated surrogates will cause an error. When the flag is set to lenient, both irregular sequences and isolated surrogates are converted. Whether the flag is strict or lenient, all illegal sequences will cause an error return. This includes sequences such as: , , or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code must check for illegal sequences. When the flag is set to lenient, characters over 0x10FFFF are converted to the replacement character; otherwise (when the flag is set to strict) they constitute an error. Output parameters: The value "sourceIllegal" is returned from some routines if the input sequence is malformed. When "sourceIllegal" is returned, the source value will point to the illegal value that caused the problem. E.g., in UTF-8 when a sequence is malformed, it points to the start of the malformed sequence. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Fixes & updates, Sept 2001. ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- The following 4 definitions are compiler-specific. The C standard does not guarantee that wchar_t has at least 16 bits, so wchar_t is no less portable than unsigned short! All should be unsigned values to avoid sign extension during bit mask & shift operations. ------------------------------------------------------------------------ */ //typedef unsigned long unsigned int; /* at least 32 bits */ //typedef unsigned short wchar_t; /* at least 16 bits */ //typedef unsigned char unsigned char; /* typically 8 bits */ //typedef unsigned char Boolean; /* 0 or 1 */ namespace nux { /* Some fundamental constants */ #define UNI_REPLACEMENT_CHAR (unsigned int)0x0000FFFD #define UNI_MAX_BMP (unsigned int)0x0000FFFF #define UNI_MAX_UTF16 (unsigned int)0x0010FFFF #define UNI_MAX_UTF32 (unsigned int)0x7FFFFFFF #define UNI_MAX_LEGAL_UTF32 (unsigned int)0x0010FFFF typedef enum { conversionOK = 0, /* conversion successful */ sourceExhausted, /* partial character in source, but hit end */ targetExhausted, /* insuff. room in target for conversion */ sourceIllegal /* source sequence is illegal/malformed */ } ConversionResult; typedef enum { strictConversion = 0, lenientConversion } ConversionFlags; ConversionResult ConvertUTF8toUTF16 ( const unsigned char **sourceStart, const unsigned char *sourceEnd, wchar_t **targetStart, wchar_t *targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF8 ( const wchar_t **sourceStart, const wchar_t *sourceEnd, unsigned char **targetStart, unsigned char *targetEnd, ConversionFlags flags); ConversionResult ConvertUTF8toUTF32 ( const unsigned char **sourceStart, const unsigned char *sourceEnd, unsigned int **targetStart, unsigned int *targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF8 ( const unsigned int **sourceStart, const unsigned int *sourceEnd, unsigned char **targetStart, unsigned char *targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF32 ( const wchar_t **sourceStart, const wchar_t *sourceEnd, unsigned int **targetStart, unsigned int *targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF16 ( const unsigned int **sourceStart, const unsigned int *sourceEnd, wchar_t **targetStart, wchar_t *targetEnd, ConversionFlags flags); bool isLegalUTF8Sequence (const unsigned char *source, const unsigned char *sourceEnd); /* intended to work the same as g_utf8_validate */ bool tr_utf8_validate ( const char *str, int max_len, const char **end ); } #endif /* NUNI_H */ nux-4.0.8+18.10.20180623/NuxCore/Character/NUnicode.cpp0000644000000000000000000000466413313373365016302 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "NUnicode.h" namespace nux { ANSICHAR *UnicharToAnsicharConvertion::Convert (const UNICHAR *Source) { std::wstring utf16string (Source); size_t utf16size = utf16string.length(); size_t utf8size = 6 * utf16size; ANSICHAR *utf8string = new ANSICHAR[utf8size+1]; const wchar_t *source_start = utf16string.c_str(); const wchar_t *source_end = source_start + utf16size; unsigned char *target_start = reinterpret_cast (utf8string); unsigned char *target_end = target_start + utf8size; ConversionResult res = ConvertUTF16toUTF8 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { delete [] utf8string; utf8string = 0; } // mark end of string *target_start = 0; return utf8string; } UNICHAR *AnsicharToUnicharConvertion::Convert (const ANSICHAR *Source) { std::string utf8string (Source); size_t utf8size = utf8string.length(); size_t utf16size = utf8size; UNICHAR *utf16string = new UNICHAR[utf16size+1]; const unsigned char *source_start = reinterpret_cast (utf8string.c_str() ); const unsigned char *source_end = source_start + utf8size; wchar_t *target_start = reinterpret_cast (utf16string); wchar_t *target_end = target_start + utf16size; ConversionResult res = ConvertUTF8toUTF16 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { delete[] utf16string; utf16string = 0; } // mark end of string *target_start = 0; return utf16string; } } nux-4.0.8+18.10.20180623/NuxCore/Character/NUnicode.h0000644000000000000000000002474613313373365015752 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUNICODE_H #define NUNICODE_H namespace nux { // UTF-16 is the primary encoding mechanism used by Microsoft Windows 2000, Windows 2000 Server, Windows XP and Windows 2003 Server. // Unicode Byte Order Mark (BOM) enum {UNICODE_UTF32_BE = 0x0000FEFF }; enum {UNICODE_UTF32_LE = 0xFFFE0000 }; enum {UNICODE_UTF16_BE = 0xFEFF }; enum {UNICODE_UTF16_LE = 0xFFFE }; enum {UNICODE_UTF8 = 0xEFBBBF }; const BYTE UTF32_BE[] = {0x04 /*size*/, 0x00, 0x00, 0xFE, 0xFF }; const BYTE UTF32_LE[] = {0x04 /*size*/, 0xFF, 0xFE, 0x00, 0x00 }; const BYTE UTF16_BE[] = {0x02 /*size*/, 0xFE, 0xFF }; const BYTE UTF16_LE[] = {0x02 /*size*/, 0xFF, 0xFE }; const BYTE UTF8[] = {0x03 /*size*/, 0xEF, 0xBB, 0xBF }; enum {UNICODE_BOM = 0xfeff}; // UTF-16 is the default encoding form of the Unicode Standard // On Linux and Mac OS X, wchar_t is 4 bytes! // On windows wchar_t is 2 bytes! #ifdef UNICODE inline TCHAR ConvertAnsiCharToTCHAR (ANSICHAR In) { TCHAR output; const unsigned char *source_start = &In; const unsigned char *source_end = source_start + 1; wchar_t *target_start = reinterpret_cast (&output); wchar_t *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF8toUTF16 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } inline ANSICHAR ConvertTCHARToAnsiChar (TCHAR In) { ANSICHAR output; const wchar_t *source_start = &In; const wchar_t *source_end = source_start + 1; unsigned char *target_start = reinterpret_cast (&output); unsigned char *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF16toUTF8 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } inline TCHAR ConvertUnicodeCharToTCHAR (UNICHAR In) { return In; } inline UNICHAR ConvertTCHARToUnicodeChar (TCHAR In) { return In; } #else inline TCHAR ConvertUnicodeCharToTCHAR (UNICHAR In) { TCHAR output; const wchar_t *source_start = &In; const wchar_t *source_end = source_start + 1; unsigned char *target_start = reinterpret_cast (&output); unsigned char *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF16toUTF8 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } inline UNICHAR ConvertTCHARToUnicodeChar (TCHAR In) { UNICHAR output; const unsigned char *source_start = reinterpret_cast (&In); const unsigned char *source_end = source_start + 1; wchar_t *target_start = reinterpret_cast (&output); wchar_t *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF8toUTF16 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } inline TCHAR ConvertAnsiCharToTCHAR (ANSICHAR In) { return In; } inline ANSICHAR ConvertTCHARToAnsiChar (TCHAR In) { return In; } #endif /*! Convert a single UNICHAR to ANSICHAR. */ inline ANSICHAR ConvertUnicodeCharToAnsiChar (UNICHAR In) { TCHAR output; const wchar_t *source_start = &In; const wchar_t *source_end = source_start + 1; unsigned char *target_start = reinterpret_cast (&output); unsigned char *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF16toUTF8 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } /*! Convert a single ANSICHAR to UNICHAR. */ inline UNICHAR ConvertAnsiCharToUnicodeChar (ANSICHAR In) { UNICHAR output; const unsigned char *source_start = reinterpret_cast (&In); const unsigned char *source_end = source_start + 1; wchar_t *target_start = reinterpret_cast (&output); wchar_t *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF8toUTF16 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } class UnicharToAnsicharConvertion { public: // Default to ANSI code page UnicharToAnsicharConvertion() {} /*! Convert from UNICHAR to ANSICHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ ANSICHAR *Convert (const UNICHAR *Source); /*{ std::wstring utf16string(Source); size_t utf16size = utf16string.length(); size_t utf8size = 6 * utf16size; ANSICHAR *utf8string = new ANSICHAR[utf8size+1]; const wchar_t *source_start = utf16string.c_str(); const wchar_t *source_end = source_start + utf16size; unsigned char* target_start = reinterpret_cast(utf8string); unsigned char* target_end = target_start + utf8size; ConversionResult res = ConvertUTF16toUTF8(&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { delete utf8string; utf8string = 0; } // mark end of string *target_start = 0; return utf8string; }*/ }; //! ANSICHAR to UNICHAR conversion class AnsicharToUnicharConvertion { public: AnsicharToUnicharConvertion() {} /*! Convert from ANSICHAR to UNICHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ UNICHAR *Convert (const ANSICHAR *Source); }; //! TCHAR to ANSI conversion // TCHAR can be ansi or unicode depending if UNICODE is defined or not. class TCharToAnsiConvertion { public: NUX_INLINE TCharToAnsiConvertion() {} /*! Convert from TCHAR to ANSICHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ NUX_INLINE ANSICHAR *Convert (const TCHAR *Source) { // Determine whether we need to allocate memory or not #ifdef UNICODE UnicharToAnsicharConvertion convert; return convert.Convert (Source); #else size_t length = strlen (Source) + 1; size_t size = length * sizeof (ANSICHAR); ANSICHAR *Dest = new ANSICHAR[size]; STRNCPY_S (Dest, size, Source, length); return Dest; #endif } }; //! TCHAR to Unichar conversion // TCHAR can be ansi or unicode depending if UNICODE is defined or not. class TCharToUnicharConvertion { public: NUX_INLINE TCharToUnicharConvertion() {} /*! Convert from TCHAR to ANSICHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ NUX_INLINE UNICHAR *Convert (const TCHAR *Source) { // Determine whether we need to allocate memory or not #ifdef UNICODE size_t length = strlen (Source) + 1; size_t size = length * sizeof (UNICHAR); UNICHAR *Dest = new UNICHAR[size]; STRNCPY_S (Dest, size, Source, length); return Dest; #else AnsicharToUnicharConvertion convert; return convert.Convert (Source); #endif } }; //! ANSI to TCHAR conversion // TCHAR can be ansi or unicode depending if UNICODE is defined or not. class AnsiToTCharConversion { public: NUX_INLINE AnsiToTCharConversion() {} /*! Convert from ANSICHAR to TCHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ NUX_INLINE TCHAR *Convert (const ANSICHAR *Source) { #ifdef UNICODE AnsicharToUnicharConvertion convert; return convert.Convert (Source); #else size_t length = strlen (Source) + 1; size_t size = length; TCHAR *Dest = new TCHAR[size]; STRNCPY_S (Dest, size, Source, length); return Dest; #endif } }; /*! Convert from one string format to another. */ template < typename CONVERT_TO, typename CONVERT_FROM, typename BASE_CONVERTER, DWORD DefaultConversionSize = 128 > class NCharacterConversion: public BASE_CONVERTER { CONVERT_TO *ConvertedString; // Hide the default constructor NCharacterConversion(); public: /*! Converts the data by using the Convert() method on the base class */ explicit inline NCharacterConversion (const CONVERT_FROM *Source) { if (Source != NULL) { // Use base class' convert method ConvertedString = BASE_CONVERTER::Convert (Source); } else { ConvertedString = NULL; } } /*! If memory was allocated, then it is freed below */ inline ~NCharacterConversion() { if (ConvertedString != NULL) { delete [] ConvertedString; } } // Operator to get access to the converted string inline operator CONVERT_TO* (void) const { return ConvertedString; } }; // Conversion typedefs // typedef NCharacterConversion ANSI_To_TCHAR_Conversion; // typedef NCharacterConversion TCHAR_To_ANSI_Conversion; // typedef NCharacterConversion UNICHAR_To_ANSICHAR_Conversion; // typedef NCharacterConversion ANSICHAR_To_UNICHAR_Conversion; } #endif // NUNICODE_H nux-4.0.8+18.10.20180623/NuxCore/Character/NUnicodeGNU.cpp0000644000000000000000000000153713313373365016650 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "NUnicodeGNU.h" namespace nux { } nux-4.0.8+18.10.20180623/NuxCore/Character/NUnicodeGNU.h0000644000000000000000000002445013313373365016314 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUNICODEGNU_H #define NUNICODEGNU_H namespace nux { // UTF-16 is the primary encoding mechanism used by Microsoft Windows 2000, Windows 2000 Server, Windows XP and Windows 2003 Server. // Unicode Byte Order Mark (BOM) enum {UNICODE_UTF32_BE = 0x0000FEFF }; enum {UNICODE_UTF32_LE = 0xFFFE0000 }; enum {UNICODE_UTF16_BE = 0xFEFF }; enum {UNICODE_UTF16_LE = 0xFFFE }; enum {UNICODE_UTF8 = 0xEFBBBF }; const BYTE UTF32_BE[] = {0x04 /*size*/, 0x00, 0x00, 0xFE, 0xFF }; const BYTE UTF32_LE[] = {0x04 /*size*/, 0xFF, 0xFE, 0x00, 0x00 }; const BYTE UTF16_BE[] = {0x02 /*size*/, 0xFE, 0xFF }; const BYTE UTF16_LE[] = {0x02 /*size*/, 0xFF, 0xFE }; const BYTE UTF8[] = {0x03 /*size*/, 0xEF, 0xBB, 0xBF }; enum {UNICODE_BOM = 0xfeff}; // UTF-16 is the default encoding form of the Unicode Standard // On Linux and Mac OS X, wchar_t is 4 bytes! // On windows wchar_t is 2 bytes! #ifdef UNICODE inline TCHAR ConvertAnsiCharToTCHAR (ANSICHAR In) { TCHAR output; const t_UTF8 *source_start = &In; const t_UTF8 *source_end = source_start + 1; t_UTF16 *target_start = reinterpret_cast (&output); t_UTF16 *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF8toUTF16 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } inline ANSICHAR ConvertTCHARToAnsiChar (TCHAR In) { ANSICHAR output; const t_UTF16 *source_start = &In; const t_UTF16 *source_end = source_start + 1; t_UTF8 *target_start = reinterpret_cast (&output); t_UTF8 *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF16toUTF8 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } inline TCHAR ConvertUnicodeCharToTCHAR (UNICHAR In) { return In; } inline UNICHAR ConvertTCHARToUnicodeChar (TCHAR In) { return In; } #else inline TCHAR ConvertUnicodeCharToTCHAR (UNICHAR In) { TCHAR output; const t_UTF16 *source_start = &In; const t_UTF16 *source_end = source_start + 1; t_UTF8 *target_start = reinterpret_cast (&output); t_UTF8 *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF16toUTF8 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } inline UNICHAR ConvertTCHARToUnicodeChar (TCHAR In) { UNICHAR output; const t_UTF8 *source_start = reinterpret_cast (&In); const t_UTF8 *source_end = source_start + 1; t_UTF16 *target_start = reinterpret_cast (&output); t_UTF16 *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF8toUTF16 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } inline TCHAR ConvertAnsiCharToTCHAR (ANSICHAR In) { return In; } inline ANSICHAR ConvertTCHARToAnsiChar (TCHAR In) { return In; } #endif /*! Convert a single UNICHAR to ANSICHAR. */ inline ANSICHAR ConvertUnicodeCharToAnsiChar (UNICHAR In) { TCHAR output; const t_UTF16 *source_start = &In; const t_UTF16 *source_end = source_start + 1; t_UTF8 *target_start = reinterpret_cast (&output); t_UTF8 *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF16toUTF8 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } /*! Convert a single ANSICHAR to UNICHAR. */ inline UNICHAR ConvertAnsiCharToUnicodeChar (ANSICHAR In) { TCHAR output; const t_UTF8 *source_start = reinterpret_cast (&In); const t_UTF8 *source_end = source_start + 1; t_UTF16 *target_start = reinterpret_cast (&output); t_UTF16 *target_end = target_start + sizeof (wchar_t); ConversionResult res = ConvertUTF8toUTF16 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { output = 0; } return output; } class UnicharToAnsicharConvertion { public: // Default to ANSI code page UnicharToAnsicharConvertion() {} /*! Convert from UNICHAR to ANSICHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ ANSICHAR *Convert (const UNICHAR *Source) { std::wstring utf16string (Source); size_t utf16size = utf16string.length(); size_t utf8size = 6 * utf16size + 1; ANSICHAR *utf8string = new ANSICHAR[utf8size]; const t_UTF16 *source_start = utf16string.c_str(); const t_UTF16 *source_end = source_start + utf16size; t_UTF8 *target_start = reinterpret_cast (&utf8string); t_UTF8 *target_end = target_start + utf8size; ConversionResult res = ConvertUTF16toUTF8 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { delete [] utf8string; utf8string = 0; } // mark end of string *target_start = 0; return utf8string; } }; //! ANSICHAR to UNICHAR conversion class AnsicharToUnicharConvertion { public: NUX_INLINE AnsicharToUnicharConvertion() {} /*! Convert from ANSICHAR to UNICHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ NUX_INLINE UNICHAR *Convert (const ANSICHAR *Source) { std::string utf8string (Source); size_t utf8size = utf8string.length(); size_t utf16size = utf8size + 1; UNICHAR *utf16string = new UNICHAR[utf16size]; const t_UTF8 *source_start = reinterpret_cast (utf8string.c_str() ); const t_UTF8 *source_end = source_start + utf8size; t_UTF16 *target_start = reinterpret_cast (&utf16string); t_UTF16 *target_end = target_start + utf16size; ConversionResult res = ConvertUTF8toUTF16 (&source_start, source_end, &target_start, target_end, lenientConversion); if (res != conversionOK) { delete [] utf16string; utf16string = 0; } // mark end of string *target_start = 0; return utf16string; } }; //! TCHAR to ANSI conversion // TCHAR can be ansi or unicode depending if UNICODE is defined or not. class TCharToAnsiConvertion { public: NUX_INLINE TCharToAnsiConvertion() {} /*! Convert from TCHAR to ANSICHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ NUX_INLINE ANSICHAR *Convert (const TCHAR *Source) { // Determine whether we need to allocate memory or not #ifdef UNICODE UnicharToAnsicharConvertion convert; return convert.Convert (Source); #else int length = strlen (Source) + 1; int size = length * sizeof (ANSICHAR); ANSICHAR *Dest = new ANSICHAR[size]; STRNCPY_S (Dest, size, Source, length); return Dest; #endif } }; //! ANSI to TCHAR conversion // TCHAR can be ansi or unicode depending if UNICODE is defined or not. class AnsiToTCharConversion { public: NUX_INLINE AnsiToTCharConversion() {} /*! Convert from ANSICHAR to TCHAR @param Source String to convert. Null terminated. @return Return a pointer to the new string. Null terminated. */ NUX_INLINE TCHAR *Convert (const ANSICHAR *Source) { #ifdef UNICODE AnsicharToUnicharConvertion convert; return convert.Convert (Source); #else unsigned int length = strlen (Source) + 1; unsigned int size = length; TCHAR *Dest = new TCHAR[size]; STRNCPY_S (Dest, size, Source, length); return Dest; #endif } }; /*! Convert from one string format to another. */ template < typename CONVERT_TO, typename CONVERT_FROM, typename BASE_CONVERTER, DWORD DefaultConversionSize = 128 > class NCharacterConversion: public BASE_CONVERTER { CONVERT_TO *ConvertedString; // Hide the default constructor NCharacterConversion(); public: /*! Converts the data by using the Convert() method on the base class */ explicit inline NCharacterConversion (const CONVERT_FROM *Source) { if (Source != NULL) { // Use base class' convert method ConvertedString = BASE_CONVERTER::Convert (Source); } else { ConvertedString = NULL; } } /*! If memory was allocated, then it is freed below */ inline ~NCharacterConversion() { if (ConvertedString != NULL) { delete [] ConvertedString; } } // Operator to get access to the converted string inline operator CONVERT_TO* (void) const { return ConvertedString; } }; // Conversion typedefs typedef NCharacterConversion ANSI_To_TCHAR_Conversion; typedef NCharacterConversion TCHAR_To_ANSI_Conversion; typedef NCharacterConversion UNICHAR_To_ANSICHAR_Conversion; typedef NCharacterConversion ANSICHAR_To_UNICHAR_Conversion; } #endif // NUNICODEGNU_H nux-4.0.8+18.10.20180623/NuxCore/Color.cpp0000644000000000000000000002627313313373365013760 0ustar /* * Copyright 2010-2012 Inalogic Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Color.h" #include "ColorPrivate.h" #include #include #include #define NUX_RGBA_GET_ALPHA(rgba) ((rgba) >> 24) #define NUX_RGBA_GET_RED(rgba) (((rgba) >> 16) & 0xff) #define NUX_RGBA_GET_GREEN(rgba) (((rgba) >> 8) & 0xff) #define NUX_RGBA_GET_BLUE(rgba) ((rgba) & 0xff) namespace nux { namespace color { Color::Color() : red(0.0f) , green(0.0f) , blue(0.0f) , alpha(1.0f) , premultiplied_(false) {} Color::Color(RedGreenBlue const& rgb, float a) : red(rgb.red) , green(rgb.green) , blue(rgb.blue) , alpha(a) , premultiplied_(false) {} Color::Color (unsigned int c) : red(NUX_RGBA_GET_RED(c) / 255.0f) , green(NUX_RGBA_GET_GREEN(c) / 255.0f) , blue(NUX_RGBA_GET_BLUE(c) / 255.0f) , alpha(NUX_RGBA_GET_ALPHA(c) / 255.0f) , premultiplied_(false) {} Color::Color(int r, int g, int b) : red(r / 255.0f) , green(g / 255.0f) , blue(b / 255.0f) , alpha(1.0f) , premultiplied_(false) {} Color::Color(float r, float g, float b, float a) : red(r) , green(g) , blue(b) , alpha(a) , premultiplied_(false) {} Color::Color(std::string const& hex) : red(0.0f) , green(0.0f) , blue(0.0f) , alpha(1.0f) , premultiplied_(false) { HexToRGBA(hex, red, green, blue, alpha); } Color Color::GetPremultiplied() { if (premultiplied_) { // Already pre-multiplied. Return *this; return *this; } Color c; c.SetPremultiplied(red, green, blue, alpha); return c; } void Color::SetPremultiplied(float r, float g, float b, float a) { red = r * a; green = g * a; blue = b * a; alpha = a; premultiplied_ = true; } bool Color::IsPremultiplied() { return premultiplied_; } bool operator == (const Color& lhs, const Color& rhs) { return (lhs.red == rhs.red && lhs.green == rhs.green && lhs.blue == rhs.blue && lhs.alpha == rhs.alpha && lhs.premultiplied_ == rhs.premultiplied_); } bool operator != (const Color& lhs, const Color& rhs) { return !(lhs == rhs); } Color RandomColor() { return Color(RandomColorINT()); } unsigned int RandomColorINT() { // std::rand isn't defined to be more random than 2^15, so we need // to generate the full unsigned in chunks. // MSB is alpha, which is set to 255. The next three bytes are // red, green, blue. return (0xff << 24) | ((std::rand() & 0xff) << 16) | ((std::rand() & 0xff) << 8) | (std::rand() & 0xff); } Color operator + (Color const& lhs, Color const& rhs) { return Color(lhs.red + rhs.red, lhs.green + rhs.green, lhs.blue + rhs.blue, lhs.alpha + rhs.alpha); } Color operator - (Color const& lhs, Color const& rhs) { return Color(lhs.red - rhs.red, lhs.green - rhs.green, lhs.blue - rhs.blue, lhs.alpha - rhs.alpha); } Color operator + (float scalar, Color const& c) { return Color(c.red + scalar, c.green + scalar, c.blue + scalar, c.alpha + scalar); } Color operator + (Color const& c, float scalar) { return scalar + c; } Color operator - (float scalar, Color const& c) { return Color(scalar - c.red, scalar - c.green, scalar - c.blue, scalar - c.alpha); } Color operator - (Color const& c, float scalar) { return Color(c.red - scalar, c.green - scalar, c.blue - scalar, c.alpha - scalar); } Color operator * (float scalar, Color const& c) { return Color(c.red * scalar, c.green * scalar, c.blue * scalar, c.alpha * scalar); } Color operator * (Color const& c, float scalar) { return scalar * c; } // The Hue/Saturation/Value model was created by A. R. Smith in 1978. It is // based on such intuitive color characteristics as tint, shade and tone (or // family, purety and intensity). The coordinate system is cylindrical, and // the colors are defined inside a hexcone. The hue value H runs from 0 to // 360. The saturation S is the degree of strength or purity and is from 0 to // 1. Purity is how much white is added to the color, so S=1 makes the purest // color (no white). Brightness V also ranges from 0 to 1, where 0 is the // black. There is no transformation matrix for RGB/HSV conversion, but the // algorithm follows: // r,g,b values are from 0 to 1 // h = [0,360], s = [0,1], v = [0,1] // if s == 0, then h = -1 (undefined) void RGBtoHSV(float r, float g, float b, float& h, float& s, float& v) { float mini, maxi, delta; mini = std::min(std::min(r, g), b); maxi = std::max(std::max(r, g), b); v = maxi; delta = maxi - mini; if (maxi != 0) { s = delta / maxi; } else { // MAX = 0 (i.e. if v = 0), then s is undefined. r = g = b = 0 s = 0; h = -1; return; } if (delta == 0) // MAX = MIN (i.e. s = 0), then h is undefined. r = g = b { h = 0; s = 0; return; } if (r == maxi) h = (g - b) / delta; // between yellow & magenta else if (g == maxi) h = 2 + (b - r) / delta; // between cyan & yellow else h = 4 + (r - g) / delta; // between magenta & cyan h *= 60; // degrees if (h < 0) h += 360; // convert h from [0, 360] to [0, 1] h = h / 360.0f; } void HSVtoRGB(float& r, float& g, float& b, float h, float s, float v ) { int i; float f, p, q, t; // convert h from [0, 1] to [0, 360] h = h * 360.0f; if (s == 0) { // achromatic (grey) r = g = b = v; return; } h /= 60.0f; // sector 0 to 5 i = (int) std::floor(h); f = h - i; // factorial part of h p = v * (1 - s); q = v * (1 - s * f); t = v * (1 - s * (1 - f)); switch ( i ) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; default: // case 5: r = v; g = p; b = q; break; } } ///////////////////////// // HLS-RGB Conversions // ///////////////////////// // Static function. Auxiliary to HLS2RGB(). static float HLStoRGB_(float rn1, float rn2, float huei) { float hue = huei; if (hue > 360.0f) hue = hue - 360.0f; if (hue < 0.0f) hue = hue + 360.0f; if (hue < 60.0f ) return rn1 + (rn2 - rn1) * hue / 60.0f; if (hue < 180.0f) return rn2; if (hue < 240.0f) return rn1 + (rn2 - rn1) * (240.0f - hue) / 60.0f; return rn1; } void HLStoRGB(float& r, float& g, float& b, float hue, float light, float satur) { // Static method to compute RGB from HLS. The l and s are between [0,1] // and h is between [0, 1]. The returned r,g,b triplet is between [0,1]. hue *= 360.0f; float rh, rl, rs, rm1, rm2; rh = rl = rs = 0; if (hue > 0) rh = hue; if (rh > 360.0f) rh = 360.0f; if (light > 0) rl = light; if (rl > 1) rl = 1; if (satur > 0) rs = satur; if (rs > 1) rs = 1.0f; if (rl <= 0.5f) rm2 = rl * (1.0f + rs); else rm2 = rl + rs - rl * rs; rm1 = 2.0f * rl - rm2; if (!rs) { r = rl; g = rl; b = rl; return; } r = HLStoRGB_(rm1, rm2, rh + 120); g = HLStoRGB_(rm1, rm2, rh); b = HLStoRGB_(rm1, rm2, rh - 120); } void RGBtoHLS(float rr, float gg, float bb, float& hue, float& light, float& satur) { // Static method to compute HLS from RGB. The r,g,b triplet is between // [0,1], hue is between [0,1], light and satur are [0,1]. float rnorm, gnorm, bnorm, minval, maxval, msum, mdiff, r, g, b; r = g = b = 0; if (rr > 0) r = rr; if (r > 1) r = 1; if (gg > 0) g = gg; if (g > 1) g = 1; if (bb > 0) b = bb; if (b > 1) b = 1; minval = r; if (g < minval) minval = g; if (b < minval) minval = b; maxval = r; if (g > maxval) maxval = g; if (b > maxval) maxval = b; rnorm = gnorm = bnorm = 0; mdiff = maxval - minval; msum = maxval + minval; light = 0.5f * msum; if (maxval != minval) { rnorm = (maxval - r) / mdiff; gnorm = (maxval - g) / mdiff; bnorm = (maxval - b) / mdiff; } else { satur = hue = 0; return; } if (light < 0.5f) satur = mdiff / msum; else satur = mdiff / (2.0f - msum); if (r == maxval) hue = 60.0f * (6.0f + bnorm - gnorm); else if (g == maxval) hue = 60.0f * (2.0f + rnorm - bnorm); else hue = 60.0f * (4.0f + gnorm - rnorm); if (hue > 360) hue = hue - 360; hue = hue / 360.0f; } RedGreenBlue::RedGreenBlue(float r, float g, float b) : red(r) , green(g) , blue(b) {} RedGreenBlue::RedGreenBlue(Color const& color) : red(color.red) , green(color.green) , blue(color.blue) {} RedGreenBlue::RedGreenBlue(HueSaturationValue const& hsv) { HSVtoRGB(red, green, blue, hsv.hue, hsv.saturation, hsv.value); } RedGreenBlue::RedGreenBlue(HueLightnessSaturation const& hls) { HLStoRGB(red, green, blue, hls.hue, hls.lightness, hls.saturation); } HueSaturationValue::HueSaturationValue(float h, float s, float v) : hue(h) , saturation(s) , value(v) {} HueSaturationValue::HueSaturationValue(RedGreenBlue const& rgb) { RGBtoHSV(rgb.red, rgb.green, rgb.blue, hue, saturation, value); } HueSaturationValue::HueSaturationValue(Color const& c) { RGBtoHSV(c.red, c.green, c.blue, hue, saturation, value); } HueLightnessSaturation::HueLightnessSaturation(float h, float l, float s) : hue(h) , lightness(l) , saturation(s) {} HueLightnessSaturation::HueLightnessSaturation(RedGreenBlue const& rgb) { RGBtoHLS(rgb.red, rgb.green, rgb.blue, hue, lightness, saturation); } HueLightnessSaturation::HueLightnessSaturation(Color const& c) { RGBtoHLS(c.red, c.green, c.blue, hue, lightness, saturation); } } } nux-4.0.8+18.10.20180623/NuxCore/Color.h0000644000000000000000000001552313313373365013421 0ustar /* * Copyright 2010-2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef COLOR_H #define COLOR_H #include namespace nux { namespace color { // DirectX D3DFormat // // All formats are listed from left to right, most significant bit (MSB) to // least significant bit (LSB). For example, D3DFORMAT_ARGB is ordered from // the MSB channel A (alpha), to the LSB channel B (blue). When traversing // surface data, the data is stored in memory from LSB to MSB, which means // that the channel order in memory is from LSB (blue) to MSB (alpha). // // The default value for formats that contain undefined channels (G16R16, // A8, and so on) is 1. The only exception is the A8 format, which is // initialized to 000 for the three color channels. // // The order of the bits is from the most significant byte first, so // D3DFMT_A8L8 indicates that the high byte of this 2-byte format is // alpha. D3DFMT_D16 indicates a 16-bit integer value and an // application-lockable surface. // // Pixel formats have been chosen to enable the expression of // hardware-vendor-defined extension formats, as well as to include the // well-established four-character code (FOURCC) method. The set of formats // understood by the Microsoft Direct3D runtime is defined by D3DFORMAT. //Format of RGBA colors is //7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //| alpha | red | green | blue | //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //MSB 31 0 LSB //Format of RGB colors is //7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //| ignored | red | green | blue | //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //Format of BGR colors is //7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //| ignored | blue | green | red | //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //Format of RGBA colors is //7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //| red | green | blue | alpha | //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //Format of BGRA colors is //7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //| blue | green | red | alpha | //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ enum Model { RGB, HSV, HLS, YUV }; enum Channel { RED, GREEN, BLUE, HUE, SATURATION, LIGHT, VALUE }; enum Format { FLOAT, HEX, INT }; class RedGreenBlue; class Color { public: Color(); explicit Color(unsigned int c); Color(int r, int g, int b); Color(float r, float g, float b, float a = 1.0f); Color(RedGreenBlue const& rgb, float a = 1.0f); //! Constructor - Initializes the color using an hex string /*! Initializes the color using an hex string, which may be in one of these formats: #RGB (each of R, G, B, A is a single hex digit) #RGBA #RRGGBB #RRGGBBAA The color is #ffffffff if hex cannot be parsed. */ Color(std::string const& hex); //! Returns the pre-multiplied version of this color. /*! Returns the pre-multiplied version of this color. If this color is already pre-multiplied then *this is returned.\n The premultiplied color is Color(red * alpha, green * alpha, blue * alpha, alpha). @return The pre-multiplied version of this color. */ Color GetPremultiplied(); //! Sets a pre-multiplied color /*! Sets a pre-multiplied color @param r Red value. @param g Green value. @param b Blue value. @param a Alpha value. */ void SetPremultiplied(float r, float g, float b, float a); //! Returns True if this color is pre-multiplied. /*! Returns True if this color is pre-multiplied. @return True is this color is pre-multiplied. */ bool IsPremultiplied(); float red; float green; float blue; float alpha; protected: bool premultiplied_; //!< True if the rgb components have been pre-multiplied with the alpha component. friend bool operator == (Color const& lhs, Color const& rhs); }; bool operator == (Color const& lhs, Color const& rhs); bool operator != (Color const& lhs, Color const& rhs); Color operator + (Color const&, Color const&); Color operator + (float, Color const&); Color operator + (Color const&, float); Color operator - (Color const&, Color const&); Color operator - (float, Color const&); Color operator - (Color const&, float); Color operator * (float, Color const&); Color operator * (Color const&, float); Color RandomColor(); unsigned int RandomColorINT(); class HueSaturationValue; class HueLightnessSaturation; class RedGreenBlue { public: RedGreenBlue(float r, float g, float b); RedGreenBlue(Color const& color); RedGreenBlue(HueSaturationValue const&); RedGreenBlue(HueLightnessSaturation const&); float red; float green; float blue; }; class HueSaturationValue { public: HueSaturationValue(float h, float s, float v); HueSaturationValue(Color const&); HueSaturationValue(RedGreenBlue const&); float hue; float saturation; float value; }; class HueLightnessSaturation { public: HueLightnessSaturation(float h, float l, float s); HueLightnessSaturation(Color const&); HueLightnessSaturation(RedGreenBlue const&); float hue; float lightness; float saturation; }; } using color::Color; } #endif // COLOR_H nux-4.0.8+18.10.20180623/NuxCore/ColorPrivate.cpp0000644000000000000000000000434213313373365015304 0ustar /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Andrea Azzarone * */ #include #include "ColorPrivate.h" namespace nux { namespace color { bool IsValidHex(std::string hex) { static const std::string allowed_chars("0123456789abcdefABCDEF"); if (hex.empty()) return false; if (hex[0] == '#') hex.erase(hex.begin()); switch (hex.length()) { case 3: // #rgb case 4: // #rgba case 6: // #rrggbb case 8: // #rrggbbaa return (hex.find_first_not_of(allowed_chars) == hex.npos); default: return false; } } int HexToInt(std::string const& hex) { std::istringstream istr(hex); int ret; istr >> std::hex >> ret; return ret; } bool HexToRGBA(std::string hex, float& r, float& g, float& b, float& a) { if (!IsValidHex(hex)) return false; if (hex[0] == '#') hex.erase(hex.begin()); a = 1.0f; if (hex.length() == 3 || hex.length() == 4) { r = HexToInt(hex.substr(0, 1) + hex.substr(0, 1)) / 255.0f; g = HexToInt(hex.substr(1, 1) + hex.substr(1, 1)) / 255.0f; b = HexToInt(hex.substr(2, 1) + hex.substr(2, 1)) / 255.0f; if (hex.length() == 4) a = HexToInt(hex.substr(3, 1) + hex.substr(3, 1)) / 255.0f; } else if (hex.length() == 6 || hex.length() == 8) { r = HexToInt(hex.substr(0, 2)) / 255.0f; g = HexToInt(hex.substr(2, 2)) / 255.0f; b = HexToInt(hex.substr(4, 2)) / 255.0f; if (hex.length() == 8) a = HexToInt(hex.substr(6, 2)) / 255.0f; } return true; } } // namespace color } // namespace nux nux-4.0.8+18.10.20180623/NuxCore/ColorPrivate.h0000644000000000000000000000202013313373365014740 0ustar /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Andrea Azzarone * */ #include namespace nux { namespace color { bool IsValidHex(std::string hex); int HexToInt(std::string const& hex); bool HexToRGBA(std::string hex, float& r, float& g, float& b, float& a); } // namespace color } // namespace nux nux-4.0.8+18.10.20180623/NuxCore/Colors.cpp0000644000000000000000000001754313313373365014143 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "Colors.h" namespace nux { namespace color { // Definition of Luma coefficients as per ITU-R Recommendation BT.601 // http://en.wikipedia.org/wiki/Rec._601 const float LumaRed = 0.299f; const float LumaGreen = 0.587f; const float LumaBlue = 0.114f; // // Definition of Luma coefficients as per ITU-R Recommendation BT.709 // // http://en.wikipedia.org/wiki/Rec._709 // float LumaRed = 0.2126f; // float LumaGreen = 0.7152f; // float LumaBlue = 0.0722f; const Color Transparent(0, 0, 0, 0); //Red colors const Color IndianRed(0xCD, 0x5C, 0x5C); const Color LightCoral(0xF0, 0x80, 0x80); const Color Salmon(0xFA, 0x80, 0x72); const Color DarkSalmon(0xE9, 0x96, 0x7A); const Color LightSalmon(0xFF, 0xA0, 0x7A); const Color Crimson(0xDC, 0x14, 0x3C); const Color Red(0xFF, 0x00, 0x00); const Color FireBrick(0xB2, 0x22, 0x22); const Color DarkRed(0x8B, 0x00, 0x00); //Pink colors const Color Pink(0xFF, 0xC0, 0xCB); const Color LightPink(0xFF, 0xB6, 0xC1); const Color HotPink(0xFF, 0x69, 0xB4); const Color DeepPink(0xFF, 0x14, 0x93); const Color MediumVioletRed(0xC7, 0x15, 0x85); const Color PaleVioletRed(0xDB, 0x70, 0x93); //Orange colors //const Color LightSalmon = Color (0xFF/255.0f, 0xA0/255.0f, 0x7A/255.0f);// 255 160 122 const Color Coral(0xFF, 0x7F, 0x50); const Color Tomato(0xFF, 0x63, 0x47); const Color OrangeRed(0xFF, 0x45, 0x00); const Color DarkOrange(0xFF, 0x8C, 0x00); const Color Orange(0xFF, 0xA5, 0x00); //Yellow colors const Color Gold(0xFF, 0xD7, 0x00); const Color Yellow(0xFF, 0xFF, 0x00); const Color LightYellow(0xFF, 0xFF, 0xE0); const Color LemonChiffon(0xFF, 0xFA, 0xCD); const Color LightGoldenrodYellow(0xFA, 0xFA, 0xD2); const Color PapayaWhip(0xFF, 0xEF, 0xD5); const Color Moccasin(0xFF, 0xE4, 0xB5); const Color PeachPuff(0xFF, 0xDA, 0xB9); const Color PaleGoldenrod(0xEE, 0xE8, 0xAA); const Color Khaki(0xF0, 0xE6, 0x8C); const Color DarkKhaki(0xBD, 0xB7, 0x6B); //Purple colors const Color Lavender(0xE6, 0xE6, 0xFA); const Color Thistle(0xD8, 0xBF, 0xD8); const Color Plum(0xDD, 0xA0, 0xDD); const Color Violet(0xEE, 0x82, 0xEE); const Color Orchid(0xDA, 0x70, 0xD6); const Color Fuchsia(0xFF, 0x00, 0xFF); const Color Magenta(0xFF, 0x00, 0xFF); const Color MediumOrchid(0xBA, 0x55, 0xD3); const Color MediumPurple(0x93, 0x70, 0xDB); const Color BlueViolet(0x8A, 0x2B, 0xE2); const Color DarkViolet(0x94, 0x00, 0xD3); const Color DarkOrchid(0x99, 0x32, 0xCC); const Color DarkMagenta(0x8B, 0x00, 0x8B); const Color Purple(0x80, 0x00, 0x80); const Color Indigo(0x4B, 0x00, 0x82); const Color SlateBlue(0x6A, 0x5A, 0xCD); const Color DarkSlateBlue(0x48, 0x3D, 0x8B); //Green colors const Color GreenYellow(0xAD, 0xFF, 0x2F); const Color Chartreuse(0x7F, 0xFF, 0x00); const Color LawnGreen(0x7C, 0xFC, 0x00); const Color Lime(0x00, 0xFF, 0x00); const Color LimeGreen(0x32, 0xCD, 0x32); const Color PaleGreen(0x98, 0xFB, 0x98); const Color LightGreen(0x90, 0xEE, 0x90); const Color MediumSpringGreen(0x00, 0xFA, 0x9A); const Color SpringGreen(0x00, 0xFF, 0x7F); const Color MediumSeaGreen(0x3C, 0xB3, 0x71); const Color SeaGreen(0x2E, 0x8B, 0x57); const Color ForestGreen(0x22, 0x8B, 0x22); const Color Green(0x00, 0x80, 0x00); const Color DarkGreen(0x00, 0x64, 0x00); const Color YellowGreen(0x9A, 0xCD, 0x32); const Color OliveDrab(0x6B, 0x8E, 0x23); const Color Olive(0x80, 0x80, 0x00); const Color DarkOliveGreen(0x55, 0x6B, 0x2F); const Color MediumAquamarine(0x66, 0xCD, 0xAA); const Color DarkSeaGreen(0x8F, 0xBC, 0x8F); const Color LightSeaGreen(0x20, 0xB2, 0xAA); const Color DarkCyan(0x00, 0x8B, 0x8B); const Color Teal(0x00, 0x80, 0x80); //Blue colors const Color Aqua(0x00, 0xFF, 0xFF); const Color Cyan(0x00, 0xFF, 0xFF); const Color LightCyan(0xE0, 0xFF, 0xFF); const Color PaleTurquoise(0xAF, 0xEE, 0xEE); const Color Aquamarine(0x7F, 0xFF, 0xD4); const Color Turquoise(0x40, 0xE0, 0xD0); const Color MediumTurquoise(0x48, 0xD1, 0xCC); const Color DarkTurquoise(0x00, 0xCE, 0xD1); const Color CadetBlue(0x5F, 0x9E, 0xA0); const Color SteelBlue(0x46, 0x82, 0xB4); const Color LightSteelBlue(0xB0, 0xC4, 0xDE); const Color PowderBlue(0xB0, 0xE0, 0xE6); const Color LightBlue(0xAD, 0xD8, 0xE6); const Color SkyBlue(0x87, 0xCE, 0xEB); const Color LightSkyBlue(0x87, 0xCE, 0xFA); const Color DeepSkyBlue(0x00, 0xBF, 0xFF); const Color DodgerBlue(0x1E, 0x90, 0xFF); const Color CornflowerBlue(0x64, 0x95, 0xED); const Color MediumSlateBlue(0x7B, 0x68, 0xEE); const Color RoyalBlue(0x41, 0x69, 0xE1); const Color Blue(0x00, 0x00, 0xFF); const Color MediumBlue(0x00, 0x00, 0xCD); const Color DarkBlue(0x00, 0x00, 0x8B); const Color Navy(0x00, 0x00, 0x80); const Color MidnightBlue(0x19, 0x19, 0x70); //Brown colors const Color Cornsilk(0xFF, 0xF8, 0xDC); const Color BlanchedAlmond(0xFF, 0xEB, 0xCD); const Color Bisque(0xFF, 0xE4, 0xC4); const Color NavajoWhite(0xFF, 0xDE, 0xAD); const Color Wheat(0xF5, 0xDE, 0xB3); const Color BurlyWood(0xDE, 0xB8, 0x87); const Color Tan(0xD2, 0xB4, 0x8C); const Color RosyBrown(0xBC, 0x8F, 0x8F); const Color SandyBrown(0xF4, 0xA4, 0x60); const Color Goldenrod(0xDA, 0xA5, 0x20); const Color DarkGoldenrod(0xB8, 0x86, 0x0B); const Color Peru(0xCD, 0x85, 0x3F); const Color Chocolate(0xD2, 0x69, 0x1E); const Color SaddleBrown(0x8B, 0x45, 0x13); const Color Sienna(0xA0, 0x52, 0x2D); const Color Brown(0xA5, 0x2A, 0x2A); const Color Maroon(0x80, 0x00, 0x00); //White colors const Color White(0xFF, 0xFF, 0xFF); const Color Snow(0xFF, 0xFA, 0xFA); const Color Honeydew(0xF0, 0xFF, 0xF0); const Color MintCream(0xF5, 0xFF, 0xFA); const Color Azure(0xF0, 0xFF, 0xFF); const Color AliceBlue(0xF0, 0xF8, 0xFF); const Color GhostWhite(0xF8, 0xF8, 0xFF); const Color WhiteSmoke(0xF5, 0xF5, 0xF5); const Color Seashell(0xFF, 0xF5, 0xEE); const Color Beige(0xF5, 0xF5, 0xDC); const Color OldLace(0xFD, 0xF5, 0xE6); const Color FloralWhite(0xFF, 0xFA, 0xF0); const Color Ivory(0xFF, 0xFF, 0xF0); const Color AntiqueWhite(0xFA, 0xEB, 0xD7); const Color Linen(0xFA, 0xF0, 0xE6); const Color LavenderBlush(0xFF, 0xF0, 0xF5); const Color MistyRose(0xFF, 0xE4, 0xE1); //Grey colors const Color Gainsboro(0xDC, 0xDC, 0xDC); const Color LightGrey(0xD3, 0xD3, 0xD3); const Color Silver(0xC0, 0xC0, 0xC0); const Color DarkGray(0xA9, 0xA9, 0xA9); const Color Gray(0x80, 0x80, 0x80); const Color DimGray(0x69, 0x69, 0x69); const Color LightSlateGray(0x77, 0x88, 0x99); const Color SlateGray(0x70, 0x80, 0x90); const Color DarkSlateGray(0x2F, 0x4F, 0x4F); const Color Black(0x00, 0x00, 0x00); // More Colors const Color Aubergine(0x2B, 0x0B, 0x30); } } nux-4.0.8+18.10.20180623/NuxCore/Colors.h0000644000000000000000000001415413313373365013603 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef COLORS_H #define COLORS_H #include "Color.h" namespace nux { namespace color { // Definition of Luma coefficients as per ITU-R Recommendation BT.709 // http://en.wikipedia.org/wiki/Rec._709 extern const float LumaRed; extern const float LumaGreen; extern const float LumaBlue; // X11 color names from:http://en.wikipedia.org/wiki/Web_colors extern const Color Transparent; // Red colors extern const Color IndianRed; extern const Color LightCoral; extern const Color Salmon; extern const Color DarkSalmon; extern const Color LightSalmon; extern const Color Crimson; extern const Color Red; extern const Color FireBrick; extern const Color DarkRed; // Pink colors extern const Color Pink; extern const Color LightPink; extern const Color HotPink; extern const Color DeepPink; extern const Color MediumVioletRed; extern const Color PaleVioletRed; // Orange colors extern const Color Coral; extern const Color Tomato; extern const Color OrangeRed; extern const Color DarkOrange; extern const Color Orange; // Yellow colors extern const Color Gold; extern const Color Yellow; extern const Color LightYellow; extern const Color LemonChiffon; extern const Color LightGoldenrodYellow; extern const Color PapayaWhip; extern const Color Moccasin; extern const Color PeachPuff; extern const Color PaleGoldenrod; extern const Color Khaki; extern const Color DarkKhaki; // Purple colors extern const Color Lavender; extern const Color Thistle; extern const Color Plum; extern const Color Violet; extern const Color Orchid; extern const Color Fuchsia; extern const Color Magenta; extern const Color MediumOrchid; extern const Color MediumPurple; extern const Color BlueViolet; extern const Color DarkViolet; extern const Color DarkOrchid; extern const Color DarkMagenta; extern const Color Purple; extern const Color Indigo; extern const Color SlateBlue; extern const Color DarkSlateBlue; // Green colors extern const Color GreenYellow; extern const Color Chartreuse; extern const Color LawnGreen; extern const Color Lime; extern const Color LimeGreen; extern const Color PaleGreen; extern const Color LightGreen; extern const Color MediumSpringGreen; extern const Color SpringGreen; extern const Color MediumSeaGreen; extern const Color SeaGreen; extern const Color ForestGreen; extern const Color Green; extern const Color DarkGreen; extern const Color YellowGreen; extern const Color OliveDrab; extern const Color Olive; extern const Color DarkOliveGreen; extern const Color MediumAquamarine; extern const Color DarkSeaGreen; extern const Color LightSeaGreen; extern const Color DarkCyan; extern const Color Teal; // Blue colors extern const Color Aqua; extern const Color Cyan; extern const Color LightCyan; extern const Color PaleTurquoise; extern const Color Aquamarine; extern const Color Turquoise; extern const Color MediumTurquoise; extern const Color DarkTurquoise; extern const Color CadetBlue; extern const Color SteelBlue; extern const Color LightSteelBlue; extern const Color PowderBlue; extern const Color LightBlue; extern const Color SkyBlue; extern const Color LightSkyBlue; extern const Color DeepSkyBlue; extern const Color DodgerBlue; extern const Color CornflowerBlue; extern const Color MediumSlateBlue; extern const Color RoyalBlue; extern const Color Blue; extern const Color MediumBlue; extern const Color DarkBlue; extern const Color Navy; extern const Color MidnightBlue; // Brown colors extern const Color Cornsilk; extern const Color BlanchedAlmond; extern const Color Bisque; extern const Color NavajoWhite; extern const Color Wheat; extern const Color BurlyWood; extern const Color Tan; extern const Color RosyBrown; extern const Color SandyBrown; extern const Color Goldenrod; extern const Color DarkGoldenrod; extern const Color Peru; extern const Color Chocolate; extern const Color SaddleBrown; extern const Color Sienna; extern const Color Brown; extern const Color Maroon; // White colors extern const Color White; extern const Color Snow; extern const Color Honeydew; extern const Color MintCream; extern const Color Azure; extern const Color AliceBlue; extern const Color GhostWhite; extern const Color WhiteSmoke; extern const Color Seashell; extern const Color Beige; extern const Color OldLace; extern const Color FloralWhite; extern const Color Ivory; extern const Color AntiqueWhite; extern const Color Linen; extern const Color LavenderBlush; extern const Color MistyRose; // Grey colors extern const Color Gainsboro; extern const Color LightGrey; extern const Color Silver; extern const Color DarkGray; extern const Color Gray; extern const Color DimGray; extern const Color LightSlateGray; extern const Color SlateGray; extern const Color DarkSlateGray; extern const Color Black; // More Colors extern const Color Aubergine; } } #endif // COLORS_H nux-4.0.8+18.10.20180623/NuxCore/CppReadme.txt0000644000000000000000000002133113313373365014565 0ustar Storage types in C++ --------------------- *Constant Data Values are known at compile-time. This kind of data stored outside of the program read-write area. Therefore write attempt is undefined. const char *hello1 = "Hello world"; char *hello2 = "Other hello"; // hello1[1] = 'a'; // syntax error hello2[1] = 'a'; // could cause runtime error char *s = const_cast(hello1); // dangerous s[3] = 'x'; // could be runtime error ! There is difference between a string literal and an initialized character array. int main() { // declaration of three arrays in the user data area // read and write permissions for the elements: char t1[] = {'H','e','l','l','o','\0'}; char t2[] = "Hello"; char t3[] = "Hello"; // declaration of two pointers in the user data area // read and write permissions for the pointers // ...and... // allocation of the "Hello" literal (possibly) read-only char *s1 = "Hello"; // s1 points to 'H' char *s2 = "Hello"; // ... and s2 likely points to the same place void *v1 = t1, *v2 = t2, *v3 = t3, *v4 = s1, *v5 = s2; std::cout < * * Authored by: Tim Penhey * */ #include "NuxCore.h" #include "EasingCurve.h" namespace na = nux::animation; namespace { // These easing curves are an attempt to match the Qt curves // defined here: // http://doc.qt.nokia.com/4.7-snapshot/qeasingcurve.html double linear(double progress) { return progress; } double in_quad(double progress) { return progress * progress; } double reverse(double progress, na::EasingCurve::EasingFunction func) { // invert progress, and pass to ease_in progress = 1 - progress; return 1 - func(progress); } double in_out(double progress, na::EasingCurve::EasingFunction func) { if (progress > 0.5) { double out_progress = 1 - (progress - 0.5) * 2; return 1 - (func(out_progress) / 2); } else { double in_progress = progress * 2; return func(in_progress) / 2; } } double out_quad(double progress) { return reverse(progress, in_quad); } double in_out_quad(double progress) { return in_out(progress, in_quad); } double back_ease_in(double progress) { // (s+1)*t^3 - s*t^2 const double overshoot = 1.70158; return (((overshoot + 1) * progress * progress * progress) - (overshoot * progress * progress)); } double back_ease_out(double progress) { return reverse(progress, back_ease_in); } double back_ease_in_out(double progress) { return in_out(progress, back_ease_in); } double bounce_in(double progress) { if (progress < (1 / 2.75)) { return 7.5625 * progress * progress; } else if (progress < (2 / 2.75)) { progress -= (1.5 / 2.75); return 7.5625 * progress * progress + 0.75; } else if (progress < (2.5 / 2.75) ) { progress -= (2.25 / 2.75); return 7.5625 * progress * progress + 0.9375; } else { progress -= (2.625 / 2.75); return 7.5625 * progress * progress + 0.984375; } } double bounce_out(double progress) { return reverse(progress, bounce_in); } double bounce_in_out(double progress) { return in_out(progress, bounce_out); } double expo_ease_in(double progress) { return (progress == 0) ? 0.0 : 1.0 * std::pow (2, 10 * (progress / 1.0 - 1) ) + 0.0; } double expo_ease_out(double progress) { return reverse(progress, expo_ease_in); } na::EasingCurve::EasingFunction GetEasingFunction(na::EasingCurve::Type type) { switch (type) { case na::EasingCurve::Type::InQuad: return in_quad; case na::EasingCurve::Type::OutQuad: return out_quad; case na::EasingCurve::Type::InOutQuad: return in_out_quad; case na::EasingCurve::Type::BackEaseIn: return back_ease_in; case na::EasingCurve::Type::BackEaseOut: return back_ease_out; case na::EasingCurve::Type::BackEaseInOut: return back_ease_in_out; case na::EasingCurve::Type::BounceIn: return bounce_in; case na::EasingCurve::Type::BounceOut: return bounce_out; case na::EasingCurve::Type::BounceInOut: return bounce_in_out; case na::EasingCurve::Type::ExpoEaseIn: return expo_ease_in; case na::EasingCurve::Type::ExpoEaseOut: return expo_ease_out; case na::EasingCurve::Type::Linear: default: return linear; } } } na::EasingCurve::EasingCurve(Type type) : func_(GetEasingFunction(type)) {} double na::EasingCurve::ValueForProgress(double progress) { if (progress <= 0) return 0; if (progress >= 1) return 1; return func_(progress); } nux-4.0.8+18.10.20180623/NuxCore/EasingCurve.h0000644000000000000000000000333413313373365014553 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUX_CORE_EASING_CURVE_H #define NUX_CORE_EASING_CURVE_H namespace nux { namespace animation { class EasingCurve { public: #if defined(NUX_OS_WINDOWS) && !defined(NUX_VISUAL_STUDIO_VC11) enum Type #else enum class Type #endif { Linear, InQuad, OutQuad, InOutQuad, BackEaseIn, BackEaseOut, BackEaseInOut, BounceIn, BounceOut, BounceInOut, ExpoEaseIn, ExpoEaseOut }; typedef double (*EasingFunction)(double); explicit EasingCurve(Type type = Type::Linear); // progress is expected to be between zero and one inclusive. // // Values less than zero will return zero will return zero, and // greater than one will return one. // // The returned value may be greater than one, or less than zero for some // special curves. double ValueForProgress(double progress); private: EasingFunction func_; }; }} #endif nux-4.0.8+18.10.20180623/NuxCore/Error.h0000644000000000000000000000261713313373365013434 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NYERROR_H #define NYERROR_H //#include //#include //#include //#include //void ny_output_error(const char *error_msg); //void ny_output_system_error(const char *error_msg); // //void ny_output_error(const char *error_msg) //{ // cout << error_msg << endl; //} // //void ny_output_system_error(const char *error_msg) //{ // perror(error_msg); //} typedef enum { HR_SUCCESS, HR_FAIL, HR_INVALID_ARG, HR_INVALID_CALL, HR_NOT_ENOUGH_MEMORY, HR_FILE_NOT_FOUND, HR_FILE_IO_FAIL, HR_UNSUPPORTED_FORMAT, HR_UNKNOW_ERROR } HReport; #endif // NYERROR_H nux-4.0.8+18.10.20180623/NuxCore/Exception.cpp0000644000000000000000000000153713313373365014634 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "Exception.h" namespace nux { } nux-4.0.8+18.10.20180623/NuxCore/Exception.h0000644000000000000000000000463613313373365014304 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef EXCEPTION_H #define EXCEPTION_H #include namespace nux { // ***************** // * * // * Exception * // * * // ***************** // // The exception handling classes from the STL do what we want, // so this is nothing more than a base class for any of our // derived exceptions. I have changed the constructor to take a // std::string object, but this gets converted before calling // std::exception. class Exception : public std::exception { public: Exception (std::string name) throw() : std::exception (), name_ (name) { } virtual ~Exception () throw () {} virtual const char *what () const throw() { return name_.c_str(); } protected: std::string name_; }; // ************************ // * * // * Derived Exceptions * // * * // ************************ class BoundsException : public Exception { public: BoundsException (std::string name = "") : Exception ("apBoundsException: " + name) { } }; class NotSupportedException : public Exception { public: NotSupportedException (std::string name = "") : Exception ("NotSupportedException: " + name) { } }; class DivisionByZeroException : public Exception { public: DivisionByZeroException (std::string name = "") : Exception ("DivisionByZeroException: " + name) { } }; class InvalidIndexException : public Exception { public: InvalidIndexException (std::string name = "") : Exception ("InvalidIndexException: " + name) { } }; } #endif // EXCEPTION_H nux-4.0.8+18.10.20180623/NuxCore/FileIO.cpp0000644000000000000000000002671613313373365014013 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" namespace nux { // // Load a binary file to a dynamic array. // bool LoadFileToArray (std::vector& Result, const TCHAR *Filename, NFileManager &FileManager ) { NSerializer *Reader = FileManager.CreateFileReader ( Filename ); if ( !Reader ) return FALSE; Result.clear(); if (Reader->GetFileSize() < 0) { Reader->Close(); delete Reader; return FALSE; } Result.resize (Reader->GetFileSize() ); Reader->Serialize (&Result[0], Result.size() ); bool Success = Reader->Close(); delete Reader; return Success; } /*! Load a text file the a ANSICHAR array. The Array is null terminated. Useful for loading shader files. */ bool LoadTextFileToAnsiArray ( std::vector& Result, const TCHAR *Filename, NFileManager &FileManager ) { Result.clear(); NSerializer *Reader = FileManager.CreateFileReader ( Filename ); if ( !Reader ) return FALSE; int Size = Reader->GetFileSize(); if (Size < 0) { Reader->Close(); delete Reader; return FALSE; } std::vector ByteArray; ByteArray.clear(); ByteArray.resize (Size); Reader->Serialize (&ByteArray[0], Result.size() ); bool Success = Reader->Close(); delete Reader; if ( Size >= 2 && ! (Size & 1) && Memcmp (&Result[0], &NUX_UTF16_LE[1], NUX_UTF16_LE[0]) == 0) // (BYTE)ByteArray[0]==0xff && (BYTE)ByteArray[1]==0xfe ) { // UTF16 - Little Endian int numElement = Size / sizeof (UNICHAR) + 1; // +1 for null char Result.resize (numElement); for ( int i = 0; i < numElement - 1; i++ ) Result[i] = ConvertUnicodeCharToTCHAR ( (WORD) (ANSIUCHAR) ByteArray[i*2+2] + (WORD) (ANSIUCHAR) ByteArray[i*2+3] * 256 ); Result[numElement] = 0; } else if ( Size >= 2 && ! (Size & 1) && Memcmp (&Result[0], &NUX_UTF16_LE[1], NUX_UTF16_LE[0]) == 0) { // UTF16 - Big Endian. int numElement = Size / sizeof (TCHAR) + 1; // +1 for null char Result.resize (numElement); for ( int i = 0; i < numElement - 1; i++ ) Result[i] = ConvertUnicodeCharToTCHAR ( (WORD) (ANSIUCHAR) ByteArray[i*2+3] + (WORD) (ANSIUCHAR) ByteArray[i*2+2] * 256 ); Result[numElement] = 0; } else { // ANSI. Result.clear(); Result.resize (Size + 1); // +1 for null char for (int i = 0; i < Size; i++) Result[i] = ByteArray[i]; Result[Size] = 0; } return Success; } /*! Load a text file in an ANSICHAR array. The Array is null terminated. */ bool LoadTextFileToUnicodeArray ( std::vector& Result, const TCHAR *Filename, NFileManager &FileManager ) { Result.clear(); NSerializer *Reader = FileManager.CreateFileReader ( Filename ); if ( !Reader ) return FALSE; int Size = Reader->GetFileSize(); if (Size < 0) { Reader->Close(); delete Reader; return FALSE; } std::vector ByteArray; ByteArray.clear(); ByteArray.resize (Size); Reader->Serialize ( &ByteArray[0], Result.size() ); bool Success = Reader->Close(); delete Reader; if ( Size >= 2 && ! (Size & 1) && Memcmp (&Result[0], &NUX_UTF16_LE[1], NUX_UTF16_LE[0]) == 0) // (BYTE)ByteArray[0]==0xff && (BYTE)ByteArray[1]==0xfe ) { // UTF16 - Little Endian int numElement = Size + 1; // +1 for null char Result.resize (numElement); for ( int i = 0; i < numElement - 1; i++ ) Result[i] = ( (WORD) (ANSIUCHAR) ByteArray[i*2+2] + (WORD) (ANSIUCHAR) ByteArray[i*2+3] * 256 ); Result[numElement] = 0; } else if ( Size >= 2 && ! (Size & 1) && Memcmp (&Result[0], &NUX_UTF16_LE[1], NUX_UTF16_LE[0]) == 0) { // UTF16 - Big Endian. int numElement = Size + 1; // +1 for null char Result.resize (numElement); for ( int i = 0; i < numElement - 1; i++ ) Result[i] = ConvertUnicodeCharToTCHAR ( (WORD) (ANSIUCHAR) ByteArray[i*2+3] + (WORD) (ANSIUCHAR) ByteArray[i*2+2] * 256 ); Result[numElement] = 0; } else { // There is no way to detect that a file really contains ascii. Or is there? // Make sure this file is really ascii. /* However as an additional check to the heuristic of looking for unprintable characters, another trick is to check if the newline string is consistent. It should always be either "\n" (for UNIX-like systems), "\r" (for Mac-like systems) or "\r\n" (for Windows-like systems). If the file starts switching around between these, it probably isn't a valid ASCII file on any of the above three platforms. */ BOOL isASCII = TRUE; for ( int i = 0; i < Size; i++ ) { if (Result[i] == 0 && (i != Size - 1) ) { isASCII = FALSE; } if ( (Result[i] < 0x20 || Result[i] >= 0xFF) && ( (Result[i] != 0x0A/*New Line, Line feed*/) && (Result[i] != 0x0D/*Carriage return*/) ) ) { isASCII = FALSE; } // http://www.websiterepairguy.com/articles/os/crlf.html /* The carriage return is often referred to by the capital letters CR. On a Macintosh, every line has a CR at the end. Under Linux (a variant of Unix), the end of a line is indicated by a line feed. Every line ends with a line feed or LF. Calling the end of a line an LF versus a CR is not just semantics. These are 2 very real characters with 2 very real and very separate numeric representations on a computer. A CR is a 13 in the ASCII table of characters and an LF is a 10 in the ASCII table of characters. Contributing to the confusion is that fact that Microsoft Windows does things yet another way. Under Microsoft Windows, lines end with a combination of 2 characters -- a CR followed by a LF. Symbolically, this is represented as CRLF or carriage return, line feed. */ // Todo. Check if the file mixes a combination of \n (Linux) \r (Mac) and \r\n (Windows). // If it does, the file is not ASCII. if (isASCII == FALSE) return FALSE; } Result.clear(); Result.resize (Size + 1); for ( int i = 0; i < Size; i++ ) Result[i] = ConvertAnsiCharToUnicodeChar (ByteArray[i]); Result[Size] = 0; } return Success; } /*! Load a text file to an std::string. The file maybe ANSI or Unicode. The resulting string is TCHAR. */ bool LoadFileToString(std::string &Result, const TCHAR *Filename, NFileManager &FileManager) { NSerializer *Reader = FileManager.CreateFileReader (Filename); if ( !Reader ) { nuxDebugMsg (TEXT ("[LoadFileToString] Cannot read from file: %s"), Filename); return false; } unsigned int Size = Reader->GetFileSize(); std::vector ByteArray (Size + 2); Reader->Serialize (&ByteArray[0], Size); bool Success = Reader->Close(); delete Reader; ByteArray[Size+0] = 0; ByteArray[Size+1] = 0; std::vector ResultArray; // Detect Unicode Byte Order Mark // EF BB BF UTF-8 // FF FE UTF-16, little endian // FE FF UTF-16, big endian // FF FE 00 00 UTF-32, little endian // 00 00 FE FF UTF-32, big-endian // Note: Microsoft uses UTF-16, little endian byte order. // Little Endian UTF-16: size should be >=2, even, and the first two bytes should be 0xFF followed by 0xFE if ( (Size >= 2) && ! (Size & 1) && ( (BYTE) ByteArray[0] == 0xff) && ( (BYTE) ByteArray[1] == 0xfe) ) { // UTF16 - Little Endian int numElement = Size / sizeof (TCHAR); ResultArray.clear(); ResultArray.resize (numElement); for ( int i = 0; i < numElement - 1; i++ ) ResultArray[i] = ConvertUnicodeCharToTCHAR ( (WORD) (ANSIUCHAR) ByteArray[i*2+2] + (WORD) (ANSIUCHAR) ByteArray[i*2+3] * 256 ); ResultArray[numElement] = 0; } else if ( (Size >= 2) && ! (Size & 1) && ( (BYTE) ByteArray[0] == 0xfe) && ( (BYTE) ByteArray[1] == 0xff) ) { // UTF16 - Big Endian. int numElement = Size / sizeof (TCHAR); ResultArray.clear(); ResultArray.resize (numElement); for (int i = 0; i < numElement - 1; i++) ResultArray[i] = ConvertUnicodeCharToTCHAR ( (WORD) (ANSIUCHAR) ByteArray[i*2+3] + (WORD) (ANSIUCHAR) ByteArray[i*2+2] * 256 ); ResultArray[numElement] = 0; } else { // ANSI. ResultArray.clear(); ResultArray.resize (Size + 1); for (unsigned int i = 0; i < Size; i++) ResultArray[i] = ConvertAnsiCharToTCHAR (ByteArray[i]); ResultArray[Size] = 0; } Result = &ResultArray[0]; return Success; } /*! Save BYTE array to file. */ bool SaveArrayToFile ( const std::vector& Array, const TCHAR *Filename, NFileManager &FileManager ) { NSerializer *Ar = FileManager.CreateFileWriter ( Filename ); if ( !Ar ) return 0; Ar->Serialize ( const_cast (&Array[0]), Array.size() ); delete Ar; return 1; } /*! Save string to File. Attempt to write it as ASCII if possible. If not write as UTF16-BE. */ bool SaveStringToFile(const std::string &String, const TCHAR *Filename, NFileManager &FileManager) { if ( !String.length() ) return 0; NSerializer *Ar = FileManager.CreateFileWriter ( Filename ); if ( !Ar ) return 0; bool SaveAsUnicode = false, Success = true; #if UNICODE for ( int i = 0; i < String.length(); i++ ) { // Test if the UNICODE 0xABCD is the same as the ASCII 0x00CB. if ( (*String) [i] != (TCHAR) (ANSIUCHAR) ConvertTCHARToAnsiChar ( (*String) [i]) ) { //The string need to be written in ASCII. We write the string as UTF16-BigEndian Ar->Serialize (NUX_CONST_CAST (BYTE *, &UTF16_BE[1]), UTF16_BE[0] /*size*/); SaveAsUnicode = true; break; } } #endif if ( SaveAsUnicode || (sizeof (TCHAR) == 1) ) { unsigned int s = (unsigned int) String.length() * sizeof (TCHAR); Ar->Serialize(NUX_CONST_CAST(TCHAR *, String.c_str()), (unsigned int) s); } else { unsigned int s = (unsigned int) String.length(); std::vector AnsiBuffer ( (unsigned int) s); // Cast all character down from UTF16 to ANSI for (unsigned int i = 0; i < (unsigned int) String.length(); i++) AnsiBuffer[i] = ConvertTCHARToAnsiChar ( (unsigned int) String[i]); // serialize s = (unsigned int) String.length(); Ar->Serialize ( NUX_CONST_CAST (ANSICHAR *, &AnsiBuffer[0]), s); } delete Ar; if ( !Success ) GFileManager.Delete ( Filename ); return Success; } } nux-4.0.8+18.10.20180623/NuxCore/FileIO.h0000644000000000000000000000315213313373365013445 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NFILE_H #define NFILE_H #include #include namespace nux { bool LoadFileToArray ( std::vector& Result, const TCHAR *Filename, NFileManager &FileManager = GFileManager ); bool LoadTextFileToAnsiArray ( std::vector& Result, const TCHAR *Filename, NFileManager &FileManager = GFileManager ); bool LoadTextFileToUnicodeArray ( std::vector& Result, const TCHAR *Filename, NFileManager &FileManager = GFileManager ); bool LoadFileToString(std::string &Result, const TCHAR *Filename, NFileManager &FileManager = GFileManager ); bool SaveArrayToFile(const std::vector& Array, const TCHAR *Filename, NFileManager &FileManager = GFileManager ); bool SaveStringToFile(const std::string &String, const TCHAR *Filename, NFileManager &FileManager = GFileManager ); } #endif // NFILE_H nux-4.0.8+18.10.20180623/NuxCore/FileManager/0000755000000000000000000000000013313373365014336 5ustar nux-4.0.8+18.10.20180623/NuxCore/FileManager/NFileManagerGNU.cpp0000644000000000000000000004466713313373365017725 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" namespace nux { // Choose the size so it is a power of 2. Example (size-1)= 11111111. const int NGNUSerialFileReader::sBufferSize = 1024; NGNUSerialFileReader::NGNUSerialFileReader (int InFileDescriptor, LogOutputDevice &InError, int InSize) : m_FileDescriptor (InFileDescriptor) , m_Error (InError) , m_FileSize (InSize) , m_FilePos (0) , m_BufferBase (0) , m_BufferCount (0) { m_Buffer = new BYTE[sBufferSize]; } NGNUSerialFileReader::~NGNUSerialFileReader() { NUX_SAFE_DELETE_ARRAY (m_Buffer); if (m_FileDescriptor) { Close(); } } bool NGNUSerialFileReader::Precache (int PrecacheOffset, int PrecacheSize) { // Only pre-cache at current position and avoid work if pre-caching same offset twice. if ( (m_FilePos == PrecacheOffset) && (!m_BufferBase || !m_BufferCount || m_BufferBase != m_FilePos) ) { m_BufferBase = m_FilePos; // (sBufferSize - 1) contains only '1', i.e 1111111111. // So (m_FilePos & (sBufferSize-1)) is equal to m_FilePos if m_FilePos <= (sBufferSize-1). m_BufferCount = Min (Min (PrecacheSize, (int) (sBufferSize - (m_FilePos & (sBufferSize - 1) ) ) ), m_FileSize - m_FilePos); long long Count = 0; //GTotalBytesReadViaFileManager += m_BufferCount; Count = read (m_FileDescriptor, m_Buffer, m_BufferCount); if (Count == 0) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileReader::Precache] Reached end of file while attempting to read %i bytes"), m_BufferCount); } if (Count == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileReader::Precache] Read error while attempting to read file: ???") ); } } return TRUE; } long long NGNUSerialFileReader::Seek (long long InPos, NSerializer::SeekPos seekpos) { nuxAssert (InPos >= 0); nuxAssert (InPos <= m_FileSize); Flush(); // Because we precache our reads, we must perform Seek accordingly. long long pos = m_FilePos; long long filepos = 0; // Set the file pointer to m_FilePos. filepos = lseek (m_FileDescriptor, pos, SEEK_SET); if (filepos == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileReader::Seek] Seek to %i has failed."), InPos); } // Now the file pointer is current with what we have read so far. pos = InPos; filepos = lseek (m_FileDescriptor, pos, (seekpos == SeekStart) ? SEEK_SET : (seekpos == SeekCurrent) ? SEEK_CUR : SEEK_END); if ( filepos == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileReader::Seek] Seek to %i has failed."), InPos); } m_FilePos = filepos; m_BufferBase = 0; m_BufferCount = 0; Precache (m_FilePos, sBufferSize); return filepos; } long long NGNUSerialFileReader::Tell() { // Flush(); // LARGE_INTEGER pos; // LARGE_INTEGER filepos; // pos.QuadPart = 0; // ::SetFilePointerEx(m_FileDescriptor, pos, &filepos, FILE_CURRENT); // return filepos.QuadPart; return m_FilePos; } long long NGNUSerialFileReader::GetFileSize() { return m_FileSize; } bool NGNUSerialFileReader::Close() { if (m_FileDescriptor) { int ret = close (m_FileDescriptor); if (ret == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileReader::Close] Error while closing file") ); } } m_FileDescriptor = 0; return !m_ErrorCode; } void NGNUSerialFileReader::SerializeFinal (void *Dest, long long Length) { nuxAssert (Dest); while (Length > 0) { int DataSize = Min (Length, m_BufferBase + m_BufferCount - m_FilePos); if (DataSize == 0) { if (Length >= sBufferSize) { long long Count = 0; //GTotalBytesReadViaFileManager += Length; Count = read (m_FileDescriptor, Dest, Length); if (Count == 0) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileReader::Serialize] Reached end of file while attempting to read %i bytes"), Length); } if (Count == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileReader::Serialize] Read error while attempting to read file: ???") ); } m_FilePos += Length; m_BufferBase += Length; return; } Precache (m_FilePos, 0x7FFFFFFF); DataSize = Min (Length, m_BufferBase + m_BufferCount - m_FilePos); if (DataSize <= 0) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("ReadFile beyond EOF %i+%i/%i"), m_FilePos, Length, m_FileSize); } if (m_ErrorCode) return; } Memcpy (Dest, m_Buffer + m_FilePos - m_BufferBase, DataSize); m_FilePos += DataSize; Length -= DataSize; Dest = (BYTE *) Dest + DataSize; } } ////////////////////////////////////////////////////////////////////////// // Choose the size so it is a power of 2. Example (size-1)= 11111111. const int NGNUSerialFileWriter::sBufferSize = 32; NGNUSerialFileWriter::NGNUSerialFileWriter (int InFileDescriptor, LogOutputDevice &InError, int /* InPos */) : m_FileDescriptor (InFileDescriptor) , m_Error (InError) , m_BufferCount (0) { m_Pos = Tell(); m_Buffer = new BYTE[sBufferSize]; } NGNUSerialFileWriter::~NGNUSerialFileWriter() { NUX_SAFE_DELETE_ARRAY (m_Buffer); if (m_FileDescriptor) Close(); m_FileDescriptor = 0; } long long NGNUSerialFileWriter::Seek (long long InPos, NSerializer::SeekPos seekpos) { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileDescriptor); if (m_FileDescriptor == 0) return -1; _Flush(); long long pos = InPos; long long filepos = 0; filepos = lseek (m_FileDescriptor, pos, (seekpos == SeekStart) ? SEEK_SET : (seekpos == SeekCurrent) ? SEEK_CUR : SEEK_END); if (filepos == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileWriter::Seek] Seek to %i has failed."), InPos); } m_Pos = filepos; return filepos; } long long NGNUSerialFileWriter::Tell() { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileDescriptor); if (m_FileDescriptor == 0) return -1; _Flush(); long long pos = 0; long long filepos = 0; filepos = lseek (m_FileDescriptor, pos, SEEK_CUR); if (filepos == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileWriter::Tell] Seek to %i has failed."), pos); } return filepos; } bool NGNUSerialFileWriter::Close() { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileDescriptor); if (m_FileDescriptor == 0) return true; _Flush(); int ret = close (m_FileDescriptor); if (ret == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileWriter::Close] Error while closing file") ); } m_FileDescriptor = 0; return !m_ErrorCode; } long long NGNUSerialFileWriter::GetFileSize() { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileDescriptor); if (m_FileDescriptor == 0) return -1; struct stat sb; if (fstat (m_FileDescriptor, &sb) != 0) { m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileWriter::GetFileSize] Can't get file size.") ); return -1; } return sb.st_size; } void NGNUSerialFileWriter::SerializeFinal (void *V, long long Length) { // This method is not re-entrant by itself. It relies on m_Buffer and other variables // that belong to this object. Therefore, it is not thread safe. We add a critical section // to make it thread safe. NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileDescriptor); nuxAssert (V); NUX_RETURN_IF_NULL (m_FileDescriptor); m_Pos += Length; int FreeSpace; while (Length > (FreeSpace = sBufferSize - m_BufferCount) ) { // m_Buffer is Full. Write it to the file. Memcpy (m_Buffer + m_BufferCount, V, FreeSpace); m_BufferCount += FreeSpace; Length -= FreeSpace; V = (BYTE *) V + FreeSpace; _Flush(); } if (Length) { Memcpy (m_Buffer + m_BufferCount, V, Length); m_BufferCount += Length; // Count the number of Characters stored in m_Buffer. } } void NGNUSerialFileWriter::Flush() { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileDescriptor); if (m_FileDescriptor == 0) return; _Flush(); } void NGNUSerialFileWriter::_Flush() { //GTotalBytesWrittenViaFileManager += m_BufferCount; if (m_BufferCount) { long long Result = 0; Result = write (m_FileDescriptor, m_Buffer, m_BufferCount); if (Result == -1) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileWriter::Flush] Write error.") ); } } m_BufferCount = 0; } ////////////////////////////////////////////////////////////////////////// NUX_IMPLEMENT_GLOBAL_OBJECT (NFileManagerGNU); void NFileManagerGNU::Constructor() { } void NFileManagerGNU::Destructor() { } NSerializer *NFileManagerGNU::CreateFileReader (const TCHAR *Filename, DWORD Flags, LogOutputDevice &Error) { int FileDesc = open (TCHAR_TO_ANSI (Filename), O_RDONLY); if (FileDesc == -1) { nuxDebugMsg (TEXT ("[NFileManagerGNU::CreateFileReader] Can't create file reade for: %s"), Filename); if (Flags & NSerializer::OutputErrorIfFail) { nuxError (TEXT ("[NFileManagerGNU::CreateFileReader] Can't open file: %s"), Filename); } return NULL; } struct stat sb; if (fstat (FileDesc, &sb) != 0) { int ret = close (FileDesc); if (ret == -1) { Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NFileManagerGNU::CreateFileReader] Error while closing file descriptor: %s"), Filename); } nuxDebugMsg (TEXT ("[NFileManagerGNU::CreateFileReader] Can't get file descriptor: %s"), Filename); Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NFileManagerGNU::CreateFileReader] Can't get file descriptor: %s"), Filename); return NULL; } return new NGNUSerialFileReader (FileDesc, Error, sb.st_size); } NSerializer *NFileManagerGNU::CreateFileWriter (const TCHAR *Filename, DWORD Flags, LogOutputDevice &Error) { if (FileExist (Filename) && (Flags & NSerializer::OverWriteReadOnly) ) { int ret = chmod (TCHAR_TO_ANSI (Filename), S_IRUSR | S_IWUSR); if (ret == -1) { Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NFileManagerGNU::CreateFileWriter] Can't change file mode") ); } } DWORD ModeFlags = 0; if ( (Flags & NSerializer::Read) && (Flags & NSerializer::Write) ) { ModeFlags |= O_RDWR; } else if (Flags & NSerializer::Read) { ModeFlags |= O_RDONLY; } else if (Flags & NSerializer::Write) { ModeFlags |= O_WRONLY; } ModeFlags |= (Flags & NSerializer::Append) ? O_APPEND : O_TRUNC; ModeFlags |= (Flags & NSerializer::NoOverWrite) ? (O_CREAT | O_EXCL) /*fail if the file already exist*/ : O_CREAT /*create the file if it does not exist*/; int FileDesc = open (TCHAR_TO_ANSI (Filename), ModeFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (FileDesc == -1) { if (Flags & NSerializer::OutputErrorIfFail) { nuxError (TEXT ("[NFileManagerGNU::CreateFileWriter] Failed to create file %s."), Filename); } return NULL; } if (Flags & NSerializer::Append) { long long Pos = lseek (FileDesc, 0, SEEK_END); if (Pos == -1) { Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NGNUSerialFileReader::Seek] Seek to %i has failed."), Pos); } } struct stat sb; if (fstat (FileDesc, &sb) != 0) { int ret = close (FileDesc); if (ret == -1) { Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NFileManagerGNU::CreateFileWriter] Error while closing file") ); } Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NFileManagerGNU::CreateFileWriter] Can't create file reader.") ); return NULL; } // The third param is never used. return new NGNUSerialFileWriter (FileDesc, Error, 0); } long long NFileManagerGNU::FileSize (const TCHAR *Filename) { struct stat sb; if (stat (TCHAR_TO_ANSI (Filename), &sb) != 0) { nuxDebugMsg (TEXT ("[NFileManagerGNU::FileSize] Can't get file size") ); return 0; } if (sb.st_mode & S_IFDIR) { // This is a directory return 0; } return sb.st_size; } bool NFileManagerGNU::FileExist (const TCHAR *Filename) { struct stat sb; if (stat (TCHAR_TO_ANSI (Filename), &sb) != 0) { return false; } return true; } int NFileManagerGNU::Copy (const TCHAR *DestFile, const TCHAR *SrcFile, bool OverWriteExisting, bool /* OverWriteReadOnly */, NFileTransferMonitor * /* Monitor */) { size_t nmemb; //int nmemb; FILE *ifp, *ofp; char buf[BUFSIZ]; if (OverWriteExisting) { if (access (DestFile, F_OK) == 0) { //OUTLOG((FUNC, TRWRN, "file %s already exists\n", DestFile)); return false; } else if (errno != ENOENT) { //OUTLOG((FUNC, TRERR, "access(%s, F_OK) failed\n", DestFile)); return false; } } if ( (ifp = fopen (SrcFile, "r") ) == NULL) { //OUTLOG((FUNC, TRERR, "%s doesn't exist\n", SrcFile)); return false; } if ( (ofp = fopen (DestFile, "w+") ) == NULL) { //OUTLOG((FUNC, TRERR, "can't create %s\n", DestFile)); fclose (ifp); return false; } while ( (nmemb = fread (buf, 1, sizeof (buf), ifp) ) > 0) { if (fwrite (buf, 1, nmemb, ofp) != nmemb) { //OUTLOG((FUNC, TRERR, "fwrite failed\n")); fclose (ifp); fclose (ofp); return false; } } fclose (ifp); fclose (ofp); return true; } bool NFileManagerGNU::Delete (const TCHAR *Filename, bool OverWriteReadOnly) { if (OverWriteReadOnly) { chmod (TCHAR_TO_ANSI (Filename), S_IRUSR | S_IWUSR); } if (unlink (TCHAR_TO_ANSI (Filename) ) != 0) { nuxDebugMsg (TEXT ("[NFileManagerGNU::Delete] Error deleting file '%s'."), Filename); return false; } return true; } bool NFileManagerGNU::IsReadOnly (const TCHAR *Filename) { struct stat sb; if (stat (TCHAR_TO_ANSI (Filename), &sb) != 0) { nuxDebugMsg (TEXT ("[NFileManagerGNU::IsReadOnly] Error reading file status '%s'."), Filename); return false; } if ( (sb.st_mode & S_IRUSR) && ! (sb.st_mode & S_IWUSR) ) { return true; } return false; } bool NFileManagerGNU::IsDirectory (const TCHAR *DirectoryName) { struct stat sb; if (stat (TCHAR_TO_ANSI (DirectoryName), &sb) != 0) { nuxDebugMsg (TEXT ("[NFileManagerGNU::IsDirectory] Error reading file status '%s'."), DirectoryName); return false; } if (sb.st_mode & S_IFDIR) { return true; } return false; } bool NFileManagerGNU::IsHidden (const TCHAR * /* Filename */) { return false; } /*! @return TRUE is the file exist. */ bool NFileManagerGNU::GetFileAttribute (const TCHAR *Filename, bool &isDirectory, bool &isReadOnly, bool &isHidden, long long &Size) { isDirectory = false; isReadOnly = false; isHidden = false; Size = 0; struct stat sb; if (stat (TCHAR_TO_ANSI (Filename), &sb) != 0) { return false; } if (sb.st_mode & S_IFDIR) { isDirectory = true; } if ( (sb.st_mode & S_IRUSR) && ! (sb.st_mode & S_IWUSR) ) { isReadOnly = true; } Size = sb.st_mode; return true; } bool NFileManagerGNU::Move (const TCHAR * /* Dest */, const TCHAR * /* Src */, bool /* OverWriteExisting */, bool /* OverWriteReadOnly */, NFileTransferMonitor * /* Monitor */) { nuxAssert (0); return false; } bool NFileManagerGNU::MakeDirectory (const TCHAR *Path, bool CreateCompletePath) { if (CreateCompletePath) { return NFileManagerGeneric::MakeDirectory (Path, CreateCompletePath); } mkdir (TCHAR_TO_ANSI (Path), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH); // EEXIST = -2147418092 = 0x80010014 // if((errno != 0) && (errno != EEXIST)) // { // nuxDebugMsg(TEXT("[NFileManagerGNU::MakeDirectory] Error creating directory '%s'."), Path); // return NUX_ERROR; // } return NUX_OK; } bool NFileManagerGNU::DeleteDirectory (const TCHAR * /* Path */, bool /* DeleteContentFirst */) { // if(DeleteContentFirst) // { // return NFileManagerGeneric::DeleteDirectory(Path, DeleteContentFirst); // } // if((::RemoveDirectory(Path) == 0) && (::GetLastError() != ERROR_FILE_NOT_FOUND)) // { // nuxDebugMsg(TEXT("[NFileManagerWindows::DeleteDirectory] Error deleting directory '%s' (GetLastError: %d)"), Path, ::GetLastError()); // return false; // } return true; } } nux-4.0.8+18.10.20180623/NuxCore/FileManager/NFileManagerGNU.h0000644000000000000000000001205213313373365017351 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NFILEMANAGERGNU_H #define NFILEMANAGERGNU_H #include /*----------------------------------------------------------------------------- File Manager. -----------------------------------------------------------------------------*/ namespace nux { // File manager. class NGNUSerialFileReader : public NSerializer { public: NGNUSerialFileReader (int InFileDescriptor, LogOutputDevice &InError, int InSize); ~NGNUSerialFileReader(); virtual bool Precache (int PrecacheOffset, int PrecacheSize); virtual long long Seek (long long InPos, NSerializer::SeekPos seekpos); virtual long long Tell(); virtual long long GetFileSize(); virtual bool Close(); virtual void SerializeFinal (void *V, long long Length); virtual bool isReader() { return true; } virtual bool isWriter() { return false; } protected: int m_FileDescriptor; LogOutputDevice &m_Error; long long m_FileSize; long long m_FilePos; long long m_BufferBase; int m_BufferCount; BYTE *m_Buffer; static const int sBufferSize; }; class NGNUSerialFileWriter : public NSerializer { public: NGNUSerialFileWriter (int InFileDescriptor, LogOutputDevice &InError, int InPos); ~NGNUSerialFileWriter(); virtual long long Seek (long long InPos, NSerializer::SeekPos seekpos); virtual long long Tell(); virtual bool Close(); virtual void SerializeFinal (void *V, long long Length); virtual void Flush(); virtual long long GetFileSize(); virtual bool isReader() { return false; } virtual bool isWriter() { return true; } protected: void _Flush(); int m_FileDescriptor; LogOutputDevice &m_Error; long long m_Pos; int m_BufferCount; BYTE *m_Buffer; static const int sBufferSize; NCriticalSection m_CriticalSection; }; class NFileManagerGNU : public NFileManagerGeneric { NUX_DECLARE_GLOBAL_OBJECT (NFileManagerGNU, GlobalSingletonInitializer); public: // Flags is a combination of // NSerializer::OutputErrorIfFail // NSerializer::NoOverWrite // NSerializer::OverWriteReadOnly // NSerializer::Unbuffered // NSerializer::Append // NSerializer::Read virtual NSerializer *CreateFileReader (const TCHAR *Filename, DWORD Flags, LogOutputDevice &Error = GNullDevice); virtual NSerializer *CreateFileWriter (const TCHAR *Filename, DWORD Flags, LogOutputDevice &Error = GNullDevice); /*! @return Size of the File. Return -1 if an error occurs. */ long long FileSize (const TCHAR *Filename); bool FileExist (const TCHAR *Filename); int Copy (const TCHAR *DestFile, const TCHAR *SrcFile, bool OverWriteExisting, bool OverWriteReadOnly, NFileTransferMonitor *Monitor); bool Move (const TCHAR *Dest, const TCHAR *Src, bool OverWriteExisting = true, bool OverWriteReadOnly = false, NFileTransferMonitor *Monitor = NULL); bool Delete (const TCHAR *Filename, bool OverWriteReadOnly = false); bool IsReadOnly (const TCHAR *Filename); bool IsDirectory (const TCHAR *DirectoryName); bool IsHidden (const TCHAR *Filename); /*! @return TRUE is the file exist. */ bool GetFileAttribute (const TCHAR *Filename, bool &isDirectory, bool &isReadOnly, bool &isHidden, long long &Size); bool MakeDirectory (const TCHAR *Path, bool CreateCompletePath = false); bool DeleteDirectory (const TCHAR *Path, bool DeleteContentFirst = false); void FindFiles(std::vector& /* Result */, const TCHAR* /* Filename */, bool /* Files */, bool /* Directories */) {}; void ListFilesInDirectory (std::vector& /* Result */, const TCHAR* /* DirName */) {}; double GetFileAgeSeconds (const TCHAR* /* Filename */) { return 0; }; time_t GetFileLastModified (const TCHAR * /* Filename */) { return 0; }; bool SetDefaultDirectory() { return false; }; std::string GetCurrentDirectory() { return std::string(); }; bool GetTimeStamp (const TCHAR * /* Filename */, FileTimeStamp & /* Timestamp */) { return false; }; }; } #endif // NFILEMANAGERGNU_H nux-4.0.8+18.10.20180623/NuxCore/FileManager/NFileManagerGeneric.cpp0000644000000000000000000001636413313373365020641 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "Math/MathUtility.h" namespace nux { #define COPYBLOCKSIZE 32768 int NFileManagerGeneric::Copy (const TCHAR *InDestFile, const TCHAR *InSrcFile, bool OverWriteExisting, bool OverWriteReadOnly, NFileTransferMonitor *Monitor) { // Direct file copier. if (Monitor && !Monitor->Progress (0.0) ) { return COPY_CANCELED; } int Result = COPY_OK; std::string SrcFile = InSrcFile; std::string DestFile = InDestFile; NSerializer *Src = CreateFileReader (SrcFile.c_str() ); if (!Src) { Result = COPY_READFAIL; } else { unsigned int Size = Src->GetFileSize(); NSerializer *Dest = CreateFileWriter (DestFile.c_str(), (OverWriteExisting ? 0 : FILEWRITE_NOREPLACEEXISTING) | (OverWriteReadOnly ? FILEWRITE_EVENIFREADONLY : 0) ); if (!Dest) { Result = COPY_WRITEFAIL; } else { unsigned int Percent = 0, NewPercent = 0; BYTE Buffer[COPYBLOCKSIZE]; for (unsigned int Total = 0; Total < Size; Total += sizeof (Buffer) ) { unsigned int Count = Min (Size - Total, (unsigned int) sizeof (Buffer) ); Src->Serialize (Buffer, Count); if (Src->IsError() ) { Result = COPY_READFAIL; break; } Dest->Serialize (Buffer, Count); if (Dest->IsError() ) { Result = COPY_WRITEFAIL; break; } NewPercent = Total * 100 / Size; if (Monitor && Percent != NewPercent && !Monitor->Progress ( (float) NewPercent / 100.f) ) { Result = COPY_CANCELED; break; } Percent = NewPercent; } if (Result == COPY_OK) { if (!Dest->Close() ) { Result = COPY_WRITEFAIL; } } delete Dest; if (Result != COPY_OK) { Delete (DestFile.c_str() ); } } if (Result == COPY_OK) { if (!Src->Close() ) { Result = COPY_READFAIL; } } delete Src; } if (Monitor && Result == COPY_OK && !Monitor->Progress (1.0) ) { Result = COPY_CANCELED; } return Result; } bool NFileManagerGeneric::IsDrive (const TCHAR *Path) { // Does Path refer to a drive letter or UNC path? // A UNC is a naming convention that permits you to use a network resource, // such as a network server, without formally connecting to the network resource // with a mapped drive. A UNC path uses the following syntax: // \\\ // The share is a drive: D:\Folder of ServerA = "\\ServerA\D\Folder" if (Stricmp (Path, TEXT ("") ) == 0) return 1; else if ( (ToUpperCase (Path[0]) != ToLowerCase (Path[0]) ) && (Path[1] == TEXT (':') ) && (Path[2] == 0) ) // look for "a:", "c:", "d:" ... return 1; else if (Stricmp (Path, TEXT ("\\") ) == 0) // look for "\" return 1; else if (Stricmp (Path, TEXT ("\\\\") ) == 0) // look for "\\" return 1; else if (Path[0] == TEXT ('\\') && Path[1] == TEXT ('\\') && !Strchr (Path + 2, TEXT ('\\') ) ) // look for "\\Server" return 1; else if (Path[0] == TEXT ('\\') && Path[1] == TEXT ('\\') && Strchr (Path + 2, TEXT ('\\') ) && !Strchr (Strchr (Path + 2, TEXT ('\\') ) + 1, TEXT ('\\') ) ) // look for "\\Server\share" return 1; else return 0; } bool NFileManagerGeneric::MakeDirectory (const TCHAR *Path, bool /* CreateCompletePath */) { // Support code for making a directory tree. unsigned int SlashCount = 0, CreateCount = 0; for (TCHAR Full[256] = TEXT (""), *Ptr = Full; ; *Ptr++ = *Path++) { if ( (*Path == NUX_BACKSLASH_CHAR) || (*Path == NUX_SLASH_CHAR) || (*Path == 0) ) { if ( (SlashCount++ > 0) && !IsDrive (Full) ) { *Ptr = 0; if (MakeDirectory (Full, 0) != NUX_OK) return 0; CreateCount++; } } if (*Path == 0) break; } return CreateCount != 0; } bool NFileManagerGeneric::DeleteDirectory (const TCHAR *Path, bool /* DeleteContentFirst */) { nuxAssert (Path != NULL); size_t PathLength = StringLength (Path); if (PathLength == 0) return false; std::string WildcardPath = std::string (Path); if ( (WildcardPath[PathLength - 1] != NUX_BACKSLASH_CHAR) && (WildcardPath[PathLength - 1] != NUX_SLASH_CHAR) ) WildcardPath += NUX_BACKSLASH_CHAR; WildcardPath += TEXT ("*"); std::vector List; FindFiles (List, WildcardPath.c_str(), 1, 0); for (unsigned int i = 0; i < List.size(); i++) { if (!Delete ((std::string (Path) + NUX_BACKSLASH_CHAR + List[i]).c_str(), 1) ) return 0; } List.clear(); FindFiles (List, WildcardPath.c_str(), 0, 1); for (unsigned int i = 0; i < List.size(); i++) { if (!DeleteDirectory ((std::string (Path) + NUX_BACKSLASH_CHAR + List[i]).c_str(), true) ) return 0; } List.clear(); return DeleteDirectory (Path, false); } bool NFileManagerGeneric::Move (const TCHAR *Dest, const TCHAR *Src, bool OverWriteExisting, bool OverWriteReadOnly, NFileTransferMonitor * /* Monitor */) { // Move file manually. if (Copy (Dest, Src, OverWriteExisting, OverWriteReadOnly, NULL) != COPY_OK) return 0; Delete (Src, 1); return 1; } int NFileManagerGeneric::CreateUniqueFileName (const TCHAR *Filename, const TCHAR *Extension, std::string &OutputFilename, unsigned int BaseIndex) { nuxAssert (Filename); nuxAssert (Extension); std::string FullPath (Filename); const size_t IndexMarker = FullPath.length(); // Marks location of the four-digit index. FullPath += TEXT ("0000."); FullPath += Extension; // Iterate over indices, searching for a file that doesn't exist. for (DWORD i = BaseIndex + 1 ; i < 10000 ; ++i) { FullPath[IndexMarker ] = i / 1000 + TEXT ('0'); FullPath[IndexMarker+1] = (i / 100) % 10 + TEXT ('0'); FullPath[IndexMarker+2] = (i / 10) % 10 + TEXT ('0'); FullPath[IndexMarker+3] = i % 10 + TEXT ('0'); if (GFileManager.FileSize (FullPath.c_str() ) == -1) { // The file doesn't exist; output success. OutputFilename = FullPath; return static_cast (i); } } // Can't find an empty filename slot with index in (StartVal, 9999]. return -1; } } nux-4.0.8+18.10.20180623/NuxCore/FileManager/NFileManagerGeneric.h0000644000000000000000000001707413313373365020305 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NFILEMANAGERGENERIC_H #define NFILEMANAGERGENERIC_H namespace nux { class NFileManagerWindows; class NFileTransferMonitor { public: NFileTransferMonitor() { m_bCancel = false; } virtual ~NFileTransferMonitor() {} void Cancel() { m_bCancel = true; } virtual bool Progress (float Fraction) = 0; #ifdef _WIN32 static DWORD CALLBACK CopyProgressRoutine ( NUX_IN LARGE_INTEGER TotalFileSize, NUX_IN LARGE_INTEGER TotalBytesTransferred, NUX_IN LARGE_INTEGER StreamSize, NUX_IN LARGE_INTEGER StreamBytesTransferred, NUX_IN DWORD dwStreamNumber, NUX_IN DWORD dwCallbackReason, NUX_IN HANDLE hSourceFile, NUX_IN HANDLE hDestinationFile, NUX_IN LPVOID lpData ) { NFileTransferMonitor *filetransfer = NUX_STATIC_CAST (NFileTransferMonitor *, lpData); if (filetransfer) { if (filetransfer->Progress (100.0 * double (TotalBytesTransferred.QuadPart) / double (TotalFileSize.QuadPart) ) == false) { return PROGRESS_CANCEL; } } return PROGRESS_CONTINUE; } //private: #endif BOOL m_bCancel; friend class NFileManagerWindows; }; class NFileManager { public: NFileManager() {} virtual ~NFileManager() {} /** Timestamp structure */ struct FileTimeStamp { // Time is in UTC INT Year; /* year */ INT Month; /* months since January - [0,11] */ INT Day; /* day of the month - [1,31] */ INT Hour; /* hours since midnight - [0,23] */ INT Minute; /* minutes after the hour - [0,59] */ INT Second; /* seconds after the minute - [0,59]*/ INT DayOfWeek; /* days since Sunday - [0,6] */ INT DayOfYear; /* days since January 1 - [0,365] */ INT GetJulian ( void ) const; INT GetSecondOfDay ( void ) const; bool operator == ( FileTimeStamp &Other ) const; bool operator != ( FileTimeStamp &Other ) const; bool operator < ( FileTimeStamp &Other ) const; bool operator > ( FileTimeStamp &Other ) const; bool operator >= ( FileTimeStamp &Other ) const; bool operator <= ( FileTimeStamp &Other ) const; }; virtual void Init (bool /* Startup */) {} virtual NSerializer *CreateFileReader ( const TCHAR *Filename, DWORD ReadFlags = 0, LogOutputDevice &Error = GNullDevice ) = 0; virtual NSerializer *CreateFileWriter ( const TCHAR *Filename, DWORD WriteFlags = 0, LogOutputDevice &Error = GNullDevice ) = 0; //! Return TRUE if the file exist. /*! Return TRUE if the file exist. @param Filename the full path of the file to search. @return TRUE if the file exist. */ virtual long long FileSize (const TCHAR *Filename) = 0; // Max file size is 16 terabytes minus 64 KB on NTFS. 4 gigabytes on Fat32. virtual bool FileExist (const TCHAR *Filename) = 0; virtual int Copy (const TCHAR *Dest, const TCHAR *Src, bool OverWriteExisting = true, bool OverWriteReadOnly = false, NFileTransferMonitor *Progress = NULL) = 0; virtual bool Move (const TCHAR *Dest, const TCHAR *Src, bool OverWriteExisting = true, bool OverWriteReadOnly = false, NFileTransferMonitor *Monitor = NULL) = 0; virtual bool Delete (const TCHAR *Filename, bool OverWriteReadOnly = false) = 0; virtual bool IsReadOnly (const TCHAR *Filename) = 0; virtual bool IsDirectory (const TCHAR *DirectoryName) = 0; virtual bool IsHidden (const TCHAR *Filename) = 0; virtual bool GetFileAttribute (const TCHAR *Filename, bool &isDirectory, bool &IsReadOnly, bool &IsHidden, long long &Size) = 0; virtual bool MakeDirectory (const TCHAR *Path, bool CreateCompletePath = false) = 0; //! Delete directory /*! Delete a Directory. If DeleteContent is true, The content of the directory is deleted before the directory itself; @param Path Path of the directory @param DeleteContentFirst Delete the content of the directory before deleting the directory itself. @return TRUE if the directory was deleted. */ virtual bool DeleteDirectory (const TCHAR *Path, bool DeleteContentFirst = false) = 0; /*! Creates a unique file name. The format of the name is "DirectoryPath/BaseName####.Extension" where #### is a 4-digit number in [0, 9999]. The new name is unique and does not exist in the path directory. The function returns the value of the index created for the new file name or -1 if none could be found. The return value can be saved and passed the he next call to CreateUniqueFileName in order to speed up the search. Example usage: Create a new file name for of form DirectoryPath/Filename####.ext CreateUniqueFileName(TEXT("DirectoryPath/Filename"), TEXT("ext"), Output); @param Filename Filename with optional path. @param Extension Extension. @param OutputFilename New filename. @param BaseIndex Base for index search. @return Index of the new file. -1 if the file couldn't be created The index has to be in the range [0, 9999]. */ virtual int CreateUniqueFileName (const TCHAR *Filename, const TCHAR *Extension, std::string &OutputFilename, unsigned int BaseIndex = 0xffffffff) = 0; virtual void FindFiles ( std::vector& FileNames, const TCHAR *Filename, bool Files, bool Directories ) = 0; virtual void ListFilesInDirectory ( std::vector& Result, const TCHAR *DirName) = 0; virtual time_t GetFileLastModified (const TCHAR *Filename) = 0; virtual double GetFileAgeSeconds (const TCHAR *Filename) = 0; virtual bool SetDefaultDirectory() = 0; virtual std::string GetCurrentDirectory() = 0; virtual bool GetTimeStamp ( const TCHAR *Path, FileTimeStamp &Timestamp ) = 0; protected: }; class NFileManagerGeneric : public NFileManager { public: int Copy (const TCHAR *InDestFile, const TCHAR *InSrcFile, bool OverWriteExisting, bool OverWriteReadOnly, NFileTransferMonitor *Monitor); bool MakeDirectory (const TCHAR *Path, bool CreateCompletePath = false); bool DeleteDirectory (const TCHAR *Path, bool DeleteContentFirst = false); bool Move (const TCHAR *Dest, const TCHAR *Src, bool OverWriteExisting = true, bool OverWriteReadOnly = false, NFileTransferMonitor *Monitor = NULL); int CreateUniqueFileName (const TCHAR *Filename, const TCHAR *Extension, std::string &OutputFilename, unsigned int BaseIndex = 0xffffffff); bool IsDrive (const TCHAR *Path); }; } #endif // NFILEMANAGERGENERIC_H nux-4.0.8+18.10.20180623/NuxCore/FileManager/NFileManagerWindows.cpp0000644000000000000000000006257413313373365020723 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "Math/MathUtility.h" namespace nux { // Choose the size so it is a power of 2. Example (size-1)= 11111111. const int NWindowsSerialFileReader::sBufferSize = 1024; NWindowsSerialFileReader::NWindowsSerialFileReader (HANDLE InHandle, LogOutputDevice &InError) : m_FileHandle (InHandle) , m_Error (InError) , m_FilePos (0) , m_BufferBase (0) , m_BufferCount (0) { m_Buffer = new BYTE[sBufferSize]; m_FileSize = GetFileSize(); } NWindowsSerialFileReader::~NWindowsSerialFileReader() { NUX_SAFE_DELETE_ARRAY (m_Buffer); if (m_FileHandle) { Close(); } } bool NWindowsSerialFileReader::Precache (int PrecacheOffset, int PrecacheSize) { // Only pre-cache at current position and avoid work if pre-caching same offset twice. if ( (m_FilePos == PrecacheOffset) && (!m_BufferBase || !m_BufferCount || m_BufferBase != m_FilePos) ) { m_BufferBase = m_FilePos; // (sBufferSize - 1) contains only '1', i.e 1111111111. // So (m_FilePos & (sBufferSize-1)) is equal to m_FilePos if m_FilePos <= (sBufferSize-1). m_BufferCount = Min (Min (PrecacheSize, (int) (sBufferSize - (m_FilePos & (sBufferSize - 1) ) ) ), m_FileSize - m_FilePos); unsigned int Count = 0; //GTotalBytesReadViaFileManager += m_BufferCount; ::ReadFile (m_FileHandle, m_Buffer, m_BufferCount, NUX_REINTERPRET_CAST (DWORD *, &Count), NULL); if (Count != m_BufferCount) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("ReadFile failed: Count=%i BufferCount=%i Error=%s"), Count, m_BufferCount, inlGetSystemErrorMessage() ); } } return TRUE; } long long NWindowsSerialFileReader::Seek (long long InPos, NSerializer::SeekPos seekpos) { nuxAssert (InPos >= 0); nuxAssert (InPos <= m_FileSize); Flush(); // Because we precache our reads, we must perform Seek accordingly. LARGE_INTEGER pos; pos.QuadPart = m_FilePos; LARGE_INTEGER filepos; filepos.QuadPart = 0; // Set the file pointer to m_FilePos. if (::SetFilePointerEx (m_FileHandle, pos, &filepos, FILE_BEGIN) == 0) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("SetFilePointer Failed %i/%i: %i %s"), InPos, m_FileSize, m_FilePos, inlGetSystemErrorMessage() ); } // Now the file pointer is current with what we have read so far. pos.QuadPart = InPos; filepos.QuadPart = 0; if (::SetFilePointerEx (m_FileHandle, pos, &filepos, (seekpos == SeekStart) ? FILE_BEGIN : (seekpos == SeekCurrent) ? FILE_CURRENT : FILE_END) == 0) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("SetFilePointer Failed %i/%i: %i %s"), InPos, m_FileSize, m_FilePos, inlGetSystemErrorMessage() ); } m_FilePos = filepos.QuadPart; m_BufferBase = 0; m_BufferCount = 0; Precache (m_FilePos, sBufferSize); return filepos.QuadPart; } long long NWindowsSerialFileReader::Tell() { // Flush(); // LARGE_INTEGER pos; // LARGE_INTEGER filepos; // pos.QuadPart = 0; // ::SetFilePointerEx(m_FileHandle, pos, &filepos, FILE_CURRENT); // return filepos.QuadPart; return m_FilePos; } long long NWindowsSerialFileReader::GetFileSize() { nuxAssert (m_FileHandle); if (m_FileHandle == NULL) return -1; long long Size = 0; if (::GetFileSizeEx (m_FileHandle, NUX_REINTERPRET_CAST (PLARGE_INTEGER, &Size) ) == 0) { Size = -1; } m_FileSize = Size > 0 ? Size : 0; return Size; } bool NWindowsSerialFileReader::Close() { if (m_FileHandle) { CloseHandle (m_FileHandle); } m_FileHandle = NULL; return !m_ErrorCode; } void NWindowsSerialFileReader::SerializeFinal (void* Dest, long long Length) { nuxAssert (Dest); while (Length > 0) { int DataSize = Min (Length, m_BufferBase + m_BufferCount - m_FilePos); if (DataSize == 0) { if (Length >= sBufferSize) { int Count = 0; //GTotalBytesReadViaFileManager += Length; ReadFile (m_FileHandle, Dest, Length, (DWORD*) &Count, NULL); if (Count != Length) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("ReadFile failed: Count=%i Length=%i Error=%s"), Count, Length, inlGetSystemErrorMessage() ); } m_FilePos += Length; m_BufferBase += Length; return; } Precache (m_FilePos, 0x7FFFFFFF); DataSize = Min (Length, m_BufferBase + m_BufferCount - m_FilePos); if (DataSize <= 0) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("ReadFile beyond EOF %i+%i/%i"), m_FilePos, Length, m_FileSize); } if (m_ErrorCode) return; } Memcpy (Dest, m_Buffer + m_FilePos - m_BufferBase, DataSize); m_FilePos += DataSize; Length -= DataSize; Dest = (BYTE *) Dest + DataSize; } } ////////////////////////////////////////////////////////////////////////// // Choose the size so it is a power of 2. Example (size-1)= 11111111. const int NWindowsSerialFileWriter::sBufferSize = 32; //NCriticalSection NWindowsSerialFileWriter::m_CriticalSection; NWindowsSerialFileWriter::NWindowsSerialFileWriter (HANDLE InHandle, LogOutputDevice &InError) : m_FileHandle (InHandle) , m_Error (InError) , m_BufferCount (0) { m_Pos = Tell(); m_Buffer = new BYTE[sBufferSize]; } NWindowsSerialFileWriter::~NWindowsSerialFileWriter() { NUX_SAFE_DELETE_ARRAY (m_Buffer); if (m_FileHandle) Close(); m_FileHandle = NULL; } long long NWindowsSerialFileWriter::Seek (long long InPos, NSerializer::SeekPos seekpos) { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileHandle); if (m_FileHandle == NULL) return -1; _Flush(); LARGE_INTEGER pos; pos.QuadPart = InPos; LARGE_INTEGER filepos; filepos.QuadPart = 0; if (::SetFilePointerEx (m_FileHandle, pos, &filepos, (seekpos == SeekStart) ? FILE_BEGIN : (seekpos == SeekCurrent) ? FILE_CURRENT : FILE_END) == 0) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("SeekFailed") ); } m_Pos = filepos.QuadPart; return filepos.QuadPart; } long long NWindowsSerialFileWriter::Tell() { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileHandle); if (m_FileHandle == NULL) return -1; _Flush(); LARGE_INTEGER pos; LARGE_INTEGER filepos; filepos.QuadPart = 0; pos.QuadPart = 0; ::SetFilePointerEx (m_FileHandle, pos, &filepos, FILE_CURRENT); return filepos.QuadPart; } bool NWindowsSerialFileWriter::Close() { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileHandle); if (m_FileHandle == NULL) return true; _Flush(); if (m_FileHandle && !CloseHandle (m_FileHandle) ) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("WriteFailed") ); } m_FileHandle = NULL; return !m_ErrorCode; } long long NWindowsSerialFileWriter::GetFileSize() { nuxAssert (m_FileHandle); if (m_FileHandle == NULL) return -1; long long Size = 0; if (::GetFileSizeEx (m_FileHandle, NUX_REINTERPRET_CAST (PLARGE_INTEGER, &Size) ) == 0) { Size = -1; } return Size; } void NWindowsSerialFileWriter::SerializeFinal (void *V, long long Length) { // This method is not re-entrant by itself. It relies on m_Buffer and other variables // that belong to this object. Therefore, it is not thread safe. We add a critical section // to make it thread safe. NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileHandle); nuxAssert (V); NUX_RETURN_IF_NULL (m_FileHandle); m_Pos += Length; int FreeSpace; while (Length > (FreeSpace = sBufferSize - m_BufferCount) ) { // m_Buffer is Full. Write it to the file. Memcpy (m_Buffer + m_BufferCount, V, FreeSpace); m_BufferCount += FreeSpace; Length -= FreeSpace; V = (BYTE *) V + FreeSpace; _Flush(); } if (Length) { Memcpy (m_Buffer + m_BufferCount, V, Length); m_BufferCount += Length; // Count the number of Characters stored in m_Buffer. } } void NWindowsSerialFileWriter::Flush() { NScopeLock Scope (&m_CriticalSection); nuxAssert (m_FileHandle); if (m_FileHandle == NULL) return; _Flush(); } void NWindowsSerialFileWriter::_Flush() { //GTotalBytesWrittenViaFileManager += m_BufferCount; if (m_BufferCount) { int Result = 0; if (!WriteFile (m_FileHandle, m_Buffer, m_BufferCount, (DWORD *) &Result, NULL) ) { m_ErrorCode = 1; m_Error.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("[NWindowsSerialFileWriter::_Flush] Write failed") ); } } m_BufferCount = 0; } ////////////////////////////////////////////////////////////////////////// NUX_IMPLEMENT_GLOBAL_OBJECT (NFileManagerWindows); void NFileManagerWindows::Constructor() { } void NFileManagerWindows::Destructor() { } HANDLE NFileManagerWindows::CreateReadFileHandle (const TCHAR *Filename, DWORD Flags) { DWORD Access = GENERIC_READ; DWORD Create = OPEN_EXISTING; DWORD SharedModeFlags = 0; SharedModeFlags |= (Flags & NSerializer::Read) ? FILE_SHARE_READ : 0; SharedModeFlags |= (Flags & NSerializer::Write) ? FILE_SHARE_WRITE : 0; HANDLE Handle = ::CreateFile (Filename, Access, SharedModeFlags, NULL, Create, FILE_ATTRIBUTE_NORMAL, NULL); if (Handle == INVALID_HANDLE_VALUE) { if (Flags & NSerializer::OutputErrorIfFail) nuxError (TEXT ("Failed to read file: %s"), Filename); } return Handle; } NSerializer *NFileManagerWindows::CreateFileReader (const TCHAR *Filename, DWORD Flags, LogOutputDevice &Error) { HANDLE Handle = CreateReadFileHandle (Filename, Flags); if (Handle == INVALID_HANDLE_VALUE) { return 0; } return new NWindowsSerialFileReader (Handle, Error); } HANDLE NFileManagerWindows::CreateWriteFileHandle (const TCHAR *Filename, DWORD Flags) { if (Flags & NSerializer::OverWriteReadOnly) { ::SetFileAttributes (Filename, 0); } DWORD Access = GENERIC_WRITE; DWORD SharedModeFlags = 0; SharedModeFlags |= (Flags & NSerializer::Read) ? FILE_SHARE_READ : 0; SharedModeFlags |= (Flags & NSerializer::Write) ? FILE_SHARE_WRITE : 0; DWORD Create = 0; Create |= (Flags & NSerializer::Append) ? OPEN_ALWAYS : 0; Create |= (Flags & NSerializer::NoOverWrite) ? CREATE_NEW /*fail if the file already exist*/ : CREATE_ALWAYS /*create the file if it does not exist*/; HANDLE Handle = ::CreateFile (Filename, Access, SharedModeFlags, NULL, Create, FILE_ATTRIBUTE_NORMAL, NULL); if (Handle == INVALID_HANDLE_VALUE) { if (Flags & NSerializer::OutputErrorIfFail) { nuxError (TEXT ("[NFileManagerWindows::CreateFileWriter] Failed to create file %s (GetLastError: %d)"), Filename, ::GetLastError() ); } } if ( (Flags & NSerializer::Append) && (Handle != INVALID_HANDLE_VALUE) ) { int Pos = ::SetFilePointer (Handle, 0, 0, FILE_END); } return Handle; } NSerializer *NFileManagerWindows::CreateFileWriter (const TCHAR *Filename, DWORD Flags, LogOutputDevice &Error) { HANDLE Handle = CreateWriteFileHandle (Filename, Flags); if (Handle == INVALID_HANDLE_VALUE) { return 0; } return new NWindowsSerialFileWriter (Handle, Error); } /*! @return Size of the File. Return -1 if an error occurs. */ long long NFileManagerWindows::FileSize (const TCHAR *Filename) { HANDLE Handle = ::CreateFile (Filename, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (Handle == INVALID_HANDLE_VALUE) { LPVOID lpMsgBuf = 0; ::FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ::GetLastError(), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); nuxDebugMsg (TEXT ("[NFileManagerWindows::FileSize] Failed to open file %s for attribute read (GetLastError: %d - %s)"), Filename, ::GetLastError(), lpMsgBuf); ::LocalFree (lpMsgBuf); return -1; } long long Size = 0; if (::GetFileSizeEx (Handle, NUX_REINTERPRET_CAST (PLARGE_INTEGER, &Size) ) == 0) { Size = -1; } CloseHandle (Handle); return Size; } bool NFileManagerWindows::FileExist (const TCHAR *Filename) { WIN32_FILE_ATTRIBUTE_DATA FileAttrData; if (::GetFileAttributesEx (Filename, GetFileExInfoStandard, NUX_STATIC_CAST (void *, &FileAttrData) ) ) { return true; } return false; } int NFileManagerWindows::Copy (const TCHAR *DestFile, const TCHAR *SrcFile, bool OverWriteExisting, bool OverWriteReadOnly, NFileTransferMonitor *Monitor) { // In case file exist and OverWriteReadOnly is true, Remove the ReadOnly attribute from the file. if (OverWriteReadOnly) { ::SetFileAttributes (DestFile, FILE_ATTRIBUTE_NORMAL); } DWORD Flags = (OverWriteExisting ? 0 : COPY_FILE_FAIL_IF_EXISTS); BOOL *pCancel = NULL; if (Monitor) pCancel = & (Monitor->m_bCancel); if (::CopyFileEx (SrcFile, DestFile, NFileTransferMonitor::CopyProgressRoutine, NUX_REINTERPRET_CAST (void *, Monitor), pCancel, Flags) == 0) { LPVOID lpMsgBuf = 0; ::FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ::GetLastError(), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); nuxDebugMsg (TEXT ("[NFileManagerWindows::Copy] Error copying file from '%s' to '%s'(GetLastError: %d - %s)"), SrcFile, DestFile, ::GetLastError(), lpMsgBuf); ::LocalFree (lpMsgBuf); return false; } ::SetFileAttributes (DestFile, FILE_ATTRIBUTE_NORMAL); return true; } bool NFileManagerWindows::Delete (const TCHAR *Filename, bool OverWriteReadOnly) { if (OverWriteReadOnly) { ::SetFileAttributes (Filename, FILE_ATTRIBUTE_NORMAL); } if ( (::DeleteFile (Filename) == 0) && (GetLastError() != ERROR_FILE_NOT_FOUND) ) { LPVOID lpMsgBuf = 0; ::FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ::GetLastError(), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); nuxDebugMsg (TEXT ("[NFileManagerWindows::Delete] Error deleting file '%s' (GetLastError: %d - %s)"), Filename, ::GetLastError(), lpMsgBuf); ::LocalFree (lpMsgBuf); return false; } return true; } bool NFileManagerWindows::IsReadOnly (const TCHAR *Filename) { WIN32_FILE_ATTRIBUTE_DATA FileAttrData; if (::GetFileAttributesEx (Filename, GetFileExInfoStandard, NUX_STATIC_CAST (void *, &FileAttrData) ) ) { return ( (FileAttrData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0); } else { nuxDebugMsg (TEXT ("[NFileManagerWindows::IsReadOnly]: Error reading attributes for file '%s'"), Filename); } return false; } bool NFileManagerWindows::IsDirectory (const TCHAR *DirectoryName) { WIN32_FILE_ATTRIBUTE_DATA FileAttrData; if (::GetFileAttributesEx (DirectoryName, GetFileExInfoStandard, NUX_STATIC_CAST (void *, &FileAttrData) ) ) { return ( (FileAttrData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); } else { nuxDebugMsg (TEXT ("[NFileManagerWindows::IsDirectory]: Error reading attributes for directory '%s'"), DirectoryName); } return false; } bool NFileManagerWindows::IsHidden (const TCHAR *Filename) { WIN32_FILE_ATTRIBUTE_DATA FileAttrData; if (::GetFileAttributesEx (Filename, GetFileExInfoStandard, NUX_STATIC_CAST (void *, &FileAttrData) ) ) { return ( (FileAttrData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0); } else { nuxDebugMsg (TEXT ("[NFileManagerWindows::IsHidden]: Error reading attributes for file '%s'"), Filename); } return false; } /*! @return TRUE is the file exist. */ bool NFileManagerWindows::GetFileAttribute (const TCHAR *Filename, bool &isDirectory, bool &isReadOnly, bool &isHidden, long long &Size) { isDirectory = false; isReadOnly = false; isHidden = false; Size = 0; WIN32_FILE_ATTRIBUTE_DATA FileAttrData; if (::GetFileAttributesEx (Filename, GetFileExInfoStandard, (void *) &FileAttrData) ) { isDirectory = ( (FileAttrData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); isReadOnly = ( (FileAttrData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0); isHidden = ( (FileAttrData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0); Size = FileAttrData.nFileSizeLow | ( (long long) (FileAttrData.nFileSizeHigh) << 32); } else { nuxDebugMsg (TEXT ("[NFileManagerWindows::GetFileAttribute]: Error reading attributes for file '%s'"), Filename); return (0); } return TRUE; } bool NFileManagerWindows::Move (const TCHAR *Dest, const TCHAR *Src, bool Replace, bool EvenIfReadOnly, NFileTransferMonitor *Monitor) { DWORD Flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_FAIL_IF_NOT_TRACKABLE; Flags |= (EvenIfReadOnly ? MOVEFILE_REPLACE_EXISTING : 0); BOOL *pCancel = NULL; if (Monitor) pCancel = & (Monitor->m_bCancel); if (::MoveFileWithProgress (Src, Dest, NFileTransferMonitor::CopyProgressRoutine, NUX_REINTERPRET_CAST (void *, Monitor), Flags) != 0) { nuxDebugMsg (TEXT ("[NFileManagerWindows::Move] Error moving file '%s' to '%s' (GetLastError: %d)"), Src, Dest, ::GetLastError() ); return false; } return true; } bool NFileManagerWindows::MakeDirectory (const TCHAR *Path, bool CreateCompletePath) { if (CreateCompletePath) { return NFileManagerGeneric::MakeDirectory (Path, CreateCompletePath); } if ( (::CreateDirectory (Path, NULL) == 0) && (::GetLastError() != ERROR_ALREADY_EXISTS) ) { nuxDebugMsg (TEXT ("[NFileManagerWindows::MakeDirectory] Error creating directory '%s' (GetLastError: %d)"), Path, ::GetLastError() ); return NUX_ERROR; } return NUX_OK; } bool NFileManagerWindows::DeleteDirectory (const TCHAR *Path, bool DeleteContentFirst) { if (DeleteContentFirst) { return NFileManagerGeneric::DeleteDirectory (Path, DeleteContentFirst); } if ( (::RemoveDirectory (Path) == 0) && (::GetLastError() != ERROR_FILE_NOT_FOUND) ) { nuxDebugMsg (TEXT ("[NFileManagerWindows::DeleteDirectory] Error deleting directory '%s' (GetLastError: %d)"), Path, ::GetLastError() ); return false; } return true; } void NFileManagerWindows::FindFiles (std::vector& Result, const TCHAR *Filename, bool Files, bool Directories) { HANDLE Handle = INVALID_HANDLE_VALUE; WIN32_FIND_DATA SearchData; Handle = ::FindFirstFile (Filename, &SearchData); if (Handle != INVALID_HANDLE_VALUE) { do { if (Stricmp (SearchData.cFileName, TEXT (".") ) && Stricmp (SearchData.cFileName, TEXT ("..") ) && ! (SearchData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) && ! (SearchData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ) { if ( (SearchData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? Directories : Files) Result.push_back (std::string(SearchData.cFileName) ); } } while (::FindNextFile (Handle, &SearchData) ); } if (Handle != INVALID_HANDLE_VALUE) ::FindClose (Handle); } void NFileManagerWindows::ListFilesInDirectory (std::vector& Result, const TCHAR *DirName) { WIN32_FIND_DATA SearchData; HANDLE Handle = INVALID_HANDLE_VALUE; std::string DirectoryName = DirName; DirectoryName += TEXT ("\\*"); Handle = ::FindFirstFile (DirectoryName.c_str(), &SearchData); if (Handle != INVALID_HANDLE_VALUE) { // List all the other files in the directory. do { if (Stricmp (SearchData.cFileName, TEXT (".") ) && Stricmp (SearchData.cFileName, TEXT ("..") ) && ! (SearchData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) && ! (SearchData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ) { Result.push_back(std::string(SearchData.cFileName)); } } while (::FindNextFile (Handle, &SearchData) ); } if (Handle != INVALID_HANDLE_VALUE) ::FindClose (Handle); } double NFileManagerWindows::GetFileAgeSeconds (const TCHAR *Filename) { struct _stat FileInfo; if (_tstat (Filename, &FileInfo) == 0) { time_t CurrentTime, FileTime; FileTime = FileInfo.st_mtime; time (&CurrentTime); return difftime (CurrentTime, FileTime); } return -1.0; } time_t NFileManagerWindows::GetFileLastModified (const TCHAR *Filename) { struct _stat FileInfo; if (_tstat (Filename, &FileInfo) == 0) { time_t FileTime; FileTime = FileInfo.st_mtime; return FileTime; } return -1; } // bool GetFileLastModified(const TCHAR* Filename, SYSTEMTIME& sysTime, bool bLocalTime) // { // ZeroMemory(&sysTime, sizeof(SYSTEMTIME)); // // DWORD dwAttr = ::GetFileAttributes(Filename); // // // files only // if (dwAttr == 0xFFFFFFFF) // return false; // // WIN32_FIND_DATA findFileData; // HANDLE hFind = ::FindFirstFile((LPTSTR)Filename, &findFileData); // // if (hFind == INVALID_HANDLE_VALUE) // return FALSE; // // ::FindClose(hFind); // // FILETIME ft = findFileData.ftLastWriteTime; // // if (bLocalTime) // ::FileTimeToLocalFileTime(&findFileData.ftLastWriteTime, &ft); // // ::FileTimeToSystemTime(&ft, &sysTime); // return true; // } bool NFileManagerWindows::SetDefaultDirectory() { return CALL_OS_TCHAR_FUNCTION(SetCurrentDirectoryW(GetProgramDirectory()), SetCurrentDirectoryA(TCHAR_TO_ANSI(GetProgramDirectory().c_str()))) != 0; } std::string NFileManagerWindows::GetCurrentDirectory() { #if UNICODE TCHAR Buffer[1024] = TEXT (""); ::GetCurrentDirectoryW (NUX_ARRAY_COUNT (Buffer), Buffer); return std::string(Buffer); #else ANSICHAR Buffer[1024] = ""; ::GetCurrentDirectoryA (NUX_ARRAY_COUNT (Buffer), Buffer); return std::string(Buffer); #endif } bool NFileManagerWindows::GetTimeStamp (const TCHAR *Filename, FileTimeStamp &Timestamp) { Memzero (&Timestamp, sizeof (Timestamp) ); struct _stat FileInfo; if (_tstat (Filename, &FileInfo) == 0) { #ifdef WIN32_SECURE __time64_t FileTime; // FileTime represents seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC). FileTime = FileInfo.st_mtime; tm pTime; // _gmtime64_s can express time up to 23:59:59, December 31, 3000, UTC _gmtime64_s (&pTime, &FileTime); Timestamp.Day = pTime.tm_mday; Timestamp.DayOfWeek = pTime.tm_wday; Timestamp.DayOfYear = pTime.tm_yday; Timestamp.Hour = pTime.tm_hour; Timestamp.Minute = pTime.tm_min; Timestamp.Second = pTime.tm_sec; Timestamp.Year = pTime.tm_year + 1900; #else time_t FileTime; // FileTime represents seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC). FileTime = FileInfo.st_mtime; // gmtime can express time up to 03:14:07 January 19, 2038, UTC tm *pTime = gmtime (&FileTime); Timestamp.Day = pTime->tm_mday; Timestamp.DayOfWeek = pTime->tm_wday; Timestamp.DayOfYear = pTime->tm_yday; Timestamp.Hour = pTime->tm_hour; Timestamp.Minute = pTime->tm_min; Timestamp.Second = pTime->tm_sec; Timestamp.Year = pTime->tm_year + 1900; #endif return TRUE; } return FALSE; } } nux-4.0.8+18.10.20180623/NuxCore/FileManager/NFileManagerWindows.h0000644000000000000000000001205513313373365020355 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NFILEMANAGERWINDOWS_H #define NFILEMANAGERWINDOWS_H /*----------------------------------------------------------------------------- File Manager. -----------------------------------------------------------------------------*/ // File manager. namespace nux { class NWindowsSerialFileReader: public NSerializer { public: NWindowsSerialFileReader (HANDLE InHandle, LogOutputDevice &InError); ~NWindowsSerialFileReader(); virtual bool Precache (int PrecacheOffset, int PrecacheSize); virtual long long Seek (long long InPos, NSerializer::SeekPos seekpos); virtual long long Tell(); virtual long long GetFileSize(); virtual bool Close(); virtual void SerializeFinal (void *V, long long Length); virtual bool isReader() { return true; } virtual bool isWriter() { return false; } protected: HANDLE m_FileHandle; LogOutputDevice &m_Error; long long m_FileSize; long long m_FilePos; long long m_BufferBase; int m_BufferCount; BYTE *m_Buffer; static const int sBufferSize; }; class NWindowsSerialFileWriter : public NSerializer { public: NWindowsSerialFileWriter (HANDLE InHandle, LogOutputDevice &InError); ~NWindowsSerialFileWriter(); virtual long long Seek (long long InPos, NSerializer::SeekPos seekpos); virtual long long Tell(); virtual bool Close(); virtual void SerializeFinal (void *V, long long Length); virtual void Flush(); virtual long long GetFileSize(); virtual bool isReader() { return false; } virtual bool isWriter() { return true; } protected: void _Flush(); HANDLE m_FileHandle; LogOutputDevice &m_Error; long long m_Pos; int m_BufferCount; BYTE *m_Buffer; static const int sBufferSize; NCriticalSection m_CriticalSection; }; class NFileManagerWindows : public NFileManagerGeneric { NUX_DECLARE_GLOBAL_OBJECT (NFileManagerWindows, GlobalSingletonInitializer); public: // Flags is a combination of // NSerializer::OutputErrorIfFail // NSerializer::NoOverWrite // NSerializer::OverWriteReadOnly // NSerializer::Unbuffered // NSerializer::Append // NSerializer::Read virtual NSerializer *CreateFileReader (const TCHAR *Filename, DWORD Flags, LogOutputDevice &Error = GNullDevice); virtual NSerializer *CreateFileWriter (const TCHAR *Filename, DWORD Flags, LogOutputDevice &Error = GNullDevice); HANDLE CreateReadFileHandle (const TCHAR *Filename, DWORD Flags); HANDLE CreateWriteFileHandle (const TCHAR *Filename, DWORD Flags); /*! @return Size of the File. Return -1 if an error occurs. */ long long FileSize (const TCHAR *Filename); bool FileExist (const TCHAR *Filename); int Copy (const TCHAR *DestFile, const TCHAR *SrcFile, bool OverWriteExisting, bool OverWriteReadOnly, NFileTransferMonitor *Monitor); bool Move (const TCHAR *Dest, const TCHAR *Src, bool OverWriteExisting = true, bool OverWriteReadOnly = false, NFileTransferMonitor *Monitor = NULL); bool Delete (const TCHAR *Filename, bool OverWriteReadOnly = false); bool IsReadOnly (const TCHAR *Filename); bool IsDirectory (const TCHAR *DirectoryName); bool IsHidden (const TCHAR *Filename); /*! @return TRUE is the file exist. */ bool GetFileAttribute (const TCHAR *Filename, bool &isDirectory, bool &isReadOnly, bool &isHidden, long long &Size); bool MakeDirectory (const TCHAR *Path, bool CreateCompletePath = false); bool DeleteDirectory (const TCHAR *Path, bool DeleteContentFirst = false); void FindFiles (std::vector& Result, const TCHAR *Filename, bool Files, bool Directories); void ListFilesInDirectory (std::vector& Result, const TCHAR *DirName); double GetFileAgeSeconds (const TCHAR *Filename); time_t GetFileLastModified (const TCHAR *Filename); bool GetFileLastModified (const TCHAR *Filename, SYSTEMTIME &sysTime, bool bLocalTime); bool SetDefaultDirectory(); std::string GetCurrentDirectory(); bool GetTimeStamp (const TCHAR *Filename, FileTimeStamp &Timestamp); }; } #endif // NFILEMANAGERWINDOWS_H nux-4.0.8+18.10.20180623/NuxCore/FileManager/NSerializer.cpp0000644000000000000000000001167013313373365017276 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" namespace nux { // template // void NSerializer::SerializeBuffer(T* buffer, unsigned long long Length, unsigned long long ElementSize) // { // for(unsigned long long i = 0; i < Length; i++) // { // unsigned char* bytebuffer = (unsigned char*)(&buffer[i]); // Serialize(bytebuffer, ElementSize); // } // } // NSerializer& operator << (NSerializer& Sr, std::string& s) // { // Sr.SerializeBuffer(NUX_CONST_CAST(TCHAR*, s.GetTCharPtr()), s.Size()+1, sizeof(TCHAR)); // return Sr; // } // // NSerializer& operator << (NSerializer& Sr, std::string& s) // { // Sr.SerializeBuffer(NUX_CONST_CAST(char*, s.c_str()), s.size()+1, sizeof(char)); // return Sr; // } void NSerializer::Serialize (char &data) { SerializeFinal (&data, sizeof (char) ); } void NSerializer::Serialize (wchar_t &data) { SerializeFinal (&data, sizeof (wchar_t) ); } void NSerializer::Serialize (bool &data) { SerializeFinal (&data, sizeof (bool) ); } void NSerializer::Serialize (unsigned char &data) { SerializeFinal (&data, sizeof (unsigned char) ); } void NSerializer::Serialize (unsigned short &data) { SerializeFinal (&data, sizeof (unsigned short) ); } void NSerializer::Serialize (short &data) { SerializeFinal (&data, sizeof (short) ); } void NSerializer::Serialize (unsigned int &data) { SerializeFinal (&data, sizeof (unsigned int) ); } void NSerializer::Serialize (int &data) { SerializeFinal (&data, sizeof (int) ); } void NSerializer::Serialize (long &data) { SerializeFinal (&data, sizeof (long) ); } void NSerializer::Serialize (unsigned long &data) { SerializeFinal (&data, sizeof (unsigned long) ); } void NSerializer::Serialize (float &data) { SerializeFinal (&data, sizeof (float) ); } void NSerializer::Serialize (double &data) { SerializeFinal (&data, sizeof (double) ); } void NSerializer::Serialize (unsigned long long &data) { SerializeFinal (&data, sizeof (unsigned long long) ); } void NSerializer::Serialize (long long &data) { SerializeFinal (&data, sizeof (long long) ); } void NSerializer::Serialize (wchar_t *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (bool *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (char *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (unsigned char *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (unsigned short *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (short *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (unsigned int *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (int *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (long *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (unsigned long *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (float *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (double *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (unsigned long long *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } void NSerializer::Serialize (long long *buffer, unsigned int len, unsigned int stride) { SerializeFinal (buffer, len * stride); } } nux-4.0.8+18.10.20180623/NuxCore/FileManager/NSerializer.h0000644000000000000000000001536013313373365016743 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NSERIALIZER_H #define NSERIALIZER_H namespace nux { class NSerializer { public: enum { OutputErrorIfFail = 0x01, NoOverWrite = 0x02, OverWriteReadOnly = 0x04, Unbuffered = 0x08, Append = 0x10, Read = 0x20, Write = 0x40, }; typedef enum { SeekStart = 0x00, SeekCurrent = 0x01, SeekEnd = 0x02, } SeekPos; // NSerializer interface. virtual ~NSerializer() {} virtual void SerializeFinal (void *V, long long Length) = 0; // template // void SerializeBuffer( T* buffer, unsigned long long NumberOfElements, unsigned long long ElementSize = sizeof(T)) // { // for(unsigned long long i = 0; i < NumberOfElements; i++) // { // unsigned char* bytebuffer = (unsigned char*)(&buffer[i]); // Serialize(bytebuffer, ElementSize); // } // } virtual bool isReader() = 0; virtual bool isWriter() = 0; virtual long long Tell() = 0; virtual long long GetFileSize() { return -1; } virtual long long Seek (long long FilePos, NSerializer::SeekPos) = 0; virtual bool Precache (INT /* PrecacheOffset */, INT /* PrecacheSize */) { return TRUE; } virtual void Flush() {}; virtual bool Close() = 0; virtual bool GetError() { return m_ErrorCode; } NSerializer &ByteOrderSerialize (void *V, INT Length ) { BOOL SwapBytes = 0; if ( SwapBytes ) { // Transferring between memory and file, so flip the byte order. for ( INT i = Length - 1; i >= 0; i-- ) Serialize ( (unsigned char *) V + i, 1 ); } else { // Transferring around within memory, so keep the byte order. Serialize ( (unsigned char *) V, Length); } return *this; } // Constructor. NSerializer() { Reset(); } NUX_INLINE bool IsError() const { return m_ErrorCode; } virtual void Serialize (char &data); virtual void Serialize (wchar_t &data); virtual void Serialize (bool &data); virtual void Serialize (unsigned char &data); virtual void Serialize (unsigned short &data); virtual void Serialize (short &data); virtual void Serialize (unsigned int &data); virtual void Serialize (int &data); virtual void Serialize (long &data); virtual void Serialize (unsigned long &data); virtual void Serialize (float &data); virtual void Serialize (double &data); virtual void Serialize (unsigned long long &data); virtual void Serialize (long long &data); virtual void Serialize (wchar_t *buffer, unsigned int len, unsigned int stride = sizeof (wchar_t) ); virtual void Serialize (bool *buffer, unsigned int len, unsigned int stride = sizeof (bool) ); virtual void Serialize (char *buffer, unsigned int len, unsigned int stride = sizeof (char) ); virtual void Serialize (unsigned char *buffer, unsigned int len, unsigned int stride = sizeof (unsigned char) ); virtual void Serialize (unsigned short *buffer, unsigned int len, unsigned int stride = sizeof (unsigned short) ); virtual void Serialize (short *buffer, unsigned int len, unsigned int stride = sizeof (short) ); virtual void Serialize (unsigned int *buffer, unsigned int len, unsigned int stride = sizeof (unsigned int) ); virtual void Serialize (int *buffer, unsigned int len, unsigned int stride = sizeof (int) ); virtual void Serialize (long *buffer, unsigned int len, unsigned int stride = sizeof (long) ); virtual void Serialize (unsigned long *buffer, unsigned int len, unsigned int stride = sizeof (unsigned long) ); virtual void Serialize (float *buffer, unsigned int len, unsigned int stride = sizeof (float) ); virtual void Serialize (double *buffer, unsigned int len, unsigned int stride = sizeof (double) ); virtual void Serialize (unsigned long long *buffer, unsigned int len, unsigned int stride = sizeof (unsigned long long) ); virtual void Serialize (long long *buffer, unsigned int len, unsigned int stride = sizeof (long long) ); virtual void Identify (const char* /* name */) {}; virtual void Begin() {}; virtual void End() {}; protected: void Reset (void) { m_ErrorCode = FALSE; } bool m_ErrorCode; }; NUX_INLINE NSerializer &operator << (NSerializer &Sr, bool &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, char &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, unsigned char &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, unsigned short &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, short &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, unsigned int &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, int &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, long &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, unsigned long &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, float &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, double &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, unsigned long long &v) { Sr.Serialize (v); return Sr; } NUX_INLINE NSerializer &operator << (NSerializer &Sr, long long &v) { Sr.Serialize (v); return Sr; } } #endif // NSERIALIZER_H nux-4.0.8+18.10.20180623/NuxCore/FileName.cpp0000644000000000000000000001150513313373365014352 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "FileName.h" #include "Math/MathUtility.h" namespace nux { std::string NFileName::GetDrive() const { size_t Pos = find('\\', 0); return Pos != std::string::npos ? substr(0, Pos) : ""; } std::string NFileName::GetExtension() const { size_t Pos = rfind('.'); return Pos != std::string::npos ? substr(Pos + 1) : ""; } // Returns the base filename without the path std::string NFileName::GetCleanFilename() const { size_t bsPos = rfind('\\'); size_t sPos = rfind('/'); size_t Pos = std::string::npos; if (bsPos != std::string::npos && sPos != std::string::npos) { Pos = Max(bsPos, sPos); } else if (bsPos != std::string::npos) { Pos = bsPos; } else if (sPos != std::string::npos) { Pos = sPos; } return Pos != std::string::npos ? (const std::string)substr(Pos + 1) : *this; } std::string NFileName::GetFilenameNoExtension() const { size_t Pos = rfind('.'); if (Pos != std::string::npos && Pos != 0) { return substr(0, Pos); } return *this; } // Returns the base filename without the path and without the extension std::string NFileName::GetBaseFilename() const { std::string Wk = GetCleanFilename(); size_t Pos = Wk.rfind('.'); if (Pos != std::string::npos) { return Wk.substr(Pos); } return Wk; } // Returns the path in front of the filename std::string NFileName::GetDirectoryPath() const { size_t bsPos = rfind('\\'); size_t sPos = rfind('/'); size_t Pos = std::string::npos; if (bsPos != std::string::npos && sPos != std::string::npos) { Pos = Max(bsPos, sPos); } else if (bsPos != std::string::npos) { Pos = bsPos; } else if (sPos != std::string::npos) { Pos = sPos; } return Pos != std::string::npos ? substr(Pos) : "."; } void NFileName::ChangeFileExtension (const TCHAR *ext) { size_t Pos = rfind('.'); if (Pos != std::string::npos) { replace(begin() + Pos, end(), ext); } *this = *this + "." + ext; } void NFileName::ConvertSlashToBackslash() { size_t Pos = find('/'); while (Pos != std::string::npos) { replace(Pos, 1, 1, '\\'); } } void NFileName::ConvertBackslashToSlash() { size_t Pos = find('\\'); while (Pos != std::string::npos) { replace(Pos, 1, 1, '/'); } } void NFileName::AddSlashAtEnd() { if (!empty() && operator[](size() - 1) != '/') append("/"); } void NFileName::AddBackSlashAtEnd() { if (!empty() && operator[](size() - 1) != '\\') *this += '\\'; } void NFileName::AddSlashAtStart() { if (!empty() && operator[](0) != '/') insert(0, 1, '/'); } void NFileName::AddBackSlashAtStart() { if (!empty() && operator[](0) != '\\') insert(0, 1, '\\'); } void NFileName::RemoveSlashAtEnd() { if (!empty() && operator[](size() - 1) == '/') { erase(end() - 1); } } void NFileName::RemoveBackSlashAtEnd() { if (!empty() && operator[](size() - 1) == '\\') { erase(end() - 1); } } void NFileName::RemoveSlashAtStart() { if (!empty() && operator[](0) == '/') { erase(0, 1); } } void NFileName::RemoveBackSlashAtStart() { if (!empty() && operator[](0) == '\\') { erase(0, 1); } } void NFileName::ConvertToCleanSlash() { ConvertBackslashToSlash(); size_t count = size(); for (size_t i = 0; i < count; ) { if ( (i < count - 1) && (operator[] (i) == '/' ) && (operator[] (i + 1) == ('/') ) ) { erase (i + 1, 1); --count; } else { i++; } } } void NFileName::ConvertToCleanBackslash() { ConvertSlashToBackslash(); size_t count = size(); for (size_t i = 0; i < count; ) { if ( (i < count - 1) && (operator[] (i) == '\\' ) && (operator[] (i + 1) == '\\' ) ) { erase (i + 1, 1); } else { i++; } } } } nux-4.0.8+18.10.20180623/NuxCore/FileName.h0000644000000000000000000000577513313373365014033 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NFILENAME_H #define NFILENAME_H #include "TextString.h" namespace nux { class NFileName : public std::string { public: NFileName() : std::string() {} NFileName ( const NFileName &Filename ) : std::string ( Filename ) {} NFileName ( const std::string &str ) : std::string ( str ) {} NFileName ( const ANSICHAR *str ) : std::string ( str ) {} //! Replace all slash with backslash. void ConvertSlashToBackslash(); //! Replace all backslash with slash. void ConvertBackslashToSlash(); //! Add slash at the end if there isn't one already. void AddSlashAtEnd(); //! Add backslash at the end if there isn't one already. void AddBackSlashAtEnd(); //! Add slash at the start if there isn't one already. void AddSlashAtStart(); //! Add backslash at the start if there isn't one already. void AddBackSlashAtStart(); //! Remove slash at the end if there is one. void RemoveSlashAtEnd(); //! Remove backslash at the end if there is one. void RemoveBackSlashAtEnd(); //! Remove slash at the start if there is one. void RemoveSlashAtStart(); //! Remove backslash at the start if there is one. void RemoveBackSlashAtStart(); //! Replace all backslash with slash. Replace multiple consecutive slash with one slash. void ConvertToCleanSlash(); //! Replace all slash with backslash. Replace multiple consecutive backslash with one backslash. void ConvertToCleanBackslash(); std::string GetDrive() const; //! Returns the text following the last period. std::string GetExtension() const; //! Returns the base filename, minus any path information. std::string GetCleanFilename() const; //! Returns the base filename, without the extension (keep the path) std::string GetFilenameNoExtension() const; //! Returns the same thing as GetCleanFilename, but without the extension std::string GetBaseFilename() const; //! Returns the path in front of the filename std::string GetDirectoryPath() const; //! Change the file extension. Do not start ext with a dot character '.'. //! ie ext = "com" void ChangeFileExtension (const TCHAR *ext); }; } #endif // NFILENAME_H nux-4.0.8+18.10.20180623/NuxCore/FilePath.cpp0000644000000000000000000001026213313373365014365 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "FilePath.h" namespace nux { FilePath::FilePath() { if (std::find (m_SearchPath.begin(), m_SearchPath.end(), TEXT ("") ) != m_SearchPath.end() ) return; m_SearchPath.push_back (TEXT ("") ); // for fully qualified path } FilePath::~FilePath() { } void FilePath::AddSearchPath (const std::string &searchpath) { if (std::find (m_SearchPath.begin(), m_SearchPath.end(), searchpath) != m_SearchPath.end() ) return; m_SearchPath.push_back (searchpath); } void FilePath::AddSearchPath (const std::vector& searchpath) { for (unsigned int i = 0; i < searchpath.size(); i++) { if (std::find (m_SearchPath.begin(), m_SearchPath.end(), searchpath[i]) == m_SearchPath.end() ) m_SearchPath.push_back (searchpath[i]); } } std::string FilePath::GetPathToFile (const TCHAR *filename) const { std::string FileName = GetFile (filename); size_t loc = FileName.rfind(TEXT('\\'), 0); if (loc == std::string::npos) { loc = FileName.rfind(TEXT('/'), 0); } if (loc != std::string::npos) FileName = FileName.substr(0, loc); else FileName = std::string(TEXT (".")); return FileName; } std::string FilePath::GetFile (const TCHAR *filename) const { NUX_RETURN_VALUE_IF_NULL (filename, std::string (TEXT ("") ) ); if (std::string (filename) == std::string (TEXT ("") ) ) return std::string (TEXT ("") ); std::string FileName = filename; if (GFileManager.FileExist(FileName.c_str() ) ) return FileName; for (unsigned int i = 0; i < m_SearchPath.size(); i++) { if (m_SearchPath[i].size() == 0) continue; std::string FilePath; char last = m_SearchPath[i][m_SearchPath[i].size() - 1]; if (last == TEXT('/') || last == TEXT('\\')) FilePath = m_SearchPath[i] + filename; else FilePath = m_SearchPath[i] + NUX_PATH_SEPARATOR_STRING + filename; if (GFileManager.FileExist (FilePath.c_str() ) ) return FilePath; } // Still not found. Then peel off the root of the filename and append our custom search path. // filename = "MediaProg/UI3DGraphics/MyFile.txt" // search for: // CustomPath0/UI3DGraphics/MyFile.txt // CustomPath1/UI3DGraphics/MyFile.txt // CustomPath2/UI3DGraphics/MyFile.txt // CustomPath3/UI3DGraphics/MyFile.txt // CustomPath0/MyFile.txt // CustomPath1/MyFile.txt // CustomPath2/MyFile.txt // CustomPath3/MyFile.txt // FileName = filename; for (size_t i = 0; i < m_SearchPath.size(); i++) { size_t pos; std::string PathName; while (FileName.find_first_of(TEXT ("\\/")) != std::string::npos) { pos = FileName.find_first_of(TEXT ("\\/")) + 1; FileName = FileName.substr(pos, FileName.length() - pos); char last = m_SearchPath[i][m_SearchPath[i].size() - 1]; if (last == TEXT('/') || last == TEXT('\\')) PathName = m_SearchPath[i] + FileName; else PathName = m_SearchPath[i] + NUX_PATH_SEPARATOR_STRING + FileName; if (GFileManager.FileExist (PathName.c_str() ) ) return PathName; } } nuxDebugMsg (TEXT ("[FilePath::GetFile] Cannot find file: %s"), filename); return std::string (TEXT ("") ); } } nux-4.0.8+18.10.20180623/NuxCore/FilePath.h0000644000000000000000000000321013313373365014025 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ ////////////////////////////////////////////////////////////////////////// // This file comes from NVidia SDK 9.5 data_path.h // ////////////////////////////////////////////////////////////////////////// #ifndef FILEPATH_H #define FILEPATH_H #ifdef _WIN32 # pragma warning(disable:4786) // symbol size limitation ... STL #endif #include #include #include #include #include namespace nux { class FilePath { public: FilePath(); ~FilePath(); void AddSearchPath (const std::string &searchpath); void AddSearchPath (const std::vector& searchpath); std::string GetPathToFile (const TCHAR *filename) const; std::string GetFile (const TCHAR *filename) const; private: std::vector m_SearchPath; }; } #endif // FILEPATH_H nux-4.0.8+18.10.20180623/NuxCore/GlobalInitializer.cpp0000644000000000000000000000463613313373365016305 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" namespace nux { static GlobalSingletonInitializer *GGlobalInitializer = 0; static void SystemStart() { static unsigned char StaticBuffer [sizeof (GlobalSingletonInitializer)]; // Placement new in our reserved buffer. GGlobalInitializer = new (StaticBuffer) GlobalSingletonInitializer (); #if defined (NUX_OS_WINDOWS) GLogDevice.AddOutputDevice (&NUX_GLOBAL_OBJECT_INSTANCE (LogFileOutput)); GLogDevice.AddOutputDevice (&NUX_GLOBAL_OBJECT_INSTANCE (VisualOutputConsole)); GLogDevice.AddOutputDevice (&NUX_GLOBAL_OBJECT_INSTANCE (PrintfOutputConsole)); #else GLogDevice.AddOutputDevice (&NUX_GLOBAL_OBJECT_INSTANCE (LogFileOutput)); GLogDevice.AddOutputDevice (&NUX_GLOBAL_OBJECT_INSTANCE (PrintfOutputConsole)); #endif } static void SystemShutdown() { // Manually destroy initializer if (GGlobalInitializer) GGlobalInitializer->~GlobalSingletonInitializer(); GGlobalInitializer = 0; } bool GlobalSingletonInitializer::m_bGlobalObjectsReady = false; GlobalSingletonInitializer::GlobalSingletonInitializer () { m_bGlobalObjectsReady = true; } GlobalSingletonInitializer::~GlobalSingletonInitializer() { m_bGlobalObjectsReady = false; } bool GlobalSingletonInitializer::Ready() { return m_bGlobalObjectsReady; } int GlobalInitializer::m_Count = 0; GlobalInitializer::GlobalInitializer() { if (m_Count++ == 0) { SystemStart(); } } GlobalInitializer::~GlobalInitializer() { if (--m_Count == 0) { SystemShutdown(); } } void GlobalInitializer::ForceShutdown() { SystemShutdown(); } } nux-4.0.8+18.10.20180623/NuxCore/GlobalInitializer.h0000644000000000000000000001020213313373365015734 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NGLOBALINITIALIZER_H #define NGLOBALINITIALIZER_H #include "Macros.h" #include "System.h" #ifdef _WIN32 #define NUX_GLOBAL_OBJECT_INIT_SEQUENCE() \ NUX_GLOBAL_OBJECT_VARIABLE(NGlobalData); \ NUX_GLOBAL_OBJECT_VARIABLE(NProcess); \ NUX_GLOBAL_OBJECT_VARIABLE(NullOutput); \ NUX_GLOBAL_OBJECT_VARIABLE(UniqueIndex); \ NUX_GLOBAL_OBJECT_VARIABLE(NFileManagerWindows); \ NUX_GLOBAL_OBJECT_VARIABLE(VisualOutputConsole); \ NUX_GLOBAL_OBJECT_VARIABLE(PrintfOutputConsole); \ NUX_GLOBAL_OBJECT_VARIABLE(LogFileOutput); \ NUX_GLOBAL_OBJECT_VARIABLE(LogOutputRedirector); \ NUX_GLOBAL_OBJECT_VARIABLE(ObjectStats); #elif (defined NUX_OS_LINUX) #define NUX_GLOBAL_OBJECT_INIT_SEQUENCE() \ NUX_GLOBAL_OBJECT_VARIABLE(NGlobalData); \ NUX_GLOBAL_OBJECT_VARIABLE(NullOutput); \ NUX_GLOBAL_OBJECT_VARIABLE(UniqueIndex); \ NUX_GLOBAL_OBJECT_VARIABLE(NFileManagerGNU); \ NUX_GLOBAL_OBJECT_VARIABLE(PrintfOutputConsole); \ NUX_GLOBAL_OBJECT_VARIABLE(LogFileOutput); \ NUX_GLOBAL_OBJECT_VARIABLE(LogOutputRedirector); \ NUX_GLOBAL_OBJECT_VARIABLE(ObjectStats); #endif namespace nux { // This class initialize all inalogic singleton (global objects) in order. It also initialize memory allocators. // Therefore, do not call new GlobalSingletonInitializer as it will try to call inalogic memory allocator and fail. // You may use the global placement new operator(it is not overwritten by inalogic) to create GlobalSingletonInitializer // inside the application data space by calling SystemInitializer(). At shutdown, call SystemShutdown() // // You may also create GlobalSingletonInitializer in this way: // main() // { // GlobalSingletonInitializer GlobalInitializer; // } // // class GlobalSingletonInitializer { NUX_DISABLE_OBJECT_COPY (GlobalSingletonInitializer); GlobalSingletonInitializer *operator & (); const GlobalSingletonInitializer *operator & () const; public: GlobalSingletonInitializer(); ~GlobalSingletonInitializer(); static bool Ready(); private: static bool m_bGlobalObjectsReady; NUX_GLOBAL_OBJECT_INIT_SEQUENCE(); }; // Nifty Counter idiom. See http://www-d0.fnal.gov/KAI/doc/tutorials/static_initialization.html class GlobalInitializer { public: GlobalInitializer(); ~GlobalInitializer(); static void ForceShutdown(); private: static int m_Count; }; // Every compilation unit that includes this file will have its own instance of sGlobalInitializer. sGlobalInitializer is initialized // before the main function of the program is called. The first time sGlobalInitializer is initialized, it calls SystemStart() to create // our global object singleton. In SystemStart() we have a change to create our singletons in any order we like. // When the program exits, every instance of sGlobalInitializer will be destroyed. The last instance destroyed will call SystemShutdown(). // In SystemShutdown() we can destroy our global objects in any order we like. static GlobalInitializer sGlobalInitializer; } #endif // NGLOBALINITIALIZER_H nux-4.0.8+18.10.20180623/NuxCore/Inalogic.h0000644000000000000000000000156413313373365014070 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef INALOGIC_H #define INALOGIC_H #include "SystemTypes.h" #endif // INALOGIC_H nux-4.0.8+18.10.20180623/NuxCore/InitiallyUnownedObject.cpp0000644000000000000000000000217113313373365017316 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Neil Jagdish Patel * */ #include "NuxCore.h" #include "InitiallyUnownedObject.h" #include "ObjectPtr.h" namespace nux { NUX_IMPLEMENT_OBJECT_TYPE (InitiallyUnownedObject); InitiallyUnownedObject::InitiallyUnownedObject (NUX_FILE_LINE_DECL) : Object (false, NUX_FILE_LINE_PARAM) { } InitiallyUnownedObject::~InitiallyUnownedObject() { } } nux-4.0.8+18.10.20180623/NuxCore/InitiallyUnownedObject.h0000644000000000000000000000233513313373365016765 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Neil Jagdish Patel * */ #include "Object.h" #ifndef NUXINITIALLYUNOWNEDOBJECT_H #define NUXINITIALLYUNOWNEDOBJECT_H namespace nux { //! The base class of Nux initially unowned objects. class InitiallyUnownedObject: public Object { public: NUX_DECLARE_OBJECT_TYPE (InitiallyUnownedObject, Object); //! Constructor InitiallyUnownedObject (NUX_FILE_LINE_PROTO); ~InitiallyUnownedObject (); }; } #endif // NUXINITIALLYUNOWNEDOBJECT_H nux-4.0.8+18.10.20180623/NuxCore/Logger.cpp0000644000000000000000000002474213313373365014120 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifdef _MSC_VER #pragma warning(disable: 4996) // 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators' // 'std::_Equal1': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators' #endif #include "NuxCore.h" #include "Logger.h" #include "LoggerPrivate.h" #include "LoggingWriter.h" #if defined(NUX_OS_LINUX) # include #endif #include #include #include #include namespace nux { namespace logging { namespace { char const* str_level(Level severity); } inline std::string const& LoggerModule::module() const { return module_; } inline bool LoggerModule::IsErrorEnabled() const { return GetEffectiveLogLevel() <= Error; } inline bool LoggerModule::IsWarningEnabled() const { return GetEffectiveLogLevel() <= Warning; } inline bool LoggerModule::IsInfoEnabled() const { return GetEffectiveLogLevel() <= Info; } inline bool LoggerModule::IsDebugEnabled() const { return GetEffectiveLogLevel() <= Debug; } inline bool LoggerModule::IsTraceEnabled() const { return GetEffectiveLogLevel() <= Trace; } inline void LoggerModule::SetLogLevel(Level level) { // The root module can't be unspecified. if (module_ == "" && level == NotSpecified) level = Warning; level_ = level; } inline Level LoggerModule::GetLogLevel() const { return level_; } inline Level LoggerModule::GetEffectiveLogLevel() const { if (level_ == NotSpecified && parent_) return parent_->GetEffectiveLogLevel(); else return level_; } Logger::Logger(std::string const& module) : pimpl(LoggerModules::Instance().GetModule(module)) { } std::string const& Logger::module() const { return pimpl->module(); } bool Logger::IsErrorEnabled() const { return pimpl->IsErrorEnabled(); } bool Logger::IsWarningEnabled() const { return pimpl->IsWarningEnabled(); } bool Logger::IsInfoEnabled() const { return pimpl->IsInfoEnabled(); } bool Logger::IsDebugEnabled() const { return pimpl->IsDebugEnabled(); } bool Logger::IsTraceEnabled() const { return pimpl->IsTraceEnabled(); } void Logger::SetLogLevel(Level level) { pimpl->SetLogLevel(level); } Level Logger::GetLogLevel() const { return pimpl->GetLogLevel(); } Level Logger::GetEffectiveLogLevel() const { return pimpl->GetEffectiveLogLevel(); } LoggerModule::LoggerModule(std::string const& module, LoggerModulePtr const& parent) : module_(module) , level_(NotSpecified) , parent_(parent) , writer_(Writer::Instance()) { } LoggerModules::LoggerModules() : root_(new LoggerModule("", LoggerModulePtr())) { // Make sure we have the root logger available. root_->SetLogLevel(Warning); modules_.insert(ModuleMap::value_type("", root_)); } LoggerModules& LoggerModules::Instance() { static LoggerModules instance; return instance; } bool LoggerModules::HasModule(std::string const& module) const { // This method assumes that the module string has been lowercased already. // This method is primarily an internal function, but is also used by the // testing code. return modules_.find(module) != modules_.end(); } LoggerModulePtr const& LoggerModules::GetModule(std::string const& module) { std::string lower_module = boost::to_lower_copy(module); ModuleMap::iterator i = modules_.find(lower_module); if (i != modules_.end()) return i->second; // Make the new LoggerModule and its parents. // Split on '.' std::string::size_type idx = lower_module.rfind("."); LoggerModulePtr parent = root_; if (idx != std::string::npos) { parent = GetModule(lower_module.substr(0, idx)); } LoggerModulePtr logger(new LoggerModule(lower_module, parent)); // std::map insert method returns a pair which seems // overly annoying to make a temporary of, so just return the const // reference pointed to by the iterator. return modules_.insert(ModuleMap::value_type(lower_module, logger)).first->second; } void LoggerModules::Reset() { for (ModuleMap::iterator i = modules_.begin(), end = modules_.end(); i != end; ++i) { i->second->SetLogLevel(NotSpecified); } } std::string LoggerModules::DumpLoggingLevels(std::string const& prefix) const { std::ostringstream sout; bool first = true; for (ModuleMap::const_iterator i = modules_.begin(), end = modules_.end(); i != end; ++i) { std::string const& module_name = i->first; LoggerModulePtr const& module = i->second; Level severity = module->GetLogLevel(); if (severity == NotSpecified) continue; // Don't write out unspecified ones. if (first) first = false; else sout << "\n"; sout << prefix; if (module_name == "") sout << ""; else sout << module_name; sout << " " << str_level(severity); } return sout.str(); } class LogStreamBuffer : public std::stringbuf { public: LogStreamBuffer(Level severity, std::string const& module, std::string const& filename, int line_number); protected: virtual int sync(); private: Level severity_; std::string module_; std::string filename_; int line_number_; std::time_t timestamp_; }; LogStream::LogStream(Level severity, std::string const& module, std::string const& filename, int line_number) : std::ostream(new LogStreamBuffer(severity, module, filename, line_number)) { } LogStream::~LogStream() { rdbuf()->pubsync(); std::streambuf* buff = rdbuf(0); delete buff; } LogStreamBuffer::LogStreamBuffer(Level severity, std::string const& module, std::string const& filename, int line_number) : std::stringbuf(std::ios_base::out) , severity_(severity) , module_(module) , filename_(filename) , line_number_(line_number) , timestamp_(std::time(0)) { } int LogStreamBuffer::sync() { std::string message = str(); // reset the stream str(""); // Only log the message if there is something there. if (!message.empty()) Writer::Instance().WriteMessage(severity_, module_, filename_, line_number_, timestamp_, message); return 0; // success } /** * A helper function for testing. Not exported, but used in tests. * * Resets the root logger to warning, and sets all other modules to not * specified. */ void reset_logging() { LoggerModules::Instance().Reset(); } std::string dump_logging_levels(std::string const& prefix) { return LoggerModules::Instance().DumpLoggingLevels(prefix); } void configure_logging(const char* config_string) { if (!config_string) return; std::vector values; boost::split(values, config_string, boost::is_any_of(";:")); for (std::vector::iterator i = values.begin(), end = values.end(); i != end; ++i) { std::string& value = *i; std::string::size_type pos = value.find("="); if (pos != std::string::npos) { std::string name = value.substr(0, pos); std::string level = value.substr(pos+1); if (name == "") name = ""; Logger(name).SetLogLevel(get_logging_level(level)); } } } Level get_logging_level(std::string level) { boost::to_upper(level); if (level == "TRACE") return Trace; if (level == "DEBUG") return Debug; if (level == "INFO") return Info; if (level == "WARN" || level == "WARNING") return Warning; if (level == "ERROR") return Error; return Warning; } #if defined(NUX_OS_LINUX) std::string Backtrace(int levels) { std::ostringstream sout; void* trace[256]; int n = ::backtrace(trace, 256); if (!n) { return sout.str(); } char** strings = ::backtrace_symbols(trace, n); if (levels != -1) { n = std::min(n, levels); } // Skip outputting the first string as it is: // nux::logging::backtrace for (int i = 1; i < n; ++i) { sout << i << ": " << strings[i] << '\n'; } if (strings) { free (strings); } return sout.str(); } #else std::string Backtrace(int /*levels*/) { return "Backtrace not supported on this platform.\n"; } #endif BlockTracer::BlockTracer(Logger const& logger, Level level, std::string const& function_name, std::string const& filename, int line_number) : logger_(logger) , level_(level) , function_name_(function_name) , filename_(filename) , line_number_(line_number) { if (logger_.GetEffectiveLogLevel() <= level_) { LogStream(level_, logger_.module(), filename_, line_number_).stream() << "+" << function_name_; } } BlockTracer::~BlockTracer() { if (logger_.GetEffectiveLogLevel() <= level_) { LogStream(level_, logger_.module(), filename_, line_number_).stream() << "-" << function_name_; } } namespace { char const* str_level(Level severity) { switch (severity) { case NotSpecified: return "NOT_SPECIFIED"; case Trace: return "TRACE"; case Debug: return "DEBUG"; case Info: return "INFO"; case Warning: return "WARNING"; case Error: return "ERROR"; case Critical: return "CRITICAL"; } return ""; } } } // namespace logging } // namespace nux nux-4.0.8+18.10.20180623/NuxCore/Logger.h0000644000000000000000000001421213313373365013554 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUX_CORE_LOGGER_H #define NUX_CORE_LOGGER_H #include #include #include #if defined(NUX_OS_WINDOWS) #define __func__ __FUNCTION__ #endif #define LOG_TRACE(logger) \ if (!Unwrap(logger).IsTraceEnabled()) {} \ else ::nux::logging::LogStream(::nux::logging::Trace, Unwrap(logger).module(), __FILE__, __LINE__).stream() #define LOG_DEBUG(logger) \ if (!Unwrap(logger).IsDebugEnabled()) {} \ else ::nux::logging::LogStream(::nux::logging::Debug, Unwrap(logger).module(), __FILE__, __LINE__).stream() #define LOG_INFO(logger) \ if (!Unwrap(logger).IsInfoEnabled()) {} \ else ::nux::logging::LogStream(::nux::logging::Info, Unwrap(logger).module(), __FILE__, __LINE__).stream() #define LOG_WARN(logger) LOG_WARNING(logger) #define LOG_WARNING(logger) \ if (!Unwrap(logger).IsWarningEnabled()) {} \ else ::nux::logging::LogStream(::nux::logging::Warning, Unwrap(logger).module(), __FILE__, __LINE__).stream() #define LOG_ERROR(logger) \ if (!Unwrap(logger).IsErrorEnabled()) {} \ else ::nux::logging::LogStream(::nux::logging::Error, Unwrap(logger).module(), __FILE__, __LINE__).stream() // We shouldn't really be logging block level information at anything higher than debug. #if defined(NUX_OS_WINDOWS) #define LOG_TRACE_BLOCK(logger) #define LOG_DEBUG_BLOCK(logger) #else #define LOG_TRACE_BLOCK(logger) ::nux::logging::BlockTracer _block_tracer_ ## __LINE__ (Unwrap(logger), ::nux::logging::Trace, __PRETTY_FUNCTION__, __FILE__, __LINE__) #define LOG_DEBUG_BLOCK(logger) ::nux::logging::BlockTracer _block_tracer_ ## __LINE__ (Unwrap(logger), ::nux::logging::Debug, __PRETTY_FUNCTION__, __FILE__, __LINE__) #endif /* * This macro is used to declare a file scoped logger module function. The * purpose of this is to allow a file scoped logger that doesn't use static * initialisation, but instead is a method that creates the object the first * time it is used. * * Used like: * * DECLARE_LOGGER(logger, "test.module"); * * Then used like this in some function (just like a normal logger object): * * LOG_DEBUG(logger) << "foo"; */ #define DECLARE_LOGGER(logger, module) \ namespace { \ ::nux::logging::Logger& logger() \ { \ static ::nux::logging::Logger instance(module); \ return instance; \ } \ } namespace nux { namespace logging { enum Level { NotSpecified, Trace, Debug, Info, Warning, Error, Critical, }; // Convert a string representation of a logging level into the enum value. Level get_logging_level(std::string level); /** * Configure multiple logging modules. * * This function expects a string of the format: * module=info;sub.module=debug;other.module=warning * * * The root module can be specified by using the value "", eg: * =info;other.module=debug * * The specified modules will have their logging level set to the specified * level as defined by the get_logging_level function. * * It is expected that this method is called during application startup with * the content of some environment variable. * nux::logging::configure_logging(::getenv("MY_APP_LOGGING_CONFIG")); */ void configure_logging(const char* config_string); std::string Backtrace(int levels = -1); void reset_logging(); std::string dump_logging_levels(std::string const& prefix = ""); class LogStream : public std::ostream { public: LogStream(Level severity, std::string const& module, std::string const& filename, int line_number); ~LogStream(); std::ostream& stream() { return *this; } }; class LoggerModule; typedef std::shared_ptr LoggerModulePtr; class Logger { public: explicit Logger(std::string const& module); std::string const& module() const; bool IsErrorEnabled() const; bool IsWarningEnabled() const; bool IsInfoEnabled() const; bool IsDebugEnabled() const; bool IsTraceEnabled() const; void SetLogLevel(Level level); Level GetLogLevel() const; Level GetEffectiveLogLevel() const; private: LoggerModulePtr pimpl; }; // The Unwrap function is used by the LOG_* macros above to accept either a // reference to a Logger object, or a function that when called returns a // reference to a Logger object. inline Logger const& Unwrap(Logger const& logger) { return logger; } typedef Logger& (*LoggerFunc)(); inline Logger const& Unwrap(LoggerFunc func) { return func(); } /** * This class is used to log the entry and exit of a block. * * Entry is defined as where the object is created. This is most likely going * to be defined using the macros defined above. Exit is defined as object * destruction, which is normally controlled through the end of scope killing * the stack object. * * int some_func(params...) * { * LOG_TRACE_BLOCK(logger); * ... * } */ class BlockTracer { public: BlockTracer(Logger const& logger, Level level, std::string const& function_name, std::string const& filename, int line_number); ~BlockTracer(); private: Logger const& logger_; Level level_; std::string function_name_; std::string filename_; int line_number_; }; } } #endif nux-4.0.8+18.10.20180623/NuxCore/LoggerPrivate.h0000644000000000000000000000406613313373365015115 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUX_CORE_LOGGER_PRIVATE_H #define NUX_CORE_LOGGER_PRIVATE_H #include #include #include #include "Logger.h" #include "LoggingWriter.h" namespace nux { namespace logging { class LoggerModule { public: LoggerModule(std::string const& module, LoggerModulePtr const& parent); std::string const& module() const; bool IsErrorEnabled() const; bool IsWarningEnabled() const; bool IsInfoEnabled() const; bool IsDebugEnabled() const; bool IsTraceEnabled() const; void SetLogLevel(Level level); Level GetLogLevel() const; Level GetEffectiveLogLevel() const; private: std::string module_; Level level_; LoggerModulePtr parent_; // An attempt to make sure the writer is around for as long as the loggers. Writer& writer_; }; class LoggerModules : boost::noncopyable { public: static LoggerModules& Instance(); LoggerModulePtr const& GetModule(std::string const& module); void Reset(); std::string DumpLoggingLevels(std::string const& prefix) const; bool HasModule(std::string const& module) const; private: LoggerModules(); private: typedef std::map ModuleMap; ModuleMap modules_; LoggerModulePtr root_; }; } } #endif nux-4.0.8+18.10.20180623/NuxCore/LoggingWriter.cpp0000644000000000000000000001236713313373365015464 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ //#if defined(NUX_OS_WINDOWS) #include "NuxCore.h" //#endif #include "System.h" #include "LoggingWriter.h" #include #include #include #include namespace nux { namespace logging { namespace { Writer* pInstance; void cleanup_writer_instance() { delete pInstance; pInstance = 0; } struct StreamWrapper { typedef std::shared_ptr Ptr; StreamWrapper(std::ostream& output) : out(output) {} std::ostream& out; }; const char* severity_string(Level severity) { // The return value is always padded out here. switch (severity) { case Critical: return "CRIT "; case Error: return "ERROR"; case Warning: return "WARN "; case Info: return "INFO "; case Debug: return "DEBUG"; case Trace: return "TRACE"; default: // We technically shouldn't get this. return " "; } } std::string TimestampString(std::time_t timestamp) { // return an ISO format string: YYYY-MM-DD HH:MM:SS static const char* format = "%Y-%m-%d %H:%M:%S"; const int buf_size = 20; char buffer[buf_size]; tm local_time; #if defined(NUX_OS_WINDOWS) if (localtime_s(&local_time, ×tamp) == 0) std::strftime(buffer, buf_size, format, &local_time); else { static const char* invalid_time_stamp = "invalid_time_stamp"; memcpy_s(buffer, sizeof(buffer), invalid_time_stamp, strnlen(invalid_time_stamp, 30)); } #else std::strftime(buffer, buf_size, format, ::localtime_r(×tamp, &local_time)); #endif return buffer; } std::string ShortenedFilename(std::string const& filename) { std::string::size_type pos = filename.rfind('/'); if (pos == std::string::npos) return filename; return filename.substr(pos+1); } } // anon namespace class Writer::Impl { public: Impl(); void WriteMessage(Level severity, std::string const& module, std::string const& filename, int line_number, std::time_t timestamp, std::string const& message); void SetOutputStream(std::ostream& out); private: typedef std::vector OutputStreams; OutputStreams output_streams_; }; Writer::Impl::Impl() { output_streams_.push_back(StreamWrapper::Ptr(new StreamWrapper(std::cout))); } void Writer::Impl::SetOutputStream(std::ostream& out) { output_streams_.clear(); output_streams_.push_back(StreamWrapper::Ptr(new StreamWrapper(out))); } void Writer::Impl::WriteMessage(Level severity, std::string const& module, std::string const& filename, int line_number, std::time_t timestamp, std::string const& message) { // If we want to have some form of custom formatter, here is where we do it. // Right now, format the line independently, and then write it to each // output stream. std::stringstream sout; sout << severity_string(severity) << " " << TimestampString(timestamp) << " " << module << " " << ShortenedFilename(filename) << ":" << line_number << " " << message; for (OutputStreams::iterator i = output_streams_.begin(), end = output_streams_.end(); i != end; ++i) { std::ostream& out = (*i)->out; out << sout.rdbuf() << std::endl; } #if defined(NUX_OS_WINDOWS) && defined(NUX_DEBUG) // Quick hack to print messages to Visual Studio output. // Should create a Visual Studio StreamWrapper instead! OutputDebugString (sout.str().c_str()); #endif } Writer::Writer() : pimpl(new Impl()) { #ifdef NUX_DEBUG std::cerr << "nux::logging::Writer::Writer()\n"; #endif } Writer::~Writer() { delete pimpl; #ifdef NUX_DEBUG std::cerr << "nux::logging::Writer::~Writer()\n"; #endif } Writer& Writer::Instance() { if (pInstance == 0) { pInstance = new Writer(); std::atexit(cleanup_writer_instance); } return *pInstance; } void Writer::WriteMessage(Level severity, std::string const& module, std::string const& filename, int line_number, std::time_t timestamp, std::string const& message) { pimpl->WriteMessage(severity, module, filename, line_number, timestamp, message); } void Writer::SetOutputStream(std::ostream& out) { pimpl->SetOutputStream(out); } } } nux-4.0.8+18.10.20180623/NuxCore/LoggingWriter.h0000644000000000000000000000363713313373365015131 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUX_CORE_LOGGING_WRITER_H #define NUX_CORE_LOGGING_WRITER_H #include #include #include #include "Logger.h" /** * The Writer singleton is responsible for controlling where the * logging message go. For testing purposes it is able to define the logging * stream, normally a std::stringstream. * * The default behaviour is to output to std::cout. * * As far as logging the timestamp goes, we only go to second precision in the * logging format itself. If a high performance timer is needed it should be * managed by the caller. */ namespace nux { namespace logging { class Writer : boost::noncopyable { public: static Writer& Instance(); ~Writer(); void WriteMessage(Level severity, std::string const& module, std::string const& filename, int line_number, std::time_t timestamp, std::string const& message); void SetOutputStream(std::ostream& out); private: Writer(); private: class Impl; Impl* pimpl; }; } } #endif nux-4.0.8+18.10.20180623/NuxCore/Macros.h0000644000000000000000000001464613313373365013574 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NMACROS_H #define NMACROS_H // Disable object copy constructor and assignment operator #define NUX_DISABLE_OBJECT_COPY(Class) \ private: \ Class(const Class &); \ const Class& operator = (const Class &); /// GLOBAL OBJECT /////////////////////////////////////////////////////////////////////// #define NUX_GLOBAL_OBJECT_VARIABLE(Class) Class m_##Class; #define NUX_GLOBAL_OBJECT_INSTANCE(Class) Class::Instance() #define NUX_GLOBAL_OBJECT_REFERENCE(Class) Class::Instance() #define NUX_IMPLEMENT_GLOBAL_OBJECT(Class) Class* Class::pInstance = 0; // Note: Methods that are implicitly generated by the compiler if they are not explicitly defined are: // * Default constructor (C::C()) // * Copy constructor (C::C (const C& rhs)) // * Destructor (C::~C()) // * Assignment operator (C& C::operator= (const C& rhs)) // * Address-of operator (C* C::operator&()) // * Address-of operator (const C* C::operator&() const;) /*! A Global Object with a behavior similar to a singleton. Only one instance of this object can exist. The unique instance is created by a friend class: GlobalInitializer. Only GlobalInitializer can create this instance. example: class GlobalObject { NUX_DECLARE_GLOBAL_OBJECT(GlobalObject, , GlobalSingletonInitializer) public: void foo(void); }; The macro also define a Constructor and Destructor method to be implemented: - void Constructor() - void Destructor() They are replacement for the real Constructor and Destructor. */ #define NUX_DECLARE_GLOBAL_OBJECT(Class, GlobalInitializer) \ NUX_DISABLE_OBJECT_COPY(Class); \ /* Disable address-of operator */ \ /*Class* operator & (); */ \ /*const Class* operator & () const; */ \ friend class GlobalInitializer; \ private: \ static Class* pInstance; \ Class() \ { \ pInstance = this; \ Constructor(); \ } \ virtual ~Class() \ { \ Destructor(); \ } \ \ void Constructor(); \ void Destructor(); \ \ public: \ static bool Ready() \ { \ return pInstance != 0; \ } \ static Class& Instance() \ { \ if(pInstance == 0) \ { \ PrintOutputDebugString(ANSI_TO_TCHAR(__FILE__), __LINE__, \ TEXT("Global object %s has not been initialized"), ANSI_TO_TCHAR(TEXT(#Class))); \ inlDebugBreak(); \ } \ return *pInstance; \ } \ /// Loki Singleton //////////////////////////////////////////////////////////////////////////////////// #define NUX_SINGLETON_CLASS_INTERNAL(ClassImpl) \ private: \ ClassImpl(); \ ~ClassImpl(); \ ClassImpl(const ClassImpl &); \ ClassImpl& operator=(const ClassImpl &); \ ClassImpl* operator &(); \ friend struct Loki::CreateUsingNew; \ friend struct Loki::CreateUsingMalloc; \ friend struct Loki::CreateStatic; #define NUX_SINGLETON_CLASS_DECLARE(ClassImpl, SingletonClass) typedef ::Loki::SingletonHolder SingletonClass; #define NUX_SINGLETON_INSTANCE(SingletonClass) SingletonClass::Instance() // Silence unused parameters: no warning #define NUX_UNUSED(parameter) (void)parameter; #endif // NMACROS_H nux-4.0.8+18.10.20180623/NuxCore/Makefile.am0000644000000000000000000001123613313373365014223 0ustar CLEANFILES = DISTCLEANFILES = EXTRA_DIST = AM_CPPFLAGS = \ -I$(srcdir) \ -I$(top_srcdir) \ -DPREFIX=\""$(prefix)"\" \ -DLIBDIR=\""$(libdir)"\" \ -DDATADIR=\""$(datadir)"\" \ -DG_LOG_DOMAIN=\"NuxCore\" lib_LTLIBRARIES = \ libnux-core-@NUX_API_VERSION@.la libnux_core_@NUX_API_VERSION@_la_CPPFLAGS= \ $(GCC_FLAGS) \ $(NUX_CORE_CFLAGS) \ $(MAINTAINER_CFLAGS) \ $(COVERAGE_CFLAGS) libnux_core_@NUX_API_VERSION@_la_LIBADD = \ $(NUX_CORE_LIBS) -lpthread libnux_core_@NUX_API_VERSION@_la_LDFLAGS = \ $(NUX_LT_LDFLAGS) \ $(COVERAGE_LDFLAGS) source_cpp = \ Animation.cpp \ AnimationController.cpp \ AsyncFileWriter.cpp \ EasingCurve.cpp \ TextString.cpp \ TimeFunctions.cpp \ Template.cpp \ FilePath.cpp \ FileManager/NSerializer.cpp \ FileManager/NFileManagerGeneric.cpp \ FileManager/NFileManagerGNU.cpp \ SystemGNU.cpp \ OutputDevice.cpp \ Exception.cpp \ Memory.cpp \ Character/NUTF.cpp \ Character/NUni.cpp \ Character/NUnicode.cpp \ Color.cpp \ ColorPrivate.cpp \ Colors.cpp \ FileName.cpp \ ThreadGNU.cpp \ Parsing.cpp \ Logger.cpp \ LoggingWriter.cpp \ NUniqueIndex.cpp \ GlobalInitializer.cpp \ ObjectType.cpp \ Platform.cpp \ Rect.cpp \ FileIO.cpp \ Process.cpp \ NumberConversion.cpp \ NuxCore.cpp \ Object.cpp \ Math/Algo.cpp \ Math/Constants.cpp \ Math/MathFunctions.cpp \ Math/Line2D.cpp \ Math/Bezier.cpp \ Math/Spline.cpp \ Math/Quaternion.cpp \ Math/Matrix2.cpp \ Math/Trigonometry.cpp \ Math/Tweening.cpp \ Math/Complex.cpp \ Math/Point3D.cpp \ Math/Matrix4.cpp \ Math/Matrix3.cpp \ Math/Line3D.cpp \ RollingFileAppender.cpp \ InitiallyUnownedObject.cpp source_file_manager_h = \ FileManager/NFileManagerGNU.h \ FileManager/NFileManagerGeneric.h \ FileManager/NSerializer.h source_character_h = \ Character/NUTF.h \ Character/NUni.h \ Character/NUnicode.h \ Character/NTChar.h source_math_h = \ Math/Algo.h \ Math/Bezier.h \ Math/Constants.h \ Math/Point3D.h \ Math/Vector4.h \ Math/Matrix2.h \ Math/Spline.h \ Math/Vector3.h \ Math/MathFunctions.h \ Math/Quaternion.h \ Math/Trigonometry.h \ Math/Line3D.h \ Math/MathInc.h \ Math/Complex.h \ Math/Matrix3.h \ Math/Vector2.h \ Math/Line2D.h \ Math/Point2D.h \ Math/Point2D-inl.h \ Math/Tweening.h \ Math/Matrix4.h \ Math/MathUtility.h source_h = \ Animation.h \ Animation-inl.h \ AnimationController.h \ AsyncFileWriter.h \ EasingCurve.h \ Point.h \ FilePath.h \ System.h \ Parsing.h \ StringConversion.h \ GlobalInitializer.h \ Rect.h \ Platform.h \ Inalogic.h \ Color.h \ Colors.h \ Logger.h \ LoggerPrivate.h \ LoggingWriter.h \ RollingFileAppender.h \ Memory.h \ Error.h \ SystemGNU.h \ NuxCore.h \ FileName.h \ OutputDevice.h \ Process.h \ ObjectType.h \ ObjectPtr.h \ NumberConversion.h \ Object.h \ Size.h \ Size-inl.h \ Exception.h \ TimeFunctions.h \ Macros.h \ ThreadGNU.h \ TextString.h \ Template.h \ NUniqueIndex.h \ FileIO.h \ InitiallyUnownedObject.h \ Property.h \ Property-inl.h \ PropertyAnimation.h \ PropertyOperators.h \ PropertyTraits.h \ Win32Dialogs/NWin32Clipboard.h libnux_core_@NUX_API_VERSION@_la_SOURCES = \ $(source_cpp) \ $(source_h) \ $(source_character_h) \ $(source_file_manager_h) \ $(source_math_h) \ $(source_memory_h) nux_coredir = $(includedir)/Nux-@NUX_API_VERSION@/NuxCore nux_core_HEADERS = $(source_h) nux_chardir = $(nux_coredir)/Character nux_char_HEADERS = $(source_character_h) nux_file_managerdir = $(nux_coredir)/FileManager nux_file_manager_HEADERS = $(source_file_manager_h) nux_mathdir = $(nux_coredir)/Math nux_math_HEADERS = $(source_math_h) nux_memorydir = $(nux_coredir)/Memory nux_memory_HEADERS = $(source_memory_h) # pkg-config file nux-core-@NUX_API_VERSION@.pc: nux-core.pc $(AM_V_GEN) cp -f nux-core.pc nux-core-@NUX_API_VERSION@.pc pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = nux-core-@NUX_API_VERSION@.pc unused_src = \ Character/NAscii.cpp \ Character/NAscii.h \ Character/NUnicodeGNU.cpp \ Character/NUnicodeGNU.h \ CppReadme.txt \ FileManager/NFileManagerWindows.cpp \ FileManager/NFileManagerWindows.h \ Plugin/NPlugin.h \ Plugin/NPluginInterface.h \ Plugin/NPluginManager.cpp \ Plugin/NPluginManager.h \ Plugin/NPluging.cpp \ SystemWindows.cpp \ SystemWindows.h \ ThreadWin.cpp \ ThreadWin.h \ Win32Dialogs/NWin32Clipboard.cpp \ Win32Dialogs/NWin32CustomDialog.cpp \ Win32Dialogs/NWin32CustomDialog.h \ Win32Dialogs/NWin32MessageBox.cpp \ Win32Dialogs/NWin32MessageBox.h CLEANFILES += nux-core-@NUX_API_VERSION@.pc DISTCLEANFILES += nux-core.pc EXTRA_DIST += nux-core.pc.in ${unused_src} nux-4.0.8+18.10.20180623/NuxCore/Math/0000755000000000000000000000000013313373365013055 5ustar nux-4.0.8+18.10.20180623/NuxCore/Math/Algo.cpp0000644000000000000000000000577713313373365014463 0ustar /* * Copyright 2010-2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "MathInc.h" namespace nux { int PointInside2DPolygon(Point2* polygon, int n, Point2 pt, const int onedge) { nuxAssert(n > 3); if(n < 3) return 0; //cross points count of x int __count = 0; //neighbor bound vertices Point2D p1, p2; //left vertex p1 = polygon[0]; //check all rays for(int i = 1; i <= n; ++i) { //point is an vertex if(pt == p1) return onedge; //right vertex p2 = polygon[i % n]; //ray is outside of our interests if(pt.y < Min(p1.y, p2.y) || pt.y > Max(p1.y, p2.y)) { //next ray left point p1 = p2; continue; } //ray is crossing over by the algorithm (common part of) if(pt.y > Min(p1.y, p2.y) && pt.y < Max(p1.y, p2.y)) { //x is before of ray if(pt.x <= Max(p1.x, p2.x)) { //overlies on a horizontal ray if(p1.y == p2.y && pt.x >= Min(p1.x, p2.x)) return onedge; //ray is vertical if(p1.x == p2.x) { //overlies on a ray if(p1.x == pt.x) return onedge; //before ray else ++__count; } //cross point on the left side else { //cross point of x double xinters = (pt.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x; //overlies on a ray if(fabs(pt.x - xinters) < constants::dbl_epsilon) return onedge; //before ray if(pt.x < xinters) ++__count; } } } //special case when ray is crossing through the vertex else { //p crossing over p2 if(pt.y == p2.y && pt.x <= p2.x) { //next vertex const Point2& p3 = polygon[(i+1) % n]; //pt.y lies between p1.y & p3.y if(pt.y >= Min(p1.y, p3.y) && pt.y <= Max(p1.y, p3.y)) { ++__count; } else { __count += 2; } } } //next ray left point p1 = p2; } //EVEN if(__count % 2 == 0) return(0); //ODD else return(1); } } nux-4.0.8+18.10.20180623/NuxCore/Math/Algo.h0000644000000000000000000000274213313373365014115 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef ALGO_H #define ALGO_H #include "Constants.h" #include "Constants.h" namespace nux { //http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/ //! Determine if a point lies inside a polygon. /*! If the point is on an edge or a point of the polygon, return the parameter "OnEdge" @polygon The polygon to test. @n Number of points in the polygon @n pt The point to test. @onedge Value to return if the point lies on an edge or a vertex of the polygon @return 1 if the point is inside, 0 if it is outside, onedge if it is on the edges of the polygon. */ int PointInside2DPolygon(Point2* polygon, int n, Point2 pt, const int onedge); } #endif // ALGO_H nux-4.0.8+18.10.20180623/NuxCore/Math/Bezier.cpp0000644000000000000000000000427313313373365015007 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "MathFunctions.h" #include "Bezier.h" namespace nux { NUX_DECLSPEC_DLL double *Bernstein (int n, double t) { if (n < 0) { NUX_BREAK_ASM_INT3; } double *bernstein; int i; bernstein = new double[n+1]; for (i = 0; i <= n; i++ ) { bernstein[i] = BinomialCoefficient (n, i) * PowerInt (t, i) * PowerInt (1.0 - t, n - i); } return bernstein; } NUX_DECLSPEC_DLL void Bezier_XY (int n, double t, double xcon[], double ycon[], double *xval, double *yval) { if (n < 0) { NUX_BREAK_ASM_INT3; } double *bval; int i; bval = Bernstein ( n, t ); *xval = 0.0; for ( i = 0; i <= n; i++ ) *xval = *xval + xcon[i] * bval[i]; *yval = 0.0; for ( i = 0; i <= n; i++ ) *yval = *yval + ycon[i] * bval[i]; delete [] bval; } NUX_DECLSPEC_DLL void Bezier_XYZ (int n, double t, double xcon[], double ycon[], double zcon[], double *xval, double *yval, double *zval) { if (n < 0) NUX_BREAK_ASM_INT3; double *bval; int i; bval = Bernstein ( n, t ); *xval = 0.0; for ( i = 0; i <= n; i++ ) *xval = *xval + xcon[i] * bval[i]; *yval = 0.0; for ( i = 0; i <= n; i++ ) *yval = *yval + ycon[i] * bval[i]; *zval = 0.0; for ( i = 0; i <= n; i++ ) *zval = *zval + zcon[i] * bval[i]; delete [] bval; } } nux-4.0.8+18.10.20180623/NuxCore/Math/Bezier.h0000644000000000000000000000502413313373365014447 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef BEZIER_H #define BEZIER_H #include "Constants.h" namespace nux { //! Evaluate the Bernstein polynomial of degree n, at parameter t. /*! Evaluate the Bernstein polynomial of degree n, at parameter t. @param n The degree of the Bernstein basis polynomials. @param t The evaluation point. @return the values of the n+1 Bernstein basis of degree n. */ NUX_DECLSPEC_DLL double *Bernstein (int n, double t); //! Evaluate 2D Bezier curve of degree n. /*! Evaluate 2D Bezier curve of degree n. @param n The degree of the Bezier curve. @param t Parameter. @param xcon Array of n+1 x coordinates of control points. @param ycon Array of n+1 y coordinates of control points. @param xval Return the x coordinates of the Bezier curve at parameter t. @param yval Return the y coordinates of the Bezier curve at parameter t. */ NUX_DECLSPEC_DLL void Bezier_XY (int n, double t, double xcon[], double ycon[], double *xval, double *yval); //! Evaluate 2D Bezier curve of degree n. /*! Evaluate 2D Bezier curve of degree n. @param n The degree of the Bezier curve. @param t Parameter. @param xcon Array of n+1 x coordinates of control points. @param ycon Array of n+1 y coordinates of control points. @param ycon Array of n+1 z coordinates of control points. @param xval Return the x coordinates of the Bezier curve at parameter t. @param yval Return the y coordinates of the Bezier curve at parameter t. @param yval Return the z coordinates of the Bezier curve at parameter t. */ NUX_DECLSPEC_DLL void Bezier_XYZ (int n, double t, double xcon[], double ycon[], double zcon[], double *xval, double *yval, double *zval); } #endif // BEZIER_H nux-4.0.8+18.10.20180623/NuxCore/Math/Complex.cpp0000644000000000000000000001704513313373365015177 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Complex.h" namespace nux { ComplexNumber::ComplexNumber (float re, float im) { real_ = re; imaginary_ = im; } ComplexNumber::ComplexNumber (const ComplexNumber &complex) { real_ = complex.real_; imaginary_ = complex.imaginary_; } ComplexNumber::~ComplexNumber() { } ComplexNumber &ComplexNumber::operator= (const ComplexNumber &complex) { real_ = complex.real_; imaginary_ = complex.imaginary_; return *this; } /*const ComplexNumber ComplexNumber::operator + (const ComplexNumber& complex) const { ComplexNumber result; result.real_ = real_ + complex.real_; result.imaginary_ = imaginary_ + complex.imaginary_; return result; } const ComplexNumber ComplexNumber::operator - (const ComplexNumber& complex) const { ComplexNumber result; result.real_ = real_ - complex.real_; result.imaginary_ = imaginary_ - complex.imaginary_; return result; } const ComplexNumber ComplexNumber::operator*(const ComplexNumber& complex) const { ComplexNumber result; float a, b, c, d; a = real_; b = imaginary_; c = complex.real_; d = complex.imaginary_; result.real_ = (a*c - b*d); result.imaginary_ = (a*d + b*c); return result; } const ComplexNumber ComplexNumber::operator / (const ComplexNumber& complex) const { ComplexNumber result; float a, b, c, d; float inv_denominator; a = real_; b = imaginary_; c = complex.real_; d = complex.imaginary_; inv_denominator = (float) 1.0 / (c*c + d*d); result.real_ = (a*c + b*d) * inv_denominator; result.imaginary_ = (b*c - a*d) * inv_denominator; return result; } */ /*const ComplexNumber ComplexNumber::operator * (const float& f) const { ComplexNumber result; result.real_ = real_ * f; result.imaginary_ = imaginary_ * f; return result; }*/ /*const ComplexNumber ComplexNumber::operator / (const float& f) const { ComplexNumber result; //if(f == 0.0f) // trow(Exception); result.real_ = real_ / f ; result.imaginary_ = imaginary_ / f; return result; }*/ void ComplexNumber::operator+= (const ComplexNumber &complex) { real_ += complex.real_; imaginary_ += complex.imaginary_; } void ComplexNumber::operator-= (const ComplexNumber &complex) { real_ -= complex.real_; imaginary_ -= complex.imaginary_; } void ComplexNumber::operator*= (const ComplexNumber &complex) { ComplexNumber result; float a, b, c, d; a = real_; b = imaginary_; c = complex.real_; d = complex.imaginary_; real_ = (a * c - b * d); imaginary_ = (a * d + b * c); } void ComplexNumber::operator /= (const ComplexNumber &complex) { ComplexNumber result; float a, b, c, d; float inv_denominator; //if(complex.real_ == 0 && complex.imaginary_ == 0) // trow(Exeption); a = real_; b = imaginary_; c = complex.real_; d = complex.imaginary_; inv_denominator = (float) 1.0 / (c * c + d * d); real_ = (a * c + b * d) * inv_denominator; imaginary_ = (b * c - a * d) * inv_denominator; } /*void ComplexNumber::operator *= (const float& f) { real_ *= f; imaginary_ *= f; }*/ /*void ComplexNumber::operator/=(const float& f) { //if(f == 0.0f) // trow(Exception); real_ *= (float)1.0 / f; imaginary_ *= (float)1.0 / f; }*/ void ComplexNumber::conjugue() { imaginary_ = -imaginary_; } float ComplexNumber::absolute() { float x, y, result; x = (float) std::fabs (real_); y = (float) std::fabs (imaginary_); if (x == 0.0) result = y; else { if (y == 0.0) result = x; else { float temp; if (x > y) { temp = y / x; result = x * (float) std::sqrt (1.0 + temp * temp); } else { temp = x / y; result = y * (float) std::sqrt (1.0 + temp * temp); } } } return result; } bool ComplexNumber::IsNull() { if ( (real_ == 0) && (imaginary_ == 0) ) { return true; } return false; } float ComplexNumber::real() const { return real_; } float ComplexNumber::imaginary() const { return imaginary_; } void ComplexNumber::real (float r) { real_ = r; } void ComplexNumber::imaginary (float i) { imaginary_ = i; } const ComplexNumber operator + (const ComplexNumber &lhs, const ComplexNumber &rhs) { return ComplexNumber (lhs.real() + rhs.real(), lhs.imaginary() + rhs.imaginary() ); } const ComplexNumber operator - (const ComplexNumber &lhs, const ComplexNumber &rhs) { return ComplexNumber (lhs.real() - rhs.real(), lhs.imaginary() - rhs.imaginary() ); } const ComplexNumber operator* (const ComplexNumber &lhs, const ComplexNumber &rhs) { ComplexNumber result; float a, b, c, d; a = lhs.real(); b = lhs.imaginary(); c = rhs.real(); d = rhs.imaginary(); result.real (a * c - b * d); result.imaginary (a * d + b * c); return result; } const ComplexNumber operator/ (const ComplexNumber &lhs, const ComplexNumber &rhs) { ComplexNumber result; float a, b, c, d; float inv_denominator; a = lhs.real(); b = lhs.imaginary(); c = rhs.real(); d = rhs.imaginary(); inv_denominator = (float) 1.0 / (c * c + d * d); result.real ( (a * c + b * d) * inv_denominator); result.imaginary ( (b * c - a * d) * inv_denominator); return result; } /*fcomplex Cdiv(fcomplex a, fcomplex b) { fcomplex c; float den, r; if (fabs(b.r) >= fabs(b.i)) { r = b.i/b.r; den = b.r + r*b.i; c.r = (a.r+r*a.i) / den; c.i = (a.i-r*a.r) / den; } else { r = b.r/b.i; den = b.i + r*b.r; c.r = (a.r*r+a.i) / den; c.i = (a.i*r-a.r) / den; } return c; } */ /* fcomplex Csqrt(fcomplex z) { fcomplex c; float w; if ((z.r == 0.0) && (z.i == 0.0)) { c.r = 0.0; c.i = 0.0; } else { w = sqrt( (sqrt( z.r*z.r + z.i*z.i ) + fabs(z.r)) * 0.5); if (z.r >= 0.0) { c.r = w; c.i = z.i / (2.0*w); } else { c.i = (z.i >= 0) ? w : -w; c.r = z.i / (2.0*c.i); } } return c; } fcomplex RCmul(float x, fcomplex a) { fcomplex c; c.r = x*a.r; c.i = x*a.i; return c; } fcomplex Cinv( fcomplex z) { fcomplex c; float s = 1.0 / (z.r*z.r + z.i*z.i); c.r = z.r * s; c.i = -z.i * s; return c; } */ } nux-4.0.8+18.10.20180623/NuxCore/Math/Complex.h0000644000000000000000000000447713313373365014651 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef COMPLEX_H #define COMPLEX_H namespace nux { class ComplexNumber { public: ~ComplexNumber(); ComplexNumber (float re = 0.0f, float im = 0.0f); ComplexNumber (const ComplexNumber &); ComplexNumber &operator = (const ComplexNumber &); //const ComplexNumber operator + (const ComplexNumber&) const; //const ComplexNumber operator - (const ComplexNumber&) const; //const ComplexNumber operator * (const ComplexNumber&) const; //const ComplexNumber operator / (const ComplexNumber&) const; //const ComplexNumber operator * (const float& f) const; //const ComplexNumber operator / (const float& f) const; void operator += (const ComplexNumber &); void operator -= (const ComplexNumber &); void operator *= (const ComplexNumber &); void operator /= (const ComplexNumber &); //void operator *= (const float& f); //void operator /= (const float& f); void conjugue(); float absolute(); bool IsNull(); float real() const; float imaginary() const; void real (float r); void imaginary (float i); private: float real_; float imaginary_; }; // does that conflict with the operators above??? const ComplexNumber operator+ (const ComplexNumber &lhs, const ComplexNumber &rhs); const ComplexNumber operator- (const ComplexNumber &lhs, const ComplexNumber &rhs); const ComplexNumber operator* (const ComplexNumber &lhs, const ComplexNumber &rhs); const ComplexNumber operator/ (const ComplexNumber &lhs, const ComplexNumber &rhs); } #endif // COMPLEX_H nux-4.0.8+18.10.20180623/NuxCore/Math/Constants.cpp0000644000000000000000000000340213313373365015534 0ustar /* * Copyright 2010-2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Constants.h" #include namespace nux { namespace constants { const float pi = 3.1415926535f; const float e = 2.7182817f; const float sqrt2 = 1.414214f; const float sqrt3 = 1.732051f; const float golden = 1.618034f; const double epsilon_milli = 0.001; const double epsilon_micro = 0.000001; const double epsilon_nano = 0.000000001; const double epsilon_pico = 0.000000000001; const double epsilon_femto = 0.000000000000001; #if defined(NUX_OS_WINDOWS) const float flt_epsilon = FLT_EPSILON; const double dbl_epsilon = DBL_EPSILON; #elif defined(NUX_OS_LINUX) const float flt_epsilon = __FLT_EPSILON__; const double dbl_epsilon = __DBL_EPSILON__; #elif defined(NUX_OS_MACOSX) const float dbl_epsilon = _FLT_EPSILON_; const double dbl_epsilon = _DBL_EPSILON_; #else #error Undefined OS. #endif } // namespace constants } nux-4.0.8+18.10.20180623/NuxCore/Math/Constants.h0000644000000000000000000000246013313373365015204 0ustar /* * Copyright 2010-2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef CONSTANTS_H #define CONSTANTS_H namespace nux { namespace constants { extern const float pi; extern const float e; extern const float sqrt2; extern const float sqrt3; extern const float golden; extern const double epsilon_milli; extern const double epsilon_micro; extern const double epsilon_nano; extern const double epsilon_pico; extern const double epsilon_femto; extern const float flt_epsilon; extern const double dbl_epsilon; }; } #endif // CONSTANTS_H nux-4.0.8+18.10.20180623/NuxCore/Math/Line2D.cpp0000644000000000000000000000156313313373365014643 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Vector2.h" #include "Line2D.h" namespace nux { } nux-4.0.8+18.10.20180623/NuxCore/Math/Line2D.h0000644000000000000000000000637313313373365014314 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef LINE2D_H #define LINE2D_H #include "Vector2.h" namespace nux { template class Line2D { public: Line2D(); ~Line2D(); Line2D (const Line2D &line); Line2D (T lx_start, T ly_start, T lz_start, T lx_end, T ly_end, T lz_end); Line2D (const Vec2& pt, Vec2 v); const Line2D& operator = (const Line2D&); bool operator == (const Line2D& line) const; float Length() const; const Vec2 GetDirectionVector() const; const Vec2 GetStartPoint() const; const Vec2 GetEndPoint() const; private: T x_start, y_start; T x_end, y_end; }; template Line2D::Line2D() { x_start = y_start = x_end = y_end = 0; } template Line2D::~Line2D() { } template Line2D::Line2D (const Line2D &line) { x_start = line.x_start; x_end = line.x_end; y_start = line.y_start; y_end = line.y_end; } template Line2D::Line2D (T lx_start, T ly_start, T lz_start, T lx_end, T ly_end, T lz_end) { x_start = lx_start; x_end = lx_end; y_start = ly_start; y_end = ly_end; } template Line2D::Line2D (const Vec2& pt, Vec2 v) { x_start = pt.x; y_start = pt.y; x_end = x_start + v.x; y_end = y_start + v.y; } template const Line2D& Line2D::operator = (const Line2D& Line) { x_start = Line.x_start; x_end = Line.x_end; y_start = Line.y_start; y_end = Line.y_end; } template bool Line2D::operator == (const Line2D& line) const { if ( (x_start == line.x_start) && (y_start == line.y_start) && (x_end == line.x_end) && (y_end == line.y_end) ) { return true; } else { return false; } } template float Line2D::Length() const { float l; l = (float) std::sqrt ( (x_end - x_start) * (x_end - x_start) + (y_end - y_start) * (y_end - y_start) ); return l; } template const Vec2 Line2D::GetDirectionVector() const { return Vec2 (x_start - x_end, y_start - y_end); } template const Vec2 Line2D::GetStartPoint() const { Vec2 p (x_start, y_start); return p; } template const Vec2 Line2D::GetEndPoint() const { Vec2 p (x_end, y_end); return p; } }; #endif // LINE2D_H nux-4.0.8+18.10.20180623/NuxCore/Math/Line3D.cpp0000644000000000000000000000156513313373365014646 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Vector3.h" #include "Line3D.h" namespace nux { } nux-4.0.8+18.10.20180623/NuxCore/Math/Line3D.h0000644000000000000000000000725713313373365014317 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef LINE3D_H #define LINE3D_H #include "Vector3.h" namespace nux { template class Line3D { public: Line3D(); ~Line3D(); Line3D (const Line3D &line); Line3D (T lx_start, T ly_start, T lz_start, T lx_end, T ly_end, T lz_end); Line3D (const Vector3 &pt, Vector3 v); const Line3D& operator = (const Line3D&); bool operator == (const Line3D& line) const; float Length() const; const Vec3 GetDirectionVector() const; const Vec3 GetStartPoint() const; const Vec3 GetEndPoint() const; private: T x_start, y_start, z_start; T x_end, y_end, z_end; }; template Line3D::Line3D() { x_start = y_start = z_start = x_end = y_end = z_end = 0; } template Line3D::~Line3D() { } template Line3D::Line3D (const Line3D &line) { x_start = line.x_start; x_end = line.x_end; y_start = line.y_start; y_end = line.y_end; z_start = line.z_start; z_end = line.z_end; } template Line3D::Line3D (T lx_start, T ly_start, T lz_start, T lx_end, T ly_end, T lz_end) { x_start = lx_start; x_end = lx_end; y_start = ly_start; y_end = ly_end; z_start = lz_start; z_end = lz_end; } template Line3D::Line3D (const Vector3 &pt, Vector3 v) { x_start = pt.x; y_start = pt.y; z_start = pt.z; x_end = x_start + v.x; y_end = y_start + v.y; z_end = y_start + v.z; } template const Line3D& Line3D::operator = (const Line3D& Line) { x_start = Line.x_start; y_start = Line.y_start; z_start = Line.z_start; x_end = Line.x_end; y_end = Line.y_end; z_end = Line.z_end; } template bool Line3D::operator == (const Line3D &line) const { if ( (x_start == line.x_start) && (y_start == line.y_start) && (z_start == line.z_start) && (x_end == line.x_end) && (y_end == line.y_end) && (z_end == line.z_end) ) { return true; } else { return false; } } template float Line3D::Length() const { float l; l = (float) std::sqrt ( (x_end - x_start) * (x_end - x_start) + (y_end - y_start) * (y_end - y_start) + (z_end - z_start) * (z_end - z_start) ); return l; } template const Vec3 Line3D::GetDirectionVector() const { return Vec3 (x_start - x_end, y_start - y_end, z_start - z_end); } template const Vec3 Line3D::GetStartPoint() const { Vec3 p (x_start, y_start, z_start); return p; } template const Vec3 Line3D::GetEndPoint() const { Vec3 p (x_end, y_end, z_end); return p; } } #endif // LINE3D_H nux-4.0.8+18.10.20180623/NuxCore/Math/MathFunctions.cpp0000644000000000000000000000263613313373365016352 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "MathFunctions.h" namespace nux { int Factorial (int n) { int i = 1; while (0 < n) { i *= n; n--; } return i; } double BinomialCoefficient (int n, int k) { if (n < 0) NUX_BREAK_ASM_INT3; if (k < 0 || k > n) return 0.0; double d = (double) Factorial (n) / (double) (Factorial (n - k) * Factorial (k) ); return d; } double Power (double x, double y) { return std::pow (x, y); } double Log2 (double d) { return std::log (d) / std::log (2.0); } double Floor (double d) { return std::floor (d); } } nux-4.0.8+18.10.20180623/NuxCore/Math/MathFunctions.h0000644000000000000000000000302013313373365016003 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MATHFUNCTIONS_H #define MATHFUNCTIONS_H #include "Constants.h" namespace nux { int Factorial (int n); double BinomialCoefficient (int n, int k); //! Template power function. The exponent is an integer. /*! Template power function. The exponent is an integer. */ template inline T PowerInt (T _X, int _Y) // taken from Microsoft { unsigned int _N; if (_Y >= 0) _N = _Y; else _N = -_Y; for (T _Z = T (1); ; _X *= _X) { if ( (_N & 1) != 0) _Z *= _X; if ( (_N >>= 1) == 0) return (_Y < 0 ? T (1) / _Z : _Z); } } double Power (double x, double y); double Log2 (double d); double Floor (double d); } #endif // MATHFUNCTIONS_H nux-4.0.8+18.10.20180623/NuxCore/Math/MathInc.h0000644000000000000000000000223013313373365014546 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MATHINC_H #define MATHINC_H #include "Constants.h" #include "MathUtility.h" #include "Complex.h" #include "Line2D.h" #include "Line3D.h" #include "Matrix2.h" #include "Matrix3.h" #include "Matrix4.h" #include "Quaternion.h" #include "Vector2.h" #include "Vector3.h" #include "Vector4.h" #include "Point2D.h" #include "Point3D.h" #include "Algo.h" #endif // MATHINC_H nux-4.0.8+18.10.20180623/NuxCore/Math/MathUtility.h0000644000000000000000000002673613313373365015521 0ustar /* * Copyright 2010-2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MATHUTILITY_H #define MATHUTILITY_H #include #include #include #include #include #include #include "Constants.h" #define DEGTORAD(d) (d) * nux::constants::pi / 180.0f #define RADTODEG(d) (d) * 180.0f / nux::constants::pi namespace nux { template inline T Square (const T A) { return A * A; } template inline T Clamp (const T X, const T min_value, const T max_value) { return X < min_value ? min_value : X < max_value ? X : max_value; } template inline T ClampUp (const T X, const T min_value) { return X < min_value ? min_value : X; } template inline T ClampDown (const T X, const T max_value) { return X > max_value ? max_value : X; } template inline T Align (const T Ptr, int Alignment) { return (T) (((unsigned int) Ptr + Alignment - 1) & ~ (Alignment - 1)); } //Bitwise rotation on the left. template inline const T Rol (const T &a, const unsigned int n = 1) { return (a << n) | (a >> ((sizeof (T) << 3) - n)); } //Bitwise rotation on the right. template inline const T Ror (const T &a, const unsigned int n = 1) { return (a >> n) | (a << ((sizeof (T) << 3) - n)); } //! Return the absolute value of a. template inline const T Abs (const T &a) { return a >= 0 ? a : -a; } //! Return the minimum between a and b. template inline const T &Min (const T &a, const T &b) { return a <= b ? a : b; } //! Return the minimum between a, b and c. template inline const T &Min (const T &a, const T &b, const T &c) { return Min (Min (a, b), c); } //! Return the minimum between a, b, c and d. template inline const T &Min (const T &a, const T &b, const T &c, const T &d) { return Min (Min (Min (a, b), c), d); } //! Return the maximum between a and b. template inline const T &Max (const T &a, const T &b) { return a >= b ? a : b; } //! Return the maximum between a, b and c. template inline const T &Max (const T &a, const T &b, const T &c) { return Max (Max (a, b), c); } //! Return the maximum between a,b,c and d. template inline const T &Max (const T &a, const T &b, const T &c, const T &d) { return Max (Max (a, b, c), d); } template inline T Max3 (const T A, const T B, const T C) { return Max (Max (A, B), C); } template inline T Min3 (const T A, const T B, const T C) { return Min (Min (A, B), C); } //! Return the sign of x. template inline T Sign (const T &x) { return (x < 0) ? -1 : (x == 0 ? 0 : 1); } template inline T Modulo (const T &x, const T &m) { return x - m * (T) std::floor ((double) x / m); } inline int ModuloInt (const int x, const int m) { return x >= 0 ? x % m : (x % m ? m + x % m : 0); } template inline T MinMod (const T &a, const T &b) { return a * b <= 0 ? 0 : (a > 0 ? (a < b ? a : b) : (a < b ? b : a)); } //! Return a random variable between [0,1[ (uniform distribution). /*! @return a random double value in the range [0, 1[ */ inline double Random() { return (double) std::rand() / RAND_MAX; } //! Return a random variable between [-1,1[ (uniform distribution). /*! @return a random double value in the range [-1, 1[. */ inline double CRandom() { return 1 - 2 * (std::rand() / RAND_MAX); } //! Return a random variable using a gaussian distribution and a variance of 1. /*! @return a random double value in the range [-1, 1[. */ inline double RandomGaussian() { return std::sqrt (-2 * std::log ((double) (1e-10 + (1 - 2e-10) * std::rand()))) * std::cos ((double) (2 * constants::pi * std::rand())); } inline unsigned int RandomUInt() { return std::rand(); } inline unsigned int RandomUInt (unsigned int max_random) { return std::rand() % max_random; } inline size_t DiffPointer (void *Ptr0, void *Ptr1) { if ((size_t) Ptr0 >= (size_t) Ptr1) return (size_t) ((size_t) Ptr0 - (size_t) Ptr1); return (size_t) ((size_t) Ptr1 - (size_t) Ptr0); } // Dangerous to use! template inline T SubstractPointer (void *Ptr, size_t Value) { return (T) (((size_t) Ptr) - Value); } template inline T AddPointer (void *Ptr, size_t Value) { return (T) (((size_t) Ptr) + Value); } //! Round up to the nearest multiple of Alignment that is greater or equal to Value /*! @param Alignment Must be a power of 2 */ template inline T RoundUp (T Value, int Alignment) { return (Value + (Alignment - 1)) & ~ (Alignment - 1); } //! Round down to the nearest multiple of Alignment that is smaller or equal to Value /*! @param Alignment Must be a power of 2 */ template inline T RoundDown (T Value, int Alignment) { return ((Value) & ~ (Alignment - 1)); } //! Return true is Value is aligned on Alignment /*! @param Alignment Must be a power of 2 */ template inline bool IsAligned (T Value, int Alignment) { return (((Value) & ~ (Alignment - 1)) == 0); } /*! Revert Byte order 0x0011 -> 0x1100 */ inline unsigned short ReverseByteOrdering (unsigned short value) { unsigned short temp; unsigned char *src = (unsigned char *) &value; unsigned char *dest = (unsigned char *) &temp; dest[0] = src[1]; dest[1] = src[0]; return temp; } /*! Revert Byte order 0x00112233 -> 0x33221100 */ inline unsigned int ReverseByteOrdering (unsigned int value) { unsigned int temp; unsigned char *src = (unsigned char *) &value; unsigned char *dest = (unsigned char *) &temp; dest[0] = src[3]; dest[1] = src[2]; dest[2] = src[1]; dest[3] = src[0]; return temp; } /*! Revert Byte order 0x0011223344556677 -> 0x7766554433221100 */ inline unsigned long long ReverseByteOrdering (unsigned long long value) { unsigned long long temp; unsigned char *src = (unsigned char *) &value; unsigned char *dest = (unsigned char *) &temp; dest[0] = src[7]; dest[1] = src[6]; dest[2] = src[5]; dest[3] = src[4]; dest[4] = src[3]; dest[5] = src[2]; dest[6] = src[1]; dest[7] = src[0]; return temp; } // Bit Hack // Determining if an integer is a power of 2 // http://graphics.stanford.edu/~seander/bithacks.html inline bool IsPowerOf2 (unsigned int n) { // The algorithm does not 0 consider 0 a power of two. (this is right) return ! (n & (n - 1)) && n; } // Compute the next highest power of 2 of 32-bit v // http://graphics.stanford.edu/~seander/bithacks.html inline unsigned int NextPowerOfTwo (unsigned int x) { x = x - 1; x = x | (x >> 1); x = x | (x >> 2); x = x | (x >> 4); x = x | (x >> 8); x = x | (x >> 16); return x + 1; } inline unsigned int GetLowerPowerOfTwoExponent (unsigned int x) { int count = 0; while (x > 1) { x >>= 1; count++; } return count; } inline unsigned int PowerOfTwo (int i) { int e = 0; unsigned int power = 1; while (e < i) { power = power << 1; e++; } return power; } // ClearLSBBit(0x01001100) = 0x01001000 inline unsigned int Hak32_ClearLSBBit (unsigned int N) { return N & (N - 1); } // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan // Hak32_CountNumBits(0x01001100) = 3 inline unsigned int Hak32_CountNumBits (unsigned int N) { unsigned int v = N; // count the number of bits set in v unsigned int c; // c accumulates the total bits set in v for (c = 0; v; c++) { v &= v - 1; // clear the least significant bit set } return c; } // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan : Compute parity in parallel inline unsigned int Hak32_BitParity (unsigned int N) { unsigned int v = N; // word value to compute the parity of v ^= v >> 16; v ^= v >> 8; v ^= v >> 4; v &= 0xf; return (0x6996 >> v) & 1; } #define HAK32_SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) // Return true if the CPU is little endian inline bool Hak32_CPULittleEndian() { const int x = 1; return ((unsigned char *) &x) [0]; } // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious // Find the log base 10 of an N-bit integer in O(lg(N)) inline unsigned int Hak32_Log2 (unsigned int N) { unsigned int v = N; // find the log base 2 of 32-bit v int r; // result goes here static const int MultiplyDeBruijnBitPosition[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; v |= v >> 1; // first round down to power of 2 v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v = (v >> 1) + 1; r = MultiplyDeBruijnBitPosition[static_cast (v * 0x077CB531UL) >> 27]; return r; } // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious // Find the log base 2 of an N-bit integer in O(lg(N)) inline unsigned int Hak32_Log10 (unsigned int N) { unsigned int v = N; // non-zero 32-bit integer value to compute the log base 10 of int r; // result goes here int t; // temporary static unsigned int const PowersOf10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; t = (Hak32_Log2 (v) + 1) * 1233 >> 12; // (use a lg2 method from above) r = t - (v < PowersOf10[t]); return r; } // http://graphics.stanford.edu/~seander/bithacks.html // Count the consecutive zero bits (trailing) on the right by binary search inline unsigned int Hack32_TrailingZeroRight (unsigned int N) { unsigned int v = N; // 32-bit word input to count zero bits on right unsigned int c; // c will be the number of zero bits on the right, // so if v is 1101000 (base 2), then c will be 3 // NOTE: if 0 == v, then c = 31. if (v & 0x1) { // special case for odd v (assumed to happen half of the time) c = 0; } else { c = 1; if ((v & 0xffff) == 0) { v >>= 16; c += 16; } if ((v & 0xff) == 0) { v >>= 8; c += 8; } if ((v & 0xf) == 0) { v >>= 4; c += 4; } if ((v & 0x3) == 0) { v >>= 2; c += 2; } c -= v & 0x1; } return c; } } #endif // MATHUTILITY_H nux-4.0.8+18.10.20180623/NuxCore/Math/Matrix2.cpp0000644000000000000000000000174013313373365015111 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Matrix2.h" // When writing to a matrix at row r and colum c use m[r][c]. // When reading from a matrix at row r and colum c use m[c][r]. namespace nux { } nux-4.0.8+18.10.20180623/NuxCore/Math/Matrix2.h0000644000000000000000000003405513313373365014563 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MATRIX2_H #define MATRIX2_H #include "Vector2.h" namespace nux { template class Matrix2x2 { public: Matrix2x2(); ~Matrix2x2(); Matrix2x2 (const Matrix2x2&); Matrix2x2& operator = (const Matrix2x2&); bool operator == (const Matrix2x2&); Matrix2x2 operator * (const Matrix2x2&) const; Matrix2x2 operator + (const Matrix2x2&) const; Matrix2x2 operator - (const Matrix2x2&) const; Matrix2x2& operator *= (const Matrix2x2&) const; Matrix2x2& operator += (const Matrix2x2&) const; Matrix2x2& operator -= (const Matrix2x2&) const; Matrix2x2 operator * (const T &) const; Matrix2x2 operator / (const T &) const; Matrix2x2& operator *= (const T &) const; Matrix2x2& operator /= (const T &) const; Vec2 operator * (const Vec2&) const; Matrix2x2 operator - (); // Get the (i, j) element of the current matrix. T &operator() (unsigned int i, unsigned int j); T operator () (unsigned int i, unsigned int j) const; void Zero(); void Identity(); T Determinant() const ; void Inverse(); Matrix2x2 GetInverse() const; static Matrix2x2 IDENTITY(); static Matrix2x2 ZERO(); T m[2][2]; }; /***************************************************************************************\ Function: Matrix2::Matrix2 Description: Constructor. Initialize the matrix to identity. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template Matrix2x2::Matrix2x2() { Identity(); } template T Matrix2x2::Determinant() const { T det; det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; return det; } template void Matrix2x2::Inverse() { T det = Determinant(); if (det == T (0) ) { // Determinant is null. Matrix cannot be inverted. #ifdef NUX_DEBUG NUX_HARDWARE_BREAK; #endif return; } Matrix2x2 Temp; Temp.m[0][0] = m[1][1]; Temp.m[0][1] = -m[0][1]; Temp.m[1][0] = -m[1][0]; Temp.m[1][1] = m[0][0]; *this = (T (1) / det) * Temp; } template Matrix2x2 Matrix2x2::GetInverse() const { Matrix2x2 Temp = *this; Temp.Inverse(); return Temp; } /***************************************************************************************\ Function: Matrix2x2::~Matrix2 Description: Destructor. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template Matrix2x2::~Matrix2x2() { } /***************************************************************************************\ Function: Matrix2x2::Matrix2 Description: Copy constructor. Parameters: - M Return Value: None. Comments: None. \***************************************************************************************/ template Matrix2x2::Matrix2x2 (const Matrix2x2& M) { m[0][0] = M.m[0][0]; m[0][1] = M.m[0][1]; m[1][0] = M.m[1][0]; m[1][1] = M.m[1][1]; } /***************************************************************************************\ Function: Matrix2x2::operator = Description: Assignment operator. Parameters: - M Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2& Matrix2x2::operator = (const Matrix2x2& M) { m[0][0] = M.m[0][0]; m[0][1] = M.m[0][1]; m[1][0] = M.m[1][0]; m[1][1] = M.m[1][1]; return (*this); } template bool Matrix2x2::operator == (const Matrix2x2& M) { for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) { if (m[i][j] != M.m[i][j]) return false; } return true; } /***************************************************************************************\ Function: Matrix2x2::operator * Description: Multiply by matrix iM. Parameters: - iM. Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2 Matrix2x2::operator * (const Matrix2x2& iM) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] * iM.m[0][0] + m[0][1] * iM.m[1][0]; oM.m[1][0] = m[1][0] * iM.m[0][0] + m[1][1] * iM.m[1][0]; oM.m[0][1] = m[0][0] * iM.m[0][1] + m[0][1] * iM.m[1][1]; oM.m[1][1] = m[1][0] * iM.m[0][1] + m[1][1] * iM.m[1][1]; return oM; } /***************************************************************************************\ Function: Matrix2x2::operator + Description: Add matrix iM. Parameters: - iM Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2 Matrix2x2::operator + (const Matrix2x2& iM) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] + iM.m[0][0]; oM.m[0][1] = m[0][1] + iM.m[0][1]; oM.m[1][0] = m[1][0] + iM.m[1][0]; oM.m[1][1] = m[1][1] + iM.m[1][1]; return oM; } /***************************************************************************************\ Function: Matrix2x2::operator - Description: Substract matrix iM. Parameters: -iM Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2 Matrix2x2::operator - (const Matrix2x2& iM) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] - iM.m[0][0]; oM.m[0][1] = m[0][1] - iM.m[0][1]; oM.m[1][0] = m[1][0] - iM.m[1][0]; oM.m[1][1] = m[1][1] - iM.m[1][1]; return oM; } /***************************************************************************************\ Function: Matrix2x2::operator *= Description: Multiply by matrix iM. Parameters: - iM. Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2& Matrix2x2::operator *= (const Matrix2x2& iM) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] * iM.m[0][0] + m[0][1] * iM.m[1][0]; oM.m[1][0] = m[1][0] * iM.m[0][0] + m[1][1] * iM.m[1][0]; oM.m[0][1] = m[0][0] * iM.m[0][1] + m[0][1] * iM.m[1][1]; oM.m[1][1] = m[1][0] * iM.m[0][1] + m[1][1] * iM.m[1][1]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix2x2::operator += Description: Add matrix iM. Parameters: - iM Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2& Matrix2x2::operator += (const Matrix2x2& iM) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] + iM.m[0][0]; oM.m[0][1] = m[0][1] + iM.m[0][1]; oM.m[1][0] = m[1][0] + iM.m[1][0]; oM.m[1][1] = m[1][1] + iM.m[1][1]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix2x2::operator -= Description: Substract matrix iM. Parameters: -iM Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2& Matrix2x2::operator -= (const Matrix2x2& iM) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] - iM.m[0][0]; oM.m[0][1] = m[0][1] - iM.m[0][1]; oM.m[1][0] = m[1][0] - iM.m[1][0]; oM.m[1][1] = m[1][1] - iM.m[1][1]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix2x2::operator *= Description: Multiply all elements by f. Parameters: - f. Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2& Matrix2x2::operator *= (const T &f) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] * f; oM.m[0][1] = m[0][1] * f; oM.m[1][0] = m[1][0] * f; oM.m[1][1] = m[1][1] * f; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix2x2::operator / Description: Divide all elements by f. Parameters: - f Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2 Matrix2x2::operator / (const T &f) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] / f; oM.m[0][1] = m[0][1] / f; oM.m[1][0] = m[1][0] / f; oM.m[1][1] = m[1][1] / f; return oM; } /***************************************************************************************\ Function: Matrix2x2::operator /= Description: Divide all elements by f. Parameters: - f Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2& Matrix2x2::operator /= (const T &f) const { Matrix2x2 oM; oM.m[0][0] = m[0][0] / f; oM.m[0][1] = m[0][1] / f; oM.m[1][0] = m[1][0] / f; oM.m[1][1] = m[1][1] / f; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix2x2::operator * Description: Multiply a matrix by a vector. Parameters: - V Return Value: Vector2. Comments: None. \***************************************************************************************/ template Vec2 Matrix2x2::operator * (const Vec2& V) const { Vec2 oV; oV.x = V.x * m[0][0] + V.y * m[0][1]; oV.y = V.x * m[1][0] + V.y * m[1][1]; return oV; } /***************************************************************************************\ Function: Matrix2x2::operator - Description: Negate all elements of the matrix. Parameters: None. Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2 Matrix2x2::operator - () { Matrix2x2 oM; oM.m[0][0] = -m[0][0]; oM.m[0][1] = -m[0][1]; oM.m[1][0] = -m[1][0]; oM.m[1][1] = -m[1][1]; return oM; } template T &Matrix2x2::operator () (unsigned int i, unsigned int j) { return m[i][j]; } template T Matrix2x2::operator () (unsigned int i, unsigned int j) const { return m[i][j]; } /***************************************************************************************\ Function: Matrix2x2::zero Description: Set the matrix to zero. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix2x2::Zero() { m[0][0] = 0.0; m[0][1] = 0.0; m[1][0] = 0.0; m[1][1] = 0.0; //memset(m, 0, sizeof(m)); } /***************************************************************************************\ Function: Matrix2x2::identity Description: Set the matrix to identity. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix2x2::Identity() { m[0][0] = 1.0; m[0][1] = 0.0; m[1][0] = 0.0; m[1][1] = 1.0; } template Matrix2x2 Matrix2x2::IDENTITY() { Matrix2x2 matrix; matrix.Identity(); return matrix; } template Matrix2x2 Matrix2x2::ZERO() { Matrix2x2 matrix; matrix.Zero(); return matrix; } /***************************************************************************************\ Function: Matrix2x2::operator * Description: Multiply matrix rhs by constant lhs. Allow "f * matrix" operation. Parameters: None. Return Value: Matrix2x2. Comments: None. \***************************************************************************************/ template Matrix2x2 operator * (const T &lhs, const Matrix2x2& rhs) { Matrix2x2 oM; oM.m[0][0] = rhs.m[0][0] / lhs; oM.m[0][1] = rhs.m[0][1] / lhs; oM.m[1][0] = rhs.m[1][0] / lhs; oM.m[1][1] = rhs.m[1][1] / lhs; return oM; } } #endif // MATRIX2_H nux-4.0.8+18.10.20180623/NuxCore/Math/Matrix3.cpp0000644000000000000000000000173513313373365015116 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Matrix3.h" // When writing to a matrix at row r and colum c use m[r][c]. // When reading from a matrix at row r and colum c use m[c][r]. namespace nux { } nux-4.0.8+18.10.20180623/NuxCore/Math/Matrix3.h0000644000000000000000000004703713313373365014570 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MATRIX3_H #define MATRIX3_H #include "Vector3.h" namespace nux { template class Matrix3x3 { public: Matrix3x3(); ~Matrix3x3(); Matrix3x3 (const Matrix3x3&); Matrix3x3 ( T a00, T a01, T a02, T a10, T a11, T a12, T a20, T a21, T a22); Matrix3x3& operator = (const Matrix3x3&); bool operator == (const Matrix3x3&); Matrix3x3 operator * (const Matrix3x3&) const; Matrix3x3 operator + (const Matrix3x3&) const; Matrix3x3 operator - (const Matrix3x3&) const; Matrix3x3& operator *= (const Matrix3x3&) const; Matrix3x3& operator += (const Matrix3x3&) const; Matrix3x3& operator -= (const Matrix3x3&) const; Matrix3x3 operator * (const T &) const; Matrix3x3 operator / (const T &) const; Matrix3x3& operator *= (const T &) const; Matrix3x3& operator /= (const T &) const; Vec3 operator * (const Vec3&) const; Matrix3x3 operator - (); // Get the (i, j) element of the current matrix. T &operator() (unsigned int i, unsigned int j); T operator () (unsigned int i, unsigned int j) const; T Determinant() const ; void Inverse(); Matrix3x3 GetInverse() const; //Matrix2x2 GetUpper2x2() const; void Zero(); void Identity(); static Matrix3x3 IDENTITY(); static Matrix3x3 ZERO(); T m[3][3]; }; /***************************************************************************************\ Function: Matrix3x3::Matrix3x3 Description: Constructor. Initialize the matrix to identity. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template Matrix3x3::Matrix3x3() { Identity(); } /***************************************************************************************\ Function: Matrix3x3::~Matrix3x3 Description: Destructor. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template Matrix3x3::~Matrix3x3() { } /***************************************************************************************\ Function: Matrix3x3::Matrix3x3 Description: None. Parameters: - M Return Value: None. Comments: None. \***************************************************************************************/ template Matrix3x3::Matrix3x3 (const Matrix3x3& M) { m[0][0] = M.m[0][0]; m[0][1] = M.m[0][1]; m[0][2] = M.m[0][2]; m[1][0] = M.m[1][0]; m[1][1] = M.m[1][1]; m[1][2] = M.m[1][2]; m[2][0] = M.m[2][0]; m[2][1] = M.m[2][1]; m[2][2] = M.m[2][2]; } /***************************************************************************************\ Function: Matrix3x3::Matrix3x3 Description: None. Parameters: T a00, T a01, T a02, T a10, T a11, T a12, T a20, T a21, T a22 Return Value: None. Comments: None. \***************************************************************************************/ template Matrix3x3::Matrix3x3 ( T a00, T a01, T a02, T a10, T a11, T a12, T a20, T a21, T a22) { m[0][0] = a00; m[0][1] = a01; m[0][2] = a02; m[1][0] = a10; m[1][1] = a11; m[1][2] = a12; m[2][0] = a20; m[2][1] = a21; m[2][2] = a22; } /***************************************************************************************\ Function: Matrix3x3::operator = Description: None. Parameters: - M Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3& Matrix3x3::operator = (const Matrix3x3& M) { m[0][0] = M.m[0][0]; m[0][1] = M.m[0][1]; m[0][2] = M.m[0][2]; m[1][0] = M.m[1][0]; m[1][1] = M.m[1][1]; m[1][2] = M.m[1][2]; m[2][0] = M.m[2][0]; m[2][1] = M.m[2][1]; m[2][2] = M.m[2][2]; return (*this); } template bool Matrix3x3::operator == (const Matrix3x3& M) { for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) { if (m[i][j] != M.m[i][j]) return false; } return true; } /***************************************************************************************\ Function: Matrix3x3::operator * Description: Multiply by matrix iM. Parameters: - iM Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3 Matrix3x3::operator * (const Matrix3x3& iM) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] * iM.m[0][0] + m[0][1] * iM.m[1][0] + m[0][2] * iM.m[2][0]; oM.m[1][0] = m[1][0] * iM.m[0][0] + m[1][1] * iM.m[1][0] + m[1][2] * iM.m[2][0]; oM.m[2][0] = m[2][0] * iM.m[0][0] + m[2][1] * iM.m[1][0] + m[2][2] * iM.m[2][0]; oM.m[0][1] = m[0][0] * iM.m[0][1] + m[0][1] * iM.m[1][1] + m[0][2] * iM.m[2][1]; oM.m[1][1] = m[1][0] * iM.m[0][1] + m[1][1] * iM.m[1][1] + m[1][2] * iM.m[2][1]; oM.m[2][1] = m[2][0] * iM.m[0][1] + m[2][1] * iM.m[1][1] + m[2][2] * iM.m[2][1]; oM.m[0][2] = m[0][0] * iM.m[0][2] + m[0][1] * iM.m[1][2] + m[0][2] * iM.m[2][2]; oM.m[1][2] = m[1][0] * iM.m[0][2] + m[1][1] * iM.m[1][2] + m[1][2] * iM.m[2][2]; oM.m[2][2] = m[2][0] * iM.m[0][2] + m[2][1] * iM.m[1][2] + m[2][2] * iM.m[2][2]; return oM; } /***************************************************************************************\ Function: Matrix3x3::operator + Description: Add matrix iM. Parameters: - iM Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3 Matrix3x3::operator+ (const Matrix3x3& iM) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] + iM.m[0][0]; oM.m[0][1] = m[0][1] + iM.m[0][1]; oM.m[0][2] = m[0][2] + iM.m[0][2]; oM.m[1][0] = m[1][0] + iM.m[1][0]; oM.m[1][1] = m[1][1] + iM.m[1][1]; oM.m[1][2] = m[1][2] + iM.m[1][2]; oM.m[2][0] = m[2][0] + iM.m[2][0]; oM.m[2][1] = m[2][1] + iM.m[2][1]; oM.m[2][2] = m[2][2] + iM.m[2][2]; return oM; } /***************************************************************************************\ Function: Matrix3x3::operator - Description: Substract matrix iM. Parameters: - iM Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3 Matrix3x3::operator- (const Matrix3x3& iM) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] - iM.m[0][0]; oM.m[0][1] = m[0][1] - iM.m[0][1]; oM.m[0][2] = m[0][2] - iM.m[0][2]; oM.m[1][0] = m[1][0] - iM.m[1][0]; oM.m[1][1] = m[1][1] - iM.m[1][1]; oM.m[1][2] = m[1][2] - iM.m[1][2]; oM.m[2][0] = m[2][0] - iM.m[2][0]; oM.m[2][1] = m[2][1] - iM.m[2][1]; oM.m[2][2] = m[2][2] - iM.m[2][2]; return oM; } /***************************************************************************************\ Function: Matrix3x3::operator *= Description: Multiply by matrix iM. Parameters: - iM Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3& Matrix3x3::operator *= (const Matrix3x3& iM) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] * iM.m[0][0] + m[0][1] * iM.m[1][0] + m[0][2] * iM.m[2][0]; oM.m[1][0] = m[1][0] * iM.m[0][0] + m[1][1] * iM.m[1][0] + m[1][2] * iM.m[2][0]; oM.m[2][0] = m[2][0] * iM.m[0][0] + m[2][1] * iM.m[1][0] + m[2][2] * iM.m[2][0]; oM.m[0][1] = m[0][0] * iM.m[0][1] + m[0][1] * iM.m[1][1] + m[0][2] * iM.m[2][1]; oM.m[1][1] = m[1][0] * iM.m[0][1] + m[1][1] * iM.m[1][1] + m[1][2] * iM.m[2][1]; oM.m[2][1] = m[2][0] * iM.m[0][1] + m[2][1] * iM.m[1][1] + m[2][2] * iM.m[2][1]; oM.m[0][2] = m[0][0] * iM.m[0][2] + m[0][1] * iM.m[1][2] + m[0][2] * iM.m[2][2]; oM.m[1][2] = m[1][0] * iM.m[0][2] + m[1][1] * iM.m[1][2] + m[1][2] * iM.m[2][2]; oM.m[2][2] = m[2][0] * iM.m[0][2] + m[2][1] * iM.m[1][2] + m[2][2] * iM.m[2][2]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix3x3::operator += Description: Add matrix iM. Parameters: - iM Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3& Matrix3x3::operator += (const Matrix3x3& iM) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] + iM.m[0][0]; oM.m[0][1] = m[0][1] + iM.m[0][1]; oM.m[0][2] = m[0][2] + iM.m[0][2]; oM.m[1][0] = m[1][0] + iM.m[1][0]; oM.m[1][1] = m[1][1] + iM.m[1][1]; oM.m[1][2] = m[1][2] + iM.m[1][2]; oM.m[2][0] = m[2][0] + iM.m[2][0]; oM.m[2][1] = m[2][1] + iM.m[2][1]; oM.m[2][2] = m[2][2] + iM.m[2][2]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix3x3::operator -= Description: Substract matrix iM. Parameters: - iM Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3& Matrix3x3::operator -= (const Matrix3x3& iM) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] - iM.m[0][0]; oM.m[0][1] = m[0][1] - iM.m[0][1]; oM.m[0][2] = m[0][2] - iM.m[0][2]; oM.m[1][0] = m[1][0] - iM.m[1][0]; oM.m[1][1] = m[1][1] - iM.m[1][1]; oM.m[1][2] = m[1][2] - iM.m[1][2]; oM.m[2][0] = m[2][0] - iM.m[2][0]; oM.m[2][1] = m[2][1] - iM.m[2][1]; oM.m[2][2] = m[2][2] - iM.m[2][2]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix3x3::operator * Description: Multiply all elements by f. Parameters: - f Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3 Matrix3x3::operator * (const T &f) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] * f; oM.m[0][1] = m[0][1] * f; oM.m[0][2] = m[0][2] * f; oM.m[1][0] = m[1][0] * f; oM.m[1][1] = m[1][1] * f; oM.m[1][2] = m[1][2] * f; oM.m[2][0] = m[2][0] * f; oM.m[2][1] = m[2][1] * f; oM.m[2][2] = m[2][2] * f; return oM; } /***************************************************************************************\ Function: Matrix3x3::operator / Description: Divide all elements by f. Parameters: - f Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3 Matrix3x3::operator/ (const T &f) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] / f; oM.m[0][1] = m[0][1] / f; oM.m[0][2] = m[0][2] / f; oM.m[1][0] = m[1][0] / f; oM.m[1][1] = m[1][1] / f; oM.m[1][2] = m[1][2] / f; oM.m[2][0] = m[2][0] / f; oM.m[2][1] = m[2][1] / f; oM.m[2][2] = m[2][2] / f; return oM; } /***************************************************************************************\ Function: Matrix3x3::operator *= Description: Multiply all elements by f. Parameters: - f Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3& Matrix3x3::operator *= (const T &f) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] * f; oM.m[0][1] = m[0][1] * f; oM.m[0][2] = m[0][2] * f; oM.m[1][0] = m[1][0] * f; oM.m[1][1] = m[1][1] * f; oM.m[1][2] = m[1][2] * f; oM.m[2][0] = m[2][0] * f; oM.m[2][1] = m[2][1] * f; oM.m[2][2] = m[2][2] * f; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix3x3::operator /= Description: Divide all elements by f. Parameters: - f Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3& Matrix3x3::operator /= (const T &f) const { Matrix3x3 oM; oM.m[0][0] = m[0][0] / f; oM.m[0][1] = m[0][1] / f; oM.m[0][2] = m[0][2] / f; oM.m[1][0] = m[1][0] / f; oM.m[1][1] = m[1][1] / f; oM.m[1][2] = m[1][2] / f; oM.m[2][0] = m[2][0] / f; oM.m[2][1] = m[2][1] / f; oM.m[2][2] = m[2][2] / f; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix3x3::operator * Description: Multiply a matrix by a vector. Parameters: - V Return Value: Vector4. Comments: None. \***************************************************************************************/ template Vec3 Matrix3x3::operator * (const Vec3& V) const { Vec3 oV; oV.x = V.x * m[0][0] + V.y * m[0][1] + V.z * m[0][2]; oV.y = V.x * m[1][0] + V.y * m[1][1] + V.z * m[1][2]; oV.z = V.x * m[2][0] + V.y * m[2][1] + V.z * m[2][2]; return oV; } /***************************************************************************************\ Function: Matrix3x3::operator - () Description: Negate all elements of the matrix. Parameters: None. Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3 Matrix3x3::operator- () { Matrix3x3 oM; oM.m[0][0] = -m[0][0]; oM.m[0][1] = -m[0][1]; oM.m[0][2] = -m[0][2]; oM.m[1][0] = -m[1][0]; oM.m[1][1] = -m[1][1]; oM.m[1][2] = -m[1][2]; oM.m[2][0] = -m[2][0]; oM.m[2][1] = -m[2][1]; oM.m[2][2] = -m[2][2]; return oM; } template T &Matrix3x3::operator () (unsigned int i, unsigned int j) { return m[i][j]; } template T Matrix3x3::operator () (unsigned int i, unsigned int j) const { return m[i][j]; } /***************************************************************************************\ Function: Matrix3x3::zero Description: Set the matrix to zero. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix3x3::Zero() { m[0][0] = 0.0; m[0][1] = 0.0; m[0][2] = 0.0; m[1][0] = 0.0; m[1][1] = 0.0; m[1][2] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 0.0; //memset(m, 0, sizeof(m)); } /***************************************************************************************\ Function: Matrix3x3::identity Description: Set the matrix to identity. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix3x3::Identity() { m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; } template T Matrix3x3::Determinant() const { T det; det = m[0][0] * m[1][1] * m[2][2] + m[0][1] * m[1][2] * m[2][0] + m[0][2] * m[2][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] - m[0][2] * m[1][1] * m[2][0]; return det; } template void Matrix3x3::Inverse() { T det = Determinant(); if (det == T (0) ) { // Determinant is null. Matrix cannot be inverted. #ifdef NUX_DEBUG NUX_HARDWARE_BREAK; #endif return; } Matrix3x3 Temp; Temp.m[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1]; Temp.m[0][1] = m[0][2] * m[2][1] - m[0][1] * m[2][2]; Temp.m[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1]; Temp.m[1][0] = m[1][2] * m[2][0] - m[1][0] * m[2][2]; Temp.m[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0]; Temp.m[1][2] = m[0][2] * m[1][0] - m[0][0] * m[1][2]; Temp.m[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0]; Temp.m[2][1] = m[0][1] * m[2][0] - m[0][0] * m[2][1]; Temp.m[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0]; *this = (T (1) / det) * Temp; } template Matrix3x3 Matrix3x3::GetInverse() const { Matrix3x3 Temp = *this; Temp.Inverse(); return Temp; } // template // Matrix2x2 Matrix3x3::GetUpper2x2() const // { // Matrix2x2 Temp; // Temp.m[0][0] = m[0][0]; // Temp.m[0][1] = m[0][1]; // // Temp.m[1][0] = m[1][0]; // Temp.m[1][1] = m[1][1]; // // return Temp; // } template Matrix3x3 Matrix3x3::IDENTITY() { Matrix3x3 matrix; matrix.Identity(); return matrix; } template Matrix3x3 Matrix3x3::ZERO() { Matrix3x3 matrix; matrix.Zero(); return matrix; } /***************************************************************************************\ Function: Matrix3x3::operator * Description: Multiply matrix rhs by constant lhs. Allow "f * matrix" operation.. Parameters: None. Return Value: Matrix3x3. Comments: None. \***************************************************************************************/ template Matrix3x3 operator * (const T &lhs, const Matrix3x3& rhs) { Matrix3x3 oM; oM.m[0][0] = rhs.m[0][0] / lhs; oM.m[0][1] = rhs.m[0][1] / lhs; oM.m[0][2] = rhs.m[0][2] / lhs; oM.m[1][0] = rhs.m[1][0] / lhs; oM.m[1][1] = rhs.m[1][1] / lhs; oM.m[1][2] = rhs.m[1][2] / lhs; oM.m[2][0] = rhs.m[2][0] / lhs; oM.m[2][1] = rhs.m[2][1] / lhs; oM.m[2][2] = rhs.m[2][2] / lhs; return oM; } typedef Matrix3x3 Matrix3; } #endif // MATRIX3_H nux-4.0.8+18.10.20180623/NuxCore/Math/Matrix4.cpp0000644000000000000000000000211713313373365015112 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Vector3.h" #include "Vector4.h" #include "Matrix4.h" #include "Constants.h" // When writing to a matrix at row r and colum c use m[r][c]. // When reading from a matrix (that is the result of matrix op) at row r and colum c use m[c][r]. namespace nux { #if 0 #endif } nux-4.0.8+18.10.20180623/NuxCore/Math/Matrix4.h0000644000000000000000000012045713313373365014567 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef MATRIX4_H #define MATRIX4_H #include "Constants.h" #include "Vector3.h" #include "Vector4.h" namespace nux { // Our matrices are Row major just like C/C++: // m[2][3] represent the element at row 2 and column 3. // When multiplying a vector by a matrix, the vector is a column at the right of the matrix // // |a00, a01, a02, a03| |v0| // |a10, a11, a12, a13| * |v1| // |a20, a21, a22, a23| |v2| // |a30, a31, a32, a33| |v3| // // Note: OpenGL is column major. Before passing it a Matrix4x4 through glLoadMatrix, transpose it. template class Matrix4x4 { public: Matrix4x4(); ~Matrix4x4(); Matrix4x4 (const Matrix4x4 &); Matrix4x4 ( T a00, T a01, T a02, T a03, T a10, T a11, T a12, T a13, T a20, T a21, T a22, T a23, T a30, T a31, T a32, T a33); Matrix4x4& operator = (const Matrix4x4&); bool operator == (const Matrix4x4&); Matrix4x4 operator * (const Matrix4x4&) const; Matrix4x4 operator + (const Matrix4x4&) const; Matrix4x4 operator - (const Matrix4x4&) const; Matrix4x4& operator *= (const Matrix4x4&) const; Matrix4x4& operator += (const Matrix4x4&) const; Matrix4x4& operator -= (const Matrix4x4&) const; Matrix4x4 operator * (const T &) const; Matrix4x4 operator / (const T &) const; Matrix4x4 operator *= (const T &) const; Matrix4x4 operator /= (const T &) const; Vector4 operator * (const Vector4 &) const; Matrix4x4 operator - (); // Get the (i, j) element of the current matrix. T &operator() (unsigned int i, unsigned int j); T operator () (unsigned int i, unsigned int j) const; // Get a pointer to the current matrix. operator T *(); operator const T *() const; // Utility for 3D void Translate (T x, T y, T z); void Translate (const Vector3 &); void Rotate_x (T angle); void Rotate_y (T angle); void Rotate_z (T angle); void Scale (T sx, T sy, T sz); // Matrix Math T Trace() const; T Determinant() const ; void Inverse(); Matrix4x4 GetInverse() const; void Transpose(); //Matrix3x3 GetUpper3x3() const; //Matrix2x2 GetUpper2x2() const; /////////////////////////////////////////////// void Scale (T s); void Diagonal (T x, T y, T z, T w = T (1) ); void Rotate (T angle, Vector3 axis); // OpenGL void LookAt (const Vector3 &eye, const Vector3 &at, const Vector3 &up); void Orthographic (T l, T r, T b, T t, T n, T f); void Perspective (T l, T r, T t, T b, T n, T f); void PerspectiveInverse (T l, T r, T t, T b, T n, T f); void Perspective (T FoV, T AspectRatio, T NearPlane, T FarPlane); void Zero(); void Identity(); static Matrix4x4 IDENTITY(); static Matrix4x4 ZERO(); static Matrix4x4 ROTATEX(T angle); static Matrix4x4 ROTATEY(T angle); static Matrix4x4 ROTATEZ(T angle); static Matrix4x4 TRANSLATE(T x, T y, T z); static Matrix4x4 SCALE(T x, T y, T z); T m[4][4]; }; /***************************************************************************************\ Function: Matrix4x4::Matrix4x4 Description: Constructor. Initialize the matrix to identity. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template Matrix4x4::Matrix4x4() { Identity(); } /***************************************************************************************\ Function: Matrix4x4::~Matrix4x4 Description: Destructor. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template Matrix4x4::~Matrix4x4() { } /***************************************************************************************\ Function: Matrix4x4::Matrix4x4 Description: None. Parameters: - M Return Value: None. Comments: None. \***************************************************************************************/ template Matrix4x4::Matrix4x4 (const Matrix4x4 &M) { m[0][0] = M.m[0][0]; m[0][1] = M.m[0][1]; m[0][2] = M.m[0][2]; m[0][3] = M.m[0][3]; m[1][0] = M.m[1][0]; m[1][1] = M.m[1][1]; m[1][2] = M.m[1][2]; m[1][3] = M.m[1][3]; m[2][0] = M.m[2][0]; m[2][1] = M.m[2][1]; m[2][2] = M.m[2][2]; m[2][3] = M.m[2][3]; m[3][0] = M.m[3][0]; m[3][1] = M.m[3][1]; m[3][2] = M.m[3][2]; m[3][3] = M.m[3][3]; } /***************************************************************************************\ Function: Matrix4x4::Matrix4x4 Description: None. Parameters: T a00, T a01, T a02, T a03, T a10, T a11, T a12, T a13, T a20, T a21, T a22, T a23, T a30, T a31, T a32, T a33 Return Value: None. Comments: None. \***************************************************************************************/ template Matrix4x4::Matrix4x4 ( T a00, T a01, T a02, T a03, T a10, T a11, T a12, T a13, T a20, T a21, T a22, T a23, T a30, T a31, T a32, T a33) { m[0][0] = a00; m[0][1] = a01; m[0][2] = a02; m[0][3] = a03; m[1][0] = a10; m[1][1] = a11; m[1][2] = a12; m[1][3] = a13; m[2][0] = a20; m[2][1] = a21; m[2][2] = a22; m[2][3] = a23; m[3][0] = a30; m[3][1] = a31; m[3][2] = a32; m[3][3] = a33; } /***************************************************************************************\ Function: Matrix4x4::Matrix4x4 Description: Assignment operator. Parameters: - M Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4& Matrix4x4::operator = (const Matrix4x4& M) { m[0][0] = M.m[0][0]; m[0][1] = M.m[0][1]; m[0][2] = M.m[0][2]; m[0][3] = M.m[0][3]; m[1][0] = M.m[1][0]; m[1][1] = M.m[1][1]; m[1][2] = M.m[1][2]; m[1][3] = M.m[1][3]; m[2][0] = M.m[2][0]; m[2][1] = M.m[2][1]; m[2][2] = M.m[2][2]; m[2][3] = M.m[2][3]; m[3][0] = M.m[3][0]; m[3][1] = M.m[3][1]; m[3][2] = M.m[3][2]; m[3][3] = M.m[3][3]; return (*this); } template bool Matrix4x4::operator == (const Matrix4x4& M) { for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { if (m[i][j] != M.m[i][j]) return false; } return true; } /***************************************************************************************\ Function: Matrix4x4::operator * Description: Multiply by matrix iM. Parameters: - iM Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4 Matrix4x4::operator * (const Matrix4x4& iM) const { Matrix4x4 oM; // Output matrix first row oM.m[0][0] = m[0][0] * iM.m[0][0] + m[0][1] * iM.m[1][0] + m[0][2] * iM.m[2][0] + m[0][3] * iM.m[3][0]; oM.m[0][1] = m[0][0] * iM.m[0][1] + m[0][1] * iM.m[1][1] + m[0][2] * iM.m[2][1] + m[0][3] * iM.m[3][1]; oM.m[0][2] = m[0][0] * iM.m[0][2] + m[0][1] * iM.m[1][2] + m[0][2] * iM.m[2][2] + m[0][3] * iM.m[3][2]; oM.m[0][3] = m[0][0] * iM.m[0][3] + m[0][1] * iM.m[1][3] + m[0][2] * iM.m[2][3] + m[0][3] * iM.m[3][3]; // Output matrix second row oM.m[1][0] = m[1][0] * iM.m[0][0] + m[1][1] * iM.m[1][0] + m[1][2] * iM.m[2][0] + m[1][3] * iM.m[3][0]; oM.m[1][1] = m[1][0] * iM.m[0][1] + m[1][1] * iM.m[1][1] + m[1][2] * iM.m[2][1] + m[1][3] * iM.m[3][1]; oM.m[1][2] = m[1][0] * iM.m[0][2] + m[1][1] * iM.m[1][2] + m[1][2] * iM.m[2][2] + m[1][3] * iM.m[3][2]; oM.m[1][3] = m[1][0] * iM.m[0][3] + m[1][1] * iM.m[1][3] + m[1][2] * iM.m[2][3] + m[1][3] * iM.m[3][3]; // Output matrix third row oM.m[2][0] = m[2][0] * iM.m[0][0] + m[2][1] * iM.m[1][0] + m[2][2] * iM.m[2][0] + m[2][3] * iM.m[3][0]; oM.m[2][1] = m[2][0] * iM.m[0][1] + m[2][1] * iM.m[1][1] + m[2][2] * iM.m[2][1] + m[2][3] * iM.m[3][1]; oM.m[2][2] = m[2][0] * iM.m[0][2] + m[2][1] * iM.m[1][2] + m[2][2] * iM.m[2][2] + m[2][3] * iM.m[3][2]; oM.m[2][3] = m[2][0] * iM.m[0][3] + m[2][1] * iM.m[1][3] + m[2][2] * iM.m[2][3] + m[2][3] * iM.m[3][3]; // Output matrix fourth row oM.m[3][0] = m[3][0] * iM.m[0][0] + m[3][1] * iM.m[1][0] + m[3][2] * iM.m[2][0] + m[3][3] * iM.m[3][0]; oM.m[3][1] = m[3][0] * iM.m[0][1] + m[3][1] * iM.m[1][1] + m[3][2] * iM.m[2][1] + m[3][3] * iM.m[3][1]; oM.m[3][2] = m[3][0] * iM.m[0][2] + m[3][1] * iM.m[1][2] + m[3][2] * iM.m[2][2] + m[3][3] * iM.m[3][2]; oM.m[3][3] = m[3][0] * iM.m[0][3] + m[3][1] * iM.m[1][3] + m[3][2] * iM.m[2][3] + m[3][3] * iM.m[3][3]; return oM; } /***************************************************************************************\ Function: Matrix4x4::operator + Description: Add matrix iM. Parameters: - iM Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4 Matrix4x4::operator + (const Matrix4x4& iM) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] + iM.m[0][0]; oM.m[0][1] = m[0][1] + iM.m[0][1]; oM.m[0][2] = m[0][2] + iM.m[0][2]; oM.m[0][3] = m[0][3] + iM.m[0][3]; oM.m[1][0] = m[1][0] + iM.m[1][0]; oM.m[1][1] = m[1][1] + iM.m[1][1]; oM.m[1][2] = m[1][2] + iM.m[1][2]; oM.m[1][3] = m[1][3] + iM.m[1][3]; oM.m[2][0] = m[2][0] + iM.m[2][0]; oM.m[2][1] = m[2][1] + iM.m[2][1]; oM.m[2][2] = m[2][2] + iM.m[2][2]; oM.m[2][3] = m[2][3] + iM.m[2][3]; oM.m[3][0] = m[3][0] + iM.m[3][0]; oM.m[3][1] = m[3][1] + iM.m[3][1]; oM.m[3][2] = m[3][2] + iM.m[3][2]; oM.m[3][3] = m[3][3] + iM.m[3][3]; return oM; } /***************************************************************************************\ Function: Matrix4x4::operator - Description: Substract matrix iM. Parameters: - iM Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4 Matrix4x4::operator - (const Matrix4x4& iM) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] - iM.m[0][0]; oM.m[0][1] = m[0][1] - iM.m[0][1]; oM.m[0][2] = m[0][2] - iM.m[0][2]; oM.m[0][3] = m[0][3] - iM.m[0][3]; oM.m[1][0] = m[1][0] - iM.m[1][0]; oM.m[1][1] = m[1][1] - iM.m[1][1]; oM.m[1][2] = m[1][2] - iM.m[1][2]; oM.m[1][3] = m[1][3] - iM.m[1][3]; oM.m[2][0] = m[2][0] - iM.m[2][0]; oM.m[2][1] = m[2][1] - iM.m[2][1]; oM.m[2][2] = m[2][2] - iM.m[2][2]; oM.m[2][3] = m[2][3] - iM.m[2][3]; oM.m[3][0] = m[3][0] - iM.m[3][0]; oM.m[3][1] = m[3][1] - iM.m[3][1]; oM.m[3][2] = m[3][2] - iM.m[3][2]; oM.m[3][3] = m[3][3] - iM.m[3][3]; return oM; } /***************************************************************************************\ Function: Matrix4x4::operator *= Description: Multiply by matrix iM. Parameters: - iM Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4& Matrix4x4::operator *= (const Matrix4x4& iM) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] * iM.m[0][0] + m[0][1] * iM.m[1][0] + m[0][2] * iM.m[2][0] + m[0][3] * iM.m[3][0]; oM.m[1][0] = m[1][0] * iM.m[0][0] + m[1][1] * iM.m[1][0] + m[1][2] * iM.m[2][0] + m[1][3] * iM.m[3][0]; oM.m[2][0] = m[2][0] * iM.m[0][0] + m[2][1] * iM.m[1][0] + m[2][2] * iM.m[2][0] + m[2][3] * iM.m[3][0]; oM.m[3][0] = m[3][0] * iM.m[0][0] + m[3][1] * iM.m[1][0] + m[3][2] * iM.m[2][0] + m[3][3] * iM.m[3][0]; oM.m[0][1] = m[0][0] * iM.m[0][1] + m[0][1] * iM.m[1][1] + m[0][2] * iM.m[2][1] + m[0][3] * iM.m[3][1]; oM.m[1][1] = m[1][0] * iM.m[0][1] + m[1][1] * iM.m[1][1] + m[1][2] * iM.m[2][1] + m[1][3] * iM.m[3][1]; oM.m[2][1] = m[2][0] * iM.m[0][1] + m[2][1] * iM.m[1][1] + m[2][2] * iM.m[2][1] + m[2][3] * iM.m[3][1]; oM.m[3][1] = m[3][0] * iM.m[0][1] + m[3][1] * iM.m[1][1] + m[3][2] * iM.m[2][1] + m[3][3] * iM.m[3][1]; oM.m[0][2] = m[0][0] * iM.m[0][2] + m[0][1] * iM.m[1][2] + m[0][2] * iM.m[2][2] + m[0][3] * iM.m[3][2]; oM.m[1][2] = m[1][0] * iM.m[0][2] + m[1][1] * iM.m[1][2] + m[1][2] * iM.m[2][2] + m[1][3] * iM.m[3][2]; oM.m[2][2] = m[2][0] * iM.m[0][2] + m[2][1] * iM.m[1][2] + m[2][2] * iM.m[2][2] + m[2][3] * iM.m[3][2]; oM.m[3][2] = m[3][0] * iM.m[0][2] + m[3][1] * iM.m[1][2] + m[3][2] * iM.m[2][2] + m[3][3] * iM.m[3][2]; oM.m[0][3] = m[0][0] * iM.m[0][3] + m[0][1] * iM.m[1][3] + m[0][2] * iM.m[2][3] + m[0][3] * iM.m[3][3]; oM.m[1][3] = m[1][0] * iM.m[0][3] + m[1][1] * iM.m[1][3] + m[1][2] * iM.m[2][3] + m[1][3] * iM.m[3][3]; oM.m[2][3] = m[2][0] * iM.m[0][3] + m[2][1] * iM.m[1][3] + m[2][2] * iM.m[2][3] + m[2][3] * iM.m[3][3]; oM.m[3][3] = m[3][0] * iM.m[0][3] + m[3][1] * iM.m[1][3] + m[3][2] * iM.m[2][3] + m[3][3] * iM.m[3][3]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix4x4::operator += Description: Add matrix iM. Parameters: - iM Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4& Matrix4x4::operator += (const Matrix4x4& iM) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] + iM.m[0][0]; oM.m[0][1] = m[0][1] + iM.m[0][1]; oM.m[0][2] = m[0][2] + iM.m[0][2]; oM.m[0][3] = m[0][3] + iM.m[0][3]; oM.m[1][0] = m[1][0] + iM.m[1][0]; oM.m[1][1] = m[1][1] + iM.m[1][1]; oM.m[1][2] = m[1][2] + iM.m[1][2]; oM.m[1][3] = m[1][3] + iM.m[1][3]; oM.m[2][0] = m[2][0] + iM.m[2][0]; oM.m[2][1] = m[2][1] + iM.m[2][1]; oM.m[2][2] = m[2][2] + iM.m[2][2]; oM.m[2][3] = m[2][3] + iM.m[2][3]; oM.m[3][0] = m[3][0] + iM.m[3][0]; oM.m[3][1] = m[3][1] + iM.m[3][1]; oM.m[3][2] = m[3][2] + iM.m[3][2]; oM.m[3][3] = m[3][3] + iM.m[3][3]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix4x4::operator -= Description: Substract matrix iM. Parameters: - iM Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4& Matrix4x4::operator -= (const Matrix4x4& iM) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] - iM.m[0][0]; oM.m[0][1] = m[0][1] - iM.m[0][1]; oM.m[0][2] = m[0][2] - iM.m[0][2]; oM.m[0][3] = m[0][3] - iM.m[0][3]; oM.m[1][0] = m[1][0] - iM.m[1][0]; oM.m[1][1] = m[1][1] - iM.m[1][1]; oM.m[1][2] = m[1][2] - iM.m[1][2]; oM.m[1][3] = m[1][3] - iM.m[1][3]; oM.m[2][0] = m[2][0] - iM.m[2][0]; oM.m[2][1] = m[2][1] - iM.m[2][1]; oM.m[2][2] = m[2][2] - iM.m[2][2]; oM.m[2][3] = m[2][3] - iM.m[2][3]; oM.m[3][0] = m[3][0] - iM.m[3][0]; oM.m[3][1] = m[3][1] - iM.m[3][1]; oM.m[3][2] = m[3][2] - iM.m[3][2]; oM.m[3][3] = m[3][3] - iM.m[3][3]; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix4x4::operator * Description: Multiply all elements by f. Parameters: - f Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4 Matrix4x4::operator * (const T &f) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] * f; oM.m[0][1] = m[0][1] * f; oM.m[0][2] = m[0][2] * f; oM.m[0][3] = m[0][3] * f; oM.m[1][0] = m[1][0] * f; oM.m[1][1] = m[1][1] * f; oM.m[1][2] = m[1][2] * f; oM.m[1][3] = m[1][3] * f; oM.m[2][0] = m[2][0] * f; oM.m[2][1] = m[2][1] * f; oM.m[2][2] = m[2][2] * f; oM.m[2][3] = m[2][3] * f; oM.m[3][0] = m[3][0] * f; oM.m[3][1] = m[3][1] * f; oM.m[3][2] = m[3][2] * f; oM.m[3][3] = m[3][3] * f; return oM; } /***************************************************************************************\ Function: Matrix4x4::operator / Description: Divide all elements by f. Parameters: - f Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4 Matrix4x4::operator / (const T &f) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] / f; oM.m[0][1] = m[0][1] / f; oM.m[0][2] = m[0][2] / f; oM.m[0][3] = m[0][3] / f; oM.m[1][0] = m[1][0] / f; oM.m[1][1] = m[1][1] / f; oM.m[1][2] = m[1][2] / f; oM.m[1][3] = m[1][3] / f; oM.m[2][0] = m[2][0] / f; oM.m[2][1] = m[2][1] / f; oM.m[2][2] = m[2][2] / f; oM.m[2][3] = m[2][3] / f; oM.m[3][0] = m[3][0] / f; oM.m[3][1] = m[3][1] / f; oM.m[3][2] = m[3][2] / f; oM.m[3][3] = m[3][3] / f; return oM; } /***************************************************************************************\ Function: Matrix4x4::operator *= Description: Multiply all elements by f. Parameters: - f Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4 Matrix4x4::operator *= (const T &f) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] * f; oM.m[0][1] = m[0][1] * f; oM.m[0][2] = m[0][2] * f; oM.m[0][3] = m[0][3] * f; oM.m[1][0] = m[1][0] * f; oM.m[1][1] = m[1][1] * f; oM.m[1][2] = m[1][2] * f; oM.m[1][3] = m[1][3] * f; oM.m[2][0] = m[2][0] * f; oM.m[2][1] = m[2][1] * f; oM.m[2][2] = m[2][2] * f; oM.m[2][3] = m[2][3] * f; oM.m[3][0] = m[3][0] * f; oM.m[3][1] = m[3][1] * f; oM.m[3][2] = m[3][2] * f; oM.m[3][3] = m[3][3] * f; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix4x4::operator /= Description: Divide all elements by f. Parameters: - f Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4 Matrix4x4::operator /= (const T &f) const { Matrix4x4 oM; oM.m[0][0] = m[0][0] / f; oM.m[0][1] = m[0][1] / f; oM.m[0][2] = m[0][2] / f; oM.m[0][3] = m[0][3] / f; oM.m[1][0] = m[1][0] / f; oM.m[1][1] = m[1][1] / f; oM.m[1][2] = m[1][2] / f; oM.m[1][3] = m[1][3] / f; oM.m[2][0] = m[2][0] / f; oM.m[2][1] = m[2][1] / f; oM.m[2][2] = m[2][2] / f; oM.m[2][3] = m[2][3] / f; oM.m[3][0] = m[3][0] / f; oM.m[3][1] = m[3][1] / f; oM.m[3][2] = m[3][2] / f; oM.m[3][3] = m[3][3] / f; *this = oM; return *this; } /***************************************************************************************\ Function: Matrix4x4::operator * Description: Multiply a matrix by a vector. Parameters: - V Return Value: Vector4. Comments: None. \***************************************************************************************/ template Vector4 Matrix4x4::operator * (const Vector4 &V) const { Vector4 oV; oV.x = V.x * m[0][0] + V.y * m[0][1] + V.z * m[0][2] + V.w * m[0][3]; oV.y = V.x * m[1][0] + V.y * m[1][1] + V.z * m[1][2] + V.w * m[1][3]; oV.z = V.x * m[2][0] + V.y * m[2][1] + V.z * m[2][2] + V.w * m[2][3]; oV.w = V.x * m[3][0] + V.y * m[3][1] + V.z * m[3][2] + V.w * m[3][3]; return oV; } /***************************************************************************************\ Function: Matrix4x4::operator - () Description: Negate all elements of the matrix. Parameters: None. Return Value: Matrix4x4. Comments: None. \***************************************************************************************/ template Matrix4x4 Matrix4x4::operator - () { Matrix4x4 oM; oM.m[0][0] = -m[0][0]; oM.m[0][1] = -m[0][1]; oM.m[0][2] = -m[0][2]; oM.m[0][3] = -m[0][3]; oM.m[1][0] = -m[1][0]; oM.m[1][1] = -m[1][1]; oM.m[1][2] = -m[1][2]; oM.m[1][3] = -m[1][3]; oM.m[2][0] = -m[2][0]; oM.m[2][1] = -m[2][1]; oM.m[2][2] = -m[2][2]; oM.m[2][3] = -m[2][3]; oM.m[3][0] = -m[3][0]; oM.m[3][1] = -m[3][1]; oM.m[3][2] = -m[3][2]; oM.m[3][3] = -m[3][3]; return oM; } template T &Matrix4x4::operator () (unsigned int i, unsigned int j) { return m[i][j]; } template T Matrix4x4::operator () (unsigned int i, unsigned int j) const { return m[i][j]; } template Matrix4x4::operator T *() { return reinterpret_cast (&m); } template Matrix4x4::operator const T *() const { return reinterpret_cast (&m); } /***************************************************************************************\ Function: Matrix4x4::zero Description: Set the matrix to zero. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix4x4::Zero() { m[0][0] = 0.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = 0.0; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 0.0; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 0.0; //memset(m, 0, sizeof(m)); } /***************************************************************************************\ Function: Matrix4x4::identity Description: Set the matrix to identity. Parameters: None. Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix4x4::Identity() { m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0; } /***************************************************************************************\ Function: Matrix4x4::translate Description: Add a translation to the current matrix. Parameters: - x - y - z Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix4x4::Translate (T x, T y, T z) { Identity(); m[0][3] = x; m[1][3] = y; m[2][3] = z; } /***************************************************************************************\ Function: Matrix4x4::Transpose Description: Transpose the current matrix. Parameters: None Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix4x4::Transpose() { for (int i = 0; i < 4; i++) { for (int j = 0; j < i; j++) { T t = m[i][j]; m[i][j] = m[j][i]; m[j][i] = t; } } } /***************************************************************************************\ Function: Matrix4x4::Rotate_x Description: Add rotation matrix around axe X. Parameters: - angle Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix4x4::Rotate_x (T angle) { Identity(); m[0][0] = 1.0f; m[1][0] = 0.0f; m[2][0] = 0.0f; m[3][0] = 0.0f; m[0][1] = 0.0f; m[1][1] = (T) cos (angle); m[2][1] = (T) sin (angle); m[3][1] = 0.0f; m[0][2] = 0.0f; m[1][2] = (T) - sin (angle); m[2][2] = (T) cos (angle); m[3][2] = 0.0f; m[0][3] = 0.0f; m[1][3] = 0.0f; m[2][3] = 0.0f; m[3][3] = 1.0f; } /***************************************************************************************\ Function: Matrix4x4::Rotate_y Description: Add rotation matrix around axe Y. Parameters: - angle Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix4x4::Rotate_y (T angle) { Identity(); m[0][0] = (T) cos (angle); m[1][0] = 0.0f; m[2][0] = (T) - sin (angle); m[3][0] = 0.0f; m[0][1] = 0.0f; m[1][1] = 1.0f; m[2][1] = 0.0f; m[3][1] = 0.0f; m[0][2] = (T) sin (angle); m[1][2] = 0.0f; m[2][2] = (T) cos (angle); m[3][2] = 0.0f; m[0][3] = 0.0f; m[1][3] = 0.0f; m[2][3] = 0.0f; m[3][3] = 1.0f; } /***************************************************************************************\ Function: Matrix4x4::Rotate_z Description: Add rotation matrix around axe Z. Parameters: - angle Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix4x4::Rotate_z (T angle) { Identity(); m[0][0] = (T) cos (angle); m[1][0] = (T) sin (angle); m[2][0] = 0.0f; m[3][0] = 0.0f; m[0][1] = (T) - sin (angle); m[1][1] = (T) cos (angle); m[2][1] = 0.0f; m[3][1] = 0.0f; m[0][2] = 0.0f; m[1][2] = 0.0f; m[2][2] = 1.0f; m[3][2] = 0.0f; m[0][3] = 0.0f; m[1][3] = 0.0f; m[2][3] = 0.0f; m[3][3] = 1.0f; } /***************************************************************************************\ Function: Matrix4x4::Scale Description: Add a scale matrix. Parameters: - sx, sy, sz Return Value: None. Comments: None. \***************************************************************************************/ template void Matrix4x4::Scale (T sx, T sy, T sz) { Identity(); m[0][0] = sx; m[1][0] = 0.0f; m[2][0] = 0.0f; m[3][0] = 0.0f; m[0][1] = 0.0f; m[1][1] = sy; m[2][1] = 0.0f; m[3][1] = 0.0f; m[0][2] = 0.0f; m[1][2] = 0.0f; m[2][2] = sz; m[3][2] = 0.0f; m[0][3] = 0.0f; m[1][3] = 0.0f; m[2][3] = 0.0f; m[3][3] = 1.0f; } template T Matrix4x4::Trace() const { return m[0][0] + m[1][1] + m[2][2] + m[3][3]; } template T Matrix4x4::Determinant() const { const T &m00 = m[0][0]; const T &m01 = m[0][1]; const T &m02 = m[0][2]; const T &m03 = m[0][3]; const T &m10 = m[1][0]; const T &m11 = m[1][1]; const T &m12 = m[1][2]; const T &m13 = m[1][3]; const T &m20 = m[2][0]; const T &m21 = m[2][1]; const T &m22 = m[2][2]; const T &m23 = m[2][3]; const T &m30 = m[3][0]; const T &m31 = m[3][1]; const T &m32 = m[3][2]; const T &m33 = m[3][3]; T det = m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 - m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30 + m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30 - m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 + m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 - m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 + m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32 - m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32 + m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 - m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 + m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 - m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33; return det; } template void Matrix4x4::Inverse() { T det = Determinant(); if (det == T (0) ) { // Determinant is null. Matrix cannot be inverted. #ifdef NUX_DEBUG NUX_HARDWARE_BREAK; #endif return; } const T &m00 = m[0][0]; const T &m01 = m[0][1]; const T &m02 = m[0][2]; const T &m03 = m[0][3]; const T &m10 = m[1][0]; const T &m11 = m[1][1]; const T &m12 = m[1][2]; const T &m13 = m[1][3]; const T &m20 = m[2][0]; const T &m21 = m[2][1]; const T &m22 = m[2][2]; const T &m23 = m[2][3]; const T &m30 = m[3][0]; const T &m31 = m[3][1]; const T &m32 = m[3][2]; const T &m33 = m[3][3]; Matrix4x4 Temp; Temp.m[0][0] = m12 * m23 * m31 - m13 * m22 * m31 + m13 * m21 * m32 - m11 * m23 * m32 - m12 * m21 * m33 + m11 * m22 * m33; Temp.m[0][1] = m03 * m22 * m31 - m02 * m23 * m31 - m03 * m21 * m32 + m01 * m23 * m32 + m02 * m21 * m33 - m01 * m22 * m33; Temp.m[0][2] = m02 * m13 * m31 - m03 * m12 * m31 + m03 * m11 * m32 - m01 * m13 * m32 - m02 * m11 * m33 + m01 * m12 * m33; Temp.m[0][3] = m03 * m12 * m21 - m02 * m13 * m21 - m03 * m11 * m22 + m01 * m13 * m22 + m02 * m11 * m23 - m01 * m12 * m23; Temp.m[1][0] = m13 * m22 * m30 - m12 * m23 * m30 - m13 * m20 * m32 + m10 * m23 * m32 + m12 * m20 * m33 - m10 * m22 * m33; Temp.m[1][1] = m02 * m23 * m30 - m03 * m22 * m30 + m03 * m20 * m32 - m00 * m23 * m32 - m02 * m20 * m33 + m00 * m22 * m33; Temp.m[1][2] = m03 * m12 * m30 - m02 * m13 * m30 - m03 * m10 * m32 + m00 * m13 * m32 + m02 * m10 * m33 - m00 * m12 * m33; Temp.m[1][3] = m02 * m13 * m20 - m03 * m12 * m20 + m03 * m10 * m22 - m00 * m13 * m22 - m02 * m10 * m23 + m00 * m12 * m23; Temp.m[2][0] = m11 * m23 * m30 - m13 * m21 * m30 + m13 * m20 * m31 - m10 * m23 * m31 - m11 * m20 * m33 + m10 * m21 * m33; Temp.m[2][1] = m03 * m21 * m30 - m01 * m23 * m30 - m03 * m20 * m31 + m00 * m23 * m31 + m01 * m20 * m33 - m00 * m21 * m33; Temp.m[2][2] = m01 * m13 * m30 - m03 * m11 * m30 + m03 * m10 * m31 - m00 * m13 * m31 - m01 * m10 * m33 + m00 * m11 * m33; Temp.m[2][3] = m03 * m11 * m20 - m01 * m13 * m20 - m03 * m10 * m21 + m00 * m13 * m21 + m01 * m10 * m23 - m00 * m11 * m23; Temp.m[3][0] = m12 * m21 * m30 - m11 * m22 * m30 - m12 * m20 * m31 + m10 * m22 * m31 + m11 * m20 * m32 - m10 * m21 * m32; Temp.m[3][1] = m01 * m22 * m30 - m02 * m21 * m30 + m02 * m20 * m31 - m00 * m22 * m31 - m01 * m20 * m32 + m00 * m21 * m32; Temp.m[3][2] = m02 * m11 * m30 - m01 * m12 * m30 - m02 * m10 * m31 + m00 * m12 * m31 + m01 * m10 * m32 - m00 * m11 * m32; Temp.m[3][3] = m01 * m12 * m20 - m02 * m11 * m20 + m02 * m10 * m21 - m00 * m12 * m21 - m01 * m10 * m22 + m00 * m11 * m22; *this = (T (1) / det) * Temp; } template Matrix4x4 Matrix4x4::GetInverse() const { Matrix4x4 Temp = *this; Temp.Inverse(); return Temp; } // template // Matrix3x3 Matrix4x4::GetUpper3x3() const // { // Matrix3x3 Temp; // Temp.m[0][0] = m[0][0]; // Temp.m[0][1] = m[0][1]; // Temp.m[0][2] = m[0][2]; // // Temp.m[1][0] = m[1][0]; // Temp.m[1][1] = m[1][1]; // Temp.m[1][2] = m[1][2]; // // Temp.m[2][0] = m[2][0]; // Temp.m[2][1] = m[2][1]; // Temp.m[2][2] = m[2][2]; // // return Temp; // } // // template // Matrix2x2 Matrix4x4::GetUpper2x2() const // { // Matrix2x2 Temp; // Temp.m[0][0] = m[0][0]; // Temp.m[0][1] = m[0][1]; // // Temp.m[1][0] = m[1][0]; // Temp.m[1][1] = m[1][1]; // // return Temp; // } // s 0 0 0 // 0 s 0 0 // 0 0 s 0 // 0 0 0 1 template void Matrix4x4::Scale (T s) { m[0][0] = s; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = s; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = s; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1; } // x 0 0 0 // 0 y 0 0 // 0 0 z 0 // 0 0 0 w template void Matrix4x4::Diagonal (T x, T y, T z, T w) { m[0][0] = x; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0; m[1][0] = 0.0; m[1][1] = y; m[1][2] = 0.0; m[1][3] = 0.0; m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = z; m[2][3] = 0.0; m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = w; } template void Matrix4x4::Rotate (T angle, Vector3 axis) { //See Quaternion::from_angle_axis() and Quaternion::get_matrix() // note: adapted from david eberly's code without permission //TODO: make sure it is correct if (axis.LengthSquared() < constants::epsilon_micro) { Identity(); } else { axis.Normalize(); T fCos = (T) cos(angle); T fSin = (T) sin(angle); T fOneMinusCos = 1.0f-fCos; T fX2 = axis.x*axis.x; T fY2 = axis.y*axis.y; T fZ2 = axis.z*axis.z; T fXYM = axis.x*axis.y*fOneMinusCos; T fXZM = axis.x*axis.z*fOneMinusCos; T fYZM = axis.y*axis.z*fOneMinusCos; T fXSin = axis.x*fSin; T fYSin = axis.y*fSin; T fZSin = axis.z*fSin; m[0][0] = fX2*fOneMinusCos+fCos; m[0][1] = fXYM-fZSin; m[0][2] = fXZM+fYSin; m[0][3] = 0; m[1][0] = fXYM+fZSin; m[1][1] = fY2*fOneMinusCos+fCos; m[1][2] = fYZM-fXSin; m[1][3] = 0; m[2][0] = fXZM-fYSin; m[2][1] = fYZM+fXSin; m[2][2] = fZ2*fOneMinusCos+fCos; m[2][3] = 0; m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1; } } template void Matrix4x4::LookAt (const Vector3 &eye, const Vector3 &at, const Vector3 &up) { // left handed Vector3 z_axis = at - eye; Vector3 x_axis = z_axis.CrossProduct (up); Vector3 y_axis = x_axis.CrossProduct (z_axis); x_axis.Normalize(); y_axis.Normalize(); z_axis.Normalize(); Matrix4x4 Rot; Rot.m[0][0] = x_axis.x; Rot.m[0][1] = x_axis.y; Rot.m[0][2] = x_axis.z; Rot.m[0][3] = 0; Rot.m[1][0] = y_axis.x; Rot.m[1][1] = y_axis.y; Rot.m[1][2] = y_axis.z; Rot.m[1][3] = 0; Rot.m[2][0] = -z_axis.x; Rot.m[2][1] = -z_axis.y; Rot.m[2][2] = -z_axis.z; Rot.m[2][3] = 0; Rot.m[3][0] = 0.0f; Rot.m[3][1] = 0.0f; Rot.m[3][2] = 0.0f; Rot.m[3][3] = 1.0f; Matrix4x4 Trans; Trans.Translate (-eye.x, -eye.y, -eye.z); *this = Rot * Trans; } /// set to an orthographic projection matrix. // 2/(r-l) 0 0 -(r+l)/(r-l) // 0 2/(t-b) 0 -(t+b)/(t-b) // 0 0 -2/(f-n) -(f+n)/(f-n) // 0 0 0 1 template void Matrix4x4::Orthographic (T l, T r, T b, T t, T n, T f) { T sx = 1 / (r - l); T sy = 1 / (t - b); T sz = 1 / (f - n); m[0][0] = 2.0f * sx; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = - (r + l) * sx; m[1][0] = 0.0f; m[1][1] = 2.0f * sy; m[1][2] = 0.0f; m[1][3] = - (t + b) * sy; m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = -2.0f * sz; m[2][3] = - (f + n) * sz; m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f; } /// set to a perspective projection matrix. // 2*n/(r-l) 0 (r+l)/(r-l) 0 // 0 2*n/(t-b) (t+b)/(t-b) 0 // 0 0 -(f+n)/(f-n) -2*f*n/(f-n) // 0 0 -1 0 template void Matrix4x4::Perspective (T l, T r, T t, T b, T n, T f) { m[0][0] = 2.0f * n / (r - l); m[0][1] = 0.0f; m[0][2] = (r + l) / (r - l); m[0][3] = 0.0f; m[1][0] = 0.0f; m[1][1] = 2.0f * n / (t - b); m[1][2] = (t + b) / (t - b); m[1][3] = 0.0f; m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = - (f + n) / (f - n); m[2][3] = -2.0f * f * n / (f - n); m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = -1.0f; m[3][3] = 0.0f; } // (r-l)/2*n 0 0 (r+l)/(2*n) // 0 (t-b)/(2*n) 0 (t+b)/(2*n) // 0 0 0 -1 // 0 0 -(f-n)/(2*f*n) (f+n)/(2*f*n) template void Matrix4x4::PerspectiveInverse (T l, T r, T t, T b, T n, T f) { m[0][0] = (r - l) / (2.0f * n); m[0][1] = 0; m[0][2] = 0; m[0][3] = (r + l) / (2.0f * n); m[1][0] = 0; m[1][1] = (t - b) / (2.0f * n); m[1][2] = (t + b) / (2.0f * n); m[1][3] = 0; m[2][0] = 0; m[2][1] = 0; m[2][2] = 0; m[2][3] = -1; m[3][0] = 0; m[3][1] = 0; m[3][2] = - (f - n) / (2.0f * f * n); m[3][3] = (f + n) / (2.0f * f * n); } /// set to a perspective projection matrix specified in terms of field of view and aspect ratio. template void Matrix4x4::Perspective (T FoV, T AspectRatio, T NearPlane, T FarPlane) { const T t = tan (FoV * 0.5f) * NearPlane; const T b = -t; const T l = AspectRatio * b; const T r = AspectRatio * t; Perspective (l, r, t, b, NearPlane, FarPlane); } template Matrix4x4 Matrix4x4::IDENTITY() { Matrix4x4 matrix; matrix.Identity(); return matrix; } template Matrix4x4 Matrix4x4::ZERO() { Matrix4x4 matrix; matrix.Zero(); return matrix; } template Matrix4x4 Matrix4x4::ROTATEX(T angle) { Matrix4x4 matrix; matrix.Rotate_x(angle); return matrix; } template Matrix4x4 Matrix4x4::ROTATEY(T angle) { Matrix4x4 matrix; matrix.Rotate_y(angle); return matrix; } template Matrix4x4 Matrix4x4::ROTATEZ(T angle) { Matrix4x4 matrix; matrix.Rotate_z(angle); return matrix; } template Matrix4x4 Matrix4x4::TRANSLATE(T x, T y, T z) { Matrix4x4 matrix; matrix.Translate(x, y, z); return matrix; } template Matrix4x4 Matrix4x4::SCALE(T x, T y, T z) { Matrix4x4 matrix; matrix.Scale(x, y, z); return matrix; } /***************************************************************************************\ Function: operator * Description: Multiply matrix rhs by constant lhs. Allow "f * matrix" operation. Parameters: None. Return Value: Matrix4. Comments: None. \***************************************************************************************/ template Matrix4x4 operator * (const T &lhs, const Matrix4x4& rhs) { Matrix4x4 oM; oM.m[0][0] = rhs.m[0][0] * lhs; oM.m[0][1] = rhs.m[0][1] * lhs; oM.m[0][2] = rhs.m[0][2] * lhs; oM.m[0][3] = rhs.m[0][3] * lhs; oM.m[1][0] = rhs.m[1][0] * lhs; oM.m[1][1] = rhs.m[1][1] * lhs; oM.m[1][2] = rhs.m[1][2] * lhs; oM.m[1][3] = rhs.m[1][3] * lhs; oM.m[2][0] = rhs.m[2][0] * lhs; oM.m[2][1] = rhs.m[2][1] * lhs; oM.m[2][2] = rhs.m[2][2] * lhs; oM.m[2][3] = rhs.m[2][3] * lhs; oM.m[3][0] = rhs.m[3][0] * lhs; oM.m[3][1] = rhs.m[3][1] * lhs; oM.m[3][2] = rhs.m[3][2] * lhs; oM.m[3][3] = rhs.m[3][3] * lhs; return oM; } typedef Matrix4x4 Matrix4; } #endif // MATRIX4_H nux-4.0.8+18.10.20180623/NuxCore/Math/Point2D-inl.h0000644000000000000000000000214013313373365015262 0ustar #ifndef POINT2D_INL_H #define POINT2D_INL_H namespace nux { template Point2D::Point2D() : x(0), y(0) { } template Point2D::Point2D(T const& X, T const& Y) : x(X), y(Y) { } template bool operator ==(const Point2D& lhs, const Point2D& rhs) { return (lhs.x == rhs.x) && (lhs.y == rhs.y); } template bool operator !=(const Point2D& lhs, const Point2D& rhs) { return !(lhs == rhs); } template Point2D operator -(const Point2D& lhs, const Point2D& rhs) { return Point2D(lhs.x - rhs.x, lhs.y - rhs.y); } template Point2D operator +(const Point2D& lhs, const Point2D& rhs) { return Point2D(lhs.x + rhs.x, lhs.y + rhs.y); } template Point2D operator *(const Point2D& lhs, S rhs) { return Point2D(lhs.x * rhs, lhs.y * rhs); } template Point2D operator *(S lhs, const Point2D& rhs) { return Point2D(rhs.x * lhs, rhs.y * lhs); } } #endif nux-4.0.8+18.10.20180623/NuxCore/Math/Point2D.h0000644000000000000000000000237313313373365014512 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef POINT2D_H #define POINT2D_H namespace nux { template class Point2D { public: Point2D(); Point2D(T const& x, T const& y); T x, y; }; template bool operator ==(const Point2D& lhs, const Point2D& rhs); template bool operator !=(const Point2D& lhs, const Point2D& rhs); // Do we want to keep this really? typedef Point2D Point2; } #include "Point2D-inl.h" #endif // POINT2D_H nux-4.0.8+18.10.20180623/NuxCore/Math/Point3D.cpp0000644000000000000000000000154113313373365015042 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Point3D.h" namespace nux { } nux-4.0.8+18.10.20180623/NuxCore/Math/Point3D.h0000644000000000000000000000373713313373365014520 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef POINT3D_H #define POINT3D_H namespace nux { template class Point3D { public: Point3D(); ~Point3D(); Point3D (const Point3D &Pt); Point3D (T x, T y, T z); void Set (T X, T Y, T Z); bool operator == (const Point3D& Pt) const; bool operator != (const Point3D& Pt) const; T x, y, z; }; template Point3D::Point3D() { x = 0; y = 0; z = 0; } template Point3D::~Point3D() { } template Point3D::Point3D (const Point3D &Pt) { x = Pt.x; y = Pt.y; z = Pt.z; } template Point3D::Point3D (T X, T Y, T Z) { x = X; y = Y; z = Z; } template void Point3D::Set (T X, T Y, T Z) { x = X; y = Y; z = Z; } template bool Point3D::operator == (const Point3D& Pt) const { if ( (x == Pt.x) && (y == Pt.y) && (z == Pt.z) ) { return true; } return false; } template bool Point3D::operator != (const Point3D& Pt) const { return ! ( (*this) == Pt); } typedef Point3D Point3; } #endif // POINT3D_H nux-4.0.8+18.10.20180623/NuxCore/Math/Quaternion.cpp0000644000000000000000000003144613313373365015716 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Matrix4.h" #include "Vector3.h" #include "Quaternion.h" // When writing to a matrix at row r and column c use m[r][c]. // When reading from a matrix at row r and column c use m[c][r]. namespace nux { Quaternion::Quaternion() { x = y = z = w = 0.0f; } Quaternion::Quaternion (const Quaternion &quat) { x = quat.x; y = quat.y; z = quat.z; w = quat.w; } Quaternion::Quaternion (const Vector3 &vec, float angle) { FromAngleAxis (vec.x, vec.y, vec.z, angle); } Quaternion::Quaternion (const Vector4 &vec) { FromAngleAxis (vec.w, vec.x, vec.y, vec.z); } Quaternion::Quaternion (float axis_x, float axis_y, float axis_z, float angle_radian) { FromAngleAxis (axis_x, axis_y, axis_z, angle_radian); } Quaternion::Quaternion (float euler_x, float euler_y, float euler_z) { FromEulerZXY (euler_x, euler_y, euler_z); } Quaternion::~Quaternion() { } Quaternion &Quaternion::operator = (const Quaternion &quat) { x = quat.x; y = quat.y; z = quat.z; w = quat.w; return (*this); } Quaternion Quaternion::operator + (const Quaternion &quat) const { Quaternion qt; qt.x = x + quat.x; qt.y = y + quat.y; qt.z = z + quat.z; qt.w = w + quat.w; return qt; } Quaternion Quaternion::operator - (const Quaternion &quat) const { Quaternion qt; qt.x = x - quat.x; qt.y = y - quat.y; qt.z = z - quat.z; qt.w = w - quat.w; return qt; } Quaternion Quaternion::operator * (const Quaternion &quat) const { Quaternion qt; float x1, x2, y1, y2, z1, z2, w1, w2; x1 = x; y1 = y; z1 = z; w1 = w; x2 = quat.x; y2 = quat.y; z2 = quat.z; w2 = quat.w; qt.x = w1 * x2 + x1 * w2 - z1 * y2 + y1 * z2; qt.y = w1 * y2 + y1 * w2 + z1 * x2 - x1 * z2; qt.z = w1 * z2 + z1 * w2 + x1 * y2 - y1 * x2; qt.w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2; return qt; } Quaternion Quaternion::operator * (const float &f) const { Quaternion qt; qt.x = x * f; qt.y = y * f; qt.z = z * f; qt.w = w * f; return qt; } Quaternion Quaternion::operator / (const float &f) const { Quaternion qt; qt.x = x / f; qt.y = y / f; qt.z = z / f; qt.w = w / f; return qt; } ////////////////////////////////////////////////////////////////////////// Quaternion &Quaternion::operator += (const Quaternion &quat) { x = x + quat.x; y = y + quat.y; z = z + quat.z; w = w + quat.w; return *this; } Quaternion &Quaternion::operator -= (const Quaternion &quat) { x = x - quat.x; y = y - quat.y; z = z - quat.z; w = w - quat.w; return *this; } Quaternion &Quaternion::operator *= (const Quaternion &quat) { Quaternion qt; float x1, x2, y1, y2, z1, z2, w1, w2; x1 = x; y1 = y; z1 = z; w1 = w; x2 = quat.x; y2 = quat.y; z2 = quat.z; w2 = quat.w; qt.x = w1 * x2 + x1 * w2 - z1 * y2 + y1 * z2; qt.y = w1 * y2 + y1 * w2 + z1 * x2 - x1 * z2; qt.z = w1 * z2 + z1 * w2 + x1 * y2 - y1 * x2; qt.w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2; x = qt.x; y = qt.y; z = qt.z; w = qt.w; return *this; } Quaternion &Quaternion::operator *= (const float &f) { x = x * f; y = y * f; z = z * f; w = w * f; return *this; } Quaternion &Quaternion::operator /= (const float &f) { x = x / f; y = y / f; z = z / f; w = w / f; return *this; } Quaternion Quaternion::operator + () const { Quaternion qt; qt.x = x; qt.y = y; qt.z = z; qt.w = w; return qt; } Quaternion Quaternion::operator - () const { Quaternion qt; qt.x = -x; qt.y = -y; qt.z = -z; qt.w = -w; return qt; } bool Quaternion::operator == (const Quaternion &quat) const { if ( (x == quat.x) && (y == quat.y) && (z == quat.z) && (w == quat.w) ) { return true; } return true; } bool Quaternion::operator != ( const Quaternion &quat) const { return ! ( (*this) == quat); } void Quaternion::Conjugate() { x = -x; y = -y; z = -z; } void Quaternion::Inverse() { float len; len = (float) std::sqrt (x * x + y * y + z * z + w * w); Conjugate(); x = x / len; y = y / len; z = z / len; w = w / len; } void Quaternion::Normalize() { float len; len = (float) std::sqrt (x * x + y * y + z * z + w * w); x = x / len; y = y / len; z = z / len; w = w / len; } /***************************************************************************************\ Function: Quaternion::dot_product Description: Compute the dot product of *this and the input quaternion vector Parameters: - quat Return Value: float. Comments: None. \***************************************************************************************/ float Quaternion::DotProduct (const Quaternion &quat) const { float d_p; d_p = x * quat.x + y * quat.y + z * quat.z + w * quat.w; return d_p; } /***************************************************************************************\ Function: Quaternion::length Description: Compute the length of a quaternion vector Parameters: None. Return Value: float Comments: None. \***************************************************************************************/ float Quaternion::Length() const { float len; len = (float) std::sqrt (x * x + y * y + z * z + w * w); return len; } /***************************************************************************************\ Function: Quaternion::FromAngleAxis Description: Set the quaternion to define a rotation of angle_randian around the vector define by (axis_x, axis_y, axis_z) Parameters: - angle_radian: angle in radian - axis_x - axis_y - axis_z Return Value: None. Comments: None. \***************************************************************************************/ void Quaternion::FromAngleAxis (float axis_x, float axis_y, float axis_z, float angle_radian) { float ax = axis_x; float ay = axis_y; float az = axis_z; // required: Normalize the axis float len = 1.0f / (float) std::sqrt ( ax * ax + ay * ay + az * az ); ax = ax * len; ay = ay * len; az = az * len; float sin_theta_over_two = (float) std::sin ( angle_radian / 2.0); x = ax * sin_theta_over_two; y = ay * sin_theta_over_two; z = az * sin_theta_over_two; w = (float) std::cos (angle_radian / 2.0); } /***************************************************************************************\ Function: Quaternion::FromEulerZXY Description: Set the quaternion to define a Euler transform Parameters: - euler_x: rotation angle around X axis (in radian) - euler_y: rotation angle around Y axis (in radian) - euler_z: rotation angle around Z axis (in radian) Return Value: None. Comments: The rotation are applied in the following order: rotation around Y axis rotation around X axis rotation around Z axis \***************************************************************************************/ void Quaternion::FromEulerZXY (float euler_x, float euler_y, float euler_z) { float roll_axis[3] = {0.0f, 0.0f, 1.0f}; float pitch_axis[3] = {1.0f, 0.0f, 0.0f}; float yaw_axis[3] = {0.0f, 1.0f, 0.0f}; Quaternion roll (euler_z, roll_axis[0], roll_axis[1], roll_axis[2]); Quaternion pitch (euler_x, pitch_axis[0], pitch_axis[1], pitch_axis[2]); Quaternion yaw (euler_y, yaw_axis[0], yaw_axis[1], yaw_axis[2]); (*this) = roll * pitch * yaw; } void Quaternion::GetAngleAxis (Vector3 &axis, float &angle_radian) const { Quaternion qt; qt.x = x; qt.y = y; qt.z = z; qt.w = w; // make a unit quaternion qt.Normalize(); // qt = sin(angle/2)*Uq + cos(angle/2) angle_radian = 2.0f * (float) std::acos (qt.w); float one_over_sin = 1.0f / (float) std::sqrt (qt.x * qt.x + qt.y * qt.y + qt.z * qt.z); //float one_over_sin = 1.0f / (float) sin(angle_radian / 2.0f); axis.x = qt.x * one_over_sin; axis.y = qt.y * one_over_sin; axis.z = qt.z * one_over_sin; } /***************************************************************************************\ Function: Quaternion::get_matrix Description: Return a Matrix4 object containing the rotation defined by the quaternion. Parameters: None. Return Value: Matrix4. Comments: None. \***************************************************************************************/ Matrix4 Quaternion::GetMatrix() const { Matrix4 mat4; /*float x = x; float y = y; float z = z; float w = w;*/ float s; s = 2.0f / ( (float) std::sqrt (x * x + y * y + z * z + w * w) ); mat4.m[0][0] = 1.0f - s * (y * y + z * z); mat4.m[0][1] = s * (x * y - w * z); mat4.m[0][2] = s * (x * z + w * y); mat4.m[0][3] = 0.0f; mat4.m[1][0] = s * (x * y + w * z); mat4.m[1][1] = 1.0f - s * (x * x + z * z); mat4.m[1][2] = s * (y * z - w * x); mat4.m[1][3] = 0.0f; mat4.m[2][0] = s * (x * z - w * y); mat4.m[2][1] = s * (y * z + w * x); mat4.m[2][2] = 1.0f - s * (x * x + y * y); mat4.m[2][3] = 0.0f; mat4.m[3][0] = 0.0f; mat4.m[3][1] = 0.0f; mat4.m[3][2] = 0.0f; mat4.m[3][3] = 1.0f; return mat4; } /*const Quaternion operator * (const Quaternion& quat1, const Quaternion& quat2) { Quaternion qt; float x1, x2, y1, y2, z1, z2, w1, w2; x1 = quat1.x; y1 = quat1.y; z1 = quat1.z; w1 = quat1.w; x2 = quat2.x; y2 = quat2.y; z2 = quat2.z; w2 = quat2.w; qt.x = w1*x2 + x1*w2 - z1*y2 + y1*z2; qt.y = w1*y2 + y1*w2 + z1*x2 - x1*z2; qt.z = w1*z2 + z1*w2 + x1*y2 - y1*x2; qt.w = w1*w2 - x1*x2 - y1*y2 - z1*z2; return qt; }*/ Quaternion operator * (float f, const Quaternion &quat) { Quaternion qt; qt.x = quat.x * f; qt.y = quat.y * f; qt.z = quat.z * f; qt.w = quat.w * f; return qt; } Quaternion Slerp (const float t, const Quaternion &lhs, const Quaternion &rhs) { // the slerp of a pair of unit quaterions is the weighted // interpolation between them, where the interpolation weight is // given by t = [0, 1.0] // // the trick to slerping is that we find the angle between the two // quats by treating them as a pair of four vectors and getting the // cosine [as the dot product]. // // then the slerp between two quaternions A and B is: // // A * (upper_weight) + B * (lower_weight) // // where the weights are the sines of the t-weighted angle // divided by the sine of the angle. // // the resulting quaternion is also a unit quaternion. // find the angle between the two quats by treating // them as 4-length vectors -- V1.V2 = cos(theta) float cosine_angle, angle_over_two; float coef1, coef2; Quaternion qt; Quaternion lhs_n, rhs_n; lhs_n = lhs; rhs_n = rhs; lhs_n.Normalize(); rhs_n.Normalize(); cosine_angle = lhs_n.DotProduct (rhs_n); // = cos(angle_over_two) // adjust signs (if necessary) if ( cosine_angle < 0.0 ) { cosine_angle = -cosine_angle; rhs_n = - rhs_n; } angle_over_two = (float) std::acos (cosine_angle); if ( (1 - cosine_angle) > 0.000001) { coef1 = (float) std::sin (angle_over_two * (1 - t) ) / (float) std::sin (angle_over_two); coef2 = (float) std::sin (angle_over_two * t) / (float) std::sin (angle_over_two); } else { // lhs and rhs are very close ... so we can do a linear interpolation coef1 = 1 - t; coef2 = t; } qt = coef1 * lhs_n + coef2 * rhs_n; return qt; } } nux-4.0.8+18.10.20180623/NuxCore/Math/Quaternion.h0000644000000000000000000000661713313373365015365 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef QUATERNION_H #define QUATERNION_H #include "Vector3.h" #include "Vector4.h" namespace nux { /***************************************************************************************\ Class: Quaternion Description: Define basic quaternion initialization and function. Comments: Member functions uses input angles in radian. \***************************************************************************************/ class Quaternion { public: Quaternion(); Quaternion (const Quaternion &s); Quaternion (const Vector3 &vec, float angle); Quaternion (const Vector4 &vec); // creates a Quaternion from an angle axis -- note that if angle > 2*PI the resulting // rotation is angle mod 2*PI Quaternion (float axis_x, float axis_y, float axis_z, float angle_radian); // creates a Quaternion from an angle-around-XYZ euler triple using roll-pitch-yaw order Quaternion (float euler_x, float euler_y, float euler_z); ~Quaternion(); Quaternion &operator = (const Quaternion &quat); // binary operators Quaternion operator + (const Quaternion &quat) const; Quaternion operator - (const Quaternion &quat) const; Quaternion operator * (const Quaternion &quat) const; Quaternion operator * (const float &f) const; Quaternion operator / (const float &f) const; // assignment operators Quaternion &operator += (const Quaternion &quat); Quaternion &operator -= (const Quaternion &quat); Quaternion &operator *= (const Quaternion &quat); Quaternion &operator *= (const float &f); Quaternion &operator /= (const float &f); // unary operators Quaternion operator + () const; Quaternion operator - () const; //const Quaternion operator / (const Quaternion& quat); bool operator == ( const Quaternion & ) const; bool operator != ( const Quaternion & ) const; void Conjugate(); void Inverse(); void Normalize(); float DotProduct (const Quaternion &quat) const; float Length() const; void GetAngleAxis (Vector3 &axis, float &angle_radian) const; // fetches the angle/axis given by the quat // Fetches 4x4 homogeneous matrix given by the quat Matrix4 GetMatrix() const; float x, y, z, w; friend Quaternion operator * (float f, const Quaternion &quat); private: // set the quaternion by angle-axis (see AA constructor) void FromAngleAxis (float axis_x, float axis_y, float axis_z, float angle_radian); // set the quaternion by euler axis angles (see euler constructor) void FromEulerZXY (float euler_x, float euler_y, float euler_z); }; } #endif // QUATERNION_H nux-4.0.8+18.10.20180623/NuxCore/Math/Spline.cpp0000644000000000000000000001741313313373365015021 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Spline.h" #include "MathFunctions.h" namespace nux { double *CubicSpline::SolveTridiag ( int n, double a[], double b[] ) { int i; double *x; double xmult; // // Check. // for ( i = 0; i < n; i++ ) { if ( a[1+i*3] == 0.0 ) { return NULL; } } x = new double[n]; for ( i = 0; i < n; i++ ) { x[i] = b[i]; } for ( i = 1; i < n; i++ ) { xmult = a[2+ (i-1) *3] / a[1+ (i-1) *3]; a[1+i*3] = a[1+i*3] - xmult * a[0+i*3]; x[i] = x[i] - xmult * x[i-1]; } x[n-1] = x[n-1] / a[1+ (n-1) *3]; for ( i = n - 2; 0 <= i; i-- ) { x[i] = ( x[i] - a[0+ (i+1) *3] * x[i+1] ) / a[1+i*3]; } return x; } CubicSpline::CubicSpline (int numpoint, std::vector x_array, std::vector y_array, int ibcbeg, double ybcbeg, int ibcend, double ybcend ) { if ( ( (int) x_array.size() != numpoint) || ( (int) y_array.size() != numpoint) ) { NUX_BREAK_ASM_INT3; } np = numpoint; t = new double[np]; y = new double[np]; ddy = 0; //new double[np]; for (int i = 0; i < np; i++) { t[i] = x_array[i]; y[i] = y_array[i]; //ddy[i] = 0; } ibcbeg_ = ibcbeg; ybcbeg_ = ybcbeg; ibcend_ = ibcend; ybcend_ = ybcend; Compute (ibcbeg_, ybcbeg_, ibcend_, ybcend_ ); } CubicSpline::CubicSpline() { np = 2; t = new double[np]; y = new double[np]; ddy = 0; //new double[np]; t[0] = 0.0; t[1] = 1.0; y[0] = 0.0; y[1] = 1.0; ibcbeg_ = 0; ybcbeg_ = 0; ibcend_ = 0; ybcend_ = 0; Compute (ibcbeg_, ybcbeg_, ibcend_, ybcend_ ); } CubicSpline::CubicSpline (const CubicSpline &Other) { if (Other.np == 0) NUX_BREAK_ASM_INT3; np = Other.np; t = new double[np]; y = new double[np]; for (int i = 0; i < np; i++) { t[i] = Other.t[i]; y[i] = Other.y[i]; } ibcbeg_ = Other.ibcbeg_; ybcbeg_ = Other.ybcbeg_; ibcend_ = Other.ibcend_; ybcend_ = Other.ybcend_; Compute (ibcbeg_, ybcbeg_, ibcend_, ybcend_ ); } CubicSpline &CubicSpline::operator = (const CubicSpline &Other) { if (Other.np == 0) NUX_BREAK_ASM_INT3; np = Other.np; t = new double[np]; y = new double[np]; for (int i = 0; i < np; i++) { t[i] = Other.t[i]; y[i] = Other.y[i]; } ibcbeg_ = Other.ibcbeg_; ybcbeg_ = Other.ybcbeg_; ibcend_ = Other.ibcend_; ybcend_ = Other.ybcend_; Compute (ibcbeg_, ybcbeg_, ibcend_, ybcend_); return *this; } void CubicSpline::Set (int numpoint, std::vector x_array, std::vector y_array, int ibcbeg, double ybcbeg, int ibcend, double ybcend) { if (numpoint <= 1) { np = 0; return; } if ( ( (int) x_array.size() != numpoint) || ( (int) y_array.size() != numpoint) ) { NUX_BREAK_ASM_INT3; } np = numpoint; if (t) delete [] t; if (y) delete [] y; if (ddy) delete [] ddy; t = new double[np]; y = new double[np]; ddy = 0; for (int i = 0; i < np; i++) { t[i] = x_array[i]; y[i] = y_array[i]; } Compute (ibcbeg, ybcbeg, ibcend, ybcend ); } CubicSpline::~CubicSpline() { if (t) delete [] t; if (y) delete [] y; if (ddy) delete [] ddy; } double *CubicSpline::Compute (int ibcbeg, double ybcbeg, int ibcend, double ybcend ) { double *a; double *b; int i; // // Check. // if ( np <= 1 ) { //"Fatal error: The number of data points N must be at least 2.\n"; NUX_BREAK_ASM_INT3; return 0; } for ( i = 0; i < np - 1; i++ ) { if ( t[i+1] <= t[i] ) { //"Fatal error: The knots must be strictly increasing, but\n"; NUX_BREAK_ASM_INT3; return NULL; } } a = new double[3*np]; b = new double[np]; // // Set up the first equation. // if ( ibcbeg == 0 ) { b[0] = 0.0; a[1+0*3] = 1.0; a[0+1*3] = -1.0; } else if ( ibcbeg == 1 ) { b[0] = ( y[1] - y[0] ) / ( t[1] - t[0] ) - ybcbeg; a[1+0*3] = ( t[1] - t[0] ) / 3.0; a[0+1*3] = ( t[1] - t[0] ) / 6.0; } else if ( ibcbeg == 2 ) { b[0] = ybcbeg; a[1+0*3] = 1.0; a[0+1*3] = 0.0; } else { //"Fatal error: IBCBEG must be 0, 1 or 2.\n"; NUX_BREAK_ASM_INT3; delete [] a; delete [] b; return NULL; } // // Set up the intermediate equations. // for ( i = 1; i < np - 1; i++ ) { b[i] = ( y[i+1] - y[i] ) / ( t[i+1] - t[i] ) - ( y[i] - y[i-1] ) / ( t[i] - t[i-1] ); a[2+ (i-1) *3] = ( t[i] - t[i-1] ) / 6.0; a[1+ i *3] = ( t[i+1] - t[i-1] ) / 3.0; a[0+ (i+1) *3] = ( t[i+1] - t[i] ) / 6.0; } // // Set up the last equation. // if ( ibcend == 0 ) { b[np-1] = 0.0; a[2+ (np-2) *3] = -1.0; a[1+ (np-1) *3] = 1.0; } else if ( ibcend == 1 ) { b[np-1] = ybcend - ( y[np-1] - y[np-2] ) / ( t[np-1] - t[np-2] ); a[2+ (np-2) *3] = ( t[np-1] - t[np-2] ) / 6.0; a[1+ (np-1) *3] = ( t[np-1] - t[np-2] ) / 3.0; } else if ( ibcend == 2 ) { b[np-1] = ybcend; a[2+ (np-2) *3] = 0.0; a[1+ (np-1) *3] = 1.0; } else { //"Fatal error: IBCEND must be 0, 1 or 2.\n"; NUX_BREAK_ASM_INT3; delete [] a; delete [] b; return NULL; } // // Solve the linear system. // if ( np == 2 && ibcbeg == 0 && ibcend == 0 ) { ddy = new double[2]; ddy[0] = 0.0; ddy[1] = 0.0; } else { if (ddy) { delete [] ddy; } ddy = SolveTridiag ( np, a, b ); if ( !ddy ) { //"Fatal error: The linear system could not be solved.\n"; NUX_BREAK_ASM_INT3; delete [] a; delete [] b; return NULL; } } delete [] a; delete [] b; return ddy; } double CubicSpline::Eval (double tval) { double dt; double h; int i; int ival; double yval; // // Determine the interval [ T(I), T(I+1) ] that contains TVAL. // Values below T[0] or above T[N-1] use extrapolation. // if (np <= 1) return 0.0; ival = np - 2; if (tval > t[np-1]) { tval = t[np-1]; } if (tval < t[0]) { tval = t[0]; } for ( i = 0; i < np - 1; i++ ) { if ( tval < t[i+1] ) { ival = i; break; } } // // In the interval I, the polynomial is in terms of a normalized // coordinate between 0 and 1. // dt = tval - t[ival]; h = t[ival+1] - t[ival]; yval = y[ival] + dt * ( ( y[ival+1] - y[ival] ) / h - ( ddy[ival+1] / 6.0 + ddy[ival] / 3.0 ) * h + dt * ( 0.5 * ddy[ival] + dt * ( ( ddy[ival+1] - ddy[ival] ) / ( 6.0 * h ) ) ) ); return yval; } } nux-4.0.8+18.10.20180623/NuxCore/Math/Spline.h0000644000000000000000000002314213313373365014462 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef SPLINE_H #define SPLINE_H #include namespace nux { double *d3_np_fs ( int n, double a[], double b[] ); double *spline_cubic_set ( int n, double t[], double y[], int ibcbeg, double ybcbeg, int ibcend, double ybcend ); double spline_cubic_val ( int n, double t[], double tval, double y[], double ypp[], double *ypval, double *yppval ); class CubicSpline { public: CubicSpline(); CubicSpline (const CubicSpline &Other); CubicSpline &operator = (const CubicSpline &Other); CubicSpline (int numpoint, std::vector x_array, std::vector y_array, int ibcbeg = 0, double ybcbeg = 0, int ibcend = 0, double ybcend = 0); void Set (int numpoint, std::vector x_array, std::vector y_array, int ibcbeg = 0, double ybcbeg = 0, int ibcend = 0, double ybcend = 0); ~CubicSpline(); //********************************************************************** // double* CubicSpline::Compute ( int n, double t[], double y[], int ibcbeg, double ybcbeg, int ibcend, double ybcend ) // Purpose: // // SPLINE_CUBIC_SET computes the second derivatives of a piecewise cubic spline. // // Discussion: // // For data interpolation, the user must call SPLINE_SET to determine // the second derivative data, passing in the data to be interpolated, // and the desired boundary conditions. // // The data to be interpolated, plus the SPLINE_SET output, defines // the spline. The user may then call SPLINE_VAL to evaluate the // spline at any point. // // The cubic spline is a piecewise cubic polynomial. The intervals // are determined by the "knots" or abscissas of the data to be // interpolated. The cubic spline has continous first and second // derivatives over the entire interval of interpolation. // // For any point T in the interval T(IVAL), T(IVAL+1), the form of // the spline is // // SPL(T) = A(IVAL) // + B(IVAL) * ( T - T(IVAL) ) // + C(IVAL) * ( T - T(IVAL) )**2 // + D(IVAL) * ( T - T(IVAL) )**3 // // If we assume that we know the values Y(*) and DDY(*), which represent // the values and second derivatives of the spline at each knot, then // the coefficients can be computed as: // // A(IVAL) = Y(IVAL) // B(IVAL) = ( Y(IVAL+1) - Y(IVAL) ) / ( T(IVAL+1) - T(IVAL) ) // - ( DDY(IVAL+1) + 2 * DDY(IVAL) ) * ( T(IVAL+1) - T(IVAL) ) / 6 // C(IVAL) = DDY(IVAL) / 2 // D(IVAL) = ( DDY(IVAL+1) - DDY(IVAL) ) / ( 6 * ( T(IVAL+1) - T(IVAL) ) ) // // Since the first derivative of the spline is // // SPL'(T) = B(IVAL) // + 2 * C(IVAL) * ( T - T(IVAL) ) // + 3 * D(IVAL) * ( T - T(IVAL) )**2, // // the requirement that the first derivative be continuous at interior // knot I results in a total of N-2 equations, of the form: // // B(IVAL-1) + 2 C(IVAL-1) * (T(IVAL)-T(IVAL-1)) + 3 * D(IVAL-1) * (T(IVAL) - T(IVAL-1))^2 = B(IVAL) // // or, setting H(IVAL) = T(IVAL+1) - T(IVAL) // // ( Y(IVAL) - Y(IVAL-1) ) / H(IVAL-1) - ( DDY(IVAL) + 2 * DDY(IVAL-1) ) * H(IVAL-1) / 6 + DDY(IVAL-1) * H(IVAL-1) // + ( DDY(IVAL) - DDY(IVAL-1) ) * H(IVAL-1) / 2 // = ( Y(IVAL+1) - Y(IVAL) ) / H(IVAL) - ( DDY(IVAL+1) + 2 * DDY(IVAL) ) * H(IVAL) / 6 // // or // // DDY(IVAL-1) * H(IVAL-1) + 2 * DDY(IVAL) * ( H(IVAL-1) + H(IVAL) ) + DDY(IVAL) * H(IVAL) // = 6 * ( Y(IVAL+1) - Y(IVAL) ) / H(IVAL) - 6 * ( Y(IVAL) - Y(IVAL-1) ) / H(IVAL-1) // // Boundary conditions must be applied at the first and last knots. // The resulting tridiagonal system can be solved for the DDY values. // // // Parameters: // // Input, int N, the number of data points. N must be at least 2. // In the special case where N = 2 and IBCBEG = IBCEND = 0, the // spline will actually be linear. // // Input, double T[N], the knot values, that is, the points were data is // specified. The knot values should be distinct, and increasing. // // Input, double Y[N], the data values to be interpolated. // // Input, int IBCBEG, left boundary condition flag: // 0: the cubic spline should be a quadratic over the first interval; // 1: the first derivative at the left endpoint should be YBCBEG; // 2: the second derivative at the left endpoint should be YBCBEG. // // Input, double YBCBEG, the values to be used in the boundary // conditions if IBCBEG is equal to 1 or 2. // // Input, int IBCEND, right boundary condition flag: // 0: the cubic spline should be a quadratic over the last interval; // 1: the first derivative at the right endpoint should be YBCEND; // 2: the second derivative at the right endpoint should be YBCEND. // // Input, double YBCEND, the values to be used in the boundary // conditions if IBCEND is equal to 1 or 2. // // Output, double SPLINE_CUBIC_SET[N], the second derivatives of the cubic spline. // double *Compute (int ibcbeg, double ybcbeg, int ibcend, double ybcend); //********************************************************************** // double Eval ( int n, double t[], double tval, double y[], double ddy[], double *dyval, double *ddyval ) // Purpose: // // SPLINE_CUBIC_VAL evaluates a piecewise cubic spline at a point. // // Discussion: // // SPLINE_CUBIC_SET must have already been called to define the values of YPP. // // For any point T in the interval T(IVAL), T(IVAL+1), the form of // the spline is // // SPL(T) = A // + B * ( T - T(IVAL) ) // + C * ( T - T(IVAL) )**2 // + D * ( T - T(IVAL) )**3 // // Here: // A = Y(IVAL) // B = ( Y(IVAL+1) - Y(IVAL) ) / ( T(IVAL+1) - T(IVAL) ) // - ( YPP(IVAL+1) + 2 * YPP(IVAL) ) * ( T(IVAL+1) - T(IVAL) ) / 6 // C = YPP(IVAL) / 2 // D = ( YPP(IVAL+1) - YPP(IVAL) ) / ( 6 * ( T(IVAL+1) - T(IVAL) ) ) // // Modified: // // 04 February 1999 // // Author: // // John Burkardt // // Parameters: // // Input, int N, the number of knots. // // Input, double Y[N], the data values at the knots. // // Input, double T[N], the knot values. // // Input, double TVAL, a point, typically between T[0] and T[N-1], at // which the spline is to be evalulated. If TVAL lies outside // this range, extrapolation is used. // // Input, double Y[N], the data values at the knots. // // Input, double YPP[N], the second derivatives of the spline at // the knots. // // Output, double *YPVAL, the derivative of the spline at TVAL. // // Output, double *YPPVAL, the second derivative of the spline at TVAL. // // Output, double SPLINE_VAL, the value of the spline at TVAL. // double Eval (double tval); //********************************************************************** // double* SolveTridiag ( int n, double a[], double b[] ); // Purpose: // // D3_NP_FS factors and solves a D3 system. // // Discussion: // // The D3 storage format is used for a tridiagonal matrix. // The superdiagonal is stored in entries (1,2:N), the diagonal in // entries (2,1:N), and the subdiagonal in (3,1:N-1). Thus, the // original matrix is "collapsed" vertically into the array. // // This algorithm requires that each diagonal entry be nonzero. // It does not use pivoting, and so can fail on systems that // are actually nonsingular. // // Example: // // Here is how a D3 matrix of order 5 would be stored: // // * A12 A23 A34 A45 // A11 A22 A33 A44 A55 // A21 A32 A43 A54 * // // Parameters: // // Input, int N, the order of the linear system. // // Input/output, double A[3*N]. // On input, the nonzero diagonals of the linear system. // On output, the data in these vectors has been overwritten // by factorization information. // // Input, double B[N], the right hand side. // // Output, double D3_NP_FS[N], the solution of the linear system. // This is NULL if there was an error because one of the diagonal // entries was zero. // double *SolveTridiag ( int n, double a[], double b[] ); public: double *t; double *y; double *ddy; int ibcbeg_; double ybcbeg_; int ibcend_; double ybcend_; int np; // number of points }; } #endif // SPLINE_H nux-4.0.8+18.10.20180623/NuxCore/Math/Trigonometry.cpp0000644000000000000000000000554413313373365016273 0ustar /* * Copyright 2010-2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "Trigonometry.h" #include "Constants.h" namespace nux { // Assume the spherical coordinate system relatively to a right handed xyz, // with Z pointing up. // 0 <= phi < 180 // 0 <= theta < 360 ->>> along X axis, theta = 0. Vector3 SphericalToCartesianXBaseDeg (float r, float theta, float phi) { Vector3 v; v.x = r * std::cos (theta * constants::pi / 180.0f) * std::sin (phi * constants::pi / 180.0f); v.y = r * std::sin (theta * constants::pi / 180.0f) * std::sin (phi * constants::pi / 180.0f); v.z = r * std::cos (phi * constants::pi / 180.0f); return v; } Vector3 SphericalToCartesianXBaseRad (float r, float theta, float phi) { Vector3 v; v.x = r * std::cos (theta) * std::sin (phi); v.y = r * std::sin (theta) * std::sin (phi); v.z = r * std::cos (phi); return v; } // Assume the spherical coordinate system relatively to a right handed xyz, // with Y pointing up. // 0 <= phi < 180 // 0 <= theta < 360 ->>> along Z axis, theta = 0. Vector3 SphericalToCartesianZBaseDeg (float r, float theta, float phi) { Vector3 v; v.z = r * std::cos (theta * constants::pi / 180.0f) * std::sin (phi * constants::pi / 180.0f); v.x = r * std::sin (theta * constants::pi / 180.0f) * std::sin (phi * constants::pi / 180.0f); v.y = r * std::cos (phi * constants::pi / 180.0f); return v; } Vector3 SphericalToCartesianZBaseRad (float r, float theta, float phi) { Vector3 v; v.z = r * std::cos (theta) * std::sin (phi); v.x = r * std::sin (theta) * std::sin (phi); v.y = r * std::cos (phi); return v; } Vector3 CartesianToSphericalXBaseRad (float x, float y, float z) { float r, theta, phi; r = std::sqrt (x * x + y * y + z * z); theta = std::atan (y / x); phi = std::acos (z / r); return Vector3 (r, theta, phi); } Vector3 CartesianToSphericalZBaseDeg (float x, float y, float z) { float r, theta, phi; r = std::sqrt (x * x + y * y + z * z); theta = std::atan (x / z); phi = std::acos (y / r); return Vector3 (r, theta, phi); } } nux-4.0.8+18.10.20180623/NuxCore/Math/Trigonometry.h0000644000000000000000000000322213313373365015727 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef TRIGONOMETRY_H #define TRIGONOMETRY_H #include "Vector3.h" namespace nux { // Assume the spherical coordinate system relatively to a right handed xyz, // with Z pointing up. // 0 <= phi < 180 // 0 <= theta < 360 ->>> along X axis, theta = 0. Vector3 SphericalToCartesianXBaseDeg (float r, float theta, float phi); Vector3 SphericalToCartesianXBaseRad (float r, float theta, float phi); // Assume the spherical coordinate system relatively to a right handed xyz, // with Y pointing up. // 0 <= phi < 180 // 0 <= theta < 360 ->>> along Z axis, theta = 0. Vector3 SphericalToCartesianZBaseDeg (float r, float theta, float phi); Vector3 SphericalToCartesianZBaseRad (float r, float theta, float phi); Vector3 CartesianToSphericalXBaseRad (float x, float y, float z); Vector3 CartesianToSphericalZBaseDeg (float x, float y, float z); } #endif // TRIGONOMETRY_H nux-4.0.8+18.10.20180623/NuxCore/Math/Tweening.cpp0000644000000000000000000001733613313373365015353 0ustar /* * Copyright 2010-2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "MathInc.h" #include "Tweening.h" namespace nux { // Back double BackEaseIn (double t, double b, double c, double d, double s) { //return c*(t/=d)*t*((s+1)*t - s) + b; t /= d; return c * t * t * ( (s + 1) * t - s) + b; } double BackEaseOut (double t, double b, double c, double d, double s) { //return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; t = t / d - 1; return c * (t * t * ( (s + 1) * t + s) + 1) + b; } double BackEaseInOut (double t, double b, double c, double d, double s) { // if ((t/=d/2) < 1) // return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; // return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; if ( (t /= d / 2) < 1) { s *= (1.525); return c / 2 * (t * t * ( (s + 1) * t - s) ) + b; } s *= 1.525; t -= 2.0; return c / 2 * (t * t * ( (s + 1) * t + s) + 2) + b; } // Bounce double BounceEaseOut (double t, double b, double c, double d) { if ( (t /= d) < (1 / 2.75) ) { return c * (7.5625 * t * t) + b; } else if (t < (2 / 2.75) ) { t -= (1.5 / 2.75); return c * (7.5625 * t * t + .75) + b; } else if (t < (2.5 / 2.75) ) { t -= (2.25 / 2.75); return c * (7.5625 * t * t + .9375) + b; } else { t -= (2.625 / 2.75); return c * (7.5625 * t * t + .984375) + b; } } double BounceEaseIn (double t, double b, double c, double d) { return c - BounceEaseOut (d - t, 0, c, d) + b; } double BounceEaseInOut (double t, double b, double c, double d) { if (t < d / 2.0) return BounceEaseIn (t * 2, 0, c, d) * .5 + b; else return BounceEaseOut (t * 2 - d, 0, c, d) * .5 + c * .5 + b; } // Circ double CircEaseIn (double t, double b, double c, double d) { t /= d; return -c * (std::sqrt (1 - t * t) - 1) + b; } double CircEaseOut (double t, double b, double c, double d) { t = t / d - 1.0; return c * std::sqrt (1.0 - t * t) + b; } double CircEaseInOut (double t, double b, double c, double d) { if ( (t /= d / 2) < 1) { return -c / 2 * (std::sqrt (1 - t * t) - 1) + b; } t -= 2.0; return c / 2 * (std::sqrt (1.0 - t * t) + 1) + b; } // Cubic double CubicEaseIn (double t, double b, double c, double d) { t /= d; return c * t * t * t + b; } double CubicEaseOut (double t, double b, double c, double d) { t = t / d - 1.0; return c * (t * t * t + 1.0) + b; } double CubicEaseInOut (double t, double b, double c, double d) { if ( (t /= d / 2) < 1) { return c / 2 * t * t * t + b; } t -= 2.0; return c / 2 * (t * t * t + 2) + b; } // Elastic double ElasticEaseIn (double t, double b, double c, double d, double a, double p) { double s = 0; if (t == 0) return b; if ( (t /= d) == 1) return b + c; if (!p) p = d * .3; if (!a || a < std::abs (c) ) { a = c; s = p / 4; } else s = p / (2 * constants::pi) * std::asin (c / a); t -= 1.0; return - (a * std::pow (2, 10 * t) * std::sin ( (t * d - s) * (2 * constants::pi) / p ) ) + b; } double ElasticEaseOut (double t, double b, double c, double d, double a, double p) { double s = 0; if (t == 0) return b; if ( (t /= d) == 1) return b + c; if (!p) p = d * .3; if (!a || a < std::abs (c) ) { a = c; s = p / 4; } else s = p / (2 * constants::pi) * std::asin (c / a); return (a * std::pow (2, -10 * t) * std::sin ( (t * d - s) * (2 * constants::pi) / p ) + c + b); } double ElasticEaseInOut (double t, double b, double c, double d, double a, double p) { double s = 0; if (t == 0) return b; if ( (t /= d / 2) == 2) return b + c; if (!p) p = d * (.3 * 1.5); if (!a || a < std::abs (c) ) { a = c; s = p / 4; } else { s = p / (2 * constants::pi) * std::asin (c / a); } if (t < 1.0) { t -= 1; return -0.5 * (a * std::pow (2, 10.0 * t) * std::sin ( (t * d - s) * (2 * constants::pi) / p ) ) + b; } t -= 1; return a * std::pow (2, -10 * t) * std::sin ( (t * d - s) * (2 * constants::pi) / p ) * .5 + c + b; } // Expo double ExpoEaseIn (double t, double b, double c, double d) { return (t == 0) ? b : c * std::pow (2, 10 * (t / d - 1) ) + b; } double ExpoEaseOut (double t, double b, double c, double d) { return (t == d) ? b + c : c * (-std::pow (2, -10 * t / d) + 1) + b; } double ExpoEaseInOut (double t, double b, double c, double d) { if (t == 0) return b; if (t == d) return b + c; if ( (t /= d / 2) < 1) return c / 2 * std::pow (2, 10 * (t - 1) ) + b; return c / 2 * (-std::pow (2, -10 * --t) + 2) + b; } // Linear double LinearEaseNone (double t, double b, double c, double d) { return c * t / d + b; } double LinearEaseIn (double t, double b, double c, double d) { return c * t / d + b; } double LinearEaseOut (double t, double b, double c, double d) { return c * t / d + b; } double LinearEaseInOut (double t, double b, double c, double d) { return c * t / d + b; } // Quad double QuadEaseIn (double t, double b, double c, double d) { t /= d; return c * t * t + b; } double QuadEaseOut (double t, double b, double c, double d) { t /= d; return -c * t * (t - 2) + b; } double QuadEaseInOut (double t, double b, double c, double d) { if ( (t /= d / 2) < 1) { return c / 2 * t * t + b; } --t; return -c / 2 * (t * (t - 2) - 1) + b; } // Quart double QuartEaseIn (double t, double b, double c, double d) { t /= d; return c * t * t * t * t + b; } double QuartEaseOut (double t, double b, double c, double d) { t = t / d - 1; return -c * (t * t * t * t - 1) + b; } double QuartEaseInOut (double t, double b, double c, double d) { if ( (t /= d / 2) < 1) { return c / 2 * t * t * t * t + b; } t -= 2.0; return -c / 2 * (t * t * t * t - 2) + b; } // Quint double QuintEaseIn (double t, double b, double c, double d) { t /= d; return c * t * t * t * t * t + b; } double QuintEaseOut (double t, double b, double c, double d) { t = t / d - 1; return c * (t * t * t * t * t + 1) + b; } double QuintEaseInOut (double t, double b, double c, double d) { if ( (t /= d / 2) < 1) { return c / 2 * t * t * t * t * t + b; } t -= 2; return c / 2 * (t * t * t * t * t + 2) + b; } // Sine double SineEaseIn (double t, double b, double c, double d) { return -c * std::cos (t / d * (constants::pi / 2) ) + c + b; } double SineEaseOut (double t, double b, double c, double d) { return c * std::sin (t / d * (constants::pi / 2) ) + b; } double SineEaseInOut (double t, double b, double c, double d) { return -c / 2 * (std::cos (constants::pi * t / d) - 1) + b; } } nux-4.0.8+18.10.20180623/NuxCore/Math/Tweening.h0000644000000000000000000000632413313373365015013 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef TWEENING_H #define TWEENING_H namespace nux { // Back double BackEaseIn (double t, double b, double c, double d, double s = 1.70158); double BackEaseOut (double t, double b, double c, double d, double s = 1.70158); double BackEaseInOut (double t, double b, double c, double d, double s = 1.70158); // Bounce double BounceEaseOut (double t, double b, double c, double d); double BounceEaseIn (double t, double b, double c, double d); double BounceEaseInOut (double t, double b, double c, double d); // Circ double CircEaseIn (double t, double b, double c, double d); double CircEaseOut (double t, double b, double c, double d); double CircEaseInOut (double t, double b, double c, double d); // Cubic double CubicEaseIn (double t, double b, double c, double d); double CubicEaseOut (double t, double b, double c, double d); double CubicEaseInOut (double t, double b, double c, double d); // Elastic double ElasticEaseIn (double t, double b, double c, double d, double a, double p); double ElasticEaseOut (double t, double b, double c, double d, double a, double p); double ElasticEaseInOut (double t, double b, double c, double d, double a, double p); // Expo double ExpoEaseIn (double t, double b, double c, double d); double ExpoEaseOut (double t, double b, double c, double d); double ExpoEaseInOut (double t, double b, double c, double d); // Linear double LinearEaseNone (double t, double b, double c, double d); double LinearEaseIn (double t, double b, double c, double d); double LinearEaseOut (double t, double b, double c, double d); double LinearEaseInOut (double t, double b, double c, double d); // Quad double QuadEaseIn (double t, double b, double c, double d); double QuadEaseOut (double t, double b, double c, double d); double QuadEaseInOut (double t, double b, double c, double d); // Quart double QuartEaseIn (double t, double b, double c, double d); double QuartEaseOut (double t, double b, double c, double d); double QuartEaseInOut (double t, double b, double c, double d); // Quint double QuintEaseIn (double t, double b, double c, double d); double QuintEaseOut (double t, double b, double c, double d); double QuintEaseInOut (double t, double b, double c, double d); // Sine double SineEaseIn (double t, double b, double c, double d); double SineEaseOut (double t, double b, double c, double d); double SineEaseInOut (double t, double b, double c, double d); } #endif // TWEENING_H nux-4.0.8+18.10.20180623/NuxCore/Math/Vector2.h0000644000000000000000000001270713313373365014561 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef VECTOR2_H #define VECTOR2_H #include "../Exception.h" #include "Vector4.h" #include "Vector3.h" namespace nux { class Matrix2; template class Vec2; template class Vec2 { public: inline Vec2(); inline ~Vec2(); inline Vec2 (const T &, const T &); inline Vec2 (const Vec2 &); inline Vec2& operator = (const Vec2&); inline bool operator == (const Vec2&) const; inline bool operator != (const Vec2&) const; inline Vec2 operator+ (const Vec2&) const; inline Vec2 operator* (const Vec2&) const; inline Vec2 operator- (const Vec2&) const; inline Vec2 operator- () const; inline Vec2& operator*= (const Vec2&); inline Vec2& operator+= (const Vec2&); inline Vec2& operator-= (const Vec2&); inline Vec2 operator/ (const T &) const; inline Vec2 operator* (const T &) const; inline T &operator [] (int i); inline const T &operator [] (int i) const; inline T Length() const; inline T DotProduct (const Vec2 &) const; inline T CrossProduct (const Vec2 &) const; inline void Normalize(); template friend Vec2 operator* (const U &, const Vec2&); friend class Matrix2; T x, y; }; template Vec2::Vec2() { x = 0; y = 0; } template Vec2::~Vec2() { } //template //Vec2::Vec2(const T& fx) //{ // x = fx; // y = fx; //} template Vec2::Vec2 (const T &fx, const T &fy) { x = fx; y = fy; } //Vec2::Vec2(double fx, double fy) //{ // x = float(fx); // y = float(fy); //} // //Vec2::Vec2(int fx, int fy) //{ // x = float(fx); // y = float(fy); //} template Vec2::Vec2 (const Vec2& v) { x = v.x; y = v.y; } template Vec2& Vec2::operator = (const Vec2& v) { x = v.x; y = v.y; return *this; } template bool Vec2::operator == (const Vec2& v) const { if ( (x == v.x) && (y == v.y) ) { return true; } return false; } template bool Vec2::operator != (const Vec2& v) const { return ! (*this == v); } template Vec2 Vec2::operator+ (const Vec2& v) const { return Vec2 (x + v.x, y + v.y); } template Vec2 Vec2::operator* (const Vec2& v) const { return Vec2 (x * v.x, y * v.y); } template Vec2 Vec2::operator- (const Vec2& v) const { return Vec2 (x - v.x, y - v.y); } template Vec2 Vec2::operator- () const { return Vec2 (-x, -y); } template Vec2& Vec2::operator*= (const Vec2& v) { x *= v.x; y *= v.y; return *this; } template Vec2& Vec2::operator+= (const Vec2& v) { x += v.x; y += v.y; return *this; } template Vec2& Vec2::operator-= (const Vec2& v) { x -= v.x; y -= v.y; return *this; } template Vec2 Vec2::operator/ (const T &f) const { if (f == 0) { throw DivisionByZeroException(); } return Vec2 (x / f, y / f); } template Vec2 Vec2::operator* (const T &f) const { return Vec2 (x * f, y * f); } /// element access template T &Vec2::operator [] (int i) { assert (i >= 0); assert (i <= 1); return * (&x + i); } /// element access (const) template const T &Vec2::operator [] (int i) const { assert (i >= 0); assert (i <= 1); return * (&x + i); } template T Vec2::Length() const { return (T) sqrt (x * x + y * y); } template T Vec2::DotProduct (const Vec2& v) const { return x * v.x + y * v.y; } template T Vec2::CrossProduct (const Vec2& v) const { T val; val = x * v.y - y * v.x; return val; } template void Vec2::Normalize() { T l; l = Length(); if (l == 0) { throw DivisionByZeroException(); } x = x / l; y = y / l; } template T DotProduct (const Vec2& lhs, const Vec2& rhs) { return lhs.x * rhs.x + lhs.y * rhs.y; } template T CrossProduct (const Vec2& lhs, const Vec2& rhs) { return lhs.x * rhs.y - lhs.y * rhs.x; } template Vec2 operator* (const U &f, const Vec2& v) { return v * f; } typedef Vec2 Vector2; typedef Vec2 Vertex2; } #endif // VECTOR2_H nux-4.0.8+18.10.20180623/NuxCore/Math/Vector3.h0000644000000000000000000001454213313373365014561 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef VECTOR3_H #define VECTOR3_H #include "../Exception.h" #include "Vector4.h" namespace nux { template class Vec3 { public: inline Vec3(); inline Vec3 (const T &, const T &, const T &); inline ~Vec3(); inline Vec3 (const Vec3 &); inline Vec3& operator = (const Vec3&); inline bool operator == (const Vec3&) const; inline bool operator != (const Vec3&) const; inline Vec3 operator + (const Vec3&) const; inline Vec3 operator * (const Vec3&) const; inline Vec3 operator - (const Vec3&) const; inline Vec3 operator - () const; inline Vec3& operator *= (const Vec3&); inline Vec3& operator += (const Vec3&); inline Vec3& operator -= (const Vec3&); inline Vec3 operator / (const T &) const; inline Vec3 operator * (const T &) const; inline Vec3& operator /= (const T &); inline Vec3& operator *= (const T &); inline T &operator [] (int i); inline const T &operator [] (int i) const; inline T Length() const; inline T LengthSquared() const; inline T DotProduct (const Vec3&) const; inline Vec3 CrossProduct (const Vec3&) const; inline void Normalize(); template friend Vec3 operator* (const U &, const Vec3&); //friend Vec3 operator * (T, Vec3&); T x, y, z; }; template inline Vec3::Vec3() { x = 0; y = 0; z = 0; } template inline Vec3::~Vec3() { } template inline Vec3::Vec3 (const T &fx, const T &fy, const T &fz) { x = fx; y = fy; z = fz; } //Vec3::Vec3(double fx, double fy, double fz) //{ // x = T(fx); // y = T(fy); // z = T(fz); //} // //Vec3::Vec3(int fx, int fy, int fz) //{ // x = T(fx); // y = T(fy); // z = T(fz); //} template Vec3::Vec3 (const Vec3& v) { x = v.x; y = v.y; z = v.z; } template Vec3& Vec3::operator = (const Vec3& v) { x = v.x; y = v.y; z = v.z; return *this; } template bool Vec3::operator == (const Vec3& v) const { if ( (x == v.x) && (y == v.y) && (z == v.z) ) { return true; } return false; } template bool Vec3::operator != (const Vec3& v) const { return ! (*this == v); } template Vec3 Vec3::operator + (const Vec3& v) const { return Vec3 (x + v.x, y + v.y, z + v.z); } template Vec3 Vec3::operator * (const Vec3 &v) const { return Vec3 (x * v.x, y * v.y, z * v.z); } template Vec3 Vec3::operator - (const Vec3 &v) const { return Vec3 (x - v.x, y - v.y, z - v.z); } template Vec3 Vec3::operator - () const { return Vec3 (-x, -y, -z); } template Vec3& Vec3::operator *= (const Vec3 &v) { x *= v.x; y *= v.y; z *= v.z; return *this; } template Vec3& Vec3::operator += (const Vec3 &v) { x += v.x; y += v.y; z += v.z; return *this; } template Vec3& Vec3::operator -= (const Vec3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; } template Vec3 Vec3::operator / (const T &f) const { if (f == 0) { throw DivisionByZeroException(); } return Vec3 (x / f, y / f, z / f); } template Vec3 Vec3::operator * (const T &f) const { return Vec3 (x * f, y * f, z * f); } template Vec3& Vec3::operator /= (const T &f) { if (f == 0) { throw DivisionByZeroException(); } x = x / f; y = y / f; z = z / f; return *this; } template Vec3& Vec3::operator *= (const T &f) { x = x * f; y = y * f; z = z * f; return *this; } /// element access template T &Vec3::operator [] (int i) { assert (i >= 0); assert (i <= 2); return * (&x + i); } /// element access (const) template const T &Vec3::operator [] (int i) const { assert (i >= 0); assert (i <= 2); return * (&x + i); } template T Vec3::Length() const { return sqrt (x * x + y * y + z * z); } template T Vec3::LengthSquared() const { return (x * x + y * y + z * z); } template T Vec3::DotProduct (const Vec3& v) const { return x * v.x + y * v.y + z * v.z; } template Vec3 Vec3::CrossProduct (const Vec3& v) const { return Vec3 (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } template void Vec3::Normalize() { T l; l = Length(); if (l == 0) { throw DivisionByZeroException(); } x = x / l; y = y / l; z = z / l; } template T DotProduct (const Vec3& lhs, const Vec3& rhs) { T out; out = lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; return out; } template const Vec3 CrossProduct (const Vec3& lhs, const Vec3& rhs) { Vec3 out; out.x = lhs.y * rhs.z - lhs.z * rhs.y; out.y = lhs.z * rhs.x - lhs.x * rhs.z; out.z = lhs.x * rhs.y - lhs.y * rhs.x; return out; } template inline Vec3 operator * (const U &f, const Vec3& v) { return v * f; } typedef Vec3 Vector3; typedef Vec3 Vertex3; } #endif // VECTOR3_H nux-4.0.8+18.10.20180623/NuxCore/Math/Vector4.h0000644000000000000000000001327213313373365014561 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef VECTOR4_H #define VECTOR4_H namespace nux { template class Vec4 { public: inline Vec4(); inline ~Vec4(); inline Vec4 (const T &, const T &, const T &, const T &); inline Vec4 (const Vec4&); inline Vec4& operator = (const Vec4&); inline bool operator == (const Vec4&) const; inline bool operator != (const Vec4&) const; inline Vec4 operator + (const Vec4&) const; inline Vec4 operator * (const Vec4&) const; inline Vec4 operator - (const Vec4&) const; inline Vec4 operator - () const; inline Vec4& operator *= (const Vec4&); inline Vec4& operator += (const Vec4&); inline Vec4& operator -= (const Vec4&); inline Vec4 operator / (const T &) const; inline Vec4 operator * (const T &) const; inline Vec4& operator /= (const T &); inline Vec4& operator *= (const T &); inline T &operator [] (int i); inline const T &operator [] (int i) const; void divide_xyz_by_w(); template friend Vec4 operator* (const U &, const Vec4&); T x, y, z, w; }; template inline Vec4::Vec4() { x = 0; y = 0; z = 0; w = 1; } template inline Vec4::~Vec4() { } template inline Vec4::Vec4 (const T &fx, const T &fy, const T &fz, const T &fw) { x = fx; y = fy; z = fz; w = fw; } //Vec4::Vec4(double fx, double fy, double fz, double fw) //{ // x = T(fx); // y = T(fy); // z = T(fz); // w = T(fw); //} // //Vec4::Vec4(int fx, int fy, int fz, int fw) //{ // x = T(fx); // y = T(fy); // z = T(fz); // w = T(fw); //} template inline Vec4::Vec4 (const Vec4& v) { x = v.x; y = v.y; z = v.z; w = v.w; } template inline Vec4& Vec4::operator= (const Vec4& v) { x = v.x; y = v.y; z = v.z; w = v.w; return (*this); } template inline bool Vec4::operator == (const Vec4& v) const { if ( (x == v.x) && (y == v.y) && (z == v.z) && (w == v.w) ) { return true; } return false; } template inline bool Vec4::operator != (const Vec4& v) const { return ! (*this == v); } template inline Vec4 Vec4::operator+ (const Vec4& v) const { return Vec4 (x + v.x, y + v.y, z + v.z, w + v.w); } template inline Vec4 Vec4::operator* (const Vec4& v) const { return Vec4 (x * v.x, y * v.y, z * v.z, w * v.w); } template inline Vec4 Vec4::operator- (const Vec4& v) const { return Vec4 (x - v.x, y - v.y, z - v.z, w - v.w); } template inline Vec4 Vec4::operator- () const { //Do that for Matices too return Vec4 (-x, -y, -z, -w); } template inline Vec4& Vec4::operator*= (const Vec4& v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } template inline Vec4& Vec4::operator+= (const Vec4& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } template inline Vec4& Vec4::operator-= (const Vec4& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } template inline Vec4 Vec4::operator / (const T &f) const { if (f == 0) { throw DivisionByZeroException(); } return Vec4 (x / f, y / f, z / f, w / f); } template inline Vec4 Vec4::operator * (const T &f) const { return Vec4 (x * f, y * f, z * f, w * f); } template inline Vec4& Vec4::operator /= (const T &f) { if (f == 0) { throw DivisionByZeroException(); } x = x / f; y = y / f; z = z / f; w = w / f; return *this; } template inline Vec4& Vec4::operator *= (const T &f) { x = x * f; y = y * f; z = z * f; w = w * f; return *this; } template inline Vec4 operator* (T f , const Vec4& v) { return Vec4 (f * v.x, f * v.y, f * v.z, f * v.w); } /// element access template inline T &Vec4::operator [] (int i) { assert (i >= 0); assert (i <= 3); return * (&x + i); } /// element access (const) template inline const T &Vec4::operator [] (int i) const { assert (i >= 0); assert (i <= 3); return * (&x + i); } template void Vec4::divide_xyz_by_w() { if (w == 0) { throw DivisionByZeroException(); } x = x / w; y = y / w; z = z / w; } template Vec4 operator* (const U &f, const Vec4& v) { return v * f; } typedef Vec4 Vector4; } #endif // VECTOR4_H nux-4.0.8+18.10.20180623/NuxCore/Memory.cpp0000644000000000000000000000465213313373365014147 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" namespace nux { unsigned int Memcmp ( const void *Buf1, const void *Buf2, unsigned int Count ) { return std::memcmp ( Buf1, Buf2, Count ); } bool MemIsZero ( const void *V, size_t Count ) { unsigned char *B = (unsigned char *) V; while ( Count-- > 0 ) if ( *B++ != 0 ) return false; return true; } void *Memmove ( void *Dest, const void *Src, size_t Count ) { if (Count == 0) return Dest; return std::memmove ( Dest, Src, Count ); } void Memset ( void *Dest, int C, size_t Count ) { std::memset ( Dest, C, Count ); } void Memzero ( void *Dest, size_t Count ) { std::memset ( Dest, 0, Count ); } void Memcpy ( void *Dest, const void *Src, size_t Count ) { std::memcpy ( Dest, Src, Count ); } void Memswap ( void *Ptr1, void *Ptr2, size_t Size ) { void *Temp = malloc (Size); Memcpy ( Temp, Ptr1, Size ); Memcpy ( Ptr1, Ptr2, Size ); Memcpy ( Ptr2, Temp, Size ); free (Temp); } bool IsMemoryAligned (void *data, unsigned int alignment) { nuxAssertMsg ( (alignment & (alignment - 1) ) == 0, TEXT ("[IsMemAligned] Argument for memory alignment test is not a power of two: %d"), alignment); return ( ( (uintptr_t) &data) & (alignment - 1) ) == 0; } void *Malloc (size_t Count, unsigned int /* Alignment */) { return std::malloc ( Count ); } void *Realloc (void *Original, size_t Count, unsigned int /* Alignment */) { void *mem = std::realloc ( Original, Count ); if (mem == 0) { nuxCriticalMsg (TEXT ("[Realloc] realloc failed.")); return NULL; } return mem; } } nux-4.0.8+18.10.20180623/NuxCore/Memory.h0000644000000000000000000000423113313373365013605 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NMEMORY_H #define NMEMORY_H #define NUX_DEFAULT_ALIGNMENT 4 #define NUX_SAFE_DELETE(mem) if(mem) \ { \ delete(mem); \ (mem) = 0; \ } #define NUX_SAFE_DELETE_ARRAY(mem_array) if(mem_array) \ { \ delete[](mem_array); \ (mem_array) = 0; \ } namespace nux { unsigned int Memcmp ( const void *Buf1, const void *Buf2, unsigned int Count ); bool MemIsZero ( const void *V, size_t Count ); void *Memmove ( void *Dest, const void *Src, size_t Count ); void Memset ( void *Dest, int C, size_t Count ); void Memzero ( void *Dest, size_t Count ); void Memcpy ( void *Dest, const void *Src, size_t Count ); void Memswap ( void *Ptr1, void *Ptr2, size_t Size ); //! Check that the alignment is a power of two bool IsMemoryAligned (void *data, unsigned int alignment); void *Malloc (size_t Count, unsigned int Alignment = NUX_DEFAULT_ALIGNMENT); void *Realloc (void *Original, size_t Count, unsigned int Alignment = NUX_DEFAULT_ALIGNMENT); } #endif // NMEMORY_H nux-4.0.8+18.10.20180623/NuxCore/NUniqueIndex.cpp0000644000000000000000000000230313313373365015242 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "NUniqueIndex.h" namespace nux { NUX_IMPLEMENT_GLOBAL_OBJECT (UniqueIndex); NCriticalSection UniqueIndex::m_CriticalSection; void UniqueIndex::Constructor() { } void UniqueIndex::Destructor() { } unsigned long long UniqueIndex::GetUniqueIndex() { NScopeLock Scope (&m_CriticalSection); m_UniqueIndex.Increment(); return m_UniqueIndex.GetValue(); } } nux-4.0.8+18.10.20180623/NuxCore/NUniqueIndex.h0000644000000000000000000000216013313373365014710 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef UNIQUEINDEX_H #define UNIQUEINDEX_H namespace nux { class UniqueIndex { NUX_DECLARE_GLOBAL_OBJECT (UniqueIndex, GlobalSingletonInitializer); public: unsigned long long GetUniqueIndex(); private: NThreadSafeCounter m_UniqueIndex; static NCriticalSection m_CriticalSection; }; } #endif // UNIQUEINDEX_H nux-4.0.8+18.10.20180623/NuxCore/NumberConversion.cpp0000644000000000000000000000760513313373365016176 0ustar /* * Copyright 2010 Inalogic Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "NumberConversion.h" namespace nux { /** * From: http://www.strudel.org.uk/itoa/ * C++ version 0.4 char* style "itoa": * Written by Luks Chmela * Released under GPLv3. */ std::string IntegerToChar (int value, int base) { char result[65]; // check that the base if valid if (base < 2 || base > 36) { return std::string(); } char *ptr = result, *ptr1 = result, tmp_char; int tmp_value; do { tmp_value = value; value /= base; *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base) ]; } while ( value ); // Apply negative sign if (tmp_value < 0) *ptr++ = '-'; *ptr-- = '\0'; while (ptr1 < ptr) { tmp_char = *ptr; *ptr-- = *ptr1; *ptr1++ = tmp_char; } std::string str = result; return str; } double CharToDouble (const TCHAR *digit) { char *endptr = NULL; std::string str = TCHAR_TO_ANSICHAR (digit); errno = 0; double ret = std::strtod (str.c_str(), &endptr); unsigned int error = errno; if (error == ERANGE) { nuxDebugMsg ("[CharToDouble] Out for range value"); } return ret; } std::string DoubleToChar (double d) { TCHAR *buffer = new TCHAR[64]; Memset (buffer, 0, 64); SPRINTF_S (buffer, 64, "%.39f", d); std::string str = buffer; while (!str.empty() && str[str.size() - 1] == '0') { str.erase(str.end() - 1); } delete[] buffer; return str; } int CharToInteger (const TCHAR *digit) { std::string str = TCHAR_TO_ANSICHAR (digit); long long ret = std::atoi (str.c_str() ); return ret; } // convert an hexadecimal string to unsigned int unsigned int HexCharToInteger (const TCHAR *s) { int n = 0; // position in string int m = 0; // position in digit[] to shift int count; // loop index unsigned long intValue = 0; // integer value of hex string int digit[16]; // hold values to convert const TCHAR *hexStg = s; if ( (s[0] == TEXT ('0') ) && ( (s[1] == TEXT ('X') ) || (s[1] == TEXT ('x') ) ) ) { hexStg = s + 2; } while (n < 16) { if (hexStg[n] == TEXT ('\0') ) break; if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9 digit[n] = hexStg[n] & 0x0f; //convert to int else if (hexStg[n] >= TEXT ('a') && hexStg[n] <= TEXT ('f') ) //if a to f digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int else if (hexStg[n] >= TEXT ('A') && hexStg[n] <= TEXT ('F') ) //if A to F digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int else break; n++; } count = n; m = n - 1; n = 0; while (n < count) { // digit[n] is value of hex digit at position n // (m << 2) is the number of positions to shift // OR the bits into return value intValue = intValue | (digit[n] << (m << 2) ); m--; // adjust the position to set n++; // next digit to process } return (intValue); } } nux-4.0.8+18.10.20180623/NuxCore/NumberConversion.h0000644000000000000000000000375513313373365015645 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUMBERCONVERSION_H #define NUMBERCONVERSION_H namespace nux { //! Convert a TCHAR string to a double value. /*! @param digit A TCHAR string. @return A double value translated from a TCHAR string. */ double CharToDouble (const TCHAR *digit); //! Convert a double to an std::string. /*! @param d A double value. @return An std::string. */ std::string DoubleToChar (double d); //! Convert a TCHAR string to a 32 bits long value. /*! @param digit A TCHAR string. @return A 32 bits long value translated from a TCHAR string. */ int CharToInteger (const TCHAR *digit); //! Convert an integer to a tstring. /*! @param value An integer value. @param base Base of the integer representation. @return A string. */ std::string IntegerToChar (int value, int base = 10); //! Convert an string to an integer. /*! @param digit A TCHAR string. @return An integer value. */ int IntegerToChar (const TCHAR *digit); //! Convert an Hex TCHAR string to an integer value. /*! @param value A TCHAR string. @return An integer value. */ unsigned int HexCharToInteger (const TCHAR *s); } #endif // NUMBERCONVERSION_H nux-4.0.8+18.10.20180623/NuxCore/NuxCore.cpp0000644000000000000000000001046113313373365014255 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" namespace nux { // MessageBox resolves to: // MessageBoxA, if UNICODE is not defined // MessageBoxW, if UNICODE is defined // In all cases in the code, it is assumed that we have UNICODE and _UNICODE defined or not. // We have no support for cases of (UNICODE, !_UNICODE) or (!UNICODE, _UNICODE) // TCHAR resolves: // char, if _UNICODE is not defined // wchar_t, if _UNICODE is defined // Set to true to disable the popping of dialog box. The message will go to the log. const bool GNoDialog = false; /*----------------------------------------------------------------------------- Formatted printing and messages. -----------------------------------------------------------------------------*/ #if defined(NUX_OS_WINDOWS) unsigned int GetVariableArgs ( TCHAR *Dest, unsigned int Size, unsigned int Count, const TCHAR*& Fmt, va_list ArgPtr) #else unsigned int GetVariableArgs ( TCHAR *Dest, unsigned int /* Size */, unsigned int Count, const TCHAR*& Fmt, va_list ArgPtr) #endif { unsigned int Result = VSNTPRINTF_S (Dest, Size, Count, Fmt, ArgPtr); va_end (ArgPtr); return Result; } #if defined(NUX_OS_WINDOWS) unsigned int GetVariableArgsAnsi(ANSICHAR *Dest, unsigned int Size, unsigned int Count, const ANSICHAR*& Fmt, va_list ArgPtr) #else unsigned int GetVariableArgsAnsi ( ANSICHAR *Dest, unsigned int /* Size */, unsigned int Count, const ANSICHAR*& Fmt, va_list ArgPtr) #endif { unsigned int Result = VSNPRINTF_S (Dest, Size, Count, Fmt, ArgPtr); va_end (ArgPtr); return Result; } // This function can be used to print anything before the other output are initialized. void PrintOutputDebugString (const TCHAR *Format, ... ) { TCHAR TempStr[4096]; GET_VARARGS ( TempStr, 4096, NUX_ARRAY_COUNT (TempStr) - 1, Format ); #ifdef _WIN32 OutputDebugString ( TempStr ); #else printf ("%s\n", TCHAR_TO_ANSI (TempStr) ); #endif } void LogOutputAssertMessage (const ANSICHAR *File, int Line, const TCHAR *Format/*=TEXT("")*/, ... ) { TCHAR TempStr[4096]; GET_VARARGS ( TempStr, NUX_ARRAY_COUNT (TempStr), NUX_ARRAY_COUNT (TempStr) - 1, Format ); // Logged to a file... Put "\r\n" at the end of each line. if (LogOutputRedirector::Ready() ) GLogDevice.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("Assertion failed: %s\r\n [File:%s]\r\n [Line: %i]\r\n"), (const TCHAR *) TempStr, ANSI_TO_TCHAR (File), Line); } void LogOutputErrorMessage (const ANSICHAR *File, int Line, const TCHAR *Format/*=TEXT("")*/, ... ) { TCHAR TempStr[4096]; GET_VARARGS ( TempStr, NUX_ARRAY_COUNT (TempStr), NUX_ARRAY_COUNT (TempStr) - 1, Format ); if (LogOutputRedirector::Ready() ) GLogDevice.LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("Error: %s\r\n [File:%s]\r\n [Line: %d]\r\n"), (const TCHAR *) TempStr, ANSI_TO_TCHAR (File), Line); } void LogOutputDebugMessage (const TCHAR *Format/*=TEXT("")*/, ... ) { TCHAR TempStr[4096]; GET_VARARGS ( TempStr, NUX_ARRAY_COUNT (TempStr), NUX_ARRAY_COUNT (TempStr) - 1, Format ); if (LogOutputRedirector::Ready() ) GLogDevice.LogFunction (NUX_MSG_SEVERITY_NONE, TempStr); } void LogOutputSeverityMessage (int Severity, const TCHAR *Format/*=TEXT("")*/, ... ) { TCHAR TempStr[4096]; GET_VARARGS ( TempStr, NUX_ARRAY_COUNT (TempStr), NUX_ARRAY_COUNT (TempStr) - 1, Format ); if (LogOutputRedirector::Ready() ) GLogDevice.LogFunction (Severity, TempStr); } bool OutputRedirectorReady() { return LogOutputRedirector::Ready(); } } nux-4.0.8+18.10.20180623/NuxCore/NuxCore.h0000644000000000000000000011173213313373365013725 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUXCORE_H #define NUXCORE_H #include "System.h" #include // (assert.h) #include // (ctype.h) #include // (errno.h) #include // (float.h) #include // (iso646.h) #include // (limits.h) #include // (locale.h) #include // (math.h) //#include // (setjmp.h) conflict with libpng on GNU systems //#include // (signal.h) #include // (stdarg.h) #include // (stddef.h) #include // (stdio.h) #include // (stdlib.h) #include // (string.h) #include // (time.h) #include // (wchar.h) #include // (wctype.h) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // WIN32_SECURE if define for the latest version of Visual Studio starting at VS 2005. We use it for security improvement. #if (defined NUX_VISUAL_STUDIO_2005) || (defined NUX_VISUAL_STUDIO_2008) || (defined NUX_VISUAL_STUDIO_2010) #define WIN32_SECURE #endif #define NUX_STATIC_CAST(a, b) static_cast(b) #define NUX_REINTERPRET_CAST(a, b) reinterpret_cast(b) #define NUX_CONST_CAST(a, b) const_cast(b) #define NUX_DYNAMIC_CAST(a, b) dynamic_cast(b) #define NUX_INVALID_INDEX -1 #define NUX_INVALID_HANDLE -1 #define NUX_IN #define NUX_OUT #define NUX_MAKEFOURCHARTAG(ch0, ch1, ch2, ch3) \ ((DWORD)(BYTE)(ch0) | \ ((DWORD)(BYTE)(ch1) << 8) | \ ((DWORD)(BYTE)(ch2) << 16) | \ ((DWORD)(BYTE)(ch3) << 24 )) #define INLNEW new #define INLDELETE delete #define INLDELETEARRAY delete [] #define NUX_RUNTIME_ERROR(str, ...) LogOutputErrorMessage(__FILE__, __LINE__, str, ##__VA_ARGS__); #define NUX_ERROR_IF_NULL(test, str, ...) if((test) == 0) LogOutputErrorMessage(__FILE__, __LINE__, str, ##__VA_ARGS__); #define NUX_ERROR_IF_TRUE(test, str, ...) if(test) LogOutputErrorMessage(__FILE__, __LINE__, str, ##__VA_ARGS__); #define NUX_ERROR_IF_FALSE(test, str, ...) if(!(test)) LogOutputErrorMessage(__FILE__, __LINE__, str, ##__VA_ARGS__); #define NUX_RETURN_IF_NULL(test) if((test) == 0) return; #define NUX_RETURN_IF_NOTNULL(test) if((test) != 0) return; #define NUX_RETURN_IF_TRUE(test) if(test) return; #define NUX_RETURN_IF_FALSE(test) if(!(test)) return; #define NUX_RETURN_IF_FAIL(test) if(!(test)) return; #define NUX_RETURN_VALUE_IF_NULL(test, value) if((test) == 0) return value; #define NUX_RETURN_VALUE_IF_NOTNULL(test, value) if((test) != 0) return value; #define NUX_RETURN_VALUE_IF_TRUE(test, value) if(test) return value; #define NUX_RETURN_VALUE_IF_FALSE(test, value) if(!(test)) return value; // Structure Alignment #if defined(NUX_MICROSOFT_COMPILER) #define NUX_DATA_ALIGN(declaration, alignment) __declspec(align(alignment)) declaration #elif defined (NUX_GNUCPP_COMPILER) #define NUX_DATA_ALIGN(declaration, alignment) declaration __attribute__ ((aligned (alignment))) #endif // Sizeof is a compile time function. So array must be totally defined if sizeof is used on it. // The number of elements in array must be a constant at compile time. // Example: int array[10] is valid. #define NUX_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) // Compiler specific include. #if defined(NUX_OS_WINDOWS) && defined (NUX_MICROSOFT_COMPILER) #include "SystemWindows.h" #elif defined (NUX_OS_LINUX) && defined (NUX_GNUCPP_COMPILER) #include "SystemGNU.h" #elif defined (NUX_OS_MACOSX) && defined (NUX_GNUCPP_COMPILER) #error Unknown Compiler #else #error Unknown Compiler #endif namespace nux { // Variable arguments. unsigned int GetVariableArgs (TCHAR *Dest, unsigned int Size, unsigned int Count, const TCHAR*& Fmt, va_list ArgPtr); unsigned int GetVariableArgsAnsi (ANSICHAR *Dest, unsigned int Size, unsigned int Count, const ANSICHAR*& Fmt, va_list ArgPtr); #define GET_VARARGS(msg, size, len, fmt) \ { \ va_list arg_list; \ va_start(arg_list,fmt); \ VSNTPRINTF_S( msg, size, len, fmt, arg_list ); \ va_end( arg_list ); \ } #define GET_VARARGS_ANSI(msg, size, len, fmt) \ { \ va_list arg_list; \ va_start(arg_list,fmt); \ VSNPRINTF_S( msg, size, len, fmt, arg_list ); \ va_end( arg_list ); \ } #define GET_VARARGS_RESULT(msg, size, len, fmt, result) \ { \ va_list arg_list; \ va_start(arg_list, fmt); \ result = GetVariableArgs(msg, size, len, fmt, arg_list); \ va_end(arg_list); \ } ////////////////////////////////////////////////////////////////////////// // Check macros for assertions. // ////////////////////////////////////////////////////////////////////////// typedef enum { NUX_MSG_SEVERITY_CRITICAL = 0, NUX_MSG_SEVERITY_ALERT = 1, NUX_MSG_SEVERITY_WARNING = 2, NUX_MSG_SEVERITY_INFO = 3, NUX_MSG_SEVERITY_NONE = 4, } MessageSeverity; #define nuxOkMsg(str, ...) { nux::LogOutputSeverityMessage(nux::NUX_MSG_SEVERITY_INFO, str, ##__VA_ARGS__);} #define nuxWarningMsg(str, ...) { nux::LogOutputSeverityMessage(nux::NUX_MSG_SEVERITY_WARNING, str, ##__VA_ARGS__);} #define nuxAlertMsg(str, ...) { nux::LogOutputSeverityMessage(nux::NUX_MSG_SEVERITY_ALERT, str, ##__VA_ARGS__);} #define nuxCriticalMsg(str, ...) { nux::LogOutputSeverityMessage(nux::NUX_MSG_SEVERITY_CRITICAL, str, ##__VA_ARGS__);} #ifdef NUX_ENABLE_ASSERT_MACROS #define nuxAssert(expr) { if(!(expr)) nuxFailAssert(TEXT(#expr)); } // Expression is always evaluated no matter if NUX_ENABLE_ASSERT_MACROS is enabled. nuxFailAssert is called if enabled. #define nuxVerifyExpr(expr) { if(!(expr)) nuxFailAssert(TEXT(#expr)); } #define DEBUGTRACE(str, ...) nuxDebugMsg(str, ##__VA_ARGS__) #ifdef NUX_VARIADIC_MACROS_SUPPORT #define nuxFailAssert(str, ...) { if(nuxIsDebuggerPresent()){nux::LogOutputAssertMessage(__FILE__, __LINE__, str, ##__VA_ARGS__);} inlDebugBreak();} #define nuxError(str, ...) { if(nuxIsDebuggerPresent()){nux::LogOutputErrorMessage(__FILE__, __LINE__, str, ##__VA_ARGS__);} inlDebugBreak();} #define nuxDebugMsg(str, ...) { if(nuxIsDebuggerPresent()) nux::LogOutputDebugMessage(str, ##__VA_ARGS__);} #define nuxAssertMsg(expr, a, ...) { if(!(expr)) nuxFailAssert( TEXT(#expr) TEXT(" : ") a, ##__VA_ARGS__); } #define nuxVerifyExprMsg(expr, a, ...) { if(!(expr)) nuxFailAssert( TEXT(#expr) TEXT(" : ") a, ##__VA_ARGS__); } // Expression is always evaluated. nuxFailAssert is called if enabled. #else #define nuxFailAssert(a,b,c,d,e,f,g,h,i,j,k,l) { if(nuxIsDebuggerPresent()){nux::LogOutputAssertMessage(__FILE__,__LINE__,VARG(a),VARG(b),VARG(c),VARG(d),VARG(e),VARG(f),VARG(g),VARG(h),VARG(i),VARG(j),VARG(k),VARG(l));} inlDebugBreak();} #define nuxError(a,b,c,d,e,f,g,h,i,j,k,l) { if(nuxIsDebuggerPresent()) {nux::LogOutputErrorMessage(__FILE__,__LINE__,VARG(a),VARG(b),VARG(c),VARG(d),VARG(e),VARG(f),VARG(g),VARG(h),VARG(i),VARG(j),VARG(k),VARG(l));} inlDebugBreak();} #define nuxAssertMsg(expr,a,b,c,d,e,f,g,h,i,j,k,l) { if(!(expr)) { nuxFailAssert( TEXT(#expr) TEXT(" : ") a,b,c,d,e,f,g,h,i,j,k,l); } } #define nuxVerifyExprMsg(expr,a,b,c,d,e,f,g,h,i,j,k,l) { if(!(expr)) { nuxFailAssert( TEXT(#expr) TEXT(" : ") a,b,c,d,e,f,g,h,i,j,k,l); } } // Expression is always evaluated. nuxFailAssert is called if enabled. #define nuxDebugMsg(a,b,c,d,e,f,g,h,i,j,k,l) { if(nuxIsDebuggerPresent() && LogOutputRedirector::Ready()) GLogDevice.LogFunction(a,b,c,d,e,f,g,h,i,j,k,l); } #endif // Break if codepaths should never be reached. #define nuxAssertNoEntry() { nuxFailAssert( TEXT("This section of code should not be executed.") ); } // Break if codepaths should not be executed more than once. #define nuxAssertNoReEntry() \ { \ static bool s_inlRuntimeHasBeenHere##__LINE__ = false; \ nuxAssertMsg( !s_inlRuntimeHasBeenHere##__LINE__, TEXT("This section of code has already been called.") ); \ s_inlRuntimeHasBeenHere##__LINE__ = true; \ } class NRecursionScopeCounter { public: NRecursionScopeCounter (WORD &InCounter) : Counter ( InCounter ) { ++Counter; } ~NRecursionScopeCounter() { --Counter; } private: WORD &Counter; }; // Break if codepaths should never be called recursively. #define nuxAssertNoRecursion() \ static WORD RecursionCounter##__LINE__ = 0; \ nuxAssertMsg( RecursionCounter##__LINE__ == 0, TEXT("This section of code was entered recursively.") ); \ const NRecursionScopeCounter ScopeMarker##__LINE__( RecursionCounter##__LINE__ ) // Compile time assertion. Break if the assertion fails. // @param expr Must be evaluated at compile time. #define nuxAssertAtCompileTime(expr) typedef BYTE CompileTimeCheckType##__LINE__[(expr) ? 1 : -1] #else #ifdef NUX_MICROSOFT_COMPILER #define nuxAssert(expr) NUX_NOOP #define nuxVerifyExpr(expr) { if(!(expr)) {} } #define nuxDebugMsg(a, ...) NUX_NOOP #ifdef NUX_VARIADIC_MACROS_SUPPORT #define nuxAssertMsg(expr, a, ...) NUX_NOOP #define nuxVerifyExprMsg(expr, a, ...) { if(!(expr)) {} } #define nuxError(a, ...) NUX_NOOP #else #define nuxAssertMsg(expr,a,b,c,d,e,f,g,h,i,j,k,l) NUX_NOOP #define nuxVerifyExprMsg(expr,a,b,c,d,e,f,g,h,i,j,k,l) { if(!(expr)) {} } #define nuxError(a,b,c,d,e,f,g,h,i,j,k,l) NUX_NOOP #endif #define nuxAssertNoEntry() NUX_NOOP #define nuxAssertNoReentry() NUX_NOOP #define nuxAssertNoRecursion() NUX_NOOP #define nuxAssertAtCompileTime(expr) NUX_NOOP #else #define nuxDebugMsg(a, ...) #define nuxError(a, ...) {} #define nuxAssert(expr) {} #define nuxVerifyExpr(expr) { if(!(expr)) {} } #define nuxAssertMsg(expr,msg, ...) {} #define nuxVerifyExprMsg(expr, a, ...) { if(!(expr)) {} } #define nuxAssertNoEntry() {} #define nuxAssertNoReentry() {} #define nuxAssertNoRecursion() {} #define nuxAssertAtCompileTime(expr) {} #endif #endif ////////////////////////////////////////////////////////////////////////// // String conversion classes // ////////////////////////////////////////////////////////////////////////// #ifndef _UNICODE #define CALL_OS_TCHAR_FUNCTION(funcW,funcA) funcA #define TCHAR_TO_ANSI(str) str #define ANSI_TO_TCHAR(str) (const TCHAR*)((const ANSICHAR*)str) #define UTF8ToTCHAR(str) str #define TCHARToUTF8(str) str #define UTF16ToTCHAR(str) (const char*)NUTF8(str) #define TCHARToUTF16(str) (const wchar_t*)NUTF16(str) #else #define CALL_OS_TCHAR_FUNCTION(funcW,funcA) funcW /*! NOTE: Theses macros creates objects with very short lifespan. They are meant to be used as parameters to functions. Do not assign a variable to the content of the converted string as the object will go out of scope and the string released. Usage: SomeApi(TCHAR_TO_ANSI(SomeUnicodeString)); const char* SomePointer = TCHAR_TO_ANSI(SomeUnicodeString); <--- Bad!!! */ #define TCHAR_TO_ANSI(str) (ANSICHAR*)typedef NCharacterConversion((const TCHAR*)str) #define ANSI_TO_TCHAR(str) (TCHAR*)NCharacterConversion((const ANSICHAR*)str) #define UTF8ToTCHAR(str) (const wchar_t*)NUTF16(str) #define TCHARToUTF8(str) (const char*)NUTF8(str) #define UTF16ToTCHAR(str) str #define TCHARToUTF16(str) str #endif #define inlUTF16ToUTF8(s) (const char*)nux::NUTF8(s) #define inlUTF8ToUTF16(s) (const wchar_t*)nux::NUTF16(s) #define ANSICHAR_TO_UNICHAR(str) (UNICHAR*) nux::NCharacterConversion ((const ANSICHAR*)str) #define UNICHAR_TO_ANSICHAR(str) (ANSICHAR*) nux::NCharacterConversion ((const UNICHAR*)str) #define ANSICHAR_TO_TCHAR(str) (UNICHAR*) nux::NCharacterConversion ((const ANSICHAR*)str) #define TCHAR_TO_ANSICHAR(str) (ANSICHAR*) nux::NCharacterConversion ((const TCHAR*)str) #define TCHAR_TO_UNICHAR(str) (UNICHAR*) nux::NCharacterConversion ((const TCHAR*)str) #define NUX_WIN32_LINE_TERMINATOR TEXT("\r\n") #define NUX_UNIX_LINE_TERMINATOR TEXT("\n") #define NUX_MACOSX_LINE_TERMINATOR TEXT("\n") #if defined(NUX_OS_WINDOWS) #define NUX_LINE_TERMINATOR NUX_WIN32_LINE_TERMINATOR #elif defined(NUX_OS_LINUX) || defined(NUX_OS_MACOSX) #define NUX_LINE_TERMINATOR NUX_UNIX_LINE_TERMINATOR #endif #if defined(NUX_OS_WINDOWS) #define NUX_PATH_SEPARATOR_STRING NUX_BACKSLASH_STRING #define NUX_PATH_SEPARATOR_CHAR NUX_BACKSLASH_CHAR #elif defined(NUX_OS_LINUX) || defined(NUX_OS_MACOSX) #define NUX_PATH_SEPARATOR_STRING NUX_SLASH_STRING #define NUX_PATH_SEPARATOR_CHAR NUX_SLASH_CHAR #endif #define NUX_BACKSLASH_CHAR TEXT('\\') #define NUX_BACKSLASH_STRING TEXT("\\") #define NUX_SLASH_CHAR TEXT('/') #define NUX_SLASH_STRING TEXT("/") #define NUX_MAX_FILEPATH_SIZE 1024 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if (defined _WIN32) && (defined WIN32_SECURE) #define WCSNCPY_S(strDest, numberOfElements, strSource, count) wcsncpy_s (strDest, numberOfElements, strSource, count) #define STRNCPY_S(strDest, numberOfElements, strSource, count) _tcsncpy_s(strDest, numberOfElements, strSource, count) #define STRCPY_S(strDest, numberOfElements, strSource) _tcscpy_s(strDest, numberOfElements, strSource) #define STRCAT_S(strDest, numberOfElements, strSource) _tcscat_s(strDest, numberOfElements, strSource) #define VSNPRINTF_S(strDest, numberOfElements, Count, format, VA_Arg_List) vsnprintf_s(strDest, numberOfElements, Count, format, VA_Arg_List) #define VSNTPRINTF_S(strDest, numberOfElements, Count, format, VA_Arg_List) _vsntprintf_s(strDest, numberOfElements, Count, format, VA_Arg_List) #define SPRINTF_S(strDest, numberOfElements, format, ...) _stprintf_s(strDest, numberOfElements, format, ##__VA_ARGS__) #define SNPRINTF_S(strDest, numberOfElements, Count, format, ...) _sntprintf_s(strDest, numberOfElements, Count, format, ##__VA_ARGS__) #define STRDATE_S(strDest, numberOfElements) _tstrdate_s(strDest, numberOfElements) #define STRTIME_S(strDest, numberOfElements) _tstrtime_s(strDest, numberOfElements) #define FOPEN_S(file, filename, mode) _tfopen_s(file, filename, mode) #define STRLEN_S(str, numberOfElements) _tcsnlen(str, numberOfElements) #define SPLITPATH_S(path, Drive, DriveNumElements, Dir, DirNumElements, Filename, FileNumElements, Extension, ExtNumElements) _tsplitpath_s(path, Drive, DriveNumElements, Dir, DirNumElements, Filename, FileNumElements, Extension, ExtNumElements) #define MAKEPATH_S(path, numberOfElements, Drive, Dir, Filename, Extension) _tmakepath_s(path, numberOfElements, Drive, Dir, Filename, Extension) #define SSCANF_S(buffer, format, ...) _stscanf_s(buffer, format, ##__VA_ARGS__) #define SNSCANF_S(input, length, format, ...) _sntscanf_s(input, length, format, ##__VA_ARGS__) #else #define WCSNCPY_S(strDest, numberOfElements, strSource, count) wcsncpy (strDest, strSource, count) // The weird numElmt - numElmt in the expansion is to stop the compiler from complaining about unused params. #define STRNCPY_S(strDest, numElmt, strSource, count) _tcsncpy(strDest, strSource, count + numElmt - numElmt) #define STRCPY_S(strDest, numberOfElements, strSource) _tcscpy(strDest, strSource) #define STRCAT_S(strDest, numberOfElements, strSource) _tcscat(strDest, strSource) #define VSNPRINTF_S(strDest, numberOfElements, Count, format, VA_Arg_List) vsnprintf(strDest, Count, format, VA_Arg_List) #define VSNTPRINTF_S(strDest, numberOfElements, Count, format, VA_Arg_List) _vsntprintf(strDest, Count, format, VA_Arg_List) #define SPRINTF_S(strDest, numberOfElements, format, ...) _stprintf(strDest, format, ##__VA_ARGS__) #define SNPRINTF_S(strDest, numberOfElements, Count, format, ...) _sntprintf(strDest, Count, format, ##__VA_ARGS__) #define STRDATE_S(strDest, numberOfElements) _tstrdate(strDest) #define STRTIME_S(strDest, numberOfElements) _tstrtime(strDest) #define FOPEN_S(file, filename, mode) (file = _tfopen(filename, mode)) #define STRLEN_S(str, numberOfElements) _tcslen(str) #define SPLITPATH_S(path, Drive, DriveNumElements, Dir, DirNumElements, Filename, FileNumElements, Extension, ExtNumElements) _tsplitpath(path, Drive, Dir, Filename, Extension) #define MAKEPATH_S(path, numberOfElements, Drive, Dir, Filename, Extension) _makepath(path, Drive, Dir, Filename, Extension) #define SSCANF_S(buffer, format, ...) _stscanf(buffer, format, ##__VA_ARGS__) #define SNSCANF_S(input, length, format, ...) _sntscanf(input, length, format, ##__VA_ARGS__) #endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// extern const bool GNoDialog; // Set to true to disable the popping of dialog box. The message will go to the log. #ifdef NUX_VISUAL_STUDIO_2003 //Visual Studio C++ 2003 doesn't support it, but there is a workaround: #pragma warning(disable: 4002) // Warning: too many actual parameters for macro 'ident' #pragma warning(disable: 4003) // Warning: not enough actual parameters for macro 'ident' template inline const T &VARG ( const T &t ) { return t; } inline const TCHAR *VARG( ) { return TEXT (""); } #endif #ifdef _UNICODE #define tstring std::wstring #define tostream std::wostream #define tistream std::wistream #define tiostream std::wiostream #define tofstream std::wofstream #define tfstream std::wfstream #else #define tstring std::string #define tostream std::ostream #define tistream std::istream #define tiostream std::iostream #define tofstream std::ofstream #define tfstream std::fstream #endif // // UTF-16 is the primary encoding mechanism used by Microsoft Windows 2000, Windows 2000 Server, Windows XP and Windows 2003 Server. // // Unicode Byte Order Mark (BOM) // enum {UNICODE_UTF32_BE = 0x0000FEFF }; // enum {UNICODE_UTF32_LE = 0xFFFE0000 }; // enum {UNICODE_UTF16_BE = 0xFEFF }; // enum {UNICODE_UTF16_LE = 0xFFFE }; // enum {UNICODE_UTF8 = 0xEFBBBF }; const BYTE NUX_UTF32_BE[] = {0x04 /*size*/, 0x00, 0x00, 0xFE, 0xFF }; const BYTE NUX_UTF32_LE[] = {0x04 /*size*/, 0xFF, 0xFE, 0x00, 0x00 }; const BYTE NUX_UTF16_BE[] = {0x02 /*size*/, 0xFE, 0xFF }; const BYTE NUX_UTF16_LE[] = {0x02 /*size*/, 0xFF, 0xFE }; const BYTE NUX_UTF8[] = {0x03 /*size*/, 0xEF, 0xBB, 0xBF }; // enum {UNICODE_BOM = 0xfeff }; class LogOutputDevice; class NFileManager; #define GNullDevice NUX_GLOBAL_OBJECT_INSTANCE(nux::NullOutput) #define GLogDevice NUX_GLOBAL_OBJECT_INSTANCE(nux::LogOutputRedirector) #if (defined NUX_OS_WINDOWS) #define GFileManager NUX_GLOBAL_OBJECT_INSTANCE(nux::NFileManagerWindows) #elif (defined NUX_OS_LINUX) #define GFileManager NUX_GLOBAL_OBJECT_INSTANCE(nux::NFileManagerGNU) #endif // Define architecture specific asm statements for hardware breakpoint #if defined(NUX_GNUC_COMPILER) #if (defined __i386__) || (defined __x86_64__) #define ARCH_HARDWARE_BREAK std::abort () #elif defined (__arm__) || (defined __ppc__) #define ARCH_HARDWARE_BREAK do {} while(0) #else #define ARCH_HARDWARE_BREAK do {} while(0) #endif #endif // Breaks into the debugger. Forces a GPF in non-debug builds. #if (defined NUX_DEBUG) && (defined NUX_MICROSOFT_COMPILER) #define nuxIsDebuggerPresent() IsDebuggerPresent() #define inlDebugBreak() ( IsDebuggerPresent() ? (DebugBreak(),1) : 1 ) #elif (defined _WIN32) #define nuxIsDebuggerPresent() IsDebuggerPresent() #define inlDebugBreak() std::abort () #elif (defined NUX_DEBUG) && (defined NUX_GNUCPP_COMPILER) #define nuxIsDebuggerPresent() 1 #define inlDebugBreak() ARCH_HARDWARE_BREAK #else #define nuxIsDebuggerPresent() 0 #define inlDebugBreak() #endif #if defined(NUX_MICROSOFT_COMPILER) #define NUX_HARDWARE_BREAK {__debugbreak();} #define NUX_BREAK_ASM_INT3 {__debugbreak();} #elif defined(NUX_GNUC_COMPILER) #define NUX_HARDWARE_BREAK ARCH_HARDWARE_BREAK #define NUX_BREAK_ASM_INT3 ARCH_HARDWARE_BREAK #else #define NUX_HARDWARE_BREAK #define NUX_BREAK_ASM_INT3 #endif ////////////////////////////////////////////////////////////////////////// // Variadic function prototypes. ////////////////////////////////////////////////////////////////////////// #define VARARG_EXTRA(A) A, #define VARARG_NONE #define VARARG_PURE =0 #if _MSC_VER static inline DWORD VAType (DWORD dw) { return dw; } static inline unsigned char VAType (unsigned char b) { return b; } static inline unsigned int VAType (unsigned int ui) { return ui; } static inline int VAType (int i) { return i; } static inline unsigned long long VAType (unsigned long long qw) { return qw; // possible conflict with size_t when compiling in 64 bits } static inline long long VAType (long long sqw) { return sqw; } static inline double VAType (double d) { return d; } static inline TCHAR VAType (TCHAR c) { return c; } static inline ANSICHAR *VAType (ANSICHAR *s) { return s; } static inline UNICHAR *VAType (UNICHAR *s) { return s; } template T *VAType (T *p) { return p; } template const T *VAType (const T *p) { return p; } // Declaration of prototypes with lots of arguments // If(the function return nothing) // { // Return = {} // StaticFuncRet = void // } // else // { // Return = return // StaticFuncRet = type0 // FuncRet = type1 // } // // If this is a pure virtual function then PURE is equal to: ==0 // ExtraParamDecl is declaration for additional parameters: VARARG_EXTRA(TCHAR* Dest) VARARG_EXTRA(INT Size) VARARG_EXTRA(INT Count) // ExtraParam is the parameters presented in ExtraParamDecl: VARARG_EXTRA(Dest) VARARG_EXTRA(Size) VARARG_EXTRA(Count) #define VARARG_DECL( FuncRet, StaticFuncRet, Return, FuncName, Pure, FmtType, ExtraParamDecl, ExtraParam ) \ FuncRet FuncName##__VA(ExtraParamDecl FmtType Fmt, ... ) Pure; \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt) {Return FuncName##__VA(ExtraParam (Fmt));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1) {T1 v1=VAType(V1);Return FuncName##__VA(ExtraParam (Fmt),(v1));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2) {T1 v1=VAType(V1);T2 v2=VAType(V2);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11,T12 V12) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);T12 v12=VAType(V12);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11),(v12));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11,T12 V12,T13 V13) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);T12 v12=VAType(V12);T13 v13=VAType(V13);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11),(v12),(v13));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11,T12 V12,T13 V13,T14 V14) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);T12 v12=VAType(V12);T13 v13=VAType(V13);T14 v14=VAType(V14);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11),(v12),(v13),(v14));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11,T12 V12,T13 V13,T14 V14,T15 V15) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);T12 v12=VAType(V12);T13 v13=VAType(V13);T14 v14=VAType(V14);T15 v15=VAType(V15);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11),(v12),(v13),(v14),(v15));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11,T12 V12,T13 V13,T14 V14,T15 V15,T16 V16) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);T12 v12=VAType(V12);T13 v13=VAType(V13);T14 v14=VAType(V14);T15 v15=VAType(V15);T16 v16=VAType(V16);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11),(v12),(v13),(v14),(v15),(v16));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11,T12 V12,T13 V13,T14 V14,T15 V15,T16 V16,T17 V17) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);T12 v12=VAType(V12);T13 v13=VAType(V13);T14 v14=VAType(V14);T15 v15=VAType(V15);T16 v16=VAType(V16);T17 v17=VAType(V17);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11),(v12),(v13),(v14),(v15),(v16),(v17));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11,T12 V12,T13 V13,T14 V14,T15 V15,T16 V16,T17 V17,T18 V18) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);T12 v12=VAType(V12);T13 v13=VAType(V13);T14 v14=VAType(V14);T15 v15=VAType(V15);T16 v16=VAType(V16);T17 v17=VAType(V17);T18 v18=VAType(V18);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11),(v12),(v13),(v14),(v15),(v16),(v17),(v18));} \ template \ StaticFuncRet FuncName(ExtraParamDecl FmtType Fmt,T1 V1,T2 V2,T3 V3,T4 V4,T5 V5,T6 V6,T7 V7,T8 V8,T9 V9,T10 V10,T11 V11,T12 V12,T13 V13,T14 V14,T15 V15,T16 V16,T17 V17,T18 V18,T19 V19) {T1 v1=VAType(V1);T2 v2=VAType(V2);T3 v3=VAType(V3);T4 v4=VAType(V4);T5 v5=VAType(V5);T6 v6=VAType(V6);T7 v7=VAType(V7);T8 v8=VAType(V8);T9 v9=VAType(V9);T10 v10=VAType(V10);T11 v11=VAType(V11);T12 v12=VAType(V12);T13 v13=VAType(V13);T14 v14=VAType(V14);T15 v15=VAType(V15);T16 v16=VAType(V16);T17 v17=VAType(V17);T18 v18=VAType(V18);T19 v19=VAType(V19);Return FuncName##__VA(ExtraParam (Fmt),(v1),(v2),(v3),(v4),(v5),(v6),(v7),(v8),(v9),(v10),(v11),(v12),(v13),(v14),(v15),(v16),(v17),(v18),(v19));} #define VARARG_BODY( FuncRet, FuncName, FmtType, ExtraParamDecl ) \ FuncRet FuncName##__VA( ExtraParamDecl FmtType Fmt, ... ) #else // !_MSC_VER #define VARARG_DECL( FuncRet, StaticFuncRet, Return, FuncName, Pure, FmtType, ExtraParamDecl, ExtraParam ) \ FuncRet FuncName( ExtraParamDecl FmtType Fmt, ... ) Pure #define VARARG_BODY( FuncRet, FuncName, FmtType, ExtraParamDecl ) \ FuncRet FuncName( ExtraParamDecl FmtType Fmt, ... ) #endif // _MSC_VER //! Log an outpout message to console or visual studio output. To be used while the log redirector is not initialized. void PrintOutputDebugString (const TCHAR *Format, ...); //! Log an assertion failure to registered output. void LogOutputAssertMessage (const ANSICHAR *File, int Line, const TCHAR *Format = TEXT (""), ...); //! Log an error message to registered output. void LogOutputErrorMessage (const ANSICHAR *File, int Line, const TCHAR *Format = TEXT (""), ...); //! Log and output message with a severity factor to registered output. Print colored output in XTerm. void LogOutputDebugMessage (const TCHAR *Format, ...); //! Log and output message with a severity factor to registered output. Print colored output in XTerm. void LogOutputSeverityMessage (int Severity, const TCHAR *Format/*=TEXT("")*/, ...); // Returns true is the output redirector is ready bool OutputRedirectorReady(); enum EFileWrite { FILEWRITE_NOFAIL = 0x01, FILEWRITE_NOREPLACEEXISTING = 0x02, FILEWRITE_EVENIFREADONLY = 0x04, FILEWRITE_UNBUFFERED = 0x08, FILEWRITE_APPEND = 0x10, FILEWRITE_ALLOWREAD = 0x20, }; enum ECopyResult { COPY_OK = 0x00, COPY_MISCFAIL = 0x01, COPY_READFAIL = 0x02, COPY_WRITEFAIL = 0x03, COPY_CANCELED = 0x06, }; enum NUX_STATUS { NUX_OK, NUX_ERROR, NUX_FILENOTFOUND, NUX_COPYFILE_ERROR, NUX_DELETEFILE_ERROR, }; } #include "Macros.h" #include "Memory.h" #include "Character/NUni.h" #if defined(NUX_OS_WINDOWS) #include "Character/NUnicode.h" #elif defined(NUX_OS_LINUX) #include "Character/NUnicode.h" #endif #include "Template.h" #include "NumberConversion.h" #include "TextString.h" #if defined(NUX_OS_WINDOWS) #include "ThreadWin.h" #elif defined(NUX_OS_LINUX) #include "ThreadGNU.h" #endif /*#include "Memory/NMemoryAllocatorInterface.h" #include "Memory/NDefaultMemoryAllocator.h" #include "Memory/NMemoryHook.h" #include "Memory/NMemoryAllocator.h" */ #include "NUniqueIndex.h" //#include "GlobalInitializer.h" #ifdef NUX_OS_WINDOWS #include "Win32Dialogs/NWin32MessageBox.h" #endif #include "Character/NTChar.h" #include "TimeFunctions.h" #include "Platform.h" #include "FileManager/NSerializer.h" #include "Process.h" #include "OutputDevice.h" #include "FileManager/NFileManagerGeneric.h" #ifdef NUX_OS_WINDOWS #include "FileManager/NFileManagerWindows.h" #elif defined NUX_OS_LINUX #include "FileManager/NFileManagerGNU.h" #endif #include "FileIO.h" #include "ObjectType.h" #include "FileName.h" #include "Color.h" #include "Colors.h" #include "Object.h" #ifdef NUX_OS_WINDOWS #include "Win32Dialogs/NWin32CustomDialog.h" #include "Win32Dialogs/NWin32Clipboard.h" #endif #include "GlobalInitializer.h" #endif // NUXCORE_H nux-4.0.8+18.10.20180623/NuxCore/Object.cpp0000644000000000000000000002444113313373365014103 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2010-2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "Object.h" #include "ObjectPtr.h" #include "Logger.h" namespace nux { DECLARE_LOGGER(logger, "nux.core.object"); NUX_IMPLEMENT_ROOT_OBJECT_TYPE (Trackable); NUX_IMPLEMENT_OBJECT_TYPE (Object); NUX_IMPLEMENT_GLOBAL_OBJECT (ObjectStats); void ObjectStats::Constructor() { _total_allocated_size= 0; _number_of_objects = 0; } void ObjectStats::Destructor() { #if defined(NUX_DEBUG) if (_number_of_objects) { std::cerr << "[ObjectStats::Destructor] " << _number_of_objects << " undeleted objects.\n\t" << _allocation_list.size() << " items in allocation list.\n"; } int index = 0; #if defined(NUX_OS_WINDOWS) // Visual Studio does not support range based for loops. for (AllocationList::iterator ptr = _allocation_list.begin(); ptr != _allocation_list.end(); ++ptr) { Object* obj = static_cast(*ptr); std::stringstream sout; sout << "\t" << ++index << " Undeleted object: Type " << obj->GetTypeName() << ", " << obj->GetAllocationLocation() << "\n"; OutputDebugString(sout.str().c_str()); std::cerr << sout.str().c_str(); } #else for (auto ptr : _allocation_list) { Object* obj = static_cast(ptr); std::cerr << "\t" << ++index << " Undeleted object: Type " << obj->GetTypeName() << ", " << obj->GetAllocationLocation() << "\n"; } #endif #endif } std::new_handler Trackable::_new_current_handler = 0; Trackable::Trackable() { _heap_allocated = -1; _owns_the_reference = false; } Trackable::~Trackable() { } bool Trackable::Reference() { return false; } bool Trackable::UnReference() { return false; } bool Trackable::SinkReference() { return false; } bool Trackable::Dispose() { return false; } bool Trackable::OwnsTheReference() { return _owns_the_reference; } void Trackable::SetOwnedReference (bool b) { if (_owns_the_reference == true) { LOG_DEBUG(logger) << "Do not change the ownership if is already set to true!" << "\n"; return; } _owns_the_reference = b; } std::new_handler Trackable::set_new_handler (std::new_handler handler) { std::new_handler old_handler = _new_current_handler; _new_current_handler = handler; return old_handler; } void* Trackable::operator new (size_t size) { // Set the new_handler for this call std::new_handler global_handler = std::set_new_handler (_new_current_handler); // If allocation fails _new_current_handler is called, if specified, // otherwise the global new_handler is called. void *ptr; try { ptr = ::operator new (size); GObjectStats._allocation_list.push_front (ptr); NUX_STATIC_CAST (Trackable *, ptr)->_size_of_this_object = size; GObjectStats._total_allocated_size += size; ++GObjectStats._number_of_objects; } catch (std::bad_alloc &) { std::set_new_handler (global_handler); throw; } // Reset gloabal new_handler std::set_new_handler (global_handler); return ptr; } #if (__GNUC__ < 4 && __GNUC_MINOR__ < 4) void *Trackable::operator new (size_t size, void *ptr) { return ::operator new (size, ptr); } #endif void Trackable::operator delete (void *ptr) { ObjectStats::AllocationList::iterator i = std::find (GObjectStats._allocation_list.begin(), GObjectStats._allocation_list.end(), ptr); if (i != GObjectStats._allocation_list.end() ) { GObjectStats._total_allocated_size -= NUX_STATIC_CAST (Trackable *, ptr)->_size_of_this_object; --GObjectStats._number_of_objects; GObjectStats._allocation_list.erase (i); ::operator delete (ptr); } #ifdef NUX_DEBUG else { // Complain quite loudly as this should never happen. LOG_ERROR(logger) << "Attempting to delete a pointer we can't find."; } #endif } bool Trackable::IsHeapAllocated() { if (_heap_allocated == -1) { _heap_allocated = IsDynamic(); } return _heap_allocated; } bool Trackable::IsDynamic() const { // Get pointer to beginning of the memory occupied by this. const void *ptr = dynamic_cast (this); // Search for ptr in allocation_list #if defined(NUX_OS_WINDOWS) && !defined(NUX_VISUAL_STUDIO_2010) std::list::iterator i = std::find(GObjectStats._allocation_list.begin(), GObjectStats._allocation_list.end(), ptr); #else auto i = std::find(GObjectStats._allocation_list.begin(), GObjectStats._allocation_list.end(), ptr); #endif return i != GObjectStats._allocation_list.end(); } int Trackable::GetObjectSize () { return _size_of_this_object; } ////////////////////////////////////////////////////////////////////// Object::Object(bool OwnTheReference, NUX_FILE_LINE_DECL) : reference_count_(new NThreadSafeCounter()) , objectptr_count_(new NThreadSafeCounter()) { reference_count_->Set(1); SetOwnedReference(OwnTheReference); #ifdef NUX_DEBUG std::ostringstream sout; if (__Nux_FileName__) sout << __Nux_FileName__; else sout << ""; sout << ":" << __Nux_LineNumber__; allocation_location_ = sout.str(); #endif } Object::~Object() { if (IsHeapAllocated()) { // If the object has properly been UnReference, it should have gone // through Destroy(). if that is the case then _reference_count should // be NULL or its value (returned by GetValue ()) should be equal to 0; // We can use this to detect when delete is called directly on an // object. if (reference_count_->GetValue() > 0) { LOG_WARN(logger) << "Invalid object destruction, still has " << reference_count_->GetValue() << " references." << "\nObject allocated at: " << GetAllocationLocation() << "\n"; } } delete reference_count_; delete objectptr_count_; } bool Object::Reference() { if (!IsHeapAllocated()) { LOG_WARN(logger) << "Trying to reference an object that was not heap allocated." << "\nObject allocated at: " << GetAllocationLocation() << "\n"; return false; } if (!OwnsTheReference()) { SetOwnedReference(true); // The ref count remains at 1. Exit the method. return true; } reference_count_->Increment(); return true; } bool Object::UnReference() { if (!IsHeapAllocated()) { LOG_WARN(logger) << "Trying to un-reference an object that was not heap allocated." << "\nObject allocated at: " << GetAllocationLocation() << "\n"; return false; } if (objectptr_count_->GetValue() == reference_count_->GetValue()) { // There are ObjectPtr's hosting this object. Release all of them to // destroy this object. This prevent from calling UnReference () many // times and destroying the object when there are ObjectPtr's hosting // it. This method should not be called directly in that case. LOG_WARN(logger) << "There are ObjectPtr hosting this object. " << "Release all of them to destroy this object. " << "\nObject allocated at: " << GetAllocationLocation() << "\n"; #if defined(NUX_OS_LINUX) LOG_WARN(logger) << "UnReference occuring here: \n" << logging::Backtrace(); #endif return false; } reference_count_->Decrement(); if (reference_count_->GetValue() == 0) { Destroy(); return true; } return false; } bool Object::SinkReference() { return Reference(); } bool Object::Dispose() { // The intent of the Dispose call is to destroy objects with a float // reference (reference count is equal to 1 and the '_owns_the_reference' // flag is set to false). In Nux, only widgets object can have a floating // reference. And widgets are only visible if added to the widget tree. // When an object with a floating reference is added to the widget tree, // it becomes "owned'. It looses it floating reference status but it still // has a reference count number of 1. In practice, since widgets must be // added to the widget tree, there should never be a need to call Dispose // (except in a few cases). // Dispose() was designed to only destroy objects with floating // references, while UnReference() destroys objects that are "owned". // That is now relaxed. Dispose() calls UnReference(). return UnReference(); } void Object::Destroy() { #ifdef NUX_DEBUG static int delete_depth = 0; ++delete_depth; std::string obj_type = GetTypeName(); LOG_TRACE(logger) << "Depth: " << delete_depth << ", about to delete " << obj_type << " allocated at " << GetAllocationLocation(); #endif // Weak smart pointers will clear their pointers when they get this signal. object_destroyed.emit(this); delete this; #ifdef NUX_DEBUG LOG_TRACE(logger) << "Depth: " << delete_depth << ", delete successful for " << obj_type; --delete_depth; #endif } int Object::GetReferenceCount() const { return reference_count_->GetValue(); } int Object::ObjectPtrCount() const { return objectptr_count_->GetValue(); } std::string Object::GetAllocationLocation() const { return allocation_location_; } std::string Object::GetTypeName() const { return Type().name; } } nux-4.0.8+18.10.20180623/NuxCore/Object.h0000644000000000000000000002011213313373365013537 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2010-2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUXCORE_OBJECT_H #define NUXCORE_OBJECT_H #include #include #include #include #include "ObjectType.h" #include "Property.h" #include "PropertyTraits.h" #define NUX_FILE_LINE_PROTO const char* __Nux_FileName__=__FILE__, int __Nux_LineNumber__ = __LINE__ #define NUX_FILE_LINE_DECL const char* __Nux_FileName__, int __Nux_LineNumber__ #define NUX_FILE_LINE_PARAM __Nux_FileName__, __Nux_LineNumber__ #define NUX_TRACKER_LOCATION __FILE__, __LINE__ #define OnDestroyed object_destroyed namespace nux { template class ObjectPtr; template class ObjectWeakPtr; class ObjectStats { NUX_DECLARE_GLOBAL_OBJECT (ObjectStats, GlobalSingletonInitializer); public: typedef std::list AllocationList; AllocationList _allocation_list; int _total_allocated_size; //! Total allocated memory size in bytes. int _number_of_objects; //! Number of allocated objects; }; #define GObjectStats NUX_GLOBAL_OBJECT_INSTANCE(nux::ObjectStats) //! Base class of heap allocated objects. /*! Trackable does not implement reference counting. It only defines the API. It is up to the class that inherit from Trackable to implement the reference counting. */ class Trackable: public nux::Introspectable, public sigc::trackable, public boost::noncopyable { public: NUX_DECLARE_ROOT_OBJECT_TYPE (Trackable); //! Test if object reference is owned. /* @return True if the object reference is owned. */ bool OwnsTheReference(); //! Test if object was allocated dynamically. /* @return True if the object was allocated dynamically. */ bool IsHeapAllocated(); //! Test if object was allocated dynamically. /* @return True if the object was allocated dynamically. */ bool IsDynamic() const; //! Increase the reference count. /* Widget are typically created and added to containers. It is decided that when widgets are created, they should have a floating reference and their reference count is set to 1. { Button* button = new Button(); // button ref_cout = 1, floating = true; container->AddButton(button); // button has a floating reference; when container call button->ref() the ref count // of button remains at 1 but the floating reference is set to false. From now on, // calling button->ref will always increase the ref count (since button no longer has a floating reference). } It is best to pair calls to ref() with unref() when it comes to widgets. So if a widget was not added to a container and so it still has a floating reference, then call Dispose(). Dispose does some sanity check; it verifies that: ref_count == 1 floating == true If these conditions are verified, dispose will cause the object to be destroyed. Calling unref() on an object that has a floating reference will trigger a warning/error in order to invite the developer. The developer can either ref the object first before calling unref or simply not create the widget since it does not appear to have been used. During development it often happen that one forget to dispose an object with a floating reference. Assuming that all functions that receive a reference counted object properly call ref on the object and that the compiler can detect unused variables, then the developer should have a way to detect reference counted objects that are not owned. It is up to the developer to properly handle these objects. @return True if the object has been referenced. */ virtual bool Reference(); //! Decrease the reference count. /*! @return True if the object has been destroyed */ virtual bool UnReference(); //! Mark the object as owned. /*! If this object is not owned, calling SinkReference() as the same effect as calling Reference(). @return True if the object was not owned previously */ virtual bool SinkReference(); //! Destroy and object that has a floating reference. /*! @return True if the object has been destroyed */ virtual bool Dispose(); //! Return the size of allocated for this object. /*! @return The size allocated for this object. */ virtual int GetObjectSize (); static std::new_handler set_new_handler (std::new_handler handler); static void *operator new (size_t size); #if (__GNUC__ < 4 && __GNUC_MINOR__ < 4) static void *operator new (size_t size, void *ptr); #endif static void operator delete (void *ptr); protected: Trackable(); virtual ~Trackable() = 0; void SetOwnedReference (bool b); int _heap_allocated; private: static std::new_handler _new_current_handler; bool _owns_the_reference; int _size_of_this_object; }; //! The base class of Nux objects. class Object: public Trackable { public: NUX_DECLARE_OBJECT_TYPE (BaseObject, Trackable); //! Constructor Object (bool OwnTheReference = true, NUX_FILE_LINE_PROTO); //! Increase reference count. /*! @return True if the object has successfully referenced. */ bool Reference(); //! Decrease reference count. /*! @return True if the object reference count has reached 0 and the object has been destroyed. */ bool UnReference(); //! Mark the object as owned. /*! If this object is not owned, calling SinkReference() as the same effect as calling Reference(). @return True if the object was not owned previously */ virtual bool SinkReference(); //! Destroy and object that has a floating reference. /*! @return True is the object has been destroyed */ virtual bool Dispose(); //! Get the reference count of this object. /*! @return The reference count of this object. */ int GetReferenceCount() const; //! Get the number of ObjectPtr holding this object. /*! @return The number of ObjectPtr holding this object. */ int ObjectPtrCount() const; //! Signal emitted immediately before the object is destroyed. sigc::signal object_destroyed; std::string GetAllocationLocation() const; std::string GetTypeName() const; protected: //! Private destructor. /* Private destructor. Ensure that Object cannot be created on the stack (only on the heap), but objects that inherits from Object can stil be created on the stack or on the heap. (MEC++ item27) */ virtual ~Object(); private: //! Destroy the object. void Destroy(); Object (const Object &); Object &operator = (const Object &); NThreadSafeCounter* reference_count_; //!< Number of ObjectPtr hosting the object. NThreadSafeCounter* objectptr_count_; std::string allocation_location_; std::string allocation_stacktrace_; template friend class ObjectPtr; template friend class ObjectWeakPtr; friend class ObjectStats; }; } #endif // NUXOBJECT_H nux-4.0.8+18.10.20180623/NuxCore/ObjectPtr.h0000644000000000000000000004575413313373365014250 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2010-2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NUXCORE_OBJECTPTR_H #define NUXCORE_OBJECTPTR_H #include #include namespace nux { template class ObjectWeakPtr; template class ObjectPtr; //! A smart pointer class. Implemented as an intrusive smart pointer. template class ObjectPtr { public: //! Constructor ObjectPtr() : ptr_(NULL) { } //! Copy constructor ObjectPtr(ObjectPtr const& other) : ptr_(other.ptr_) { if (ptr_) { ptr_->objectptr_count_->Increment(); ptr_->Reference(); } } //! Copy constructor /*! This method takes advantage of the nux type information using the virtual Type function. @param other Parameter with a type derived from T. */ template ObjectPtr(ObjectPtr const& other) : ptr_(NULL) { if (other.ptr_ && other.ptr_->Type().IsDerivedFromType(T::StaticObjectType)) { ptr_ = static_cast(other.ptr_); ptr_->objectptr_count_->Increment(); ptr_->Reference(); } } //! Construction with a base pointer of type T. /*! @param ptr Start maintaining a reference count of the passed pointer. @param WarnMissuse If True, then ObjectPtr test is ptr is owned or not. If ptr is not owned and WarnMissuse is True, then Print a warning message. This is a debug feature to detect cases such as "ObjectPtr(ObjectA) myobject(ptr);", because the calling code will no longer have a reference on ptr. */ explicit ObjectPtr(T *ptr, bool WarnMissuse = false) : ptr_(NULL) { if (ptr) { if (WarnMissuse && (!ptr->OwnsTheReference())) { nuxDebugMsg (TEXT ("[ObjectPtr::ObjectPtr] Warning: Constructing a smart pointer from an object with a floating reference.") ); } ptr_ = ptr; ptr_->objectptr_count_->Increment(); ptr_->Reference(); } } //! Construction with a base pointer of type O that inherits from type T. /*! @param ptr Start maintaining a reference count of the passed pointer. @param WarnMissuse If True, then ObjectPtr test is ptr is owned or not. If ptr is not owned and WarnMissuse is True, then Print a warning message. This is a debug feature to detect cases such as "ObjectPtr(ObjectA) myobject(ptr);", because the calling code will no longer have a reference on ptr. */ template explicit ObjectPtr(O *ptr, bool WarnMissuse = false) : ptr_(NULL) { if (ptr && ptr->Type().IsDerivedFromType(T::StaticObjectType)) { if (WarnMissuse && (!ptr->OwnsTheReference())) { nuxDebugMsg (TEXT ("[ObjectPtr::ObjectPtr] Warning: Constructing a smart pointer from an object with a floating reference.") ); } ptr_ = static_cast(ptr); ptr_->objectptr_count_->Increment(); ptr_->Reference(); } } //! Take ownership of ptr. void Adopt(T* ptr) { bool was_owned = false; if (ptr) { // If 'was_owned' is false, then ptr has a floating reference status. The next line: // ObjectPtr temp(ptr); // will not increase its reference count. It will only make the object "Owned". was_owned = ptr->OwnsTheReference(); } // If 'was_owned' is true then the next line increases the reference count of ptr. // Otherwise, ptr just becomes "Owned" (it looses it floating reference status). ObjectPtr temp(ptr); Swap(temp); // Now we want to release the reference that was added on construction, // but keep the smart pointer count. if (ptr_ && was_owned) { // ptr was already owned. Reduce the reference count that was added by the call to // ObjectPtr temp(ptr); ptr_->UnReference(); } } //! Assignment of a smart pointer of type T. /*! @param other Smart pointer of type T. */ ObjectPtr& operator=(T* ptr) { ObjectPtr temp(ptr); Swap(temp); return *this; } //! Assignment of a smart pointer of type T. /*! @param other Smart pointer of type T. */ ObjectPtr& operator=(ObjectPtr const& other) { ObjectPtr temp(other); Swap(temp); return *this; } //! Assignment of a smart pointer of type O that inherits from type T. /*! @param other Smart pointer of type O. */ template ObjectPtr& operator=(ObjectPtr const& other) { ObjectPtr temp(other); Swap(temp); return *this; } ~ObjectPtr() { ReleaseReference(); } T& operator*() const { nuxAssert(ptr_ != 0); return *ptr_; } T* operator->() const { nuxAssert(ptr_ != 0); return ptr_; } //! Return the stored pointer. /*! Caller of this function should Reference the pointer if they intend to keep it. @param Return the stored pointer. */ T* GetPointer () const { return ptr_; } //! Swap the content of 2 smart pointers. /*! @param other Smart pointer to swap with. */ void Swap (ObjectPtr& other) { std::swap(ptr_, other.ptr_); } operator bool() const { return bool(ptr_); } //! Test validity of the smart pointer. /*! Return True if the internal pointer is not null. */ bool operator() () const { return bool(ptr_); } //! Test validity of the smart pointer. /*! Return True if the internal pointer is null. */ bool IsNull() const { return !IsValid(); } //! Test validity of the smart pointer. /*! Return True if the internal pointer is not null. */ bool IsValid() const { return (ptr_ != NULL); } bool operator < (T *ptr) const { return (ptr_ < ptr); } bool operator > (T *ptr) const { return (ptr_ > ptr); } bool operator < (ObjectPtr other) const { return (ptr_ < other.ptr_); } bool operator > (ObjectPtr other) const { return (ptr_ > other.ptr_); } bool operator == (T *ptr) const { return ptr_ == ptr; } template bool operator != (U other) const { return !(*this == other); } template bool operator == (U* ptr) const { if (ptr && (!ptr->Type().IsDerivedFromType(T::StaticObjectType))) return false; return ptr_ == static_cast(ptr); } template bool operator == (ObjectPtr const& other) const { if (other.ptr_ && (!other.ptr_->Type().IsDerivedFromType (T::StaticObjectType) ) ) return false; return ptr_ == static_cast(other.ptr_); } template bool operator == (ObjectWeakPtr const& other) const { if (other.ptr_ && (!other.ptr_->Type().IsDerivedFromType (T::StaticObjectType) ) ) return false; return ptr_ == static_cast(other.ptr_); } //! Release the hosted pointer from this object. /*! Release the hosted pointer from this object. After this call, all the members are null. @return True if the hosted object was destroyed. */ bool Release() { return ReleaseReference(); } private: bool ReleaseReference() { if (!ptr_) { return false; } // Decrease the number of strong reference on the hosted pointer. ptr_->objectptr_count_->Decrement(); bool destroyed = ptr_->UnReference(); ptr_ = NULL; return destroyed; } T* ptr_; template friend class ObjectPtr; template friend class ObjectWeakPtr; }; //! A weak smart pointer class. Implemented as an intrusive smart pointer. /*! A weak smart pointer is built from a smart pointer or another weak smart pointer. It increments and decrements the total reference count of an pointer. Even is the original pointer is destroyed, weak smart pointers still point to the RefCounts pointers of the original pointer and can use it to check if the pointer is still valid or not. */ template class ObjectWeakPtr { public: //! Constructor ObjectWeakPtr() : ptr_(NULL) { } //! Construction with a base pointer of type T. /*! @param ptr Start maintaining a reference count of the passed pointer. @param WarnMissuse If True, then ObjectPtr test is ptr is owned or not. If ptr is not owned and WarnMissuse is True, then Print a warning message. This is a debug feature to detect cases such as "ObjectPtr(ObjectA) myobject(ptr);", because the calling code will no longer have a reference on ptr. */ explicit ObjectWeakPtr(T* ptr) : ptr_(ptr) { ConnectListener(); } //! Construction with a base pointer of type O that inherits from type T. /*! @param ptr Start maintaining a reference count of the passed pointer. @param WarnMissuse If True, then ObjectPtr test is ptr is owned or not. If ptr is not owned and WarnMissuse is True, then Print a warning message. This is a debug feature to detect cases such as "ObjectPtr(ObjectA) myobject(ptr);", because the calling code will no longer have a reference on ptr. */ template explicit ObjectWeakPtr(O* ptr, bool /* WarnMissuse */ = false) : ptr_(NULL) { if (ptr && (ptr->Type().IsDerivedFromType(T::StaticObjectType))) { ptr_ = static_cast(ptr); ConnectListener(); } } //! Copy constructor /*! @param other Parameter with type T. */ ObjectWeakPtr(ObjectWeakPtr const& other) : ptr_(other.ptr_) { ConnectListener(); } //! Copy constructor /*! @param other Parameter with a type derived from T. */ template ObjectWeakPtr(const ObjectWeakPtr& other) : ptr_(NULL) { if (other.ptr_ && (other.ptr_->Type().IsDerivedFromType(T::StaticObjectType))) { ptr_ = static_cast(other.ptr_); ConnectListener(); } } //! Construction from a smart pointer of type O that inherits from type T. /*! @param other Maintains a weak smart pointer reference to this parameter. */ template ObjectWeakPtr(const ObjectPtr &other) : ptr_(NULL) { if (other.ptr_ && (other.ptr_->Type().IsDerivedFromType(T::StaticObjectType))) { ptr_ = static_cast(other.ptr_); ConnectListener(); } } //! Assignment of a weak smart pointer of type T. /*! @param other Weak smart pointer of type T. */ ObjectWeakPtr& operator = (ObjectWeakPtr const& other) { Disconnect(); ptr_ = other.ptr_; ConnectListener(); return *this; } // Warning: We are not sure that other.ptr_ is valid. // Warning: Cannot call other.ptr_->Type().IsDerivedFromType (T::StaticObjectType) //! Assignment of a weak smart pointer of Type O that inherits from type T. /*! @param other Weak smart pointer of type O. */ template ObjectWeakPtr &operator = (const ObjectWeakPtr& other) { Disconnect(); if (other.ptr_ && other.ptr_->Type().IsDerivedFromType(T::StaticObjectType)) { ptr_ = static_cast(other.ptr_); ConnectListener(); } return *this; } //! Assignment of a smart pointer of Type O that inherits from type T. /*! @param other Maintains a weak smart pointer reference to this parameter. */ template ObjectWeakPtr &operator = (const ObjectPtr& other) { Disconnect(); if (other.ptr_ && other.ptr_->Type().IsDerivedFromType(T::StaticObjectType)) { ptr_ = static_cast(other.ptr_); ConnectListener(); } return *this; } //! Construction with a base pointer of type T. /*! @param ptr Start maintaining a reference count of the passed pointer. @param WarnMissuse If True, then ObjectPtr test is ptr is owned or not. If ptr is not owned and WarnMissuse is True, then Print a warning message. This is a debug feature to detect cases such as "ObjectPtr(ObjectA) myobject(ptr);", because the calling code will no longer have a reference on ptr. */ ObjectWeakPtr& operator = (T* ptr) { Disconnect(); ptr_ = ptr; ConnectListener(); return *this; } template ObjectWeakPtr &operator = (O* ptr) { Disconnect(); if (ptr && ptr->Type().IsDerivedFromType(T::StaticObjectType)) { ptr_ = static_cast(ptr); ConnectListener(); } return *this; } ~ObjectWeakPtr() { Disconnect(); } T& operator* () const { nuxAssert (ptr_ != 0); return *(const_cast(ptr_)); } T* operator -> () const { nuxAssert (ptr_ != 0); return const_cast(ptr_); } bool operator < (T *ptr) const { return (ptr_ < ptr); } bool operator > (T *ptr) const { return (ptr_ > ptr); } bool operator < (ObjectWeakPtr other) const { return (ptr_ < other.ptr_); } bool operator > (ObjectWeakPtr other) const { return (ptr_ > other.ptr_); } template bool operator != (U other) const { return !(*this == other); } bool operator == (T *ptr) const { return ptr_ == ptr; } template bool operator == (U *ptr) const { if (ptr && (!ptr->Type().IsDerivedFromType (T::StaticObjectType) ) ) return false; return ptr_ == static_cast(ptr); } /*! @other A weak pointer @return True is this weak pointer host the same pointer as the weak pointer passed as parameter. */ template bool operator == (const ObjectWeakPtr& other) const { if (other.ptr_ && (!other.ptr_->Type().IsDerivedFromType (T::StaticObjectType) ) ) return false; return ptr_ == static_cast(other.ptr_); } /*! @other An object pointer @return True is this weak pointer host the same pointer as the object pointer passed as parameter. */ template bool operator == (const ObjectPtr& other) const { if (other.ptr_ && (!other.ptr_->Type().IsDerivedFromType (T::StaticObjectType) ) ) return false; return ptr_ == static_cast(other.ptr_); } //! Return true is the hosted pointer is not null or has not been destroyed. /*! @return True if the internal pointer is not null. */ bool operator() () const { return bool(ptr_); } //! Return true is the hosted pointer is not null or has not been destroyed. /*! @return True if the internal pointer is not null or has not been destroyed. */ bool IsValid() const { return (ptr_ != NULL); } //! Return true is the hosted pointer is null or has been destroyed. /*! @return True if the internal pointer is null or has been destroyed. */ bool IsNull() const { return !IsValid(); } //! Release the hosted pointer from this object. /*! Release the hosted pointer from this object. After this call, the following members are null: _reference_count _weak_reference_count ptr_ This call decreases the count of weak reference before setting _weak_reference_count to null. @return True this was the last weak reference on the hosted object. */ bool Release() { Disconnect(); ptr_ = NULL; return false; } //! Return the stored pointer. /*! Caller of this function should Reference the pointer if they intend to keep it. @param Return the stored pointer. */ T* GetPointer () const { return ptr_; } private: void Disconnect() { if (destroy_listener_.connected()) destroy_listener_.disconnect(); } void ConnectListener() { if (ptr_) { auto slot = sigc::mem_fun(this, &ObjectWeakPtr::TargetDestroyed); destroy_listener_ = ptr_->object_destroyed.connect(slot); } } void TargetDestroyed(Object* /* ptr */) { ptr_ = NULL; // rese the connetion too destroy_listener_ = sigc::connection(); } T* ptr_; sigc::connection destroy_listener_; template friend class ObjectWeakPtr; template friend bool operator == (U *, const ObjectWeakPtr& a); template friend bool operator != (U *, const ObjectWeakPtr& a); template friend ObjectWeakPtr staticCast (const ObjectWeakPtr& from); template friend ObjectWeakPtr constCast (const ObjectWeakPtr& from); template friend ObjectWeakPtr dynamicCast (const ObjectWeakPtr& from); template friend ObjectWeakPtr checkedCast (const ObjectWeakPtr& from); template friend ObjectWeakPtr queryCast (const ObjectWeakPtr& from); }; /////////////////////////////////////////////////////// // globals template inline bool operator == (T *ptr, const ObjectPtr& a) { return a.ptr_ == ptr; } template inline bool operator != (T *ptr, const ObjectPtr& a) { return a.ptr_ != ptr; } template inline bool operator == (T *ptr, const ObjectWeakPtr& a) { return a.ptr_ == ptr; } template inline bool operator != (T *ptr, const ObjectWeakPtr& a) { return a.ptr_ != ptr; } } #endif nux-4.0.8+18.10.20180623/NuxCore/ObjectType.cpp0000644000000000000000000000162213313373365014741 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "ObjectType.h" namespace nux { const NObjectType NObjectType::Null_Type("NULL", 0); } nux-4.0.8+18.10.20180623/NuxCore/ObjectType.h0000644000000000000000000000755413313373365014420 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NOBJECTTYPE_H #define NOBJECTTYPE_H #include namespace nux { // TODO: write a nice is_instance (and is_derived_instance) //template //bool is_instance(T const& struct NObjectType { const char* name; NObjectType* super; static const NObjectType Null_Type; NObjectType() : name("Null_Type") , super(NULL) { } NObjectType(const char* type_name, NObjectType* super_type) : name(type_name) , super(super_type) { } //! Return true is this has the same type as the argument type. inline bool operator == (const NObjectType &Type) const { return IsObjectType (Type); } //! Return true is this has is of a different type than the argument type. inline bool operator != (const NObjectType &Type) const { return !IsObjectType (Type); } //! Return true is this has the same type as the argument type. inline bool IsObjectType (const NObjectType &Type) const { return this == &Type; } //! Return true if this has the same type as the argument type or is derived from it. inline bool IsDerivedFromType (const NObjectType &Type) const { const NObjectType *current_type = this; while (current_type) { if (current_type == &Type) return true; current_type = current_type->super; } return false; } inline unsigned int SubClassDepth() const { const NObjectType* current_type = this; unsigned int depth = 0; while (current_type) { depth++; current_type = current_type->super; } return depth; } }; #define NUX_DECLARE_OBJECT_TYPE(TypeName, SuperType) \ public: \ typedef SuperType SuperObject; \ static ::nux::NObjectType StaticObjectType; \ public: \ virtual ::nux::NObjectType& Type() const { return StaticObjectType; } \ ::nux::NObjectType& GetTypeInfo() const { return StaticObjectType; } #define NUX_IMPLEMENT_OBJECT_TYPE(TypeName) \ ::nux::NObjectType TypeName::StaticObjectType(#TypeName, &TypeName::SuperObject::StaticObjectType); #define NUX_DECLARE_ROOT_OBJECT_TYPE(TypeName) \ public: \ typedef ::nux::NObjectType SuperObject; \ static ::nux::NObjectType StaticObjectType; \ public: \ virtual ::nux::NObjectType& Type() const { return StaticObjectType; } \ ::nux::NObjectType& GetTypeInfo() const { return StaticObjectType; } #define NUX_IMPLEMENT_ROOT_OBJECT_TYPE(TypeName) \ ::nux::NObjectType TypeName::StaticObjectType(#TypeName, 0); } // namespace nux #endif // NOBJECTTYPE_H nux-4.0.8+18.10.20180623/NuxCore/OutputDevice.cpp0000644000000000000000000003105313313373365015312 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "Parsing.h" #include #include namespace nux { #if defined(NUX_DEBUG) //! Create a backup copy of a file if it exist. The copy feature a timestamp in the filename. /*! @param Filename The name of the file to check. */ static void CreateBackupCopy (const TCHAR *Filename) { if (GFileManager.FileSize (Filename) > 0) { // Create string with system time to create a unique filename. unsigned int Year, Month, Day, Hour, Min, Sec, MSec; GetLocalTime (Year, Month, Day, Hour, Min, Sec, MSec); std::string Name, Extension; std::string file = Filename; size_t pos = file.rfind('.'); if (pos != std::string::npos) { Name = file.substr(0, pos); Extension = file.substr(pos + 1); } else { Name = file; } std::ostringstream s; s << std::setfill('0') << Name << "-backup-" << Year << "." << std::setw(2) << Month << "." << std::setw(2) << Day << "." << std::setw(2) << Hour << "." << std::setw(2) << Min << "." << std::setw(2) << Sec; if (Extension.size() ) { s << "." << Extension; } std::string BackupFilename = s.str(); GFileManager.Copy (BackupFilename.c_str(), Filename, true, true, NULL); } } #endif NUX_IMPLEMENT_GLOBAL_OBJECT (NullOutput); NUX_IMPLEMENT_GLOBAL_OBJECT (LogOutputRedirector); NUX_IMPLEMENT_GLOBAL_OBJECT (LogFileOutput); NUX_IMPLEMENT_GLOBAL_OBJECT (VisualOutputConsole) NUX_IMPLEMENT_GLOBAL_OBJECT (PrintfOutputConsole) LogOutputDevice::LogOutputDevice() : _object_destroyed (false) { _enabled = true; } LogOutputDevice::~LogOutputDevice() { _object_destroyed = true; } void LogOutputDevice::Shutdown() { _object_destroyed = true; } void LogOutputDevice::Flush() { } void LogOutputDevice::Enable () { _enabled = true; } void LogOutputDevice::Disable () { _enabled = false; } VARARG_BODY ( void /*FuncRet*/, LogOutputDevice::LogFunction/*FuncName*/, const TCHAR* /*FmtType*/, VARARG_EXTRA (int severity) /*ExtraDecl*/) { if (_object_destroyed) return; int BufferSize = 1024; int NewBufferSize = 0; TCHAR *Buffer = NULL; int Result = -1; while (Result == -1) { if (NewBufferSize) { TCHAR *temp = new TCHAR[NewBufferSize]; Memcpy (temp, Buffer, BufferSize); NUX_SAFE_DELETE_ARRAY (Buffer); Buffer = temp; BufferSize = NewBufferSize; } else { Buffer = new TCHAR[BufferSize]; } GET_VARARGS_RESULT (Buffer, BufferSize, BufferSize - 1, Fmt, Result); if (Result == -1) NewBufferSize = 2 * BufferSize; }; Buffer[Result] = 0; Serialize (Buffer, TEXT ("Nux"), severity); NUX_SAFE_DELETE_ARRAY (Buffer); } void LogFileOutput::Constructor() { m_LogSerializer = NULL; m_Opened = false; m_Closed = false; #if defined(NUX_DEBUG) // The Editor requires a fully qualified directory to not end up putting the log in various directories. m_Filename = GetProgramDirectory(); if ( (m_Filename[m_Filename.size()-1] != NUX_SLASH_CHAR) || (m_Filename[m_Filename.size()-1] != NUX_BACKSLASH_CHAR) ) m_Filename += (const TCHAR *) NUX_PATH_SEPARATOR_STRING; m_Filename += GetLogDirectory(); // Create the directory tree where the Logs file will be stored. GFileManager.MakeDirectory (m_Filename.c_str(), 1); m_Filename += (const TCHAR *) NUX_PATH_SEPARATOR_STRING; m_Filename += TEXT ("nux"); m_Filename += TEXT (".log"); // if the file already exists, create a backup as we are going to overwrite it if (!m_Opened) { CreateBackupCopy (m_Filename.c_str() ); } // Open log file. m_LogSerializer = GFileManager.CreateFileWriter (m_Filename.c_str(), NSerializer::Read | NSerializer::Write | NSerializer::OverWriteReadOnly | (m_Opened ? NSerializer::Append : 0) ); if (m_LogSerializer) { m_Opened = true; #if UNICODE && !NUX_LOG_FILE_ANSI m_LogSerializer->Serialize ( (void *) &NUX_UTF16_BE[1], NUX_UTF16_BE[0] /*size*/ ); #endif LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("Log file open, %s"), GetFormattedLocalTime().c_str()); } else { m_Closed = true; } #endif } void LogFileOutput::Destructor() { Shutdown(); } /*! Closes output device and cleans up. This can't happen in the destructor as we have to call "delete" which cannot be done for static/ global objects. */ void LogFileOutput::Shutdown() { if (m_LogSerializer) { LogFunction (NUX_MSG_SEVERITY_NONE, TEXT ("Log file closed, %s"), GetFormattedLocalTime().c_str()); Flush(); delete m_LogSerializer; m_LogSerializer = NULL; } m_Closed = true; } void LogFileOutput::Flush() { if (m_LogSerializer) { m_LogSerializer->Flush(); } } //! Write data to the output log file. /*! @param log_data Text to log. @param log_prefix Prefix for the text */ void LogFileOutput::Serialize (const TCHAR *log_data, const TCHAR *log_prefix, int /* severity */) { if (!_enabled) return; if (_object_destroyed) return; if (m_LogSerializer) { #if UNICODE && NUX_LOG_FILE_ANSI ANSICHAR ACh[1024]; INT DataOffset = 0; INT i; while (log_data[DataOffset]) { for (i = 0; i < NUX_ARRAY_COUNT (ACh) && log_data[DataOffset]; i++, DataOffset++) { ACh[i] = ConvertTCHARToAnsiChar (log_data[DataOffset]); } // serialize chunks of 1024 characters m_LogSerializer->Serialize (ACh, i); }; for (i = 0; NUX_LINE_TERMINATOR[i]; i++) { ACh[i] = NUX_LINE_TERMINATOR[i]; } m_LogSerializer->Serialize (ACh, i); #else std::string Raw = std::string (log_prefix) + std::string (TEXT (": ") ) + std::string (log_data) + std::string (NUX_LINE_TERMINATOR); SerializeRaw (Raw.c_str() ); #endif } } void LogFileOutput::SerializeRaw (const TCHAR *log_data) { unsigned int s = (unsigned int) StringLength (log_data) * sizeof (TCHAR); m_LogSerializer->Serialize (NUX_CONST_CAST (TCHAR *, log_data), s); } void LogOutputRedirector::Constructor() { } void LogOutputRedirector::Destructor() { Shutdown(); } void LogOutputRedirector::AddOutputDevice (LogOutputDevice *OutputDevice) { if ( OutputDevice ) { if (std::find (OutputDevices.begin(), OutputDevices.end(), OutputDevice) != OutputDevices.end() ) return; OutputDevices.push_back (OutputDevice); } } void LogOutputRedirector::RemoveOutputDevice (LogOutputDevice *OutputDevice) { std::vector::iterator it = std::find (OutputDevices.begin(), OutputDevices.end(), OutputDevice); OutputDevices.erase (it); } bool LogOutputRedirector::IsRedirectingTo (LogOutputDevice *OutputDevice) { if (std::find (OutputDevices.begin(), OutputDevices.end(), OutputDevice) != OutputDevices.end() ) return true; return false; } void LogOutputRedirector::Serialize (const TCHAR *log_data, const TCHAR *log_prefix, int severity) { if (!_enabled) return; for (unsigned int OutputDeviceIndex = 0; OutputDeviceIndex < OutputDevices.size(); OutputDeviceIndex++) { OutputDevices[OutputDeviceIndex]->Serialize (log_data, log_prefix, severity); } } void LogOutputRedirector::Flush() { for (unsigned int OutputDeviceIndex = 0; OutputDeviceIndex < OutputDevices.size(); OutputDeviceIndex++) { OutputDevices[OutputDeviceIndex]->Flush(); } } void LogOutputRedirector::Shutdown() { for (unsigned int OutputDeviceIndex = 0; OutputDeviceIndex < OutputDevices.size(); OutputDeviceIndex++) { OutputDevices[OutputDeviceIndex]->Shutdown(); // do not delete the output device. This is the responsibility of the owwners. } OutputDevices.clear(); } void VisualOutputConsole::Constructor() {} void VisualOutputConsole::Destructor() {} //! Write data to visual studio output debug console. /*! @param log_data Text to log. @param log_prefix Prefix for the text */ #if defined(NUX_OS_WINDOWS) void VisualOutputConsole::Serialize(const TCHAR* text, const TCHAR* log_prefix, int severity) { if (!_enabled) return; TCHAR Temp[4096]; Snprintf (Temp, 4096, 4096 - 1, TEXT ("%s: %s%s"), log_prefix, text, NUX_LINE_TERMINATOR); OutputDebugString (Temp); } #else void VisualOutputConsole::Serialize(const TCHAR * /* text */, const TCHAR * /* log_prefix */, int /* severity */) { } #endif void PrintfOutputConsole::Constructor() {} void PrintfOutputConsole::Destructor() {} //! Write data to visual studio output debug console. /*! @param log_data Text to log. @param log_prefix Prefix for the text */ void PrintfOutputConsole::Serialize (const TCHAR *text, const TCHAR *log_prefix, int severity) { if (!_enabled) return; TCHAR Temp[4096]; #if defined (NUX_OS_WINDOWS) Snprintf (Temp, 4096, 4096 - 1, TEXT ("%s: %s%s"), log_prefix, text, NUX_LINE_TERMINATOR); HANDLE hConsole; hConsole = GetStdHandle(STD_OUTPUT_HANDLE); if (severity == NUX_MSG_SEVERITY_CRITICAL) { SetConsoleTextAttribute(hConsole, FOREGROUND_RED|FOREGROUND_INTENSITY|BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_INTENSITY); } else if (severity == NUX_MSG_SEVERITY_ALERT) { SetConsoleTextAttribute(hConsole, FOREGROUND_RED|FOREGROUND_INTENSITY); } else if (severity == NUX_MSG_SEVERITY_WARNING) { SetConsoleTextAttribute(hConsole, FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY); } else if (severity == NUX_MSG_SEVERITY_INFO) { SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN|FOREGROUND_INTENSITY); } else if (severity == NUX_MSG_SEVERITY_NONE) { SetConsoleTextAttribute(hConsole, FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); } printf ("%s", &Temp[0]); SetConsoleTextAttribute(hConsole, FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); #elif defined (NUX_OS_LINUX) // {attr} is one of following // // 0 Reset All Attributes (return to normal mode) // 1 Bright (Usually turns on BOLD) // 2 Dim // 3 Underline // 5 Blink // 7 Reverse // 8 Hidden // // {fg} is one of the following // // 30 Black // 31 Red // 32 Green // 33 Yellow // 34 Blue // 35 Magenta // 36 Cyan // 37 White (greyish) // 38 White // // {bg} is one of the following // // 40 Black // 41 Red // 42 Green // 43 Yellow // 44 Blue // 45 Magenta // 46 Cyan // 47 White (greyish) // 48 White int Foreground = 38; int Background = 48; int Bold = 0; if (severity == NUX_MSG_SEVERITY_CRITICAL) { Foreground = 31; Background = 44; Bold = 1; } else if (severity == NUX_MSG_SEVERITY_ALERT) { Foreground = 31; Bold = 1; } else if (severity == NUX_MSG_SEVERITY_WARNING) { Foreground = 33; Bold = 1; } else if (severity == NUX_MSG_SEVERITY_INFO) { Foreground = 32; Bold = 1; } else if (severity == NUX_MSG_SEVERITY_NONE) { Foreground = 38; Bold = 0; } Snprintf (Temp, 4096, 4096 - 1, TEXT ("%c[%d;%d;%dm%s: %s%c[%d;%d;%dm%s"), 0x1B, Bold, Foreground, Background, log_prefix, text, 0x1B, 0, 38, 48, NUX_LINE_TERMINATOR); printf ("%s", &Temp[0]); #else Snprintf (Temp, 4096, 4096 - 1, TEXT ("%s: %s%s"), log_prefix, text, NUX_LINE_TERMINATOR); printf ("%s", &Temp[0]); #endif } void NullOutput::Constructor() {} void NullOutput::Destructor() {} } nux-4.0.8+18.10.20180623/NuxCore/OutputDevice.h0000644000000000000000000001041213313373365014753 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NOUTPUTDEVICE_H #define NOUTPUTDEVICE_H namespace nux { class NSerializer; class LogOutputDevice { public: LogOutputDevice (); virtual ~LogOutputDevice (); BOOL m_terminated; virtual void Serialize (const TCHAR *log_data, const TCHAR *log_prefix, int severity) = 0; virtual void Flush (); virtual void Shutdown (); VARARG_DECL (void/*FuncRet*/, void/*StaticFuncRet*/, {}/*Return*/, LogFunction/*FuncName*/, VARARG_NONE/*Pure*/, const TCHAR*/*FmtType*/, VARARG_EXTRA (int severity) /*ExtraDecl*/, VARARG_EXTRA (severity) /*ExtraParam*/ ); void Enable (); void Disable (); protected: bool _object_destroyed; bool _enabled; }; //! Output to null device. class NullOutput : public LogOutputDevice { NUX_DECLARE_GLOBAL_OBJECT (NullOutput, GlobalSingletonInitializer); public: void Serialize ( const TCHAR * /* V */, const TCHAR * /* LogPrefix */, int /* severity */) {} }; //! Output to log file. class LogFileOutput : public LogOutputDevice { NUX_DECLARE_GLOBAL_OBJECT (LogFileOutput, GlobalSingletonInitializer); //LogFileOutput( const TCHAR* InFilename); public: /*! Closes output device and cleans up. */ void Shutdown(); /*! Flush the write cache so the output to the file isn't truncated. */ void Flush(); /*! Write a stream to the log file. @param log_data Stream characters to write. @param LogPrefix A string to write before the input stream of characters. */ void Serialize (const TCHAR *log_data, const TCHAR *LogPrefix, int severity); private: NSerializer *m_LogSerializer; std::string m_Filename; bool m_Opened; bool m_Closed; /*! Serialize data directly to the log file without any type of conversion or preprocessing. @param log_data String of char to write to the output file. */ void SerializeRaw (const TCHAR *log_data); }; //! Output to microsoft visual console. class VisualOutputConsole : public LogOutputDevice { NUX_DECLARE_GLOBAL_OBJECT (VisualOutputConsole, GlobalSingletonInitializer); public: //! Write data to visual studio output debug console. /*! @param text Text to log. @param log_prefix Prefix for the text. @param severity Importance of the message. */ void Serialize (const TCHAR *text, const TCHAR *log_prefix, int severity); }; //! Standard printf output console. class PrintfOutputConsole : public LogOutputDevice { NUX_DECLARE_GLOBAL_OBJECT (PrintfOutputConsole, GlobalSingletonInitializer); public: //! Write text to the standard printf output debug console. /*! @param text Text to log. @param log_prefix Prefix for the text. @param severity Importance of the message. */ void Serialize (const TCHAR *text, const TCHAR *log_prefix, int severity); }; class LogOutputRedirector : public LogOutputDevice { NUX_DECLARE_GLOBAL_OBJECT (LogOutputRedirector, GlobalSingletonInitializer); public: virtual void AddOutputDevice (LogOutputDevice *OutputDevice); virtual void RemoveOutputDevice (LogOutputDevice *OutputDevice); virtual bool IsRedirectingTo (LogOutputDevice *OutputDevice); void Serialize (const TCHAR *log_data, const TCHAR *log_prefix, int severity); void Flush(); void Shutdown(); private: std::vector OutputDevices; }; } #endif // NOUTPUTDEVICE_H nux-4.0.8+18.10.20180623/NuxCore/Parsing.cpp0000644000000000000000000002315613313373365014302 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #include "Parsing.h" #define CHAR_TAB TEXT('\t') #define CHAR_CR TEXT('\r') #define CHAR_FF TEXT('\f') #define CHAR_NEW_LINE TEXT('\n') #define CHAR_QUOTE TEXT('\"') namespace nux { bool ParseCommand (const TCHAR **Stream, const TCHAR *Match) { while ( (**Stream == TEXT (' ') ) || (**Stream == CHAR_TAB) ) (*Stream) ++; if (TCharStringNICompare (*Stream, Match, StringLength (Match) ) == 0) { *Stream += StringLength (Match); if (!IsAlphanumericChar (**Stream) ) { while ( (**Stream == TEXT (' ') ) || (**Stream == CHAR_TAB) ) (*Stream) ++; return true; // Success. } else { *Stream -= StringLength (Match); return false; // Only found partial match. } } else return false; // No match. } bool Parse_tchar (const TCHAR *Stream, const TCHAR *Match, TCHAR *Value, int Size, int MaxLen) { const TCHAR *Found = Strfind (Stream, Match); if (Found) { const TCHAR *Start; Start = Found + StringLength (Match); if (*Start == '\x22') // Character '"' { // The value begins with the quotation mark character: ". We skip it. Strncpy (Value, Size, Start + 1, MaxLen); Value[MaxLen - 1] = 0; TCHAR *Temp = Strstr (Value, TEXT ("\x22") ); if (Temp != NULL) { // We read in the termination quotation mark. Set it t0 0 to null terminate the Value buffer. *Temp = 0; } } else { // Non-quoted string without spaces. Strncpy (Value, Size, Start, MaxLen); Value[MaxLen - 1] = 0; TCHAR *Temp; Temp = Strstr (Value, TEXT (" ") ); if (Temp) *Temp = 0; Temp = Strstr (Value, TEXT ("\r") ); if (Temp) *Temp = 0; Temp = Strstr (Value, TEXT ("\n") ); if (Temp) *Temp = 0; Temp = Strstr (Value, TEXT ("\t") ); if (Temp) *Temp = 0; Temp = Strstr (Value, TEXT (",") ); if (Temp) *Temp = 0; } return true; } else return false; } bool ParseParam (const TCHAR *Stream, const TCHAR *Param) { const TCHAR *Start = Stream; if (*Stream) { while ( (Start = Strfind (Start + 1, Param) ) != NULL) { if (Start > Stream && ( (Start[-1] == TEXT ('-') ) || (Start[-1] == TEXT ('/') ) ) ) { const TCHAR *End = Start + StringLength (Param); if (End == NULL || *End == 0 || IsWhitespaceChar (*End) ) return true; } } } return false; } bool Parse_string (const TCHAR *Stream, const TCHAR *Match, std::string &Value) { TCHAR Temp[4096] = TEXT (""); if (Parse_tchar (Stream, Match, Temp, NUX_ARRAY_COUNT (Temp), NUX_ARRAY_COUNT (Temp) ) ) { Value = Temp; return true; } else return false; } bool Parse_u64 (const TCHAR *Stream, const TCHAR *Match, QWORD &Value) { return Parse_s64 (Stream, Match, * (SQWORD *) &Value); } bool Parse_s64 (const TCHAR *Stream, const TCHAR *Match, SQWORD &Value) { TCHAR Temp[4096] = TEXT (""), *Ptr = Temp; if (Parse_tchar (Stream, Match, Temp, NUX_ARRAY_COUNT (Temp), NUX_ARRAY_COUNT (Temp) ) ) { Value = 0; bool Negative = (*Ptr == TEXT ('-') ); Ptr += Negative; while ( (*Ptr >= TEXT ('0') ) && (*Ptr <= TEXT ('9') ) ) Value = Value * 10 + *Ptr++ - TEXT ('0'); if (Negative) Value = -Value; return true; } else return false; } bool Parse_u32 (const TCHAR *Stream, const TCHAR *Match, DWORD &Value) { const TCHAR *Temp = Strfind (Stream, Match); TCHAR *End; if (Temp == NULL) return false; Value = Strtoi (Temp + StringLength (Match), &End, 10); return true; } bool Parse_u8 (const TCHAR *Stream, const TCHAR *Match, BYTE &Value) { const TCHAR *Temp = Strfind (Stream, Match); if (Temp == NULL) return false; Temp += StringLength (Match); Value = (BYTE) CharToInteger (Temp); return (Value != 0) || IsDigitChar (Temp[0]); } bool Parse_s8 (const TCHAR *Stream, const TCHAR *Match, SBYTE &Value) { const TCHAR *Temp = Strfind (Stream, Match); if (Temp == NULL) return false; Temp += StringLength (Match); Value = CharToInteger (Temp); return Value != 0 || IsDigitChar (Temp[0]); } bool Parse_u16 (const TCHAR *Stream, const TCHAR *Match, WORD &Value) { const TCHAR *Temp = Strfind (Stream, Match); if (Temp == NULL) return false; Temp += StringLength (Match); Value = (unsigned short) CharToInteger (Temp); return Value != 0 || IsDigitChar (Temp[0]); } bool Parse_s16 (const TCHAR *Stream, const TCHAR *Match, SWORD &Value) { const TCHAR *Temp = Strfind (Stream, Match); if (Temp == NULL) return false; Temp += StringLength (Match); Value = (short) CharToInteger (Temp); return Value != 0 || IsDigitChar (Temp[0]); } bool Parse_float (const TCHAR *Stream, const TCHAR *Match, float &Value) { const TCHAR *Temp = Strfind (Stream, Match); if (Temp == NULL) return false; Value = CharToDouble (Temp + StringLength (Match) ); return true; } bool Parse_int (const TCHAR *Stream, const TCHAR *Match, int &Value) { const TCHAR *Temp = Strfind (Stream, Match); if (Temp == NULL) return false; Value = CharToInteger (Temp + StringLength (Match) ); return true; } bool Parse_bool (const TCHAR *Stream, const TCHAR *Match, bool &OnOff) { TCHAR TempStr[16]; if (Parse_tchar (Stream, Match, TempStr, NUX_ARRAY_COUNT (TempStr), NUX_ARRAY_COUNT (TempStr) - 1) ) { OnOff = !Stricmp (TempStr, TEXT ("On") ) || !Stricmp (TempStr, TEXT ("True") ) || !Stricmp (TempStr, TEXT ("1") ); return true; } else return false; } void ParseToNextLine (const TCHAR **Stream, TCHAR CommentChar) { // Skip over spaces, tabs, cr's, and linefeeds. while (1) { while ( (**Stream == TEXT (' ') ) || (**Stream == CHAR_TAB) || (**Stream == CHAR_CR) || (**Stream == CHAR_NEW_LINE) || (**Stream == CHAR_FF) ) { // Skip tabs, cr, new line, form feed ++*Stream; } if (**Stream == CommentChar) { // Start of a comment while ( (**Stream != 0) && (**Stream != CHAR_NEW_LINE) && (**Stream != CHAR_CR) ) { // Advance to a new line ++*Stream; } } else { break; } } } bool ParseToken (const TCHAR *Str, TCHAR *TokenBuffer, int BufferSize) { int sz = 0; while ( (*Str == TEXT (' ') ) || (*Str == CHAR_TAB) ) { // Skip spaces and tabs. Str++; } if (*Str == CHAR_QUOTE) { // Get quoted string. Str++; while (*Str && (*Str != CHAR_QUOTE) && (sz + 1 < BufferSize) ) { TCHAR c = *Str++; if (sz + 1 < BufferSize) TokenBuffer[sz++] = c; } if (*Str == CHAR_QUOTE) Str++; } else { // Get unquoted string. for (; *Str && (*Str != TEXT (' ') ) && (*Str != CHAR_TAB); Str++) { if (sz + 1 < BufferSize) TokenBuffer[sz++] = *Str; } } TokenBuffer[sz] = 0; return sz != 0; } bool ParseToken (const TCHAR *Str, std::string &TokenString) { TokenString.clear(); // Skip spaces and tabs. while (IsWhitespaceChar (*Str) ) Str++; if (*Str == CHAR_QUOTE) { // Get quoted string. Str++; while (*Str && *Str != CHAR_QUOTE) { TCHAR c = *Str++; TokenString += c; } if (*Str == CHAR_QUOTE) Str++; } else { // Get unquoted string. for (; *Str && !IsWhitespaceChar (*Str); Str++) { TokenString += *Str; } } return TokenString.length() > 0; } std::string ParseToken (const TCHAR *Str, bool /* UseEscape */) { TCHAR Buffer[1024]; if (ParseToken (Str, Buffer, NUX_ARRAY_COUNT (Buffer) ) ) return Buffer; else return TEXT (""); } // // Get a line of Stream (everything up to, but not including, CR/LF. // Returns 0 if ok, nonzero if at end of stream and returned 0-length string. // bool ParseLine (const TCHAR **Stream, TCHAR *LineBuffer, int BufferSize) { TCHAR *tmp = LineBuffer; *tmp = 0; while ( (**Stream != 0) && (**Stream != CHAR_NEW_LINE) && (**Stream != CHAR_CR) && (**Stream != CHAR_FF) && (--BufferSize > 0) ) { * (tmp++) = * ( (*Stream) ++); } *tmp = 0; return LineBuffer[0] != 0; } bool ParseLine (const TCHAR **Stream, std::string &LineString) { LineString.clear(); while ( (**Stream != 0) && (**Stream != CHAR_NEW_LINE) && (**Stream != CHAR_CR) && (**Stream != CHAR_FF) ) { LineString += **Stream++; } return LineString.size() > 0; } } nux-4.0.8+18.10.20180623/NuxCore/Parsing.h0000644000000000000000000002164313313373365013746 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NPARSING_H #define NPARSING_H namespace nux { //! Parse a stream of characters and look for a string of TCHAR at the start of the stream. /*! If the string is found, Stream points to the next character after the string. Space and tab characters at the beginning of the stream are ignored. @param Stream Character stream to search. @param Match Token to match. @return TRUE if the character string is found at the start of the stream (excluding space and tab characters). */ bool ParseCommand (const TCHAR **Stream, const TCHAR *Match); //! Parse a stream of characters and look for a t_32 value after the token string. /*! Parse a unsigned int after the named token. @param stream Character stream to search. @param token Token to match. @return True if the character string is found at the start of the stream (excluding space and tab characters). */ bool Parse_u32 (const TCHAR *stream, const TCHAR *Match, DWORD &value); //! Parses a string of N character from a character stream after a named token. /*! Parses a string from a character stream. @param Stream Character stream to search. @param Match Token to match. @param Value Buffer containing the parsed value. @param Size The size of the Value buffer, in characters. @param MaxLen Max number of character to return. @return TRUE if the token is found inside the stream. */ bool Parse_tchar (const TCHAR *stream, const TCHAR *Match, TCHAR *value, int size, int MaxLen); //! Parse a BYTE after the named token. /*! Parse a BYTE after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value Buffer containing the parsed value. @return TRUE if the token is found inside the stream. */ bool Parse_u8 (const TCHAR *Stream, const TCHAR *Match, BYTE &Value); //! Parse a signed BYTE after the named token. /*! Parse a signed BYTE after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed signed BYTE @return TRUE if the token is found inside the stream. */ bool Parse_s8 (const TCHAR *Stream, const TCHAR *Match, SBYTE &Value); //! Parse a WORD after the named token. /*! Parse a WORD after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed WORD @return TRUE if the token is found inside the stream. */ bool Parse_u16 (const TCHAR *Stream, const TCHAR *Match, WORD &Value); //! Parse a signed WORD after the named token. /*! Parse a signed WORD after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed signed WORD @return TRUE if the token is found inside the stream. */ bool Parse_s16 (const TCHAR *Stream, const TCHAR *Match, SWORD &Value); //! Parse a floating point value after the named token. /*! Parse a floating point value after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed floating point value @return TRUE if the token is found inside the stream. */ bool Parse_float (const TCHAR *Stream, const TCHAR *Match, float &Value); //! Parse a double WORD after the named token. /*! Parse a double WORD after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed double WORD @return TRUE if the token is found inside the stream. */ bool Parse_int (const TCHAR *Stream, const TCHAR *Match, int &Value); //! Parse a std::string after the named token. /*! Parse a std::string after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed std::string @return TRUE if the token is found inside the stream. */ bool Parse_string (const TCHAR *Stream, const TCHAR *Match, std::string &Value); //! Parse a QUADWORD after the named token. /*! Parse a QUADWORD after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed QUADWORD @return TRUE if the token is found inside the stream. */ bool Parse_u64 (const TCHAR *Stream, const TCHAR *Match, QWORD &Value); //! Parse a SIGNED QUADWORD after the named token. /*! Parse a SIGNED QUADWORD after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed SIGNED QUADWORD @return TRUE if the token is found inside the stream. */ bool Parse_s64 (const TCHAR *Stream, const TCHAR *Match, SQWORD &Value); //! Parse a BOOLEAN after the named token. /*! Parse a BOOLEAN after the named token. @param Stream Character stream to search. @param Match Token to match. @param Value parsed BOOLEAN value @return TRUE if the token is found inside the stream. */ bool Parse_bool (const TCHAR *Stream, const TCHAR *Match, bool &OnOff); //! Extract a line of Stream (everything up to, but not including, CR/LF). /*! @param Stream Character stream to search. @param LineBuffer The first line in Stream. @param BufferSize Size of LineBuffer. @param GoToNextLine If true, advanced the pointer after the first CR/LF character at the end of the string. If FALSE advanced the pointer past all the CR/LF character at the end of the string. @return True i a line was copied to LineString; */ bool ParseLine (const TCHAR **Stream, TCHAR *LineBuffer, int BufferSize); //! Extract a line of Stream (everything up to, but not including, CR/LF). /*! @param Stream Character stream to search. @param LineString The first line in Stream. @param GoToNextLine If true, advanced the pointer after the first CR/LF character at the end of the string. If FALSE advanced the pointer past all the CR/LF character at the end of the string. @return True i a line was copied to LineString; */ bool ParseLine (const TCHAR **Stream, std::string &LineString); //! Parse the next space-delimited string from the input stream. If the next token starts with a quote, gets entire quoted string. /*! @param Str stream of characters to search. @param TokenBuffer The parsed token string. @param BufferSize Size of the TokenBuffer. @return True if a token was found. */ bool ParseToken (const TCHAR *Str, TCHAR *TokenBuffer, int BufferSize); //! Parse the next space-delimited string from the input stream. If the next token starts with a quote, gets entire quoted string. /*! @param Str stream of characters to search. @param TokenBuffer The parsed token string. @return True if a token was found. */ bool ParseToken (const TCHAR *Str, std::string &TokenString); //! Parse the next space-delimited string from the input stream. If the next token starts with a quote, gets entire quoted string. /*! @param Str stream of characters to parse. @return The next token in a std::string. */ std::string ParseToken (const TCHAR *Str); //! Go to the next token in the stream. /*! Skip tabs, and space at the beginning of each line. Skip everything on a line that follows the given comment char token If there is a valid token in the input, Stream will point to it. @param Stream stream of characters @param CommentChar Character representing the beginning of a comment on a line. ie ';' '#". */ void ParseToNextLine (const TCHAR **Stream, TCHAR CommentChar); //! Checks if a Token command-line parameter exists in the stream. /*! Checks if a Token command-line parameter exists in the stream @param Stream stream of characters to search @param token to match @return True if found. */ bool ParseParam (const TCHAR *Stream, const TCHAR *Param); } #endif // NPARSING_H nux-4.0.8+18.10.20180623/NuxCore/Platform.cpp0000644000000000000000000001220613313373365014455 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" #if defined(NUX_OS_LINUX) #include #endif namespace nux { NUX_IMPLEMENT_GLOBAL_OBJECT (NGlobalData); void NuxCoreInitialize (const TCHAR *CommandLine) { static bool sInitialized = false; // Avoid initializing multiple times. if (sInitialized) return; sInitialized = true; NUX_GLOBAL_OBJECT_INSTANCE (NGlobalData).Initialize (CommandLine); NThreadLocalStorage::Initialize(); } void ExitSystem() { //SystemShutdown(); } void inlInitRandomGenerator() { #if _WIN32 std::srand ( time (NULL) ); #endif } static std::string _GetProgramDirectory() { #if defined(NUX_OS_WINDOWS) TCHAR RootDirectory[NUX_MAX_FILEPATH_SIZE] = TEXT (""); if (!RootDirectory[0]) { DWORD Result = ::GetModuleFileName (NULL, RootDirectory, NUX_MAX_FILEPATH_SIZE); nuxAssertMsg (Result, TEXT ("[GetProgramDirectory] Can't get program's directory path.") ); if (Result == 0) std::string (TEXT ("Unknown Program Directory") ); unsigned int i; // Skip the program name for (i = (unsigned int) StringLength (RootDirectory) - 1; i > 0; i--) { if ( (RootDirectory[i - 1] == NUX_BACKSLASH_CHAR) || (RootDirectory[i-1] == TEXT ('/') ) ) break; } RootDirectory[i] = 0; } return std::string (RootDirectory); #elif defined(NUX_OS_LINUX) TCHAR RootDirectory[NUX_MAX_FILEPATH_SIZE] = TEXT (""); if (!RootDirectory[0]) { char *Result = getcwd (RootDirectory, NUX_MAX_FILEPATH_SIZE); nuxAssertMsg (Result, TEXT ("[GetProgramDirectory] Can't get program's directory path.") ); if (Result == 0) std::string (TEXT ("Unknown Program Directory") ); } nuxDebugMsg (TEXT ("[GetProgramDirectory] Program directory path: %s"), RootDirectory); return std::string (RootDirectory); #else return std::string (TEXT ("Unknown Program Directory") ); #endif } static std::string _GetComputerName() { #if defined(NUX_OS_WINDOWS) TCHAR ComputerName[NUX_MAX_FILEPATH_SIZE] = TEXT (""); if (!ComputerName[0]) { DWORD Size = NUX_ARRAY_COUNT (ComputerName); ::GetComputerName (ComputerName, &Size); TCHAR *c, *d; for (c = ComputerName, d = ComputerName; *c != 0; c++) { if (IsAlphanumericChar (*c) ) *d++ = *c; } *d++ = 0; } return std::string (ComputerName); #elif defined(NUX_OS_LINUX) char Buffer[NUX_MAX_FILEPATH_SIZE]; size_t BufferSize = NUX_ARRAY_COUNT (Buffer); if (gethostname (Buffer, BufferSize) != -1) { return std::string (Buffer); } return std::string (TEXT ("Unknown Computer Name") ); #else return std::string (TEXT ("Unknown Computer Name") ); #endif } // Get user name. NOTE: Only one return value is valid at a time! static std::string _GetUserName() { #if defined(NUX_OS_WINDOWS) TCHAR UserName[256] = TEXT (""); if ( !UserName[0] ) { DWORD Size = NUX_ARRAY_COUNT (UserName); ::GetUserName (UserName, &Size); TCHAR *c, *d; for (c = UserName, d = UserName; *c != 0; c++) if (IsAlphanumericChar (*c) ) *d++ = *c; *d++ = 0; } return std::string (UserName); #elif defined(NUX_OS_LINUX) struct passwd *userinfo; userinfo = getpwuid (getuid() ); if (userinfo == 0) return std::string (TEXT ("Unknown User") ); return std::string (userinfo->pw_name); #else return return std::string (TEXT ("Unknown User") ); #endif } void NGlobalData::Initialize (const TCHAR * /* CommandLine */) { } void NGlobalData::Constructor() { m_ComputerName = _GetComputerName(); m_ProgramDirectory = _GetProgramDirectory(); m_UserName = _GetUserName(); m_RandomSeed = 0x5A7CF91E; // arbitrary std::srand (m_RandomSeed); } void NGlobalData::Destructor() { } std::string GetComputerName() { return NUX_GLOBAL_OBJECT_INSTANCE (NGlobalData).m_ComputerName; } std::string GetProgramDirectory() { return NUX_GLOBAL_OBJECT_INSTANCE (NGlobalData).m_ProgramDirectory; } std::string GetUserName() { return NUX_GLOBAL_OBJECT_INSTANCE (NGlobalData).m_UserName; } std::string GetCmdLine() { return NUX_GLOBAL_OBJECT_INSTANCE (NGlobalData).m_CommandLine; } std::string GetLogDirectory() { return TEXT ("Logs"); } } nux-4.0.8+18.10.20180623/NuxCore/Platform.h0000644000000000000000000000456713313373365014135 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NPLATFORM_H #define NPLATFORM_H namespace nux { void NuxCoreInitialize (const TCHAR *CommandLine); void inlPreInitializePlatform(); void inlInitializePlatform(); void inlPostInitializePlatform(); void inlExitSystem(); void inlInitRandomGenerator(); /*----------------------------------------------------------------------------- Command line. -----------------------------------------------------------------------------*/ //! Get the program command line /*! Get the program command line. @return The program command line. */ std::string GetCmdLine(); //! Get startup directory. /*! Get startup directory. @return The computer name. */ std::string GetProgramDirectory(); //! Get computer name. /*! Get computer name. @return The computer name. */ std::string GetComputerName(); //! Get user name. /*! Get the user name. @return The user name. */ std::string GetUserName(); //! Return the logs directory /*! Returns the directory where logs files are output. This cannot be in a .ini files as the system may start logging before the .ini files are read. @return The logs directory */ std::string GetLogDirectory(); class NGlobalData { NUX_DECLARE_GLOBAL_OBJECT (NGlobalData, GlobalSingletonInitializer); public: void Initialize (const TCHAR *CommandLine); unsigned int m_RandomSeed; std::string m_UserName; std::string m_ComputerName; std::string m_ProgramName; std::string m_ProgramDirectory; std::string m_CommandLine; }; } #endif // NPLATFORM_H nux-4.0.8+18.10.20180623/NuxCore/Plugin/0000755000000000000000000000000013313373365013422 5ustar nux-4.0.8+18.10.20180623/NuxCore/Plugin/NPlugin.h0000644000000000000000000000364613313373365015160 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NPLUGIN_H #define NPLUGIN_H #define NUX_DECLARE_PLUGIN(x) extern "C"{__declspec(dllexport) NPluginInterface * MakePlugin(){ return new x;}} #define NUX_SET_PLUGIN_TYPE(x) extern "C"{__declspec(dllexport) TCHAR * GetPluginType(){ return x;}} #define NUX_SET_PLUGIN_NAME(x) extern "C"{__declspec(dllexport) TCHAR * GetPluginName(){ return x;}} namespace nux { class NPluginInterface; typedef NPluginInterface * (*PLUGIN_FACTORYFUNC) (); typedef TCHAR * (*PLUGIN_TEXTFUNC) (); class NPlugin { public: NPlugin() { ClearMembers(); } ~NPlugin(); NPluginInterface *MakeNewInstance(); void SetFileName (const TCHAR *nm); TCHAR *GetName() { return pluginName; } TCHAR *GetType() { return pluginType; } void SetName (const TCHAR *nm); void SetType (const TCHAR *nm); private: void ClearMembers() { pluginType = NULL; pluginName = NULL; filename = NULL; dllHandle = NULL; } TCHAR *filename; TCHAR *pluginType; TCHAR *pluginName; HINSTANCE dllHandle; PLUGIN_FACTORYFUNC funcHandle; }; } #endif // NPLUGIN_H nux-4.0.8+18.10.20180623/NuxCore/Plugin/NPluginInterface.h0000644000000000000000000000214713313373365016774 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NPLUGININTERFACE_H #define NPLUGININTERFACE_H #include "NPlugin.h" namespace nux { class NPluginInterface { public: NPluginInterface() {} virtual ~NPluginInterface() {} virtual int Activate() = 0; virtual int Execute() = 0; virtual int Destroy() = 0; }; } #endif // NPLUGININTERFACE_H nux-4.0.8+18.10.20180623/NuxCore/Plugin/NPluginManager.cpp0000644000000000000000000000542513313373365017003 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "NPluginInterface.h" #include "NPluginManager.h" namespace nux { void NPluginManager::GetPluginList (TCHAR *dirPath, bool addToList) { if (!addToList) ClearPluginList(); WIN32_FIND_DATA fd; TCHAR fname[MAX_PATH]; STRCPY_S (fname, MAX_PATH, dirPath); size_t len = _tcslen (fname); if (fname[len-1] == TEXT ('/') || fname[len-1] == TEXT ('\\') ) STRCAT_S (fname, MAX_PATH, TEXT ("*.dll") ); else STRCAT_S (fname, MAX_PATH, TEXT ("\\*.dll") ); HANDLE hFind = FindFirstFile (fname, &fd); NFileName Path = dirPath; Path.RemoveBackSlashAtEnd(); Path.RemoveSlashAtEnd(); if (hFind == INVALID_HANDLE_VALUE) { FindClose (hFind); return; } do { HINSTANCE dllHandle = NULL; try { if (! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { NFileName FilePath = Path + NUX_PATH_SEPARATOR_STRING + fd.cFileName; dllHandle = LoadLibrary (FilePath.c_str() ); if (dllHandle != NULL) { PLUGIN_FACTORYFUNC funcHandle; funcHandle = reinterpret_cast (GetProcAddress (dllHandle, "makePlugin") ); if (funcHandle != NULL) { NPlugin *curPlugin = new NPlugin(); curPlugin->SetFileName (FilePath.c_str() ); PLUGIN_TEXTFUNC textFunc; textFunc = reinterpret_cast (GetProcAddress (dllHandle, "getPluginType") ); curPlugin->SetType (textFunc() ); textFunc = reinterpret_cast (GetProcAddress (dllHandle, "getPluginName") ); curPlugin->SetName (textFunc() ); pluginRegister.push_back (curPlugin); } FreeLibrary (dllHandle); } } } catch (...) { if (dllHandle != NULL) FreeLibrary (dllHandle); } } while (FindNextFile (hFind, &fd) ); FindClose (hFind); } } nux-4.0.8+18.10.20180623/NuxCore/Plugin/NPluginManager.h0000644000000000000000000000333713313373365016450 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NPLUGINMANAGER_H #define NPLUGINMANAGER_H #include "NPlugin.h" namespace nux { class NPluginManager { public: NPluginManager() {} ~NPluginManager() { ClearPluginList(); } void GetPluginList (TCHAR *dirPath, bool addToList = false); NPluginInterface *MakeNewPluginInstance (int index) { return pluginRegister.at (index)->MakeNewInstance(); } int GetNumPlugins() { return int (pluginRegister.size() ); } TCHAR *GetPluginName (int index) { return pluginRegister.at (index)->GetName(); } TCHAR *KetPluginType (int index) { return pluginRegister.at (index)->GetType(); } private: void ClearPluginList() { for (unsigned int i = 0; i < pluginRegister.size(); i++) { delete pluginRegister.at (i); } pluginRegister.clear(); } std::vector pluginRegister; }; } #endif // NPLUGINMANAGER_H nux-4.0.8+18.10.20180623/NuxCore/Plugin/NPluging.cpp0000644000000000000000000000345413313373365015657 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "../NuxCore.h" #include "NPlugin.h" namespace nux { NPlugin::~NPlugin() { delete[] filename; delete[] pluginType; delete[] pluginName; if (dllHandle) FreeLibrary (dllHandle); ClearMembers(); } void NPlugin::SetFileName (const TCHAR *nm) { size_t sz = _tcslen (nm) + 1; filename = new TCHAR[sz]; STRCPY_S (filename, sz, nm); } void NPlugin::SetName (const TCHAR *nm) { size_t sz = _tcslen (nm) + 1; pluginName = new TCHAR[sz]; STRCPY_S (pluginName, sz, nm); } void NPlugin::SetType (const TCHAR *nm) { size_t sz = _tcslen (nm) + 1; pluginType = new TCHAR[sz]; STRCPY_S (pluginType, sz, nm); } NPluginInterface *NPlugin::MakeNewInstance() { if (!dllHandle) dllHandle = LoadLibrary (filename); if (dllHandle != NULL) { funcHandle = reinterpret_cast (GetProcAddress (dllHandle, "MakePlugin") ); if (funcHandle != NULL) { return funcHandle(); } } return NULL; } } nux-4.0.8+18.10.20180623/NuxCore/Point.h0000644000000000000000000000164013313373365013427 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef POINT_H #define POINT_H #include "Math/Point2D.h" namespace nux { typedef Point2D Point; } #endif // POINT_H nux-4.0.8+18.10.20180623/NuxCore/Process.cpp0000644000000000000000000000743713313373365014321 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #include "NuxCore.h" namespace nux { #ifdef _WIN32 // // Launch a uniform resource locator (i.e. http://www.yahoo.com/finance). // This is expected to return immediately as the URL is launched by another // task. // void inlLaunchURL(const TCHAR *URL, const TCHAR *Parms, std::string Error) { nuxDebugMsg ( TEXT ("LaunchURL %s %s"), URL, Parms ? Parms : TEXT ("") ); HINSTANCE Code = CALL_OS_TCHAR_FUNCTION (ShellExecuteW (NULL, TEXT ("open"), URL, Parms ? Parms : TEXT (""), TEXT (""), SW_SHOWNORMAL), ShellExecuteA (NULL, "open", TCHAR_TO_ANSI (URL), Parms ? TCHAR_TO_ANSI (Parms) : "", "", SW_SHOWNORMAL) ); Error = (int) Code <= 32 ? TEXT ("UrlFailed") : TEXT (""); } // // Creates a new process and its primary thread. The new process runs the // specified executable file in the security context of the calling process. // void *inlCreateProc ( const TCHAR *URL, const TCHAR *Parms ) { nuxDebugMsg ( TEXT ("CreateProc %s %s"), URL, Parms ); TCHAR CommandLine[1024]; Snprintf ( CommandLine, 1024, 1024 - 1, TEXT ("%s %s"), URL, Parms ); PROCESS_INFORMATION ProcInfo; SECURITY_ATTRIBUTES Attr; Attr.nLength = sizeof (SECURITY_ATTRIBUTES); Attr.lpSecurityDescriptor = NULL; Attr.bInheritHandle = TRUE; STARTUPINFO StartupInfo = { sizeof (STARTUPINFO), NULL, NULL, NULL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL, SW_HIDE, NULL, NULL, NULL, NULL, NULL }; if ( !CreateProcess ( NULL, CommandLine, &Attr, &Attr, TRUE, DETACHED_PROCESS | REALTIME_PRIORITY_CLASS, NULL, NULL, &StartupInfo, &ProcInfo ) ) return NULL; return (void *) ProcInfo.hProcess; } // // Retrieves the termination status of the specified process. // BOOL inlGetProcReturnCode ( void *ProcHandle, INT *ReturnCode ) { return GetExitCodeProcess ( (HANDLE) ProcHandle, (DWORD *) ReturnCode ) && * ( (DWORD *) ReturnCode) != STILL_ACTIVE; } NUX_IMPLEMENT_GLOBAL_OBJECT (NProcess); void NProcess::Constructor() { m_ProcessID = GetCurrentProcessId(); m_ProcessHandle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, m_ProcessID); m_MainThreadID = GetCurrentThreadId(); m_MainThreadHandle = OpenThread (THREAD_ALL_ACCESS, FALSE, m_MainThreadID); } void NProcess::Destructor() { CloseHandle (m_MainThreadHandle); CloseHandle (m_ProcessHandle); } HANDLE NProcess::GetProcessHandle() { return m_ProcessHandle; } DWORD NProcess::GetProcessID() { return m_ProcessID; } HANDLE NProcess::GetMainThreadHandle() { return m_MainThreadHandle; } DWORD NProcess::GetMainThreadID() { return m_MainThreadID; } HANDLE NProcess::GetCurrentThreadHandle() { DWORD ThreadID = GetCurrentThreadId(); return OpenThread (THREAD_ALL_ACCESS, FALSE, ThreadID); } DWORD NProcess::GetCurrentThreadID() { return GetCurrentThreadId(); } #endif } nux-4.0.8+18.10.20180623/NuxCore/Process.h0000644000000000000000000000335313313373365013757 0ustar /* * Copyright 2010 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Jay Taoko * */ #ifndef NPROCESS_H #define NPROCESS_H namespace nux { #ifdef _WIN32 /** * Launches a uniform resource locator (i.e. http://www.yahoo.com/finance). * This is expected to return immediately as the URL is launched by another task. */ void inlLaunchURL ( const TCHAR* URL, const TCHAR* Parms, std::string Error); void *inlCreateProc ( const TCHAR* URL, const TCHAR* Parms ); //! Get process termination code of a process BOOL inlGetProcReturnCode ( void *ProcessHandle, INT *ReturnCode ); #endif class NProcess { NUX_DECLARE_GLOBAL_OBJECT (NProcess, GlobalSingletonInitializer); public: DWORD GetProcessID(); DWORD GetMainThreadID(); DWORD GetCurrentThreadID(); private: #ifdef _WIN32 HANDLE GetProcessHandle(); HANDLE GetMainThreadHandle(); HANDLE GetCurrentThreadHandle(); HANDLE m_ProcessHandle; DWORD m_ProcessID; HANDLE m_MainThreadHandle; DWORD m_MainThreadID; #endif }; } #endif // NPROCESS_H nux-4.0.8+18.10.20180623/NuxCore/Property-inl.h0000644000000000000000000002131013313373365014736 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUXCORE_PROPERTY_INL_H #define NUXCORE_PROPERTY_INL_H namespace nux { template PropertyChangedSignal::PropertyChangedSignal() : notify_(true) {} template void PropertyChangedSignal::DisableNotifications() { notify_ = false; } template void PropertyChangedSignal::EnableNotifications() { notify_ = true; } template void PropertyChangedSignal::EmitChanged(VALUE_TYPE const& new_value) { if (notify_) changed.emit(new_value); } template Property::Property() : value_(VALUE_TYPE()) , setter_function_(std::bind(&Property::DefaultSetter, this, std::placeholders::_1, std::placeholders::_2)) {} template Property::Property(VALUE_TYPE const& initial) : value_(initial) , setter_function_(std::bind(&Property::DefaultSetter, this, std::placeholders::_1, std::placeholders::_2)) {} template Property::Property(VALUE_TYPE const& initial, SetterFunction setter_function) : value_(initial) , setter_function_(setter_function) {} template VALUE_TYPE Property::operator=(VALUE_TYPE const& value) { return Set(value); } template Property::operator VALUE_TYPE() const { return value_; } template VALUE_TYPE Property::operator()() const { return value_; } template VALUE_TYPE Property::operator()(VALUE_TYPE const& value) { return Set(value); } template VALUE_TYPE Property::Get() const { return value_; } template VALUE_TYPE Property::Set(VALUE_TYPE const& value) { if (setter_function_(value_, value)) SignalBase::EmitChanged(value_); return value_; } template bool Property::DefaultSetter(VALUE_TYPE& target, VALUE_TYPE const& value) { bool changed = false; if (target != value) { target = value; changed = true; } return changed; } template void Property::SetSetterFunction(SetterFunction setter_function) { setter_function_ = setter_function; } template ROProperty::ROProperty() : getter_function_(std::bind(&ROProperty::DefaultGetter, this)) {} template ROProperty::ROProperty(GetterFunction getter_function) : getter_function_(getter_function) {} template ROProperty::operator VALUE_TYPE() const { return getter_function_(); } template VALUE_TYPE ROProperty::operator()() const { return getter_function_(); } template VALUE_TYPE ROProperty::Get() const { return getter_function_(); } template VALUE_TYPE ROProperty::DefaultGetter() const { return VALUE_TYPE(); } template void ROProperty::SetGetterFunction(GetterFunction getter_function) { getter_function_ = getter_function; } template RWProperty::RWProperty() : getter_function_(std::bind(&RWProperty::DefaultGetter, this)) , setter_function_(std::bind(&RWProperty::DefaultSetter, this, std::placeholders::_1)) {} template RWProperty::RWProperty(GetterFunction getter_function, SetterFunction setter_function) : getter_function_(getter_function) , setter_function_(setter_function) {} template VALUE_TYPE RWProperty::operator=(VALUE_TYPE const& value) { return Set(value); } template RWProperty::operator VALUE_TYPE() const { return getter_function_(); } template VALUE_TYPE RWProperty::operator()() const { return getter_function_(); } template VALUE_TYPE RWProperty::operator()(VALUE_TYPE const& value) { return Set(value); } template VALUE_TYPE RWProperty::Get() const { return getter_function_(); } template VALUE_TYPE RWProperty::Set(VALUE_TYPE const& value) { if (setter_function_(value)) { VALUE_TYPE new_value = getter_function_(); SignalBase::EmitChanged(new_value); return new_value; } return getter_function_(); } template VALUE_TYPE RWProperty::DefaultGetter() const { return VALUE_TYPE(); } template bool RWProperty::DefaultSetter(VALUE_TYPE const& /* value */) { return false; } template void RWProperty::SetSetterFunction(SetterFunction setter_function) { setter_function_ = setter_function; } template void RWProperty::SetGetterFunction(GetterFunction getter_function) { getter_function_ = getter_function; } // We need to provide a default constructor since we hide the copy ctor. inline Introspectable::Introspectable() {} inline void Introspectable::AddProperty(std::string const& name, PropertyBase* property) { // check to see if it exists and if it does barf horribly as we can't // have two properties with the same name; properties_[name] = property; } inline bool Introspectable::SetProperty(std::string const& name, const char* value) { PropertyContainer::iterator i = properties_.find(name); if (i == properties_.end()) return false; else return i->second->SetValue(value); } template bool Introspectable::SetProperty(std::string const& name, T const& value) { PropertyContainer::iterator i = properties_.find(name); if (i == properties_.end()) return false; else { return i->second->SetValue(type::PropertyTrait::to_string(value)); } } template T Introspectable::GetProperty(std::string const& name, T* /* foo */) { PropertyContainer::iterator i = properties_.find(name); if (i == properties_.end()) return T(); std::string s = i->second->GetSerializedValue(); std::pair result = type::PropertyTrait::from_string(s); // If this is called with a template type that the property does not // support nice conversion to, you'll get no error, but will get // a default constructed T. We could use an exception here. return result.first; } template SerializableProperty::SerializableProperty(Introspectable* owner, std::string const& name) : Base() , name_(name) { owner->AddProperty(name, this); } template SerializableProperty::SerializableProperty(Introspectable* owner, std::string const& name, T const& initial) : Base(initial) , name_(name) { owner->AddProperty(name, this); } template bool SerializableProperty::SetValue(std::string const& serialized_form) { std::pair result = TraitType::from_string(serialized_form); if (result.second) { Base::Set(result.first); } return result.second; } template std::string SerializableProperty::GetSerializedValue() const { return TraitType::to_string(Base::Get()); } template T SerializableProperty::operator=(T const& value) { Base::Set(value); // There are no arguments to ‘get’ that depend on a template parameter, // so we explicitly specify Base. return Base::Get(); } } #endif nux-4.0.8+18.10.20180623/NuxCore/Property.h0000644000000000000000000001601213313373365014161 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUXCORE_PROPERTY_H #define NUXCORE_PROPERTY_H #include "PropertyTraits.h" #include #include #include #include /** * Much of this property work is based on the work by Lois Goldthwaite, * SC22/WG21/N1615=04-0055 - C++ Properties -- a Library Solution * * The basic ideas were extended to add update notifications, and * serialisation and introspection. */ namespace nux { template class PropertyChangedSignal { public: PropertyChangedSignal(); sigc::signal changed; void DisableNotifications(); void EnableNotifications(); void EmitChanged(VALUE_TYPE const& new_value); private: bool notify_; }; /** * A read/write property that stores the value type. * * The default setter emits the changed event if and only if the value * changes. A custom setter can be provided by passing in a setter function * using sigc::mem_fun or sigc::ptr_fun. */ template class Property : public PropertyChangedSignal { public: typedef VALUE_TYPE ValueType; typedef PropertyChangedSignal SignalBase; typedef std::function SetterFunction; Property(); explicit Property(VALUE_TYPE const& initial); Property(VALUE_TYPE const& initial, SetterFunction setter_function); VALUE_TYPE operator=(VALUE_TYPE const& value); operator VALUE_TYPE() const; // function call access VALUE_TYPE operator()() const; VALUE_TYPE operator()(VALUE_TYPE const& value); // get and set access VALUE_TYPE Get() const; VALUE_TYPE Set(VALUE_TYPE const& value); void SetSetterFunction(SetterFunction setter_function); private: // Properties themselves are not copyable. Property(Property const&); Property& operator=(Property const&); bool DefaultSetter(VALUE_TYPE& target, VALUE_TYPE const& value); private: VALUE_TYPE value_; SetterFunction setter_function_; }; // We could easily add a Write Only Property if and when we need one. /** * A read only property that uses a function to get the value. * * The default constructor creates a read only property that always returns * the default constructed VALUE_TYPE. */ template class ROProperty : public PropertyChangedSignal { public: typedef VALUE_TYPE ValueType; typedef std::function GetterFunction; ROProperty(); explicit ROProperty(GetterFunction getter_function); operator VALUE_TYPE() const; VALUE_TYPE operator()() const; VALUE_TYPE Get() const; void SetGetterFunction(GetterFunction getter_function); private: // ROProperties themselves are not copyable. ROProperty(ROProperty const&); ROProperty& operator=(ROProperty const&); VALUE_TYPE DefaultGetter() const; private: GetterFunction getter_function_; }; /** * A read/write property that uses a functions to get and set the value. * * The value type is not stored in the propery, but maintained by the setter * and getter functions. * * A changed signal is emitted if the setter function specifies that the value * has changed. * * The default setter does nothing and emits no signal, and the default getter * returns a default constructed VALUE_TYPE. The default getter and setter * should be overridden through either the constructor args or through the * SetGetterFunction / SetSetterFunction. */ template class RWProperty : public PropertyChangedSignal { public: typedef VALUE_TYPE ValueType; typedef PropertyChangedSignal SignalBase; typedef std::function SetterFunction; typedef std::function GetterFunction; RWProperty(); RWProperty(GetterFunction getter_function, SetterFunction setter_function); VALUE_TYPE operator=(VALUE_TYPE const& value); operator VALUE_TYPE() const; // function call access VALUE_TYPE operator()() const; VALUE_TYPE operator()(VALUE_TYPE const& value); // get and set access VALUE_TYPE Get() const; VALUE_TYPE Set(VALUE_TYPE const& value); void SetGetterFunction(GetterFunction getter_function); void SetSetterFunction(SetterFunction setter_function); private: // RWProperties themselves are not copyable. RWProperty(RWProperty const&); RWProperty& operator=(RWProperty const&); VALUE_TYPE DefaultGetter() const; bool DefaultSetter(VALUE_TYPE const& value); private: GetterFunction getter_function_; SetterFunction setter_function_; }; class PropertyBase { public: virtual ~PropertyBase() {} virtual bool SetValue(std::string const& serialized_form) = 0; virtual std::string GetSerializedValue() const = 0; }; class Introspectable { public: Introspectable(); // Needs to have a container of properties /// If the property was not able to be set with the value, the method /// returns false. bool SetProperty(std::string const& name, const char* value); template bool SetProperty(std::string const& name, T const& value); template T GetProperty(std::string const& name, T* foo = 0); void AddProperty(std::string const& name, PropertyBase* property); private: // Introspectable objects are not copyable. Introspectable(Introspectable const&); Introspectable& operator=(Introspectable const&); private: typedef std::map PropertyContainer; PropertyContainer properties_; }; template class SerializableProperty : public Property, public PropertyBase { public: typedef Property Base; typedef typename type::PropertyTrait TraitType; typedef typename TraitType::ValueType ValueType; SerializableProperty(Introspectable* owner, std::string const& name); SerializableProperty(Introspectable* owner, std::string const& name, VALUE_TYPE const& initial); virtual bool SetValue(std::string const& serialized_form); virtual std::string GetSerializedValue() const; // Operator assignment is not inherited nicely, so redeclare it here. VALUE_TYPE operator=(VALUE_TYPE const& value); private: std::string name_; }; } #include "Property-inl.h" #include "PropertyOperators.h" #endif nux-4.0.8+18.10.20180623/NuxCore/PropertyAnimation.h0000644000000000000000000000273613313373365016031 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #ifndef NUX_CORE_PROPERTY_ANIMATION_H #define NUX_CORE_PROPERTY_ANIMATION_H #include #include "Animation.h" #include "Property.h" namespace nux { namespace animation { template std::shared_ptr> animate_property(Property& prop, T const& start, T const& finish, int ms_duration) { auto anim = std::make_shared>(start, finish, ms_duration); anim->updated.connect([&prop](T const& v) { prop = v; }); return anim; } }} #endif nux-4.0.8+18.10.20180623/NuxCore/PropertyOperators.h0000644000000000000000000001644313313373365016070 0ustar // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2011 Inalogic® Inc. * * This program 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 or 3.0 * of the License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License along with this program. If not, see * * Authored by: Tim Penhey * */ #if defined(NUX_OS_WINDOWS) #pragma warning(disable : 4519) // error C4519: default template arguments are only allowed on a class template #endif #ifndef NUXCORE_PROPERTY_OPERATORS_H #define NUXCORE_PROPERTY_OPERATORS_H namespace nux { /** * This is a very boring file. * * It adds boolean operators for properties. The challenge has been making * operators that work for properties and only properties. Since we don't * want to add explicit methods for each type of property we have, we have the * default template argument VT which gets the ValueType from the Property * definition. Since things like std::_list_iterator doesn't have a * ValueType typedef, these functions are discarded from the possible choices, * but since the Property templates do, they are valid, and get chosen. * * However as much as I'd like to have more generic operators for !=, <=, > * and >=, we can't really without making these functions choosable for types * that we don't want, so we have three functions defined for each operator. */ // operator == template