PikoPixel.Sources.1.0-b10b/0000755000076500000240000000000014400242512014243 5ustar joshstaffPikoPixel.Sources.1.0-b10b/LICENSE_agpl-3.0.txt0000644000076500000240000010333014400242505017371 0ustar joshstaff GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 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 Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are 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. 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. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. 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 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 work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. 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 AGPL, see . PikoPixel.Sources.1.0-b10b/PikoPixel/0000755000076500000240000000000014400242512016147 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/appIcon.icns0000644000076500000240000011446413727050325020442 0ustar joshstafficns4is32߀ߊ߄߀߅߁߃߁߈߀߁߀߁߁߂߁߃߀߀߄߉ߋߊ߀ߊ߀ ߀߂߁߀߃߁߀߀߁߁߂߁߃߀߀߄߉ߋߊ߀ߊ߂߁߄߀߃߁߂߃߁߁߈߀߀߁ ߂ ߃߀߄߉ߋߊs8mkil32߂ߑ߀߃ߑ߃߂߆߀l߁߀߃߅ߎ߆ߎߊߊߊߊߊ߅߄ߔ߄߅߃߅߅߂߃߆߅߂߁߇߅߂߁߈߅߂߉߃߃ߊ߃߅ߋ߁ߖ߁ߗߘߚ߸߂ߑ߀߃ߑ߃߄߂߄߆߂߀l߂߁߀߀߃߀߅߇߆߇ߊ߄ߊ߄ߊ߂ߊ߂ߊ߀߅߀߄߄߃߅߂߃߆߂߁߇߅߂߁߈߅߂߉߃߃ߊ߃߅ߋ߁ߖ߁ߗߘߚ߸߂ߑ߀߃ߑ߃߉߂߉߆߇߀l߇߁߀ߋ߃ߋ߅ߋ߆ߋߊ߉ߊ߉ߊ߇ߊ߇ߊ߅߅ߔ߄ߔ߄߅߃߅߁߂߃߆߁߂߁߇߂߁߈߂߉߃ߊ߅ߋ߁ߖ߁ߗߘߚ߸l8mkit32J߱ǣߕߣߕߕߣߕߣߣߕߣߣߕߣߣߕߣߣߊߣߊ߉ߣߊߣߣߐߣߣߐߣߣߐߣߣߐߣߣߐߣߣߐߣߣߖߣߣߖߣߣߖߣߣߖߣߣߖߣߣߖߣ߉ߣߣߜߣ߉ߣߣߜߣ߉ߣߣߜߣ߉ߣߣߜ߅߉ߊߣߜ߉ߣߣߣ߫߫ߜ߫ߣ߫ߣ߫ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߗߣ߽ߣߗߣ߽ߣߗߣ߽ߣߗߣ߽ߣߗ߅߽ߣߗ߽ߣߣߣߣߣߣߣߣߣߣߣߣߣߣߣߣ߅߱ǣߕߣߕߕߣߕߣߣߕߣߣߕߣߣߕߣߣߊߣߊ߉ߣߊߣߣߐߣߣߐߣߣߐߣߣߐߣߣߐߣߣߐߣߣߖߣߣߖߣߣߖߣߣߖߣߣߖߣߣߖߣ߉ߣߣߜߣ߉ߣߣߜߣ߉ߣߣߜߣ߉ߣߣߜ߅߉ߊߣߜ߉ߣߣߣ߫߫ߜ߫ߣ߫ߣ߫ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߗߣ߽ߣߗߣ߽ߣߗߣ߽ߣߗߣ߽ߣߗ߅߽ߣߗ߽ߣߣߣߣߣߣߣߣߣߣߣߣߣߣߣߣ߅߱ǣߕߣߕߕߣߕߣߣߕߣߣߕߣߣߕߣߣߊߣߊ߉ߣߊߣߣߐߣߣߐߣߣߐߣߣߐߣߣߐߣߣߐߣߣߖߣߣߖߣߣߖߣߣߖߣߣߖߣߣߖߣ߉ߣߣߜߣ߉ߣߣߜߣ߉ߣߣߜߣ߉ߣߣߜ߅߉ߊߣߜ߉ߣߣߣ߫߫ߜ߫ߣ߫ߣ߫ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣ߽ߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߥߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߫ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߱ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߑߣ߷ߣߗߣ߽ߣߗߣ߽ߣߗߣ߽ߣߗߣ߽ߣߗ߅߽ߣߗ߽ߣߣߣߣߣߣߣߣߣߣߣߣߣߣߣߣ߅t8mk@ic087L jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2R \ PXX`XX`XX`XXXPPXdKakadu-v5.2.1 6_$z2DQRvNS>pE$Q@{'$݈eFp=M#Y2E#ߙ2r2<8\p2?nN=x_Fyfr)b 1GhX%􂏾YB#:T = ֝IP&f30q2"3jx"<! IUu'= b'AC=8B i;&z;},;؜} X1IW2;$nT 8(09 d5\I կ52@T*ũM /i>K\{\&/6\̞~d #[Zi~JXSl%.n?b`P"`)4/mTKdb5nޮGz7s5pzdCMx&w{'K}?4BǠ Y㜲o|!Ф.߳Q?%sCzT3 ml1LMiǏu;!N.#F5O>sZE3!Ǥ*=Aо4>#c,8M3g>~7,%zTT0]Wm{Ιhd}ΰ­O.ly:{*6'd!^'P~R( Ka a᫶zP.RRK^ mj|U]<$}8jLGN55JJ6[$<8zww_6,Ұ$lUSVv@ͳ* ~X=.m&nyrdAKi:߫rj`A{| ~!$koQa5e A_ܽz Z}+ְDRҮuuILP?GP؂kVW碬~,ۉ2?1s/:Ɂx!As&e(%x2*"dLF~CpP`[2@u;,*jGkrHso~!xPg} ;W(ޞ3w5ՠ<~#B6Y0%-,KN[A t@͚i|BqkɘCXL +&͖~m1M!y$pUda+7~a3S:kkϠٿ&~VɰԧN3|0$U~n麬& I4' FMݿb8'ۻ-e lnP)*#f*:<ِ .ӛ1癇>F " K 0֩.>E#$MptrޖH "S``[ʎ5St =-l+|?|`Ҩi˲m.}HtɊIa#e{ϵ:?%D"N~jq^ӧYErf,8=&*̞h.cȧ83g?Š~>z7_dۻ<?[B Q\{5CTˁy"n}) 폓9x(({Ď~ڷݮ^?[JWlJ[)>P萲[$!g>>w-m_0LۋjR C?Xr&9qKe1xQ$'.yD A\3Yv\ccΒ”,Cbk Iuܘy#FxvKv"{6.m貋W(SH"Ik aOeO츅Lk!̪'' r&4a )/q4w1 tq7(:k 1!گE;A͗VP)VPYVĸBNl"8 |$1qkޡ̝}@8q~1|G1'-5kkV6*1hȒU?ݐ Zdף<'B'1CX5AHQamy*ݠb(fs[Xo%t8<{̰-')&[")oS.QX/ѐ hYYQd@81F#.ltnCP8'hb鉮2M" ߊ80?0:afD@ [ 9 Y&F @N(wF\] mrǂ  >]u5s`1 Qw+vxTZǂ5%=~70C.;NƶQ77!Sh{aH絍8%6`Ex,3qbXiL`w @) |@ac B=>h?wБ [Z/껪dWL\NN$:G#܃? ~\epk̺c.3^ANFvC0IQ?NxtaszK ^n|weQ fЄ#=BaeD7&Z,G0:+Oj$fOtM7.j&ݶ,=9b&jPe>l<й0ܥ̯)#1W8^;\Bo&BېyDYȤ%0ؖ 9{Tvw@_-{ˎ-`~r2k9<؏ c%KY]ecآv3:$61ڏ澄|&ě+fe27O ݃e>a1P:iL|PLf߅e.od#}`eAu<#Έ]M/*s]bHfhe͉6hP_+~QW+x3;B~Y r=u_[>4V/7b^Oi[@~!zȫE^=wڕ`f/5&;.n` 09ޅ}`VJnlY|nQB߯?G鐫=;0|WOAv{FYa+%J^̣8NF=`lVWI)ʋpхxBc}V<-#:} TAZ/3Lqx߼OX[g)c6;n3_q f6!Xd iH7.;/t|S%?Ri~ˁPjBw%^Wxi%gFb7f"L`^fu.#8#>g,|.q랧 +Fm}]vů"'R( ɦ#-9+ס]ã^lΟ9ZZ97/:\d_hrb!2*KBδc–LA?%=Ɗ|ʐ昽g.(wfv gI6.8vG6?ԋfվt!KWn8j%%v8-i x)]Pc5~owO)_}Gm3Ԃt@#N UI0`')D/h(@,+z? >EjXS^lp7[Z>`,-1E cq?45 žNjvK%񦞞tj_l%gZK6B/ْP^D>njqNT>C <70-8,ZE *AڗvJ"Ļ/hh7_Ƀ'E@V=w9p49P[^略8f,2Jy*0(p0F:Ic~A ;K(T킈^ tF] K}3%M5)eڬZh*5 p-tj6BR)v\қ8vQBf1&gAအѥ#١mn/;^> -?,]>oN8[%-.7Ճwv?N🚁hƍސLuo[V.54d7 \TFDm8ўi/iaT"_q3f'/ZIӄxNXGKXWH_0"h({ )wsh,?*rmz3SoM^Y ڢ HvOp`WJBJ( OElu--c\Ż/P_lZT:^d[Z-%\fSn PNط?vjԠD.kfoqrs>([Z%r f2y4_s.0ޗӤ^nӉ31kv J%6 >mb< _킬7r7THVVjysX/(SՖ+v(ʯ~Z*k|ko7.7,0UKʜrSIbY0$4;RoSmI]&#dVIEЀmǰMwҞG}ͺ(:$\ON肐h5){e*xӿu߱[Zx6Ε=a_8鿢X5;Bl% 0? Xcs(s! ʨ`Vmn~\_s xCY yΖIaA|z՛V]V*CO¬6䡣)x U<DE'M7Jbe"4߆rvAC1Y)(TEdr}c=x gLNbfi1<g[];E]*{K$ CS滺[ܦ3*/ye~֬MVJCcov7㇒f (*ځ8~@ ^I o'B9 38pꀥM)߯#=қْO9>ϠSxw_ݬۻ)T/#|*'dQ9yP]"B(Y' M8iI"Ad'ơȎ`dla9a5$OPxPDܽ!$-exl#GCq4>ke"̴OV#hSiHV~eo<ݺw?|EfrH&PqVtt~z!r`\JI;袸%^+1U,U40rA`*7# Ȉﱬ xJ"r JUhFY٫>;|J,> J[1%Qn7Q@"4gtFvմ1+p ĊJNkIEp$wk2J_CN /rL]S#zcw]Yp3a))^"D=f =`6[ֳQ&7{Twc"X-q$롳$}M'&ehv=`O0iRj2#|%TUnDѪ :&sAؘNw-cUxż,7Jzӌ|W$Q/"VGKѐLR.(+zsė./SZ0!4C*WJvg)vU&Nc\ܖџűSnxX2b$H}Vi.A- ԊI]A `M˃wQoMtWY; 3/ ѥ hnGH g=RUA v0n\GQ 'M@~J{̏4h깷SzԚk*䀼I RDi*ƮAlw$@o+}%`J9bsb4`>;*xz*M('=0Q8dfhr4A/1֋aI) -Wl\R4= zY:5k5 Q H9cU|Q ^#W) ws4-0]&\cL oX#@)v[-] Z1|> NI78i9yYr![B(nlJKZZJM^0Zĉ&ܔJK.uȴ-guBqV|(fE~*|dƩL fOM{0 =?} kĮ|a62p@|2BYQsu)x2IY{cA0:M0fo1BڀGdԂׅ1 MEZ Q3Op`f9C斓:gT CNzmxPW N*g{`.!Q^eeøLw ~O#(~TƑs_ܰvu#OS jjYl+6 jiW) ?v'ᥱi>plNf_UpZ`'Du6RP}u Tk1# Z''~6> ko@;: XmO06I\!ql))t&H8/%iqU⌲ؚr:+> l3t$pG pZ0j޾6DL7|E/Q7OB (@Tc(j WDX+d­HG¹p>_`J_NXnM[acLsGW\2ʒwM_X ]QmQƊ!Y%r>]@NFC'm>A8<+ Ѓ6p~ ,5+#9ŜR"tTON'1mC Fuayqd߀+O@* bB_cQ)H_16o@,me,fUiz*em9| ffX8}|YQ;K#5@ӻ4 3e:apa*7ɖEOZaaj^JGKi(\sPiA+ Tʀt"LX>/KXjD ^ Twh%Jbt:D. qVydX63~f^R:ٶ紜 s96zgh%ILK)yK)@kx~,ɍ9ͧ}5i~O_=lLb8$$CgK攞9 0{A1w1RXx0 @Օ,.aS*p 4/̓d_\+:u]N'i&7[(ӎEV xّh0tA56\1쳡l=<jgwɹEzݼ!:w)Y^85Nf_C afzVgUYFDacd(~;TOI&NT.Z^I.*F3PƁFd(@UÚ2{F`xҶ h]ËK)8f0S%Y[S |J5l<4(oQ+vriP}uQYM<鱆$#>DՇHC[딫#R͞j;?DSbbE[/LRT3tҳmp;k%uJPoJMxy}"QDG˯ya<&&e81"cBv$ XMYYs#wQ3sm/¥@"0]RLxqt KbAm+RMCtx7i*u[>ˆoM`V5R&W/]T~m8< w5 $^[` h?L]VFI$B^+[DDERMri:s#e\lI+ܓ~UFu}"]6w@_|*3,i'r+g.05pbnX'`yM{+t<^WvxB>2Y1 OeD;oV߈3_hb\eE1+2atF3aEҏ֏c.2r״z`U@\ށܙ)/_s;S{ZS?aZ |DA4C"6#@DXPĺ5_$S.G"'X" 2^z!p9tw9C8 XHB PP=p P* Nemu&鄴Nڱj馶CVë 8.6 'ZͰN.Sy= Y ujhJ O sQB<`~Œ[EC͆ j9(ׂ>W]X1S6Z!uroKG gOy5ARd%zkxWKHd/Y䒋ۘ*W6 TPLD!AJl0qfSk `n˜A u&^ܾVlL} ! 㵡}#3cHP ?hT 748NM=bglKc9դ*C c***> 4/R.Nm0Sz_-gN*o<õ1JL9r֮s^<%)mj5S Q֮s]]uiFՇjK=XWq=(B3C.:#Ȕ};,N 77W3+\c<)Uu8’x ~v= 3m\l:֧"{V4v媇ٮ;3b}{rve]GPK,8qt c9դ*ojJs0Zil+1dd-BtԐVJBP1|HM8t*?*O7*8yw}%Ҋyƒ+#(z;{1Zq.峈To`)z)o󋄋Sk$[BZTu%zP"+o=ū qӌ_eSݼ5&R$l =vdc!i?6@dH̫_tqEhZjdObsX#s&1/(V\R:T|ъqӘ `/|$BّQwDd71~[=]xcFܜ=+rɣ{eQ\C_G;'*icnV PikoPixel.Sources.1.0-b10b/PikoPixel/backgroundPatternArchiveIcon.icns0000644000076500000240000022024313727050720024631 0ustar joshstafficns is32H           ~~~~ ~~~~~~~~ ~~~ ~~~~ ~~~~s8mk+8888888889999::;;==>>??@@AACCDDEEEE6OXdknnkdXO6il32vieٺb_̷_ մ] ۶[ Đtr~T ǹ     ieٺb_̷_ մ] ۶[ Đtr~T ǹրրրָָָָָրָָ րָ ָָւցָָָָָրָָָ ָָ ָָָָָָ ցցָָָָրրրָieٺb_̷_ մ] ۶[ Đtr~T ǹ򓼀~~~~~~~~~~~ ~~~~~~~ ~~~~~~~~~~~~~~ 􀓁~~~~ ~~~~~~~~~~~ ~~~~~~~~~l8mk-MMMMMMMMMMMMM?Mm Or Tr Vs Vs Vs Vs Vm V@VPVSVUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV8dmmmmmmmmmmmmmmmmmmmmd8 !!!!!!!!!!!!!!!!!!!! it32>ڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁՁ݁ڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁՁָևָևָևָևָր݁փփփփփփփփփևևևևև֋֋֋֋֊ևևևևևփփփָ֭ևָ֌րָցցփփփփցփևևָָք֋֋րֈևևָցփփփրփָևָւָրր֋քւָևָւָրցփփփցփցևֆևָք֋ֈ֊ցևֆևցցփ֍փփָևָָָր֋րրւָևָָָրրփցփփփւֆևևքֈ֋֊ւֆևևրփփփփցփփփָָևָָևָրց֋ր֋ւָָևָָևָրրփփփփցփփփւևֆևևք֋ֈ֋֊ւևֆևևրփփփփցփփփָָևָָևָրց֋ր֋ւָָևָָևָրրփրփււևքք֊ււևրփրփփ֍փփָָָָրցցրւָָָָրրփրփփ։փփււֆևքքֈ֊ււֆևրփրփփօփփփָָָָևָրցցր֋ւָָָָևָրրփցփփցփփփւָֆևևքրֈ֋֊ւָֆևևրրփփփփփփփָָևָևָևָրց֋֋֋ւָָևָևָևָրրփփփփփփփւևևևևք֋֋֋֊ւևևևևրփփփփփփփփָָևָևָևָրց֋֋֋ւָָևָևָևָրփփփփփփփփփևևևևևڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁ͓Ձ~~~~~~~~~~݁~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~􄓁~~~~~􈓁􄓀~~~~~􁓂~~~~~~􁓄􁓀~􁓂~~~~~~~~~~~􄓁~~~~~~~~~~~􄓁~~~~􁓂~􄓀~~~~~~~􁓂~~􍓆~~􁓄􍓈~~~~􁓂~~􍓆~~~~~~~~~~~~~~~~~~~~~~~~~~~~􁓂~~~~􁓄~~~~~􁓂~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~􁓂~~~~􁓄~~~~~􁓂~~~~~~~~~~~~~~~~~~~~~~~~~~~􍓆~~􍓈~~~~􍓆~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~􅓀~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~􁓀~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~͓t8mk@ +012222222222222222222222222222222222222222222222221/+#  u; *8 3W<^ CZ"EV$GS$GS$GR$GR$GR$GQ$GR$GR$GR$FQ$FQ$FP$EQ$EP$EP$EP$EP$EO$EN$EN$EL$EJ$DE$D:$D)$C $C?$C $B,$B6 $B< $BA$BD $BE"$BE"$AE#$AE#$AE#$AE#$@E#$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$?E$$?E$$?E$$?D$$?D$$?D$$?D$$?C$$?C$$?C$$?C$$?C$$?C$$?B$$?B$$?B$$?B$$?B$$?B$$?B$$>B$$>B$$>B$$>A$$>A$$>A$$>A$$>A$$>A$$>A$$>@$$>@$$=@$$=@$$=@$$=@$$=@$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$$$<>$$<>$$<>$$<>$$<>$$<>$";<" 67 .EWenssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssofXF/ $6EOWZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZWOE6$ $.5:<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<:5.$  "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"    ic08. jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2R \ PXX`XX`XX`XXXPPXdKakadu-v5.2.1 AIavr\8i Qߧ-G0u\ Yl:+%5V$6D>J>>-Sc@]fa5 cU$PIrG?`kkgʎ,lƅ=s>,|D<_Wt8yLX)c, /ʲV6Bh|rf1,ĿB6vo~P?8{$DX $4=K}{Sf"ZX @3oDf}.𘝕!F1]> FI^hishȥYJ#7W <1~iBMW5G%[UJ0i{ڽU𞇈mZ޷D.P7JtVTC9e=MF۝3sA2U@?C*X?~t%[$Kw4@H$quqI qN?Զ雕 B#zNӋ zzw(Iy$ ZvXL|L\Xx!d=NZ-ƾ[cҙ1 ,Pg\ 98EwmNF3i^ qf>H$`<"*!`Lr v:nK(2ơ9ns|;"S^!'ح6"~cf#w"DJa#m:m13 W$x>+D?txeuBm;t!sXBC{w^22{6M0E|A;Ue. AvW z̟%M2U3+ `. 5JX뻉H⪺܉[ ?PChӓOqlB-YzDT<}$-]*/1⡂!iEX>/$k\,dhnH_cZ57@zs8BS0k8l}@ =n%'[iLhifPˊ׍ ]p- AxYY!x&F:'4l&KvY}O"t>xW[ lXG ߬H?AVD12 ;Ma +p:`w z4-uU]WlQP3P@L2gVl}5v~2aB6.N,T=#RRu;C"E SzeJVK^A7&0w^f0&u@wecR邟BL$?θM]* F*3RNJ% An5~_]7U#_Gp#qӌDJN𓚉,5"cOf""D: أU߸8  zA꾪5.?}Ί>1=lm`oufDB M"{lQoq?lv  HJkJ:kjm j<{[}Oۇ]@WuhU;F>  N9-^ gIjKX)q|K^,wDڧGkhas7lhXrzcB}7A[(V*:Υ5Ӝֻi#rq+#a|z%MY~XўzbumK\L}{DSi᠖2ͳƤtPD!![48pD%PU>գMr !l^Pfu>.R0I8*R|;NFK,wJOoYlER aފcПMHkkI^+ו ]_}'Uuy}H^ f* `s$þ ?(P̈& 6+Wc^-Ǒ1O$A-[wkUl.G2<*W>zG}ݚvׯbOf]c ģ~h,UrrSW@¤r2{7H|l' G2&LF&ޱj=s鬩 oכLjpc(_&f:> QiԚFBvZnِ[;iO@uO2&{~]cG{exkM^F @i1r(`gi-JzojmYͭ?/gnDMRRRW `>8 gæ36r+S8-|RT6X R-MC XH;B(]b#tz K*2KGiЧKAUD!/WH F7V8n@,Ĉ1=TeJtg `+c~eΨXǛU[i,d\c=Ty>Z)j]{iDy!EAe[+xּ:jD0K噗z\\w`oeڬM$ؓ^8gIYZ[ !<~A=Ҁ6xVgކmjΥaz33i|\юvdd೜Ce6AP8 =ej {q6^T?ȆtM 9Ƴ3@ɉT޽&f6BE駦2ek>SqjXhXq8d+NO_ɐ[^Dr4 ٚp)ZGoF ?}Jg"XQE=2HMʒzc1YL[0^۟OJ['qtƫgES(W(>S_0C$^r7$do0co'?i Hnz7 ?I4%M)is'R'/⭎8 tNHd6L2B*ʘoE\0`5z6wd̝[~)MN|!'hdb=Ez}Npr$F,fnzeHoOjs3S.V@?VE+M^8 $Y r0",ᒵe3]6/CE' 'u=Mi+<-~}f+0ŲAsѥyX+.r@@ d!t͇DA[ٌߪEy isteUcBy5q.XL0 1ZKxqgg`UilAug*)X0r2ZF*[x56|U4Uӓi!zVm5P#DJ[f u 3;+0閒_$\r `0Tjm:L0|X2k؃Uք{ͩwNȭ[664oW`sPGhL(mo3/?e'q4 k25?b$Lei'EG155Q.՗\( H 4b[W B,¹mxhLJ~ҙ?Rcb+:bugN|td|ʃ37I9MoS6 S63q7G2L}_7sQ Y:,3vz #k9z9HX_g,O=3}4^LiV@LŭxtOߣgiO,Iq í_9Xh`Z?dmk}I h9g3n˜WVTm dQX6qg"u+-d|L c~_Va 0ېzN &kw:yNXψ2t΃[eɔ> ܼ4ÃWXǣ ZX}x!vtf$kWX}zql1J-A[HSXy2*qGt['2{XdvJg Ȱ&J" D^ /{[}GjS)I }RmUФ\w ͇Սϔ좵\bV bH8X,G(\w6/W%Db%șߍh!|ޕ,gn^ypTʎ7b}+RČ|)pJipR=x`5PwQ E/RaHPl}ꨦ18֘"$pdEdY,lu&\2!ՌkJ ]/˨дgpk1 }ĸ֡R"g1#޾5-=ʂLoIn܄$8A.w #L J;t(xXm}xzOR(M.%r"y'0)`AQYa 7T^OϳIPlv7EvZbaBܼ~JWyҟ[K;GfҘ(Poj} tˤw/ZAS(_\Kd`6XOPjs;Jg4o#]%qaz;L 6(.'vW^51k=E_aci){91}pҁԖj|2'??`=?7[,,U"`4Cky^3[Г*O`hl8],mg>b 9)\]a+|R8i19yPb:Uƙ"MdS$tB!V ,4vJQ5]~z-LN+'CMI Im(yhkR(B`me6i(ԳFS?x ̛R43͙qR7} Y'&g$/AIz ҏe E V3k%5 `HioB2 ]B3Tкse[kГ9 ;vNGz2sui^;8x/bTxJeG{1d7jG')/M"Y*KWj(!h# =B!t]OKR׼ C}pf݁XY^&*Lcv-2pzH\mSq 3Z9[zcd=kI?y:'͈|/!2F_dSWoX7שrr(}SA (i*Ⱦ4x \dZKR;# Y5/-wL-?)KVd]8a 4T+nfч N=4~arUt9"̊+4׏k]TM0(;yFv.P?6py:JvժSfU[\۽N>Bg A1%b?;1!)*¢Њ$a+65JdD)wcZ1K/) Bd*u*RWO|/RJ =s?gW(4V"U%T1bz_4$לj_^6Ȯ*!-`> iY-)mUR(ece<&l:}(8 ^L| Y X}M/!s4Le^f) `e>=*##8ͳ[hmЈ :nM޺~ 8YSܫΙ$å:sϊi@2u"2RV*~Dٽ7 +N2ŨWd v76`J__ 'TYq+H:ꪎ\E 27UfF]f!3Lhד-;v/N+ބ6%=>߁xNTfտI#v~z2LS_1[~9K!ZȨE!rNF- (2e I,rn8YNb@ P1PY'}ՇG1&uDOJdڪ~%v#3S]dc[P&ă&tvK9} AL*iB_ޱ~4ʹ*_kPt`Fl 7,`\wAj/K2ngfb>Ń(>[?G¦Ϯ(ܩ8:6Lt> C"\hۻrA~?]HD \kmJVリ`2es$}rmX0qhkrE vNNUMB!A}+]Lzla!a˼~Lu |mW  KpŦ/ l \WծM56'HOqVL¼ίP/ZHfo\-nmYAzQ*fk(F5|x ޛjs#H\f!t$1櫌̮l&T&խVY`gg+P+}- B> HÚAv D~몥~#\[FNw`Y-鏧H%֜֜֜ڃ? P \)"1Mp&9bc] i6?Mjˌ2gZ/C?=F:]\I9^ǯA#.`כ'"*FwbzsļKW}4.$s"RloSE@yYN$~Q_j^f]ӽ͊Y֎n0@u;ZZEUt̲a)ey,?*Re,>fbθ@s"a \\N1* D40#|p)6$#A̛t%MjN4 !Offu2vhsa=HUjc*㕰lky {RsE* @mtତ?VNL~.o_Z,I$̓#yԙ[, j]$ a2102OպROfDIZ;XyBH^L Mɑ -".oY3)E[1%Fcvlѣ*mibXceO?g2},.)7_n.G+KD;FT _|7l!MjYcw -_&ÔN&\%x\\\ztk+e ֑(SmTTHFmϹdDQ ȓNEpe\Ƿ) !_+>R@ Pyz35S{)^ʚ@~bM}ۓqm ~N8מF̀Bml6>1OѸofyR/[BDQ5=Y}LJ $I$I$I$9pܚ_*E%ĂfRKi6טqu݌K3#r k1ub up.8}zyB( AeHYID֜>rMS42gqνj}iPzF1ޜd^#k*H=>hEےI$I$I$I$8Jv3ӲޏP/`ˣXڔJ=zni4f2,Y|<GMb!jrP" (>=ϬwЀa^k;a1MQ{%vF<~^YKAeIvCZzRQ$1gZ40:mp!7lT-UOj?ǘ\Z22c nEg/nH㠹fczč%tq߶8y()Z_\l\ߜDz5lP&*gE{"C@Q.]GkAo!!SFY7"*I@-&yNukmzRkiWAzM2 Ƥs54H>lK.[SjHNVѩ;$1 [F7YpͥY]xa~7rX/ 3O18Been $p?e:q7E1n#Ru+UXӘUVX 6EsL4+#!VP?7r e㑋?T5#v] plDleb9EBĞ1c Po^mݦ /H~7LDA}'U+]kl,þ:lb)# E5h1r(EcK>8"g8 (+:o6r+4؝"'j}vCRQ˨~S"0,#bpoAV>`%]DvIR|yy=A8`32TWӷ83@Y5cZJhѬ5fnR!2'hS0S7S5{ obz<ۥyMirNJm[D)&oP:Wz.}^OH$vs3! &z%A7>A #M#,ɩl= | +Ҭ픳<鿅xV(3YhPYXgp)'&,?: \o|R,UVL"ϱW U/Hޫj]MS @J)LNQX5ǗPHGԕP7$Zjp4ñ -^ >e!wFnk{,BV>G8XrXbOs`+bps6CnF+l {ƾJTÑHh;nCcz(7-cA3D~zeR~jC ;=3ugA^n5Z}i [kIEo01:K \}h_EJްiZٷNH/dCcF5D'hcqK&` 鶰䑡ϹOsʈd5ϻ&3g `X Nto 4sg=Aqԅ'SX k|Mǥ 33w\33Cwe.i+tuQv\λٛ(ƒnU)#:4ک! K}<=̧g.(jt8Omb3j/f6"$sX'(JFI& >tX;YK /`ͺPytPy S0Fb8H0"my (@FzC-yZv~UJϳ]q(5AWu FI%DD4kj'Uм)'}>LM@XSܭ&E4=OiEg9;i<>\yC~|vL=w~,J]@ك]d=2O$T|0jmk]ӣVQ۩H{p[l$6=C2xu#nI/Ku=Y.?^?aq'O1\)fMQ|'1`Y=&IKb1ǿGUy4_ z]Tp'6$i~(WkVmzf 7~5[HT1i^bԪ(i8QM#l )o -X&p6>vtuOlfYC)\+\Q{_e,G4*/P={Uf"rd.Tur=TӇE%9l/@ew.oBF>d;yBF0IJDt,!鞰g1}>݄_d̥ ǹj?0Fja !k-T1۞+gno,i nnC33EimG)4jY_0cToP ~ufg泉0%9~DwW1 \Io Kβ)0:`'ҎWW{돝v,Y1&}#SV6@tܓ%]FjMВjz'n_ }u{Α8X $%V4Yp{ ,qku?͌imC`jE){<^n_y+ 'Zc- u{)Lb`؇ ilՃK֏榾:TOv\mP>a~磕4ƴX$cE/w]$)r8*$7yd)*EfzHM6$2wF"FFzuJ1G31hol f_"Bg1ض,&vn$r_eYci$+KYӄFOC}@lAt]z68h+x"Fۂ<\`![Ƚ2.<Kpu_`h@EC $-a!(O!҂9;ŷ[mY5J!wf¹׬~_xsS) >zH|f(HJRMI|SɕN*Qg5t1Z[#9rnQ]#QbǶlǗ[Jn ip{PhetN \L>ow:V>a5L-Zl%ğ.2:l8|P8Ȭ`ceQȠNk DOB #GDuqJȞ4|x qß;~+1q=?gG]EAk;QlAy}ktZ=KPkYUG'eګ$j7(wR]dz 4Zj'~lD84vW Ro.qZn*%"o-!sNben}?ۍ S?э9KaSL_okCCvE;>>@k7$FmleE%)Q\$}" ]3p&SMj-2 m)uT|ᕈ|>bM+׎ތn:'bPgq^ ?f:>Re)Bjm |+h5#^=vF/jT !Pݟk5DN`cӿՕ:gu5w4Fמ-dUbz AzAwPXr`l6? \A^fP=dd_{qD4Ģ#|[o\˽.jAI=@ܑ.e\i/xurUM S3%J*אrs#Z3u;ڌDilW&@߆3SqP7Ѫ$GƼT~0*̯:'eQIlGP28˪qĵ\xZUp!Te+,ŵb(=^@u!jT]T. 6Ն(qQdm*BC UЅpˑwݹ#g?OOu"惄菓 ~j981(/dB{lNn3ڏv'~]-FleqduΖCvzꦲIK[5+T8}'s:XhUH7JScttذ\3xC(RoFc5WjM-Zu&Uبv*0 "9N@rx2b:.y/&WY{n5Pyt[u]f&kk43Ӫ>.NPt9☗‘(8ZP tPa>FT>07=5lPX( S[NxSCbHNkQ8gy{D\vkHyP߷cV2,7u1\C|J8ŒU;I |v`rr,pPX;Ef7uWWr)m LݺSVD$8OȋҊJ\Y४<㓎wN1w2yUeQu 7x+:^#2mkіK<\y\AN׈2>f㥖 r ]sM)s!P'r&t>} ֢n63盇5n5UC^WςJ,Xc?W( {?5H>uy#=H#It &[lFQkk]ٜǡ=7gfr::0Y]7P7x,-rx lכ)Nd'MU+Z3XM2JފSq?Iƛۊ gF,MiM௯+өI W痏4ŸAO+̈]O =bM1H>KPCCZPֻ~_}-{J_VGk9^rWũbk[G{bM_; ظ趕Q]eL>~w7AvyS;mKJ@(37瓲"0#t=7IxޡB*BUA,#"{eus m|\B.yA65iѣqD+6r "_R͹Zx.\4}40`2af9 Rg*dn|VX9} ;&i:|+ ~hpkGQ_k1&(KR_9џ]R.ܟ5ODB{!(aK#-g*$N2#g ݛ<0N4I>;JFp{ XFr@ ß> ucRsU] u6լg5+H"w,y/a/\^qj̢8DVNZNGbLCI-no*ekdG'-:3xçbeJ8NdAIJ۶OrP'h#yJ7q3.G-b(QEĆ*'fGUYRhcr;08jTzF8¶ـA~FrJ[`,vLh 5Ǚ2_}R\:.e"VAMJ/"Y꓄0o?`B_A#b#{FpA=2#YWtR>~_,5ID{+p%-+d5C%,?!Qh1aT UBܰimE RFCJim?F|x"`Ow53`5+)]].z8{8ZH*1Pt큀DNpFE{,uQcQ,>Q!Ȗu6[_"ڸX5 B~osͤjy8mܴ+{6hH8@c56%rNSoH0^GoWr6~i[oYQ4fJ0 B5u䐈"Tx>| 7g_p뙉Fե)T[pf9k%(ڐY\̸{4vb|naILpZ߸tXaR AF_ʊ CUO0^jguhe!3]z}qR]_RjF\gܾU#5CjT9料. ;ND$K}x=ߤ/F@-la|A#| 3_3DBTs[ +oA!X kqF$ϊ/chC.ukASRLʹwD7719~8eKV_wǻ@YY>dR~`M'݄UouH9]\ -8r7(,Fڟs$aS#@*Eȅ{Ur}qس?JtJ$eL]ݡrw\+$Njo}mФ]*R7S*Ϝ*C?}-n!$QP5@޴Fx&XAgFħ~+?Xd5x6Ӡ**TI{ye{0BiR `;"0`߄5?.x%:/q|1gi8*EYf2\REۏHRGtθs{htg4HHdk@shvyśAFs)"INʑiiNY sP9g_0]E%FY9$K *@DiD[(~ 57~+ƛLu#g?20cGee+B$@&ʕH`Pӷ(6IšRV2.){',u _Ԧ7VR蕈9E4eҝ#ӽ]3(e[Ӥ0$FTj 9n_ w%&j ~ՖM}؉C\ڽ^|PoutiuL6la>g(۔T,;i%:e@ Z 2t~i0<3ӯjkvJ;irILp \Н)IQsHő}_yihoQ0ehPq6 l‘!M-ojFG=(Kq𳾟.SK4Q80b# D |CJ@Prtx1 |.FK$ Ub3o(CJ`P9Fz Z`:VC od<Ƽz6$ܠriڈxdPQ:hu*n٦eKu_ZCzkشVz>t"Dw-}/m3NS;.6R|A#D,RNS;TK]5f)-3s]M{Z v]lS yA4B`M;C!BB .MJLVqJv =Y&%!k` A";)EQl_wPњ{~T"_(6{ȯ%VF*EκPa.VQU.hSl4SC-NJ6V >pjn 6H=6 T|R,ю甲3%^3=)sG J`RJX>AB)t@ZXG{jj@a= sl4@o(6`#һ}&@L7@/0Bv~wA(aN^csj08]̏I8@`63ۧvFڦw7ݠŀxƘ{k}fr t4\t ꕛGsI +&ڻBf|RG_Հ87;BVL7:i tĻSiF  /MXwKSCeF;EDb~D1J9÷kmHn:B-LJ堈v15b^BAa_·`zۛwn=nH[Xԕ#M$gvwiivu^մܖ]ON4 S=n魗v։wiy]vwiwiy]vwi4e 4B(a!.05@簤 !TvPDlbUOo.LU-, 嘇5-x*?nGb7!xA""ũoC$9tR.%\#,M[`WFr|mJ;lÍҡ/(v<3P8%/kh+ENiJ<n(Qe 1TT;;@rȗKsgNeJ(X*?''EwC )7W\Lvq`IlۜSM+6y[9ĉi㖋V'&It㼝X(Vl`8Y1̼] L1M%6+D}{dpTH!z+O^"d@3pijOU4ӫ@kNؔQEa8cZSu/V_)W; c8HJqy-Y#JMxvK+?lt%}27#ؽ6@]ī|;q7Fyg% ?S ܜp޽ŠFN,B:ºy柉|5]8 B̈́̏CI JjuW_ݝ2EpKM^~w29gn!ߠy`t1jsElp [D4x^]lG*ÅdG@D6g3ODhuץخAxtIX'9%C}ٶaK1tRHmmh1*S.{h'zL CPC|R;UB<[%e@A5`&PEQP 9@Ѿ>bQ ,b|+r`{봪OK C1gHa:(ϻS'1otݮn)]Z /5H2"4>m9NKG'TJE0+5~'E1{#DwqNLQ/qYYLۖ?!ƣ #\ǽŌ;|E "橜U};pntaK7oDD*qJK)68G?P!1pՓ%~,o"B8+ =r;vO\t3gۊP{ (%8yWQg՟_nn~ɿod_V}[5d *iL?6TFgk M:ӈ; R4 APN3Q< NE. nؤNcܩ88fj)߷731CfwebӰJÂm1m7Ű aQlXMIYPl֌?վp,|*qaZ>DUPg9m\}G`(%nD=56%PY~*\3ds:wNo,v31u=(ET Fo! Im,9aPx("^G @DqMz=U'|6'L &xLOn`ૄ@7l|&+Ÿ Xof\lN/fpDQ%9!i- gGFt[l:.닷#dPL!,g6k9[{AF` LDk!?L̞lžYz7'(0GuX ؽh>OWnOmԠd.N _hiK7`)n2T~xժ|`?{p<^b2<7+bOiUi JR>K[Sٍ?GC ɚzm_j^.Km+@&$:z cht+\?GG}6Y''UPZ|q2ץnǒqI;'puONK$NZj F*`LYybk5`i ϮrIg]미:O%VH} ý۴{uh!ߓIV 8;B& ;)(:RiiOg|kvo @@-deYW oe#ZnBZ~N/1Ph4%E?V MmCs$)9[jm3 iZ5I-[ka\v!^!܄áҖW#^{^$k7Ģ2Q:k\N{ 6ؽyuAakߌvw9Ag;ղKc:ᄹF%`t[!`x7G1|C"9})=p[~(O` 1YH%uH/Q}Eɮ䢡aA|oٍ=d j9r玪eos0P]JcadGHܥFSnTD>_?+Mbr՛F4QTpZHXؖN&SuҖB8d&&1c'·NHj*yAԄ_?er; Bs7UHG)Ez2 uz"Ic=S6sFIB<?"K5S "wsȞ4sA'QAʶ[3PdQY#B`̨8Xx%J^N'\Do>dIRX}.Ć =G0/<<\VuWf{EKɛ!ȉM8 rl(MK?4xMz,l}$J2#'Y2j퓜^2w; c'XƠXgn33>YS(dMY,H3M2¶!C9bmџEEH/?kAQ3u6jfXY8I/C~v٠Zz|Q-" |g)@~u5Wua\!L#e?'/Rxud{j+0ӠI?f{ooNHZ8zVIlN} PC/wuLΉb,,-Pkk`dYvUsipzqF앗!0aD8{J_>+=Ùe|P,W=Xۙ~oĪ>P=oO @(g_ >|5 /o&]1H/^OK+y2"jWFs{ۯK)N@z\@-}&3Nw25T4w/ELƪnuA .uA,+?Ax E~0 nH9me;yrcY}R]uܰ$׫kq3yxV(@Ōyv$-8d4i?w- >Vr] -S :5ȸdRv8 @ണC{a=xpY(H)bK4{%Y,U "˱=I!wE6,`[Z gHTxbb)'^|6ACAN셱}߷FxzݧSaPTU.rI"SrRR4?@4GWJ4 ñWx/sL@ BlO/E fqQsp Fe2  qXal̲;cFj*␪vnjq!jj7s{xqb|.[ xx a2ͨ 1s$R||L!Zk@dut|_tJ]JUx>˸8'}%0۲#x2NR2lKȀ "K뿱0Wf2uUAd̻k8$sϫh~xmt<M.3g DoPrOpX s$,3,9RF>0.ũNM(ݑb$,g=b}/Zt`E.".xmɢSaOD[IUq`si7.a5d'>%pڥ rhK=PcOƞ><#bӽ/WV/3RC٘B] O~Ii9G/)]JYuThɺx I(U.֮ jT^qpfpkRk~b CFK$->^GbCC t}|76fo4)se$E1J9O8%'䣝[?\ଠ+G-*kхCUFnr'%wu#'\Xoim^iN]`Z^guU/Cn@}<:etXN(rU^߅k1kkZwsi"QYp?@gbݙ tַHi`La1̅%XLꉄÔ VS2'R -hgp\CS/&u~_ Pi-65i[pXcwewU?*pq7w+5 itհԾ ϯV?Q6|gigu% dyd0dVYiW}+FC<UϕKf)?ש=/e" fSy~'?w,_鯾羅qv,4[ |1Z-t8|#K (SG4d0#r䍖\GOӢX`@RJQeW#ecth|JZVoPnS'%([jY0?+5ChbIqcVq~"f(#?+N⚑؁5 #\Eڵㅅ1 n59. n,aFQ[ 34RKhQpBDE~RLzM+xޒ#]n@6@'O!"=F>D~B`EιFoϞ y! k_r-=N‘WZARퟶz|>HE>*ۯ%£˗Ym">d2YܘpDQu 4M{\OQdl$coWc SíThh4uJ{q6ҽv1@9LIFA<`ZZйG.u9(maR92<"0{ 5]mzboGR'ym3Q)_3̚nIJЀLƼ{ a:<|9PmR݋nyl#qn8u p' `~sruH5جF f"46ea `ɦF]<^+ғu%RrXEQ 1S*b ='=C]J0[RW؏$C~zG访߅EM@߅Y1ɫ6WsCCa˶i7:V-7}}iksiO@K}J{fX 7YPy4%Y'ǀХZp^'g-y%_ +>5~ɩΗ<%C0@G3@m݇XO֚Lx|G6t[Ӫ[_y3յ!gl@akONv ަWktaA!azkSKX[/ Q"=U`G'UTWu~dz!kCjip>9dضJܦP~"'/;["*Ln6"ؐȯ) ʰѺf҅&- gvĂ|& o^ 9"= i3;˿ւNXz31VյW%&"^^lUCl[1̡ԐdǴ m+5x+x _ 1|I)ֶvK?K(~z?o.ÂF/ |Ɛ 1v燹V6o2/g^$_KD}*ezeGvlBh!,2?7]8K^$`6VE #'z]dc1, [BMЉx_*?*iӿO9<f'ɍo(ttјI0 SϩM!P< ߨ81o7uX(Ǔ_Xv*YaWА]_vTFD<;aaPj֯iPcAyWfO["Ie*jB_H9hWXq!JsfcU |lufJ1y`/"bMټU^s%wȽa)("'Ir̅ nZdw Gjk9rHX7 "R3:c'.ng^H6ֹ~<@G9M=ϸJb+[$u!:WTN]- C` !-2$]6%ZX}x!漜{MH#CBrMYyb<'=i Mnv~iMD&1K;CpM{EZvnVұlB a%H,Te??16KŪ]7bWzGC8( ZOYz@[ zv Q,a^e8a b&To{ч<2KE\nahj}q 5HAm˩2(5~h$I9yn[C0;%T_^Ovw4ӫ2BtU0 dY~kDy~FSq=zZCg4c67oe75A٘pŮ9J_E{QSc0"I/԰x YkȾX8jfr+V?! 6YBrgITg50Z^dґ)Ik0ԅ7 w^pymsTDYG~\ibf.h>\B8F kiKpyEk׷вy)ע|ʓ997#\2Bx7IrmE*{6daraKUtƳ Lfμ(X e5)w:Sy@Ze50f +(<( Q~"E? aFu ,&/."sl86z$Jy7pv. f?hUe̗L_B 15J  YY!xcC3"eڕ"ESۛ6!"[JɋsozBL~~~G[o&i7 ؼdx@1lct6WfRB_W,Mv/ qaZB1I9[8zZm%3'R`!p6F*&q ȶ"0hC%Bm =iԙ~D4& DDzGၠmD,w9-^q`oLHѳ7rH.Z|68&n][2e! Ea0< |"UW ʙ7L|RdW!)FAfHE~_7|7{i;prB2f v>"!""6&8:R%u$I$I$I$I xBKO :XŒ*ߞOl@gQ j "V8BBD!pl?R]w M&)wh z*+L} X6-ݤXV^ $Ρ>#;P>r$xRW 3(\{ { E(z~l/M8 H#R[7yK5VJ/AH3DmIGh:뺭]NС |[Bu} :1p|irߣrԦ˭en3(ݏ4 -6w뀧V&lWۥ[_tY9'$!ݵg]K7fˈ icnV BffPikoPixel.Sources.1.0-b10b/PikoPixel/documentIcon.icns0000644000076500000240000012144713727056135021504 0ustar joshstafficns'is32 s8mk+8888888889999::;;==>>??@@AACCDDEEEE6OXdknnkdXO6il32{ieٺb_̷_ մ] ۶[ Đtr~T ǹ ieٺb_̷_ մ] ۶[ Đtr~T ǹ ieٺb_̷_ մ] ۶[ Đtr~T ǹ   l8mk-MMMMMMMMMMMMM?Mm Or Tr Vs Vs Vs Vs Vm V@VPVSVUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV8dmmmmmmmmmmmmmmmmmmmmd8 !!!!!!!!!!!!!!!!!!!! it32ڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁڅՁ ݁ڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁڅՁ ݁ڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁڅՁ ݁t8mk@ +012222222222222222222222222222222222222222222222221/+#  u; *8 3W<^ CZ"EV$GS$GS$GR$GR$GR$GQ$GR$GR$GR$FQ$FQ$FP$EQ$EP$EP$EP$EP$EO$EN$EN$EL$EJ$DE$D:$D)$C $C?$C $B,$B6 $B< $BA$BD $BE"$BE"$AE#$AE#$AE#$AE#$@E#$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$?E$$?E$$?E$$?D$$?D$$?D$$?D$$?C$$?C$$?C$$?C$$?C$$?C$$?B$$?B$$?B$$?B$$?B$$?B$$?B$$>B$$>B$$>B$$>A$$>A$$>A$$>A$$>A$$>A$$>A$$>@$$>@$$=@$$=@$$=@$$=@$$=@$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$$$<>$$<>$$<>$$<>$$<>$$<>$";<" 67 .EWenssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssofXF/ $6EOWZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZWOE6$ $.5:<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<:5.$  "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"    ic086 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2R \ PXX`XX`XX`XXXPPXdKakadu-v5.2.1 5Iܶ) iҞd֏e{%3M@xLbҁ@ywP4~ʺvUY^)HͨL\f/=Q*1 QW孃΄l)8Yil Rec'1}i!6_Wt8yLX)c, /ʲV6Bh|rf1,ĿB6vo~P ?C45r&`FsBU02k}<4WUlFl-ceyq cw($!J@5WI_ nam 2TlZ$- \!yg}@WORL (" I= d^q-*GxC?29)}2U㉼d!ot6QubMH.U\+%Q$.};Fؒ@D@7&D*\5,O] D9iTm۳`t0nh~c`)aN"d =>q'e`HkK'EoJn bŪEȦ3 0y7Jwд`6I~c@?Tk"~& 9`٠<Ip~]gKЈ;/+Iâ !@;c6=Cμa$, ~AM7Q:ۚgr;&Za'A=fC:wh&y\q}tZ4( &\03ߑ ^|֋T:R_&Ti1=|U Ttm 8ߵ`2AOA(O8>^YjFru٘:pr$$Xw [yfg T<ࣀo_MCv1y:r/tf[卯6[&^szuhK~M{vE(#|CDt/C!hTva3N3\6-qהt! kl|AQ CM d*"Lc^>,*Ew %f@z"|]ԛ"'(q zڀ^B-G 3yݽsx{ƹ`vm,G?㦒).oEV Y;`# ^Rd0{O6zmF-#~g «7!I@3D]rcu#m@z;C_'A @nLbɱ$uNIA-qE*Q0!|=ޒJA䇀 }WSd:oo)ND#7.:Xdr 89ȧ%Y ,aeԞYכ!t^?(~pjz)sa>Yx")1@GiBQ横lS[ʴh(I1;l-}a>@LFU4;re]PgM4n^DA -ȷd= g\?θM]* F*3RNJ% An5~_]7U#_Gp#qӌDJN𓚉,5"cOf""D: أU߸8  zA꾪5.?.ڄsEƐО?LH@Q5}_|/W-YH6,ܭ6:4YBF^ĸN 6F*abj- #.!qK@-Z>PvlXHHj(O@  iG8Vڎ[`ХTQ|ȹUd [P$;}D7Ip scQcZ"Gz#;b2uRJ"r+ I3M+(P/1ַ! u:;,ۉƒǗ8$(m$C_8^;i|w.qs&ɷrnF?ĆwxMM$GPҙuJB$-bOQ4٥|U,1XE(~:{ J:_rE.)o.o13.2R"LSTI$\| Qw`oeڬorO木퓖ȱrV|˹A0YTbޤ+oCnxKT>U… (aWث<ӳPC~ٌT姣 >6xm8hߝ꛴SlwJgm3:@4~@DcT {"p׈7vM+^ vF R]~ᜯ{(!3P otWVS)ݸW&/WGuAWfzr'b'FJr: vEOΓ#^ߋ4~n^.L6훒jɣ58287|_2|*j,m(¡гwlY "H1ז*|L9&Ά4ќ0M;(vZYkwԭCk*pogBK|JLފUv=Y@ |elgMC7P,O^h΄W;{-EoΔY(#H@~1.˧skhaS|pb|HKa͙y>EV`C<@O~\ %%gMnAks3uabc ShGn|G#΀а3E߶m|?~: K?6~ "2J\Tcڏb 玗 %ܞ:hQ,B9Պ d#gq&̞S<U09|QK2()yFFdȴ.ÃOym0SNbWX Sw1 cvCEֳ 1y5ؤ% |P-f1 q5FG(s}pҁԖj|2oå7[,,V2p<q'loADkW*L~dl(#e)1N|TWfUS»GѸf<0GX6i 'r2~lꋷʃi]%xI7ɼ!).mh0HbX+jw}|ohd}qYsCZٳ 罭RZnڎ|O}a.I%VKM@51v=&vh3bS@ zU|Uymu?T4˰wʊ =5gI[> r5B: Hcg eDVRd0e1 "H»C+z%n#,Aw5o?e ?! {9::HM,RtK'$'04.nD?fB6w}O6%?:]о;ؖ_)Uy@+ .#ӭh1jx0Q,űCE*Ht+U[8SW#2M?thXe?p-+ݧytNz,]T!E vN\`nF;n/7,83#X.{ y):C#qx#F| %p꿖pN:D}WBaGQ Z٤vB^x-[bX&r35Jf x jTc]-=JΛ+<6Gױ'aHn)G_AkAj4rMAږDK+XjyBU/:5O)d$Cb#ἠִDPW;6Xz;|.Y |C}vs% T٠LKW wAHu1leOw%rkɤBNI$' ̫?vIXc.ۅvMVzww6Ҏ1Mn7jAaW3^6h[c 7S T8yLуlCC8/-}^(u<҇QT#m`'^_]q%vid;,FꠓhXG]#b:b3\zG z{ƓSg!쵲JeEYZ4bFh<-fOM7-|L4t /DyCi"Ф+i,*=#MYNc Ft5=ez lR_t>H\SĚ|\*?4U KǡOݐX '68Pht:q{#B`ih3[R\i̷* @FPVsu5-X6( BmGJ(r$Zrϝ1D|Osڟ{ ̤0O7}gz;J\/"nxϿ &ц f=9& J[旝)PKI ,(euaH r i,\Ә N;d'Ljw(^"oRRq0Wv=ԅ9_sēRq[ff|uMџPNmww 4{&=1rZvM6Vṣz%w\0b@vUVc+B5*xNѿ{T jr{i"eo>Ҡ!$a:nʳR$6f5EHfm bCDŽܚ\6JSq H TP`aлgeqic."Y0`:$p ?I|!(Jz2YD%oaé\GݎYZ_[3yËn 3ɳw]L@{\#<Vʁ=jntۛ6˾К 3kD##[?^ZcoF#ؖ :\eV|7|e."]E-GAjf??+ (Y+_7|7ztFTdFSj1,7?O=Ǎ5@jG"%0\S#T "SLcW[pe_WJL!Y%GxE` WأՈwAuoOP0vBVPE@C` ,q7zA".g)HNGUoyf=uF*KR/lY%e4VCdah6P!p 2h@Dd]Q# vt}P D \6?,$%A}_ ZQf^*-Q N!$2_'(DKfn.C=Q:Ads|΄wQ" 𷿇La²lP/oVӐe\ߵvmx@yG936evؓKZ@^"lb@AIjcX8a1Ͷ Z|7|6fb3^4xs?K\ c+0~έ<ώ#Dz -no[홎S,?kڂ>}Ryi(n 'Lz79qM.: 'MxBхmq"SL,_oM.x Q>7"V&+V͒r>L4S1[<4`(@ď ))cQ-}+Ӏ1^;~9xl+ .ql5mp;C-vt<7i g@('AwD%ɸbOd哆wb]3ה w)͠^Dk$B8\7) YB3 6 oҘN=\1{dt񸶲l$WeMed1l{@<ٱL$ E_h7P;kE2UHoOY2wA]ϻqHw>D`PcYg1lˊvÜhr AnE,mbDpk!ҫ 8nzQ2=2@+;U(wZ0F2 ~чG, !QXy܈k1" N)ջ ˜|k[o:'_=tsoh3*.KD#{w:&QUE5'\CGrfgԥ &a5FvƳԳref{&[P웯7*:*Tfoˊ'Z~p%5eƳgI5_c2H""&ly_8?5)JT(Qyᾀe\U(H{1 T3O^I}Zv^Ab  H#6p PuΠQg" ߒ9;c?cl ^o2'-R+09@Gx`Bd0zv'Wo׋M0JGpRz;J+a/ZA8+s'xP- # F@AǑ`}Ux:})oFhxoy50dĎs@7qiZ-B]'uB_/H-XL`X $&JAd2Udņr0P_C+>uK[OWBH.5yve\(?n>eRQy9NaOB5մafG؝C)nAes"ɀH@[8޶+?RpW˶oRFQR3RxXK~YmN { ꧩZ̚~wz cǫSn~w)kHK"2iheN: B`UT5Wت#i?Y} o45 脥v9b'EuFp[MISDȵB^!MiK?(EkNo+|e',KT77[H_B'ɶK#ΝW`?b5֨8qE[!l#n\sumg$Jp/'!,tOΘ*quLt2'h9+|yS7nV*7L"Kf؈4ۗq c:oC4C.((* $fq6=ڬsp ~8:Ɲ2ұsk# {AQ{m LH4@i/{>e"<0Z/P34@)@4M*K)ԏjL9EL[}sHHM$Q살 {<xmo tw9a!#!K*}2MY1GtJxfՕ8D#/ v|{d)84&y$0ZP ѷO5acP@U-%TQjՖka3.9B#_ۢ6 IDշ1S)=v1xk4}~JށT1YEiMH/ LB*<[Xi6ynq-õ# J,lQΕ0X>vQ;N,]aU; kR_YgVU|? O vsjtDd,`AQ[psݥ`k!y%mS.~ $!RwÝiKuLCq o' 6#Ơ/d2꧒(HKwġ,vB04x+"=v*{f]?(08og8Ӕ(=˹;q`U-(B]Lk'Gq!8 /r=T@ "FS$#,-muz#f_ed܆~ե*8FzBo(`WFfYۨ2t5 ;23|fKM [DUۘ{(?3uoY1̼] L1M%6+D}{dpTH!z+O^"d@3pir5)<7ǁ^ 9+}j &ig'`-cxnGW.yjFhWu8z3|o& O?E6R?E쨍y\K{wrA'ZGM2ʹȰ>º A8ScȢmPl ?VK2] uce̗CXI!s%T˨s<5K}a4."}v\[iB &:?(;4NUz.gtqMᨢ蘑%8dB=F"!""6&8:R%u$I$I$I$I xBKO :XŒ*ߞOl@gQ j "V8BBD!pl?R]w M&)wh z*+L} X6-ݤXV^ $Ρ>#;P>r$xRW 3(\{ { E(z~l/M8 H#R[7yK5VJ/AH3DmIGh:뺭]NС |[Bu} :1p|irߣrԦ˭en3(ݏ4 -6w뀧V&lWۥ[_tY9'$!ݵg]K7fˈ icnV BffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/0000755000076500000240000000000014400242511020664 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ColorPickerPopupPanel.nib/0000755000076500000240000000000014400242511025653 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ColorPickerPopupPanel.nib/classes.nib0000644000076500000240000000240612120476556030023 0ustar joshstaff{ IBClasses = ( { ACTIONS = { "" = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = PPColorPickerPopupPanel; LANGUAGE = ObjC; SUPERCLASS = PPPopupPanel; }, { ACTIONS = { colorWellUpdated = id; contentFrameButtonPressed = id; nextSamplerImageButtonPressed = id; previousSamplerImageButtonPressed = id; }; CLASS = PPColorPickerPopupPanelController; LANGUAGE = ObjC; OUTLETS = { "_clickableControlsBoundsTrackingView" = NSView; "_colorWell" = NSColorWell; "_nekoButton" = NSButton; "_nextSamplerImageButton" = NSButton; "_previousSamplerImageButton" = NSButton; }; SUPERCLASS = PPPopupPanelController; }, { CLASS = PPColorWell; LANGUAGE = ObjC; SUPERCLASS = NSColorWell; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPPopupPanel; LANGUAGE = ObjC; SUPERCLASS = NSPanel; }, { CLASS = PPPopupPanelController; LANGUAGE = ObjC; SUPERCLASS = PPPanelController; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ColorPickerPopupPanel.nib/info.nib0000644000076500000240000000067512120476556027327 0ustar joshstaff IBDocumentLocation 134 159 670 250 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 10K549 PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ColorPickerPopupPanel.nib/keyedobjects.nib0000644000076500000240000001272212120476556031043 0ustar joshstaffbplist00 !T$topX$objectsX$versionY$archiver]IB.objectdatay /34:;?COWopqrvz  $%&*23@DEMN[_`deghijmnrwx}~     U$null  !"#$%&'()*+,-.[NSNamesKeys[NSFramework_NSAccessibilityOidsValues_NSAccessibilityConnectors_NSObjectsValues]NSNamesValues]NSConnections]NSFontManagerVNSRootYNSNextOid_NSVisibleWindows]NSObjectsKeys]NSClassesKeysZNSOidsKeys\NSOidsValues_NSAccessibilityOidsKeysV$class_NSClassesValuesYwuXZDV_abvx`012[NSClassName_!PPColorPickerPopupPanelController5678X$classesZ$classname89^NSCustomObjectXNSObject_IBCocoaFramework<=>ZNS.objects56@AAB9\NSMutableSetUNSSet<DNEFGHIJKLM EGJLNPRT<PQRSTU%]NSDestinationWNSLabelXNSSource CDXYZ[\]^_`abcdefghijklmn_NSWindowStyleMask_NSWindowBackingYNSMinSize]NSWindowTitle]NSWindowClass\NSWindowRect\NSScreenRectYNSMaxSize\NSWindowViewYNSWTFlags[NSViewClass@ ?AxB_{{438, 627}, {100, 126}}UPanel_PPColorPickerPopupPanelstuYNS.stringTView56wxxy9_NSMutableStringXNSString{|}~$ZNSSubviews_NSNextResponderWNSFrame=><N!*27<|}kk[NSSuperviewYNSEnabledXNSvFlagsVNSCell _{{0, 58}, {100, 80}}_NSKeyEquivalent_NSAlternateImageYNSSupportZNSContents]NSControlView^NSButtonFlags2_NSPeriodicInterval]NSButtonFlags_NSPeriodicDelay[NSCellFlags_NSAlternateContents\NSCellFlags2PVNSSizeVNSNameXNSfFlags#@*\LucidaGrande569VNSFontsuP56ĥ9\NSButtonCell]%NSButtonCell\NSActionCellVNSCell56ʥ9XNSButtonYNSControlVNSView[NSResponder|0kk[NSExtension[NSFrameSize" Y{100, 60}suVNSView56ޤ9\NSCustomView|}0kkWNSColor_NSOriginalClassName[NSDragTypes'#& )$"[PPColorWell[NSColorWell<>%su_NSColor pasteboard type_{{0, 65}, {100, 20}}UNSRGB\NSColorSpaceO0.05813049898 0.05554189906 1(569WNSColor569^NSClassSwapper|}kk + $,_{{2, 4}, {9, 14}} ]NSNormalImage.-*KD@#@$ 0!"#^NSResourceName01/WNSImage_arrow_outline_left_button56'(()9_NSCustomResource_%NSCustomResource|}kk-/13 $4_{{11, 4}, {9, 14}} 59:<=?5-2KD@ 0A"#61/_arrow_outline_right_button|}kkHJL8 -9_{{13, 23}, {75, 81}} PTUWXZ:-7KD@ 0\"#;1/Tneko56abbc9^NSMutableArrayWNSArray_{{1, 1}, {100, 126}}56f̣9_{{0, 0}, {1440, 878}}]{96.2896, 21}_{3.40282e+38, 3.40282e+38}56kll9_NSWindowTemplateVwindow56oppq9_NSNibOutletConnector^NSNibConnectorPQRtU%!FDZ_colorWellPQR%z{HI!_colorWellUpdated:569_NSNibControlConnector^NSNibConnectorPQR%{KI2_nextSamplerImageButtonPressed:PQRU%2MD__nextSamplerImageButtonPQRU%*OD__previousSamplerImageButtonPQR%{QI*_"previousSamplerImageButtonPressed:PQRU%7SD[_nekoButtonPQRU%UD_$_clickableControlsBoundsTrackingView<kS* 2!7W56cc9<Skk%kkkk W<S%! W<f̀[ \]^WQ2\File's OwnerTView<!W<"W<kFHLIMSG%KEJEJ7RLT !GP 2*NW<cdefghijklmnopqrstW'5@;A7B%):3C89<N<<W<W569^NSIBObjectData_NSKeyedArchiver'0:?MODJ!(2ESaly */>GZcnoqz-AS]ky#-24=DV_p{  )^p !#%'0249;@ARY`irtvy$AMY[]_acegqz   ' 0 3 5 7 @ Z \ s       * _ m o q s u w y   0 M O Q S T W Y [ p      " $ & = r t v x z | ~  $ A J O b i r y '8:<>@artvxz  ".?ACEGnw  #(1468ADFHQxz|~   "+,.78:CHW\"nPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/Credits.rtf0000644000076500000240000000267113127530410023007 0ustar joshstaff{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 {\fonttbl\f0\fnil\fcharset0 Monaco;} {\colortbl;\red255\green255\blue255;\red0\green0\blue128;\red0\green179\blue255;} \vieww11400\viewh8400\viewkind0 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc \f0\fs24 \cf0 \ \cf2 Developed by Josh Freeman\ {\field{\*\fldinst{HYPERLINK "mailto:pikopixel@twilightedge.com"}}{\fldrslt \cf0 pikopixel@twilightedge.com}}\cf0 \ \cf2 \ Twilight Edge Software\cf0 \ {\field{\*\fldinst{HYPERLINK "http://twilightedge.com"}}{\fldrslt http://twilightedge.com}}\ \ \pard\tx480\pardeftab480\qc\pardirnatural \fs18 \cf0 \CocoaLigature0 PikoPixel is free software: you can\ redistribute it and/or modify it under\ the terms of the GNU Affero General\ Public License as published by the\ Free Software Foundation, either\ version 3 of the License, or (at your\ option) any later version approved\ for PikoPixel by its copyright holder\ (or an authorized proxy).\ \ PikoPixel 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\ Affero General Public License for more\ details.\ \ You should have received a copy of\ the GNU Affero General Public License\ along with this program. If not, see\ <{\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/"}}{\fldrslt http://www.gnu.org/licenses/}}>. \fs20 \cf3 \ }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentBackgroundSettingsSheet.nib/0000755000076500000240000000000014400242511027723 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentBackgroundSettingsSheet.nib/classes.nib0000644000076500000240000000663612153703573032102 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = NSTextField; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = NSWindow; LANGUAGE = ObjC; SUPERCLASS = NSResponder; }, { CLASS = PPColorWell; LANGUAGE = ObjC; SUPERCLASS = NSColorWell; }, { ACTIONS = { backgroundImageViewUpdated = id; copyImageToPasteboardButtonPressed = id; imageSmoothingCheckboxClicked = id; "patternPresetsMenuItemSelected_AddCurrentPatternToPresets" = id; "patternPresetsMenuItemSelected_CustomPattern" = id; "patternPresetsMenuItemSelected_DefaultPattern" = id; "patternPresetsMenuItemSelected_EditPresets" = id; "patternPresetsMenuItemSelected_ExportPresetsToFile" = id; "patternPresetsMenuItemSelected_ImportPresetsFromFile" = id; "patternPresetsMenuItemSelected_PresetPattern" = id; "patternPresetsMenuItemSelected_RestoreOriginalDefault" = id; "patternPresetsMenuItemSelected_SavePatternAsDefault" = id; patternSettingChanged = id; removeImageButtonPressed = id; setImageToFileButtonPressed = id; setImageToPasteboardButtonPressed = id; showImageCheckboxClicked = id; }; CLASS = PPDocumentBackgroundSettingsSheetController; LANGUAGE = ObjC; OUTLETS = { "_backgroundImageView" = NSImageView; "_copyImageToPasteboardButton" = NSButton; "_defaultPatternPresetsMenu" = NSMenu; "_imageSmoothingCheckbox" = NSButton; "_patternColor1Well" = NSColorWell; "_patternColor2Well" = NSColorWell; "_patternDisplayField" = NSTextField; "_patternPresetsPopUpButton" = NSPopUpButton; "_patternSizeSlider" = NSSlider; "_patternTypeMatrix" = NSMatrix; "_removeImageButton" = NSButton; "_showImageCheckbox" = NSButton; }; SUPERCLASS = PPDocumentSheetController; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; }; CLASS = PPDocumentSheetController; LANGUAGE = ObjC; OUTLETS = { "_sheet" = NSWindow; }; SUPERCLASS = NSObject; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; }, { CLASS = PPParabolicSlider; LANGUAGE = ObjC; SUPERCLASS = NSSlider; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentBackgroundSettingsSheet.nib/info.nib0000644000076500000240000000140512153703573031365 0ustar joshstaff IBDocumentLocation 271 33 356 240 0 0 1440 878 IBEditorPositions 117 802 263 301 238 0 0 1440 878 IBFramework Version 489.0 IBLastKnownRelativeProjectPath ../PikoPixel.xcodeproj IBOldestOS 5 IBOpenObjects 5 117 IBSystem Version 9L31a targetFramework IBCocoaFramework ././@LongLink0000000000000000000000000000015000000000000011702 Lustar rootwheelPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentBackgroundSettingsSheet.nib/keyedobjects.nibPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentBackgroundSettingsSheet.nib/keyedobjects.0000644000076500000240000004526012155425417032423 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AElt")*>?DEFJPWXabcuy !*+/0234<=EFGKNQT^bpwx ,1237AEFNRS[_`imnw{|}~}  '(/0456789<=BCHINOTUZ[`afglmrw|}  #$)*/056;<ABGHMNSTYZ_`efL !"#$%&'()*+,-.4:B     v !"#$%&'()*+,-./012345678;>AU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesÁEi€IhjJHk234[NSClassName_+PPDocumentBackgroundSettingsSheetController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGl$HIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijk $  #%')+-/13579;=?ACmnoprs]NSDestinationXNSSourceWNSLabel uvwxyz{|2}~~_NSNextResponderWNSFrame_NSOriginalClassNameWNSColor[NSDragTypesXNSvFlagsYNSEnabled\NSIsBordered[NSSuperview   [PPColorWell[NSColorWelluv}ZNSSubviewsznހ|z>?YNS.string_NSColor pasteboard type78;_NSMutableStringXNSString_{{269, 63}, {63, 24}}\NSColorSpaceUNSRGBO0.058130499 0.055541899 178xx;78;^NSClassSwapper_patternSettingChanged:78;_NSNibControlConnector^NSNibConnectormno#"uvwz{2}~~VNSCell   _PPParabolicSliderXNSSlider_{{199, 40}, {133, 15}}WNSValue[NSCellFlags_NSNumberOfTickMarks_NSTickMarkPositionZNSContentsYNSSupport]NSControlViewZNSMaxValueZNSMinValue\NSCellFlags2ZNSVertical]NSAltIncValue_NSAllowsTickMarkValuesOnly#@I!#@Y#݀PVNSSizeVNSNameXNSfFlags #@(YHelvetica78;VNSFont78;\NSSliderCell\NSActionCell__patternSizeSlider78;_NSNibOutletConnectormno#,%     \NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass*'px(&)_{{321, 364}, {370, 457}}VWindow_PPKeyCancellableWindowTViewu+[NSFrameSizen+>Fl!,6;zuvz{}$%&*5-. *_{{281, 5}, {80, 28}}+,-./0123456786;<=_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalent_NSPeriodicDelay]NSButtonFlags4203/0,@ROKABC #@&1 \LucidaGrandeQ 78GHHI;\NSButtonCell]%NSButtonCell78KLLMNO;XNSButtonYNSControlVNSView[NSResponderuvz{}$ST*578 *_{{197, 5}, {80, 28}}+,-./012345[6]^6;<=420:906VCancelQ.udevfghi}jlmnpqr tYNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition]NSContentView*yqo<p*=>Fwlt=uv}|};nm>;>Fl?KQV^chuvyz{}ttZNSEditable=JG H@ =>?ABCDEF_Apple PDF pasteboard type_Apple PNG pasteboard type_NSFilenamesPboardType_1NeXT Encapsulated PostScript v1.2 pasteboard type_NeXT TIFF v4.0 pasteboard type_Apple PICT pasteboard type_{{9, 53}, {138, 138}} WNSStyleWNSAlignWNSScaleZNSAnimates!I78;[NSImageCell\%NSImageCell78MNO;[NSImageViewuvz{}t$t=5LM =_{{150, 164}, {186, 28}}+,-./012345[6;<=42OPN0KoSet to File... (#O)AB 1Qouvz{}t$t=5RS =_{{150, 50}, {186, 28}}+,-./012345[6;<=42OUT0QkRemove (##+)Quvz{}t$t=5WX =_{{9, 31}, {86, 16}}+,-./0123456;42Z]Y0VH?ABCD[NSColorName]NSCatalogNamevutVSystem_textBackgroundColorHqJWNSWhiteB1HqMM0 0.8000000178OPP;_NSTextFieldCell78RSSNO;UNSBoxudevfghi}jlWXZqr ~*y{p* >F`l~ >Fdlefgrjklmno} Ȁuvz{}~rst~ ~ _{{199, 95}, {133, 49}}5y627{4}e_NSDrawsBackgroundx2}@ B #@*1O!0.52861828 0.54081023 0.55985349x>?BDt_controlTextColorHqB078MNO;[NSTextField\%NSTextFielduvz{}~r~ _{{12, 12}, {132, 132}}5y6784}f@xs2@ x>?BDtYtextColoruvwxyz{|2}~~  >?_{{199, 63}, {63, 24}}uvz{}~r~ _{{160, 131}, {34, 14}}56276jx0UType:x>?BDt\controlColorHqۀK0.66666669uvz{}~r~ _{{152, 68}, {42, 14}}56276kx0WColors:uvz{}~r~ _{{164, 42}, {30, 14}}56276lx0USize:uv5z{}~     {q~ [NSProtoCell]NSSelectedRowYNSNumRows[NSCellClass_NSCellBackgroundColorZNSCellSizeYNSNumCols_NSIntercellSpacing]NSMatrixFlags]NSSelectedColWNSCells ǀ _{{200, 96}, {131, 47}}>Fl+!,-/01"34%5B44}m;*+]NSNormalImage4222L@2-./0^NSResourceNameWNSImage]solid_segment784556;_NSCustomResource_%NSCustomResource+!,-/018234;5B44}m;*@UNSTag4222D@2-./D_diagonal_lines_segment+!,-/018234I5B44}m;*@ 42222-./Q_isometric_lines_segment+!,-/018234V5B44}m;*+q42222-./^_checkerboard_segment+!,-/018234c5B44}m;*@h42222-./l_diagonal_checkerboard_segment+!,-/018234q5B44}m;*@v42222-./z_isometric_checkerboard_segmentX{43, 23}V{1, 1}+!,-0182345B};* 42@@VButtonx\NSImageFlagsVNSRepsƀ >Fl>Ģ_NSTIFFRepresentationÀOMM*  RS78;_NSBitmapImageRepZNSImageRep78..;HqD0 07811;X%NSImage78MNO;XNSMatrixY%NSMatrixuvz{}~r~ ɀ _{{153, 13}, {41, 14}}56276nxˀ0ȀWPreset:uvz{}~~ ݀̀ _{{196, 8}, {139, 22}}+,-./0146oq_NSMenuItemRespectAlignment_NSArrowPositionZNSMenuItem_NSPreferredEdge_NSUsesItemFromMenu]NSAltersStateVNSMenuA@ 2K܀Oπ0Ѐ @݀4XNSTargetWNSTitle_NSKeyEquivModMaskZNSKeyEquiv]NSMnemonicLocYNSOnImage\NSMixedImageXNSActionWNSState΀؀2ӀՀр[NSMenuItemsۀـTNone2-./_NSMenuCheckmark2-./_NSMenuMixedState__popUpItemAction:78Ǣ;ZOtherViews>F lԀ78 ˢ;78HI;_NSPopUpButtonCell^NSMenuItemCell78LMNO;]NSPopUpButton_{{2, 2}, {344, 156}}_{{11, 262}, {348, 173}}562786xs0WPatternHqMuvz{}r#$* *_{{114, 431}, {143, 17}}5627+,!x。_Background Settings23 _LucidaGrande-BoldZ{370, 457}_{{0, 0}, {1440, 878}}Z{213, 129}_{3.40282e+38, 3.40282e+38}78:;;;_NSWindowTemplate_initialFirstRespondermnopA,_OKButtonPressed:mnopGV_showImageCheckboxClicked:mnoM#V__showImageCheckboxmnoS#%V_sheetmnogY#__patternColor1Wellmnof_#__patternDisplayFieldmnore# __patternColor2Wellmnok#?__backgroundImageViewmnopgsmnopsmno{#6%]_cancelButtonmnop?_backgroundImageViewUpdated:mnop6_cancelButtonPressed:mnom#__patternTypeMatrixmnopmsmno# "4ہ 2 TMenu>Fl 84؁2ӀՁ WDefault84 ؁2ӀՁ VCustom44]NSIsSeparator؀2 2ӀՁ 8q؁ӀՁ _!Add Current Pattern to Presets...Qk؁ӀՁ _Edit Presets...QB4؁2ӀՁ _Import Presets from File...84h؁2ӀՁ _Export Presets to File...44؀2 2ӀՁ 4؁2ӀՁ _Save Current Pattern as Default4؁!2ӀՁ _Restore Original Default__defaultPatternPresetsMenumnop$_.patternPresetsMenuItemSelected_DefaultPattern:mnop &_-patternPresetsMenuItemSelected_CustomPattern:mnop(_4patternPresetsMenuItemSelected_SavePatternAsDefault:mnop *_6patternPresetsMenuItemSelected_RestoreOriginalDefault:mnoo#̀,__patternPresetsPopUpButtonmnop"._3patternPresetsMenuItemSelected_ExportPresetsToFile:mnop(0_5patternPresetsMenuItemSelected_ImportPresetsFromFile:mnop.2_:patternPresetsMenuItemSelected_AddCurrentPatternToPresets:mnop44_+patternPresetsMenuItemSelected_EditPresets:mno:#c6__copyImageToPasteboardButtonmno@#Q8__removeImageButtonmnopFK:_setImageToFileButtonPressed:mnopL^<_"setImageToPasteboardButtonPressed:mnopRc>_#copyImageToPasteboardButtonPressed:mnopXQ@_removeImageButtonPressed:mno^#hB__imageSmoothingCheckboxmnopdhD_imageSmoothingCheckboxClicked:>hį/lftjmerk!n~goK%=Ѐ } 6^ VрȀ ch?z;F*̀Q,23G]NSApplication>į/~t~m~~~~t~tom~ttt~mm~~tmm  =  ;  р  *= * =̀ z=== **   % = *  >Ѐį lfjernk!goK%Ё }6 Ȁ^Vрch?z;F*̀Q,>į      KL'MNOOPQRSTUVWXUYZ[\]^_`abcdefg_Static Text (Size:)_Push Button (Choose...)ZText Field_Static Text (Type:)_DefaultPatternPresets\NSTextField2_Push Button (Cancel)\Color Well-1_Static Text (Size:)1_Static Text (Colors:)_!Static Text (Background Settings)_Check Box (Show Image)YPopUpListYNSButton1YNSButton4ZImage Well]Box (Pattern)[Box (Image)ZColor Well[Application_Horizontal Slider\Content View_Push Button (Clear)[NSMenuItem1_Push Button (OK)\File's Owner>0ģgr >6ģ  ><įTlf]SLVhWcm`!I~_kXo^[UQN\tKjgMeerknOZjbRHJTgaYdPif'=Ё3^-ch +zF*Ć)Q#,%K%=;󀣁7}6V   Ȁс A1? ;$/ 5?9>įTlmnopqrstuvwxyz{|}~0GA@DwlP5ONmnr#o~%pz49{"MqQ.7kt&',/u|3y}6HxLJI(s-v1>F:l>=Ġ>@Ġ78BCC;^NSIBObjectData"'1:?DRTfCJQ_q)CMZ\_behjmorux{} '245>ERXac -6>@BDFs%02468:CEHJS]_y    ( A J Q i x  ; C O e z      % & ' 0 2 3 D K R [ ] f h j t }     ; H U c m {  " + - 2 C O Q S U W ` b m o q s u w %8J\joqsuwy{}+HJLNPQSj'9GIKMOPRTVXZcehj   /Kc "-245>GS`it.?ACEbdfhjkm  UWY^`bdfhmx79;=?ACEtv+-JLNPRSUl -4Qeqsuwy{ 2;DJ{}:NPRTVX]^`qs|~ %BDFHJKMf  %'?LNkmoqstv$&(*,-/Ghjlnprt|:FT^j*,.0246ky FLNPRTVXZcprtv  < > @ B D F H J W Y [ ] t !)!+!-!/!1!3!5!7!9!F!H!J!L!m!v!}!!!!!!!!!!!!!!!!"" " """"" """+"B"D"F""#####,#1#>#@#E#N#U#^#g#t#}#################$$$$$!$"$$$<$$$$$$$%% % % %%%%%%%%%% %%%'%,%5%7%d%m%u%%%%%%%%%%%%%%%%%%%%&&&&&&&&-&:&<&>&@&S&g&p&u&~&&&&&&&&&&&&&&'''9'V'X'Z'\'^'`'h'u'w''''''''''''''''( ((((((3(K(V(s(|(((((((((((((() )) )")$)&);)L)N)P)R)T)[)l)n)p)r)t)))))))))))))))))***(***,*.*0*A*C*E*G*I*Z*\*^*`*c*q*****************+ ++++ +"+3+5+8+:+=+N+P+S+U+X+]+f+h+}++++++++++++++++++++,,,,, ,,5,C,E,G,H,J,L,N,Q,v,x,{,~,,,,,,,,,,,,,,--------<-a-c-f-h-j-l-o----------------..0.2.5.7.9.;.>.Y.v.........../ // /"/%/(/_/p/r/t/w/z//////////000;0L0N0P0S0V0000000000011/1@1B1D1F1I1h1y1{1}1111111111111122 2"2$2&2)2O2`2b2d2f2i2222222222222223`3b3e3g3i3l3n3p3r3t3w3y3{3~33333333333333333333333333333333333333334R4T4W4Y4[4^4`4b4d4f4i4k4m4o4q4s4u4w4z4|4~4444444444444444444444444444455 5 555555555 5"5$5&5(5*5,5.50525456585:5=5?5A5C5E5H5J5L5U5W55555555555555555555555555555555566)646J6b6o6666667 777(767B7M7Y7m7z77777777777777777788888888888888888888888888888888888888899999 9 999999999!9#9%9'9)9,9/919396989;9>9A9C9E9G9J9L9N9Q9S9V9Y9\9^9a9d9f9i9k9n9w9y:$:':*:-:0:3:6:9:<:?:B:E:H:K:N:Q:T:W:Z:]:`:c:f:i:l:o:r:u:x:{:~:::::::::::::::::::::::::::::::::::::::::::;;;; ;;;;;;; ;";$;&;(;*;,;.;0;2;4;6;8;:;<;>;@;B;D;F;H;J;L;N;W;Y;[;];_;a;c;e;g;i;k;m;o;q;s;u;w;y;{;};;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;D<PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditPatternPresetsSheet.nib/0000755000076500000240000000000014400242511027714 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditPatternPresetsSheet.nib/classes.nib0000644000076500000240000000263312726342617032070 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = PPColorWell; LANGUAGE = ObjC; SUPERCLASS = NSColorWell; }, { ACTIONS = { addCurrentPatternAsPresetButtonPressed = id; removeAllPresetsButtonPressed = id; removePresetButtonPressed = id; }; CLASS = PPDocumentEditPatternPresetsSheetController; LANGUAGE = ObjC; OUTLETS = { "_editablePatternsTable" = NSTableView; "_patternView" = PPPresettablePatternView; "_removeAllPresetsButton" = NSButton; "_removePresetButton" = NSButton; "_sheetTitleField" = NSTextField; }; SUPERCLASS = PPDocumentSheetController; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; }; CLASS = PPDocumentSheetController; LANGUAGE = ObjC; OUTLETS = { "_sheet" = NSWindow; }; SUPERCLASS = NSObject; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; }, { CLASS = PPParabolicSlider; LANGUAGE = ObjC; SUPERCLASS = NSSlider; }, { CLASS = PPPresettablePatternView; LANGUAGE = ObjC; SUPERCLASS = NSView; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditPatternPresetsSheet.nib/info.nib0000644000076500000240000000067512726342617031372 0ustar joshstaff IBDocumentLocation 137 227 356 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 5 IBSystem Version 10K549 ././@LongLink0000000000000000000000000000015000000000000011702 Lustar rootwheelPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditPatternPresetsSheet.nib/keyedobjects.nibPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditPatternPresetsSheet.nib/keyedobjects.0000644000076500000240000002316712726342617032422 0ustar joshstaffbplist00T$topX$objectsX$versionY$archiver]IB.objectdata /34:;?CRZrstuy} %&'9=CL^drv   #$1278@ALQRZ[ijkst !1AB CDEFGHKNmfU$null  !"#$%&'()*+,-.[NSNamesKeys[NSFramework_NSAccessibilityOidsValues_NSAccessibilityConnectors_NSObjectsValues]NSNamesValues]NSConnections]NSFontManagerVNSRootYNSNextOid_NSVisibleWindows]NSObjectsKeys]NSClassesKeysZNSOidsKeys\NSOidsValues_NSAccessibilityOidsKeysV$class_NSClassesValues̀ˀP̀΀012[NSClassName_+PPDocumentEditPatternPresetsSheetController5678X$classesZ$classname89^NSCustomObjectXNSObject_IBCocoaFramework<=>ZNS.objects56@AAB9\NSMutableSetUNSSet<DQEFGHIJKLMNOP KSTUVWX%]NSDestinationWNSLabelXNSSource [\]^_`abcdefghijklmnopq_NSWindowStyleMask_NSWindowBackingYNSMinSize]NSWindowTitle]NSWindowClass\NSWindowRect\NSScreenRectYNSMaxSize\NSWindowViewYNSWTFlags[NSViewClass px_{{420, 530}, {374, 313}}VWindow_PPKeyCancellableWindowvwxYNS.stringTView56z{{|9_NSMutableStringXNSString~$ZNSSubviews_NSNextResponderWNSFrame~u<Q#-2Knn[NSSuperviewYNSEnabledXNSvFlagsVNSCell "_{{11, 287}, {352, 17}}_NSBackgroundColor[NSTextColorYNSSupportZNSContents]NSControlView[NSCellFlags\NSCellFlags2!@_Edit Background Pattern PresetsVNSSizeVNSNameXNSfFlags#@*_LucidaGrande-Bold569VNSFontWNSColor[NSColorName\NSColorSpace]NSCatalogNameVSystem\controlColorWNSWhiteM0.666666686556ɢ9WNSColor _controlTextColorB056դ9_NSTextFieldCell\NSActionCellVNSCell56ڦ9[NSTextField\%NSTextFieldYNSControlVNSView[NSRespondernn$ ,%_{{285, 5}, {80, 28}}f_NSKeyEquivalent_NSAlternateImage^NSButtonFlags2_NSPeriodicInterval]NSButtonFlags_NSPeriodicDelay_NSAlternateContents*''&#@+)ROK#@&( \LucidaGrandePQ 56  9\NSButtonCell]%NSButtonCell\NSActionCellVNSCell56   9XNSButtonnn. ,/_{{201, 5}, {80, 28}}!"$1''0-@+)VCancelQ.~()*+,-./nn23456728\NSBorderType_NSTitlePosition[NSTitleCellYNSOffsets]NSTransparent]NSContentViewYNSBoxType3xvw4}<:Q74K~>A522tu<DQEFGHIJ6[afkoK~MNOP-QR77UVWXYZU\]]NSNextKeyView[NSHScrollerXNSsFlags[NSVScroller\NSScrollAmts7448YWrS8ZOA A AA<_QUZW8SWK~MefghEEklknopqYNSBGColorYNSDocViewYNScvFlags966:H:Q R<sQk:Kwxyz{|}~UUf22[NSRowHeight[NSFrameSize^NSTableColumns_#NSTableViewDraggingDestinationStyle\NSCornerView_NSColumnAutoresizingStyle_NSDraggingSourceMaskForLocal_NSIntercellSpacingHeight[NSGridColorYNSTvFlags_NSDraggingSourceMaskForNonLocal_NSAllowsTypeSelect_NSIntercellSpacingWidth#@1;88?<#@ M@ #@PLZ{141, 190}$=>_{{-26, 0}, {16, 17}}569]_NSCornerView]_NSCornerView<Q@Kk^NSResizingMask[NSTableView\NSHeaderCellZNSMinWidthWNSWidth^NSIsResizeable\NSIsEditableZNSDataCellZNSMaxWidth:A#@ #@a@ F#@@J2BC')EM0.3333329856 D_headerTextColor56˥9_NSTableHeaderCell\NSActionCellVNSCell_NSTableHeaderCelllkӀHG:!!@#@*(I_controlBackgroundColor569]NSTableColumn569^NSMutableArrayWNSArrayB1ONYgridColorD0.5569[NSTableView\%NSTableView[NSTableView_{{1, 1}, {141, 156}}569ZNSClipViewEEEXNSTargetYNSPercentXNSAction666T V#?F U_{{142, 1}, {15, 156}}\_doScroller:56   9ZNSScrollerOEEEf666XV#?NU_{{1, 142}, {141, 15}}_{{12, 65}, {158, 158}}569\NSScrollView77 "44\ ,]_{{174, 33}, {166, 28}}%&(Ff*+-.0`_'^[@+)oRemove Preset (#+)36#@&(Q77;=?44b "c_{{178, 65}, {158, 158}}BDGJK_NSDrawsBackgroundLdG)a !@@N eYtextColor77UWY44g ,h_{{8, 33}, {166, 28}}\&_Habcefhj_'if@+)oAdd Current Pattern (#K)Qk77npr44l ,m_{{174, 6}, {166, 28}}%&xIz{|~`_'nk@+)oRemove All Presets (##+)077[NSExtensionr44psq_{{179, 66}, {156, 156}}_PPPresettablePatternView569\NSCustomView_{{2, 2}, {348, 235}}56ݣ9_{{11, 41}, {352, 239}}V{0, 0}&2z|_y!UTitleL{_textBackgroundColorO0 0.8000000119569UNSBox_{{1, 9}, {374, 313}}_{{0, 0}, {1440, 878}}Z{213, 129}_{3.40282e+38, 3.40282e+38}569_NSWindowTemplateV_sheet569_NSNibOutletConnector^NSNibConnectorSTU%-_cancelButtonPressed:569_NSNibControlConnector^NSNibConnectorSTU%#_OKButtonPressed:STUFX%[__removePresetButtonSTUIX%k__removeAllPresetsButtonSTU%Hf_'addCurrentPatternAsPresetButtonPressed:STU%F[_removePresetButtonPressed:STU%Ik_removeAllPresetsButtonPressed:STUXV- ]_cancelButtonSTUX%__sheetTitleFieldSTUkX%:__editablePatternsTableSTUJX%o\_patternView< GJ7IFHVknEao-4#k[f2@ :6569< 77nn777nk%EV7n442444:6 4<" GJFIHVk%Eao-#[kf@ :6<2 3456685:i<=>? TViewYNSButton1YNSButton2[NSTableView\File's Owner]NSScrollView1\NSTextField2<I <L <O VJPLEEG%KMk7NnOFIHIFGJH 6@#:-42[kfao<n opqrstuvwxyz{|}~€ÀĀŀƀǀȀɀʀAOC BJ!KL "76@3N?<QK< < 569^NSIBObjectData_NSKeyedArchiver'0:?MOAMYu %?FXZ\^`bdfhjlnprtvxz|$%'07DJSlnprtvxz|~-;HU_lv.9KSUWY[dmoqsuw",7EQ^`bdfhjot  -;=?ACELYfn|~   & 2 ? I P \ y { }    * < R T V X Z \ ^ g i k p r w z  ( * , . / 2 4 6 M    ) 7 A C E G I K M O P R T ] ` b d y { }         # & ( * , ? H O Q S U W *9_l)2468:<ENOQVWZcegr+8CKZgr}#.BOVj +3@CEZ\^`bly~'024689<>GIanw  =?ACDGIKd"$&(),.0Jo<>@BDFKMVXZ_af"$-/168=n 3:WY[]_afl/8=PW`g~    13579O`bdfh 5FHJLN\moqsu   "$&(*38Abdfhjlnprtvxz|~'4BOXY[degp)+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditSizePresetsSheet.nib/0000755000076500000240000000000014400242511027211 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditSizePresetsSheet.nib/classes.nib0000644000076500000240000000261713125260206031352 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { ACTIONS = { addPresetButtonPressed = id; defaultListButtonPressed = id; deletePresetButtonPressed = id; }; CLASS = PPDocumentEditImageSizePresetsSheetController; LANGUAGE = ObjC; OUTLETS = { "_heightTextField" = NSTextField; "_presetsTable" = NSTableView; "_widthTextField" = NSTextField; }; SUPERCLASS = PPDocumentSheetController; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; }; CLASS = PPDocumentSheetController; LANGUAGE = ObjC; OUTLETS = { "_sheet" = NSWindow; }; SUPERCLASS = NSObject; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditSizePresetsSheet.nib/info.nib0000644000076500000240000000067413125260207030652 0ustar joshstaff IBDocumentLocation 665 75 483 400 0 0 1680 1028 IBFramework Version 489.0 IBOpenObjects 5 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentEditSizePresetsSheet.nib/keyedobjects.nib0000644000076500000240000002335413125260207032372 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AET\tuvw{ /39DU[im '(/0;@AFGNOW^_lqrsw~   "6FVWXY Z[\]`cqU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValues܀ۀـ%234[NSClassName_-PPDocumentEditImageSizePresetsSheetController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGKHIJKLMNOPQRS UVWXY[]NSDestinationXNSSourceWNSLabel ]^_`abcdefghijklmnopqrs\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass px _{{281, 167}, {322, 282}}VWindow_PPKeyCancellableWindowxyzYNS.stringTView78|}}~;_NSMutableStringXNSString+_NSNextResponderWNSFrameZNSSubviews>FK#-2hhVNSCellXNSvFlagsYNSEnabled[NSSuperview" _{{81, 256}, {160, 17}}[NSCellFlags_NSBackgroundColorZNSContentsYNSSupport]NSControlView\NSCellFlags2[NSTextColor!@_Edit Image Size PresetsVNSSizeVNSNameXNSfFlags#@*_LucidaGrande-Bold78;VNSFontWNSColor\NSColorSpace[NSColorName]NSCatalogNameVSystem\controlColorWNSWhiteK0.6666666978; _controlTextColorӀB078֤;_NSTextFieldCell\NSActionCell78ڦ;[NSTextField\%NSTextFieldYNSControlVNSView[NSResponderhh,$% _{{233, 5}, {80, 28}}q_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalent_NSPeriodicDelay]NSButtonFlags+)'*&'#@ROK#@&( \LucidaGrandePQ 78;\NSButtonCell]%NSButtonCell78  ;XNSButtonh h,./ _{{149, 5}, {80, 28}}+)'10'-VCancelQ. !"#$h&'()*+,&h.YNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition]NSContentView34>F1K.467252>F;K<=>?@ABC6[_cjmtyEFGHI$.KLMNOP.RSS[NSHScrollerXNSsFlags\NSScrollAmts[NSVScroller]NSNextKeyView4WZY7OA A AA4S88>FWKSRK8SW\]^I<`abcdef<eYNScvFlagsYNSDocViewYNSBGColor6RQ9 :H6:>FkKe:nopqrstuvwxyS&{|}&S_NSDraggingSourceMaskForNonLocalYNSTvFlags_NSAllowsTypeSelect\NSCornerView_NSIntercellSpacingWidth_NSColumnAutoresizingStyle_NSIntercellSpacingHeight[NSFrameSize[NSGridColor_NSDraggingSourceMaskForLocal^NSTableColumns[NSRowHeight8P@L <#@#@; M8?#@1Z{132, 190}+>=_{{-26, 0}, {16, 17}}78;]_NSCornerView>FK@e^NSIsResizeable\NSHeaderCellWNSWidthZNSDataCell^NSResizingMaskZNSMinWidthZNSMaxWidth\NSIsEditable[NSTableView JA#@` F#@ #@@ :&EB)'CK0.33333299 D_headerTextColor78;_NSTableHeaderCellfe!@!HG:Ȁ(I_controlBackgroundColor78Ѣ;]NSTableColumn78ԣ;^NSMutableArrayWNSArray؀B1ONYgridColorD0.578;\%NSTableView_{{1, 1}, {132, 150}}78;ZNSClipView<<<XNSTargetXNSActionYNSPercent66VT U6#?C^`_{{133, 1}, {15, 150}}\_doScroller:78;ZNSScrollerF<<q<66VX U6#?_{{1, 136}, {132, 15}}_{{13, 38}, {149, 152}}78;\NSScrollView.  .4"\] 4_{{170, 170}, {45, 17}}=!^G[VWidth:..4"`a 4_{{170, 138}, {50, 17}}#>!bG_WHeight:.+,.4"de 4_{{225, 168}, {58, 22}}124?8:_NSDrawsBackgroundqA!f)Gc@ h}>Lg_textBackgroundColorD iYtextColor.JK.4"kl 4_{{225, 136}, {58, 22}}124@8:!f)Gj h.Z[.4,no 4_{{11, 11}, {33, 23}}`cdpAijk]NSNormalImage+)pK))Gm@2mnop^NSResourceNamesqrWNSImage_plus_button_overlay_small78tuuv;_NSCustomResource_%NSCustomResource.z{.4,uv 4_{{46, 11}, {33, 23}}`dpBijk+)w))Gt2mnosqx_minus_button_overlay_small..4,z{ 4_{{80, 8}, {87, 28}}qC+)}~|'y\Default List(xy_{{2, 2}, {296, 204}}78ݣ;_{{11, 41}, {300, 208}}V{0, 0}4&!f}UTitleM0 0.8000000178;UNSBox_{{1, 9}, {322, 282}}_{{0, 0}, {1680, 1028}}Z{213, 129}_{3.40282e+38, 3.40282e+38}78;_NSWindowTemplateV_sheet78;_NSNibOutletConnector^NSNibConnectorUVWŀ-_cancelButtonPressed:78ɣ;_NSNibControlConnectorUVW΀#_OKButtonPressed:UBXNSMarkerVNSFilet_NSToolTipHelpKey_Delete Selected Layer78ۢ;_NSIBHelpConnectorUAրmYNew LayerUVWXe怍:]_presetsTableUVWX?쀍c__widthTextFieldUVWX@򀍀j__heightTextFieldUVWAm_addPresetButtonPressed:UVWBt_deletePresetButtonPressed:UVWCy_defaultListButtonPressed:UVWXY - ]_cancelButton> <h=?.eACBY>@6[2c4:my-t@ _#j78!բ;> $.Y.h.<.h.h.e.h.4 4426444:44> 8<?=eCY>@6c[:y-@ _#j> HIJKLMNOPQkSOU ]NSScrollView1]NSTextField21\File's Owner\NSTextField2YNSButton1]NSTextField22\NSTextField1> _> b> e<h=HOSeILNB>JP?M.AKCRQY@6[ :t_#c24my-@ j> €ÀĀŀƀǀȀɀʀˀ̀̀΀πЀрҀӀԀՀր׀ $   !"# >F€K> ŀ> Ȁ78ˢ;^NSIBObjectData"'1:?DRTf#)t{ '5HZt~ )2ENY[\ely$1>LVdq{  "'07IRcu}7CWblz$9ANZhjlnpry   , 5 B N [ e l x   & 9 K ] k m o q s u w y { }  ( * , . 0 1 3 J    ' ) + - / 1 2 4 6 8 : C E H J _ a c e g i r t      " $ & ( * 3 5 < > @ B k u  %:Ga}   %0ACEGPgpy !-.02;=FOPRotvxz|~ 0247LNPRTmv{ 7@ITy !#%.F_hq~4UWY[]_ai1FHJLNXuwy{}~ ?MOQSUWY[]`en{  *_acegikmz|~+<>@BKMdmt &1NW\ov0AJQSUWYl ,.024GXZ\^`z <>@BDFHJLNPRTVXZ\^gluw $&(*,.02468:<>LZgt~   !#%')+-/1357@B   %4PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentFlattenedSaveNoticeSheet.nib/0000755000076500000240000000000014400242511030012 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentFlattenedSaveNoticeSheet.nib/classes.nib0000644000076500000240000000216212020564612032147 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = PPDocumentFlattenedSaveNoticeSheetController; LANGUAGE = ObjC; OUTLETS = { "_dontShowAgainCheckbox" = NSButton; }; SUPERCLASS = PPDocumentSheetController; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; }; CLASS = PPDocumentSheetController; LANGUAGE = ObjC; OUTLETS = { "_sheet" = NSWindow; }; SUPERCLASS = NSObject; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentFlattenedSaveNoticeSheet.nib/info.nib0000644000076500000240000000067311771074735031470 0ustar joshstaff IBDocumentLocation 210 53 356 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 5 IBSystem Version 9L31a ././@LongLink0000000000000000000000000000015100000000000011703 Lustar rootwheelPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentFlattenedSaveNoticeSheet.nib/keyedobjects.nibPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentFlattenedSaveNoticeSheet.nib/keyedobjects0000644000076500000240000001077712147737164032447 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver^ 156<=AELTlmnosw   "#$%()-2389>?BJLT\defgjmziU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValues]CM\FLNGZE["O234[NSClassName_,PPDocumentFlattenedSaveNoticeSheetController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FG3HIJK <>@MNOPQS]NSDestinationXNSSourceWNSLabel; :UVWXYZ[\]^_`abcdefghijk\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass96 px 87_{{158, 573}, {392, 167}}VWindow_PPKeyCancellableWindowpqrYNS.stringTView78tuuv;_NSMutableStringXNSStringxyz+|}~_NSNextResponderWNSFrameZNSSubviews54>F3$xy``VNSCellXNSvFlagsYNSEnabled[NSSuperview _{{297, 6}, {80, 28}}i[NSCellFlags_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalentZNSContentsYNSSupport]NSControlView_NSPeriodicDelay\NSCellFlags2]NSButtonFlags@ROKVNSSizeVNSNameXNSfFlags#@& \LucidaGrande78;VNSFontPQ 78;\NSButtonCell]%NSButtonCell\NSActionCell78;XNSButtonYNSControlVNSView[NSResponderxy`` _{{17, 12}, {174, 18}}hր! HCDDQ` $78K;>CND``Q` >CVDQ $>C^D_cabcH IJKYNSButton4\File's Owner\NSTextField2>CiD>ClD>CoDQH`JKI $>@<>C|D}~PQRSTUVWXY !>F3>CD>CD78;^NSIBObjectData"'1:?DRTf%+v} )7J\v *3FOZ\]fmz-7ER\n*3DV^ikmoqz|&2H]l !(13<>ANW\cdfozQSUWY[]_di  0 D P R T V X Z _ a ? P R [ ] ` u }    % 2 4 7 @ I [ d q }  $ ) < C L S j y   & / 1 < > @ B D F O T ] _ j l n p r t }   "$-/DFHJLNPRTVXZ\^`bdfhqst}PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentGridSettingsSheet.nib/0000755000076500000240000000000014400242511026531 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentGridSettingsSheet.nib/classes.nib0000644000076500000240000000504012767304126030676 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPColorWell; LANGUAGE = ObjC; SUPERCLASS = NSColorWell; }, { ACTIONS = { gridSettingChanged = id; "presetsMenuItemSelected_AddCurrentPatternToPresets" = id; "presetsMenuItemSelected_CustomPattern" = id; "presetsMenuItemSelected_DefaultPattern" = id; "presetsMenuItemSelected_EditPresets" = id; "presetsMenuItemSelected_ExportPresetsToFile" = id; "presetsMenuItemSelected_ImportPresetsFromFile" = id; "presetsMenuItemSelected_PresetPattern" = id; "presetsMenuItemSelected_RestoreOriginalDefault" = id; "presetsMenuItemSelected_SavePatternAsDefault" = id; showGridCheckboxClicked = id; }; CLASS = PPDocumentGridSettingsSheetController; LANGUAGE = ObjC; OUTLETS = { "_defaultPresetsMenu" = NSMenu; "_gridColorWell" = NSColorWell; "_gridTypeSegmentedControl" = NSSegmentedControl; "_guidelinesColorWell" = NSColorWell; "_guidelinesHorizontalSpacingTextField" = NSTextField; "_guidelinesVerticalSpacingTextField" = NSTextField; "_presetsPopUpButton" = NSPopUpButton; "_showGridCheckbox" = NSButton; "_showGuidelinesCheckbox" = NSButton; }; SUPERCLASS = PPDocumentSheetController; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; }; CLASS = PPDocumentSheetController; LANGUAGE = ObjC; OUTLETS = { "_sheet" = NSWindow; }; SUPERCLASS = NSObject; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentGridSettingsSheet.nib/info.nib0000644000076500000240000000110612767304126030173 0ustar joshstaff IBDocumentLocation 568 159 356 240 0 0 1680 1028 IBEditorPositions 47 427 767 301 238 0 0 1680 1028 IBFramework Version 489.0 IBOpenObjects 5 47 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentGridSettingsSheet.nib/keyedobjects.nib0000644000076500000240000003550512767304126031725 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchivery 156<=AEbjx#*12<=>EFOPQXYcdijrsty~   '(/0:>DNUV^_fgop{  ,.BGHLMQRSUX^gRhqRrtx{|}  !"'(-.349:?@EJOPUV[\abghmnstyzz !""#$%&',1woU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesx/w.0uv^1234[NSClassName_%PPDocumentGridSettingsSheetController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGiHIJKLMNOPQRSTUVWXYZ[\]^_`a +ˀ΀ЀҀԀՀ׀  cdefgi]NSDestinationXNSSourceWNSLabel klmnopqrstuvq_NSNextResponderWNSFrameVNSCellXNSvFlagsYNSEnabled[NSSuperview   klypz{|}zZNSSubviewsLNL_{{62, 229}, {76, 16}}g[NSCellFlags_NSAlternateContents]NSNormalImage_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalentZNSContentsYNSSupport]NSControlView_NSPeriodicDelay\NSCellFlags2]NSButtonFlags H?$YNS.string%_NSColor pasteboard type78;_NSMutableStringXNSString_{{65, 163}, {60, 24}}\NSColorSpaceUNSRGB(O0.058130499 0.055541899 178Ԣ;78;^NSClassSwapper^_gridColorWellcdef,     \NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass1ɀƀ.px/-ǀ0_{{156, 523}, {275, 333}}VWindow_PPKeyCancellableWindow%TViewkly+{!"ŀ2>F%i&'(z38=Lklmnop r-.uv 145 1_{{187, 5}, {80, 28}}67&:;763@ROKQ klmnop rABuv 19: 1_{{103, 5}, {80, 28}}IKL':;<;8VCancelQ.klmnop STUuv 1K>? 1_{{92, 307}, {92, 17}}Z[\]^_(ab_NSBackgroundColor[NSTextColorJC@A=@G]Grid Settingsfgh#@*B_LucidaGrande-Boldklnopq[NSColorName]NSCatalogName(FEDVSystem\controlColoruwxWNSWhite(K0.66666669kl{o|q(IHD_controlTextColoruw(B078m;_NSTextFieldCell78;[NSTextField\%NSTextFieldklyp w qYNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition]NSContentView1€M1 >Fiq >Fig O SWlpklmnopqSuvq KPQ _{{3, 168}, {56, 14}}Z[\]bJCROBGVColor:klmnopqSuvq KTU _{{3, 201}, {56, 14}}Z[\]bJCVS@GUType:klmnopquvq kXY _{{63, 195}, {177, 24}}_NSSegmentImages_NSSelectedSegmentjZW[f>Fi\`cf_NSSegmentItemImage_NSSegmentItemImageScaling_NSSegmentItemWidth_NSSegmentItemLabel_]#@E2^_gridtype_lines_segment78;]NSSegmentItem_NSSegmentItemTag_a2b_gridtype_crosshairs_segment_d2 e_gridtype_largedots_segmentw_g2h_gridtype_dots_segment78;^NSMutableArrayWNSArray78m;_NSSegmentedCell78;_NSSegmentedControlklmnopqS#$uvq Kmn _{{3, 230}, {56, 14}}Z[\]+bJColGXEnabled:klypq346wq9 q r>FFFiGHIJKLMtx|klmnop9rQRuv9ruv r_{{5, 90}, {110, 16}}[Gwt_Show Guidelinesklmnop9Sbcuv9rKyz r_{{25, 14}, {91, 14}}Z[\]jHmbJC{xBG_Guideline Color:klno2p9stuvuvvy9r)~ }r>?}~%_{{117, 9}, {48, 24}}(klmnop9Suv9rK r_{{23, 42}, {93, 14}}Z[\]JabJCG_Vertical Spacing:klmnop9Suv9rK r_{{117, 40}, {48, 19}}Z[\Kv_NSDrawsBackgroundqAJB kloq(D_textBackgroundColoruw(B1kl{oq(IDYtextColorklmnop9Suv9rK r_{{7, 68}, {109, 14}}Z[\]LabJCG_Horizontal Spacing:klmnop9Suv9rK r_{{117, 66}, {48, 19}}Z[\MvJ T1000_{{2, 2}, {175, 112}}78ƣ;_{{62, 38}, {179, 116}}V{0, 0}Z[\JZGuidelinesuw(M0 0.8000000178;UNSBoxklmnopqSuvq K _{{3, 131}, {56, 14}}Z[\]bJCGWGuides:klmnopqSuvq K _{{3, 14}, {56, 14}}Z[\]bJCGWPreset:klmnopquvq _{{62, 9}, {179, 22}}v "$wvv()*+_NSMenuItemRespectAlignment_NSArrowPositionZNSMenuItem_NSPreferredEdge_NSUsesItemFromMenu]NSAltersStateVNSMenuA@ K @%/012345679:;=>?*AXNSTargetWNSTitle_NSKeyEquivModMaskZNSKeyEquiv]NSMnemonicLocYNSOnImage\NSMixedImageXNSActionWNSState0CDEF[NSMenuItemsUItem12K_NSMenuCheckmark2P_NSMenuMixedState__popUpItemAction:78T;W%ZOtherViews>FZi$\]/01234569a;=>?*fUItem2/01234569k;=>?*pUItem378s;78uvvwm;_NSPopUpButtonCell^NSMenuItemCell78yzz;]NSPopUpButton_{{2, 2}, {250, 255}}_{{11, 41}, {254, 259}}Z[\JÀUTitleuw(_{{1, 9}, {275, 333}}_{{0, 0}, {1680, 1028}}^{131.131, 129}_{3.40282e+38, 3.40282e+38}78;_NSWindowTemplateV_sheetcde'̀8_cancelButtonPressed:78;_NSNibControlConnectorcdef'8,]_cancelButtoncdefW__gridTypeSegmentedControlcdèW_gridSettingChanged:cdè cde&̀3_OKButtonPressed:cdef؀0CDـTMenu>Fiˀۀ݀߀0123459;=>?UNSTag܀WDefault0123459;=>?ހVCustom0123459;v=>?]NSIsSeparator 0123459;=>?w _!Add Current Pattern to Presets...Qk0123459;=>?倯_Edit Presets...QG0123459;=>?_Import Presets from File...0123459;=>?_Export Presets to File...0123459;v=>? 0123459;=>?_Save Current Pattern as Default0123459;=>?_Restore Original Default__defaultPresetsMenucdefG&t__showGuidelinesCheckboxcdefM,_%_guidelinesHorizontalSpacingTextFieldcdefK2_#_guidelinesVerticalSpacingTextFieldcdefI8|__guidelinesColorWellcdef>__presetsPopUpButtoncdeGD̀tcdeIÌ|cdegǸ _showGridCheckboxClicked:cdeT̀ہ_'presetsMenuItemSelected_DefaultPattern:cdeZ̀݁_&presetsMenuItemSelected_CustomPattern:cde`̀_3presetsMenuItemSelected_AddCurrentPatternToPresets:cdef̀_$presetsMenuItemSelected_EditPresets:cdel̀ _.presetsMenuItemSelected_ImportPresetsFromFile:cder̀ _,presetsMenuItemSelected_ExportPresetsToFile:cdex̀ _-presetsMenuItemSelected_SavePatternAsDefault:cde~̀_/presetsMenuItemSelected_RestoreOriginalDefault:>(9KLGM$\*I(JH]z &'qgr,SWt퀓߀|ۀ؀݀= lxpOL138 78;>(q99qq99**q9 qq99q*q   zqqp rr؀ r؀r ؀؀r؀؀؀؀؀1 ؀ rr 1,11L >ځKLGM$\*I(JH]&'g,WSt|ۀ؀݀= lxO38 >    . !"#$!%&'()*+,-]NSTextField11UView1\NSTextField1ZNSButton41]NSTextField12\NSTextField3[NSMenuItem1\File's OwnerYPopUpListQ2WPresets]NSTextField21\NSTextField2[NSMenuItem2YNSButton3YNSButton4]NSTextField13>)I |>.y!}>3C9aPLW\M$\[RTNIOQI^JHYz HMKJK`GX_*S]Z(LUV]&gq'rՀWSҀۀ|؀Ԁ׀xpL1 Ѐ+,ˁ t߁ ݁= ΀lO3 8>yCz{|}~23456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrst?]+DS4%$XFELWNP9)5A/6*21MZB@>U" H'C\<7T8[IO0Y3V &QRJ #G>Fi>>78;^NSIBObjectData"'1:?DRTf\b+6D`n   5>GRWfo   "%(+.147:KYbjlnprXdz!&(*,.3579;=?DISdkr{}   , . 0 9 > T U W ` k x   ( * , . 0 ] s {   ( @ M Z ` b d    - 7 E R \ n      ) + - / 1 N P R T V W Y p :<>CEGIKMTVsuwy{|~ +@LZ\^`bdkx %2cmy   2468:;=Tuwy{}!#%')*,Ebt'<>@IKXZ\^w"$&(E^`bdqsuw "$&()+Bcegikmox   .024679P   )VXZ\^`bcdfhqsvx   )FHJLNOQi)FHJLNOQh"9BIbi   $EGIKMOQYvxz|~ Zw3<DXcq{  #7@ENP[dfmoqs+:CP^u & / 4 G N _ a c e g ~ !!!!!!!1!B!D!F!H!J![!]!_!a!c!v!!!!!!!!!!!!!!!!!!!!!!!!"" """"""" "E"G"I"K"M"O"Q"X"}"""""""""""""""""########.#0#Q#S#U#W#Y#[#]#{#################$$$!$#$%$'$)$K$l$n$p$r$t$v$x$$$$$$$$$$$$$%%.%0%2%4%6%\%m%o%q%s%u%%%%%%%%%%%%%%%%%%&&&&&!&2&4&6&8&;&e&v&x&z&|&&&&&&&&' ' ' '''9'J'L'N'P'S''''''''''''((((*(,(.(1(c(l(o((((((((((((((((((((((((((((((()))))) ) ))))) ))),)))))))))))))))))))))))))))))))))))))))))))****** *"*$*&*(***,*.*0*2*4*6*8*:*<*>*@*B*D*F*H*J*L*N*W*Z*******************************+ ++"+/+;+H+R+T+\+j+w++++++++++++++++,d,f,i,k,m,o,q,s,u,x,z,|,~,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,-----------------------------------------.... ....... .#.&.).,./.2.5.8.;.>.A.D.G.J.M.P.R.T.V.X.Z.\.^.`.b.d.f.h.j.l.n.p.r.t.v.x.z.|.~.................................................../ /PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentResizeSheet.nib/0000755000076500000240000000000014400242511025364 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentResizeSheet.nib/classes.nib0000644000076500000240000000404312051747341027527 0ustar joshstaff IBClasses ACTIONS OKButtonPressed id cancelButtonPressed id CLASS PPDocumentSheetController LANGUAGE ObjC OUTLETS _sheet NSWindow SUPERCLASS NSObject CLASS PPKeyCancellableWindow LANGUAGE ObjC OUTLETS _cancelButton NSButton SUPERCLASS NSWindow CLASS NSTextField LANGUAGE ObjC SUPERCLASS NSControl CLASS FirstResponder LANGUAGE ObjC SUPERCLASS NSObject CLASS NSObject LANGUAGE ObjC CLASS NSWindow LANGUAGE ObjC SUPERCLASS NSResponder CLASS PPDocumentResizeSheetController LANGUAGE ObjC OUTLETS _heightTextField NSTextField _shouldScaleCheckbox NSButton _widthTextField NSTextField SUPERCLASS PPDocumentSheetController IBVersion 1 PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentResizeSheet.nib/info.nib0000644000076500000240000000105312051747341027023 0ustar joshstaff IBFramework Version 677 IBLastKnownRelativeProjectPath ../PikoPixel.xcodeproj IBOldestOS 5 IBOpenObjects 6 IBSystem Version 9L31a targetFramework IBCocoaFramework PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentResizeSheet.nib/keyedobjects.nib0000644000076500000240000001557112051747341030555 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AEOWopqrvz  04;CKLSTX`ahiqr}    "2BRSTUVWXYZ[\]^ad|lU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuestyzx234[NSClassName_PPDocumentResizeSheetController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGVHIJKLMN gilnprPQRSTUV]NSDestinationXNSSourceWNSLabelf. eXYZ[\]^_`abcdefghijklmn\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClassda px cb_{{697, 669}, {194, 187}}VWindow_PPKeyCancellableWindowstuYNS.stringTView78wxxy;_NSMutableStringXNSString{|}~_NSNextResponderZNSSubviewsXNSvFlags[NSFrameSizeXNSWindow[NSSuperviewX_`>FVT$.3{}ccWNSFrameVNSCellYNSEnabled# _{{47, 161}, {100, 17}}[NSCellFlags_NSBackgroundColorZNSContentsYNSSupport]NSControlView\NSCellFlags2[NSTextColor"@]Resize CanvasVNSSizeVNSNameXNSfFlags#@*_LucidaGrande-Bold78;VNSFontWNSColor\NSColorSpace[NSColorName]NSCatalogNameVSystem\controlColorWNSWhiteK0.6666666978;! _controlTextColorӀB078֤;_NSTextFieldCell\NSActionCell78ڥ;[NSTextFieldYNSControlVNSView[NSResponder{}cc-%& _{{105, 5}, {80, 28}}l_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalent_NSPeriodicDelay]NSButtonFlags,*(+'($@ROK#@&) \LucidaGrandePQ 78;\NSButtonCell78;XNSButton{}c  c-/0 _{{21, 5}, {80, 28}}T,*(21(.VCancelQ.{ |}!"#$c&'()*+-&c/YNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition]NSContentView^[Y4Z5>F2V/5{|}783XW63>F=V>?@AB7<@HK{}/FG/5#89 5_{{12, 78}, {74, 17}}OP>":;7ZNew width:W){}/[\/5#=> 5_{{12, 46}, {80, 17}}dP?"?;<[New height:{}/lm/5#AB 5_{{96, 76}, {58, 22}}stvP@z|_NSDrawsBackgroundqA"C*;@@ FED_textBackgroundColorB1!GYtextColor{}//5#IJ 5_{{96, 44}, {58, 22}}stvPAz|"C*;H F{}//5-LM 5_{{12, 10}, {131, 18}}kPB&]NSNormalImage,*OS*N;KH wT@U?c/B>A.@ <35K$7uH23v]NSApplication78!Ƣ;> $wc//Uc/cc//55 3555> 4wT@U?cB>A.@ <3K$7uH> DwEFGfIJKLMNOPQ{|} ~\File's Owner_Push Button (Cancel)ZText Field_Static Text (New height:)\Content View[Box (Title)_Check Box (Scale image to fit)_Static Text (Resize Canvas)_Push Button (OK)_Static Text (New width:)[Application\Text Field-1> `w> cw> fwTU/cB>KAHI@?LMNJ. 5K7lH g@<3n$puri> ~w     >FV> w> w78;^NSIBObjectData"'1:?DRTf 0LZfr !#%')+-/13579;=FRTVx !#%'8FOWY[]_ #%')+02468:<>Y`y "$&(+-/1:<EGIKMnv}*/13579>@N_fmvx&(*6?DY[]_at       " 9 n   ! # , . 1 > ? A J S ` i t }       K U a o |     5 7 9 ; = > @ B Y z | ~        ' H J L N P Q S U l  ",MOQSUVXZq"02468:<>@EZgvxz| )29RYvxz|~ +9BI`o  02468O`bdfhz )+-/13579;=?ACLNikmoqsuwy{}'Hfy   !#%'02_acegikmoqsuwy{}PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSamplerImagesSettingsSheet.nib/0000755000076500000240000000000014400242511030375 5ustar joshstaff././@LongLink0000000000000000000000000000014600000000000011707 Lustar rootwheelPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSamplerImagesSettingsSheet.nib/classes.nibPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSamplerImagesSettingsSheet.nib/classes.ni0000644000076500000240000000367012147740723032406 0ustar joshstaff{ IBClasses = ( { ACTIONS = { editSamplerImagesSettings = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPColorWell; LANGUAGE = ObjC; SUPERCLASS = NSColorWell; }, { ACTIONS = { addImageFromClipboardButtonPressed = id; addImageFromFileButtonPressed = id; copyImageToClipboardButtonPressed = id; removeAllImagesButtonPressed = id; removeImageButtonPressed = id; }; CLASS = PPDocumentSamplerImagesSettingsSheetController; LANGUAGE = ObjC; OUTLETS = { "_copyImageToClipboardButton" = NSButton; "_removeAllImagesButton" = NSButton; "_removeImageButton" = NSButton; "_samplerImagesTable" = NSTableView; }; SUPERCLASS = PPDocumentSheetController; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; }; CLASS = PPDocumentSheetController; LANGUAGE = ObjC; OUTLETS = { "_sheet" = NSWindow; }; SUPERCLASS = NSObject; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSamplerImagesSettingsSheet.nib/info.nib0000644000076500000240000000067412146514325032043 0ustar joshstaff IBDocumentLocation 257 189 356 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 5 IBSystem Version 9L31a ././@LongLink0000000000000000000000000000015300000000000011705 Lustar rootwheelPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSamplerImagesSettingsSheet.nib/keyedobjects.nibPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSamplerImagesSettingsSheet.nib/keyedobjec0000644000076500000240000002326412147740723032451 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AEU]uvwx| 04:CTZhl   %&./34;<DEFMNVWX_`hipqyz{|~'789:;<=>?BEgrU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesڀـ׀L234[NSClassName_.PPDocumentSamplerImagesSettingsSheetController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGRHIJKLMNOPQRST VWXYZ\]NSDestinationXNSSourceWNSLabel ^_`abcdefghijklmnopqrst\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass px _{{385, 444}, {329, 320}}VWindow_PPKeyCancellableWindowyz{YNS.stringTView78}~~;_NSMutableStringXNSString+_NSNextResponderWNSFrameZNSSubviewsz>FR"2iiVNSCellXNSvFlagsYNSEnabled[NSSuperview _{{240, 5}, {80, 28}}r[NSCellFlags_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalentZNSContentsYNSSupport]NSControlView_NSPeriodicDelay\NSCellFlags2]NSButtonFlags@ROKVNSSizeVNSNameXNSfFlags#@& \LucidaGrande78;VNSFontPQ 78ƥ;\NSButtonCell]%NSButtonCell\NSActionCell78˥;XNSButtonYNSControlVNSView[NSResponderii _{{156, 5}, {80, 28}}! VCancelQ.ii1#$ _{{109, 294}, {111, 17}}_NSBackgroundColor[NSTextColor0(%&"@-^Sampler Images#@*'_LucidaGrande-BoldWNSColor\NSColorSpace[NSColorName]NSCatalogName,+*)VSystem\controlColor  WNSWhite,K0.6666666978 ;,/.)_controlTextColor ,B078;_NSTextFieldCell78;[NSTextField\%NSTextField !"#$%i'()*+, -'i/YNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition]NSContentView}{3|4>F2R/4782zy52>F?@AB6`fkptDEFGH%/JKLMNO/QRR[NSHScrollerXNSsFlags\NSScrollAmts[NSVScroller]NSNextKeyView4\_^р7OA A BB4X88>FVRRQJ8X\[\]H=_`abcde=dYNScvFlagsYNSDocViewYNSBGColor6WV9 :I6:>FjRd:mnopqrstuvwxyR'{|}aqR_NSDraggingSourceMaskForNonLocalYNSTvFlags_NSAllowsTypeSelect\NSCornerView_NSIntercellSpacingWidth_NSColumnAutoresizingStyle_NSIntercellSpacingHeight[NSFrameSize[NSGridColor_NSGridStyleMask^NSTableColumns_NSDraggingSourceMaskForLocal[NSRowHeight8U S <#@#@; T8?#@QY{93, 720}+>=_{{-26, 0}, {16, 17}}78;]_NSCornerView>FR@Ld\NSHeaderCellWNSWidthZNSDataCellZNSMinWidthZNSMaxWidth[NSTableViewKA#@.H:'GBE,DC)[headerColor ,B1,/F)_headerTextColor78;_NSTableHeaderCelled!@0I:-,+J)_controlBackgroundColor78̢;]NSTableColumnd\NSIdentifier\NSIsEditableKNMP#@@ :VImages'GOE ,K0.33333299'''WNSStyleWNSAlignWNSScaleZNSAnimatesQ 78;[NSImageCell\%NSImageCell78;^NSMutableArrayWNSArray ,K0.60000002 ,78;\%NSTableView_{{1, 1}, {93, 216}}78;ZNSClipView=== XNSTargetXNSActionYNSPercent66[Y Z6#?33@_{{94, 1}, {15, 216}}\_doScroller:78;ZNSScrollerE==r=66[] Z6#? _{{-100, -100}, {131, 15}}_{{12, 12}, {110, 218}}78;\NSScrollView/!"/4ab 4_{{128, 179}, {168, 28}})*+>dec`oAdd from Pasteboard (#V)2Qv/78/4gh 4_{{128, 206}, {168, 28}})@A?djifoAdd from File... (#O)Qo/IJ/4lm 4_{{128, 32}, {168, 28}}r)RS@donkjRemove (#+)Q/[\/4qr 4_{{128, 5}, {168, 28}})ReAdospoRemove All (##+)/lm/4uv 4_{{128, 106}, {168, 28}})uvBdxwtoCopy to Pasteboard (#C)Qc_{{2, 2}, {303, 242}}78}ͣ;_{{11, 41}, {307, 246}}V{0, 0}'0~UTitle,D)_textBackgroundColor ,M0 0.8000000178;UNSBox_{{1, 9}, {329, 320}}_{{0, 0}, {1440, 878}}^{131.131, 129}_{3.40282e+38, 3.40282e+38}78;_NSWindowTemplateV_sheet78;_NSNibOutletConnector^NSNibConnectorVWX_cancelButtonPressed:78;_NSNibControlConnectorVWXYZ ]_cancelButtonVWX_OKButtonPressed:VWXYd:__samplerImagesTableVWXYBt__copyImageToClipboardButtonVWXY@Āk__removeImageButtonVWXYAʀp__removeAllImagesButtonVWX>Ѐ`_#addImageFromClipboardButtonPressed:VWX?րf_addImageFromFileButtonPressed:VWXB܀t_"copyImageToClipboardButtonPressed:VWX@‌k_removeImageButtonPressed:VWXA而p_removeAllImagesButtonPressed:>쀥dZ@>/i?B=A": k`L4f2t6p@'''Q 78;>i=/i/dZ/ii///d644:2L 4444:>dZ@>?B=A": k`Lft6p>)*+l-./.123456 ]NSTextField21\File's OwnerYNSButton2YNSButton1YNSButton3ZNSButton11]NSScrollView1ZNSButton21>A>D>GMKI@>/iS?PRAHJOdZNLB=TQ"k`L4f2p : t6@>ijklmnopqrstuvwxyz{|}~€ÀĀŀƀǀȀɀʀˀ̀̀΀πЀрҀӀԀՀD+31.#0J2GI"4F- E>A,KH@>FR>>78;^NSIBObjectData"'1:?DRTf%pw~#1DVpz&/BKVXYbiv|%2?MWer|!#(18JSdv~JVl  !*->ELUW`ber{   ! # % & ( ? t v x }         " $ 3 D F O Q T h }      - : < ? H Q c l y   " $ & ( ) + - / 1 : < ? A V X Z \ ^ ` i k x z | ~      " $ + - / 1 Z d n x z | ~ -:Tp$-7HJLNWnw/13579NPRTVboqt   *38Fkx ',.34=FR_ho~+4=GIKMOPRT]t&3PRTVXY[u!#%')*,F{}.02468:<QSprtvxy{9nprtvxz|#8:<>@Vces|5DUWY[]t}/1357Ufhjln   .?ACEGl}   "$&(*,IKLUZce "$&(*,:GQ[ep~   !#%')+46wy{}!0PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentScaleSheet.nib/0000755000076500000240000000000014400242511025152 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentScaleSheet.nib/classes.nib0000644000076500000240000000375312060344232027314 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = NSTextField; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = NSWindow; LANGUAGE = ObjC; SUPERCLASS = NSResponder; }, { ACTIONS = { scalingFactorSliderMoved = id; scalingFactorTypePopUpButtonItemSelected = id; }; CLASS = PPDocumentScaleSheetController; LANGUAGE = ObjC; OUTLETS = { "_newSizeTextField" = NSTextField; "_previewImageView" = NSImageView; "_scalingFactorSlider" = NSSlider; "_scalingFactorTextField" = NSTextField; "_scalingFactorTypePopUpButton" = NSPopUpButton; }; SUPERCLASS = PPDocumentSheetController; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; }; CLASS = PPDocumentSheetController; LANGUAGE = ObjC; OUTLETS = { "_sheet" = NSWindow; }; SUPERCLASS = NSObject; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; }, { CLASS = PPParabolicSlider; LANGUAGE = ObjC; SUPERCLASS = NSSlider; }, { CLASS = PPScaledImageView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentScaleSheet.nib/info.nib0000644000076500000240000000117312060344232026604 0ustar joshstaff IBDocumentLocation 69 10 356 240 0 0 1680 1028 IBFramework Version 489.0 IBLastKnownRelativeProjectPath ../PikoPixel.xcodeproj IBOldestOS 5 IBOpenObjects 5 IBSystem Version 9L31a targetFramework IBCocoaFramework PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentScaleSheet.nib/keyedobjects.nib0000644000076500000240000002537612060344232030337 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AES[ipq  !"69=BCFIJO\]^mvwxyz{|}")019:>?DEHMN_cnuv}~    %&>ABFGIay!     U$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesӀҀԀ=234[NSClassName_PPDocumentScaleSheetController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGdHIJKLMNOPQR +2?OiTUVWXZ]NSDestinationXNSSourceWNSLabel \]^_`abcdefgb_NSNextResponderWNSFrameVNSCellXNSvFlagsYNSEnabled[NSSuperview   \]jaklmnkZNSSubviews{}{_{{154, 16}, {33, 22}}rstuvwxyz{|}~Xg[NSCellFlags_NSBackgroundColorZNSContentsYNSSupport]NSControlView\NSCellFlags2_NSDrawsBackground[NSTextColorqA @ S123VNSSizeVNSNameXNSfFlags#@*\LucidaGrande78;VNSFontWNSColor\NSColorSpace[NSColorName]NSCatalogNameVSystem_textBackgroundColorWNSWhiteB178;YtextColorB078^;_NSTextFieldCell\NSActionCell78;[NSTextField\%NSTextFieldYNSControlVNSView[NSResponder__scalingFactorTextField78;_NSNibOutletConnector^NSNibConnectorTUV*)\]^_`afg€ (!" \j+l[NSFrameSizeo_{{230, 5}, {80, 28}}rtuvw_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalent_NSPeriodicDelay]NSButtonFlags'%$&#$@ROK#@& PQ 78^;\NSButtonCell]%NSButtonCell78;XNSButton_OKButtonPressed:78;_NSNibControlConnectorTUV*,1\]^_`afg€ (-. _{{146, 5}, {80, 28}}rtuvw  '%$0/$,VCancelQ._cancelButtonPressed:TUV*3>\]^_`2abfgb_NSOriginalClassName =657 4 _PPParabolicSliderXNSSlider_{{193, 14}, {79, 21}}#r$%tuv&'w()*+,-./023.434WNSValue_NSNumberOfTickMarks_NSTickMarkPositionZNSMaxValueZNSMinValueZNSVertical]NSAltIncValue_NSAllowsTickMarkValuesOnly#@><8:3#@Y#78YNS.string978:;;<;_NSMutableStringXNSString?@A#@(;YHelvetica78DEE^;\NSSliderCell78GHH;^NSClassSwapper_scalingFactorSliderMoved:TUVWLN@N\P^Q_`2aRTgVWfXgZRZNSEditable[NSDragTypesC=B LDK AC_PPScaledImageView[NSImageView\]_j_`aabcdefghLjcLYNScvFlagsYNSDocViewYNSBGColor]NSNextKeyView@@>?opqrstuEFGHIJ_Apple PDF pasteboard type_Apple PNG pasteboard type_NSFilenamesPboardType_1NeXT Encapsulated PostScript v1.2 pasteboard type_NeXT TIFF v4.0 pasteboard type_Apple PICT pasteboard typeZ{200, 200}r~w..4WNSStyleWNSAlignWNSScaleZNSAnimatesM78^;[NSImageCell\%NSImageCell__previewImageViewTUV*Ph\]^_`abfgb gQR _{{17, 12}, {118, 26}}ruvwg~~ggh_NSMenuItemRespectAlignment_NSArrowPositionZNSMenuItem_NSPreferredEdge_NSUsesItemFromMenu]NSAltersStateVNSMenu_NSSelectedIndexA@ %KfSTP U@789XNSTargetWNSTitleZNSKeyEquiv]NSMnemonicLocYNSOnImage\NSMixedImageXNSActionUNSTagWNSStateR^V%W[U][NSMenuItemse_`ZScale DOWN2^NSResourceNameZXYWNSImage_NSMenuCheckmark78գ;_NSCustomResource_%NSCustomResource2ڀZX\_NSMenuMixedState__popUpItemAction:78;789ZOtherViews>FdaT_NSKeyEquivModMaskR^b%W[UcXScale UP78;^NSMutableArrayWNSArray78;78^;_NSPopUpButtonCell^NSMenuItemCell78;]NSPopUpButton_)scalingFactorTypePopUpButtonItemSelected:TUVWj     \NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass lpxmkn_{{250, 364}, {322, 429}}VWindow_PPKeyCancellableWindow78!9TView>F$d%kp,{\]^_`ac,-fg€ qr _{{115, 403}, {91, 17}}rstuvwy{345%78vstp@y\Scale Canvas<=u_LucidaGrande-BoldABxw\controlColorGK0.66666669Kz_controlTextColor\OP]QjRSTaU.WXY4[\.bYNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition]NSContentView | >Fadb >FedXijclmP 3~\]^_`abcqrfgb  _{{18, 44}, {65, 17}}rstuvwy{3y~i78v~yYNew size:\]^_`abcfgb  _{{81, 44}, {128, 17}}rstuvwy{35j78vtyUXXxXX\]j_abUbfbRR[NSHScrollerXNSsFlags[NSVScroller 2 CC>FdRC>FdL@_{{1, 1}, {248, 248}}_NSCustomColorSpaceTNSID78;78;ZNSClipView\]_accfcZNSCurValueYNSPercent#?#?_{{238, 1}, {11, 248}}\_doScroller:78å;ZNSScroller\]_accc̀#? _{{1, 163}, {236, 11}}_{{20, 82}, {250, 250}}78Ѥ;\NSScrollView\]^_`abcfgb  _{{137, 18}, {12, 17}}rstuvwy{3~l78vyQx\OP]QRSTabW4\.b  _{{21, 66}, {249, 5}}V{0, 0}rstuwy{|~.SBoxM0 0.8000000178;UNSBox_{{2, 2}, {290, 352}}78;_{{14, 41}, {294, 356}}rstuwy{|.$UTitleZ{322, 429}_{{0, 0}, {1680, 1028}}]{131.131, 27}_{3.40282e+38, 3.40282e+38}78   ;_NSWindowTemplateV_sheetTUVW3__scalingFactorSliderTUVWP__scalingFactorTypePopUpButtonTUVWj__newSizeTextFieldTUVW$,j]_cancelButton>'(k,i.jX%Lclmb{j~PU, p@T a3 23@]NSApplication\]+lE_{{2, 2}, {125, 1}}78H;>'Kbmbbbcbbbbk  P U j U {>'ck,i.LjX%lcm{j~P@, pU Ta3>'{|}l€ÀĀŀƀǀȀɀʀˀ̀̀΀πЀ_Push Button (OK)[Box (Title)[Application\File's Owner_Static Text (New size:)_Popup Button (Scale DOWN)_Scaled Image View_Push Button (Cancel)_Static Text (XXxXX)_Text Field (123)_Static Text (Scale Canvas)_Static Text (x)_!Bordered Scroll View (Image View)_Menu (OtherViews)\Content View_Menu Item (Scale DOWN)_Horizontal Line_Menu Item (Scale UP)_Horizontal Slider>'L@3>'ZA4>'!kQ.L%MPOIR,iJjXlcHLNKmb{U@pOj~P+, T ? i23a >'Ԁ!ր׀؀ـڀۀ܀݀ހ߀)<0:9(, #+ $1/'5*8 ;>Fd>'>'78  ;^NSIBObjectData"'1:?DRTf_e .9Gcq%.7BGV_r{ 9KSZcmy{}#1>R^gikmoqvwy} !#%,BOWY[^gl"<ELcr $ : O ^ q   ) 4 = P Y ` x          ! 8 I K M O Q v  ' < G R ] k       ' 0 = F K Z v .8BLZ\^`bdgikmoxz8U`}$&(*,-/G "+,.02468:<=>ACHQS  $3579AS\cv%9;=?DFHJLNW`gv~(*,.0an{  &-FOQV_ajlnpr 3579;HUWcxz|~!#%'(*,.09;>@IK\^`bdfhjl "CEGIKMOU!*/1:?HQ\*,.02579BZs|*,.02357NUrtvxz|"/1<Uc"$&(*>OQSUWenp !#PRTVXZ\^`bdfhjlnprtvxz "$&(*,.02468:<>Q]iv  / S g t !B!D!F!H!J!L!N!P!R!T!V!X!Z!\!^!`!b!d!f!h!j!l!n!p!r!t!v!x!z!|!~!!!!!!!!!!!!!!!!!!!!!!!!!!!"""""" " """""""""" """$"&"("*","."0"9";"="?"A"C"E"G"I"K"M"O"Q"S"U"W"Y"["d"f"g"p"r"s"|"~"""!"PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSizeSheet.nib/0000755000076500000240000000000014400242511025035 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSizeSheet.nib/classes.nib0000644000076500000240000000323312175564254027207 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; }; CLASS = PPDocumentSheetController; LANGUAGE = ObjC; OUTLETS = { "_sheet" = NSWindow; }; SUPERCLASS = NSObject; }, { ACTIONS = { "sizePresetsMenuItemSelected_CustomDimensions" = id; "sizePresetsMenuItemSelected_EditSizePresets" = id; "sizePresetsMenuItemSelected_PresetSize" = id; }; CLASS = PPDocumentSizeSheetController; LANGUAGE = ObjC; OUTLETS = { "_defaultSizePresetsMenu" = NSMenu; "_heightTextField" = NSTextField; "_sizePresetsTitleablePopUpButton" = PPTitleablePopUpButton; "_widthTextField" = NSTextField; }; SUPERCLASS = PPDocumentSheetController; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; }, { CLASS = PPTitleablePopUpButton; LANGUAGE = ObjC; SUPERCLASS = NSPopUpButton; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSizeSheet.nib/info.nib0000644000076500000240000000110312175564254026477 0ustar joshstaff IBDocumentLocation 156 33 356 240 0 0 1440 878 IBEditorPositions 48 210 275 160 100 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 5 48 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentSizeSheet.nib/keyedobjects.nib0000644000076500000240000002102312175564254030222 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AERZhop  !"#(?@ABFJQXYabfglmpuv    !()012456<=@CDEFGJKPQV[\clu~#EFGHIJKLMNOPQRSTUVWXYZ[\]^_`abehkU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesȀǀŀA234[NSClassName_PPDocumentSizeSheetController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGhHIJKLMNOPQ #/6~STUVWY]NSDestinationXNSSourceWNSLabel [\]^_`abcdefa_NSNextResponderWNSFrameVNSCellXNSvFlagsYNSEnabled[NSSuperview   [\i`jklmjZNSSubviewsIqpKI_{{101, 45}, {58, 22}}qrstuvwxyz{|}Wf[NSCellFlags_NSBackgroundColorZNSContentsYNSSupport]NSControlView\NSCellFlags2_NSDrawsBackground[NSTextColorqA @ PVNSSizeVNSNameXNSfFlags#@*\LucidaGrande78;VNSFontWNSColor\NSColorSpace[NSColorName]NSCatalogNameVSystem_textBackgroundColorWNSWhiteB178;YtextColorB078];_NSTextFieldCell\NSActionCell78;[NSTextField\%NSTextFieldYNSControlVNSView[NSResponder__widthTextField78;_NSNibOutletConnector^NSNibConnectorSTUV"[\]^_`abefa  ! _{{101, 13}, {58, 22}}qrstuvwxyz{|}f __heightTextFieldSTUՀ.$-[\]^_`ef׀%,&' %[\i+kqx=_{{142, 5}, {80, 28}}qstuv|_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalent_NSPeriodicDelay]NSButtonFlags+)*()$@ROK#@& Q 78];\NSButtonCell]%NSButtonCell78;XNSButton_OKButtonPressed:78  ;_NSNibControlConnectorSTU .05[\]^_`ef׀%,12 %_{{58, 5}, {80, 28}}qstuv| +)43)0VCancelQ._cancelButtonPressed:STUV &'07})*+,-./012356789:;<=>\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass%|y9px:8{z;_{{263, 391}, {231, 190}}VWindow_PPKeyCancellableWindowCDEYNS.stringFLhM j>$0I[\]^_`bTUef׀%?@ %_{{76, 164}, {78, 17}}qrstuvxz[\]M_`DAB>@GYNew ImagedeC_LucidaGrande-BoldijFE\controlColoroK0.66666669sH_controlTextColor[wx\yiz{|`}aYNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition]NSContentView%wtrJs% >Fha >FhWLP Tl[\]^_`abefa MN _{{46, 47}, {45, 17}}qrstuvxz[}_`DOLGVWidth:[\]^_`abefa QR _{{46, 15}, {50, 17}}qrstuvxz[}_`DSPGWHeight:[\]^_2`aefa_NSOriginalClassName kWVX U _PPTitleablePopUpButton]NSPopUpButton_{{46, 75}, {149, 26}}qtuvf|}ff_NSMenuItemRespectAlignment_NSArrowPositionZNSMenuItem_NSPreferredEdge_NSUsesItemFromMenu]NSAltersStateVNSMenuA@ KjYZ[T \@݀CD<|XNSTargetWNSTitle_NSKeyEquivModMaskZNSKeyEquiv]NSMnemonicLocYNSOnImage\NSMixedImageXNSActionWNSStateXe]^b\d[NSMenuItemsifgVCustom2^NSResourceNamea_`WNSImage_NSMenuCheckmark78;_NSCustomResource_%NSCustomResource2a_c_NSMenuMixedState__popUpItemAction:78 Ţ;CDFhҀ[78;^NSMutableArrayWNSArray78ɢ;78];_NSPopUpButtonCell^NSMenuItemCell78  ;^NSClassSwapper[\]^_`ab$%efa mn _{{10, 81}, {34, 17}}qrstuvxz[,}_`DolGUSize:_{{2, 2}, {205, 112}}783;_{{11, 41}, {209, 116}}V{0, 0}qrstvxz{9;u)vTSize?M0 0.8000000178ABB;UNSBox_{{1, 9}, {231, 190}}_{{0, 0}, {1440, 878}}]{131.131, 27}_{3.40282e+38, 3.40282e+38}78HII;_NSWindowTemplate]_cancelButtonSTUV&O7V_sheetSTUVSUX|ZiTMenu>F^h_`abd|SkUNSTage]^bm|f|S]NSIsSeparatore ^bmdwf|S}e ^bQ |Se^b_Edit Size Presets...__defaultSizePresetsMenuSTU_._-sizePresetsMenuItemSelected_CustomDimensions:STUb._,sizePresetsMenuItemSelected_EditSizePresets:STUVT_ _sizePresetsTitleablePopUpButton>aa &SjW`M_b؀Pl 07LI[T >$%\78;>aajSaaaaSS&S I% %\ %%7T>̀ &SWM_b؀Pl07L[T >$\>߀79V]NSTextField22\NSTextField2YNSButton1_SizeMenuDefault]NSTextField21\NSTextField1\File's Owner[NSMenuItem1YPopUpList>T>U>LaH&MW`IQb MPKaJSNjO_׀6 l 7[> T$\P0~/#LI%>%&'()*+,-./0123456789:;<=>?@ABCD€À9& 3$@ 2%  :?40; =1>Fdh>g>j78lmm;^NSIBObjectData"'1:?DRTfLSZhz  2LVcegikmoqsuwy{} !#$-4AGPRgikmoqsuwy{3>@BDFH` ")09;DFIV_dk'469BK]js468:<=?W|~ B X m |    " / = F Q Z m v } ! # % * , . 0 2 4 ; = T e g i k m   % 1 3 5 7 9 > @ B D F H J e l     & G I K M O Q V X b s u w z 4>JXeo68:<>@BIfhjlnoq .F !#%&'*-/4EGIKTV ")6EGIKSenu )1:?HWkz  )0IPmoqsuw| ,:KMOQSZkmoqs !#%'PRTUWY[]`b  "Qbdfhj/13579;=?ACEGIKMOQSUW`b*8ER^hqsvx  ^`bdfhjlnprtvxz|~nPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentWindow.nib/0000755000076500000240000000000014400242511024401 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentWindow.nib/classes.nib0000644000076500000240000000403712744251411026544 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = MyDocument; LANGUAGE = ObjC; SUPERCLASS = NSDocument; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPCanvasView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, { CLASS = PPDocumentWindow; LANGUAGE = ObjC; SUPERCLASS = NSWindow; }, { ACTIONS = { clearBackgroundImage = id; copy = id; copyMerged = id; cropToSelection = id; cut = id; cutMerged = id; decreaseActiveLayerOpacity = id; decreaseZoom = id; delete = id; deleteActiveLayer = id; deleteMerged = id; disableAllLayers = id; duplicateActiveLayer = id; editBackgroundSettings = id; editGridSettings = id; enableAllLayers = id; fillSelection = id; flattenAllLayers = id; flipHorizontally = id; flipVertically = id; increaseActiveLayerOpacity = id; increaseZoom = id; invertSelection = id; makeNextLayerActive = id; makePreviousLayerActive = id; mergeWithLayerAbove = id; mergeWithLayerBelow = id; newLayer = id; paste = id; pasteIntoActiveLayer = id; resize = id; rotate180 = id; rotate90Clockwise = id; rotate90Counterclockwise = id; selectAll = id; selectNone = id; toggleActiveLayerEnabledFlag = id; toggleActivePanelsVisibility = id; toggleBackgroundImageVisibility = id; toggleGridVisibility = id; toggleLayersPanelVisibility = id; togglePreviewPanelVisibility = id; toggleToolsPanelVisibility = id; zoomToFit = id; }; CLASS = PPDocumentWindowController; LANGUAGE = ObjC; OUTLETS = { "_canvasView" = PPCanvasView; }; SUPERCLASS = NSWindowController; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentWindow.nib/info.nib0000644000076500000240000000067512744251411026046 0ustar joshstaff IBDocumentLocation 142 149 356 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 5 IBSystem Version 10K549 PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/DocumentWindow.nib/keyedobjects.nib0000644000076500000240000001537512744251411027571 0ustar joshstaffbplist00deT$topX$objectsX$versionY$archiver]IB.objectdataN /34:;?CIQijklmuy %,3458;FQRSTUVWX[^aU$null  !"#$%&'()*+,-.[NSNamesKeys[NSFramework_NSAccessibilityOidsValues_NSAccessibilityConnectors_NSObjectsValues]NSNamesValues]NSConnections]NSFontManagerVNSRootYNSNextOid_NSVisibleWindows]NSObjectsKeys]NSClassesKeysZNSOidsKeys\NSOidsValues_NSAccessibilityOidsKeysV$class_NSClassesValues:LJ9;<7>@AKM?012[NSClassName_PPDocumentWindowController5678X$classesZ$classname89^NSCustomObjectXNSObject_IBCocoaFramework<=>ZNS.objects56@AAB9\NSMutableSetUNSSet<DHEFG 35JKL%NOP]NSDestinationWNSLabelXNSSource12 RSTUVWXYZ[\]^_`abcdefgh_NSWindowStyleMask_NSWindowBackingYNSMinSize]NSWindowTitle]NSWindowClass\NSWindowRect\NSScreenRectYNSMaxSize\NSWindowViewYNSWTFlags[NSViewClass. -/Px0_{{329, 228}, {600, 600}}P_PPDocumentWindowTViewnopq$stZNSSubviews_NSNextResponderWNSFrame+,<vHwnoz{|}~ee[NSFrameSize[NSSuperview]NSNextKeyView[NSHScrollerXNSvFlagsXNSsFlags[NSVScroller]NSContentView)'0#*<H#'noz{|~wwYNSDocViewYNSBGColorYNScvFlags"<Hzo{0[NSExtensionZ{500, 500}\PPCanvasViewVNSView569\NSCustomView[NSResponder569^NSMutableArrayWNSArrayZ{600, 600}_NSCustomColorSpace\NSComponentsUNSRGB\NSColorSpaceO(0.5684555173 0.5685424209 0.5684366226 1O'0.4959160089 0.4959964454 0.4958871305!UNSICC WNS.dataO H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP ?.J`<_|}cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km56ͣ9]NSMutableDataVNSData56Ң9\NSColorSpace\NSColorSpace56բ9WNSColor56ؤ9ZNSClipViewo{p~wwwZNSCurValueXNSTargetYNSPercentXNSAction#?$&#?,`%_{{585, 0}, {15, 522}}\_doScroller:569ZNSScrollerYNSControlo{p~www(&#?%_{{0, 585}, {600, 15}}Z{600, 600}569\NSScrollView_{{1, 9}, {600, 600}}569_{{0, 0}, {1440, 878}}^{131.131, 108}_{3.40282e+38, 3.40282e+38}569_NSWindowTemplateXdelegate569_NSNibOutletConnector^NSNibConnectorJKLP O% 42VwindowJKLO%62[_canvasView<ePw 8569<wP%e 8<&eP% 8<-h`01 <=8VWindow\File's Owner<68<98<<EGPwFe% 5 38<GHIJKLMNOBCDEFGHI8<YH<\8<_856bcc9^NSIBObjectData_NSKeyedArchiver'0:?MO?KWs #=DVXZ\^`bdfhjlnprtvxz$17@GIKMO`nv(5?KMOQSUWY[]bdf!-;GPYesuwy{}  (468:<>@KX_hq~3]_ajprt} ).6?HSx 9;=?AJLUWoz %.7>Uduwy{}  !#%'.;DEGPQS\moqsuwy{}fPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ExportPanelAccessoryView.nib/0000755000076500000240000000000014400242511026403 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ExportPanelAccessoryView.nib/classes.nib0000644000076500000240000000325613237763115030557 0ustar joshstaff{ IBClasses = ( { ACTIONS = { "" = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { ACTIONS = { canvasSettingCheckboxClicked = id; fileFormatPopupMenuItemSelected = id; scalingFactorSliderMoved = id; }; CLASS = PPExportPanelAccessoryViewController; LANGUAGE = ObjC; OUTLETS = { "_backgroundImageCheckbox" = NSButton; "_backgroundImageTextField" = NSTextField; "_backgroundPatternCheckbox" = NSButton; "_backgroundPatternTitleablePopUpButton" = PPTitleablePopUpButton; "_exportAccessoryView" = NSView; "_exportSizeTextField" = NSTextField; "_fileFormatPopUpButton" = NSPopUpButton; "_gridCheckbox" = NSButton; "_gridTitleablePopUpButton" = PPTitleablePopUpButton; "_previewImageView" = NSImageView; "_scalingFactorSlider" = NSSlider; "_scalingFactorTextField" = NSTextField; }; SUPERCLASS = NSObject; }, { CLASS = PPParabolicSlider; LANGUAGE = ObjC; SUPERCLASS = NSSlider; }, { CLASS = PPTitleablePopUpButton; LANGUAGE = ObjC; SUPERCLASS = NSPopUpButton; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ExportPanelAccessoryView.nib/info.nib0000644000076500000240000000105313237763115030046 0ustar joshstaff IBDocumentLocation 347 45 571 346 0 0 1440 878 IBEditorPositions 5 632 585 467 247 0 0 1680 1028 IBFramework Version 489.0 IBOpenObjects 5 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ExportPanelAccessoryView.nib/keyedobjects.nib0000644000076500000240000003216113237763115031572 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiverF 156<=AE^fq~"#&)0189@AIJNO_euy%*+0126:;<>AIR;S\;]f;gp;qsy} {  #%.2;359BCOQZ^;_aelmtuvw}  .0Qm !"#$%&'( )*+,-./0123456789:;<=>?@!ABCDEFGHKNQU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesE D  BC] 234[NSClassName_$PPExportPanelAccessoryViewController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGKHIJKLMNOPQRSTUVWXYZ[\] ĀƀȀʀ̀ЀҀԀր؀ڀ܀ހ_`abce]NSDestinationXNSSourceWNSLabelÀ ghi2j+lmnop_NSNextResponderZNSSubviews[NSFrameSize[NSExtension >FsKtuvwxyz{|} &15;Z^gccWNSFrameVNSCellXNSvFlagsYNSEnabled[NSSuperview   _{{211, 146}, {40, 17}}t[NSCellFlags_NSBackgroundColorZNSContentsYNSSupport]NSControlView\NSCellFlags2[NSTextColor @VScale:VNSSizeVNSNameXNSfFlags#@*\LucidaGrande78;VNSFontWNSColor\NSColorSpace[NSColorName]NSCatalogNameVSystem\controlColorWNSWhiteK0.6666666978;_controlTextColorĀB078Ǥ;_NSTextFieldCell\NSActionCell78˦;[NSTextField\%NSTextFieldYNSControlVNSView[NSRespondergcc  _{{255, 144}, {41, 22}}u_NSDrawsBackgroundqA! @ $Q1#"_textBackgroundColorB1%YtextColorg2cc_NSOriginalClassName 0)(* ' _PPParabolicSliderXNSSlider_{{302, 144}, {127, 21}}     v WNSValue_NSNumberOfTickMarks_NSTickMarkPositionZNSMaxValueZNSMinValueZNSVertical]NSAltIncValue_NSAllowsTickMarkValuesOnly#@I/+-&#@Y#YNS.string,P78;_NSMutableStringXNSString !#@(.YHelvetica78$%%;\NSSliderCell78'((;^NSClassSwappergc,-c 23 _{{211, 175}, {137, 17}}4w41_Exported Image Size:gc<=c 67 _{{349, 175}, {81, 17}}DExG895@Y0000x0000LM:_LucidaGrande-BoldgPQhRSTcVWXYZc\]][NSHScrollerXNSsFlags[NSVScroller]NSNextKeyView]NSContentView VYX< R==>FaK]\V=RVgfghhiSyklmnopqryqXNSBoundsYNScvFlagsYNSDocViewYNSBGColor;QLM>?N;?>FwKq?gz{]}~]ZNSEditable[NSDragTypes=JG H@ =>?ABCDEF_Apple PDF pasteboard type_Apple PNG pasteboard type_NSFilenamesPboardType_1NeXT Encapsulated PostScript v1.2 pasteboard type_NeXT TIFF v4.0 pasteboard type_Apple PICT pasteboard type_{{0, -42}, {200, 200}}  WNSStyleWNSAlignWNSScaleZNSAnimatesI78;[NSImageCell\%NSImageCell78;[NSImageView78;^NSMutableArrayWNSArray_{{1, 1}, {162, 162}}_{{0, -42}, {162, 162}}_NSCustomColorSpaceOTNSIDP78;78;ZNSClipViewgQyyyXNSTargetXNSActionZNSCurValueYNSPercent;;US T;#?#? _{{163, 1}, {11, 162}}\_doScroller:78ɥ;ZNSScrollergQyyyĀ;;UW T;_{{1, 163}, {162, 11}}_{{17, 15}, {175, 175}}78פ;\NSScrollViewgcc [\ _{{211, 18}, {79, 17}}z]Z\File Format:gcc _` _{{292, 12}, {138, 26}}  { p  _NSMenuItemRespectAlignment_NSArrowPosition_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalentZNSMenuItem_NSPreferredEdge_NSUsesItemFromMenu]NSAltersState_NSPeriodicDelayVNSMenu]NSButtonFlagsA@ bK~acd^ e@!, !" $ WNSTitle_NSKeyEquivModMaskZNSKeyEquiv]NSMnemonicLocYNSOnImage\NSMixedImageWNSState`nfbgkem&'()[NSMenuItems}op[PNG Graphic2,-./^NSResourceNamejhiWNSImage_NSMenuCheckmark783445;_NSCustomResource_%NSCustomResource2,-.9jhl_NSMenuMixedState__popUpItemAction:78=;@,ZOtherViews>FCKEFGHdqtwzL !" Q`nrbgkes\TIFF GraphicV !" [`nubgkev[GIF Graphic` !" e`nxbgkey\JPEG Graphicj !" o`n{bgke|[BMP Graphic78r;78tuuvwx;_NSPopUpButtonCell^NSMenuItemCell\NSButtonCell]%NSButtonCell78z{{|;]NSPopUpButtonXNSButtong~hc cYNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition  >FKg||_{{2, 2}, {1, 111}}78Σ;_{{200, 15}, {5, 175}}V{0, 0} !SBoxM0 0.8000000178;UNSBoxg~hTc  c  >FKgh}}>FKÀg _{{6, 29}, {22, 18}} րbbHF7Kg2<> 0 _{{24, 26}, {186, 22}}  HJ N b~ ,>T !"NY nbgk&'\]}_Background Pattern@,>FcKJghi _{{24, 8}, {110, 14}}p_Background Image_{{2, 2}, {215, 77}}_{{211, 49}, {219, 81}} |!bZ{447, 205}78;\NSCustomView__exportAccessoryView78;_NSNibOutletConnector^NSNibConnector_`abuÀ__scalingFactorTextField_`abqÀ?__previewImageView_`abvÀ&__scalingFactorSlider_`abxÀ5__exportSizeTextField_XNSMarkerVNSFileπd΀_NSToolTipHelpKeySpng78;_NSIBHelpConnector_FπtрSgif_EπqӀTtiff_GπwՀSjpg_`ab{€À^__fileFormatPopUpButton_HπzـSbmp_`ab΀À__backgroundImageCheckbox_`abԀÀ__backgroundPatternCheckbox_`abڀÀ]_gridCheckbox_`av&_scalingFactorSliderMoved:78;_NSNibControlConnector_`a{^_ fileFormatPopupMenuItemSelected:_`a_canvasSettingCheckboxClicked:_`a_`a_`abÀ__gridTitleablePopUpButton_`abÀ_&_backgroundPatternTitleablePopUpButton_`ab À__backgroundImageTextField>wxuyt}|E {qJzGHvcNF1d5; qe^?Zwz& t78/;>2c cccc}cc {cyNc  |c e e^ ; ee e>Swxut|E{ JzvNcF1d5 q^eZ& t>opqrstuvxyr{}~rZNSButton42]NSTextField22]NSTextField23]NSTextField21^NSPopUpButton1YPopUpListXNSBox211[NSMenuItem1\NSTextField1YNSButton4\NSTextField2\File's OwnerZNSButton41WNSView1YNSSlider2TView[NSMenuItem2>v&>  '>5NwPOLuy]XY|Eqz\MTJFKxtSWIQ}H {VUJGH[ZvcNRЀ1ԀҀdʀ;瀧q?Z̀܀ƀtȀ5 ڀĀր e^ހwz& >5       !"#$%&'()*+,-./0123456789:;<=>?@A7+984-.T\LMP<2Y!/[6F"3$, EOD:C1S0IGX5?=ZN#U@>FJK>M>P78RSS;^NSIBObjectData"'1:?DRTfGNUcu-GQ^`cehkmoqtwy|~ +-.7>KQZ\%1=?ACEGIRTikmoqsuwy{}0;ES`lqsuwy{ ')+-/18ERZ\^jsx   $ + 7 T V X Z \ ] _ x     ( * , . 0 : _ u w y { }   ' 2 = H V s |    + 4 9 H e g i k m n p  0 2 4 6 8 : ? A K \ ^ ` c w   ;DNXbdfhjlnqsuwy/G{ !*3?LU`lu| (U^gr|~  0IR[h #r 2@RYgpqsuwy{}&.0249;@BDFHUacegs  ).79DMOZ\^`bd "$&(5^`bdfhjlnz 8BN\is "$&(,9;IR[a4ikmoqsuwy{  +`bdfhjln!#<T)+-/13579FHJLYbdmort "+-Z\^`bdfhjwy{} ,B[xz|~      ! ; L N P R T h y { }  !!!!!*!;!=!?!A!C!G!X!Z!\!^!`!e!v!x!z!|!~!!!!!!!!!!!!!!!!!!""""""";"L"N"P"R"T"b"s"u"w"y"{""""""""""# #####4#E#G#I#K#M#^#`#b#d#f#w#y#{#}#############$$$$\$^$`$b$d$f$h$j$l$n$p$r$t$v$x$z$|$~$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%% % %%%%%%%%%% %"%$%&%(%*%,%5%7%l%n%p%r%t%v%x%z%|%~%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&& & &&&&&$&2&@&N&]&g&p&|&&&&&&&&&&&&&&&&&''' ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''(e(h(k(n(q(t(w(z(}((((((((((((((((((((((((((((((((((((((((((())))) ) )))))))))) )")$)&)()*),).)0)2)4)6)8):)<)>)@)B)D)F)H)J)L)N)P)R)T)V)X)Z)\)^)`)b)d)f)h)q)s)t)})))))))T)PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/HotkeySettings.nib/0000755000076500000240000000000014400242511024417 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/HotkeySettings.nib/classes.nib0000644000076500000240000000226312401511350026550 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { ACTIONS = { OKButtonPressed = id; cancelButtonPressed = id; insertSystemKeyButtonPressed = id; loadDefaultsForLanguageButtonPressed = id; }; CLASS = PPHotkeySettingsWindowController; LANGUAGE = ObjC; OUTLETS = { "_actionFieldsMatrix" = NSMatrix; "_languagePopUpButton" = NSPopUpButton; "_popupPanelFieldsMatrix" = NSMatrix; "_systemKeyPopUpButton" = NSPopUpButton; "_toolFieldsMatrix1" = NSMatrix; "_toolFieldsMatrix2" = NSMatrix; "_window" = NSWindow; }; SUPERCLASS = NSObject; }, { CLASS = PPKeyCancellableWindow; LANGUAGE = ObjC; OUTLETS = { "_cancelButton" = NSButton; }; SUPERCLASS = NSWindow; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/HotkeySettings.nib/info.nib0000644000076500000240000000067312401511350026051 0ustar joshstaff IBDocumentLocation 295 80 356 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 5 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/HotkeySettings.nib/keyedobjects.nib0000644000076500000240000004305312401511350027570 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AET\tuvw{ %&-.56>?GHLMNTU\ijs~M $,4<DLT[\^_`fgjmw{M !)19AHIJPQS]aglyzM %H,-346=>QRVWX\_fgpqryz  #-./01256:?@EFKLQRWX]^afglmrsxy~-BZWXYl^Z[\]^_`adg-./0123456789:;<=>?@ABCDEEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdqefghijklmnopqrstuvwxyz{|}~U$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValues';*:<+)?=234[NSClassName_ PPHotkeySettingsWindowController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FG1HIJKLMNOPQRS !#%UVWXY[]NSDestinationXNSSourceWNSLabel ]^_`abcdefghijklmnopqrs\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass  x   _{{183, 515}, {668, 278}}_Hotkey Settings_PPKeyCancellableWindowxyzYNS.stringTView78|}}~;_NSMutableStringXNSString+_NSNextResponderWNSFrameZNSSubviewsl >F1sЀـހhphYNSBoxType[NSTitleCell]NSTransparent\NSBorderTypeYNSOffsets_NSTitlePosition[NSSuperview]NSContentViewromn>F1lk>F18K^q[NSProtoCell]NSSelectedRowYNSNumRows_NSBackgroundColor[NSCellClass_NSCellBackgroundColorZNSCellSizeXNSvFlagsYNSEnabledYNSNumCols_NSIntercellSpacing]NSMatrixFlags]NSSelectedColWNSCells7542 3_{{9, 13}, {37, 139}}>Fڀ1')+-/[NSCellFlagsZNSContentsYNSSupport]NSControlView\NSCellFlags2[NSTextColor&@#VPencilVNSSizeVNSNameXNSfFlags#@& \LucidaGrande78;VNSFontWNSColor\NSColorSpace[NSColorName]NSCatalogName"! VSystem\controlColor  WNSWhite"K0.6666666978 ;"%$_controlTextColor "B078;_NSTextFieldCell\NSActionCellVNSCell!qUNSTag&(#VEraser)p&*#TFill1&,#TLine9<&.#TRectBE&0#TOval78IJJK;^NSMutableArrayWNSArrayX{37, 14}W{8, 11}Q&6#_Small System Font Text78VWWXYZ[;XNSMatrixY%NSMatrixYNSControlVNSView[NSResponder_`bdqgh79JIG H:_{{50, 11}, {20, 144}}>Fl1mnopqr;BCDEFtuwx{}_NSDrawsBackgroundqA&=<8B @QW"?>_textBackgroundColor "B1"%AYtextColortuwx{q}&=<8 @tuwx{p}&=<8 @tuwx{}&=<8 @tuwx{<}&=<8 @tuwx{E}&=<8 @X{20, 19}V{8, 6}tuwx{}&=< @qˀ7L]\Z [M_{{77, 13}, {92, 139}}>Fπ1ՀNPRTVX&OK#_Freehand Selectq&QK#[Rect Selectp&SK#ZMagic Wand&UK#]Color Sampler<&WK#TMoveE&YK#YMagnifierX{92, 14}Q&6#q7_jig h`_{{173, 11}, {20, 144}}>F1 !"#abcdeftuwx{}&=<^ @tuwx{q}&=<^ @tuwx{p}&=<^ @tuwx{}&=<^ @tuwx{<}&=<^ @tuwx{E}&=<^ @tuwx{}&=< @_{{2, 2}, {206, 166}}78]ZZ[;_{{17, 86}, {210, 183}}V{0, 0}wce&=pqUTools i"M0 0.8000000178kllZ[;UNSBoxhpqsphvrtnu>Fy1vu~slvs>F1wvqvu7x uy_{{12, 15}, {154, 189}}>F1z{}c&pw#q&|w#_Color Picker/Samplerp&~w#^Layer Controls&w#YNavigator<&w#_Tools AlternateE&w#_Color Picker/Sampler Alt.&w#_Layer Controls Alternate&w#_Navigator AlternateY{154, 14}Q&6#vqvu7 u _{{170, 13}, {20, 194}}>F1tuwx{}&=< @tuwx{q}&=< @tuwx{p}&=< @tuwx{}&=< @tuwx{<}&=< @tuwx{E}&=< @tuwx{}&=< @tuwx{}&=< @tuwx{}&=< @_{{2, 2}, {206, 218}}_{{229, 34}, {210, 235}}wMO&=\Popup Panels i"hVWYph\r̀n>F_1\delˀ>Fi1jk\oprtq\wx7 _{{19, 15}, {147, 189}}>F|1}~jq&#_Switch Canvas View Modejp&#_Switch Operation Targetj&#_Toggle Active Panelsj<&#_Toggle Color Picker PaneljE&#WZoom Inj&#XZoom Outj&#[Zoom To Fitj&#\Blink LayersY{147, 14}Q&6#\q\ـ7ʀɀ Ȁ>F܀1䀿€ÀĀŀtuwxk{}&=< @tuwxk{q}&=< @tuwxk{p}&=< @tuwxk{}&=< @tuwxk{<}&=< @tuwxk{E}&=< @tuwxk{}&=< @tuwxk{}&=< @tuwx{}&=< @_{{441, 34}, {210, 235}}w02&=΀WActions i"h89:h؀р _{{545, 4}, {108, 28}}?@ABCDEFGHqIJKNOP_NSAlternateContents_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalent_NSPeriodicDelay]NSButtonFlags׀ԀրӀ@ROKUPQ 78YZZ[;\NSButtonCell]%NSButtonCell78]^^YZ[;XNSButtonh8bch؀ڀ _{{439, 4}, {108, 28}}?@ABCDEFGHjIlmNOP׀Ԁ݀܀VCancelQ.h8uvh؀߀ _{{15, 32}, {124, 28}}?@ABCDEFGHqI~NOP׀ՀԀ_Load Defaults For:xyVhh _{{139, 35}, {88, 22}}?@ABCDEqGqI_NSMenuItemRespectAlignment_NSArrowPositionZNSMenuItem_NSPreferredEdge_NSUsesItemFromMenu]NSAltersStateVNSMenuA@ KԀ @xyVGqXNSTargetWNSTitle_NSKeyEquivModMaskZNSKeyEquiv]NSMnemonicLocYNSOnImage\NSMixedImageXNSActionWNSState[NSMenuItemsVeng_US2^NSResourceNameWNSImage_NSMenuCheckmark78ʣ;_NSCustomResource_%NSCustomResource2π_NSMenuMixedState__popUpItemAction:78;xyրZOtherViews>Fـ178;78ߧZ[;_NSPopUpButtonCell^NSMenuItemCell78^YZ[;]NSPopUpButtonh8h؀ _{{15, 59}, {124, 28}}?@ABCDEFGHqINOP׀ՀԀ_Insert System Key:xyVhh _{{139, 62}, {88, 22}}?@ABCDEqGqI  ՀԀ xyVG qՀ VReturnxyր>F 1"&G +,Հ STab_{{1, 9}, {668, 278}}_{{0, 0}, {1440, 878}}Z{213, 129}_{3.40282e+38, 3.40282e+38}78344;_NSWindowTemplateW_window787889;_NSNibOutletConnector^NSNibConnectorUVWX>8__toolFieldsMatrix1UVWXD^__toolFieldsMatrix2UVWXJ__popupPanelFieldsMatrixUVWXkP__actionFieldsMatrixUVWXYVـ ]_cancelButtonUVWY\Ё_OKButtonPressed:78_``9;_NSNibControlConnectorUVWYeف_cancelButtonPressed:UVWXk __systemKeyPopUpButtonUVWXq"__languagePopUpButtonUVWYw$_insertSystemKeyButtonPressedUVWY}ށ&_$loadDefaultsForLanguageButtonPressed>(Sv"!h}"oqpn\mr~jY k #Xu-dbK})ĀŀTeÀaPCED瀮B€V;sFƀހ '^{8ـ/Ѐ+NczRwf78KK;>ف(S Y jkhjkkjhkjhkhkjhkhkj\\hvhhjvjKs^w^ wK^^K888耥ww8Kw88〼wuK^wKuw^>/(v\Y uـЀsހ >D(EFGHIEKLMNOEQRSRUO,-./0,12345,678795YNSButton1WNSBox11YNSButton2VNSBox1\File's Owner[NSMenuItem2ZNSButton11YPopUpListVWindow^NSPopUpButton1>c(>f(>i(`!}N"qnOmI~Y Rk#vJH"hLQopMr\KPj S-dbeEB€ƀVs; #{8/Ѐ+NfXu K})ĀŀT!ÀaCPDFހ^'ـwRzc%>́(`      !"#$%&'()*+,>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\#)90[`3+7:8*"=Sm#F./9$UT5!-^]6(b<4a 8Z,WY_c1V;2d :R>X>F1>(>(78;^NSIBObjectData"'1:?DRTf -IWco} !$&)+.1479;>ADGP\^` .0369<?BEHKNQbpy %9COQTWYbdfikmpr (357:<EGZ\^`bdfhjl           " $ ' ) > @ B D F H Q S \ ^ ` b d   ) 3 H V d l n p r t }   ! . : C E G I K M R T [ l s z    " * , 8 A F [ ] _ a c v  ( * , . 0 2 4 9 ^ ` b d f h j o 8:<>@B[dqz$&3579;=?dx*,.02457`bdfhjkm   DFHJLMO,QSUWY[]i   ?ACEGIKU^ "$&(*,QSUWY[\^)+-/1346_acegijl -6?Evxz|~!#%'(*,.GPRcegikmoqs (MOQSUWYc "$?dfhjlnpr !#%>GIZ\^`bdfhj13579;<>gikmoqrt   ;=?ACDF]w  !#%')+46;=?  1VXZ\^`b|68:<>@BJoqsuwy{  & ( * , . 0  !!!!#!%!'!)!*!,!U!W!Y![!]!_!`!b!!!!!!!!!!!!!!!!!!!!!""""-"/"1"3"5"7"8":"c"e"g"i"k"m"n"p"""""""""""""""""####### #8#m################$$ $$ $"$$$&$'$)$2$=$J$X$a$l$u$$$$$$$$$$$$$$$$$%%%#%%%'%)%+%,%.%F%{%}%%%%%%%%%%%%%%%%%&8&U&g&r&&&&&&&&&&&&&&&&&&&&&&'''"'6'A'O'Y'f'o'w'y'{'}'''''''''''''''''''''(((*(7(9(;(=(P(d(m(r({(}((((((((((((())")$)&)()*)+)-)E)z)|)~))))))))))))))))*7*8*:*<*>*@*B*E*G*H*I*L*U*W**********************++ + ++++++++ +7+O+Z+w+++++++++++++,,,,,,!,6,G,J,L,N,Q,k,|,,,,,,,,,,,,,,,,,,---,-/-1-3-6-M-^-a-c-e-h--------------.......7.:..............///// / / //////////!/#/%/'/)/+/-///1/3/5/7/9/;/=/?/A/C/E/G/I/K/M/O/Q/S/U/W/Y/[/]/`/b/d/f/h/j/l/n/p/r/t/v/x/z/|/~///////////0O0Q0S0U0X0Z0\0^0`0b0d0f0i0k0m0o0q0s0u0w0y0{0}0000000000000000000000000000000000000000000000000000000000000111*1,1.10121416181:1<1>1A1C1E1G1I1L1N1P1Y1\111111111111111111111111122 22 2)2,2-26292:2C2F3 3 3 333333333!3#3%3'3)3+3-3/313436383;3=3?3B3E3G3I3K3M3O3Q3S3U3W3Y3[3]3_3a3d3f3i3k3m3o3q3s3u3w3z3|3~333333333333333333333333333333333333333333334444444444444444444444444444445555 5 5555555!5$5'5*5-505356595<5?5B5E5H5K5N5Q5T5W5Z5]5`5c5f5i5l5o5r5u5x5{5~555555555555555555555555555555555555555555555556666 6 666666666 6"6$6'6*6-6/616365686;6>6A6C6E6H6K6M6O6R6U6W6Y6[6]6_6a6d6f6i6k6m6o6q6s6v6y6{6~666666666666666666666666666PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/InfoPlist.strings0000644000076500000240000000036614374535524024236 0ustar joshstaff/* Localized versions of Info.plist keys */ NSHumanReadableCopyright = "Copyright (c) 2013-2018,2020,2023 Josh Freeman"; PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/KeyboardNameToLocale.plist0000644000076500000240000000133212044622214025730 0ustar joshstaff Australian en_AU Austrian de_AT Belgian nl_BE Brazilian pt_BR British en_GB Canadian English en_CA Canadian French - CSA fr_CA Portuguese pt_PT Swiss French fr_CH Swiss German de_CH U.S. en_US PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayerControlButtonImageViews.nib/0000755000076500000240000000000014400242511027225 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayerControlButtonImageViews.nib/classes.nib0000644000076500000240000000155612171055225031372 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = PPLayerControlButtonImagesManager; LANGUAGE = ObjC; OUTLETS = { "_displayModeDrawLayerThumbnailView" = NSView; "_displayModeDrawLayerView" = NSView; "_displayModeEnabledLayersThumbnailView" = NSView; "_displayModeEnabledLayersView" = NSView; "_operationTargetDrawLayerThumbnailView" = NSView; "_operationTargetDrawLayerView" = NSView; "_operationTargetEnabledLayersThumbnailView" = NSView; "_operationTargetEnabledLayersView" = NSView; }; SUPERCLASS = NSObject; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayerControlButtonImageViews.nib/info.nib0000644000076500000240000000145712171614220030664 0ustar joshstaff IBDocumentLocation 92 112 356 240 0 0 1440 878 IBEditorPositions 5 422 438 132 106 0 0 1440 878 7 419 313 132 106 0 0 1440 878 8 589 440 132 106 0 0 1440 878 9 595 318 132 106 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 9 8 5 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayerControlButtonImageViews.nib/keyedobjects.nib0000644000076500000240000001470212171614220032401 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AEPXciz &/378?FMNQUV[bhov}~   0@ABCDEFGJMiU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuestwxv1234[NSClassName_!PPLayerControlButtonImagesManager789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FG2HIJKLMNO 6I[lnprQRSTUW]NSDestinationXNSSourceWNSLabel5 4YZ[2\+^_`ab_NSNextResponderZNSSubviews[NSFrameSize[NSExtension 3>Fe2fgh !YjklmnopUrstuvwtUWNSFrameZNSEditableVNSCell[NSDragTypesXNSvFlagsYNSEnabled[NSSuperview    >?|}~_Apple PDF pasteboard type_Apple PNG pasteboard type_NSFilenamesPboardType_1NeXT Encapsulated PostScript v1.2 pasteboard type_NeXT TIFF v4.0 pasteboard type_Apple PICT pasteboard type_{{14, 13}, {52, 27}}[NSCellFlagsWNSStyleZNSContentsWNSAlignWNSScale\NSCellFlags2ZNSAnimates2^NSResourceNameWNSImage_view_draw_layer_icon78;_NSCustomResource_%NSCustomResource78l;[NSImageCell\%NSImageCell78;[NSImageViewYNSControlVNSView[NSResponderYjn2\pU^abU  _{{71, 13}, {27, 27}}78;\NSCustomViewYln[opUtU 1# " Y{112, 11}h_NSBackgroundColorYNSSupport]NSControlView[NSTextColor@0($%!D-_View: DRAW LayerVNSSizeVNSNameXNSfFlags'#@"&\LucidaGrande78ܢ;VNSFontWNSColor\NSColorSpace[NSColorName]NSCatalogName,+*)VSystem_textBackgroundColorWNSWhite,B178ޢ;,/.)YtextColor,B078l;_NSTextFieldCell\NSActionCell78;[NSTextField\%NSTextField78;^NSMutableArrayWNSArrayY{112, 40}__displayModeDrawLayerView78   ;_NSNibOutletConnector^NSNibConnectorQRST 57HYZ[2\+^b 8EF>F29?AYjklmnop r t"#wt 7; <: 7>?(}~1=26>_view_enabled_layers_iconYjn2\p ^;ab 7 @7Yln[op BCt 71CB 7Iπ0(D%A-_View: ENABLED LayersOPYNS.stringG78RSST;_NSMutableStringXNSString__displayModeEnabledLayersViewQRSTXZ5JZYZ[2\+^^_`b KXY>Fd2efgLNRYjn2\pX^kabXJ MJYln[opXrstXJ1PO Jyfπ0(Q%N-_Target: DRAW LayerYjklmnopXrtwtXJT US J>?}~V2W_target_draw_layer_iconOPG__operationTargetDrawLayerViewQRST5\kYZ[2\+^ab ]j>F2^`dYj2\p^ab\ _\Yln[opt\1ba \π0(c%`-_Target: ENABLED LayersYjklmnoprtwt\f ge \>?π}~h2݀i_target_enabled_layers_icon_!_operationTargetEnabledLayersViewQRSTg5m_"_displayModeDrawLayerThumbnailViewQRST5?o_&_displayModeEnabledLayersThumbnailViewQRSTe5Lq_&_operationTargetDrawLayerThumbnailViewQRST5^s_*_operationTargetEnabledLayersThumbnailView>ufhgfXeUg ?N!^R \9JL`A d778 ;>u XUXU X U7J \J 7J\7 \>"uefUhg XL?N`^ !A\7J>2u33553855;3=>?yyzzy{zz|y}~_Thumbnail Image View-1_Static Text (ENABLED Layers)[DisplayDraw\File's Owner]TargetEnabled^DisplayEnabledZTargetDraw>Iu>Lu>OuNfLhgfJOIXeUHKg Mp?Nl!^R \I9r6JL`A [d7n>kulmnopqrstuvwxyz{|}~- +  )$.(#'*,>F2>u>u78;^NSIBObjectData"'1:?DRTf *FT`lz!#%')+-/1357@LNPt}!#%'8FOWY[]_x %/;=?ABDFIJLUWdfhjlnp2Ijv~(<ENZgp{"$&(+-.0:[oy     / 7 D P ^ ` b d f h o  " / ; H Q X g o y          ! F H J L M O Q R T ] _ l n p r t v x        > @ B D F H J a j t v       4 6 8 : < > @ ] _ a c e f h "$&'468:S\^~!BDFHJLNg8IKMOQv  @IKnprtvxz|~ "$&(*35PRTVXZ\^`bdfhj;=?ACEGIKMOQSUWY[]_acegikmvx   $&'023<APPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayerControlsPopupPanel.nib/0000755000076500000240000000000014400242511026237 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayerControlsPopupPanel.nib/classes.nib0000644000076500000240000000377013116554144030410 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { ACTIONS = { canvasDisplayModeButtonPressed = id; drawingLayerEnabledCheckboxClicked = id; drawingLayerOpacitySliderMoved = id; drawingLayerPopupMenuItemSelected = id; layerOperationTargetButtonPressed = id; }; CLASS = PPLayerControlsPopupPanelController; LANGUAGE = ObjC; OUTLETS = { "_backgroundFillTextField" = NSTextField; "_canvasDisplayModeButton" = NSButton; "_drawingLayerEnabledCheckbox" = NSButton; "_drawingLayerOpacitySlider" = NSSlider; "_drawingLayerOpacityTextField" = NSTextField; "_drawingLayerThumbnailView" = PPThumbnailImageView; "_drawingLayerTitleablePopUpButton" = PPTitleablePopUpButton; "_layerOperationTargetButton" = NSButton; }; SUPERCLASS = PPPopupPanelController; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPPopupPanel; LANGUAGE = ObjC; SUPERCLASS = NSPanel; }, { CLASS = PPPopupPanelController; LANGUAGE = ObjC; SUPERCLASS = PPPanelController; }, { CLASS = PPThumbnailImageView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, { CLASS = PPTitleablePopUpButton; LANGUAGE = ObjC; SUPERCLASS = NSPopUpButton; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayerControlsPopupPanel.nib/info.nib0000644000076500000240000000067512176005123027700 0ustar joshstaff IBDocumentLocation 149 611 470 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 56 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayerControlsPopupPanel.nib/keyedobjects.nib0000644000076500000240000002315013116554144031420 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AEV^lrs!$%*34589>UVWX[hop|  #)23<=?CFMNZ^_^cfmnuv{| !"#$%&'(,0Rtuvwxyz{|}~ U$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValues݀܀ڀd234[NSClassName_#PPLayerControlsPopupPanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGHIJKLMNOPQRSTU $*5<WXYZ[]]NSDestinationXNSSourceWNSLabel# "_`abcdefghije_NSNextResponderWNSFrameVNSCellXNSvFlagsYNSEnabled[NSSuperview !  _`m+opqZNSSubviewsB_{{20, 74}, {135, 57}}tuvwxyz{|}~[[NSCellFlags_NSAlternateContents]NSNormalImage_NSPeriodicInterval^NSButtonFlags2_NSKeyEquivalentZNSContentsYNSSupport]NSControlView_NSPeriodicDelay\NSCellFlags2]NSButtonFlags K @_Canvas Display ModeVNSSizeVNSNameXNSfFlags#@$\LucidaGrande78;VNSFont\NSImageFlagsVNSRepsWNSColor V{1, 1}>F>_NSTIFFRepresentationOMM* RS78;_NSBitmapImageRepZNSImageRep78;WNSArray78;^NSMutableArray\NSColorSpaceWNSWhiteD0 078;78ǣ;WNSImageX%NSImageP78̥a;\NSButtonCell]%NSButtonCell\NSActionCell78ѥ;XNSButtonYNSControlVNSView[NSResponder__canvasDisplayModeButton78أ;_NSNibOutletConnector^NSNibConnectorWXYZހ#%)_`abcdefije !&' _{{153, 74}, {135, 57}}tuvwxyz{|}~ (%_Layer Operation Target__layerOperationTargetButtonWXYZ#+4_`abcdeije 3,- _{{83, 21}, {204, 21}}tz{|~    WNSValue_NSNumberOfTickMarks_NSTickMarkPositionZNSMaxValueZNSMinValueZNSVertical]NSAltIncValue_NSAllowsTickMarkValuesOnly#?2.0+#?#YNS.string/78;_NSMutableStringXNSString#@(1YHelvetica78  a;\NSSliderCell78"##;XNSSlider__drawingLayerOpacitySliderWXYZ')#6;_`b2+de-./01e[NSExtension :789 _{{56, 46}, {24, 24}}_PPThumbnailImageView78677;\NSCustomView__drawingLayerThumbnailViewWXYZ;=#=?@ABCDEFGHIeKLMNOPQRST\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass ?x@>A_{{143, 193}, {308, 151}}UPanel\PPPopupPanelZ/TView>F]^[abd'fgC %N^+z6_`abcdejklije MDE _{{20, 20}, {268, 111}}tqz{|~rstuw^yj{_NSBackgroundColor_NSDrawsBackground[NSTextColorLGFC@ H~#@*K0.91761363[NSColorName]NSCatalogNameKJIVSystem_controlTextColorB078a;_NSTextFieldCell78;[NSTextField\%NSTextField_`abcdejijeZNSEditable[NSDragTypes ]V WO >?PQRSTU_Apple PDF pasteboard type_Apple PNG pasteboard type_NSFilenamesPboardType_1NeXT Encapsulated PostScript v1.2 pasteboard type_NeXT TIFF v4.0 pasteboard type_Apple PICT pasteboard type_{{21, 52}, {13, 11}}tz~WNSStyleWNSAlignWNSScaleZNSAnimates\X2^NSResourceName[YZ^pencil_segment78ţ;_NSCustomResource_%NSCustomResource78ɤa;[NSImageCell\%NSImageCell78ͥ;[NSImageView_`abc2deije_NSOriginalClassName ya`b _ _PPTitleablePopUpButton]NSPopUpButton_{{82, 44}, {206, 26}}tuwxy{|}~j  wbjj_NSMenuItemRespectAlignment_NSArrowPosition_NSAlternateImageZNSMenuItem_NSPreferredEdge_NSUsesItemFromMenu]NSAltersStateVNSMenuA@ xFecf^ g@~d_LucidaGrande-Boldɀ/    XNSTargetWNSTitle_NSKeyEquivModMaskZNSKeyEquiv]NSMnemonicLocYNSOnImage\NSMixedImageXNSActionWNSStatebnhikgm[NSMenuItemswopUItem12[Yj_NSMenuCheckmark2l_NSMenuMixedState__popUpItemAction:78ߢ;"/ZOtherViews>F%'(fqt,  1bnrikgsUItem26  ;bnuikgvUItem378>;78@AABa;_NSPopUpButtonCell^NSMenuItemCell78DEE;^NSClassSwapper_`abcdefIJije !{| _{{36, 48}, {22, 18}}tuvwxyz{|}~QRSwdXY }FzHڀ(a'b[ed;'^fgftNq%^ z=+6Cg>eeee;eeeebeegg g =  ^ >'('bd;^fg6tgq^z=+fC>M`?VView21[NSMenuItem2YPopUpList[NSMenuItem1YNSButton4YNSSlider2\NSTextField2\NSTextField1]NSTextField11\File's Owner>*b^>.ր_>2'KPb[IdS;RfgHJQ(aMeULONT^'q5^ $z=+f *tN% TUVWXYZ[\]^_`abcdefghijklmnopqrs€ÀĀŀƀǀȀɀʀˀ̀̀΀πЀрҀӀԀՀր׀؀BP?:H\`8D_A<^GIYC=;M9cLONbS>@>F>>78;^NSIBObjectData"'1:?DRTf%+v} )7J\v !*=FQST]dqw"*1:DPRTVX[\^oz|~#5@JXjw1>EMOQVXZajloqz|Zcj}     ! , 9 G T ] h q {       9 n p r t v x z | E M c x     ' 0 A C L N X a j w   / 8 A N k | ~  2<HJLNPY[]_ace=Qeqsuwy{!$-6HQ^jw5i  -/13BKRey   '5M%./13579;=>?BDIZ\^au~  %')+-:FHJLR_acew "$&,UWY[]_acektyIKMOQSUWY[]boqsu~ "$&(=?ACER_am&-FQnw|  7HJLNPr%68:<>^oqsuw   (*MOQSUWY[]_acegikmvx  *7DR_hjmoxz} UWY[]_acegikmoqsuwy{}PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayersPanel.nib/0000755000076500000240000000000014400242511023652 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayersPanel.nib/classes.nib0000644000076500000240000000514413046246733026024 0ustar joshstaff{ IBClasses = ( { ACTIONS = { "" = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPLayerBlendingModeButton; LANGUAGE = ObjC; SUPERCLASS = NSButton; }, { CLASS = PPLayerEnabledButtonCell; LANGUAGE = ObjC; SUPERCLASS = NSButtonCell; }, { CLASS = PPLayerOpacitySliderCell; LANGUAGE = ObjC; SUPERCLASS = NSSliderCell; }, { CLASS = PPLayersPanel; LANGUAGE = ObjC; SUPERCLASS = NSPanel; }, { ACTIONS = { addLayerButtonPressed = id; canvasDisplayModeButtonPressed = id; deleteLayerButtonPressed = id; duplicateLayerButtonPressed = id; layerBlendingModeButtonPressed = id; layerOperationTargetButtonPressed = id; layersTableOpacitySliderMoved = id; }; CLASS = PPLayersPanelController; LANGUAGE = ObjC; OUTLETS = { "_canvasDisplayModeButton" = NSButton; "_layerBlendingModeButton" = PPLayerBlendingModeButton; "_layerOperationTargetButton" = NSButton; "_layersTable" = PPLayersTableView; }; SUPERCLASS = PPPanelController; }, { ACTIONS = { layerEnabledButtonCellClicked = id; }; CLASS = PPLayersTableView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; }, { CLASS = PPLayersWindow; LANGUAGE = ObjC; SUPERCLASS = NSPanel; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { ACTIONS = { restoreSelectionFromLastMouseDown = id; }; CLASS = PPTableView; LANGUAGE = ObjC; SUPERCLASS = NSTableView; }, { CLASS = PPThumbnailImageView; LANGUAGE = ObjC; SUPERCLASS = NSView; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayersPanel.nib/info.nib0000644000076500000240000000067412372226540025320 0ustar joshstaff IBDocumentLocation 168 -65 425 447 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/LayersPanel.nib/keyedobjects.nib0000644000076500000240000002704113046246733027042 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AE\d   789>?DEFJENQTW]^dijmvz  $%(456:CDHILST_cdgjqrz~i  #$)*/056;<ABGHMNSTilnV     = #&)U$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValues􀺀ǀƀȀi234[NSClassName_PPLayersPanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGMHIJKLMNOPQRSTUVWXYZ[ S]^_`ac]NSDestinationXNSSourceWNSLabelR Qefghijklmnopqr2stuvwxyz{|}~x_NSNextResponder_NSDraggingSourceMaskForNonLocalYNSTvFlags_NSOriginalClassName\NSHeaderView_NSBackgroundColor_NSAllowsTypeSelect\NSCornerView_NSIntercellSpacingWidth_NSColumnAutoresizingStyle_NSIntercellSpacingHeightXNSvFlags[NSFrameSizeYNSEnabled[NSGridColor_NSDraggingSourceMaskForLocal[NSSuperview^NSTableColumns[NSRowHeight 2@ 9 #@#@ N #@6_PPLayersTableView[NSTableViewepuaaWNSFrameYNScvFlagsZNSSubviewsYNSDocViewYNSBGColor]NSNextKeyView_^] A Z{237, 240}epqua epqu}}_fgAY{237, 17}78;_NSTableHeaderViewVNSView[NSResponderepuelpuxx[NSHScrollerXNSsFlags_NSHeaderClipView\NSScrollAmts[NSVScroller]NSContentViewZdihЀ\OA A AAZ` _{{237, 0}, {16, 17}}78Ӥ;]_NSCornerView>FրMڀ4=#@Y?#@D#@@ TNamejy%=!j&a!@FA@ D#@*  CB"_controlBackgroundColor K0.66666669  $E"_controlTextColor78;a3IH#@TJ WOpacityj)`y%7H!h&2zyyaWNSValue_NSNumberOfTickMarks_NSTickMarkPositionZNSMaxValueZNSMinValueZNSVertical]NSAltIncValue_NSAllowsTickMarkValuesOnly#2L#? K_PPLayerOpacitySliderCell\NSSliderCell78ң;^NSMutableArrayWNSArray  PO"YgridColor܀ D0.5\_layersTable78;_NSNibOutletConnector^NSNibConnector]^_`RT-\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClassZVxWUX_{{339, 390}, {252, 236}}VLayersWNSPanelYNS.stringYTView78;_NSMutableStringXNSStringe+   [>FMjqv{>FMx `d>F"Ma _{{0, 17}, {237, 137}}78&'';ZNSClipViewe)pr*u+./13XNSTargetXNSActionYNSPercentca b#?DD@_{{237, 17}, {15, 137}}\_doScroller:787889;ZNSScrollerYNSControle)pr*u+.>1Bce b#?Dc_{{-100, -100}, {262, 15}}>FFM}_{{0, 26}, {252, 154}}78JKK;\NSScrollViewepruNOP€Zpkl Z_{{2, 1}, {33, 23}}U!%"$&'()VX0-4]^_NSAlternateContentsom@j@2@ABb.,n_plus_button_overlay_small78e88f;]%NSButtonCell78hii9;XNSButtonepruNmn€Zprs Z_{{37, 1}, {33, 23}}U!%"$&'()Vu0-4]^ot@q2@AB}.,u_minus_button_overlay_smallepruN€Zpwx Z_{{72, 1}, {79, 23}}U%"#$&'()V0-4]ozyzv@YDuplicate;=epruN€Zp|} Z_{{0, 179}, {127, 57}}U%"$&'()V0-4]o~{@\Display Mode=#@$epruN€Zp Z_{{125, 179}, {127, 57}}U%"$&'()V0-4]o_Operation Targetehpr2uz€Z2 Z_PPLayerBlendingModeButton_{{208, 3}, {21, 19}}U!%"$&'()V04]΀o@D@_Layer Blending Mode2@ABӀ.,_blend_mode_icon_standard_{{1, 1}, {252, 236}}78;_{{0, 0}, {1680, 1028}}Z{252, 187}_{600, 3.40282e+38}78ݢ;_NSWindowTemplateVwindow]^_`aR ZdataSource]^_`aR Xdelegate]^_j_addLayerButtonPressed:78;_NSNibControlConnector]^_q_deleteLayerButtonPressed:]^_v_duplicateLayerButtonPressed:]XNSMarkerVNSFilej_NSToolTipHelpKeyYNew Layer78   ;_NSIBHelpConnector]q_Delete Selected Layer]v_Duplicate Selected Layer]^_`R{__canvasDisplayModeButton]^_`"R__layerOperationTargetButton]^_({_canvasDisplayModeButtonPressed:]^_._"layerOperationTargetButtonPressed:]3{_'The Canvas View Mode determines the set of layers to display in the document window of a multi-layer document. The view mode can either be "ENABLED Layers", which is the normal setting for displaying the document's merged layers, or "DRAW Layer", which displays only the active (drawing) layer.]9_ The Operation Target determines the set of layers to read from - or write to - when performing a non-drawing operation on a multi-layer document. The target can either be "ENABLED Layers", which targets all enabled layers at once, or "DRAW Layer", which targets only the active (drawing) layer. Operations that use the target setting: Edit menu actions (Cut, Copy, Delete, Select Visible, Deselect Invisible, Tile Selection), Operation menu actions (Flip, Rotate, Nudge), and Tools (Fill, Magic Wand, Color Sampler, Move).]^_a@ &_layerEnabledButtonCellClicked:]^_FJ_layersTableOpacitySliderMoved:]^_`LR__layerBlendingModeButton]^_R_layerBlendingModeButtonPressed:>UV^a[vGZ4J& qT:j<{nopqrsy-t; 78mӢ;>Upaaaa€Z T Z Z4GZZ4Z Z>Ua T<>U€ÀĀUPanel]NSScrollView1^NSTableColumn1\File's Owner>Ua& J>U5ˀ' K>U'NSV[RQWPUIM[XZYJ^aHTKOLv4:Z&qSUӀ'ʀˀ̀̀΀πЀрҀӀԀՀր׀؀ـڀۀ܀݀ހ߀&Z!(^*Y N_M \X %hagbe f)cW [L$>F"M>U%>U(78*++;^NSIBObjectData"'1:?DRTfSY"-;Wex$/4CL_hsuv')+-/7Snw   ';Gpx!#%')+5>G[bn        " $ 7 : < > @ B Y b k y       & C O Z d q }   " ' / D P ^ ` b d f h o . = P b w     $ 1 @ B D F N W ` g z %')+-/9VXZ\^`uwy{}@O^_acenpy7DFRgikmo5=Shs~ !)>@BDFP]_dqz #1>HZnx!#%')24CEGIKMOQZ\gikmoqz| &3<GR\!#$&;p-/13568N468:<>@BKUfhj;=?ACDF`OQSUWY[]f| +2CEGIKVgikmox ?PY`bdfh{ !#%@QSUWYw 4EGIKM!]!n!p!r!t!v!!!!!!!!!!!!"""""""@"I"K"r"t"v"x"z"|"~""""""""""""""""""""""""###### # ##########%#2#4#6#8#:#<#>#G#I#V#X#Z#\#^#`#b#h#v##################$&$($*$,$.$0$2$4$6$8$:$<$>$@$B$D$F$H$J$L$N$P$R$T$V$X$Z$\$^$`$b$d$f$h$j$l$n$p$r$t$}$$$$$$$$$$$$$$$$$$$$$$$$$%%%%%% % %%%%%%%%%% %"%$%&%(%*%,%.%0%2%4%6%8%:%<%>%@%B%D%F%H%J%L%N%P%R%T%V%X%Z%\%^%`%b%d%f%h%q%s%t%}%%%%%%%,%PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/MainMenu.nib/0000755000076500000240000000000014400242511023144 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/MainMenu.nib/classes.nib0000644000076500000240000001135613065607343025317 0ustar joshstaff{ IBClasses = ( { ACTIONS = { closeHolesInSelection = id; copyMerged = id; cropToSelection = id; cutMerged = id; decreaseActiveLayerOpacity = id; decreaseZoom = id; deleteActiveLayer = id; deleteMerged = id; deselectAll = id; deselectInvisibleTargetPixels = id; disableAllLayers = id; duplicateActiveLayer = id; editBackgroundSettings = id; editGridSettings = id; editHotkeySettings = id; editSamplerImagesSettings = id; enableAllLayers = id; eraseSelectedPixels = id; exportImage = id; fillSelectedPixels = id; flipCanvasHorizontally = id; flipCanvasVertically = id; flipHorizontally = id; flipVertically = id; hotkeySettings = id; increaseActiveLayerOpacity = id; increaseZoom = id; invertSelection = id; makeNextLayerActive = id; makePreviousLayerActive = id; mergeAllLayers = id; mergeWithLayerAbove = id; mergeWithLayerBelow = id; moveActiveLayerDown = id; moveActiveLayerUp = id; newDocumentFromSelection = id; newLayer = id; nextSamplerPanelImage = id; nudgeDown = id; nudgeLeft = id; nudgeRight = id; nudgeSelectionOutlineDown = id; nudgeSelectionOutlineLeft = id; nudgeSelectionOutlineRight = id; nudgeSelectionOutlineUp = id; nudgeUp = id; pasteIntoActiveLayer = id; previousSamplerPanelImage = id; resize = id; rotate180 = id; rotate90Clockwise = id; rotate90Counterclockwise = id; rotateCanvas180 = id; rotateCanvas90Clockwise = id; rotateCanvas90Counterclockwise = id; scale = id; selectVisibleTargetPixels = id; tileSelection = id; tileSelectionAsNewLayer = id; toggleActiveLayerEnabledFlag = id; toggleActivePanelsVisibility = id; toggleBackgroundImageSmoothing = id; toggleBackgroundImageVisibility = id; toggleCanvasDisplayMode = id; toggleColorPickerVisibility = id; toggleGridGuidelinesVisibility = id; toggleGridType = id; toggleGridVisibility = id; toggleLayerBlendingMode = id; toggleLayerOperationTarget = id; toggleLayersPanelVisibility = id; togglePreviewPanelVisibility = id; toggleSamplerImagePanelVisibility = id; toggleToolModifierTipsPanelVisibility = id; toggleToolsPanelVisibility = id; zoomToFit = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSDocumentController; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = NSWindow; LANGUAGE = ObjC; SUPERCLASS = NSResponder; }, { ACTIONS = { activateNextDocumentWindow = id; activatePreviousDocumentWindow = id; editHotkeySettings = id; newDocumentFromPasteboard = id; }; CLASS = PPApplication; LANGUAGE = ObjC; OUTLETS = { "_canvasDisplayModeMenuItem" = NSMenuItem; "_layerOperationTargetMenuItem" = NSMenuItem; "_leftArrowKeyEquivalentMenuItem" = NSMenuItem; "_pasteMenuItem" = NSMenuItem; "_previousWindowMenuItem" = NSMenuItem; "_rightArrowKeyEquivalentMenuItem" = NSMenuItem; "_toggleActivePanelsMenuItem" = NSMenuItem; "_toggleColorPickerMenuItem" = NSMenuItem; "_zoomInMenuItem" = NSMenuItem; "_zoomOutMenuItem" = NSMenuItem; "_zoomToFitMenuItem" = NSMenuItem; }; SUPERCLASS = NSApplication; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/MainMenu.nib/info.nib0000644000076500000240000000135513033323112024573 0ustar joshstaff IBDocumentLocation 236 85 356 240 0 0 1680 1028 IBEditorPositions 29 103 842 495 44 0 0 1680 1028 IBFramework Version 489.0 IBLastKnownRelativeProjectPath ../PikoPixel.xcodeproj IBOldestOS 5 IBOpenObjects 29 IBSystem Version 9L31a targetFramework IBCocoaFramework PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/MainMenu.nib/keyedobjects.nib0000644000076500000240000010665113065607343026340 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AE !"#'.23459@ABCHOPQV]abcdhopqrv} %,-.29:;@ADHOPQRV]^_`elmnrz{|#*+,0789=DEFGKRSTUY`abchopqu|}~ $+,-.348?@AFGKLPWXYZ^efghlstuy")*+/7;<=AHIJNUVW[bcdhopqu|#*+,127>?@ELMNOT[\]^bijklqrwx}abz "&'09BKT]fg     # % ( ) * 8 A J S T W X Y d m v w           56789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGJMPU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesjki234[NSClassName]PPApplication789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGoHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ #(.37=BHNRW\aejoty~ĀȀ̀рՀـހ "',.246;@DHLQVZ_dimosw{ƁˁρсՁځ߁]NSDestinationXNSSourceWNSLabel WNSTitle_NSKeyEquivModMaskZNSKeyEquiv]NSMnemonicLocYNSOnImage\NSMixedImageVNSMenu   VNSName[NSMenuItems HMI[Hide OthersQh2^NSResourceNameWNSImage_NSMenuCheckmark78;_NSCustomResource_%NSCustomResource2_NSMenuMixedState78;ZNSMenuItem_hideOtherApplications:78;_NSNibControlConnector^NSNibConnector )+SCutQxTcut:"    ! YShow GridQg_toggleGridVisibility:$'%&TUndoQzUundo:%&)-)*-+,*01 _aoRotate 90 CounterclockwiseQR_rotate90Counterclockwise:78/2;< 01YView ModeP_toggleCanvasDisplayMode:FG46J<΀51 XShow All_unhideAllApplications:TU8<XY\:;9_` fPrint &Qp^runPageLayout:fg>Ajk-?@*_Flip VerticallyQF_flipVertically:tuCGxy|EFD UW_Increase Opacitya_increaseActiveLayerOpacity:IMKLJ <>UToolsQ1_toggleToolsPanelVisibility:OQ<P1J_Toggle Active Panels_toggleActivePanelsVisibility:SV\TU9eOpen &Qo]openDocument:X[|YZD_Select Layer Belowa_makeNextLayerActive:€]`^__Fill Selected PixelsQl_fillSelectedPixels:Ѐbdc__Close Holes in Selection_closeHolesInSelection:݀fighJVLayersQ2_toggleLayersPanelVisibility:knlmUPasteQvVpaste:ps\qr9UCloseQw]performClose:ux  vw_Paste into Draw LayerQV_pasteIntoActiveLayer:z}{|ZSelect AllQaZselectAll:#$'΀  ^Hide PikoPixelUhide:014< 1XZoom Out]decreaseZoom:<7?/__canvasDisplayModeMenuItem78BCC;_NSNibOutletConnectorFGJKJWPreviewQ3_togglePreviewPanelVisibility:TUXYTRedoQZUredo:cU<gh\9kPage Setup &QPpqtu*-,*kRotate 180Zrotate180:~\9hSave As &QS_saveDocumentAs: _Image with SelectionQn_newDocumentFromSelection:u  !YGrid Type_toggleGridType:TCopyQcUcopy:Ɓ 6:7XMinimizeQM_performMiniaturize:̀ oBackground Settings &QB_editBackgroundSettings:ۀ|D_Merge with Layer Abovea_mergeWithLayerAbove:-€*oRotate 90 ClockwiseQr_rotate90Clockwise:ŀ|D]Move Layer Up_moveActiveLayerUp:ɀ |ʀZD_Merge with Layer Below_mergeWithLayerBelow:̀ ΀π_Grid Settings...QG_editGridSettings:< "Ҁ%< Ӏ1[Zoom To Fit__zoomToFitMenuItem./ր2|׀D_Select Layer Above_makePreviousLayerActive:;<ڀ?@ۀ܀J_Tool Modifier TipsQ5_&toggleToolModifierTipsPanelVisibility:IJ߀MN\Deselect AllQd\deselectAll:WX[\_Invert SelectionQI_invertSelection:<egj< 1WZoom In__zoomInMenuItemstw<\19VRevert_revertDocumentToSaved: ҀZzoomToFit:_Select Visible PixelsQA_selectVisibleTargetPixels:VDeleteQWdelete:΀ ^Quit PikoPixelQqZterminate:<1 ! ZClear Menu_clearRecentDocuments:À | D_Decrease Opacitya_decreaseActiveLayerOpacity:р  TZoomQm\performZoom:߀<1_Bring All to Front_arrangeInFront:-*_Flip HorizontallyQf_flipHorizontally:|ZD_Move Layer Down_moveActiveLayerDown:!  \ 9TSaveQs]saveDocument:#& $%_Show Background ImageQb_ toggleBackgroundImageVisibility:"#(+&'\)*9oSave a Copy As &QE_saveDocumentTo:<02-__zoomOutMenuItem67/1:0UImage\newDocument:<EO3__toggleActivePanelsMenuItemeJ5]increaseZoom:NO7:RS|89D\Enable LayerQt_toggleActiveLayerEnabledFlag:\]<?`a=>J]Sampler ImageQ4_"toggleSamplerImagePanelVisibility:jkACn<-B1*_Operation Target_toggleLayerOperationTarget:wxEG{|FDYNew LayerYnewLayer:IK|JD\Delete Layer_deleteActiveLayer:MP|NOD_Duplicate LayerQk_duplicateActiveLayer:RUu|STD_Disable All LayersQT_disableAllLayers:WY|XTD_Enable All Layers_enableAllLayers:[^|\]D_Merge All LayersQ _mergeAllLayers:ɀ`c ab_Resize Canvas...QjWresize:׀eh fg_Scale Canvas Proportionally...QJVscale:jl k ]_Crop Canvas to Selection_cropToSelection:<j􀈁An__layerOperationTargetMenuItempr-q *ZNudge LeftZnudgeLeft:tv y-uF*[Nudge Right[nudgeRight:xz-y*XNudge UpXnudgeUp: !|~$-}Z*ZNudge DownZnudgeDown:-.126  9: 13TLeft_nudgeSelectionOutlineLeft:?@C2y6FURight_nudgeSelectionOutlineRight:LMP26RUp_nudgeSelectionOutlineUp:YZ]26ZTDown_nudgeSelectionOutlineDown:fgj__Erase Selected Pixels_eraseSelectedPixels:stw{~ \Horizontally_flipCanvasHorizontally:k{@ZVertically_flipCanvasVertically:€   m90 Clockwise_rotateCanvas90Clockwise:*,o90 Counterclockwise_rotateCanvas90Counterclockwise:€d180_rotateCanvas180:J_Sampler Images...QU_editSamplerImagesSettings:̀yFJ_Next Sampler Image_nextSamplerPanelImage:ـ J_Previous Sampler Image_previousSamplerPanelImage:<1J_Toggle Color Picker_toggleColorPickerVisibility:<􀈁__toggleColorPickerMenuItem_Deselect Invisible PixelsQD_deselectInvisibleTargetPixels:Á u ā%_Background Image Smoothing_toggleBackgroundImageSmoothing:ǁȁɀ_Tile Selection as New LayerQy_tileSelectionAsNewLayer:!"́%́ɀ^Tile Selection^tileSelection:<0k^_pasteMenuItem56ҁ9<΀Ӏ1 _About PikoPixel_orderFrontStandardAboutPanel:CDցGH΀ׁ؀ oHotkey Settings &Q,_editHotkeySettings:RSہVW܁݀_Image with PasteboardQN_newDocumentFromPasteboard:`ade\9gExport &Qe\exportImage:<p_ _rightArrowKeyEquivalentMenuItem<v__leftArrowKeyEquivalentMenuItem{|[Next WindowQ _activateNextDocumentWindow:_Previous WindowQ`_activatePreviousDocumentWindow:<__previousWindowMenuItem  !_Show Grid Guidelines_toggleGridGuidelinesVisibility:u|D^Layer BlendingQK_toggleLayerBlendingMode:78;^NSMutableArrayWNSArray>hF- ;f\`et  W{TLR%6- wCT"!#Y&c!,7\/03I69:#s?B0E|G{.KLMN~Q6jUNf5ZsFp4OځW%&>9'C|ҁp(;8Rt$#ۀ ǁJ5@A)9Á N*Sp?8ez4IIfEց d$RTc(`jK^Ł xL]Ɂ́MJ/<Z[/k߁Yu"0X\DDbց,#.b/AX[7ҁ-VCanvas>Fd7e0 G#/逃ҁ̀#Á `ej{|<< ]NSIsSeparator\NSIsDisabled1 1 {|<< 1 1 {|<< 1 1 {|<< 1 1 {~< YNSSubmenuXNSAction1[Flip Canvas^submenuAction:>Fs78Ƣ;<  1 ]Rotate Canvas>F{|<< 1 1 {|<<|1 1 D{|<<|1 1 D\<91 PgQTFileYNS.string78;_NSMutableStringXNSString>FN9~"sL`cTS"p(#$8<\19SNew>F6R/ۀ<\19[Open Recent>F$__NSRecentDocumentsMenu{|<<\1 1 9{|<<\1 1 9{|<<\1 1 9{|<<1 1 J{|<<΀1 1  {|<<|1 1 D<e)1*TEdit>FiTKZIM3W: f!$,ku-z߁./0b4]5́{|<<1 1 {|<<1 1 {|<<1 1 {|<<1 1 69<112_Nudge Selection>F-?LY{|<<1 1 {|<<1 1 ˁVWindow>F΁{ހ 89{|<<1 1 {|<<1 1 ^_NSWindowsMenu<J<1=UPanel>FF\;؀If<ځ?O%{|<<1 1 J{|<<-1 1 *E < DB1 CXServices ! " EGF >F '__NSServicesMenuYPikoPixel>F ,5C,#F&ҁ&ցJAK 4L{|<<΀1 1  {|<<΀1 1  {|<<΀1 1  \_NSAppleMenu23 VO]NSApplicationXMainMenu>F [B!R(T\^;d< l H1S|< uDU1VULayer>F ywNU6t/.0EMI'7XWRYCZրX[ŁɁ[{|<<|1 1 D{|<<|1 1 D{|<<|1 1 D{|<<|1 1 D < 1]-0< ƀ*_1`YOperation>F ʁjQf%p Ab>c)@ptx|{|<<-1 1 *{|<<-1 1 * < e1f[_NSMainMenu78 ;> h6B|||--|\ |#|- \   \|6-  |- \-\ :  !\- {N||\ -\  -| -6\|| ||||\ |\6  G|\\\--|||{-| J\JDDDJ **D9D D* 9dJ9D*J D;* 9*90R^9*JJDJ(D 9*9* D* 9DD JDDDD9 JD9ATD999J**DDD J*D> hwF; f\`et WTR%-wCT"!&c,7/03I69#sB0E|.KLN~6jN5ZFp4OڀW&>9'CҀp(;8R$#ۀ JA)9N *S?ezIIfEց d$RTc(`jK^ŁL]ɁMJ/Z[/k߁Yu"X\DDbց,#/A[7ҁ-> hw         ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B 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 { | } ~  lmnopqrstuvwxyz{|}~PÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁_Menu Item (Show All)_ Menu Item (Toggle Active Panels)_Menu Item (Tool Modifier Tips)]Menu (Canvas)[Separator-3_Menu Item (Enable All Layers)_Menu Item (File)o Menu Item (Rotate 90 Clockwise)\Separator-18_Menu Item (Flip Vertically)[Menu (File)oMenu Item (Export &)_Menu Item (Zoom In)[Separator-2_Menu Item (Clear Menu)_Menu Item (Increase Opacity)_Menu Item (Quit PikoPixel)_Menu Item (Zoom To Fit)_Menu Item (Close)_Menu Item (Edit)]Menu (Window)_Menu Item (Invert Selection)_Menu Item (Panel)[Separator-7_Menu Item (Show Grid)o Menu Item (Background Settings &)oMenu Item (Print &)_Menu Item (Disable All Layers)_Menu Item (Undo)_!Menu Item (Show Background Image)[Separator-8_ Menu Item (Image with Clipboard)_Menu Item (Hide Others)_Menu Item (Decrease Opacity)\Menu (Panel)_Menu Item (Services)_Menu Item (Switch Grid Type)_Menu Item (Save)o'Menu Item (Rotate 90 Counterclockwise)YSeparator_Menu Item (New)[Application_Menu (PikoPixel)^Menu (Actions)oMenu Item (Open &)_Menu Item (Copy)_Menu Item (Cut)\Separator-21_#Menu Item (Scale Proportionally...)_Menu Item (Delete)_Menu Item (Select All)_Menu Item (Tools)_Menu (Open Recent)_Menu Item (Delete Active Layer)_Menu Item (Layers)[Menu (Edit)_Menu Item (New Layer)oMenu Item (Hotkey Settings &)_Menu Item (Zoom)_Menu Item (Window)\Separator-14[Separator-9_Menu Item (PikoPixel)_Menu Item (Redo)_Menu Item (Layer)\Separator-20oMenu Item (Save a Copy As &)_Menu Item (Resize...)_Menu Item (Crop To Selection)_Menu Item (Flip Horizontally)\Separator-17_!Menu Item (Select Visible Pixels)_Menu Item (Actions)_ Menu Item (Move Active Layer Up)\Separator-19oMenu Item (Page Setup &)_-Menu Item (Fill Selection With Current Color)_"Menu Item (Merge With Layer Below)_"Menu Item (Duplicate Active Layer)\Separator-16_#Menu Item (Switch Canvas View Mode)[Separator-5[Separator-4_Menu Item (Bring All to Front)_Menu Item (Minimize)\Separator-24_Menu Item (Paste)_Menu Item (Select None)[Separator-1_"Menu Item (Move Active Layer Down)_#Menu Item (Paste Into Active Layer)\Separator-15_Menu Item (Hide PikoPixel)_"Menu Item (Make Next Layer Active)_Menu Item (Revert)_Menu Item (Canvas)_Menu Item (Zoom Out)ZMenu (New)_Menu (Services)\Menu (Layer)_$Menu Item (Close Holes In Selection)_&Menu Item (Make Previous Layer Active)\Separator-23\Separator-13_Menu Item (Open Recent)oMenu Item (Save As &)_Menu Item (Image)_)Menu Item (Switch Layer Operation Target)_ Menu Item (Image with Selection)_Menu Item (Flatten Canvas)_Menu Item (Toggle Enabled)_Menu Item (About PikoPixel)\Separator-25_Menu Item (Preview)oMenu Item (Rotate 180)\File's Owner_"Menu Item (Merge With Layer Above)_Menu Item (Grid Settings...)> h> h> hF\ ;tJ\aS [j{NRT%c6_- T`QTb"}L!y#HOmYp7\d^/rY3Ix6{B?E.LN6~jNf5Zspk-nzPfeq`t ~WXfiLR]ZwC|eMug&c!WK,l0vV9:s#I0U|G{KwMoQhUsF4Oyځ€9w'NVҀt3Ht8R$#ՁǁD5,)N *oрS?e84RρIf$RBTc(j(Ł^ 7ȁՁɀ]/<Zށdj/߁Y;s\6D'րb#/@A7ҁ-W%&́߁=>iف.C|p(;e_ۀ ƁJA@9À~pQ"mHzIoEց  d.`KxˁĹMa#J{Lā[Z\k2u"0XځWD4,.сbX[《> "h # $ % & ' ( ) * + , - . / 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 { | } ~        !"#$%&'()*+,-./01234      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁GqSe QH~!CNfs04P9c+HF}AE<8l7w'-2^*[pIK|] ax}J|VPS:16/3.rW;5I>DtR?K\@U#NM~`"JgO_pQ\h%B>FI>Lh>Oh78QRR;^NSIBObjectData"'1:?DRTfbh  # 1 < J f t     " + 4 ? D S \ o x         ! $ ' * - 0 3 6 9 < ? B E H K N Q T W Z ] ` c f i l o r u x { ~  & 1 ? I V ] _ a f h m o q s $1357JSXc| &(*,MOQSUWYfiloy{ -036oq)+-/135>Whjlnp   #%7DFHJkmoqsuw=JLNPmoqsuwy ?ACEGIK`cz!#%')D]jlnp  !#%'HJLNPRTZ\jwy{}')4EGIKMnprtvxz!(?LNPRsuwy{}   02468:<SUbdfh !.024UWY[]_anqtw<>@BDFHMOUbdfh   >@Zgikm  =?Taceg,9;=?`bdfhjl  ,.02468Mhuwy{   " $ & ( 5 7 D Q S U W x z | ~ !!!!!!8!:!!@!B!D!K!d!q!s!u!w!!!!!!!!!!!!!!!""" " ")"+"-"/"1"3"5"<">"F"W"Y"["]"`""""""""""""""""""""""#### ##-#:#<#?#B#c#e#h#k#m#o#q#################$ $ $$$3$5$8$:$<$>$@$U$g$t$v$y$|$$$$$$$$$$$$$$% % %%%%%%*%A%N%P%S%V%w%y%|%%%%%%%%%%%%%%%%%%%%&&(&*&-&0&Q&S&V&Y&[&]&_&&&&&&&&&&&&&&&&&'''' ''('*','.'1'O'\'^'`'c'q'~'''''''''''''''''(((("($(&(((6(8(](j(l(o(r((((((((((((()))) ) ))))$)1)3)6)9)Z)\)_)a)c)e)g)t)))))))))))))))*** **/*1*4*7*9*;*=*R*T*h*u*w*z*}*************+ + ++++++*+,+>+K+M+P+S+t+v+y+|+~++++++++++++++++,,, ,,,,",C,E,H,M,P,R,T,V,q,,,,,,,,,,,,,,,-------+---0-3-T-V-Y-[-]-_-a-m-y-----------------... . . ....'.4.6.9.<.]._.b.g.j.l.n.q.~................./// /#/&/G/I/L/N/P/R/U/X/s/////////////////0000000040K0X0Z0]0`000000000000000001111 1 111141A1C1F1I1j1l1o1q1s1u1x11111111111112222232U2b2d2g2j22222222222222222222233313>3@3C3F3c3e3h3j3l3n3p3333333333333344!4#4&4)4F4H4K4M4O4Q4S4i4444444444444445555 5"5C5P5R5U5X5y5{5~55555555555566666 6(6*6E6R6T6W6Z6{6}66666666666666666677 7 77777'7G7X7Z7\7_7b77777777777777788 8 88888.808M8Z8\8_8b8888888888888888899999*9;9=9?9B9E9f9h9k9p9s9u9w9y999999999999999:::%:6:8:;:=:@:Z:g:i:l:o:::::::::::::; ;;;;;;;);+;F;O;V;e;m;v;y<<<<<<<<<<<<<<<<<<<<<<<<<===== = ========!=$='=*=,=/=2=5=8=:===@=B=E=H=K=M=P=R=U=X=[=^=a=d=f=i=l=n=p=r=u=w=z=}================================================>>>> > >>>>>>>> >">%>'>*>->/>1>4>7>:>=>?>B>E>H>K>M>P>S>V>Y>\>_>b>d>f>i>k>m>t>}>>>>>>>>>>>>>>>>>>>>>>>? ??(?*?,?-?/?0?2?4?6?_?a?c?d?f?g?i?k?m??????????????????@@@@@@@!@#@%@'@*@6@E@N@Q@V@Y@\@e@j@@@@@@@@@@@@@@@@@@@@AAAAAA0A2A4A5A7A8A:AAgAiAkAlAnAoAqAsAuAAAAAAAAAAAAAAAAAAAAB BBB B=B@BBBEBHBJBMBOBRBTBWBZB]B_BaBBBBBBBBBBBBBBBBBBBBBBBBBCC CCCCC!C:CcCeCgChCjCkCmCoCqCCCCCCCCCCCCCCCCCCDD D D DDDDDD?DADCDDDFDGDIDKDMDvDxDzD{D}D~DDDDDDDDDDDDDDDEEEE E EEEEEEEEE!E$E'E)E,E.E1E3E6E9EIGIJIaIdIgIjImIpIsIuIwIyI|I~IIIIIIIIIIIIIIIIIIJJJJJJJJ!J#J0J9J;J>JLJUJ^JaJrJuJxJ{J~JJJJJJJJJJJJJJJJJJJJJKKKKKEKHKKKNKQKTKWKZK]K`KbKeKhKjKlKoKqKtKwKyK{K~KKKKKKKKKKKKKKKKKKKKLLLL L"L#L%L'L)LRLTLVLWLYLZL\L^L`LLLLLLLLLLLLLLLLLLLLLM M MMMMMMMM M#M&M)M,MUMWMYMZM\M]M_MaMcMMMMMMMMMMMMMMMMMMMMMMMOCOEOGOJOMOOOQOSOUOXOZO\O^O`OcOeOgOiOkOnOqOsOuOwOyO{O}OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOPPPP P PPPPPPPPPP!P#P%P(P*P,P.P0P2P4P6P8P:P

P@PBPDPFPHPJPLPNPPPRPTPVPXPZP\P_PbPePgPjPmPpPrPuPwPyP{P}PPPPPPPPPPPPPPPPPPPPPPQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQRRRR R RRRRRRRRR!R#R%R(R+R-R/R2R5R8R;R>RARDRFRIRLRORRRURXR[R]R`RbReRgRiRkRnRqRsRvRyR|R~RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRSSSSSSSSSSSSSSSSSSTTTT TTTTTTT T#T&T)T,T/T2T5T8T;T>TATDTGTJTMTPTSTVTYT\T_TbTeThTkTnTqTtTwTzT}TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTUUUU U UUUUUUU"U%U(U+U.U1UHUkUUUUUVV)VGVSV|VVVVVW W!W4WBWaWuWWWXX$X7X[XgXXXXXYYYjYtYYYYYYYZ Z1ZFZ_ZsZZZZZ[[1[F[S[_[w[[[[[\\<\I\m\\\\]]9]^]k]]]]]]^^^(^M^s^^^^^___ _-_T_}_____``?`\`y`````aadAdDdFdHdJdMdPdSdUdWdZd\d_dbdedhdkdmdodrdtdwdyd{d}dddddddddddddddddddddddddddddddddddddddddddddddddeeee e eeeeeeee!e#e&e(e+e.e0e3e6e9e;e>e@eCeEeGeJeLeOeQeSeUeWeZe]e`ecefehekenepeseveye|eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffff f fffffffff!f$f'f)f+f.f1f4f7f9ffAfCfFfIfKfMfPfRfTf]f`hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiii i iiiiiii!i$i'i*i-i0i3i6i9ijAjDjGjJjMjPjSjVjYj\j_jbjejhjkjnjqjtjwjzj}jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkk k kkkkkkk"k%k(k+k.k1k4k7k:k=k@kCkFkIkLkOkRkUkXk[k^kakdkgkjkmkpkskvkyk|kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklllll l lllllll l#l%l(l+l.l1l4l7l:l=l@lClLlNlQlSlVlXlZl]l`lbldlgljlmlplslulxl{l~llllllllllllllllllllllllllllllllllllllllllllllllmmmmm m mmmmmmmm"m$m'm*m-m0m3m6m8m:m=m@mBmEmHmKmNmQmSmVmYm[m^mamdmgmimlmomrmumxm{m~mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmnnnnn n nnnnnnnn"n%n(n+n.n1n3n5n8n;n>n@nCnEnGnJnMnPnSnUnWnYn\n^n`ncnfninlnonqnsnunxn{n}nnnnnnnnnnnnnnnnnnnnnnnSnPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/NavigatorPopupPanel.nib/0000755000076500000240000000000014400242511025371 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/NavigatorPopupPanel.nib/classes.nib0000644000076500000240000000675512401513343027540 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPDocumentPreviewWindowController; LANGUAGE = ObjC; OUTLETS = { "_previewView" = PPPreviewView; }; SUPERCLASS = NSWindowController; }, { ACTIONS = { movedZoomSlider = id; pressedZoomButton = id; selectedDisplayTypeSegment = id; }; CLASS = PPNavigatorPanelController; LANGUAGE = ObjC; OUTLETS = { "_decreaseZoomButton" = NSButton; "_displayTypeSegmentedControl" = NSSegmentedControl; "_increaseZoomButton" = NSButton; "_navigatorView" = PPNavigatorView; "_zoomSlider" = NSSlider; }; SUPERCLASS = PPPanelController; }, { ACTIONS = { zoomButtonPressed = id; zoomSliderMoved = id; }; CLASS = PPNavigatorPopupPanelController; LANGUAGE = ObjC; OUTLETS = { "_decreaseZoomButton" = NSButton; "_increaseZoomButton" = NSButton; "_navigatorView" = PPNavigatorPopupView; "_zoomSlider" = NSSlider; }; SUPERCLASS = PPPopupPanelController; }, { CLASS = PPNavigatorPopupView; LANGUAGE = ObjC; SUPERCLASS = PPThumbnailImageView; }, { CLASS = PPNavigatorView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPParabolicSlider; LANGUAGE = ObjC; SUPERCLASS = NSSlider; }, { CLASS = PPPopupPanel; LANGUAGE = ObjC; SUPERCLASS = NSPanel; }, { CLASS = PPPopupPanelController; LANGUAGE = ObjC; SUPERCLASS = PPPanelController; }, { ACTIONS = { movedZoomSlider = id; pressedZoomButton = id; selectedDisplayTypeSegment = id; }; CLASS = PPPreviewPanelController; LANGUAGE = ObjC; OUTLETS = { "_decreaseZoomButton" = NSButton; "_displayTypeSegmentedControl" = NSSegmentedControl; "_increaseZoomButton" = NSButton; "_previewView" = PPPreviewView; "_zoomSlider" = NSSlider; }; SUPERCLASS = PPPanelController; }, { CLASS = PPPreviewView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }, { CLASS = PPThumbnailImageView; LANGUAGE = ObjC; SUPERCLASS = NSView; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/NavigatorPopupPanel.nib/info.nib0000644000076500000240000000067513730032276027040 0ustar joshstaff IBDocumentLocation 226 293 356 240 0 0 1680 1028 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/NavigatorPopupPanel.nib/keyedobjects.nib0000644000076500000240000001150213734771733030563 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiverm 156<=AEPXpqrsw{  "#$'+,./01459>?DEJKPQVWZ_denpyvU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValueslKWkNVXOiMj)Y234[NSClassName_PPNavigatorPopupPanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FG4HIJKLMNO =?ACEHIQRSTUW]NSDestinationXNSSourceWNSLabel< ;YZ[\]^_`abcdefghijklmno\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass:7 x 98_{{115, 541}, {280, 305}}YNavigator\PPPopupPaneltuvYNS.stringTView78xyyz;_NSMutableStringXNSString|}~+_NSNextResponderWNSFrameZNSSubviews65>F4)/|}2dd_NSOriginalClassNameVNSCellXNSvFlagsYNSEnabled[NSSuperview _PPParabolicSliderXNSSlider_{{51, 13}, {178, 21}}WNSValue[NSCellFlags_NSNumberOfTickMarks_NSTickMarkPositionZNSContentsYNSSupport]NSControlViewZNSMaxValueZNSMinValue\NSCellFlags2ZNSVertical]NSAltIncValue_NSAllowsTickMarkValuesOnly#?#tuPVNSSizeVNSNameXNSfFlags#@(YHelvetica78â;VNSFont78Ƥ;\NSSliderCell\NSActionCell78ʢ;^NSClassSwapper|}dd( _{{17, 8}, {30, 31}}l_NSAlternateContents]NSNormalImage_NSPeriodicInterval^NSButtonFlags2_NSKeyEquivalent_NSPeriodicDelay]NSButtonFlags ' # !#@$" \LucidaGrande2^NSResourceName&$%WNSImage_minus_button_overlay78;_NSCustomResource_%NSCustomResource78;\NSButtonCell]%NSButtonCell78;XNSButtonYNSControlVNSView[NSResponder|}dd(*+ _{{233, 8}, {30, 31}} l' ,. !)2&$-_plus_button_overlaytu|}2d d[NSExtension3012_{{20, 45}, {240, 240}}_PPNavigatorPopupView78%&&;\NSCustomView78())*;^NSMutableArrayWNSArray_{{1, 1}, {280, 305}}78-;_{{0, 0}, {1680, 1028}}Y{174, 66}Z{600, 616}78233;_NSWindowTemplateVwindow786778;_NSNibOutletConnector^NSNibConnectorQRST=<>[_zoomSliderQRSTC<@__decreaseZoomButtonQRSTI<)B__increaseZoomButtonQRSTOfgLdU/) 78o**;>frLdUddd >f{LU/) >fLPQRSTUYNSButton3\File's OwnerZNSButton31UPanelYNSSlider2>fL>fL>fLNdJIKOLUMHH?=/)AIC E >fLZ[\]^_`abcdefgh' "!(#& >F̀4>fπL>fҀL78բ;^NSIBObjectData"'1:?DRTfCI+GUhz ',;DW`kmnw~&3@NXfs} $-4FO`rz  09Q(ENSUWY[]_hijsuv2468:;=S          ' 8 : C E H U b q s u w     # * 6 S U W Y [ \ ^ u     " $ & ? V _ h u ~   " ) @ O ` b d f h t    ( 1 8 P a c e g i z | ~    ')+-/13=JU[enpsu~   !#%')+-/135>@AJLMVXYbgvPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/PreviewPanel.nib/0000755000076500000240000000000014400242511024034 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/PreviewPanel.nib/classes.nib0000644000076500000240000000221611645452753026207 0ustar joshstaff{ IBClasses = ( { ACTIONS = { "" = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPDocumentPreviewWindowController; LANGUAGE = ObjC; OUTLETS = { "_previewView" = PPPreviewView; }; SUPERCLASS = NSWindowController; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPPreviewPanelController; LANGUAGE = ObjC; OUTLETS = { "_previewView" = PPPreviewView; }; SUPERCLASS = PPPanelController; }, { CLASS = PPPreviewView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/PreviewPanel.nib/info.nib0000644000076500000240000000067511645452753025514 0ustar joshstaff IBDocumentLocation 326 399 356 240 0 0 1680 1028 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/PreviewPanel.nib/keyedobjects.nib0000644000076500000240000000653411645452753027234 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiverH 156<=AEKSklmnrv~  %&'()*+,/25U$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesG2:F59;6D4E<234[NSClassName_PPPreviewPanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FG#HIJ ,.LMNOPR]NSDestinationXNSSourceWNSLabel+ *TUVWXYZ[\]^_`abcdefghij\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass)& x ('_{{1218, 683}, {174, 170}}WPreviewWNSPanelopqYNS.stringTView78sttu;_NSMutableStringXNSStringwxy+{|}_NSNextResponderWNSFrameZNSSubviews%$>F#w2___NSOriginalClassNameZNSEditableVNSCell[NSDragTypesXNSvFlags[NSFrameSizeYNSEnabled[NSSuperview"  ]PPPreviewView[NSImageView>?_Apple PDF pasteboard type_Apple PNG pasteboard type_NSFilenamesPboardType_1NeXT Encapsulated PostScript v1.2 pasteboard type_NeXT TIFF v4.0 pasteboard type_Apple PICT pasteboard typeZ{174, 170}[NSCellFlagsWNSStyleYNSSupportWNSAlignWNSScale\NSCellFlags2ZNSAnimates!VNSSizeVNSNameXNSfFlags #@"\LucidaGrande78;VNSFont78Ĥ;[NSImageCell\%NSImageCell78Ȣ;^NSClassSwapper78ˣ;^NSMutableArrayWNSArray_{{1, 1}, {174, 170}}78У;VNSView[NSResponder_{{0, 0}, {1680, 1028}}]{108.187, 21}\{1000, 1016}78ע;_NSWindowTemplateVwindow78ۣ;_NSNibOutletConnector^NSNibConnectorLMNO+-\_previewViewLXNSMarkerVNSFile10/_NSToolTipHelpKey_"Click to change background pattern78;_NSIBHelpConnector>3P_ 78̢;>3P_ >3P >378\File's OwnerUPanel> 3>3>3IJHP_,. >3 !"#$=>?@ABC >F.#>13>4378677;^NSIBObjectData"'1:?DRTfJQXfx 0JTacegikmoqsuwy{}&-:@IKRTVXiw*>HTVXZ\egikmoqs "+-02_u   -Ia %-:EJLNPUVgnu~6?FMYr    " + 2 4 6 8 : M r {      & ( + - 6 8 G I K M O Q S U ^ ` o q s u w y { }  8 PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/SamplerImagePanel.nib/0000755000076500000240000000000014400242511024761 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/SamplerImagePanel.nib/classes.nib0000644000076500000240000000307212120260175027115 0ustar joshstaff{ IBClasses = ( { ACTIONS = { "" = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPMiniColorWell; LANGUAGE = ObjC; SUPERCLASS = NSView; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPPreviewView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }, { ACTIONS = { nextSamplerImageButtonPressed = id; previousSamplerImageButtonPressed = id; }; CLASS = PPSamplerImagePanelController; LANGUAGE = ObjC; OUTLETS = { "_miniColorWell" = PPMiniColorWell; "_nextSamplerImageButton" = NSButton; "_previousSamplerImageButton" = NSButton; "_samplerImageView" = PPSamplerImageView; }; SUPERCLASS = PPPanelController; }, { CLASS = PPSamplerImageView; LANGUAGE = ObjC; SUPERCLASS = NSView; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/SamplerImagePanel.nib/info.nib0000644000076500000240000000067412074700204026420 0ustar joshstaff IBDocumentLocation 115 118 356 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/SamplerImagePanel.nib/keyedobjects.nib0000644000076500000240000001162112120260175030132 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchivero 156<=AEOWopqrvz  #*+378<=?@ABEFJOPUV[\_dejkpq{}uU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesnNYmQXZRkPlI[234[NSClassName_PPSamplerImagePanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FG8HIJKLMN ACEHJLPQRSTV]NSDestinationXNSSourceWNSLabel@ ?XYZ[\]^_`abcdefghijklmn\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass>; x =<_{{444, 606}, {170, 184}}]Sampler ImageWNSPanelstuYNS.stringTView78wxxy;_NSMutableStringXNSString{|}+_NSNextResponderWNSFrameZNSSubviews:9>F8!&)3{ccVNSCellXNSvFlags[NSFrameSizeYNSEnabled[NSSuperview  Z{170, 184}[NSCellFlags_NSBackgroundColorZNSContentsYNSSupport]NSControlView\NSCellFlags2_NSDrawsBackground[NSTextColor@ PVNSSizeVNSNameXNSfFlags#@*\LucidaGrande78;VNSFont\NSColorSpaceWNSWhiteK0.6491935378;WNSColor[NSColorName]NSCatalogNameVSystem_controlTextColor̀B078Ϥ;_NSTextFieldCell\NSActionCell78Ӧ;[NSTextField\%NSTextFieldYNSControlVNSView[NSResponder{|2cc[NSExtension%"#$_{{0, 14}, {170, 170}}_PPSamplerImageView78;\NSCustomView{|2cc%'%($_{{73, 1}, {24, 12}}_PPMiniColorWell{cc2+$* W{9, 14}   _NSAlternateContents]NSNormalImage_NSPeriodicInterval^NSButtonFlags2_NSKeyEquivalent_NSPeriodicDelay]NSButtonFlags1-K,)D@#@$2^NSResourceName0./WNSImage_arrow_left_button78;_NSCustomResource_%NSCustomResource78;\NSButtonCell]%NSButtonCell78!"";XNSButton{|c&'c245 _{{9, 0}, {9, 14}}.   16,3260.7_arrow_right_button789::;;^NSMutableArrayWNSArray_{{1, 1}, {170, 184}}78>֣;_{{0, 0}, {1440, 878}}]{108.187, 21}\{1000, 1016}78CDD;_NSWindowTemplateVwindow78GHHI;_NSNibOutletConnector^NSNibConnectorPQRSN@&B^_miniColorWellPQRST@!D__samplerImageViewPQRWZG)F_"previousSamplerImageButtonPressed:78]^^I;_NSNibControlConnectorPQRWcG3I_nextSamplerImageButtonPressed:PQRSi@)K__previousSamplerImageButtonPQRSo@3M__nextSamplerImageButton>rsOcT! &3)78|;;;>rOTccccc >rOT&! >rOSTUVW\File's OwnerUView1UPanel\NSTextField2>rO>rO>rOHMJcKTLNI J3C!E &HL)A>rOĀ\]^_`abcdefghij GD=>E!FHC">Fր8>rـO>r܀O78ߢ;^NSIBObjectData"'1:?DRTfGM!/KYl~ ).=FYbmopy$1>LVdq{!*1CL]ow7CWblz &3;=?KTYav &07C`lnprtvxz   6 8 : < ? A B D L        - / 8 : < I X Z \ ^ f z    " # % 9 n p r t v x z |  % . 3 F M V ] t   & > O Q S U W x  !#2468:<>@IKVXZ\^`ikvxz|~468:<>@BDFHJLNPRTVXZ\^`bdfhjlnpy{|PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/SamplerImagePopupPanel.nib/0000755000076500000240000000000014400242511026005 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/SamplerImagePopupPanel.nib/classes.nib0000644000076500000240000000342512110051616030140 0ustar joshstaff{ IBClasses = ( { ACTIONS = { "" = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = PPColorWell; LANGUAGE = ObjC; SUPERCLASS = NSColorWell; }, { CLASS = PPMiniColorWell; LANGUAGE = ObjC; SUPERCLASS = NSView; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPPopupPanel; LANGUAGE = ObjC; SUPERCLASS = NSPanel; }, { CLASS = PPPopupPanelController; LANGUAGE = ObjC; SUPERCLASS = PPPanelController; }, { CLASS = PPResizeControl; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }, { ACTIONS = { nextSamplerImageButtonPressed = id; previousSamplerImageButtonPressed = id; }; CLASS = PPSamplerImagePopupPanelController; LANGUAGE = ObjC; OUTLETS = { "_miniColorWell" = PPMiniColorWell; "_resizeControl" = PPResizeControl; "_samplerImageView" = PPSamplerImageView; }; SUPERCLASS = PPPopupPanelController; }, { CLASS = PPSamplerImageView; LANGUAGE = ObjC; SUPERCLASS = NSView; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/SamplerImagePopupPanel.nib/info.nib0000644000076500000240000000067412110051616027441 0ustar joshstaff IBDocumentLocation 406 279 356 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/SamplerImagePopupPanel.nib/keyedobjects.nib0000644000076500000240000001170612110051616031157 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchivern 156<=AENVnopquy #*+378<=?@ABEFJOPUV[\abejkuwtU$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesmPYlSXZTjRkG[234[NSClassName_"PPSamplerImagePopupPanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FG<HIJKLM EGIKNOPQRSU]NSDestinationXNSSourceWNSLabelD CWXYZ[\]^_`abcdefghijklm\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClassB? x A@_{{438, 552}, {226, 226}}UPanel\PPPopupPanelrstYNS.stringTView78vwwx;_NSMutableStringXNSStringz{|+~_NSNextResponderWNSFrameZNSSubviews>=>F<$),7z{2bb_NSOriginalClassNameZNSEditableVNSCell[NSDragTypesXNSvFlagsYNSEnabled[NSSuperview# ! _PPResizeControl[NSImageView>?_Apple PDF pasteboard type_Apple PNG pasteboard type_NSFilenamesPboardType_1NeXT Encapsulated PostScript v1.2 pasteboard type_NeXT TIFF v4.0 pasteboard type_Apple PICT pasteboard type_{{208, 6}, {12, 12}}[NSCellFlagsWNSStyleZNSContentsWNSAlignWNSScale\NSCellFlags2ZNSAnimates"2^NSResourceName! WNSImage_resize_control.png78ţ;_NSCustomResource_%NSCustomResource78ɤ;[NSImageCell\%NSImageCell78͢;^NSClassSwapperz{2bb[NSExtension(% &'_{{7, 208}, {11, 11}}_PPMiniColorWellVNSView78ܤ;\NSCustomView[NSResponderz{2bb(*+'_{{20, 20}, {186, 186}}_PPSamplerImageViewz{bb6-.$ _{{2, 4}, {9, 14}}_NSAlternateContents]NSNormalImage_NSPeriodicInterval^NSButtonFlags2_NSKeyEquivalentYNSSupport]NSControlView_NSPeriodicDelay]NSButtonFlags5/3K//0,D@P    VNSSizeVNSNameXNSfFlags2#@$1\LucidaGrande78;VNSFont2!4_arrow_outline_left_button78;\NSButtonCell]%NSButtonCell\NSActionCell78 !!";XNSButtonYNSControlz{b&'b689 _{{11, 4}, {9, 14}}.5/://0726!;_arrow_outline_right_button789::;;^NSMutableArrayWNSArray_{{1, 1}, {226, 226}}78>٣;_{{0, 0}, {1440, 878}}]{96.2896, 21}_{3.40282e+38, 3.40282e+38}78CDD;_NSWindowTemplateVwindow78GHHI;_NSNibOutletConnector^NSNibConnectorOPQRNDF^_resizeControlOPQRTD$H^_miniColorWellOPQRZD)J__samplerImageViewOPQ]`M,L_"previousSamplerImageButtonPressed:78cddI;_NSNibControlConnectorOPQ]iM7O_nextSamplerImageButtonPressed:>lmQSb,)$ 778v;;;>lyQbbbbSb >lQS)$ >lQeUVW UView1\File's Owner>lQ>lQ>lQHMJLIKSb 7NGK$)EI ,>lQ\]^_`abcdefghi4DF@E;=?BC>Fˀ<>l΀Q>lрQ78Ԣ;^NSIBObjectData"'1:?DRTfEK-IWj|!,1@I\eprs|#0=KUcpz &-?HYks~&(*,./13679;MYbdqsuwy{}"?Vw1ENWcpy~    < > @ B D F H J c x   % 4 F P ^ p ~    / 8 C P ^ k t         ! # % B K R a i  " 1 B D F H J Y j l n p r %')+-NWYhjlnprtv "?ACEGIKMOQSUWY[dfPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ScreencastPopupPanel.nib/0000755000076500000240000000000014400242511025531 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ScreencastPopupPanel.nib/classes.nib0000644000076500000240000000234012271102053027657 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSObject; LANGUAGE = ObjC; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPNavigatorPopupView; LANGUAGE = ObjC; SUPERCLASS = PPThumbnailImageView; }, { CLASS = PPNavigatorView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPParabolicSlider; LANGUAGE = ObjC; SUPERCLASS = NSSlider; }, { CLASS = PPPopupPanel; LANGUAGE = ObjC; SUPERCLASS = NSPanel; }, { CLASS = PPPopupPanelController; LANGUAGE = ObjC; SUPERCLASS = PPPanelController; }, { CLASS = PPPreviewView; LANGUAGE = ObjC; SUPERCLASS = NSImageView; }, { CLASS = PPScreencastPopupPanelController; LANGUAGE = ObjC; OUTLETS = { "_stateTextField" = NSTextField; }; SUPERCLASS = PPPopupPanelController; }, { CLASS = PPThumbnailImageView; LANGUAGE = ObjC; SUPERCLASS = NSView; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ScreencastPopupPanel.nib/info.nib0000644000076500000240000000067512271102053027166 0ustar joshstaff IBDocumentLocation 185 238 356 240 0 0 1440 878 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 10K549 PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ScreencastPopupPanel.nib/keyedobjects.nib0000644000076500000240000000627512271102053030710 0ustar joshstaffbplist0012T$topX$objectsX$versionY$archiver]IB.objectdataD /34:;?CHPhijkos{   !"#$%(+.U$null  !"#$%&'()*+,-.[NSNamesKeys[NSFramework_NSAccessibilityOidsValues_NSAccessibilityConnectors_NSObjectsValues]NSNamesValues]NSConnections]NSFontManagerVNSRootYNSNextOid_NSVisibleWindows]NSObjectsKeys]NSClassesKeysZNSOidsKeys\NSOidsValues_NSAccessibilityOidsKeysV$class_NSClassesValues1B@02).689AC7012[NSClassName_ PPScreencastPopupPanelController5678X$classesZ$classname89^NSCustomObjectXNSObject_IBCocoaFramework<=>ZNS.objects56@AAB9\NSMutableSetUNSSet<DGEF ,#IJKLMN%]NSDestinationWNSLabelXNSSource *+QRSTUVWXYZ[\]^_`abcdefg_NSWindowStyleMask_NSWindowBackingYNSMinSize]NSWindowTitle]NSWindowClass\NSWindowRect\NSScreenRectYNSMaxSize\NSWindowViewYNSWTFlags[NSViewClass' &(x)_{{294, 654}, {332, 76}}ZScreencast\PPPopupPanellmnYNS.stringTView56pqqr9_NSMutableStringXNSStringtuvw$yzZNSSubviews_NSNextResponderWNSFrame$%<|G}#uvdd[NSSuperviewYNSEnabledXNSvFlagsVNSCell "_{{0, -5}, {332, 86}}}_NSBackgroundColor[NSTextColorYNSSupportZNSContents]NSControlView[NSCellFlags\NSCellFlags2!@TWWWWVNSSizeVNSNameXNSfFlags#@R_LucidaGrande-Bold569VNSFontWNSColor[NSColorName\NSColorSpace]NSCatalogNameVSystem\controlColorWNSWhiteM0.6666666865569WNSColor _controlTextColorB056Ȥ9_NSTextFieldCell\NSActionCellVNSCell56ͦ9[NSTextField\%NSTextFieldYNSControlVNSView[NSResponder56ԣ9^NSMutableArrayWNSArray_{{1, 1}, {332, 76}}56У9_{{0, 0}, {1440, 878}}Y{174, 66}Z{600, 616}56ޢ9_NSWindowTemplateVwindow569_NSNibOutletConnector^NSNibConnectorIJK}N%-+__stateTextField<L}d /56բ9<%dL /<L}% /<345/UPanel\NSTextField2\File's Owner</< /<%FEL}d, /<:;<=>?/( &<&G#<)/<,/56/009^NSIBObjectData_NSKeyedArchiver'0:?MO+7C_{)0BDFHJLNPRTVXZ\^`bdfo{}#)279;=N\dmoqsu #-9;=?ACEGIKTVXr}   :FPY`bdfgjln  .5<ENPRThqv}13579LY\^gp (/GQ\ej}      ! # , 3 5 7 9 ; D K M O Q S Y f s | }     %3 7PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolModifierTipsPanel.nib/0000755000076500000240000000000014400242511025647 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolModifierTipsPanel.nib/classes.nib0000644000076500000240000000142212137660500030004 0ustar joshstaff{ IBClasses = ( { CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPToolModifierTipsPanelController; LANGUAGE = ObjC; OUTLETS = { "_actionModifierDescriptionsTextField" = NSTextField; "_actionModifierKeysTextField" = NSTextField; "_typeModifierKeysTextField" = NSTextField; "_typeModifierToolNamesTextField" = NSTextField; }; SUPERCLASS = PPPanelController; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolModifierTipsPanel.nib/info.nib0000644000076500000240000000100512426750065027306 0ustar joshstaff IBDocumentLocation 260 177 356 240 0 0 1680 1028 IBFramework Version 489.0 IBLockedTabItems 24 IBOpenObjects 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolModifierTipsPanel.nib/keyedobjects.nib0000644000076500000240000001100212426750065031024 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiverf 156<=AEMUmnoptx $%'()*-.278=>CDIJTV`jtuvwxyz{~U$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValueseERdHQSIbGcՀT234[NSClassName_!PPToolModifierTipsPanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FG4HIJKL =?ACNOPQRT]NSDestinationXNSSourceWNSLabel< ;VWXYZ[\]^_`abcdefghijkl\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClass:7 x 98_{{131, 496}, {449, 254}}_Tool Modifier TipsWNSPanelqrsYNS.stringTView78uvvw;_NSMutableStringXNSStringyz{+}~_NSNextResponderWNSFrameZNSSubviews65>F4!(,0yaaVNSCellXNSvFlags[NSFrameSizeYNSEnabled[NSSuperview  Z{449, 254}[NSCellFlags_NSBackgroundColorZNSContentsYNSSupport]NSControlView\NSCellFlags2_NSDrawsBackground[NSTextColor@ PVNSSizeVNSNameXNSfFlags#@*\LucidaGrande78;VNSFont\NSColorSpaceWNSWhiteK0.8104838778;WNSColor[NSColorName]NSCatalogNameVSystem_controlTextColorʀB078ͤ;_NSTextFieldCell\NSActionCell78Ѧ;[NSTextField\%NSTextFieldYNSControlVNSView[NSResponderyzaa "# _{{17, 134}, {232, 100}}%$!_Type Modifier Tool Namesŀ'&\controlColorK0.66666669yzaa )* _{{251, 134}, {181, 100}}%+(_Type Modifier Keysyzaa -. _{{17, 26}, {232, 100}} %/,_Action Modifier Descriptionsyzaa 12 _{{251, 26}, {181, 100}}%30_Action Modifier Keys78!""#;^NSMutableArrayWNSArray_{{1, 1}, {449, 254}}78&ԣ;_{{0, 0}, {1680, 1028}}Z{213, 129}_{3.40282e+38, 3.40282e+38}78+,,;_NSWindowTemplateVwindow78/001;_NSNibOutletConnector^NSNibConnectorNOPQ6__typeModifierToolNamesTextFieldNOPQ<<(@__typeModifierKeysTextFieldNOPQB<,B_$_actionModifierDescriptionsTextFieldNOPQH<0D__actionModifierKeysTextField>KLFRa 0!,(78U##;>KXFRaaaaa >KbFR 0!,(>KlFmnopqrsJKLMNOPUPanel^NSTextField211]NSTextField23\NSTextField2\File's Owner]NSTextField22]NSTextField21>K}F>KF>KFRKJLaIH 0A!?C(= ,>KFUVWXYZ[\]^_`ah>F4>KF>KF78;^NSIBObjectData"'1:?DRTf5;9GZl /8KT_abkr(6@N[ew  "4=N`hsuwy{(4HS]kx $,.0<EJRgs !(4QSUWY\]_y  # % ' ) + , . I j l n p r t v  5 7 9 ; = > @ Z { }    - 6 ; N U ^ e |     < M O Q S U t }          " ( 7 E R _ m {    !#%')+-689BDENPQZ_nPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolModifierTipsStrings.plist0000644000076500000240000004121113061567776026577 0ustar joshstaff TypeModifierTitlesDict DescriptionTitlePrefix Switch from KeyNamesTitle Modifier Key(s) DefaultDescriptionSubtitle (Before mouse click) DefaultKeyNamesSubtitle Hold until mouse down ActionModifierTitlesDict DescriptionTitlePrefix Modify Action of KeyNamesTitle Modifier Key(s) DefaultDescriptionSubtitle (While mouse down) DefaultKeyNamesSubtitle Hold until mouse up ToolModifierDicts ToolName Pencil TypeModifierDicts ModifierStringDicts Description Eraser KeyNames Control Description Fill Tool KeyNames Option + Shift Description Color Sampler Tool KeyNames Option Description Move Tool KeyNames Control + Shift Description Magnifier KeyNames Command + Option ActionModifierDicts CustomKeyNamesSubtitle Hold until segment done ModifierStringDicts Description Draw Line Segment KeyNames Shift CustomDescriptionSubtitle ModifierStringDicts Description Fill Drawn Shape KeyNames Command ToolName Eraser TypeModifierDicts ModifierStringDicts Description Move Tool KeyNames Control + Shift Description Magnifier KeyNames Command + Option ActionModifierDicts ModifierStringDicts Description Erase Drawn Shape KeyNames Command ToolName Fill Tool TypeModifierDicts ModifierStringDicts Description Color Sampler Tool KeyNames Option Description Move Tool KeyNames Control + Shift Description Magnifier KeyNames Command + Option ActionModifierDicts ModifierStringDicts Description Match Diagonally KeyNames Control Description Match Anywhere KeyNames Command ToolName Line Tool TypeModifierDicts ModifierStringDicts Description Eraser KeyNames Control Description Fill Tool KeyNames Option + Shift Description Color Sampler Tool KeyNames Option Description Move Tool KeyNames Control + Shift Description Magnifier KeyNames Command + Option ActionModifierDicts CustomDescriptionSubtitle (Before mouse click) CustomKeyNamesSubtitle Hold until mouse down ModifierStringDicts Description Color Ramp Line (Gradient) KeyNames Control + Option CustomKeyNamesSubtitle Press anytime ModifierStringDicts Description New Segment KeyNames Control Description Delete Segment KeyNames Option CustomDescriptionSubtitle CustomKeyNamesSubtitle Hold until segment done ModifierStringDicts Description Align to Nearest 1/16 Angle KeyNames Shift CustomDescriptionSubtitle ModifierStringDicts Description Fill Drawn Shape KeyNames Command ToolName Rectangle Tool TypeModifierDicts ModifierStringDicts Description Fill Tool KeyNames Option + Shift Description Color Sampler Tool KeyNames Option Description Magnifier KeyNames Command + Option ActionModifierDicts ModifierStringDicts Description Force Square Shape KeyNames Shift Description Center Shape at Click Point KeyNames Control Description Fill Shape KeyNames Command ToolName Oval Tool TypeModifierDicts ModifierStringDicts Description Fill Tool KeyNames Option + Shift Description Color Sampler Tool KeyNames Option Description Magnifier KeyNames Command + Option ActionModifierDicts ModifierStringDicts Description Force Circle Shape KeyNames Shift Description Center Shape at Click Point KeyNames Control Description Fill Shape KeyNames Command ToolName Freehand Select Tool TypeModifierDicts ModifierStringDicts Description Move Tool KeyNames Control + Shift Description Magnifier KeyNames Command + Option ActionModifierDicts ModifierStringDicts Description Add to Existing Selection KeyNames Shift Description Subtract from Existing Selection KeyNames Option Description Intersect Existing Selection KeyNames Option + Shift ToolName Rectangle Select Tool TypeModifierDicts ModifierStringDicts Description Move Tool KeyNames Control + Shift Description Magnifier KeyNames Command + Option ActionModifierDicts ModifierStringDicts Description Add to Existing Selection KeyNames Shift Description Subtract from Existing Selection KeyNames Option Description Intersect Existing Selection KeyNames Option + Shift Description Snap Rectangle to Grid Guidelines KeyNames Control CustomDescriptionSubtitle CustomKeyNamesSubtitle Hold anytime ModifierStringDicts Description Move Rectangle Outline KeyNames Command ToolName Magic Wand Tool TypeModifierDicts ModifierStringDicts Description Magnifier KeyNames Command + Option ActionModifierDicts ModifierStringDicts Description Match Diagonally KeyNames Control Description Match Anywhere KeyNames Command Description Add to Existing Selection KeyNames Shift Description Subtract from Existing Selection KeyNames Option Description Intersect Existing Selection KeyNames Option + Shift ToolName Color Sampler Tool TypeModifierDicts ModifierStringDicts Description Magnifier KeyNames Command + Option ActionModifierDicts CustomDescriptionSubtitle No modifiers CustomKeyNamesSubtitle ToolName Move Tool TypeModifierDicts ModifierStringDicts Description Magnifier KeyNames Command + Option ActionModifierDicts ModifierStringDicts Description Leave Copy in Place KeyNames Command Description Move Selection Outline Only KeyNames Option ToolName Magnifier TypeModifierDicts CustomDescriptionSubtitle No switches CustomKeyNamesSubtitle ActionModifierDicts ModifierStringDicts Description Zoom Out KeyNames Shift Description Center Outline at Click Point KeyNames Control ToolName Line Tool (Clr. Ramp) TypeModifierDicts CustomDescriptionSubtitle No switches CustomKeyNamesSubtitle ActionModifierDicts CustomDescriptionSubtitle No modifiers CustomKeyNamesSubtitle PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolsPanel.nib/0000755000076500000240000000000014400242511023513 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolsPanel.nib/classes.nib0000644000076500000240000000253113063373654025664 0ustar joshstaff{ IBClasses = ( { ACTIONS = { "" = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }, { CLASS = PPColorWell; LANGUAGE = ObjC; SUPERCLASS = NSColorWell; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPThumbnailImageView; LANGUAGE = ObjC; SUPERCLASS = NSView; }, { CLASS = PPToolButtonMatrix; LANGUAGE = ObjC; SUPERCLASS = NSMatrix; }, { ACTIONS = { fillColorWellUpdated = id; toolButtonMatrixClicked = id; }; CLASS = PPToolsPanelController; LANGUAGE = ObjC; OUTLETS = { "_fillColorWell" = NSColorWell; "_toolButtonMatrix" = PPToolButtonMatrix; }; SUPERCLASS = PPPanelController; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolsPanel.nib/info.nib0000644000076500000240000000067513063373654025171 0ustar joshstaff IBDocumentLocation 183 138 356 240 0 0 1680 1028 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolsPanel.nib/keyedobjects.nib0000644000076500000240000001757213063373654026715 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AEZbz{|} !"+,01:;?@JKOPYZ^_ijnoyz~  #$)*/056;<ABGHMNSTYZ_`efkl      xh!U$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValues234[NSClassName_PPToolsPanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGMHIJKLMNOPQRSTUVWXY hjmqsuwy{}[\]^_a]NSDestinationXNSSourceWNSLabelg fcdefghijklmnopqrstuvwxy\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClasseb x dc_{{75, 648}, {122, 195}}PWNSPanel~YNS.stringTView78;_NSMutableStringXNSString+_NSNextResponderWNSFrameZNSSubviewsa`>FMY2nn_NSOriginalClassName[NSProtoCell]NSSelectedRowYNSNumRows_NSBackgroundColor[NSCellClass_NSCellBackgroundColorZNSCellSizeXNSvFlagsYNSEnabledYNSNumCols[NSSuperview_NSIntercellSpacing]NSMatrixFlags]NSSelectedColWNSCellsXQRPTN O_PPToolButtonMatrixXNSMatrix_{{0, 32}, {122, 163}}>FMǀ!%)-159=AEIqq[NSCellFlags_NSAlternateContents]NSNormalImage_NSPeriodicInterval^NSButtonFlags2_NSAlternateImage_NSKeyEquivalentZNSContentsYNSSupport]NSControlView_NSPeriodicDelay\NSCellFlags2]NSButtonFlags  t@VPencilVNSSizeVNSNameXNSfFlags#@*\LucidaGrande78;VNSFont2^NSResourceNameWNSImage]pencil_button78;_NSCustomResource_%NSCustomResource78;\NSButtonCell]%NSButtonCell\NSActionCellVNSCellqq  UNSTag ## "VEraser2$]eraser_buttonqqv '' &TFill2 (_paintcan_buttonq%%q( ++ *TLine2/,[line_buttonq44q7 // .TRect2>0[rect_buttonqCCqFI 33 2TOval2N4[oval_buttonqSSqVۀ 77 6^FreehandSelect2]8_freehand_select_buttonqbbqeh ;; :ZRectSelect2m<_selection_rect_buttonqrrqux ?? >YMagicWand2}@[wand_buttonqq CC B \ColorSampler2D_eyedropper_buttonqq GG F TMove2H[move_buttonqq KK J YMagnifier2L_magnifier_button78;^NSMutableArrayWNSArrayX{40, 40}V{1, 1}qq ȼ@\NSColorSpaceWNSWhiteSH0.4687578¢;WNSColor[NSColorName]NSCatalogNameSWVUVSystem\controlColor΀SK0.6666666978Ѣ;^NSClassSwapper2nn[NSDragTypes\NSIsBorderedX^[_\ Z[PPColorWell[NSColorWell>?]~_NSColor pasteboard type_{{-1, 0}, {124, 32}} UNSRGBSO0.058130499 0.055541899 1_{{1, 1}, {122, 195}}78;VNSView[NSResponder_{{0, 0}, {1680, 1028}}X{96, 21}_{3.40282e+38, 3.40282e+38}78;_NSWindowTemplateVwindow78;_NSNibOutletConnector^NSNibConnector[\]^gYi^_fillColorWell[\]lYk_fillColorWellUpdated:78   ;_NSNibControlConnector[ XNSMarkerVNSFilepon_NSToolTipHelpKeyZPencil (P)78;_NSIBHelpConnector[ p!rnZEraser (E)[ !p%tn]Fill Tool (F)[ 'p)vn_Line Drawing Tool (L)[ -p-xn_Rectangle Drawing Tool (R)[ 3p1zn_Oval Drawing Tool (O)[ 9p5|n_Freehand Selection Tool (A)[ ?p9~n_Rectangular Selection Tool (S)[ Ep=n_Magic Wand Selection Tool (W)[ KpAn_Color Sampler Tool (D)[ QpEn]Move Tool (V)[ WpIn]Magnifier (M)[ ]pYn_Color Picker (\)[\]^dg__toolButtonMatrix[\]jl_toolButtonMatrixClicked>mnn_ƀI1A%=-9)5!Y E78;>m_nn >m_ Y>mUPanel\File's OwnerQ2>mY>mZ>m#JIMKHXYNSTPVnQLO_URWIjh1As%-9m 5uEy=){!qwY }>mՀ#s@>mqjlonrpkhi$>FM>m>m 78"##;^NSIBObjectData"'1:?DRTf:AHVh :DQSUWY[]_acegikmoqsu~  (.79`bdfhjlnprtvxz|~-:DVjt*2=?ACENPUWY)2<FRgu!#%')+-/1jv   % 3 8 : < > @ B D F H J L N P Y ` q x    ) 2 = J X e l * , . 0 2 4 6 8 : ? L N P R d      " $ & + 8 : < > J       * , . 0 I !+8:<>J %2468D)+-/1:GT\^gpu}-9FHJLNPRSTVXdpy{~(AJgpu'.FW`gikmo  +<>@BDartvxz<MOQSUn&(*,.HQSvxz|~  "(57@BGIKTV[]_hjMOQSUWY[]_acegikmoqsuwy{}$PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolsPopupPanel.nib/0000755000076500000240000000000014400242511024537 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolsPopupPanel.nib/classes.nib0000644000076500000240000000221413063374130026674 0ustar joshstaff{ IBClasses = ( { ACTIONS = { "" = id; }; CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { CLASS = PPPanelController; LANGUAGE = ObjC; SUPERCLASS = NSWindowController; }, { CLASS = PPPopupPanel; LANGUAGE = ObjC; SUPERCLASS = NSPanel; }, { CLASS = PPPopupPanelController; LANGUAGE = ObjC; SUPERCLASS = PPPanelController; }, { CLASS = PPToolButtonMatrix; LANGUAGE = ObjC; SUPERCLASS = NSMatrix; }, { ACTIONS = { toolButtonMatrixClicked = id; }; CLASS = PPToolsPopupPanelController; LANGUAGE = ObjC; OUTLETS = { "_toolButtonMatrix" = PPToolButtonMatrix; }; SUPERCLASS = PPPopupPanelController; } ); IBVersion = 1; }PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolsPopupPanel.nib/info.nib0000644000076500000240000000067513063374130026203 0ustar joshstaff IBDocumentLocation 377 206 356 240 0 0 1680 1028 IBFramework Version 489.0 IBOpenObjects 7 IBSystem Version 9L31a PikoPixel.Sources.1.0-b10b/PikoPixel/English.lproj/ToolsPopupPanel.nib/keyedobjects.nib0000644000076500000240000001633013063374130027716 0ustar joshstaffbplist00 X$versionT$topY$archiverX$objects]IB.objectdata_NSKeyedArchiver 156<=AEW_wxyz~ &*+489CGHQUV`deost~  #$)*/03EGY_efhkos}nt_ U$null  !"#$%&'()*+,-./0VNSRootV$class]NSObjectsKeys_NSClassesValues_NSAccessibilityOidsValues]NSConnections[NSNamesKeys[NSFramework]NSClassesKeysZNSOidsKeys]NSNamesValues_NSAccessibilityConnectors]NSFontManager_NSVisibleWindows_NSObjectsValues_NSAccessibilityOidsKeysYNSNextOid\NSOidsValuesu~x}yw'234[NSClassName_PPToolsPopupPanelController789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FGBHIJKLMNOPQRSTUV VZ\^`bdfhjlnprXYZ[\^]NSDestinationXNSSourceWNSLabelU T`abcdefghijklmnopqrstuv\NSWindowView\NSScreenRect]NSWindowTitleYNSWTFlags]NSWindowClass\NSWindowRectYNSMaxSize_NSWindowBacking_NSWindowStyleMaskYNSMinSize[NSViewClassSP x RQ_{{441, 562}, {168, 211}}UPanel\PPPopupPanel{|}YNS.stringTView78;_NSMutableStringXNSString+_NSNextResponderWNSFrameZNSSubviewsON>FB2kk_NSOriginalClassName[NSProtoCell]NSSelectedRowYNSNumRows_NSBackgroundColor[NSCellClass_NSCellBackgroundColorZNSCellSizeXNSvFlagsYNSEnabledYNSNumCols[NSSuperview_NSIntercellSpacing]NSMatrixFlags]NSSelectedColWNSCellsMFGEIC D_PPToolButtonMatrixXNSMatrix_{{20, 20}, {128, 171}}>FBÀ!$'*-0369[move_button @@ 2A_magnifier_button78;^NSMutableArrayWNSArrayX{42, 42}V{1, 1} \NSColorSpaceWNSWhiteHK0.3323863778;WNSColor[NSColorName]NSCatalogNameHLKJVSystem\controlColor€HK0.6666666978Ţ;^NSClassSwapper_{{1, 1}, {168, 211}}78ɣ;VNSView[NSResponder_{{0, 0}, {1680, 1028}}Y{115, 27}_{3.40282e+38, 3.40282e+38}78Т;_NSWindowTemplateVwindow78ԣ;_NSNibOutletConnector^NSNibConnectorXXNSMarkerVNSFileYXW_NSToolTipHelpKeyZPencil (P)78;_NSIBHelpConnectorX܀Y![WZEraser (E)X܀Y$]W]Fill Tool (F)X܀Y'_W_Line Drawing Tool (L)X܀Y*aW_Rectangle Drawing Tool (R)X܀Y-cW_Oval Drawing Tool (O)X܀Y0eW_Freehand Selection Tool (A)X ܀Y3gW_Rectangular Selection Tool (S)X܀Y6iW_Magic Wand Selection Tool (W)X܀Y9kW_Color Sampler Tool (D)X܀Y45v\k '!0?*3$<69-78F;>4Iv\k >4[v\ >4avbndz {\File's Ownerg|78ijj;VNSNull>4mv>4qv>4uvJIUOLkTMS\HNVKPQRZVpd^?*3$4v% $# & !">FрB>4Ԁv>4׀v78ڢ;^NSIBObjectData"'1:?DRTf 0LZfr !#%')+-/13579;=FRTVt}')+-/13579;=?ACEVdmuwy{}+5ACEGIRTVXZ\^`{   !t/=KSUWY[]fhjlnpstvxz|3?Ucx          ! * + < C J S U ^ ` c p y ~   # 0 7 v |       ( g i k m o q s u w  C E G I K M O Q S U b d f h t . 0 2 4 6 8 : < > @ M O Q S k  "$&(*,9;=?S  !#%':CJYajq-/135<IVXdmr #,3JYjsz|~  "$&>OQSUWt')+-/O`bdfh :CJbkm %'.024AFHQV]fhkmvx{}SUWY[]_acegikmoqsuwy{}PikoPixel.Sources.1.0-b10b/PikoPixel/fix_GNUstep_PP_desktop_file.sh0000755000076500000240000000205613262551635024051 0ustar joshstaff# Script to modify PikoPixel.desktop for better integration with Freedesktop environments # 1) Add a "%F" to the end of the "Exec=" line, otherwise the desktop manager won't allow # image documents in its file browser to choose PikoPixel as the app to open them. # Can't use sed's in-place option, because the sed version on FreeBSD uses a different syntax # for -i, so instead using a temporary file. sed -e 's/^Exec=.*PikoPixel$/& %F/' PikoPixel.app/Resources/PikoPixel.desktop \ > PikoPixel.app/Resources/PikoPixel_fixed.desktop \ && mv PikoPixel.app/Resources/PikoPixel_fixed.desktop PikoPixel.app/Resources/PikoPixel.desktop # 2) Add "StartupWMClass=" line grep -q "StartupWMClass=" PikoPixel.app/Resources/PikoPixel.desktop \ || echo "StartupWMClass=PikoPixel" >> PikoPixel.app/Resources/PikoPixel.desktop # 3) Add "Keywords=" line grep -q "Keywords=" PikoPixel.app/Resources/PikoPixel.desktop \ || echo "Keywords=Graphics;Pixelart;Icon;Bitmap;Raster;Image;Png;Gif;Jpg;Tiff;Bmp;Art;Draw;Paint;Fill;Pencil;Trace;" \ >> PikoPixel.app/Resources/PikoPixel.desktop PikoPixel.Sources.1.0-b10b/PikoPixel/GNUmakefile0000644000076500000240000003066314374046166020252 0ustar joshstaffinclude $(GNUSTEP_MAKEFILES)/common.make PACKAGE_NAME = PikoPixel APP_NAME = PikoPixel VERSION = 1.0BETA PikoPixel_APPLICATION_ICON = GNUstepAppIcon.png PikoPixel_OBJC_PRECOMPILED_HEADERS = PikoPixel_Prefix.pch PikoPixel_OBJC_FILES = \ main.m \ \ PPApplication.m \ \ PPDocument.m \ PPDocument_ActiveTool.m \ PPDocument_CanvasSettings.m \ PPDocument_Drawing.m \ PPDocument_FileFormats.m \ PPDocument_LayerOperationTarget.m \ PPDocument_Layers.m \ PPDocument_MirroringRotating.m \ PPDocument_Moving.m \ PPDocument_NativeFileFormat.m \ PPDocument_NativeFileIcon.m \ PPDocument_NotificationOverrides.m \ PPDocument_Notifications.m \ PPDocument_Pasteboard.m \ PPDocument_PixelMatching.m \ PPDocument_Resizing.m \ PPDocument_SamplerImages.m \ PPDocument_Saving.m \ PPDocument_Selection.m \ PPDocument_Tiling.m \ PPDocumentLayer.m \ PPDocumentSamplerImage.m \ \ PPToolbox.m \ PPTool.m \ PPToolUtilities.m \ PPPencilTool.m \ PPEraserTool.m \ PPFillTool.m \ PPLineTool.m \ PPRectTool.m \ PPOvalTool.m \ PPFreehandSelectTool.m \ PPRectSelectTool.m \ PPMagicWandTool.m \ PPColorSamplerTool.m \ PPMoveTool.m \ PPMagnifierTool.m \ PPColorRampTool.m \ \ PPDocumentWindowController.m \ PPDocumentWindowController_Actions.m \ PPDocumentWindowController_MenuValidation.m \ PPDocumentWindowController_Notifications.m \ PPDocumentWindowController_Sheets.m \ PPDocumentWindow.m \ \ PPCanvasView.m \ PPCanvasView_Autoscrolling.m \ PPCanvasView_ColorRampToolOverlay.m \ PPCanvasView_EraserToolOverlay.m \ PPCanvasView_FillToolOverlay.m \ PPCanvasView_MagnifierToolOverlay.m \ PPCanvasView_MatchToolToleranceIndicator.m \ PPCanvasView_MouseCursor.m \ PPCanvasView_Notifications.m \ PPCanvasView_SelectionOutline.m \ PPCanvasView_SelectionToolOverlay.m \ \ PPDocumentSheetController.m \ PPDocumentAnimationFileNoticeSheetController.m \ PPDocumentBackgroundSettingsSheetController.m \ PPDocumentEditImageSizePresetsSheetController.m \ PPDocumentEditPatternPresetsSheetController.m \ PPPresettablePatternView.m \ PPDocumentFlattenedSaveNoticeSheetController.m \ PPDocumentGridSettingsSheetController.m \ PPDocumentResizeSheetController.m \ PPDocumentSamplerImagesSettingsSheetController.m \ PPDocumentScaleSheetController.m \ PPScaledImageView.m \ PPDocumentSizeSheetController.m \ PPExportPanelAccessoryViewController.m \ \ PPPanelsController.m \ PPPanelController.m \ PPToolsPanelController.m \ PPLayersPanelController.m \ PPLayersTableView.m \ PPLayerEnabledButtonCell.m \ PPLayerOpacitySliderCell.m \ PPLayerBlendingModeButton.m \ PPPreviewPanelController.m \ PPPreviewView.m \ PPSamplerImagePanelController.m \ PPToolModifierTipsPanelController.m \ PPToolModifierTipsText.m \ \ PPPopupPanelsController.m \ PPPopupPanelController.m \ PPPopupPanel.m \ PPFilledRoundedRectView.m \ PPNavigatorPopupPanelController.m \ PPNavigatorPopupView.m \ PPToolsPopupPanelController.m \ PPColorPickerPopupPanelController.m \ PPColorPickerPopupPanel.m \ PPSamplerImagePopupPanelController.m \ PPResizeControl.m \ PPLayerControlsPopupPanelController.m \ PPScreencastPopupPanelController.m \ \ PPLayerControlButtonImagesManager.m \ PPLayerControlButtonImagesManager_Notifications.m \ PPCompositeThumbnail.m \ PPMiniColorWell.m \ PPSamplerImageView.m \ PPToolButtonMatrix.m \ \ PPHotkeySettingsWindowController.m \ \ PPCursorManager.m \ \ PPThumbnailImageView.m \ PPColorWell.m \ PPKeyCancellableWindow.m \ PPTitleablePopUpButton.m \ PPParabolicSlider.m \ \ PPBackgroundPattern.m \ PPGridPattern.m \ PPHotkeys.m \ PPImageSizePresets.m \ PPPatternPresets.m \ PPBackgroundPatternPresets.m \ PPGridPatternPresets.m \ PPUserDefaults.m \ \ NSBezierPath_PPUtilities.m \ NSBezierPath_PPUtilities_MaskBitmapPaths.m \ NSBitmapImageRep_PPUtilities.m \ NSBitmapImageRep_PPUtilities_ColorMasking.m \ NSBitmapImageRep_PPUtilities_ImageBitmaps.m \ NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m \ NSBitmapImageRep_PPUtilities_MaskBitmaps.m \ NSBitmapImageRep_PPUtilities_PatternBitmaps.m \ NSColor_PPUtilities.m \ NSColor_PPUtilities_PatternColors.m \ NSColorPanel_PPUtilities.m \ NSCursor_PPUtilities.m \ NSDocument_PPUtilities.m \ NSDocumentController_PPUtilities.m \ NSError_PPUtilities.m \ NSEvent_PPUtilities.m \ NSFileManager_PPUtilities.m \ NSImage_PPUtilities.m \ NSImageRep_PPUtilities.m \ NSMutableArray_PPUtilities.m \ NSObject_PPUtilities.m \ NSObject_PPUtilities_MethodSwizzling.m \ NSPasteboard_PPUtilities.m \ NSTextField_PPUtilities.m \ NSWindow_PPUtilities.m \ NSData_PPNativePasteboardType.m \ \ PPAppBootUtilities.m \ PPGeometry.m \ PPHotkeyDisplayUtilities.m \ PPImagePixelAlphaPremultiplyTables.m \ PPKeyboardLayout.m \ PPObjCUtilities.m \ PPSRGBUtilities.m \ PPTextAttributesDicts.m \ PPThumbnailUtilities.m \ PPUserFolderPaths.m \ \ PPGNUstepGlue_BezierPathAliasing.m \ PPGNUstepGlue_BitmapGraphicsContext.m \ PPGNUstepGlue_BitmapNonpremultipliedPNG.m \ PPGNUstepGlue_ColorPanel.m \ PPGNUstepGlue_ColorPickerPopupPanel.m \ PPGNUstepGlue_CustomTheme.m \ PPGNUstepGlue_DisableMenuKeysDuringTextEntry.m \ PPGNUstepGlue_DocumentAutosaving.m \ PPGNUstepGlue_DocumentSheets.m \ PPGNUstepGlue_DocumentWindow.m \ PPGNUstepGlue_ImageRecacheSpeedups.m \ PPGNUstepGlue_KeyCancellableWindow.m \ PPGNUstepGlue_KeyUpEvents.m \ PPGNUstepGlue_LayerControlsPopupMenu.m \ PPGNUstepGlue_LayersTable.m \ PPGNUstepGlue_MenuKeyEquivalents.m \ PPGNUstepGlue_MenuUpdates.m \ PPGNUstepGlue_MenuView.m \ PPGNUstepGlue_MenuWindowHiding.m \ PPGNUstepGlue_Miscellaneous.m \ PPGNUstepGlue_ModalSessions.m \ PPGNUstepGlue_ModalSheets.m \ PPGNUstepGlue_ModifierKeys.m \ PPGNUstepGlue_PanelResizing.m \ PPGNUstepGlue_PatternColorDrawingSpeedup.m \ PPGNUstepGlue_PatternedLines.m \ PPGNUstepGlue_PopupPanelFrames.m \ PPGNUstepGlue_PopupPanelHidingOnWindowMove.m \ PPGNUstepGlue_PreviewImageViewResizing.m \ PPGNUstepGlue_ResizeControl.m \ PPGNUstepGlue_ScrollerAutohiding.m \ PPGNUstepGlue_SegmentedCellTracking.m \ PPGNUstepGlue_SliderDragging.m \ PPGNUstepGlue_TIFFRepresentations.m \ PPGNUstepGlue_TitleablePopUpButton.m \ PPGNUstepGlue_ViewDisplayCaching.m \ PPGNUstepGlue_WindowOrdering.m \ PPGNUstepGlue_WindowPlacement.m \ PPGNUstepGlue_WindowStyleOffsets.m \ PPGNUstepGlue_Workspace.m \ PPGNUstepGlueUtilities.m \ \ PPOptional_CanvasSpeedCheck.m \ PPOptional_Screencasting.m \ PPScreencastController.m PikoPixel_RESOURCE_FILES = \ images/GNUstepAppIcon.png \ PikoPixel.appdata.xml \ \ images/arrow_left_button.png \ images/arrow_outline_left_button.png \ images/arrow_outline_right_button.png \ images/arrow_right_button.png \ images/blend_mode_icon_linear.png \ images/blend_mode_icon_standard.png \ images/checkerboard_segment.png \ images/diagonal_checkerboard_segment.png \ images/diagonal_lines_segment.png \ images/eraser_tool_overlay_outline_pattern.png \ images/gridpatternpreview_foreground.png \ images/gridtype_crosshairs_segment.png \ images/gridtype_dots_segment.png \ images/gridtype_largedots_segment.png \ images/gridtype_lines_segment.png \ images/isometric_checkerboard_segment.png \ images/isometric_lines_segment.png \ images/marching_ants_pattern.png \ images/minus_button_overlay.png \ images/minus_button_overlay_small.png \ images/neko.png \ images/pencil_segment.png \ images/plus_button_overlay.png \ images/plus_button_overlay_small.png \ images/resize_control.png \ images/selection_tool_overlay_add_pattern.png \ images/selection_tool_overlay_subtract_pattern.png \ images/solid_segment.png \ images/target_draw_layer_icon.png \ images/target_enabled_layers_icon.png \ images/view_draw_layer_icon.png \ images/view_enabled_layers_icon.png \ \ images/tools/color_ramp_cursor.png \ images/tools/eraser_button.png \ images/tools/eraser_cursor.png \ images/tools/eyedropper_button.png \ images/tools/eyedropper_cursor.png \ images/tools/freehand_select_button.png \ images/tools/freehand_select_cursor.png \ images/tools/line_button.png \ images/tools/line_cursor.png \ images/tools/magnifier_button.png \ images/tools/magnifier_cursor.png \ images/tools/move_button.png \ images/tools/move_cursor.png \ images/tools/move_selection_outline_cursor.png \ images/tools/oval_button.png \ images/tools/oval_cursor.png \ images/tools/paintcan_button.png \ images/tools/paintcan_cursor.png \ images/tools/pencil_button.png \ images/tools/pencil_cursor.png \ images/tools/rect_button.png \ images/tools/rect_cursor.png \ images/tools/selection_rect_button.png \ images/tools/selection_rect_cursor.png \ images/tools/wand_button.png \ images/tools/wand_cursor.png \ \ hotkey_defaults/Hotkeys_ar.plist \ hotkey_defaults/Hotkeys_be.plist \ hotkey_defaults/Hotkeys_bg.plist \ hotkey_defaults/Hotkeys_cs.plist \ hotkey_defaults/Hotkeys_da.plist \ hotkey_defaults/Hotkeys_de_AT.plist \ hotkey_defaults/Hotkeys_de_CH.plist \ hotkey_defaults/Hotkeys_de.plist \ hotkey_defaults/Hotkeys_el.plist \ hotkey_defaults/Hotkeys_en_AU.plist \ hotkey_defaults/Hotkeys_en_CA.plist \ hotkey_defaults/Hotkeys_en_GB.plist \ hotkey_defaults/Hotkeys_en.plist \ hotkey_defaults/Hotkeys_en_US.plist \ hotkey_defaults/Hotkeys_es.plist \ hotkey_defaults/Hotkeys_et.plist \ hotkey_defaults/Hotkeys_fa.plist \ hotkey_defaults/Hotkeys_fi.plist \ hotkey_defaults/Hotkeys_fr_CA.plist \ hotkey_defaults/Hotkeys_fr_CH.plist \ hotkey_defaults/Hotkeys_fr.plist \ hotkey_defaults/Hotkeys_he.plist \ hotkey_defaults/Hotkeys_hr.plist \ hotkey_defaults/Hotkeys_hu.plist \ hotkey_defaults/Hotkeys_hy.plist \ hotkey_defaults/Hotkeys_is.plist \ hotkey_defaults/Hotkeys_it.plist \ hotkey_defaults/Hotkeys_lt.plist \ hotkey_defaults/Hotkeys_lv.plist \ hotkey_defaults/Hotkeys_mi.plist \ hotkey_defaults/Hotkeys_mk.plist \ hotkey_defaults/Hotkeys_mt.plist \ hotkey_defaults/Hotkeys_nb.plist \ hotkey_defaults/Hotkeys_ne.plist \ hotkey_defaults/Hotkeys_nl_BE.plist \ hotkey_defaults/Hotkeys_nl.plist \ hotkey_defaults/Hotkeys_pl.plist \ hotkey_defaults/Hotkeys_ps.plist \ hotkey_defaults/Hotkeys_pt_BR.plist \ hotkey_defaults/Hotkeys_pt_PT.plist \ hotkey_defaults/Hotkeys_ro.plist \ hotkey_defaults/Hotkeys_ru.plist \ hotkey_defaults/Hotkeys_sk.plist \ hotkey_defaults/Hotkeys_sl.plist \ hotkey_defaults/Hotkeys_sr-Cyrl.plist \ hotkey_defaults/Hotkeys_sv.plist \ hotkey_defaults/Hotkeys_th.plist \ hotkey_defaults/Hotkeys_tr.plist \ hotkey_defaults/Hotkeys_uk.plist \ hotkey_defaults/Hotkeys_uz.plist \ hotkey_defaults/Hotkeys_vi.plist \ \ PPGNUstepDefaults_CustomTheme.plist PikoPixel_LOCALIZED_RESOURCE_FILES = \ MainMenu.nib \ \ InfoPlist.strings \ KeyboardNameToLocale.plist \ ToolModifierTipsStrings.plist \ \ ColorPickerPopupPanel.nib \ DocumentBackgroundSettingsSheet.nib \ DocumentEditPatternPresetsSheet.nib \ DocumentEditSizePresetsSheet.nib \ DocumentFlattenedSaveNoticeSheet.nib \ DocumentGridSettingsSheet.nib \ DocumentResizeSheet.nib \ DocumentSamplerImagesSettingsSheet.nib \ DocumentScaleSheet.nib \ DocumentSizeSheet.nib \ DocumentWindow.nib \ ExportPanelAccessoryView.nib \ HotkeySettings.nib \ LayerControlButtonImageViews.nib \ LayerControlsPopupPanel.nib \ LayersPanel.nib \ NavigatorPopupPanel.nib \ PreviewPanel.nib \ SamplerImagePanel.nib \ SamplerImagePopupPanel.nib \ ScreencastPopupPanel.nib \ ToolModifierTipsPanel.nib \ ToolsPanel.nib \ ToolsPopupPanel.nib PikoPixel_LANGUAGES = \ English -include GNUmakefile.preamble include $(GNUSTEP_MAKEFILES)/application.make -include GNUmakefile.postamble PikoPixel.Sources.1.0-b10b/PikoPixel/GNUmakefile.postamble0000644000076500000240000000005713244033327022217 0ustar joshstaffafter-all:: ./fix_GNUstep_PP_desktop_file.sh PikoPixel.Sources.1.0-b10b/PikoPixel/GNUmakefile.preamble0000644000076500000240000000115113746400367022025 0ustar joshstaff# Additional flags to pass to the preprocessor ADDITIONAL_CPPFLAGS += # Additional flags to pass to Objective C compiler ADDITIONAL_OBJCFLAGS += -include PikoPixel_Prefix.pch -Winvalid-pch \ -Wno-unknown-pragmas -Wno-parentheses -Wno-multichar # Additional flags to pass to C compiler ADDITIONAL_CFLAGS += # Additional flags to pass to the linker ADDITIONAL_LDFLAGS += # Additional include directories the compiler should search ADDITIONAL_INCLUDE_DIRS += # Additional library directories the linker should search ADDITIONAL_LIB_DIRS += # Additional GUI libraries to link ADDITIONAL_GUI_LIBS += PikoPixel.Sources.1.0-b10b/PikoPixel/gridPatternArchiveIcon.icns0000644000076500000240000015673713727050720023457 0ustar joshstafficnsis32&&π&&π&&π&&&&&& &&&&&&π&&&&ƀƀƀ ƀs8mk+8888888889999::;;==>>??@@AACCDDEEEE6OXdknnkdXO6il32ieٺb_̷_ մ] ۶[ Đtr~T ǹieٺb_̷_ մ] ۶[ Đtr~T ǹ؁؁؁؁؁؁؀ ؁؀؁؁؁ ؁ ؁؁؁؁؁؁؁؁ieٺb_̷_ մ] ۶[ Đtr~T ǹсссссср срссс с ссссссссl8mk-MMMMMMMMMMMMM?Mm Or Tr Vs Vs Vs Vs Vm V@VPVSVUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV8dmmmmmmmmmmmmmmmmmmmmd8 !!!!!!!!!!!!!!!!!!!! it32.ڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁՁ݁ڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁՁɄɄɄɄɄɄɄɄɃ݁ɄɄɄɄɄɄɄɄɃɄɄɄɄɄɄɄɄɃɄɄɄɄɄɄɄɄɃɄɄɄɄɄɄɄɄɃɄɄɁɄɄɁɌɭɄɄɄɁɄɄɄɁɄɄɄɁɄɄɄɁɄɄɄɁɃɄɄɄɁɃɓɁɁɄɄɄɁɃɄɄɁɃɄɄɄɁɃɄɄɄɁɃɄɄɄɁɃɄɁɄɃɄɄɁɁɄɃɁɍɄɄɁɁɄɃɕɁɄɄɃɕɁɄɄɃɕɁɄɄɃɕɁɄɄɃɁɄɄɄɁɄɄɃɁɄɄɄɁɄɄɃɁɁɁɄɄɄɁɄɄɃɁɄɄɄɁɄɄɃɁɄɄɄɁɄɄɃɁɄɄɄɁɄɄɃɁɄɄɄɁɄɄɃɁɄɄɄɁɄɄɃɁɄɄɄɁɄɄɃɁɁɁɄɄɄɁɄɄɃɁɄɥɃɁɄɥɃɁɄɥɃɁɄɥɃɁɄɁɄɁɄɃɁɄɁɄɁɄɃɁɁɍɁɄɁɄɁɄɃɁɄɁɄɁɄɃɁɄɁɄɁɄɃɁɄɁɄɁɄɃɁɄɁɄɁɄɃɁɄɁɄɁɄɄɃɁɄɁɄɁɄɄɃɁɁɅɁɄɁɄɁɄɄɃɁɁɄɁɄɄɃɁɁɄɁɄɄɃɁɁɄɁɄɄɃɁɁɄɁɄɄɃɁɁɄɄɄɄɄɄɃɁɁɄɄɄɄɄɄɃɁɁɁɁɄɄɄɄɄɄɃɅɄɄɄɄɄɄɃɅɄɄɄɄɄɄɃɅɄɄɄɄɄɄɃɅɄɄɄɄɄɄɃɁɄɄɄɄɄɄɄɃɁɄɄɄɄɄɄɄɃɁɁɄɄɄɄɄɄɄɃɄɄɄɄɄɄɄɄɃɄɄɄɄɄɄɄɄɃڳ=@ x܀w tɿrrpĺpƽpȿqpŸpƻpǼqʿqsqvv v v wʄ yyöy Ź~uȿg·Fǿ"ſ UŁ ́̀ցԁ ʁՁ݁t8mk@ +012222222222222222222222222222222222222222222222221/+#  u; *8 3W<^ CZ"EV$GS$GS$GR$GR$GR$GQ$GR$GR$GR$FQ$FQ$FP$EQ$EP$EP$EP$EP$EO$EN$EN$EL$EJ$DE$D:$D)$C $C?$C $B,$B6 $B< $BA$BD $BE"$BE"$AE#$AE#$AE#$AE#$@E#$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$@E$$?E$$?E$$?E$$?D$$?D$$?D$$?D$$?C$$?C$$?C$$?C$$?C$$?C$$?B$$?B$$?B$$?B$$?B$$?B$$?B$$>B$$>B$$>B$$>A$$>A$$>A$$>A$$>A$$>A$$>A$$>@$$>@$$=@$$=@$$=@$$=@$$=@$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$=?$$$$<>$$<>$$<>$$<>$$<>$$<>$";<" 67 .EWenssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssofXF/ $6EOWZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZWOE6$ $.5:<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<:5.$  "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"    ic08b jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2R \ PXX`XX`XX`XXXPPXdKakadu-v5.2.1 aIuGi2LiEZ[kV8F5Q5$Zny4Vky 9k:h$%62)s1 _3sJd;7N4=%ox[`Q;,^Y=R_Wt8yLX)c, /ʲV6Bh|rf1,ĿB6vo~P?8<[qNۑ);tִ \r f-UUYr 6CR]diHtPG>9$he޵:Q* W{nvMv(fLr/ .#/F7a` Hɽ#ïǏo0)jI d %3H;b#ʥ %K6˜@2Ql6ϡz~_]}`.Pb;TzD wi?pPI.9,O VTA-|61FR1z v00au\.{d}SxPpcAZ*Rл)$k-+Eltf3|K}޿N ߅c}T+.(wWD( a v[$RQt[HCʺXen jw=aA^5U5zrrESS&|Ԛ˓θE ~7ƧNlEɪ5A<S,R=D挿o`nX79}Z#Ԃ6[a)`_Y>֗Zg*G3;0JJ"]ۮWH oDYl"2Ч'g = pȊ-b#NmxU._O碵=@R=\T% ;]e 7wxxmHijA2۷g=1R=pq0g}&-[ fldqCm(x-5lX$WᇸhAŪ'+dt6v㹹8E Nzɭy5gny!tas$þ2s}Ry==v#$:沍^jIY?o'LdXeqRRr!qӯo,r`Qއ;a%# X8 Hl9~'[7#E*HE=)q-H K$]&Ogm6"X+aoeu*fxߜن7FPP8 MX IFm:.yJ9nv֢b= fy^BHa+_#d^҄'yanTQ]E[m|ZHDvIusx \3SpIS`i.JeKu+1}ccc0<7eYDmO6zhqhZ>8_  x-L2a׺O ו|&婐>QG1k!$SK 1-VSmjhG˃CA c8W? 8ʸkD"'Mvņ%\Uaðmw`oeڬeQCWnj ݱ2L|%H`;{x]'|.O_j5 j)!qDNHȒA%P _4 #r4nlu#Q\B@ 3- $dο~ Ζe&"@ǻ0aZD:\S.a#N#Ӱ'Re\[^ES /MX.nhEbkJ/'19sQpN'lqضͨUߜ$r4{ㄼH)ؘ)KX٤vuK];z%XG4hUh}'3:whƤݲ9=;yMoCD E쟆VSAB*i"#BLG}+tg{4[f[ҷ'sjW؏+ @*{'.[Vg3>0Ui8?B`oqìbYǥS)ӝI`{J b(#앛;HY ۿS0^%l? Tv@͞39jUҖȭ'QiiI˚1v.?0ף+Qxu"xpk6Ah~:pIya9#twt<|h3oΫ4ʝ]={+B ɘdt-K.o5FY?cO^_I880Jg }Ԃ q5od&k͠ Y?.'p`(/қ3oI%R} ՟ ?.&*SZo?#3@cPb%O@Q;RpmƄMTax~ *[/k ەXĄ[( Um&ru~Xp{i?By򬃼|afKW3NsL8 )ݲ˒1 |fg05ťOtjnLu@ G:r^ Lu݈qm@ӝz(4DLJ+DC9O.<)RԳ'mb~/P 5#„08.SH&7tt'7[0H#,]L9^' rxW+1"~ё^-xb/J&'yӜ6>P9X&?8F.~aѤ3 `. Q8Ա*C#.1r.w)2|8R[1Sz'樻ȇ(k#BUUUɅ(l9Y$5AH78c`W_0ꁃ E. Yet"èaA:Pg5sAފ8.[Yn7ԛҶ8(F^u_v̇J] bV4'xmz/"} X/$upBU=6}pҁԖj|2%??TH;7[,,U! Qd4a/Pdf{ט't|VK`7auȬ7LA1 ح ,"C"LINѤcK@w]hG J?IIy(:+XSx6~ étYno'f|ܽtr<&Vo[ -,y '-zVdMU ­EEU&$Աw(yuZ-rZ l"z P%o2bMrd^ӷ!Z,9zhοG=P<}À4z\ǯ l'8m %?|nskY"Ďah'zޏ _VDjZQ?)qI 'a#:-u`k/#AT$ Y0rB"#'2QJenD3o6~"cOv}txԐyjZp R"a{4,!0]x\cRy5j7 ;c9P47/N#'hphYNG_kyP'~k Hzhm19"e4zf߫s´0X8r,%/ , ٠3V,\{=,([) D`1ф̞Ӷ(=V&16԰FFE0e(<'I))\`.z]R !aیJ=_ocHAwLP*4AAXtvK0 է|$OVаl,uV5[ZisTn Kul Ag踳w:P#GunP泧: qW^QQXU0N.tk)wuHZԴiH.Xu4|P ;+"( .Fp5ꀈ"/;]]?W?f '{z  O05E,dSBK^~E6ܥj Q)Hsgu-u}%EonW 1 E]0A# )zy/0DR@CYRa4J+{dX̘CuϨA{{{{{^D,磻`,7 +zk|XFDF~؟[aϬҰ{f[d85tW؏ﻥC3Ym@y\1ڳj1g md<$kqGz_DUjnAwE`ŪRĮ\ pVCE vNSF~JwՏ0y:#WBID̆)^0 7MP$ ̇Kl~CR/ƚ4è۸#ȸTe_<4@ޔ1jW̄ڌIFnjE.;߻atC^c-hp=HV&=\%G1|c[G%a#Rx]C噥8H8 =bb;~dy-kZֵUilr^.=V ;=t,ēqkwЌuIo7 FlncR9T_>gX5rnm Wm4kl#pߒZ|iwM3/:u:FZ#ׯOVkTmi>o'eC"`:N7-w~wehЗzM٧W8 [^2kÂ>á9)&YNJެ4z?P77*`BHaOH %ު,&B+HQSOFl,RFOPwB׳Xh E#d.xƨ2LFu*.e3_#'=(߆~rtƓHy6&bR9XS[6s#m"E/+uHP ,dygfV01e.t<,H@r0ّ~_ȹ>׊`2)xG5ѳlxGRģ.DDB<=X"DF2---H_9R_P׶J ES/Ō5=i@aaʍB)BP_?eu2_(M1"~irn З#q H(J)sMɚ8)فUZ.f@ów-=O:$=r<+ʾﮅ8*R巡Xk\<힦`Pm$I$I$I$θuf*؇NF8,u:SK([bn ƦKFB"왈lSo>Yv՟e!!^Nf~ G2N$ߥ [륨+|"vej`+zp%JhNO3U1|dz~t3S%@x5aV =ϫ+DK+#1 }ɝѝќNW$I$I$I$I$Y;ܳ B+|̶̉-/mzBc!;KɔJ=zni4f2,YYz 8:m 䈵vh+`+.5 HW3,J rc B0 nEĉzDx{stJ'8k/fiVnR3NΪFk,n_hFu(KĦZYf*ZA?Wgs1aFo!FS,ˁ?4L9ŚA+M\Fόn'ߌ%OpH&-D5#3&/|pUxc"]Lĕ" A6ci_`_nf5C u'RʞeV)⤃֞z&B-NUK|G9)xIOț-fQ5 m`YgKH'kGTXhR}`COG9!T(tJ%*3~MKgS>&"eYo]tnIPb]VM< tUonHAԣ2cNL͡rCk*"A<ݏhMJ}8qb'4:a_$< W}J` ZkmK&?qhx@A 1LӃ?>w:3jgzf1^mtIH>]1CKX0 7.a+s+ U DiP\! x|qx6^Q|;?}$L}&Цݥj%Hmئɞ<KQG. }7_Z~%߆?-X $DEp֙ҥL'_pjN1UygzGb˿Emg;6?IQH90 Ҋrpx>)-U \*֏!Or0P 7͕kH7f 02ՠ SH;D=`Л`/~MHPZda7h`,^T:ȖweB},e$>mb;DG&; LX}Tq1vExϙ'?7ŞB^! cۣnx dq<27o|am .7O/3a؀IF:1E qפX_%7S@,l o&6nΣ! 0܉(7rsjv1Y=fnUFb guMV)*d3&Dj^Ic" K"h. _ Ns{sB*?ci|qԥe Tv{$Y[,HV,RFddH Z$\Ew& z HÕlRJE *\RP1dfz%\o'jѥPg\dcI}z){azQ6ô{O&+dhOGXMAf]y<}ӽm_Y&?Gam."nt5o&B_0aۛ詍jaay4l̜Qa .&/aSU6uÂ|(r\蠎lB0 |q&ySfhYL}֩H [C}y iJ"T JJƠCBЊ,h;|hJ km3hd=#@ 7&ϵ`-Nb~`X٪7p ɵ7d l:2/wjnOw`ۤdG^$ W6Z;c> IҤ=T| ~})9CϽh;ɇp1 EɴBm T<_6Cﰒ0X-'^' 2֦ܤVI72A7t/jZڴ$;}wOOK_*'CpNǐl/˾ o p;\lBHv /`PwMGUGA^)ju ' 0}$Tr #BߝV+2͢LXrB5a nW1jZ=Zb~Ms%PQVɰ4Γ]8Itp>j3ƟV璝pKԗ͝+Uť8"SLd\M{paC{֗ߧs䨿i`WyZXivCA. jX)XKF}dr25C<2ӡ;?$/! 4oS~-x#hnXOP*?s>UpTџ`uիJ{NV^=U3YdctѾCc̛@v^b$:!v7?e~COu'9ϢF9}`?f k6]M01Kڼ_J RAؚQ.|t9ybb}:*jzaYvQo&hXeX,(-c+^7{:m,lSaޝga6|;~Dg vWbsl8/ؤcq0 TYuGqa~S#>sms/!V&c=XU ( +Ч3Sl[+wچؕ< ǫrzx1PO@dpEX?$(V@/C9Шw xd17h[("/\F+L9qJ{LKb ~y;֛';m6'=t ^&X\E}&sPǔ$ goM!)#UKDh 轜Bϰ^7.I9%juNBLJrF6C!dzSp|JΣ AP\Fxe$N~0Ue$nAPd}vn 9W՘[9g)C}c:2BTP:<t*rut&IQ2 t0 huҖ:u'#c|I"1zkķZ 11Wp]_HW>_2 Yfٜl8?2;I#_KVGZFt"u8C9pKyFJ_Y,K& c1K*k6L^xmSoA1..mkk)ZOtT >ߢ}N􍩇2"4^#up /šq5 i );>))c0%{Lĸ |H"0,QY:j2Rg3,bb-1qSpFZ^Ja3N'p ϝ[xKE(~(BL\el4"[X|eS˽7y_'+J̊Az<}dJJ U9m¸ℾ5RMis;ze 2O#^~^BR. 9G%$AQb!@XߖkXL9:*Ow[ڢRvAKc F>6y_ZBT'?~%i&އwk P ~n/L}Cw^d7\!+*m ~C =c##[?^ZcoF#ؖ :\eV|7|e."]E-GAjf??+ (Y+_7|7ztFTdFSj1,7?O=Ǎ5@jG"%0\S#T "SLcW[pe_WJL!Y%GxE` WأՈwAuoOP0vBVPE@C` ,q7zA".g)HNGUoyf=uF*KR/lY%e4VCdah6P!p 2h@Dd]Q# vt}P D \6?,$%A}_ ZQf^*-Q N!$2_'(DKfn.C=Q:Ads|΄wQ" ׯkt\]xCoq}XwWe\gK ,Ds;T'> ihԯ#t!S$Tp+A/}?eAH,->{1s+(= }@3:Q"S!T;zͬ)Ӯ` -W娽2i!Dv raeamÒڹY$F' X AI*;o%YiE2L*] f7H_/g{{c" aP 0 31WjpY_*`tڹ|1u?(\ *;Ӆk+®=|d@oB^!_c=7@~?t+ \(ފ(=ۤ/) ke~ 5 . S7NRfF2\A78!nSIU">BYdDAvXN=@_i^\֨ZJOn6M\<22*dk,rmp Sq4Jg7N+n pU*ml5ZYyZ:Չx70A1r|@&S3CAӰAa0ֻqR\=fhgFAcclFoOqx5m;6k8Z \[M Nb6/J*")Bh}XGyVrL^ t{Z6~8*uۑw$ҭ5vZe3$ T l"rIYXPF,IғgYvh7~20J,6?Qœ)UBEs.7x<}K@+/f'&Y!yY} Lp]=x5!{U0ǸB':1@*UG2uhfAf,-%3Jrj^+4TXX`!wQ<QRO:7_, Ǿ11̸W0 <5 "_V,:67!.iՋUokxi굀kjdgCn(&Mx , _-kdZnġGh-tZ\siQHc`Qr^<>ip-L7_7)j8(NVίϜ*+o__n=Hw']FK*mO|((muH:e]Sr t~iҹj;u[SHW)|X0^EuFplؔiw_&>.x%/q>]"3_Dpݙ.)a"ǁ$v)#g\9~K=:jcmi|TH=C.D\ῲ؞*ÂT1Uby͇}ON~*I nƂSaqs\rFPtRCIzu_V*VȀ~f,7/iʒt ߈J_>;yĸ`ZH} A[/$pހA<)m(ͦ|(NtNI^ CM[͋ ^ Ps #L~-3qH瓙' XC; HC˶δU/B#F5֖DQNO(%~w$Kcj7^y0n^h#SDiҚTSb--tLf3[T>xht@+qݝ>\w!#r1cgc)b؁y^s ĬhB4 j{X?3-6lUm0mH &Vw`[q,$۴P^y!۵m0޽#Αe?O f`s<[>zU^n/K𲣌iTfzEsɪl3GZz{C?!(R84W(z f|oTy'w$P!HECc !]9`{˙+>@R]Djښ=rI/8ō2+tHwn+ 2COsa1F%G\kpV tG&~@ݩ=Qi +U*H-#"/J8Y)d/(XMh+ݤ`\d'-hxH4r՗RX*B!&t)O5E#E2\/9ح=.2J-q5RP=Lx0q8 ΢۟M:$3ezHR/dc)u]?˟TRPEӓN7\I)e|fa(s oإR#\YM\hʼ.f,X9;~PhfaNEҸBPQ0VB4D|۸Sa=-Sl4SC-XnƲBDZװ{Dq0 4|1Dv}*;ʱ}tۿ-"4)Xz $A ؑ05-|1" YbJB`{qaΙNqtH^KqtH^%KhwA {:6"EoodS^P) snxiJ2B_Vu1b1$\xSO(\XS}8-o5PmU%l\+y9b<", >jxu}*Ϩf\wno,бl "+Dg4\kK(LJqXj̄PpnKN>TUR8bBCc9؅~erga;}^ ư0Qڗ w:I{fgDTUdq:}eC''Q3qce^4=Ҽ$,j I!#;7X%%N Zi Vt-JцjjQw)օ%-oD>M4vF 'ަG Zd0@OCQ7Fyg% ?S% ܜp޽ŠFN,B01?`Xޙӟy?, S-#Kc{֍M]N;D~IpN5e V|>N%͵ 6=s2}iJ5C{#,H!Iʮ̡"@sW32':Y}I1~;UB<[%e@A5`&PEQPh1k}@ȹ};ݙ6"HH^? >#anLmT{o`B=(V·&@_H8*qEQ3&SƏp:L`ue_@2mA?vտ0]:plt{ݜ_Nĺ}U_sYkӔ0j՞+s!سQy \J GV"'a.d @IЬOWi;MiSd ڽ2%P+*|.qmfg+zH\trXn;M$- 6e`-"q 3NC~g[tP6-HhX'M^|H)f眎~{w>)\p bK$ ݈ CSv\^K6y@;#0ŗ^ָ2 %;[+hy >OzyڛSpk.9ׯPyA1] ]s:^fi(`K0nLr%so+( Ňkǻ(`sC`+qE9jmR(2FB,Ph f7!ݟ^6)*j ?k HnJ"D E(3Z|`Gjw ?D#mb"RddO D2B ϹDVX?U 1dnM2/0x1)GaϰmB&}6nx'Z0;oH1XlpsD8<>uCn[sQW~"9uL{SqyoOU}:Cst WFw:!c,^2b%G˯)N? ]J2?H\rBDZgǙ1tkBcegoْeYm/3HT3'_1Qed#gR%̶h:;pA6$Os-'V֗ɹ%^)k% d>+mیWG="]x^1tBl#g=e ! ~,zծ$#dFӻ X 0!lBlAjoV]_p?MہL!@N5bKtV9Aȯh1C$3|0=ad919DByRKOƷ)@C.e}0ӜxlT>+*Z?ٹD%۷?2 hՋښJ홙po09gJ=J[M BuOB4v(C? 0T<Ԥ.{vu4 ϡ# [0pt祈d8z@UTUUT~{?pӟ_^ZkR.i3YpNt3^١ $zJjB+V?fʢ(v%G` Paȹc=hyyIr3`*@Xٔ f)d<TQ &ð@M F5Ohqt@#I*b9O۝H{xSYh,M [.:Fԟk߁+s%s_~ lOJO}@?_. / `T8%̛LP֗}h=4YV%DA01|٢ Q! {;bWi:y&"V$l7sP. SmцJ<7hs Da& ?:A4SY5*_&+2#fIg# G>,wh͈CQ˪|%&Q1:dXp=F>l1vl lc N4dd Vumq8trY Pbrp('#X(5}z"[,1mB#,,?- >;qSwp>K+q)aXZDwǭ #!F[ERl(O!ЋS`f 4}'8<|g|=MBio;f=4 Tg> Ey:-ga] 5y#‚#1@9FAPA%ؤWjWNT=A=FcH {yO.8iƮccSI"OYCk>?X/J*wbg}mt5n ' m0Mjy=n~M tDLϕǁZbr8!׎^i/m).O- xP"ug+.3g=klj s܏pK}<yDq ;zWS*zl y%րϻ1XuL@UT$:jxycrQ^YԽAx ꍘ 1[>lȞ~MyRy$Xɳ};w"%uKiXԜ$?=wG>b)@ «GݷU֫& ma=ĵ"D^f {D'VEGEX*rp 9D0쿈VXAQf[F{hh> »2ߢ+ UqY(Y\EՂ6#IKuf[JjH,Y?2NAHqdž$:4h~X"8n zQZ?|B4pq8HS##$6 8_!Q Δ@t3.!^H m`|)y,f@0???7E`THnYᬦ8wĈ\e=P;X"Qd~{7q(b:ôixԿ;P!ZgRj`6Ek1lk? LSE.e,=gbK֑ε>ҐaKuf[6HGք[^&M U"1H瞒*G,pV|`KU6]^<[Æ_8_%&N{|LFtcх|6cJ-_ z((eF>|1[8\Lkz-jg_ tsi @`($8'`ƠC2zڐMR%k@lm&NEǠ )N[3H='U}qXyvʓT6EXѮa-*)xOةx,`$%Ec 8]MqYXsMXo2I&BH?R/wrqFr^N32>'{ ;\R4Qof'9H| C̴\o}tTz#4)S,X|Q CX7Zo&!tCBv ۳e?RwVqZv1IZJm9gI0ϐd$vwRG$: E ߹soY5(njr#Ԩu^lFZ `0MH2y`dpZ] ]/X|4E]U6"`2/_rID#hf ;V4Ka6t|bcF $E/CuzA[V@ɲTwArEeQ8Jc YcAR F"y"F"zӞVdL49`U!X\KnԄ:|X"^]9#:B2â#xq]˹A]:G%:GHv XI9M/B+EƼrC4V8wk>0'"QYXA.o0j 34{ =*Ij^&͛ hel5>. _ %OECb%609:Uk.OLeCf:; uõ+TTw5.m/x5h7^uZ[~IKA,p֑egZ{p ’KL"!""6&8:R%u$I$I$I$I xBKO :XŒ*ߞOl@gQ j "V8BBD!pl?R]w M&)wh z*+L} X6-ݤXV^ $Ρ>#;P>r$xRW 3(\{ { E(z~l/M8 H#R[7yK5VJ/AH3DmIGh:뺭]NС |[Bu} :1p|irߣrԦ˭en3(ݏ4 -6w뀧V&lWۥ[_tY9'$!ݵg]K7fˈ icnV BffPikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/0000755000076500000240000000000014400242512021341 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_ar.plist0000644000076500000240000000301612143535304024534 0ustar joshstaff PencilTool ح EraserTool ث FillTool ب LineTool م RectTool ق OvalTool خ FreehandSelectTool ش RectSelectTool س MagicWandTool ص ColorSamplerTool ي MoveTool د MagnifierTool و NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ظ ToolsPopup_Alternate / ColorPickerPopup ط ColorPickerPopup_Alternate . LayerControlsPopup ذ LayerControlsPopup_Alternate ، BlinkDocumentLayers ز SwitchCanvasViewMode ـ SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit ٠ PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_be.plist0000644000076500000240000000302012143535304024513 0ustar joshstaff PencilTool з EraserTool у FillTool а LineTool д RectTool к OvalTool ў FreehandSelectTool ф RectSelectTool ы MagicWandTool ц ColorSamplerTool в MoveTool м MagnifierTool ь NavigatorPopup NavigatorPopup_Alternate * ToolsPopup я ToolsPopup_Alternate / ColorPickerPopup ч ColorPickerPopup_Alternate ю LayerControlsPopup с LayerControlsPopup_Alternate б BlinkDocumentLayers и SwitchCanvasViewMode SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ё ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_bg.plist0000644000076500000240000000301612143535304024522 0ustar joshstaff PencilTool з EraserTool е FillTool о LineTool в RectTool и OvalTool д FreehandSelectTool ь RectSelectTool я MagicWandTool у ColorSamplerTool а MoveTool э MagnifierTool п NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ю ToolsPopup_Alternate б ColorPickerPopup й ColorPickerPopup_Alternate л LayerControlsPopup ъ LayerControlsPopup_Alternate р BlinkDocumentLayers ф SwitchCanvasViewMode , SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ( ZoomIn . ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_cs.plist0000644000076500000240000000277612143535304024553 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup y ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode \ SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel § ZoomIn = ZoomOut é ZoomToFit í PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_da.plist0000644000076500000240000000300312143535304024512 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ' ZoomIn + ZoomOut 0 ZoomToFit 9 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_de.plist0000644000076500000240000000277712143535304024537 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup y ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel # ZoomIn + ZoomOut ü ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_de_AT.plist0000644000076500000240000000277712143535304025123 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup y ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel # ZoomIn + ZoomOut ü ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_de_CH.plist0000644000076500000240000000300312143535304025070 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup y ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel $ ZoomIn ' ZoomOut 0 ZoomToFit 9 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_el.plist0000644000076500000240000000301312143535304024527 0ustar joshstaff PencilTool π EraserTool ε FillTool φ LineTool λ RectTool ρ OvalTool ο FreehandSelectTool α RectSelectTool σ MagicWandTool ς ColorSamplerTool δ MoveTool ω MagnifierTool μ NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ζ ToolsPopup_Alternate / ColorPickerPopup χ ColorPickerPopup_Alternate . LayerControlsPopup ψ LayerControlsPopup_Alternate , BlinkDocumentLayers β SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_en.plist0000644000076500000240000000277312143535304024545 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_en_AU.plist0000644000076500000240000000277312143535304025132 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_en_CA.plist0000644000076500000240000000277312143535304025110 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_en_GB.plist0000644000076500000240000000277312143535304025115 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_en_US.plist0000644000076500000240000000277312143535304025154 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_es.plist0000644000076500000240000000300412143535304024536 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate ç ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ' ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_et.plist0000644000076500000240000000300312143535304024536 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ' ZoomIn + ZoomOut 0 ZoomToFit 9 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_fa.plist0000644000076500000240000000301712143535304024521 0ustar joshstaff PencilTool ح EraserTool ث FillTool ب LineTool م RectTool ق OvalTool خ FreehandSelectTool ش RectSelectTool س MagicWandTool ص ColorSamplerTool ی MoveTool د MagnifierTool و NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ظ ToolsPopup_Alternate ژ ColorPickerPopup ط ColorPickerPopup_Alternate . LayerControlsPopup ذ LayerControlsPopup_Alternate ، BlinkDocumentLayers ز SwitchCanvasViewMode پ SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit ۰ PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_fi.plist0000644000076500000240000000300312143535304024524 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ' ZoomIn + ZoomOut 0 ZoomToFit 9 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_fr.plist0000644000076500000240000000277712143535304024556 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool z ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup w ToolsPopup_Alternate = ColorPickerPopup x ColorPickerPopup_Alternate : LayerControlsPopup c LayerControlsPopup_Alternate ; BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel $ ZoomIn ) ZoomOut - ZoomToFit à PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_fr_CA.plist0000644000076500000240000000277612143535304025120 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate é ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ù SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel à ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_fr_CH.plist0000644000076500000240000000300312143535304025107 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup y ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel $ ZoomIn ' ZoomOut 0 ZoomToFit 9 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_he.plist0000644000076500000240000000302212143535304024523 0ustar joshstaff PencilTool פ EraserTool ק FillTool כ LineTool ך RectTool ר OvalTool ם FreehandSelectTool ש RectSelectTool ד MagicWandTool ' ColorSamplerTool ג MoveTool ה MagnifierTool צ NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ז ToolsPopup_Alternate . ColorPickerPopup ס ColorPickerPopup_Alternate ץ LayerControlsPopup ב LayerControlsPopup_Alternate ת BlinkDocumentLayers נ SwitchCanvasViewMode ; SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ֿ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_hr.plist0000644000076500000240000000277712143535304024560 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ž ZoomIn + ZoomOut / ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_hu.plist0000644000076500000240000000300012143535304024537 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup y ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode í SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ű ZoomIn ó ZoomOut ü ZoomToFit ö PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_hy.plist0000644000076500000240000000302312143535304024550 0ustar joshstaff PencilTool բ EraserTool է FillTool ֆ LineTool լ RectTool ր OvalTool ո FreehandSelectTool ա RectSelectTool ս MagicWandTool վ ColorSamplerTool տ MoveTool ւ MagnifierTool մ NavigatorPopup NavigatorPopup_Alternate * ToolsPopup զ ToolsPopup_Alternate ծ ColorPickerPopup ց ColorPickerPopup_Alternate ղ LayerControlsPopup գ LayerControlsPopup_Alternate շ BlinkDocumentLayers պ SwitchCanvasViewMode ՝ SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ՚ ZoomIn ժ ZoomOut ռ ZoomToFit օ PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_is.plist0000644000076500000240000000300012143535304024536 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate þ ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel + ZoomIn ö ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_it.plist0000644000076500000240000000300112143535304024540 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool z ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup w ToolsPopup_Alternate ò ColorPickerPopup x ColorPickerPopup_Alternate : LayerControlsPopup c LayerControlsPopup_Alternate ; BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel § ZoomIn = ZoomOut - ZoomToFit é PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_lt.plist0000644000076500000240000000277412143535304024563 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode q SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn ž ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_lv.plist0000644000076500000240000000300012143535304024544 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ' SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_mi.plist0000644000076500000240000000277312143535304024550 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode q SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_mk.plist0000644000076500000240000000301712143535304024542 0ustar joshstaff PencilTool п EraserTool е FillTool ф LineTool л RectTool р OvalTool о FreehandSelectTool а RectSelectTool с MagicWandTool њ ColorSamplerTool д MoveTool в MagnifierTool м NavigatorPopup NavigatorPopup_Alternate * ToolsPopup з ToolsPopup_Alternate - ColorPickerPopup џ ColorPickerPopup_Alternate . LayerControlsPopup ц LayerControlsPopup_Alternate , BlinkDocumentLayers б SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ж ZoomIn + ZoomOut / ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_mt.plist0000644000076500000240000000277412143535304024564 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ż SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_nb.plist0000644000076500000240000000277612143535304024545 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel @ ZoomIn + ZoomOut 0 ZoomToFit 9 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_ne.plist0000644000076500000240000000304712143535304024540 0ustar joshstaff PencilTool EraserTool FillTool LineTool ि RectTool OvalTool FreehandSelectTool RectSelectTool MagicWandTool ColorSamplerTool MoveTool MagnifierTool NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ToolsPopup_Alternate / ColorPickerPopup ColorPickerPopup_Alternate LayerControlsPopup LayerControlsPopup_Alternate BlinkDocumentLayers SwitchCanvasViewMode SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ZoomIn ZoomOut ( ZoomToFit PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_nl.plist0000644000076500000240000000277312143535304024554 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_nl_BE.plist0000644000076500000240000000300012143535304025102 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool z ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup w ToolsPopup_Alternate = ColorPickerPopup x ColorPickerPopup_Alternate : LayerControlsPopup c LayerControlsPopup_Alternate ; BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ù ZoomIn ) ZoomOut - ZoomToFit à PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_pl.plist0000644000076500000240000000277712143535304024562 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup y ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ; ZoomIn [ ZoomOut ż ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_ps.plist0000644000076500000240000000302012143535304024547 0ustar joshstaff PencilTool ح EraserTool ث FillTool ب LineTool م RectTool ق OvalTool خ FreehandSelectTool ش RectSelectTool س MagicWandTool ص ColorSamplerTool ی MoveTool ر MagnifierTool ړ NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ۍ ToolsPopup_Alternate / ColorPickerPopup ې ColorPickerPopup_Alternate ږ LayerControlsPopup ز LayerControlsPopup_Alternate و BlinkDocumentLayers ذ SwitchCanvasViewMode SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit ۰ PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_pt_BR.plist0000644000076500000240000000277312143535304025151 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_pt_PT.plist0000644000076500000240000000300312143535304025154 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn + ZoomOut ' ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_ro.plist0000644000076500000240000000277512143535304024565 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode î SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ț ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_ru.plist0000644000076500000240000000301612143535304024560 0ustar joshstaff PencilTool з EraserTool у FillTool а LineTool д RectTool к OvalTool щ FreehandSelectTool ф RectSelectTool ы MagicWandTool ц ColorSamplerTool в MoveTool м MagnifierTool ь NavigatorPopup NavigatorPopup_Alternate * ToolsPopup я ToolsPopup_Alternate / ColorPickerPopup ч ColorPickerPopup_Alternate ю LayerControlsPopup с LayerControlsPopup_Alternate б BlinkDocumentLayers и SwitchCanvasViewMode ] SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ё ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_sk.plist0000644000076500000240000000277612143535304024563 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup y ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode \ SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ň ZoomIn = ZoomOut é ZoomToFit í PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_sl.plist0000644000076500000240000000277712143535304024565 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ž ZoomIn + ZoomOut / ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_sr-Cyrl.plist0000644000076500000240000000302112143535304025461 0ustar joshstaff PencilTool п EraserTool е FillTool ф LineTool л RectTool р OvalTool о FreehandSelectTool а RectSelectTool с MagicWandTool њ ColorSamplerTool д MoveTool в MagnifierTool м NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ѕ ToolsPopup_Alternate - ColorPickerPopup џ ColorPickerPopup_Alternate . LayerControlsPopup ц LayerControlsPopup_Alternate , BlinkDocumentLayers б SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ж ZoomIn + ZoomOut ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_sv.plist0000644000076500000240000000300312143535304024556 0ustar joshstaff PencilTool p EraserTool e FillTool f LineTool l RectTool r OvalTool o FreehandSelectTool a RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate - ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode < SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ' ZoomIn + ZoomOut 0 ZoomToFit 9 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_th.plist0000644000076500000240000000305112143535304024544 0ustar joshstaff PencilTool EraserTool FillTool LineTool RectTool OvalTool FreehandSelectTool RectSelectTool MagicWandTool ColorSamplerTool MoveTool MagnifierTool NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ToolsPopup_Alternate ColorPickerPopup ColorPickerPopup_Alternate LayerControlsPopup LayerControlsPopup_Alternate BlinkDocumentLayers SwitchCanvasViewMode - SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ZoomIn ZoomOut ZoomToFit PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_tr.plist0000644000076500000240000000277712143535304024574 0ustar joshstaff PencilTool p EraserTool ğ FillTool a LineTool l RectTool ı OvalTool h FreehandSelectTool u RectSelectTool i MagicWandTool g ColorSamplerTool e MoveTool c MagnifierTool s NavigatorPopup NavigatorPopup_Alternate * ToolsPopup j ToolsPopup_Alternate , ColorPickerPopup ö ColorPickerPopup_Alternate . LayerControlsPopup v LayerControlsPopup_Alternate b BlinkDocumentLayers ç SwitchCanvasViewMode w SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel = ZoomIn q ZoomOut x ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_uk.plist0000644000076500000240000000302312143535304024547 0ustar joshstaff PencilTool з EraserTool у FillTool а LineTool д RectTool к OvalTool щ FreehandSelectTool ф RectSelectTool и MagicWandTool ц ColorSamplerTool в MoveTool м MagnifierTool ь NavigatorPopup NavigatorPopup_Alternate * ToolsPopup я ToolsPopup_Alternate / ColorPickerPopup ч ColorPickerPopup_Alternate ю LayerControlsPopup с LayerControlsPopup_Alternate б BlinkDocumentLayers і SwitchCanvasViewMode ' SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel ґ ZoomIn = ZoomOut - ZoomToFit 0 PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_uz.plist0000644000076500000240000000301712143535304024571 0ustar joshstaff PencilTool ح EraserTool ث FillTool ب LineTool م RectTool ق OvalTool خ FreehandSelectTool ش RectSelectTool س MagicWandTool ص ColorSamplerTool ی MoveTool ر MagnifierTool پ NavigatorPopup NavigatorPopup_Alternate * ToolsPopup ظ ToolsPopup_Alternate / ColorPickerPopup ط ColorPickerPopup_Alternate . LayerControlsPopup ز LayerControlsPopup_Alternate و BlinkDocumentLayers ذ SwitchCanvasViewMode SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn = ZoomOut - ZoomToFit ۰ PikoPixel.Sources.1.0-b10b/PikoPixel/hotkey_defaults/Hotkeys_vi.plist0000644000076500000240000000277612143535304024564 0ustar joshstaff PencilTool p EraserTool g FillTool f LineTool l RectTool r OvalTool k FreehandSelectTool q RectSelectTool s MagicWandTool w ColorSamplerTool d MoveTool v MagnifierTool m NavigatorPopup NavigatorPopup_Alternate * ToolsPopup z ToolsPopup_Alternate / ColorPickerPopup x ColorPickerPopup_Alternate . LayerControlsPopup c LayerControlsPopup_Alternate , BlinkDocumentLayers b SwitchCanvasViewMode ` SwitchLayerOperationTarget \T ToggleActivePanels \R ToggleColorPickerPanel \ ZoomIn ZoomOut - ZoomToFit đ PikoPixel.Sources.1.0-b10b/PikoPixel/images/0000755000076500000240000000000014400242512017414 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/images/arrow_left_button.png0000644000076500000240000000533013722612313023670 0ustar joshstaffPNG  IHDR 6 AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .ҀB$# #c'RB$8@ws"}|'IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/eraser_tool_overlay_outline_pattern.png0000644000076500000240000000525113722612314027507 0ustar joshstaffPNG  IHDRV( AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .aIDATx;r@aRF(&원pNlΌBFJ+-{R5z q@GfceN[$co$c Gڟ׫v^L6ca8|}iGRk1{4i`/˿:8 v1(~s?[C/fD@Qs~ @Gĭkijնܿ66R1<d0V؛Uo#Iz6]?QyJ(k}w@mEQ @kYK5m>W!딟h#8ջt#8 #tgi}qGq@6 @Gĥ;X}k :#=Uҝ>^q@G&Kw+m%_/zAgUb}ƬOxFBq@\\[[6SHL!Yg q@F '~ @Gĥ;U,.dk3[k3@Gąu~YK`ven ]G:8 sUھ]tdvVtq@h*h9q@YdZ> ~WH5IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/gridpatternpreview_foreground.png0000644000076500000240000000531512732051204026307 0ustar joshstaffPNG  IHDR Vu\ AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .`rC/q:#d8IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/gridtype_dots_segment.png0000644000076500000240000000527513722612314024544 0ustar joshstaffPNG  IHDRm?h AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .LXNKW$V5@Vl?@'-w \[w_+qIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/gridtype_largedots_segment.png0000644000076500000240000000531613722612314025553 0ustar joshstaffPNG  IHDRm?h AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw . A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf&"IDATxq1 D-{IEi" Wjˌ~I쬾p RǗs9>[>Dل`j.wYJYĂphbQMk,eNV Bl=rH#+І<3RϚ^,B V765Β:7hx:I,X _(u3~f?+eEd`9PmngS*``TDt݆ 9`|kl ~?~Z|˿EI,X aSl9Xz축\,~R|.nvnkҵm61VrIϸ mabMVV/* IY i7g]7FI""e!e%9,XĩSQҴR0pp'?{2Ի\,LbJqRj֣\9yG{-o~)+EQ X,Ҩgt#b̞=*jmx XotñJY]uˣ׆&UF"m0?Gj8܏EI,X !Jq$c4Q~dX#eF VlȦb#g6mAjG;͆=㈕g>üeG3-6(cn!p]e}TzRi$`%8l&r儙*G{ '"XX 9,d5]'>#5/eF V=/pgh;ֵΉC<'IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/pencil_segment.png0000644000076500000240000000532713722612314023134 0ustar joshstaffPNG  IHDR a AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .ܪIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/plus_button_overlay_small.png0000644000076500000240000000530313117663772025455 0ustar joshstaffPNG  IHDR  AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .9皜IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/selection_tool_overlay_add_pattern.png0000644000076500000240000000530313117663772027276 0ustar joshstaffPNG  IHDRH AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .^P^$Sm`x""' 3- mNskw#Cbm CEfqy6GeV_Szq0a[199_@{/Vb;wt,@ `Z[M*T.(Hr&V=`yT\|4пR>TQ@|:݀(W@-rs!F2* ^GrIwLS.$i$_-冃خL1՜\vs[C6PacҊtb@0@NANU`&)$R7XMO*YIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/target_enabled_layers_icon.png0000644000076500000240000000676712777774662025530 0ustar joshstaffPNG  IHDR43 AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw ._RqRèV*Tc'ϦJ} GTeTP4m h$Fq5ƩK~[k[:_cy8t: ̒>hYSYyS2ϴy|2w@QC?~7V%`0ڞjS-R|C}U꫊^^W-ٗP蕐$l< c8Y?{ۍ)t6Ce*X zcl`hr yeÏx0;\ϑ@+~YN)X$򈈈@n `>tfSXI!yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .;a0 h9;تPVIk3G!+ | w%j0tT"0/0|3e20.{mn8SF<`q3Nx80O~GRҖ$38P#*jXtlCzSj +)\a{ݢ(*ql20$8ˇfgOIOۇZ@bfWGK5sy`m۰ DjOURp6PFUak>/^l{wvIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/eraser_button.png0000644000076500000240000000547013722612335024156 0ustar joshstaffPNG  IHDRrP6 AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw . Fk;#,>}]D,.%-ƔI;NR%lQ1IM$p.Xll 8@7'IK3s}p:t68K:<PMq?8NP\J"j^$} bap yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .=o^&C`#w۶y \E`8ު 6Xj:phl`V-SJ]NқmlWr;K]*I=W`VJ~(5`?cwø, Opt̊)Vк^6g SA7dIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/line_button.png0000644000076500000240000000536013722612335023622 0ustar joshstaffPNG  IHDR c AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw . w*x&%E᪪ I[9S+Ksgqzu=1fjK)0֌@̏,"{@>^W9Iwq+".B `VMI]Y)N7|;~.> p5yIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/magnifier_button.png0000644000076500000240000000546413757350652024652 0ustar joshstaffPNG  IHDRĴl; AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .!nVSTuTEJ[Z"kjJ%To'%ylJ|kӄ1IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/magnifier_cursor.png0000644000076500000240000000610413757350652024644 0ustar joshstaffPNG  IHDRw= AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .YX &|=D-qX^WapxJC`P: 0sDҏ0[$]A[Q+ᭀ  η%]% ξ>?]xyQ~3;V;g <8C`N&,Mp@A`zTl n|ETrGc/AefP/[Iܮ-mM\*v$} %sG3u//9o//1% g`EIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/move_button.png0000644000076500000240000000552113722612335023640 0ustar joshstaffPNG  IHDR/8 AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .g{ayƾ8 ?I@}.m_g<'8? .>u-m(jT]?{\ !IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/move_selection_outline_cursor.png0000644000076500000240000000614613722612335027452 0ustar joshstaffPNG  IHDR$c AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .pE'xKzGj )PJl- vc\Jk۝7Qmt\?;mO@@&+h x"6Y[s۫;|/(m7JgR[w\ԾJ׉mCientLYZk3)7xljN{4?>NɃ08rO RľyK`1? 72vXߏ}VvٳQ{ }yf xzOqK:jז{[~uge _>^IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/oval_button.png0000644000076500000240000000544413722612335023637 0ustar joshstaffPNG  IHDR_%.- AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw . tWג§z hIo@́I|€.C=^,p (. Y8,Rw'^sg+lζU@G1;۟$*qELoldp mBjGܢG4ls`kluRD;WlV=U$I#)){ ej` +09++SRf7R^ }'ˤa t JwcCU̖\k^>> Y*qml<ȯн^ t:PEIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/paintcan_button.png0000644000076500000240000000555713722612335024500 0ustar joshstaffPNG  IHDR/8 AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .5KÎp6Q!u\O|eR IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/paintcan_cursor.png0000644000076500000240000000577613722612335024505 0ustar joshstaffPNG  IHDR连 AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .x7Y,FymfI33$=EI_$e%jV.x3Q <ΉsI|788,lvCpWX,D>#]$)tYuf '{`袝+ٛ~ 0ͺP `-xT>g?J2/ n!iIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/pencil_button.png0000644000076500000240000000540613722612335024146 0ustar joshstaffPNG  IHDR nd AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .kX6&.ztBB o$;Upz>if&X텦Pdr-ɴ߉uKYMi˔iWOJ)Ncdo G N>fIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/pencil_cursor.png0000644000076500000240000000553413722612335024152 0ustar joshstaffPNG  IHDRvY߉ AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .88Lu~W;jP4ϧ;TzA] \R},k_"0RN*W)rYkzܶĉ^X~jJ-ӶWp5NrjI"ղ8O+Z/P_ǽAu'xvjx {ulǿT*}8j.o %XrS IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/rect_button.png0000644000076500000240000000533113722612335023626 0ustar joshstaffPNG  IHDRٱ\ AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .V&0{WIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/rect_cursor.png0000644000076500000240000000611213722612335023626 0ustar joshstaffPNG  IHDRe AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .ʒ"BKNLbA%t5zCILLIZ͡'53c1k/p-rcmC[+w n(Ӿy7)R$% "tJXt[jcI9*9l6{?QwTeۍGtIi  ,/wzIPF+Cxg.d2i$5$e"\H3jV@ H]!h4|Eh c zy 5A_)_.& mO rML@7^$YʁWY~\GnoIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/selection_rect_button.png0000644000076500000240000000535713722612335025703 0ustar joshstaffPNG  IHDRٱ\ AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .} :& xcН#)>#$} H<}aS%Km ,`?ӹ{ J+ jY] &^p]wMJh]^dq~ғxЬta `૊/>#\#ߚ\r0 0`C݆Q?\0¾&'t,̀ `}֛1~`?ZIENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/images/tools/wand_button.png0000644000076500000240000000544313722612335023626 0ustar joshstaffPNG  IHDR AiCCPICC ProfileHwXS{o`%!#= 3!{BH0$ eTN*bjR'8(T)"j-V&yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .zްϊ!%$$ݿPˮ}=eï=;I/p47JC+4S*p p'))CbxByhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .yhyI ,,rssy\:}=svMb҅tiؙ"=;<:0 &q\$"R2e<~|Oy'ϵDOo(D푬@- 7/Jsb~? ] #9Ng9kk Ѐd  vO@8 Š l;@ AhA8΃Kn o,AX Q H҃L k9CP @ P2ćDP**:h?} CWA.4 MBBa&TXև-`28^Eny|i Dh!fa"AH,5H)R4 -HҋDs (3#bV֠QuèvT&j5&&h/:Emq C`0>L*fӊ9ČaX  ²Bl1{{{;}#4q8/\,+Un&px9F|~?% NpB*a=BHOxE$"XCH>C\' X}OB cCaRؔ FE8C5RSeo)EE+O+iMKKUЎӆhԕܔJ%J-J7f(*sK[o+WxlSPyR5V QUݣzQ /R;֧6^~AMU#UJƤ&EYYyV)]FO{SZjZ>Z"ZZڅڭt: $*n)]M@f{zx=^N^}(MO |  ] W621Ҍv]7mSL`[nAS)ߴt،dfcl6jN30/40akk͢ⓥee刕UUկlz[ ]ع"EE{ݱlhkg+mӵKe7̠2h{w9:;hxbōǜXNt}b-K#WWA 7#Tn/-m3Lj9ۣԣS3³󡗶WWה*s>hm>þl&)?;~=$0:G@8/p{%zKK:@o+ԇ< - Ň {^>a!莔l򈪌G[DËF^t8⸡eV.\uy 脨# XAto)6ʩLr܉$ʤ'Nۓ'S\RS:TԽ3iAiң[3p ' 4~OF,, ;VL eٝBgOd((qΩy{bJʾ<㼒|WVWuh/]zhM:k֎^wx=a} - + _oU^hlbbA&M{766,,-T)ZfYV]]~+jے¶bVV֡m.WWWm^E*z#~ǕE{wvvkj:kuk~K]^ߺKmWɮݜ7i٫l}}w{ooo>9sqcdc׌,;p&#jG*fQѸ׿Ŭe+8&:ۄo>8w(mP{^TGJ3s.ǮͿ?tJTigg̝?;}.ǺG.D_K^.t+'2v\gmvw .|]n| GC\T{Q*%R_$ww0flj4*Brj~"ݷ!h}saUXӻyndј"_D΁^-;0C7; wv4%";0ߜO#ܸvYYĕLM`ox=o$J!TLy"JImmo?[nRH)xf>s_~B*bvfpB Z7R`lzmfRnf-m6^M$tEMIu7it:]m۾/mXG@ BӪR?B3ZG}cr<@$IENDB`PikoPixel.Sources.1.0-b10b/PikoPixel/Info.plist0000644000076500000240000001005414400204616020122 0ustar joshstaff CFBundleDevelopmentRegion English CFBundleDocumentTypes CFBundleTypeExtensions piko piko-gif piko-jpg piko-jpeg piko-png piko-tif piko-tiff piko-bmp CFBundleTypeIconFile documentIcon.icns CFBundleTypeName PikoPixel Document CFBundleTypeOSTypes Piko CFBundleTypeRole Editor NSDocumentClass PPDocument CFBundleTypeExtensions pikopatr CFBundleTypeIconFile backgroundPatternArchiveIcon.icns CFBundleTypeName PikoPixel Background Patterns Archive CFBundleTypeRole None CFBundleTypeExtensions pikogrid CFBundleTypeIconFile gridPatternArchiveIcon.icns CFBundleTypeName PikoPixel Grid Patterns Archive CFBundleTypeRole None CFBundleTypeExtensions gif CFBundleTypeIconFile CFBundleTypeName GIF Graphic CFBundleTypeRole Editor NSDocumentClass PPDocument CFBundleTypeExtensions jpg jpeg CFBundleTypeIconFile CFBundleTypeName JPEG Graphic CFBundleTypeRole Editor NSDocumentClass PPDocument CFBundleTypeExtensions png CFBundleTypeIconFile CFBundleTypeName PNG Graphic CFBundleTypeRole Editor NSDocumentClass PPDocument CFBundleTypeExtensions tif tiff CFBundleTypeIconFile CFBundleTypeName TIFF Graphic CFBundleTypeRole Editor NSDocumentClass PPDocument CFBundleTypeExtensions bmp CFBundleTypeIconFile CFBundleTypeName BMP Graphic CFBundleTypeRole Editor NSDocumentClass PPDocument CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile appIcon.icns CFBundleIdentifier com.twilightedge.PikoPixel CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleSignature Piko CFBundleShortVersionString 1.0 BETA10b CFBundleVersion 0077 NSMainNibFile MainMenu NSPrincipalClass PPApplication NSRequiresAquaSystemAppearance true PikoPixel.Sources.1.0-b10b/PikoPixel/main.m0000644000076500000240000000210613234403207017254 0ustar joshstaff/* main.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import int main(int argc, char *argv[]) { return NSApplicationMain(argc, (const char **) argv); } PikoPixel.Sources.1.0-b10b/PikoPixel/NSBezierPath_PPUtilities.h0000644000076500000240000000474713234403416023133 0ustar joshstaff/* NSBezierPath_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSBezierPath (PPUtilities) - (void) ppAppendSinglePixelLineAtPoint: (NSPoint) point; - (void) ppAppendLineFromPixelAtPoint: (NSPoint) startPoint toPixelAtPoint: (NSPoint) endPoint; - (void) ppLineToPixelAtPoint: (NSPoint) point; - (void) ppSetLastLineEndPointToPixelAtPoint: (NSPoint) point; - (void) ppAppendZeroLengthLineAtLastLineEndPoint; - (bool) ppRemoveLastLineStartPointAndGetPreviousStartPoint: (NSPoint *) returnedStartPoint; - (void) ppAppendPixelColumnSeparatorLinesInBounds: (NSRect) bounds; - (void) ppAppendPixelRowSeparatorLinesInBounds: (NSRect) bounds; - (void) ppAntialiasedFill; + (NSBezierPath *) ppPixelatedBezierPathWithOvalInRect: (NSRect) rect; @end @interface NSBezierPath (PPUtilities_MaskBitmapPaths) + (void) ppAppendOutlinePathsForMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) bounds toTopRightBezierPath: (NSBezierPath *) topRightPath andBottomLeftBezierPath: (NSBezierPath *) bottomLeftPath; - (void) ppAppendOutlinePathForMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) bounds; - (void) ppAppendRightEdgePathForMaskBitmap: (NSBitmapImageRep *) maskBitmap; - (void) ppAppendBottomEdgePathForMaskBitmap: (NSBitmapImageRep *) maskBitmap; - (void) ppAppendFillPathForMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) bounds; - (void) ppAppendXMarksForUnmaskedPixelsInMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) bounds; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSBezierPath_PPUtilities.m0000644000076500000240000003511013234403205023120 0ustar joshstaff/* NSBezierPath_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSBezierPath_PPUtilities.h" #import "PPGeometry.h" @implementation NSBezierPath (PPUtilities) - (void) ppAppendSinglePixelLineAtPoint: (NSPoint) point { point = PPGeometry_PixelCenteredPoint(point); // the slightly-offset (+0.25, +0.25) line element prevents [self bounds] from returning // an empty rect [self moveToPoint: point]; [self lineToPoint: NSMakePoint(point.x + 0.25f, point.y + 0.25f)]; [self lineToPoint: point]; } - (void) ppAppendLineFromPixelAtPoint: (NSPoint) startPoint toPixelAtPoint: (NSPoint) endPoint { startPoint = PPGeometry_PixelCenteredPoint(startPoint); endPoint = PPGeometry_PixelCenteredPoint(endPoint); [self moveToPoint: startPoint]; if ((startPoint.x == endPoint.x) || (startPoint.y == endPoint.y)) { // the slightly-offset (+0.25, +0.25) line element prevents [self bounds] from // returning an empty rect (horizontal or vertical lines have a zero dimension) [self lineToPoint: NSMakePoint(startPoint.x + 0.25f, startPoint.y + 0.25f)]; [self lineToPoint: startPoint]; } if (!NSEqualPoints(startPoint, endPoint)) { [self lineToPoint: endPoint]; } } - (void) ppLineToPixelAtPoint: (NSPoint) point { [self lineToPoint: PPGeometry_PixelCenteredPoint(point)]; } - (void) ppSetLastLineEndPointToPixelAtPoint: (NSPoint) point { NSInteger indexOfLastElement; point = PPGeometry_PixelCenteredPoint(point); indexOfLastElement = [self elementCount] - 1; if ((indexOfLastElement < 0) || ([self elementAtIndex: indexOfLastElement] != NSLineToBezierPathElement)) { goto ERROR; } [self setAssociatedPoints: &point atIndex: indexOfLastElement]; return; ERROR: return; } - (void) ppAppendZeroLengthLineAtLastLineEndPoint { NSInteger indexOfLastElement; NSPoint lastPoints[3]; indexOfLastElement = [self elementCount] - 1; if ((indexOfLastElement < 0) || ([self elementAtIndex: indexOfLastElement associatedPoints: lastPoints] != NSLineToBezierPathElement)) { goto ERROR; } [self lineToPoint: lastPoints[0]]; return; ERROR: return; } - (bool) ppRemoveLastLineStartPointAndGetPreviousStartPoint: (NSPoint *) returnedStartPoint { NSInteger indexOfElementToCopy, indexOfLastElementToOverwrite, index; NSPoint copyPoints[3], overwritePoints[3]; // removes the last line segment by overwriting the next-to-last lineTo element's point // (start point of the last line segment) with the point from the next previous different // element - since there's no way to delete elements from an NSBezierPath, this procedure // leaves 'removed' elements in place as zero-length lines, so it may need to scan through // one or more zero-length line elements (left by previous removals) to find one with a // different start point (each zero-length lineTo element's point will also have to be // overwritten with the updated start point) indexOfLastElementToOverwrite = [self elementCount] - 2; if (indexOfLastElementToOverwrite < 1) { goto ERROR; } if ([self elementAtIndex: indexOfLastElementToOverwrite associatedPoints: overwritePoints] != NSLineToBezierPathElement) { goto ERROR; } indexOfElementToCopy = indexOfLastElementToOverwrite; copyPoints[0] = overwritePoints[0]; while (NSEqualPoints(copyPoints[0], overwritePoints[0])) { if ((--indexOfElementToCopy < 0) || ([self elementAtIndex: indexOfElementToCopy associatedPoints: copyPoints] != NSLineToBezierPathElement)) { goto ERROR; } } for (index=indexOfElementToCopy+1; index<=indexOfLastElementToOverwrite; index++) { [self setAssociatedPoints: copyPoints atIndex: index]; } if (returnedStartPoint) { *returnedStartPoint = PPGeometry_PointClippedToIntegerValues(copyPoints[0]); } return YES; ERROR: return NO; } - (void) ppAppendPixelColumnSeparatorLinesInBounds: (NSRect) bounds { CGFloat firstCol, lastCol, topRow, bottomRow, col; bounds = PPGeometry_PixelBoundsCoveredByRect(bounds); firstCol = NSMinX(bounds) + 1.0; lastCol = NSMaxX(bounds) - 1.0; topRow = NSMaxY(bounds); bottomRow = NSMinY(bounds); for (col=firstCol; col<=lastCol; col+=1.0) { [self moveToPoint: NSMakePoint(col, topRow)]; [self lineToPoint: NSMakePoint(col, bottomRow)]; } } - (void) ppAppendPixelRowSeparatorLinesInBounds: (NSRect) bounds { CGFloat firstRow, lastRow, leftCol, rightCol, row; bounds = PPGeometry_PixelBoundsCoveredByRect(bounds); firstRow = NSMinY(bounds) + 1.0; lastRow = NSMaxY(bounds) - 1.0; leftCol = NSMinX(bounds); rightCol = NSMaxX(bounds); for (row=firstRow; row<=lastRow; row+=1.0) { [self moveToPoint: NSMakePoint(leftCol, row)]; [self lineToPoint: NSMakePoint(rightCol, row)]; } } - (void) ppAntialiasedFill { NSGraphicsContext *currentContext; bool oldShouldAntialias; currentContext = [NSGraphicsContext currentContext]; oldShouldAntialias = [currentContext shouldAntialias]; [currentContext setShouldAntialias: YES]; [self fill]; [currentContext setShouldAntialias: oldShouldAntialias]; } // A pixelated path is a path with well-defined pixel boundaries - it's made up exclusively of // horizontal, vertical, or 1:1 diagonal line-elements, each with pixel-centered endpoints - // this prevents interpolation/roundoff issues from curve elements or differently-sloped lines, // which can cause the path's fill area to have a slightly different shape than a stroke of the // same path (due to some additional or missing pixels along the path's edges). + (NSBezierPath *) ppPixelatedBezierPathWithOvalInRect: (NSRect) rect { NSBezierPath *path; NSPoint *arcPoints = NULL, centerPoint, offsetToCenterOfPixel, diagonalTangentPoint, arcPoint, pixelEdgePoint; NSSize arcSize, arcSizeSquared; int numArcPoints = 0, maxNumArcPoints, i; float arcHorizontalAspectRatio, arcVerticalAspectRatio, cosArctanOfVerticalAspectRatio, pixelTopEdgeIntersectionPos; bool arcIsCircular = NO, arcIsTransposed = NO; rect = PPGeometry_PixelCenteredRect(rect); if ((rect.size.width <= 1) || (rect.size.height <= 1)) { return [self bezierPathWithRect: rect]; } path = [NSBezierPath bezierPath]; if (!path) goto ERROR; centerPoint = PPGeometry_CenterOfRect(rect); offsetToCenterOfPixel = NSMakePoint((centerPoint.x == floorf(centerPoint.x)) ? 0.5f : 0.0f, (centerPoint.y == floorf(centerPoint.y)) ? 0.5f : 0.0f); arcSize = NSMakeSize(NSMaxX(rect) - centerPoint.x, NSMaxY(rect) - centerPoint.y); if (arcSize.height == arcSize.width) { arcIsCircular = YES; } else if (arcSize.height > arcSize.width) { // 'tall' non-circular arcs are calculated using transposed geometry (coordinates are // flipped diagonally) - a single codepath for calculating arcs with the same dimensions // but different rotations ([w,h] vs. [h,w]) prevents shape mismatches when rotating // because both orientations share the same roundoff errors arcSize = NSMakeSize(arcSize.height, arcSize.width); offsetToCenterOfPixel = NSMakePoint(offsetToCenterOfPixel.y, offsetToCenterOfPixel.x); arcIsTransposed = YES; } arcSizeSquared = NSMakeSize(arcSize.width * arcSize.width, arcSize.height * arcSize.height); arcHorizontalAspectRatio = arcSize.width / arcSize.height; arcVerticalAspectRatio = arcSize.height / arcSize.width; // rough upper-bounds for maximum expected number of arc points - verified for rects in // the size range, ([3 - 6000],[3 - 6000]) maxNumArcPoints = ceilf(arcSize.height * (2.0f - arcVerticalAspectRatio)) + 8; arcPoints = (NSPoint *) malloc (sizeof(NSPoint) * maxNumArcPoints); if (!arcPoints) goto ERROR; // diagonalTangentPoint: point on the arc where the tangent is 1:1 diagonal, determines // where to switch from drawing vertical lines to horizonal lines cosArctanOfVerticalAspectRatio = 1.0f / sqrtf(1.0f + arcVerticalAspectRatio * arcVerticalAspectRatio); diagonalTangentPoint = NSMakePoint(arcSize.width * cosArctanOfVerticalAspectRatio, arcSize.height * arcVerticalAspectRatio * cosArctanOfVerticalAspectRatio); arcPoint = NSMakePoint(arcSize.width, 0.0f); pixelEdgePoint.x = arcPoint.x - 0.5f; pixelEdgePoint.y = arcPoint.y + offsetToCenterOfPixel.y + 0.5f; pixelTopEdgeIntersectionPos = ceilf(sqrtf(arcSizeSquared.height - pixelEdgePoint.y * pixelEdgePoint.y) * arcHorizontalAspectRatio - offsetToCenterOfPixel.x) + offsetToCenterOfPixel.x; if (pixelTopEdgeIntersectionPos < arcPoint.x) { arcPoints[numArcPoints++] = arcPoint; if (offsetToCenterOfPixel.y) { arcPoint.y += offsetToCenterOfPixel.y; arcPoints[numArcPoints++] = arcPoint; } arcPoint.x = pixelTopEdgeIntersectionPos; arcPoints[numArcPoints++] = arcPoint; arcPoint.x -= 1.0f; arcPoint.y += 1.0f; pixelEdgePoint.x -= 1.0f; } while (arcPoint.x > diagonalTangentPoint.x) { arcPoints[numArcPoints++] = arcPoint; arcPoint.y = ceilf(sqrtf(arcSizeSquared.width - pixelEdgePoint.x * pixelEdgePoint.x) * arcVerticalAspectRatio - 1.0f - offsetToCenterOfPixel.y) + offsetToCenterOfPixel.y; if (arcPoint.y > diagonalTangentPoint.y) { arcPoint.y -= 1.0f; } if (arcPoint.y < arcPoints[numArcPoints-1].y) { arcPoint.y = arcPoints[numArcPoints-1].y; } if (arcPoint.y != arcPoints[numArcPoints-1].y) { arcPoints[numArcPoints++] = arcPoint; } arcPoint.x -= 1.0f; arcPoint.y += 1.0f; pixelEdgePoint.x -= 1.0f; } if (arcIsCircular) { int arcPointIndex; if (arcPoint.x >= arcPoint.y) { arcPoints[numArcPoints++] = arcPoint; } arcPointIndex = numArcPoints - 1; if (arcPoints[arcPointIndex].x == arcPoints[arcPointIndex].y) { arcPointIndex--; } while (arcPointIndex > 0) { arcPoint = NSMakePoint(arcPoints[arcPointIndex].y, arcPoints[arcPointIndex].x); arcPoints[numArcPoints++] = arcPoint; arcPointIndex--; } arcPoint = NSMakePoint(arcPoints[arcPointIndex].y, arcPoints[arcPointIndex].x); } pixelEdgePoint.y = arcPoint.y + 0.5f; while (arcPoint.y < arcSize.height) { arcPoints[numArcPoints++] = arcPoint; arcPoint.x = ceilf(sqrtf(arcSizeSquared.height - pixelEdgePoint.y * pixelEdgePoint.y) * arcHorizontalAspectRatio - offsetToCenterOfPixel.x) + offsetToCenterOfPixel.x; if (arcPoint.x > arcPoints[numArcPoints-1].x) { arcPoint.x = arcPoints[numArcPoints-1].x; } if (arcPoint.x != arcPoints[numArcPoints-1].x) { arcPoints[numArcPoints++] = arcPoint; } arcPoint.x -= 1.0f; arcPoint.y += 1.0f; pixelEdgePoint.y += 1.0f; } arcPoints[numArcPoints++] = arcPoint; arcPoint = NSMakePoint(0.0f, arcSize.height); if (!NSEqualPoints(arcPoint, arcPoints[numArcPoints-1])) { arcPoints[numArcPoints++] = arcPoint; } if (arcIsTransposed) { int index1, index2, index1Cutoff; NSPoint tempPoint; // flip the transposed arc back to its desired orientation by reversing the order of the // arcPoints array & swapping each point's x & y coordinates // index1Cutoff's value includes the array's middle entry (if there is one) in the // reordering/swapping loop - the middle point doesn't need reordering, but its x & y // coordinates need to be swapped index1Cutoff = (numArcPoints + 1) / 2; for (index1=0, index2=numArcPoints-1; index1=0; i--) { [path lineToPoint: NSMakePoint(centerPoint.x - arcPoints[i].x, centerPoint.y + arcPoints[i].y)]; } for (i=1; i=0; i--) { [path lineToPoint: NSMakePoint(centerPoint.x + arcPoints[i].x, centerPoint.y - arcPoints[i].y)]; } free(arcPoints); return path; ERROR: if (arcPoints) { free(arcPoints); } return nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSBezierPath_PPUtilities_MaskBitmapPaths.m0000644000076500000240000006534513234403205026245 0ustar joshstaff/* NSBezierPath_PPUtilities_MaskBitmapPaths.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSBezierPath_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" #pragma mark Macros & definitions for +ppAppendOutlinePathsForMaskBitmap:... method //*******************************************************************************************/ // +ppAppendOutlinePathsForMaskBitmap:... method appends paths that can be used to draw an // animated, continuous "marching ants" outline around the selected (nonzero) pixels in a // 1-channel mask bitmap. // // PPCanvasView currently animates the selection outline using a pattern color, so the // outline needs to be in two separate paths in order for the "marching ants" motion to appear // continuous (horizontal lines on top need to move to the right, and move to the left on the // bottom); If a single closed path is animated by offsetting a pattern color, all parallel // lines will move in the same direction and won't appear continuous - the "ants" would appear // to be coming out of some corners in both directions, then disappearing into opposite corners. // // The outline paths are calculated by scanning the mask bitmap two rows at a time, examining // 4 pixels at once (2x2 grid) for patterns of pixels that should be represented as corners on // the outline. Neighboring corners are then connected by adding vertical or horizontal lines // to the appropriate path. // // An outline corner's type (the direction the outline takes into and out of the corner's // vertex) is used to determine the particular set of lines to add to the outline path(s). // The corner type is calculated by converting the 4 mask-pixel values into a 4-bit bitmask; // The mask's 16 possible values are then used to index into a lookup table, // kCornerTypeFor2x2PixelBitMask[], which matches the bitmask pattern to one of 11 possible // types of corners (several pixel patterns result in "NotACorner"). The corner type is // represented by the enum, PPCornerType. //*******************************************************************************************/ // macroShiftMaskPixelsInto2x2BitMask(): Macro to convert a 2x2 grid of mask pixel values into // a bitmask, with each bit representing whether the pixel's value is nonzero. The bitfields // are: // +---+---+ // | 2 | 0 | // +---+---+ // | 3 | 1 | // +---+---+ // The macro shifts in two pixel values at a time from the right side, as pixelValueAbove & // pixelValueBelow (0 & 1), shifting the previous right column to the left (0 -> 2, 1 -> 3). #define macroShiftMaskPixelsInto2x2BitMask(mask, pixelValueAbove, pixelValueBelow) \ { \ mask = (mask << 2) & 0x0F; \ if (pixelValueAbove) mask |= 1; \ if (pixelValueBelow) mask |= 2; \ } //*******************************************************************************************/ // PPCornerType enumerates the 11 possible types of outline path corners: // (L=Left, R=Right, T=Top, B=Bottom, N/C=NotACorner) // // N/C L-B T-L R-T B-R B-L R-B T-R L-T LB,RT TL,BR // | ^ | ^ ^ | // -+ <+ +- +> <+ +- +> -+ -+- <+> // v | | v v | typedef enum { kPPCornerType_NotACorner, kPPCornerType_LeftToBottom, kPPCornerType_TopToLeft, kPPCornerType_RightToTop, kPPCornerType_BottomToRight, kPPCornerType_BottomToLeft, kPPCornerType_RightToBottom, kPPCornerType_TopToRight, kPPCornerType_LeftToTop, kPPCornerType_LeftToBottom_RightToTop, kPPCornerType_TopToLeft_BottomToRight, } PPCornerType; //*******************************************************************************************/ // kCornerTypeFor2x2PixelBitMask[] is a lookup table for coverting the 16 possible values of // the mask-pixel 2x2 bitmask into one of the 11 possible corner types: // (@=Selected (nonzero) pixel, .=Unselected pixel) // // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // . . .^@ . . .|@ @|. @ @ @|. @ @ . . .^@ . . .^@ @|. @ @ @|. @ @ // +- +> | <+ --- <+> <+ -+ -+- --- -+ | +- +> // . . . . .|@ .|@ . . . . .|@ .|@ @v. @v. @ @ @ @ @|. @v. @ @ @ @ // N/C R-T B-R N/C T-L N/C TL,BR B-L L-B LB,RT N/C L-T N/C R-B T-R N/C const int kCornerTypeFor2x2PixelBitMask[16] = { kPPCornerType_NotACorner, kPPCornerType_RightToTop, kPPCornerType_BottomToRight, kPPCornerType_NotACorner, kPPCornerType_TopToLeft, kPPCornerType_NotACorner, kPPCornerType_TopToLeft_BottomToRight, kPPCornerType_BottomToLeft, kPPCornerType_LeftToBottom, kPPCornerType_LeftToBottom_RightToTop, kPPCornerType_NotACorner, kPPCornerType_LeftToTop, kPPCornerType_NotACorner, kPPCornerType_RightToBottom, kPPCornerType_TopToRight, kPPCornerType_NotACorner }; //*******************************************************************************************/ // Horizontal-line macros for +ppAppendOutlinePathsForMaskBitmap:... method #define macroSaveCurrentPointAsHorizontalLineEndpoint \ { \ horizontalLineEndpoint = currentPoint.x; \ } #define macroHorizontalLineEndpoint \ (NSMakePoint(horizontalLineEndpoint, currentPoint.y)) #define macroAddHorizontalLineRightToCurrentPoint \ { \ [topRightPath moveToPoint: macroHorizontalLineEndpoint]; \ [topRightPath lineToPoint: currentPoint]; \ } #define macroAddHorizontalLineLeftFromCurrentPoint \ { \ [bottomLeftPath moveToPoint: currentPoint]; \ [bottomLeftPath lineToPoint: macroHorizontalLineEndpoint]; \ } //*******************************************************************************************/ // Vertical-line macros for +ppAppendOutlinePathsForMaskBitmap:... method #define macroSaveCurrentPointAsVerticalLineEndpoint \ { \ verticalLineEndpoints[currentCol] = currentPoint.y; \ } #define macroVerticalLineEndpoint \ (NSMakePoint(currentPoint.x, verticalLineEndpoints[currentCol])) #define macroAddVerticalLineDownToCurrentPoint \ { \ [topRightPath moveToPoint: macroVerticalLineEndpoint]; \ [topRightPath lineToPoint: currentPoint]; \ } #define macroAddVerticalLineUpFromCurrentPoint \ { \ [bottomLeftPath moveToPoint: currentPoint]; \ [bottomLeftPath lineToPoint: macroVerticalLineEndpoint]; \ } //*******************************************************************************************/ // macroHandleCornerTypeAtCurrentPoint(): Macro for +ppAppendOutlinePathsForMaskBitmap:... // method which handles adding lines to the appropriate path or storing line endpoints for // later use, depending on the current point's corner type #define macroHandleCornerTypeAtCurrentPoint(cornerType) \ { \ switch (cornerType) \ { \ case kPPCornerType_NotACorner: \ break; \ \ case kPPCornerType_LeftToBottom: \ macroAddHorizontalLineRightToCurrentPoint; \ macroSaveCurrentPointAsVerticalLineEndpoint; \ break; \ \ case kPPCornerType_TopToLeft: \ macroAddVerticalLineDownToCurrentPoint; \ macroAddHorizontalLineLeftFromCurrentPoint; \ break; \ \ case kPPCornerType_RightToTop: \ macroSaveCurrentPointAsHorizontalLineEndpoint; \ macroAddVerticalLineUpFromCurrentPoint; \ break; \ \ case kPPCornerType_BottomToRight: \ macroSaveCurrentPointAsVerticalLineEndpoint; \ macroSaveCurrentPointAsHorizontalLineEndpoint; \ break; \ \ case kPPCornerType_BottomToLeft: \ macroSaveCurrentPointAsVerticalLineEndpoint; \ macroAddHorizontalLineLeftFromCurrentPoint; \ break; \ \ case kPPCornerType_RightToBottom: \ macroSaveCurrentPointAsHorizontalLineEndpoint; \ macroSaveCurrentPointAsVerticalLineEndpoint; \ break; \ \ case kPPCornerType_TopToRight: \ macroAddVerticalLineDownToCurrentPoint; \ macroSaveCurrentPointAsHorizontalLineEndpoint; \ break; \ \ case kPPCornerType_LeftToTop: \ macroAddHorizontalLineRightToCurrentPoint; \ macroAddVerticalLineUpFromCurrentPoint; \ break; \ \ case kPPCornerType_LeftToBottom_RightToTop: \ macroAddHorizontalLineRightToCurrentPoint; \ macroAddVerticalLineUpFromCurrentPoint; \ macroSaveCurrentPointAsHorizontalLineEndpoint; \ macroSaveCurrentPointAsVerticalLineEndpoint; \ break; \ \ case kPPCornerType_TopToLeft_BottomToRight: \ macroAddVerticalLineDownToCurrentPoint; \ macroAddHorizontalLineLeftFromCurrentPoint; \ macroSaveCurrentPointAsHorizontalLineEndpoint; \ macroSaveCurrentPointAsVerticalLineEndpoint; \ break; \ \ default: \ break; \ } \ } @implementation NSBezierPath (PPUtilities_MaskBitmapPaths) + (void) ppAppendOutlinePathsForMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) bounds toTopRightBezierPath: (NSBezierPath *) topRightPath andBottomLeftBezierPath: (NSBezierPath *) bottomLeftPath { static float *verticalLineEndpoints = NULL; static int numVerticalLineEndpoints = 0; float horizontalLineEndpoint = 0; NSRect bitmapFrame; int bytesPerRow, rowOffset, dataOffset, startCol, endCol, numRows, numInteriorRows, rowCounter, currentCol, pixelValues2x2BitMask; NSPoint currentPoint; unsigned char *maskData, *currentRowAbove, *currentRowBelow; PPMaskBitmapPixel *currentPixelAbove, *currentPixelBelow; if (![maskBitmap ppIsMaskBitmap]) { goto ERROR; } bitmapFrame = [maskBitmap ppFrameInPixels]; bounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(bounds), bitmapFrame); if (NSIsEmptyRect(bounds)) { goto ERROR; } if (!verticalLineEndpoints || (numVerticalLineEndpoints <= ((int) bitmapFrame.size.width))) { int requiredNumVerticalLineEndpoints = bitmapFrame.size.width + 1; if (verticalLineEndpoints) { free(verticalLineEndpoints); verticalLineEndpoints = NULL; numVerticalLineEndpoints = 0; } verticalLineEndpoints = (float *) malloc (requiredNumVerticalLineEndpoints * sizeof(float)); if (!verticalLineEndpoints) goto ERROR; numVerticalLineEndpoints = requiredNumVerticalLineEndpoints; } maskData = [maskBitmap bitmapData]; if (!maskData) goto ERROR; bytesPerRow = [maskBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - bounds.size.height - bounds.origin.y; dataOffset = rowOffset * bytesPerRow + (int) bounds.origin.x * sizeof(PPMaskBitmapPixel); currentRowAbove = NULL; currentRowBelow = &maskData[dataOffset]; startCol = bounds.origin.x; endCol = startCol + bounds.size.width; numRows = bounds.size.height; numInteriorRows = (numRows > 1) ? numRows - 1 : 0; // TOP ROW currentPixelBelow = (PPMaskBitmapPixel *) currentRowBelow; currentPoint = NSMakePoint(bounds.origin.x, bounds.origin.y + bounds.size.height); pixelValues2x2BitMask = 0; for (currentCol=startCol; currentCol=bottomRow; row--) { maskPixel = (PPMaskBitmapPixel *) maskRow; col = startCol; while (col <= endCol) { if (*maskPixel) { fillBeginCol = col; maskPixel++; col++; while ((col <= endCol) && *maskPixel) { maskPixel++; col++; } fillRect = NSMakeRect(fillBeginCol, row, col - fillBeginCol, 1); [self appendBezierPathWithRect: fillRect]; } maskPixel++; col++; } maskRow += maskBytesPerRow; } return; ERROR: return; } - (void) ppAppendXMarksForUnmaskedPixelsInMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) bounds { NSRect bitmapFrame; unsigned char *maskData, *maskRow; int maskBytesPerRow, rowOffset, maskDataOffset, topRow, bottomRow, startCol, endCol, row, col; PPMaskBitmapPixel *maskPixel; if (![maskBitmap ppIsMaskBitmap]) { goto ERROR; } bitmapFrame = [maskBitmap ppFrameInPixels]; bounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(bounds), bitmapFrame); if (NSIsEmptyRect(bounds)) { goto ERROR; } maskData = [maskBitmap bitmapData]; if (!maskData) goto ERROR; maskBytesPerRow = [maskBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - bounds.size.height - bounds.origin.y; maskDataOffset = rowOffset * maskBytesPerRow + (int) bounds.origin.x * sizeof(PPMaskBitmapPixel); maskRow = &maskData[maskDataOffset]; bottomRow = bounds.origin.y; topRow = bottomRow + bounds.size.height - 1; startCol = bounds.origin.x; endCol = startCol + bounds.size.width - 1; for (row=topRow; row>=bottomRow; row--) { maskPixel = (PPMaskBitmapPixel *) maskRow; col = startCol; while (col <= endCol) { if (!*maskPixel) { [self moveToPoint: NSMakePoint(col, row)]; [self lineToPoint: NSMakePoint(col+1, row+1)]; [self moveToPoint: NSMakePoint(col, row+1)]; [self lineToPoint: NSMakePoint(col+1, row)]; } maskPixel++; col++; } maskRow += maskBytesPerRow; } return; ERROR: return; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSBitmapImageRep_PPUtilities.h0000644000076500000240000002504113234403416023712 0ustar joshstaff/* NSBitmapImageRep_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "NSImageRep_PPUtilities.h" #import "PPBitmapPixelTypes.h" #import "PPGridType.h" @interface NSBitmapImageRep (PPUtilities) - (bool) ppIsEqualToBitmap: (NSBitmapImageRep *) comparisonBitmap; - (bool) ppImportedBitmapHasAnimationFrames; - (NSData *) ppCompressedTIFFData; - (NSData *) ppCompressedTIFFDataFromBounds: (NSRect) bounds; - (NSData *) ppCompressedPNGData; - (void) ppSetAsCurrentGraphicsContext; - (void) ppRestoreGraphicsContext; - (void) ppClearBitmap; - (void) ppClearBitmapInBounds: (NSRect) bounds; - (void) ppCopyFromBitmap: (NSBitmapImageRep *) sourceBitmap toPoint: (NSPoint) targetPoint; - (void) ppCopyFromBitmap: (NSBitmapImageRep *) sourceBitmap inRect: (NSRect) sourceRect toPoint: (NSPoint) targetPoint; - (void) ppCenteredCopyFromBitmap: (NSBitmapImageRep *) sourceBitmap; - (NSBitmapImageRep *) ppBitmapCroppedToBounds: (NSRect) croppingBounds; // ppShallowDuplicateFromBounds: returns an autoreleased copy that uses the same bitmapData // pointer as the original (depending on croppingBounds, it may be offset). // It's faster than ppBitmapCroppedToBounds:, which allocates a new buffer and copies the // bitmapData. It should generally be used where the copy is just for reading, as writing to // the copy's bitmapData will overwrite the original's. The copy should not outlive the // original, as the copy's bitmapData pointer will become invalid when the original is // deallocated. - (NSBitmapImageRep *) ppShallowDuplicateFromBounds: (NSRect) croppingBounds; - (NSBitmapImageRep *) ppBitmapResizedToSize: (NSSize) newSize shouldScale: (bool) shouldScale; - (NSBitmapImageRep *) ppBitmapMirroredHorizontally; - (NSBitmapImageRep *) ppBitmapMirroredVertically; - (NSBitmapImageRep *) ppBitmapRotated90Clockwise; - (NSBitmapImageRep *) ppBitmapRotated90Counterclockwise; - (NSBitmapImageRep *) ppBitmapRotated180; @end @interface NSBitmapImageRep (PPUtilities_ImageBitmaps) + (NSBitmapImageRep *) ppImageBitmapOfSize: (NSSize) size; + (NSBitmapImageRep *) ppImageBitmapWithImportedData: (NSData *) importedData; + (NSBitmapImageRep *) ppImageBitmapFromImageResource: (NSString *) imageName; - (bool) ppIsImageBitmap; - (bool) ppIsImageBitmapAndSameSizeAsMaskBitmap: (NSBitmapImageRep *) maskBitmap; - (NSColor *) ppImageColorAtPoint: (NSPoint) point; - (bool) ppImageBitmapHasTransparentPixels; - (void) ppMaskedFillUsingMask: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) fillBounds fillPixelValue: (PPImageBitmapPixel) fillPixelValue; - (void) ppMaskedEraseUsingMask: (NSBitmapImageRep *) maskBitmap; - (void) ppMaskedEraseUsingMask: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) eraseBounds; - (void) ppMaskedCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap usingMask: (NSBitmapImageRep *) maskBitmap; - (void) ppMaskedCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap usingMask: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) copyBounds; - (void) ppMaskedCopyFromImageBitmap:(NSBitmapImageRep *) sourceBitmap usingMask: (NSBitmapImageRep *) maskBitmap toPoint: (NSPoint) targetPoint; - (void) ppScaledCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap inRect: (NSRect) sourceRect toPoint: (NSPoint) destinationPoint scalingFactor: (unsigned) scalingFactor; - (void) ppScaledCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap inRect: (NSRect) sourceRect toPoint: (NSPoint) destinationPoint scalingFactor: (unsigned) scalingFactor gridType: (PPGridType) gridType gridPixelValue: (PPImageBitmapPixel) gridPixelValue; - (NSBitmapImageRep *) ppImageBitmapWithMaxDimension: (float) maxDimension; - (NSBitmapImageRep *) ppImageBitmapCompositedWithBackgroundColor: (NSColor *) backgroundColor andBackgroundImage: (NSImage *) backgroundImage backgroundImageInterpolation: (NSImageInterpolation) backgroundImageInterpolation; - (NSBitmapImageRep *) ppImageBitmapDissolvedToOpacity: (float) opacity; - (NSBitmapImageRep *) ppImageBitmapMaskedWithMask: (NSBitmapImageRep *) maskBitmap; - (NSBitmapImageRep *) ppImageBitmapScaledByFactor: (unsigned) scalingFactor shouldDrawGrid: (bool) shouldDrawGrid gridType: (PPGridType) gridType gridColor: (NSColor *) gridColor; - (NSBitmapImageRep *) ppMaskBitmapForVisiblePixelsInImageBitmap; - (void) ppDrawImageGuidelinesInBounds: (NSRect) drawBounds topLeftPhase: (NSPoint) topLeftPhase unscaledSpacingSize: (NSSize) unscaledSpacingSize scalingFactor: (unsigned) scalingFactor guidelinePixelValue: (PPImageBitmapPixel) guidelinePixelValue; @end @interface NSBitmapImageRep (PPUtilities_LinearRGB16Bitmaps) + (NSBitmapImageRep *) ppLinearRGB16BitmapOfSize: (NSSize) size; - (NSBitmapImageRep *) ppLinearRGB16BitmapFromImageBitmap; - (NSBitmapImageRep *) ppImageBitmapFromLinearRGB16Bitmap; - (bool) ppIsLinearRGB16Bitmap; - (void) ppLinearCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap inBounds: (NSRect) bounds; - (void) ppLinearCopyToImageBitmap: (NSBitmapImageRep *) destinationBitmap inBounds: (NSRect) bounds; - (void) ppLinearBlendFromLinearBitmapUnderneath: (NSBitmapImageRep *) sourceBitmap sourceOpacity: (float) sourceOpacity inBounds: (NSRect) blendingBounds; - (void) ppLinearCopyFromLinearBitmap: (NSBitmapImageRep *) sourceBitmap opacity: (float) opacity inBounds: (NSRect) copyBounds; @end @interface NSBitmapImageRep (PPUtilities_MaskBitmaps) + (NSBitmapImageRep *) ppMaskBitmapOfSize: (NSSize) size; - (bool) ppIsMaskBitmap; - (NSRect) ppMaskBounds; - (NSRect) ppMaskBoundsInRect: (NSRect) bounds; - (bool) ppMaskIsNotEmpty; - (bool) ppMaskCoversAllPixels; - (bool) ppMaskCoversPoint: (NSPoint) point; - (void) ppMaskPixelsInBounds: (NSRect) bounds; - (void) ppIntersectMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap; - (void) ppIntersectMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) intersectBounds; - (void) ppSubtractMaskBitmap: (NSBitmapImageRep *) maskBitmap; - (void) ppSubtractMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) subtractBounds; - (void) ppMergeMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap; - (void) ppMergeMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) mergeBounds; - (void) ppInvertMaskBitmap; - (void) ppCloseHolesInMaskBitmap; - (void) ppThresholdMaskBitmapPixelValues; - (void) ppThresholdMaskBitmapPixelValuesInBounds: (NSRect) bounds; @end @interface NSBitmapImageRep (PPUtilities_PatternBitmaps) + (NSBitmapImageRep *) ppCheckerboardPatternBitmapWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSBitmapImageRep *) ppDiagonalCheckerboardPatternBitmapWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSBitmapImageRep *) ppIsometricCheckerboardPatternBitmapWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSBitmapImageRep *) ppDiagonalLinePatternBitmapWithLineWidth: (float) lineWidth color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSBitmapImageRep *) ppIsometricLinePatternBitmapWithLineWidth: (float) lineWidth color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSBitmapImageRep *) ppHorizontalGradientPatternBitmapWithWidth: (unsigned) width leftColor: (NSColor *) leftColor rightColor: (NSColor *) rightColor; + (NSBitmapImageRep *) ppVerticalGradientPatternBitmapWithHeight: (unsigned) height topColor: (NSColor *) topColor bottomColor: (NSColor *) bottomColor; + (NSBitmapImageRep *) ppCenteredVerticalGradientPatternBitmapWithHeight: (unsigned) height innerColor: (NSColor *) innerColor outerColor: (NSColor *) outerColor; + (NSBitmapImageRep *) ppFillOverlayPatternBitmapWithSize: (float) patternSize fillColor: (NSColor *) fillColor; @end @interface NSBitmapImageRep (PPUtilities_ColorMasking) - (void) ppMaskNeighboringPixelsMatchingColorAtPoint: (NSPoint) point inImageBitmap: (NSBitmapImageRep *) sourceBitmap colorMatchTolerance: (unsigned) colorMatchTolerance selectionMask: (NSBitmapImageRep *) selectionMask selectionMaskBounds: (NSRect) selectionMaskBounds matchDiagonally: (bool) matchDiagonally; - (void) ppMaskAllPixelsMatchingColorAtPoint: (NSPoint) point inImageBitmap: (NSBitmapImageRep *) sourceBitmap colorMatchTolerance: (unsigned) colorMatchTolerance selectionMask: (NSBitmapImageRep *) selectionMask selectionMaskBounds: (NSRect) selectionMaskBounds; - (void) ppMaskVisiblePixelsInImageBitmap: (NSBitmapImageRep *) sourceBitmap selectionMask: (NSBitmapImageRep *) selectionMask; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSBitmapImageRep_PPUtilities.m0000644000076500000240000007006513234403205023721 0ustar joshstaff/* NSBitmapImageRep_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" #define kMinimumBitmapAreaToUseTIFFDataLZWCompression 60 @interface NSBitmapImageRep (PPUtilitiesPrivateMethods) - (int) ppBytesPerPixel; - (NSBitmapImageRep *) ppUnclearedMatchedBitmapOfSize: (NSSize) bitmapSize; - (NSBitmapImageRep *) ppBitmapScaledToSize: (NSSize) scaledSize; - (NSBitmapImageRep *) ppBitmapCroppedToUncontainedBounds: (NSRect) croppingBounds; - (void) ppAttachColorProfileFromBitmap: (NSBitmapImageRep *) sourceBitmap; @end @implementation NSBitmapImageRep (PPUtilities) - (bool) ppIsEqualToBitmap: (NSBitmapImageRep *) comparisonBitmap { int bytesPerPixel, sourceBytesPerRow, comparisonBytesPerRow, rowCounter; NSSize sizeInPixels; unsigned char *sourceRow, *comparisonRow; size_t numBytesToCheckPerRow; bytesPerPixel = [self ppBytesPerPixel]; if (bytesPerPixel != [comparisonBitmap ppBytesPerPixel]) { return NO; } sizeInPixels = [self ppSizeInPixels]; if (!NSEqualSizes(sizeInPixels, [comparisonBitmap ppSizeInPixels])) { return NO; } sourceRow = [self bitmapData]; comparisonRow = [comparisonBitmap bitmapData]; if (!sourceRow || !comparisonRow) { return NO; } sourceBytesPerRow = [self bytesPerRow]; comparisonBytesPerRow = [comparisonBitmap bytesPerRow]; numBytesToCheckPerRow = sizeInPixels.width * bytesPerPixel; rowCounter = sizeInPixels.height; while (rowCounter--) { if (memcmp(sourceRow, comparisonRow, numBytesToCheckPerRow) != 0) { return NO; } sourceRow += sourceBytesPerRow; comparisonRow += comparisonBytesPerRow; } return YES; } - (bool) ppImportedBitmapHasAnimationFrames { return ([[self valueForProperty: NSImageFrameCount] intValue] > 1) ? YES : NO; } - (NSData *) ppCompressedTIFFData { NSSize bitmapSize; int bitmapArea; NSTIFFCompression compressionType; bitmapSize = [self ppSizeInPixels]; bitmapArea = bitmapSize.width * bitmapSize.height; if (bitmapArea >= kMinimumBitmapAreaToUseTIFFDataLZWCompression) { compressionType = NSTIFFCompressionLZW; } else { compressionType = NSTIFFCompressionNone; } return [self TIFFRepresentationUsingCompression: compressionType factor: 1.0f]; } - (NSData *) ppCompressedTIFFDataFromBounds: (NSRect) bounds { // ppShallowDuplicateFromBounds: would be faster here, however, there's a bug on OS X 10.8 // & earlier (GNUstep also?) where the TIFF compression loads the bitmapData rows using // bytesPerRow instead of pixelsWide * bytesPerPixel, which can cause it to read off the // end of the bitmapData buffer if the 'cropped' buffer includes the original's bottom row // and is offset from the original's left column. (Pointer to duplicate's left column // plus bytesPerRow could be past the end of the original's buffer). // So, sticking with the safe but slower ppBitmapCroppedToBounds: method. return [[self ppBitmapCroppedToBounds: bounds] ppCompressedTIFFData]; } - (NSData *) ppCompressedPNGData { return [self representationUsingType: NSPNGFileType properties: nil]; } - (void) ppSetAsCurrentGraphicsContext { NSGraphicsContext *graphicsContext; graphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep: self]; [graphicsContext setShouldAntialias: NO]; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext: graphicsContext]; } - (void) ppRestoreGraphicsContext { [NSGraphicsContext restoreGraphicsState]; } - (void) ppClearBitmap { unsigned char *bitmapData; unsigned bytesPerRow, numBytesToClear, numPaddingBytesPerRow; bitmapData = [self bitmapData]; if (!bitmapData) goto ERROR; bytesPerRow = [self bytesPerRow]; numBytesToClear = [self pixelsHigh] * bytesPerRow; // just to be safe, assume the last row ends where the pixel data finishes // (last row may or may not have the full bytesPerRow allocated if it's larger // than the size of the row's pixel data) numPaddingBytesPerRow = bytesPerRow - [self pixelsWide] * [self ppBytesPerPixel]; numBytesToClear -= numPaddingBytesPerRow; memset(bitmapData, 0, numBytesToClear); return; ERROR: return; } - (void) ppClearBitmapInBounds: (NSRect) bounds { NSRect bitmapFrame; unsigned char *bitmapData; unsigned numRowsToSkip, bytesPerRow, bytesPerPixel, numBytesToClearPerRow, rowCounter; bitmapFrame = [self ppFrameInPixels]; bounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(bounds), bitmapFrame); if (NSIsEmptyRect(bounds)) { return; } bitmapData = [self bitmapData]; if (!bitmapData) goto ERROR; numRowsToSkip = bitmapFrame.size.height - (bounds.origin.y + bounds.size.height); bytesPerRow = [self bytesPerRow]; bytesPerPixel = [self ppBytesPerPixel]; numBytesToClearPerRow = bounds.size.width * bytesPerPixel; bitmapData += numRowsToSkip * bytesPerRow + (int) bounds.origin.x * bytesPerPixel; rowCounter = bounds.size.height; while (rowCounter--) { memset(bitmapData, 0, numBytesToClearPerRow); bitmapData += bytesPerRow; } return; ERROR: return; } - (void) ppCopyFromBitmap: (NSBitmapImageRep *) sourceBitmap toPoint: (NSPoint) targetPoint { [self ppCopyFromBitmap: sourceBitmap inRect: [sourceBitmap ppFrameInPixels] toPoint: targetPoint]; } - (void) ppCopyFromBitmap: (NSBitmapImageRep *) sourceBitmap inRect: (NSRect) sourceRect toPoint: (NSPoint) targetPoint { int bytesPerPixel, destinationBytesPerRow, destinationDataOffset, sourceBytesPerRow, sourceDataOffset, rowOffset, bytesToCopyPerRow, rowCounter; NSRect destinationFrame, destinationRect, sourceFrame; unsigned char *destinationData, *destinationRow, *sourceData, *sourceRow; bytesPerPixel = [self ppBytesPerPixel]; if (bytesPerPixel != [sourceBitmap ppBytesPerPixel]) { goto ERROR; } destinationFrame = [self ppFrameInPixels]; sourceFrame = [sourceBitmap ppFrameInPixels]; targetPoint = PPGeometry_PointClippedToIntegerValues(targetPoint); sourceRect = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(sourceRect), sourceFrame); destinationRect.origin = targetPoint; destinationRect.size = sourceRect.size; destinationRect = NSIntersectionRect(destinationRect, destinationFrame); if (NSIsEmptyRect(destinationRect)) { goto ERROR; } if (!NSEqualSizes(destinationRect.size, sourceRect.size)) { sourceRect.origin.x += destinationRect.origin.x - targetPoint.x; sourceRect.origin.y += destinationRect.origin.y - targetPoint.y; sourceRect.size = destinationRect.size; } destinationData = [self bitmapData]; sourceData = [sourceBitmap bitmapData]; if (!destinationData || !sourceData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; rowOffset = destinationFrame.size.height - destinationRect.size.height - destinationRect.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + destinationRect.origin.x * bytesPerPixel; destinationRow = &destinationData[destinationDataOffset]; sourceBytesPerRow = [sourceBitmap bytesPerRow]; rowOffset = sourceFrame.size.height - sourceRect.size.height - sourceRect.origin.y; sourceDataOffset = rowOffset * sourceBytesPerRow + sourceRect.origin.x * bytesPerPixel; sourceRow = &sourceData[sourceDataOffset]; bytesToCopyPerRow = destinationRect.size.width * bytesPerPixel; rowCounter = destinationRect.size.height; while (rowCounter--) { memcpy(destinationRow, sourceRow, bytesToCopyPerRow); destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; } return; ERROR: return; } - (void) ppCenteredCopyFromBitmap: (NSBitmapImageRep *) sourceBitmap { NSSize sourceSize, destinationSize; NSPoint drawingOrigin; sourceSize = [sourceBitmap ppSizeInPixels]; destinationSize = [self ppSizeInPixels]; drawingOrigin = PPGeometry_OriginPointForCenteringSizeInSize(sourceSize, destinationSize); [self ppCopyFromBitmap: sourceBitmap toPoint: drawingOrigin]; } - (NSBitmapImageRep *) ppBitmapCroppedToBounds: (NSRect) croppingBounds { NSRect sourceBitmapFrame; NSBitmapImageRep *croppedBitmap; unsigned char *sourceData, *croppedData, *sourceRow, *croppedRow; int bytesPerPixel, numSourceRowsToSkip, sourceBytesPerRow, croppedBytesPerRow, rowCounter; size_t numBytesToCopyPerRow; croppingBounds = PPGeometry_PixelBoundsCoveredByRect(croppingBounds); sourceBitmapFrame = [self ppFrameInPixels]; if (!NSContainsRect(sourceBitmapFrame, croppingBounds)) { return [self ppBitmapCroppedToUncontainedBounds: croppingBounds]; } croppedBitmap = [self ppUnclearedMatchedBitmapOfSize: croppingBounds.size]; if (!croppedBitmap) goto ERROR; sourceData = [self bitmapData]; croppedData = [croppedBitmap bitmapData]; if (!sourceData || !croppedData) { goto ERROR; } bytesPerPixel = [self ppBytesPerPixel]; numSourceRowsToSkip = sourceBitmapFrame.size.height - (croppingBounds.origin.y + croppingBounds.size.height); sourceBytesPerRow = [self bytesPerRow]; sourceRow = sourceData; sourceRow += (sourceBytesPerRow * numSourceRowsToSkip) + (bytesPerPixel * (int) croppingBounds.origin.x); croppedBytesPerRow = [croppedBitmap bytesPerRow]; croppedRow = croppedData; numBytesToCopyPerRow = bytesPerPixel * croppingBounds.size.width; rowCounter = croppingBounds.size.height; while (rowCounter--) { memcpy(croppedRow, sourceRow, numBytesToCopyPerRow); croppedRow += croppedBytesPerRow; sourceRow += sourceBytesPerRow; } return croppedBitmap; ERROR: return nil; } // ppShallowDuplicateFromBounds: returns an autoreleased copy that uses the same bitmapData // pointer as the original (depending on croppingBounds, it may be offset). // It's faster than ppBitmapCroppedToBounds:, which allocates a new buffer and copies the // bitmapData. It should generally be used where the copy is just for reading, as writing to // the copy's bitmapData will overwrite the original's. The copy should not outlive the // original, as the copy's bitmapData pointer will become invalid when the original is // deallocated. - (NSBitmapImageRep *) ppShallowDuplicateFromBounds: (NSRect) croppingBounds; { NSRect sourceBitmapFrame; unsigned char *sourceData, *croppedData; int bytesPerRow, numSourceRowsToSkip, croppedDataOffsetInSourceData; NSBitmapImageRep *croppedBitmap; croppingBounds = PPGeometry_PixelBoundsCoveredByRect(croppingBounds); sourceBitmapFrame = [self ppFrameInPixels]; if (!NSContainsRect(sourceBitmapFrame, croppingBounds)) { return [self ppBitmapCroppedToUncontainedBounds: croppingBounds]; } sourceData = [self bitmapData]; if (!sourceData) goto ERROR; bytesPerRow = [self bytesPerRow]; numSourceRowsToSkip = sourceBitmapFrame.size.height - (croppingBounds.origin.y + croppingBounds.size.height); croppedDataOffsetInSourceData = bytesPerRow * numSourceRowsToSkip + [self ppBytesPerPixel] * (int) croppingBounds.origin.x; croppedData = &sourceData[croppedDataOffsetInSourceData]; croppedBitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &croppedData pixelsWide: croppingBounds.size.width pixelsHigh: croppingBounds.size.height bitsPerSample: [self bitsPerSample] samplesPerPixel: [self samplesPerPixel] hasAlpha: [self hasAlpha] isPlanar: NO colorSpaceName: [self colorSpaceName] bytesPerRow: bytesPerRow bitsPerPixel: 0] autorelease]; if (!croppedBitmap) goto ERROR; [croppedBitmap ppAttachColorProfileFromBitmap: self]; return croppedBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppBitmapResizedToSize: (NSSize) newSize shouldScale: (bool) shouldScale { NSBitmapImageRep *resizedBitmap = nil; newSize = PPGeometry_SizeClippedToIntegerValues(newSize); if (shouldScale) { resizedBitmap = [self ppBitmapScaledToSize: newSize]; } else { NSRect resizeBounds = PPGeometry_CenterRectInRect(PPGeometry_OriginRectOfSize(newSize), [self ppFrameInPixels]); resizedBitmap = [self ppBitmapCroppedToBounds: resizeBounds]; } return resizedBitmap; } - (NSBitmapImageRep *) ppBitmapMirroredHorizontally { NSSize bitmapSize; NSBitmapImageRep *mirroredBitmap; unsigned int bytesPerPixel, pixelsPerRow, rowCounter, sourceBytesPerRow, destinationBytesPerRow, destinationRowLastPixelOffset, pixelCounter; unsigned char *sourceData, *destinationData, *sourceRow, *destinationRow; bitmapSize = [self ppSizeInPixels]; mirroredBitmap = [self ppUnclearedMatchedBitmapOfSize: bitmapSize]; if (!mirroredBitmap) goto ERROR; sourceData = [self bitmapData]; destinationData = [mirroredBitmap bitmapData]; if (!sourceData || !destinationData) { goto ERROR; } bytesPerPixel = [self ppBytesPerPixel]; pixelsPerRow = bitmapSize.width; rowCounter = bitmapSize.height; sourceRow = sourceData; sourceBytesPerRow = [self bytesPerRow]; destinationRow = destinationData; destinationBytesPerRow = [mirroredBitmap bytesPerRow]; destinationRowLastPixelOffset = (pixelsPerRow - 1) * bytesPerPixel; switch (bytesPerPixel) { case sizeof(PPImageBitmapPixel): { PPImageBitmapPixel *sourceImagePixel, *destinationImagePixel; while (rowCounter--) { sourceImagePixel = (PPImageBitmapPixel *) sourceRow; destinationImagePixel = (PPImageBitmapPixel *) (&destinationRow[destinationRowLastPixelOffset]); pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationImagePixel-- = *sourceImagePixel++; } sourceRow += sourceBytesPerRow; destinationRow += destinationBytesPerRow; } } break; case sizeof(PPMaskBitmapPixel): { PPMaskBitmapPixel *sourceMaskPixel, *destinationMaskPixel; while (rowCounter--) { sourceMaskPixel = (PPMaskBitmapPixel *) sourceRow; destinationMaskPixel = (PPMaskBitmapPixel *) (&destinationRow[destinationRowLastPixelOffset]); pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationMaskPixel-- = *sourceMaskPixel++; } sourceRow += sourceBytesPerRow; destinationRow += destinationBytesPerRow; } } break; case sizeof(PPLinearRGB16BitmapPixel): { PPLinearRGB16BitmapPixel *sourceLinearPixel, *destinationLinearPixel; while (rowCounter--) { sourceLinearPixel = (PPLinearRGB16BitmapPixel *) sourceRow; destinationLinearPixel = (PPLinearRGB16BitmapPixel *) (&destinationRow[destinationRowLastPixelOffset]); pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationLinearPixel-- = *sourceLinearPixel++; } sourceRow += sourceBytesPerRow; destinationRow += destinationBytesPerRow; } } break; default: break; } return mirroredBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppBitmapMirroredVertically { NSSize bitmapSize; NSBitmapImageRep *mirroredBitmap; unsigned char *sourceData, *destinationData, *sourceRow, *destinationRow; unsigned int sourceBytesPerRow, destinationBytesPerRow, destinationDataOffset, rowDataSize, rowCounter; bitmapSize = [self ppSizeInPixels]; mirroredBitmap = [self ppUnclearedMatchedBitmapOfSize: bitmapSize]; if (!mirroredBitmap) goto ERROR; sourceData = [self bitmapData]; destinationData = [mirroredBitmap bitmapData]; if (!sourceData || !destinationData) { goto ERROR; } sourceBytesPerRow = [self bytesPerRow]; sourceRow = sourceData; destinationBytesPerRow = [mirroredBitmap bytesPerRow]; destinationDataOffset = (bitmapSize.height - 1) * destinationBytesPerRow; destinationRow = &destinationData[destinationDataOffset];; rowDataSize = bitmapSize.width * [self ppBytesPerPixel]; rowCounter = bitmapSize.height; while (rowCounter--) { memcpy(destinationRow, sourceRow, rowDataSize); sourceRow += sourceBytesPerRow; destinationRow -= destinationBytesPerRow; } return mirroredBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppBitmapRotated90Clockwise { NSSize sourceBitmapSize, destinationBitmapSize; NSBitmapImageRep *destinationBitmap; unsigned char *sourceData, *destinationData, *sourceColumn, *destinationRow, *sourcePixel; unsigned int sourceBytesPerRow, destinationBytesPerRow, destinationRowLastPixelOffset, bytesPerPixel, pixelsPerRow, rowCounter, pixelCounter; sourceBitmapSize = [self ppSizeInPixels]; destinationBitmapSize = NSMakeSize(sourceBitmapSize.height, sourceBitmapSize.width); destinationBitmap = [self ppUnclearedMatchedBitmapOfSize: destinationBitmapSize]; if (!destinationBitmap) goto ERROR; sourceData = [self bitmapData]; destinationData = [destinationBitmap bitmapData]; if (!sourceData || !destinationData) { goto ERROR; } bytesPerPixel = [self ppBytesPerPixel]; pixelsPerRow = destinationBitmapSize.width; rowCounter = destinationBitmapSize.height; sourceBytesPerRow = [self bytesPerRow]; sourceColumn = sourceData; destinationBytesPerRow = [destinationBitmap bytesPerRow]; destinationRow = destinationData; destinationRowLastPixelOffset = (pixelsPerRow - 1) * bytesPerPixel; switch (bytesPerPixel) { case sizeof(PPImageBitmapPixel): { PPImageBitmapPixel *destinationImagePixel; while (rowCounter--) { sourcePixel = sourceColumn; destinationImagePixel = (PPImageBitmapPixel *) (&destinationRow[destinationRowLastPixelOffset]); pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationImagePixel-- = *((PPImageBitmapPixel *) sourcePixel); sourcePixel += sourceBytesPerRow; } sourceColumn += bytesPerPixel; destinationRow += destinationBytesPerRow; } } break; case sizeof(PPMaskBitmapPixel): { PPMaskBitmapPixel *destinationMaskPixel; while (rowCounter--) { sourcePixel = sourceColumn; destinationMaskPixel = (PPMaskBitmapPixel *) (&destinationRow[destinationRowLastPixelOffset]); pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationMaskPixel-- = *((PPMaskBitmapPixel *) sourcePixel); sourcePixel += sourceBytesPerRow; } sourceColumn += bytesPerPixel; destinationRow += destinationBytesPerRow; } } break; case sizeof(PPLinearRGB16BitmapPixel): { PPLinearRGB16BitmapPixel *destinationLinearPixel; while (rowCounter--) { sourcePixel = sourceColumn; destinationLinearPixel = (PPLinearRGB16BitmapPixel *) (&destinationRow[destinationRowLastPixelOffset]); pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationLinearPixel-- = *((PPLinearRGB16BitmapPixel *) sourcePixel); sourcePixel += sourceBytesPerRow; } sourceColumn += bytesPerPixel; destinationRow += destinationBytesPerRow; } } break; default: break; } return destinationBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppBitmapRotated90Counterclockwise { NSSize sourceBitmapSize, destinationBitmapSize; NSBitmapImageRep *destinationBitmap; unsigned char *sourceData, *destinationData, *sourceColumn, *destinationRow, *sourcePixel; unsigned int sourceBytesPerRow, destinationBytesPerRow, destinationDataOffset, bytesPerPixel, pixelsPerRow, rowCounter, pixelCounter; sourceBitmapSize = [self ppSizeInPixels]; destinationBitmapSize = NSMakeSize(sourceBitmapSize.height, sourceBitmapSize.width); destinationBitmap = [self ppUnclearedMatchedBitmapOfSize: destinationBitmapSize]; if (!destinationBitmap) goto ERROR; sourceData = [self bitmapData]; destinationData = [destinationBitmap bitmapData]; if (!sourceData || !destinationData) { goto ERROR; } bytesPerPixel = [self ppBytesPerPixel]; pixelsPerRow = destinationBitmapSize.width; rowCounter = destinationBitmapSize.height; sourceBytesPerRow = [self bytesPerRow]; sourceColumn = sourceData; destinationBytesPerRow = [destinationBitmap bytesPerRow]; destinationDataOffset = destinationBytesPerRow * (destinationBitmapSize.height - 1); destinationRow = &destinationData[destinationDataOffset]; switch (bytesPerPixel) { case sizeof(PPImageBitmapPixel): { PPImageBitmapPixel *destinationImagePixel; while (rowCounter--) { sourcePixel = sourceColumn; destinationImagePixel = (PPImageBitmapPixel *) destinationRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationImagePixel++ = *((PPImageBitmapPixel *) sourcePixel); sourcePixel += sourceBytesPerRow; } sourceColumn += bytesPerPixel; destinationRow -= destinationBytesPerRow; } } break; case sizeof(PPMaskBitmapPixel): { PPMaskBitmapPixel *destinationMaskPixel; while (rowCounter--) { sourcePixel = sourceColumn; destinationMaskPixel = (PPMaskBitmapPixel *) destinationRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationMaskPixel++ = *((PPMaskBitmapPixel *) sourcePixel); sourcePixel += sourceBytesPerRow; } sourceColumn += bytesPerPixel; destinationRow -= destinationBytesPerRow; } } break; case sizeof(PPLinearRGB16BitmapPixel): { PPLinearRGB16BitmapPixel *destinationLinearPixel; while (rowCounter--) { sourcePixel = sourceColumn; destinationLinearPixel = (PPLinearRGB16BitmapPixel *) destinationRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { *destinationLinearPixel++ = *((PPLinearRGB16BitmapPixel *) sourcePixel); sourcePixel += sourceBytesPerRow; } sourceColumn += bytesPerPixel; destinationRow -= destinationBytesPerRow; } } break; default: break; } return destinationBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppBitmapRotated180 { return [[self ppBitmapMirroredHorizontally] ppBitmapMirroredVertically]; } #pragma mark Private methods - (int) ppBytesPerPixel { return [self samplesPerPixel] * [self bitsPerSample] / 8; } - (NSBitmapImageRep *) ppUnclearedMatchedBitmapOfSize: (NSSize) bitmapSize { NSBitmapImageRep *matchedBitmap; if (PPGeometry_IsZeroSize(bitmapSize)) { goto ERROR; } matchedBitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: bitmapSize.width pixelsHigh: bitmapSize.height bitsPerSample: [self bitsPerSample] samplesPerPixel: [self samplesPerPixel] hasAlpha: [self hasAlpha] isPlanar: NO colorSpaceName: [self colorSpaceName] bytesPerRow: 0 bitsPerPixel: 0] autorelease]; if (!matchedBitmap) goto ERROR; [matchedBitmap ppAttachColorProfileFromBitmap: self]; return matchedBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppBitmapScaledToSize: (NSSize) scaledSize { NSBitmapImageRep *scaledBitmap = [self ppUnclearedMatchedBitmapOfSize: scaledSize]; if (!scaledBitmap) goto ERROR; [scaledBitmap ppSetAsCurrentGraphicsContext]; [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationNone]; [self drawInRect: [scaledBitmap ppFrameInPixels]]; [scaledBitmap ppRestoreGraphicsContext]; return scaledBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppBitmapCroppedToUncontainedBounds: (NSRect) croppingBounds { NSBitmapImageRep *croppedBitmap = [self ppUnclearedMatchedBitmapOfSize: croppingBounds.size]; if (!croppedBitmap) goto ERROR; [croppedBitmap ppClearBitmap]; [croppedBitmap ppCopyFromBitmap: self toPoint: NSMakePoint(-croppingBounds.origin.x, -croppingBounds.origin.y)]; return croppedBitmap; ERROR: return nil; } - (void) ppAttachColorProfileFromBitmap: (NSBitmapImageRep *) sourceBitmap { NSData *iccProfile = [sourceBitmap valueForProperty: NSImageColorSyncProfileData]; if (iccProfile) { [self setProperty: NSImageColorSyncProfileData withValue: iccProfile]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSBitmapImageRep_PPUtilities_ColorMasking.m0000644000076500000240000007033713234403205026373 0ustar joshstaff/* NSBitmapImageRep_PPUtilities_ColorMasking.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" #define kMaxMatchTolerance kMaxImagePixelComponentValue #define macroImagePixelMatchesMinAndMaxPixels(imagePixel, minPixel, maxPixel) \ \ (((macroImagePixelComponent_Red(imagePixel) \ >= macroImagePixelComponent_Red(minPixel)) \ \ && (macroImagePixelComponent_Green(imagePixel) \ >= macroImagePixelComponent_Green(minPixel)) \ \ && (macroImagePixelComponent_Blue(imagePixel) \ >= macroImagePixelComponent_Blue(minPixel)) \ \ && (macroImagePixelComponent_Alpha(imagePixel) \ >= macroImagePixelComponent_Alpha(minPixel)) \ \ && (macroImagePixelComponent_Red(imagePixel) \ <= macroImagePixelComponent_Red(maxPixel)) \ \ && (macroImagePixelComponent_Green(imagePixel) \ <= macroImagePixelComponent_Green(maxPixel)) \ \ && (macroImagePixelComponent_Blue(imagePixel) \ <= macroImagePixelComponent_Blue(maxPixel)) \ \ && (macroImagePixelComponent_Alpha(imagePixel) \ <= macroImagePixelComponent_Alpha(maxPixel))) ? \ \ YES : NO) static bool GetMinAndMaxMatchingPixelsForImagePixelWithTolerance( PPImageBitmapPixel *sourcePixel, unsigned matchTolerance, PPImageBitmapPixel *returnedMinPixel, PPImageBitmapPixel *returnedMaxPixel); @interface NSBitmapImageRep (PPUtilities_ColorMaskingPrivateMethods) - (bool) seedMatchingMaskInRow: (unsigned) row col: (unsigned) col colorMatchTolerance: (int) colorMatchTolerance sourceBitmap: (NSBitmapImageRep *) sourceBitmap selectionMask: (NSBitmapImageRep *) selectionMask returnedMinMatchingPixel: (PPImageBitmapPixel *) returnedMinMatchingPixel returnedMaxMatchingPixel: (PPImageBitmapPixel *) returnedMaxMatchingPixel; - (bool) expandMatchingMaskInRow: (unsigned) row startCol: (unsigned) startCol endCol: (unsigned) endCol minMatchingPixel: (PPImageBitmapPixel *) minMatchingPixel maxMatchingPixel: (PPImageBitmapPixel *) maxMatchingPixel sourceBitmap: (NSBitmapImageRep *) sourceBitmap selectionMask: (NSBitmapImageRep *) selectionMask shouldCheckDiagonals: (bool) shouldCheckDiagonals; @end @implementation NSBitmapImageRep (PPUtilities_ColorMasking) - (void) ppMaskNeighboringPixelsMatchingColorAtPoint: (NSPoint) point inImageBitmap: (NSBitmapImageRep *) sourceBitmap colorMatchTolerance: (unsigned) colorMatchTolerance selectionMask: (NSBitmapImageRep *) selectionMask selectionMaskBounds: (NSRect) selectionMaskBounds matchDiagonally: (bool) matchDiagonally { NSRect bitmapFrame, matchBounds; int maskHeight, row, startCol, endCol, rowToCheck, lastRowToCheck, bottomRow, rowAbove, rowBelow; PPImageBitmapPixel minMatchingPixelValue, maxMatchingPixelValue; unsigned char *rowCheckFlags; if (![sourceBitmap ppIsImageBitmapAndSameSizeAsMaskBitmap: self]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; point = PPGeometry_PointClippedToIntegerValues(point); if (PPGeometry_IsZeroSize(bitmapFrame.size) || !NSPointInRect(point, bitmapFrame)) { goto ERROR; } if (selectionMask) { if (![sourceBitmap ppIsImageBitmapAndSameSizeAsMaskBitmap: selectionMask]) { goto ERROR; } selectionMaskBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(selectionMaskBounds), bitmapFrame); if (NSIsEmptyRect(selectionMaskBounds)) { goto ERROR; } matchBounds = selectionMaskBounds; } else { matchBounds = bitmapFrame; } maskHeight = bitmapFrame.size.height; row = maskHeight - point.y - 1; startCol = matchBounds.origin.x; endCol = startCol + matchBounds.size.width - 1; if (![self seedMatchingMaskInRow: row col: point.x colorMatchTolerance: colorMatchTolerance sourceBitmap: sourceBitmap selectionMask: selectionMask returnedMinMatchingPixel: &minMatchingPixelValue returnedMaxMatchingPixel: &maxMatchingPixelValue]) { goto ERROR; } if (maskHeight < 2) { return; } rowCheckFlags = (unsigned char *) calloc (maskHeight, sizeof(*rowCheckFlags)); if (!rowCheckFlags) goto ERROR; bottomRow = maskHeight - 1; rowToCheck = bottomRow; lastRowToCheck = 0; if (row > 0) { rowAbove = row - 1; rowCheckFlags[rowAbove] = YES; rowToCheck = lastRowToCheck = rowAbove; } if (row < bottomRow) { rowBelow = row + 1; rowCheckFlags[rowBelow] = YES; if (rowToCheck > rowBelow) { rowToCheck = rowBelow; } lastRowToCheck = rowBelow; } while (rowToCheck <= lastRowToCheck) { if (rowCheckFlags[rowToCheck]) { rowCheckFlags[rowToCheck] = NO; if ([self expandMatchingMaskInRow: rowToCheck startCol: startCol endCol: endCol minMatchingPixel: &minMatchingPixelValue maxMatchingPixel: &maxMatchingPixelValue sourceBitmap: sourceBitmap selectionMask: selectionMask shouldCheckDiagonals: matchDiagonally]) { row = rowToCheck; if (row < bottomRow) { rowBelow = row + 1; rowCheckFlags[rowBelow] = YES; rowToCheck = rowBelow; if (lastRowToCheck < rowBelow) { lastRowToCheck = rowBelow; } } if (row > 0) { rowAbove = row - 1; rowCheckFlags[rowAbove] = YES; rowToCheck = rowAbove; } } else { rowToCheck++; } } else { rowToCheck++; } } free(rowCheckFlags); return; ERROR: if ([self ppIsMaskBitmap]) { [self ppClearBitmap]; } return; } - (void) ppMaskAllPixelsMatchingColorAtPoint: (NSPoint) point inImageBitmap: (NSBitmapImageRep *) sourceBitmap colorMatchTolerance: (unsigned) colorMatchTolerance selectionMask: (NSBitmapImageRep *) selectionMask selectionMaskBounds: (NSRect) selectionMaskBounds { NSRect bitmapFrame, matchBounds; unsigned char *destinationMaskData, *destinationMaskRow, *sourceBitmapData, *sourceBitmapRow; int destinationMaskBytesPerRow, destinationMaskDataOffset, sourceBitmapBytesPerRow, sourceBitmapDataOffset, rowOffset, rowCounter, pixelsPerRow, pixelCounter; PPImageBitmapPixel *sourcePixelToMatch, minMatchingPixelValue, maxMatchingPixelValue; PPMaskBitmapPixel *destinationMaskPixel; if (![sourceBitmap ppIsImageBitmapAndSameSizeAsMaskBitmap: self]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; point = PPGeometry_PointClippedToIntegerValues(point); if (NSIsEmptyRect(bitmapFrame) || !NSPointInRect(point, bitmapFrame)) { goto ERROR; } if (selectionMask) { if (![sourceBitmap ppIsImageBitmapAndSameSizeAsMaskBitmap: selectionMask]) { goto ERROR; } selectionMaskBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(selectionMaskBounds), bitmapFrame); if (NSIsEmptyRect(selectionMaskBounds)) { goto ERROR; } matchBounds = selectionMaskBounds; } else { matchBounds = bitmapFrame; } [self ppClearBitmap]; destinationMaskData = [self bitmapData]; sourceBitmapData = [sourceBitmap bitmapData]; if (!destinationMaskData || !sourceBitmapData) { goto ERROR; } destinationMaskBytesPerRow = [self bytesPerRow]; sourceBitmapBytesPerRow = [sourceBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - matchBounds.size.height - matchBounds.origin.y; destinationMaskDataOffset = rowOffset * destinationMaskBytesPerRow + matchBounds.origin.x * sizeof(PPMaskBitmapPixel); sourceBitmapDataOffset = rowOffset * sourceBitmapBytesPerRow + matchBounds.origin.x * sizeof(PPImageBitmapPixel); destinationMaskRow = &destinationMaskData[destinationMaskDataOffset]; sourceBitmapRow = &sourceBitmapData[sourceBitmapDataOffset]; rowCounter = matchBounds.size.height; pixelsPerRow = matchBounds.size.width; sourceBitmapDataOffset = (bitmapFrame.size.height - point.y - 1) * sourceBitmapBytesPerRow + point.x * sizeof(PPImageBitmapPixel); sourcePixelToMatch = (PPImageBitmapPixel *) &sourceBitmapData[sourceBitmapDataOffset]; if (!GetMinAndMaxMatchingPixelsForImagePixelWithTolerance(sourcePixelToMatch, colorMatchTolerance, &minMatchingPixelValue, &maxMatchingPixelValue)) { goto ERROR; } if (selectionMask) { // Has selection mask unsigned char *selectionMaskData, *selectionMaskRow; int selectionMaskBytesPerRow, selectionMaskDataOffset; PPMaskBitmapPixel *selectionMaskPixel; selectionMaskData = [selectionMask bitmapData]; if (!selectionMaskData) goto ERROR; selectionMaskBytesPerRow = [selectionMask bytesPerRow]; selectionMaskDataOffset = rowOffset * selectionMaskBytesPerRow + matchBounds.origin.x * sizeof(PPMaskBitmapPixel); selectionMaskRow = &selectionMaskData[selectionMaskDataOffset]; while (rowCounter--) { destinationMaskPixel = (PPMaskBitmapPixel *) destinationMaskRow; sourcePixelToMatch = (PPImageBitmapPixel *) sourceBitmapRow; selectionMaskPixel = (PPMaskBitmapPixel *) selectionMaskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (*selectionMaskPixel && macroImagePixelMatchesMinAndMaxPixels(sourcePixelToMatch, &minMatchingPixelValue, &maxMatchingPixelValue)) { *destinationMaskPixel = kMaskPixelValue_ON; } destinationMaskPixel++; sourcePixelToMatch++; selectionMaskPixel++; } destinationMaskRow += destinationMaskBytesPerRow; sourceBitmapRow += sourceBitmapBytesPerRow; selectionMaskRow += selectionMaskBytesPerRow; } } else { // No selection mask while (rowCounter--) { destinationMaskPixel = (PPMaskBitmapPixel *) destinationMaskRow; sourcePixelToMatch = (PPImageBitmapPixel *) sourceBitmapRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (macroImagePixelMatchesMinAndMaxPixels(sourcePixelToMatch, &minMatchingPixelValue, &maxMatchingPixelValue)) { *destinationMaskPixel = kMaskPixelValue_ON; } destinationMaskPixel++; sourcePixelToMatch++; } destinationMaskRow += destinationMaskBytesPerRow; sourceBitmapRow += sourceBitmapBytesPerRow; } } return; ERROR: if ([self ppIsMaskBitmap]) { [self ppClearBitmap]; } return; } - (void) ppMaskVisiblePixelsInImageBitmap: (NSBitmapImageRep *) sourceBitmap selectionMask: (NSBitmapImageRep *) selectionMask { int maskWidth, maskHeight, destinationMaskBytesPerRow, sourceBitmapBytesPerRow, selectionMaskBytesPerRow, rowCounter, columnCounter; unsigned char *destinationMaskRow, *sourceBitmapRow, *selectionMaskRow; PPMaskBitmapPixel *destinationMaskPixel, *selectionMaskPixel; PPImageBitmapPixel *sourceBitmapPixel; maskWidth = [self pixelsWide]; maskHeight = [self pixelsHigh]; destinationMaskRow = [self bitmapData]; destinationMaskBytesPerRow = [self bytesPerRow]; sourceBitmapRow = [sourceBitmap bitmapData]; sourceBitmapBytesPerRow = [sourceBitmap bytesPerRow]; if (!destinationMaskRow || !sourceBitmapRow) { goto ERROR; } if (selectionMask) { selectionMaskRow = [selectionMask bitmapData]; selectionMaskBytesPerRow = [selectionMask bytesPerRow]; if (!selectionMaskRow) goto ERROR; } rowCounter = maskHeight; if (selectionMask) { // Has selection mask while (rowCounter--) { destinationMaskPixel = (PPMaskBitmapPixel *) destinationMaskRow; sourceBitmapPixel = (PPImageBitmapPixel *) sourceBitmapRow; selectionMaskPixel = (PPMaskBitmapPixel *) selectionMaskRow; columnCounter = maskWidth; while (columnCounter--) { if (macroImagePixelComponent_Alpha(sourceBitmapPixel)) { *destinationMaskPixel = kMaskPixelValue_ON; } destinationMaskPixel++; sourceBitmapPixel++; selectionMaskPixel++; } destinationMaskRow += destinationMaskBytesPerRow; sourceBitmapRow += sourceBitmapBytesPerRow; selectionMaskRow += selectionMaskBytesPerRow; } } else { // No selection mask while (rowCounter--) { destinationMaskPixel = (PPMaskBitmapPixel *) destinationMaskRow; sourceBitmapPixel = (PPImageBitmapPixel *) sourceBitmapRow; columnCounter = maskWidth; while (columnCounter--) { if (macroImagePixelComponent_Alpha(sourceBitmapPixel)) { *destinationMaskPixel = kMaskPixelValue_ON; } destinationMaskPixel++; sourceBitmapPixel++; } destinationMaskRow += destinationMaskBytesPerRow; sourceBitmapRow += sourceBitmapBytesPerRow; } } return; ERROR: return; } #pragma mark Private methods - (bool) seedMatchingMaskInRow: (unsigned) row col: (unsigned) col colorMatchTolerance: (int) colorMatchTolerance sourceBitmap: (NSBitmapImageRep *) sourceBitmap selectionMask: (NSBitmapImageRep *) selectionMask returnedMinMatchingPixel: (PPImageBitmapPixel *) returnedMinMatchingPixel returnedMaxMatchingPixel: (PPImageBitmapPixel *) returnedMaxMatchingPixel { int maskWidth, maskHeight, checkCol, maskablePixelsStartCol, maskablePixelsEndCol; unsigned char *destinationMaskData, *sourceBitmapData, *selectionMaskData, *destinationMaskRow, *sourceBitmapRow, *selectionMaskRow; PPImageBitmapPixel *sourcePixelToMatch, minMatchingPixelValue, maxMatchingPixelValue; [self ppClearBitmap]; maskWidth = [self pixelsWide]; maskHeight = [self pixelsHigh]; if ((col >= maskWidth) || (row >= maskHeight)) { goto ERROR; } destinationMaskData = [self bitmapData]; sourceBitmapData = [sourceBitmap bitmapData]; if (!destinationMaskData || !sourceBitmapData) { goto ERROR; } destinationMaskRow = &destinationMaskData[[self bytesPerRow] * row]; sourceBitmapRow = &sourceBitmapData[[sourceBitmap bytesPerRow] * row]; if (selectionMask) { selectionMaskData = [selectionMask bitmapData]; if (!selectionMaskData) goto ERROR; selectionMaskRow = &selectionMaskData[[selectionMask bytesPerRow] * row]; if (!selectionMaskRow[col]) goto ERROR; } maskablePixelsStartCol = maskablePixelsEndCol = col; sourcePixelToMatch = (PPImageBitmapPixel *) &sourceBitmapRow[col * sizeof(PPImageBitmapPixel)]; if (!GetMinAndMaxMatchingPixelsForImagePixelWithTolerance(sourcePixelToMatch, colorMatchTolerance, &minMatchingPixelValue, &maxMatchingPixelValue)) { goto ERROR; } if (col > 0) { checkCol = col - 1; sourcePixelToMatch = (PPImageBitmapPixel *) &sourceBitmapRow[checkCol * sizeof(PPImageBitmapPixel)]; while (checkCol >= 0) { if ((selectionMask && !selectionMaskRow[checkCol]) || !macroImagePixelMatchesMinAndMaxPixels(sourcePixelToMatch, &minMatchingPixelValue, &maxMatchingPixelValue)) { break; } maskablePixelsStartCol = checkCol; checkCol--; sourcePixelToMatch--; } } if (col < (maskWidth - 1)) { checkCol = col + 1; sourcePixelToMatch = (PPImageBitmapPixel *) &sourceBitmapRow[checkCol * sizeof(PPImageBitmapPixel)]; while (checkCol < maskWidth) { if ((selectionMask && !selectionMaskRow[checkCol]) || !macroImagePixelMatchesMinAndMaxPixels(sourcePixelToMatch, &minMatchingPixelValue, &maxMatchingPixelValue)) { break; } maskablePixelsEndCol = checkCol; checkCol++; sourcePixelToMatch++; } } memset(&destinationMaskRow[maskablePixelsStartCol], -1, maskablePixelsEndCol - maskablePixelsStartCol + 1); if (returnedMinMatchingPixel) { *returnedMinMatchingPixel = minMatchingPixelValue; } if (returnedMaxMatchingPixel) { *returnedMaxMatchingPixel = maxMatchingPixelValue; } return YES; ERROR: return NO; } - (bool) expandMatchingMaskInRow: (unsigned) row startCol: (unsigned) startCol endCol: (unsigned) endCol minMatchingPixel: (PPImageBitmapPixel *) minMatchingPixel maxMatchingPixel: (PPImageBitmapPixel *) maxMatchingPixel sourceBitmap: (NSBitmapImageRep *) sourceBitmap selectionMask: (NSBitmapImageRep *) selectionMask shouldCheckDiagonals: (bool) shouldCheckDiagonals { int maskWidth, maskHeight, col, destinationBytesPerRow, maskablePixelsStartCol, maskablePixelsEndCol, checkStartCol, checkEndCol, i; unsigned char *destinationMaskData, *sourceBitmapData, *selectionMaskData, *destinationMaskRow; PPMaskBitmapPixel *destinationMaskPixel, *selectionMaskPixel = NULL; PPImageBitmapPixel *sourcePixelToMatch; bool didExpandMask, foundMaskablePixelsEndCol, shouldEnableMaskablePixels; maskWidth = [self pixelsWide]; maskHeight = [self pixelsHigh]; if ((row >= maskHeight) || (startCol > maskWidth) || (endCol > maskWidth) || (startCol > endCol)) { goto ERROR; } destinationMaskData = [self bitmapData]; sourceBitmapData = [sourceBitmap bitmapData]; if (!destinationMaskData || !sourceBitmapData) { goto ERROR; } if (selectionMask) { selectionMaskData = [selectionMask bitmapData]; if (!selectionMaskData) goto ERROR; selectionMaskPixel = (PPMaskBitmapPixel *) &selectionMaskData[[selectionMask bytesPerRow] * row + startCol * sizeof(PPMaskBitmapPixel)]; } destinationBytesPerRow = [self bytesPerRow]; destinationMaskRow = &destinationMaskData[destinationBytesPerRow * row]; destinationMaskPixel = (PPMaskBitmapPixel *) &destinationMaskRow[startCol * sizeof(PPMaskBitmapPixel)]; sourcePixelToMatch = (PPImageBitmapPixel *) &sourceBitmapData[[sourceBitmap bytesPerRow] * row + startCol * sizeof(PPImageBitmapPixel)]; didExpandMask = NO; col = startCol; while (col <= endCol) { if ((!selectionMask || *selectionMaskPixel) && !*destinationMaskPixel && macroImagePixelMatchesMinAndMaxPixels(sourcePixelToMatch, minMatchingPixel, maxMatchingPixel)) { maskablePixelsStartCol = col; col++; destinationMaskPixel++; sourcePixelToMatch++; selectionMaskPixel++; foundMaskablePixelsEndCol = NO; while ((col <= endCol) && !foundMaskablePixelsEndCol) { if ((selectionMask && !*selectionMaskPixel) || !macroImagePixelMatchesMinAndMaxPixels(sourcePixelToMatch, minMatchingPixel, maxMatchingPixel)) { maskablePixelsEndCol = col - 1; foundMaskablePixelsEndCol = YES; } if (!foundMaskablePixelsEndCol) { col++; destinationMaskPixel++; sourcePixelToMatch++; selectionMaskPixel++; } } if (!foundMaskablePixelsEndCol) { maskablePixelsEndCol = endCol; } checkStartCol = maskablePixelsStartCol; checkEndCol = maskablePixelsEndCol; if (shouldCheckDiagonals) { if (checkStartCol > startCol) { checkStartCol--; } if (checkEndCol < endCol) { checkEndCol++; } } shouldEnableMaskablePixels = NO; if (row > 0) { unsigned char *destinationMaskRowAbove; destinationMaskRowAbove = &destinationMaskRow[-destinationBytesPerRow]; for (i=checkStartCol; i<=checkEndCol; i++) { if (destinationMaskRowAbove[i]) { shouldEnableMaskablePixels = YES; break; } } } if (!shouldEnableMaskablePixels && (row < (maskHeight - 1))) { unsigned char *destinationMaskRowBelow; destinationMaskRowBelow = &destinationMaskRow[destinationBytesPerRow]; for (i=checkStartCol; i<=checkEndCol; i++) { if (destinationMaskRowBelow[i]) { shouldEnableMaskablePixels = YES; break; } } } if (shouldEnableMaskablePixels) { memset(&destinationMaskRow[maskablePixelsStartCol], -1, maskablePixelsEndCol - maskablePixelsStartCol + 1); didExpandMask = YES; } } col++; destinationMaskPixel++; sourcePixelToMatch++; selectionMaskPixel++; } return didExpandMask; ERROR: return NO; } @end #pragma mark Private functions static bool GetMinAndMaxMatchingPixelsForImagePixelWithTolerance( PPImageBitmapPixel *sourcePixel, unsigned matchTolerance, PPImageBitmapPixel *returnedMinPixel, PPImageBitmapPixel *returnedMaxPixel) { unsigned toleranceLowerBound, toleranceUpperBound; PPImagePixelComponentType componentType; PPImagePixelComponent sourcePixelComponent, minPixelComponent, maxPixelComponent; if (!sourcePixel || !returnedMinPixel || !returnedMaxPixel) { goto ERROR; } if (matchTolerance > kMaxMatchTolerance) { matchTolerance = kMaxMatchTolerance; } toleranceLowerBound = matchTolerance; toleranceUpperBound = kMaxImagePixelComponentValue - matchTolerance; for (componentType=0; componentType toleranceLowerBound) ? sourcePixelComponent - matchTolerance : 0; maxPixelComponent = (sourcePixelComponent < toleranceUpperBound) ? sourcePixelComponent + matchTolerance : kMaxImagePixelComponentValue; macroImagePixelComponent(returnedMinPixel, componentType) = minPixelComponent; macroImagePixelComponent(returnedMaxPixel, componentType) = maxPixelComponent; } return YES; ERROR: return NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/NSBitmapImageRep_PPUtilities_ImageBitmaps.m0000644000076500000240000012512013234403205026334 0ustar joshstaff/* NSBitmapImageRep_PPUtilities_ImageBitmaps.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSBitmapImageRep_PPUtilities.h" #import "PPDefines.h" #import "PPGeometry.h" #import "NSColor_PPUtilities.h" #import "NSImage_PPUtilities.h" #define kImageBitmapBitsPerSample \ (sizeof(PPImagePixelComponent) * 8) #define kImageBitmapSamplesPerPixel \ (sizeof(PPImageBitmapPixel) / sizeof(PPImagePixelComponent)) #define kMaxScalingFactorToForceDotsGridType 6 #define kCrosshairLegSizeToScalingFactorRatio (1.0/7.0) @implementation NSBitmapImageRep (PPUtilities_ImageBitmaps) + (NSBitmapImageRep *) ppImageBitmapOfSize: (NSSize) size { NSBitmapImageRep *imageBitmap; size = PPGeometry_SizeClippedToIntegerValues(size); if (PPGeometry_IsZeroSize(size)) { goto ERROR; } imageBitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: size.width pixelsHigh: size.height bitsPerSample: kImageBitmapBitsPerSample samplesPerPixel: kImageBitmapSamplesPerPixel hasAlpha: YES isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0] autorelease]; if (!imageBitmap) goto ERROR; // use sRGB colorspace [imageBitmap ppAttachSRGBColorProfile]; [imageBitmap ppClearBitmap]; return imageBitmap; ERROR: return nil; } + (NSBitmapImageRep *) ppImageBitmapWithImportedData: (NSData *) importedData { return [[NSBitmapImageRep imageRepWithData: importedData] ppImageBitmap]; } + (NSBitmapImageRep *) ppImageBitmapFromImageResource: (NSString *) imageName { NSString *imageResourcePath; NSData *imageData; if (!imageName) goto ERROR; imageResourcePath = [[NSBundle mainBundle] pathForImageResource: imageName]; if (!imageResourcePath) goto ERROR; imageData = [NSData dataWithContentsOfFile: imageResourcePath]; if (!imageData) goto ERROR; return [NSBitmapImageRep ppImageBitmapWithImportedData: imageData]; ERROR: return nil; } - (bool) ppIsImageBitmap { return (([self samplesPerPixel] == kImageBitmapSamplesPerPixel) && ([self bitsPerSample] == kImageBitmapBitsPerSample)) ? YES : NO; } - (bool) ppIsImageBitmapAndSameSizeAsMaskBitmap: (NSBitmapImageRep *) maskBitmap { if ([self ppIsImageBitmap] && [maskBitmap ppIsMaskBitmap] && NSEqualSizes([self ppSizeInPixels], [maskBitmap ppSizeInPixels])) { return YES; } else { return NO; } } // ppImageColorAtPoint: is used instead of the Cocoa-native -[NSBitmapImageRep colorAtX:y:], // because it returns image-bitmap colors in the correct colorspace (sRGB); As of OS X 10.6, // colorAtX:y: incorrectly ignores image-bitmaps' custom colorspace, returning colors in // NSCalibratedRGBColorSpace - (NSColor *) ppImageColorAtPoint: (NSPoint) point { NSRect bitmapFrame; unsigned char *bitmapData; int rowOffset, dataOffset; PPImageBitmapPixel *bitmapPixel; CGFloat alphaComponent, redValue, greenValue, blueValue, alphaValue; if (![self ppIsImageBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; point = PPGeometry_PointClippedToRect(PPGeometry_PointClippedToIntegerValues(point), bitmapFrame); bitmapData = [self bitmapData]; if (!bitmapData) goto ERROR; rowOffset = bitmapFrame.size.height - 1 - point.y; dataOffset = rowOffset * [self bytesPerRow] + point.x * sizeof(PPImageBitmapPixel); bitmapPixel = (PPImageBitmapPixel *) &bitmapData[dataOffset]; alphaComponent = macroImagePixelComponent_Alpha(bitmapPixel); if (alphaComponent > 0) { // nonzero alpha: un-premultiply RGB components redValue= ((CGFloat) macroImagePixelComponent_Red(bitmapPixel)) / alphaComponent; greenValue = ((CGFloat) macroImagePixelComponent_Green(bitmapPixel)) / alphaComponent; blueValue = ((CGFloat) macroImagePixelComponent_Blue(bitmapPixel)) / alphaComponent; alphaValue = alphaComponent / ((CGFloat) kMaxImagePixelComponentValue); } else { // zero alpha: all components are zero due to premultiply redValue = greenValue = blueValue = alphaValue = 0; } return [NSColor ppSRGBColorWithRed: redValue green: greenValue blue: blueValue alpha: alphaValue]; ERROR: return nil; } - (bool) ppImageBitmapHasTransparentPixels { unsigned char *bitmapRow; int bytesPerRow, pixelsPerRow, rowCounter, pixelCounter; NSSize bitmapSize; PPImageBitmapPixel *bitmapPixel; if (![self ppIsImageBitmap]) { goto ERROR; } bitmapRow = [self bitmapData]; if (!bitmapRow) goto ERROR; bytesPerRow = [self bytesPerRow]; bitmapSize = [self ppSizeInPixels]; pixelsPerRow = bitmapSize.width; rowCounter = bitmapSize.height; while (rowCounter--) { bitmapPixel = (PPImageBitmapPixel *) bitmapRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (macroImagePixelComponent_Alpha(bitmapPixel) != kMaxImagePixelComponentValue) { return YES; } bitmapPixel++; } bitmapRow += bytesPerRow; } return NO; ERROR: return NO; } - (void) ppMaskedFillUsingMask: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) fillBounds fillPixelValue: (PPImageBitmapPixel) fillPixelValue { NSRect bitmapFrame; unsigned char *destinationData, *maskData, *destinationRow, *maskRow; int destinationBytesPerRow, maskBytesPerRow, rowOffset, destinationDataOffset, maskDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPImageBitmapPixel *destinationPixel; PPMaskBitmapPixel *maskPixel; if (![self ppIsImageBitmapAndSameSizeAsMaskBitmap: maskBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; fillBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(fillBounds), bitmapFrame); if (NSIsEmptyRect(fillBounds)) { goto ERROR; } destinationData = [self bitmapData]; maskData = [maskBitmap bitmapData]; if (!destinationData || !maskData) { goto ERROR; } rowOffset = bitmapFrame.size.height - fillBounds.size.height - fillBounds.origin.y; destinationBytesPerRow = [self bytesPerRow]; destinationDataOffset = rowOffset * destinationBytesPerRow + fillBounds.origin.x * sizeof(PPImageBitmapPixel); destinationRow = &destinationData[destinationDataOffset]; maskBytesPerRow = [maskBitmap bytesPerRow]; maskDataOffset = rowOffset * maskBytesPerRow + fillBounds.origin.x * sizeof(PPMaskBitmapPixel); maskRow = &maskData[maskDataOffset]; pixelsPerRow = fillBounds.size.width; rowCounter = fillBounds.size.height; while (rowCounter--) { destinationPixel = (PPImageBitmapPixel *) destinationRow; maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (*maskPixel++) { *destinationPixel = fillPixelValue; } destinationPixel++; } destinationRow += destinationBytesPerRow; maskRow += maskBytesPerRow; } return; ERROR: return; } - (void) ppMaskedEraseUsingMask: (NSBitmapImageRep *) maskBitmap { [self ppMaskedFillUsingMask: maskBitmap inBounds: [self ppFrameInPixels] fillPixelValue: 0]; } - (void) ppMaskedEraseUsingMask: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) eraseBounds { [self ppMaskedFillUsingMask: maskBitmap inBounds: eraseBounds fillPixelValue: 0]; } - (void) ppMaskedCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap usingMask: (NSBitmapImageRep *) maskBitmap { return [self ppMaskedCopyFromImageBitmap: sourceBitmap usingMask: maskBitmap inBounds: [self ppFrameInPixels]]; } - (void) ppMaskedCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap usingMask: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) copyBounds { NSRect bitmapFrame; unsigned char *destinationData, *sourceData, *maskData, *destinationRow, *sourceRow, *maskRow; int destinationBytesPerRow, sourceBytesPerRow, maskBytesPerRow, rowOffset, destinationDataOffset, sourceDataOffset, maskDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPImageBitmapPixel *destinationPixel, *sourcePixel; PPMaskBitmapPixel *maskPixel; if (![self ppIsImageBitmap] || ![sourceBitmap ppIsImageBitmapAndSameSizeAsMaskBitmap: maskBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; if (!NSEqualSizes(bitmapFrame.size, [sourceBitmap ppSizeInPixels])) { goto ERROR; } copyBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(copyBounds), bitmapFrame); if (NSIsEmptyRect(copyBounds)) { goto ERROR; } destinationData = [self bitmapData]; sourceData = [sourceBitmap bitmapData]; maskData = [maskBitmap bitmapData]; if (!destinationData || !sourceData || !maskData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; sourceBytesPerRow = [sourceBitmap bytesPerRow]; maskBytesPerRow = [maskBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - copyBounds.size.height - copyBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + copyBounds.origin.x * sizeof(PPImageBitmapPixel); sourceDataOffset = rowOffset * sourceBytesPerRow + copyBounds.origin.x * sizeof(PPImageBitmapPixel); maskDataOffset = rowOffset * maskBytesPerRow + copyBounds.origin.x * sizeof(PPMaskBitmapPixel); destinationRow = &destinationData[destinationDataOffset]; sourceRow = &sourceData[sourceDataOffset]; maskRow = &maskData[maskDataOffset]; pixelsPerRow = copyBounds.size.width; rowCounter = copyBounds.size.height; while (rowCounter--) { destinationPixel = (PPImageBitmapPixel *) destinationRow; sourcePixel = (PPImageBitmapPixel *) sourceRow; maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (*maskPixel++) { *destinationPixel = *sourcePixel; } destinationPixel++; sourcePixel++; } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; maskRow += maskBytesPerRow; } return; ERROR: return; } - (void) ppMaskedCopyFromImageBitmap:(NSBitmapImageRep *) sourceBitmap usingMask: (NSBitmapImageRep *) maskBitmap toPoint: (NSPoint) targetPoint { NSRect destinationFrame, sourceFrame, destinationCopyBounds, sourceCopyBounds; unsigned char *destinationData, *sourceData, *maskData, *destinationRow, *sourceRow, *maskRow; int destinationBytesPerRow, sourceBytesPerRow, maskBytesPerRow, rowOffset, destinationDataOffset, sourceDataOffset, maskDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPImageBitmapPixel *destinationPixel, *sourcePixel; PPMaskBitmapPixel *maskPixel; if (![self ppIsImageBitmap] || ![sourceBitmap ppIsImageBitmapAndSameSizeAsMaskBitmap: maskBitmap]) { goto ERROR; } targetPoint = PPGeometry_PointClippedToIntegerValues(targetPoint); destinationFrame = [self ppFrameInPixels]; sourceFrame = [sourceBitmap ppFrameInPixels]; destinationCopyBounds = NSIntersectionRect(NSOffsetRect(sourceFrame, targetPoint.x, targetPoint.y), destinationFrame); if (NSIsEmptyRect(destinationCopyBounds)) { goto ERROR; } sourceCopyBounds = NSOffsetRect(destinationCopyBounds, -targetPoint.x, -targetPoint.y); destinationData = [self bitmapData]; sourceData = [sourceBitmap bitmapData]; maskData = [maskBitmap bitmapData]; if (!destinationData || !sourceData || !maskData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; sourceBytesPerRow = [sourceBitmap bytesPerRow]; maskBytesPerRow = [maskBitmap bytesPerRow]; rowOffset = destinationFrame.size.height - destinationCopyBounds.size.height - destinationCopyBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + destinationCopyBounds.origin.x * sizeof(PPImageBitmapPixel); rowOffset = sourceFrame.size.height - sourceCopyBounds.size.height - sourceCopyBounds.origin.y; sourceDataOffset = rowOffset * sourceBytesPerRow + sourceCopyBounds.origin.x * sizeof(PPImageBitmapPixel); maskDataOffset = rowOffset * maskBytesPerRow + sourceCopyBounds.origin.x * sizeof(PPMaskBitmapPixel); destinationRow = &destinationData[destinationDataOffset]; sourceRow = &sourceData[sourceDataOffset]; maskRow = &maskData[maskDataOffset]; pixelsPerRow = destinationCopyBounds.size.width; rowCounter = destinationCopyBounds.size.height; while (rowCounter--) { destinationPixel = (PPImageBitmapPixel *) destinationRow; sourcePixel = (PPImageBitmapPixel *) sourceRow; maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (*maskPixel++) { *destinationPixel = *sourcePixel; } destinationPixel++; sourcePixel++; } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; maskRow += maskBytesPerRow; } return; ERROR: return; } - (void) ppScaledCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap inRect: (NSRect) sourceRect toPoint: (NSPoint) destinationPoint scalingFactor: (unsigned) scalingFactor { NSRect destinationRect, sourceBitmapFrame, destinationBitmapFrame; unsigned char *sourceData, *destinationData, *scaledRowData, *sourceRow, *destinationRow; int sourceBytesPerRow, numSourceRowsToSkip, sourceDataOffset, destinationBytesPerRow, numDestinationRowsToSkip, destinationDataOffset, scaledRowDataSize, numTimesToCopyScaledRow, pixelsPerRow, rowCounter, pixelCounter, scaleCounter; PPImageBitmapPixel *currentSourcePixel, *currentScaledPixel; if (scalingFactor == 1) { [self ppCopyFromBitmap: sourceBitmap inRect: sourceRect toPoint: destinationPoint]; return; } if (![self ppIsImageBitmap] || ![sourceBitmap ppIsImageBitmap] || (scalingFactor < 1)) { goto ERROR; } sourceRect = PPGeometry_PixelBoundsCoveredByRect(sourceRect); if (NSIsEmptyRect(sourceRect)) { goto ERROR; } destinationRect.origin = PPGeometry_PointClippedToIntegerValues(destinationPoint); destinationRect.size = NSMakeSize(sourceRect.size.width * scalingFactor, sourceRect.size.height * scalingFactor); sourceBitmapFrame = [sourceBitmap ppFrameInPixels]; destinationBitmapFrame = [self ppFrameInPixels]; if (!NSContainsRect(sourceBitmapFrame, sourceRect) || !NSContainsRect(destinationBitmapFrame, destinationRect)) { goto ERROR; } sourceData = [sourceBitmap bitmapData]; destinationData = [self bitmapData]; if (!sourceData || !destinationData) { goto ERROR; } sourceBytesPerRow = [sourceBitmap bytesPerRow]; numSourceRowsToSkip = sourceBitmapFrame.size.height - (sourceRect.origin.y + sourceRect.size.height); sourceDataOffset = numSourceRowsToSkip * sourceBytesPerRow + sizeof(PPImageBitmapPixel) * sourceRect.origin.x; sourceRow = &sourceData[sourceDataOffset]; destinationBytesPerRow = [self bytesPerRow]; numDestinationRowsToSkip = destinationBitmapFrame.size.height - (destinationRect.origin.y + destinationRect.size.height); destinationDataOffset = numDestinationRowsToSkip * destinationBytesPerRow + sizeof(PPImageBitmapPixel) * destinationRect.origin.x; destinationRow = &destinationData[destinationDataOffset]; scaledRowDataSize = sourceRect.size.width * sizeof(PPImageBitmapPixel) * scalingFactor; numTimesToCopyScaledRow = scalingFactor - 1; pixelsPerRow = sourceRect.size.width; rowCounter = sourceRect.size.height; while (rowCounter--) { currentSourcePixel = (PPImageBitmapPixel *) sourceRow; currentScaledPixel = (PPImageBitmapPixel *) destinationRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { scaleCounter = scalingFactor; while (scaleCounter--) { *currentScaledPixel++ = *currentSourcePixel; } currentSourcePixel++; } scaledRowData = destinationRow; destinationRow += destinationBytesPerRow; scaleCounter = numTimesToCopyScaledRow; while (scaleCounter--) { memcpy(destinationRow, scaledRowData, scaledRowDataSize); destinationRow += destinationBytesPerRow; } sourceRow += sourceBytesPerRow; } return; ERROR: return; } - (void) ppScaledCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap inRect: (NSRect) sourceRect toPoint: (NSPoint) destinationPoint scalingFactor: (unsigned) scalingFactor gridType: (PPGridType) gridType gridPixelValue: (PPImageBitmapPixel) gridPixelValue { NSRect destinationRect, sourceBitmapFrame, destinationBitmapFrame; unsigned char *sourceData, *destinationData, *sourceRow, *destinationRow, *scaledRowData; int scaledRowDataSize, sourceBytesPerRow, numSourceRowsToSkip, sourceDataOffset, destinationBytesPerRow, numDestinationRowsToSkip, destinationDataOffset, pixelsPerRow, rowCounter, pixelCounter, scaledPixelCounter, scaledRowCounter; PPImageBitmapPixel *currentSourcePixel, *currentScaledPixel; if (scalingFactor < kMinScalingFactorToDrawGrid) { if (scalingFactor == 1) { [self ppCopyFromBitmap: sourceBitmap inRect: sourceRect toPoint: destinationPoint]; return; } else { [self ppScaledCopyFromImageBitmap: sourceBitmap inRect: sourceRect toPoint: destinationPoint scalingFactor: scalingFactor]; return; } } if (![self ppIsImageBitmap] || ![sourceBitmap ppIsImageBitmap]) { goto ERROR; } if (scalingFactor <= kMaxScalingFactorToForceDotsGridType) { if (gridType != kPPGridType_Lines) { gridType = kPPGridType_Dots; } } sourceRect = PPGeometry_PixelBoundsCoveredByRect(sourceRect); if (NSIsEmptyRect(sourceRect)) { goto ERROR; } destinationRect.origin = PPGeometry_PointClippedToIntegerValues(destinationPoint); destinationRect.size = NSMakeSize(sourceRect.size.width * scalingFactor, sourceRect.size.height * scalingFactor); sourceBitmapFrame = [sourceBitmap ppFrameInPixels]; destinationBitmapFrame = [self ppFrameInPixels]; if (!NSContainsRect(sourceBitmapFrame, sourceRect) || !NSContainsRect(destinationBitmapFrame, destinationRect)) { goto ERROR; } sourceData = [sourceBitmap bitmapData]; destinationData = [self bitmapData]; if (!sourceData || !destinationData) { goto ERROR; } sourceBytesPerRow = [sourceBitmap bytesPerRow]; numSourceRowsToSkip = sourceBitmapFrame.size.height - (sourceRect.origin.y + sourceRect.size.height); sourceDataOffset = numSourceRowsToSkip * sourceBytesPerRow + sizeof(PPImageBitmapPixel) * sourceRect.origin.x; sourceRow = &sourceData[sourceDataOffset]; destinationBytesPerRow = [self bytesPerRow]; numDestinationRowsToSkip = destinationBitmapFrame.size.height - (destinationRect.origin.y + destinationRect.size.height); destinationDataOffset = numDestinationRowsToSkip * destinationBytesPerRow + sizeof(PPImageBitmapPixel) * destinationRect.origin.x; destinationRow = &destinationData[destinationDataOffset]; pixelsPerRow = sourceRect.size.width; scaledRowDataSize = pixelsPerRow * scalingFactor * sizeof(PPImageBitmapPixel); switch (gridType) { case kPPGridType_Lines: // GRIDTYPE: Lines { unsigned char *scaledHorizontalGridLineData; // set up horizontal grid line scaledHorizontalGridLineData = destinationRow; currentScaledPixel = (PPImageBitmapPixel *) scaledHorizontalGridLineData; scaledPixelCounter = pixelsPerRow * scalingFactor; while (scaledPixelCounter--) { *currentScaledPixel++ = gridPixelValue; } // row loop rowCounter = sourceRect.size.height; while (rowCounter--) { // copy horizontal grid line if (destinationRow != scaledHorizontalGridLineData) { memcpy(destinationRow, scaledHorizontalGridLineData, scaledRowDataSize); } destinationRow += destinationBytesPerRow; // set up scaled row data scaledRowData = destinationRow; currentSourcePixel = (PPImageBitmapPixel *) sourceRow; currentScaledPixel = (PPImageBitmapPixel *) scaledRowData; pixelCounter = pixelsPerRow; while (pixelCounter--) { // vertical grid line *currentScaledPixel++ = gridPixelValue; // scaled source-pixel data scaledPixelCounter = scalingFactor - 1; while (scaledPixelCounter--) { *currentScaledPixel++ = *currentSourcePixel; } currentSourcePixel++; } destinationRow += destinationBytesPerRow; // copy scaled row data to remaining rows scaledRowCounter = scalingFactor - 2; while (scaledRowCounter--) { memcpy(destinationRow, scaledRowData, scaledRowDataSize); destinationRow += destinationBytesPerRow; } sourceRow += sourceBytesPerRow; } } break; case kPPGridType_Dots: // GRIDTYPE: Dots { rowCounter = sourceRect.size.height; while (rowCounter--) { // set up scaled row data scaledRowData = destinationRow; currentSourcePixel = (PPImageBitmapPixel *) sourceRow; currentScaledPixel = (PPImageBitmapPixel *) scaledRowData; pixelCounter = pixelsPerRow; while (pixelCounter--) { // scaled source-pixel data (no grid pixels - dots are drawn at the end) scaledPixelCounter = scalingFactor; while (scaledPixelCounter--) { *currentScaledPixel++ = *currentSourcePixel; } currentSourcePixel++; } destinationRow += destinationBytesPerRow; // copy scaled row data to remaining rows scaledRowCounter = scalingFactor - 1; while (scaledRowCounter--) { memcpy(destinationRow, scaledRowData, scaledRowDataSize); destinationRow += destinationBytesPerRow; } // draw dots to first scaled row currentScaledPixel = (PPImageBitmapPixel *) scaledRowData; pixelCounter = pixelsPerRow; while (pixelCounter--) { *currentScaledPixel = gridPixelValue; currentScaledPixel += scalingFactor; } sourceRow += sourceBytesPerRow; } } break; default: // GRIDTYPE: Crosshairs or Large Dots { unsigned gridLegLength, numScaledPixelsBetweenGridLegs; unsigned char *scaledRowWithVerticalGridLegData; if (gridType == kPPGridType_LargeDots) { // Large Dots gridLegLength = 1; } else { // Crosshairs gridLegLength = roundf(scalingFactor * kCrosshairLegSizeToScalingFactorRatio); } numScaledPixelsBetweenGridLegs = scalingFactor - 2 * gridLegLength - 1; // row loop rowCounter = sourceRect.size.height; while (rowCounter--) { // set up scaled row data scaledRowData = destinationRow; currentSourcePixel = (PPImageBitmapPixel *) sourceRow; currentScaledPixel = (PPImageBitmapPixel *) scaledRowData; pixelCounter = pixelsPerRow; while (pixelCounter--) { // scaled source-pixel data (no grid pixels) scaledPixelCounter = scalingFactor; while (scaledPixelCounter--) { *currentScaledPixel++ = *currentSourcePixel; } currentSourcePixel++; } destinationRow += destinationBytesPerRow; // set up scaled row with vertical grid-leg data (single left-edge grid-pixel) scaledRowWithVerticalGridLegData = destinationRow; memcpy(scaledRowWithVerticalGridLegData, scaledRowData, scaledRowDataSize); currentScaledPixel = (PPImageBitmapPixel *) scaledRowWithVerticalGridLegData; pixelCounter = pixelsPerRow; while (pixelCounter--) { *currentScaledPixel = gridPixelValue; currentScaledPixel += scalingFactor; } destinationRow += destinationBytesPerRow; // copy scaled row with vertical grid-leg data to upper rows scaledRowCounter = gridLegLength - 1; while (scaledRowCounter--) { memcpy(destinationRow, scaledRowWithVerticalGridLegData, scaledRowDataSize); destinationRow += destinationBytesPerRow; } // copy scaled row data between grid-leg rows scaledRowCounter = numScaledPixelsBetweenGridLegs; while (scaledRowCounter--) { memcpy(destinationRow, scaledRowData, scaledRowDataSize); destinationRow += destinationBytesPerRow; } // copy scaled row with vertical grid-leg data to lower rows scaledRowCounter = gridLegLength; while (scaledRowCounter--) { memcpy(destinationRow, scaledRowWithVerticalGridLegData, scaledRowDataSize); destinationRow += destinationBytesPerRow; } // draw horizontal grid-legs on first scaled row currentScaledPixel = (PPImageBitmapPixel *) scaledRowData; pixelCounter = pixelsPerRow; while (pixelCounter--) { // center pixel at intersection of horizontal & vertical grid legs *currentScaledPixel++ = gridPixelValue; scaledPixelCounter = gridLegLength; while (scaledPixelCounter--) { *currentScaledPixel++ = gridPixelValue; } currentScaledPixel += numScaledPixelsBetweenGridLegs; scaledPixelCounter = gridLegLength; while (scaledPixelCounter--) { *currentScaledPixel++ = gridPixelValue; } } sourceRow += sourceBytesPerRow; } } break; } return; ERROR: return; } - (NSBitmapImageRep *) ppImageBitmapWithMaxDimension: (float) maxDimension { NSSize originalBitmapSize, maxSize, shrunkenBitmapSize; NSBitmapImageRep *shrunkenBitmap; NSImage *originalBitmapImage; originalBitmapSize = [self ppSizeInPixels]; if (!PPGeometry_SizeExceedsDimension(originalBitmapSize, maxDimension)) { return [self ppImageBitmap]; } maxSize = NSMakeSize(maxDimension, maxDimension); shrunkenBitmapSize = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(originalBitmapSize, maxSize).size; shrunkenBitmap = [NSBitmapImageRep ppImageBitmapOfSize: shrunkenBitmapSize]; originalBitmapImage = [NSImage ppImageWithBitmap: self]; if (!shrunkenBitmap || !originalBitmapImage) { goto ERROR; } [shrunkenBitmap ppSetAsCurrentGraphicsContext]; [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationNone]; [originalBitmapImage drawInRect: PPGeometry_OriginRectOfSize(shrunkenBitmapSize) fromRect: PPGeometry_OriginRectOfSize(originalBitmapSize) operation: NSCompositeCopy fraction: 1.0f]; [shrunkenBitmap ppRestoreGraphicsContext]; return shrunkenBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppImageBitmapCompositedWithBackgroundColor: (NSColor *) backgroundColor andBackgroundImage: (NSImage *) backgroundImage backgroundImageInterpolation: (NSImageInterpolation) backgroundImageInterpolation { NSRect bitmapFrame; NSBitmapImageRep *compositedBitmap; NSImage *bitmapImage; if (!backgroundColor && !backgroundImage) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; compositedBitmap = [NSBitmapImageRep ppImageBitmapOfSize: bitmapFrame.size]; bitmapImage = [NSImage ppImageWithBitmap: self]; if (!compositedBitmap || !bitmapImage) { goto ERROR; } [compositedBitmap ppSetAsCurrentGraphicsContext]; if (backgroundColor) { [backgroundColor set]; NSRectFill(bitmapFrame); } if (backgroundImage) { NSRect backgroundImageFrame, backgroundDestinationBounds; backgroundImageFrame = PPGeometry_OriginRectOfSize([backgroundImage size]); backgroundDestinationBounds = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(backgroundImageFrame.size, bitmapFrame.size); [[NSGraphicsContext currentContext] setImageInterpolation: backgroundImageInterpolation]; [backgroundImage drawInRect: backgroundDestinationBounds fromRect: backgroundImageFrame operation: NSCompositeSourceOver fraction: 1.0f]; } [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationNone]; [bitmapImage drawInRect: bitmapFrame fromRect: bitmapFrame operation: NSCompositeSourceOver fraction: 1.0f]; [compositedBitmap ppRestoreGraphicsContext]; return compositedBitmap; ERROR: return self; } - (NSBitmapImageRep *) ppImageBitmapDissolvedToOpacity: (float) opacity { NSBitmapImageRep *dissolvedBitmap; if (![self ppIsImageBitmap]) { goto ERROR; } if (opacity >= 1.0f) { dissolvedBitmap = [[self copy] autorelease]; if (!dissolvedBitmap) goto ERROR; } else { NSRect bitmapFrame = [self ppFrameInPixels]; dissolvedBitmap = [NSBitmapImageRep ppImageBitmapOfSize: bitmapFrame.size]; if (!dissolvedBitmap) goto ERROR; if (opacity > 0.0f) { NSImage *image = [NSImage ppImageWithBitmap: self]; if (!image) goto ERROR; [dissolvedBitmap ppSetAsCurrentGraphicsContext]; [image drawInRect: bitmapFrame fromRect: bitmapFrame operation: NSCompositeCopy fraction: opacity]; [dissolvedBitmap ppRestoreGraphicsContext]; } } return dissolvedBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppImageBitmapMaskedWithMask: (NSBitmapImageRep *) maskBitmap { NSBitmapImageRep *maskedBitmap; if (![self ppIsImageBitmapAndSameSizeAsMaskBitmap: maskBitmap]) { goto ERROR; } maskedBitmap = [NSBitmapImageRep ppImageBitmapOfSize: [self ppSizeInPixels]]; if (!maskedBitmap) goto ERROR; [maskedBitmap ppMaskedCopyFromImageBitmap: self usingMask: maskBitmap]; return maskedBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppImageBitmapScaledByFactor: (unsigned) scalingFactor shouldDrawGrid: (bool) shouldDrawGrid gridType: (PPGridType) gridType gridColor: (NSColor *) gridColor { NSRect bitmapFrame; NSSize scaledBitmapSize; NSBitmapImageRep *scaledBitmap; if (![self ppIsImageBitmap] || !scalingFactor) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; scaledBitmapSize = NSMakeSize(bitmapFrame.size.width * scalingFactor, bitmapFrame.size.height * scalingFactor); scaledBitmap = [NSBitmapImageRep ppImageBitmapOfSize: scaledBitmapSize]; if (!scaledBitmap) goto ERROR; if (shouldDrawGrid) { [scaledBitmap ppScaledCopyFromImageBitmap: self inRect: bitmapFrame toPoint: NSZeroPoint scalingFactor: scalingFactor gridType: gridType gridPixelValue: [gridColor ppImageBitmapPixelValue]]; } else { [scaledBitmap ppScaledCopyFromImageBitmap: self inRect: bitmapFrame toPoint: NSZeroPoint scalingFactor: scalingFactor]; } return scaledBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppMaskBitmapForVisiblePixelsInImageBitmap { NSSize bitmapSize; NSBitmapImageRep *maskBitmap; if (![self ppIsImageBitmap]) { goto ERROR; } bitmapSize = [self ppSizeInPixels]; if (PPGeometry_IsZeroSize(bitmapSize)) { goto ERROR; } maskBitmap = [NSBitmapImageRep ppMaskBitmapOfSize: bitmapSize]; if (!maskBitmap) goto ERROR; [maskBitmap ppMaskVisiblePixelsInImageBitmap: self selectionMask: nil]; return maskBitmap; ERROR: return nil; } - (void) ppDrawImageGuidelinesInBounds: (NSRect) drawBounds topLeftPhase: (NSPoint) topLeftPhase unscaledSpacingSize: (NSSize) unscaledSpacingSize scalingFactor: (unsigned) scalingFactor guidelinePixelValue: (PPImageBitmapPixel) guidelinePixelValue { NSRect bitmapFrame; int colOffsetToNextVerticalLine, rowOffsetToNextHorizontalLine, drawBoundsLeftCol, drawBoundsRightCol, drawBoundsTopRow, drawBoundsBottomRow, colOfFirstVerticalLine, numVerticalLines = 0, rowOfFirstHorizontalLine, numHorizontalLines = 0, bytesPerRow, startRow, rowIncrement, rowDataOffsetToFirstVerticalLine, dataOffset, rowDataIncrement, horizontalLineDataSize, rowOfNextHorizontalLine, row, verticalLineCounter; NSPoint offsetToNextGuidelineVertex; unsigned char *bitmapData, *previousHorizontalLineData = NULL, *rowData; PPImageBitmapPixel *verticalLinePixel; if (![self ppIsImageBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; drawBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(drawBounds), bitmapFrame); if (NSIsEmptyRect(drawBounds)) { goto ERROR; } topLeftPhase = PPGeometry_PointClippedToIntegerValues(topLeftPhase); if (scalingFactor > kMaxCanvasZoomFactor) { goto ERROR; } colOffsetToNextVerticalLine = unscaledSpacingSize.width * scalingFactor; rowOffsetToNextHorizontalLine = unscaledSpacingSize.height * scalingFactor; if ((colOffsetToNextVerticalLine < kMinScalingFactorToDrawGrid) || (rowOffsetToNextHorizontalLine < kMinScalingFactorToDrawGrid)) { // guidelines are too close together at current scalingFactor, so don't draw return; } drawBoundsLeftCol = drawBounds.origin.x; drawBoundsRightCol = drawBoundsLeftCol + drawBounds.size.width - 1; drawBoundsTopRow = bitmapFrame.size.height - (drawBounds.origin.y + drawBounds.size.height); drawBoundsBottomRow = drawBoundsTopRow + drawBounds.size.height - 1; offsetToNextGuidelineVertex = PPGeometry_OffsetPointToNextNearestVertexOnGridWithSpacingSize( NSMakePoint(drawBoundsLeftCol + topLeftPhase.x, drawBoundsTopRow + topLeftPhase.y), NSMakeSize(colOffsetToNextVerticalLine, rowOffsetToNextHorizontalLine)); if ((offsetToNextGuidelineVertex.x < 0) || (offsetToNextGuidelineVertex.y < 0)) { goto ERROR; } colOfFirstVerticalLine = drawBoundsLeftCol + offsetToNextGuidelineVertex.x; if (colOfFirstVerticalLine <= drawBoundsRightCol) { numVerticalLines = 1 + (drawBoundsRightCol - colOfFirstVerticalLine) / colOffsetToNextVerticalLine; } rowOfFirstHorizontalLine = drawBoundsTopRow + offsetToNextGuidelineVertex.y; if (rowOfFirstHorizontalLine <= drawBoundsBottomRow) { numHorizontalLines = 1 + (drawBoundsBottomRow - rowOfFirstHorizontalLine) / rowOffsetToNextHorizontalLine; } if (!numVerticalLines && !numHorizontalLines) { // no guidelines within drawBounds - nothing to draw return; } bitmapData = [self bitmapData]; bytesPerRow = [self bytesPerRow]; if (!bitmapData || (bytesPerRow <= 0)) { goto ERROR; } if (numVerticalLines > 0) { startRow = drawBoundsTopRow; rowIncrement = 1; rowDataOffsetToFirstVerticalLine = (colOfFirstVerticalLine - drawBoundsLeftCol) * sizeof(PPImageBitmapPixel); } else { // no vertical guidelines within drawBounds - only need to draw horizontal guidelines startRow = rowOfFirstHorizontalLine; rowIncrement = rowOffsetToNextHorizontalLine; rowDataOffsetToFirstVerticalLine = 0; // avoids analyzer warning (undefined subscript) } dataOffset = startRow * bytesPerRow + drawBoundsLeftCol * sizeof(PPImageBitmapPixel); rowData = &bitmapData[dataOffset]; rowDataIncrement = rowIncrement * bytesPerRow; horizontalLineDataSize = drawBounds.size.width * sizeof(PPImageBitmapPixel); rowOfNextHorizontalLine = rowOfFirstHorizontalLine; row = startRow; while (row <= drawBoundsBottomRow) { if (row == rowOfNextHorizontalLine) { // row with horizontal line if (!previousHorizontalLineData) { PPImageBitmapPixel *currentPixel = (PPImageBitmapPixel *) rowData; int pixelCounter = drawBounds.size.width; while (pixelCounter--) { *currentPixel++ = guidelinePixelValue; } } else { memcpy(rowData, previousHorizontalLineData, horizontalLineDataSize); } previousHorizontalLineData = rowData; rowOfNextHorizontalLine += rowOffsetToNextHorizontalLine; } else { // row with vertical lines verticalLinePixel = (PPImageBitmapPixel *) &rowData[rowDataOffsetToFirstVerticalLine]; verticalLineCounter = numVerticalLines; while (verticalLineCounter--) { *verticalLinePixel = guidelinePixelValue; verticalLinePixel += colOffsetToNextVerticalLine; } } rowData += rowDataIncrement; row += rowIncrement; } return; ERROR: return; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m0000644000076500000240000007213413234403205027234 0ustar joshstaff/* NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" #import "PPImagePixelAlphaPremultiplyTables.h" #import "PPSRGBUtilities.h" #define kLinearRGB16BitmapBitsPerSample \ (sizeof(PPLinear16PixelComponent) * 8) #define kLinearRGB16BitmapSamplesPerPixel \ (sizeof(PPLinearRGB16BitmapPixel) / sizeof(PPLinear16PixelComponent)) #define kImagePixelComponentToLinear16PixelComponentConversionFactor \ (kMaxLinear16PixelComponentValue / kMaxImagePixelComponentValue) #define macroRoundoffValueForDivisor(divisor) \ (((divisor) + 1) / 2) #define kImageToLinear16ConversionPrenormalizationRoundoff \ macroRoundoffValueForDivisor( \ kImagePixelComponentToLinear16PixelComponentConversionFactor) #define kLinear16PixelComponentPrenormalizationRoundoff \ macroRoundoffValueForDivisor(kMaxLinear16PixelComponentValue) #define macroClampFloatValueTo0_1(floatValue) \ ((floatValue >= 1.0f) ? 1.0f : ((floatValue <= 0.0f) ? 0.0f : floatValue)) static PPImagePixelComponent *gSRGBValuesForLinear16ValuesTable; static PPLinear16PixelComponent *gLinear16ValuesForSRGBValuesTable; static bool SetupGlobalLinearConversionTables(void); @implementation NSBitmapImageRep (PPUtilities_LinearRGB16Bitmaps) + (void) load { SetupGlobalLinearConversionTables(); } + (NSBitmapImageRep *) ppLinearRGB16BitmapOfSize: (NSSize) size { NSBitmapImageRep *linearBitmap; size = PPGeometry_SizeClippedToIntegerValues(size); if (PPGeometry_IsZeroSize(size)) { goto ERROR; } linearBitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: size.width pixelsHigh: size.height bitsPerSample: kLinearRGB16BitmapBitsPerSample samplesPerPixel: kLinearRGB16BitmapSamplesPerPixel hasAlpha: YES isPlanar: NO colorSpaceName: NSDeviceRGBColorSpace bitmapFormat: NSAlphaNonpremultipliedBitmapFormat bytesPerRow: 0 bitsPerPixel: 0] autorelease]; if (!linearBitmap) goto ERROR; [linearBitmap ppClearBitmap]; return linearBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppLinearRGB16BitmapFromImageBitmap { NSRect frame; NSBitmapImageRep *linearBitmap; if (![self ppIsImageBitmap]) { goto ERROR; } frame = [self ppFrameInPixels]; if (NSIsEmptyRect(frame)) { goto ERROR; } linearBitmap = [NSBitmapImageRep ppLinearRGB16BitmapOfSize: frame.size]; if (!linearBitmap) goto ERROR; [linearBitmap ppLinearCopyFromImageBitmap: self inBounds: frame]; return linearBitmap; ERROR: return nil; } - (NSBitmapImageRep *) ppImageBitmapFromLinearRGB16Bitmap { NSRect frame; NSBitmapImageRep *imageBitmap; if (![self ppIsLinearRGB16Bitmap]) { goto ERROR; } frame = [self ppFrameInPixels]; if (NSIsEmptyRect(frame)) { goto ERROR; } imageBitmap = [NSBitmapImageRep ppImageBitmapOfSize: frame.size]; if (!imageBitmap) goto ERROR; [self ppLinearCopyToImageBitmap: imageBitmap inBounds: frame]; return imageBitmap; ERROR: return nil; } - (bool) ppIsLinearRGB16Bitmap { return (([self bitsPerSample] == kLinearRGB16BitmapBitsPerSample) && ([self samplesPerPixel] == kLinearRGB16BitmapSamplesPerPixel)) ? YES : NO; } - (void) ppLinearCopyFromImageBitmap: (NSBitmapImageRep *) sourceBitmap inBounds: (NSRect) copyBounds { NSRect bitmapFrame; unsigned char *destinationData, *sourceData, *destinationRow, *sourceRow; int destinationBytesPerRow, sourceBytesPerRow, rowOffset, destinationDataOffset, sourceDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPLinearRGB16BitmapPixel *destinationPixel; PPImageBitmapPixel *sourcePixel; PPImagePixelComponent *unpremultiplyTable; if (![self ppIsLinearRGB16Bitmap] || ![sourceBitmap ppIsImageBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; if (!NSEqualSizes(bitmapFrame.size, [sourceBitmap ppSizeInPixels])) { goto ERROR; } copyBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(copyBounds), bitmapFrame); if (NSIsEmptyRect(copyBounds)) { goto ERROR; } destinationData = [self bitmapData]; sourceData = [sourceBitmap bitmapData]; if (!destinationData || !sourceData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; sourceBytesPerRow = [sourceBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - copyBounds.size.height - copyBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + copyBounds.origin.x * sizeof(PPLinearRGB16BitmapPixel); sourceDataOffset = rowOffset * sourceBytesPerRow + copyBounds.origin.x * sizeof(PPImageBitmapPixel); destinationRow = &destinationData[destinationDataOffset]; sourceRow = &sourceData[sourceDataOffset]; pixelsPerRow = copyBounds.size.width; rowCounter = copyBounds.size.height; while (rowCounter--) { destinationPixel = (PPLinearRGB16BitmapPixel *) destinationRow; sourcePixel = (PPImageBitmapPixel *) sourceRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (macroImagePixelComponent_Alpha(sourcePixel) == 0) { *destinationPixel = 0; } else if (macroImagePixelComponent_Alpha(sourcePixel) == kMaxImagePixelComponentValue) { macroLinearRGB16PixelComponent_Red(destinationPixel) = gLinear16ValuesForSRGBValuesTable[ macroImagePixelComponent_Red(sourcePixel)]; macroLinearRGB16PixelComponent_Green(destinationPixel) = gLinear16ValuesForSRGBValuesTable[ macroImagePixelComponent_Green(sourcePixel)]; macroLinearRGB16PixelComponent_Blue(destinationPixel) = gLinear16ValuesForSRGBValuesTable[ macroImagePixelComponent_Blue(sourcePixel)]; macroLinearRGB16PixelComponent_Alpha(destinationPixel) = kMaxLinear16PixelComponentValue; } else { unpremultiplyTable = macroAlphaUnpremultiplyTableForImagePixel(sourcePixel); macroLinearRGB16PixelComponent_Red(destinationPixel) = gLinear16ValuesForSRGBValuesTable[ unpremultiplyTable[macroImagePixelComponent_Red(sourcePixel)]]; macroLinearRGB16PixelComponent_Green(destinationPixel) = gLinear16ValuesForSRGBValuesTable[ unpremultiplyTable[macroImagePixelComponent_Green(sourcePixel)]]; macroLinearRGB16PixelComponent_Blue(destinationPixel) = gLinear16ValuesForSRGBValuesTable[ unpremultiplyTable[macroImagePixelComponent_Blue(sourcePixel)]]; macroLinearRGB16PixelComponent_Alpha(destinationPixel) = ((int) macroImagePixelComponent_Alpha(sourcePixel)) * kImagePixelComponentToLinear16PixelComponentConversionFactor; } destinationPixel++; sourcePixel++; } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; } return; ERROR: return; } - (void) ppLinearCopyToImageBitmap: (NSBitmapImageRep *) destinationBitmap inBounds: (NSRect) copyBounds { NSRect bitmapFrame; unsigned char *destinationData, *sourceData, *destinationRow, *sourceRow; int destinationBytesPerRow, sourceBytesPerRow, rowOffset, destinationDataOffset, sourceDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPImageBitmapPixel *destinationPixel; PPLinearRGB16BitmapPixel *sourcePixel; PPImagePixelComponent *premultiplyTable; if (![self ppIsLinearRGB16Bitmap] || ![destinationBitmap ppIsImageBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; if (!NSEqualSizes(bitmapFrame.size, [destinationBitmap ppSizeInPixels])) { goto ERROR; } copyBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(copyBounds), bitmapFrame); if (NSIsEmptyRect(copyBounds)) { goto ERROR; } destinationData = [destinationBitmap bitmapData]; sourceData = [self bitmapData]; if (!destinationData || !sourceData) { goto ERROR; } destinationBytesPerRow = [destinationBitmap bytesPerRow]; sourceBytesPerRow = [self bytesPerRow]; rowOffset = bitmapFrame.size.height - copyBounds.size.height - copyBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + copyBounds.origin.x * sizeof(PPImageBitmapPixel); sourceDataOffset = rowOffset * sourceBytesPerRow + copyBounds.origin.x * sizeof(PPLinearRGB16BitmapPixel); destinationRow = &destinationData[destinationDataOffset]; sourceRow = &sourceData[sourceDataOffset]; pixelsPerRow = copyBounds.size.width; rowCounter = copyBounds.size.height; while (rowCounter--) { destinationPixel = (PPImageBitmapPixel *) destinationRow; sourcePixel = (PPLinearRGB16BitmapPixel *) sourceRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { macroImagePixelComponent_Alpha(destinationPixel) = (macroLinearRGB16PixelComponent_Alpha(sourcePixel) + kImageToLinear16ConversionPrenormalizationRoundoff) / kImagePixelComponentToLinear16PixelComponentConversionFactor; if (macroImagePixelComponent_Alpha(destinationPixel) == 0) { *destinationPixel = 0; } else if (macroImagePixelComponent_Alpha(destinationPixel) == kMaxImagePixelComponentValue) { macroImagePixelComponent_Red(destinationPixel) = gSRGBValuesForLinear16ValuesTable[ macroLinearRGB16PixelComponent_Red(sourcePixel)]; macroImagePixelComponent_Green(destinationPixel) = gSRGBValuesForLinear16ValuesTable[ macroLinearRGB16PixelComponent_Green(sourcePixel)]; macroImagePixelComponent_Blue(destinationPixel) = gSRGBValuesForLinear16ValuesTable[ macroLinearRGB16PixelComponent_Blue(sourcePixel)]; } else { premultiplyTable = macroAlphaPremultiplyTableForImagePixel(destinationPixel); macroImagePixelComponent_Red(destinationPixel) = premultiplyTable[ gSRGBValuesForLinear16ValuesTable[ macroLinearRGB16PixelComponent_Red(sourcePixel)]]; macroImagePixelComponent_Green(destinationPixel) = premultiplyTable[ gSRGBValuesForLinear16ValuesTable[ macroLinearRGB16PixelComponent_Green(sourcePixel)]]; macroImagePixelComponent_Blue(destinationPixel) = premultiplyTable[ gSRGBValuesForLinear16ValuesTable[ macroLinearRGB16PixelComponent_Blue(sourcePixel)]]; } destinationPixel++; sourcePixel++; } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; } return; ERROR: return; } - (void) ppLinearBlendFromLinearBitmapUnderneath: (NSBitmapImageRep *) sourceBitmap sourceOpacity: (float) sourceOpacity inBounds: (NSRect) blendingBounds { NSRect bitmapFrame; unsigned char *destinationData, *sourceData, *destinationRow, *sourceRow; unsigned int sourceOpacityFactor, destinationComponentAlphaFactor, sourceComponentAlphaFactor, sumOfAlphaFactors, alphaFactorsPrenormalizationRoundoff; int destinationBytesPerRow, sourceBytesPerRow, rowOffset, destinationDataOffset, sourceDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPLinearRGB16BitmapPixel *destinationPixel, *sourcePixel; if (![self ppIsLinearRGB16Bitmap] || ![sourceBitmap ppIsLinearRGB16Bitmap]) { goto ERROR; } sourceOpacity = macroClampFloatValueTo0_1(sourceOpacity); sourceOpacityFactor = roundf(sourceOpacity * kMaxLinear16PixelComponentValue); if (sourceOpacityFactor == 0) { return; } bitmapFrame = [self ppFrameInPixels]; if (!NSEqualSizes(bitmapFrame.size, [sourceBitmap ppSizeInPixels])) { goto ERROR; } blendingBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(blendingBounds), bitmapFrame); if (NSIsEmptyRect(blendingBounds)) { goto ERROR; } destinationData = [self bitmapData]; sourceData = [sourceBitmap bitmapData]; if (!destinationData || !sourceData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; sourceBytesPerRow = [sourceBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - blendingBounds.size.height - blendingBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + blendingBounds.origin.x * sizeof(PPLinearRGB16BitmapPixel); sourceDataOffset = rowOffset * sourceBytesPerRow + blendingBounds.origin.x * sizeof(PPLinearRGB16BitmapPixel); destinationRow = &destinationData[destinationDataOffset]; sourceRow = &sourceData[sourceDataOffset]; pixelsPerRow = blendingBounds.size.width; rowCounter = blendingBounds.size.height; if (sourceOpacityFactor < kMaxLinear16PixelComponentValue) { while (rowCounter--) { destinationPixel = (PPLinearRGB16BitmapPixel *) destinationRow; sourcePixel = (PPLinearRGB16BitmapPixel *) sourceRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (macroLinearRGB16PixelComponent_Alpha(destinationPixel) > 0) { if ((macroLinearRGB16PixelComponent_Alpha(destinationPixel) < kMaxLinear16PixelComponentValue) && (macroLinearRGB16PixelComponent_Alpha(sourcePixel) > 0)) { destinationComponentAlphaFactor = macroLinearRGB16PixelComponent_Alpha(destinationPixel); sourceComponentAlphaFactor = (sourceOpacityFactor * (kMaxLinear16PixelComponentValue - destinationComponentAlphaFactor) + kLinear16PixelComponentPrenormalizationRoundoff) / kMaxLinear16PixelComponentValue; if (macroLinearRGB16PixelComponent_Alpha(sourcePixel) < kMaxLinear16PixelComponentValue) { sourceComponentAlphaFactor = (sourceComponentAlphaFactor * macroLinearRGB16PixelComponent_Alpha(sourcePixel) + kLinear16PixelComponentPrenormalizationRoundoff) / kMaxLinear16PixelComponentValue; } sumOfAlphaFactors = destinationComponentAlphaFactor + sourceComponentAlphaFactor; alphaFactorsPrenormalizationRoundoff = macroRoundoffValueForDivisor(sumOfAlphaFactors); macroLinearRGB16PixelComponent_Red(destinationPixel) = (destinationComponentAlphaFactor * macroLinearRGB16PixelComponent_Red(destinationPixel) + sourceComponentAlphaFactor * macroLinearRGB16PixelComponent_Red(sourcePixel) + alphaFactorsPrenormalizationRoundoff) / sumOfAlphaFactors; macroLinearRGB16PixelComponent_Green(destinationPixel) = (destinationComponentAlphaFactor * macroLinearRGB16PixelComponent_Green(destinationPixel) + sourceComponentAlphaFactor * macroLinearRGB16PixelComponent_Green(sourcePixel) + alphaFactorsPrenormalizationRoundoff) / sumOfAlphaFactors; macroLinearRGB16PixelComponent_Blue(destinationPixel) = (destinationComponentAlphaFactor * macroLinearRGB16PixelComponent_Blue(destinationPixel) + sourceComponentAlphaFactor * macroLinearRGB16PixelComponent_Blue(sourcePixel) + alphaFactorsPrenormalizationRoundoff) / sumOfAlphaFactors; macroLinearRGB16PixelComponent_Alpha(destinationPixel) = sumOfAlphaFactors; } } else if (macroLinearRGB16PixelComponent_Alpha(sourcePixel) > 0) { *destinationPixel = *sourcePixel; macroLinearRGB16PixelComponent_Alpha(destinationPixel) = (sourceOpacityFactor * macroLinearRGB16PixelComponent_Alpha(destinationPixel) + kLinear16PixelComponentPrenormalizationRoundoff) / kMaxLinear16PixelComponentValue; } destinationPixel++; sourcePixel++; } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; } } else // sourceOpacity is 1.0 { while (rowCounter--) { destinationPixel = (PPLinearRGB16BitmapPixel *) destinationRow; sourcePixel = (PPLinearRGB16BitmapPixel *) sourceRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (macroLinearRGB16PixelComponent_Alpha(destinationPixel) > 0) { if ((macroLinearRGB16PixelComponent_Alpha(destinationPixel) < kMaxLinear16PixelComponentValue) && (macroLinearRGB16PixelComponent_Alpha(sourcePixel) > 0)) { destinationComponentAlphaFactor = macroLinearRGB16PixelComponent_Alpha(destinationPixel); sourceComponentAlphaFactor = kMaxLinear16PixelComponentValue - destinationComponentAlphaFactor; if (macroLinearRGB16PixelComponent_Alpha(sourcePixel) < kMaxLinear16PixelComponentValue) { sourceComponentAlphaFactor = (sourceComponentAlphaFactor * macroLinearRGB16PixelComponent_Alpha(sourcePixel) + kLinear16PixelComponentPrenormalizationRoundoff) / kMaxLinear16PixelComponentValue; } sumOfAlphaFactors = destinationComponentAlphaFactor + sourceComponentAlphaFactor; alphaFactorsPrenormalizationRoundoff = macroRoundoffValueForDivisor(sumOfAlphaFactors); macroLinearRGB16PixelComponent_Red(destinationPixel) = (destinationComponentAlphaFactor * macroLinearRGB16PixelComponent_Red(destinationPixel) + sourceComponentAlphaFactor * macroLinearRGB16PixelComponent_Red(sourcePixel) + alphaFactorsPrenormalizationRoundoff) / sumOfAlphaFactors; macroLinearRGB16PixelComponent_Green(destinationPixel) = (destinationComponentAlphaFactor * macroLinearRGB16PixelComponent_Green(destinationPixel) + sourceComponentAlphaFactor * macroLinearRGB16PixelComponent_Green(sourcePixel) + alphaFactorsPrenormalizationRoundoff) / sumOfAlphaFactors; macroLinearRGB16PixelComponent_Blue(destinationPixel) = (destinationComponentAlphaFactor * macroLinearRGB16PixelComponent_Blue(destinationPixel) + sourceComponentAlphaFactor * macroLinearRGB16PixelComponent_Blue(sourcePixel) + alphaFactorsPrenormalizationRoundoff) / sumOfAlphaFactors; macroLinearRGB16PixelComponent_Alpha(destinationPixel) = sumOfAlphaFactors; } } else if (macroLinearRGB16PixelComponent_Alpha(sourcePixel) > 0) { *destinationPixel = *sourcePixel; } destinationPixel++; sourcePixel++; } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; } } return; ERROR: return; } - (void) ppLinearCopyFromLinearBitmap: (NSBitmapImageRep *) sourceBitmap opacity: (float) opacity inBounds: (NSRect) copyBounds { NSRect bitmapFrame; unsigned char *destinationData, *sourceData, *destinationRow, *sourceRow; unsigned int opacityFactor; int destinationBytesPerRow, sourceBytesPerRow, rowOffset, destinationDataOffset, sourceDataOffset, pixelsPerRow, bytesToCopyPerRow, rowCounter, pixelCounter; PPLinearRGB16BitmapPixel *destinationPixel; if (![self ppIsLinearRGB16Bitmap] || ![sourceBitmap ppIsLinearRGB16Bitmap]) { goto ERROR; } opacity = macroClampFloatValueTo0_1(opacity); opacityFactor = roundf(opacity * kMaxLinear16PixelComponentValue); if (opacityFactor >= kMaxLinear16PixelComponentValue) { [self ppCopyFromBitmap: sourceBitmap inRect: copyBounds toPoint: copyBounds.origin]; return; } else if (opacityFactor == 0) { [self ppClearBitmapInBounds: copyBounds]; return; } bitmapFrame = [self ppFrameInPixels]; if (!NSEqualSizes(bitmapFrame.size, [sourceBitmap ppSizeInPixels])) { goto ERROR; } copyBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(copyBounds), bitmapFrame); if (NSIsEmptyRect(copyBounds)) { goto ERROR; } destinationData = [self bitmapData]; sourceData = [sourceBitmap bitmapData]; if (!destinationData || !sourceData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; sourceBytesPerRow = [sourceBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - copyBounds.size.height - copyBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + copyBounds.origin.x * sizeof(PPLinearRGB16BitmapPixel); sourceDataOffset = rowOffset * sourceBytesPerRow + copyBounds.origin.x * sizeof(PPLinearRGB16BitmapPixel); destinationRow = &destinationData[destinationDataOffset]; sourceRow = &sourceData[sourceDataOffset]; pixelsPerRow = copyBounds.size.width; bytesToCopyPerRow = pixelsPerRow * sizeof(PPLinearRGB16BitmapPixel); rowCounter = copyBounds.size.height; while (rowCounter--) { // copy the row's pixel data memcpy(destinationRow, sourceRow, bytesToCopyPerRow); // loop over the copied pixels & multiply the alpha components by the opacity destinationPixel = (PPLinearRGB16BitmapPixel *) destinationRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { macroLinearRGB16PixelComponent_Alpha(destinationPixel) = (opacityFactor * macroLinearRGB16PixelComponent_Alpha(destinationPixel) + kLinear16PixelComponentPrenormalizationRoundoff) / kMaxLinear16PixelComponentValue; destinationPixel++; } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; } return; ERROR: return; } @end #pragma mark Private functions static bool SetupGlobalLinearConversionTables(void) { int sizeOfSRGBValuesForLinearValuesTable, sizeOfLinearValuesForSRGBValuesTable, tableIndexCounter; unsigned char *tablesBuffer = NULL; PPImagePixelComponent *sRGBComponentTableEntry; PPLinear16PixelComponent *linearComponentTableEntry; float linearFloatValue, sRGBFloatValue; sizeOfSRGBValuesForLinearValuesTable = ((int) kMaxLinear16PixelComponentValue + 1) * sizeof(PPImagePixelComponent); sizeOfLinearValuesForSRGBValuesTable = ((int) kMaxImagePixelComponentValue + 1) * sizeof(PPLinear16PixelComponent); tablesBuffer = (unsigned char *) malloc (sizeOfSRGBValuesForLinearValuesTable + sizeOfLinearValuesForSRGBValuesTable); if (!tablesBuffer) goto ERROR; gSRGBValuesForLinear16ValuesTable = (PPImagePixelComponent *) &tablesBuffer[0]; gLinear16ValuesForSRGBValuesTable = (PPLinear16PixelComponent *) &tablesBuffer[sizeOfSRGBValuesForLinearValuesTable]; sRGBComponentTableEntry = gSRGBValuesForLinear16ValuesTable; for (tableIndexCounter=0; tableIndexCounter<=kMaxLinear16PixelComponentValue; tableIndexCounter++) { linearFloatValue = ((float) tableIndexCounter) / ((float) kMaxLinear16PixelComponentValue); *sRGBComponentTableEntry++ = (PPImagePixelComponent) roundf(((float) kMaxImagePixelComponentValue) * macroSRGBUtils_SRGBFloatValueFromLinearFloatValue(linearFloatValue)); } linearComponentTableEntry = gLinear16ValuesForSRGBValuesTable; for (tableIndexCounter=0; tableIndexCounter<=kMaxImagePixelComponentValue; tableIndexCounter++) { sRGBFloatValue = ((float) tableIndexCounter) / ((float) kMaxImagePixelComponentValue); *linearComponentTableEntry++ = (PPLinear16PixelComponent) roundf(((float) kMaxLinear16PixelComponentValue) * macroSRGBUtils_LinearFloatValueFromSRGBFloatValue(sRGBFloatValue)); } return YES; ERROR: if (tablesBuffer) { free(tablesBuffer); } gSRGBValuesForLinear16ValuesTable = NULL; gLinear16ValuesForSRGBValuesTable = NULL; return NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/NSBitmapImageRep_PPUtilities_MaskBitmaps.m0000644000076500000240000005150513234403205026212 0ustar joshstaff/* NSBitmapImageRep_PPUtilities_MaskBitmaps.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" #define kMaskBitmapBitsPerSample (sizeof(PPMaskBitmapPixel) * 8) #define kMaskBitmapSamplesPerPixel (1) @implementation NSBitmapImageRep (PPUtilities_MaskBitmaps) + (NSBitmapImageRep *) ppMaskBitmapOfSize: (NSSize) size { NSBitmapImageRep *maskBitmap; size = PPGeometry_SizeClippedToIntegerValues(size); if (PPGeometry_IsZeroSize(size)) { goto ERROR; } maskBitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: size.width pixelsHigh: size.height bitsPerSample: kMaskBitmapBitsPerSample samplesPerPixel: kMaskBitmapSamplesPerPixel hasAlpha: NO isPlanar: NO colorSpaceName: NSDeviceWhiteColorSpace bytesPerRow: 0 bitsPerPixel: 0] autorelease]; if (!maskBitmap) goto ERROR; [maskBitmap ppClearBitmap]; return maskBitmap; ERROR: return nil; } - (bool) ppIsMaskBitmap { return ([self samplesPerPixel] == kMaskBitmapSamplesPerPixel) ? YES : NO; } - (NSRect) ppMaskBounds { return [self ppMaskBoundsInRect: [self ppFrameInPixels]]; } - (NSRect) ppMaskBoundsInRect: (NSRect) checkBounds { NSRect frame; int bytesPerRow, maskLeft, maskTop, maskBottom, maskRight, checkLeft, checkRight, checkBottom, checkTop, row, col; unsigned char *upperLeftBoundedData, *rowData; PPMaskBitmapPixel *maskPixel; if (![self ppIsMaskBitmap]) { goto ERROR; } frame = [self ppFrameInPixels]; checkBounds = NSIntersectionRect(frame, PPGeometry_PixelBoundsCoveredByRect(checkBounds)); if (NSIsEmptyRect(checkBounds)) { goto ERROR; } checkBottom = checkBounds.origin.y; checkTop = checkBottom + checkBounds.size.height - 1; checkLeft = checkBounds.origin.x; checkRight = checkLeft + checkBounds.size.width - 1; bytesPerRow = [self bytesPerRow]; upperLeftBoundedData = [self bitmapData]; upperLeftBoundedData += checkLeft + bytesPerRow * (int) (frame.size.height - (checkBounds.origin.y + checkBounds.size.height)); maskRight = checkLeft; maskLeft = checkRight; maskTop = checkBottom; maskBottom = checkTop + 1; rowData = upperLeftBoundedData; for (row=checkTop; row>=checkBottom; row--) { maskPixel = (PPMaskBitmapPixel *) rowData; for (col=checkLeft; col<=checkRight; col++) { if (*maskPixel) { if (maskLeft > col) { maskLeft = col; } if (maskRight < col) { maskRight = col; } if (maskTop < row) { maskTop = row; } maskBottom = row; } maskPixel++; } rowData += bytesPerRow; } if (maskBottom > checkTop) { return NSZeroRect; } return NSMakeRect(maskLeft, maskBottom, maskRight - maskLeft + 1, maskTop - maskBottom + 1); ERROR: return NSZeroRect; } - (bool) ppMaskIsNotEmpty { unsigned char *maskRow; NSSize maskSize; int bytesPerRow, pixelsPerRow, rowCounter, pixelCounter; PPMaskBitmapPixel *maskPixel; if (![self ppIsMaskBitmap]) { goto ERROR; } maskRow = [self bitmapData]; if (!maskRow) goto ERROR; bytesPerRow = [self bytesPerRow]; maskSize = [self ppSizeInPixels]; pixelsPerRow = maskSize.width; rowCounter = maskSize.height; while (rowCounter--) { maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (*maskPixel++) { return YES; } } maskRow += bytesPerRow; } return NO; ERROR: return NO; } - (bool) ppMaskCoversAllPixels { unsigned char *maskRow; NSSize maskSize; int bytesPerRow, pixelsPerRow, rowCounter, pixelCounter; PPMaskBitmapPixel *maskPixel; if (![self ppIsMaskBitmap]) { goto ERROR; } maskRow = [self bitmapData]; if (!maskRow) goto ERROR; bytesPerRow = [self bytesPerRow]; maskSize = [self ppSizeInPixels]; pixelsPerRow = maskSize.width; rowCounter = maskSize.height; while (rowCounter--) { maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (!*maskPixel++) { return NO; } } maskRow += bytesPerRow; } return YES; ERROR: return NO; } - (bool) ppMaskCoversPoint: (NSPoint) point { NSRect bitmapFrame; unsigned char *maskData; int maskDataOffset; PPMaskBitmapPixel *maskPixel; if (![self ppIsMaskBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; point = PPGeometry_PointClippedToIntegerValues(point); if (!NSPointInRect(point, bitmapFrame)) { goto ERROR; } maskData = [self bitmapData]; if (!maskData) goto ERROR; maskDataOffset = (bitmapFrame.size.height - 1 - point.y) * [self bytesPerRow] + point.x * sizeof(PPMaskBitmapPixel); maskPixel = (PPMaskBitmapPixel *) (&maskData[maskDataOffset]); return (*maskPixel) ? YES : NO; ERROR: return NO; } - (void) ppMaskPixelsInBounds: (NSRect) bounds { NSRect bitmapFrame; unsigned char *bitmapData; unsigned numRowsToSkip, bytesPerRow, bytesPerPixel, numBytesToSetPerRow, rowCounter; if (![self ppIsMaskBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; bounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(bounds), bitmapFrame); if (NSIsEmptyRect(bounds)) { return; } bitmapData = [self bitmapData]; if (!bitmapData) goto ERROR; numRowsToSkip = bitmapFrame.size.height - (bounds.origin.y + bounds.size.height); bytesPerRow = [self bytesPerRow]; bytesPerPixel = sizeof(PPMaskBitmapPixel); numBytesToSetPerRow = bounds.size.width * bytesPerPixel; bitmapData += numRowsToSkip * bytesPerRow + (int) bounds.origin.x * bytesPerPixel; rowCounter = bounds.size.height; while (rowCounter--) { memset(bitmapData, kMaskPixelValue_ON, numBytesToSetPerRow); bitmapData += bytesPerRow; } return; ERROR: return; } - (void) ppIntersectMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap { [self ppIntersectMaskWithMaskBitmap: maskBitmap inBounds: [maskBitmap ppFrameInPixels]]; } - (void) ppIntersectMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) intersectBounds { NSRect bitmapFrame; unsigned char *destinationData, *maskData, *destinationRow, *maskRow; int destinationBytesPerRow, maskBytesPerRow, rowOffset, destinationDataOffset, maskDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPMaskBitmapPixel *destinationPixel, *maskPixel; if (![self ppIsMaskBitmap] || ![maskBitmap ppIsMaskBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; if (!NSEqualSizes(bitmapFrame.size, [maskBitmap ppSizeInPixels])) { goto ERROR; } intersectBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(intersectBounds), bitmapFrame); if (NSIsEmptyRect(intersectBounds)) { goto ERROR; } destinationData = [self bitmapData]; maskData = [maskBitmap bitmapData]; if (!destinationData || !maskData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; maskBytesPerRow = [maskBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - intersectBounds.size.height - intersectBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + intersectBounds.origin.x * sizeof(PPMaskBitmapPixel); maskDataOffset = rowOffset * maskBytesPerRow + intersectBounds.origin.x * sizeof(PPMaskBitmapPixel); destinationRow = &destinationData[destinationDataOffset]; maskRow = &maskData[maskDataOffset]; pixelsPerRow = intersectBounds.size.width; rowCounter = intersectBounds.size.height; while (rowCounter--) { destinationPixel = (PPMaskBitmapPixel *) destinationRow; maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (*destinationPixel && !*maskPixel) { *destinationPixel = kMaskPixelValue_OFF; } destinationPixel++; maskPixel++; } destinationRow += destinationBytesPerRow; maskRow += maskBytesPerRow; } return; ERROR: return; } - (void) ppSubtractMaskBitmap: (NSBitmapImageRep *) maskBitmap { [self ppSubtractMaskBitmap: maskBitmap inBounds: [maskBitmap ppFrameInPixels]]; } - (void) ppSubtractMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) subtractBounds { NSRect bitmapFrame; unsigned char *destinationData, *maskData, *destinationRow, *maskRow; int destinationBytesPerRow, maskBytesPerRow, rowOffset, destinationDataOffset, maskDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPMaskBitmapPixel *destinationPixel, *maskPixel; if (![self ppIsMaskBitmap] || ![maskBitmap ppIsMaskBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; if (!NSEqualSizes(bitmapFrame.size, [maskBitmap ppSizeInPixels])) { goto ERROR; } subtractBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(subtractBounds), bitmapFrame); if (NSIsEmptyRect(subtractBounds)) { goto ERROR; } destinationData = [self bitmapData]; maskData = [maskBitmap bitmapData]; if (!destinationData || !maskData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; maskBytesPerRow = [maskBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - subtractBounds.size.height - subtractBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + subtractBounds.origin.x * sizeof(PPMaskBitmapPixel); maskDataOffset = rowOffset * maskBytesPerRow + subtractBounds.origin.x * sizeof(PPMaskBitmapPixel); destinationRow = &destinationData[destinationDataOffset]; maskRow = &maskData[maskDataOffset]; pixelsPerRow = subtractBounds.size.width; rowCounter = subtractBounds.size.height; while (rowCounter--) { destinationPixel = (PPMaskBitmapPixel *) destinationRow; maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (*destinationPixel && *maskPixel) { *destinationPixel = kMaskPixelValue_OFF; } destinationPixel++; maskPixel++; } destinationRow += destinationBytesPerRow; maskRow += maskBytesPerRow; } return; ERROR: return; } - (void) ppMergeMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap { [self ppMergeMaskWithMaskBitmap: maskBitmap inBounds: [maskBitmap ppFrameInPixels]]; } - (void) ppMergeMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) mergeBounds { NSRect bitmapFrame; unsigned char *destinationData, *maskData, *destinationRow, *maskRow; int destinationBytesPerRow, maskBytesPerRow, rowOffset, destinationDataOffset, maskDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPMaskBitmapPixel *destinationPixel, *maskPixel; if (![self ppIsMaskBitmap] || ![maskBitmap ppIsMaskBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; if (!NSEqualSizes(bitmapFrame.size, [maskBitmap ppSizeInPixels])) { goto ERROR; } mergeBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(mergeBounds), bitmapFrame); if (NSIsEmptyRect(mergeBounds)) { goto ERROR; } destinationData = [self bitmapData]; maskData = [maskBitmap bitmapData]; if (!destinationData || !maskData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; maskBytesPerRow = [maskBitmap bytesPerRow]; rowOffset = bitmapFrame.size.height - mergeBounds.size.height - mergeBounds.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + mergeBounds.origin.x * sizeof(PPMaskBitmapPixel); maskDataOffset = rowOffset * maskBytesPerRow + mergeBounds.origin.x * sizeof(PPMaskBitmapPixel); destinationRow = &destinationData[destinationDataOffset]; maskRow = &maskData[maskDataOffset]; pixelsPerRow = mergeBounds.size.width; rowCounter = mergeBounds.size.height; while (rowCounter--) { destinationPixel = (PPMaskBitmapPixel *) destinationRow; maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (!*destinationPixel && *maskPixel) { *destinationPixel = kMaskPixelValue_ON; } destinationPixel++; maskPixel++; } destinationRow += destinationBytesPerRow; maskRow += maskBytesPerRow; } return; ERROR: return; } - (void) ppInvertMaskBitmap { NSSize maskSize; int bytesPerRow, pixelsPerRow, rowCounter, pixelCounter; unsigned char *maskData, *maskRow; PPMaskBitmapPixel *maskPixel; if (![self ppIsMaskBitmap]) { goto ERROR; } maskData = [self bitmapData]; if (!maskData) goto ERROR; maskRow = maskData; bytesPerRow = [self bytesPerRow]; maskSize = [self ppSizeInPixels]; pixelsPerRow = maskSize.width; rowCounter = maskSize.height; while (rowCounter--) { maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { *maskPixel = ~*maskPixel; maskPixel++; } maskRow += bytesPerRow; } return; ERROR: return; } - (void) ppCloseHolesInMaskBitmap { NSRect maskBounds; NSBitmapImageRep *workingMaskBitmap, *workingImageBitmap, *scratchMaskBitmap; NSInteger lastRow, lastCol, row, col; if (![self ppIsMaskBitmap]) { goto ERROR; } maskBounds = [self ppMaskBounds]; // no holes if width or height is 2 or less if ((maskBounds.size.width < 3) || (maskBounds.size.height < 3)) { return; } workingMaskBitmap = [self ppBitmapCroppedToBounds: maskBounds]; workingImageBitmap = [NSBitmapImageRep ppImageBitmapOfSize: maskBounds.size]; scratchMaskBitmap = [NSBitmapImageRep ppMaskBitmapOfSize: maskBounds.size]; if (!workingMaskBitmap || !workingImageBitmap || !scratchMaskBitmap) { goto ERROR; } [workingImageBitmap ppMaskedFillUsingMask: workingMaskBitmap inBounds: maskBounds fillPixelValue: -1]; [workingMaskBitmap ppInvertMaskBitmap]; lastRow = maskBounds.size.height - 1; lastCol = maskBounds.size.width - 1; // first row, all cols row = 0; for (col=0; col<=lastCol; col++) { if ([[workingMaskBitmap colorAtX: col y: row] whiteComponent] > 0.5f) { [scratchMaskBitmap ppMaskNeighboringPixelsMatchingColorAtPoint: NSMakePoint(col, lastRow - row) inImageBitmap: workingImageBitmap colorMatchTolerance: 0.0f selectionMask: nil selectionMaskBounds: NSZeroRect matchDiagonally: NO]; [workingMaskBitmap ppSubtractMaskBitmap: scratchMaskBitmap]; } } // middle rows, first & last cols for (row=1; row 0.5f) { [scratchMaskBitmap ppMaskNeighboringPixelsMatchingColorAtPoint: NSMakePoint(col, lastRow - row) inImageBitmap: workingImageBitmap colorMatchTolerance: 0.0f selectionMask: nil selectionMaskBounds: NSZeroRect matchDiagonally: NO]; [workingMaskBitmap ppSubtractMaskBitmap: scratchMaskBitmap]; } col = lastCol; if ([[workingMaskBitmap colorAtX: col y: row] whiteComponent] > 0.5f) { [scratchMaskBitmap ppMaskNeighboringPixelsMatchingColorAtPoint: NSMakePoint(col, lastRow - row) inImageBitmap: workingImageBitmap colorMatchTolerance: 0.0f selectionMask: nil selectionMaskBounds: NSZeroRect matchDiagonally: NO]; [workingMaskBitmap ppSubtractMaskBitmap: scratchMaskBitmap]; } } // last row, all cols row = lastRow; for (col=0; col<=lastCol; col++) { if ([[workingMaskBitmap colorAtX: col y: row] whiteComponent] > 0.5f) { [scratchMaskBitmap ppMaskNeighboringPixelsMatchingColorAtPoint: NSMakePoint(col, lastRow - row) inImageBitmap: workingImageBitmap colorMatchTolerance: 0.0f selectionMask: nil selectionMaskBounds: NSZeroRect matchDiagonally: NO]; [workingMaskBitmap ppSubtractMaskBitmap: scratchMaskBitmap]; } } scratchMaskBitmap = [self ppShallowDuplicateFromBounds: maskBounds]; if (!scratchMaskBitmap) goto ERROR; // merging to scratchMaskBitmap also merges to self, since they share bitmapData // (ShallowDuplicate) [scratchMaskBitmap ppMergeMaskWithMaskBitmap: workingMaskBitmap]; return; ERROR: return; } - (void) ppThresholdMaskBitmapPixelValues { [self ppThresholdMaskBitmapPixelValuesInBounds: [self ppFrameInPixels]]; } - (void) ppThresholdMaskBitmapPixelValuesInBounds: (NSRect) bounds { NSRect bitmapFrame; unsigned char *maskData, *maskRow; int numRowsToSkip, bytesPerRow, maskDataOffset, pixelsPerRow, rowCounter, pixelCounter; PPMaskBitmapPixel *maskPixel; if (![self ppIsMaskBitmap]) { goto ERROR; } bitmapFrame = [self ppFrameInPixels]; bounds = NSIntersectionRect(bitmapFrame, PPGeometry_PixelBoundsCoveredByRect(bounds)); if (NSIsEmptyRect(bounds)) { goto ERROR; } maskData = [self bitmapData]; if (!maskData) goto ERROR; numRowsToSkip = bitmapFrame.size.height - (bounds.origin.y + bounds.size.height); bytesPerRow = [self bytesPerRow]; maskDataOffset = numRowsToSkip * bytesPerRow + (int) bounds.origin.x * sizeof(PPMaskBitmapPixel); maskRow = &maskData[maskDataOffset]; pixelsPerRow = bounds.size.width; rowCounter = bounds.size.height; while (rowCounter--) { maskPixel = (PPMaskBitmapPixel *) maskRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { *maskPixel = (*maskPixel > kMaskPixelValue_Threshold) ? kMaskPixelValue_ON : kMaskPixelValue_OFF; maskPixel++; } maskRow += bytesPerRow; } return; ERROR: return; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSBitmapImageRep_PPUtilities_PatternBitmaps.m0000644000076500000240000006403013234403205026731 0ustar joshstaff/* NSBitmapImageRep_PPUtilities_PatternBitmaps.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSBitmapImageRep_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "PPGeometry.h" #import "PPSRGBUtilities.h" #import "PPImagePixelAlphaPremultiplyTables.h" #define kMinPatternSizeForPixelFramingInFillOverlayPattern (4.0f) #define kMinPatternSizeForDoubleLineWidthInFillOverlayPattern (17.0f) #define kMinVerticalGradientHeight (5) static PPImageBitmapPixel *PPImagePixelGradientArrayOfSizeWithEndColors(unsigned arraySize, NSColor *firstColor, NSColor *lastColor); @interface NSBitmapImageRep (PPUtilities_PatternBitmapsPrivateMethods) + (NSBitmapImageRep *) ppPixelCheckerboardPatternBitmapWithColor1: (NSColor *) color1 color2: (NSColor *) color2; @end @implementation NSBitmapImageRep (PPUtilities_PatternBitmaps) + (NSBitmapImageRep *) ppCheckerboardPatternBitmapWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2 { NSSize patternSize; NSBitmapImageRep *patternBitmap; unsigned char *patternRow; PPImageBitmapPixel color1PixelValue, color2PixelValue, averagedPixelValue, *patternPixel; int patternBytesPerRow, bytesToCopyPerRow, pixelCounter, rowCounter; boxDimension = floorf(boxDimension); if (boxDimension < 2.0f) { return [self ppPixelCheckerboardPatternBitmapWithColor1: color1 color2: color2]; } patternSize = NSMakeSize(2.0f * boxDimension, 2.0f * boxDimension); patternBitmap = [NSBitmapImageRep ppImageBitmapOfSize: patternSize]; if (!patternBitmap) goto ERROR; patternRow = [patternBitmap bitmapData]; if (!patternRow) goto ERROR; patternBytesPerRow = [patternBitmap bytesPerRow]; bytesToCopyPerRow = patternSize.width * sizeof(PPImageBitmapPixel); color1PixelValue = [color1 ppImageBitmapPixelValue]; color2PixelValue = [color2 ppImageBitmapPixelValue]; averagedPixelValue = [[color1 ppColorBlendedWithColor: color2] ppImageBitmapPixelValue]; // first row of top half patternPixel = (PPImageBitmapPixel *) patternRow; pixelCounter = boxDimension - 1; while (pixelCounter--) { *patternPixel++ = color1PixelValue; } *patternPixel++ = averagedPixelValue; pixelCounter = boxDimension - 1; while (pixelCounter--) { *patternPixel++ = color2PixelValue; } *patternPixel = averagedPixelValue; patternRow += patternBytesPerRow; // lower rows of top half rowCounter = boxDimension - 2; while (rowCounter--) { memcpy(patternRow, &patternRow[-patternBytesPerRow], bytesToCopyPerRow); patternRow += patternBytesPerRow; } // middle row patternPixel = (PPImageBitmapPixel *) patternRow; pixelCounter = patternSize.width; while (pixelCounter--) { *patternPixel++ = averagedPixelValue; } patternRow += patternBytesPerRow; // first row of bottom half patternPixel = (PPImageBitmapPixel *) patternRow; pixelCounter = boxDimension - 1; while (pixelCounter--) { *patternPixel++ = color2PixelValue; } *patternPixel++ = averagedPixelValue; pixelCounter = boxDimension - 1; while (pixelCounter--) { *patternPixel++ = color1PixelValue; } *patternPixel++ = averagedPixelValue; patternRow += patternBytesPerRow; // lower rows of bottom half rowCounter = boxDimension - 2; while (rowCounter--) { memcpy(patternRow, &patternRow[-patternBytesPerRow], bytesToCopyPerRow); patternRow += patternBytesPerRow; } // bottom row patternPixel = (PPImageBitmapPixel *) patternRow; pixelCounter = patternSize.width; while (pixelCounter--) { *patternPixel++ = averagedPixelValue; } return patternBitmap; ERROR: return nil; } + (NSBitmapImageRep *) ppDiagonalCheckerboardPatternBitmapWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2 { NSSize patternSize; NSBitmapImageRep *patternBitmap; NSColor *averageColor; int row, rowCounter, leftEdgeCol, rightEdgeCol; boxDimension = floorf(boxDimension); if (boxDimension < 1.0f) { boxDimension = 1.0f; } patternSize = NSMakeSize(2.0f * boxDimension, 2.0f * boxDimension); patternBitmap = [NSBitmapImageRep ppImageBitmapOfSize: patternSize]; if (!patternBitmap) goto ERROR; averageColor = [color1 ppColorBlendedWithColor: color2]; if (!averageColor) goto ERROR; [patternBitmap ppSetAsCurrentGraphicsContext]; [color2 set]; NSRectFill(PPGeometry_OriginRectOfSize(patternSize)); row = 0; [averageColor set]; NSRectFill(NSMakeRect(0.0f, row, 1.0f, 1.0f)); [color1 set]; NSRectFill(NSMakeRect(1.0f, row, patternSize.width - 1.0f, 1.0f)); row++; leftEdgeCol = 1; rightEdgeCol = patternSize.width - 1; rowCounter = boxDimension - 1; while (rowCounter > 0) { [averageColor set]; NSRectFill(NSMakeRect(leftEdgeCol, row, 1.0f, 1.0f)); NSRectFill(NSMakeRect(rightEdgeCol, row, 1.0f, 1.0f)); [color1 set]; NSRectFill(NSMakeRect(leftEdgeCol + 1, row, rightEdgeCol - leftEdgeCol - 1, 1.0f)); leftEdgeCol++; rightEdgeCol--; row++; rowCounter--; } [averageColor set]; NSRectFill(NSMakeRect(patternSize.width - boxDimension, row, 1.0f, 1.0f)); row++; leftEdgeCol--; rightEdgeCol++; rowCounter = boxDimension - 1; while (rowCounter > 0) { [averageColor set]; NSRectFill(NSMakeRect(leftEdgeCol, row, 1.0f, 1.0f)); NSRectFill(NSMakeRect(rightEdgeCol, row, 1.0f, 1.0f)); [color1 set]; NSRectFill(NSMakeRect(leftEdgeCol + 1, row, rightEdgeCol - leftEdgeCol - 1, 1.0f)); leftEdgeCol--; rightEdgeCol++; row++; rowCounter--; } [patternBitmap ppRestoreGraphicsContext]; return patternBitmap; ERROR: return nil; } + (NSBitmapImageRep *) ppIsometricCheckerboardPatternBitmapWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2 { NSSize patternSize; NSBitmapImageRep *patternBitmap; NSColor *averageColor, *mixed25PercentColor, *mixed75PercentColor; int row, rowCounter, leftEdgeCol, rightEdgeCol; boxDimension = floorf(boxDimension); if (boxDimension < 1.0f) { boxDimension = 1.0f; } patternSize = NSMakeSize(4.0f * boxDimension, 2.0f * boxDimension); patternBitmap = [NSBitmapImageRep ppImageBitmapOfSize: patternSize]; if (!patternBitmap) goto ERROR; averageColor = [color1 ppColorBlendedWithColor: color2]; mixed25PercentColor = [color2 ppColorBlendedWith25PercentOfColor: color1]; mixed75PercentColor = [color1 ppColorBlendedWith25PercentOfColor: color2]; if (!averageColor) goto ERROR; [patternBitmap ppSetAsCurrentGraphicsContext]; [color2 set]; NSRectFill(PPGeometry_OriginRectOfSize(patternSize)); row = 0; [averageColor set]; NSRectFill(NSMakeRect(0.0f, row, 2.0f, 1.0f)); [color1 set]; NSRectFill(NSMakeRect(2.0f, row, patternSize.width - 2.0f, 1.0f)); row++; leftEdgeCol = 2; rightEdgeCol = patternSize.width - 2; rowCounter = boxDimension - 1; while (rowCounter > 0) { [mixed25PercentColor set]; NSRectFill(NSMakeRect(leftEdgeCol, row, 1.0f, 1.0f)); NSRectFill(NSMakeRect(rightEdgeCol + 1.0f, row, 1.0f, 1.0f)); [mixed75PercentColor set]; NSRectFill(NSMakeRect(leftEdgeCol + 1.0f, row, 1.0f, 1.0f)); NSRectFill(NSMakeRect(rightEdgeCol, row, 1.0f, 1.0f)); [color1 set]; NSRectFill(NSMakeRect(leftEdgeCol + 2, row, rightEdgeCol - leftEdgeCol - 2, 1.0f)); leftEdgeCol += 2; rightEdgeCol -= 2; row++; rowCounter--; } [averageColor set]; NSRectFill(NSMakeRect(patternSize.width - 2.0f * boxDimension, row, 2.0f, 1.0f)); row++; leftEdgeCol -= 2; rightEdgeCol += 2; rowCounter = boxDimension - 1; while (rowCounter > 0) { [mixed25PercentColor set]; NSRectFill(NSMakeRect(leftEdgeCol, row, 1.0f, 1.0f)); NSRectFill(NSMakeRect(rightEdgeCol + 1.0f, row, 1.0f, 1.0f)); [mixed75PercentColor set]; NSRectFill(NSMakeRect(leftEdgeCol + 1.0f, row, 1.0f, 1.0f)); NSRectFill(NSMakeRect(rightEdgeCol, row, 1.0f, 1.0f)); [color1 set]; NSRectFill(NSMakeRect(leftEdgeCol + 2, row, rightEdgeCol - leftEdgeCol - 2, 1.0f)); leftEdgeCol -= 2; rightEdgeCol += 2; row++; rowCounter--; } [patternBitmap ppRestoreGraphicsContext]; return patternBitmap; ERROR: return nil; } + (NSBitmapImageRep *) ppDiagonalLinePatternBitmapWithLineWidth: (float) lineWidth color1: (NSColor *) color1 color2: (NSColor *) color2 { NSSize patternSize; NSBitmapImageRep *patternBitmap; unsigned char *patternRow; PPImageBitmapPixel color1PixelValue, color2PixelValue, averagedPixelValue, *patternPixel; int patternBytesPerRow, pixelCounter, rowCounter, wraparoundBytesPerRow, shiftedBytesPerRow; lineWidth = floorf(lineWidth); if (lineWidth < 2.0f) { return [self ppPixelCheckerboardPatternBitmapWithColor1: color1 color2: color2]; } patternSize = NSMakeSize(2.0f * lineWidth, 2.0f * lineWidth); patternBitmap = [NSBitmapImageRep ppImageBitmapOfSize: patternSize]; if (!patternBitmap) goto ERROR; patternRow = [patternBitmap bitmapData]; if (!patternRow) goto ERROR; patternBytesPerRow = [patternBitmap bytesPerRow]; color1PixelValue = [color1 ppImageBitmapPixelValue]; color2PixelValue = [color2 ppImageBitmapPixelValue]; averagedPixelValue = [[color1 ppColorBlendedWithColor: color2] ppImageBitmapPixelValue]; // first row patternPixel = (PPImageBitmapPixel *) patternRow; pixelCounter = lineWidth - 1; while (pixelCounter--) { *patternPixel++ = color1PixelValue; } *patternPixel++ = averagedPixelValue; pixelCounter = lineWidth - 1; while (pixelCounter--) { *patternPixel++ = color2PixelValue; } *patternPixel = averagedPixelValue; patternRow += patternBytesPerRow; // remaining rows wraparoundBytesPerRow = sizeof(PPImageBitmapPixel); shiftedBytesPerRow = patternSize.width * sizeof(PPImageBitmapPixel) - wraparoundBytesPerRow; rowCounter = patternSize.height - 1; while (rowCounter--) { memcpy(patternRow, &patternRow[-patternBytesPerRow + wraparoundBytesPerRow], shiftedBytesPerRow); memcpy(&patternRow[shiftedBytesPerRow], &patternRow[-patternBytesPerRow], wraparoundBytesPerRow); patternRow += patternBytesPerRow; } return patternBitmap; ERROR: return nil; } + (NSBitmapImageRep *) ppIsometricLinePatternBitmapWithLineWidth: (float) lineWidth color1: (NSColor *) color1 color2: (NSColor *) color2 { NSSize patternSize; NSBitmapImageRep *patternBitmap; unsigned char *patternRow; PPImageBitmapPixel color1PixelValue, color2PixelValue, mixed25PercentPixelValue, mixed75PercentPixelValue, *patternPixel; int patternBytesPerRow, pixelCounter, rowCounter, wraparoundBytesPerRow, shiftedBytesPerRow; lineWidth = floorf(2.0f * lineWidth); if (lineWidth < 2.0f) { lineWidth = 2.0f; } patternSize = NSMakeSize(2.0f * lineWidth, lineWidth); patternBitmap = [NSBitmapImageRep ppImageBitmapOfSize: patternSize]; if (!patternBitmap) goto ERROR; patternRow = [patternBitmap bitmapData]; if (!patternRow) goto ERROR; patternBytesPerRow = [patternBitmap bytesPerRow]; color1PixelValue = [color1 ppImageBitmapPixelValue]; color2PixelValue = [color2 ppImageBitmapPixelValue]; mixed25PercentPixelValue = [[color2 ppColorBlendedWith25PercentOfColor: color1] ppImageBitmapPixelValue]; mixed75PercentPixelValue = [[color1 ppColorBlendedWith25PercentOfColor: color2] ppImageBitmapPixelValue]; // first row patternPixel = (PPImageBitmapPixel *) patternRow; pixelCounter = lineWidth - 2; while (pixelCounter--) { *patternPixel++ = color1PixelValue; } *patternPixel++ = mixed75PercentPixelValue; *patternPixel++ = mixed25PercentPixelValue; pixelCounter = lineWidth - 2; while (pixelCounter--) { *patternPixel++ = color2PixelValue; } *patternPixel++ = mixed25PercentPixelValue; *patternPixel++ = mixed75PercentPixelValue; patternRow += patternBytesPerRow; // remaining rows wraparoundBytesPerRow = 2 * sizeof(PPImageBitmapPixel); shiftedBytesPerRow = patternSize.width * sizeof(PPImageBitmapPixel) - wraparoundBytesPerRow; rowCounter = patternSize.height - 1; while (rowCounter--) { memcpy(patternRow, &patternRow[-patternBytesPerRow + wraparoundBytesPerRow], shiftedBytesPerRow); memcpy(&patternRow[shiftedBytesPerRow], &patternRow[-patternBytesPerRow], wraparoundBytesPerRow); patternRow += patternBytesPerRow; } return patternBitmap; ERROR: return nil; } + (NSBitmapImageRep *) ppHorizontalGradientPatternBitmapWithWidth: (unsigned) width leftColor: (NSColor *) leftColor rightColor: (NSColor *) rightColor { NSBitmapImageRep *gradientBitmap; PPImageBitmapPixel *gradientPixelValuesArray = NULL; unsigned char *gradientBitmapData; if (width < 1) { goto ERROR; } gradientBitmap = [NSBitmapImageRep ppImageBitmapOfSize: NSMakeSize(width, 1.0f)]; if (!gradientBitmap) goto ERROR; gradientPixelValuesArray = PPImagePixelGradientArrayOfSizeWithEndColors(width, leftColor, rightColor); if (!gradientPixelValuesArray) goto ERROR; gradientBitmapData = [gradientBitmap bitmapData]; if (!gradientBitmapData) goto ERROR; memcpy(gradientBitmapData, gradientPixelValuesArray, width * sizeof(PPImageBitmapPixel)); free(gradientPixelValuesArray); return gradientBitmap; ERROR: if (gradientPixelValuesArray) { free(gradientPixelValuesArray); } return nil; } + (NSBitmapImageRep *) ppVerticalGradientPatternBitmapWithHeight: (unsigned) height topColor: (NSColor *) topColor bottomColor: (NSColor *) bottomColor { NSBitmapImageRep *gradientBitmap; PPImageBitmapPixel *gradientPixelValuesArray = NULL, *gradientBitmapPixel, *gradientArrayPixel; unsigned char *gradientBitmapData, *gradientBitmapRow; NSInteger bytesPerRow, pixelCounter; if (height < 1) { goto ERROR; } gradientBitmap = [NSBitmapImageRep ppImageBitmapOfSize: NSMakeSize(1.0f, height)]; if (!gradientBitmap) goto ERROR; gradientPixelValuesArray = PPImagePixelGradientArrayOfSizeWithEndColors(height, topColor, bottomColor); if (!gradientPixelValuesArray) goto ERROR; gradientBitmapData = [gradientBitmap bitmapData]; if (!gradientBitmapData) goto ERROR; bytesPerRow = [gradientBitmap bytesPerRow]; gradientBitmapRow = gradientBitmapData; gradientArrayPixel = &gradientPixelValuesArray[0]; pixelCounter = height; while (pixelCounter--) { gradientBitmapPixel = (PPImageBitmapPixel *) gradientBitmapRow; *gradientBitmapPixel = *gradientArrayPixel++; gradientBitmapRow += bytesPerRow; } free(gradientPixelValuesArray); return gradientBitmap; ERROR: if (gradientPixelValuesArray) { free(gradientPixelValuesArray); } return nil; } + (NSBitmapImageRep *) ppCenteredVerticalGradientPatternBitmapWithHeight: (unsigned) height innerColor: (NSColor *) innerColor outerColor: (NSColor *) outerColor { NSBitmapImageRep *gradientBitmap; NSInteger arraySize, bytesPerRow, pixelCounter; PPImageBitmapPixel *gradientPixelValuesArray = NULL, *gradientBitmapPixel, *gradientArrayPixel; unsigned char *gradientBitmapData, *gradientBitmapRow; if (height < kMinVerticalGradientHeight) { goto ERROR; } gradientBitmap = [NSBitmapImageRep ppImageBitmapOfSize: NSMakeSize(1.0f, height)]; if (!gradientBitmap) goto ERROR; arraySize = ceilf((height + 1.0f)/ 2.0f); gradientPixelValuesArray = PPImagePixelGradientArrayOfSizeWithEndColors(arraySize, outerColor, innerColor); if (!gradientPixelValuesArray) goto ERROR; gradientBitmapData = [gradientBitmap bitmapData]; if (!gradientBitmapData) goto ERROR; bytesPerRow = [gradientBitmap bytesPerRow]; gradientBitmapRow = gradientBitmapData; gradientArrayPixel = &gradientPixelValuesArray[0]; pixelCounter = arraySize; while (pixelCounter--) { gradientBitmapPixel = (PPImageBitmapPixel *) gradientBitmapRow; *gradientBitmapPixel = *gradientArrayPixel++; gradientBitmapRow += bytesPerRow; } gradientArrayPixel--; pixelCounter = arraySize - 2; if ((height - pixelCounter) > arraySize) { gradientBitmapPixel = (PPImageBitmapPixel *) gradientBitmapRow; *gradientBitmapPixel = *gradientArrayPixel; gradientBitmapRow += bytesPerRow; } gradientArrayPixel--; while (pixelCounter--) { gradientBitmapPixel = (PPImageBitmapPixel *) gradientBitmapRow; *gradientBitmapPixel = *gradientArrayPixel--; gradientBitmapRow += bytesPerRow; } free(gradientPixelValuesArray); return gradientBitmap; ERROR: if (gradientPixelValuesArray) { free(gradientPixelValuesArray); } return nil; } + (NSBitmapImageRep *) ppFillOverlayPatternBitmapWithSize: (float) patternSize fillColor: (NSColor *) fillColor { NSBitmapImageRep *patternBitmap; NSRect pixelFrame; if (!fillColor) goto ERROR; patternSize = floorf(patternSize); if (patternSize < kMinPatternSizeForPixelFramingInFillOverlayPattern) { return [self ppPixelCheckerboardPatternBitmapWithColor1: fillColor color2: [NSColor clearColor]]; } patternBitmap = [NSBitmapImageRep ppImageBitmapOfSize: NSMakeSize(patternSize, patternSize)]; if (!patternBitmap) goto ERROR; [patternBitmap ppSetAsCurrentGraphicsContext]; [fillColor set]; pixelFrame = NSMakeRect(1.0f, 0.0f, patternSize - 1.0f, patternSize - 1.0f); NSFrameRect(pixelFrame); if (patternSize >= kMinPatternSizeForDoubleLineWidthInFillOverlayPattern) { pixelFrame = NSInsetRect(pixelFrame, 1.0f, 1.0f); NSFrameRect(pixelFrame); } [patternBitmap ppRestoreGraphicsContext]; return patternBitmap; ERROR: return nil; } #pragma mark Private methods + (NSBitmapImageRep *) ppPixelCheckerboardPatternBitmapWithColor1: (NSColor *) color1 color2: (NSColor *) color2 { NSSize patternSize; NSBitmapImageRep *patternBitmap; unsigned char *patternRow; int patternBytesPerRow; PPImageBitmapPixel color1PixelValue, color2PixelValue, *patternPixel; patternSize = NSMakeSize(2.0f, 2.0f); patternBitmap = [NSBitmapImageRep ppImageBitmapOfSize: patternSize]; if (!patternBitmap) goto ERROR; patternRow = [patternBitmap bitmapData]; if (!patternRow) goto ERROR; patternBytesPerRow = [patternBitmap bytesPerRow]; color1PixelValue = [color1 ppImageBitmapPixelValue]; color2PixelValue = [color2 ppImageBitmapPixelValue]; // first row patternPixel = (PPImageBitmapPixel *) patternRow; *patternPixel++ = color1PixelValue; *patternPixel = color2PixelValue; patternRow += patternBytesPerRow; // second row patternPixel = (PPImageBitmapPixel *) patternRow; *patternPixel++ = color2PixelValue; *patternPixel = color1PixelValue; return patternBitmap; ERROR: return nil; } @end #pragma mark Private functions static PPImageBitmapPixel *PPImagePixelGradientArrayOfSizeWithEndColors(unsigned arraySize, NSColor *firstColor, NSColor *lastColor) { PPImageBitmapPixel *pixelArray, *currentPixel; CGFloat firstColorComponents[kNumPPImagePixelComponents], lastColorComponents[kNumPPImagePixelComponents], gradientCounterMax, gradientCounter, gradientRemainderCounter, alphaComponent, linearComponent; int componentIndex; PPImagePixelComponent *premultiplyTable; if (!arraySize) goto ERROR; firstColor = [firstColor ppSRGBColor]; lastColor = [lastColor ppSRGBColor]; if (!firstColor || !lastColor) { goto ERROR; } pixelArray = (PPImageBitmapPixel *) malloc (arraySize * sizeof(PPImageBitmapPixel)); if (!pixelArray) goto ERROR; if (arraySize <= 2) { pixelArray[arraySize-1] = [lastColor ppImageBitmapPixelValue]; if (arraySize > 1) { pixelArray[0] = [firstColor ppImageBitmapPixelValue]; } return pixelArray; } [firstColor getComponents: firstColorComponents]; [lastColor getComponents: lastColorComponents]; // convert RGB components from sRGB to Linear for (componentIndex=0; componentIndex<3; componentIndex++) { firstColorComponents[componentIndex] = macroSRGBUtils_LinearFloatValueFromSRGBFloatValue( firstColorComponents[componentIndex]); lastColorComponents[componentIndex] = macroSRGBUtils_LinearFloatValueFromSRGBFloatValue( lastColorComponents[componentIndex]); } // If either end color is completely transparent (zero alpha), its RGB components are // likely also zero (black) - blending with those color values will result in an incorrect // gradient that darkens to black as it approaches the transparent end. // To prevent the color values from darkening (only the alpha values should change), copy // the other end's RGB values to the transparent end. if (firstColorComponents[kPPImagePixelComponent_Alpha] == 0) { for (componentIndex=0; componentIndex<3; componentIndex++) { firstColorComponents[componentIndex] = lastColorComponents[componentIndex]; } } else if (lastColorComponents[kPPImagePixelComponent_Alpha] == 0) { for (componentIndex=0; componentIndex<3; componentIndex++) { lastColorComponents[componentIndex] = firstColorComponents[componentIndex]; } } currentPixel = &pixelArray[0]; gradientCounterMax = arraySize - 1; for (gradientCounter=0; gradientCounter<=gradientCounterMax; gradientCounter+=1.0) { gradientRemainderCounter = gradientCounterMax - gradientCounter; // Alpha component alphaComponent = (firstColorComponents[kPPImagePixelComponent_Alpha] * gradientRemainderCounter + lastColorComponents[kPPImagePixelComponent_Alpha] * gradientCounter) / gradientCounterMax; macroImagePixelComponent_Alpha(currentPixel) = roundf(alphaComponent * kMaxImagePixelComponentValue); premultiplyTable = macroAlphaPremultiplyTableForImagePixel(currentPixel); // RGB components for (componentIndex=0; componentIndex<3; componentIndex++) { linearComponent = (firstColorComponents[componentIndex] * gradientRemainderCounter + lastColorComponents[componentIndex] * gradientCounter) / gradientCounterMax; macroImagePixelComponent(currentPixel, componentIndex) = premultiplyTable[ ((int) roundf( macroSRGBUtils_SRGBFloatValueFromLinearFloatValue(linearComponent) * kMaxImagePixelComponentValue))]; } currentPixel++; } return pixelArray; ERROR: return NULL; } PikoPixel.Sources.1.0-b10b/PikoPixel/NSColor_PPUtilities.h0000644000076500000240000000652713234403416022152 0ustar joshstaff/* NSColor_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPSRGBUtilities.h" #import "PPBitmapPixelTypes.h" @interface NSColor (PPUtilities) - (PPImageBitmapPixel) ppImageBitmapPixelValue; - (bool) ppIsEqualToColor: (NSColor *) otherColor; - (NSColor *) ppColorBlendedWithColor: (NSColor *) otherColor; - (NSColor *) ppColorBlendedWith25PercentOfColor: (NSColor *) otherColor; + (NSColor *) ppMaskBitmapOnColor; + (NSColor *) ppMaskBitmapOffColor; // +ppColorWithData_DEPRECATED: was deprecated because it is not cross-platform compatible // between OS X & GNUstep (uses NSArchiver format, which is platform-specific) - should not be // used for current files, only for loading files created by older versions (1.0b4 & earlier) + (NSColor *) ppColorWithData_DEPRECATED: (NSData *) colorData; @end @interface NSColor (PPUtilities_PatternColors) + (NSColor *) ppCheckerboardPatternColorWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSColor *) ppDiagonalCheckerboardPatternColorWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSColor *) ppIsometricCheckerboardPatternColorWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSColor *) ppDiagonalLinePatternColorWithLineWidth: (float) lineWidth color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSColor *) ppIsometricLinePatternColorWithLineWidth: (float) lineWidth color1: (NSColor *) color1 color2: (NSColor *) color2; + (NSColor *) ppCenteredVerticalGradientPatternColorWithHeight: (unsigned) height innerColor: (NSColor *) innerColor outerColor: (NSColor *) outerColor; + (NSColor *) ppFillOverlayPatternColorWithSize: (float) patternSize fillColor: (NSColor *) fillColor; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSColor_PPUtilities.m0000644000076500000240000001373113234403205022146 0ustar joshstaff/* NSColor_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSColor_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #define kMaskBitmapOnColor [NSColor colorWithDeviceWhite: 1.0f alpha: 1.0f] #define kMaskBitmapOffColor [NSColor colorWithDeviceWhite: 0.0f alpha: 1.0f] // Occasionally see small floating-point differences (~1.0e-10) when comparing two calibrated // colors that had the same original source (appears on 10.10 Yosemite - other versions too?). // Epsilon value (largest difference allowed between two distinct component values to still be // considered equal for practical purposes) is a few orders of magnitude larger to be safe, but // still small compared to 1/255 stepsize between values in an 8-bit channel. #define kEpsilonForColorComponentValueComparison (1.0e-7) static inline bool ColorComponentValuesAreWithinEpsilon(CGFloat component1, CGFloat component2); @implementation NSColor (PPUtilities) - (PPImageBitmapPixel) ppImageBitmapPixelValue { static NSBitmapImageRep *bitmap = nil; static NSGraphicsContext *bitmapGraphicsContext = nil; unsigned char *bitmapData; if (!bitmap) { bitmap = [[NSBitmapImageRep ppImageBitmapOfSize: NSMakeSize(1.0f, 1.0f)] retain]; if (!bitmap) goto ERROR; bitmapGraphicsContext = [[NSGraphicsContext graphicsContextWithBitmapImageRep: bitmap] retain]; if (!bitmapGraphicsContext) goto ERROR; [bitmapGraphicsContext setShouldAntialias: NO]; } [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext: bitmapGraphicsContext]; [self set]; NSRectFill(NSMakeRect(0.0f, 0.0f, 1.0f, 1.0f)); [NSGraphicsContext restoreGraphicsState]; bitmapData = [bitmap bitmapData]; if (!bitmapData) goto ERROR; return *((PPImageBitmapPixel *) bitmapData); ERROR: [bitmapGraphicsContext release]; bitmapGraphicsContext = nil; [bitmap release]; bitmap = nil; return (PPImageBitmapPixel) 0; } - (bool) ppIsEqualToColor: (NSColor *) otherColor { CGFloat colorComponents[kNumPPImagePixelComponents], otherColorComponents[kNumPPImagePixelComponents]; int componentIndex; self = [self ppSRGBColor]; otherColor = [otherColor ppSRGBColor]; if (!self || !otherColor) { goto ERROR; } if (([self numberOfComponents] != kNumPPImagePixelComponents) || ([otherColor numberOfComponents] != kNumPPImagePixelComponents)) { goto ERROR; } [self getComponents: colorComponents]; [otherColor getComponents: otherColorComponents]; for (componentIndex=0; componentIndex= component2) ? YES : NO; } else { return ((component2 + kEpsilonForColorComponentValueComparison) >= component1) ? YES : NO; } } PikoPixel.Sources.1.0-b10b/PikoPixel/NSColor_PPUtilities_PatternColors.m0000644000076500000240000001421613234403205025024 0ustar joshstaff/* NSColor_PPUtilities_PatternColors.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSColor_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" @implementation NSColor (PPUtilities_PatternColors) + (NSColor *) ppCheckerboardPatternColorWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2 { NSBitmapImageRep *patternBitmap; NSImage *patternImage; patternBitmap = [NSBitmapImageRep ppCheckerboardPatternBitmapWithBoxDimension: boxDimension color1: color1 color2: color2]; if (!patternBitmap) goto ERROR; patternImage = [NSImage ppImageWithBitmap: patternBitmap]; if (!patternImage) goto ERROR; return [NSColor colorWithPatternImage: patternImage]; ERROR: return nil; } + (NSColor *) ppDiagonalCheckerboardPatternColorWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2 { NSBitmapImageRep *patternBitmap; NSImage *patternImage; patternBitmap = [NSBitmapImageRep ppDiagonalCheckerboardPatternBitmapWithBoxDimension: boxDimension color1: color1 color2: color2]; if (!patternBitmap) goto ERROR; patternImage = [NSImage ppImageWithBitmap: patternBitmap]; if (!patternImage) goto ERROR; return [NSColor colorWithPatternImage: patternImage]; ERROR: return nil; } + (NSColor *) ppIsometricCheckerboardPatternColorWithBoxDimension: (float) boxDimension color1: (NSColor *) color1 color2: (NSColor *) color2 { NSBitmapImageRep *patternBitmap; NSImage *patternImage; patternBitmap = [NSBitmapImageRep ppIsometricCheckerboardPatternBitmapWithBoxDimension: boxDimension color1: color1 color2: color2]; if (!patternBitmap) goto ERROR; patternImage = [NSImage ppImageWithBitmap: patternBitmap]; if (!patternImage) goto ERROR; return [NSColor colorWithPatternImage: patternImage]; ERROR: return nil; } + (NSColor *) ppDiagonalLinePatternColorWithLineWidth: (float) lineWidth color1: (NSColor *) color1 color2: (NSColor *) color2 { NSBitmapImageRep *patternBitmap; NSImage *patternImage; patternBitmap = [NSBitmapImageRep ppDiagonalLinePatternBitmapWithLineWidth: lineWidth color1: color1 color2: color2]; if (!patternBitmap) goto ERROR; patternImage = [NSImage ppImageWithBitmap: patternBitmap]; if (!patternImage) goto ERROR; return [NSColor colorWithPatternImage: patternImage]; ERROR: return nil; } + (NSColor *) ppIsometricLinePatternColorWithLineWidth: (float) lineWidth color1: (NSColor *) color1 color2: (NSColor *) color2 { NSBitmapImageRep *patternBitmap; NSImage *patternImage; patternBitmap = [NSBitmapImageRep ppIsometricLinePatternBitmapWithLineWidth: lineWidth color1: color1 color2: color2]; if (!patternBitmap) goto ERROR; patternImage = [NSImage ppImageWithBitmap: patternBitmap]; if (!patternImage) goto ERROR; return [NSColor colorWithPatternImage: patternImage]; ERROR: return nil; } + (NSColor *) ppCenteredVerticalGradientPatternColorWithHeight: (unsigned) height innerColor: (NSColor *) innerColor outerColor: (NSColor *) outerColor { NSBitmapImageRep *patternBitmap; NSImage *patternImage; patternBitmap = [NSBitmapImageRep ppCenteredVerticalGradientPatternBitmapWithHeight: height innerColor: innerColor outerColor: outerColor]; if (!patternBitmap) goto ERROR; patternImage = [NSImage ppImageWithBitmap: patternBitmap]; if (!patternImage) goto ERROR; return [NSColor colorWithPatternImage: patternImage]; ERROR: return nil; } + (NSColor *) ppFillOverlayPatternColorWithSize: (float) patternSize fillColor: (NSColor *) fillColor { NSBitmapImageRep *patternBitmap; NSImage *patternImage; patternBitmap = [NSBitmapImageRep ppFillOverlayPatternBitmapWithSize: patternSize fillColor: fillColor]; if (!patternBitmap) goto ERROR; patternImage = [NSImage ppImageWithBitmap: patternBitmap]; if (!patternImage) goto ERROR; return [NSColor colorWithPatternImage: patternImage]; ERROR: return nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSColorPanel_PPUtilities.h0000644000076500000240000000211213234403416023114 0ustar joshstaff/* NSColorPanel_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSColorPanel (PPUtilities) + (void) ppSetupSharedColorPanel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSColorPanel_PPUtilities.m0000644000076500000240000000351113717371610023133 0ustar joshstaff/* NSColorPanel_PPUtilities.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSColorPanel_PPUtilities.h" #import "PPUserDefaultsInitialValues.h" #import "NSWindow_PPUtilities.h" #define kUserDefaultsKey_NSColorPanelMode @"NSColorPanelMode" @implementation NSColorPanel (PPUtilities) + (void) ppSetupSharedColorPanel { static bool didSetupSharedColorPanel = NO; NSColorPanel *sharedColorPanel; if (didSetupSharedColorPanel) return; sharedColorPanel = [NSColorPanel sharedColorPanel]; // Initial mode if (![[NSUserDefaults standardUserDefaults] stringForKey: kUserDefaultsKey_NSColorPanelMode]) { [sharedColorPanel setMode: kUserDefaultsInitialValue_ColorPickerPopupPanelMode]; } // Disable fade animations on OS X Lion & later [sharedColorPanel ppDisableWindowAnimation]; didSetupSharedColorPanel = YES; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSCursor_PPUtilities.h0000644000076500000240000000302113234403416022333 0ustar joshstaff/* NSCursor_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSCursor (PPUtilities) + (NSCursor *) ppPencilCursor; + (NSCursor *) ppEraserCursor; + (NSCursor *) ppFillToolCursor; + (NSCursor *) ppLineToolCursor; + (NSCursor *) ppRectToolCursor; + (NSCursor *) ppOvalToolCursor; + (NSCursor *) ppFreehandSelectCursor; + (NSCursor *) ppRectSelectCursor; + (NSCursor *) ppMagicWandCursor; + (NSCursor *) ppColorSamplerToolCursor; + (NSCursor *) ppMoveToolCursor; + (NSCursor *) ppMoveSelectionOutlineToolCursor; + (NSCursor *) ppMagnifierCursor; + (NSCursor *) ppColorRampToolCursor; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSCursor_PPUtilities.m0000644000076500000240000001422213234403205022341 0ustar joshstaff/* NSCursor_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSCursor_PPUtilities.h" #import "PPCursorDefines.h" @implementation NSCursor (PPUtilities) + (NSCursor *) ppPencilCursor { static NSCursor *pencilCursor = nil; if (!pencilCursor) { pencilCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_Pencil] hotSpot: kPPCursorHotSpotPoint_Pencil]; } return pencilCursor; } + (NSCursor *) ppEraserCursor; { static NSCursor *eraserCursor = nil; if (!eraserCursor) { eraserCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_Eraser] hotSpot: kPPCursorHotSpotPoint_Eraser]; } return eraserCursor; } + (NSCursor *) ppFillToolCursor; { static NSCursor *fillBucketCursor = nil; if (!fillBucketCursor) { fillBucketCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_FillBucket] hotSpot: kPPCursorHotSpotPoint_FillBucket]; } return fillBucketCursor; } + (NSCursor *) ppLineToolCursor; { static NSCursor *lineToolCursor = nil; if (!lineToolCursor) { lineToolCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_LineTool] hotSpot: kPPCursorHotSpotPoint_LineTool]; } return lineToolCursor; } + (NSCursor *) ppRectToolCursor; { static NSCursor *rectToolCursor = nil; if (!rectToolCursor) { rectToolCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_RectTool] hotSpot: kPPCursorHotSpotPoint_RectTool]; } return rectToolCursor; } + (NSCursor *) ppOvalToolCursor; { static NSCursor *ovalToolCursor = nil; if (!ovalToolCursor) { ovalToolCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_OvalTool] hotSpot: kPPCursorHotSpotPoint_OvalTool]; } return ovalToolCursor; } + (NSCursor *) ppFreehandSelectCursor; { static NSCursor *freehandSelectCursor = nil; if (!freehandSelectCursor) { freehandSelectCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_FreehandSelect] hotSpot: kPPCursorHotSpotPoint_FreehandSelect]; } return freehandSelectCursor; } + (NSCursor *) ppRectSelectCursor; { static NSCursor *rectSelectCursor = nil; if (!rectSelectCursor) { rectSelectCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_RectSelect] hotSpot: kPPCursorHotSpotPoint_RectSelect]; } return rectSelectCursor; } + (NSCursor *) ppMagicWandCursor; { static NSCursor *magicWandCursor = nil; if (!magicWandCursor) { magicWandCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_MagicWand] hotSpot: kPPCursorHotSpotPoint_MagicWand]; } return magicWandCursor; } + (NSCursor *) ppColorSamplerToolCursor; { static NSCursor *colorSamplerCursor = nil; if (!colorSamplerCursor) { colorSamplerCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_ColorSampler] hotSpot: kPPCursorHotSpotPoint_ColorSampler]; } return colorSamplerCursor; } + (NSCursor *) ppMoveToolCursor; { static NSCursor *moveToolCursor = nil; if (!moveToolCursor) { moveToolCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_MoveTool] hotSpot: kPPCursorHotSpotPoint_MoveTool]; } return moveToolCursor; } + (NSCursor *) ppMoveSelectionOutlineToolCursor { static NSCursor *moveSelectionOutlineToolCursor = nil; if (!moveSelectionOutlineToolCursor) { moveSelectionOutlineToolCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_MoveSelectionOutlineTool] hotSpot: kPPCursorHotSpotPoint_MoveTool]; } return moveSelectionOutlineToolCursor; } + (NSCursor *) ppMagnifierCursor; { static NSCursor *magnifierCursor = nil; if (!magnifierCursor) { magnifierCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_Magnifier] hotSpot: kPPCursorHotSpotPoint_Magnifier]; } return magnifierCursor; } + (NSCursor *) ppColorRampToolCursor { static NSCursor *colorRampToolCursor = nil; if (!colorRampToolCursor) { colorRampToolCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: kPPCursorImageName_ColorRampTool] hotSpot: kPPCursorHotSpotPoint_ColorRampTool]; } return colorRampToolCursor; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSData_PPNativePasteboardType.h0000644000076500000240000000327113234403416024060 0ustar joshstaff/* NSData_PPNativePasteboardType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSData (PPNativePasteboardType) + (NSData *) ppNativePasteboardDataWithImageBitmap: (NSBitmapImageRep *) imageBitmap maskBitmap: (NSBitmapImageRep *) maskBitmap bitmapOrigin: (NSPoint) bitmapOrigin canvasSize: (NSSize) canvasSize opacity: (float) opacity; - (bool) ppNativePasteboardDataGetImageBitmap: (NSBitmapImageRep **) returnedImageBitmap maskBitmap: (NSBitmapImageRep **) returnedMaskBitmap bitmapOrigin: (NSPoint *) returnedBitmapOrigin canvasSize: (NSSize *) returnedCanvasSize opacity: (float *) returnedOpacity; @end extern NSString *kPPNativePasteboardType; PikoPixel.Sources.1.0-b10b/PikoPixel/NSData_PPNativePasteboardType.m0000644000076500000240000001072213234403205024060 0ustar joshstaff/* NSData_PPNativePasteboardType.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSData_PPNativePasteboardType.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" NSString *kPPNativePasteboardType = @"PikoPixel Native Pasteboard Type"; @implementation NSData (PPNativePasteboardType) + (NSData *) ppNativePasteboardDataWithImageBitmap: (NSBitmapImageRep *) imageBitmap maskBitmap: (NSBitmapImageRep *) maskBitmap bitmapOrigin: (NSPoint) bitmapOrigin canvasSize: (NSSize) canvasSize opacity: (float) opacity { NSData *imageBitmapData, *maskBitmapData; NSString *positionRectString; NSNumber *opacityNumber; NSArray *nativePasteboardArray; if (![imageBitmap ppIsImageBitmapAndSameSizeAsMaskBitmap: maskBitmap]) { goto ERROR; } imageBitmapData = [imageBitmap ppCompressedTIFFData]; maskBitmapData = [maskBitmap ppCompressedTIFFData]; positionRectString = NSStringFromRect(NSMakeRect(bitmapOrigin.x, bitmapOrigin.y, canvasSize.width, canvasSize.height)); opacityNumber = [NSNumber numberWithFloat: opacity]; if (!imageBitmapData || !maskBitmapData || !positionRectString || !opacityNumber) { goto ERROR; } nativePasteboardArray = [NSArray arrayWithObjects: imageBitmapData, maskBitmapData, positionRectString, opacityNumber, nil]; if (!nativePasteboardArray) goto ERROR; return [NSArchiver archivedDataWithRootObject: nativePasteboardArray]; ERROR: return nil; } - (bool) ppNativePasteboardDataGetImageBitmap: (NSBitmapImageRep **) returnedImageBitmap maskBitmap: (NSBitmapImageRep **) returnedMaskBitmap bitmapOrigin: (NSPoint *) returnedBitmapOrigin canvasSize: (NSSize *) returnedCanvasSize opacity: (float *) returnedOpacity { NSArray *nativePasteboardArray; NSData *imageBitmapData, *maskBitmapData; NSString *positionRectString; NSNumber *opacityNumber; NSBitmapImageRep *imageBitmap, *maskBitmap; NSRect positionRect; float opacity; nativePasteboardArray = [NSUnarchiver unarchiveObjectWithData: self]; if (!nativePasteboardArray || ![nativePasteboardArray isKindOfClass: [NSArray class]] || ([nativePasteboardArray count] != 4)) { goto ERROR; } imageBitmapData = [nativePasteboardArray objectAtIndex: 0]; maskBitmapData = [nativePasteboardArray objectAtIndex: 1]; positionRectString = [nativePasteboardArray objectAtIndex: 2]; opacityNumber = [nativePasteboardArray objectAtIndex: 3]; if (!imageBitmapData || !maskBitmapData || !positionRectString || !opacityNumber) { goto ERROR; } imageBitmap = [NSBitmapImageRep imageRepWithData: imageBitmapData]; maskBitmap = [NSBitmapImageRep imageRepWithData: maskBitmapData]; positionRect = NSRectFromString(positionRectString); opacity = [opacityNumber floatValue]; if (!imageBitmap || !maskBitmap) { goto ERROR; } if (returnedImageBitmap) { *returnedImageBitmap = imageBitmap; } if (returnedMaskBitmap) { *returnedMaskBitmap = maskBitmap; } if (returnedBitmapOrigin) { *returnedBitmapOrigin = positionRect.origin; } if (returnedCanvasSize) { *returnedCanvasSize = positionRect.size; } if (returnedOpacity) { *returnedOpacity = opacity; } return YES; ERROR: return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSDocument_PPUtilities.h0000644000076500000240000000213013234403416022634 0ustar joshstaff/* NSDocument_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSDocument (PPUtilities) - (NSWindow *) ppWindow; - (void) ppMakeWindowKey; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSDocument_PPUtilities.m0000644000076500000240000000257013234403205022645 0ustar joshstaff/* NSDocument_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSDocument_PPUtilities.h" #import "NSWindow_PPUtilities.h" @implementation NSDocument (PPUtilities) - (NSWindow *) ppWindow { NSArray *windowControllers = [self windowControllers]; if (![windowControllers count]) { return nil; } return [[windowControllers objectAtIndex: 0] window]; } - (void) ppMakeWindowKey { [[self ppWindow] ppMakeKeyWindowIfMain]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSDocumentController_PPUtilities.h0000644000076500000240000000241113234403416024702 0ustar joshstaff/* NSDocumentController_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @class PPDocument; @interface NSDocumentController (PPUtilities) - (bool) ppOpenUntitledDuplicateOfPPDocument: (PPDocument *) ppDocumentToDuplicate; - (void) ppActivateNextDocument; - (void) ppActivatePreviousDocument; - (bool) ppHasMultipleDocuments; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSDocumentController_PPUtilities.m0000644000076500000240000000666013234403205024715 0ustar joshstaff/* NSDocumentController_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSDocumentController_PPUtilities.h" #import "PPDocument.h" @implementation NSDocumentController (PPUtilities) - (bool) ppOpenUntitledDuplicateOfPPDocument: (PPDocument *) ppDocumentToDuplicate { PPDocument *newPPDocument = nil; NSError *error; if (!ppDocumentToDuplicate) goto ERROR; newPPDocument = [self openUntitledDocumentAndDisplay: NO error: &error]; if (!newPPDocument || ![newPPDocument isKindOfClass: [PPDocument class]]) { goto ERROR; } [newPPDocument loadFromPPDocument: ppDocumentToDuplicate]; [newPPDocument makeWindowControllers]; [newPPDocument showWindows]; return YES; ERROR: [newPPDocument close]; return NO; } - (void) ppActivateNextDocument { NSArray *documents; NSInteger documentCount, documentIndex, nextDocumentIndex; NSDocument *currentDocument, *nextDocument; documents = [self documents]; documentCount = [documents count]; if (documentCount < 2) { goto ERROR; } currentDocument = [self currentDocument]; if (!currentDocument) goto ERROR; documentIndex = [documents indexOfObject: currentDocument]; if (documentIndex == NSNotFound) { goto ERROR; } nextDocumentIndex = documentIndex + 1; if (nextDocumentIndex >= documentCount) { nextDocumentIndex = 0; } nextDocument = [documents objectAtIndex: nextDocumentIndex]; [[nextDocument ppWindow] makeKeyAndOrderFront: self]; return; ERROR: return; } - (void) ppActivatePreviousDocument { NSArray *documents; NSInteger documentCount, documentIndex, previousDocumentIndex; NSDocument *currentDocument, *previousDocument; documents = [self documents]; documentCount = [documents count]; if (documentCount < 2) { goto ERROR; } currentDocument = [self currentDocument]; if (!currentDocument) goto ERROR; documentIndex = [documents indexOfObject: currentDocument]; if (documentIndex == NSNotFound) { goto ERROR; } previousDocumentIndex = documentIndex - 1; if (previousDocumentIndex < 0) { previousDocumentIndex = documentCount - 1; } previousDocument = [documents objectAtIndex: previousDocumentIndex]; [[previousDocument ppWindow] makeKeyAndOrderFront: self]; return; ERROR: return; } - (bool) ppHasMultipleDocuments { return ([[self documents] count] > 1) ? YES : NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSError_PPUtilities.h0000644000076500000240000000240213234403416022151 0ustar joshstaff/* NSError_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSError (PPUtilities) + (NSError *) ppError_ImageFileIsCorrupt; + (NSError *) ppError_ImageFileVersionIsTooNew; + (NSError *) ppError_ImageFileDimensionsAreTooLarge; + (NSError *) ppError_UnableToCreateDataOfType: (NSString *) typeName; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSError_PPUtilities.m0000644000076500000240000000677313234403205022171 0ustar joshstaff/* NSError_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSError_PPUtilities.h" #import "PPDefines.h" #define kErrorDescription_ImageFileVersionIsTooNew \ @"\n\nThe file was created by a newer version of PikoPixel and cannot be read " \ "by this version." #define kErrorDescription_ImageFileDimensionsAreTooLarge \ [NSString stringWithFormat: \ @"\n\nThe image is too large.\nMaximum size allowed is: %d x %d", \ kMaxCanvasDimension, kMaxCanvasDimension] #define kErrorDescriptionFormatString_UnableToCreateDataOfType \ @"\n\nUnable to create data in \"%@\" format." @implementation NSError (PPUtilities) + (NSError *) ppError_ImageFileIsCorrupt { return [NSError errorWithDomain: NSCocoaErrorDomain code: NSFileReadCorruptFileError userInfo: nil]; } + (NSError *) ppError_ImageFileVersionIsTooNew { NSDictionary *errorUserInfoDict = [NSDictionary dictionaryWithObject: kErrorDescription_ImageFileVersionIsTooNew forKey: NSLocalizedFailureReasonErrorKey]; return [NSError errorWithDomain: NSCocoaErrorDomain code: NSFileReadUnknownError userInfo: errorUserInfoDict]; } + (NSError *) ppError_ImageFileDimensionsAreTooLarge { NSDictionary *errorUserInfoDict = [NSDictionary dictionaryWithObject: kErrorDescription_ImageFileDimensionsAreTooLarge forKey: NSLocalizedFailureReasonErrorKey]; return [NSError errorWithDomain: NSCocoaErrorDomain code: NSFileReadUnknownError userInfo: errorUserInfoDict]; } + (NSError *) ppError_UnableToCreateDataOfType: (NSString *) typeName { NSString *errorDescription = [NSString stringWithFormat: kErrorDescriptionFormatString_UnableToCreateDataOfType, typeName]; NSDictionary *errorUserInfoDict = [NSDictionary dictionaryWithObject: errorDescription forKey: NSLocalizedFailureReasonErrorKey]; return [NSError errorWithDomain: NSCocoaErrorDomain code: NSFileWriteUnknownError userInfo: errorUserInfoDict]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSEvent_PPUtilities.h0000644000076500000240000000224013234403416022141 0ustar joshstaff/* NSEvent_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSEvent (PPUtilities) - (NSPoint) ppMouseDragDeltaPointByMergingWithEnqueuedMouseDraggedEvents; - (NSEvent *) ppLatestMouseDraggedEventFromEventQueue; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSEvent_PPUtilities.m0000644000076500000240000000554613234403205022156 0ustar joshstaff/* NSEvent_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSEvent_PPUtilities.h" @implementation NSEvent (PPUtilities) - (NSPoint) ppMouseDragDeltaPointByMergingWithEnqueuedMouseDraggedEvents { NSPoint mouseDragAmount; NSEvent *mouseEvent; if ([self type] != NSLeftMouseDragged) { goto ERROR; } mouseDragAmount = NSZeroPoint; mouseEvent = self; while (mouseEvent) { mouseDragAmount.x += [mouseEvent deltaX]; # if PP_DEPLOYMENT_TARGET_NSEVENT_DELTAY_RETURNS_FLIPPED_COORDINATE mouseDragAmount.y -= [mouseEvent deltaY]; // flipped - change sign # else mouseDragAmount.y += [mouseEvent deltaY]; // not flipped # endif mouseEvent = [NSApp nextEventMatchingMask: NSLeftMouseDraggedMask | NSLeftMouseUpMask untilDate: nil inMode: NSEventTrackingRunLoopMode dequeue: YES]; if ([mouseEvent type] == NSLeftMouseUp) { [NSApp postEvent: mouseEvent atStart: YES]; mouseEvent = nil; } } return mouseDragAmount; ERROR: return NSZeroPoint; } - (NSEvent *) ppLatestMouseDraggedEventFromEventQueue { NSEvent *dequeuedEvent, *lastMouseDraggedEvent; if ([self type] != NSLeftMouseDragged) { goto ERROR; } dequeuedEvent = lastMouseDraggedEvent = self; while (dequeuedEvent) { lastMouseDraggedEvent = dequeuedEvent; dequeuedEvent = [NSApp nextEventMatchingMask: NSLeftMouseDraggedMask | NSLeftMouseUpMask untilDate: nil inMode: NSEventTrackingRunLoopMode dequeue: YES]; if ([dequeuedEvent type] == NSLeftMouseUp) { [NSApp postEvent: dequeuedEvent atStart: YES]; dequeuedEvent = nil; } } return lastMouseDraggedEvent; ERROR: return self; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSFileManager_PPUtilities.h0000644000076500000240000000234013234403416023233 0ustar joshstaff/* NSFileManager_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSFileManager (PPUtilities) - (bool) ppVerifySupportFileDirectory; + (NSString *) ppFilepathForSupportFileWithName: (NSString *) filename; - (bool) ppDeleteSupportFileAtPath: (NSString *) filepath; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSFileManager_PPUtilities.m0000644000076500000240000000607313234403205023243 0ustar joshstaff/* NSFileManager_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSFileManager_PPUtilities.h" #import "PPUserFolderPaths.h" @implementation NSFileManager (PPUtilities) - (bool) ppVerifySupportFileDirectory { NSString *supportFolderPath = PPUserFolderPaths_ApplicationSupport(); BOOL isDirectory = NO, returnValue = NO; if (![supportFolderPath length]) { goto ERROR; } if ([self fileExistsAtPath: supportFolderPath isDirectory: &isDirectory]) { if (!isDirectory) goto ERROR; return YES; } #if PP_DEPLOYMENT_TARGET_DEPRECATED_CREATEDIRECTORYATPATHATTRIBUTES returnValue = [self createDirectoryAtPath: supportFolderPath withIntermediateDirectories: NO attributes: nil error: nil]; #else // Deployment target supports createDirectoryAtPath:attributes: returnValue = [self createDirectoryAtPath: supportFolderPath attributes: nil]; #endif // PP_DEPLOYMENT_TARGET_DEPRECATED_CREATEDIRECTORYATPATHATTRIBUTES return returnValue; ERROR: return NO; } + (NSString *) ppFilepathForSupportFileWithName: (NSString *) filename { NSString *supportFolderPath = PPUserFolderPaths_ApplicationSupport(); if (![supportFolderPath length] || ![filename length]) { goto ERROR; } return [supportFolderPath stringByAppendingPathComponent: filename]; ERROR: return nil; } - (bool) ppDeleteSupportFileAtPath: (NSString *) filepath; { NSString *supportFolderPath = PPUserFolderPaths_ApplicationSupport(); bool returnValue = NO; if (![supportFolderPath length] || ![filepath hasPrefix: supportFolderPath] || ![self isDeletableFileAtPath: filepath]) { goto ERROR; } #if PP_DEPLOYMENT_TARGET_DEPRECATED_REMOVEFILEATPATHHANDLER returnValue = [self removeItemAtPath: filepath error: nil]; #else // Deployment target supports removeFileAtPath:handler: returnValue = [self removeFileAtPath: filepath handler: NULL]; #endif // PP_DEPLOYMENT_TARGET_DEPRECATED_REMOVEFILEATPATHHANDLER return returnValue; ERROR: return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSImage_PPUtilities.h0000644000076500000240000000227213234403416022107 0ustar joshstaff/* NSImage_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSImage (PPUtilities) + (NSImage *) ppImageWithBitmap: (NSBitmapImageRep *) bitmap; - (NSBitmapImageRep *) ppBitmap; - (NSData *) ppCompressedBitmapData; - (bool) ppIsOpaque; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSImage_PPUtilities.m0000644000076500000240000000501213234403205022103 0ustar joshstaff/* NSImage_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSImage_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" @implementation NSImage (PPUtilities) + (NSImage *) ppImageWithBitmap: (NSBitmapImageRep *) bitmap { NSSize imageSize; NSImage *image; if (!bitmap) goto ERROR; imageSize = [bitmap ppSizeInPixels]; if (PPGeometry_IsZeroSize(imageSize)) { goto ERROR; } image = [[[NSImage alloc] initWithSize: imageSize] autorelease]; if (!image) goto ERROR; [image addRepresentation: bitmap]; return image; ERROR: return nil; } - (NSBitmapImageRep *) ppBitmap { NSData *imageData; NSBitmapImageRep *bitmap; NSSize bitmapSize; imageData = [self TIFFRepresentation]; if (!imageData) goto ERROR; bitmap = [NSBitmapImageRep imageRepWithData: imageData]; if (!bitmap) goto ERROR; // -[NSBitmapImageRep imageRepWithData:] sometimes sets the wrong size, so set manually: bitmapSize = [bitmap ppSizeInPixels]; [bitmap setSize: bitmapSize]; return bitmap; ERROR: return nil; } - (NSData *) ppCompressedBitmapData { return [[self ppBitmap] ppCompressedTIFFData]; } - (bool) ppIsOpaque { NSBitmapImageRep *bitmap, *imageBitmap; bitmap = [self ppBitmap]; if (!bitmap) goto ERROR; if (![bitmap hasAlpha]) { return YES; } imageBitmap = [bitmap ppImageBitmap]; if (!imageBitmap) goto ERROR; return ([imageBitmap ppImageBitmapHasTransparentPixels]) ? NO : YES; ERROR: return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSImageRep_PPUtilities.h0000644000076500000240000000220313234403416022550 0ustar joshstaff/* NSImageRep_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSImageRep (PPUtilities) - (NSSize) ppSizeInPixels; - (NSRect) ppFrameInPixels; - (NSBitmapImageRep *) ppImageBitmap; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSImageRep_PPUtilities.m0000644000076500000240000000333113234403205022554 0ustar joshstaff/* NSImageRep_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSImageRep_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" @implementation NSImageRep (PPUtilities) - (NSSize) ppSizeInPixels { return NSMakeSize([self pixelsWide], [self pixelsHigh]); } - (NSRect) ppFrameInPixels { return NSMakeRect(0, 0, [self pixelsWide], [self pixelsHigh]); } - (NSBitmapImageRep *) ppImageBitmap { NSRect bitmapFrame; NSBitmapImageRep *imageBitmap; bitmapFrame = [self ppFrameInPixels]; imageBitmap = [NSBitmapImageRep ppImageBitmapOfSize: bitmapFrame.size]; if (!imageBitmap) goto ERROR; [imageBitmap ppSetAsCurrentGraphicsContext]; [self drawInRect: bitmapFrame]; [imageBitmap ppRestoreGraphicsContext]; return imageBitmap; ERROR: return nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSMutableArray_PPUtilities.h0000644000076500000240000000216113234403416023452 0ustar joshstaff/* NSMutableArray_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSMutableArray (PPUtilities) - (void) ppAddCopiesOfObjectsFromArray: (NSArray *) array; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSMutableArray_PPUtilities.m0000644000076500000240000000266113234403205023460 0ustar joshstaff/* NSMutableArray_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSMutableArray_PPUtilities.h" @implementation NSMutableArray (PPUtilities) - (void) ppAddCopiesOfObjectsFromArray: (NSArray *) array { NSArray *copiedObjects; if (!array || ![array count]) { return; } copiedObjects = [[[NSArray alloc] initWithArray: array copyItems: YES] autorelease]; if (!copiedObjects) goto ERROR; [self addObjectsFromArray: copiedObjects]; return; ERROR: return; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSObject_PPUtilities.h0000644000076500000240000000407613234403416022277 0ustar joshstaff/* NSObject_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSObject (PPUtilities) - (void) ppPerformSelectorFromNewStackFrame: (SEL) aSelector; - (void) ppPerformSelectorAtomicallyFromNewStackFrame: (SEL) aSelector; - (void) ppPerformSelectorAtomically: (SEL) aSelector afterDelay: (NSTimeInterval) delay; @end @interface NSObject (PPUtilities_MethodSwizzling) + (bool) ppSwizzleClassMethodWithSelector: (SEL) selector1 forClassMethodWithSelector: (SEL) selector2; + (bool) ppSwizzleInstanceMethodWithSelector: (SEL) selector1 forInstanceMethodWithSelector: (SEL) selector2; @end #define macroSwizzleClassMethod(class, selectorName1, selectorName2) \ [class ppSwizzleClassMethodWithSelector: @selector(selectorName1) \ forClassMethodWithSelector: @selector(selectorName2)] #define macroSwizzleInstanceMethod(class, selectorName1, selectorName2) \ [class ppSwizzleInstanceMethodWithSelector: @selector(selectorName1) \ forInstanceMethodWithSelector: @selector(selectorName2)] PikoPixel.Sources.1.0-b10b/PikoPixel/NSObject_PPUtilities.m0000644000076500000240000000337213234403205022276 0ustar joshstaff/* NSObject_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSObject_PPUtilities.h" @implementation NSObject (PPUtilities) - (void) ppPerformSelectorFromNewStackFrame: (SEL) aSelector { [self performSelector: aSelector withObject: nil afterDelay: 0.0f]; } - (void) ppPerformSelectorAtomicallyFromNewStackFrame: (SEL) aSelector { [[self class] cancelPreviousPerformRequestsWithTarget: self selector: aSelector object: nil]; [self ppPerformSelectorFromNewStackFrame: aSelector]; } - (void) ppPerformSelectorAtomically: (SEL) aSelector afterDelay: (NSTimeInterval) delay { [[self class] cancelPreviousPerformRequestsWithTarget: self selector: aSelector object: nil]; [self performSelector: aSelector withObject: nil afterDelay: delay]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSObject_PPUtilities_MethodSwizzling.m0000644000076500000240000001242113716041206025516 0ustar joshstaff/* NSObject_PPUtilities_MethodSwizzling.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSObject_PPUtilities.h" #import @implementation NSObject (PPUtilities_MethodSwizzling_OBJC_API_2) + (bool) ppSwizzleClassMethodWithSelector: (SEL) selector1 forClassMethodWithSelector: (SEL) selector2 { Method method1, method2; const char *typeEncoding1, *typeEncoding2; IMP implementation1, implementation2; Class metaClass; if (!selector1 || !selector2 || sel_isEqual(selector1, selector2)) { goto ERROR; } method1 = class_getClassMethod(self, selector1); method2 = class_getClassMethod(self, selector2); if (!method1 || !method2) { goto ERROR; } typeEncoding1 = method_getTypeEncoding(method1); typeEncoding2 = method_getTypeEncoding(method2); if (!typeEncoding1 || !typeEncoding2 || strcmp(typeEncoding1, typeEncoding2)) { goto ERROR; } implementation1 = method_getImplementation(method1); implementation2 = method_getImplementation(method2); if (!implementation1 || !implementation2) { goto ERROR; } metaClass = object_getClass(self); // set method1's imp to implementation2 if (class_addMethod(metaClass, selector1, implementation2, typeEncoding1)) { method1 = class_getClassMethod(self, selector1); if (!method1) goto ERROR; } else { class_replaceMethod(metaClass, selector1, implementation2, typeEncoding1); } // set method2's imp to implementation1 if (class_addMethod(metaClass, selector2, implementation1, typeEncoding2)) { method2 = class_getClassMethod(self, selector2); if (!method2) goto ERROR; } else { class_replaceMethod(metaClass, selector2, implementation1, typeEncoding2); } // verify imps are swapped if ((method_getImplementation(method1) != implementation2) || (method_getImplementation(method2) != implementation1)) { goto ERROR; } return YES; ERROR: NSLog(@"WARNING: Unable to swizzle %@ class methods: %@ & %@", [self className], (selector1) ? NSStringFromSelector(selector1) : @"", (selector2) ? NSStringFromSelector(selector2) : @""); return NO; } + (bool) ppSwizzleInstanceMethodWithSelector: (SEL) selector1 forInstanceMethodWithSelector: (SEL) selector2 { Method method1, method2; const char *typeEncoding1, *typeEncoding2; IMP implementation1, implementation2; if (!selector1 || !selector2 || sel_isEqual(selector1, selector2)) { goto ERROR; } method1 = class_getInstanceMethod(self, selector1); method2 = class_getInstanceMethod(self, selector2); if (!method1 || !method2) { goto ERROR; } typeEncoding1 = method_getTypeEncoding(method1); typeEncoding2 = method_getTypeEncoding(method2); if (!typeEncoding1 || !typeEncoding2 || strcmp(typeEncoding1, typeEncoding2)) { goto ERROR; } implementation1 = method_getImplementation(method1); implementation2 = method_getImplementation(method2); if (!implementation1 || !implementation2) { goto ERROR; } // set method1's imp to implementation2 if (class_addMethod(self, selector1, implementation2, typeEncoding1)) { method1 = class_getInstanceMethod(self, selector1); if (!method1) goto ERROR; } else { class_replaceMethod(self, selector1, implementation2, typeEncoding1); } // set method2's imp to implementation1 if (class_addMethod(self, selector2, implementation1, typeEncoding2)) { method2 = class_getInstanceMethod(self, selector2); if (!method2) goto ERROR; } else { class_replaceMethod(self, selector2, implementation1, typeEncoding2); } // verify imps are swapped if ((method_getImplementation(method1) != implementation2) || (method_getImplementation(method2) != implementation1)) { goto ERROR; } return YES; ERROR: NSLog(@"WARNING: Unable to swizzle %@ instance methods: %@ & %@", [self className], (selector1) ? NSStringFromSelector(selector1) : @"", (selector2) ? NSStringFromSelector(selector2) : @""); return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSPasteboard_PPUtilities.h0000644000076500000240000000336313234403416023153 0ustar joshstaff/* NSPasteboard_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSPasteboard (PPUtilities) + (bool) ppPasteboardHasBitmap; + (bool) ppGetImageBitmap: (NSBitmapImageRep **) returnedImageBitmap maskBitmap: (NSBitmapImageRep **) returnedMaskBitmap bitmapOrigin: (NSPoint *) returnedBitmapOrigin canvasSize: (NSSize *) returnedCanvasSize andOpacity: (float *) returnedOpacity; + (void) ppSetImageBitmap: (NSBitmapImageRep *) imageBitmap maskBitmap: (NSBitmapImageRep *) maskBitmap bitmapOrigin: (NSPoint) bitmapOrigin canvasSize: (NSSize) canvasSize andOpacity: (float) opacity; + (bool) ppGetImageBitmap: (NSBitmapImageRep **) returnedImageBitmap; + (void) ppSetImageBitmap: (NSBitmapImageRep *) imageBitmap; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSPasteboard_PPUtilities.m0000644000076500000240000001603013234403205023147 0ustar joshstaff/* NSPasteboard_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSPasteboard_PPUtilities.h" #import "NSData_PPNativePasteboardType.h" #import "NSBitmapImageRep_PPUtilities.h" #define kPPPasteboardImportTypeNames \ {kPPNativePasteboardType, NSTIFFPboardType, NSPICTPboardType} static NSArray *PPPasteboardImportTypes(void); @implementation NSPasteboard (PPUtilities) + (bool) ppPasteboardHasBitmap { NSPasteboard *pasteboard; NSArray *pasteboardTypes; pasteboard = [NSPasteboard generalPasteboard]; pasteboardTypes = PPPasteboardImportTypes(); if (!pasteboard || !pasteboardTypes) { return NO; } return ([pasteboard availableTypeFromArray: pasteboardTypes]) ? YES : NO; } + (bool) ppGetImageBitmap: (NSBitmapImageRep **) returnedImageBitmap maskBitmap: (NSBitmapImageRep **) returnedMaskBitmap bitmapOrigin: (NSPoint *) returnedBitmapOrigin canvasSize: (NSSize *) returnedCanvasSize andOpacity: (float *) returnedOpacity { NSPasteboard *pasteboard; NSString *availableType; NSBitmapImageRep *imageBitmap, *maskBitmap; NSPoint bitmapOrigin; NSSize canvasSize; float opacity; pasteboard = [NSPasteboard generalPasteboard]; availableType = [pasteboard availableTypeFromArray: PPPasteboardImportTypes()]; if (!availableType) goto ERROR; if ([availableType isEqualToString: kPPNativePasteboardType]) { NSData *pasteboardData = [pasteboard dataForType: availableType]; if (![pasteboardData ppNativePasteboardDataGetImageBitmap: &imageBitmap maskBitmap: &maskBitmap bitmapOrigin: &bitmapOrigin canvasSize: &canvasSize opacity: &opacity]) { goto ERROR; } } else { NSImageRep *pasteboardImageRep = [NSImageRep imageRepWithPasteboard: pasteboard]; imageBitmap = [pasteboardImageRep ppImageBitmap]; if (!imageBitmap) goto ERROR; maskBitmap = nil; bitmapOrigin = NSZeroPoint; canvasSize = [imageBitmap ppSizeInPixels]; opacity = 1.0f; } if (returnedImageBitmap) { *returnedImageBitmap = imageBitmap; } if (returnedMaskBitmap) { *returnedMaskBitmap = maskBitmap; } if (returnedBitmapOrigin) { *returnedBitmapOrigin = bitmapOrigin; } if (returnedCanvasSize) { *returnedCanvasSize = canvasSize; } if (returnedOpacity) { *returnedOpacity = opacity; } return YES; ERROR: return NO; } + (void) ppSetImageBitmap: (NSBitmapImageRep *) imageBitmap maskBitmap: (NSBitmapImageRep *) maskBitmap bitmapOrigin: (NSPoint) bitmapOrigin canvasSize: (NSSize) canvasSize andOpacity: (float) opacity { NSData *nativePasteboardData, *tiffData; NSPasteboard *pasteboard; NSArray *pasteboardTypes; if (!imageBitmap || !maskBitmap) { goto ERROR; } imageBitmap = [imageBitmap ppImageBitmapMaskedWithMask: maskBitmap]; if (!imageBitmap) goto ERROR; nativePasteboardData = [NSData ppNativePasteboardDataWithImageBitmap: imageBitmap maskBitmap: maskBitmap bitmapOrigin: bitmapOrigin canvasSize: canvasSize opacity: opacity]; if (!nativePasteboardData) goto ERROR; if (opacity < 1.0f) { imageBitmap = [imageBitmap ppImageBitmapDissolvedToOpacity: opacity]; } tiffData = [imageBitmap ppCompressedTIFFData]; if (!tiffData) goto ERROR; pasteboard = [NSPasteboard generalPasteboard]; pasteboardTypes = [NSArray arrayWithObjects: kPPNativePasteboardType, NSTIFFPboardType, nil]; if (!pasteboard || !pasteboardTypes) { goto ERROR; } [pasteboard declareTypes: pasteboardTypes owner: self]; [pasteboard setData: nativePasteboardData forType: kPPNativePasteboardType]; [pasteboard setData: tiffData forType: NSTIFFPboardType]; return; ERROR: return; } + (bool) ppGetImageBitmap: (NSBitmapImageRep **) returnedImageBitmap { NSBitmapImageRep *imageBitmap; float opacity; if (!returnedImageBitmap) goto ERROR; if (![self ppGetImageBitmap: &imageBitmap maskBitmap: NULL bitmapOrigin: NULL canvasSize: NULL andOpacity: &opacity]) { goto ERROR; } if (opacity < 1.0f) { NSBitmapImageRep *dissolvedBitmap = [imageBitmap ppImageBitmapDissolvedToOpacity: opacity]; if (dissolvedBitmap) { imageBitmap = dissolvedBitmap; } } *returnedImageBitmap = imageBitmap; return YES; ERROR: return NO; } + (void) ppSetImageBitmap: (NSBitmapImageRep *) imageBitmap { NSData *tiffData; NSPasteboard *pasteboard; NSArray *pasteboardTypes; if (!imageBitmap) goto ERROR; tiffData = [imageBitmap ppCompressedTIFFData]; if (!tiffData) goto ERROR; pasteboard = [NSPasteboard generalPasteboard]; pasteboardTypes = [NSArray arrayWithObjects: NSTIFFPboardType, nil]; if (!pasteboard || !pasteboardTypes) { goto ERROR; } [pasteboard declareTypes: pasteboardTypes owner: self]; [pasteboard setData: tiffData forType: NSTIFFPboardType]; return; ERROR: return; } @end static NSArray *PPPasteboardImportTypes(void) { static NSArray *pasteboardImportTypes = nil; if (!pasteboardImportTypes) { id pasteboardImportTypeNames[] = kPPPasteboardImportTypeNames; int numTypes = sizeof(pasteboardImportTypeNames) / sizeof(*pasteboardImportTypeNames); pasteboardImportTypes = [[NSArray arrayWithObjects: pasteboardImportTypeNames count: numTypes] retain]; } return pasteboardImportTypes; } PikoPixel.Sources.1.0-b10b/PikoPixel/NSTextField_PPUtilities.h0000644000076500000240000000224113234403416022751 0ustar joshstaff/* NSTextField_PPUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSTextField (PPUtilities) - (int) ppClampIntValueToMax: (int) maxValue min: (int) minValue defaultValue: (int) defaultValue; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSTextField_PPUtilities.m0000644000076500000240000000545513234403205022764 0ustar joshstaff/* NSTextField_PPUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSTextField_PPUtilities.h" #import "PPAppBootUtilities.h" static NSCharacterSet *gNonDigitCharacterSet = nil; @implementation NSObject (NSTextField_PPUtilities) + (void) ppNSTextField_PPUtilities_SetupGlobals { gNonDigitCharacterSet = [[[NSCharacterSet decimalDigitCharacterSet] invertedSet] retain]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppNSTextField_PPUtilities_SetupGlobals); } @end @implementation NSTextField (PPUtilities) - (int) ppClampIntValueToMax: (int) maxValue min: (int) minValue defaultValue: (int) defaultValue { int clampedValue, currentValue; bool needToUpdateTextField = YES, selectTextFieldAfterUpdate = YES; if ([[self stringValue] rangeOfCharacterFromSet: gNonDigitCharacterSet].length) { clampedValue = defaultValue; selectTextFieldAfterUpdate = NO; } else { currentValue = [self intValue]; if (currentValue < minValue) { if ((currentValue > 0) && ((currentValue * 10) <= maxValue)) { // don't clamp valid positive integers less than minValue, because they can // become valid values after more digits are typed clampedValue = currentValue; needToUpdateTextField = NO; } else { clampedValue = minValue; } } else if (currentValue > maxValue) { clampedValue = maxValue; } else { clampedValue = currentValue; needToUpdateTextField = NO; } } if (needToUpdateTextField) { [self setIntValue: clampedValue]; if (selectTextFieldAfterUpdate) { [self selectText: nil]; } } return clampedValue; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSWindow_PPUtilities.h0000644000076500000240000000224713717302652022344 0ustar joshstaff/* NSWindow_PPUtilities.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSWindow (PPUtilities) - (void) ppMakeKeyWindowIfMain; - (void) ppSetDocumentWindowTitlebarIcon: (NSImage *) image; - (void) ppDisableWindowAnimation; @end PikoPixel.Sources.1.0-b10b/PikoPixel/NSWindow_PPUtilities.m0000644000076500000240000000711313721525630022344 0ustar joshstaff/* NSWindow_PPUtilities.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "NSWindow_PPUtilities.h" #import "PPGeometry.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #if !PP_SDK_HAS_NSWINDOWANIMATION # define NSWindowAnimationBehaviorNone 2 @interface NSWindow (SetAnimationBehaviorMethodForLegacySDKs) - (void) setAnimationBehavior: (NSInteger) animationBehavior; @end #endif // !PP_SDK_HAS_NSWINDOWANIMATION @implementation NSWindow (PPUtilities) - (void) ppMakeKeyWindowIfMain { if ([self isMainWindow] && ![self isKeyWindow] && ![NSApp modalWindow]) { [self makeKeyWindow]; } } - (void) ppSetDocumentWindowTitlebarIcon: (NSImage *) iconImage { NSButton *titlebarIconButton; NSSize buttonImageSize; NSBitmapImageRep *buttonBitmap = nil; NSImage *buttonImage = nil; titlebarIconButton = [self standardWindowButton: NSWindowDocumentIconButton]; if (!titlebarIconButton) return; buttonImageSize = [titlebarIconButton bounds].size; if (iconImage) { buttonBitmap = [NSBitmapImageRep ppImageBitmapOfSize: buttonImageSize]; } if (buttonBitmap) { NSRect iconImageFrame, buttonBoundsForIconImage; iconImageFrame = PPGeometry_OriginRectOfSize([iconImage size]); buttonBoundsForIconImage = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(iconImageFrame.size, buttonImageSize); if (!NSIsEmptyRect(buttonBoundsForIconImage)) { [buttonBitmap ppSetAsCurrentGraphicsContext]; [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh]; [iconImage drawInRect: buttonBoundsForIconImage fromRect: iconImageFrame operation: NSCompositeCopy fraction: 1.0f]; [buttonBitmap ppRestoreGraphicsContext]; } buttonImage = [NSImage ppImageWithBitmap: buttonBitmap]; } [titlebarIconButton setImage: buttonImage]; } - (void) ppDisableWindowAnimation { static bool needToCheckSetAnimationBehaviorSelector = YES, setAnimationBehaviorSelectorIsSupported = NO; if (needToCheckSetAnimationBehaviorSelector) { setAnimationBehaviorSelectorIsSupported = ([NSWindow instancesRespondToSelector: @selector(setAnimationBehavior:)]) ? YES : NO; needToCheckSetAnimationBehaviorSelector = NO; } if (setAnimationBehaviorSelectorIsSupported) { [self setAnimationBehavior: NSWindowAnimationBehaviorNone]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PikoPixel.appdata.xml0000644000076500000240000000375614400202344022220 0ustar joshstaff PikoPixel FSFAP AGPL-3.0+ PikoPixel

Pixel-art image editor

PikoPixel is a free, open-source application for drawing and editing pixel-art images and icons.

Features:

  • Easy to use
  • Unlimited undo
  • Supports multiple layers
  • Customizable canvas background and grid patterns
  • Hotkey-activated popup panels
  • Export upscaled images
  • Supports linear (gamma-correct) color blending

Originally a Mac app, PikoPixel runs natively on GNU/Linux by using the GNUstep framework.

Graphics 2DGraphics RasterGraphics PikoPixel.desktop https://screenshots.debian.net/shrine/screenshot/23198/simage/large-9e8e5c7476e202d6a071b513c1c6d24c.png https://screenshots.debian.net/shrine/screenshot/16084/simage/large-eec7d6c92dfa74ecac3e53751f340eec.png https://twilightedge.com/mac/pikopixel/ Josh Freeman pikopixel_appdata_AT_twilightedge.com PikoPixel.Sources.1.0-b10b/PikoPixel/PikoPixel.xcodeproj/0000755000076500000240000000000014400242511022046 5ustar joshstaffPikoPixel.Sources.1.0-b10b/PikoPixel/PikoPixel.xcodeproj/project.pbxproj0000644000076500000240000066247013732541442025155 0ustar joshstaff// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 45; objects = { /* Begin PBXBuildFile section */ 03020DB61441786500A988DB /* PPColorPickerPopupPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03020DB51441786500A988DB /* PPColorPickerPopupPanelController.m */; }; 030F1A9813800DAC00C79F03 /* PPDocument_CanvasSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 030F1A9713800DAC00C79F03 /* PPDocument_CanvasSettings.m */; }; 030FD3EF1511F629005E6E54 /* NSError_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 030FD3EE1511F629005E6E54 /* NSError_PPUtilities.m */; }; 0314535B1866A6FA00DE2EC4 /* PPScreencastController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0314535A1866A6FA00DE2EC4 /* PPScreencastController.m */; }; 0314CCDB164845E100F8B809 /* KeyboardNameToLocale.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0314CCD9164845E100F8B809 /* KeyboardNameToLocale.plist */; }; 03158CB2130B705900E08C31 /* PPDocument_Notifications.m in Sources */ = {isa = PBXBuildFile; fileRef = 03158CB1130B705900E08C31 /* PPDocument_Notifications.m */; }; 03158D76130BEDCF00E08C31 /* PPPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03158D75130BEDCF00E08C31 /* PPPanelController.m */; }; 031DAFB21E772A25006D2758 /* PPToolButtonMatrix.m in Sources */ = {isa = PBXBuildFile; fileRef = 031DAFB11E772A25006D2758 /* PPToolButtonMatrix.m */; }; 031EC10513CE551800582645 /* PPThumbnailImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 031EC10413CE551800582645 /* PPThumbnailImageView.m */; }; 031EC2C313CFFF5500582645 /* PPDocumentWindowController_Notifications.m in Sources */ = {isa = PBXBuildFile; fileRef = 031EC2C213CFFF5500582645 /* PPDocumentWindowController_Notifications.m */; }; 031FCB74251AF171006EF3B3 /* PPOSXGlue_NavigatorSliderVisibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 031FCB73251AF171006EF3B3 /* PPOSXGlue_NavigatorSliderVisibility.m */; }; 0324E1C2157336C5006D12BC /* PPDocument_NotificationOverrides.m in Sources */ = {isa = PBXBuildFile; fileRef = 0324E1C1157336C5006D12BC /* PPDocument_NotificationOverrides.m */; }; 0325B9A41595D1D7006472D9 /* wand_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B98C1595D1D7006472D9 /* wand_button.png */; }; 0325B9A61595D1D7006472D9 /* eyedropper_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B98E1595D1D7006472D9 /* eyedropper_button.png */; }; 0325B9A71595D1D7006472D9 /* eyedropper_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B98F1595D1D7006472D9 /* eyedropper_cursor.png */; }; 0325B9A81595D1D7006472D9 /* oval_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9901595D1D7006472D9 /* oval_cursor.png */; }; 0325B9A91595D1D7006472D9 /* line_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9911595D1D7006472D9 /* line_cursor.png */; }; 0325B9AA1595D1D7006472D9 /* magnifier_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9921595D1D7006472D9 /* magnifier_button.png */; }; 0325B9AB1595D1D7006472D9 /* line_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9931595D1D7006472D9 /* line_button.png */; }; 0325B9AC1595D1D7006472D9 /* magnifier_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9941595D1D7006472D9 /* magnifier_cursor.png */; }; 0325B9AD1595D1D7006472D9 /* pencil_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9951595D1D7006472D9 /* pencil_button.png */; }; 0325B9AE1595D1D7006472D9 /* wand_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9961595D1D7006472D9 /* wand_cursor.png */; }; 0325B9AF1595D1D7006472D9 /* rect_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9971595D1D7006472D9 /* rect_button.png */; }; 0325B9B01595D1D7006472D9 /* paintcan_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9981595D1D7006472D9 /* paintcan_button.png */; }; 0325B9B21595D1D7006472D9 /* oval_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B99A1595D1D7006472D9 /* oval_button.png */; }; 0325B9B31595D1D7006472D9 /* paintcan_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B99B1595D1D7006472D9 /* paintcan_cursor.png */; }; 0325B9B41595D1D7006472D9 /* eraser_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B99C1595D1D7006472D9 /* eraser_button.png */; }; 0325B9B51595D1D7006472D9 /* pencil_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B99D1595D1D7006472D9 /* pencil_cursor.png */; }; 0325B9B61595D1D7006472D9 /* selection_rect_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B99E1595D1D7006472D9 /* selection_rect_button.png */; }; 0325B9B71595D1D7006472D9 /* move_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B99F1595D1D7006472D9 /* move_cursor.png */; }; 0325B9B81595D1D7006472D9 /* selection_rect_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9A01595D1D7006472D9 /* selection_rect_cursor.png */; }; 0325B9B91595D1D7006472D9 /* rect_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9A11595D1D7006472D9 /* rect_cursor.png */; }; 0325B9BA1595D1D7006472D9 /* move_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9A21595D1D7006472D9 /* move_button.png */; }; 0325B9BB1595D1D7006472D9 /* eraser_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9A31595D1D7006472D9 /* eraser_cursor.png */; }; 0325B9E51596B4BE006472D9 /* pencil_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9E41596B4BE006472D9 /* pencil_segment.png */; }; 0325B9FA1596B5A6006472D9 /* solid_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9E91596B5A6006472D9 /* solid_segment.png */; }; 0325B9FB1596B5A6006472D9 /* selection_tool_overlay_subtract_pattern.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9EA1596B5A6006472D9 /* selection_tool_overlay_subtract_pattern.png */; }; 0325B9FC1596B5A6006472D9 /* selection_tool_overlay_add_pattern.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9EB1596B5A6006472D9 /* selection_tool_overlay_add_pattern.png */; }; 0325B9FD1596B5A6006472D9 /* plus_button_overlay_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9EC1596B5A6006472D9 /* plus_button_overlay_small.png */; }; 0325B9FE1596B5A6006472D9 /* plus_button_overlay.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9ED1596B5A6006472D9 /* plus_button_overlay.png */; }; 0325B9FF1596B5A6006472D9 /* neko.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9EE1596B5A6006472D9 /* neko.png */; }; 0325BA001596B5A6006472D9 /* minus_button_overlay_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9EF1596B5A6006472D9 /* minus_button_overlay_small.png */; }; 0325BA011596B5A6006472D9 /* minus_button_overlay.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9F01596B5A6006472D9 /* minus_button_overlay.png */; }; 0325BA021596B5A6006472D9 /* marching_ants_pattern.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9F11596B5A6006472D9 /* marching_ants_pattern.png */; }; 0325BA031596B5A6006472D9 /* gridtype_lines_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9F21596B5A6006472D9 /* gridtype_lines_segment.png */; }; 0325BA041596B5A6006472D9 /* gridtype_largedots_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9F31596B5A6006472D9 /* gridtype_largedots_segment.png */; }; 0325BA051596B5A6006472D9 /* gridtype_dots_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9F41596B5A6006472D9 /* gridtype_dots_segment.png */; }; 0325BA061596B5A6006472D9 /* gridtype_crosshairs_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9F51596B5A6006472D9 /* gridtype_crosshairs_segment.png */; }; 0325BA081596B5A6006472D9 /* diagonal_lines_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9F71596B5A6006472D9 /* diagonal_lines_segment.png */; }; 0325BA091596B5A6006472D9 /* checkerboard_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 0325B9F81596B5A6006472D9 /* checkerboard_segment.png */; }; 0327FA51141C908C0072EC1E /* appIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 0327FA50141C908C0072EC1E /* appIcon.icns */; }; 0329D51412DB71D10073FF2E /* PPCanvasView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0329D51312DB71D10073FF2E /* PPCanvasView.m */; }; 0329D55E12DBA08D0073FF2E /* PPDocumentWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0329D55D12DBA08D0073FF2E /* PPDocumentWindowController.m */; }; 032E7DC41AF0867D0097C0D7 /* NSObject_PPUtilities_MethodSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 032E7DC31AF0867D0097C0D7 /* NSObject_PPUtilities_MethodSwizzling.m */; }; 032FC8FE17D181E1004EC4E3 /* NSDocument_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 032FC8FD17D181E1004EC4E3 /* NSDocument_PPUtilities.m */; }; 0331D79025192FCE003EFA1C /* PPThumbnailUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 0331D78F25192FCE003EFA1C /* PPThumbnailUtilities.m */; }; 0332D8AB19F6070100CB3213 /* NSBitmapImageRep_PPUtilities_PatternBitmaps.m in Sources */ = {isa = PBXBuildFile; fileRef = 0332D8AA19F6070100CB3213 /* NSBitmapImageRep_PPUtilities_PatternBitmaps.m */; }; 0332D95C19FAF3E900CB3213 /* NSColor_PPUtilities_PatternColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 0332D95B19FAF3E900CB3213 /* NSColor_PPUtilities_PatternColors.m */; }; 033346C41574E2AE008EE9D1 /* PPDocumentLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 033346C31574E2AE008EE9D1 /* PPDocumentLayer.m */; }; 0334540613DB905B00DD0435 /* PPColorWell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0334540513DB905B00DD0435 /* PPColorWell.m */; }; 0335B0711AFADF6D00726F22 /* PPCanvasView_RetinaDrawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 0335B0701AFADF6D00726F22 /* PPCanvasView_RetinaDrawing.m */; }; 033626B81E5BEA5600BA5807 /* PPCanvasView_ColorRampToolOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 033626B71E5BEA5600BA5807 /* PPCanvasView_ColorRampToolOverlay.m */; }; 03365C0715035AA800F7DFFF /* PPApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 03365C0615035AA800F7DFFF /* PPApplication.m */; }; 03365E0B15089B7B00F7DFFF /* Hotkeys_pt_BR.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DF415089B7B00F7DFFF /* Hotkeys_pt_BR.plist */; }; 03365E0C15089B7B00F7DFFF /* Hotkeys_fr_CA.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DF515089B7B00F7DFFF /* Hotkeys_fr_CA.plist */; }; 03365E0D15089B7B00F7DFFF /* Hotkeys_fr.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DF615089B7B00F7DFFF /* Hotkeys_fr.plist */; }; 03365E0E15089B7B00F7DFFF /* Hotkeys_it.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DF715089B7B00F7DFFF /* Hotkeys_it.plist */; }; 03365E0F15089B7B00F7DFFF /* Hotkeys_el.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DF815089B7B00F7DFFF /* Hotkeys_el.plist */; }; 03365E1015089B7B00F7DFFF /* Hotkeys_en_US.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DF915089B7B00F7DFFF /* Hotkeys_en_US.plist */; }; 03365E1115089B7B00F7DFFF /* Hotkeys_is.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DFA15089B7B00F7DFFF /* Hotkeys_is.plist */; }; 03365E1215089B7B00F7DFFF /* Hotkeys_fr_CH.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DFB15089B7B00F7DFFF /* Hotkeys_fr_CH.plist */; }; 03365E1315089B7B00F7DFFF /* Hotkeys_en.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DFC15089B7B00F7DFFF /* Hotkeys_en.plist */; }; 03365E1415089B7B00F7DFFF /* Hotkeys_ru.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DFD15089B7B00F7DFFF /* Hotkeys_ru.plist */; }; 03365E1515089B7B00F7DFFF /* Hotkeys_de.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DFE15089B7B00F7DFFF /* Hotkeys_de.plist */; }; 03365E1615089B7B00F7DFFF /* Hotkeys_de_CH.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365DFF15089B7B00F7DFFF /* Hotkeys_de_CH.plist */; }; 03365E1715089B7B00F7DFFF /* Hotkeys_nl.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0015089B7B00F7DFFF /* Hotkeys_nl.plist */; }; 03365E1815089B7B00F7DFFF /* Hotkeys_es.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0115089B7B00F7DFFF /* Hotkeys_es.plist */; }; 03365E1915089B7B00F7DFFF /* Hotkeys_en_AU.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0215089B7B00F7DFFF /* Hotkeys_en_AU.plist */; }; 03365E1A15089B7B00F7DFFF /* Hotkeys_en_CA.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0315089B7B00F7DFFF /* Hotkeys_en_CA.plist */; }; 03365E1B15089B7B00F7DFFF /* Hotkeys_he.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0415089B7B00F7DFFF /* Hotkeys_he.plist */; }; 03365E1C15089B7B00F7DFFF /* Hotkeys_pt_PT.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0515089B7B00F7DFFF /* Hotkeys_pt_PT.plist */; }; 03365E1D15089B7B00F7DFFF /* Hotkeys_fi.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0615089B7B00F7DFFF /* Hotkeys_fi.plist */; }; 03365E1E15089B7B00F7DFFF /* Hotkeys_nb.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0715089B7B00F7DFFF /* Hotkeys_nb.plist */; }; 03365E1F15089B7B00F7DFFF /* Hotkeys_sv.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0815089B7B00F7DFFF /* Hotkeys_sv.plist */; }; 03365E2015089B7B00F7DFFF /* Hotkeys_en_GB.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0915089B7B00F7DFFF /* Hotkeys_en_GB.plist */; }; 03365E2115089B7B00F7DFFF /* Hotkeys_da.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03365E0A15089B7B00F7DFFF /* Hotkeys_da.plist */; }; 033661821763B7C30075C305 /* PPDocument_Tiling.m in Sources */ = {isa = PBXBuildFile; fileRef = 033661811763B7C30075C305 /* PPDocument_Tiling.m */; }; 033B6DF6176D169A005DD093 /* PPCanvasView_FillToolOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 033B6DF5176D169A005DD093 /* PPCanvasView_FillToolOverlay.m */; }; 033BA017168422B50044D327 /* PPSamplerImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 033BA016168422B50044D327 /* PPSamplerImageView.m */; }; 033BA05C168446DB0044D327 /* PPResizeControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 033BA05B168446DB0044D327 /* PPResizeControl.m */; }; 033BA06A16844DD70044D327 /* resize_control.png in Resources */ = {isa = PBXBuildFile; fileRef = 033BA06916844DD70044D327 /* resize_control.png */; }; 033BA170168498AC0044D327 /* PPMiniColorWell.m in Sources */ = {isa = PBXBuildFile; fileRef = 033BA16F168498AC0044D327 /* PPMiniColorWell.m */; }; 033BA628168D69620044D327 /* NSCursor_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 033BA627168D69620044D327 /* NSCursor_PPUtilities.m */; }; 033BA83D168EE8800044D327 /* PPDocumentSamplerImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 033BA83C168EE8800044D327 /* PPDocumentSamplerImage.m */; }; 033BA9381692B8F50044D327 /* PPDocumentSamplerImagesSettingsSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 033BA9371692B8F50044D327 /* PPDocumentSamplerImagesSettingsSheetController.m */; }; 033BA9531692D6650044D327 /* DocumentSamplerImagesSettingsSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 033BA9511692D6650044D327 /* DocumentSamplerImagesSettingsSheet.nib */; }; 033DBDEC1D76974E0087D27C /* PPObjCUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 033DBDEB1D76974E0087D27C /* PPObjCUtilities.m */; }; 033DBDF01D76976F0087D27C /* PPOSXGlue_RetinaDrawingArtifacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 033DBDED1D76976F0087D27C /* PPOSXGlue_RetinaDrawingArtifacts.m */; }; 033DBDF11D76976F0087D27C /* PPOSXGlueUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 033DBDEF1D76976F0087D27C /* PPOSXGlueUtilities.m */; }; 0341042414DF228900E75BA2 /* PPCanvasView_SelectionToolOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 0341042314DF228900E75BA2 /* PPCanvasView_SelectionToolOverlay.m */; }; 034105A014E03D8200E75BA2 /* PPCanvasView_Notifications.m in Sources */ = {isa = PBXBuildFile; fileRef = 0341059F14E03D8200E75BA2 /* PPCanvasView_Notifications.m */; }; 03432A31130F627200F9F676 /* PPToolsPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03432A30130F627200F9F676 /* PPToolsPanelController.m */; }; 03432A3A130F635F00F9F676 /* ToolsPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03432A38130F635F00F9F676 /* ToolsPanel.nib */; }; 03432A6F130FAEF500F9F676 /* PPToolbox.m in Sources */ = {isa = PBXBuildFile; fileRef = 03432A6E130FAEF500F9F676 /* PPToolbox.m */; }; 03432A82130FB03F00F9F676 /* PPTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03432A81130FB03F00F9F676 /* PPTool.m */; }; 03432A8C130FB46A00F9F676 /* PPPencilTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03432A8B130FB46A00F9F676 /* PPPencilTool.m */; }; 03432AE1130FD92D00F9F676 /* PPFillTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03432AE0130FD92D00F9F676 /* PPFillTool.m */; }; 03432AF1130FD9AF00F9F676 /* PPLineTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03432AF0130FD9AF00F9F676 /* PPLineTool.m */; }; 03432B11130FDA1A00F9F676 /* PPRectTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03432B10130FDA1A00F9F676 /* PPRectTool.m */; }; 03432B1F130FDACB00F9F676 /* PPOvalTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03432B1E130FDACB00F9F676 /* PPOvalTool.m */; }; 0344AC1A14459B370073A6AF /* ColorPickerPopupPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 0344AC1414459B370073A6AF /* ColorPickerPopupPanel.nib */; }; 0346D3601A114A4500C17251 /* PPOSXGlue_KeyUpDuringControlTracking.m in Sources */ = {isa = PBXBuildFile; fileRef = 0346D35F1A114A4500C17251 /* PPOSXGlue_KeyUpDuringControlTracking.m */; }; 0346EFD61BFE30640007A2C2 /* PPOptional_CanvasSpeedCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 0346EFD51BFE30640007A2C2 /* PPOptional_CanvasSpeedCheck.m */; }; 0349A7591304B6D4007DCD51 /* PPDocument_FileFormats.m in Sources */ = {isa = PBXBuildFile; fileRef = 0349A7581304B6D4007DCD51 /* PPDocument_FileFormats.m */; }; 0349A7611304B76E007DCD51 /* PPDocument_Drawing.m in Sources */ = {isa = PBXBuildFile; fileRef = 0349A7601304B76E007DCD51 /* PPDocument_Drawing.m */; }; 0349A77F1304BACD007DCD51 /* DocumentWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = 0349A77D1304BACD007DCD51 /* DocumentWindow.nib */; }; 034AEA2E1660AF19006C5617 /* NSObject_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 034AEA2D1660AF19006C5617 /* NSObject_PPUtilities.m */; }; 034B5FB7138ED8FB003A8E77 /* PPPopupPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 034B5FB6138ED8FB003A8E77 /* PPPopupPanelController.m */; }; 034B5FD1138EDBE8003A8E77 /* PPPopupPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = 034B5FD0138EDBE8003A8E77 /* PPPopupPanel.m */; }; 034B629113989470003A8E77 /* PPPopupPanelsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 034B629013989470003A8E77 /* PPPopupPanelsController.m */; }; 034B6354139978A4003A8E77 /* ToolsPopupPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 034B6352139978A4003A8E77 /* ToolsPopupPanel.nib */; }; 034B635C139979B1003A8E77 /* PPToolsPopupPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 034B635B139979B1003A8E77 /* PPToolsPopupPanelController.m */; }; 034B6490139AE38A003A8E77 /* NavigatorPopupPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 034B648A139AE38A003A8E77 /* NavigatorPopupPanel.nib */; }; 034B92E4150C7F2600599E0C /* Hotkeys_de_AT.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B92E3150C7F2600599E0C /* Hotkeys_de_AT.plist */; }; 034B92F3150C84A500599E0C /* Hotkeys_nl_BE.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B92F2150C84A500599E0C /* Hotkeys_nl_BE.plist */; }; 034B933A150C94C500599E0C /* Hotkeys_pl.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9339150C94C500599E0C /* Hotkeys_pl.plist */; }; 034B934D150C96DD00599E0C /* Hotkeys_ar.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B934C150C96DD00599E0C /* Hotkeys_ar.plist */; }; 034B9351150C98A600599E0C /* Hotkeys_be.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9350150C98A600599E0C /* Hotkeys_be.plist */; }; 034B9355150C99D800599E0C /* Hotkeys_bg.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9354150C99D800599E0C /* Hotkeys_bg.plist */; }; 034B935A150C9ABF00599E0C /* Hotkeys_hr.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9359150C9ABF00599E0C /* Hotkeys_hr.plist */; }; 034B9363150C9C5E00599E0C /* Hotkeys_cs.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9362150C9C5E00599E0C /* Hotkeys_cs.plist */; }; 034B9367150C9D6600599E0C /* Hotkeys_hu.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9366150C9D6600599E0C /* Hotkeys_hu.plist */; }; 034B936A150C9DFB00599E0C /* Hotkeys_lv.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9369150C9DFB00599E0C /* Hotkeys_lv.plist */; }; 034B936E150C9E7800599E0C /* Hotkeys_lt.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B936D150C9E7800599E0C /* Hotkeys_lt.plist */; }; 034B9374150C9F8D00599E0C /* Hotkeys_mk.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9373150C9F8D00599E0C /* Hotkeys_mk.plist */; }; 034B9378150CA00100599E0C /* Hotkeys_mt.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9377150CA00100599E0C /* Hotkeys_mt.plist */; }; 034B937C150CA09F00599E0C /* Hotkeys_fa.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B937B150CA09F00599E0C /* Hotkeys_fa.plist */; }; 034B937F150CA13100599E0C /* Hotkeys_ro.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B937E150CA13100599E0C /* Hotkeys_ro.plist */; }; 034B9382150CA1C900599E0C /* Hotkeys_sr-Cyrl.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9381150CA1C900599E0C /* Hotkeys_sr-Cyrl.plist */; }; 034B9385150CA2AA00599E0C /* Hotkeys_sk.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9384150CA2AA00599E0C /* Hotkeys_sk.plist */; }; 034B9388150CA34B00599E0C /* Hotkeys_sl.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9387150CA34B00599E0C /* Hotkeys_sl.plist */; }; 034B938C150CA3FD00599E0C /* Hotkeys_th.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B938B150CA3FD00599E0C /* Hotkeys_th.plist */; }; 034B938F150CA4A000599E0C /* Hotkeys_tr.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B938E150CA4A000599E0C /* Hotkeys_tr.plist */; }; 034B9392150CA50E00599E0C /* Hotkeys_uk.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9391150CA50E00599E0C /* Hotkeys_uk.plist */; }; 034B9396150CA62500599E0C /* Hotkeys_vi.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B9395150CA62500599E0C /* Hotkeys_vi.plist */; }; 034B939C150CA89900599E0C /* Hotkeys_hy.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B939B150CA89900599E0C /* Hotkeys_hy.plist */; }; 034B939F150CA97200599E0C /* Hotkeys_et.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B939E150CA97200599E0C /* Hotkeys_et.plist */; }; 034B93A2150CA9DE00599E0C /* Hotkeys_mi.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B93A1150CA9DE00599E0C /* Hotkeys_mi.plist */; }; 034B93A6150CAA7500599E0C /* Hotkeys_ne.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B93A5150CAA7500599E0C /* Hotkeys_ne.plist */; }; 034B93AA150CAB1B00599E0C /* Hotkeys_ps.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B93A9150CAB1B00599E0C /* Hotkeys_ps.plist */; }; 034B93AF150CAC2100599E0C /* Hotkeys_uz.plist in Resources */ = {isa = PBXBuildFile; fileRef = 034B93AE150CAC2100599E0C /* Hotkeys_uz.plist */; }; 034C69C81B025EEF001CC371 /* NSBezierPath_PPUtilities_MaskBitmapPaths.m in Sources */ = {isa = PBXBuildFile; fileRef = 034C69C71B025EEF001CC371 /* NSBezierPath_PPUtilities_MaskBitmapPaths.m */; }; 034D7EF61B8A6D8E0064D5D5 /* PPGridPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 034D7EF51B8A6D8E0064D5D5 /* PPGridPattern.m */; }; 0351F5271CE5071700F1501D /* PPGridPatternPresets.m in Sources */ = {isa = PBXBuildFile; fileRef = 0351F5261CE5071700F1501D /* PPGridPatternPresets.m */; }; 0358FADF1ABB0E360075A25A /* NSEvent_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 0358FADE1ABB0E360075A25A /* NSEvent_PPUtilities.m */; }; 035B00C3179078D100AA1DB7 /* PPCompositeThumbnail.m in Sources */ = {isa = PBXBuildFile; fileRef = 035B00C2179078D000AA1DB7 /* PPCompositeThumbnail.m */; }; 035B00E41790997300AA1DB7 /* PPLayerControlButtonImagesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 035B00E31790997300AA1DB7 /* PPLayerControlButtonImagesManager.m */; }; 035B01161791BDDC00AA1DB7 /* LayerControlButtonImageViews.nib in Resources */ = {isa = PBXBuildFile; fileRef = 035B01141791BDDB00AA1DB7 /* LayerControlButtonImageViews.nib */; }; 035B018D179235CC00AA1DB7 /* PPLayerControlButtonImagesManager_Notifications.m in Sources */ = {isa = PBXBuildFile; fileRef = 035B018C179235CC00AA1DB7 /* PPLayerControlButtonImagesManager_Notifications.m */; }; 035E8A4414D0980B008A66D3 /* PPDocument_PixelMatching.m in Sources */ = {isa = PBXBuildFile; fileRef = 035E8A4314D0980B008A66D3 /* PPDocument_PixelMatching.m */; }; 035F62C713E7A94400B54019 /* NSTextField_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 035F62C613E7A94400B54019 /* NSTextField_PPUtilities.m */; }; 0361D7DF153A5FEF00BCAE1D /* PPHotkeyDisplayUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 0361D7DE153A5FEF00BCAE1D /* PPHotkeyDisplayUtilities.m */; }; 0362BA0817271C8100850475 /* move_selection_outline_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 0362BA0717271C8100850475 /* move_selection_outline_cursor.png */; }; 0362BA64172873D300850475 /* PPToolModifierTipsText.m in Sources */ = {isa = PBXBuildFile; fileRef = 0362BA63172873D300850475 /* PPToolModifierTipsText.m */; }; 03635E8217BAF4BB008DA58C /* NSBitmapImageRep_PPUtilities_ImageBitmaps.m in Sources */ = {isa = PBXBuildFile; fileRef = 03635E8117BAF4BB008DA58C /* NSBitmapImageRep_PPUtilities_ImageBitmaps.m */; }; 03635E8717BAF4C7008DA58C /* NSBitmapImageRep_PPUtilities_MaskBitmaps.m in Sources */ = {isa = PBXBuildFile; fileRef = 03635E8617BAF4C7008DA58C /* NSBitmapImageRep_PPUtilities_MaskBitmaps.m */; }; 03635FC417BD56C0008DA58C /* NSBitmapImageRep_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03635FC317BD56C0008DA58C /* NSBitmapImageRep_PPUtilities.m */; }; 0363606A17BD6871008DA58C /* NSBitmapImageRep_PPUtilities_ColorMasking.m in Sources */ = {isa = PBXBuildFile; fileRef = 0363606917BD6871008DA58C /* NSBitmapImageRep_PPUtilities_ColorMasking.m */; }; 03649FF9177E9872003E30D9 /* documentIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 03649FF8177E9872003E30D9 /* documentIcon.icns */; }; 036548E816D4AA9900B98B1D /* diagonal_checkerboard_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 036548E716D4AA9900B98B1D /* diagonal_checkerboard_segment.png */; }; 036548EA16D4AAA600B98B1D /* isometric_checkerboard_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 036548E916D4AAA600B98B1D /* isometric_checkerboard_segment.png */; }; 036C750E1328B56E006AF469 /* NSImage_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 036C750D1328B56E006AF469 /* NSImage_PPUtilities.m */; }; 03700CC913261F6000FDE20E /* PPDocument_Pasteboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 03700CC813261F6000FDE20E /* PPDocument_Pasteboard.m */; }; 03721FDE15F29E1B0000E65A /* PPDocumentSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03721FDD15F29E1B0000E65A /* PPDocumentSheetController.m */; }; 0373531213B7191000F4FDC8 /* PPPanelsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0373531113B7191000F4FDC8 /* PPPanelsController.m */; }; 03744DC716098832000DB41D /* PPCanvasView_MagnifierToolOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 03744DC616098832000DB41D /* PPCanvasView_MagnifierToolOverlay.m */; }; 0374721912F3A6340026A596 /* PPLayersPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0374721812F3A6340026A596 /* PPLayersPanelController.m */; }; 037472C7143E208B00BBA96F /* PPDocumentFlattenedSaveNoticeSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 037472C6143E208B00BBA96F /* PPDocumentFlattenedSaveNoticeSheetController.m */; }; 037472EB12FBD9480026A596 /* PPDocument_Layers.m in Sources */ = {isa = PBXBuildFile; fileRef = 037472EA12FBD9480026A596 /* PPDocument_Layers.m */; }; 0374731D143E595300BBA96F /* DocumentFlattenedSaveNoticeSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 0374731B143E595300BBA96F /* DocumentFlattenedSaveNoticeSheet.nib */; }; 0377183E1EB31E8400556F9A /* PPOSXGlue_PreserveDrawColorDuringAboutPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0377183D1EB31E8400556F9A /* PPOSXGlue_PreserveDrawColorDuringAboutPanel.m */; }; 0378357513768B450046E201 /* PPDocument_Saving.m in Sources */ = {isa = PBXBuildFile; fileRef = 0378357413768B450046E201 /* PPDocument_Saving.m */; }; 037836EF137694700046E201 /* PPExportPanelAccessoryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 037836EE137694700046E201 /* PPExportPanelAccessoryViewController.m */; }; 0379BEE614440BCD006BD02A /* PPFilledRoundedRectView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0379BEE514440BCD006BD02A /* PPFilledRoundedRectView.m */; }; 037A461E1681B7B500F0C363 /* PPDocument_SamplerImages.m in Sources */ = {isa = PBXBuildFile; fileRef = 037A461D1681B7B500F0C363 /* PPDocument_SamplerImages.m */; }; 037A7AEB17B56046002D56F6 /* PPTextAttributesDicts.m in Sources */ = {isa = PBXBuildFile; fileRef = 037A7AEA17B56046002D56F6 /* PPTextAttributesDicts.m */; }; 037A7C7917B8CC38002D56F6 /* PPDocument_LayerOperationTarget.m in Sources */ = {isa = PBXBuildFile; fileRef = 037A7C7817B8CC37002D56F6 /* PPDocument_LayerOperationTarget.m */; }; 037CB6AA1D690F8300B51DA0 /* PPOSXGlue_PatternPhaseGlitches.m in Sources */ = {isa = PBXBuildFile; fileRef = 037CB6A91D690F8300B51DA0 /* PPOSXGlue_PatternPhaseGlitches.m */; }; 037CFC4A13041BE700ED3E48 /* PreviewPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 037CFC4813041BE700ED3E48 /* PreviewPanel.nib */; }; 037CFC6A13041CCB00ED3E48 /* LayersPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 037CFC6813041CCB00ED3E48 /* LayersPanel.nib */; }; 0384F85017C6F44400F766BC /* PPCanvasView_EraserToolOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 0384F84F17C6F44400F766BC /* PPCanvasView_EraserToolOverlay.m */; }; 0384F8BB17C71F7500F766BC /* eraser_tool_overlay_outline_pattern.png in Resources */ = {isa = PBXBuildFile; fileRef = 0384F8BA17C71F7500F766BC /* eraser_tool_overlay_outline_pattern.png */; }; 0385B304138011A500BE900B /* PPDocumentWindowController_Sheets.m in Sources */ = {isa = PBXBuildFile; fileRef = 0385B303138011A500BE900B /* PPDocumentWindowController_Sheets.m */; }; 038A4717141F508500CFC168 /* PPDocumentWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 038A4716141F508500CFC168 /* PPDocumentWindow.m */; }; 0393BA871D0C9CF200449C89 /* NSMutableArray_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 0393BA861D0C9CF200449C89 /* NSMutableArray_PPUtilities.m */; }; 0393BB151D18692E00449C89 /* gridpatternpreview_foreground.png in Resources */ = {isa = PBXBuildFile; fileRef = 0393BB141D18692E00449C89 /* gridpatternpreview_foreground.png */; }; 0393BB431D1882A600449C89 /* backgroundPatternArchiveIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 0393BB411D1882A600449C89 /* backgroundPatternArchiveIcon.icns */; }; 0393BB441D1882A600449C89 /* gridPatternArchiveIcon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 0393BB421D1882A600449C89 /* gridPatternArchiveIcon.icns */; }; 039769E91696113C002855D4 /* NSImageRep_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 039769E81696113C002855D4 /* NSImageRep_PPUtilities.m */; }; 039772641E1C3FCC0061D6EC /* blend_mode_icon_standard.png in Resources */ = {isa = PBXBuildFile; fileRef = 039772621E1C3FCC0061D6EC /* blend_mode_icon_standard.png */; }; 039772651E1C3FCC0061D6EC /* blend_mode_icon_linear.png in Resources */ = {isa = PBXBuildFile; fileRef = 039772631E1C3FCC0061D6EC /* blend_mode_icon_linear.png */; }; 0399D19F1DA1E58100C1DBF1 /* PPSRGBUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 0399D19E1DA1E58100C1DBF1 /* PPSRGBUtilities.m */; }; 039CB4841BCAAE4F00A9E473 /* PPAppBootUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 039CB4821BCAAE4F00A9E473 /* PPAppBootUtilities.m */; }; 039FB7BC137A74BB00D9E286 /* ExportPanelAccessoryView.nib in Resources */ = {isa = PBXBuildFile; fileRef = 039FB7B6137A74BB00D9E286 /* ExportPanelAccessoryView.nib */; }; 039FB7F0137A884900D9E286 /* DocumentBackgroundSettingsSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 039FB7EE137A884900D9E286 /* DocumentBackgroundSettingsSheet.nib */; }; 03A0DDE816719BC0000BC982 /* PPParabolicSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A0DDE716719BC0000BC982 /* PPParabolicSlider.m */; }; 03A5BEFC1523AD1E003EC48D /* ToolModifierTipsPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03A5BEFA1523AD1E003EC48D /* ToolModifierTipsPanel.nib */; }; 03A5BF0715279EB6003EC48D /* PPToolModifierTipsPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A5BF0615279EB6003EC48D /* PPToolModifierTipsPanelController.m */; }; 03A7C17E131884CE00DF3B23 /* PPDocument_Selection.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A7C17D131884CE00DF3B23 /* PPDocument_Selection.m */; }; 03A90B77156AD363008C5B1E /* PPUserFolderPaths.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A90B76156AD363008C5B1E /* PPUserFolderPaths.m */; }; 03AC18BC1890A5150059488A /* PPOptional_Screencasting.m in Sources */ = {isa = PBXBuildFile; fileRef = 03AC18BB1890A5150059488A /* PPOptional_Screencasting.m */; }; 03AC283713BCD1C300C7A477 /* NSWindow_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03AC283613BCD1C300C7A477 /* NSWindow_PPUtilities.m */; }; 03B27A391479CB1C00520BE4 /* PPLayerControlsPopupPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B27A381479CB1C00520BE4 /* PPLayerControlsPopupPanelController.m */; }; 03B27A401479CC5B00520BE4 /* LayerControlsPopupPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03B27A3E1479CC5B00520BE4 /* LayerControlsPopupPanel.nib */; }; 03B446EE16058E78009CD1D0 /* PPCanvasView_Autoscrolling.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B446ED16058E78009CD1D0 /* PPCanvasView_Autoscrolling.m */; }; 03B5E43C1DF681FF00D99F97 /* NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B5E43B1DF681FF00D99F97 /* NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m */; }; 03B5E5171DFE910300D99F97 /* PPImagePixelAlphaPremultiplyTables.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B5E5161DFE910300D99F97 /* PPImagePixelAlphaPremultiplyTables.m */; }; 03B971C91498C07C00175B89 /* NSColorPanel_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B971C81498C07C00175B89 /* NSColorPanel_PPUtilities.m */; }; 03BB8E1D14FF697300B47930 /* HotkeySettings.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03BB8E1B14FF697300B47930 /* HotkeySettings.nib */; }; 03BB8E2614FF69BF00B47930 /* PPHotkeySettingsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BB8E2514FF69BF00B47930 /* PPHotkeySettingsWindowController.m */; }; 03BD47F3133F8ACC003B0F56 /* NSColor_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BD47F2133F8ACC003B0F56 /* NSColor_PPUtilities.m */; }; 03BD4809133F9305003B0F56 /* PPDocumentGridSettingsSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BD4808133F9305003B0F56 /* PPDocumentGridSettingsSheetController.m */; }; 03BD48811340EC0E003B0F56 /* DocumentGridSettingsSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03BD487F1340EC0E003B0F56 /* DocumentGridSettingsSheet.nib */; }; 03BD48BE13410758003B0F56 /* PPUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BD48BD13410758003B0F56 /* PPUserDefaults.m */; }; 03BF0A0B135AA6D3000F2C14 /* PPPreviewPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BF0A09135AA6D3000F2C14 /* PPPreviewPanelController.m */; }; 03BF0A0E135AA6E4000F2C14 /* PPPreviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BF0A0C135AA6E4000F2C14 /* PPPreviewView.m */; }; 03BF3DDB15D84F2D00371534 /* PPDocumentScaleSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BF3DDA15D84F2D00371534 /* PPDocumentScaleSheetController.m */; }; 03BF404215E4122700371534 /* DocumentScaleSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03BF404015E4122700371534 /* DocumentScaleSheet.nib */; }; 03BF407115E4263C00371534 /* PPScaledImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BF407015E4263C00371534 /* PPScaledImageView.m */; }; 03BF414D15E8251600371534 /* PPDocumentAnimationFileNoticeSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BF414C15E8251600371534 /* PPDocumentAnimationFileNoticeSheetController.m */; }; 03BFCAF218837020001844A6 /* PPScreencastPopupPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BFCAF118837020001844A6 /* PPScreencastPopupPanelController.m */; }; 03BFCB2F18839658001844A6 /* ScreencastPopupPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03BFCB2D18839658001844A6 /* ScreencastPopupPanel.nib */; }; 03C22A14172DB76900478538 /* ToolModifierTipsStrings.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03C22A12172DB76900478538 /* ToolModifierTipsStrings.plist */; }; 03C26EAB144FEA74003D5B4E /* NSDocumentController_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C26EAA144FEA74003D5B4E /* NSDocumentController_PPUtilities.m */; }; 03C26EF614506E09003D5B4E /* NSPasteboard_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C26EF514506E09003D5B4E /* NSPasteboard_PPUtilities.m */; }; 03C26F0A1453EF9C003D5B4E /* NSData_PPNativePasteboardType.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C26F091453EF9C003D5B4E /* NSData_PPNativePasteboardType.m */; }; 03C3E5B714FA40D90050214C /* PPKeyboardLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C3E5B614FA40D90050214C /* PPKeyboardLayout.m */; }; 03C3E5C314FA41EA0050214C /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03C3E5C214FA41EA0050214C /* Carbon.framework */; }; 03C4051512FFFCC4006930D2 /* PPLayersTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C4051412FFFCC4006930D2 /* PPLayersTableView.m */; }; 03C405681300BF13006930D2 /* PPLayerOpacitySliderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C405671300BF13006930D2 /* PPLayerOpacitySliderCell.m */; }; 03C406EA1303DFEC006930D2 /* PPLayerEnabledButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C406E91303DFEC006930D2 /* PPLayerEnabledButtonCell.m */; }; 03C56B0B1E491AB20096E7C9 /* PPLayerBlendingModeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C56B0A1E491AB20096E7C9 /* PPLayerBlendingModeButton.m */; }; 03C591AD15606CF600B8AD34 /* PPImageSizePresets.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C591AC15606CF600B8AD34 /* PPImageSizePresets.m */; }; 03C591FA156314C600B8AD34 /* DocumentEditSizePresetsSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03C591F8156314C600B8AD34 /* DocumentEditSizePresetsSheet.nib */; }; 03C5920C1563184C00B8AD34 /* PPDocumentEditImageSizePresetsSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C5920B1563184C00B8AD34 /* PPDocumentEditImageSizePresetsSheetController.m */; }; 03C617F213126A1F00EE17F1 /* PPDocumentSizeSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C617F113126A1F00EE17F1 /* PPDocumentSizeSheetController.m */; }; 03C617FB1313245300EE17F1 /* DocumentSizeSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03C617F91313245300EE17F1 /* DocumentSizeSheet.nib */; }; 03C72F3414E072E90017C73C /* PPCanvasView_SelectionOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C72F3314E072E90017C73C /* PPCanvasView_SelectionOutline.m */; }; 03C7325514E6E3D00017C73C /* NSBezierPath_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C7325414E6E3D00017C73C /* NSBezierPath_PPUtilities.m */; }; 03C77650132A34410056BEC3 /* PPDocument_Moving.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C7764F132A34410056BEC3 /* PPDocument_Moving.m */; }; 03C7E0411320E7CC00236E79 /* PPDocumentWindowController_Actions.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C7E0401320E7CC00236E79 /* PPDocumentWindowController_Actions.m */; }; 03C7E0801321042300236E79 /* PPDocumentWindowController_MenuValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C7E07F1321042300236E79 /* PPDocumentWindowController_MenuValidation.m */; }; 03C8114C16A0EEBB008BBA3D /* PPColorPickerPopupPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C8114B16A0EEBB008BBA3D /* PPColorPickerPopupPanel.m */; }; 03C811CE16A32352008BBA3D /* SamplerImagePopupPanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03C811CC16A32352008BBA3D /* SamplerImagePopupPanel.nib */; }; 03C8F376179F02EB0025C1C4 /* PPTitleablePopUpButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 03C8F375179F02EA0025C1C4 /* PPTitleablePopUpButton.m */; }; 03CAB0A8142A79A8009EBA86 /* PPKeyCancellableWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CAB0A7142A79A8009EBA86 /* PPKeyCancellableWindow.m */; }; 03CAB204142BB663009EBA86 /* PPDocumentResizeSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CAB203142BB663009EBA86 /* PPDocumentResizeSheetController.m */; }; 03CAB210142BB9ED009EBA86 /* DocumentResizeSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03CAB20A142BB9ED009EBA86 /* DocumentResizeSheet.nib */; }; 03CAD73814D85EA400C37C2E /* PPCanvasView_MatchToolToleranceIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CAD73714D85EA400C37C2E /* PPCanvasView_MatchToolToleranceIndicator.m */; }; 03CAE6271681A13A005BC961 /* PPSamplerImagePopupPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CAE6261681A13A005BC961 /* PPSamplerImagePopupPanelController.m */; }; 03CB29F212E4B87600A51C92 /* PPNavigatorPopupPanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CB29F112E4B87600A51C92 /* PPNavigatorPopupPanelController.m */; }; 03CB29FA12E4B95B00A51C92 /* PPNavigatorPopupView.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CB29F912E4B95B00A51C92 /* PPNavigatorPopupView.m */; }; 03CB764B179721B4006CFD58 /* view_enabled_layers_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CB7647179721B3006CFD58 /* view_enabled_layers_icon.png */; }; 03CB764C179721B4006CFD58 /* target_draw_layer_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CB7648179721B3006CFD58 /* target_draw_layer_icon.png */; }; 03CB764D179721B4006CFD58 /* view_draw_layer_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CB7649179721B3006CFD58 /* view_draw_layer_icon.png */; }; 03CB764E179721B4006CFD58 /* target_enabled_layers_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CB764A179721B3006CFD58 /* target_enabled_layers_icon.png */; }; 03CE4BE91E5E286600FD6B5C /* color_ramp_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CE4BE81E5E286600FD6B5C /* color_ramp_cursor.png */; }; 03CE51FA135234E2009E57B9 /* PPDocument_MirroringRotating.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CE51F9135234E2009E57B9 /* PPDocument_MirroringRotating.m */; }; 03CE54BB135798B6009E57B9 /* PPDocument_Resizing.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CE54BA135798B6009E57B9 /* PPDocument_Resizing.m */; }; 03CEF1D3137A944C005B32E7 /* PPDocumentBackgroundSettingsSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CEF1D2137A944C005B32E7 /* PPDocumentBackgroundSettingsSheetController.m */; }; 03CF86B5169B13720037A5FD /* PPSamplerImagePanelController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03CF86B4169B13720037A5FD /* PPSamplerImagePanelController.m */; }; 03CF87B1169C6E3B0037A5FD /* SamplerImagePanel.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03CF87AF169C6E3B0037A5FD /* SamplerImagePanel.nib */; }; 03CF881B169C8BDB0037A5FD /* arrow_left_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CF8819169C8BDB0037A5FD /* arrow_left_button.png */; }; 03CF881C169C8BDB0037A5FD /* arrow_right_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CF881A169C8BDB0037A5FD /* arrow_right_button.png */; }; 03D5469514F8BA120063091B /* PPHotkeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 03D5469414F8BA120063091B /* PPHotkeys.m */; }; 03D791A016C3451E00BD9820 /* arrow_outline_left_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 03D7919E16C3451E00BD9820 /* arrow_outline_left_button.png */; }; 03D791A116C3451E00BD9820 /* arrow_outline_right_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 03D7919F16C3451E00BD9820 /* arrow_outline_right_button.png */; }; 03DB0C7A1323604F00978A94 /* PPGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 03DB0C791323604F00978A94 /* PPGeometry.m */; }; 03DECB6C1C5E71D300953470 /* PPCanvasView_MouseCursor.m in Sources */ = {isa = PBXBuildFile; fileRef = 03DECB6B1C5E71D300953470 /* PPCanvasView_MouseCursor.m */; }; 03E2E37314D160110040A7A3 /* PPToolUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E2E37214D160110040A7A3 /* PPToolUtilities.m */; }; 03E3974613A1807B00276376 /* PPDocument_NativeFileFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E3974513A1807B00276376 /* PPDocument_NativeFileFormat.m */; }; 03E3FF9616BCD192007F86E3 /* PPCursorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E3FF9516BCD192007F86E3 /* PPCursorManager.m */; }; 03E41EAF164C8F74009D2495 /* isometric_lines_segment.png in Resources */ = {isa = PBXBuildFile; fileRef = 03E41EAE164C8F74009D2495 /* isometric_lines_segment.png */; }; 03E69219130FDB300086A468 /* PPEraserTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E69218130FDB300086A468 /* PPEraserTool.m */; }; 03E69229130FDBD30086A468 /* PPColorSamplerTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E69228130FDBD30086A468 /* PPColorSamplerTool.m */; }; 03E69247130FDCCD0086A468 /* PPMagnifierTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E69246130FDCCD0086A468 /* PPMagnifierTool.m */; }; 03E69253130FDD230086A468 /* PPRectSelectTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E69252130FDD230086A468 /* PPRectSelectTool.m */; }; 03E6925D130FDD810086A468 /* PPMagicWandTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E6925C130FDD810086A468 /* PPMagicWandTool.m */; }; 03E69269130FDDEF0086A468 /* PPFreehandSelectTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E69268130FDDEF0086A468 /* PPFreehandSelectTool.m */; }; 03E69273130FDE300086A468 /* PPMoveTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E69272130FDE300086A468 /* PPMoveTool.m */; }; 03E6929F130FE16A0086A468 /* PPDocument_ActiveTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E6929E130FE16A0086A468 /* PPDocument_ActiveTool.m */; }; 03E951CF1E2F028B007460DC /* PPColorRampTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 03E951CD1E2F028B007460DC /* PPColorRampTool.m */; }; 03ED61071CF61F1F0061EF22 /* PPPatternPresets.m in Sources */ = {isa = PBXBuildFile; fileRef = 03ED61061CF61F1F0061EF22 /* PPPatternPresets.m */; }; 03ED62EC1CFB4EA60061EF22 /* PPPresettablePatternView.m in Sources */ = {isa = PBXBuildFile; fileRef = 03ED62EB1CFB4EA60061EF22 /* PPPresettablePatternView.m */; }; 03F0D596137D9C5800161F87 /* PPBackgroundPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F0D595137D9C5800161F87 /* PPBackgroundPattern.m */; }; 03F23727183AAEDF00D37EB5 /* PPDocument_NativeFileIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F23726183AAEDF00D37EB5 /* PPDocument_NativeFileIcon.m */; }; 03F2EF4F174439E800EBFA6B /* PPBackgroundPatternPresets.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F2EF4E174439E800EBFA6B /* PPBackgroundPatternPresets.m */; }; 03F2EF8817444AA500EBFA6B /* PPDocumentEditPatternPresetsSheetController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F2EF8717444AA500EBFA6B /* PPDocumentEditPatternPresetsSheetController.m */; }; 03F2EF9317444DF200EBFA6B /* DocumentEditPatternPresetsSheet.nib in Resources */ = {isa = PBXBuildFile; fileRef = 03F2EF9117444DF200EBFA6B /* DocumentEditPatternPresetsSheet.nib */; }; 03F2F06E1746A95400EBFA6B /* NSFileManager_PPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F2F06D1746A95400EBFA6B /* NSFileManager_PPUtilities.m */; }; 03FDC66817E56D7D0086EE53 /* freehand_select_cursor.png in Resources */ = {isa = PBXBuildFile; fileRef = 03FDC66717E56D7D0086EE53 /* freehand_select_cursor.png */; }; 03FDC66A17E56D860086EE53 /* freehand_select_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 03FDC66917E56D860086EE53 /* freehand_select_button.png */; }; 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */; }; 8D15AC2D0486D014006FF6A4 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B6FDCFA73011CA2CEA /* MainMenu.nib */; }; 8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165FFE840EACC02AAC07 /* InfoPlist.strings */; }; 8D15AC310486D014006FF6A4 /* PPDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4ACFDCFA73011CA2CEA /* PPDocument.m */; settings = {ATTRIBUTES = (); }; }; 8D15AC320486D014006FF6A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4B0FDCFA73011CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 03020DB41441786500A988DB /* PPColorPickerPopupPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPColorPickerPopupPanelController.h; sourceTree = ""; }; 03020DB51441786500A988DB /* PPColorPickerPopupPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPColorPickerPopupPanelController.m; sourceTree = ""; }; 030E8F0E1334E1D10011B0C9 /* PPModifierKeyMasks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPModifierKeyMasks.h; sourceTree = ""; }; 030F1A9713800DAC00C79F03 /* PPDocument_CanvasSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_CanvasSettings.m; sourceTree = ""; }; 030FD3ED1511F629005E6E54 /* NSError_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSError_PPUtilities.h; sourceTree = ""; }; 030FD3EE1511F629005E6E54 /* NSError_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSError_PPUtilities.m; sourceTree = ""; }; 0311371517E22D1100C3D4FB /* PPFramePinningType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPFramePinningType.h; sourceTree = ""; }; 0311375D17E23E2E00C3D4FB /* PPPanelDefaultFramePinnings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPanelDefaultFramePinnings.h; sourceTree = ""; }; 031453591866A6FA00DE2EC4 /* PPScreencastController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPScreencastController.h; sourceTree = ""; }; 0314535A1866A6FA00DE2EC4 /* PPScreencastController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPScreencastController.m; sourceTree = ""; }; 0314CCDA164845E100F8B809 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = English; path = English.lproj/KeyboardNameToLocale.plist; sourceTree = ""; }; 03158CB0130B705900E08C31 /* PPDocument_Notifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocument_Notifications.h; sourceTree = ""; }; 03158CB1130B705900E08C31 /* PPDocument_Notifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Notifications.m; sourceTree = ""; }; 03158D74130BEDCF00E08C31 /* PPPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPanelController.h; sourceTree = ""; }; 03158D75130BEDCF00E08C31 /* PPPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPanelController.m; sourceTree = ""; }; 031DAFB01E772A25006D2758 /* PPToolButtonMatrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPToolButtonMatrix.h; sourceTree = ""; }; 031DAFB11E772A25006D2758 /* PPToolButtonMatrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPToolButtonMatrix.m; sourceTree = ""; }; 031EC10313CE551800582645 /* PPThumbnailImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPThumbnailImageView.h; sourceTree = ""; }; 031EC10413CE551800582645 /* PPThumbnailImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPThumbnailImageView.m; sourceTree = ""; }; 031EC2C113CFFF5500582645 /* PPDocumentWindowController_Notifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentWindowController_Notifications.h; sourceTree = ""; }; 031EC2C213CFFF5500582645 /* PPDocumentWindowController_Notifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentWindowController_Notifications.m; sourceTree = ""; }; 031FCB73251AF171006EF3B3 /* PPOSXGlue_NavigatorSliderVisibility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOSXGlue_NavigatorSliderVisibility.m; sourceTree = ""; }; 0324E1C1157336C5006D12BC /* PPDocument_NotificationOverrides.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_NotificationOverrides.m; sourceTree = ""; }; 0325B98C1595D1D7006472D9 /* wand_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = wand_button.png; path = images/tools/wand_button.png; sourceTree = ""; }; 0325B98E1595D1D7006472D9 /* eyedropper_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = eyedropper_button.png; path = images/tools/eyedropper_button.png; sourceTree = ""; }; 0325B98F1595D1D7006472D9 /* eyedropper_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = eyedropper_cursor.png; path = images/tools/eyedropper_cursor.png; sourceTree = ""; }; 0325B9901595D1D7006472D9 /* oval_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = oval_cursor.png; path = images/tools/oval_cursor.png; sourceTree = ""; }; 0325B9911595D1D7006472D9 /* line_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = line_cursor.png; path = images/tools/line_cursor.png; sourceTree = ""; }; 0325B9921595D1D7006472D9 /* magnifier_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = magnifier_button.png; path = images/tools/magnifier_button.png; sourceTree = ""; }; 0325B9931595D1D7006472D9 /* line_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = line_button.png; path = images/tools/line_button.png; sourceTree = ""; }; 0325B9941595D1D7006472D9 /* magnifier_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = magnifier_cursor.png; path = images/tools/magnifier_cursor.png; sourceTree = ""; }; 0325B9951595D1D7006472D9 /* pencil_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pencil_button.png; path = images/tools/pencil_button.png; sourceTree = ""; }; 0325B9961595D1D7006472D9 /* wand_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = wand_cursor.png; path = images/tools/wand_cursor.png; sourceTree = ""; }; 0325B9971595D1D7006472D9 /* rect_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = rect_button.png; path = images/tools/rect_button.png; sourceTree = ""; }; 0325B9981595D1D7006472D9 /* paintcan_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = paintcan_button.png; path = images/tools/paintcan_button.png; sourceTree = ""; }; 0325B99A1595D1D7006472D9 /* oval_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = oval_button.png; path = images/tools/oval_button.png; sourceTree = ""; }; 0325B99B1595D1D7006472D9 /* paintcan_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = paintcan_cursor.png; path = images/tools/paintcan_cursor.png; sourceTree = ""; }; 0325B99C1595D1D7006472D9 /* eraser_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = eraser_button.png; path = images/tools/eraser_button.png; sourceTree = ""; }; 0325B99D1595D1D7006472D9 /* pencil_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pencil_cursor.png; path = images/tools/pencil_cursor.png; sourceTree = ""; }; 0325B99E1595D1D7006472D9 /* selection_rect_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = selection_rect_button.png; path = images/tools/selection_rect_button.png; sourceTree = ""; }; 0325B99F1595D1D7006472D9 /* move_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = move_cursor.png; path = images/tools/move_cursor.png; sourceTree = ""; }; 0325B9A01595D1D7006472D9 /* selection_rect_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = selection_rect_cursor.png; path = images/tools/selection_rect_cursor.png; sourceTree = ""; }; 0325B9A11595D1D7006472D9 /* rect_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = rect_cursor.png; path = images/tools/rect_cursor.png; sourceTree = ""; }; 0325B9A21595D1D7006472D9 /* move_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = move_button.png; path = images/tools/move_button.png; sourceTree = ""; }; 0325B9A31595D1D7006472D9 /* eraser_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = eraser_cursor.png; path = images/tools/eraser_cursor.png; sourceTree = ""; }; 0325B9E41596B4BE006472D9 /* pencil_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = pencil_segment.png; path = images/pencil_segment.png; sourceTree = ""; }; 0325B9E91596B5A6006472D9 /* solid_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = solid_segment.png; path = images/solid_segment.png; sourceTree = ""; }; 0325B9EA1596B5A6006472D9 /* selection_tool_overlay_subtract_pattern.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = selection_tool_overlay_subtract_pattern.png; path = images/selection_tool_overlay_subtract_pattern.png; sourceTree = ""; }; 0325B9EB1596B5A6006472D9 /* selection_tool_overlay_add_pattern.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = selection_tool_overlay_add_pattern.png; path = images/selection_tool_overlay_add_pattern.png; sourceTree = ""; }; 0325B9EC1596B5A6006472D9 /* plus_button_overlay_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = plus_button_overlay_small.png; path = images/plus_button_overlay_small.png; sourceTree = ""; }; 0325B9ED1596B5A6006472D9 /* plus_button_overlay.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = plus_button_overlay.png; path = images/plus_button_overlay.png; sourceTree = ""; }; 0325B9EE1596B5A6006472D9 /* neko.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = neko.png; path = images/neko.png; sourceTree = ""; }; 0325B9EF1596B5A6006472D9 /* minus_button_overlay_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = minus_button_overlay_small.png; path = images/minus_button_overlay_small.png; sourceTree = ""; }; 0325B9F01596B5A6006472D9 /* minus_button_overlay.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = minus_button_overlay.png; path = images/minus_button_overlay.png; sourceTree = ""; }; 0325B9F11596B5A6006472D9 /* marching_ants_pattern.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = marching_ants_pattern.png; path = images/marching_ants_pattern.png; sourceTree = ""; }; 0325B9F21596B5A6006472D9 /* gridtype_lines_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gridtype_lines_segment.png; path = images/gridtype_lines_segment.png; sourceTree = ""; }; 0325B9F31596B5A6006472D9 /* gridtype_largedots_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gridtype_largedots_segment.png; path = images/gridtype_largedots_segment.png; sourceTree = ""; }; 0325B9F41596B5A6006472D9 /* gridtype_dots_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gridtype_dots_segment.png; path = images/gridtype_dots_segment.png; sourceTree = ""; }; 0325B9F51596B5A6006472D9 /* gridtype_crosshairs_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gridtype_crosshairs_segment.png; path = images/gridtype_crosshairs_segment.png; sourceTree = ""; }; 0325B9F71596B5A6006472D9 /* diagonal_lines_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = diagonal_lines_segment.png; path = images/diagonal_lines_segment.png; sourceTree = ""; }; 0325B9F81596B5A6006472D9 /* checkerboard_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = checkerboard_segment.png; path = images/checkerboard_segment.png; sourceTree = ""; }; 0327FA50141C908C0072EC1E /* appIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = appIcon.icns; sourceTree = ""; }; 0329D51212DB71D10073FF2E /* PPCanvasView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPCanvasView.h; sourceTree = ""; }; 0329D51312DB71D10073FF2E /* PPCanvasView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView.m; sourceTree = ""; }; 0329D55C12DBA08D0073FF2E /* PPDocumentWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentWindowController.h; sourceTree = ""; }; 0329D55D12DBA08D0073FF2E /* PPDocumentWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentWindowController.m; sourceTree = ""; }; 032E7DC31AF0867D0097C0D7 /* NSObject_PPUtilities_MethodSwizzling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObject_PPUtilities_MethodSwizzling.m; sourceTree = ""; }; 032FC8FC17D181E1004EC4E3 /* NSDocument_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSDocument_PPUtilities.h; sourceTree = ""; }; 032FC8FD17D181E1004EC4E3 /* NSDocument_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDocument_PPUtilities.m; sourceTree = ""; }; 0331D72D2517D6B2003EFA1C /* PPThumbnailUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPThumbnailUtilities.h; sourceTree = ""; }; 0331D78F25192FCE003EFA1C /* PPThumbnailUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPThumbnailUtilities.m; sourceTree = ""; }; 0332D8AA19F6070100CB3213 /* NSBitmapImageRep_PPUtilities_PatternBitmaps.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBitmapImageRep_PPUtilities_PatternBitmaps.m; sourceTree = ""; }; 0332D95B19FAF3E900CB3213 /* NSColor_PPUtilities_PatternColors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSColor_PPUtilities_PatternColors.m; sourceTree = ""; }; 033346C21574E2AE008EE9D1 /* PPDocumentLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentLayer.h; sourceTree = ""; }; 033346C31574E2AE008EE9D1 /* PPDocumentLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentLayer.m; sourceTree = ""; }; 0334540413DB905B00DD0435 /* PPColorWell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPColorWell.h; sourceTree = ""; }; 0334540513DB905B00DD0435 /* PPColorWell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPColorWell.m; sourceTree = ""; }; 0335B0701AFADF6D00726F22 /* PPCanvasView_RetinaDrawing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_RetinaDrawing.m; sourceTree = ""; }; 03361FBD1DD41F6E00DFA5AE /* PPOSXPrefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPOSXPrefix.h; sourceTree = ""; }; 033626B71E5BEA5600BA5807 /* PPCanvasView_ColorRampToolOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_ColorRampToolOverlay.m; sourceTree = ""; }; 03365C0515035AA800F7DFFF /* PPApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPApplication.h; sourceTree = ""; }; 03365C0615035AA800F7DFFF /* PPApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPApplication.m; sourceTree = ""; }; 03365D85150612E800F7DFFF /* PPKeyConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPKeyConstants.h; sourceTree = ""; }; 03365DF415089B7B00F7DFFF /* Hotkeys_pt_BR.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_pt_BR.plist; path = hotkey_defaults/Hotkeys_pt_BR.plist; sourceTree = ""; }; 03365DF515089B7B00F7DFFF /* Hotkeys_fr_CA.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_fr_CA.plist; path = hotkey_defaults/Hotkeys_fr_CA.plist; sourceTree = ""; }; 03365DF615089B7B00F7DFFF /* Hotkeys_fr.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_fr.plist; path = hotkey_defaults/Hotkeys_fr.plist; sourceTree = ""; }; 03365DF715089B7B00F7DFFF /* Hotkeys_it.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_it.plist; path = hotkey_defaults/Hotkeys_it.plist; sourceTree = ""; }; 03365DF815089B7B00F7DFFF /* Hotkeys_el.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_el.plist; path = hotkey_defaults/Hotkeys_el.plist; sourceTree = ""; }; 03365DF915089B7B00F7DFFF /* Hotkeys_en_US.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_en_US.plist; path = hotkey_defaults/Hotkeys_en_US.plist; sourceTree = ""; }; 03365DFA15089B7B00F7DFFF /* Hotkeys_is.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_is.plist; path = hotkey_defaults/Hotkeys_is.plist; sourceTree = ""; }; 03365DFB15089B7B00F7DFFF /* Hotkeys_fr_CH.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_fr_CH.plist; path = hotkey_defaults/Hotkeys_fr_CH.plist; sourceTree = ""; }; 03365DFC15089B7B00F7DFFF /* Hotkeys_en.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_en.plist; path = hotkey_defaults/Hotkeys_en.plist; sourceTree = ""; }; 03365DFD15089B7B00F7DFFF /* Hotkeys_ru.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_ru.plist; path = hotkey_defaults/Hotkeys_ru.plist; sourceTree = ""; }; 03365DFE15089B7B00F7DFFF /* Hotkeys_de.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_de.plist; path = hotkey_defaults/Hotkeys_de.plist; sourceTree = ""; }; 03365DFF15089B7B00F7DFFF /* Hotkeys_de_CH.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_de_CH.plist; path = hotkey_defaults/Hotkeys_de_CH.plist; sourceTree = ""; }; 03365E0015089B7B00F7DFFF /* Hotkeys_nl.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_nl.plist; path = hotkey_defaults/Hotkeys_nl.plist; sourceTree = ""; }; 03365E0115089B7B00F7DFFF /* Hotkeys_es.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_es.plist; path = hotkey_defaults/Hotkeys_es.plist; sourceTree = ""; }; 03365E0215089B7B00F7DFFF /* Hotkeys_en_AU.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_en_AU.plist; path = hotkey_defaults/Hotkeys_en_AU.plist; sourceTree = ""; }; 03365E0315089B7B00F7DFFF /* Hotkeys_en_CA.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_en_CA.plist; path = hotkey_defaults/Hotkeys_en_CA.plist; sourceTree = ""; }; 03365E0415089B7B00F7DFFF /* Hotkeys_he.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_he.plist; path = hotkey_defaults/Hotkeys_he.plist; sourceTree = ""; }; 03365E0515089B7B00F7DFFF /* Hotkeys_pt_PT.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_pt_PT.plist; path = hotkey_defaults/Hotkeys_pt_PT.plist; sourceTree = ""; }; 03365E0615089B7B00F7DFFF /* Hotkeys_fi.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_fi.plist; path = hotkey_defaults/Hotkeys_fi.plist; sourceTree = ""; }; 03365E0715089B7B00F7DFFF /* Hotkeys_nb.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_nb.plist; path = hotkey_defaults/Hotkeys_nb.plist; sourceTree = ""; }; 03365E0815089B7B00F7DFFF /* Hotkeys_sv.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_sv.plist; path = hotkey_defaults/Hotkeys_sv.plist; sourceTree = ""; }; 03365E0915089B7B00F7DFFF /* Hotkeys_en_GB.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_en_GB.plist; path = hotkey_defaults/Hotkeys_en_GB.plist; sourceTree = ""; }; 03365E0A15089B7B00F7DFFF /* Hotkeys_da.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_da.plist; path = hotkey_defaults/Hotkeys_da.plist; sourceTree = ""; }; 033661811763B7C30075C305 /* PPDocument_Tiling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Tiling.m; sourceTree = ""; }; 033A216717E4BF6A00D06CF9 /* PPToolUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPToolUtilities.h; sourceTree = ""; }; 033B6DF5176D169A005DD093 /* PPCanvasView_FillToolOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_FillToolOverlay.m; sourceTree = ""; }; 033BA015168422B50044D327 /* PPSamplerImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSamplerImageView.h; sourceTree = ""; }; 033BA016168422B50044D327 /* PPSamplerImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPSamplerImageView.m; sourceTree = ""; }; 033BA05A168446DB0044D327 /* PPResizeControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPResizeControl.h; sourceTree = ""; }; 033BA05B168446DB0044D327 /* PPResizeControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPResizeControl.m; sourceTree = ""; }; 033BA06916844DD70044D327 /* resize_control.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = resize_control.png; path = images/resize_control.png; sourceTree = ""; }; 033BA16E168498AC0044D327 /* PPMiniColorWell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPMiniColorWell.h; sourceTree = ""; }; 033BA16F168498AC0044D327 /* PPMiniColorWell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPMiniColorWell.m; sourceTree = ""; }; 033BA61B168D5C0F0044D327 /* PPCursorDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPCursorDefines.h; sourceTree = ""; }; 033BA626168D69620044D327 /* NSCursor_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSCursor_PPUtilities.h; sourceTree = ""; }; 033BA627168D69620044D327 /* NSCursor_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSCursor_PPUtilities.m; sourceTree = ""; }; 033BA83B168EE8800044D327 /* PPDocumentSamplerImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentSamplerImage.h; sourceTree = ""; }; 033BA83C168EE8800044D327 /* PPDocumentSamplerImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentSamplerImage.m; sourceTree = ""; }; 033BA9361692B8F50044D327 /* PPDocumentSamplerImagesSettingsSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentSamplerImagesSettingsSheetController.h; sourceTree = ""; }; 033BA9371692B8F50044D327 /* PPDocumentSamplerImagesSettingsSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentSamplerImagesSettingsSheetController.m; sourceTree = ""; }; 033BA9521692D6650044D327 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentSamplerImagesSettingsSheet.nib; sourceTree = ""; }; 033BAB031694C6300044D327 /* PPDirectionType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDirectionType.h; sourceTree = ""; }; 033DBDEA1D76974E0087D27C /* PPObjCUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPObjCUtilities.h; sourceTree = ""; }; 033DBDEB1D76974E0087D27C /* PPObjCUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPObjCUtilities.m; sourceTree = ""; }; 033DBDED1D76976F0087D27C /* PPOSXGlue_RetinaDrawingArtifacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOSXGlue_RetinaDrawingArtifacts.m; sourceTree = ""; }; 033DBDEE1D76976F0087D27C /* PPOSXGlueUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPOSXGlueUtilities.h; sourceTree = ""; }; 033DBDEF1D76976F0087D27C /* PPOSXGlueUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOSXGlueUtilities.m; sourceTree = ""; }; 0341042314DF228900E75BA2 /* PPCanvasView_SelectionToolOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_SelectionToolOverlay.m; sourceTree = ""; }; 0341059E14E03D8200E75BA2 /* PPCanvasView_Notifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPCanvasView_Notifications.h; sourceTree = ""; }; 0341059F14E03D8200E75BA2 /* PPCanvasView_Notifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_Notifications.m; sourceTree = ""; }; 03432A2F130F627200F9F676 /* PPToolsPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPToolsPanelController.h; sourceTree = ""; }; 03432A30130F627200F9F676 /* PPToolsPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPToolsPanelController.m; sourceTree = ""; }; 03432A39130F635F00F9F676 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/ToolsPanel.nib; sourceTree = ""; }; 03432A6D130FAEF500F9F676 /* PPToolbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPToolbox.h; sourceTree = ""; }; 03432A6E130FAEF500F9F676 /* PPToolbox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPToolbox.m; sourceTree = ""; }; 03432A80130FB03F00F9F676 /* PPTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPTool.h; sourceTree = ""; }; 03432A81130FB03F00F9F676 /* PPTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPTool.m; sourceTree = ""; }; 03432A8A130FB46A00F9F676 /* PPPencilTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPencilTool.h; sourceTree = ""; }; 03432A8B130FB46A00F9F676 /* PPPencilTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPencilTool.m; sourceTree = ""; }; 03432AD7130FD8BD00F9F676 /* PPToolType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPToolType.h; sourceTree = ""; }; 03432ADF130FD92D00F9F676 /* PPFillTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPFillTool.h; sourceTree = ""; }; 03432AE0130FD92D00F9F676 /* PPFillTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPFillTool.m; sourceTree = ""; }; 03432AEF130FD9AF00F9F676 /* PPLineTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLineTool.h; sourceTree = ""; }; 03432AF0130FD9AF00F9F676 /* PPLineTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLineTool.m; sourceTree = ""; }; 03432B0F130FDA1A00F9F676 /* PPRectTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPRectTool.h; sourceTree = ""; }; 03432B10130FDA1A00F9F676 /* PPRectTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPRectTool.m; sourceTree = ""; }; 03432B1D130FDACB00F9F676 /* PPOvalTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPOvalTool.h; sourceTree = ""; }; 03432B1E130FDACB00F9F676 /* PPOvalTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOvalTool.m; sourceTree = ""; }; 0344AC1514459B370073A6AF /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/ColorPickerPopupPanel.nib; sourceTree = ""; }; 0346D35F1A114A4500C17251 /* PPOSXGlue_KeyUpDuringControlTracking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOSXGlue_KeyUpDuringControlTracking.m; sourceTree = ""; }; 0346EFB81BFE2E520007A2C2 /* PPOptional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPOptional.h; sourceTree = ""; }; 0346EFD51BFE30640007A2C2 /* PPOptional_CanvasSpeedCheck.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOptional_CanvasSpeedCheck.m; sourceTree = ""; }; 03492B851E6DF1C900B031B0 /* PPModifiablePPToolTypesMasks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPModifiablePPToolTypesMasks.h; sourceTree = ""; }; 0349A7581304B6D4007DCD51 /* PPDocument_FileFormats.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_FileFormats.m; sourceTree = ""; }; 0349A7601304B76E007DCD51 /* PPDocument_Drawing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Drawing.m; sourceTree = ""; }; 0349A77E1304BACD007DCD51 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentWindow.nib; sourceTree = ""; }; 034AEA2C1660AF19006C5617 /* NSObject_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSObject_PPUtilities.h; sourceTree = ""; }; 034AEA2D1660AF19006C5617 /* NSObject_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObject_PPUtilities.m; sourceTree = ""; }; 034B5FB5138ED8FB003A8E77 /* PPPopupPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPopupPanelController.h; sourceTree = ""; }; 034B5FB6138ED8FB003A8E77 /* PPPopupPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPopupPanelController.m; sourceTree = ""; }; 034B5FCF138EDBE8003A8E77 /* PPPopupPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPopupPanel.h; sourceTree = ""; }; 034B5FD0138EDBE8003A8E77 /* PPPopupPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPopupPanel.m; sourceTree = ""; }; 034B628F13989470003A8E77 /* PPPopupPanelsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPopupPanelsController.h; sourceTree = ""; }; 034B629013989470003A8E77 /* PPPopupPanelsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPopupPanelsController.m; sourceTree = ""; }; 034B6353139978A4003A8E77 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/ToolsPopupPanel.nib; sourceTree = ""; }; 034B635A139979B1003A8E77 /* PPToolsPopupPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPToolsPopupPanelController.h; sourceTree = ""; }; 034B635B139979B1003A8E77 /* PPToolsPopupPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPToolsPopupPanelController.m; sourceTree = ""; }; 034B648B139AE38A003A8E77 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/NavigatorPopupPanel.nib; sourceTree = ""; }; 034B92E3150C7F2600599E0C /* Hotkeys_de_AT.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_de_AT.plist; path = hotkey_defaults/Hotkeys_de_AT.plist; sourceTree = ""; }; 034B92F2150C84A500599E0C /* Hotkeys_nl_BE.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_nl_BE.plist; path = hotkey_defaults/Hotkeys_nl_BE.plist; sourceTree = ""; }; 034B9339150C94C500599E0C /* Hotkeys_pl.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_pl.plist; path = hotkey_defaults/Hotkeys_pl.plist; sourceTree = ""; }; 034B934C150C96DD00599E0C /* Hotkeys_ar.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_ar.plist; path = hotkey_defaults/Hotkeys_ar.plist; sourceTree = ""; }; 034B9350150C98A600599E0C /* Hotkeys_be.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_be.plist; path = hotkey_defaults/Hotkeys_be.plist; sourceTree = ""; }; 034B9354150C99D800599E0C /* Hotkeys_bg.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_bg.plist; path = hotkey_defaults/Hotkeys_bg.plist; sourceTree = ""; }; 034B9359150C9ABF00599E0C /* Hotkeys_hr.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_hr.plist; path = hotkey_defaults/Hotkeys_hr.plist; sourceTree = ""; }; 034B9362150C9C5E00599E0C /* Hotkeys_cs.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_cs.plist; path = hotkey_defaults/Hotkeys_cs.plist; sourceTree = ""; }; 034B9366150C9D6600599E0C /* Hotkeys_hu.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_hu.plist; path = hotkey_defaults/Hotkeys_hu.plist; sourceTree = ""; }; 034B9369150C9DFB00599E0C /* Hotkeys_lv.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_lv.plist; path = hotkey_defaults/Hotkeys_lv.plist; sourceTree = ""; }; 034B936D150C9E7800599E0C /* Hotkeys_lt.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_lt.plist; path = hotkey_defaults/Hotkeys_lt.plist; sourceTree = ""; }; 034B9373150C9F8D00599E0C /* Hotkeys_mk.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_mk.plist; path = hotkey_defaults/Hotkeys_mk.plist; sourceTree = ""; }; 034B9377150CA00100599E0C /* Hotkeys_mt.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_mt.plist; path = hotkey_defaults/Hotkeys_mt.plist; sourceTree = ""; }; 034B937B150CA09F00599E0C /* Hotkeys_fa.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_fa.plist; path = hotkey_defaults/Hotkeys_fa.plist; sourceTree = ""; }; 034B937E150CA13100599E0C /* Hotkeys_ro.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_ro.plist; path = hotkey_defaults/Hotkeys_ro.plist; sourceTree = ""; }; 034B9381150CA1C900599E0C /* Hotkeys_sr-Cyrl.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Hotkeys_sr-Cyrl.plist"; path = "hotkey_defaults/Hotkeys_sr-Cyrl.plist"; sourceTree = ""; }; 034B9384150CA2AA00599E0C /* Hotkeys_sk.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_sk.plist; path = hotkey_defaults/Hotkeys_sk.plist; sourceTree = ""; }; 034B9387150CA34B00599E0C /* Hotkeys_sl.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_sl.plist; path = hotkey_defaults/Hotkeys_sl.plist; sourceTree = ""; }; 034B938B150CA3FD00599E0C /* Hotkeys_th.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_th.plist; path = hotkey_defaults/Hotkeys_th.plist; sourceTree = ""; }; 034B938E150CA4A000599E0C /* Hotkeys_tr.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_tr.plist; path = hotkey_defaults/Hotkeys_tr.plist; sourceTree = ""; }; 034B9391150CA50E00599E0C /* Hotkeys_uk.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_uk.plist; path = hotkey_defaults/Hotkeys_uk.plist; sourceTree = ""; }; 034B9395150CA62500599E0C /* Hotkeys_vi.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_vi.plist; path = hotkey_defaults/Hotkeys_vi.plist; sourceTree = ""; }; 034B939B150CA89900599E0C /* Hotkeys_hy.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_hy.plist; path = hotkey_defaults/Hotkeys_hy.plist; sourceTree = ""; }; 034B939E150CA97200599E0C /* Hotkeys_et.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_et.plist; path = hotkey_defaults/Hotkeys_et.plist; sourceTree = ""; }; 034B93A1150CA9DE00599E0C /* Hotkeys_mi.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_mi.plist; path = hotkey_defaults/Hotkeys_mi.plist; sourceTree = ""; }; 034B93A5150CAA7500599E0C /* Hotkeys_ne.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_ne.plist; path = hotkey_defaults/Hotkeys_ne.plist; sourceTree = ""; }; 034B93A9150CAB1B00599E0C /* Hotkeys_ps.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_ps.plist; path = hotkey_defaults/Hotkeys_ps.plist; sourceTree = ""; }; 034B93AE150CAC2100599E0C /* Hotkeys_uz.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Hotkeys_uz.plist; path = hotkey_defaults/Hotkeys_uz.plist; sourceTree = ""; }; 034C69C71B025EEF001CC371 /* NSBezierPath_PPUtilities_MaskBitmapPaths.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBezierPath_PPUtilities_MaskBitmapPaths.m; sourceTree = ""; }; 034D7EF41B8A6D8E0064D5D5 /* PPGridPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPGridPattern.h; sourceTree = ""; }; 034D7EF51B8A6D8E0064D5D5 /* PPGridPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPGridPattern.m; sourceTree = ""; }; 0351F5251CE5071700F1501D /* PPGridPatternPresets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPGridPatternPresets.h; sourceTree = ""; }; 0351F5261CE5071700F1501D /* PPGridPatternPresets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPGridPatternPresets.m; sourceTree = ""; }; 0358FADD1ABB0E360075A25A /* NSEvent_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSEvent_PPUtilities.h; sourceTree = ""; }; 0358FADE1ABB0E360075A25A /* NSEvent_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSEvent_PPUtilities.m; sourceTree = ""; }; 035B00C1179078D000AA1DB7 /* PPCompositeThumbnail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPCompositeThumbnail.h; sourceTree = ""; }; 035B00C2179078D000AA1DB7 /* PPCompositeThumbnail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCompositeThumbnail.m; sourceTree = ""; }; 035B00E21790997300AA1DB7 /* PPLayerControlButtonImagesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayerControlButtonImagesManager.h; sourceTree = ""; }; 035B00E31790997300AA1DB7 /* PPLayerControlButtonImagesManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLayerControlButtonImagesManager.m; sourceTree = ""; }; 035B01151791BDDB00AA1DB7 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/LayerControlButtonImageViews.nib; sourceTree = ""; }; 035B018B179235CC00AA1DB7 /* PPLayerControlButtonImagesManager_Notifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayerControlButtonImagesManager_Notifications.h; sourceTree = ""; }; 035B018C179235CC00AA1DB7 /* PPLayerControlButtonImagesManager_Notifications.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLayerControlButtonImagesManager_Notifications.m; sourceTree = ""; }; 035BFFD5178E4F0000AA1DB7 /* PPRuntimeEnvironmentMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPRuntimeEnvironmentMacros.h; sourceTree = ""; }; 035E8A4314D0980B008A66D3 /* PPDocument_PixelMatching.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_PixelMatching.m; sourceTree = ""; }; 035F62C513E7A94400B54019 /* NSTextField_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSTextField_PPUtilities.h; sourceTree = ""; }; 035F62C613E7A94400B54019 /* NSTextField_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSTextField_PPUtilities.m; sourceTree = ""; }; 0361D7DD153A5FEF00BCAE1D /* PPHotkeyDisplayUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPHotkeyDisplayUtilities.h; sourceTree = ""; }; 0361D7DE153A5FEF00BCAE1D /* PPHotkeyDisplayUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPHotkeyDisplayUtilities.m; sourceTree = ""; }; 0362BA0717271C8100850475 /* move_selection_outline_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = move_selection_outline_cursor.png; path = images/tools/move_selection_outline_cursor.png; sourceTree = ""; }; 0362BA62172873D300850475 /* PPToolModifierTipsText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPToolModifierTipsText.h; sourceTree = ""; }; 0362BA63172873D300850475 /* PPToolModifierTipsText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPToolModifierTipsText.m; sourceTree = ""; }; 03635E6817BAF349008DA58C /* PPBitmapPixelTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPBitmapPixelTypes.h; sourceTree = ""; }; 03635E8117BAF4BB008DA58C /* NSBitmapImageRep_PPUtilities_ImageBitmaps.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBitmapImageRep_PPUtilities_ImageBitmaps.m; sourceTree = ""; }; 03635E8617BAF4C7008DA58C /* NSBitmapImageRep_PPUtilities_MaskBitmaps.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBitmapImageRep_PPUtilities_MaskBitmaps.m; sourceTree = ""; }; 03635FC317BD56C0008DA58C /* NSBitmapImageRep_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBitmapImageRep_PPUtilities.m; sourceTree = ""; }; 0363606917BD6871008DA58C /* NSBitmapImageRep_PPUtilities_ColorMasking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBitmapImageRep_PPUtilities_ColorMasking.m; sourceTree = ""; }; 03649FF8177E9872003E30D9 /* documentIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = documentIcon.icns; sourceTree = ""; }; 036548E716D4AA9900B98B1D /* diagonal_checkerboard_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = diagonal_checkerboard_segment.png; path = images/diagonal_checkerboard_segment.png; sourceTree = ""; }; 036548E916D4AAA600B98B1D /* isometric_checkerboard_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = isometric_checkerboard_segment.png; path = images/isometric_checkerboard_segment.png; sourceTree = ""; }; 03654BD716DC8A3200B98B1D /* PPPopupPanelActionKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPopupPanelActionKeys.h; sourceTree = ""; }; 036C750C1328B56E006AF469 /* NSImage_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSImage_PPUtilities.h; sourceTree = ""; }; 036C750D1328B56E006AF469 /* NSImage_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSImage_PPUtilities.m; sourceTree = ""; }; 03700CC813261F6000FDE20E /* PPDocument_Pasteboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Pasteboard.m; sourceTree = ""; }; 03721FDC15F29E1B0000E65A /* PPDocumentSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentSheetController.h; sourceTree = ""; }; 03721FDD15F29E1B0000E65A /* PPDocumentSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentSheetController.m; sourceTree = ""; }; 0373531013B7191000F4FDC8 /* PPPanelsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPanelsController.h; sourceTree = ""; }; 0373531113B7191000F4FDC8 /* PPPanelsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPanelsController.m; sourceTree = ""; }; 03744DC616098832000DB41D /* PPCanvasView_MagnifierToolOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_MagnifierToolOverlay.m; sourceTree = ""; }; 0374721712F3A6340026A596 /* PPLayersPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayersPanelController.h; sourceTree = ""; }; 0374721812F3A6340026A596 /* PPLayersPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLayersPanelController.m; sourceTree = ""; }; 037472C5143E208B00BBA96F /* PPDocumentFlattenedSaveNoticeSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentFlattenedSaveNoticeSheetController.h; sourceTree = ""; }; 037472C6143E208B00BBA96F /* PPDocumentFlattenedSaveNoticeSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentFlattenedSaveNoticeSheetController.m; sourceTree = ""; }; 037472EA12FBD9480026A596 /* PPDocument_Layers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Layers.m; sourceTree = ""; }; 0374731C143E595300BBA96F /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentFlattenedSaveNoticeSheet.nib; sourceTree = ""; }; 0377183D1EB31E8400556F9A /* PPOSXGlue_PreserveDrawColorDuringAboutPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOSXGlue_PreserveDrawColorDuringAboutPanel.m; sourceTree = ""; }; 0378357413768B450046E201 /* PPDocument_Saving.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Saving.m; sourceTree = ""; }; 037836ED137694700046E201 /* PPExportPanelAccessoryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPExportPanelAccessoryViewController.h; sourceTree = ""; }; 037836EE137694700046E201 /* PPExportPanelAccessoryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPExportPanelAccessoryViewController.m; sourceTree = ""; }; 0379BEE414440BCD006BD02A /* PPFilledRoundedRectView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPFilledRoundedRectView.h; sourceTree = ""; }; 0379BEE514440BCD006BD02A /* PPFilledRoundedRectView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPFilledRoundedRectView.m; sourceTree = ""; }; 037A461D1681B7B500F0C363 /* PPDocument_SamplerImages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_SamplerImages.m; sourceTree = ""; }; 037A7AE917B56046002D56F6 /* PPTextAttributesDicts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPTextAttributesDicts.h; sourceTree = ""; }; 037A7AEA17B56046002D56F6 /* PPTextAttributesDicts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPTextAttributesDicts.m; sourceTree = ""; }; 037A7AF517B56405002D56F6 /* PPUIFontDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPUIFontDefines.h; sourceTree = ""; }; 037A7C7817B8CC37002D56F6 /* PPDocument_LayerOperationTarget.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_LayerOperationTarget.m; sourceTree = ""; }; 037CB6A91D690F8300B51DA0 /* PPOSXGlue_PatternPhaseGlitches.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOSXGlue_PatternPhaseGlitches.m; sourceTree = ""; }; 037CFC4913041BE700ED3E48 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/PreviewPanel.nib; sourceTree = ""; }; 037CFC6913041CCB00ED3E48 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/LayersPanel.nib; sourceTree = ""; }; 0384F0BA153A85670027C3B0 /* PPGridType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPGridType.h; sourceTree = ""; }; 0384F84F17C6F44400F766BC /* PPCanvasView_EraserToolOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_EraserToolOverlay.m; sourceTree = ""; }; 0384F8BA17C71F7500F766BC /* eraser_tool_overlay_outline_pattern.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = eraser_tool_overlay_outline_pattern.png; path = images/eraser_tool_overlay_outline_pattern.png; sourceTree = ""; }; 0385B303138011A500BE900B /* PPDocumentWindowController_Sheets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentWindowController_Sheets.m; sourceTree = ""; }; 038A4715141F508500CFC168 /* PPDocumentWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentWindow.h; sourceTree = ""; }; 038A4716141F508500CFC168 /* PPDocumentWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentWindow.m; sourceTree = ""; }; 0393BA851D0C9CF200449C89 /* NSMutableArray_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSMutableArray_PPUtilities.h; sourceTree = ""; }; 0393BA861D0C9CF200449C89 /* NSMutableArray_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSMutableArray_PPUtilities.m; sourceTree = ""; }; 0393BB141D18692E00449C89 /* gridpatternpreview_foreground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gridpatternpreview_foreground.png; path = images/gridpatternpreview_foreground.png; sourceTree = ""; }; 0393BB411D1882A600449C89 /* backgroundPatternArchiveIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = backgroundPatternArchiveIcon.icns; sourceTree = ""; }; 0393BB421D1882A600449C89 /* gridPatternArchiveIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = gridPatternArchiveIcon.icns; sourceTree = ""; }; 039769E71696113C002855D4 /* NSImageRep_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSImageRep_PPUtilities.h; sourceTree = ""; }; 039769E81696113C002855D4 /* NSImageRep_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSImageRep_PPUtilities.m; sourceTree = ""; }; 039772621E1C3FCC0061D6EC /* blend_mode_icon_standard.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = blend_mode_icon_standard.png; path = images/blend_mode_icon_standard.png; sourceTree = ""; }; 039772631E1C3FCC0061D6EC /* blend_mode_icon_linear.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = blend_mode_icon_linear.png; path = images/blend_mode_icon_linear.png; sourceTree = ""; }; 0399D19D1DA1E58100C1DBF1 /* PPSRGBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSRGBUtilities.h; sourceTree = ""; }; 0399D19E1DA1E58100C1DBF1 /* PPSRGBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPSRGBUtilities.m; sourceTree = ""; }; 039CB4821BCAAE4F00A9E473 /* PPAppBootUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPAppBootUtilities.m; sourceTree = ""; }; 039CB4831BCAAE4F00A9E473 /* PPAppBootUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPAppBootUtilities.h; sourceTree = ""; }; 039CD35616670B8300ED977A /* PPDocumentTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentTypes.h; sourceTree = ""; }; 039CD3C7166747DE00ED977A /* PPPanelType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPanelType.h; sourceTree = ""; }; 039CD3D916674AD000ED977A /* PPPopupPanelType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPopupPanelType.h; sourceTree = ""; }; 039CD3E816674F2600ED977A /* PPLayerDisplayMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayerDisplayMode.h; sourceTree = ""; }; 039CD4001667524500ED977A /* PPPreviewBackgroundType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPreviewBackgroundType.h; sourceTree = ""; }; 039CD49F16688F5700ED977A /* PPBackgroundPatternType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPBackgroundPatternType.h; sourceTree = ""; }; 039CD4B41668972600ED977A /* PPHotkeyType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPHotkeyType.h; sourceTree = ""; }; 039FB7B7137A74BB00D9E286 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/ExportPanelAccessoryView.nib; sourceTree = ""; }; 039FB7EF137A884900D9E286 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentBackgroundSettingsSheet.nib; sourceTree = ""; }; 03A0DDE616719BC0000BC982 /* PPParabolicSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPParabolicSlider.h; sourceTree = ""; }; 03A0DDE716719BC0000BC982 /* PPParabolicSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPParabolicSlider.m; sourceTree = ""; }; 03A5BEFB1523AD1E003EC48D /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/ToolModifierTipsPanel.nib; sourceTree = ""; }; 03A5BF0515279EB6003EC48D /* PPToolModifierTipsPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPToolModifierTipsPanelController.h; sourceTree = ""; }; 03A5BF0615279EB6003EC48D /* PPToolModifierTipsPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPToolModifierTipsPanelController.m; sourceTree = ""; }; 03A7C17D131884CE00DF3B23 /* PPDocument_Selection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Selection.m; sourceTree = ""; }; 03A90B75156AD363008C5B1E /* PPUserFolderPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPUserFolderPaths.h; sourceTree = ""; }; 03A90B76156AD363008C5B1E /* PPUserFolderPaths.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPUserFolderPaths.m; sourceTree = ""; }; 03AC18BB1890A5150059488A /* PPOptional_Screencasting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPOptional_Screencasting.m; sourceTree = ""; }; 03AC283513BCD1C300C7A477 /* NSWindow_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSWindow_PPUtilities.h; sourceTree = ""; }; 03AC283613BCD1C300C7A477 /* NSWindow_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSWindow_PPUtilities.m; sourceTree = ""; }; 03B27A371479CB1C00520BE4 /* PPLayerControlsPopupPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayerControlsPopupPanelController.h; sourceTree = ""; }; 03B27A381479CB1C00520BE4 /* PPLayerControlsPopupPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLayerControlsPopupPanelController.m; sourceTree = ""; }; 03B27A3F1479CC5B00520BE4 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/LayerControlsPopupPanel.nib; sourceTree = ""; }; 03B3814E15EF1B6E001FC276 /* PPDocumentWindowController_Sheets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentWindowController_Sheets.h; sourceTree = ""; }; 03B446ED16058E78009CD1D0 /* PPCanvasView_Autoscrolling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_Autoscrolling.m; sourceTree = ""; }; 03B5E43B1DF681FF00D99F97 /* NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m; sourceTree = ""; }; 03B5E5151DFE910300D99F97 /* PPImagePixelAlphaPremultiplyTables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPImagePixelAlphaPremultiplyTables.h; sourceTree = ""; }; 03B5E5161DFE910300D99F97 /* PPImagePixelAlphaPremultiplyTables.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPImagePixelAlphaPremultiplyTables.m; sourceTree = ""; }; 03B971C71498C07C00175B89 /* NSColorPanel_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSColorPanel_PPUtilities.h; sourceTree = ""; }; 03B971C81498C07C00175B89 /* NSColorPanel_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSColorPanel_PPUtilities.m; sourceTree = ""; }; 03BB8E1C14FF697300B47930 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/HotkeySettings.nib; sourceTree = ""; }; 03BB8E2414FF69BF00B47930 /* PPHotkeySettingsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPHotkeySettingsWindowController.h; sourceTree = ""; }; 03BB8E2514FF69BF00B47930 /* PPHotkeySettingsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPHotkeySettingsWindowController.m; sourceTree = ""; }; 03BD47F1133F8ACC003B0F56 /* NSColor_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSColor_PPUtilities.h; sourceTree = ""; }; 03BD47F2133F8ACC003B0F56 /* NSColor_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSColor_PPUtilities.m; sourceTree = ""; }; 03BD4807133F9305003B0F56 /* PPDocumentGridSettingsSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentGridSettingsSheetController.h; sourceTree = ""; }; 03BD4808133F9305003B0F56 /* PPDocumentGridSettingsSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentGridSettingsSheetController.m; sourceTree = ""; }; 03BD48801340EC0E003B0F56 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentGridSettingsSheet.nib; sourceTree = ""; }; 03BD48BC13410758003B0F56 /* PPUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPUserDefaults.h; sourceTree = ""; }; 03BD48BD13410758003B0F56 /* PPUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPUserDefaults.m; sourceTree = ""; }; 03BF0A09135AA6D3000F2C14 /* PPPreviewPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPreviewPanelController.m; sourceTree = ""; }; 03BF0A0A135AA6D3000F2C14 /* PPPreviewPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPreviewPanelController.h; sourceTree = ""; }; 03BF0A0C135AA6E4000F2C14 /* PPPreviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPreviewView.m; sourceTree = ""; }; 03BF0A0D135AA6E4000F2C14 /* PPPreviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPreviewView.h; sourceTree = ""; }; 03BF3DD915D84F2D00371534 /* PPDocumentScaleSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentScaleSheetController.h; sourceTree = ""; }; 03BF3DDA15D84F2D00371534 /* PPDocumentScaleSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentScaleSheetController.m; sourceTree = ""; }; 03BF404115E4122700371534 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentScaleSheet.nib; sourceTree = ""; }; 03BF406F15E4263C00371534 /* PPScaledImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPScaledImageView.h; sourceTree = ""; }; 03BF407015E4263C00371534 /* PPScaledImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPScaledImageView.m; sourceTree = ""; }; 03BF414B15E8251600371534 /* PPDocumentAnimationFileNoticeSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentAnimationFileNoticeSheetController.h; sourceTree = ""; }; 03BF414C15E8251600371534 /* PPDocumentAnimationFileNoticeSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentAnimationFileNoticeSheetController.m; sourceTree = ""; }; 03BFCAF018837020001844A6 /* PPScreencastPopupPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPScreencastPopupPanelController.h; sourceTree = ""; }; 03BFCAF118837020001844A6 /* PPScreencastPopupPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPScreencastPopupPanelController.m; sourceTree = ""; }; 03BFCB2E18839658001844A6 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/ScreencastPopupPanel.nib; sourceTree = ""; }; 03C22A13172DB76900478538 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = English; path = English.lproj/ToolModifierTipsStrings.plist; sourceTree = ""; }; 03C26EA9144FEA74003D5B4E /* NSDocumentController_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSDocumentController_PPUtilities.h; sourceTree = ""; }; 03C26EAA144FEA74003D5B4E /* NSDocumentController_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDocumentController_PPUtilities.m; sourceTree = ""; }; 03C26EF414506E09003D5B4E /* NSPasteboard_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSPasteboard_PPUtilities.h; sourceTree = ""; }; 03C26EF514506E09003D5B4E /* NSPasteboard_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSPasteboard_PPUtilities.m; sourceTree = ""; }; 03C26F081453EF9C003D5B4E /* NSData_PPNativePasteboardType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSData_PPNativePasteboardType.h; sourceTree = ""; }; 03C26F091453EF9C003D5B4E /* NSData_PPNativePasteboardType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSData_PPNativePasteboardType.m; sourceTree = ""; }; 03C3E5B514FA40D90050214C /* PPKeyboardLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPKeyboardLayout.h; sourceTree = ""; }; 03C3E5B614FA40D90050214C /* PPKeyboardLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPKeyboardLayout.m; sourceTree = ""; }; 03C3E5C214FA41EA0050214C /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = ""; }; 03C4051312FFFCC4006930D2 /* PPLayersTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayersTableView.h; sourceTree = ""; }; 03C4051412FFFCC4006930D2 /* PPLayersTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLayersTableView.m; sourceTree = ""; }; 03C405661300BF13006930D2 /* PPLayerOpacitySliderCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayerOpacitySliderCell.h; sourceTree = ""; }; 03C405671300BF13006930D2 /* PPLayerOpacitySliderCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLayerOpacitySliderCell.m; sourceTree = ""; }; 03C406E81303DFEC006930D2 /* PPLayerEnabledButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayerEnabledButtonCell.h; sourceTree = ""; }; 03C406E91303DFEC006930D2 /* PPLayerEnabledButtonCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLayerEnabledButtonCell.m; sourceTree = ""; }; 03C51ECB218A086D00F2B145 /* PPXCConfig_10.5sdk.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = PPXCConfig_10.5sdk.xcconfig; sourceTree = ""; }; 03C51ECC218A086D00F2B145 /* PPXCConfig_10.14sdk.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = PPXCConfig_10.14sdk.xcconfig; sourceTree = ""; }; 03C52017218E12BD00F2B145 /* PPXCConfigCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPXCConfigCheck.h; sourceTree = ""; }; 03C56B091E491AB20096E7C9 /* PPLayerBlendingModeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPLayerBlendingModeButton.h; sourceTree = ""; }; 03C56B0A1E491AB20096E7C9 /* PPLayerBlendingModeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPLayerBlendingModeButton.m; sourceTree = ""; }; 03C591AB15606CF600B8AD34 /* PPImageSizePresets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPImageSizePresets.h; sourceTree = ""; }; 03C591AC15606CF600B8AD34 /* PPImageSizePresets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPImageSizePresets.m; sourceTree = ""; }; 03C591F9156314C600B8AD34 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentEditSizePresetsSheet.nib; sourceTree = ""; }; 03C5920B1563184C00B8AD34 /* PPDocumentEditImageSizePresetsSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentEditImageSizePresetsSheetController.m; sourceTree = ""; }; 03C617F013126A1F00EE17F1 /* PPDocumentSizeSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentSizeSheetController.h; sourceTree = ""; }; 03C617F113126A1F00EE17F1 /* PPDocumentSizeSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentSizeSheetController.m; sourceTree = ""; }; 03C617FA1313245300EE17F1 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentSizeSheet.nib; sourceTree = ""; }; 03C6183E1313364000EE17F1 /* PPDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDefines.h; sourceTree = ""; }; 03C72F3314E072E90017C73C /* PPCanvasView_SelectionOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_SelectionOutline.m; sourceTree = ""; }; 03C7325314E6E3D00017C73C /* NSBezierPath_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSBezierPath_PPUtilities.h; sourceTree = ""; }; 03C7325414E6E3D00017C73C /* NSBezierPath_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSBezierPath_PPUtilities.m; sourceTree = ""; }; 03C7764F132A34410056BEC3 /* PPDocument_Moving.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Moving.m; sourceTree = ""; }; 03C7E0401320E7CC00236E79 /* PPDocumentWindowController_Actions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentWindowController_Actions.m; sourceTree = ""; }; 03C7E07F1321042300236E79 /* PPDocumentWindowController_MenuValidation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentWindowController_MenuValidation.m; sourceTree = ""; }; 03C8114A16A0EEBB008BBA3D /* PPColorPickerPopupPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPColorPickerPopupPanel.h; sourceTree = ""; }; 03C8114B16A0EEBB008BBA3D /* PPColorPickerPopupPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPColorPickerPopupPanel.m; sourceTree = ""; }; 03C811CD16A32352008BBA3D /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/SamplerImagePopupPanel.nib; sourceTree = ""; }; 03C8F374179F02EA0025C1C4 /* PPTitleablePopUpButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPTitleablePopUpButton.h; sourceTree = ""; }; 03C8F375179F02EA0025C1C4 /* PPTitleablePopUpButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPTitleablePopUpButton.m; sourceTree = ""; }; 03CAB0A6142A79A8009EBA86 /* PPKeyCancellableWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPKeyCancellableWindow.h; sourceTree = ""; }; 03CAB0A7142A79A8009EBA86 /* PPKeyCancellableWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPKeyCancellableWindow.m; sourceTree = ""; }; 03CAB202142BB663009EBA86 /* PPDocumentResizeSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentResizeSheetController.h; sourceTree = ""; }; 03CAB203142BB663009EBA86 /* PPDocumentResizeSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentResizeSheetController.m; sourceTree = ""; }; 03CAB20B142BB9ED009EBA86 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentResizeSheet.nib; sourceTree = ""; }; 03CAD73714D85EA400C37C2E /* PPCanvasView_MatchToolToleranceIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_MatchToolToleranceIndicator.m; sourceTree = ""; }; 03CAE6251681A13A005BC961 /* PPSamplerImagePopupPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSamplerImagePopupPanelController.h; sourceTree = ""; }; 03CAE6261681A13A005BC961 /* PPSamplerImagePopupPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPSamplerImagePopupPanelController.m; sourceTree = ""; }; 03CB29F012E4B87600A51C92 /* PPNavigatorPopupPanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPNavigatorPopupPanelController.h; sourceTree = ""; }; 03CB29F112E4B87600A51C92 /* PPNavigatorPopupPanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPNavigatorPopupPanelController.m; sourceTree = ""; }; 03CB29F812E4B95B00A51C92 /* PPNavigatorPopupView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPNavigatorPopupView.h; sourceTree = ""; }; 03CB29F912E4B95B00A51C92 /* PPNavigatorPopupView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPNavigatorPopupView.m; sourceTree = ""; }; 03CB7647179721B3006CFD58 /* view_enabled_layers_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = view_enabled_layers_icon.png; path = images/view_enabled_layers_icon.png; sourceTree = ""; }; 03CB7648179721B3006CFD58 /* target_draw_layer_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = target_draw_layer_icon.png; path = images/target_draw_layer_icon.png; sourceTree = ""; }; 03CB7649179721B3006CFD58 /* view_draw_layer_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = view_draw_layer_icon.png; path = images/view_draw_layer_icon.png; sourceTree = ""; }; 03CB764A179721B3006CFD58 /* target_enabled_layers_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = target_enabled_layers_icon.png; path = images/target_enabled_layers_icon.png; sourceTree = ""; }; 03CE4BE81E5E286600FD6B5C /* color_ramp_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = color_ramp_cursor.png; path = images/tools/color_ramp_cursor.png; sourceTree = ""; }; 03CE51F9135234E2009E57B9 /* PPDocument_MirroringRotating.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_MirroringRotating.m; sourceTree = ""; }; 03CE54BA135798B6009E57B9 /* PPDocument_Resizing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_Resizing.m; sourceTree = ""; }; 03CEF1D1137A944C005B32E7 /* PPDocumentBackgroundSettingsSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentBackgroundSettingsSheetController.h; sourceTree = ""; }; 03CEF1D2137A944C005B32E7 /* PPDocumentBackgroundSettingsSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentBackgroundSettingsSheetController.m; sourceTree = ""; }; 03CF86B3169B13720037A5FD /* PPSamplerImagePanelController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSamplerImagePanelController.h; sourceTree = ""; }; 03CF86B4169B13720037A5FD /* PPSamplerImagePanelController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPSamplerImagePanelController.m; sourceTree = ""; }; 03CF87B0169C6E3B0037A5FD /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/SamplerImagePanel.nib; sourceTree = ""; }; 03CF8819169C8BDB0037A5FD /* arrow_left_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = arrow_left_button.png; path = images/arrow_left_button.png; sourceTree = ""; }; 03CF881A169C8BDB0037A5FD /* arrow_right_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = arrow_right_button.png; path = images/arrow_right_button.png; sourceTree = ""; }; 03CF8885169CB7800037A5FD /* PPSamplerImagePanelType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSamplerImagePanelType.h; sourceTree = ""; }; 03D0B91B16EDA28600B50FE4 /* PPResizableDirectionsMasks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPResizableDirectionsMasks.h; sourceTree = ""; }; 03D280DF15CEF65F002606F6 /* PPBuildEnvironmentMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPBuildEnvironmentMacros.h; sourceTree = ""; }; 03D5469314F8BA120063091B /* PPHotkeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPHotkeys.h; sourceTree = ""; }; 03D5469414F8BA120063091B /* PPHotkeys.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPHotkeys.m; sourceTree = ""; }; 03D7919E16C3451E00BD9820 /* arrow_outline_left_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = arrow_outline_left_button.png; path = images/arrow_outline_left_button.png; sourceTree = ""; }; 03D7919F16C3451E00BD9820 /* arrow_outline_right_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = arrow_outline_right_button.png; path = images/arrow_outline_right_button.png; sourceTree = ""; }; 03DB0BD8132250C600978A94 /* NSBitmapImageRep_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSBitmapImageRep_PPUtilities.h; sourceTree = ""; }; 03DB0C781323604F00978A94 /* PPGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPGeometry.h; sourceTree = ""; }; 03DB0C791323604F00978A94 /* PPGeometry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPGeometry.m; sourceTree = ""; }; 03DECB6B1C5E71D300953470 /* PPCanvasView_MouseCursor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCanvasView_MouseCursor.m; sourceTree = ""; }; 03E13B46166F3221002328B2 /* PPUIColors_Panels.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPUIColors_Panels.h; sourceTree = ""; }; 03E13B49166F3236002328B2 /* PPUserDefaultsInitialValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPUserDefaultsInitialValues.h; sourceTree = ""; }; 03E2E37214D160110040A7A3 /* PPToolUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPToolUtilities.m; sourceTree = ""; }; 03E3974413A1807B00276376 /* PPDocument_NativeFileFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocument_NativeFileFormat.h; sourceTree = ""; }; 03E3974513A1807B00276376 /* PPDocument_NativeFileFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_NativeFileFormat.m; sourceTree = ""; }; 03E3FF9416BCD192007F86E3 /* PPCursorManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPCursorManager.h; sourceTree = ""; }; 03E3FF9516BCD192007F86E3 /* PPCursorManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPCursorManager.m; sourceTree = ""; }; 03E3FFA016BCD8D4007F86E3 /* PPCursorLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPCursorLevel.h; sourceTree = ""; }; 03E41EAE164C8F74009D2495 /* isometric_lines_segment.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = isometric_lines_segment.png; path = images/isometric_lines_segment.png; sourceTree = ""; }; 03E69217130FDB300086A468 /* PPEraserTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPEraserTool.h; sourceTree = ""; }; 03E69218130FDB300086A468 /* PPEraserTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPEraserTool.m; sourceTree = ""; }; 03E69227130FDBD30086A468 /* PPColorSamplerTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPColorSamplerTool.h; sourceTree = ""; }; 03E69228130FDBD30086A468 /* PPColorSamplerTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPColorSamplerTool.m; sourceTree = ""; }; 03E69245130FDCCD0086A468 /* PPMagnifierTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPMagnifierTool.h; sourceTree = ""; }; 03E69246130FDCCD0086A468 /* PPMagnifierTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPMagnifierTool.m; sourceTree = ""; }; 03E69251130FDD230086A468 /* PPRectSelectTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPRectSelectTool.h; sourceTree = ""; }; 03E69252130FDD230086A468 /* PPRectSelectTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPRectSelectTool.m; sourceTree = ""; }; 03E6925B130FDD810086A468 /* PPMagicWandTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPMagicWandTool.h; sourceTree = ""; }; 03E6925C130FDD810086A468 /* PPMagicWandTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPMagicWandTool.m; sourceTree = ""; }; 03E69267130FDDEF0086A468 /* PPFreehandSelectTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPFreehandSelectTool.h; sourceTree = ""; }; 03E69268130FDDEF0086A468 /* PPFreehandSelectTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPFreehandSelectTool.m; sourceTree = ""; }; 03E69271130FDE300086A468 /* PPMoveTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPMoveTool.h; sourceTree = ""; }; 03E69272130FDE300086A468 /* PPMoveTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPMoveTool.m; sourceTree = ""; }; 03E6929E130FE16A0086A468 /* PPDocument_ActiveTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_ActiveTool.m; sourceTree = ""; }; 03E951CD1E2F028B007460DC /* PPColorRampTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPColorRampTool.m; sourceTree = ""; }; 03E951CE1E2F028B007460DC /* PPColorRampTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPColorRampTool.h; sourceTree = ""; }; 03ED60DD1CF611A10061EF22 /* PPPresettablePatternProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPresettablePatternProtocol.h; sourceTree = ""; }; 03ED61051CF61F1F0061EF22 /* PPPatternPresets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPatternPresets.h; sourceTree = ""; }; 03ED61061CF61F1F0061EF22 /* PPPatternPresets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPatternPresets.m; sourceTree = ""; }; 03ED62EA1CFB4EA60061EF22 /* PPPresettablePatternView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPPresettablePatternView.h; sourceTree = ""; }; 03ED62EB1CFB4EA60061EF22 /* PPPresettablePatternView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPPresettablePatternView.m; sourceTree = ""; }; 03F0D594137D9C5800161F87 /* PPBackgroundPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPBackgroundPattern.h; sourceTree = ""; }; 03F0D595137D9C5800161F87 /* PPBackgroundPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPBackgroundPattern.m; sourceTree = ""; }; 03F23725183AAEDF00D37EB5 /* PPDocument_NativeFileIcon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocument_NativeFileIcon.h; sourceTree = ""; }; 03F23726183AAEDF00D37EB5 /* PPDocument_NativeFileIcon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument_NativeFileIcon.m; sourceTree = ""; }; 03F2A544177F718200171715 /* PPSDKNativeTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSDKNativeTypes.h; sourceTree = ""; }; 03F2EF4D174439E800EBFA6B /* PPBackgroundPatternPresets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPBackgroundPatternPresets.h; sourceTree = ""; }; 03F2EF4E174439E800EBFA6B /* PPBackgroundPatternPresets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPBackgroundPatternPresets.m; sourceTree = ""; }; 03F2EF8517444A4600EBFA6B /* PPDocumentEditImageSizePresetsSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentEditImageSizePresetsSheetController.h; sourceTree = ""; }; 03F2EF8617444A9A00EBFA6B /* PPDocumentEditPatternPresetsSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocumentEditPatternPresetsSheetController.h; sourceTree = ""; }; 03F2EF8717444AA500EBFA6B /* PPDocumentEditPatternPresetsSheetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocumentEditPatternPresetsSheetController.m; sourceTree = ""; }; 03F2EF9217444DF200EBFA6B /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/DocumentEditPatternPresetsSheet.nib; sourceTree = ""; }; 03F2F06C1746A95400EBFA6B /* NSFileManager_PPUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSFileManager_PPUtilities.h; sourceTree = ""; }; 03F2F06D1746A95400EBFA6B /* NSFileManager_PPUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSFileManager_PPUtilities.m; sourceTree = ""; }; 03FDC66717E56D7D0086EE53 /* freehand_select_cursor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = freehand_select_cursor.png; path = images/tools/freehand_select_cursor.png; sourceTree = ""; }; 03FDC66917E56D860086EE53 /* freehand_select_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = freehand_select_button.png; path = images/tools/freehand_select_button.png; sourceTree = ""; }; 089C1660FE840EACC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 2A37F4ACFDCFA73011CA2CEA /* PPDocument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPDocument.m; sourceTree = ""; }; 2A37F4AEFDCFA73011CA2CEA /* PPDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPDocument.h; sourceTree = ""; }; 2A37F4B0FDCFA73011CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2A37F4B7FDCFA73011CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = ""; }; 2A37F4BAFDCFA73011CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = ""; }; 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32DBCF750370BD2300C91783 /* PikoPixel_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PikoPixel_Prefix.pch; sourceTree = ""; }; 8D15AC360486D014006FF6A4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8D15AC370486D014006FF6A4 /* PikoPixel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PikoPixel.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 8D15AC330486D014006FF6A4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */, 03C3E5C314FA41EA0050214C /* Carbon.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 030E248F15F32396005B8DDA /* Edit Size Presets Sheet */ = { isa = PBXGroup; children = ( 03F2EF8517444A4600EBFA6B /* PPDocumentEditImageSizePresetsSheetController.h */, 03C5920B1563184C00B8AD34 /* PPDocumentEditImageSizePresetsSheetController.m */, ); name = "Edit Size Presets Sheet"; sourceTree = ""; }; 0332D95719FAF3BB00CB3213 /* NSColor */ = { isa = PBXGroup; children = ( 03BD47F1133F8ACC003B0F56 /* NSColor_PPUtilities.h */, 03BD47F2133F8ACC003B0F56 /* NSColor_PPUtilities.m */, 0332D95B19FAF3E900CB3213 /* NSColor_PPUtilities_PatternColors.m */, ); name = NSColor; sourceTree = ""; }; 033A20E017E2B4F200D06CF9 /* Shared */ = { isa = PBXGroup; children = ( 03432A80130FB03F00F9F676 /* PPTool.h */, 03432A81130FB03F00F9F676 /* PPTool.m */, 033A216717E4BF6A00D06CF9 /* PPToolUtilities.h */, 03E2E37214D160110040A7A3 /* PPToolUtilities.m */, ); name = Shared; sourceTree = ""; }; 033BA9311692B8720044D327 /* Sampler Images Settings Sheet */ = { isa = PBXGroup; children = ( 033BA9361692B8F50044D327 /* PPDocumentSamplerImagesSettingsSheetController.h */, 033BA9371692B8F50044D327 /* PPDocumentSamplerImagesSettingsSheetController.m */, ); name = "Sampler Images Settings Sheet"; sourceTree = ""; }; 0342F82616720BA500823E4E /* Enum Types */ = { isa = PBXGroup; children = ( 039CD49F16688F5700ED977A /* PPBackgroundPatternType.h */, 033BAB031694C6300044D327 /* PPDirectionType.h */, 039CD35616670B8300ED977A /* PPDocumentTypes.h */, 0311371517E22D1100C3D4FB /* PPFramePinningType.h */, 0384F0BA153A85670027C3B0 /* PPGridType.h */, 039CD4B41668972600ED977A /* PPHotkeyType.h */, 039CD3E816674F2600ED977A /* PPLayerDisplayMode.h */, 039CD3C7166747DE00ED977A /* PPPanelType.h */, 039CD3D916674AD000ED977A /* PPPopupPanelType.h */, 03CF8885169CB7800037A5FD /* PPSamplerImagePanelType.h */, 03432AD7130FD8BD00F9F676 /* PPToolType.h */, ); name = "Enum Types"; sourceTree = ""; }; 03432A2C130F623E00F9F676 /* Tools Panel */ = { isa = PBXGroup; children = ( 03432A2F130F627200F9F676 /* PPToolsPanelController.h */, 03432A30130F627200F9F676 /* PPToolsPanelController.m */, ); name = "Tools Panel"; sourceTree = ""; }; 03432A74130FAF1D00F9F676 /* Toolbox */ = { isa = PBXGroup; children = ( 03432A6D130FAEF500F9F676 /* PPToolbox.h */, 03432A6E130FAEF500F9F676 /* PPToolbox.m */, 03432B1A130FDA8700F9F676 /* Tools */, ); name = Toolbox; sourceTree = ""; }; 03432A77130FAF4300F9F676 /* UI */ = { isa = PBXGroup; children = ( 03C405BA13011694006930D2 /* Document Window */, 03432A7C130FAF8500F9F676 /* Panels */, 03CF87A1169C5FDB0037A5FD /* Hotkey Settings Window */, 03E0A2BC1896210500DC315D /* Cursor Manager */, 03E0A2B31896201700DC315D /* Shared */, ); name = UI; sourceTree = ""; }; 03432A7C130FAF8500F9F676 /* Panels */ = { isa = PBXGroup; children = ( 034B5FBF138EDB50003A8E77 /* Standard Panels */, 034B5FC2138EDBAD003A8E77 /* Popup Panels */, 036549BA16D6EC0C00B98B1D /* Shared */, ); name = Panels; sourceTree = ""; }; 03432B1A130FDA8700F9F676 /* Tools */ = { isa = PBXGroup; children = ( 033A20E017E2B4F200D06CF9 /* Shared */, 03432A8A130FB46A00F9F676 /* PPPencilTool.h */, 03432A8B130FB46A00F9F676 /* PPPencilTool.m */, 03E69217130FDB300086A468 /* PPEraserTool.h */, 03E69218130FDB300086A468 /* PPEraserTool.m */, 03432ADF130FD92D00F9F676 /* PPFillTool.h */, 03432AE0130FD92D00F9F676 /* PPFillTool.m */, 03432AEF130FD9AF00F9F676 /* PPLineTool.h */, 03432AF0130FD9AF00F9F676 /* PPLineTool.m */, 03432B0F130FDA1A00F9F676 /* PPRectTool.h */, 03432B10130FDA1A00F9F676 /* PPRectTool.m */, 03432B1D130FDACB00F9F676 /* PPOvalTool.h */, 03432B1E130FDACB00F9F676 /* PPOvalTool.m */, 03E69267130FDDEF0086A468 /* PPFreehandSelectTool.h */, 03E69268130FDDEF0086A468 /* PPFreehandSelectTool.m */, 03E69251130FDD230086A468 /* PPRectSelectTool.h */, 03E69252130FDD230086A468 /* PPRectSelectTool.m */, 03E6925B130FDD810086A468 /* PPMagicWandTool.h */, 03E6925C130FDD810086A468 /* PPMagicWandTool.m */, 03E69227130FDBD30086A468 /* PPColorSamplerTool.h */, 03E69228130FDBD30086A468 /* PPColorSamplerTool.m */, 03E69271130FDE300086A468 /* PPMoveTool.h */, 03E69272130FDE300086A468 /* PPMoveTool.m */, 03E69245130FDCCD0086A468 /* PPMagnifierTool.h */, 03E69246130FDCCD0086A468 /* PPMagnifierTool.m */, 03E951CE1E2F028B007460DC /* PPColorRampTool.h */, 03E951CD1E2F028B007460DC /* PPColorRampTool.m */, ); name = Tools; sourceTree = ""; }; 0346EFB31BFE2B840007A2C2 /* Optional */ = { isa = PBXGroup; children = ( 0346EFB81BFE2E520007A2C2 /* PPOptional.h */, 0346EFC31BFE303D0007A2C2 /* Canvas Speed Check */, 0346EFC01BFE30320007A2C2 /* Screencasting */, ); name = Optional; sourceTree = ""; }; 0346EFC01BFE30320007A2C2 /* Screencasting */ = { isa = PBXGroup; children = ( 03AC18BB1890A5150059488A /* PPOptional_Screencasting.m */, 031453591866A6FA00DE2EC4 /* PPScreencastController.h */, 0314535A1866A6FA00DE2EC4 /* PPScreencastController.m */, ); name = Screencasting; sourceTree = ""; }; 0346EFC31BFE303D0007A2C2 /* Canvas Speed Check */ = { isa = PBXGroup; children = ( 0346EFD51BFE30640007A2C2 /* PPOptional_CanvasSpeedCheck.m */, ); name = "Canvas Speed Check"; sourceTree = ""; }; 034B5FBF138EDB50003A8E77 /* Standard Panels */ = { isa = PBXGroup; children = ( 0373531013B7191000F4FDC8 /* PPPanelsController.h */, 0373531113B7191000F4FDC8 /* PPPanelsController.m */, 036549EA16D7075800B98B1D /* Shared */, 03432A2C130F623E00F9F676 /* Tools Panel */, 03C405C11301170C006930D2 /* Layers Panel */, 03BF0A08135AA6A1000F2C14 /* Preview Panel */, 03976A6E16962966002855D4 /* Sampler Image Panel */, 03A5BF0115279E62003EC48D /* Tool Modifier Tips Panel */, ); name = "Standard Panels"; sourceTree = ""; }; 034B5FC2138EDBAD003A8E77 /* Popup Panels */ = { isa = PBXGroup; children = ( 034B628F13989470003A8E77 /* PPPopupPanelsController.h */, 034B629013989470003A8E77 /* PPPopupPanelsController.m */, 036549BD16D6EC7D00B98B1D /* Shared */, 03C405C0130116F5006930D2 /* Navigator Popup */, 034B635913997967003A8E77 /* Tools Popup */, 038D482914427A73004BAE97 /* Color Picker Popup */, 03CAE6211681A05F005BC961 /* Sampler Image Popup */, 03B27A341479CAFB00520BE4 /* Layer Controls Popup */, 03BFCAEA18836FD5001844A6 /* Screencast Popup */, ); name = "Popup Panels"; sourceTree = ""; }; 034B635913997967003A8E77 /* Tools Popup */ = { isa = PBXGroup; children = ( 034B635A139979B1003A8E77 /* PPToolsPopupPanelController.h */, 034B635B139979B1003A8E77 /* PPToolsPopupPanelController.m */, ); name = "Tools Popup"; sourceTree = ""; }; 034B6477139AE1F6003A8E77 /* Document Window */ = { isa = PBXGroup; children = ( 0349A77D1304BACD007DCD51 /* DocumentWindow.nib */, 03C617F91313245300EE17F1 /* DocumentSizeSheet.nib */, 03C591F8156314C600B8AD34 /* DocumentEditSizePresetsSheet.nib */, 03BF404015E4122700371534 /* DocumentScaleSheet.nib */, 03CAB20A142BB9ED009EBA86 /* DocumentResizeSheet.nib */, 039FB7EE137A884900D9E286 /* DocumentBackgroundSettingsSheet.nib */, 03BD487F1340EC0E003B0F56 /* DocumentGridSettingsSheet.nib */, 03F2EF9117444DF200EBFA6B /* DocumentEditPatternPresetsSheet.nib */, 033BA9511692D6650044D327 /* DocumentSamplerImagesSettingsSheet.nib */, 0374731B143E595300BBA96F /* DocumentFlattenedSaveNoticeSheet.nib */, 039FB7B6137A74BB00D9E286 /* ExportPanelAccessoryView.nib */, ); name = "Document Window"; sourceTree = ""; }; 034B647E139AE246003A8E77 /* Panels */ = { isa = PBXGroup; children = ( 03CF87AC169C63150037A5FD /* Standard Panels */, 034B6485139AE2A0003A8E77 /* Popup Panels */, 035B01141791BDDB00AA1DB7 /* LayerControlButtonImageViews.nib */, ); name = Panels; sourceTree = ""; }; 034B6485139AE2A0003A8E77 /* Popup Panels */ = { isa = PBXGroup; children = ( 034B648A139AE38A003A8E77 /* NavigatorPopupPanel.nib */, 034B6352139978A4003A8E77 /* ToolsPopupPanel.nib */, 0344AC1414459B370073A6AF /* ColorPickerPopupPanel.nib */, 03C811CC16A32352008BBA3D /* SamplerImagePopupPanel.nib */, 03B27A3E1479CC5B00520BE4 /* LayerControlsPopupPanel.nib */, 03BFCB2D18839658001844A6 /* ScreencastPopupPanel.nib */, ); name = "Popup Panels"; sourceTree = ""; }; 034C69C51B025EDA001CC371 /* NSBezierPath */ = { isa = PBXGroup; children = ( 03C7325314E6E3D00017C73C /* NSBezierPath_PPUtilities.h */, 03C7325414E6E3D00017C73C /* NSBezierPath_PPUtilities.m */, 034C69C71B025EEF001CC371 /* NSBezierPath_PPUtilities_MaskBitmapPaths.m */, ); name = NSBezierPath; sourceTree = ""; }; 034C69CB1B025EFD001CC371 /* NSObject */ = { isa = PBXGroup; children = ( 034AEA2C1660AF19006C5617 /* NSObject_PPUtilities.h */, 034AEA2D1660AF19006C5617 /* NSObject_PPUtilities.m */, 032E7DC31AF0867D0097C0D7 /* NSObject_PPUtilities_MethodSwizzling.m */, ); name = NSObject; sourceTree = ""; }; 035B01881792359900AA1DB7 /* Layer Control Button Images Manager */ = { isa = PBXGroup; children = ( 035B00E21790997300AA1DB7 /* PPLayerControlButtonImagesManager.h */, 035B00E31790997300AA1DB7 /* PPLayerControlButtonImagesManager.m */, 035B018B179235CC00AA1DB7 /* PPLayerControlButtonImagesManager_Notifications.h */, 035B018C179235CC00AA1DB7 /* PPLayerControlButtonImagesManager_Notifications.m */, 035B00C1179078D000AA1DB7 /* PPCompositeThumbnail.h */, 035B00C2179078D000AA1DB7 /* PPCompositeThumbnail.m */, ); name = "Layer Control Button Images Manager"; sourceTree = ""; }; 036549BA16D6EC0C00B98B1D /* Shared */ = { isa = PBXGroup; children = ( 035B01881792359900AA1DB7 /* Layer Control Button Images Manager */, 033BA16E168498AC0044D327 /* PPMiniColorWell.h */, 033BA16F168498AC0044D327 /* PPMiniColorWell.m */, 033BA015168422B50044D327 /* PPSamplerImageView.h */, 033BA016168422B50044D327 /* PPSamplerImageView.m */, 031DAFB01E772A25006D2758 /* PPToolButtonMatrix.h */, 031DAFB11E772A25006D2758 /* PPToolButtonMatrix.m */, ); name = Shared; sourceTree = ""; }; 036549BD16D6EC7D00B98B1D /* Shared */ = { isa = PBXGroup; children = ( 034B5FB5138ED8FB003A8E77 /* PPPopupPanelController.h */, 034B5FB6138ED8FB003A8E77 /* PPPopupPanelController.m */, 034B5FCF138EDBE8003A8E77 /* PPPopupPanel.h */, 034B5FD0138EDBE8003A8E77 /* PPPopupPanel.m */, 0379BEE414440BCD006BD02A /* PPFilledRoundedRectView.h */, 0379BEE514440BCD006BD02A /* PPFilledRoundedRectView.m */, ); name = Shared; sourceTree = ""; }; 036549EA16D7075800B98B1D /* Shared */ = { isa = PBXGroup; children = ( 03158D74130BEDCF00E08C31 /* PPPanelController.h */, 03158D75130BEDCF00E08C31 /* PPPanelController.m */, ); name = Shared; sourceTree = ""; }; 0379615817C3EF1F00C1DE16 /* NSBitmapImageRep */ = { isa = PBXGroup; children = ( 03DB0BD8132250C600978A94 /* NSBitmapImageRep_PPUtilities.h */, 03635FC317BD56C0008DA58C /* NSBitmapImageRep_PPUtilities.m */, 03635E8117BAF4BB008DA58C /* NSBitmapImageRep_PPUtilities_ImageBitmaps.m */, 03B5E43B1DF681FF00D99F97 /* NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m */, 03635E8617BAF4C7008DA58C /* NSBitmapImageRep_PPUtilities_MaskBitmaps.m */, 0332D8AA19F6070100CB3213 /* NSBitmapImageRep_PPUtilities_PatternBitmaps.m */, 0363606917BD6871008DA58C /* NSBitmapImageRep_PPUtilities_ColorMasking.m */, ); name = NSBitmapImageRep; sourceTree = ""; }; 037CB6AD1D69100400B51DA0 /* OS X Glue */ = { isa = PBXGroup; children = ( 0346D35F1A114A4500C17251 /* PPOSXGlue_KeyUpDuringControlTracking.m */, 031FCB73251AF171006EF3B3 /* PPOSXGlue_NavigatorSliderVisibility.m */, 037CB6A91D690F8300B51DA0 /* PPOSXGlue_PatternPhaseGlitches.m */, 0377183D1EB31E8400556F9A /* PPOSXGlue_PreserveDrawColorDuringAboutPanel.m */, 033DBDED1D76976F0087D27C /* PPOSXGlue_RetinaDrawingArtifacts.m */, 033DBDEE1D76976F0087D27C /* PPOSXGlueUtilities.h */, 033DBDEF1D76976F0087D27C /* PPOSXGlueUtilities.m */, ); name = "OS X Glue"; sourceTree = ""; }; 038D482914427A73004BAE97 /* Color Picker Popup */ = { isa = PBXGroup; children = ( 03020DB41441786500A988DB /* PPColorPickerPopupPanelController.h */, 03020DB51441786500A988DB /* PPColorPickerPopupPanelController.m */, 03C8114A16A0EEBB008BBA3D /* PPColorPickerPopupPanel.h */, 03C8114B16A0EEBB008BBA3D /* PPColorPickerPopupPanel.m */, ); name = "Color Picker Popup"; sourceTree = ""; }; 03976A6E16962966002855D4 /* Sampler Image Panel */ = { isa = PBXGroup; children = ( 03CF86B3169B13720037A5FD /* PPSamplerImagePanelController.h */, 03CF86B4169B13720037A5FD /* PPSamplerImagePanelController.m */, ); name = "Sampler Image Panel"; sourceTree = ""; }; 039FB7F7137A928700D9E286 /* Sheets */ = { isa = PBXGroup; children = ( 03721FDC15F29E1B0000E65A /* PPDocumentSheetController.h */, 03721FDD15F29E1B0000E65A /* PPDocumentSheetController.m */, 03A90B86156AE03A008C5B1E /* Size Sheet (New Document) */, 030E248F15F32396005B8DDA /* Edit Size Presets Sheet */, 03BF3DD815D84F0F00371534 /* Scale Sheet */, 03A90B8A156AE0DC008C5B1E /* Resize Sheet */, 03A90B8D156AE113008C5B1E /* Background Settings Sheet */, 03A90B96156AE16C008C5B1E /* Grid Settings Sheet */, 03F2EF7B1744499B00EBFA6B /* Edit Pattern Presets Sheet */, 033BA9311692B8720044D327 /* Sampler Images Settings Sheet */, 03BF415215E8252700371534 /* Animation File Notice Sheet */, 03A90B97156AE18E008C5B1E /* Flattened Save Notice Sheet */, 03CF87A7169C616F0037A5FD /* Export Panel */, ); name = Sheets; sourceTree = ""; }; 03A5BF0115279E62003EC48D /* Tool Modifier Tips Panel */ = { isa = PBXGroup; children = ( 03A5BF0515279EB6003EC48D /* PPToolModifierTipsPanelController.h */, 03A5BF0615279EB6003EC48D /* PPToolModifierTipsPanelController.m */, 0362BA62172873D300850475 /* PPToolModifierTipsText.h */, 0362BA63172873D300850475 /* PPToolModifierTipsText.m */, ); name = "Tool Modifier Tips Panel"; sourceTree = ""; }; 03A8E98F134E675E00A94ECB /* Images */ = { isa = PBXGroup; children = ( 03D5F4C61346B40A006C6919 /* Tools */, 0325B9E41596B4BE006472D9 /* pencil_segment.png */, 03E41EAE164C8F74009D2495 /* isometric_lines_segment.png */, 0325B9F71596B5A6006472D9 /* diagonal_lines_segment.png */, 0325B9F81596B5A6006472D9 /* checkerboard_segment.png */, 036548E716D4AA9900B98B1D /* diagonal_checkerboard_segment.png */, 036548E916D4AAA600B98B1D /* isometric_checkerboard_segment.png */, 0325B9E91596B5A6006472D9 /* solid_segment.png */, 0325B9ED1596B5A6006472D9 /* plus_button_overlay.png */, 0325B9EC1596B5A6006472D9 /* plus_button_overlay_small.png */, 0325B9F01596B5A6006472D9 /* minus_button_overlay.png */, 0325B9EF1596B5A6006472D9 /* minus_button_overlay_small.png */, 0325B9F11596B5A6006472D9 /* marching_ants_pattern.png */, 0325B9EA1596B5A6006472D9 /* selection_tool_overlay_subtract_pattern.png */, 0325B9EB1596B5A6006472D9 /* selection_tool_overlay_add_pattern.png */, 0384F8BA17C71F7500F766BC /* eraser_tool_overlay_outline_pattern.png */, 0325B9F51596B5A6006472D9 /* gridtype_crosshairs_segment.png */, 0325B9F41596B5A6006472D9 /* gridtype_dots_segment.png */, 0325B9F31596B5A6006472D9 /* gridtype_largedots_segment.png */, 0325B9F21596B5A6006472D9 /* gridtype_lines_segment.png */, 0393BB141D18692E00449C89 /* gridpatternpreview_foreground.png */, 033BA06916844DD70044D327 /* resize_control.png */, 03CB7649179721B3006CFD58 /* view_draw_layer_icon.png */, 03CB7647179721B3006CFD58 /* view_enabled_layers_icon.png */, 03CB7648179721B3006CFD58 /* target_draw_layer_icon.png */, 03CB764A179721B3006CFD58 /* target_enabled_layers_icon.png */, 039772621E1C3FCC0061D6EC /* blend_mode_icon_standard.png */, 039772631E1C3FCC0061D6EC /* blend_mode_icon_linear.png */, 03CF8819169C8BDB0037A5FD /* arrow_left_button.png */, 03CF881A169C8BDB0037A5FD /* arrow_right_button.png */, 03D7919E16C3451E00BD9820 /* arrow_outline_left_button.png */, 03D7919F16C3451E00BD9820 /* arrow_outline_right_button.png */, 0325B9EE1596B5A6006472D9 /* neko.png */, ); name = Images; sourceTree = ""; }; 03A90B86156AE03A008C5B1E /* Size Sheet (New Document) */ = { isa = PBXGroup; children = ( 03C617F013126A1F00EE17F1 /* PPDocumentSizeSheetController.h */, 03C617F113126A1F00EE17F1 /* PPDocumentSizeSheetController.m */, ); name = "Size Sheet (New Document)"; sourceTree = ""; }; 03A90B8A156AE0DC008C5B1E /* Resize Sheet */ = { isa = PBXGroup; children = ( 03CAB202142BB663009EBA86 /* PPDocumentResizeSheetController.h */, 03CAB203142BB663009EBA86 /* PPDocumentResizeSheetController.m */, ); name = "Resize Sheet"; sourceTree = ""; }; 03A90B8D156AE113008C5B1E /* Background Settings Sheet */ = { isa = PBXGroup; children = ( 03CEF1D1137A944C005B32E7 /* PPDocumentBackgroundSettingsSheetController.h */, 03CEF1D2137A944C005B32E7 /* PPDocumentBackgroundSettingsSheetController.m */, ); name = "Background Settings Sheet"; sourceTree = ""; }; 03A90B96156AE16C008C5B1E /* Grid Settings Sheet */ = { isa = PBXGroup; children = ( 03BD4807133F9305003B0F56 /* PPDocumentGridSettingsSheetController.h */, 03BD4808133F9305003B0F56 /* PPDocumentGridSettingsSheetController.m */, ); name = "Grid Settings Sheet"; sourceTree = ""; }; 03A90B97156AE18E008C5B1E /* Flattened Save Notice Sheet */ = { isa = PBXGroup; children = ( 037472C5143E208B00BBA96F /* PPDocumentFlattenedSaveNoticeSheetController.h */, 037472C6143E208B00BBA96F /* PPDocumentFlattenedSaveNoticeSheetController.m */, ); name = "Flattened Save Notice Sheet"; sourceTree = ""; }; 03AC18B71890A4BC0059488A /* Application */ = { isa = PBXGroup; children = ( 03365C0515035AA800F7DFFF /* PPApplication.h */, 03365C0615035AA800F7DFFF /* PPApplication.m */, ); name = Application; sourceTree = ""; }; 03B27A341479CAFB00520BE4 /* Layer Controls Popup */ = { isa = PBXGroup; children = ( 03B27A371479CB1C00520BE4 /* PPLayerControlsPopupPanelController.h */, 03B27A381479CB1C00520BE4 /* PPLayerControlsPopupPanelController.m */, ); name = "Layer Controls Popup"; sourceTree = ""; }; 03BF0A08135AA6A1000F2C14 /* Preview Panel */ = { isa = PBXGroup; children = ( 03BF0A0A135AA6D3000F2C14 /* PPPreviewPanelController.h */, 03BF0A09135AA6D3000F2C14 /* PPPreviewPanelController.m */, 039CD4001667524500ED977A /* PPPreviewBackgroundType.h */, 03BF0A0D135AA6E4000F2C14 /* PPPreviewView.h */, 03BF0A0C135AA6E4000F2C14 /* PPPreviewView.m */, ); name = "Preview Panel"; sourceTree = ""; }; 03BF3DD815D84F0F00371534 /* Scale Sheet */ = { isa = PBXGroup; children = ( 03BF3DD915D84F2D00371534 /* PPDocumentScaleSheetController.h */, 03BF3DDA15D84F2D00371534 /* PPDocumentScaleSheetController.m */, 03BF406F15E4263C00371534 /* PPScaledImageView.h */, 03BF407015E4263C00371534 /* PPScaledImageView.m */, ); name = "Scale Sheet"; sourceTree = ""; }; 03BF415215E8252700371534 /* Animation File Notice Sheet */ = { isa = PBXGroup; children = ( 03BF414B15E8251600371534 /* PPDocumentAnimationFileNoticeSheetController.h */, 03BF414C15E8251600371534 /* PPDocumentAnimationFileNoticeSheetController.m */, ); name = "Animation File Notice Sheet"; sourceTree = ""; }; 03BFCAEA18836FD5001844A6 /* Screencast Popup */ = { isa = PBXGroup; children = ( 03BFCAF018837020001844A6 /* PPScreencastPopupPanelController.h */, 03BFCAF118837020001844A6 /* PPScreencastPopupPanelController.m */, ); name = "Screencast Popup"; sourceTree = ""; }; 03C3E6A914FA44290050214C /* Hotkey Defaults */ = { isa = PBXGroup; children = ( 034B934C150C96DD00599E0C /* Hotkeys_ar.plist */, 034B9350150C98A600599E0C /* Hotkeys_be.plist */, 034B9354150C99D800599E0C /* Hotkeys_bg.plist */, 034B9362150C9C5E00599E0C /* Hotkeys_cs.plist */, 03365E0A15089B7B00F7DFFF /* Hotkeys_da.plist */, 03365DFE15089B7B00F7DFFF /* Hotkeys_de.plist */, 034B92E3150C7F2600599E0C /* Hotkeys_de_AT.plist */, 03365DFF15089B7B00F7DFFF /* Hotkeys_de_CH.plist */, 03365DF815089B7B00F7DFFF /* Hotkeys_el.plist */, 03365DFC15089B7B00F7DFFF /* Hotkeys_en.plist */, 03365E0215089B7B00F7DFFF /* Hotkeys_en_AU.plist */, 03365E0315089B7B00F7DFFF /* Hotkeys_en_CA.plist */, 03365E0915089B7B00F7DFFF /* Hotkeys_en_GB.plist */, 03365DF915089B7B00F7DFFF /* Hotkeys_en_US.plist */, 03365E0115089B7B00F7DFFF /* Hotkeys_es.plist */, 034B939E150CA97200599E0C /* Hotkeys_et.plist */, 034B937B150CA09F00599E0C /* Hotkeys_fa.plist */, 03365E0615089B7B00F7DFFF /* Hotkeys_fi.plist */, 03365DF615089B7B00F7DFFF /* Hotkeys_fr.plist */, 03365DF515089B7B00F7DFFF /* Hotkeys_fr_CA.plist */, 03365DFB15089B7B00F7DFFF /* Hotkeys_fr_CH.plist */, 03365E0415089B7B00F7DFFF /* Hotkeys_he.plist */, 034B9359150C9ABF00599E0C /* Hotkeys_hr.plist */, 034B9366150C9D6600599E0C /* Hotkeys_hu.plist */, 034B939B150CA89900599E0C /* Hotkeys_hy.plist */, 03365DFA15089B7B00F7DFFF /* Hotkeys_is.plist */, 03365DF715089B7B00F7DFFF /* Hotkeys_it.plist */, 034B936D150C9E7800599E0C /* Hotkeys_lt.plist */, 034B9369150C9DFB00599E0C /* Hotkeys_lv.plist */, 034B93A1150CA9DE00599E0C /* Hotkeys_mi.plist */, 034B9373150C9F8D00599E0C /* Hotkeys_mk.plist */, 034B9377150CA00100599E0C /* Hotkeys_mt.plist */, 03365E0715089B7B00F7DFFF /* Hotkeys_nb.plist */, 034B93A5150CAA7500599E0C /* Hotkeys_ne.plist */, 03365E0015089B7B00F7DFFF /* Hotkeys_nl.plist */, 034B92F2150C84A500599E0C /* Hotkeys_nl_BE.plist */, 034B9339150C94C500599E0C /* Hotkeys_pl.plist */, 034B93A9150CAB1B00599E0C /* Hotkeys_ps.plist */, 03365DF415089B7B00F7DFFF /* Hotkeys_pt_BR.plist */, 03365E0515089B7B00F7DFFF /* Hotkeys_pt_PT.plist */, 034B937E150CA13100599E0C /* Hotkeys_ro.plist */, 03365DFD15089B7B00F7DFFF /* Hotkeys_ru.plist */, 034B9384150CA2AA00599E0C /* Hotkeys_sk.plist */, 034B9387150CA34B00599E0C /* Hotkeys_sl.plist */, 034B9381150CA1C900599E0C /* Hotkeys_sr-Cyrl.plist */, 03365E0815089B7B00F7DFFF /* Hotkeys_sv.plist */, 034B938B150CA3FD00599E0C /* Hotkeys_th.plist */, 034B938E150CA4A000599E0C /* Hotkeys_tr.plist */, 034B9391150CA50E00599E0C /* Hotkeys_uk.plist */, 034B93AE150CAC2100599E0C /* Hotkeys_uz.plist */, 034B9395150CA62500599E0C /* Hotkeys_vi.plist */, ); name = "Hotkey Defaults"; sourceTree = ""; }; 03C405BA13011694006930D2 /* Document Window */ = { isa = PBXGroup; children = ( 0329D55C12DBA08D0073FF2E /* PPDocumentWindowController.h */, 0329D55D12DBA08D0073FF2E /* PPDocumentWindowController.m */, 03C7E0401320E7CC00236E79 /* PPDocumentWindowController_Actions.m */, 03C7E07F1321042300236E79 /* PPDocumentWindowController_MenuValidation.m */, 03B3814E15EF1B6E001FC276 /* PPDocumentWindowController_Sheets.h */, 0385B303138011A500BE900B /* PPDocumentWindowController_Sheets.m */, 031EC2C113CFFF5500582645 /* PPDocumentWindowController_Notifications.h */, 031EC2C213CFFF5500582645 /* PPDocumentWindowController_Notifications.m */, 038A4715141F508500CFC168 /* PPDocumentWindow.h */, 038A4716141F508500CFC168 /* PPDocumentWindow.m */, 03CAD73314D85E6500C37C2E /* Canvas View */, 039FB7F7137A928700D9E286 /* Sheets */, ); name = "Document Window"; sourceTree = ""; }; 03C405BD130116AF006930D2 /* Document */ = { isa = PBXGroup; children = ( 2A37F4AEFDCFA73011CA2CEA /* PPDocument.h */, 2A37F4ACFDCFA73011CA2CEA /* PPDocument.m */, 0349A7581304B6D4007DCD51 /* PPDocument_FileFormats.m */, 0378357413768B450046E201 /* PPDocument_Saving.m */, 037A7C7817B8CC37002D56F6 /* PPDocument_LayerOperationTarget.m */, 037472EA12FBD9480026A596 /* PPDocument_Layers.m */, 03E6929E130FE16A0086A468 /* PPDocument_ActiveTool.m */, 0349A7601304B76E007DCD51 /* PPDocument_Drawing.m */, 03A7C17D131884CE00DF3B23 /* PPDocument_Selection.m */, 035E8A4314D0980B008A66D3 /* PPDocument_PixelMatching.m */, 03C7764F132A34410056BEC3 /* PPDocument_Moving.m */, 03CE51F9135234E2009E57B9 /* PPDocument_MirroringRotating.m */, 03700CC813261F6000FDE20E /* PPDocument_Pasteboard.m */, 030F1A9713800DAC00C79F03 /* PPDocument_CanvasSettings.m */, 03CE54BA135798B6009E57B9 /* PPDocument_Resizing.m */, 033661811763B7C30075C305 /* PPDocument_Tiling.m */, 037A461D1681B7B500F0C363 /* PPDocument_SamplerImages.m */, 0324E1C1157336C5006D12BC /* PPDocument_NotificationOverrides.m */, 03158CB0130B705900E08C31 /* PPDocument_Notifications.h */, 03158CB1130B705900E08C31 /* PPDocument_Notifications.m */, 03E3974413A1807B00276376 /* PPDocument_NativeFileFormat.h */, 03E3974513A1807B00276376 /* PPDocument_NativeFileFormat.m */, 03F23725183AAEDF00D37EB5 /* PPDocument_NativeFileIcon.h */, 03F23726183AAEDF00D37EB5 /* PPDocument_NativeFileIcon.m */, 033346C21574E2AE008EE9D1 /* PPDocumentLayer.h */, 033346C31574E2AE008EE9D1 /* PPDocumentLayer.m */, 033BA83B168EE8800044D327 /* PPDocumentSamplerImage.h */, 033BA83C168EE8800044D327 /* PPDocumentSamplerImage.m */, ); name = Document; sourceTree = ""; }; 03C405C0130116F5006930D2 /* Navigator Popup */ = { isa = PBXGroup; children = ( 03CB29F012E4B87600A51C92 /* PPNavigatorPopupPanelController.h */, 03CB29F112E4B87600A51C92 /* PPNavigatorPopupPanelController.m */, 03CB29F812E4B95B00A51C92 /* PPNavigatorPopupView.h */, 03CB29F912E4B95B00A51C92 /* PPNavigatorPopupView.m */, ); name = "Navigator Popup"; sourceTree = ""; }; 03C405C11301170C006930D2 /* Layers Panel */ = { isa = PBXGroup; children = ( 0374721712F3A6340026A596 /* PPLayersPanelController.h */, 0374721812F3A6340026A596 /* PPLayersPanelController.m */, 03C4051312FFFCC4006930D2 /* PPLayersTableView.h */, 03C4051412FFFCC4006930D2 /* PPLayersTableView.m */, 03C405661300BF13006930D2 /* PPLayerOpacitySliderCell.h */, 03C405671300BF13006930D2 /* PPLayerOpacitySliderCell.m */, 03C406E81303DFEC006930D2 /* PPLayerEnabledButtonCell.h */, 03C406E91303DFEC006930D2 /* PPLayerEnabledButtonCell.m */, 03C56B091E491AB20096E7C9 /* PPLayerBlendingModeButton.h */, 03C56B0A1E491AB20096E7C9 /* PPLayerBlendingModeButton.m */, ); name = "Layers Panel"; sourceTree = ""; }; 03C51EBF218A07E100F2B145 /* Config */ = { isa = PBXGroup; children = ( 03C51ECB218A086D00F2B145 /* PPXCConfig_10.5sdk.xcconfig */, 03C51ECC218A086D00F2B145 /* PPXCConfig_10.14sdk.xcconfig */, 03C52017218E12BD00F2B145 /* PPXCConfigCheck.h */, ); name = Config; sourceTree = ""; }; 03CAD73314D85E6500C37C2E /* Canvas View */ = { isa = PBXGroup; children = ( 0329D51212DB71D10073FF2E /* PPCanvasView.h */, 0329D51312DB71D10073FF2E /* PPCanvasView.m */, 03C72F3314E072E90017C73C /* PPCanvasView_SelectionOutline.m */, 0341042314DF228900E75BA2 /* PPCanvasView_SelectionToolOverlay.m */, 0384F84F17C6F44400F766BC /* PPCanvasView_EraserToolOverlay.m */, 033B6DF5176D169A005DD093 /* PPCanvasView_FillToolOverlay.m */, 03744DC616098832000DB41D /* PPCanvasView_MagnifierToolOverlay.m */, 033626B71E5BEA5600BA5807 /* PPCanvasView_ColorRampToolOverlay.m */, 03CAD73714D85EA400C37C2E /* PPCanvasView_MatchToolToleranceIndicator.m */, 03DECB6B1C5E71D300953470 /* PPCanvasView_MouseCursor.m */, 03B446ED16058E78009CD1D0 /* PPCanvasView_Autoscrolling.m */, 0335B0701AFADF6D00726F22 /* PPCanvasView_RetinaDrawing.m */, 0341059E14E03D8200E75BA2 /* PPCanvasView_Notifications.h */, 0341059F14E03D8200E75BA2 /* PPCanvasView_Notifications.m */, ); name = "Canvas View"; sourceTree = ""; }; 03CAE6211681A05F005BC961 /* Sampler Image Popup */ = { isa = PBXGroup; children = ( 03CAE6251681A13A005BC961 /* PPSamplerImagePopupPanelController.h */, 03CAE6261681A13A005BC961 /* PPSamplerImagePopupPanelController.m */, 033BA05A168446DB0044D327 /* PPResizeControl.h */, 033BA05B168446DB0044D327 /* PPResizeControl.m */, ); name = "Sampler Image Popup"; sourceTree = ""; }; 03CF87A1169C5FDB0037A5FD /* Hotkey Settings Window */ = { isa = PBXGroup; children = ( 03BB8E2414FF69BF00B47930 /* PPHotkeySettingsWindowController.h */, 03BB8E2514FF69BF00B47930 /* PPHotkeySettingsWindowController.m */, ); name = "Hotkey Settings Window"; sourceTree = ""; }; 03CF87A7169C616F0037A5FD /* Export Panel */ = { isa = PBXGroup; children = ( 037836ED137694700046E201 /* PPExportPanelAccessoryViewController.h */, 037836EE137694700046E201 /* PPExportPanelAccessoryViewController.m */, ); name = "Export Panel"; sourceTree = ""; }; 03CF87AC169C63150037A5FD /* Standard Panels */ = { isa = PBXGroup; children = ( 03432A38130F635F00F9F676 /* ToolsPanel.nib */, 037CFC6813041CCB00ED3E48 /* LayersPanel.nib */, 037CFC4813041BE700ED3E48 /* PreviewPanel.nib */, 03CF87AF169C6E3B0037A5FD /* SamplerImagePanel.nib */, 03A5BEFA1523AD1E003EC48D /* ToolModifierTipsPanel.nib */, ); name = "Standard Panels"; sourceTree = ""; }; 03D5F4C61346B40A006C6919 /* Tools */ = { isa = PBXGroup; children = ( 0325B99D1595D1D7006472D9 /* pencil_cursor.png */, 0325B9951595D1D7006472D9 /* pencil_button.png */, 0325B9A31595D1D7006472D9 /* eraser_cursor.png */, 0325B99C1595D1D7006472D9 /* eraser_button.png */, 0325B99B1595D1D7006472D9 /* paintcan_cursor.png */, 0325B9981595D1D7006472D9 /* paintcan_button.png */, 0325B9911595D1D7006472D9 /* line_cursor.png */, 0325B9931595D1D7006472D9 /* line_button.png */, 0325B9A11595D1D7006472D9 /* rect_cursor.png */, 0325B9971595D1D7006472D9 /* rect_button.png */, 0325B9901595D1D7006472D9 /* oval_cursor.png */, 0325B99A1595D1D7006472D9 /* oval_button.png */, 03FDC66717E56D7D0086EE53 /* freehand_select_cursor.png */, 03FDC66917E56D860086EE53 /* freehand_select_button.png */, 0325B9A01595D1D7006472D9 /* selection_rect_cursor.png */, 0325B99E1595D1D7006472D9 /* selection_rect_button.png */, 0325B9961595D1D7006472D9 /* wand_cursor.png */, 0325B98C1595D1D7006472D9 /* wand_button.png */, 0325B98F1595D1D7006472D9 /* eyedropper_cursor.png */, 0325B98E1595D1D7006472D9 /* eyedropper_button.png */, 0325B99F1595D1D7006472D9 /* move_cursor.png */, 0362BA0717271C8100850475 /* move_selection_outline_cursor.png */, 0325B9A21595D1D7006472D9 /* move_button.png */, 0325B9941595D1D7006472D9 /* magnifier_cursor.png */, 0325B9921595D1D7006472D9 /* magnifier_button.png */, 03CE4BE81E5E286600FD6B5C /* color_ramp_cursor.png */, ); name = Tools; sourceTree = ""; }; 03E0A2B31896201700DC315D /* Shared */ = { isa = PBXGroup; children = ( 031EC10313CE551800582645 /* PPThumbnailImageView.h */, 031EC10413CE551800582645 /* PPThumbnailImageView.m */, 0334540413DB905B00DD0435 /* PPColorWell.h */, 0334540513DB905B00DD0435 /* PPColorWell.m */, 03CAB0A6142A79A8009EBA86 /* PPKeyCancellableWindow.h */, 03CAB0A7142A79A8009EBA86 /* PPKeyCancellableWindow.m */, 03C8F374179F02EA0025C1C4 /* PPTitleablePopUpButton.h */, 03C8F375179F02EA0025C1C4 /* PPTitleablePopUpButton.m */, 03A0DDE616719BC0000BC982 /* PPParabolicSlider.h */, 03A0DDE716719BC0000BC982 /* PPParabolicSlider.m */, ); name = Shared; sourceTree = ""; }; 03E0A2BC1896210500DC315D /* Cursor Manager */ = { isa = PBXGroup; children = ( 03E3FFA016BCD8D4007F86E3 /* PPCursorLevel.h */, 03E3FF9416BCD192007F86E3 /* PPCursorManager.h */, 03E3FF9516BCD192007F86E3 /* PPCursorManager.m */, ); name = "Cursor Manager"; sourceTree = ""; }; 03E2E39C14D168380040A7A3 /* Cocoa Categories */ = { isa = PBXGroup; children = ( 034C69C51B025EDA001CC371 /* NSBezierPath */, 0379615817C3EF1F00C1DE16 /* NSBitmapImageRep */, 0332D95719FAF3BB00CB3213 /* NSColor */, 03B971C71498C07C00175B89 /* NSColorPanel_PPUtilities.h */, 03B971C81498C07C00175B89 /* NSColorPanel_PPUtilities.m */, 033BA626168D69620044D327 /* NSCursor_PPUtilities.h */, 033BA627168D69620044D327 /* NSCursor_PPUtilities.m */, 032FC8FC17D181E1004EC4E3 /* NSDocument_PPUtilities.h */, 032FC8FD17D181E1004EC4E3 /* NSDocument_PPUtilities.m */, 03C26EA9144FEA74003D5B4E /* NSDocumentController_PPUtilities.h */, 03C26EAA144FEA74003D5B4E /* NSDocumentController_PPUtilities.m */, 030FD3ED1511F629005E6E54 /* NSError_PPUtilities.h */, 030FD3EE1511F629005E6E54 /* NSError_PPUtilities.m */, 0358FADD1ABB0E360075A25A /* NSEvent_PPUtilities.h */, 0358FADE1ABB0E360075A25A /* NSEvent_PPUtilities.m */, 03F2F06C1746A95400EBFA6B /* NSFileManager_PPUtilities.h */, 03F2F06D1746A95400EBFA6B /* NSFileManager_PPUtilities.m */, 036C750C1328B56E006AF469 /* NSImage_PPUtilities.h */, 036C750D1328B56E006AF469 /* NSImage_PPUtilities.m */, 039769E71696113C002855D4 /* NSImageRep_PPUtilities.h */, 039769E81696113C002855D4 /* NSImageRep_PPUtilities.m */, 0393BA851D0C9CF200449C89 /* NSMutableArray_PPUtilities.h */, 0393BA861D0C9CF200449C89 /* NSMutableArray_PPUtilities.m */, 034C69CB1B025EFD001CC371 /* NSObject */, 03C26EF414506E09003D5B4E /* NSPasteboard_PPUtilities.h */, 03C26EF514506E09003D5B4E /* NSPasteboard_PPUtilities.m */, 035F62C513E7A94400B54019 /* NSTextField_PPUtilities.h */, 035F62C613E7A94400B54019 /* NSTextField_PPUtilities.m */, 03AC283513BCD1C300C7A477 /* NSWindow_PPUtilities.h */, 03AC283613BCD1C300C7A477 /* NSWindow_PPUtilities.m */, 03C26F081453EF9C003D5B4E /* NSData_PPNativePasteboardType.h */, 03C26F091453EF9C003D5B4E /* NSData_PPNativePasteboardType.m */, ); name = "Cocoa Categories"; sourceTree = ""; }; 03E2E3DE14D169C00040A7A3 /* Defines */ = { isa = PBXGroup; children = ( 03C6183E1313364000EE17F1 /* PPDefines.h */, 03635E6817BAF349008DA58C /* PPBitmapPixelTypes.h */, 033BA61B168D5C0F0044D327 /* PPCursorDefines.h */, 03365D85150612E800F7DFFF /* PPKeyConstants.h */, 03492B851E6DF1C900B031B0 /* PPModifiablePPToolTypesMasks.h */, 030E8F0E1334E1D10011B0C9 /* PPModifierKeyMasks.h */, 0311375D17E23E2E00C3D4FB /* PPPanelDefaultFramePinnings.h */, 03654BD716DC8A3200B98B1D /* PPPopupPanelActionKeys.h */, 03D0B91B16EDA28600B50FE4 /* PPResizableDirectionsMasks.h */, 03E13B46166F3221002328B2 /* PPUIColors_Panels.h */, 037A7AF517B56405002D56F6 /* PPUIFontDefines.h */, 03E13B49166F3236002328B2 /* PPUserDefaultsInitialValues.h */, ); name = Defines; sourceTree = ""; }; 03E2E3E114D16A090040A7A3 /* Other */ = { isa = PBXGroup; children = ( 03F0D594137D9C5800161F87 /* PPBackgroundPattern.h */, 03F0D595137D9C5800161F87 /* PPBackgroundPattern.m */, 034D7EF41B8A6D8E0064D5D5 /* PPGridPattern.h */, 034D7EF51B8A6D8E0064D5D5 /* PPGridPattern.m */, 03D5469314F8BA120063091B /* PPHotkeys.h */, 03D5469414F8BA120063091B /* PPHotkeys.m */, 03C591AB15606CF600B8AD34 /* PPImageSizePresets.h */, 03C591AC15606CF600B8AD34 /* PPImageSizePresets.m */, 03ED62E31CFB4CF40061EF22 /* Pattern Presets */, 03BD48BC13410758003B0F56 /* PPUserDefaults.h */, 03BD48BD13410758003B0F56 /* PPUserDefaults.m */, ); name = Other; sourceTree = ""; }; 03ED62E31CFB4CF40061EF22 /* Pattern Presets */ = { isa = PBXGroup; children = ( 03ED60DD1CF611A10061EF22 /* PPPresettablePatternProtocol.h */, 03ED61051CF61F1F0061EF22 /* PPPatternPresets.h */, 03ED61061CF61F1F0061EF22 /* PPPatternPresets.m */, 03F2EF4D174439E800EBFA6B /* PPBackgroundPatternPresets.h */, 03F2EF4E174439E800EBFA6B /* PPBackgroundPatternPresets.m */, 0351F5251CE5071700F1501D /* PPGridPatternPresets.h */, 0351F5261CE5071700F1501D /* PPGridPatternPresets.m */, ); name = "Pattern Presets"; sourceTree = ""; }; 03F2A556177F76C100171715 /* Prefix */ = { isa = PBXGroup; children = ( 32DBCF750370BD2300C91783 /* PikoPixel_Prefix.pch */, 03D280DF15CEF65F002606F6 /* PPBuildEnvironmentMacros.h */, 035BFFD5178E4F0000AA1DB7 /* PPRuntimeEnvironmentMacros.h */, 03F2A544177F718200171715 /* PPSDKNativeTypes.h */, 03361FBD1DD41F6E00DFA5AE /* PPOSXPrefix.h */, ); name = Prefix; sourceTree = ""; }; 03F2EF7B1744499B00EBFA6B /* Edit Pattern Presets Sheet */ = { isa = PBXGroup; children = ( 03F2EF8617444A9A00EBFA6B /* PPDocumentEditPatternPresetsSheetController.h */, 03F2EF8717444AA500EBFA6B /* PPDocumentEditPatternPresetsSheetController.m */, 03ED62EA1CFB4EA60061EF22 /* PPPresettablePatternView.h */, 03ED62EB1CFB4EA60061EF22 /* PPPresettablePatternView.m */, ); name = "Edit Pattern Presets Sheet"; sourceTree = ""; }; 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */, 03C3E5C214FA41EA0050214C /* Carbon.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A8FEA54F5311CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */, 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FB0FE9D524F11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 8D15AC370486D014006FF6A4 /* PikoPixel.app */, ); name = Products; sourceTree = ""; }; 2A37F4AAFDCFA73011CA2CEA /* PikoPixel */ = { isa = PBXGroup; children = ( 2A37F4B0FDCFA73011CA2CEA /* main.m */, 03C51EBF218A07E100F2B145 /* Config */, 03F2A556177F76C100171715 /* Prefix */, 03E2E3DE14D169C00040A7A3 /* Defines */, 0342F82616720BA500823E4E /* Enum Types */, 2A37F4ABFDCFA73011CA2CEA /* Classes */, 03E2E39C14D168380040A7A3 /* Cocoa Categories */, 2A37F4AFFDCFA73011CA2CEA /* Other Sources */, 2A37F4B8FDCFA73011CA2CEA /* Resources */, 2A37F4C3FDCFA73011CA2CEA /* Frameworks */, 19C28FB0FE9D524F11CA2CBB /* Products */, ); name = PikoPixel; sourceTree = ""; }; 2A37F4ABFDCFA73011CA2CEA /* Classes */ = { isa = PBXGroup; children = ( 03AC18B71890A4BC0059488A /* Application */, 03C405BD130116AF006930D2 /* Document */, 03432A74130FAF1D00F9F676 /* Toolbox */, 03432A77130FAF4300F9F676 /* UI */, 03E2E3E114D16A090040A7A3 /* Other */, ); name = Classes; sourceTree = ""; }; 2A37F4AFFDCFA73011CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( 039CB4831BCAAE4F00A9E473 /* PPAppBootUtilities.h */, 039CB4821BCAAE4F00A9E473 /* PPAppBootUtilities.m */, 03DB0C781323604F00978A94 /* PPGeometry.h */, 03DB0C791323604F00978A94 /* PPGeometry.m */, 0361D7DD153A5FEF00BCAE1D /* PPHotkeyDisplayUtilities.h */, 0361D7DE153A5FEF00BCAE1D /* PPHotkeyDisplayUtilities.m */, 03B5E5151DFE910300D99F97 /* PPImagePixelAlphaPremultiplyTables.h */, 03B5E5161DFE910300D99F97 /* PPImagePixelAlphaPremultiplyTables.m */, 03C3E5B514FA40D90050214C /* PPKeyboardLayout.h */, 03C3E5B614FA40D90050214C /* PPKeyboardLayout.m */, 033DBDEA1D76974E0087D27C /* PPObjCUtilities.h */, 033DBDEB1D76974E0087D27C /* PPObjCUtilities.m */, 0399D19D1DA1E58100C1DBF1 /* PPSRGBUtilities.h */, 0399D19E1DA1E58100C1DBF1 /* PPSRGBUtilities.m */, 037A7AE917B56046002D56F6 /* PPTextAttributesDicts.h */, 037A7AEA17B56046002D56F6 /* PPTextAttributesDicts.m */, 0331D72D2517D6B2003EFA1C /* PPThumbnailUtilities.h */, 0331D78F25192FCE003EFA1C /* PPThumbnailUtilities.m */, 03A90B75156AD363008C5B1E /* PPUserFolderPaths.h */, 03A90B76156AD363008C5B1E /* PPUserFolderPaths.m */, 037CB6AD1D69100400B51DA0 /* OS X Glue */, 0346EFB31BFE2B840007A2C2 /* Optional */, ); name = "Other Sources"; sourceTree = ""; }; 2A37F4B8FDCFA73011CA2CEA /* Resources */ = { isa = PBXGroup; children = ( 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */, 2A37F4B6FDCFA73011CA2CEA /* MainMenu.nib */, 034B6477139AE1F6003A8E77 /* Document Window */, 034B647E139AE246003A8E77 /* Panels */, 03BB8E1B14FF697300B47930 /* HotkeySettings.nib */, 03C3E6A914FA44290050214C /* Hotkey Defaults */, 0314CCD9164845E100F8B809 /* KeyboardNameToLocale.plist */, 03C22A12172DB76900478538 /* ToolModifierTipsStrings.plist */, 03A8E98F134E675E00A94ECB /* Images */, 8D15AC360486D014006FF6A4 /* Info.plist */, 089C165FFE840EACC02AAC07 /* InfoPlist.strings */, 0327FA50141C908C0072EC1E /* appIcon.icns */, 03649FF8177E9872003E30D9 /* documentIcon.icns */, 0393BB411D1882A600449C89 /* backgroundPatternArchiveIcon.icns */, 0393BB421D1882A600449C89 /* gridPatternArchiveIcon.icns */, ); name = Resources; sourceTree = ""; }; 2A37F4C3FDCFA73011CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */, 1058C7A8FEA54F5311CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 8D15AC270486D014006FF6A4 /* PikoPixel */ = { isa = PBXNativeTarget; buildConfigurationList = C05733C708A9546B00998B17 /* Build configuration list for PBXNativeTarget "PikoPixel" */; buildPhases = ( 8D15AC2B0486D014006FF6A4 /* Resources */, 8D15AC300486D014006FF6A4 /* Sources */, 8D15AC330486D014006FF6A4 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = PikoPixel; productInstallPath = "$(HOME)/Applications"; productName = PikoPixel; productReference = 8D15AC370486D014006FF6A4 /* PikoPixel.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 2A37F4A9FDCFA73011CA2CEA /* Project object */ = { isa = PBXProject; buildConfigurationList = C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "PikoPixel" */; compatibilityVersion = "Xcode 3.1"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, ); mainGroup = 2A37F4AAFDCFA73011CA2CEA /* PikoPixel */; projectDirPath = ""; projectRoot = ""; targets = ( 8D15AC270486D014006FF6A4 /* PikoPixel */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D15AC2B0486D014006FF6A4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */, 8D15AC2D0486D014006FF6A4 /* MainMenu.nib in Resources */, 8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */, 037CFC4A13041BE700ED3E48 /* PreviewPanel.nib in Resources */, 037CFC6A13041CCB00ED3E48 /* LayersPanel.nib in Resources */, 0349A77F1304BACD007DCD51 /* DocumentWindow.nib in Resources */, 03432A3A130F635F00F9F676 /* ToolsPanel.nib in Resources */, 03C617FB1313245300EE17F1 /* DocumentSizeSheet.nib in Resources */, 03BD48811340EC0E003B0F56 /* DocumentGridSettingsSheet.nib in Resources */, 039FB7BC137A74BB00D9E286 /* ExportPanelAccessoryView.nib in Resources */, 039FB7F0137A884900D9E286 /* DocumentBackgroundSettingsSheet.nib in Resources */, 034B6354139978A4003A8E77 /* ToolsPopupPanel.nib in Resources */, 034B6490139AE38A003A8E77 /* NavigatorPopupPanel.nib in Resources */, 0327FA51141C908C0072EC1E /* appIcon.icns in Resources */, 03CAB210142BB9ED009EBA86 /* DocumentResizeSheet.nib in Resources */, 0374731D143E595300BBA96F /* DocumentFlattenedSaveNoticeSheet.nib in Resources */, 0344AC1A14459B370073A6AF /* ColorPickerPopupPanel.nib in Resources */, 03B27A401479CC5B00520BE4 /* LayerControlsPopupPanel.nib in Resources */, 03BB8E1D14FF697300B47930 /* HotkeySettings.nib in Resources */, 03365E0B15089B7B00F7DFFF /* Hotkeys_pt_BR.plist in Resources */, 03365E0C15089B7B00F7DFFF /* Hotkeys_fr_CA.plist in Resources */, 03365E0D15089B7B00F7DFFF /* Hotkeys_fr.plist in Resources */, 03365E0E15089B7B00F7DFFF /* Hotkeys_it.plist in Resources */, 03365E0F15089B7B00F7DFFF /* Hotkeys_el.plist in Resources */, 03365E1015089B7B00F7DFFF /* Hotkeys_en_US.plist in Resources */, 03365E1115089B7B00F7DFFF /* Hotkeys_is.plist in Resources */, 03365E1215089B7B00F7DFFF /* Hotkeys_fr_CH.plist in Resources */, 03365E1315089B7B00F7DFFF /* Hotkeys_en.plist in Resources */, 03365E1415089B7B00F7DFFF /* Hotkeys_ru.plist in Resources */, 03365E1515089B7B00F7DFFF /* Hotkeys_de.plist in Resources */, 03365E1615089B7B00F7DFFF /* Hotkeys_de_CH.plist in Resources */, 03365E1715089B7B00F7DFFF /* Hotkeys_nl.plist in Resources */, 03365E1815089B7B00F7DFFF /* Hotkeys_es.plist in Resources */, 03365E1915089B7B00F7DFFF /* Hotkeys_en_AU.plist in Resources */, 03365E1A15089B7B00F7DFFF /* Hotkeys_en_CA.plist in Resources */, 03365E1B15089B7B00F7DFFF /* Hotkeys_he.plist in Resources */, 03365E1C15089B7B00F7DFFF /* Hotkeys_pt_PT.plist in Resources */, 03365E1D15089B7B00F7DFFF /* Hotkeys_fi.plist in Resources */, 03365E1E15089B7B00F7DFFF /* Hotkeys_nb.plist in Resources */, 03365E1F15089B7B00F7DFFF /* Hotkeys_sv.plist in Resources */, 03365E2015089B7B00F7DFFF /* Hotkeys_en_GB.plist in Resources */, 03365E2115089B7B00F7DFFF /* Hotkeys_da.plist in Resources */, 034B92E4150C7F2600599E0C /* Hotkeys_de_AT.plist in Resources */, 034B92F3150C84A500599E0C /* Hotkeys_nl_BE.plist in Resources */, 034B933A150C94C500599E0C /* Hotkeys_pl.plist in Resources */, 034B934D150C96DD00599E0C /* Hotkeys_ar.plist in Resources */, 034B9351150C98A600599E0C /* Hotkeys_be.plist in Resources */, 034B9355150C99D800599E0C /* Hotkeys_bg.plist in Resources */, 034B935A150C9ABF00599E0C /* Hotkeys_hr.plist in Resources */, 034B9363150C9C5E00599E0C /* Hotkeys_cs.plist in Resources */, 034B9367150C9D6600599E0C /* Hotkeys_hu.plist in Resources */, 034B936A150C9DFB00599E0C /* Hotkeys_lv.plist in Resources */, 034B936E150C9E7800599E0C /* Hotkeys_lt.plist in Resources */, 034B9374150C9F8D00599E0C /* Hotkeys_mk.plist in Resources */, 034B9378150CA00100599E0C /* Hotkeys_mt.plist in Resources */, 034B937C150CA09F00599E0C /* Hotkeys_fa.plist in Resources */, 034B937F150CA13100599E0C /* Hotkeys_ro.plist in Resources */, 034B9382150CA1C900599E0C /* Hotkeys_sr-Cyrl.plist in Resources */, 034B9385150CA2AA00599E0C /* Hotkeys_sk.plist in Resources */, 034B9388150CA34B00599E0C /* Hotkeys_sl.plist in Resources */, 034B938C150CA3FD00599E0C /* Hotkeys_th.plist in Resources */, 034B938F150CA4A000599E0C /* Hotkeys_tr.plist in Resources */, 034B9392150CA50E00599E0C /* Hotkeys_uk.plist in Resources */, 034B9396150CA62500599E0C /* Hotkeys_vi.plist in Resources */, 034B939C150CA89900599E0C /* Hotkeys_hy.plist in Resources */, 034B939F150CA97200599E0C /* Hotkeys_et.plist in Resources */, 034B93A2150CA9DE00599E0C /* Hotkeys_mi.plist in Resources */, 034B93A6150CAA7500599E0C /* Hotkeys_ne.plist in Resources */, 034B93AA150CAB1B00599E0C /* Hotkeys_ps.plist in Resources */, 034B93AF150CAC2100599E0C /* Hotkeys_uz.plist in Resources */, 03A5BEFC1523AD1E003EC48D /* ToolModifierTipsPanel.nib in Resources */, 03C591FA156314C600B8AD34 /* DocumentEditSizePresetsSheet.nib in Resources */, 0325B9A41595D1D7006472D9 /* wand_button.png in Resources */, 0325B9A61595D1D7006472D9 /* eyedropper_button.png in Resources */, 0325B9A71595D1D7006472D9 /* eyedropper_cursor.png in Resources */, 0325B9A81595D1D7006472D9 /* oval_cursor.png in Resources */, 0325B9A91595D1D7006472D9 /* line_cursor.png in Resources */, 0325B9AA1595D1D7006472D9 /* magnifier_button.png in Resources */, 0325B9AB1595D1D7006472D9 /* line_button.png in Resources */, 0325B9AC1595D1D7006472D9 /* magnifier_cursor.png in Resources */, 0325B9AD1595D1D7006472D9 /* pencil_button.png in Resources */, 0325B9AE1595D1D7006472D9 /* wand_cursor.png in Resources */, 0325B9AF1595D1D7006472D9 /* rect_button.png in Resources */, 0325B9B01595D1D7006472D9 /* paintcan_button.png in Resources */, 0325B9B21595D1D7006472D9 /* oval_button.png in Resources */, 0325B9B31595D1D7006472D9 /* paintcan_cursor.png in Resources */, 0325B9B41595D1D7006472D9 /* eraser_button.png in Resources */, 0325B9B51595D1D7006472D9 /* pencil_cursor.png in Resources */, 0325B9B61595D1D7006472D9 /* selection_rect_button.png in Resources */, 0325B9B71595D1D7006472D9 /* move_cursor.png in Resources */, 0325B9B81595D1D7006472D9 /* selection_rect_cursor.png in Resources */, 0325B9B91595D1D7006472D9 /* rect_cursor.png in Resources */, 0325B9BA1595D1D7006472D9 /* move_button.png in Resources */, 0325B9BB1595D1D7006472D9 /* eraser_cursor.png in Resources */, 0325B9E51596B4BE006472D9 /* pencil_segment.png in Resources */, 0325B9FA1596B5A6006472D9 /* solid_segment.png in Resources */, 0325B9FB1596B5A6006472D9 /* selection_tool_overlay_subtract_pattern.png in Resources */, 0325B9FC1596B5A6006472D9 /* selection_tool_overlay_add_pattern.png in Resources */, 0325B9FD1596B5A6006472D9 /* plus_button_overlay_small.png in Resources */, 0325B9FE1596B5A6006472D9 /* plus_button_overlay.png in Resources */, 0325B9FF1596B5A6006472D9 /* neko.png in Resources */, 0325BA001596B5A6006472D9 /* minus_button_overlay_small.png in Resources */, 0325BA011596B5A6006472D9 /* minus_button_overlay.png in Resources */, 0325BA021596B5A6006472D9 /* marching_ants_pattern.png in Resources */, 0325BA031596B5A6006472D9 /* gridtype_lines_segment.png in Resources */, 0325BA041596B5A6006472D9 /* gridtype_largedots_segment.png in Resources */, 0325BA051596B5A6006472D9 /* gridtype_dots_segment.png in Resources */, 0325BA061596B5A6006472D9 /* gridtype_crosshairs_segment.png in Resources */, 0325BA081596B5A6006472D9 /* diagonal_lines_segment.png in Resources */, 0325BA091596B5A6006472D9 /* checkerboard_segment.png in Resources */, 03BF404215E4122700371534 /* DocumentScaleSheet.nib in Resources */, 0314CCDB164845E100F8B809 /* KeyboardNameToLocale.plist in Resources */, 03E41EAF164C8F74009D2495 /* isometric_lines_segment.png in Resources */, 033BA06A16844DD70044D327 /* resize_control.png in Resources */, 033BA9531692D6650044D327 /* DocumentSamplerImagesSettingsSheet.nib in Resources */, 03CF87B1169C6E3B0037A5FD /* SamplerImagePanel.nib in Resources */, 03CF881B169C8BDB0037A5FD /* arrow_left_button.png in Resources */, 03CF881C169C8BDB0037A5FD /* arrow_right_button.png in Resources */, 03C811CE16A32352008BBA3D /* SamplerImagePopupPanel.nib in Resources */, 03D791A016C3451E00BD9820 /* arrow_outline_left_button.png in Resources */, 03D791A116C3451E00BD9820 /* arrow_outline_right_button.png in Resources */, 036548E816D4AA9900B98B1D /* diagonal_checkerboard_segment.png in Resources */, 036548EA16D4AAA600B98B1D /* isometric_checkerboard_segment.png in Resources */, 0362BA0817271C8100850475 /* move_selection_outline_cursor.png in Resources */, 03C22A14172DB76900478538 /* ToolModifierTipsStrings.plist in Resources */, 03F2EF9317444DF200EBFA6B /* DocumentEditPatternPresetsSheet.nib in Resources */, 03649FF9177E9872003E30D9 /* documentIcon.icns in Resources */, 035B01161791BDDC00AA1DB7 /* LayerControlButtonImageViews.nib in Resources */, 03CB764B179721B4006CFD58 /* view_enabled_layers_icon.png in Resources */, 03CB764C179721B4006CFD58 /* target_draw_layer_icon.png in Resources */, 03CB764D179721B4006CFD58 /* view_draw_layer_icon.png in Resources */, 03CB764E179721B4006CFD58 /* target_enabled_layers_icon.png in Resources */, 0384F8BB17C71F7500F766BC /* eraser_tool_overlay_outline_pattern.png in Resources */, 03FDC66817E56D7D0086EE53 /* freehand_select_cursor.png in Resources */, 03FDC66A17E56D860086EE53 /* freehand_select_button.png in Resources */, 03BFCB2F18839658001844A6 /* ScreencastPopupPanel.nib in Resources */, 0393BB151D18692E00449C89 /* gridpatternpreview_foreground.png in Resources */, 0393BB431D1882A600449C89 /* backgroundPatternArchiveIcon.icns in Resources */, 0393BB441D1882A600449C89 /* gridPatternArchiveIcon.icns in Resources */, 039772641E1C3FCC0061D6EC /* blend_mode_icon_standard.png in Resources */, 039772651E1C3FCC0061D6EC /* blend_mode_icon_linear.png in Resources */, 03CE4BE91E5E286600FD6B5C /* color_ramp_cursor.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 8D15AC300486D014006FF6A4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D15AC310486D014006FF6A4 /* PPDocument.m in Sources */, 8D15AC320486D014006FF6A4 /* main.m in Sources */, 0329D51412DB71D10073FF2E /* PPCanvasView.m in Sources */, 0329D55E12DBA08D0073FF2E /* PPDocumentWindowController.m in Sources */, 03CB29F212E4B87600A51C92 /* PPNavigatorPopupPanelController.m in Sources */, 03CB29FA12E4B95B00A51C92 /* PPNavigatorPopupView.m in Sources */, 0374721912F3A6340026A596 /* PPLayersPanelController.m in Sources */, 037472EB12FBD9480026A596 /* PPDocument_Layers.m in Sources */, 03C4051512FFFCC4006930D2 /* PPLayersTableView.m in Sources */, 03C405681300BF13006930D2 /* PPLayerOpacitySliderCell.m in Sources */, 03C406EA1303DFEC006930D2 /* PPLayerEnabledButtonCell.m in Sources */, 0349A7591304B6D4007DCD51 /* PPDocument_FileFormats.m in Sources */, 0349A7611304B76E007DCD51 /* PPDocument_Drawing.m in Sources */, 03158CB2130B705900E08C31 /* PPDocument_Notifications.m in Sources */, 03158D76130BEDCF00E08C31 /* PPPanelController.m in Sources */, 03432A31130F627200F9F676 /* PPToolsPanelController.m in Sources */, 03432A6F130FAEF500F9F676 /* PPToolbox.m in Sources */, 03432A82130FB03F00F9F676 /* PPTool.m in Sources */, 03432A8C130FB46A00F9F676 /* PPPencilTool.m in Sources */, 03432AE1130FD92D00F9F676 /* PPFillTool.m in Sources */, 03432AF1130FD9AF00F9F676 /* PPLineTool.m in Sources */, 03432B11130FDA1A00F9F676 /* PPRectTool.m in Sources */, 03432B1F130FDACB00F9F676 /* PPOvalTool.m in Sources */, 03E69219130FDB300086A468 /* PPEraserTool.m in Sources */, 03E69229130FDBD30086A468 /* PPColorSamplerTool.m in Sources */, 03E69247130FDCCD0086A468 /* PPMagnifierTool.m in Sources */, 03E69253130FDD230086A468 /* PPRectSelectTool.m in Sources */, 03E6925D130FDD810086A468 /* PPMagicWandTool.m in Sources */, 03E69269130FDDEF0086A468 /* PPFreehandSelectTool.m in Sources */, 03E69273130FDE300086A468 /* PPMoveTool.m in Sources */, 03E6929F130FE16A0086A468 /* PPDocument_ActiveTool.m in Sources */, 03C617F213126A1F00EE17F1 /* PPDocumentSizeSheetController.m in Sources */, 03A7C17E131884CE00DF3B23 /* PPDocument_Selection.m in Sources */, 03C7E0411320E7CC00236E79 /* PPDocumentWindowController_Actions.m in Sources */, 03C7E0801321042300236E79 /* PPDocumentWindowController_MenuValidation.m in Sources */, 03DB0C7A1323604F00978A94 /* PPGeometry.m in Sources */, 03700CC913261F6000FDE20E /* PPDocument_Pasteboard.m in Sources */, 036C750E1328B56E006AF469 /* NSImage_PPUtilities.m in Sources */, 03C77650132A34410056BEC3 /* PPDocument_Moving.m in Sources */, 03BD47F3133F8ACC003B0F56 /* NSColor_PPUtilities.m in Sources */, 03BD4809133F9305003B0F56 /* PPDocumentGridSettingsSheetController.m in Sources */, 03BD48BE13410758003B0F56 /* PPUserDefaults.m in Sources */, 03CE51FA135234E2009E57B9 /* PPDocument_MirroringRotating.m in Sources */, 03CE54BB135798B6009E57B9 /* PPDocument_Resizing.m in Sources */, 03BF0A0B135AA6D3000F2C14 /* PPPreviewPanelController.m in Sources */, 03BF0A0E135AA6E4000F2C14 /* PPPreviewView.m in Sources */, 0378357513768B450046E201 /* PPDocument_Saving.m in Sources */, 037836EF137694700046E201 /* PPExportPanelAccessoryViewController.m in Sources */, 03CEF1D3137A944C005B32E7 /* PPDocumentBackgroundSettingsSheetController.m in Sources */, 03F0D596137D9C5800161F87 /* PPBackgroundPattern.m in Sources */, 030F1A9813800DAC00C79F03 /* PPDocument_CanvasSettings.m in Sources */, 0385B304138011A500BE900B /* PPDocumentWindowController_Sheets.m in Sources */, 034B5FB7138ED8FB003A8E77 /* PPPopupPanelController.m in Sources */, 034B5FD1138EDBE8003A8E77 /* PPPopupPanel.m in Sources */, 034B629113989470003A8E77 /* PPPopupPanelsController.m in Sources */, 034B635C139979B1003A8E77 /* PPToolsPopupPanelController.m in Sources */, 03E3974613A1807B00276376 /* PPDocument_NativeFileFormat.m in Sources */, 0373531213B7191000F4FDC8 /* PPPanelsController.m in Sources */, 03AC283713BCD1C300C7A477 /* NSWindow_PPUtilities.m in Sources */, 031EC10513CE551800582645 /* PPThumbnailImageView.m in Sources */, 031EC2C313CFFF5500582645 /* PPDocumentWindowController_Notifications.m in Sources */, 0334540613DB905B00DD0435 /* PPColorWell.m in Sources */, 035F62C713E7A94400B54019 /* NSTextField_PPUtilities.m in Sources */, 038A4717141F508500CFC168 /* PPDocumentWindow.m in Sources */, 03CAB0A8142A79A8009EBA86 /* PPKeyCancellableWindow.m in Sources */, 03CAB204142BB663009EBA86 /* PPDocumentResizeSheetController.m in Sources */, 037472C7143E208B00BBA96F /* PPDocumentFlattenedSaveNoticeSheetController.m in Sources */, 03020DB61441786500A988DB /* PPColorPickerPopupPanelController.m in Sources */, 0379BEE614440BCD006BD02A /* PPFilledRoundedRectView.m in Sources */, 03C26EAB144FEA74003D5B4E /* NSDocumentController_PPUtilities.m in Sources */, 03C26EF614506E09003D5B4E /* NSPasteboard_PPUtilities.m in Sources */, 03C26F0A1453EF9C003D5B4E /* NSData_PPNativePasteboardType.m in Sources */, 03B27A391479CB1C00520BE4 /* PPLayerControlsPopupPanelController.m in Sources */, 03B971C91498C07C00175B89 /* NSColorPanel_PPUtilities.m in Sources */, 035E8A4414D0980B008A66D3 /* PPDocument_PixelMatching.m in Sources */, 03E2E37314D160110040A7A3 /* PPToolUtilities.m in Sources */, 03CAD73814D85EA400C37C2E /* PPCanvasView_MatchToolToleranceIndicator.m in Sources */, 0341042414DF228900E75BA2 /* PPCanvasView_SelectionToolOverlay.m in Sources */, 034105A014E03D8200E75BA2 /* PPCanvasView_Notifications.m in Sources */, 03C72F3414E072E90017C73C /* PPCanvasView_SelectionOutline.m in Sources */, 03C7325514E6E3D00017C73C /* NSBezierPath_PPUtilities.m in Sources */, 03D5469514F8BA120063091B /* PPHotkeys.m in Sources */, 03C3E5B714FA40D90050214C /* PPKeyboardLayout.m in Sources */, 03BB8E2614FF69BF00B47930 /* PPHotkeySettingsWindowController.m in Sources */, 03365C0715035AA800F7DFFF /* PPApplication.m in Sources */, 030FD3EF1511F629005E6E54 /* NSError_PPUtilities.m in Sources */, 03A5BF0715279EB6003EC48D /* PPToolModifierTipsPanelController.m in Sources */, 0361D7DF153A5FEF00BCAE1D /* PPHotkeyDisplayUtilities.m in Sources */, 03C591AD15606CF600B8AD34 /* PPImageSizePresets.m in Sources */, 03C5920C1563184C00B8AD34 /* PPDocumentEditImageSizePresetsSheetController.m in Sources */, 03A90B77156AD363008C5B1E /* PPUserFolderPaths.m in Sources */, 0324E1C2157336C5006D12BC /* PPDocument_NotificationOverrides.m in Sources */, 033346C41574E2AE008EE9D1 /* PPDocumentLayer.m in Sources */, 03BF3DDB15D84F2D00371534 /* PPDocumentScaleSheetController.m in Sources */, 03BF407115E4263C00371534 /* PPScaledImageView.m in Sources */, 03BF414D15E8251600371534 /* PPDocumentAnimationFileNoticeSheetController.m in Sources */, 03721FDE15F29E1B0000E65A /* PPDocumentSheetController.m in Sources */, 03B446EE16058E78009CD1D0 /* PPCanvasView_Autoscrolling.m in Sources */, 03744DC716098832000DB41D /* PPCanvasView_MagnifierToolOverlay.m in Sources */, 034AEA2E1660AF19006C5617 /* NSObject_PPUtilities.m in Sources */, 03A0DDE816719BC0000BC982 /* PPParabolicSlider.m in Sources */, 03CAE6271681A13A005BC961 /* PPSamplerImagePopupPanelController.m in Sources */, 037A461E1681B7B500F0C363 /* PPDocument_SamplerImages.m in Sources */, 033BA017168422B50044D327 /* PPSamplerImageView.m in Sources */, 033BA05C168446DB0044D327 /* PPResizeControl.m in Sources */, 033BA170168498AC0044D327 /* PPMiniColorWell.m in Sources */, 033BA628168D69620044D327 /* NSCursor_PPUtilities.m in Sources */, 033BA83D168EE8800044D327 /* PPDocumentSamplerImage.m in Sources */, 033BA9381692B8F50044D327 /* PPDocumentSamplerImagesSettingsSheetController.m in Sources */, 039769E91696113C002855D4 /* NSImageRep_PPUtilities.m in Sources */, 03CF86B5169B13720037A5FD /* PPSamplerImagePanelController.m in Sources */, 03C8114C16A0EEBB008BBA3D /* PPColorPickerPopupPanel.m in Sources */, 03E3FF9616BCD192007F86E3 /* PPCursorManager.m in Sources */, 0362BA64172873D300850475 /* PPToolModifierTipsText.m in Sources */, 03F2EF4F174439E800EBFA6B /* PPBackgroundPatternPresets.m in Sources */, 03F2EF8817444AA500EBFA6B /* PPDocumentEditPatternPresetsSheetController.m in Sources */, 03F2F06E1746A95400EBFA6B /* NSFileManager_PPUtilities.m in Sources */, 033661821763B7C30075C305 /* PPDocument_Tiling.m in Sources */, 033B6DF6176D169A005DD093 /* PPCanvasView_FillToolOverlay.m in Sources */, 035B00C3179078D100AA1DB7 /* PPCompositeThumbnail.m in Sources */, 035B00E41790997300AA1DB7 /* PPLayerControlButtonImagesManager.m in Sources */, 035B018D179235CC00AA1DB7 /* PPLayerControlButtonImagesManager_Notifications.m in Sources */, 03C8F376179F02EB0025C1C4 /* PPTitleablePopUpButton.m in Sources */, 037A7AEB17B56046002D56F6 /* PPTextAttributesDicts.m in Sources */, 037A7C7917B8CC38002D56F6 /* PPDocument_LayerOperationTarget.m in Sources */, 03635E8217BAF4BB008DA58C /* NSBitmapImageRep_PPUtilities_ImageBitmaps.m in Sources */, 03635E8717BAF4C7008DA58C /* NSBitmapImageRep_PPUtilities_MaskBitmaps.m in Sources */, 03635FC417BD56C0008DA58C /* NSBitmapImageRep_PPUtilities.m in Sources */, 0363606A17BD6871008DA58C /* NSBitmapImageRep_PPUtilities_ColorMasking.m in Sources */, 0384F85017C6F44400F766BC /* PPCanvasView_EraserToolOverlay.m in Sources */, 032FC8FE17D181E1004EC4E3 /* NSDocument_PPUtilities.m in Sources */, 03F23727183AAEDF00D37EB5 /* PPDocument_NativeFileIcon.m in Sources */, 0314535B1866A6FA00DE2EC4 /* PPScreencastController.m in Sources */, 03BFCAF218837020001844A6 /* PPScreencastPopupPanelController.m in Sources */, 03AC18BC1890A5150059488A /* PPOptional_Screencasting.m in Sources */, 0332D8AB19F6070100CB3213 /* NSBitmapImageRep_PPUtilities_PatternBitmaps.m in Sources */, 0332D95C19FAF3E900CB3213 /* NSColor_PPUtilities_PatternColors.m in Sources */, 0346D3601A114A4500C17251 /* PPOSXGlue_KeyUpDuringControlTracking.m in Sources */, 0358FADF1ABB0E360075A25A /* NSEvent_PPUtilities.m in Sources */, 032E7DC41AF0867D0097C0D7 /* NSObject_PPUtilities_MethodSwizzling.m in Sources */, 0335B0711AFADF6D00726F22 /* PPCanvasView_RetinaDrawing.m in Sources */, 034C69C81B025EEF001CC371 /* NSBezierPath_PPUtilities_MaskBitmapPaths.m in Sources */, 034D7EF61B8A6D8E0064D5D5 /* PPGridPattern.m in Sources */, 039CB4841BCAAE4F00A9E473 /* PPAppBootUtilities.m in Sources */, 0346EFD61BFE30640007A2C2 /* PPOptional_CanvasSpeedCheck.m in Sources */, 03DECB6C1C5E71D300953470 /* PPCanvasView_MouseCursor.m in Sources */, 0351F5271CE5071700F1501D /* PPGridPatternPresets.m in Sources */, 03ED61071CF61F1F0061EF22 /* PPPatternPresets.m in Sources */, 03ED62EC1CFB4EA60061EF22 /* PPPresettablePatternView.m in Sources */, 0393BA871D0C9CF200449C89 /* NSMutableArray_PPUtilities.m in Sources */, 037CB6AA1D690F8300B51DA0 /* PPOSXGlue_PatternPhaseGlitches.m in Sources */, 033DBDEC1D76974E0087D27C /* PPObjCUtilities.m in Sources */, 033DBDF01D76976F0087D27C /* PPOSXGlue_RetinaDrawingArtifacts.m in Sources */, 033DBDF11D76976F0087D27C /* PPOSXGlueUtilities.m in Sources */, 0399D19F1DA1E58100C1DBF1 /* PPSRGBUtilities.m in Sources */, 03B5E43C1DF681FF00D99F97 /* NSBitmapImageRep_PPUtilities_LinearRGB16Bitmaps.m in Sources */, 03B5E5171DFE910300D99F97 /* PPImagePixelAlphaPremultiplyTables.m in Sources */, 03E951CF1E2F028B007460DC /* PPColorRampTool.m in Sources */, 03C56B0B1E491AB20096E7C9 /* PPLayerBlendingModeButton.m in Sources */, 033626B81E5BEA5600BA5807 /* PPCanvasView_ColorRampToolOverlay.m in Sources */, 031DAFB21E772A25006D2758 /* PPToolButtonMatrix.m in Sources */, 0377183E1EB31E8400556F9A /* PPOSXGlue_PreserveDrawColorDuringAboutPanel.m in Sources */, 0331D79025192FCE003EFA1C /* PPThumbnailUtilities.m in Sources */, 031FCB74251AF171006EF3B3 /* PPOSXGlue_NavigatorSliderVisibility.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 0314CCD9164845E100F8B809 /* KeyboardNameToLocale.plist */ = { isa = PBXVariantGroup; children = ( 0314CCDA164845E100F8B809 /* English */, ); name = KeyboardNameToLocale.plist; sourceTree = ""; }; 033BA9511692D6650044D327 /* DocumentSamplerImagesSettingsSheet.nib */ = { isa = PBXVariantGroup; children = ( 033BA9521692D6650044D327 /* English */, ); name = DocumentSamplerImagesSettingsSheet.nib; sourceTree = ""; }; 03432A38130F635F00F9F676 /* ToolsPanel.nib */ = { isa = PBXVariantGroup; children = ( 03432A39130F635F00F9F676 /* English */, ); name = ToolsPanel.nib; sourceTree = ""; }; 0344AC1414459B370073A6AF /* ColorPickerPopupPanel.nib */ = { isa = PBXVariantGroup; children = ( 0344AC1514459B370073A6AF /* English */, ); name = ColorPickerPopupPanel.nib; sourceTree = ""; }; 0349A77D1304BACD007DCD51 /* DocumentWindow.nib */ = { isa = PBXVariantGroup; children = ( 0349A77E1304BACD007DCD51 /* English */, ); name = DocumentWindow.nib; sourceTree = ""; }; 034B6352139978A4003A8E77 /* ToolsPopupPanel.nib */ = { isa = PBXVariantGroup; children = ( 034B6353139978A4003A8E77 /* English */, ); name = ToolsPopupPanel.nib; sourceTree = ""; }; 034B648A139AE38A003A8E77 /* NavigatorPopupPanel.nib */ = { isa = PBXVariantGroup; children = ( 034B648B139AE38A003A8E77 /* English */, ); name = NavigatorPopupPanel.nib; sourceTree = ""; }; 035B01141791BDDB00AA1DB7 /* LayerControlButtonImageViews.nib */ = { isa = PBXVariantGroup; children = ( 035B01151791BDDB00AA1DB7 /* English */, ); name = LayerControlButtonImageViews.nib; sourceTree = ""; }; 0374731B143E595300BBA96F /* DocumentFlattenedSaveNoticeSheet.nib */ = { isa = PBXVariantGroup; children = ( 0374731C143E595300BBA96F /* English */, ); name = DocumentFlattenedSaveNoticeSheet.nib; sourceTree = ""; }; 037CFC4813041BE700ED3E48 /* PreviewPanel.nib */ = { isa = PBXVariantGroup; children = ( 037CFC4913041BE700ED3E48 /* English */, ); name = PreviewPanel.nib; sourceTree = ""; }; 037CFC6813041CCB00ED3E48 /* LayersPanel.nib */ = { isa = PBXVariantGroup; children = ( 037CFC6913041CCB00ED3E48 /* English */, ); name = LayersPanel.nib; sourceTree = ""; }; 039FB7B6137A74BB00D9E286 /* ExportPanelAccessoryView.nib */ = { isa = PBXVariantGroup; children = ( 039FB7B7137A74BB00D9E286 /* English */, ); name = ExportPanelAccessoryView.nib; sourceTree = ""; }; 039FB7EE137A884900D9E286 /* DocumentBackgroundSettingsSheet.nib */ = { isa = PBXVariantGroup; children = ( 039FB7EF137A884900D9E286 /* English */, ); name = DocumentBackgroundSettingsSheet.nib; sourceTree = ""; }; 03A5BEFA1523AD1E003EC48D /* ToolModifierTipsPanel.nib */ = { isa = PBXVariantGroup; children = ( 03A5BEFB1523AD1E003EC48D /* English */, ); name = ToolModifierTipsPanel.nib; sourceTree = ""; }; 03B27A3E1479CC5B00520BE4 /* LayerControlsPopupPanel.nib */ = { isa = PBXVariantGroup; children = ( 03B27A3F1479CC5B00520BE4 /* English */, ); name = LayerControlsPopupPanel.nib; sourceTree = ""; }; 03BB8E1B14FF697300B47930 /* HotkeySettings.nib */ = { isa = PBXVariantGroup; children = ( 03BB8E1C14FF697300B47930 /* English */, ); name = HotkeySettings.nib; sourceTree = ""; }; 03BD487F1340EC0E003B0F56 /* DocumentGridSettingsSheet.nib */ = { isa = PBXVariantGroup; children = ( 03BD48801340EC0E003B0F56 /* English */, ); name = DocumentGridSettingsSheet.nib; sourceTree = ""; }; 03BF404015E4122700371534 /* DocumentScaleSheet.nib */ = { isa = PBXVariantGroup; children = ( 03BF404115E4122700371534 /* English */, ); name = DocumentScaleSheet.nib; sourceTree = ""; }; 03BFCB2D18839658001844A6 /* ScreencastPopupPanel.nib */ = { isa = PBXVariantGroup; children = ( 03BFCB2E18839658001844A6 /* English */, ); name = ScreencastPopupPanel.nib; sourceTree = ""; }; 03C22A12172DB76900478538 /* ToolModifierTipsStrings.plist */ = { isa = PBXVariantGroup; children = ( 03C22A13172DB76900478538 /* English */, ); name = ToolModifierTipsStrings.plist; sourceTree = ""; }; 03C591F8156314C600B8AD34 /* DocumentEditSizePresetsSheet.nib */ = { isa = PBXVariantGroup; children = ( 03C591F9156314C600B8AD34 /* English */, ); name = DocumentEditSizePresetsSheet.nib; sourceTree = ""; }; 03C617F91313245300EE17F1 /* DocumentSizeSheet.nib */ = { isa = PBXVariantGroup; children = ( 03C617FA1313245300EE17F1 /* English */, ); name = DocumentSizeSheet.nib; sourceTree = ""; }; 03C811CC16A32352008BBA3D /* SamplerImagePopupPanel.nib */ = { isa = PBXVariantGroup; children = ( 03C811CD16A32352008BBA3D /* English */, ); name = SamplerImagePopupPanel.nib; sourceTree = ""; }; 03CAB20A142BB9ED009EBA86 /* DocumentResizeSheet.nib */ = { isa = PBXVariantGroup; children = ( 03CAB20B142BB9ED009EBA86 /* English */, ); name = DocumentResizeSheet.nib; sourceTree = ""; }; 03CF87AF169C6E3B0037A5FD /* SamplerImagePanel.nib */ = { isa = PBXVariantGroup; children = ( 03CF87B0169C6E3B0037A5FD /* English */, ); name = SamplerImagePanel.nib; sourceTree = ""; }; 03F2EF9117444DF200EBFA6B /* DocumentEditPatternPresetsSheet.nib */ = { isa = PBXVariantGroup; children = ( 03F2EF9217444DF200EBFA6B /* English */, ); name = DocumentEditPatternPresetsSheet.nib; sourceTree = ""; }; 089C165FFE840EACC02AAC07 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 089C1660FE840EACC02AAC07 /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; 2A37F4B6FDCFA73011CA2CEA /* MainMenu.nib */ = { isa = PBXVariantGroup; children = ( 2A37F4B7FDCFA73011CA2CEA /* English */, ); name = MainMenu.nib; sourceTree = ""; }; 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */ = { isa = PBXVariantGroup; children = ( 2A37F4BAFDCFA73011CA2CEA /* English */, ); name = Credits.rtf; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ C05733C808A9546B00998B17 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = PikoPixel; WRAPPER_EXTENSION = app; ZERO_LINK = NO; }; name = Debug; }; C05733C908A9546B00998B17 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(PPXCCONFIG__RELEASE_ARCHS)"; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_MODEL_TUNING = G5; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = PikoPixel; WRAPPER_EXTENSION = app; ZERO_LINK = NO; }; name = Release; }; C05733CC08A9546B00998B17 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 03C51ECB218A086D00F2B145 /* PPXCConfig_10.5sdk.xcconfig */; buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = PikoPixel_Prefix.pch; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; }; name = Debug; }; C05733CD08A9546B00998B17 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 03C51ECB218A086D00F2B145 /* PPXCConfig_10.5sdk.xcconfig */; buildSettings = { GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = PikoPixel_Prefix.pch; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ C05733C708A9546B00998B17 /* Build configuration list for PBXNativeTarget "PikoPixel" */ = { isa = XCConfigurationList; buildConfigurations = ( C05733C808A9546B00998B17 /* Debug */, C05733C908A9546B00998B17 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "PikoPixel" */ = { isa = XCConfigurationList; buildConfigurations = ( C05733CC08A9546B00998B17 /* Debug */, C05733CD08A9546B00998B17 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 2A37F4A9FDCFA73011CA2CEA /* Project object */; } PikoPixel.Sources.1.0-b10b/PikoPixel/PikoPixel_Prefix.pch0000644000076500000240000000241113234403570022071 0ustar joshstaff/* PikoPixel_Prefix.pch Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Prefix header for all source files #ifdef __OBJC__ # import #endif #import "PPBuildEnvironmentMacros.h" #import "PPRuntimeEnvironmentMacros.h" #import "PPSDKNativeTypes.h" #ifdef __APPLE__ # import "PPOSXPrefix.h" #endif #ifdef GNUSTEP # import "PPGNUstepPrefix.h" #endif PikoPixel.Sources.1.0-b10b/PikoPixel/PikoPixelInfo.plist0000644000076500000240000000634214400203025021745 0ustar joshstaff// PikoPixel Info property list for GNUstep { ApplicationDescription = "Pixel-art image editor"; ApplicationName = PikoPixel; ApplicationRelease = "1.0 BETA10b"; Authors = ( "Developed by Josh Freeman ", "Twilight Edge Software ", "https://twilightedge.com ", "pikopixel@twilightedge.com ", " ", "Contributors: ", "Fred Kiefer, Riccardo Mottola ", " ", "Thank you: ", "• GNUstep framework developers ", "• Gürkan Myczko, Yavor Doganov (Debian package) ", "• David Chisnall, Edwin Ancaer, Steve Wills (FreeBSD port) ", "• Bernard Cafarelli (Gentoo package) ", "• Carsten Teibes (AUR package) ", "• Kira Patton (Void Linux package) "); Copyright = "Copyright (C) 2013-2018,2020,2023 Josh Freeman"; CopyrightDescription = "Released under the GNU Affero General Public License v3"; NSExecutable = "PikoPixel"; NSMainNibFile = "MainMenu.nib"; NSPrincipalClass = PPApplication; NSRole = Application; FreeDesktopCategories = ("Graphics", "2DGraphics", "RasterGraphics", "X-GNUstep"); NSTypes = ( { NSHumanReadableName = "PikoPixel Document"; NSName = "PikoPixel Document"; NSUnixExtensions = ("piko", "piko-gif", "piko-jpg", "piko-jpeg", "piko-png", "piko-tif", "piko-tiff", "piko-bmp"); NSRole = Editor; NSDocumentClass = PPDocument; NSMIMETypes = ("image/piko", "image/x-piko"); }, { NSHumanReadableName = "PikoPixel Background Patterns Archive"; NSName = "PikoPixel Background Patterns Archive"; NSUnixExtensions = ("pikopatr"); NSRole = None; }, { NSHumanReadableName = "PikoPixel Grid Patterns Archive"; NSName = "PikoPixel Grid Patterns Archive"; NSUnixExtensions = ("pikogrid"); NSRole = None; }, { NSHumanReadableName = "GIF Graphic"; NSName = "GIF Graphic"; NSUnixExtensions = ("gif"); NSRole = Editor; NSDocumentClass = PPDocument; NSMIMETypes = ("image/gif"); }, { NSHumanReadableName = "JPEG Graphic"; NSName = "JPEG Graphic"; NSUnixExtensions = ("jpg", "jpeg"); NSRole = Editor; NSDocumentClass = PPDocument; NSMIMETypes = ("image/jpeg"); }, { NSHumanReadableName = "PNG Graphic"; NSName = "PNG Graphic"; NSUnixExtensions = ("png"); NSRole = Editor; NSDocumentClass = PPDocument; NSMIMETypes = ("image/png", "image/x-png"); }, { NSHumanReadableName = "TIFF Graphic"; NSName = "TIFF Graphic"; NSUnixExtensions = ("tif", "tiff"); NSRole = Editor; NSDocumentClass = PPDocument; NSMIMETypes = ("image/tiff"); }, { NSHumanReadableName = "BMP Graphic"; NSName = "BMP Graphic"; NSUnixExtensions = ("bmp"); NSRole = Editor; NSDocumentClass = PPDocument; NSMIMETypes = ("image/bmp"); } ); } PikoPixel.Sources.1.0-b10b/PikoPixel/PPAppBootUtilities.h0000644000076500000240000000246313234403416022033 0ustar joshstaff/* PPAppBootUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import bool PPAppBootUtils_PerformNSObjectSelectorAfterAppLoads(SEL selector); void PPAppBootUtils_HandleAppDidFinishLoading(void); #define macroPerformNSObjectSelectorAfterAppLoads(selectorName) \ PPAppBootUtils_PerformNSObjectSelectorAfterAppLoads(@selector(selectorName)) PikoPixel.Sources.1.0-b10b/PikoPixel/PPAppBootUtilities.m0000644000076500000240000000730213271735115022042 0ustar joshstaff/* PPAppBootUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPAppBootUtilities.h" #import "PPObjCUtilities.h" #define kMaxNumStoredSelectors 50 static SEL *gStoredSelectors = NULL; static int gNumStoredSelectors = 0; static bool gAppDidFinishLoading = NO, gHadBootError_UnableToAllocateMemoryForStoredSelectors = NO, gHadBootError_StoredSelectorsArrayTooSmall = NO; bool PPAppBootUtils_PerformNSObjectSelectorAfterAppLoads(SEL selector) { if (gAppDidFinishLoading) { [NSObject performSelector: selector]; return YES; } if (!gStoredSelectors) { gStoredSelectors = (SEL *) malloc (kMaxNumStoredSelectors * sizeof(SEL)); if (!gStoredSelectors) { gHadBootError_UnableToAllocateMemoryForStoredSelectors = YES; goto ERROR; } } if (gNumStoredSelectors >= kMaxNumStoredSelectors) { gHadBootError_StoredSelectorsArrayTooSmall = YES; goto ERROR; } gStoredSelectors[gNumStoredSelectors++] = selector; return YES; ERROR: return NO; } void PPAppBootUtils_HandleAppDidFinishLoading(void) { int selectorIndex; if (gAppDidFinishLoading) return; gAppDidFinishLoading = YES; if (gHadBootError_UnableToAllocateMemoryForStoredSelectors) { NSLog(@"ERROR: Out of memory in PPAppUtils_PerformNSObjectSelectorAfterAppLoads()"); } if (gHadBootError_StoredSelectorsArrayTooSmall) { NSLog(@"ERROR: Selector array is full - unable to store all delayed selector(s) in " "PPAppUtils_PerformNSObjectSelectorAfterAppLoads(); Need to increase " "kMaxNumStoredSelectors to more than (%d) in PPAppBootUtilities.m", (int) kMaxNumStoredSelectors); } if (!gStoredSelectors) return; // sort the stored selectors alphabetically by name so they're always called in the same // order instead of depending on the undefined order in which +load methods are called PPObjCUtils_AlphabeticallySortSelectorArray(gStoredSelectors, gNumStoredSelectors); for (selectorIndex=0; selectorIndex. */ #import @interface PPApplication : NSApplication { IBOutlet NSMenuItem *_pasteMenuItem; IBOutlet NSMenuItem *_canvasDisplayModeMenuItem; IBOutlet NSMenuItem *_layerOperationTargetMenuItem; IBOutlet NSMenuItem *_zoomInMenuItem; IBOutlet NSMenuItem *_zoomOutMenuItem; IBOutlet NSMenuItem *_zoomToFitMenuItem; IBOutlet NSMenuItem *_toggleActivePanelsMenuItem; IBOutlet NSMenuItem *_toggleColorPickerMenuItem; IBOutlet NSMenuItem *_leftArrowKeyEquivalentMenuItem; IBOutlet NSMenuItem *_rightArrowKeyEquivalentMenuItem; IBOutlet NSMenuItem *_previousWindowMenuItem; } - (IBAction) editHotkeySettings: (id) sender; - (IBAction) newDocumentFromPasteboard: (id) sender; - (IBAction) activateNextDocumentWindow: (id) sender; - (IBAction) activatePreviousDocumentWindow: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPApplication.m0000644000076500000240000002316313234403205021037 0ustar joshstaff/* PPApplication.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPApplication.h" #import "PPHotkeys.h" #import "PPHotkeySettingsWindowController.h" #import "PPDocument.h" #import "NSDocumentController_PPUtilities.h" #import "NSPasteboard_PPUtilities.h" #import "PPDocumentWindow.h" #import "NSColorPanel_PPUtilities.h" #import "NSDocumentController_PPUtilities.h" #import "PPModifierKeyMasks.h" #import "PPAppBootUtilities.h" #define kNonzeroModifierMaskForMenuItemsWithArrowKeyEquivalents (NSAlternateKeyMask) @interface PPApplication (PrivateMethods) - (void) addAsObserverForNSWindowNotifications; - (void) removeAsObserverForNSWindowNotifications; - (void) handleNSWindowNotification_DidBecomeKey: (NSNotification *) notification; - (void) addAsObserverForPPHotkeysNotifications; - (void) removeAsObserverForPPHotkeysNotifications; - (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification; - (void) updateMainMenuForWindow: (NSWindow *) window; - (void) updateMainMenuForCurrentKeyWindow; - (void) updateMenuItemKeyEquivalentsForCurrentHotkeys; - (void) setupPreviousWindowMenuItemKeyEquivalentFromLocalizedHotkey; - (void) setupNonzeroModifierMasksForMenuItemsWithArrowKeyEquivalents; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPApplication (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPApplication - init { self = [super init]; if (!self) goto ERROR; [self setDelegate: self]; return self; ERROR: [self release]; return nil; } #pragma mark Actions - (IBAction) editHotkeySettings: (id) sender { [[PPHotkeySettingsWindowController sharedController] showPanel]; } - (IBAction) newDocumentFromPasteboard: (id) sender { [[NSDocumentController sharedDocumentController] ppOpenUntitledDuplicateOfPPDocument: [PPDocument ppDocumentFromPasteboard]]; } - (IBAction) activateNextDocumentWindow: (id) sender { [[NSDocumentController sharedDocumentController] ppActivateNextDocument]; } - (IBAction) activatePreviousDocumentWindow: (id) sender { [[NSDocumentController sharedDocumentController] ppActivatePreviousDocument]; } #pragma mark NSApplication overrides - (void) finishLaunching { PPAppBootUtils_HandleAppDidFinishLoading(); [super finishLaunching]; } - (BOOL) validateMenuItem: (PPSDKNativeType_NSMenuItemPtr) menuItem { SEL menuItemAction = [menuItem action]; if (menuItemAction == @selector(newDocumentFromPasteboard:)) { return [NSPasteboard ppPasteboardHasBitmap] ? YES : NO; } // printing is currently disabled, so both printing-related menu items (print & page setup) // use runPageLayout: as their action for convenience when invalidating them if (menuItemAction == @selector(runPageLayout:)) { return NO; } if ((menuItemAction == @selector(activateNextDocumentWindow:)) || (menuItemAction == @selector(activatePreviousDocumentWindow:))) { return [[NSDocumentController sharedDocumentController] ppHasMultipleDocuments]; } return YES; } #pragma mark NSApplication delegate methods - (void) applicationDidFinishLaunching: (NSNotification *) notification { // Main menu [self updateMainMenuForCurrentKeyWindow]; [self addAsObserverForNSWindowNotifications]; if (PP_RUNTIME_CHECK__RUNTIME_INTERCEPTS_INACTIVE_MENUITEM_KEY_EQUIVALENTS) { // if the runtime intercepts keyDown events for menu items that are inactive (10.4), // then set nonzero modifier masks for menu items with arrow key equivalents, // otherwise the arrow keys won't work on popup panels [self setupNonzeroModifierMasksForMenuItemsWithArrowKeyEquivalents]; } // Hotkeys [PPHotkeys setupGlobals]; [self updateMenuItemKeyEquivalentsForCurrentHotkeys]; [self setupPreviousWindowMenuItemKeyEquivalentFromLocalizedHotkey]; [self addAsObserverForPPHotkeysNotifications]; // Alpha-channel support [NSColor setIgnoresAlpha: NO]; // enable alpha-channel support & color panel opacity slider // Shared Color Panel [NSColorPanel ppSetupSharedColorPanel]; // Autosaving Delay [[NSDocumentController sharedDocumentController] setAutosavingDelay: kAutosaveDelay]; } - (BOOL) applicationShouldHandleReopen: (NSApplication *) sender hasVisibleWindows: (BOOL) flag { return NO; } #pragma mark NSWindow notifications - (void) addAsObserverForNSWindowNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNSWindowNotification_DidBecomeKey:) name: NSWindowDidBecomeKeyNotification object: nil]; } - (void) removeAsObserverForNSWindowNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSWindowDidBecomeKeyNotification object: nil]; } - (void) handleNSWindowNotification_DidBecomeKey: (NSNotification *) notification { [self updateMainMenuForWindow: [notification object]]; } #pragma mark PPHotkeys notifications - (void) addAsObserverForPPHotkeysNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPHotkeysNotification_UpdatedHotkeys:) name: PPHotkeysNotification_UpdatedHotkeys object: nil]; } - (void) removeAsObserverForPPHotkeysNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPHotkeysNotification_UpdatedHotkeys object: nil]; } - (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification { [self updateMenuItemKeyEquivalentsForCurrentHotkeys]; } #pragma mark Private methods - (void) updateMainMenuForWindow: (NSWindow *) window { bool windowIsPPDocumentWindow; NSString *pasteItemTitle; windowIsPPDocumentWindow = [window isKindOfClass: [PPDocumentWindow class]]; pasteItemTitle = (windowIsPPDocumentWindow) ? @"Paste as New Layer" : @"Paste"; if (![[_pasteMenuItem title] isEqualToString: pasteItemTitle]) { [_pasteMenuItem setTitle: pasteItemTitle]; } } - (void) updateMainMenuForCurrentKeyWindow { [self updateMainMenuForWindow: [self keyWindow]]; } - (void) updateMenuItemKeyEquivalentsForCurrentHotkeys { [_canvasDisplayModeMenuItem setKeyEquivalent: gHotkeys[kPPHotkeyType_SwitchCanvasViewMode]]; [_layerOperationTargetMenuItem setKeyEquivalent: gHotkeys[kPPHotkeyType_SwitchLayerOperationTarget]]; [_zoomInMenuItem setKeyEquivalent: gHotkeys[kPPHotkeyType_ZoomIn]]; [_zoomOutMenuItem setKeyEquivalent: gHotkeys[kPPHotkeyType_ZoomOut]]; [_zoomToFitMenuItem setKeyEquivalent: gHotkeys[kPPHotkeyType_ZoomToFit]]; [_toggleActivePanelsMenuItem setKeyEquivalent: gHotkeys[kPPHotkeyType_ToggleActivePanels]]; [_toggleColorPickerMenuItem setKeyEquivalent: gHotkeys[kPPHotkeyType_ToggleColorPickerPanel]]; } - (void) setupPreviousWindowMenuItemKeyEquivalentFromLocalizedHotkey { NSString *localizedBacktickKeyEquivalent; // The "Previous Window" menu item's key equivalent should be whichever localized key // occupies the position above the Tab key (which is used as the key equivalent for // "Next Window"); On US keyboards (default), it's the backtick (`) key // Verify the menu item's key equivalent is a modified backtick if (![[_previousWindowMenuItem keyEquivalent] isEqualToString: @"`"] || !([_previousWindowMenuItem keyEquivalentModifierMask] & kModifierKeyMask_RecognizedModifierKeys)) { goto ERROR; } localizedBacktickKeyEquivalent = [PPHotkeys localizedBacktickKeyEquivalent]; if (!localizedBacktickKeyEquivalent) goto ERROR; if (![localizedBacktickKeyEquivalent isEqualToString: @"`"]) { [_previousWindowMenuItem setKeyEquivalent: localizedBacktickKeyEquivalent]; } return; ERROR: return; } - (void) setupNonzeroModifierMasksForMenuItemsWithArrowKeyEquivalents { [_leftArrowKeyEquivalentMenuItem setKeyEquivalentModifierMask: kNonzeroModifierMaskForMenuItemsWithArrowKeyEquivalents]; [_rightArrowKeyEquivalentMenuItem setKeyEquivalentModifierMask: kNonzeroModifierMaskForMenuItemsWithArrowKeyEquivalents]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPBackgroundPattern.h0000644000076500000240000000405413234403416022206 0ustar joshstaff/* PPBackgroundPattern.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPBackgroundPatternType.h" #import "PPPresettablePatternProtocol.h" @interface PPBackgroundPattern : NSObject { PPBackgroundPatternType _patternType; int _patternSize; NSColor *_color1; NSColor *_color2; NSColor *_patternFillColor; NSString *_presetName; } + backgroundPatternOfType: (PPBackgroundPatternType) patternType patternSize: (int) patternSize color1: (NSColor *) color1 color2: (NSColor *) color2; - initWithPatternType: (PPBackgroundPatternType) patternType patternSize: (int) patternSize color1: (NSColor *) color1 color2: (NSColor *) color2; - (PPBackgroundPatternType) patternType; - (int) patternSize; - (NSColor *) color1; - (NSColor *) color2; - (NSColor *) patternFillColor; - (bool) isEqualToBackgroundPattern: (PPBackgroundPattern *) otherPattern; - (PPBackgroundPattern *) backgroundPatternScaledByFactor: (float) scalingFactor; - (NSData *) archivedData; + (PPBackgroundPattern *) backgroundPatternWithArchivedData: (NSData *) archivedData; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPBackgroundPattern.m0000644000076500000240000003113313234403205022205 0ustar joshstaff/* PPBackgroundPattern.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPBackgroundPattern.h" #import "PPDefines.h" #import "NSColor_PPUtilities.h" #define kBackgroundPatternCodingVersion_Current kBackgroundPatternCodingVersion_1 // Coding Version 1 // To allow sharing a .piko file between OS X & GNUstep, no longer encodes pattern colors // with -[NSColor ppColorData], because that method used NSArchiver, which writes in a // different format on each platform #define kBackgroundPatternCodingVersion_1 1 #define kBackgroundPatternCodingKey_CodingVersion @"CodingVersion" #define kBackgroundPatternCodingKey_PatternType kBackgroundPatternCodingKey_v0_PatternType #define kBackgroundPatternCodingKey_PatternSize kBackgroundPatternCodingKey_v0_PatternSize #define kBackgroundPatternCodingKey_Color1 @"PatternColor1" #define kBackgroundPatternCodingKey_Color2 @"PatternColor2" #define kBackgroundPatternCodingKey_PresetName kBackgroundPatternCodingKey_v0_PresetName // Coding Version 0 // Used in PikoPixel 1.0 beta4 & earlier #define kBackgroundPatternCodingVersion_0 0 #define kBackgroundPatternCodingKey_v0_PatternType @"PatternType" #define kBackgroundPatternCodingKey_v0_PatternSize @"PatternSize" #define kBackgroundPatternCodingKey_v0_Color1 @"Color1" #define kBackgroundPatternCodingKey_v0_Color2 @"Color2" #define kBackgroundPatternCodingKey_v0_PresetName @"PresetName" @interface PPBackgroundPattern (PrivateMethods) - (id) initWithCoder_v0: (NSCoder *) aDecoder; - (void) setupPatternFillColor; @end @implementation PPBackgroundPattern + backgroundPatternOfType: (PPBackgroundPatternType) patternType patternSize: (int) patternSize color1: (NSColor *) color1 color2: (NSColor *) color2 { return [[[self alloc] initWithPatternType: patternType patternSize: patternSize color1: color1 color2: color2] autorelease]; } - initWithPatternType: (PPBackgroundPatternType) patternType patternSize: (int) patternSize color1: (NSColor *) color1 color2: (NSColor *) color2 { self = [super init]; if (!self) goto ERROR; if (!PPBackgroundPatternType_IsValid(patternType) || (patternSize < kMinBackgroundPatternSize) || (patternSize > kMaxBackgroundPatternSize)) { goto ERROR; } if (!color2) { color2 = color1; } color1 = [color1 ppSRGBColor]; color2 = [color2 ppSRGBColor]; if (!color1 || !color2) { goto ERROR; } _patternType = patternType; _patternSize = patternSize; _color1 = [color1 retain]; _color2 = [color2 retain]; return self; ERROR: [self release]; return nil; } - init { return [self initWithPatternType: 0 patternSize: 0 color1: nil color2: nil]; } - (void) dealloc { [_color1 release]; [_color2 release]; [_patternFillColor release]; [_presetName release]; [super dealloc]; } - (PPBackgroundPatternType) patternType { return _patternType; } - (int) patternSize { return _patternSize; } - (NSColor *) color1 { return _color1; } - (NSColor *) color2 { return _color2; } - (NSColor *) patternFillColor { if (!_patternFillColor) { [self setupPatternFillColor]; } return _patternFillColor; } - (bool) isEqualToBackgroundPattern: (PPBackgroundPattern *) otherPattern { if (self == otherPattern) { return YES; } if (!otherPattern || (_patternType != [otherPattern patternType]) || (_patternSize != [otherPattern patternSize]) || (![_color1 ppIsEqualToColor: [otherPattern color1]]) || (![_color2 ppIsEqualToColor: [otherPattern color2]])) { return NO; } return YES; } - (PPBackgroundPattern *) backgroundPatternScaledByFactor: (float) scalingFactor { int scaledPatternSize = roundf(scalingFactor * _patternSize); if (scaledPatternSize > kMaxBackgroundPatternSize) { scaledPatternSize = kMaxBackgroundPatternSize; } else if (scaledPatternSize < kMinBackgroundPatternSize) { scaledPatternSize = kMinBackgroundPatternSize; } if (scaledPatternSize == _patternSize) { return [[self retain] autorelease]; } return [[self class] backgroundPatternOfType: _patternType patternSize: scaledPatternSize color1: _color1 color2: _color2]; } - (NSData *) archivedData { return [NSKeyedArchiver archivedDataWithRootObject: self]; } + (PPBackgroundPattern *) backgroundPatternWithArchivedData: (NSData *) archivedData { PPBackgroundPattern *pattern = [NSKeyedUnarchiver unarchiveObjectWithData: archivedData]; if (![pattern isKindOfClass: [PPBackgroundPattern class]]) { goto ERROR; } return pattern; ERROR: return nil; } #pragma mark NSCoding protocol - (id) initWithCoder: (NSCoder *) aDecoder { int codingVersion = [aDecoder decodeIntForKey: kBackgroundPatternCodingKey_CodingVersion]; if (codingVersion == kBackgroundPatternCodingVersion_0) { return [self initWithCoder_v0: aDecoder]; } self = [self initWithPatternType: [aDecoder decodeIntForKey: kBackgroundPatternCodingKey_PatternType] patternSize: [aDecoder decodeIntForKey: kBackgroundPatternCodingKey_PatternSize] color1: [aDecoder decodeObjectForKey: kBackgroundPatternCodingKey_Color1] color2: [aDecoder decodeObjectForKey: kBackgroundPatternCodingKey_Color2]]; if ([aDecoder containsValueForKey: kBackgroundPatternCodingKey_PresetName]) { [self setPresetName: [aDecoder decodeObjectForKey: kBackgroundPatternCodingKey_PresetName]]; } return self; } - (void) encodeWithCoder: (NSCoder *) coder { [coder encodeInt: kBackgroundPatternCodingVersion_Current forKey: kBackgroundPatternCodingKey_CodingVersion]; [coder encodeInt: _patternType forKey: kBackgroundPatternCodingKey_PatternType]; [coder encodeInt: _patternSize forKey: kBackgroundPatternCodingKey_PatternSize]; [coder encodeObject: _color1 forKey: kBackgroundPatternCodingKey_Color1]; [coder encodeObject: _color2 forKey: kBackgroundPatternCodingKey_Color2]; if (_presetName) { [coder encodeObject: _presetName forKey: kBackgroundPatternCodingKey_PresetName]; } } #if PP_DEPLOYMENT_TARGET_SUPPORTS_APPLE_NSARCHIVER_FORMAT - (id) initWithCoder_v0: (NSCoder *) aDecoder { NSData *color1Data, *color2Data; color1Data = [aDecoder decodeObjectForKey: kBackgroundPatternCodingKey_v0_Color1]; color2Data = [aDecoder decodeObjectForKey: kBackgroundPatternCodingKey_v0_Color2]; self = [self initWithPatternType: [aDecoder decodeIntForKey: kBackgroundPatternCodingKey_v0_PatternType] patternSize: [aDecoder decodeIntForKey: kBackgroundPatternCodingKey_v0_PatternSize] color1: [NSColor ppColorWithData_DEPRECATED: color1Data] color2: [NSColor ppColorWithData_DEPRECATED: color2Data]]; if ([aDecoder containsValueForKey: kBackgroundPatternCodingKey_v0_PresetName]) { [self setPresetName: [aDecoder decodeObjectForKey: kBackgroundPatternCodingKey_v0_PresetName]]; } return self; } /* - (void) encodeWithCoder_v0: (NSCoder *) coder { [coder encodeInt: _patternType forKey: kBackgroundPatternCodingKey_v0_PatternType]; [coder encodeInt: _patternSize forKey: kBackgroundPatternCodingKey_v0_PatternSize]; [coder encodeObject: [_color1 ppColorData_DEPRECATED] forKey: kBackgroundPatternCodingKey_v0_Color1]; [coder encodeObject: [_color2 ppColorData_DEPRECATED] forKey: kBackgroundPatternCodingKey_v0_Color2]; if (_presetName) { [coder encodeObject: _presetName forKey: kBackgroundPatternCodingKey_v0_PresetName]; } } */ #else // !PP_DEPLOYMENT_TARGET_SUPPORTS_APPLE_NSARCHIVER_FORMAT - (id) initWithCoder_v0: (NSCoder *) aDecoder { return [self init]; } #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_APPLE_NSARCHIVER_FORMAT #pragma mark NSCopying protocol - (id) copyWithZone: (NSZone *) zone { PPBackgroundPattern *copiedPattern; copiedPattern = [[[self class] allocWithZone: zone] initWithPatternType: _patternType patternSize: _patternSize color1: [[_color1 copyWithZone: zone] autorelease] color2: [[_color2 copyWithZone: zone] autorelease]]; if (_presetName) { [copiedPattern setPresetName: [[_presetName copyWithZone: zone] autorelease]]; } return copiedPattern; } #pragma mark PPPresettablePattern protocol - (void) setPresetName: (NSString *) presetName { [_presetName autorelease]; _presetName = [presetName retain]; } - (NSString *) presetName { return _presetName; } - (bool) isEqualToPresettablePattern: (id ) pattern { if ([pattern isKindOfClass: [self class]]) { return [self isEqualToBackgroundPattern: (PPBackgroundPattern *) pattern]; } return NO; } - (NSColor *) patternColorForPresettablePatternViewOfSize: (NSSize) viewSize { return [self patternFillColor]; } #pragma mark Private methods - (void) setupPatternFillColor { NSColor *patternFillColor; switch (_patternType) { case kPPBackgroundPatternType_DiagonalLines: { patternFillColor = [NSColor ppDiagonalLinePatternColorWithLineWidth: _patternSize color1: _color1 color2: _color2]; } break; case kPPBackgroundPatternType_IsometricLines: { patternFillColor = [NSColor ppIsometricLinePatternColorWithLineWidth: _patternSize color1: _color1 color2: _color2]; } break; case kPPBackgroundPatternType_Checkerboard: { patternFillColor = [NSColor ppCheckerboardPatternColorWithBoxDimension: _patternSize color1: _color1 color2: _color2]; } break; case kPPBackgroundPatternType_DiagonalCheckerboard: { patternFillColor = [NSColor ppDiagonalCheckerboardPatternColorWithBoxDimension: _patternSize color1: _color1 color2: _color2]; } break; case kPPBackgroundPatternType_IsometricCheckerboard: { patternFillColor = [NSColor ppIsometricCheckerboardPatternColorWithBoxDimension: _patternSize color1: _color1 color2: _color2]; } break; case kPPBackgroundPatternType_Solid: default: { patternFillColor = _color1; } break; } if (_patternFillColor) { [_patternFillColor release]; } _patternFillColor = [patternFillColor retain]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPBackgroundPatternPresets.h0000644000076500000240000000210513234403416023547 0ustar joshstaff/* PPBackgroundPatternPresets.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPatternPresets.h" @interface PPBackgroundPatternPresets : PPPatternPresets { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPBackgroundPatternPresets.m0000644000076500000240000000326113234403205023554 0ustar joshstaff/* PPBackgroundPatternPresets.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPBackgroundPatternPresets.h" #import "PPBackgroundPattern.h" #define kStoredBackgroundPatternPresetsFilename @"BackgroundPatternPresets" #define kBackgroundPatternPresetsFiletype @"pikopatr" @implementation PPBackgroundPatternPresets + sharedPresets { static PPBackgroundPatternPresets *sharedPresets = nil; if (!sharedPresets) { sharedPresets = [[self alloc] initWithPresettablePatternClass: [PPBackgroundPattern class] storedPresetsFilename: kStoredBackgroundPatternPresetsFilename presetsFiletype: kBackgroundPatternPresetsFiletype]; } return sharedPresets; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPBackgroundPatternType.h0000644000076500000240000000275413234403416023055 0ustar joshstaff/* PPBackgroundPatternType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPBackgroundPatternType_Solid, kPPBackgroundPatternType_DiagonalLines, kPPBackgroundPatternType_IsometricLines, kPPBackgroundPatternType_Checkerboard, kPPBackgroundPatternType_DiagonalCheckerboard, kPPBackgroundPatternType_IsometricCheckerboard, kNumPPBackgroundPatternTypes } PPBackgroundPatternType; static inline bool PPBackgroundPatternType_IsValid(PPBackgroundPatternType patternType) { return (((unsigned) patternType) < kNumPPBackgroundPatternTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPBitmapPixelTypes.h0000644000076500000240000000714513234403416022040 0ustar joshstaff/* PPBitmapPixelTypes.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Mask bitmap pixels #pragma mark Mask bitmap pixels typedef uint8_t PPMaskBitmapPixel; #define kMaskPixelValue_ON UINT8_MAX #define kMaskPixelValue_OFF 0 #define kMaskPixelValue_Threshold (UINT8_MAX >> 1) // Image bitmap pixels #pragma mark Image bitmap pixels typedef uint32_t PPImageBitmapPixel; typedef uint8_t PPImagePixelComponent; #define kMaxImagePixelComponentValue UINT8_MAX typedef enum { kPPImagePixelComponent_Red, kPPImagePixelComponent_Green, kPPImagePixelComponent_Blue, kPPImagePixelComponent_Alpha, kNumPPImagePixelComponents } PPImagePixelComponentType; #define macroImagePixelComponent(imagePixel, componentType) \ (((PPImagePixelComponent *) (imagePixel))[componentType]) #define macroImagePixelComponent_Red(imagePixel) \ macroImagePixelComponent(imagePixel, kPPImagePixelComponent_Red) #define macroImagePixelComponent_Green(imagePixel) \ macroImagePixelComponent(imagePixel, kPPImagePixelComponent_Green) #define macroImagePixelComponent_Blue(imagePixel) \ macroImagePixelComponent(imagePixel, kPPImagePixelComponent_Blue) #define macroImagePixelComponent_Alpha(imagePixel) \ macroImagePixelComponent(imagePixel, kPPImagePixelComponent_Alpha) // Linear RGB16 bitmap pixels #pragma mark Linear RGB16 bitmap pixels typedef uint64_t PPLinearRGB16BitmapPixel; typedef uint16_t PPLinear16PixelComponent; #define kMaxLinear16PixelComponentValue UINT16_MAX typedef enum { kPPLinearRGB16PixelComponent_Red, kPPLinearRGB16PixelComponent_Green, kPPLinearRGB16PixelComponent_Blue, kPPLinearRGB16PixelComponent_Alpha, kNumPPLinearRGB16PixelComponents } PPLinearRGB16PixelComponentType; #define macroLinearRGB16PixelComponent(linearPixel, componentType) \ (((PPLinear16PixelComponent *) (linearPixel))[componentType]) #define macroLinearRGB16PixelComponent_Red(linearPixel) \ macroLinearRGB16PixelComponent(linearPixel, kPPLinearRGB16PixelComponent_Red) #define macroLinearRGB16PixelComponent_Green(linearPixel) \ macroLinearRGB16PixelComponent(linearPixel, kPPLinearRGB16PixelComponent_Green) #define macroLinearRGB16PixelComponent_Blue(linearPixel) \ macroLinearRGB16PixelComponent(linearPixel, kPPLinearRGB16PixelComponent_Blue) #define macroLinearRGB16PixelComponent_Alpha(linearPixel) \ macroLinearRGB16PixelComponent(linearPixel, kPPLinearRGB16PixelComponent_Alpha) PikoPixel.Sources.1.0-b10b/PikoPixel/PPBuildEnvironmentMacros.h0000644000076500000240000001307113761241757023236 0ustar joshstaff/* PPBuildEnvironmentMacros.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Utility Macros for OS X #if defined(__APPLE__) # define _PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(DOT_VERSION) \ (defined(MAC_OS_X_VERSION_10_##DOT_VERSION) \ && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_##DOT_VERSION)) # define _PP_MAC_OS_X_DEPLOYMENT_TARGET_IS_AT_LEAST_10_(DOT_VERSION) \ (defined(MAC_OS_X_VERSION_10_##DOT_VERSION) \ && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_##DOT_VERSION)) #endif // defined(__APPLE__) // SDK Macros #if defined(__APPLE__) # define PP_SDK_ALLOWS_NONASCII_STRING_LITERALS (true) # define PP_SDK_DEPRECATED_NSMENUITEM_PROTOCOL (true) # define PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES \ (_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(6)) # define PP_SDK_HAS_NSWINDOW_SETCOLORSPACE_METHOD \ (_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(6)) # define PP_SDK_HAS_NSIMAGEREP_DRAWINRECTFROMRECT_METHOD \ (_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(6)) # define PP_SDK_HAS_NSWINDOWANIMATION \ (_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(7)) # define PP_SDK_HAS_BACKINGSCALEFACTOR_METHODS \ (_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(7)) # define PP_SDK_HAS_NSWINDOWSTYLEMASK_TYPE \ (_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(12)) #elif defined(GNUSTEP) // !defined(__APPLE__) # define PP_SDK_ALLOWS_NONASCII_STRING_LITERALS (false) # define PP_SDK_DEPRECATED_NSMENUITEM_PROTOCOL (false) # define PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES (true) # define PP_SDK_HAS_NSWINDOW_SETCOLORSPACE_METHOD (false) # define PP_SDK_HAS_NSIMAGEREP_DRAWINRECTFROMRECT_METHOD (true) # define PP_SDK_HAS_NSWINDOWANIMATION (false) # define PP_SDK_HAS_BACKINGSCALEFACTOR_METHODS (false) # define PP_SDK_HAS_NSWINDOWSTYLEMASK_TYPE (false) #endif // defined(GNUSTEP) // Deployment Target Macros #if defined(__APPLE__) # define PP_DEPLOYMENT_TARGET_DEPRECATED_CREATEDIRECTORYATPATHATTRIBUTES \ (_PP_MAC_OS_X_DEPLOYMENT_TARGET_IS_AT_LEAST_10_(5)) # define PP_DEPLOYMENT_TARGET_DEPRECATED_REMOVEFILEATPATHHANDLER \ (_PP_MAC_OS_X_DEPLOYMENT_TARGET_IS_AT_LEAST_10_(5)) # define PP_DEPLOYMENT_TARGET_SUPPORTS_CARBON (true) # define PP_DEPLOYMENT_TARGET_SUPPORTS_COLOR_MANAGEMENT (true) # define PP_DEPLOYMENT_TARGET_DEPRECATED_KEYBOARDLAYOUT \ (_PP_MAC_OS_X_DEPLOYMENT_TARGET_IS_AT_LEAST_10_(5)) # define PP_DEPLOYMENT_TARGET_SUPPORTS_APPLE_NSARCHIVER_FORMAT (true) # define PP_DEPLOYMENT_TARGET_NSEVENT_DELTAY_RETURNS_FLIPPED_COORDINATE (true) # define PP_DEPLOYMENT_TARGET_INCORRECTLY_FILLS_PIXEL_CENTERED_RECTS (false) # define PP_DEPLOYMENT_TARGET_ALLOWS_SYSTEM_INTERCEPTION_OF_COMMAND_KEY (false) # define PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY !defined(__ppc__) #elif defined(GNUSTEP) // !defined(__APPLE__) # define PP_DEPLOYMENT_TARGET_DEPRECATED_CREATEDIRECTORYATPATHATTRIBUTES (false) # define PP_DEPLOYMENT_TARGET_DEPRECATED_REMOVEFILEATPATHHANDLER (false) # define PP_DEPLOYMENT_TARGET_SUPPORTS_CARBON (false) # define PP_DEPLOYMENT_TARGET_SUPPORTS_COLOR_MANAGEMENT (false) # define PP_DEPLOYMENT_TARGET_DEPRECATED_KEYBOARDLAYOUT (false) # define PP_DEPLOYMENT_TARGET_SUPPORTS_APPLE_NSARCHIVER_FORMAT (false) # define PP_DEPLOYMENT_TARGET_NSEVENT_DELTAY_RETURNS_FLIPPED_COORDINATE (false) # define PP_DEPLOYMENT_TARGET_INCORRECTLY_FILLS_PIXEL_CENTERED_RECTS (true) # define PP_DEPLOYMENT_TARGET_ALLOWS_SYSTEM_INTERCEPTION_OF_COMMAND_KEY (true) # define PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY (false) #endif // defined(GNUSTEP) PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView.h0000644000076500000240000002666613717372553020671 0ustar joshstaff/* PPCanvasView.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPGridType.h" #import "PPDocumentTypes.h" #import "PPBitmapPixelTypes.h" @class PPGridPattern; @interface PPCanvasView : NSView { NSBitmapImageRep *_canvasBitmap; float _zoomFactor; float _inverseZoomFactor; NSPoint _canvasDrawingOffset; NSRect _canvasFrame; NSRect _zoomedCanvasFrame; NSRect _offsetZoomedCanvasFrame; NSRect _clipViewVisibleRect; NSRect _visibleCanvasBounds; NSRect _zoomedVisibleCanvasBounds; NSRect _offsetZoomedVisibleCanvasBounds; NSSize _zoomedVisibleImagesSize; NSBitmapImageRep *_zoomedVisibleCanvasBitmap; NSImage *_zoomedVisibleCanvasImage; NSBitmapImageRep *_zoomedVisibleBackgroundBitmap; NSImage *_zoomedVisibleBackgroundImage; NSImage *_backgroundImage; NSColor *_backgroundColor; #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY NSBitmapImageRep *_retinaDisplayBuffer; #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY PPGridType _gridType; PPImageBitmapPixel _gridColorPixelValue; NSSize _gridGuidelineSpacingSize; PPImageBitmapPixel _gridGuidelineColorPixelValue; NSPoint _gridGuidelinesTopLeftPhase; NSBezierPath *_selectionOutlineTopRightPath; NSBezierPath *_selectionOutlineBottomLeftPath; NSBezierPath *_selectionOutlineRightEdgePath; NSBezierPath *_selectionOutlineBottomEdgePath; NSBezierPath *_zoomedSelectionOutlineTopRightPath; NSBezierPath *_zoomedSelectionOutlineBottomLeftPath; NSRect _zoomedSelectionOutlineDisplayBounds; NSTimer *_selectionOutlineAnimationTimer; NSPoint _selectionOutlineTopRightAnimationPhase; NSPoint _selectionOutlineBottomLeftAnimationPhase; NSBezierPath *_selectionToolOverlayPath_Working; NSBezierPath *_selectionToolOverlayPath_AddFill; NSBezierPath *_selectionToolOverlayPath_SubtractFill; NSBezierPath *_selectionToolOverlayPath_ToolPath; NSBezierPath *_selectionToolOverlayPath_Outline; NSBitmapImageRep *_selectionToolOverlayWorkingMask; NSBitmapImageRep *_selectionToolOverlayWorkingPathMask; NSTimer *_selectionToolOverlayAnimationTimer; NSDate *_selectionToolOverlayAnimationStartDate; NSPoint _selectionToolOverlayAnimationPhase; NSRect _selectionToolOverlayDisplayBounds; NSBezierPath *_eraserToolOverlayPath_Outline; NSRect _eraserToolOverlayDisplayBounds; NSBezierPath *_fillToolOverlayPath_Fill; NSBezierPath *_fillToolOverlayPath_Outline; NSRect _fillToolOverlayDisplayBounds; NSColor *_fillToolOverlayPatternColor; NSPoint _fillToolOverlayPatternPhase; NSRect _magnifierToolOverlayRect; NSBezierPath *_magnifierToolOverlayRectPath; NSBezierPath *_colorRampToolOverlayPath_Outline; NSBezierPath *_colorRampToolOverlayPath_XMarks; NSRect _colorRampToolOverlayDisplayBounds; NSPoint _matchToolToleranceIndicatorOrigin; unsigned _matchToolToleranceIndicatorRadius; NSBezierPath *_matchToolToleranceIndicatorPath; NSRect _matchToolToleranceIndicatorDisplayBounds; NSCursor *_toolCursor; NSRect _viewBoundsTrackingRect; NSTrackingRectTag _viewBoundsTrackingRectTag; NSRect _visibleCanvasTrackingRect; NSTrackingRectTag _visibleCanvasTrackingRectTag; NSTimer *_autoscrollRepeatTimer; NSEvent *_autoscrollMouseDraggedEvent; int _zoomedImagesDrawMode; bool _shouldDisplayDocumentLayers; bool _shouldDisplayGrid; bool _shouldDisplayGridGuidelines; bool _shouldDisplayBackgroundImage; bool _shouldSmoothenBackgroundImage; bool _disallowBackgroundImageSmoothingForScrolling; bool _shouldDisplaySelectionToolOverlay; bool _shouldDisplayEraserToolOverlay; bool _shouldDisplayFillToolOverlay; bool _shouldDisplayMagnifierToolOverlay; bool _shouldDisplayColorRampToolOverlay; bool _shouldDisplayMatchToolToleranceIndicator; bool _backgroundImageIsOpaque; bool _isDraggingTool; bool _allowSkippingOfMouseDraggedEvents; bool _autoscrollingIsEnabled; bool _isAutoscrolling; bool _isScrolling; bool _mouseIsInsideVisibleCanvasTrackingRect; bool _disallowMouseTracking; bool _hasSelectionOutline; bool _shouldHideSelectionOutline; bool _shouldAnimateSelectionOutline; #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY bool _currentDisplayIsRetina; #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY } - (void) setCanvasBitmap: (NSBitmapImageRep *) canvasBitmap; - (void) setBackgroundImage: (NSImage *) backgroundImage backgroundImageVisibility: (bool) shouldDisplayBackgroundImage backgroundImageSmoothing: (bool) shouldSmoothenBackgroundImage backgroundColor: (NSColor *) backgroundColor; - (void) setBackgroundImage: (NSImage *) backgroundImage; - (void) setBackgroundImageVisibility: (bool) shouldDisplayBackgroundImage; - (void) setBackgroundImageSmoothing: (bool) shouldSmoothenBackgroundImage; - (void) setBackgroundColor: (NSColor *) backgroundColor; - (void) disableBackgroundImageSmoothingForScrollingBegin; - (void) updateBackgroundImageSmoothingForScrollingEnd; - (void) setGridPattern: (PPGridPattern *) gridPattern gridVisibility: (bool) shouldDisplayGrid; - (void) setDocumentLayersVisibility: (bool) shouldDisplayDocumentLayers; - (bool) documentLayersAreHidden; - (void) handleUpdateToCanvasBitmapInRect: (NSRect) updateRect; - (NSRect) normalizedVisibleBounds; - (NSPoint) imagePointAtCenterOfVisibleCanvas; - (void) centerEnclosingScrollViewAtImagePoint: (NSPoint) centerPoint; - (bool) windowPointIsInsideVisibleCanvas: (NSPoint) windowPoint; - (NSPoint) imagePointFromViewPoint: (NSPoint) viewPoint clippedToCanvasBounds: (bool) shouldClipToCanvasBounds; - (NSPoint) viewPointClippedToCanvasBounds: (NSPoint) viewPoint; - (float) zoomFactor; - (void) setZoomFactor: (float) zoomFactor; - (bool) canIncreaseZoomFactor; - (void) increaseZoomFactor; - (bool) canDecreaseZoomFactor; - (void) decreaseZoomFactor; - (void) setZoomToFitCanvas; - (void) setZoomToFitViewRect: (NSRect) rect; - (void) setIsDraggingTool: (bool) isDraggingTool; - (void) enableSkippingOfMouseDraggedEvents: (bool) allowSkippingOfMouseDraggedEvents; @end @interface PPCanvasView (SelectionOutline) + (void) initializeSelectionOutline; - (bool) initSelectionOutlineMembers; - (void) deallocSelectionOutlineMembers; - (void) setSelectionOutlineToMask: (NSBitmapImageRep *) selectionMask maskBounds: (NSRect) maskBounds; - (void) setShouldHideSelectionOutline: (bool) shouldHideSelectionOutline; - (void) setShouldAnimateSelectionOutline: (bool) shouldAnimateSelectionOutline; - (void) updateSelectionOutlineForCurrentVisibleCanvas; - (void) drawSelectionOutline; @end @interface PPCanvasView (SelectionToolOverlay) + (void) initializeSelectionToolOverlay; - (bool) initSelectionToolOverlayMembers; - (void) deallocSelectionToolOverlayMembers; - (bool) resizeSelectionToolOverlayMasksToSize: (NSSize) size; - (void) setSelectionToolOverlayToRect: (NSRect) rect selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask toolPathRect: (NSRect) toolPathRect; - (void) setSelectionToolOverlayToPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask; - (void) setSelectionToolOverlayToMask: (NSBitmapImageRep *) maskBitmap maskBounds: (NSRect) maskBounds selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask; - (void) clearSelectionToolOverlay; - (void) drawSelectionToolOverlay; @end @interface PPCanvasView (EraserToolOverlay) + (void) initializeEraserToolOverlay; - (bool) initEraserToolOverlayMembers; - (void) deallocEraserToolOverlayMembers; - (void) setEraserToolOverlayToMask: (NSBitmapImageRep *) maskBitmap maskBounds: (NSRect) maskBounds; - (void) clearEraserToolOverlay; - (void) drawEraserToolOverlay; @end @interface PPCanvasView (FillToolOverlay) + (void) initializeFillToolOverlay; - (bool) initFillToolOverlayMembers; - (void) deallocFillToolOverlayMembers; - (void) beginFillToolOverlayForOperationTarget: (PPLayerOperationTarget) operationTarget fillColor: (NSColor *) flllColor; - (void) setFillToolOverlayToMask: (NSBitmapImageRep *) maskBitmap maskBounds: (NSRect) maskBounds; - (void) endFillToolOverlay; - (void) drawFillToolOverlay; @end @interface PPCanvasView (MagnifierToolOverlay) + (void) initializeMagnifierToolOverlay; - (bool) initMagnifierToolOverlayMembers; - (void) deallocMagnifierToolOverlayMembers; - (void) setMagnifierToolOverlayToViewRect: (NSRect) rect; - (void) clearMagnifierToolOverlay; - (void) drawMagnifierToolOverlay; @end @interface PPCanvasView (ColorRampToolOverlay) + (void) initializeColorRampToolOverlay; - (bool) initColorRampToolOverlayMembers; - (void) deallocColorRampToolOverlayMembers; - (void) setColorRampToolOverlayToMask: (NSBitmapImageRep *) maskBitmap maskBounds: (NSRect) maskBounds; - (void) clearColorRampToolOverlay; - (void) drawColorRampToolOverlay; @end @interface PPCanvasView (MatchToolToleranceIndicator) + (void) initializeMatchToolToleranceIndicator; - (bool) initMatchToolToleranceIndicatorMembers; - (void) deallocMatchToolToleranceIndicatorMembers; - (void) showMatchToolToleranceIndicatorAtViewPoint: (NSPoint) viewPoint; - (void) hideMatchToolToleranceIndicator; - (void) setMatchToolToleranceIndicatorRadius: (unsigned) radius; - (void) drawMatchToolToleranceIndicator; @end @interface PPCanvasView (MouseCursor) - (void) setToolCursor: (NSCursor *) toolCursor; - (void) updateCursor; - (void) updateCursorForWindowPoint: (NSPoint) windowPoint; - (void) updateCursorForCurrentMouseLocation; @end @interface PPCanvasView (Autoscrolling) - (void) enableAutoscrolling: (bool) shouldEnableAutoscrolling; - (bool) isAutoscrolling; - (void) autoscrollHandleMouseDraggedEvent: (NSEvent *) event; - (void) autoscrollStop; @end #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY @interface PPCanvasView (RetinaDrawing) - (void) setupRetinaDrawingForCurrentDisplay; - (void) setupRetinaDrawingForResizedView; - (void) destroyRetinaDrawingMembers; - (void) beginDrawingToRetinaDisplayBufferInRect: (NSRect) rect; - (void) finishDrawingToRetinaDisplayBufferInRect: (NSRect) rect; @end #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY extern NSString *PPCanvasViewNotification_ChangedZoomFactor; extern NSString *PPCanvasViewNotification_UpdatedNormalizedVisibleBounds; PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView.m0000644000076500000240000012756413735746661020702 0ustar joshstaff/* PPCanvasView.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "PPCanvasView_Notifications.h" #import "PPGridPattern.h" #import "PPGeometry.h" #import "NSImage_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "PPUserDefaults.h" #import "PPDefines.h" #import "NSObject_PPUtilities.h" #import "PPCursorManager.h" #import "PPPanelsController.h" #import "PPPopupPanelsController.h" #import "NSWindow_PPUtilities.h" #import "NSEvent_PPUtilities.h" #import "PPSRGBUtilities.h" typedef enum { kPPZoomedImagesDrawMode_Normal, kPPZoomedImagesDrawMode_DisallowDrawing, kPPZoomedImagesDrawMode_ForceRedraw } PPZoomedImagesDrawMode; #define kTimeDelayForImageSmoothingRefreshAfterScrollingEnds (0.25f) static bool gRuntimeRoundsOffSubpixelMouseCoordinates = NO, gShouldDrawDirectlyToZoomedVisibleBackgroundImage = NO; @interface PPCanvasView (PrivateMethods) - (void) addAsObserverForNSWindowNotifications; - (void) removeAsObserverForNSWindowNotifications; - (void) handleNSWindowNotifications_DidBecomeOrResignKey: (NSNotification *) notification; - (void) addAsObserverForNotificationsFromNSClipView: (NSClipView *) clipView; - (void) removeAsObserverForNotificationsFromNSClipView: (NSClipView *) clipView; - (void) handleNSClipViewNotifications_FrameOrBoundsDidChange: (NSNotification *) notification; - (NSClipView *) enclosingClipView; - (void) updateFrameForEnclosingClipView: (NSClipView *) clipView; - (void) setCanvasSize: (NSSize) canvasSize; - (void) setZoomFactor: (float) zoomFactor forceRedrawIfZoomFactorUnchanged: (bool) forceRedraw centerRedrawnImagesAtPoint: (NSPoint) centerPoint; - (float) zoomFactorToFitCanvasSize: (NSSize) canvasSize; - (void) repositionVisibleImages; - (void) repositionVisibleBoundingRects; - (void) resizeVisibleImages; - (void) setupGridGuidelinesPhaseForVisibleCanvas; - (void) updateVisibleCanvasInRect: (NSRect) canvasUpdateRect; - (void) recacheZoomedVisibleCanvasImageInBounds: (NSRect) bounds; - (void) updateVisibleBackground; - (void) setupMouseTracking; - (void) handleScrollingBegin; - (void) handleScrollingEnd; - (void) performDelayedUpdateOfBackgroundImageSmoothingForScrollingEnd; - (void) makeWindowKeyIfMain; @end @implementation PPCanvasView + (void) load { gRuntimeRoundsOffSubpixelMouseCoordinates = (PP_RUNTIME_CHECK__RUNTIME_ROUNDS_OFF_SUBPIXEL_MOUSE_COORDINATES) ? YES : NO; gShouldDrawDirectlyToZoomedVisibleBackgroundImage = (PP_RUNTIME_CHECK__DRAWING_TO_IMAGES_IS_FASTER_THAN_DRAWING_TO_BITMAPS) ? YES : NO; } + (void) initialize { if ([self class] != [PPCanvasView class]) { return; } [self initializeSelectionOutline]; [self initializeSelectionToolOverlay]; [self initializeEraserToolOverlay]; [self initializeFillToolOverlay]; [self initializeMagnifierToolOverlay]; [self initializeColorRampToolOverlay]; [self initializeMatchToolToleranceIndicator]; } - (id) initWithFrame: (NSRect) frame { self = [super initWithFrame: frame]; if (!self) goto ERROR; if (![self initSelectionOutlineMembers] || ![self initSelectionToolOverlayMembers] || ![self initEraserToolOverlayMembers] || ![self initFillToolOverlayMembers] || ![self initMagnifierToolOverlayMembers] || ![self initColorRampToolOverlayMembers] || ![self initMatchToolToleranceIndicatorMembers]) { goto ERROR; } [self setZoomFactor: kMinCanvasZoomFactor]; _shouldDisplayDocumentLayers = YES; return self; ERROR: return nil; } - (void) dealloc { [self removeAsObserverForNSWindowNotifications]; [self removeAsObserverForNotificationsFromNSClipView: nil]; [_canvasBitmap release]; [_zoomedVisibleCanvasBitmap release]; [_zoomedVisibleCanvasImage release]; [_zoomedVisibleBackgroundBitmap release]; [_zoomedVisibleBackgroundImage release]; [_backgroundImage release]; [_backgroundColor release]; #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY [self destroyRetinaDrawingMembers]; #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY [self deallocSelectionOutlineMembers]; [self deallocSelectionToolOverlayMembers]; [self deallocEraserToolOverlayMembers]; [self deallocFillToolOverlayMembers]; [self deallocMagnifierToolOverlayMembers]; [self deallocColorRampToolOverlayMembers]; [self deallocMatchToolToleranceIndicatorMembers]; [_toolCursor release]; // _autoscrollRepeatTimer must be nil, otherwise this canvasView would not be deallocating, // because it would be retained as the timer's target [_autoscrollMouseDraggedEvent release]; [super dealloc]; } - (void) setCanvasBitmap: (NSBitmapImageRep *) canvasBitmap { NSSize canvasBitmapSize; if (!canvasBitmap || (_canvasBitmap == canvasBitmap)) { return; } [_canvasBitmap release]; _canvasBitmap = [canvasBitmap retain]; canvasBitmapSize = [canvasBitmap ppSizeInPixels]; if (!NSEqualSizes(_canvasFrame.size, canvasBitmapSize)) { [self setCanvasSize: canvasBitmapSize]; } else { [self handleUpdateToCanvasBitmapInRect: _canvasFrame]; } } - (void) setBackgroundImage: (NSImage *) backgroundImage backgroundImageVisibility: (bool) shouldDisplayBackgroundImage backgroundImageSmoothing: (bool) shouldSmoothenBackgroundImage backgroundColor: (NSColor *) backgroundColor { bool shouldUpdateVisibleBackground = NO; // background image if (_backgroundImage != backgroundImage) { [_backgroundImage release]; _backgroundImage = [backgroundImage retain]; _backgroundImageIsOpaque = [_backgroundImage ppIsOpaque]; shouldUpdateVisibleBackground = YES; } // background image visibility shouldDisplayBackgroundImage = (shouldDisplayBackgroundImage) ? YES : NO; if (_shouldDisplayBackgroundImage != shouldDisplayBackgroundImage) { _shouldDisplayBackgroundImage = shouldDisplayBackgroundImage; if (_backgroundImage) { shouldUpdateVisibleBackground = YES; } } // background image smoothing shouldSmoothenBackgroundImage = (shouldSmoothenBackgroundImage) ? YES : NO; if (_shouldSmoothenBackgroundImage != shouldSmoothenBackgroundImage) { _shouldSmoothenBackgroundImage = shouldSmoothenBackgroundImage; if (_backgroundImage) { shouldUpdateVisibleBackground = YES; } } // background color if (!backgroundColor) { backgroundColor = [NSColor whiteColor]; } if (_backgroundColor != backgroundColor) { [_backgroundColor release]; _backgroundColor = [backgroundColor retain]; shouldUpdateVisibleBackground = YES; } // update visible background if (shouldUpdateVisibleBackground) { [self updateVisibleBackground]; } } - (void) setBackgroundImage: (NSImage *) backgroundImage { if (_backgroundImage == backgroundImage) { return; } [_backgroundImage release]; _backgroundImage = [backgroundImage retain]; _backgroundImageIsOpaque = [_backgroundImage ppIsOpaque]; [self updateVisibleBackground]; } - (void) setBackgroundImageVisibility: (bool) shouldDisplayBackgroundImage { shouldDisplayBackgroundImage = (shouldDisplayBackgroundImage) ? YES : NO; if (_shouldDisplayBackgroundImage == shouldDisplayBackgroundImage) { return; } _shouldDisplayBackgroundImage = shouldDisplayBackgroundImage; if (_backgroundImage) { [self updateVisibleBackground]; } } - (void) setBackgroundImageSmoothing: (bool) shouldSmoothenBackgroundImage { shouldSmoothenBackgroundImage = (shouldSmoothenBackgroundImage) ? YES : NO; if (_shouldSmoothenBackgroundImage == shouldSmoothenBackgroundImage) { return; } _shouldSmoothenBackgroundImage = shouldSmoothenBackgroundImage; if (_backgroundImage) { [self updateVisibleBackground]; } } - (void) setBackgroundColor: (NSColor *) backgroundColor { if (!backgroundColor) { backgroundColor = [NSColor whiteColor]; } if (_backgroundColor == backgroundColor) { return; } [_backgroundColor release]; _backgroundColor = [backgroundColor retain]; [self updateVisibleBackground]; } - (void) disableBackgroundImageSmoothingForScrollingBegin { _disallowBackgroundImageSmoothingForScrolling = YES; } - (void) updateBackgroundImageSmoothingForScrollingEnd { if (_isScrolling || _isAutoscrolling || !_disallowBackgroundImageSmoothingForScrolling) { return; } _disallowBackgroundImageSmoothingForScrolling = NO; if (_backgroundImage && _shouldDisplayBackgroundImage && _shouldSmoothenBackgroundImage) { [self updateVisibleBackground]; } } - (void) setGridPattern: (PPGridPattern *) gridPattern gridVisibility: (bool) shouldDisplayGrid { if (!gridPattern) { gridPattern = [PPUserDefaults gridPattern]; } _gridType = [gridPattern pixelGridType]; _gridColorPixelValue = [[gridPattern pixelGridColor] ppImageBitmapPixelValue]; _gridGuidelineSpacingSize = [gridPattern guidelineSpacingSize]; _gridGuidelineColorPixelValue = [[gridPattern guidelineColor] ppImageBitmapPixelValue]; _shouldDisplayGrid = (shouldDisplayGrid) ? YES : NO; _shouldDisplayGridGuidelines = ([gridPattern shouldDisplayGuidelines]) ? YES : NO; [self updateVisibleCanvasInRect: _visibleCanvasBounds]; } - (void) setDocumentLayersVisibility: (bool) shouldDisplayDocumentLayers { shouldDisplayDocumentLayers = (shouldDisplayDocumentLayers) ? YES : NO; if (shouldDisplayDocumentLayers == _shouldDisplayDocumentLayers) { return; } _shouldDisplayDocumentLayers = shouldDisplayDocumentLayers; [self updateVisibleCanvasInRect: _visibleCanvasBounds]; } - (bool) documentLayersAreHidden { return (_shouldDisplayDocumentLayers) ? NO : YES; } - (void) handleUpdateToCanvasBitmapInRect: (NSRect) updateRect { [self updateVisibleCanvasInRect: updateRect]; } - (NSRect) normalizedVisibleBounds { NSRect visibleBounds; if (NSIsEmptyRect(_zoomedCanvasFrame)) { goto ERROR; } visibleBounds = [[[self enclosingScrollView] contentView] bounds]; visibleBounds = NSIntersectionRect(visibleBounds, _zoomedCanvasFrame); return NSMakeRect(visibleBounds.origin.x / _zoomedCanvasFrame.size.width, visibleBounds.origin.y / _zoomedCanvasFrame.size.height, visibleBounds.size.width / _zoomedCanvasFrame.size.width, visibleBounds.size.height / _zoomedCanvasFrame.size.height); ERROR: return NSZeroRect; } - (NSPoint) imagePointAtCenterOfVisibleCanvas { NSPoint centerPoint; centerPoint.x = (_clipViewVisibleRect.origin.x + _clipViewVisibleRect.size.width / 2.0f - _canvasDrawingOffset.x) * _inverseZoomFactor; centerPoint.y = (_clipViewVisibleRect.origin.y + _clipViewVisibleRect.size.height / 2.0f - _canvasDrawingOffset.y) * _inverseZoomFactor; return centerPoint; } - (void) centerEnclosingScrollViewAtImagePoint: (NSPoint) centerPoint { NSClipView *clipView; NSSize clipViewSize; NSPoint originPoint; clipView = [self enclosingClipView]; if (!clipView) return; clipViewSize = [clipView bounds].size; originPoint.x = roundf(centerPoint.x * _zoomFactor + _canvasDrawingOffset.x - clipViewSize.width / 2.0f); originPoint.y = roundf(centerPoint.y * _zoomFactor + _canvasDrawingOffset.y - clipViewSize.height / 2.0f); [self scrollPoint: originPoint]; // NSView's scrollPoint: method can set the cursor to an arrow, so restore it if necessary [[PPCursorManager sharedManager] refreshCursorIfNeeded]; } - (bool) windowPointIsInsideVisibleCanvas: (NSPoint) windowPoint { NSPoint viewPoint = [self convertPoint: windowPoint fromView: nil]; bool viewPointIsInsideVisibleCanvasRect = (NSPointInRect(viewPoint, _visibleCanvasTrackingRect)) ? YES : NO; // On OS X versions that round off mouse coordinates (10.7 & earlier), points touching the // edge of the tracking rect can end up on the wrong side after rounding, causing the // wrong cursor to be set, so if the point touches the tracking rect's edge, use the latest // tracking state (_mouseIsInsideVisibleCanvasTrackingRect) instead of the coordinate // check (NSPointInRect()) if (gRuntimeRoundsOffSubpixelMouseCoordinates && (viewPointIsInsideVisibleCanvasRect != _mouseIsInsideVisibleCanvasTrackingRect) && PPGeometry_PointTouchesEdgePixelOfRect(viewPoint, _visibleCanvasTrackingRect)) { viewPointIsInsideVisibleCanvasRect = _mouseIsInsideVisibleCanvasTrackingRect; } return viewPointIsInsideVisibleCanvasRect; } - (NSPoint) imagePointFromViewPoint: (NSPoint) viewPoint clippedToCanvasBounds: (bool) shouldClipToCanvasBounds; { NSPoint imagePoint; imagePoint.x = floorf((viewPoint.x - _canvasDrawingOffset.x) * _inverseZoomFactor); imagePoint.y = floorf((viewPoint.y - _canvasDrawingOffset.y) * _inverseZoomFactor); if (shouldClipToCanvasBounds) { imagePoint = PPGeometry_PointClippedToRect(imagePoint, _canvasFrame); } return imagePoint; } - (NSPoint) viewPointClippedToCanvasBounds: (NSPoint) viewPoint { return PPGeometry_PointClippedToRect(viewPoint, _offsetZoomedCanvasFrame); } - (float) zoomFactor { return _zoomFactor; } - (void) setZoomFactor: (float) zoomFactor { if (_isDraggingTool) return; [self setZoomFactor: zoomFactor forceRedrawIfZoomFactorUnchanged: NO centerRedrawnImagesAtPoint: [self imagePointAtCenterOfVisibleCanvas]]; } - (bool) canIncreaseZoomFactor { return (_zoomFactor < kMaxCanvasZoomFactor) ? YES : NO; } - (void) increaseZoomFactor { [self setZoomFactor: _zoomFactor + 1.0f]; } - (bool) canDecreaseZoomFactor { return (_zoomFactor > kMinCanvasZoomFactor) ? YES : NO; } - (void) decreaseZoomFactor { [self setZoomFactor: _zoomFactor - 1.0f]; } - (void) setZoomToFitCanvas { [self setZoomFactor: [self zoomFactorToFitCanvasSize: _canvasFrame.size]]; } - (void) setZoomToFitViewRect: (NSRect) rect { NSSize viewSize; NSPoint imageCenterPoint; float zoomFactor; rect = NSIntersectionRect(rect, _offsetZoomedCanvasFrame); if (NSIsEmptyRect(rect)) { return; } viewSize = _clipViewVisibleRect.size; if (PPGeometry_IsZeroSize(viewSize)) { return; } imageCenterPoint = [self imagePointFromViewPoint: NSMakePoint(rect.origin.x + rect.size.width / 2.0f, rect.origin.y + rect.size.height / 2.0f) clippedToCanvasBounds: YES]; zoomFactor = floorf(MIN(viewSize.width / rect.size.width, viewSize.height / rect.size.height) * _zoomFactor); [self setZoomFactor: zoomFactor forceRedrawIfZoomFactorUnchanged: YES centerRedrawnImagesAtPoint: imageCenterPoint]; } - (void) setIsDraggingTool: (bool) isDraggingTool { _isDraggingTool = (isDraggingTool) ? YES : NO; [self updateCursor]; } - (void) enableSkippingOfMouseDraggedEvents: (bool) allowSkippingOfMouseDraggedEvents { _allowSkippingOfMouseDraggedEvents = (allowSkippingOfMouseDraggedEvents) ? YES : NO; } #pragma mark NSView overrides - (void) viewDidMoveToWindow { [super viewDidMoveToWindow]; [[self window] ppSetSRGBColorSpace]; [self addAsObserverForNSWindowNotifications]; } - (void) viewDidMoveToSuperview { NSClipView *enclosingClipView; [super viewDidMoveToSuperview]; enclosingClipView = [self enclosingClipView]; [self updateFrameForEnclosingClipView: enclosingClipView]; [self addAsObserverForNotificationsFromNSClipView: enclosingClipView]; #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(setupRetinaDrawingForCurrentDisplay)]; #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY } - (void) removeFromSuperview { [self removeAsObserverForNotificationsFromNSClipView: nil]; [super removeFromSuperview]; } - (void) drawRect: (NSRect) rect { NSRect sourceRect; if (_zoomedImagesDrawMode == kPPZoomedImagesDrawMode_DisallowDrawing) { return; } rect = NSIntersectionRect(rect, _offsetZoomedVisibleCanvasBounds); if (NSIsEmptyRect(rect)) { return; } #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY if (_retinaDisplayBuffer) { [self beginDrawingToRetinaDisplayBufferInRect: rect]; } #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationNone]; sourceRect.origin = NSMakePoint(rect.origin.x - _offsetZoomedVisibleCanvasBounds.origin.x, rect.origin.y - _offsetZoomedVisibleCanvasBounds.origin.y); sourceRect.size = rect.size; [_zoomedVisibleBackgroundImage drawInRect: rect fromRect: sourceRect operation: NSCompositeCopy fraction: 1.0f]; if (_shouldDisplayDocumentLayers) { [_zoomedVisibleCanvasImage drawInRect: rect fromRect: sourceRect operation: NSCompositeSourceOver fraction: 1.0f]; } // Tool overlays drawn underneath selection outline if (_shouldDisplaySelectionToolOverlay) { [self drawSelectionToolOverlay]; } if (_shouldDisplayEraserToolOverlay) { [self drawEraserToolOverlay]; } // Selection outline if (_hasSelectionOutline && !_shouldHideSelectionOutline) { [self drawSelectionOutline]; } // Tool overlays drawn over selection outline if (_shouldDisplayFillToolOverlay) { [self drawFillToolOverlay]; } if (_shouldDisplayMagnifierToolOverlay) { [self drawMagnifierToolOverlay]; } if (_shouldDisplayColorRampToolOverlay) { [self drawColorRampToolOverlay]; } #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY if (_retinaDisplayBuffer) { [self finishDrawingToRetinaDisplayBufferInRect: rect]; } // the retina display buffer clips drawing to rect, so don't draw the match tool tolerance // indicator (which can draw outside rect bounds) until after retina display buffer drawing // is finished #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY if (_shouldDisplayMatchToolToleranceIndicator) { [self drawMatchToolToleranceIndicator]; } } - (void) mouseDragged: (NSEvent *) theEvent { if (_allowSkippingOfMouseDraggedEvents && !_isAutoscrolling) { // skipping to the latest mouseDragged event can save unnecessary redrawing during drag theEvent = [theEvent ppLatestMouseDraggedEventFromEventQueue]; } if (_autoscrollingIsEnabled) { [self autoscrollHandleMouseDraggedEvent: theEvent]; } [super mouseDragged: theEvent]; } - (void) mouseUp: (NSEvent *) theEvent { _isDraggingTool = NO; if (_autoscrollingIsEnabled) { [self autoscrollStop]; } [self updateCursorForWindowPoint: [theEvent locationInWindow]]; [super mouseUp: theEvent]; } - (void) mouseEntered: (NSEvent *) theEvent { NSTrackingRectTag trackingRectTag = [theEvent trackingNumber]; if (trackingRectTag == _viewBoundsTrackingRectTag) { [self makeWindowKeyIfMain]; } else if (trackingRectTag == _visibleCanvasTrackingRectTag) { if (!_mouseIsInsideVisibleCanvasTrackingRect) { _mouseIsInsideVisibleCanvasTrackingRect = YES; [self updateCursor]; } } else { [super mouseEntered: theEvent]; } } - (void) mouseExited: (NSEvent *) theEvent { NSTrackingRectTag trackingRectTag = [theEvent trackingNumber]; if (trackingRectTag == _visibleCanvasTrackingRectTag) { if (_mouseIsInsideVisibleCanvasTrackingRect) { _mouseIsInsideVisibleCanvasTrackingRect = NO; [self updateCursor]; } } else { [super mouseExited: theEvent]; } } - (void) scrollWheel: (NSEvent *) theEvent { if (_isDraggingTool) return; [super scrollWheel: theEvent]; } - (void) cursorUpdate: (NSEvent *) event { [[PPCursorManager sharedManager] refreshCursorIfNeeded]; } #pragma mark NSWindow notifications - (void) addAsObserverForNSWindowNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; NSWindow *parentWindow = [self window]; [self removeAsObserverForNSWindowNotifications]; if (!parentWindow) return; [notificationCenter addObserver: self selector: @selector(handleNSWindowNotifications_DidBecomeOrResignKey:) name: NSWindowDidBecomeKeyNotification object: parentWindow]; [notificationCenter addObserver: self selector: @selector(handleNSWindowNotifications_DidBecomeOrResignKey:) name: NSWindowDidResignKeyNotification object: parentWindow]; } - (void) removeAsObserverForNSWindowNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: NSWindowDidBecomeKeyNotification object: nil]; [notificationCenter removeObserver: self name: NSWindowDidResignKeyNotification object: nil]; } - (void) handleNSWindowNotifications_DidBecomeOrResignKey: (NSNotification *) notification { [self setupMouseTracking]; } #pragma mark NSClipView notifications - (void) addAsObserverForNotificationsFromNSClipView: (NSClipView *) clipView { NSNotificationCenter *notificationCenter; [self removeAsObserverForNotificationsFromNSClipView: nil]; if (!clipView) return; notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver: self selector: @selector(handleNSClipViewNotifications_FrameOrBoundsDidChange:) name: NSViewFrameDidChangeNotification object: clipView]; [notificationCenter addObserver: self selector: @selector(handleNSClipViewNotifications_FrameOrBoundsDidChange:) name: NSViewBoundsDidChangeNotification object: clipView]; [clipView setPostsBoundsChangedNotifications: YES]; } - (void) removeAsObserverForNotificationsFromNSClipView: (NSClipView *) clipView { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: NSViewFrameDidChangeNotification object: clipView]; [notificationCenter removeObserver: self name: NSViewBoundsDidChangeNotification object: clipView]; } - (void) handleNSClipViewNotifications_FrameOrBoundsDidChange: (NSNotification *) notification { NSClipView *enclosingClipView = [self enclosingClipView]; _clipViewVisibleRect = (enclosingClipView) ? [enclosingClipView documentVisibleRect] : NSZeroRect; [self handleScrollingBegin]; [self updateFrameForEnclosingClipView: enclosingClipView]; [self repositionVisibleImages]; [self setupMouseTracking]; [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(handleScrollingEnd)]; [self postNotification_UpdatedNormalizedVisibleBounds]; } #pragma mark Private methods - (NSClipView *) enclosingClipView { NSClipView *enclosingClipView = (NSClipView *) [self superview]; if (![enclosingClipView isKindOfClass: [NSClipView class]]) { return nil; } return enclosingClipView; } - (void) updateFrameForEnclosingClipView: (NSClipView *) clipView { NSSize clipViewSize; NSRect newFrame; clipViewSize = (clipView) ? [clipView bounds].size : NSZeroSize; newFrame.origin = NSZeroPoint; if (clipViewSize.width > _zoomedCanvasFrame.size.width) { _canvasDrawingOffset.x = roundf((clipViewSize.width - _zoomedCanvasFrame.size.width) / 2.0f); newFrame.size.width = clipViewSize.width; } else { _canvasDrawingOffset.x = 0.0f; newFrame.size.width = _zoomedCanvasFrame.size.width; } if (clipViewSize.height > _zoomedCanvasFrame.size.height) { _canvasDrawingOffset.y = roundf((clipViewSize.height - _zoomedCanvasFrame.size.height) / 2.0f); newFrame.size.height = clipViewSize.height; } else { _canvasDrawingOffset.y = 0.0f; newFrame.size.height = _zoomedCanvasFrame.size.height; } _offsetZoomedCanvasFrame.origin = _canvasDrawingOffset; if (!NSEqualRects([self frame], newFrame)) { [self setFrame: newFrame]; _clipViewVisibleRect = (clipView) ? [clipView documentVisibleRect] : NSZeroRect; } [self setNeedsDisplay: YES]; } - (void) setCanvasSize: (NSSize) canvasSize { canvasSize = PPGeometry_SizeClippedToIntegerValues(canvasSize); if (NSEqualSizes(_canvasFrame.size, canvasSize) || PPGeometry_IsZeroSize(canvasSize)) { goto ERROR; } if (![self resizeSelectionToolOverlayMasksToSize: canvasSize]) { goto ERROR; } _canvasFrame.size = canvasSize; [self setZoomFactor: [self zoomFactorToFitCanvasSize: canvasSize] forceRedrawIfZoomFactorUnchanged: YES centerRedrawnImagesAtPoint: PPGeometry_CenterOfRect(_canvasFrame)]; return; ERROR: return; } - (void) setZoomFactor: (float) zoomFactor forceRedrawIfZoomFactorUnchanged: (bool) forceRedraw centerRedrawnImagesAtPoint: (NSPoint) centerPoint { if (_isDraggingTool) return; zoomFactor = roundf(zoomFactor); if (zoomFactor < kMinCanvasZoomFactor) { zoomFactor = kMinCanvasZoomFactor; } else if (zoomFactor > kMaxCanvasZoomFactor) { zoomFactor = kMaxCanvasZoomFactor; } if ((zoomFactor == _zoomFactor) && !forceRedraw) { return; } _zoomFactor = zoomFactor; _inverseZoomFactor = 1.0f / zoomFactor; _zoomedCanvasFrame.size = PPGeometry_SizeScaledByFactorAndRoundedToIntegerValues(_canvasFrame.size, _zoomFactor); _offsetZoomedCanvasFrame = _zoomedCanvasFrame; // offset origin set in updateFrame... // changing the frame & scroll position can cause the zoomed images to unnecessarily redraw // several times due to setFrame: & scrollPoint: sending clipview frame/bounds-change // notifications & scrollPoint: sometimes calling drawRect: directly), so disallow drawing // zoomed images (the bitmaps themselves, as well as to the screen while the bitmaps are // out-of-date) until after both changes are made, then force a single redraw _zoomedImagesDrawMode = kPPZoomedImagesDrawMode_DisallowDrawing; [self updateFrameForEnclosingClipView: [self enclosingClipView]]; [self centerEnclosingScrollViewAtImagePoint: centerPoint]; _zoomedImagesDrawMode = kPPZoomedImagesDrawMode_ForceRedraw; [self repositionVisibleImages]; _zoomedImagesDrawMode = kPPZoomedImagesDrawMode_Normal; [self setupMouseTracking]; [self postNotification_ChangedZoomFactor]; } - (float) zoomFactorToFitCanvasSize: (NSSize) canvasSize { NSRect viewFrame; float horizontalFactor, verticalFactor, zoomFactor; viewFrame = [[self enclosingScrollView] frame]; horizontalFactor = viewFrame.size.width / canvasSize.width; verticalFactor = viewFrame.size.height / canvasSize.height; zoomFactor = (horizontalFactor < verticalFactor) ? horizontalFactor : verticalFactor; zoomFactor = floorf(zoomFactor); if (zoomFactor < kMinCanvasZoomFactor) { zoomFactor = kMinCanvasZoomFactor; } else if (zoomFactor > kMaxCanvasZoomFactor) { zoomFactor = kMaxCanvasZoomFactor; } return zoomFactor; } - (void) repositionVisibleImages { NSRect oldZoomedVisibleCanvasBounds, oldOffsetZoomedVisibleCanvasBounds; bool didChangeVisibleCanvasBounds, didChangeCanvasDrawingOffset, needToUpdateVisibleImages, needToResizeVisibleImages, needToRepositionSelectionOutline; oldZoomedVisibleCanvasBounds = _zoomedVisibleCanvasBounds; oldOffsetZoomedVisibleCanvasBounds = _offsetZoomedVisibleCanvasBounds; [self repositionVisibleBoundingRects]; if (_zoomedImagesDrawMode == kPPZoomedImagesDrawMode_DisallowDrawing) { return; } needToUpdateVisibleImages = needToResizeVisibleImages = NO; needToRepositionSelectionOutline = NO; didChangeVisibleCanvasBounds = !NSEqualRects(_zoomedVisibleCanvasBounds, oldZoomedVisibleCanvasBounds); didChangeCanvasDrawingOffset = !NSEqualPoints(_offsetZoomedVisibleCanvasBounds.origin, oldOffsetZoomedVisibleCanvasBounds.origin); if (didChangeVisibleCanvasBounds || (_zoomedImagesDrawMode == kPPZoomedImagesDrawMode_ForceRedraw)) { needToUpdateVisibleImages = YES; needToRepositionSelectionOutline = YES; if ((_zoomedVisibleCanvasBounds.size.width > _zoomedVisibleImagesSize.width) || (_zoomedVisibleCanvasBounds.size.height > _zoomedVisibleImagesSize.height)) { needToResizeVisibleImages = YES; } } else if (didChangeCanvasDrawingOffset) { needToRepositionSelectionOutline = YES; } if (needToResizeVisibleImages) { [self resizeVisibleImages]; } if (needToUpdateVisibleImages) { [self setupGridGuidelinesPhaseForVisibleCanvas]; [self updateVisibleBackground]; [self updateVisibleCanvasInRect: _visibleCanvasBounds]; } if (needToRepositionSelectionOutline && _hasSelectionOutline) { [self updateSelectionOutlineForCurrentVisibleCanvas]; } } - (void) repositionVisibleBoundingRects { _visibleCanvasBounds.origin = NSMakePoint(floorf(NSMinX(_clipViewVisibleRect) * _inverseZoomFactor), floorf(NSMinY(_clipViewVisibleRect) * _inverseZoomFactor)); _visibleCanvasBounds.size = NSMakeSize(ceilf(NSMaxX(_clipViewVisibleRect) * _inverseZoomFactor) - _visibleCanvasBounds.origin.x, ceilf(NSMaxY(_clipViewVisibleRect) * _inverseZoomFactor) - _visibleCanvasBounds.origin.y); _visibleCanvasBounds = NSIntersectionRect(_visibleCanvasBounds, _canvasFrame); _zoomedVisibleCanvasBounds = PPGeometry_RectScaledByFactor(_visibleCanvasBounds, _zoomFactor); _offsetZoomedVisibleCanvasBounds.size = _zoomedVisibleCanvasBounds.size; _offsetZoomedVisibleCanvasBounds.origin = PPGeometry_PointSum(_zoomedVisibleCanvasBounds.origin, _canvasDrawingOffset); } - (void) resizeVisibleImages { _zoomedVisibleImagesSize = _zoomedVisibleCanvasBounds.size; [_zoomedVisibleCanvasBitmap release]; _zoomedVisibleCanvasBitmap = [[NSBitmapImageRep ppImageBitmapOfSize: _zoomedVisibleImagesSize] retain]; [_zoomedVisibleCanvasImage release]; _zoomedVisibleCanvasImage = [[NSImage ppImageWithBitmap: _zoomedVisibleCanvasBitmap] retain]; if (gShouldDrawDirectlyToZoomedVisibleBackgroundImage) { [_zoomedVisibleBackgroundImage release]; _zoomedVisibleBackgroundImage = [[NSImage alloc] initWithSize: _zoomedVisibleImagesSize]; } else { [_zoomedVisibleBackgroundBitmap release]; _zoomedVisibleBackgroundBitmap = [[NSBitmapImageRep ppImageBitmapOfSize: _zoomedVisibleImagesSize] retain]; [_zoomedVisibleBackgroundImage release]; _zoomedVisibleBackgroundImage = [[NSImage ppImageWithBitmap: _zoomedVisibleBackgroundBitmap] retain]; } #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY if (_currentDisplayIsRetina) { [self setupRetinaDrawingForResizedView]; } #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY } - (void) setupGridGuidelinesPhaseForVisibleCanvas { // _zoomedVisibleImagesSize is the bitmap's actual size, not _zoomedVisibleCanvasBounds.size _gridGuidelinesTopLeftPhase = NSMakePoint(_zoomedVisibleCanvasBounds.origin.x, _zoomedCanvasFrame.size.height - (_zoomedVisibleCanvasBounds.origin.y + _zoomedVisibleImagesSize.height)); } - (void) updateVisibleCanvasInRect: (NSRect) canvasUpdateRect { NSRect zoomedUpdateRect; canvasUpdateRect = NSIntersectionRect(canvasUpdateRect, _visibleCanvasBounds); if (NSIsEmptyRect(canvasUpdateRect)) { return; } zoomedUpdateRect.origin = NSMakePoint(canvasUpdateRect.origin.x * _zoomFactor - _zoomedVisibleCanvasBounds.origin.x, canvasUpdateRect.origin.y * _zoomFactor - _zoomedVisibleCanvasBounds.origin.y); zoomedUpdateRect.size = NSMakeSize(canvasUpdateRect.size.width * _zoomFactor, canvasUpdateRect.size.height * _zoomFactor); if (_shouldDisplayGrid) { [_zoomedVisibleCanvasBitmap ppScaledCopyFromImageBitmap: _canvasBitmap inRect: canvasUpdateRect toPoint: zoomedUpdateRect.origin scalingFactor: _zoomFactor gridType: _gridType gridPixelValue: _gridColorPixelValue]; if (_shouldDisplayGridGuidelines) { [_zoomedVisibleCanvasBitmap ppDrawImageGuidelinesInBounds: zoomedUpdateRect topLeftPhase: _gridGuidelinesTopLeftPhase unscaledSpacingSize: _gridGuidelineSpacingSize scalingFactor: _zoomFactor guidelinePixelValue: _gridGuidelineColorPixelValue]; } } else { [_zoomedVisibleCanvasBitmap ppScaledCopyFromImageBitmap: _canvasBitmap inRect: canvasUpdateRect toPoint: zoomedUpdateRect.origin scalingFactor: _zoomFactor]; } [self recacheZoomedVisibleCanvasImageInBounds: zoomedUpdateRect]; zoomedUpdateRect.origin = PPGeometry_PointSum(zoomedUpdateRect.origin, _offsetZoomedVisibleCanvasBounds.origin); [self setNeedsDisplayInRect: zoomedUpdateRect]; } // recacheZoomedVisibleCanvasImageInBounds: method is a patch target on GNUstep // (PPGNUstepGlue_ImageRecacheSpeedups) - (void) recacheZoomedVisibleCanvasImageInBounds: (NSRect) bounds { [_zoomedVisibleCanvasImage recache]; } - (void) updateVisibleBackground { NSImageInterpolation imageInterpolation; if (gShouldDrawDirectlyToZoomedVisibleBackgroundImage) { [_zoomedVisibleBackgroundImage lockFocus]; } else { [_zoomedVisibleBackgroundBitmap ppSetAsCurrentGraphicsContext]; } [[NSGraphicsContext currentContext] setPatternPhase: NSMakePoint(-_zoomedVisibleCanvasBounds.origin.x, -_zoomedVisibleCanvasBounds.origin.y)]; [_backgroundColor set]; NSRectFill(PPGeometry_OriginRectOfSize(_zoomedVisibleCanvasBounds.size)); if (_shouldDisplayBackgroundImage && _backgroundImage) { NSRect imageFrame, zoomedImageBounds; NSCompositingOperation compositingOperation; imageFrame = PPGeometry_OriginRectOfSize([_backgroundImage size]); zoomedImageBounds = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(imageFrame.size, _zoomedCanvasFrame.size); imageInterpolation = (_shouldSmoothenBackgroundImage && !_disallowBackgroundImageSmoothingForScrolling) ? NSImageInterpolationLow : NSImageInterpolationNone; [[NSGraphicsContext currentContext] setImageInterpolation: imageInterpolation]; zoomedImageBounds.origin.x -= _zoomedVisibleCanvasBounds.origin.x; zoomedImageBounds.origin.y -= _zoomedVisibleCanvasBounds.origin.y; compositingOperation = (_backgroundImageIsOpaque) ? NSCompositeCopy : NSCompositeSourceOver; [_backgroundImage drawInRect: zoomedImageBounds fromRect: imageFrame operation: compositingOperation fraction: 1.0f]; } if (gShouldDrawDirectlyToZoomedVisibleBackgroundImage) { [_zoomedVisibleBackgroundImage unlockFocus]; } else { [_zoomedVisibleBackgroundBitmap ppRestoreGraphicsContext]; [_zoomedVisibleBackgroundImage recache]; } [self setNeedsDisplayInRect: _offsetZoomedVisibleCanvasBounds]; } - (void) setupMouseTracking { NSRect newViewBoundsTrackingRect = NSZeroRect, newVisibleCanvasTrackingRect = NSZeroRect; bool mouseIsInsideNewViewBoundsTrackingRect = NO, mouseIsInsideNewVisibleCanvasTrackingRect = NO; if ([[self window] isKeyWindow]) { NSPoint mouseLocationInView; bool mouseIsInsideVisiblePopupOrPanel = NO; mouseLocationInView = [self convertPoint: [[self window] mouseLocationOutsideOfEventStream] fromView: nil]; newViewBoundsTrackingRect = _clipViewVisibleRect; if (!NSIsEmptyRect(newViewBoundsTrackingRect)) { if (NSPointInRect(mouseLocationInView, newViewBoundsTrackingRect)) { if (![[PPPopupPanelsController sharedController] mouseIsInsideActivePopupPanel] && ![[PPPanelsController sharedController] mouseIsInsideVisiblePanel]) { mouseIsInsideNewViewBoundsTrackingRect = YES; } else // mouse is inside active popup or visible panel { mouseIsInsideVisiblePopupOrPanel = YES; } } } newVisibleCanvasTrackingRect = NSIntersectionRect(_offsetZoomedVisibleCanvasBounds, _clipViewVisibleRect); if (!NSIsEmptyRect(newVisibleCanvasTrackingRect) && !mouseIsInsideVisiblePopupOrPanel) { mouseIsInsideNewVisibleCanvasTrackingRect = (NSPointInRect(mouseLocationInView, newVisibleCanvasTrackingRect)) ? YES : NO; // On OS X versions that round off mouse coordinates (10.7 & earlier), treat points // touching the edge of the tracking rect as inside it - this prevents setting the // incorrect cursor for rounded-off points that are actually inside the canvas if (!mouseIsInsideNewVisibleCanvasTrackingRect && gRuntimeRoundsOffSubpixelMouseCoordinates && PPGeometry_PointTouchesEdgePixelOfRect(mouseLocationInView, newVisibleCanvasTrackingRect)) { mouseIsInsideNewVisibleCanvasTrackingRect = YES; } } } if (!NSEqualRects(newViewBoundsTrackingRect, _viewBoundsTrackingRect)) { if (_viewBoundsTrackingRectTag) { [self removeTrackingRect: _viewBoundsTrackingRectTag]; _viewBoundsTrackingRectTag = 0; _viewBoundsTrackingRect = NSZeroRect; } if (!NSIsEmptyRect(newViewBoundsTrackingRect)) { _viewBoundsTrackingRectTag = [self addTrackingRect: newViewBoundsTrackingRect owner: self userData: NULL assumeInside: mouseIsInsideNewViewBoundsTrackingRect]; if (_viewBoundsTrackingRectTag) { _viewBoundsTrackingRect = newViewBoundsTrackingRect; } } } if (!NSEqualRects(newVisibleCanvasTrackingRect, _visibleCanvasTrackingRect)) { if (_visibleCanvasTrackingRectTag) { [self removeTrackingRect: _visibleCanvasTrackingRectTag]; _visibleCanvasTrackingRectTag = 0; _visibleCanvasTrackingRect = NSZeroRect; } if (!NSIsEmptyRect(newVisibleCanvasTrackingRect)) { _visibleCanvasTrackingRectTag = [self addTrackingRect: newVisibleCanvasTrackingRect owner: self userData: NULL assumeInside: mouseIsInsideNewVisibleCanvasTrackingRect]; if (_visibleCanvasTrackingRectTag) { _visibleCanvasTrackingRect = newVisibleCanvasTrackingRect; } else { mouseIsInsideNewVisibleCanvasTrackingRect = NO; } } } if (_mouseIsInsideVisibleCanvasTrackingRect != mouseIsInsideNewVisibleCanvasTrackingRect) { _mouseIsInsideVisibleCanvasTrackingRect = mouseIsInsideNewVisibleCanvasTrackingRect; [self updateCursor]; } } - (void) handleScrollingBegin { if (_isScrolling) return; _isScrolling = YES; [self updateCursor]; [self disableBackgroundImageSmoothingForScrollingBegin]; } - (void) handleScrollingEnd { _isScrolling = NO; [self updateCursorForCurrentMouseLocation]; [self performDelayedUpdateOfBackgroundImageSmoothingForScrollingEnd]; } - (void) performDelayedUpdateOfBackgroundImageSmoothingForScrollingEnd { [[self class] cancelPreviousPerformRequestsWithTarget: self selector: @selector(updateBackgroundImageSmoothingForScrollingEnd) object: nil]; [self performSelector: @selector(updateBackgroundImageSmoothingForScrollingEnd) withObject: nil afterDelay: kTimeDelayForImageSmoothingRefreshAfterScrollingEnds]; } - (void) makeWindowKeyIfMain { [[self window] ppMakeKeyWindowIfMain]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_Autoscrolling.m0000644000076500000240000000672713234403205023556 0ustar joshstaff/* PPCanvasView_Autoscrolling.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "NSObject_PPUtilities.h" #define kAutoscrollTimeInterval 0.1f @interface PPCanvasView (AutoscrollingPrivateMethods) - (void) startAutoscrollRepeatTimer; - (void) stopAutoscrollRepeatTimer; - (void) autoscrollRepeatTimerFired: (NSTimer *) timer; @end @implementation PPCanvasView (Autoscrolling) - (void) enableAutoscrolling: (bool) shouldEnableAutoscrolling { _autoscrollingIsEnabled = (shouldEnableAutoscrolling) ? YES : NO; } - (bool) isAutoscrolling { return _isAutoscrolling; } - (void) autoscrollHandleMouseDraggedEvent: (NSEvent *) event { if ([event type] != NSLeftMouseDragged) { return; } if (_autoscrollMouseDraggedEvent) { if ([_autoscrollMouseDraggedEvent isEqual: event]) { return; } [_autoscrollMouseDraggedEvent release]; _autoscrollMouseDraggedEvent = nil; } else { [self startAutoscrollRepeatTimer]; } _autoscrollMouseDraggedEvent = [event retain]; } - (void) autoscrollStop { _isAutoscrolling = NO; if (_autoscrollMouseDraggedEvent) { [_autoscrollMouseDraggedEvent release]; _autoscrollMouseDraggedEvent = nil; } if (_autoscrollRepeatTimer) { [self stopAutoscrollRepeatTimer]; } [self updateBackgroundImageSmoothingForScrollingEnd]; } #pragma mark Autoscroll repeat timer - (void) startAutoscrollRepeatTimer { if (_autoscrollRepeatTimer) { [self stopAutoscrollRepeatTimer]; } _autoscrollRepeatTimer = [[NSTimer scheduledTimerWithTimeInterval: kAutoscrollTimeInterval target: self selector: @selector(autoscrollRepeatTimerFired:) userInfo: nil repeats: YES] retain]; } - (void) stopAutoscrollRepeatTimer { if (!_autoscrollRepeatTimer) return; [_autoscrollRepeatTimer invalidate]; [_autoscrollRepeatTimer autorelease]; _autoscrollRepeatTimer = nil; } - (void) autoscrollRepeatTimerFired: (NSTimer *) timer { if (!_autoscrollMouseDraggedEvent) return; if ([self autoscroll: _autoscrollMouseDraggedEvent]) { _isAutoscrolling = YES; [self disableBackgroundImageSmoothingForScrollingBegin]; [self mouseDragged: _autoscrollMouseDraggedEvent]; } else { [self autoscrollStop]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_ColorRampToolOverlay.m0000644000076500000240000001664313234403205025025 0ustar joshstaff/* PPCanvasView_ColorRampToolOverlay.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "PPGeometry.h" #define kMinZoomFactorToDrawOverlay 5 #define kMinZoomFactorToDrawWideOutlines 14 #define kMinZoomFactorToDrawXMarks 8 #define kOverlayPathLineWidth_WideOutline (2.0) #define kOverlayPathLineWidth_NarrowOutline (0.0) #define kOverlayPathLineWidth_XMarkLine (0.0) #define kOverlayPathLineWidth_XMarkHalo (2.0) #define kUIColor_ColorRampToolOverlay_Outline \ [NSColor ppDiagonalLinePatternColorWithLineWidth: 2.0f \ color1: [NSColor blackColor] \ color2: [NSColor whiteColor]] #define kUIColor_ColorRampToolOverlay_XMarkLine \ [NSColor ppSRGBColorWithWhite: 0.6 alpha: 0.7] #define kUIColor_ColorRampToolOverlay_XMarkHalo \ [NSColor ppSRGBColorWithWhite: 0.85 alpha: 0.7] static NSColor *gOverlayColor_Outline = nil, *gOverlayColor_XMarkLine = nil, *gOverlayColor_XMarkHalo = nil; @implementation PPCanvasView (ColorRampToolOverlay) + (void) initializeColorRampToolOverlay { gOverlayColor_Outline = [kUIColor_ColorRampToolOverlay_Outline retain]; gOverlayColor_XMarkLine = [kUIColor_ColorRampToolOverlay_XMarkLine retain]; gOverlayColor_XMarkHalo = [kUIColor_ColorRampToolOverlay_XMarkHalo retain]; } - (bool) initColorRampToolOverlayMembers { _colorRampToolOverlayPath_Outline = [[NSBezierPath bezierPath] retain]; _colorRampToolOverlayPath_XMarks = [[NSBezierPath bezierPath] retain]; if (!_colorRampToolOverlayPath_Outline || !_colorRampToolOverlayPath_XMarks) { goto ERROR; } return YES; ERROR: return NO; } - (void) deallocColorRampToolOverlayMembers { [_colorRampToolOverlayPath_Outline release]; _colorRampToolOverlayPath_Outline = nil; [_colorRampToolOverlayPath_XMarks release]; _colorRampToolOverlayPath_XMarks = nil; } - (void) setColorRampToolOverlayToMask: (NSBitmapImageRep *) maskBitmap maskBounds: (NSRect) maskBounds { NSAffineTransform *canvasViewTransform; NSRect outlinePathDisplayBounds, displayClippingBounds; CGFloat outlinePathLineWidth, outlinePathLineHalfWidth, canvasDisplayOutsetAmount; [self clearColorRampToolOverlay]; if (![maskBitmap ppIsMaskBitmap]) { goto ERROR; } maskBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(maskBounds), [maskBitmap ppFrameInPixels]); if (NSIsEmptyRect(maskBounds)) { goto ERROR; } if (_zoomFactor < kMinZoomFactorToDrawOverlay) { return; } canvasViewTransform = [NSAffineTransform transform]; if (!canvasViewTransform) { goto ERROR; } [canvasViewTransform translateXBy: _canvasDrawingOffset.x + 0.5f yBy: _canvasDrawingOffset.y - 0.5f]; [canvasViewTransform scaleBy: _zoomFactor]; if (_hasSelectionOutline) { [_colorRampToolOverlayPath_XMarks ppAppendXMarksForUnmaskedPixelsInMaskBitmap: maskBitmap inBounds: maskBounds]; [_colorRampToolOverlayPath_XMarks transformUsingAffineTransform: canvasViewTransform]; } [_colorRampToolOverlayPath_Outline appendBezierPathWithRect: maskBounds]; if (maskBounds.size.width > 1.0) { [_colorRampToolOverlayPath_Outline ppAppendPixelColumnSeparatorLinesInBounds: maskBounds]; } else if (maskBounds.size.height > 1.0) { [_colorRampToolOverlayPath_Outline ppAppendPixelRowSeparatorLinesInBounds: maskBounds]; } [_colorRampToolOverlayPath_Outline transformUsingAffineTransform: canvasViewTransform]; outlinePathLineWidth = (_zoomFactor >= kMinZoomFactorToDrawWideOutlines) ? kOverlayPathLineWidth_WideOutline : kOverlayPathLineWidth_NarrowOutline; outlinePathLineHalfWidth = outlinePathLineWidth / 2.0f; [_colorRampToolOverlayPath_Outline setLineWidth: outlinePathLineWidth]; outlinePathDisplayBounds = [_colorRampToolOverlayPath_Outline bounds]; if (outlinePathLineHalfWidth > 0) { // outset outlinePathDisplayBounds to account for path's linewidth outlinePathDisplayBounds = NSInsetRect(outlinePathDisplayBounds, -outlinePathLineHalfWidth, -outlinePathLineHalfWidth); } // allow the display bounds to extend past the canvas edges to account for the linewidth canvasDisplayOutsetAmount = 1.0f + outlinePathLineHalfWidth; displayClippingBounds = NSInsetRect(_offsetZoomedVisibleCanvasBounds, -canvasDisplayOutsetAmount, -canvasDisplayOutsetAmount); _colorRampToolOverlayDisplayBounds = PPGeometry_PixelBoundsCoveredByRect( NSIntersectionRect(outlinePathDisplayBounds, displayClippingBounds)); if (!NSIsEmptyRect(_colorRampToolOverlayDisplayBounds)) { _shouldDisplayColorRampToolOverlay = YES; [self setNeedsDisplayInRect: _colorRampToolOverlayDisplayBounds]; } return; ERROR: return; } - (void) clearColorRampToolOverlay { [_colorRampToolOverlayPath_Outline removeAllPoints]; [_colorRampToolOverlayPath_XMarks removeAllPoints]; if (_shouldDisplayColorRampToolOverlay) { [self setNeedsDisplayInRect: _colorRampToolOverlayDisplayBounds]; } _shouldDisplayColorRampToolOverlay = NO; _colorRampToolOverlayDisplayBounds = NSZeroRect; } - (void) drawColorRampToolOverlay { if (!_shouldDisplayColorRampToolOverlay) return; if (![_colorRampToolOverlayPath_XMarks isEmpty] && (_zoomFactor >= kMinZoomFactorToDrawXMarks)) { [gOverlayColor_XMarkHalo set]; [_colorRampToolOverlayPath_XMarks setLineWidth: kOverlayPathLineWidth_XMarkHalo]; [_colorRampToolOverlayPath_XMarks stroke]; [gOverlayColor_XMarkLine set]; [_colorRampToolOverlayPath_XMarks setLineWidth: kOverlayPathLineWidth_XMarkLine]; [_colorRampToolOverlayPath_XMarks stroke]; } [gOverlayColor_Outline set]; [_colorRampToolOverlayPath_Outline stroke]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_EraserToolOverlay.m0000644000076500000240000001231013234403205024333 0ustar joshstaff/* PPCanvasView_EraserToolOverlay.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #import "PPGeometry.h" #import "PPDefines.h" #define kEraserToolOverlayOutlinePatternImageName @"eraser_tool_overlay_outline_pattern" static NSColor *gEraserToolOverlayOutlineColor = nil; @interface PPCanvasView (EraserToolOverlayPrivateMethods) - (NSRect) visibleDrawingBoundsForEraserToolPathWithBounds: (NSRect) pathBounds; @end @implementation PPCanvasView (EraserToolOverlay) + (void) initializeEraserToolOverlay { NSImage *eraserToolOverlayOutlinePatternImage = [NSImage imageNamed: kEraserToolOverlayOutlinePatternImageName]; if (!eraserToolOverlayOutlinePatternImage) goto ERROR; gEraserToolOverlayOutlineColor = [[NSColor colorWithPatternImage: eraserToolOverlayOutlinePatternImage] retain]; return; ERROR: return; } - (bool) initEraserToolOverlayMembers { _eraserToolOverlayPath_Outline = [[NSBezierPath bezierPath] retain]; if (!_eraserToolOverlayPath_Outline) goto ERROR; return YES; ERROR: return NO; } - (void) deallocEraserToolOverlayMembers { [_eraserToolOverlayPath_Outline release]; _eraserToolOverlayPath_Outline = nil; } - (void) setEraserToolOverlayToMask: (NSBitmapImageRep *) maskBitmap maskBounds: (NSRect) maskBounds { NSRect pathDrawingBounds; NSAffineTransform *transform; NSRect overlayBounds, visibleClippingBounds; [self clearEraserToolOverlay]; if (_zoomFactor < kMinScalingFactorToDrawGrid) { return; } if (![maskBitmap ppIsMaskBitmap]) { goto ERROR; } pathDrawingBounds = [self visibleDrawingBoundsForEraserToolPathWithBounds: maskBounds]; [_eraserToolOverlayPath_Outline ppAppendOutlinePathForMaskBitmap: maskBitmap inBounds: pathDrawingBounds]; transform = [NSAffineTransform transform]; if (!transform) return; [transform translateXBy: _canvasDrawingOffset.x + 0.5f yBy: _canvasDrawingOffset.y - 0.5f]; [transform scaleBy: _zoomFactor]; overlayBounds = NSZeroRect; if (![_eraserToolOverlayPath_Outline isEmpty]) { [_eraserToolOverlayPath_Outline transformUsingAffineTransform: transform]; overlayBounds = [_eraserToolOverlayPath_Outline bounds]; } _eraserToolOverlayDisplayBounds = PPGeometry_PixelBoundsCoveredByRect(overlayBounds); // allow the outline to extend one pixel beyond the right & bottom canvas edges visibleClippingBounds = _offsetZoomedVisibleCanvasBounds; visibleClippingBounds.size.width += 1.0f; visibleClippingBounds.origin.y -= 1.0f; visibleClippingBounds.size.height += 1.0f; _eraserToolOverlayDisplayBounds = NSIntersectionRect(_eraserToolOverlayDisplayBounds, visibleClippingBounds); _shouldDisplayEraserToolOverlay = (NSIsEmptyRect(_eraserToolOverlayDisplayBounds)) ? NO : YES; if (_shouldDisplayEraserToolOverlay) { [self setNeedsDisplayInRect: _eraserToolOverlayDisplayBounds]; } return; ERROR: return; } - (void) clearEraserToolOverlay { [_eraserToolOverlayPath_Outline removeAllPoints]; if (_shouldDisplayEraserToolOverlay) { [self setNeedsDisplayInRect: _eraserToolOverlayDisplayBounds]; } _shouldDisplayEraserToolOverlay = NO; _eraserToolOverlayDisplayBounds = NSZeroRect; } - (void) drawEraserToolOverlay { if (!_shouldDisplayEraserToolOverlay) return; [gEraserToolOverlayOutlineColor set]; [_eraserToolOverlayPath_Outline stroke]; } #pragma mark Private methods - (NSRect) visibleDrawingBoundsForEraserToolPathWithBounds: (NSRect) pathBounds { // outset drawing bounds from _visibleCanvasBounds by 2.0 in both directions - the extra // (single-pixel) border around the visible canvas prevents false (cropped) path edges // from appearing on the window NSRect visibleCanvasDrawingBounds = NSIntersectionRect(NSInsetRect(_visibleCanvasBounds, -2.0f, -2.0f), _canvasFrame); return NSIntersectionRect(visibleCanvasDrawingBounds, pathBounds); } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_FillToolOverlay.m0000644000076500000240000001647413234403205024017 0ustar joshstaff/* PPCanvasView_FillToolOverlay.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "PPGeometry.h" #define kUIColor_FillToolOverlayOutline \ [NSColor ppSRGBColorWithRed: 0.0f green: 0.0f blue: 1.0f alpha: 0.6f] static NSColor *gOverlayOutlineColor = nil; @interface PPCanvasView (FillToolOverlayPrivateMethods) - (NSPoint) fillColorPatternPhaseForCurrentViewGeometry; - (NSRect) visibleDrawingBoundsForFillToolPathWithBounds: (NSRect) pathBounds; @end @implementation PPCanvasView (FillToolOverlay) + (void) initializeFillToolOverlay { gOverlayOutlineColor = [kUIColor_FillToolOverlayOutline retain]; } - (bool) initFillToolOverlayMembers { _fillToolOverlayPath_Fill = [[NSBezierPath bezierPath] retain]; _fillToolOverlayPath_Outline = [[NSBezierPath bezierPath] retain]; if (!_fillToolOverlayPath_Fill || !_fillToolOverlayPath_Outline) { goto ERROR; } return YES; ERROR: return NO; } - (void) deallocFillToolOverlayMembers { [_fillToolOverlayPatternColor release]; _fillToolOverlayPatternColor = nil; [_fillToolOverlayPath_Fill release]; _fillToolOverlayPath_Fill = nil; [_fillToolOverlayPath_Outline release]; _fillToolOverlayPath_Outline = nil; } - (void) beginFillToolOverlayForOperationTarget: (PPLayerOperationTarget) operationTarget fillColor: (NSColor *) fillColor; { if (_fillToolOverlayPatternColor) { [self endFillToolOverlay]; } if (!PPLayerOperationTarget_IsValid(operationTarget) || !fillColor) { goto ERROR; } if (operationTarget == kPPLayerOperationTarget_DrawingLayerOnly) { return; } _fillToolOverlayPatternColor = [[NSColor ppFillOverlayPatternColorWithSize: _zoomFactor fillColor: fillColor] retain]; if (!_fillToolOverlayPatternColor) goto ERROR; _fillToolOverlayPatternPhase = [self fillColorPatternPhaseForCurrentViewGeometry]; return; ERROR: return; } - (void) setFillToolOverlayToMask: (NSBitmapImageRep *) maskBitmap maskBounds: (NSRect) maskBounds { NSRect pathDrawingBounds; NSAffineTransform *transform; NSRect overlayBounds, visibleClippingBounds; if (!_fillToolOverlayPatternColor) return; [_fillToolOverlayPath_Fill removeAllPoints]; [_fillToolOverlayPath_Outline removeAllPoints]; if (_shouldDisplayFillToolOverlay) { [self setNeedsDisplayInRect: _fillToolOverlayDisplayBounds]; } if (![maskBitmap ppIsMaskBitmap]) { goto ERROR; } pathDrawingBounds = [self visibleDrawingBoundsForFillToolPathWithBounds: maskBounds]; [_fillToolOverlayPath_Fill ppAppendFillPathForMaskBitmap: maskBitmap inBounds: pathDrawingBounds]; [_fillToolOverlayPath_Outline ppAppendOutlinePathForMaskBitmap: maskBitmap inBounds: pathDrawingBounds]; transform = [NSAffineTransform transform]; if (!transform) return; [transform translateXBy: _canvasDrawingOffset.x + 0.5f yBy: _canvasDrawingOffset.y - 0.5f]; [transform scaleBy: _zoomFactor]; overlayBounds = NSZeroRect; if (![_fillToolOverlayPath_Fill isEmpty]) { [_fillToolOverlayPath_Fill transformUsingAffineTransform: transform]; [_fillToolOverlayPath_Outline transformUsingAffineTransform: transform]; overlayBounds = [_fillToolOverlayPath_Fill bounds]; } _fillToolOverlayDisplayBounds = PPGeometry_PixelBoundsCoveredByRect(overlayBounds); // allow the outline to extend one pixel beyond the right & bottom canvas edges visibleClippingBounds = _offsetZoomedVisibleCanvasBounds; visibleClippingBounds.size.width += 1.0f; visibleClippingBounds.origin.y -= 1.0f; visibleClippingBounds.size.height += 1.0f; _fillToolOverlayDisplayBounds = NSIntersectionRect(_fillToolOverlayDisplayBounds, visibleClippingBounds); _shouldDisplayFillToolOverlay = (NSIsEmptyRect(_fillToolOverlayDisplayBounds)) ? NO : YES; if (_shouldDisplayFillToolOverlay) { [self setNeedsDisplayInRect: _fillToolOverlayDisplayBounds]; } return; ERROR: [self endFillToolOverlay]; return; } - (void) endFillToolOverlay { [_fillToolOverlayPatternColor release]; _fillToolOverlayPatternColor = nil; [_fillToolOverlayPath_Fill removeAllPoints]; [_fillToolOverlayPath_Outline removeAllPoints]; if (_shouldDisplayFillToolOverlay) { [self setNeedsDisplayInRect: _fillToolOverlayDisplayBounds]; } _shouldDisplayFillToolOverlay = NO; _fillToolOverlayDisplayBounds = NSZeroRect; } - (void) drawFillToolOverlay { if (!_shouldDisplayFillToolOverlay) return; [_fillToolOverlayPatternColor set]; [[NSGraphicsContext currentContext] setPatternPhase: _fillToolOverlayPatternPhase]; [_fillToolOverlayPath_Fill fill]; [gOverlayOutlineColor set]; [_fillToolOverlayPath_Outline stroke]; } #pragma mark Private methods - (NSPoint) fillColorPatternPhaseForCurrentViewGeometry { NSScrollView *scrollView; NSSize scrollViewFrameSize, contentViewFrameSize; NSPoint visibleOrigin; scrollView = [self enclosingScrollView]; scrollViewFrameSize = [scrollView frame].size; contentViewFrameSize = [scrollView contentSize]; visibleOrigin = [[scrollView contentView] documentVisibleRect].origin; return NSMakePoint(_canvasDrawingOffset.x - visibleOrigin.x, _canvasDrawingOffset.y + scrollViewFrameSize.height - contentViewFrameSize.height - visibleOrigin.y); } - (NSRect) visibleDrawingBoundsForFillToolPathWithBounds: (NSRect) pathBounds { // outset drawing bounds from _visibleCanvasBounds by 2.0 in both directions - the extra // (single-pixel) border around the visible canvas prevents false (cropped) path edges // from appearing on the window NSRect visibleCanvasDrawingBounds = NSIntersectionRect(NSInsetRect(_visibleCanvasBounds, -2.0f, -2.0f), _canvasFrame); return NSIntersectionRect(visibleCanvasDrawingBounds, pathBounds); } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_MagnifierToolOverlay.m0000644000076500000240000000730413234403205025022 0ustar joshstaff/* PPCanvasView_MagnifierToolOverlay.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "PPGeometry.h" #import "PPSRGBUtilities.h" #define kUIColor_MagnifierToolOverlayLine \ [NSColor ppSRGBColorWithWhite: 0.0f alpha: 0.95f] #define kUIColor_MagnifierToolOverlayLineHalo \ [NSColor ppSRGBColorWithWhite: 1.0f alpha: 0.95f] #define kMagnifierToolOverlayLineWidth (0.0f) #define kMagnifierToolOverlayLineHaloWidth (3.0f) static NSColor *gMagnifierToolOverlayLineColor = nil, *gMagnifierToolOverlayLineHaloColor = nil; @implementation PPCanvasView (MagnifierToolOverlay) + (void) initializeMagnifierToolOverlay { if (!gMagnifierToolOverlayLineColor) { gMagnifierToolOverlayLineColor = [kUIColor_MagnifierToolOverlayLine retain]; } if (!gMagnifierToolOverlayLineHaloColor) { gMagnifierToolOverlayLineHaloColor = [kUIColor_MagnifierToolOverlayLineHalo retain]; } } - (bool) initMagnifierToolOverlayMembers { _magnifierToolOverlayRectPath = [[NSBezierPath bezierPath] retain]; if (!_magnifierToolOverlayRectPath) goto ERROR; return YES; ERROR: return NO; } - (void) deallocMagnifierToolOverlayMembers { [_magnifierToolOverlayRectPath release]; _magnifierToolOverlayRectPath = nil; } - (void) setMagnifierToolOverlayToViewRect: (NSRect) rect { NSRect updateRect; rect = PPGeometry_PixelCenteredRect(NSIntersectionRect(rect, _offsetZoomedCanvasFrame)); if (NSEqualRects(rect, _magnifierToolOverlayRect)) { return; } updateRect = NSInsetRect(NSUnionRect(rect, _magnifierToolOverlayRect), -kMagnifierToolOverlayLineHaloWidth/2.0f, -kMagnifierToolOverlayLineHaloWidth/2.0f); updateRect = PPGeometry_PixelBoundsCoveredByRect(updateRect); _magnifierToolOverlayRect = rect; [_magnifierToolOverlayRectPath removeAllPoints]; if (!NSIsEmptyRect(_magnifierToolOverlayRect)) { [_magnifierToolOverlayRectPath appendBezierPathWithRect: _magnifierToolOverlayRect]; _shouldDisplayMagnifierToolOverlay = YES; } else { _shouldDisplayMagnifierToolOverlay = NO; } [self setNeedsDisplayInRect: updateRect]; } - (void) clearMagnifierToolOverlay { [self setMagnifierToolOverlayToViewRect: NSZeroRect]; } - (void) drawMagnifierToolOverlay { if (!_shouldDisplayMagnifierToolOverlay) return; [_magnifierToolOverlayRectPath setLineWidth: kMagnifierToolOverlayLineHaloWidth]; [gMagnifierToolOverlayLineHaloColor set]; [_magnifierToolOverlayRectPath stroke]; [_magnifierToolOverlayRectPath setLineWidth: kMagnifierToolOverlayLineWidth]; [gMagnifierToolOverlayLineColor set]; [_magnifierToolOverlayRectPath stroke]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_MatchToolToleranceIndicator.m0000644000076500000240000001406013234403205026302 0ustar joshstaff/* PPCanvasView_MatchToolToleranceIndicator.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "PPDefines.h" #import "PPGeometry.h" #import "PPSRGBUtilities.h" #define kUIColor_MatchToolToleranceIndicatorLine \ [NSColor ppSRGBColorWithWhite: 0.0f alpha: 0.8f] #define kUIColor_MatchToolToleranceIndicatorLineHalo \ [NSColor ppSRGBColorWithWhite: 1.0f alpha: 0.75f] #define kIndicatorLineWidth (0.0f) #define kIndicatorLineHaloWidth (3.0f) #define kIndicatorCenterXLegLength (3.0f) static NSColor *gIndicatorLineColor = nil, *gIndicatorLineHaloColor = nil; @interface PPCanvasView (MatchToolToleranceIndicatorPrivateMethods) - (void) setupMatchToolToleranceIndicatorPathAndDisplayBounds; @end @implementation PPCanvasView (MatchToolToleranceIndicator) + (void) initializeMatchToolToleranceIndicator { if (!gIndicatorLineColor) { gIndicatorLineColor = [kUIColor_MatchToolToleranceIndicatorLine retain]; } if (!gIndicatorLineHaloColor) { gIndicatorLineHaloColor = [kUIColor_MatchToolToleranceIndicatorLineHalo retain]; } } - (bool) initMatchToolToleranceIndicatorMembers { return YES; } - (void) deallocMatchToolToleranceIndicatorMembers { [_matchToolToleranceIndicatorPath release]; _matchToolToleranceIndicatorPath = nil; } - (void) showMatchToolToleranceIndicatorAtViewPoint: (NSPoint) viewPoint { _matchToolToleranceIndicatorOrigin = PPGeometry_PixelCenteredPoint(viewPoint); _matchToolToleranceIndicatorRadius = 0; if (_matchToolToleranceIndicatorPath) { [_matchToolToleranceIndicatorPath release]; _matchToolToleranceIndicatorPath = nil; } _matchToolToleranceIndicatorDisplayBounds = NSZeroRect; _shouldDisplayMatchToolToleranceIndicator = YES; } - (void) hideMatchToolToleranceIndicator { _shouldDisplayMatchToolToleranceIndicator = NO; [self setNeedsDisplayInRect: _matchToolToleranceIndicatorDisplayBounds]; [_matchToolToleranceIndicatorPath release]; _matchToolToleranceIndicatorPath = nil; _matchToolToleranceIndicatorDisplayBounds = NSZeroRect; } - (void) setMatchToolToleranceIndicatorRadius: (unsigned) radius { NSRect oldDisplayBounds; if (radius > kMatchToolToleranceIndicator_MaxRadius) { radius = kMatchToolToleranceIndicator_MaxRadius; } if (_matchToolToleranceIndicatorRadius == radius) { return; } _matchToolToleranceIndicatorRadius = radius; oldDisplayBounds = _matchToolToleranceIndicatorDisplayBounds; [self setupMatchToolToleranceIndicatorPathAndDisplayBounds]; [self setNeedsDisplayInRect: NSUnionRect(oldDisplayBounds, _matchToolToleranceIndicatorDisplayBounds)]; } - (void) drawMatchToolToleranceIndicator { NSGraphicsContext *currentContext; bool oldShouldAntialias; if (!_shouldDisplayMatchToolToleranceIndicator) return; currentContext = [NSGraphicsContext currentContext]; oldShouldAntialias = [currentContext shouldAntialias]; [currentContext setShouldAntialias: YES]; [_matchToolToleranceIndicatorPath setLineWidth: kIndicatorLineHaloWidth]; [gIndicatorLineHaloColor set]; [_matchToolToleranceIndicatorPath stroke]; [_matchToolToleranceIndicatorPath setLineWidth: kIndicatorLineWidth]; [gIndicatorLineColor set]; [_matchToolToleranceIndicatorPath stroke]; [currentContext setShouldAntialias: oldShouldAntialias]; } #pragma mark Private methods - (void) setupMatchToolToleranceIndicatorPathAndDisplayBounds { NSPoint centerPoint; NSRect circleBounds; float circleRadius, circleDiameter; NSBezierPath *path; centerPoint = _matchToolToleranceIndicatorOrigin; // circle circleRadius = (float) _matchToolToleranceIndicatorRadius; circleBounds.origin = NSMakePoint(centerPoint.x - circleRadius, centerPoint.y - circleRadius); circleDiameter = 2.0f * circleRadius; circleBounds.size = NSMakeSize(circleDiameter, circleDiameter); path = [NSBezierPath bezierPathWithOvalInRect: circleBounds]; // center X [path moveToPoint: NSMakePoint(centerPoint.x - kIndicatorCenterXLegLength, centerPoint.y - kIndicatorCenterXLegLength)]; [path lineToPoint: NSMakePoint(centerPoint.x + kIndicatorCenterXLegLength, centerPoint.y + kIndicatorCenterXLegLength)]; [path moveToPoint: NSMakePoint(centerPoint.x - kIndicatorCenterXLegLength, centerPoint.y + kIndicatorCenterXLegLength)]; [path lineToPoint: NSMakePoint(centerPoint.x + kIndicatorCenterXLegLength, centerPoint.y - kIndicatorCenterXLegLength)]; [_matchToolToleranceIndicatorPath release]; _matchToolToleranceIndicatorPath = [path retain]; _matchToolToleranceIndicatorDisplayBounds = PPGeometry_PixelBoundsCoveredByRect(NSInsetRect([path bounds], -(kIndicatorLineHaloWidth/2.0f), -(kIndicatorLineHaloWidth/2.0f))); } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_MouseCursor.m0000644000076500000240000000447313234403205023213 0ustar joshstaff/* PPCanvasView_MouseCursor.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "PPCursorManager.h" #import "PPPanelsController.h" #import "PPPopupPanelsController.h" @implementation PPCanvasView (MouseCursor) - (void) setToolCursor: (NSCursor *) toolCursor { if (_toolCursor != toolCursor) { [_toolCursor release]; _toolCursor = [toolCursor retain]; } [self updateCursor]; } - (void) updateCursor { NSCursor *cursor = nil; if (![[self window] isKeyWindow]) { return; } if ((_mouseIsInsideVisibleCanvasTrackingRect && !_isScrolling) || _isDraggingTool) { cursor = _toolCursor; } [[PPCursorManager sharedManager] setCursor: cursor atLevel: kPPCursorLevel_CanvasView isDraggingMouse: _isDraggingTool]; } - (void) updateCursorForWindowPoint: (NSPoint) windowPoint { _mouseIsInsideVisibleCanvasTrackingRect = ([self windowPointIsInsideVisibleCanvas: windowPoint] && ![[PPPopupPanelsController sharedController] mouseIsInsideActivePopupPanel] && ![[PPPanelsController sharedController] mouseIsInsideVisiblePanel]) ? YES : NO; [self updateCursor]; } - (void) updateCursorForCurrentMouseLocation { [self updateCursorForWindowPoint: [[self window] mouseLocationOutsideOfEventStream]]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_Notifications.h0000644000076500000240000000222513234403416023526 0ustar joshstaff/* PPCanvasView_Notifications.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" @interface PPCanvasView (Notifications) - (void) postNotification_ChangedZoomFactor; - (void) postNotification_UpdatedNormalizedVisibleBounds; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_Notifications.m0000644000076500000240000000366413234403205023537 0ustar joshstaff/* PPCanvasView_Notifications.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView_Notifications.h" NSString *PPCanvasViewNotification_ChangedZoomFactor = @"PPCanvasViewNotification_ChangedZoomFactor"; NSString *PPCanvasViewNotification_UpdatedNormalizedVisibleBounds = @"PPCanvasViewNotification_UpdatedNormalizedVisibleBounds"; @implementation PPCanvasView (Notifications) - (void) postNotification_ChangedZoomFactor { [[NSNotificationCenter defaultCenter] postNotificationName: PPCanvasViewNotification_ChangedZoomFactor object: self]; } - (void) postNotification_UpdatedNormalizedVisibleBounds { [[NSNotificationCenter defaultCenter] postNotificationName: PPCanvasViewNotification_UpdatedNormalizedVisibleBounds object: self]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_RetinaDrawing.m0000644000076500000240000001074213722777100023471 0ustar joshstaff/* PPCanvasView_RetinaDrawing.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" @interface PPCanvasView (RetinaDrawingPrivateMethods) - (void) setupRetinaDisplayBuffer; - (bool) currentDisplayIsRetina; @end #if !PP_SDK_HAS_BACKINGSCALEFACTOR_METHODS @interface NSWindow (BackingScaleFactorMethodForLegacySDKs) - (CGFloat) backingScaleFactor; @end #endif // !PP_SDK_HAS_BACKINGSCALEFACTOR_METHODS #if !PP_SDK_HAS_NSIMAGEREP_DRAWINRECTFROMRECT_METHOD @interface NSImageRep (DrawInRectFromRectMethodForLegacySDKs) - (BOOL) drawInRect: (NSRect) dstSpacePortionRect fromRect: (NSRect) srcSpacePortionRect operation: (NSCompositingOperation) op fraction: (CGFloat) requestedAlpha respectFlipped: (BOOL) respectContextIsFlipped hints: (NSDictionary *) hints; @end #endif // !PP_SDK_HAS_NSIMAGEREP_DRAWINRECTFROMRECT_METHOD @implementation PPCanvasView (RetinaDrawing) - (void) setupRetinaDrawingForCurrentDisplay { _currentDisplayIsRetina = [self currentDisplayIsRetina]; if (_currentDisplayIsRetina) { [self setupRetinaDisplayBuffer]; } else { [self destroyRetinaDrawingMembers]; } } - (void) setupRetinaDrawingForResizedView; { if (!_currentDisplayIsRetina) return; [self setupRetinaDisplayBuffer]; } - (void) destroyRetinaDrawingMembers { if (!_retinaDisplayBuffer) return; [_retinaDisplayBuffer release]; _retinaDisplayBuffer = nil; } - (void) beginDrawingToRetinaDisplayBufferInRect: (NSRect) rect { NSAffineTransform *transform; if (!_retinaDisplayBuffer) return; [_retinaDisplayBuffer ppSetAsCurrentGraphicsContext]; transform = [NSAffineTransform transform]; [transform translateXBy: -_offsetZoomedVisibleCanvasBounds.origin.x yBy: -_offsetZoomedVisibleCanvasBounds.origin.y]; [transform set]; } - (void) finishDrawingToRetinaDisplayBufferInRect: (NSRect) rect { NSRect bufferRect; if (!_retinaDisplayBuffer) return; [_retinaDisplayBuffer ppRestoreGraphicsContext]; rect = NSIntersectionRect(rect, _offsetZoomedVisibleCanvasBounds); bufferRect.origin = PPGeometry_PointDifference(rect.origin, _offsetZoomedVisibleCanvasBounds.origin); bufferRect.size = rect.size; [_retinaDisplayBuffer drawInRect: rect fromRect: bufferRect operation: NSCompositeCopy fraction: 1.0 respectFlipped: YES hints: nil]; } #pragma mark Private methods - (void) setupRetinaDisplayBuffer { [self destroyRetinaDrawingMembers]; _retinaDisplayBuffer = [[NSBitmapImageRep ppImageBitmapOfSize: _zoomedVisibleImagesSize] retain]; } - (bool) currentDisplayIsRetina { static bool needToCheckBackingScaleFactorSelector = YES, backingScaleFactorSelectorIsSupported = NO; if (needToCheckBackingScaleFactorSelector) { backingScaleFactorSelectorIsSupported = ([NSWindow instancesRespondToSelector: @selector(backingScaleFactor)]) ? YES : NO; needToCheckBackingScaleFactorSelector = NO; } if (!backingScaleFactorSelectorIsSupported || ([[self window] backingScaleFactor] <= 1.0)) { return NO; } return YES; } @end #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_SelectionOutline.m0000644000076500000240000003044413234403205024207 0ustar joshstaff/* PPCanvasView_SelectionOutline.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #import "PPGeometry.h" #define kSelectionOutlinePatternImageName @"marching_ants_pattern" #define kSelectionOutlineAnimationTimerInterval 0.15f #define kSelectionOutlineAnimationPhaseInterval 1.0f static NSColor *gSelectionOutlinePatternColor = nil; static float gSelectionOutlinePatternWidth = 0.0f; @interface PPCanvasView (SelectionOutlinePrivateMethods) - (void) setupSelectionOutlineAnimationTimerForCurrentState; - (void) startSelectionOutlineAnimationTimer; - (void) stopSelectionOutlineAnimationTimer; - (void) selectionOutlineAnimationTimerDidFire: (NSTimer *) theTimer; - (void) setupSelectionOutlinePathsFromSelectionMask: (NSBitmapImageRep *) selectionMask maskBounds: (NSRect) maskBounds; - (void) clearSelectionOutlinePaths; - (void) setupZoomedSelectionOutlinePath; - (void) clearZoomedSelectionOutlinePath; @end @implementation PPCanvasView (SelectionOutline) + (void) initializeSelectionOutline { NSImage *selectionOutlinePatternImage; selectionOutlinePatternImage = [NSImage imageNamed: kSelectionOutlinePatternImageName]; gSelectionOutlinePatternColor = [[NSColor colorWithPatternImage: selectionOutlinePatternImage] retain]; gSelectionOutlinePatternWidth = [selectionOutlinePatternImage size].width; } - (bool) initSelectionOutlineMembers { return YES; } - (void) deallocSelectionOutlineMembers { [self stopSelectionOutlineAnimationTimer]; [self clearSelectionOutlinePaths]; } - (void) setSelectionOutlineToMask: (NSBitmapImageRep *) selectionMask maskBounds: (NSRect) maskBounds { NSRect updateBounds = _zoomedSelectionOutlineDisplayBounds; [self setupSelectionOutlinePathsFromSelectionMask: selectionMask maskBounds: maskBounds]; updateBounds = NSUnionRect(updateBounds, _zoomedSelectionOutlineDisplayBounds); [self setupSelectionOutlineAnimationTimerForCurrentState]; [self setNeedsDisplayInRect: updateBounds]; } - (void) setShouldHideSelectionOutline: (bool) shouldHideSelectionOutline { shouldHideSelectionOutline = (shouldHideSelectionOutline) ? YES : NO; if (shouldHideSelectionOutline == _shouldHideSelectionOutline) { return; } _shouldHideSelectionOutline = shouldHideSelectionOutline; [self setNeedsDisplayInRect: _zoomedSelectionOutlineDisplayBounds]; } - (void) setShouldAnimateSelectionOutline: (bool) shouldAnimateSelectionOutline { _shouldAnimateSelectionOutline = (shouldAnimateSelectionOutline) ? YES : NO; [self setupSelectionOutlineAnimationTimerForCurrentState]; } - (void) updateSelectionOutlineForCurrentVisibleCanvas { [self setupZoomedSelectionOutlinePath]; } - (void) drawSelectionOutline { NSGraphicsContext *graphicsContext; if (!_hasSelectionOutline || _shouldHideSelectionOutline) { return; } // the current implementation of the selection outline path allows the path to extend // one pixel beyond the right & bottom edges of the visible canvas; as a workaround, // set the clipping path to prevent drawing outside the canvas [NSGraphicsContext saveGraphicsState]; [NSBezierPath clipRect: _offsetZoomedVisibleCanvasBounds]; [gSelectionOutlinePatternColor set]; graphicsContext = [NSGraphicsContext currentContext]; [graphicsContext setPatternPhase: _selectionOutlineTopRightAnimationPhase]; [_zoomedSelectionOutlineTopRightPath stroke]; [graphicsContext setPatternPhase: _selectionOutlineBottomLeftAnimationPhase]; [_zoomedSelectionOutlineBottomLeftPath stroke]; [NSGraphicsContext restoreGraphicsState]; } #pragma mark Marching ants timer (animated selection outline) - (void) setupSelectionOutlineAnimationTimerForCurrentState { bool shouldEnableSelectionOutlineAnimationTimer = (_hasSelectionOutline && _shouldAnimateSelectionOutline) ? YES : NO; if (shouldEnableSelectionOutlineAnimationTimer) { if (!_selectionOutlineAnimationTimer) { [self startSelectionOutlineAnimationTimer]; } } else { if (_selectionOutlineAnimationTimer) { [self stopSelectionOutlineAnimationTimer]; } } } - (void) startSelectionOutlineAnimationTimer { if (_selectionOutlineAnimationTimer) return; _selectionOutlineAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval: kSelectionOutlineAnimationTimerInterval target: self selector: @selector(selectionOutlineAnimationTimerDidFire:) userInfo: nil repeats: YES] retain]; } - (void) stopSelectionOutlineAnimationTimer { if (!_selectionOutlineAnimationTimer) return; [_selectionOutlineAnimationTimer invalidate]; [_selectionOutlineAnimationTimer release]; _selectionOutlineAnimationTimer = nil; } - (void) selectionOutlineAnimationTimerDidFire: (NSTimer *) theTimer { if (!_hasSelectionOutline || _shouldHideSelectionOutline || !_shouldAnimateSelectionOutline) { return; } _selectionOutlineTopRightAnimationPhase.x += kSelectionOutlineAnimationPhaseInterval; if (_selectionOutlineTopRightAnimationPhase.x >= gSelectionOutlinePatternWidth) { _selectionOutlineTopRightAnimationPhase.x = 0.0f; } _selectionOutlineBottomLeftAnimationPhase.x = -_selectionOutlineTopRightAnimationPhase.x; [self setNeedsDisplayInRect: _zoomedSelectionOutlineDisplayBounds]; } #pragma mark Private methods - (void) setupSelectionOutlinePathsFromSelectionMask: (NSBitmapImageRep *) selectionMask maskBounds: (NSRect) maskBounds { NSBezierPath *selectionOutlineTopRightPath, *selectionOutlineBottomLeftPath, *selectionOutlinePath; NSRect selectionOutlinePathBounds; [self clearSelectionOutlinePaths]; if (![selectionMask ppIsMaskBitmap]) { return; } selectionOutlineTopRightPath = [NSBezierPath bezierPath]; selectionOutlineBottomLeftPath = [NSBezierPath bezierPath]; [NSBezierPath ppAppendOutlinePathsForMaskBitmap: selectionMask inBounds: maskBounds toTopRightBezierPath: selectionOutlineTopRightPath andBottomLeftBezierPath: selectionOutlineBottomLeftPath]; if ([selectionOutlineTopRightPath isEmpty]) { return; } _selectionOutlineTopRightPath = [selectionOutlineTopRightPath retain]; _selectionOutlineBottomLeftPath = [selectionOutlineBottomLeftPath retain]; _hasSelectionOutline = YES; // edge paths selectionOutlinePathBounds = [_selectionOutlineTopRightPath bounds]; // right edge if (NSMaxX(selectionOutlinePathBounds) >= [selectionMask pixelsWide]) { selectionOutlinePath = [NSBezierPath bezierPath]; [selectionOutlinePath ppAppendRightEdgePathForMaskBitmap: selectionMask]; if (![selectionOutlinePath isEmpty]) { _selectionOutlineRightEdgePath = [selectionOutlinePath retain]; } } // bottom edge if (selectionOutlinePathBounds.origin.y < 1.0f) { selectionOutlinePath = [NSBezierPath bezierPath]; [selectionOutlinePath ppAppendBottomEdgePathForMaskBitmap: selectionMask]; if (![selectionOutlinePath isEmpty]) { _selectionOutlineBottomEdgePath = [selectionOutlinePath retain]; } } [self setupZoomedSelectionOutlinePath]; } - (void) clearSelectionOutlinePaths { if (_selectionOutlineTopRightPath) { [_selectionOutlineTopRightPath release]; _selectionOutlineTopRightPath = nil; } if (_selectionOutlineBottomLeftPath) { [_selectionOutlineBottomLeftPath release]; _selectionOutlineBottomLeftPath = nil; } if (_selectionOutlineRightEdgePath) { [_selectionOutlineRightEdgePath release]; _selectionOutlineRightEdgePath = nil; } if (_selectionOutlineBottomEdgePath) { [_selectionOutlineBottomEdgePath release]; _selectionOutlineBottomEdgePath = nil; } [self clearZoomedSelectionOutlinePath]; _hasSelectionOutline = NO; } - (void) setupZoomedSelectionOutlinePath { NSBezierPath *zoomedSelectionOutlineTopRightPath, *zoomedSelectionOutlineBottomLeftPath, *zoomedSelectionOutlineEdgePath; NSAffineTransform *transform; [self clearZoomedSelectionOutlinePath]; if (!_hasSelectionOutline) return; transform = [NSAffineTransform transform]; zoomedSelectionOutlineTopRightPath = [[_selectionOutlineTopRightPath copy] autorelease]; zoomedSelectionOutlineBottomLeftPath = [[_selectionOutlineBottomLeftPath copy] autorelease]; if (!transform || !zoomedSelectionOutlineTopRightPath || !zoomedSelectionOutlineBottomLeftPath) { return; } [transform translateXBy: _canvasDrawingOffset.x + 0.5f yBy: _canvasDrawingOffset.y - 0.5f]; [transform scaleBy: _zoomFactor]; [zoomedSelectionOutlineTopRightPath transformUsingAffineTransform: transform]; [zoomedSelectionOutlineBottomLeftPath transformUsingAffineTransform: transform]; if (_selectionOutlineRightEdgePath) { transform = [NSAffineTransform transform]; zoomedSelectionOutlineEdgePath = [[_selectionOutlineRightEdgePath copy] autorelease]; if (transform && zoomedSelectionOutlineEdgePath) { [transform translateXBy: _canvasDrawingOffset.x - 0.5f yBy: _canvasDrawingOffset.y - 0.5f]; [transform scaleBy: _zoomFactor]; [zoomedSelectionOutlineEdgePath transformUsingAffineTransform: transform]; [zoomedSelectionOutlineTopRightPath appendBezierPath: zoomedSelectionOutlineEdgePath]; } } if (_selectionOutlineBottomEdgePath) { transform = [NSAffineTransform transform]; zoomedSelectionOutlineEdgePath = [[_selectionOutlineBottomEdgePath copy] autorelease]; if (transform && zoomedSelectionOutlineEdgePath) { [transform translateXBy: _canvasDrawingOffset.x + 0.5f yBy: _canvasDrawingOffset.y + 0.5f]; [transform scaleBy: _zoomFactor]; [zoomedSelectionOutlineEdgePath transformUsingAffineTransform: transform]; [zoomedSelectionOutlineBottomLeftPath appendBezierPath: zoomedSelectionOutlineEdgePath]; } } _zoomedSelectionOutlineTopRightPath = [zoomedSelectionOutlineTopRightPath retain]; _zoomedSelectionOutlineBottomLeftPath = [zoomedSelectionOutlineBottomLeftPath retain]; _zoomedSelectionOutlineDisplayBounds = PPGeometry_PixelBoundsCoveredByRect([zoomedSelectionOutlineTopRightPath bounds]); } - (void) clearZoomedSelectionOutlinePath { if (_zoomedSelectionOutlineTopRightPath) { [_zoomedSelectionOutlineTopRightPath release]; _zoomedSelectionOutlineTopRightPath = nil; } if (_zoomedSelectionOutlineBottomLeftPath) { [_zoomedSelectionOutlineBottomLeftPath release]; _zoomedSelectionOutlineBottomLeftPath = nil; } _zoomedSelectionOutlineDisplayBounds = NSZeroRect; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCanvasView_SelectionToolOverlay.m0000644000076500000240000004662513234403205025057 0ustar joshstaff/* PPCanvasView_SelectionToolOverlay.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCanvasView.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "PPGeometry.h" #import "PPDocument.h" #define kSelectionToolOverlayAddPatternImageName @"selection_tool_overlay_add_pattern" #define kSelectionToolOverlaySubtractPatternImageName \ @"selection_tool_overlay_subtract_pattern" #define kUIColor_SelectionToolOverlayPathFill \ [NSColor ppSRGBColorWithWhite: 0.0f alpha: 0.18f] #define kUIColor_SelectionToolOverlayOutline \ [NSColor ppSRGBColorWithRed: 0.0f green: 0.0f blue: 1.0f alpha: 0.6f] #define kSelectionToolOverlayAnimationTimerInterval (0.1f) #define kSelectionToolOverlayAnimationStartDelayInterval (0.08f) static NSColor *gOverlayAddFillColor = nil, *gOverlaySubtractFillColor = nil, *gOverlayPathFillColor, *gOverlayOutlineColor; static float gSelectionToolOverlayAnimationPatternWidth = 0.0f; @interface PPCanvasView (SelectionToolOverlayPrivateMethods) - (NSRect) visibleDrawingBoundsForPathWithBounds: (NSRect) pathBounds; - (void) setSelectionToolOverlayToPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask toolPath: (NSBezierPath *) toolPath shouldAntialias: (bool) shouldAntialias; - (void) setupSelectionToolOverlayAnimationTimerForCurrentState; - (void) startSelectionToolOverlayAnimationTimer; - (void) stopSelectionToolOverlayAnimationTimer; - (void) selectionToolOverlayAnimationTimerDidFire: (NSTimer *) theTimer; - (void) resetSelectionToolOverlayAnimationStartDate; - (void) clearSelectionToolOverlayAnimationStartDate; @end @implementation PPCanvasView (SelectionToolOverlay) + (void) initializeSelectionToolOverlay { NSImage *patternImage; patternImage = [NSImage imageNamed: kSelectionToolOverlayAddPatternImageName]; gOverlayAddFillColor = [[NSColor colorWithPatternImage: patternImage] retain]; patternImage = [NSImage imageNamed: kSelectionToolOverlaySubtractPatternImageName]; gOverlaySubtractFillColor = [[NSColor colorWithPatternImage: patternImage] retain]; gOverlayPathFillColor = [kUIColor_SelectionToolOverlayPathFill retain]; gOverlayOutlineColor = [kUIColor_SelectionToolOverlayOutline retain]; gSelectionToolOverlayAnimationPatternWidth = [patternImage size].width; } - (bool) initSelectionToolOverlayMembers { _selectionToolOverlayPath_Working = [[NSBezierPath bezierPath] retain]; _selectionToolOverlayPath_AddFill = [[NSBezierPath bezierPath] retain]; _selectionToolOverlayPath_SubtractFill = [[NSBezierPath bezierPath] retain]; _selectionToolOverlayPath_ToolPath = [[NSBezierPath bezierPath] retain]; _selectionToolOverlayPath_Outline = [[NSBezierPath bezierPath] retain]; if (!_selectionToolOverlayPath_Working || !_selectionToolOverlayPath_AddFill || !_selectionToolOverlayPath_SubtractFill || !_selectionToolOverlayPath_ToolPath || !_selectionToolOverlayPath_Outline) { goto ERROR; } return YES; ERROR: return NO; } - (void) deallocSelectionToolOverlayMembers { [self stopSelectionToolOverlayAnimationTimer]; [_selectionToolOverlayPath_Working release]; _selectionToolOverlayPath_Working = nil; [_selectionToolOverlayPath_AddFill release]; _selectionToolOverlayPath_AddFill = nil; [_selectionToolOverlayPath_SubtractFill release]; _selectionToolOverlayPath_SubtractFill = nil; [_selectionToolOverlayPath_ToolPath release]; _selectionToolOverlayPath_ToolPath = nil; [_selectionToolOverlayPath_Outline release]; _selectionToolOverlayPath_Outline = nil; [_selectionToolOverlayWorkingMask release]; _selectionToolOverlayWorkingMask = nil; [_selectionToolOverlayWorkingPathMask release]; _selectionToolOverlayWorkingPathMask = nil; } - (bool) resizeSelectionToolOverlayMasksToSize: (NSSize) size { NSBitmapImageRep *selectionToolOverlayWorkingMask, *selectionToolOverlayWorkingPathMask; if (PPGeometry_IsZeroSize(size)) { goto ERROR; } selectionToolOverlayWorkingMask = [NSBitmapImageRep ppMaskBitmapOfSize: size]; selectionToolOverlayWorkingPathMask = [NSBitmapImageRep ppMaskBitmapOfSize: size]; if (!selectionToolOverlayWorkingMask || !selectionToolOverlayWorkingPathMask) { goto ERROR; } [_selectionToolOverlayWorkingMask release]; _selectionToolOverlayWorkingMask = [selectionToolOverlayWorkingMask retain]; [_selectionToolOverlayWorkingPathMask release]; _selectionToolOverlayWorkingPathMask = [selectionToolOverlayWorkingPathMask retain]; return YES; ERROR: return NO; } - (void) setSelectionToolOverlayToRect: (NSRect) rect selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask toolPathRect: (NSRect) toolPathRect { NSBezierPath *selectionPath, *toolPath; selectionPath = _selectionToolOverlayPath_Working; rect = PPGeometry_PixelCenteredRect(rect); toolPathRect = PPGeometry_PixelCenteredRect(toolPathRect); if (NSEqualRects(rect, toolPathRect)) { toolPath = selectionPath; } else { toolPath = _selectionToolOverlayPath_ToolPath; [toolPath removeAllPoints]; [toolPath appendBezierPathWithRect: toolPathRect]; #if PP_DEPLOYMENT_TARGET_INCORRECTLY_FILLS_PIXEL_CENTERED_RECTS // GNUstep (Cairo?) incorrectly fills pixel-centered rects: corner pixels are left // blank, and the edge pixels are antialiased. // In most cases this issue doesn't appear because a rectangular path-fill is usually // accompanied by a path-stroke, which fixes the edge/corner pixels. // In this case, the fill path (rect) doesn't match the stroke path (toolPathRect), so // rect needs to be converted from pixel-centered to pixel-bounded to properly draw the // edge pixels. rect = PPGeometry_PixelBoundsCoveredByRect(rect); #endif // PP_DEPLOYMENT_TARGET_INCORRECTLY_FILLS_PIXEL_CENTERED_RECTS } [selectionPath removeAllPoints]; [selectionPath appendBezierPathWithRect: rect]; [self setSelectionToolOverlayToPath: selectionPath selectionMode: selectionMode intersectMask: intersectMask toolPath: toolPath shouldAntialias: NO]; } - (void) setSelectionToolOverlayToPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask { [self setSelectionToolOverlayToPath: path selectionMode: selectionMode intersectMask: intersectMask toolPath: path shouldAntialias: YES]; } - (void) setSelectionToolOverlayToMask: (NSBitmapImageRep *) maskBitmap maskBounds: (NSRect) maskBounds selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask { NSRect pathDrawingBounds; NSAffineTransform *transform; NSRect overlayBounds; [_selectionToolOverlayPath_AddFill removeAllPoints]; [_selectionToolOverlayPath_SubtractFill removeAllPoints]; [_selectionToolOverlayPath_Outline removeAllPoints]; if (_shouldDisplaySelectionToolOverlay) { [self setNeedsDisplayInRect: _selectionToolOverlayDisplayBounds]; } [self setShouldHideSelectionOutline: (selectionMode == kPPSelectionMode_Replace) ? YES : NO]; if (![maskBitmap ppIsMaskBitmap]) { goto ERROR; } pathDrawingBounds = maskBounds; if (!_isAutoscrolling) { pathDrawingBounds = [self visibleDrawingBoundsForPathWithBounds: pathDrawingBounds]; } [_selectionToolOverlayPath_Outline ppAppendOutlinePathForMaskBitmap: maskBitmap inBounds: pathDrawingBounds]; switch (selectionMode) { case kPPSelectionMode_Intersect: { if (![intersectMask ppIsMaskBitmap] || !NSEqualSizes([maskBitmap ppSizeInPixels], [intersectMask ppSizeInPixels])) { goto ERROR; } // add path [_selectionToolOverlayWorkingMask ppCopyFromBitmap: maskBitmap inRect: pathDrawingBounds toPoint: pathDrawingBounds.origin]; [_selectionToolOverlayWorkingMask ppIntersectMaskWithMaskBitmap: intersectMask inBounds: pathDrawingBounds]; [_selectionToolOverlayPath_AddFill ppAppendFillPathForMaskBitmap: _selectionToolOverlayWorkingMask inBounds: pathDrawingBounds]; // subtract path [_selectionToolOverlayWorkingMask ppCopyFromBitmap: maskBitmap inRect: pathDrawingBounds toPoint: pathDrawingBounds.origin]; [_selectionToolOverlayWorkingMask ppSubtractMaskBitmap: intersectMask inBounds: pathDrawingBounds]; [_selectionToolOverlayPath_SubtractFill ppAppendFillPathForMaskBitmap: _selectionToolOverlayWorkingMask inBounds: pathDrawingBounds]; } break; case kPPSelectionMode_Subtract: { [_selectionToolOverlayPath_SubtractFill ppAppendFillPathForMaskBitmap: maskBitmap inBounds: pathDrawingBounds]; } break; default: { [_selectionToolOverlayPath_AddFill ppAppendFillPathForMaskBitmap: maskBitmap inBounds: pathDrawingBounds]; } break; } transform = [NSAffineTransform transform]; if (!transform) return; [transform translateXBy: _canvasDrawingOffset.x + 0.5f yBy: _canvasDrawingOffset.y - 0.5f]; [transform scaleBy: _zoomFactor]; [_selectionToolOverlayPath_Outline transformUsingAffineTransform: transform]; overlayBounds = NSZeroRect; if (![_selectionToolOverlayPath_AddFill isEmpty]) { [_selectionToolOverlayPath_AddFill transformUsingAffineTransform: transform]; overlayBounds = [_selectionToolOverlayPath_AddFill bounds]; } if (![_selectionToolOverlayPath_SubtractFill isEmpty]) { [_selectionToolOverlayPath_SubtractFill transformUsingAffineTransform: transform]; overlayBounds = NSUnionRect(overlayBounds, [_selectionToolOverlayPath_SubtractFill bounds]); } if (![_selectionToolOverlayPath_ToolPath isEmpty]) { [_selectionToolOverlayPath_ToolPath transformUsingAffineTransform: transform]; } _selectionToolOverlayDisplayBounds = PPGeometry_PixelBoundsCoveredByRect(overlayBounds); if (!_autoscrollingIsEnabled) { NSRect visibleClippingBounds; // allow the outline to extend one pixel beyond the right & bottom canvas edges visibleClippingBounds = _offsetZoomedVisibleCanvasBounds; visibleClippingBounds.size.width += 1.0f; visibleClippingBounds.origin.y -= 1.0f; visibleClippingBounds.size.height += 1.0f; _selectionToolOverlayDisplayBounds = NSIntersectionRect(_selectionToolOverlayDisplayBounds, visibleClippingBounds); } _shouldDisplaySelectionToolOverlay = (NSIsEmptyRect(_selectionToolOverlayDisplayBounds)) ? NO : YES; if (_shouldDisplaySelectionToolOverlay) { [self setNeedsDisplayInRect: _selectionToolOverlayDisplayBounds]; } [self setupSelectionToolOverlayAnimationTimerForCurrentState]; return; ERROR: [self clearSelectionToolOverlay]; return; } - (void) clearSelectionToolOverlay { [self stopSelectionToolOverlayAnimationTimer]; [_selectionToolOverlayPath_AddFill removeAllPoints]; [_selectionToolOverlayPath_SubtractFill removeAllPoints]; [_selectionToolOverlayPath_Outline removeAllPoints]; [_selectionToolOverlayPath_ToolPath removeAllPoints]; if (_shouldDisplaySelectionToolOverlay) { [self setNeedsDisplayInRect: _selectionToolOverlayDisplayBounds]; } _shouldDisplaySelectionToolOverlay = NO; _selectionToolOverlayDisplayBounds = NSZeroRect; [self setShouldHideSelectionOutline: NO]; } - (void) drawSelectionToolOverlay { if (!_shouldDisplaySelectionToolOverlay) return; [[NSGraphicsContext currentContext] setPatternPhase: _selectionToolOverlayAnimationPhase]; [gOverlayAddFillColor set]; [_selectionToolOverlayPath_AddFill fill]; [gOverlaySubtractFillColor set]; [_selectionToolOverlayPath_SubtractFill fill]; [gOverlayPathFillColor set]; [_selectionToolOverlayPath_ToolPath fill]; [gOverlayOutlineColor set]; [_selectionToolOverlayPath_Outline stroke]; } #pragma mark Private methods - (NSRect) visibleDrawingBoundsForPathWithBounds: (NSRect) pathBounds { // outset drawing bounds from _visibleCanvasBounds by 2.0 in both directions - the extra // (single-pixel) border around the visible canvas prevents false (cropped) path edges // from appearing on the window NSRect visibleCanvasDrawingBounds = NSIntersectionRect(NSInsetRect(_visibleCanvasBounds, -2.0f, -2.0f), _canvasFrame); return NSIntersectionRect(visibleCanvasDrawingBounds, pathBounds); } - (void) setSelectionToolOverlayToPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask toolPath: (NSBezierPath *) toolPath shouldAntialias: (bool) shouldAntialias { NSRect pathDrawingBounds, toolPathDrawingBounds; pathDrawingBounds = PPGeometry_PixelBoundsCoveredByRect([path bounds]); if (!_isAutoscrolling) { pathDrawingBounds = [self visibleDrawingBoundsForPathWithBounds: pathDrawingBounds]; } if (toolPath == path) { toolPathDrawingBounds = pathDrawingBounds; } else { toolPathDrawingBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect([toolPath bounds]), pathDrawingBounds); } [_selectionToolOverlayWorkingPathMask ppClearBitmapInBounds: pathDrawingBounds]; [_selectionToolOverlayWorkingPathMask ppSetAsCurrentGraphicsContext]; [[NSColor ppMaskBitmapOnColor] set]; [toolPath stroke]; [_selectionToolOverlayPath_ToolPath removeAllPoints]; [_selectionToolOverlayPath_ToolPath ppAppendFillPathForMaskBitmap: _selectionToolOverlayWorkingPathMask inBounds: toolPathDrawingBounds]; if (shouldAntialias) { // antialiasing is necessary when filling a non-rectangular path, otherwise the fill // will cover a larger area than the stroke (some curve edges will add a pixel); // make sure to correct the antialiasing afterwards by thresholding the mask's pixel // values to 0 & 255 [path ppAntialiasedFill]; } else { [path fill]; } [_selectionToolOverlayWorkingPathMask ppRestoreGraphicsContext]; if (shouldAntialias) { [_selectionToolOverlayWorkingPathMask ppThresholdMaskBitmapPixelValuesInBounds: pathDrawingBounds]; } [self setSelectionToolOverlayToMask: _selectionToolOverlayWorkingPathMask maskBounds: pathDrawingBounds selectionMode: selectionMode intersectMask: intersectMask]; } #pragma mark Animation timer - (void) setupSelectionToolOverlayAnimationTimerForCurrentState { if (_shouldDisplaySelectionToolOverlay) { [self resetSelectionToolOverlayAnimationStartDate]; if (!_selectionToolOverlayAnimationTimer) { [self startSelectionToolOverlayAnimationTimer]; } } else { [self clearSelectionToolOverlayAnimationStartDate]; if (_selectionToolOverlayAnimationTimer) { [self stopSelectionToolOverlayAnimationTimer]; } } } - (void) startSelectionToolOverlayAnimationTimer { if (_selectionToolOverlayAnimationTimer) return; _selectionToolOverlayAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval: kSelectionToolOverlayAnimationTimerInterval target: self selector: @selector(selectionToolOverlayAnimationTimerDidFire:) userInfo: nil repeats: YES] retain]; } - (void) stopSelectionToolOverlayAnimationTimer { if (_selectionToolOverlayAnimationStartDate) { [self clearSelectionToolOverlayAnimationStartDate]; } if (!_selectionToolOverlayAnimationTimer) return; [_selectionToolOverlayAnimationTimer invalidate]; [_selectionToolOverlayAnimationTimer release]; _selectionToolOverlayAnimationTimer = nil; } - (void) selectionToolOverlayAnimationTimerDidFire: (NSTimer *) theTimer { if (!_shouldDisplaySelectionToolOverlay) return; if (_selectionToolOverlayAnimationStartDate && ([_selectionToolOverlayAnimationStartDate timeIntervalSinceNow] > 0.0f)) { return; } _selectionToolOverlayAnimationPhase.x += 1.0; if (_selectionToolOverlayAnimationPhase.x >= gSelectionToolOverlayAnimationPatternWidth) { _selectionToolOverlayAnimationPhase.x = 0.0f; } [self setNeedsDisplayInRect: _selectionToolOverlayDisplayBounds]; } - (void) resetSelectionToolOverlayAnimationStartDate { if (_selectionToolOverlayAnimationStartDate) { [_selectionToolOverlayAnimationStartDate release]; } _selectionToolOverlayAnimationStartDate = [[NSDate dateWithTimeIntervalSinceNow: kSelectionToolOverlayAnimationStartDelayInterval] retain]; } - (void) clearSelectionToolOverlayAnimationStartDate { if (!_selectionToolOverlayAnimationStartDate) return; [_selectionToolOverlayAnimationStartDate release]; _selectionToolOverlayAnimationStartDate = nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorPickerPopupPanel.h0000644000076500000240000000256113234403416023012 0ustar joshstaff/* PPColorPickerPopupPanel.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanel.h" @interface PPColorPickerPopupPanel : PPPopupPanel { } @end @interface NSObject (PPColorPickerPopupPanelDelegateMethods) - (void) colorPickerPopupPanelWillBeginHandlingMouseDownEvent: (PPColorPickerPopupPanel *) panel atLocation: (NSPoint) windowLocation; - (void) colorPickerPopupPanelDidFinishHandlingMouseDownEvent: (PPColorPickerPopupPanel *) panel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorPickerPopupPanel.m0000644000076500000240000000522313234403205023011 0ustar joshstaff/* PPColorPickerPopupPanel.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPColorPickerPopupPanel.h" #import "NSObject_PPUtilities.h" @interface PPColorPickerPopupPanel (PrivateMethods) - (void) notifyDelegateWillBeginHandlingMouseDownEventAtLocation: (NSPoint) windowLocation; - (void) notifyDelegateDidFinishHandlingMouseDownEvent; @end @implementation PPColorPickerPopupPanel #pragma mark NSPanel overrides - (void) sendEvent: (NSEvent *) theEvent { NSEventType eventType = [theEvent type]; if (eventType == NSLeftMouseDown) { [self notifyDelegateWillBeginHandlingMouseDownEventAtLocation: [theEvent locationInWindow]]; [super sendEvent: theEvent]; [self ppPerformSelectorFromNewStackFrame: @selector(notifyDelegateDidFinishHandlingMouseDownEvent)]; } else { [super sendEvent: theEvent]; } } #pragma mark Delegate notifiers - (void) notifyDelegateWillBeginHandlingMouseDownEventAtLocation: (NSPoint) windowLocation { id delegate = [self delegate]; if ([delegate respondsToSelector: @selector(colorPickerPopupPanelWillBeginHandlingMouseDownEvent: atLocation:)]) { [delegate colorPickerPopupPanelWillBeginHandlingMouseDownEvent: self atLocation: windowLocation]; } } - (void) notifyDelegateDidFinishHandlingMouseDownEvent { id delegate = [self delegate]; if ([delegate respondsToSelector: @selector(colorPickerPopupPanelDidFinishHandlingMouseDownEvent:)]) { [delegate colorPickerPopupPanelDidFinishHandlingMouseDownEvent: self]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorPickerPopupPanelController.h0000644000076500000240000000360313234403416025054 0ustar joshstaff/* PPColorPickerPopupPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanelController.h" @interface PPColorPickerPopupPanelController : PPPopupPanelController { IBOutlet NSColorWell *_colorWell; IBOutlet NSButton *_nekoButton; IBOutlet NSButton *_previousSamplerImageButton; IBOutlet NSButton *_nextSamplerImageButton; IBOutlet NSView *_clickableControlsBoundsTrackingView; NSTrackingRectTag _clickableControlsBoundsTrackingRectTag; NSSize _colorPanelFrameSize; NSSize _colorPanelContentSize; int _colorPanelMode; NSRect _oldColorPanelFrame; int _oldColorPanelMode; bool _needToReactivateToolPanelColorWell; bool _needToSaveColorPanelContentSizeToDefaults; bool _colorPanelIsChildWindow; } - (IBAction) colorWellUpdated: (id) sender; - (IBAction) contentFrameButtonPressed: (id) sender; - (IBAction) previousSamplerImageButtonPressed: (id) sender; - (IBAction) nextSamplerImageButtonPressed: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorPickerPopupPanelController.m0000644000076500000240000004074113234403205025061 0ustar joshstaff/* PPColorPickerPopupPanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPColorPickerPopupPanelController.h" #import "PPColorPickerPopupPanel.h" #import "PPDocument.h" #import "PPToolsPanelController.h" #import "PPUserDefaults.h" #import "PPUIColors_Panels.h" #import "PPPopupPanelsController.h" #import "PPPopupPanelActionKeys.h" #import "NSObject_PPUtilities.h" #import "PPGeometry.h" #define kColorPickerPopupPanelNibName @"ColorPickerPopupPanel" #define kColorPickerPopupPanelBorderThickness 20.0f @interface PPColorPickerPopupPanelController (PrivateMethods) - (void) handlePPDocumentNotification_ChangedFillColor: (NSNotification *) notification; - (void) addAsObserverForNSColorPanelNotifications; - (void) removeAsObserverForNSColorPanelNotifications; - (void) handleNSColorPanelNotification_WillMove: (NSNotification *) notification; - (void) handleNSColorPanelNotification_DidResize: (NSNotification *) notification; - (void) handleNSColorPanelNotification_WillClose: (NSNotification *) notification; - (void) setupClickableControlsMouseTracking; - (void) mouseEntered: (NSEvent *) theEvent; - (void) mouseExited: (NSEvent *) theEvent; - (void) updateDocumentFillColor; - (void) updatePopupPanelSizeForColorPanelFrameSize; - (void) updatePopupPanelPositionForColorPanelPosition; - (void) updateColorWellColor; - (void) updateSamplerImageButtonsVisibility; - (void) setColorPanelAsPopupChildWindow: (bool) shouldSetColorPanelAsChildWindow; @end @implementation PPColorPickerPopupPanelController #pragma mark Actions - (IBAction) colorWellUpdated: (id) sender { [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(updateDocumentFillColor)]; } - (IBAction) contentFrameButtonPressed: (id) sender { NSColorPanel *sharedColorPanel = [NSColorPanel sharedColorPanel]; if ([sharedColorPanel isVisible]) { [sharedColorPanel orderFront: self]; } } - (IBAction) previousSamplerImageButtonPressed: (id) sender { [[PPPopupPanelsController sharedController] positionNextActivePopupAtCurrentPopupOrigin]; [_ppDocument activatePreviousSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; } - (IBAction) nextSamplerImageButtonPressed: (id) sender { [[PPPopupPanelsController sharedController] positionNextActivePopupAtCurrentPopupOrigin]; [_ppDocument activateNextSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; } #pragma mark NSWindowController overrides - (void) windowDidLoad { [super windowDidLoad]; _colorPanelMode = [PPUserDefaults colorPickerPopupPanelMode]; _colorPanelContentSize = [PPUserDefaults colorPickerPopupPanelContentSize]; [_nekoButton setHidden: YES]; } #pragma mark PPPopupPanelController overrides + (NSString *) panelNibName { return kColorPickerPopupPanelNibName; } - (void) setPanelEnabled: (bool) enablePanel { bool popupPanelIsVisible = [self panelIsVisible]; if (enablePanel && !popupPanelIsVisible) { NSColorPanel *colorPanel; NSSize colorPanelFrameSize, colorPanelContentSize; NSPoint colorPanelOrigin; colorPanel = [NSColorPanel sharedColorPanel]; [colorPanel orderOut: self]; _oldColorPanelFrame = [colorPanel frame]; _oldColorPanelMode = [colorPanel mode]; // make sure panel is loaded before accessing IBOutlets if (!_panelDidLoad) { [self window]; } [self updateColorWellColor]; [self updateSamplerImageButtonsVisibility]; // mode should be set before content size, otherwise frame may be resized because it // doesn't fit the initial (wrong) mode [colorPanel setMode: _colorPanelMode]; [colorPanel setContentSize: _colorPanelContentSize]; colorPanelFrameSize = [colorPanel frame].size; if (!NSEqualSizes(_colorPanelFrameSize, colorPanelFrameSize)) { _colorPanelFrameSize = colorPanelFrameSize; [self updatePopupPanelSizeForColorPanelFrameSize]; } colorPanelContentSize = [[colorPanel contentView] frame].size; if (!NSEqualSizes(_colorPanelContentSize, colorPanelContentSize)) { _colorPanelContentSize = colorPanelContentSize; _needToSaveColorPanelContentSizeToDefaults = YES; } [super setPanelEnabled: enablePanel]; colorPanelOrigin = [[self window] frame].origin; colorPanelOrigin.x += kColorPickerPopupPanelBorderThickness; colorPanelOrigin.y += kColorPickerPopupPanelBorderThickness; [colorPanel setFrameOrigin: colorPanelOrigin]; _needToReactivateToolPanelColorWell = [[PPToolsPanelController sharedController] fillColorWellIsActive]; [_colorWell activate: YES]; [colorPanel orderFront: self]; // setup clickable controls mouse tracking only after showing the color panel, // otherwise the color panel may show briefly in its old location when the setup // makes the color panel the child window of the popup panel [self setupClickableControlsMouseTracking]; [self addAsObserverForNSColorPanelNotifications]; [_nekoButton setHidden: NO]; } else if (!enablePanel && popupPanelIsVisible) { NSColorPanel *colorPanel; int initialColorPanelMode; colorPanel = [NSColorPanel sharedColorPanel]; [self removeAsObserverForNSColorPanelNotifications]; [_nekoButton setHidden: YES]; [self setColorPanelAsPopupChildWindow: NO]; [colorPanel endEditingFor: nil]; initialColorPanelMode = _colorPanelMode; _colorPanelMode = [colorPanel mode]; if (_colorPanelMode != initialColorPanelMode) { [PPUserDefaults setColorPickerPopupPanelMode: _colorPanelMode]; } if (_needToSaveColorPanelContentSizeToDefaults) { [PPUserDefaults setColorPickerPopupPanelContentSize: _colorPanelContentSize]; _needToSaveColorPanelContentSizeToDefaults = NO; } [super setPanelEnabled: enablePanel]; [self setupClickableControlsMouseTracking]; if ([_colorWell isActive]) { [_colorWell deactivate]; } if (!NSIsEmptyRect(_oldColorPanelFrame)) { [colorPanel setMode: _oldColorPanelMode]; [colorPanel setFrame: _oldColorPanelFrame display: YES]; } if (_needToReactivateToolPanelColorWell) { [[PPToolsPanelController sharedController] activateFillColorWell]; } else if ([[PPToolsPanelController sharedController] fillColorWellIsActive]) { [NSApp orderFrontColorPanel: self]; } } else { [super setPanelEnabled: enablePanel]; } } - (void) addAsObserverForPPDocumentNotifications { if (!_ppDocument) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPDocumentNotification_ChangedFillColor:) name: PPDocumentNotification_ChangedFillColor object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPDocumentNotification_ChangedFillColor object: _ppDocument]; } - (NSColor *) backgroundColorForPopupPanel { return kUIColor_ColorPickerPopupPanel_Background; } - (bool) handleActionKey: (NSString *) key { if ([key isEqualToString: kColorsPopupPanelActionKey_NextSamplerImage]) { [_ppDocument activateNextSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; return YES; } return NO; } - (void) handleDirectionCommand: (PPDirectionType) directionType { if (directionType == kPPDirectionType_Right) { [_ppDocument activateNextSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; } else if (directionType == kPPDirectionType_Left) { [_ppDocument activatePreviousSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; } } #pragma mark PPColorPickerPopupPanel delegate methods - (void) colorPickerPopupPanelDidFinishHandlingMouseDownEvent: (PPColorPickerPopupPanel *) panel { if ([self panelIsVisible]) { if (![_colorWell isActive]) { [_colorWell activate: YES]; } [[NSColorPanel sharedColorPanel] orderFront: self]; } } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_ChangedFillColor: (NSNotification *) notification { [self updateColorWellColor]; } #pragma mark NSColorPanel notifications - (void) addAsObserverForNSColorPanelNotifications { NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel]; [defaultCenter addObserver: self selector: @selector(handleNSColorPanelNotification_WillMove:) name: NSWindowWillMoveNotification object: colorPanel]; [defaultCenter addObserver: self selector: @selector(handleNSColorPanelNotification_DidResize:) name: NSWindowDidResizeNotification object: colorPanel]; [defaultCenter addObserver: self selector: @selector(handleNSColorPanelNotification_WillClose:) name: NSWindowWillCloseNotification object: colorPanel]; } - (void) removeAsObserverForNSColorPanelNotifications { NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel]; [defaultCenter removeObserver: self name: NSWindowWillMoveNotification object: colorPanel]; [defaultCenter removeObserver: self name: NSWindowDidResizeNotification object: colorPanel]; [defaultCenter removeObserver: self name: NSWindowWillCloseNotification object: colorPanel]; } - (void) handleNSColorPanelNotification_WillMove: (NSNotification *) notification { NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel]; _oldColorPanelFrame = [colorPanel frame]; _oldColorPanelMode = [colorPanel mode]; _needToReactivateToolPanelColorWell = YES; } - (void) handleNSColorPanelNotification_DidResize: (NSNotification *) notification { NSColorPanel *colorPanel; NSSize colorPanelContentSize; colorPanel = [NSColorPanel sharedColorPanel]; colorPanelContentSize = [[colorPanel contentView] frame].size; if (!NSEqualSizes(_colorPanelContentSize, colorPanelContentSize)) { _colorPanelContentSize = colorPanelContentSize; _needToSaveColorPanelContentSizeToDefaults = YES; } _colorPanelFrameSize = [colorPanel frame].size; [self updatePopupPanelSizeForColorPanelFrameSize]; [self updatePopupPanelPositionForColorPanelPosition]; [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(setupClickableControlsMouseTracking)]; } - (void) handleNSColorPanelNotification_WillClose: (NSNotification *) notification { [self setPanelEnabled: NO]; } #pragma mark Clickable controls mouse tracking - (void) setupClickableControlsMouseTracking { if (_clickableControlsBoundsTrackingRectTag) { [_clickableControlsBoundsTrackingView removeTrackingRect: _clickableControlsBoundsTrackingRectTag]; _clickableControlsBoundsTrackingRectTag = 0; } if ([self panelIsVisible]) { NSPoint mouseLocationInWindow; NSRect trackingRect; bool mouseIsInsideTrackingRect; mouseLocationInWindow = [[self window] mouseLocationOutsideOfEventStream]; trackingRect = [_clickableControlsBoundsTrackingView frame]; mouseIsInsideTrackingRect = (NSPointInRect(mouseLocationInWindow, trackingRect)) ? YES : NO; _clickableControlsBoundsTrackingRectTag = [_clickableControlsBoundsTrackingView addTrackingRect: trackingRect owner: self userData: NULL assumeInside: mouseIsInsideTrackingRect]; [self setColorPanelAsPopupChildWindow: mouseIsInsideTrackingRect]; } } - (void) mouseEntered: (NSEvent *) theEvent { NSTrackingRectTag trackingRectTag = [theEvent trackingNumber]; if (trackingRectTag != _clickableControlsBoundsTrackingRectTag) { return; } if (![_colorWell isActive]) { [_colorWell activate: YES]; } // when the mouse is inside the clickable controls bounds tracking rect (which loosely // bounds the arrow buttons & the color panel's resize control), setting the color panel // to be a child window of the popup forces the popup to always stay behind the color panel, // so that mouseclicks on the popup won't bring it to the front and obscure the color panel [self setColorPanelAsPopupChildWindow: YES]; } - (void) mouseExited: (NSEvent *) theEvent { NSTrackingRectTag trackingRectTag = [theEvent trackingNumber]; if (trackingRectTag != _clickableControlsBoundsTrackingRectTag) { return; } if (![_colorWell isActive]) { [_colorWell activate: YES]; } // when the mouse is outside the clickable controls bounds tracking rect (out of range of // clickable controls), remove the color panel as a child window of the popup panel so that // a mouseclick on the popup can bring it to the front & reveal the neko image easter egg [self setColorPanelAsPopupChildWindow: NO]; } #pragma mark Private methods - (void) updateDocumentFillColor { [_ppDocument setFillColor: [_colorWell color]]; } - (void) updatePopupPanelSizeForColorPanelFrameSize { static NSSize popupPanelMarginSize = {2.0f * kColorPickerPopupPanelBorderThickness, 2.0f * kColorPickerPopupPanelBorderThickness}; NSSize newPopupPanelSize = PPGeometry_SizeSum(_colorPanelFrameSize, popupPanelMarginSize); [[self window] setContentSize: newPopupPanelSize]; } - (void) updatePopupPanelPositionForColorPanelPosition { NSPoint newPopupPanelOrigin; newPopupPanelOrigin = [[NSColorPanel sharedColorPanel] frame].origin; newPopupPanelOrigin.x -= kColorPickerPopupPanelBorderThickness; newPopupPanelOrigin.y -= kColorPickerPopupPanelBorderThickness; [[self window] setFrameOrigin: newPopupPanelOrigin]; } - (void) updateColorWellColor { [_colorWell setColor: [_ppDocument fillColor]]; } - (void) updateSamplerImageButtonsVisibility { bool shouldHideButtons = ([_ppDocument numSamplerImages] <= 0) ? YES : NO; [_previousSamplerImageButton setHidden: shouldHideButtons]; [_nextSamplerImageButton setHidden: shouldHideButtons]; } - (void) setColorPanelAsPopupChildWindow: (bool) shouldSetColorPanelAsChildWindow { NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel]; if (shouldSetColorPanelAsChildWindow) { if (_colorPanelIsChildWindow) return; [[self window] addChildWindow: colorPanel ordered: NSWindowAbove]; _colorPanelIsChildWindow = YES; } else { if (!_colorPanelIsChildWindow) return; [[self window] removeChildWindow: colorPanel]; _colorPanelIsChildWindow = NO; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorRampTool.h0000644000076500000240000000206513234403416021325 0ustar joshstaff/* PPColorRampTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPColorRampTool : PPTool { NSColor *_startColor; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorRampTool.m0000644000076500000240000000743213234403205021331 0ustar joshstaff/* PPColorRampTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPColorRampTool.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "NSCursor_PPUtilities.h" #define kColorRampToolAttributesMask \ (kPPToolAttributeMask_RequiresPointsCroppedToCanvasBounds \ | kPPToolAttributeMask_MatchCanvasDisplayModeToOperationTarget) @interface PPColorRampTool (PrivateMethods) - (void) clearStartColor; @end @implementation PPColorRampTool - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSRect rampBounds; NSBitmapImageRep *drawMask; [self clearStartColor]; _startColor = [[ppDocument colorAtPoint: currentPoint inTarget: [ppDocument layerOperationTarget]] retain]; [ppDocument beginDrawingWithPenMode: kPPPenMode_Fill]; [ppDocument drawColorRampWithStartingColor: _startColor fromPoint: currentPoint toPoint: currentPoint returnedRampBounds: &rampBounds returnedDrawMask: &drawMask]; [canvasView setColorRampToolOverlayToMask: drawMask maskBounds: rampBounds]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSRect rampBounds; NSBitmapImageRep *drawMask; if (NSEqualPoints(currentPoint, lastPoint)) { return; } [ppDocument undoCurrentDrawingAtNextDraw]; [ppDocument drawColorRampWithStartingColor: _startColor fromPoint: mouseDownPoint toPoint: currentPoint returnedRampBounds: &rampBounds returnedDrawMask: &drawMask]; [canvasView setColorRampToolOverlayToMask: drawMask maskBounds: rampBounds]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [ppDocument finishDrawing]; [canvasView clearColorRampToolOverlay]; [self clearStartColor]; } - (NSCursor *) cursor { return [NSCursor ppColorRampToolCursor]; } - (unsigned) toolAttributeFlags { return kColorRampToolAttributesMask; } #pragma mark Private methods - (void) clearStartColor { if (!_startColor) return; [_startColor release]; _startColor = nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorSamplerTool.h0000644000076500000240000000210113234403416022020 0ustar joshstaff/* PPColorSamplerTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPColorSamplerTool : PPTool { NSColor *_initialFillColor; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorSamplerTool.m0000644000076500000240000000651213234403205022033 0ustar joshstaff/* PPColorSamplerTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPColorSamplerTool.h" #import "PPDocument.h" #import "NSCursor_PPUtilities.h" #define kColorSamplerToolAttributesMask \ (kPPToolAttributeMask_RequiresPointsCroppedToCanvasBounds \ | kPPToolAttributeMask_MatchCanvasDisplayModeToOperationTarget) @implementation PPColorSamplerTool - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSColor *fillColor; _initialFillColor = [[ppDocument fillColor] retain]; fillColor = [ppDocument colorAtPoint: currentPoint inTarget: [ppDocument layerOperationTarget]]; [ppDocument setFillColorWithoutUndoRegistration: fillColor]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSColor *fillColor; if (NSEqualPoints(currentPoint, lastPoint)) { return; } fillColor = [ppDocument colorAtPoint: currentPoint inTarget: [ppDocument layerOperationTarget]]; [ppDocument setFillColorWithoutUndoRegistration: fillColor]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSColor *fillColor; fillColor = [ppDocument colorAtPoint: currentPoint inTarget: [ppDocument layerOperationTarget]]; // restore the initial fill color before setting the new fill color so the undo manager can // register the correct previous color [ppDocument setFillColorWithoutUndoRegistration: _initialFillColor]; [ppDocument setFillColor: fillColor]; [_initialFillColor release]; _initialFillColor = nil; } - (NSCursor *) cursor { return [NSCursor ppColorSamplerToolCursor]; } - (unsigned) toolAttributeFlags { return kColorSamplerToolAttributesMask; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorWell.h0000644000076500000240000000203513234403416020470 0ustar joshstaff/* PPColorWell.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPColorWell : NSColorWell { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPColorWell.m0000644000076500000240000000250413234403205020472 0ustar joshstaff/* PPColorWell.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPColorWell.h" @implementation PPColorWell - (void) deactivate { NSColorPanel *sharedColorPanel; [super deactivate]; // Hide the shared color panel when the color well is deactivated sharedColorPanel = [NSColorPanel sharedColorPanel]; if ([sharedColorPanel isVisible]) { [sharedColorPanel orderOut: self]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCompositeThumbnail.h0000644000076500000240000000264413234403416022402 0ustar joshstaff/* PPCompositeThumbnail.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPCompositeThumbnail : NSObject { NSBitmapImageRep *_compositeBitmap; NSImage *_compositeImage; NSPoint _thumbnailOrigin; } + compositeThumbnailFromView: (NSView *) view thumbnailOrigin: (NSPoint) thumbnailOrigin; - initWithView: (NSView *) view thumbnailOrigin: (NSPoint) thumbnailOrigin; - (void) setThumbnailBitmap: (NSBitmapImageRep *) thumbnailBitmap; - (NSImage *) compositeImage; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCompositeThumbnail.m0000644000076500000240000000520213234403205022374 0ustar joshstaff/* PPCompositeThumbnail.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCompositeThumbnail.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" @implementation PPCompositeThumbnail + compositeThumbnailFromView: (NSView *) view thumbnailOrigin: (NSPoint) thumbnailOrigin { return [[[self alloc] initWithView: view thumbnailOrigin: thumbnailOrigin] autorelease]; } - initWithView: (NSView *) view thumbnailOrigin: (NSPoint) thumbnailOrigin { NSRect viewBounds; NSBitmapImageRep *compositeBitmap; NSImage *compositeImage; self = [super init]; if (!self) goto ERROR; if (!view) goto ERROR; viewBounds = [view bounds]; if (NSIsEmptyRect(viewBounds)) { goto ERROR; } compositeBitmap = [NSBitmapImageRep ppImageBitmapOfSize: viewBounds.size]; if (!compositeBitmap) goto ERROR; compositeImage = [NSImage ppImageWithBitmap: compositeBitmap]; if (!compositeImage) goto ERROR; [view cacheDisplayInRect: viewBounds toBitmapImageRep: compositeBitmap]; [compositeImage recache]; _compositeBitmap = [compositeBitmap retain]; _compositeImage = [compositeImage retain]; _thumbnailOrigin = thumbnailOrigin; return self; ERROR: [self release]; return nil; } - init { return [self initWithView: nil thumbnailOrigin: NSZeroPoint]; } - (void) dealloc { [_compositeBitmap release]; [_compositeImage release]; [super dealloc]; } - (void) setThumbnailBitmap: (NSBitmapImageRep *) thumbnailBitmap { [_compositeBitmap ppCopyFromBitmap: thumbnailBitmap toPoint: _thumbnailOrigin]; [_compositeImage recache]; } - (NSImage *) compositeImage { return _compositeImage; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCursorDefines.h0000644000076500000240000000564713234403416021355 0ustar joshstaff/* PPCursorDefines.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #define kPPCursorImageName_Pencil @"pencil_cursor.png" #define kPPCursorHotSpotPoint_Pencil NSMakePoint(1.0f, 20.0f) #define kPPCursorImageName_Eraser @"eraser_cursor.png" #define kPPCursorHotSpotPoint_Eraser NSMakePoint(4.0f, 4.0f) #define kPPCursorImageName_FillBucket @"paintcan_cursor.png" #define kPPCursorHotSpotPoint_FillBucket NSMakePoint(3.0f, 20.0f) #define kPPCursorImageName_LineTool @"line_cursor.png" #define kPPCursorHotSpotPoint_LineTool NSMakePoint(3.0f, 1.0f) #define kPPCursorImageName_RectTool @"rect_cursor.png" #define kPPCursorHotSpotPoint_RectTool NSMakePoint(3.0f, 1.0f) #define kPPCursorImageName_OvalTool @"oval_cursor.png" #define kPPCursorHotSpotPoint_OvalTool NSMakePoint(3.0f, 1.0f) #define kPPCursorImageName_FreehandSelect @"freehand_select_cursor.png" #define kPPCursorHotSpotPoint_FreehandSelect NSMakePoint(3.0f, 1.0f) #define kPPCursorImageName_RectSelect @"selection_rect_cursor.png" #define kPPCursorHotSpotPoint_RectSelect NSMakePoint(3.0f, 1.0f) #define kPPCursorImageName_MagicWand @"wand_cursor.png" #define kPPCursorHotSpotPoint_MagicWand NSMakePoint(6.0f, 5.0f) #define kPPCursorImageName_ColorSampler @"eyedropper_cursor.png" #define kPPCursorHotSpotPoint_ColorSampler NSMakePoint(2.0f, 21.0f) #define kPPCursorImageName_MoveTool @"move_cursor.png" #define kPPCursorHotSpotPoint_MoveTool NSMakePoint(3.0f, 1.0f) #define kPPCursorImageName_MoveSelectionOutlineTool @"move_selection_outline_cursor.png" #define kPPCursorImageName_Magnifier @"magnifier_cursor.png" #define kPPCursorHotSpotPoint_Magnifier NSMakePoint(15.0f, 7.0f) #define kPPCursorImageName_ColorRampTool @"color_ramp_cursor.png" #define kPPCursorHotSpotPoint_ColorRampTool NSMakePoint(3.0f, 1.0f) PikoPixel.Sources.1.0-b10b/PikoPixel/PPCursorLevel.h0000644000076500000240000000237113234403416021036 0ustar joshstaff/* PPCursorLevel.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPCursorLevel_CanvasView, kPPCursorLevel_Panel, kPPCursorLevel_PopupPanel, kNumPPCursorLevels } PPCursorLevel; static inline bool PPCursorLevel_IsValid(PPCursorLevel cursorLevel) { return (((unsigned) cursorLevel) < kNumPPCursorLevels) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPCursorManager.h0000644000076500000240000000315113234403416021336 0ustar joshstaff/* PPCursorManager.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPCursorLevel.h" @interface PPCursorManager : NSObject { NSCursor *_cursors[kNumPPCursorLevels]; NSCursor *_currentCursor; PPCursorLevel _currentCursorLevel; NSCursor *_defaultCursor; NSWindow *_currentDocumentWindow; bool _isDraggingMouse; } + (PPCursorManager *) sharedManager; - (void) setCursor: (NSCursor *) cursor atLevel: (PPCursorLevel) cursorLevel isDraggingMouse: (bool) isDraggingMouse; - (void) refreshCursorIfNeeded; - (void) setCurrentDocumentWindow: (NSWindow *) documentWindow; - (void) clearCurrentDocumentWindow: (NSWindow *) documentWindow; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPCursorManager.m0000644000076500000240000001561213234403205021344 0ustar joshstaff/* PPCursorManager.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPCursorManager.h" #import "NSObject_PPUtilities.h" #import "PPGeometry.h" #define kDefaultCursor [NSCursor arrowCursor] #define kCursorRefreshDelay_Canvas (0.0) #define kCursorRefreshDelay_Panel (0.005) static bool gRuntimeOverridesCursorWhenDraggingOverResizableWindowEdges = NO; @interface PPCursorManager (PrivateMethods) - (void) refreshCursorAfterDelay; - (void) disableResizingOfCurrentDocumentWindow: (bool) disableResizing; @end @implementation PPCursorManager + (void) load { gRuntimeOverridesCursorWhenDraggingOverResizableWindowEdges = (PP_RUNTIME_CHECK__RUNTIME_OVERRIDES_CURSOR_WHEN_DRAGGING_OVER_RESIZABLE_WINDOW_EDGES) ? YES : NO; } - init { self = [super init]; if (!self) goto ERROR; _defaultCursor = [kDefaultCursor retain]; _currentCursor = _defaultCursor; return self; ERROR: [self release]; return nil; } - (void) dealloc { int i; for (i=0; i 0) && (!_cursors[cursorIndex])) { cursorIndex--; } if (cursorIndex != (int) _currentCursorLevel) { _currentCursorLevel = (PPCursorLevel) cursorIndex; } } newCursor = _cursors[(int) _currentCursorLevel]; if (!newCursor) { newCursor = _defaultCursor; } if (_currentCursor != newCursor) { _currentCursor = newCursor; shouldSetCursor = YES; } else if (_currentCursor != [NSCursor currentCursor]) { //NSLog(@"INCORRECT CURSOR SET: %d", (int) [NSCursor currentCursor]); shouldSetCursor = YES; } if (shouldSetCursor) { [_currentCursor set]; // make sure cursor sticks: [self refreshCursorAfterDelay]; } return; ERROR: return; } - (void) refreshCursorIfNeeded { if (_currentCursor != [NSCursor currentCursor]) { [_currentCursor set]; } } - (void) setCurrentDocumentWindow: (NSWindow *) documentWindow { if (_currentDocumentWindow == documentWindow) { return; } if (_currentDocumentWindow) { if (gRuntimeOverridesCursorWhenDraggingOverResizableWindowEdges) { [self disableResizingOfCurrentDocumentWindow: NO]; } [_currentDocumentWindow release]; _currentDocumentWindow = nil; } if (documentWindow) { _currentDocumentWindow = [documentWindow retain]; [_currentDocumentWindow disableCursorRects]; } else { [self setCursor: nil atLevel: kPPCursorLevel_CanvasView isDraggingMouse: NO]; } } - (void) clearCurrentDocumentWindow: (NSWindow *) documentWindow { if (!documentWindow || (_currentDocumentWindow == documentWindow)) { [self setCurrentDocumentWindow: nil]; } } #pragma mark Private methods - (void) refreshCursorAfterDelay { NSTimeInterval cursorRefreshDelay = (_currentCursorLevel == kPPCursorLevel_CanvasView) ? kCursorRefreshDelay_Canvas : kCursorRefreshDelay_Panel; [self ppPerformSelectorAtomically: @selector(refreshCursorIfNeeded) afterDelay: cursorRefreshDelay]; } - (void) disableResizingOfCurrentDocumentWindow: (bool) disableResizing { static NSSize minWindowSize = {0,0}, maxWindowSize = {0,0}; if (!_currentDocumentWindow) return; if (disableResizing) { NSSize currentSize; if (PPGeometry_IsZeroSize(minWindowSize)) { minWindowSize = [_currentDocumentWindow minSize]; maxWindowSize = [_currentDocumentWindow maxSize]; } currentSize = [_currentDocumentWindow frame].size; [_currentDocumentWindow setMinSize: currentSize]; [_currentDocumentWindow setMaxSize: currentSize]; } else // enable resizing { if (!PPGeometry_IsZeroSize(minWindowSize)) { [_currentDocumentWindow setMinSize: minWindowSize]; [_currentDocumentWindow setMaxSize: maxWindowSize]; } } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDefines.h0000644000076500000240000000364713732464311020161 0ustar joshstaff/* PPDefines.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #define kNativeFileFormatTypeName @"PikoPixel Document" #define kDefaultCanvasDimension 64 #define kMinCanvasDimension 1 #define kMaxCanvasDimension 3000 #define kMinCanvasZoomFactor 1.0f #define kMaxCanvasZoomFactor 40.0f #define kMaxCanvasExportDimension 9000 #define kMaxLayersPerDocument 128 #define kMinScalingFactorToDrawGrid 4 #define kMinBackgroundPatternSize 1 #define kMaxBackgroundPatternSize 128 #define kMinGridGuidelineSpacing 1 #define kMaxGridGuidelineSpacing kMaxCanvasDimension #define kAutosaveDelay 23.0f #define kDefaultKeyboardLayoutLanguageCode @"en_US" #define kMatchToolToleranceIndicator_MaxRadius 445 #define kScalingFactorForThumbnailBackgroundPatternSize 0.25f #define kMaxScaleForHighInterpolationOfThumbnailImages 0.25f #define kMaxScaleForLowInterpolationOfThumbnailImages 2.0f PikoPixel.Sources.1.0-b10b/PikoPixel/PPDirectionType.h0000644000076500000240000000255713234403416021361 0ustar joshstaff/* PPDirectionType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPDirectionType_Left, kPPDirectionType_Right, kPPDirectionType_Up, kPPDirectionType_Down, // add new PPDirectionType values above this line kNumPPDirectionTypes, kPPDirectionType_None } PPDirectionType; static inline bool PPDirectionType_IsValid(PPDirectionType directionType) { return (((unsigned) directionType) < kNumPPDirectionTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument.h0000644000076500000240000004167313234403416020357 0ustar joshstaff/* PPDocument.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPDocumentTypes.h" #import "PPDefines.h" #import "PPToolType.h" #import "PPGridType.h" #import "PPDirectionType.h" #import "PPLayerDisplayMode.h" #import "PPSamplerImagePanelType.h" #import "NSDocument_PPUtilities.h" #import "PPBitmapPixelTypes.h" @class PPDocumentLayer, PPTool, PPBackgroundPattern, PPGridPattern, PPDocumentSamplerImage, PPExportPanelAccessoryViewController, PPDocumentWindowController; @interface PPDocument : NSDocument { NSRect _canvasFrame; NSMutableArray *_layers; int _numLayers; PPDocumentLayer *_drawingLayer; NSBitmapImageRep *_drawingLayerBitmap; NSImage *_drawingLayerImage; int _indexOfDrawingLayer; NSBitmapImageRep *_dissolvedDrawingLayerBitmap; NSImage *_dissolvedDrawingLayerThumbnailImage; NSBitmapImageRep *_mergedVisibleLayersBitmap; NSImage *_mergedVisibleLayersThumbnailImage; NSBitmapImageRep *_mergedVisibleLayersLinearBitmap; NSObject *_cachedOverlayersImageObjects[kMaxLayersPerDocument]; NSObject *_cachedUnderlayersImageObjects[kMaxLayersPerDocument]; NSBitmapImageRep *_drawingMask; NSBitmapImageRep *_drawingUndoBitmap; NSRect _drawingUndoBounds; NSBitmapImageRep *_selectionMask; NSRect _selectionBounds; NSBitmapImageRep *_interactiveEraseMask; NSRect _interactiveEraseBounds; PPToolType _selectedToolType; PPToolType _lastSelectedToolType; PPToolType _activeToolType; PPTool *_activeTool; PPPenMode _penMode; NSColor *_fillColor; // original colorspace preserved, returned by -fillColor method NSColor *_fillColor_sRGB; // _fillColor in sRGB colorspace, used when drawing & saving PPImageBitmapPixel _fillColorPixelValue_sRGB; // _fillColor_sRGB as bitmapData pixel-value PPLayerOperationTarget _layerOperationTarget; int _targetLayerIndexes[kMaxLayersPerDocument]; int _numTargetLayerIndexes; PPLayerBlendingMode _layerBlendingMode; PPBackgroundPattern *_backgroundPattern; NSImage *_backgroundImage; NSData *_compressedBackgroundImageData; PPGridPattern *_gridPattern; NSMutableArray *_samplerImages; int _numSamplerImages; int _activeSamplerImageIndexes[kNumPPSamplerImagePanelTypes]; int _samplerImageMinIndexValues[kNumPPSamplerImagePanelTypes]; PPLayerOperationTarget _interactiveMoveOperationTarget; PPLayerDisplayMode _interactiveMoveDisplayMode; NSBitmapImageRep *_interactiveMoveTargetBitmap; NSBitmapImageRep *_interactiveMoveFloatingBitmap; NSBitmapImageRep *_interactiveMoveFloatingMask; NSBitmapImageRep *_interactiveMoveUnderlyingBitmap; NSBitmapImageRep *_interactiveMoveInitialSelectionMask; NSRect _interactiveMoveInitialSelectionBounds; PPMoveOperationType _lastInteractiveMoveType; NSPoint _lastInteractiveMoveOffset; NSRect _lastInteractiveMoveBounds; PPExportPanelAccessoryViewController *_exportPanelViewController; PPDocumentSaveFormat _saveFormat; bool _hasSelection; bool _isDrawing; bool _shouldUndoCurrentDrawing; bool _isPerformingInteractiveMove; bool _shouldDisplayBackgroundImage; bool _shouldSmoothenBackgroundImage; bool _shouldDisplayGrid; bool _shouldEnableSamplerImagePanel; bool _mergedVisibleBitmapHasEnabledLayer; bool _disallowUpdatesToMergedBitmap; bool _disallowThumbnailImageUpdateNotifications; bool _disallowAutosaving; bool _shouldAutosaveWhenAllowed; bool _savePanelShouldAttachExportAccessoryView; bool _saveToOperationShouldUseExportSettings; bool _sourceBitmapHasAnimationFrames; } - (bool) setupNewPPDocumentWithCanvasSize: (NSSize) canvasSize; - (bool) loadFromPPDocument: (PPDocument *) ppDocument; - (bool) loadFromImageBitmap: (NSBitmapImageRep *) bitmap withFileType: (NSString *) fileType; - (bool) needToSetCanvasSize; - (NSSize) canvasSize; - (bool) resizeCanvasForCurrentLayers; - (NSBitmapImageRep *) mergedVisibleLayersBitmap; - (NSImage *) mergedVisibleLayersThumbnailImage; - (NSBitmapImageRep *) drawingLayerBitmap; - (NSImage *) drawingLayerThumbnailImage; - (NSBitmapImageRep *) dissolvedDrawingLayerBitmap; - (NSImage *) dissolvedDrawingLayerThumbnailImage; - (NSBitmapImageRep *) mergedVisibleLayersBitmapUsingExportPanelSettings; - (PPDocumentWindowController *) ppDocumentWindowController; - (void) setupCompressedBackgroundImageData; - (void) destroyCompressedBackgroundImageData; - (bool) sourceBitmapHasAnimationFrames; @end @interface PPDocument (Saving) - (void) disableAutosaving: (bool) disallowAutosaving; - (void) exportImage; @end @interface PPDocument (LayerOperationTarget) - (void) setLayerOperationTarget: (PPLayerOperationTarget) operationTarget; - (PPLayerOperationTarget) layerOperationTarget; - (bool) layerOperationTargetHasEnabledLayer; - (NSBitmapImageRep *) sourceBitmapForLayerOperationTarget: (PPLayerOperationTarget) operationTarget; - (void) setupTargetLayerIndexesForOperationTarget: (PPLayerOperationTarget) operationTarget; - (NSString *) nameOfLayerOperationTarget: (PPLayerOperationTarget) operationTarget; - (NSString *) nameWithSelectionStateForLayerOperationTarget: (PPLayerOperationTarget) operationTarget; @end @interface PPDocument (Layers) - (int) numLayers; - (PPDocumentLayer *) layerAtIndex: (int) index; - (void) createNewLayer; - (void) insertLayer: (PPDocumentLayer *) layer atIndex: (int) index andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer; - (void) removeLayerAtIndex: (int) index; - (void) moveLayerAtIndex: (int) oldIndex toIndex: (int) newIndex; - (void) duplicateLayerAtIndex: (int) index; - (void) removeAllLayers; - (void) removeNontargetLayers; - (bool) setLayers: (NSArray *) newLayers; - (void) selectDrawingLayerAtIndex: (int) newDrawingLayerIndex; - (int) indexOfDrawingLayer; - (PPDocumentLayer *) drawingLayer; - (void) beginMultilayerOperation; - (void) finishMultilayerOperation; - (void) moveDrawingLayerUp; - (void) moveDrawingLayerDown; - (void) mergeDrawingLayerUp; - (void) mergeDrawingLayerDown; - (void) mergeAllLayers; - (void) setEnabledFlagForAllLayers: (bool) isEnabled; - (PPLayerBlendingMode) layerBlendingMode; - (void) setLayerBlendingMode: (PPLayerBlendingMode) layerBlendingMode; - (void) toggleLayerBlendingMode; - (bool) setupLayerBlendingBitmapOfSize: (NSSize) bitmapSize; - (void) copyImageBitmap: (NSBitmapImageRep *) bitmap toLayerAtIndex: (int) index atPoint: (NSPoint) origin; - (void) handleUpdateToLayerAtIndex: (int) index inRect: (NSRect) updateRect; @end @interface PPDocument (ActiveTool) // The Selected tool is the tool selected by the user in the tool palette; The Active tool is // the tool used on the canvas - it can be different from the Selected tool if a modifier key's // pressed. - (void) setSelectedToolType: (PPToolType) toolType; - (void) setSelectedToolTypeToLastSelectedType; - (PPToolType) selectedToolType; - (void) setActiveToolType: (PPToolType) toolType; - (PPToolType) activeToolType; - (PPTool *) activeTool; @end @interface PPDocument (Drawing) - (NSColor *) fillColor; - (void) setFillColor: (NSColor *) fillColor; - (void) setFillColorWithoutUndoRegistration: (NSColor *) fillColor; - (void) beginDrawingWithPenMode: (PPPenMode) penMode; - (void) finishDrawing; - (void) undoCurrentDrawingAtNextDraw; - (void) drawPixelAtPoint: (NSPoint) point; - (void) drawLineFromPoint: (NSPoint) startPoint toPoint: (NSPoint) endPoint; - (void) drawRect: (NSRect) rect andFill: (bool) shouldFill; - (void) drawOvalInRect: (NSRect) rect andFill: (bool) shouldFill; - (void) drawBezierPath: (NSBezierPath *) path andFill: (bool) shouldFill; - (void) drawColorRampWithStartingColor: (NSColor *) startColor fromPoint: (NSPoint) startPoint toPoint: (NSPoint) endPoint returnedRampBounds: (NSRect *) returnedRampBounds returnedDrawMask: (NSBitmapImageRep **) returnedDrawMask; - (NSColor *) colorAtPoint: (NSPoint) point inTarget: (PPLayerOperationTarget) target; - (void) fillPixelsMatchingColorAtPoint: (NSPoint) point colorMatchTolerance: (unsigned) colorMatchTolerance pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode returnedMatchMask: (NSBitmapImageRep **) returnedMatchMask returnedMatchMaskBounds: (NSRect *) returnedMatchMaskBounds; - (void) noninteractiveFillSelectedDrawingArea; - (void) noninteractiveEraseSelectedAreaInTarget: (PPLayerOperationTarget) operationTarget andClearSelectionMask: (bool) shouldClearSelectionMask; - (bool) getInteractiveEraseMask: (NSBitmapImageRep **) returnedEraseMask andBounds: (NSRect *) returnedEraseBounds; - (void) copyImageBitmapToDrawingLayer: (NSBitmapImageRep *) bitmap atPoint: (NSPoint) origin; @end @interface PPDocument (Selection) - (bool) setupSelectionMaskBitmapOfSize: (NSSize) maskSize; - (bool) hasSelection; - (NSRect) selectionBounds; - (NSBitmapImageRep *) selectionMask; - (void) setSelectionMask: (NSBitmapImageRep *) selectionMask; - (void) setSelectionMaskAreaWithBitmap: (NSBitmapImageRep *) selectionMask atPoint: (NSPoint) origin; - (void) selectRect: (NSRect) rect selectionMode: (PPSelectionMode) selectionMode; - (void) selectPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode; - (void) selectPixelsMatchingColorAtPoint: (NSPoint) point colorMatchTolerance: (unsigned) colorMatchTolerance pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode selectionMode: (PPSelectionMode) selectionMode; - (void) selectAll; - (void) selectVisibleTargetPixels; - (void) deselectAll; - (void) deselectInvisibleTargetPixels; - (void) invertSelection; - (void) closeHolesInSelection; - (PPDocument *) ppDocumentFromSelection; @end @interface PPDocument (PixelMatching) // maskForPixelsMatchingColorAtPoint::: can be called repeatedly (when dragging the fill or // wand tools), so rather than construct a new bitmap each time, it just returns a pointer to // the _drawingMask member (the returned bitmap should only be used temporarily) - (NSBitmapImageRep *) maskForPixelsMatchingColorAtPoint: (NSPoint) point colorMatchTolerance: (unsigned) colorMatchTolerance pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode shouldIntersectSelectionMask: (bool) shouldIntersectSelectionMask; @end @interface PPDocument (Moving) - (void) nudgeInDirection: (PPDirectionType) directionType moveType: (PPMoveOperationType) moveType target: (PPLayerOperationTarget) operationTarget; - (void) beginInteractiveMoveWithTarget: (PPLayerOperationTarget) operationTarget canvasDisplayMode: (PPLayerDisplayMode) canvasDisplayMode moveType: (PPMoveOperationType) moveType; - (void) setInteractiveMoveOffset: (NSPoint) offset andMoveType: (PPMoveOperationType) moveType; - (void) finishInteractiveMove; @end @interface PPDocument (MirroringRotating) - (void) mirrorHorizontallyWithTarget: (PPLayerOperationTarget) operationTarget; - (void) mirrorVerticallyWithTarget: (PPLayerOperationTarget) operationTarget; - (void) rotate180WithTarget: (PPLayerOperationTarget) operationTarget; - (void) rotate90ClockwiseWithTarget: (PPLayerOperationTarget) operationTarget; - (void) rotate90CounterclockwiseWithTarget: (PPLayerOperationTarget) operationTarget; @end @interface PPDocument (Pasteboard) - (bool) canReadFromPasteboard; - (bool) canWriteToPasteboard; - (void) copySelectionToPasteboardFromTarget: (PPLayerOperationTarget) operationTarget; - (void) cutSelectionToPasteboardFromTarget: (PPLayerOperationTarget) operationTarget; - (void) pasteNewLayerFromPasteboard; - (void) pasteIntoDrawingLayerFromPasteboard; + (PPDocument *) ppDocumentFromPasteboard; @end @interface PPDocument (CanvasSettings) - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern backgroundImage: (NSImage *) backgroundImage shouldDisplayBackgroundImage: (bool) shouldDisplayBackgroundImage shouldSmoothenBackgroundImage: (bool) shouldSmoothenBackgroundImage; - (PPBackgroundPattern *) backgroundPattern; - (NSColor *) backgroundPatternAsColor; - (NSImage *) backgroundImage; - (bool) shouldDisplayBackgroundImage; - (bool) shouldSmoothenBackgroundImage; - (void) toggleBackgroundImageVisibility; - (void) toggleBackgroundImageSmoothing; - (void) setGridPattern: (PPGridPattern *) gridPattern shouldDisplayGrid: (bool) shouldDisplayGrid; - (PPGridPattern *) gridPattern; - (bool) shouldDisplayGrid; - (void) toggleGridVisibility; - (PPGridType) pixelGridPatternType; - (void) togglePixelGridPatternType; - (bool) gridPatternShouldDisplayGuidelines; - (void) toggleGridGuidelinesVisibility; - (bool) shouldDisplayGridAndGridGuidelines; - (NSRect) gridGuidelineBoundsCoveredByRect: (NSRect) rect; - (bool) hasCustomCanvasSettings; @end @interface PPDocument (Resizing) - (void) resizeToSize: (NSSize) newSize shouldScale: (bool) shouldScale; - (void) cropToSelectionBounds; @end @interface PPDocument (Tiling) - (void) tileSelection; - (void) tileSelectionAsNewLayer; @end @interface PPDocument (SamplerImages) - (void) setupSamplerImageIndexes; - (int) numSamplerImages; - (NSArray *) samplerImages; - (void) setSamplerImages: (NSArray *) newSamplerImages; - (PPDocumentSamplerImage *) activeSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType; - (void) activateNextSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType; - (void) activatePreviousSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType; - (bool) hasActiveSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType; - (bool) shouldEnableSamplerImagePanel; - (void) setShouldEnableSamplerImagePanel: (bool) shouldEnableSamplerImagePanel; @end @interface PPDocument (NotificationOverrides) // for better performance, operations that perform multiple quick updates to the document // bitmaps (interactive drawing, interactive moving, opacity sliders) should disable thumbnail // image update notifications to prevent the various thumbnail views from redrawing (each // different size forces a resample of the entire image: SLOW) until the end of the operation - (void) disableThumbnailImageUpdateNotifications: (bool) shouldDisableThumbnailImageUpdateNotifications; - (void) sendThumbnailImageUpdateNotifications; @end extern NSString *PPDocumentNotification_UpdatedMergedVisibleArea; extern NSString *PPDocumentNotification_UpdatedDrawingLayerArea; extern NSString *PPDocumentNotification_UpdatedMergedVisibleThumbnailImage; extern NSString *PPDocumentNotification_UpdatedDrawingLayerThumbnailImage; extern NSString *PPDocumentNotification_UpdatedSelection; extern NSString *PPDocumentNotification_SwitchedDrawingLayer; extern NSString *PPDocumentNotification_ReorderedLayers; extern NSString *PPDocumentNotification_PerformedMultilayerOperation; extern NSString *PPDocumentNotification_ChangedLayerAttribute; extern NSString *PPDocumentNotification_SwitchedLayerOperationTarget; extern NSString *PPDocumentNotification_SwitchedLayerBlendingMode; extern NSString *PPDocumentNotification_SwitchedSelectedTool; extern NSString *PPDocumentNotification_SwitchedActiveTool; extern NSString *PPDocumentNotification_ChangedFillColor; extern NSString *PPDocumentNotification_UpdatedBackgroundSettings; extern NSString *PPDocumentNotification_UpdatedGridSettings; extern NSString *PPDocumentNotification_ReloadedDocument; extern NSString *PPDocumentNotification_UpdatedSamplerImages; extern NSString *PPDocumentNotification_SwitchedActiveSamplerImage; extern NSString *PPDocumentNotification_UserInfoKey_UpdateAreaRect; extern NSString *PPDocumentNotification_UserInfoKey_IndexOfChangedLayer; extern NSString *PPDocumentNotification_UserInfoKey_SamplerImagePanelType; PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument.m0000644000076500000240000005767013242524440020370 0ustar joshstaff/* PPDocument.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocumentWindowController.h" #import "PPDocumentLayer.h" #import "PPBackgroundPattern.h" #import "PPGridPattern.h" #import "NSImage_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPUserDefaults.h" #import "PPExportPanelAccessoryViewController.h" #import "PPDocumentWindowController.h" #import "PPGeometry.h" #import "NSColor_PPUtilities.h" #define kDocumentCodingVersion_Current kDocumentCodingVersion_1 // Coding Version 1 // - Background image is now encoded as compressed data (NSData) instead of an NSImage object // - Grid pattern settings are now stored as an object (PPGridPattern) // - Added Layer Blending Mode (v1.0 beta8) #define kDocumentCodingVersion_1 1 #define kDocumentCodingKey_CodingVersion @"CodingVersion" #define kDocumentCodingKey_CanvasFrame @"CanvasFrame" #define kDocumentCodingKey_Layers @"Layers" #define kDocumentCodingKey_LayerBlendingMode @"LayerBlendingMode" #define kDocumentCodingKey_IndexOfDrawingLayer @"IndexOfDrawingLayer" #define kDocumentCodingKey_FillColor @"FillColor" #define kDocumentCodingKey_SelectionMaskData @"SelectionMaskData" #define kDocumentCodingKey_BackgroundPattern @"BackgroundPattern" #define kDocumentCodingKey_BackgroundImageData @"BackgroundImageData" #define kDocumentCodingKey_BackgroundImageVisibility @"BackgroundImageVisibility" #define kDocumentCodingKey_BackgroundImageSmoothing @"BackgroundImageSmoothing" #define kDocumentCodingKey_GridPattern @"GridPattern" #define kDocumentCodingKey_GridVisibility @"GridVisibility" #define kDocumentCodingKey_SamplerImages @"SamplerImages" #define kDocumentCodingKey_NonnativeFileType @"NonnativeFileType" // Coding Version 0 // Used in PikoPixel 1.0 beta4 & earlier #define kDocumentCodingVersion_0 0 #define kDocumentCodingKey_v0_BackgroundImage @"BackgroundImage" #define kDocumentCodingKey_v0_GridType @"GridType" #define kDocumentCodingKey_v0_GridColor @"GridColor" #define kDefaultFillColor [[NSColor blackColor] ppSRGBColor] #define kDefaultBackgroundImageVisibility YES #define kDefaultBackgroundImageSmoothing NO @interface PPDocument (PrivateMethods) - (bool) setupCanvasBitmapsAndImagesOfSize: (NSSize) canvasSize; @end @implementation PPDocument - (id) init { self = [super init]; if (!self) goto ERROR; _layers = [[NSMutableArray array] retain]; _samplerImages = [[NSMutableArray array] retain]; if (!_layers || !_samplerImages) { goto ERROR; } _indexOfDrawingLayer = -1; _activeToolType = -1; // setActiveToolType: doesn't set _activeTool unless value changes [self setSelectedToolType: kPPToolType_Pencil]; [self setActiveToolType: kPPToolType_Pencil]; [self setFillColor: kDefaultFillColor]; [self setBackgroundPattern: [PPUserDefaults backgroundPattern] backgroundImage: nil shouldDisplayBackgroundImage: kDefaultBackgroundImageVisibility shouldSmoothenBackgroundImage: kDefaultBackgroundImageSmoothing]; [self setGridPattern: [PPUserDefaults gridPattern] shouldDisplayGrid: [PPUserDefaults gridVisibility]]; [self setupSamplerImageIndexes]; [[self undoManager] removeAllActions]; return self; ERROR: [self release]; return nil; } - (void) dealloc { if (_isPerformingInteractiveMove) { [self finishInteractiveMove]; } [self removeAllLayers]; // also removes all objects in _cached(Over|Under)layersImageObjects [_layers release]; [_drawingLayer release]; [_drawingLayerBitmap release]; [_drawingLayerImage release]; [_dissolvedDrawingLayerBitmap release]; [_dissolvedDrawingLayerThumbnailImage release]; [_mergedVisibleLayersBitmap release]; [_mergedVisibleLayersThumbnailImage release]; [_mergedVisibleLayersLinearBitmap release]; [_drawingMask release]; [_drawingUndoBitmap release]; [_selectionMask release]; [_interactiveEraseMask release]; // _activeTool not retained [_fillColor release]; [_fillColor_sRGB release]; [_backgroundPattern release]; [_backgroundImage release]; [_compressedBackgroundImageData release]; [_gridPattern release]; [_samplerImages release]; [_exportPanelViewController release]; [super dealloc]; } - (bool) setupNewPPDocumentWithCanvasSize: (NSSize) canvasSize { PPDocumentLayer *layer; layer = [PPDocumentLayer layerWithSize: canvasSize andName: @"Main Layer"]; if (!layer) goto ERROR; if (![self setLayers: [NSArray arrayWithObject: layer]]) { goto ERROR; } [[self undoManager] removeAllActions]; return YES; ERROR: return NO; } - (bool) loadFromPPDocument: (PPDocument *) ppDocument { if (!ppDocument) goto ERROR; if (NSIsEmptyRect(ppDocument->_canvasFrame) || ![ppDocument->_layers count]) { goto ERROR; } if (![self setLayers: ppDocument->_layers]) { goto ERROR; } [self setLayerBlendingMode: ppDocument->_layerBlendingMode]; [self setSelectionMask: ppDocument->_selectionMask]; [self selectDrawingLayerAtIndex: ppDocument->_indexOfDrawingLayer]; [self setFillColor: ppDocument->_fillColor]; [self setBackgroundPattern: ppDocument->_backgroundPattern backgroundImage: ppDocument->_backgroundImage shouldDisplayBackgroundImage: ppDocument->_shouldDisplayBackgroundImage shouldSmoothenBackgroundImage: ppDocument->_shouldSmoothenBackgroundImage]; if (ppDocument->_compressedBackgroundImageData) { _compressedBackgroundImageData = [ppDocument->_compressedBackgroundImageData retain]; } [self setGridPattern: ppDocument->_gridPattern shouldDisplayGrid: ppDocument->_shouldDisplayGrid]; [self setSamplerImages: ppDocument->_samplerImages]; [self setLayerOperationTarget: ppDocument->_layerOperationTarget]; [self setFileType: [ppDocument fileType]]; [[self undoManager] removeAllActions]; return YES; ERROR: return NO; } - (bool) loadFromImageBitmap: (NSBitmapImageRep *) bitmap withFileType: (NSString *) fileType { NSSize canvasSize; PPDocumentLayer *layer; if (![bitmap ppIsImageBitmap]) { goto ERROR; } canvasSize = [bitmap ppSizeInPixels]; if (PPGeometry_SizeExceedsDimension(canvasSize, kMaxCanvasDimension)) { goto ERROR; } layer = [PPDocumentLayer layerWithSize: canvasSize name: @"Main Layer" tiffData: [bitmap TIFFRepresentation]]; if (!layer) goto ERROR; if (![self setLayers: [NSArray arrayWithObject: layer]]) { goto ERROR; } [self selectDrawingLayerAtIndex: 0]; [self setFillColor: kDefaultFillColor]; [self setBackgroundPattern: [PPUserDefaults backgroundPattern] backgroundImage: nil shouldDisplayBackgroundImage: kDefaultBackgroundImageVisibility shouldSmoothenBackgroundImage: kDefaultBackgroundImageSmoothing]; [self setGridPattern: [PPUserDefaults gridPattern] shouldDisplayGrid: [PPUserDefaults gridVisibility]]; [self setSamplerImages: nil]; [self setLayerOperationTarget: 0]; [self setFileType: fileType]; [[self undoManager] removeAllActions]; return YES; ERROR: return NO; } - (bool) needToSetCanvasSize { return (NSIsEmptyRect(_canvasFrame)) ? YES : NO; } - (NSSize) canvasSize { return _canvasFrame.size; } - (bool) resizeCanvasForCurrentLayers { PPDocumentLayer *bottomLayer; NSSize newCanvasSize; if (![_layers count]) { goto ERROR; } bottomLayer = [_layers objectAtIndex: 0]; if (!bottomLayer) goto ERROR; newCanvasSize = [bottomLayer size]; if ((newCanvasSize.width < kMinCanvasDimension) || (newCanvasSize.width > kMaxCanvasDimension) || (newCanvasSize.height < kMinCanvasDimension) || (newCanvasSize.height > kMaxCanvasDimension)) { goto ERROR; } if (![self setupCanvasBitmapsAndImagesOfSize: newCanvasSize]) { goto ERROR; } _canvasFrame.size = newCanvasSize; return YES; ERROR: return NO; } - (NSBitmapImageRep *) mergedVisibleLayersBitmap { return _mergedVisibleLayersBitmap; } - (NSImage *) mergedVisibleLayersThumbnailImage { return _mergedVisibleLayersThumbnailImage; } - (NSBitmapImageRep *) drawingLayerBitmap { return _drawingLayerBitmap; } - (NSImage *) drawingLayerThumbnailImage { return _drawingLayerImage; } - (NSBitmapImageRep *) dissolvedDrawingLayerBitmap { return _dissolvedDrawingLayerBitmap; } - (NSImage *) dissolvedDrawingLayerThumbnailImage { return _dissolvedDrawingLayerThumbnailImage; } - (NSBitmapImageRep *) mergedVisibleLayersBitmapUsingExportPanelSettings { unsigned scalingFactor; PPGridPattern *gridPattern = nil; PPBackgroundPattern *backgroundPattern = nil; bool shouldDrawGrid, shouldDrawBackgroundPattern, shouldDrawBackgroundImage; NSBitmapImageRep *exportBitmap; if (![_exportPanelViewController getScalingFactor: &scalingFactor gridPattern: &gridPattern backgroundPattern: &backgroundPattern backgroundImageFlag: &shouldDrawBackgroundImage]) { goto ERROR; } shouldDrawGrid = (gridPattern != nil) ? YES : NO; shouldDrawBackgroundPattern = (backgroundPattern != nil) ? YES : NO; if ((scalingFactor == 1) && (!shouldDrawGrid)) { exportBitmap = _mergedVisibleLayersBitmap; } else { exportBitmap = [_mergedVisibleLayersBitmap ppImageBitmapScaledByFactor: scalingFactor shouldDrawGrid: shouldDrawGrid gridType: [gridPattern pixelGridType] gridColor: [gridPattern pixelGridColor]]; if (!exportBitmap) goto ERROR; if (shouldDrawGrid && [gridPattern shouldDisplayGuidelines]) { [exportBitmap ppDrawImageGuidelinesInBounds: [exportBitmap ppFrameInPixels] topLeftPhase: NSZeroPoint unscaledSpacingSize: [gridPattern guidelineSpacingSize] scalingFactor: scalingFactor guidelinePixelValue: [[gridPattern guidelineColor] ppImageBitmapPixelValue]]; } } if (shouldDrawBackgroundPattern || (shouldDrawBackgroundImage && _backgroundImage)) { NSColor *backgroundColor = (shouldDrawBackgroundPattern) ? [backgroundPattern patternFillColor] : nil; NSImage *backgroundImage = (shouldDrawBackgroundImage) ? _backgroundImage : nil; NSImageInterpolation backgroundImageInterpolation = (_shouldSmoothenBackgroundImage) ? NSImageInterpolationLow : NSImageInterpolationNone; exportBitmap = [exportBitmap ppImageBitmapCompositedWithBackgroundColor: backgroundColor andBackgroundImage: backgroundImage backgroundImageInterpolation: backgroundImageInterpolation]; if (!exportBitmap) goto ERROR; } return exportBitmap; ERROR: return _mergedVisibleLayersBitmap; } - (PPDocumentWindowController *) ppDocumentWindowController { NSArray *windowControllers; PPDocumentWindowController *windowController; windowControllers = [self windowControllers]; if (![windowControllers count]) { return nil; } windowController = [windowControllers objectAtIndex: 0]; if (![windowController isKindOfClass: [PPDocumentWindowController class]]) { return nil; } return windowController; } - (void) setupCompressedBackgroundImageData { if (!_backgroundImage) { if (_compressedBackgroundImageData) { [self destroyCompressedBackgroundImageData]; } return; } if (!_compressedBackgroundImageData) { _compressedBackgroundImageData = [[_backgroundImage ppCompressedBitmapData] retain]; } } - (void) destroyCompressedBackgroundImageData { if (!_compressedBackgroundImageData) return; [_compressedBackgroundImageData autorelease]; _compressedBackgroundImageData = nil; } - (bool) sourceBitmapHasAnimationFrames { return _sourceBitmapHasAnimationFrames; } #pragma mark NSDocument overrides - (void) makeWindowControllers { [self addWindowController: [PPDocumentWindowController controller]]; } #pragma mark NSCoding protocol - (id) initWithCoder: (NSCoder *) aDecoder { int codingVersion; NSRect canvasFrame; NSArray *layers; NSImage *backgroundImage = nil; PPGridPattern *gridPattern = nil; NSData *backgroundImageData = nil; self = [self init]; if (!self) goto ERROR; codingVersion = [aDecoder decodeIntForKey: kDocumentCodingKey_CodingVersion]; canvasFrame = [aDecoder decodeRectForKey: kDocumentCodingKey_CanvasFrame]; layers = [aDecoder decodeObjectForKey: kDocumentCodingKey_Layers]; if (NSIsEmptyRect(canvasFrame) || ![layers count]) { goto ERROR; } if (![self setLayers: layers]) { goto ERROR; } if ([aDecoder containsValueForKey: kDocumentCodingKey_LayerBlendingMode]) { [self setLayerBlendingMode: [aDecoder decodeIntForKey: kDocumentCodingKey_LayerBlendingMode]]; } [self selectDrawingLayerAtIndex: [aDecoder decodeIntForKey: kDocumentCodingKey_IndexOfDrawingLayer]]; if ([aDecoder containsValueForKey: kDocumentCodingKey_SelectionMaskData]) { NSData *selectionMaskData = [aDecoder decodeObjectForKey: kDocumentCodingKey_SelectionMaskData]; if (selectionMaskData) { [self setSelectionMask: [NSBitmapImageRep imageRepWithData: selectionMaskData]]; } } [self setFillColor: [aDecoder decodeObjectForKey: kDocumentCodingKey_FillColor]]; if (codingVersion == kDocumentCodingVersion_0) { // Coding version 0 // Background image encoded as NSImage backgroundImage = [aDecoder decodeObjectForKey: kDocumentCodingKey_v0_BackgroundImage]; // Grid pattern settings encoded separately gridPattern = [PPGridPattern gridPatternWithPixelGridType: [aDecoder decodeIntForKey: kDocumentCodingKey_v0_GridType] pixelGridColor: [aDecoder decodeObjectForKey: kDocumentCodingKey_v0_GridColor]]; } else { // Coding version 1 // Background image encoded as NSData backgroundImageData = [aDecoder decodeObjectForKey: kDocumentCodingKey_BackgroundImageData]; if (backgroundImageData) { backgroundImage = [NSImage ppImageWithBitmap: [NSBitmapImageRep imageRepWithData: backgroundImageData]]; } // Grid pattern settings encoded as object (PPGridPattern) gridPattern = [aDecoder decodeObjectForKey: kDocumentCodingKey_GridPattern]; } [self setBackgroundPattern: [aDecoder decodeObjectForKey: kDocumentCodingKey_BackgroundPattern] backgroundImage: backgroundImage shouldDisplayBackgroundImage: [aDecoder decodeBoolForKey: kDocumentCodingKey_BackgroundImageVisibility] shouldSmoothenBackgroundImage: [aDecoder decodeBoolForKey: kDocumentCodingKey_BackgroundImageSmoothing]]; if (_backgroundImage) { if (backgroundImageData) { _compressedBackgroundImageData = [backgroundImageData retain]; } else { [self setupCompressedBackgroundImageData]; } } [self setGridPattern: gridPattern shouldDisplayGrid: [aDecoder decodeBoolForKey: kDocumentCodingKey_GridVisibility]]; if ([aDecoder containsValueForKey: kDocumentCodingKey_SamplerImages]) { NSArray *samplerImages = [aDecoder decodeObjectForKey: kDocumentCodingKey_SamplerImages]; if (samplerImages) { [self setSamplerImages: samplerImages]; } } if ([aDecoder containsValueForKey: kDocumentCodingKey_NonnativeFileType]) { [self setFileType: [aDecoder decodeObjectForKey: kDocumentCodingKey_NonnativeFileType]]; } [[self undoManager] removeAllActions]; return self; ERROR: [self release]; return nil; } - (void) encodeWithCoder: (NSCoder *) coder { [coder encodeInt: kDocumentCodingVersion_Current forKey: kDocumentCodingKey_CodingVersion]; [coder encodeRect: _canvasFrame forKey: kDocumentCodingKey_CanvasFrame]; [coder encodeObject: _layers forKey: kDocumentCodingKey_Layers]; [coder encodeInt: _indexOfDrawingLayer forKey: kDocumentCodingKey_IndexOfDrawingLayer]; if (_layerBlendingMode != kPPLayerBlendingMode_Standard) { [coder encodeInt: _layerBlendingMode forKey: kDocumentCodingKey_LayerBlendingMode]; } if (_hasSelection) { [coder encodeObject: [_selectionMask ppCompressedTIFFData] forKey: kDocumentCodingKey_SelectionMaskData]; } [coder encodeObject: _fillColor_sRGB forKey: kDocumentCodingKey_FillColor]; [coder encodeObject: _backgroundPattern forKey: kDocumentCodingKey_BackgroundPattern]; if (_backgroundImage) { if (!_compressedBackgroundImageData) { [self setupCompressedBackgroundImageData]; } [coder encodeObject: _compressedBackgroundImageData forKey: kDocumentCodingKey_BackgroundImageData]; } [coder encodeBool: _shouldDisplayBackgroundImage forKey: kDocumentCodingKey_BackgroundImageVisibility]; [coder encodeBool: _shouldSmoothenBackgroundImage forKey: kDocumentCodingKey_BackgroundImageSmoothing]; [coder encodeObject: _gridPattern forKey: kDocumentCodingKey_GridPattern]; [coder encodeBool: _shouldDisplayGrid forKey: kDocumentCodingKey_GridVisibility]; if (_numSamplerImages > 0) { [coder encodeObject: _samplerImages forKey: kDocumentCodingKey_SamplerImages]; } // preserve nonnative filetype name when autosaving if (_saveFormat == kPPDocumentSaveFormat_Autosave) { NSString *fileType = [self fileType]; if (fileType && ![fileType isEqualToString: kNativeFileFormatTypeName]) { [coder encodeObject: fileType forKey: kDocumentCodingKey_NonnativeFileType]; } } } #pragma mark Private methods - (bool) setupCanvasBitmapsAndImagesOfSize: (NSSize) canvasSize { NSBitmapImageRep *oldMergedVisibleLayersLinearBitmap, *mergedVisibleLayersBitmap, *dissolvedDrawingLayerBitmap, *drawingMask, *drawingUndoBitmap, *interactiveEraseMask; NSImage *mergedVisibleLayersThumbnailImage, *dissolvedDrawingLayerThumbnailImage; // setupLayerBlendingBitmapOfSize: method may change the value of // _mergedVisibleLayersLinearBitmap - remember the old value, so it can be restored in case // of an error later oldMergedVisibleLayersLinearBitmap = [[_mergedVisibleLayersLinearBitmap retain] autorelease]; if (![self setupLayerBlendingBitmapOfSize: canvasSize]) { goto ERROR; } if (!_mergedVisibleLayersBitmap || !NSEqualSizes([_mergedVisibleLayersBitmap ppSizeInPixels], canvasSize)) { mergedVisibleLayersBitmap = [NSBitmapImageRep ppImageBitmapOfSize: canvasSize]; mergedVisibleLayersThumbnailImage = [NSImage ppImageWithBitmap: mergedVisibleLayersBitmap]; dissolvedDrawingLayerBitmap = [NSBitmapImageRep ppImageBitmapOfSize: canvasSize]; dissolvedDrawingLayerThumbnailImage = [NSImage ppImageWithBitmap: dissolvedDrawingLayerBitmap]; drawingMask = [NSBitmapImageRep ppMaskBitmapOfSize: canvasSize]; drawingUndoBitmap = [NSBitmapImageRep ppImageBitmapOfSize: canvasSize]; interactiveEraseMask = [NSBitmapImageRep ppMaskBitmapOfSize: canvasSize]; if (!mergedVisibleLayersBitmap || !mergedVisibleLayersThumbnailImage || !dissolvedDrawingLayerBitmap || !dissolvedDrawingLayerThumbnailImage || !drawingMask || !drawingUndoBitmap || !interactiveEraseMask) { goto ERROR; } // set up the selection mask as the last error check, because the // setupSelectionMaskBitmapOfSize: method also sets the values of other instance // members, which would need to be restored if an error happened later on if (![self setupSelectionMaskBitmapOfSize: canvasSize]) { goto ERROR; } [_mergedVisibleLayersBitmap autorelease]; _mergedVisibleLayersBitmap = [mergedVisibleLayersBitmap retain]; [_mergedVisibleLayersThumbnailImage autorelease]; _mergedVisibleLayersThumbnailImage = [mergedVisibleLayersThumbnailImage retain]; [_dissolvedDrawingLayerBitmap autorelease]; _dissolvedDrawingLayerBitmap = [dissolvedDrawingLayerBitmap retain]; [_dissolvedDrawingLayerThumbnailImage autorelease]; _dissolvedDrawingLayerThumbnailImage = [dissolvedDrawingLayerThumbnailImage retain]; [_drawingMask autorelease]; _drawingMask = [drawingMask retain]; [_drawingUndoBitmap autorelease]; _drawingUndoBitmap = [drawingUndoBitmap retain]; [_interactiveEraseMask autorelease]; _interactiveEraseMask = [interactiveEraseMask retain]; } else { if (![self setupSelectionMaskBitmapOfSize: canvasSize]) { goto ERROR; } [_mergedVisibleLayersBitmap ppClearBitmap]; [_mergedVisibleLayersThumbnailImage recache]; [_dissolvedDrawingLayerBitmap ppClearBitmap]; [_dissolvedDrawingLayerThumbnailImage recache]; [_drawingMask ppClearBitmap]; [_drawingUndoBitmap ppClearBitmap]; [_interactiveEraseMask ppClearBitmap]; } return YES; ERROR: // restore the old value of _mergedVisibleLayersLinearBitmap if it was changed (by the call // to setupLayerBlendingBitmapOfSize:) if (_mergedVisibleLayersLinearBitmap != oldMergedVisibleLayersLinearBitmap) { [_mergedVisibleLayersLinearBitmap autorelease]; _mergedVisibleLayersLinearBitmap = [oldMergedVisibleLayersLinearBitmap retain]; } return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_ActiveTool.m0000644000076500000240000000373013234403206022502 0ustar joshstaff/* PPDocument_ActiveTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_Notifications.h" #import "PPToolbox.h" @implementation PPDocument (ActiveTool) - (void) setSelectedToolType: (PPToolType) toolType { if (!PPToolType_IsValid(toolType) || (toolType == _selectedToolType)) { return; } _lastSelectedToolType = _selectedToolType; _selectedToolType = toolType; [self postNotification_SwitchedSelectedTool]; } - (void) setSelectedToolTypeToLastSelectedType { [self setSelectedToolType: _lastSelectedToolType]; } - (PPToolType) selectedToolType { return _selectedToolType; } - (void) setActiveToolType: (PPToolType) toolType { if (!PPToolType_IsValid(toolType) || (toolType == _activeToolType)) { return; } _activeTool = [[PPToolbox sharedToolbox] toolOfType: toolType]; _activeToolType = toolType; [self postNotification_SwitchedActiveTool]; } - (PPToolType) activeToolType { return _activeToolType; } - (PPTool *) activeTool { return _activeTool; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_CanvasSettings.m0000644000076500000240000002233613234403206023370 0ustar joshstaff/* PPDocument_CanvasSettings.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_Notifications.h" #import "PPBackgroundPattern.h" #import "PPGridPattern.h" #import "NSColor_PPUtilities.h" #import "PPUserDefaults.h" #import "PPGeometry.h" @implementation PPDocument (CanvasSettings) - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern backgroundImage: (NSImage *) backgroundImage shouldDisplayBackgroundImage: (bool) shouldDisplayBackgroundImage shouldSmoothenBackgroundImage: (bool) shouldSmoothenBackgroundImage { bool didUpdateBackgroundSettings, oldShouldDisplayBackgroundImage, oldShouldSmoothenBackgroundImage; PPBackgroundPattern *oldBackgroundPattern; NSImage *oldBackgroundImage; NSUndoManager *undoManager; shouldDisplayBackgroundImage = (shouldDisplayBackgroundImage) ? YES : NO; shouldSmoothenBackgroundImage = (shouldSmoothenBackgroundImage) ? YES : NO; didUpdateBackgroundSettings = NO; oldBackgroundPattern = [[_backgroundPattern retain] autorelease]; oldBackgroundImage = [[_backgroundImage retain] autorelease]; oldShouldDisplayBackgroundImage = _shouldDisplayBackgroundImage; oldShouldSmoothenBackgroundImage = _shouldSmoothenBackgroundImage; if (backgroundPattern && ![_backgroundPattern isEqualToBackgroundPattern: backgroundPattern]) { [_backgroundPattern release]; _backgroundPattern = [backgroundPattern retain]; didUpdateBackgroundSettings = YES; } if (backgroundImage != _backgroundImage) { [_backgroundImage release]; _backgroundImage = [backgroundImage retain]; [self destroyCompressedBackgroundImageData]; didUpdateBackgroundSettings = YES; } if (_shouldDisplayBackgroundImage != shouldDisplayBackgroundImage) { _shouldDisplayBackgroundImage = shouldDisplayBackgroundImage; didUpdateBackgroundSettings = YES; } if (_shouldSmoothenBackgroundImage != shouldSmoothenBackgroundImage) { _shouldSmoothenBackgroundImage = shouldSmoothenBackgroundImage; didUpdateBackgroundSettings = YES; } if (!didUpdateBackgroundSettings) return; undoManager = [self undoManager]; if (oldBackgroundImage && (oldBackgroundImage != _backgroundImage)) { [[undoManager prepareWithInvocationTarget: self] setupCompressedBackgroundImageData]; } [[undoManager prepareWithInvocationTarget: self] setBackgroundPattern: oldBackgroundPattern backgroundImage: oldBackgroundImage shouldDisplayBackgroundImage: oldShouldDisplayBackgroundImage shouldSmoothenBackgroundImage: oldShouldSmoothenBackgroundImage]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Change Canvas Background Settings"]; } [self postNotification_UpdatedBackgroundSettings]; } - (PPBackgroundPattern *) backgroundPattern { return _backgroundPattern; } - (NSColor *) backgroundPatternAsColor { return [_backgroundPattern patternFillColor]; } - (NSImage *) backgroundImage { return _backgroundImage; } - (bool) shouldDisplayBackgroundImage { return _shouldDisplayBackgroundImage; } - (bool) shouldSmoothenBackgroundImage { return _shouldSmoothenBackgroundImage; } - (void) toggleBackgroundImageVisibility { [self setBackgroundPattern: _backgroundPattern backgroundImage: _backgroundImage shouldDisplayBackgroundImage: (_shouldDisplayBackgroundImage) ? NO : YES shouldSmoothenBackgroundImage: _shouldSmoothenBackgroundImage]; [[self undoManager] setActionName: (_shouldDisplayBackgroundImage) ? @"Show Canvas Background Image" : @"Hide Canvas Background Image"]; } - (void) toggleBackgroundImageSmoothing { [self setBackgroundPattern: _backgroundPattern backgroundImage: _backgroundImage shouldDisplayBackgroundImage: _shouldDisplayBackgroundImage shouldSmoothenBackgroundImage: (_shouldSmoothenBackgroundImage) ? NO : YES]; [[self undoManager] setActionName: (_shouldSmoothenBackgroundImage) ? @"Enable Background Image Smoothing" : @"Disable Background Image Smoothing"]; } - (void) setGridPattern: (PPGridPattern *) gridPattern shouldDisplayGrid: (bool) shouldDisplayGrid { bool didUpdateGridSettings, oldShouldDisplayGrid; PPGridPattern *oldGridPattern; NSUndoManager *undoManager; if (!gridPattern) { gridPattern = [PPUserDefaults gridPattern]; } shouldDisplayGrid = (shouldDisplayGrid) ? YES : NO; didUpdateGridSettings = NO; oldGridPattern = [[_gridPattern retain] autorelease]; oldShouldDisplayGrid = _shouldDisplayGrid; if (![_gridPattern isEqualToGridPattern: gridPattern]) { [_gridPattern release]; _gridPattern = [gridPattern retain]; didUpdateGridSettings = YES; } if (_shouldDisplayGrid != shouldDisplayGrid) { _shouldDisplayGrid = shouldDisplayGrid; didUpdateGridSettings = YES; } if (!didUpdateGridSettings) return; undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] setGridPattern: oldGridPattern shouldDisplayGrid: oldShouldDisplayGrid]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Change Canvas Grid Settings"]; } [self postNotification_UpdatedGridSettings]; } - (PPGridPattern *) gridPattern { return _gridPattern; } - (bool) shouldDisplayGrid { return _shouldDisplayGrid; } - (void) toggleGridVisibility { [self setGridPattern: _gridPattern shouldDisplayGrid: (_shouldDisplayGrid) ? NO : YES]; [[self undoManager] setActionName: (_shouldDisplayGrid) ? @"Show Canvas Grid" : @"Hide Canvas Grid"]; } - (PPGridType) pixelGridPatternType { return [_gridPattern pixelGridType]; } - (void) togglePixelGridPatternType { PPGridPattern *toggledGridPattern; if (!_shouldDisplayGrid) return; toggledGridPattern = [_gridPattern gridPatternByTogglingPixelGridType]; if (!toggledGridPattern) goto ERROR; [self setGridPattern: toggledGridPattern shouldDisplayGrid: _shouldDisplayGrid]; [[self undoManager] setActionName: @"Switch Canvas Grid Type"]; return; ERROR: return; } - (bool) gridPatternShouldDisplayGuidelines { return [_gridPattern shouldDisplayGuidelines]; } - (void) toggleGridGuidelinesVisibility { PPGridPattern *toggledGridPattern; if (!_shouldDisplayGrid) return; toggledGridPattern = [_gridPattern gridPatternByTogglingGuidelinesVisibility]; if (!toggledGridPattern) goto ERROR; [self setGridPattern: toggledGridPattern shouldDisplayGrid: _shouldDisplayGrid]; [[self undoManager] setActionName: ([self gridPatternShouldDisplayGuidelines]) ? @"Show Canvas Grid Guidelines" : @"Hide Canvas Grid Guidelines"]; return; ERROR: return; } - (bool) shouldDisplayGridAndGridGuidelines { return (_shouldDisplayGrid && [_gridPattern shouldDisplayGuidelines]) ? YES : NO; } - (NSRect) gridGuidelineBoundsCoveredByRect: (NSRect) rect { return PPGeometry_GridBoundsCoveredByRectOnCanvasOfSizeWithGridOfSpacingSize( rect, _canvasFrame.size, [_gridPattern guidelineSpacingSize]); } - (bool) hasCustomCanvasSettings { return (_backgroundImage || ![_backgroundPattern isEqualToBackgroundPattern: [PPUserDefaults backgroundPattern]] || ![_gridPattern isEqualToGridPattern: [PPUserDefaults gridPattern]]) ? YES : NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Drawing.m0000644000076500000240000005502113234403206022024 0ustar joshstaff/* PPDocument_Drawing.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_Notifications.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #import "PPGeometry.h" #import "PPDocumentLayer.h" @interface PPDocument (DrawingPrivateMethods) - (void) handleUpdateToDrawingLayerBitmapInBounds: (NSRect) bounds; - (void) drawBezierPath: (NSBezierPath *) path andFill: (bool) shouldFillPath pathIsPixelated: (bool) pathIsPixelated; - (void) performDrawUsingMask: (NSBitmapImageRep *) drawingMask inBounds: (NSRect) drawBounds; - (void) undoCurrentDrawingAndForceDrawingLayerUpdate: (bool) shouldSendDrawingLayerUpdate; - (void) prepareUndoDrawingInBounds: (NSRect) undoBounds; - (void) undoDrawingWithTIFFData: (NSData *) undoBitmapTIFFData atPoint: (NSPoint) origin; - (void) mergeInteractiveEraseMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) maskBounds; - (void) clearInteractiveEraseMask; @end @implementation PPDocument (Drawing) - (NSColor *) fillColor { return _fillColor; } - (void) setFillColor: (NSColor *) fillColor { NSColor *fillColor_sRGB, *oldFillColor; NSUndoManager *undoManager; if (!fillColor) goto ERROR; fillColor_sRGB = [fillColor ppSRGBColor]; if (!fillColor_sRGB) goto ERROR; oldFillColor = [[_fillColor retain] autorelease]; [_fillColor release]; _fillColor = [fillColor retain]; [_fillColor_sRGB release]; _fillColor_sRGB = [fillColor_sRGB retain]; _fillColorPixelValue_sRGB = [_fillColor_sRGB ppImageBitmapPixelValue]; undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] setFillColor: oldFillColor]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Change Draw Color"]; } [self postNotification_ChangedFillColor]; return; ERROR: return; } - (void) setFillColorWithoutUndoRegistration: (NSColor *) fillColor { NSUndoManager *undoManager; bool needToReenableUndoRegistration = NO; undoManager = [self undoManager]; if ([undoManager isUndoRegistrationEnabled]) { [undoManager disableUndoRegistration]; needToReenableUndoRegistration = YES; } [self setFillColor: fillColor]; if (needToReenableUndoRegistration) { [undoManager enableUndoRegistration]; } } - (void) beginDrawingWithPenMode: (PPPenMode) penMode { if (![_drawingLayer isEnabled] || _isDrawing) { return; } _penMode = (penMode != kPPPenMode_Erase) ? kPPPenMode_Fill : kPPPenMode_Erase; _drawingUndoBounds = NSZeroRect; _shouldUndoCurrentDrawing = NO; // improve drawing performance by disabling thumbnail updates until the draw's done [self disableThumbnailImageUpdateNotifications: YES]; _isDrawing = YES; } - (void) finishDrawing { if (!_isDrawing) return; if (_shouldUndoCurrentDrawing) { [self undoCurrentDrawingAndForceDrawingLayerUpdate: YES]; } _isDrawing = NO; [self disableThumbnailImageUpdateNotifications: NO]; if (!NSIsEmptyRect(_drawingUndoBounds)) { [self prepareUndoDrawingInBounds: _drawingUndoBounds]; [[self undoManager] setActionName: (_penMode != kPPPenMode_Erase) ? @"Draw" : @"Erase"]; _drawingUndoBounds = NSZeroRect; [self sendThumbnailImageUpdateNotifications]; if (_penMode == kPPPenMode_Erase) { [self clearInteractiveEraseMask]; } } } - (void) undoCurrentDrawingAtNextDraw { if (!_isDrawing) return; _shouldUndoCurrentDrawing = YES; } - (void) drawPixelAtPoint: (NSPoint) point { if (!_isDrawing) return; [self drawLineFromPoint: point toPoint: point]; } - (void) drawLineFromPoint: (NSPoint) startPoint toPoint: (NSPoint) endPoint { NSBezierPath *linePath; if (!_isDrawing) return; linePath = [NSBezierPath bezierPath]; [linePath ppAppendLineFromPixelAtPoint: startPoint toPixelAtPoint: endPoint]; [self drawBezierPath: linePath andFill: NO pathIsPixelated: NO]; } - (void) drawRect: (NSRect) rect andFill: (bool) shouldFill { if (!_isDrawing) return; rect = PPGeometry_PixelCenteredRect(rect); [self drawBezierPath: [NSBezierPath bezierPathWithRect: rect] andFill: shouldFill pathIsPixelated: YES]; } - (void) drawOvalInRect: (NSRect) rect andFill: (bool) shouldFill { if (!_isDrawing) return; rect = PPGeometry_PixelCenteredRect(rect); [self drawBezierPath: [NSBezierPath ppPixelatedBezierPathWithOvalInRect: rect] andFill: shouldFill pathIsPixelated: YES]; } - (void) drawBezierPath: (NSBezierPath *) path andFill: (bool) shouldFill { [self drawBezierPath: path andFill: shouldFill pathIsPixelated: NO]; } - (void) drawColorRampWithStartingColor: (NSColor *) startColor fromPoint: (NSPoint) startPoint toPoint: (NSPoint) endPoint returnedRampBounds: (NSRect *) returnedRampBounds returnedDrawMask: (NSBitmapImageRep **) returnedDrawMask { NSColor *endColor; NSPoint deltaPoint; unsigned rampLength; NSRect rampBounds, drawBounds, updateBounds = NSZeroRect; NSBitmapImageRep *rampBitmap; bool shouldSwapRampEndpointColors = NO, rampIsVertical = NO; if (!_isDrawing) goto ERROR; if (_shouldUndoCurrentDrawing) { updateBounds = NSUnionRect(updateBounds, _drawingUndoBounds); [self undoCurrentDrawingAndForceDrawingLayerUpdate: NO]; } if (!startColor) goto ERROR; startPoint = PPGeometry_PointClippedToIntegerValues(startPoint); endPoint = PPGeometry_PointClippedToIntegerValues(endPoint); if (!NSPointInRect(startPoint, _canvasFrame) || !NSPointInRect(endPoint, _canvasFrame)) { goto ERROR; } deltaPoint = PPGeometry_PointDifference(endPoint, startPoint); if (fabsf((float) deltaPoint.x) >= fabsf((float) deltaPoint.y)) { // horizontal ramp endPoint.y = startPoint.y; if (startPoint.x > endPoint.x) { shouldSwapRampEndpointColors = YES; } rampLength = fabsf((float) deltaPoint.x) + 1; } else { // vertical ramp endPoint.x = startPoint.x; if (startPoint.y < endPoint.y) { shouldSwapRampEndpointColors = YES; } rampLength = fabsf((float) deltaPoint.y) + 1; rampIsVertical = YES; } endColor = startColor; if (rampLength > 1) { if (shouldSwapRampEndpointColors) { startColor = _fillColor_sRGB; } else { endColor = _fillColor_sRGB; } } if (rampIsVertical) { rampBitmap = [NSBitmapImageRep ppVerticalGradientPatternBitmapWithHeight: rampLength topColor: startColor bottomColor: endColor]; } else { rampBitmap = [NSBitmapImageRep ppHorizontalGradientPatternBitmapWithWidth: rampLength leftColor: startColor rightColor: endColor]; } rampBounds = PPGeometry_PixelBoundsWithCornerPoints(startPoint, endPoint); if (!rampBitmap || !NSEqualSizes(rampBounds.size, [rampBitmap ppSizeInPixels])) { goto ERROR; } if (_hasSelection) { [_drawingMask ppCopyFromBitmap: _selectionMask inRect: rampBounds toPoint: rampBounds.origin]; drawBounds = [_drawingMask ppMaskBoundsInRect: rampBounds]; if (!NSIsEmptyRect(drawBounds)) { NSBitmapImageRep *rampDrawMask = [_drawingMask ppShallowDuplicateFromBounds: rampBounds]; [_drawingLayerBitmap ppMaskedCopyFromImageBitmap: rampBitmap usingMask: rampDrawMask toPoint: rampBounds.origin]; } } else { [_drawingMask ppMaskPixelsInBounds: rampBounds]; drawBounds = rampBounds; [_drawingLayerBitmap ppCopyFromBitmap: rampBitmap toPoint: rampBounds.origin]; } _drawingUndoBounds = NSUnionRect(_drawingUndoBounds, drawBounds); updateBounds = NSUnionRect(updateBounds, drawBounds); if (!NSIsEmptyRect(updateBounds)) { [self handleUpdateToDrawingLayerBitmapInBounds: updateBounds]; } if (returnedRampBounds) { *returnedRampBounds = rampBounds; } if (returnedDrawMask) { *returnedDrawMask = _drawingMask; } return; ERROR: if (!NSIsEmptyRect(updateBounds)) { [self handleUpdateToDrawingLayerBitmapInBounds: updateBounds]; } if (returnedRampBounds) { *returnedRampBounds = NSZeroRect; } if (returnedDrawMask) { *returnedDrawMask = nil; } return; } - (NSColor *) colorAtPoint: (NSPoint) point inTarget: (PPLayerOperationTarget) target { NSBitmapImageRep *sourceBitmap = [self sourceBitmapForLayerOperationTarget: target]; return [sourceBitmap ppImageColorAtPoint: point]; } - (void) fillPixelsMatchingColorAtPoint: (NSPoint) point colorMatchTolerance: (unsigned) colorMatchTolerance pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode returnedMatchMask: (NSBitmapImageRep **) returnedMatchMask returnedMatchMaskBounds: (NSRect *) returnedMatchMaskBounds { NSBitmapImageRep *matchMask; NSRect matchMaskBounds; if (!_isDrawing) goto ERROR; if (_shouldUndoCurrentDrawing) { [self undoCurrentDrawingAndForceDrawingLayerUpdate: YES]; } matchMask = [self maskForPixelsMatchingColorAtPoint: point colorMatchTolerance: colorMatchTolerance pixelMatchingMode: pixelMatchingMode shouldIntersectSelectionMask: YES]; if (!matchMask) goto ERROR; matchMaskBounds = [matchMask ppMaskBoundsInRect: (_hasSelection) ? _selectionBounds : _canvasFrame]; if (!NSIsEmptyRect(matchMaskBounds)) { [self performDrawUsingMask: matchMask inBounds: matchMaskBounds]; } if (returnedMatchMask) { *returnedMatchMask = matchMask; } if (returnedMatchMaskBounds) { *returnedMatchMaskBounds = matchMaskBounds; } return; ERROR: if (returnedMatchMask) { *returnedMatchMask = nil; } if (returnedMatchMaskBounds) { *returnedMatchMaskBounds = NSZeroRect; } return; } - (void) noninteractiveFillSelectedDrawingArea { if (_isDrawing || !_hasSelection || ![_drawingLayer isEnabled]) { return; } [_drawingLayerBitmap ppMaskedFillUsingMask: _selectionMask inBounds: _selectionBounds fillPixelValue: _fillColorPixelValue_sRGB]; [self handleUpdateToDrawingLayerBitmapInBounds: _selectionBounds]; [self prepareUndoDrawingInBounds: _selectionBounds]; [[self undoManager] setActionName: @"Fill Selected Pixels"]; } - (void) noninteractiveEraseSelectedAreaInTarget: (PPLayerOperationTarget) operationTarget andClearSelectionMask: (bool) shouldClearSelectionMask { NSString *targetName, *actionName; if (_isDrawing || !_hasSelection) { return; } [self setupTargetLayerIndexesForOperationTarget: operationTarget]; if (_numTargetLayerIndexes > 0) { NSBitmapImageRep *updateBitmap, *eraseMask; bool eraseMaskCoversAllPixels, isMultilayerOperation; int i, layerIndex; updateBitmap = [NSBitmapImageRep ppImageBitmapOfSize: _selectionBounds.size]; eraseMask = [_selectionMask ppShallowDuplicateFromBounds: _selectionBounds]; if (!updateBitmap || !eraseMask) { goto ERROR; } eraseMaskCoversAllPixels = [eraseMask ppMaskCoversAllPixels] ? YES : NO; isMultilayerOperation = (_numTargetLayerIndexes > 1) ? YES : NO; if (isMultilayerOperation) { [self beginMultilayerOperation]; } for (i=0; i<_numTargetLayerIndexes; i++) { layerIndex = _targetLayerIndexes[i]; if (!eraseMaskCoversAllPixels) { [updateBitmap ppCopyFromBitmap: [[self layerAtIndex: layerIndex] bitmap] inRect: _selectionBounds toPoint: NSZeroPoint]; [updateBitmap ppMaskedEraseUsingMask: eraseMask]; } [self copyImageBitmap: updateBitmap toLayerAtIndex: layerIndex atPoint: _selectionBounds.origin]; } if (isMultilayerOperation) { [self finishMultilayerOperation]; } if (shouldClearSelectionMask) { targetName = [self nameWithSelectionStateForLayerOperationTarget: operationTarget]; } } else // !(_numTargetLayerIndexes > 0) { if (!shouldClearSelectionMask) goto ERROR; targetName = @"Selection Outline"; } if (shouldClearSelectionMask) { [self deselectAll]; actionName = [NSString stringWithFormat: @"Delete (%@)", targetName]; if (!actionName) { actionName = @"Delete Selection"; } } else { actionName = @"Erase Selected Pixels"; } [[self undoManager] setActionName: actionName]; return; ERROR: return; } - (bool) getInteractiveEraseMask: (NSBitmapImageRep **) returnedEraseMask andBounds: (NSRect *) returnedEraseBounds { if (!_isDrawing || (_penMode != kPPPenMode_Erase)) { goto ERROR; } if (returnedEraseMask) { *returnedEraseMask = _interactiveEraseMask; } if (returnedEraseBounds) { *returnedEraseBounds = _interactiveEraseBounds; } return YES; ERROR: return NO; } - (void) copyImageBitmapToDrawingLayer: (NSBitmapImageRep *) bitmap atPoint: (NSPoint) origin { NSRect updateBounds; if (![bitmap ppIsImageBitmap]) { goto ERROR; } origin = PPGeometry_PointClippedToIntegerValues(origin); updateBounds.origin = origin; updateBounds.size = [bitmap ppSizeInPixels]; updateBounds = NSIntersectionRect(updateBounds, _canvasFrame); if (NSIsEmptyRect(updateBounds)) { goto ERROR; } [_drawingLayerBitmap ppCopyFromBitmap: bitmap toPoint: origin]; [self handleUpdateToDrawingLayerBitmapInBounds: updateBounds]; if (!_isDrawing) { [self prepareUndoDrawingInBounds: updateBounds]; } return; ERROR: return; } #pragma mark Private methods - (void) handleUpdateToDrawingLayerBitmapInBounds: (NSRect) bounds { [_drawingLayer handleUpdateToBitmapInRect: bounds]; [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: bounds]; } - (void) drawBezierPath: (NSBezierPath *) path andFill: (bool) shouldFill pathIsPixelated: (bool) pathIsPixelated { NSRect drawBounds; bool needToThresholdAntialiasedMask = NO; if (!_isDrawing || !path) { return; } // currently doesn't account for path's linewidth drawBounds = PPGeometry_PixelBoundsCoveredByRect([path bounds]); if (_hasSelection) { drawBounds = NSIntersectionRect(drawBounds, _selectionBounds); } else { drawBounds = NSIntersectionRect(drawBounds, _canvasFrame); } if (NSIsEmptyRect(drawBounds)) { return; } [_drawingMask ppClearBitmapInBounds: drawBounds]; [_drawingMask ppSetAsCurrentGraphicsContext]; [[NSColor ppMaskBitmapOnColor] set]; if (shouldFill) { // A pixelated path is a path with well-defined pixel boundaries - it's made up // exclusively of horizontal, vertical, or 1:1 diagonal line-elements, each with // pixel-centered endpoints - this prevents interpolation/roundoff issues from curve // elements or differently-sloped lines, which can cause the path's fill area to have a // slightly different shape than a stroke of the same path (due to some additional or // missing pixels along the path's edges). if (pathIsPixelated) { [path fill]; } else { // Workaround for non-pixelated paths to make the fill area match the stroke is to // enable the graphics context's antialiasing when filling, then threshold the // mask to convert the antialiased middle-grey pixel-values (1-254) to 0 or 255. [path ppAntialiasedFill]; needToThresholdAntialiasedMask = YES; } } [path stroke]; [_drawingMask ppRestoreGraphicsContext]; if (needToThresholdAntialiasedMask) { [_drawingMask ppThresholdMaskBitmapPixelValuesInBounds: drawBounds]; } if (_hasSelection) { [_drawingMask ppIntersectMaskWithMaskBitmap: _selectionMask inBounds: drawBounds]; drawBounds = [_drawingMask ppMaskBoundsInRect: drawBounds]; if (NSIsEmptyRect(drawBounds)) { return; } } [self performDrawUsingMask: _drawingMask inBounds: drawBounds]; } - (void) performDrawUsingMask: (NSBitmapImageRep *) drawingMask inBounds: (NSRect) drawBounds { NSRect updateBounds = NSZeroRect; if (!_isDrawing || !drawingMask) { goto ERROR; } if (_shouldUndoCurrentDrawing) { updateBounds = _drawingUndoBounds; [self undoCurrentDrawingAndForceDrawingLayerUpdate: NO]; } drawBounds = NSIntersectionRect(drawBounds, _canvasFrame); if (!NSIsEmptyRect(drawBounds)) { PPImageBitmapPixel fillPixelValue; fillPixelValue = (_penMode == kPPPenMode_Fill) ? _fillColorPixelValue_sRGB : 0; [_drawingLayerBitmap ppMaskedFillUsingMask: drawingMask inBounds: drawBounds fillPixelValue: fillPixelValue]; updateBounds = NSUnionRect(updateBounds, drawBounds); _drawingUndoBounds = NSUnionRect(_drawingUndoBounds, drawBounds); if (_penMode == kPPPenMode_Erase) { [self mergeInteractiveEraseMaskWithMaskBitmap: drawingMask inBounds: drawBounds]; } } if (!NSIsEmptyRect(updateBounds)) { [self handleUpdateToDrawingLayerBitmapInBounds: updateBounds]; } return; ERROR: return; } - (void) undoCurrentDrawingAndForceDrawingLayerUpdate: (bool) shouldSendDrawingLayerUpdate { if (!_isDrawing || !_shouldUndoCurrentDrawing) { return; } if (!NSIsEmptyRect(_drawingUndoBounds)) { [_drawingLayerBitmap ppCopyFromBitmap: _drawingUndoBitmap inRect: _drawingUndoBounds toPoint: _drawingUndoBounds.origin]; if (shouldSendDrawingLayerUpdate) { [self handleUpdateToDrawingLayerBitmapInBounds: _drawingUndoBounds]; } _drawingUndoBounds = NSZeroRect; if (_penMode == kPPPenMode_Erase) { [self clearInteractiveEraseMask]; } } _shouldUndoCurrentDrawing = NO; } - (void) prepareUndoDrawingInBounds: (NSRect) undoBounds { NSData *undoBitmapTIFFData = [_drawingUndoBitmap ppCompressedTIFFDataFromBounds: undoBounds]; if (!undoBitmapTIFFData) goto ERROR; [[[self undoManager] prepareWithInvocationTarget: self] undoDrawingWithTIFFData: undoBitmapTIFFData atPoint: undoBounds.origin]; [[self undoManager] setActionName: @"Drawing"]; [_drawingUndoBitmap ppCopyFromBitmap: _drawingLayerBitmap inRect: undoBounds toPoint: undoBounds.origin]; return; ERROR: return; } - (void) undoDrawingWithTIFFData: (NSData *) undoBitmapTIFFData atPoint: (NSPoint) origin { NSBitmapImageRep *undoBitmap; NSRect undoBounds; NSData *redoBitmapTIFFData; if (!undoBitmapTIFFData) goto ERROR; undoBitmap = [NSBitmapImageRep imageRepWithData: undoBitmapTIFFData]; if (!undoBitmap) goto ERROR; undoBounds = NSMakeRect(origin.x, origin.y, [undoBitmap pixelsWide], [undoBitmap pixelsHigh]); redoBitmapTIFFData = [_drawingLayerBitmap ppCompressedTIFFDataFromBounds: undoBounds]; [_drawingLayerBitmap ppCopyFromBitmap: undoBitmap toPoint: origin]; [_drawingUndoBitmap ppCopyFromBitmap: undoBitmap toPoint: origin]; [self handleUpdateToDrawingLayerBitmapInBounds: undoBounds]; if (!redoBitmapTIFFData) goto ERROR; [[[self undoManager] prepareWithInvocationTarget: self] undoDrawingWithTIFFData: redoBitmapTIFFData atPoint: origin]; return; ERROR: return; } - (void) mergeInteractiveEraseMaskWithMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) maskBounds { [_interactiveEraseMask ppMergeMaskWithMaskBitmap: maskBitmap inBounds: maskBounds]; _interactiveEraseBounds = NSUnionRect(_interactiveEraseBounds, maskBounds); } - (void) clearInteractiveEraseMask { if (NSIsEmptyRect(_interactiveEraseBounds)) { return; } [_interactiveEraseMask ppClearBitmapInBounds: _interactiveEraseBounds]; _interactiveEraseBounds = NSZeroRect; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_FileFormats.m0000644000076500000240000001143413234403206022644 0ustar joshstaff/* PPDocument_FileFormats.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_NativeFileFormat.h" #import "PPGeometry.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSError_PPUtilities.h" #define kTypeName_GIF @"GIF Graphic" #define kTypeName_JPEG @"JPEG Graphic" #define kTypeName_PNG @"PNG Graphic" #define kTypeName_TIFF @"TIFF Graphic" #define kTypeName_BMP @"BMP Graphic" @implementation PPDocument (FileFormats) #pragma mark NSDocument overrides - (NSData *) dataOfType: (NSString *) typeName error: (NSError **) outError { NSData *returnedData; NSBitmapImageRep *bitmap; NSBitmapImageFileType bitmapImageFileType = NSPNGFileType; NSDictionary *propertiesDict = nil; if (outError) { *outError = nil; } if ([typeName isEqualToString: kNativeFileFormatTypeName]) { returnedData = [self nativeFileFormatData]; if (!returnedData) goto ERROR; return returnedData; } if (_saveFormat == kPPDocumentSaveFormat_Export) { bitmap = [self mergedVisibleLayersBitmapUsingExportPanelSettings]; } else { bitmap = _mergedVisibleLayersBitmap; } if ([typeName isEqualToString: kTypeName_PNG]) { bitmapImageFileType = NSPNGFileType; } else if ([typeName isEqualToString: kTypeName_TIFF]) { bitmapImageFileType = NSTIFFFileType; propertiesDict = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: NSTIFFCompressionLZW] forKey: NSImageCompressionMethod]; } else if ([typeName isEqualToString: kTypeName_GIF]) { bitmapImageFileType = NSGIFFileType; } else if ([typeName isEqualToString: kTypeName_JPEG]) { bitmapImageFileType = NSJPEGFileType; propertiesDict = [NSDictionary dictionaryWithObject: [NSNumber numberWithFloat: 1.0f] forKey: NSImageCompressionFactor]; } else if ([typeName isEqualToString: kTypeName_BMP]) { bitmapImageFileType = NSBMPFileType; } returnedData = [bitmap representationUsingType: bitmapImageFileType properties: propertiesDict]; if (!returnedData) goto ERROR; return returnedData; ERROR: if (outError) { *outError = [NSError ppError_UnableToCreateDataOfType: typeName]; } return nil; } - (BOOL) readFromData: (NSData *) data ofType: (NSString *) typeName error: (NSError **) outError { NSError *error = nil; NSBitmapImageRep *importedBitmap, *imageBitmap; if ([typeName isEqualToString: kNativeFileFormatTypeName]) { PPDocument *ppDocument = [PPDocument ppDocumentFromNativeFileFormatData: data returnedError: &error]; if (ppDocument && [self loadFromPPDocument: ppDocument]) { return YES; } else { goto ERROR; } } importedBitmap = [NSBitmapImageRep imageRepWithData: data]; if (!importedBitmap) goto ERROR; imageBitmap = [importedBitmap ppImageBitmap]; if (!imageBitmap) goto ERROR; if (PPGeometry_SizeExceedsDimension([imageBitmap ppSizeInPixels], kMaxCanvasDimension)) { error = [NSError ppError_ImageFileDimensionsAreTooLarge]; goto ERROR; } if (![self loadFromImageBitmap: imageBitmap withFileType: typeName]) { goto ERROR; } _sourceBitmapHasAnimationFrames = [importedBitmap ppImportedBitmapHasAnimationFrames]; if (outError) { *outError = nil; } return YES; ERROR: if (outError) { if (!error) { error = [NSError ppError_ImageFileIsCorrupt]; } *outError = error; } return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_LayerOperationTarget.m0000644000076500000240000001315613234403206024540 0ustar joshstaff/* PPDocument_LayerOperationTarget.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_Notifications.h" #import "PPDocumentLayer.h" @implementation PPDocument (LayerOperationTarget) - (void) setLayerOperationTarget: (PPLayerOperationTarget) operationTarget { if (!PPLayerOperationTarget_IsValid(operationTarget) || _isPerformingInteractiveMove) { return; } _layerOperationTarget = operationTarget; [self postNotification_SwitchedLayerOperationTarget]; } - (PPLayerOperationTarget) layerOperationTarget { return _layerOperationTarget; } - (bool) layerOperationTargetHasEnabledLayer { bool targetHasEnabledLayer; switch (_layerOperationTarget) { case kPPLayerOperationTarget_DrawingLayerOnly: { targetHasEnabledLayer = ([_drawingLayer isEnabled]) ? YES : NO; } break; case kPPLayerOperationTarget_VisibleLayers: case kPPLayerOperationTarget_Canvas: { targetHasEnabledLayer = (_mergedVisibleBitmapHasEnabledLayer) ? YES : NO; } break; default: { targetHasEnabledLayer = NO; } break; } return targetHasEnabledLayer; } - (NSBitmapImageRep *) sourceBitmapForLayerOperationTarget: (PPLayerOperationTarget) operationTarget { NSBitmapImageRep *sourceBitmap; switch (operationTarget) { case kPPLayerOperationTarget_DrawingLayerOnly: { // if _drawingLayer isn't enabled, _dissolvedDrawingLayerBitmap will be clear pixels sourceBitmap = ([_drawingLayer isEnabled]) ? _drawingLayerBitmap : _dissolvedDrawingLayerBitmap; } break; case kPPLayerOperationTarget_VisibleLayers: default: { sourceBitmap = _mergedVisibleLayersBitmap; } break; } return sourceBitmap; } - (void) setupTargetLayerIndexesForOperationTarget: (PPLayerOperationTarget) operationTarget { switch (operationTarget) { case kPPLayerOperationTarget_DrawingLayerOnly: { if ((_indexOfDrawingLayer >= 0) && [_drawingLayer isEnabled]) { _targetLayerIndexes[0] = _indexOfDrawingLayer; _numTargetLayerIndexes = 1; } else { _numTargetLayerIndexes = 0; } } break; case kPPLayerOperationTarget_VisibleLayers: { PPDocumentLayer *layer; int i; _numTargetLayerIndexes = 0; for (i=0; i<_numLayers; i++) { layer = [_layers objectAtIndex: i]; if ([layer isEnabled]) { _targetLayerIndexes[_numTargetLayerIndexes++] = i; } } } break; case kPPLayerOperationTarget_Canvas: { int i; for (i=0; i<_numLayers; i++) { _targetLayerIndexes[i] = i; } _numTargetLayerIndexes = _numLayers; } break; default: { _numTargetLayerIndexes = 0; } break; } } - (NSString *) nameOfLayerOperationTarget: (PPLayerOperationTarget) operationTarget { static NSString *operationTargetNames[kNumPPLayerOperationTargets] = { // Strings must match enum value ordering of PPLayerOperationTarget: @"Draw Layer", // _DrawingLayerOnly @"Enabled Layers", // _VisibleLayers @"Canvas" // _Canvas }; if (!PPLayerOperationTarget_IsValid(operationTarget)) { goto ERROR; } return operationTargetNames[operationTarget]; ERROR: return @"UNKNOWN TARGET"; } - (NSString *) nameWithSelectionStateForLayerOperationTarget: (PPLayerOperationTarget) operationTarget { static NSString *operationTargetNamesWithSelection[kNumPPLayerOperationTargets] = { // Strings must match enum value ordering of PPLayerOperationTarget: @"Draw Layer Selection", // _DrawingLayerOnly @"Enabled Layers Selection", // _VisibleLayers @"Canvas" // _Canvas (selection not used) }; if (_hasSelection && PPLayerOperationTarget_IsValid(operationTarget)) { return operationTargetNamesWithSelection[operationTarget]; } else { return [self nameOfLayerOperationTarget: operationTarget]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Layers.m0000644000076500000240000013540613234403206021676 0ustar joshstaff/* PPDocument_Layers.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_Notifications.h" #import "PPDocumentLayer.h" #import "PPGeometry.h" #import "NSImage_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPAppBootUtilities.h" static NSObject *gEmptyImageObject = nil; static NSBitmapImageRep *gEmptyBitmap = nil; @interface PPDocument (LayersPrivateMethods) - (bool) hasLayerAtIndex: (int) index; - (bool) isValidLayerInsertionIndex: (int) index; - (int) indexOfLayer: (PPDocumentLayer *) layer; - (bool) setupLayerForCurrentBlendingMode: (PPDocumentLayer *) layer; - (bool) setupAllLayersForCurrentBlendingMode; - (void) invalidateAllRelativeCachedLayerImagesForIndex: (int) index; - (void) invalidateCachedLayerImagesAtIndex: (int) index; - (void) invalidateImageObjectsInCache: (NSObject **) cachedImageObjectsArray fromIndex: (int) startIndex toIndex: (int) endIndex; - (void) removeAllCachedLayersImages; - (NSObject *) cachedOverlayersImageObjectForIndex: (int) index; - (NSObject *) cachedUnderlayersImageObjectForIndex: (int) index; - (NSObject *) mergedLayersImageObjectFromIndex: (int) firstIndex toIndex: (int) lastIndex; - (NSBitmapImageRep *) mergedLayersBitmapFromIndex: (int) firstIndex toIndex: (int) lastIndex; - (void) updateMergedVisibleLayersBitmapInRect: (NSRect) rect indexOfUpdatedLayer: (int) indexOfUpdatedLayer; - (NSString *) uniqueLayerNameWithRoot: (NSString *) rootName; - (NSString *) duplicateNameForLayerName: (NSString *) layerName; - (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex andPostNotification: (bool) shouldPostNotification; - (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex; - (void) setupDrawingLayerMembers; - (void) mergeDrawingLayerWithNextLayerInDirection: (PPDirectionType) directionType; - (bool) handleUpdateToLayer: (PPDocumentLayer *) layer; - (void) handleUpdateToDrawingLayerInRect: (NSRect) updateRect; - (void) updateDissolvedDrawingLayerBitmapInRect: (NSRect) updateRect; - (void) insertArchivedLayer: (NSData *) archivedLayer atIndex: (int) index andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer; - (bool) setLayersWithArchivedLayersData: (NSData *) archivedLayersData; - (void) setName: (NSString *) name forLayerAtIndex: (int) index; - (void) setEnabledFlag: (bool) isEnabled forLayerAtIndex: (int) index; - (void) setOpacity: (float) opacity forLayerAtIndex: (int) index; - (void) copyTIFFData: (NSData *) tiffData toLayerAtIndex: (int) index atPoint: (NSPoint) origin; - (void) recacheMergedVisibleLayersThumbnailImageInBounds: (NSRect) bounds; - (void) recacheDissolvedDrawingLayerThumbnailImageInBounds: (NSRect) bounds; @end @implementation NSObject (PPDocument_Layers) + (void) ppDocument_Layers_SetupGlobals { gEmptyImageObject = [[NSNull null] retain]; gEmptyBitmap = [[NSBitmapImageRep ppMaskBitmapOfSize: NSMakeSize(1,1)] retain]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppDocument_Layers_SetupGlobals); } @end @implementation PPDocument (Layers) - (int) numLayers { return _numLayers; } - (PPDocumentLayer *) layerAtIndex: (int) index { if (![self hasLayerAtIndex: index]) { return nil; } return (PPDocumentLayer *) [_layers objectAtIndex: index]; } - (void) createNewLayer { NSString *newLayerName; PPDocumentLayer *newLayer; int insertionIndex; if (!_numLayers) { newLayerName = @"Main Layer"; insertionIndex = 0; } else { newLayerName = [self uniqueLayerNameWithRoot: @"New Layer"]; insertionIndex = _indexOfDrawingLayer + 1; } newLayer = [PPDocumentLayer layerWithSize: _canvasFrame.size andName: newLayerName]; if (!newLayer) goto ERROR; [self insertLayer: newLayer atIndex: insertionIndex andSetAsDrawingLayer: YES]; [[self undoManager] setActionName: @"Add Layer"]; return; ERROR: return; } - (void) insertLayer: (PPDocumentLayer *) layer atIndex: (int) index andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer { int oldDrawingLayerIndex; NSUndoManager *undoManager; if (!layer || ![self isValidLayerInsertionIndex: index]) { return; } // manually invalidate relevant cached images that won't be invalidated later by // invalidateAllRelativeCachedLayerImagesForIndex: (called by handleUpdateToLayerAtIndex:) [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects fromIndex: index toIndex: _numLayers - 1]; [layer setDelegate: self]; [self setupLayerForCurrentBlendingMode: layer]; [_layers insertObject: layer atIndex: index]; _numLayers = [_layers count]; oldDrawingLayerIndex = _indexOfDrawingLayer; if (shouldSetAsDrawingLayer) { [self setupDrawingLayerWithLayerAtIndex: index andPostNotification: NO]; } else if (_indexOfDrawingLayer >= index) { _indexOfDrawingLayer++; } [self handleUpdateToLayerAtIndex: index inRect: _canvasFrame]; undoManager = [self undoManager]; if (shouldSetAsDrawingLayer) { [[undoManager prepareWithInvocationTarget: self] setupDrawingLayerWithLayerAtIndex: oldDrawingLayerIndex]; } [[undoManager prepareWithInvocationTarget: self] removeLayerAtIndex: index]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Insert Layer"]; } [self postNotification_ReorderedLayers]; } - (void) removeLayerAtIndex: (int) index { int topLayerIndex; PPDocumentLayer *layer; NSData *archivedLayer = nil; bool needToSetDrawingLayer = NO; NSUndoManager *undoManager; if (![self hasLayerAtIndex: index]) { return; } // manually invalidate relevant cached images that won't be invalidated later by // invalidateAllRelativeCachedLayerImagesForIndex: (called by handleUpdateToLayerAtIndex:) topLayerIndex = _numLayers - 1; [self invalidateCachedLayerImagesAtIndex: topLayerIndex]; [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects fromIndex: index toIndex: topLayerIndex]; layer = [_layers objectAtIndex: index]; [layer setDelegate: nil]; archivedLayer = [NSKeyedArchiver archivedDataWithRootObject: layer]; [_layers removeObjectAtIndex: index]; _numLayers = [_layers count]; if (index == _indexOfDrawingLayer) { needToSetDrawingLayer = YES; } undoManager = [self undoManager]; // need to register insertArchivedLayer:... undo invocation before the call to // createNewLayer, because createNewLayer registers an undo invocation for // removeLayerAtIndex: (which might cause layer ordering & draw layer index issues on // undo if the old removed layer is inserted before the newly-created layer is removed) [[undoManager prepareWithInvocationTarget: self] insertArchivedLayer: archivedLayer atIndex: index andSetAsDrawingLayer: needToSetDrawingLayer]; if (!_numLayers) { if (![undoManager isUndoing] && ![undoManager isRedoing]) { [self createNewLayer]; } } else if (needToSetDrawingLayer) { index = _indexOfDrawingLayer; if (index > 0) { index--; [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects fromIndex: index toIndex: index]; } [self setupDrawingLayerWithLayerAtIndex: index andPostNotification: NO]; } else if (_indexOfDrawingLayer > index) { _indexOfDrawingLayer--; } if (index >= _numLayers) { index--; } [self handleUpdateToLayerAtIndex: index inRect: _canvasFrame]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Delete Layer"]; } [self postNotification_ReorderedLayers]; } - (void) moveLayerAtIndex: (int) oldIndex toIndex: (int) newIndex { PPDocumentLayer *layer; NSUndoManager *undoManager; if (![self hasLayerAtIndex: oldIndex] || ![self hasLayerAtIndex: newIndex] || (oldIndex == newIndex)) { return; } // manually invalidate relevant cached images that won't be invalidated later by // invalidateAllRelativeCachedLayerImagesForIndex: (called by // handleUpdateToLayerAtIndex: newIndex) if (oldIndex < newIndex) { [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects fromIndex: oldIndex + 1 toIndex: newIndex]; } else { [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects fromIndex: newIndex toIndex: oldIndex - 1]; } layer = [[[_layers objectAtIndex: oldIndex] retain] autorelease]; [_layers removeObjectAtIndex: oldIndex]; [_layers insertObject: layer atIndex: newIndex]; _indexOfDrawingLayer = [_layers indexOfObject: _drawingLayer]; undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] moveLayerAtIndex: newIndex toIndex: oldIndex]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Reorder Layers"]; } [self handleUpdateToLayerAtIndex: newIndex inRect: _canvasFrame]; [self postNotification_ReorderedLayers]; } - (void) duplicateLayerAtIndex: (int) index { PPDocumentLayer *dupeLayer; NSString *dupeLayerName; if (![self hasLayerAtIndex: index]) { return; } dupeLayer = [[[_layers objectAtIndex: index] copy] autorelease]; if (!dupeLayer) goto ERROR; dupeLayerName = [self duplicateNameForLayerName: [dupeLayer name]]; [dupeLayer setName: dupeLayerName]; [self insertLayer: dupeLayer atIndex: index + 1 andSetAsDrawingLayer: YES]; [[self undoManager] setActionName: @"Duplicate Layer"]; return; ERROR: return; } - (void) removeAllLayers { [self removeAllCachedLayersImages]; [_layers makeObjectsPerformSelector: @selector(setDelegate:) withObject: nil]; [_layers removeAllObjects]; _numLayers = 0; _indexOfDrawingLayer = -1; [self setupDrawingLayerMembers]; } - (void) removeNontargetLayers { NSMutableArray *targetLayers; int i; NSBitmapImageRep *selectionMask = nil; targetLayers = [NSMutableArray array]; if (!targetLayers) goto ERROR; [self setupTargetLayerIndexesForOperationTarget: _layerOperationTarget]; // don't allow all layers to be removed (must be at least one target layer remaining) if (!_numTargetLayerIndexes) goto ERROR; for (i=0; i<_numTargetLayerIndexes; i++) { [targetLayers addObject: [_layers objectAtIndex: _targetLayerIndexes[i]]]; } if (_hasSelection) { selectionMask = [[_selectionMask copy] autorelease]; } [self setLayers: targetLayers]; if (selectionMask) { [self setSelectionMask: selectionMask]; } [[self undoManager] setActionName: @"Remove Nontarget Layers"]; return; ERROR: return; } - (bool) setLayers: (NSArray *) newLayers { NSData *archivedOldLayers; unsigned oldIndexOfDrawingLayer, newIndexOfDrawingLayer; NSUndoManager *undoManager; if (!newLayers || ![newLayers count]) { goto ERROR; } // use copies of the new layers, not the originals newLayers = [[[NSArray alloc] initWithArray: newLayers copyItems: YES] autorelease]; if (!newLayers) goto ERROR; archivedOldLayers = [NSKeyedArchiver archivedDataWithRootObject: _layers]; oldIndexOfDrawingLayer = _indexOfDrawingLayer; if (_hasSelection) { [self deselectAll]; // stores old selection in undo stack } [self removeAllLayers]; [_layers setArray: newLayers]; [_layers makeObjectsPerformSelector: @selector(setDelegate:) withObject: self]; _numLayers = [_layers count]; if (![self resizeCanvasForCurrentLayers]) { goto ERROR; } [self setupAllLayersForCurrentBlendingMode]; newIndexOfDrawingLayer = oldIndexOfDrawingLayer; if (![self hasLayerAtIndex: newIndexOfDrawingLayer]) { newIndexOfDrawingLayer = 0; } [self setupDrawingLayerWithLayerAtIndex: newIndexOfDrawingLayer andPostNotification: NO]; [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: _canvasFrame]; undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] setupDrawingLayerWithLayerAtIndex: oldIndexOfDrawingLayer]; [[undoManager prepareWithInvocationTarget: self] setLayersWithArchivedLayersData: archivedOldLayers]; [self postNotification_ReloadedDocument]; return YES; ERROR: return NO; } - (void) selectDrawingLayerAtIndex: (int) newDrawingLayerIndex { int oldIndexOfDrawingLayer; NSUndoManager *undoManager; if (![self hasLayerAtIndex: newDrawingLayerIndex] || (newDrawingLayerIndex == _indexOfDrawingLayer)) { return; } oldIndexOfDrawingLayer = _indexOfDrawingLayer; [self setupDrawingLayerWithLayerAtIndex: newDrawingLayerIndex]; undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] selectDrawingLayerAtIndex: oldIndexOfDrawingLayer]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Switch Drawing Layer"]; } } - (int) indexOfDrawingLayer { return _indexOfDrawingLayer; } - (PPDocumentLayer *) drawingLayer { return _drawingLayer; } - (void) beginMultilayerOperation { _disallowUpdatesToMergedBitmap = YES; [[[self undoManager] prepareWithInvocationTarget: self] finishMultilayerOperation]; } - (void) finishMultilayerOperation { _disallowUpdatesToMergedBitmap = NO; [self removeAllCachedLayersImages]; [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: _canvasFrame]; [[[self undoManager] prepareWithInvocationTarget: self] beginMultilayerOperation]; [self postNotification_PerformedMultilayerOperation]; } - (void) moveDrawingLayerUp { if ((_indexOfDrawingLayer >= (_numLayers - 1)) || (_indexOfDrawingLayer < 0)) { return; } [self moveLayerAtIndex: _indexOfDrawingLayer toIndex: _indexOfDrawingLayer+1]; [[self undoManager] setActionName: @"Move Layer Up"]; } - (void) moveDrawingLayerDown { if (_indexOfDrawingLayer < 1) { return; } [self moveLayerAtIndex: _indexOfDrawingLayer toIndex: _indexOfDrawingLayer-1]; [[self undoManager] setActionName: @"Move Layer Down"]; } - (void) mergeDrawingLayerUp { [self mergeDrawingLayerWithNextLayerInDirection: kPPDirectionType_Up]; } - (void) mergeDrawingLayerDown { [self mergeDrawingLayerWithNextLayerInDirection: kPPDirectionType_Down]; } - (void) mergeAllLayers { PPDocumentLayer *mergedLayer; NSBitmapImageRep *selectionMask = nil; mergedLayer = [[_drawingLayer copy] autorelease]; if (!mergedLayer) goto ERROR; [[mergedLayer bitmap] ppCopyFromBitmap: _mergedVisibleLayersBitmap toPoint: NSZeroPoint]; [mergedLayer handleUpdateToBitmapInRect: _canvasFrame]; [mergedLayer setOpacity: 1.0f]; [mergedLayer setEnabled: YES]; if (_hasSelection) { selectionMask = [[_selectionMask copy] autorelease]; } [self setLayers: [NSArray arrayWithObject: mergedLayer]]; if (selectionMask) { [self setSelectionMask: selectionMask]; } [[self undoManager] setActionName: @"Merge All Layers"]; return; ERROR: return; } - (void) setEnabledFlagForAllLayers: (bool) isEnabled { int i; isEnabled = (isEnabled) ? YES : NO; [self beginMultilayerOperation]; for (i=0; i<_numLayers; i++) { [(PPDocumentLayer *) [_layers objectAtIndex: i] setEnabled: isEnabled]; } [self finishMultilayerOperation]; [[self undoManager] setActionName: (isEnabled) ? @"Enable All Layers" : @"Disable All Layers"]; } - (PPLayerBlendingMode) layerBlendingMode { return _layerBlendingMode; } - (void) setLayerBlendingMode: (PPLayerBlendingMode) layerBlendingMode { PPLayerBlendingMode oldLayerBlendingMode; NSUndoManager *undoManager; if (!PPLayerBlendingMode_IsValid(layerBlendingMode) || (layerBlendingMode == _layerBlendingMode)) { return; } [self removeAllCachedLayersImages]; oldLayerBlendingMode = _layerBlendingMode; _layerBlendingMode = layerBlendingMode; if (![self setupAllLayersForCurrentBlendingMode] || ![self setupLayerBlendingBitmapOfSize: _canvasFrame.size]) { // if setup fails (can only fail in Linear mode), recover by forcing to Standard mode _layerBlendingMode = kPPLayerBlendingMode_Standard; [self setupAllLayersForCurrentBlendingMode]; [self setupLayerBlendingBitmapOfSize: _canvasFrame.size]; } [self updateMergedVisibleLayersBitmapInRect: _canvasFrame indexOfUpdatedLayer: _indexOfDrawingLayer]; undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] setLayerBlendingMode: oldLayerBlendingMode]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Switch Layer Blending Mode"]; } [self postNotification_SwitchedLayerBlendingMode]; [self postNotification_UpdatedMergedVisibleAreaInRect: _canvasFrame]; if (!_disallowThumbnailImageUpdateNotifications) { [self postNotification_UpdatedMergedVisibleThumbnailImage]; } } - (void) toggleLayerBlendingMode { PPLayerBlendingMode newLayerBlendingMode = _layerBlendingMode + 1; if (!PPLayerBlendingMode_IsValid(newLayerBlendingMode)) { newLayerBlendingMode = 0; } [self setLayerBlendingMode: newLayerBlendingMode]; } - (bool) setupLayerBlendingBitmapOfSize: (NSSize) bitmapSize { if (PPGeometry_IsZeroSize(bitmapSize)) { goto ERROR; } if (_layerBlendingMode == kPPLayerBlendingMode_Linear) { if (!_mergedVisibleLayersLinearBitmap || !NSEqualSizes([_mergedVisibleLayersLinearBitmap ppSizeInPixels], bitmapSize)) { NSBitmapImageRep *mergedVisibleLayersLinearBitmap = [NSBitmapImageRep ppLinearRGB16BitmapOfSize: bitmapSize]; if (!mergedVisibleLayersLinearBitmap) goto ERROR; [_mergedVisibleLayersLinearBitmap release]; _mergedVisibleLayersLinearBitmap = [mergedVisibleLayersLinearBitmap retain]; } else { [_mergedVisibleLayersLinearBitmap ppClearBitmap]; } } else // kPPLayerBlendingMode_Standard: no linear bitmap needed { if (_mergedVisibleLayersLinearBitmap) { [_mergedVisibleLayersLinearBitmap release]; _mergedVisibleLayersLinearBitmap = nil; } } return YES; ERROR: return NO; } - (void) copyImageBitmap: (NSBitmapImageRep *) bitmap toLayerAtIndex: (int) index atPoint: (NSPoint) origin { PPDocumentLayer *layer; NSSize bitmapSize; NSRect updateRect; NSBitmapImageRep *layerBitmap; NSData *undoBitmapTIFFData; if (index == _indexOfDrawingLayer) { [self copyImageBitmapToDrawingLayer: bitmap atPoint: origin]; return; } if (![bitmap ppIsImageBitmap]) { goto ERROR; } layer = [self layerAtIndex: index]; if (!layer) goto ERROR; origin = PPGeometry_PointClippedToIntegerValues(origin); bitmapSize = [bitmap ppSizeInPixels]; updateRect.origin = origin; updateRect.size = bitmapSize; updateRect = NSIntersectionRect(updateRect, _canvasFrame); if (NSIsEmptyRect(updateRect)) { goto ERROR; } if (!NSEqualSizes(updateRect.size, bitmapSize)) { NSRect croppingBounds; croppingBounds.origin = NSMakePoint(updateRect.origin.x - origin.x, updateRect.origin.y - origin.y); croppingBounds.size = updateRect.size; bitmap = [bitmap ppShallowDuplicateFromBounds: croppingBounds]; if (!bitmap) goto ERROR; } layerBitmap = [layer bitmap]; undoBitmapTIFFData = [layerBitmap ppCompressedTIFFDataFromBounds: updateRect]; if (!undoBitmapTIFFData) goto ERROR; [layerBitmap ppCopyFromBitmap: bitmap toPoint: updateRect.origin]; [layer handleUpdateToBitmapInRect: updateRect]; [self handleUpdateToLayerAtIndex: index inRect: updateRect]; [[[self undoManager] prepareWithInvocationTarget: self] copyTIFFData: undoBitmapTIFFData toLayerAtIndex: index atPoint: updateRect.origin]; return; ERROR: return; } - (void) handleUpdateToLayerAtIndex: (int) index inRect: (NSRect) updateRect { if (![self hasLayerAtIndex: index] || _disallowUpdatesToMergedBitmap) { return; } updateRect = NSIntersectionRect(updateRect, _canvasFrame); if (NSIsEmptyRect(updateRect)) { return; } [self invalidateAllRelativeCachedLayerImagesForIndex: index]; [self updateMergedVisibleLayersBitmapInRect: updateRect indexOfUpdatedLayer: index]; if (index == _indexOfDrawingLayer) { [self handleUpdateToDrawingLayerInRect: updateRect]; } [self postNotification_UpdatedMergedVisibleAreaInRect: updateRect]; if (!_disallowThumbnailImageUpdateNotifications) { [self postNotification_UpdatedMergedVisibleThumbnailImage]; } } #pragma mark PPDocumentLayer delegate methods - (void) layer: (PPDocumentLayer *) layer changedNameFromOldValue: (NSString *) oldName { int layerIndex; NSUndoManager *undoManager; layerIndex = [self indexOfLayer: layer]; if (layerIndex < 0) { return; } undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] setName: oldName forLayerAtIndex: layerIndex]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Rename Layer"]; } [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex]; } - (void) layer: (PPDocumentLayer *) layer changedEnabledFlagFromOldValue: (bool) oldEnabledFlag { int layerIndex; NSUndoManager *undoManager; if (![self handleUpdateToLayer: layer]) { return; } layerIndex = [self indexOfLayer: layer]; undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] setEnabledFlag: oldEnabledFlag forLayerAtIndex: layerIndex]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: [layer isEnabled] ? @"Enable Layer" : @"Disable Layer"]; } [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex]; } - (void) layer: (PPDocumentLayer *) layer changedOpacityFromOldValue: (float) oldOpacity shouldRegisterUndo: (bool) shouldRegisterUndo { int layerIndex; if (![self handleUpdateToLayer: layer]) { return; } layerIndex = [self indexOfLayer: layer]; if (shouldRegisterUndo) { NSUndoManager *undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] setOpacity: oldOpacity forLayerAtIndex: layerIndex]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { NSString *actionName; actionName = ([layer opacity] > oldOpacity) ? @"Increase" : @"Decrease"; actionName = [actionName stringByAppendingString: @" Layer Opacity"]; if (!actionName) { actionName = @"Change Layer Opacity"; } [[self undoManager] setActionName: actionName]; } } [self postNotification_ChangedAttributeOfLayerAtIndex: layerIndex]; } #pragma mark Private methods - (bool) hasLayerAtIndex: (int) index { return ((index >= 0) && (index < _numLayers)) ? YES : NO; } - (bool) isValidLayerInsertionIndex: (int) index { return ((index >= 0) && (index <= _numLayers) && (_numLayers < kMaxLayersPerDocument)) ? YES : NO; } - (int) indexOfLayer: (PPDocumentLayer *) layer { NSUInteger indexOfLayer; indexOfLayer = [_layers indexOfObject: layer]; if (indexOfLayer == NSNotFound) { return -1; } return (int) indexOfLayer; } - (bool) setupLayerForCurrentBlendingMode: (PPDocumentLayer *) layer { bool shouldEnableLinearBitmap; if (!layer) goto ERROR; shouldEnableLinearBitmap = (_layerBlendingMode == kPPLayerBlendingMode_Linear) ? YES : NO; if (![layer enableLinearBlendingBitmap: shouldEnableLinearBitmap]) { goto ERROR; } return YES; ERROR: return NO; } - (bool) setupAllLayersForCurrentBlendingMode { NSEnumerator *layerEnumerator; PPDocumentLayer *layer; layerEnumerator = [_layers objectEnumerator]; while (layer = [layerEnumerator nextObject]) { if (![self setupLayerForCurrentBlendingMode: layer]) { goto ERROR; } } return YES; ERROR: return NO; } - (void) invalidateAllRelativeCachedLayerImagesForIndex: (int) index { if (![self hasLayerAtIndex: index]) { return; } [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects fromIndex: 0 toIndex: index - 1]; [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects fromIndex: index + 1 toIndex: _numLayers - 1]; } - (void) invalidateCachedLayerImagesAtIndex: (int) index { if (![self hasLayerAtIndex: index]) { return; } [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects fromIndex: index toIndex: index]; [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects fromIndex: index toIndex: index]; } - (void) invalidateImageObjectsInCache: (NSObject **) cachedImageObjectsArray fromIndex: (int) startIndex toIndex: (int) endIndex { int i; if (!cachedImageObjectsArray) goto ERROR; if (startIndex < 0) { startIndex = 0; } if (endIndex >= _numLayers) { endIndex = _numLayers - 1; } if (startIndex > endIndex) { goto ERROR; } for (i=startIndex; i<=endIndex; i++) { if (cachedImageObjectsArray[i]) { [cachedImageObjectsArray[i] release]; cachedImageObjectsArray[i] = nil; } } return; ERROR: return; } - (void) removeAllCachedLayersImages { [self invalidateImageObjectsInCache: _cachedOverlayersImageObjects fromIndex: 0 toIndex: _numLayers - 1]; [self invalidateImageObjectsInCache: _cachedUnderlayersImageObjects fromIndex: 0 toIndex: _numLayers - 1]; } - (NSObject *) cachedOverlayersImageObjectForIndex: (int) index { if ((index >= (_numLayers - 1)) || ![self hasLayerAtIndex: index]) { return nil; } if (!_cachedOverlayersImageObjects[index]) { _cachedOverlayersImageObjects[index] = [[self mergedLayersImageObjectFromIndex: index + 1 toIndex: _numLayers - 1] retain]; } return _cachedOverlayersImageObjects[index]; } - (NSObject *) cachedUnderlayersImageObjectForIndex: (int) index { if ((index < 1) || ![self hasLayerAtIndex: index]) { return nil; } if (!_cachedUnderlayersImageObjects[index]) { _cachedUnderlayersImageObjects[index] = [[self mergedLayersImageObjectFromIndex: 0 toIndex: index - 1] retain]; } return _cachedUnderlayersImageObjects[index]; } - (NSObject *) mergedLayersImageObjectFromIndex: (int) firstIndex toIndex: (int) lastIndex { NSBitmapImageRep *mergedLayersBitmap; NSObject *imageObject = nil; mergedLayersBitmap = [self mergedLayersBitmapFromIndex: firstIndex toIndex: lastIndex]; if (!mergedLayersBitmap) goto ERROR; if (mergedLayersBitmap == gEmptyBitmap) { // Empty bitmap: return empty image-object imageObject = gEmptyImageObject; } else if (_layerBlendingMode == kPPLayerBlendingMode_Linear) { // Linear blending: image-objects are NSBitmapImageReps (LinearRGB16) imageObject = mergedLayersBitmap; } else { // Standard blending: image-objects are NSImages imageObject = [NSImage ppImageWithBitmap: mergedLayersBitmap]; } if (!imageObject) goto ERROR; return imageObject; ERROR: return nil; } - (NSBitmapImageRep *) mergedLayersBitmapFromIndex: (int) firstIndex toIndex: (int) lastIndex { NSBitmapImageRep *mergedLayersBitmap = nil; int index; PPDocumentLayer *layer; float layerOpacity; if (firstIndex < 0) { firstIndex = 0; } if (lastIndex >= [_layers count]) { lastIndex = [_layers count] - 1; } if (firstIndex > lastIndex) { goto ERROR; } if (_layerBlendingMode == kPPLayerBlendingMode_Linear) { // Linear blending - generate LinearRGB16 bitmap, merge using PikoPixel's LinearRGB16 // methods for (index=lastIndex; index>=firstIndex; index--) { layer = [self layerAtIndex: index]; layerOpacity = [layer opacity]; if ([layer isEnabled] && (layerOpacity > 0.0f)) { if (!mergedLayersBitmap) { mergedLayersBitmap = [NSBitmapImageRep ppLinearRGB16BitmapOfSize: _canvasFrame.size]; if (!mergedLayersBitmap) goto ERROR; // merge the first layer using linear-copy (faster than linear-blend) [mergedLayersBitmap ppLinearCopyFromLinearBitmap: [layer linearBlendingBitmap] opacity: layerOpacity inBounds: _canvasFrame]; } else { [mergedLayersBitmap ppLinearBlendFromLinearBitmapUnderneath: [layer linearBlendingBitmap] sourceOpacity: layerOpacity inBounds: _canvasFrame]; } } } } else { // Standard blending - generate standard Image bitmap (sRGB), merge using native Cocoa // methods NSCompositingOperation compositingOperation; for (index=firstIndex; index<=lastIndex; index++) { layer = [self layerAtIndex: index]; layerOpacity = [layer opacity]; if ([layer isEnabled] && (layerOpacity > 0.0f)) { if (!mergedLayersBitmap) { mergedLayersBitmap = [NSBitmapImageRep ppImageBitmapOfSize: _canvasFrame.size]; if (!mergedLayersBitmap) goto ERROR; [mergedLayersBitmap ppSetAsCurrentGraphicsContext]; // merge the first layer using NSCompositeCopy (faster than // NSCompositeSourceOver) compositingOperation = NSCompositeCopy; } else { compositingOperation = NSCompositeSourceOver; } [[layer image] drawInRect: _canvasFrame fromRect: _canvasFrame operation: compositingOperation fraction: layerOpacity]; } } if (mergedLayersBitmap) { [mergedLayersBitmap ppRestoreGraphicsContext]; } } if (!mergedLayersBitmap) { // No layers were merged - return empty bitmap (different from returning nil, which // signifies an error) return gEmptyBitmap; } return mergedLayersBitmap; ERROR: return nil; } - (void) updateMergedVisibleLayersBitmapInRect: (NSRect) rect indexOfUpdatedLayer: (int) indexOfUpdatedLayer { NSObject *imageObject, *imageObjectsToMerge[3]; int numImageObjectsToMerge = 0, imageIndexOfUpdatedLayer = -1, imageIndex; PPDocumentLayer *updatedLayer; float opacityOfUpdatedLayer, mergingOpacity; bool performedInitialMerge = NO; if (NSIsEmptyRect(rect) || ![self hasLayerAtIndex: indexOfUpdatedLayer]) { return; } // Collect image-objects for merge: // 1) Underlayers image (merged layers below updated layer) imageObject = [self cachedUnderlayersImageObjectForIndex: indexOfUpdatedLayer]; if (imageObject && (imageObject != gEmptyImageObject)) { imageObjectsToMerge[numImageObjectsToMerge++] = imageObject; } // 2) Updated-layer image updatedLayer = [_layers objectAtIndex: indexOfUpdatedLayer]; opacityOfUpdatedLayer = [updatedLayer opacity]; if ([updatedLayer isEnabled] && (opacityOfUpdatedLayer > 0.0f)) { // Linear blending: image-objects are NSBitmapImageReps (LinearRGB16) // Standard blending: image-objects are NSImages imageObject = (_layerBlendingMode == kPPLayerBlendingMode_Linear) ? (NSObject *) [updatedLayer linearBlendingBitmap] : (NSObject *) [updatedLayer image]; // Don't need to check that (imageObject != gEmptyImageObject), since gEmptyImageObject // is local & won't be returned by PPDocumentLayer methods if (imageObject) { imageIndexOfUpdatedLayer = numImageObjectsToMerge; imageObjectsToMerge[numImageObjectsToMerge++] = imageObject; } } // 3) Overlayers image (merged layers above updated layer) imageObject = [self cachedOverlayersImageObjectForIndex: indexOfUpdatedLayer]; if (imageObject && (imageObject != gEmptyImageObject)) { imageObjectsToMerge[numImageObjectsToMerge++] = imageObject; } // Merge collected image-objects: if (_layerBlendingMode == kPPLayerBlendingMode_Linear) { // Linear blending - image-objects are NSBitmapImageReps (LinearRGB16); merge using // PikoPixel's LinearRGB16 bitmap methods NSBitmapImageRep *mergingBitmap; for (imageIndex=numImageObjectsToMerge-1; imageIndex>=0; imageIndex--) { mergingBitmap = (NSBitmapImageRep *) imageObjectsToMerge[imageIndex]; mergingOpacity = (imageIndex == imageIndexOfUpdatedLayer) ? opacityOfUpdatedLayer : 1.0f; if (!performedInitialMerge) { // merge the first bitmap using linear-copy (faster than linear-blend) [_mergedVisibleLayersLinearBitmap ppLinearCopyFromLinearBitmap: mergingBitmap opacity: mergingOpacity inBounds: rect]; performedInitialMerge = YES; } else { [_mergedVisibleLayersLinearBitmap ppLinearBlendFromLinearBitmapUnderneath: mergingBitmap sourceOpacity: mergingOpacity inBounds: rect]; } } if (!performedInitialMerge) { // nothing was merged to the updated area, so clear it manually [_mergedVisibleLayersLinearBitmap ppClearBitmapInBounds: rect]; } [_mergedVisibleLayersLinearBitmap ppLinearCopyToImageBitmap: _mergedVisibleLayersBitmap inBounds: rect]; } else { // Standard blending - image-objects are NSImages; merge using native Cocoa methods NSImage *mergingImage; NSCompositingOperation compositingOperation; for (imageIndex=0; imageIndex 0) ? YES : NO; [self recacheMergedVisibleLayersThumbnailImageInBounds: rect]; } - (NSString *) uniqueLayerNameWithRoot: (NSString *) rootName { int rootNameLength; NSMutableSet *prefixMatches; NSEnumerator *enumerator; PPDocumentLayer *layer; NSString *layerName, *testName; int suffixValue; if (![rootName length]) { rootName = @""; } rootNameLength = [rootName length]; prefixMatches = [NSMutableSet set]; enumerator = [_layers objectEnumerator]; while (layer = [enumerator nextObject]) { layerName = [layer name]; if (([layerName length] >= rootNameLength) && [layerName hasPrefix: rootName]) { [prefixMatches addObject: layerName]; } } if (![prefixMatches count]) { return rootName; } suffixValue = 1; testName = [NSString stringWithFormat: @"%@ %02d", rootName, suffixValue]; while ([prefixMatches containsObject: testName]) { suffixValue++; testName = [NSString stringWithFormat: @"%@ %02d", rootName, suffixValue]; } return testName; } - (NSString *) duplicateNameForLayerName: (NSString *) layerName { if (![layerName hasSuffix: @" copy"]) { layerName = [layerName stringByAppendingString: @" copy"]; } return [self uniqueLayerNameWithRoot: layerName]; } - (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex andPostNotification: (bool) shouldPostNotification { if (![self hasLayerAtIndex: newDrawingLayerIndex]) { newDrawingLayerIndex = -1; } _indexOfDrawingLayer = newDrawingLayerIndex; [self setupDrawingLayerMembers]; [self handleUpdateToDrawingLayerInRect: _canvasFrame]; if (shouldPostNotification) { [self postNotification_SwitchedDrawingLayer]; } } - (void) setupDrawingLayerWithLayerAtIndex: (int) newDrawingLayerIndex { [self setupDrawingLayerWithLayerAtIndex: newDrawingLayerIndex andPostNotification: YES]; } - (void) setupDrawingLayerMembers { [_drawingLayerImage release]; _drawingLayerImage = nil; [_drawingLayerBitmap release]; _drawingLayerBitmap = nil; [_drawingLayer release]; _drawingLayer = nil; if ([self hasLayerAtIndex: _indexOfDrawingLayer]) { _drawingLayer = [[_layers objectAtIndex: _indexOfDrawingLayer] retain]; _drawingLayerBitmap = [[_drawingLayer bitmap] retain]; _drawingLayerImage = [[_drawingLayer image] retain]; [_drawingUndoBitmap ppCopyFromBitmap: _drawingLayerBitmap toPoint: NSZeroPoint]; } else { [_drawingUndoBitmap ppClearBitmap]; } } - (void) mergeDrawingLayerWithNextLayerInDirection: (PPDirectionType) directionType { int indexOfMergingLayer; NSBitmapImageRep *mergedLayersBitmap; NSString *actionName; bool shouldEnableMergedDrawLayer = YES; if (![self hasLayerAtIndex: _indexOfDrawingLayer]) { goto ERROR; } if (directionType == kPPDirectionType_Up) { indexOfMergingLayer = _indexOfDrawingLayer + 1; if (![self hasLayerAtIndex: indexOfMergingLayer]) { goto ERROR; } mergedLayersBitmap = [self mergedLayersBitmapFromIndex: _indexOfDrawingLayer toIndex: indexOfMergingLayer]; actionName = @"Merge with Layer Above"; } else if (directionType == kPPDirectionType_Down) { indexOfMergingLayer = _indexOfDrawingLayer - 1; if (![self hasLayerAtIndex: indexOfMergingLayer]) { goto ERROR; } mergedLayersBitmap = [self mergedLayersBitmapFromIndex: indexOfMergingLayer toIndex: _indexOfDrawingLayer]; actionName = @"Merge with Layer Below"; } else { // only allow up or down directions goto ERROR; } if (mergedLayersBitmap == gEmptyBitmap) { mergedLayersBitmap = [NSBitmapImageRep ppImageBitmapOfSize: _canvasFrame.size]; shouldEnableMergedDrawLayer = NO; } else if ([mergedLayersBitmap ppIsLinearRGB16Bitmap]) { mergedLayersBitmap = [mergedLayersBitmap ppImageBitmapFromLinearRGB16Bitmap]; } if (!mergedLayersBitmap) goto ERROR; [self copyImageBitmapToDrawingLayer: mergedLayersBitmap atPoint: NSZeroPoint]; [_drawingLayer setOpacity: 1.0f]; [_drawingLayer setEnabled: shouldEnableMergedDrawLayer]; [self removeLayerAtIndex: indexOfMergingLayer]; [[self undoManager] setActionName: actionName]; return; ERROR: return; } - (bool) handleUpdateToLayer: (PPDocumentLayer *) layer { int indexOfChangedLayer; indexOfChangedLayer = [_layers indexOfObject: layer]; if (![self hasLayerAtIndex: indexOfChangedLayer]) { return NO; } [self handleUpdateToLayerAtIndex: indexOfChangedLayer inRect: _canvasFrame]; return YES; } - (void) handleUpdateToDrawingLayerInRect: (NSRect) updateRect { [self updateDissolvedDrawingLayerBitmapInRect: updateRect]; [self postNotification_UpdatedDrawingLayerAreaInRect: updateRect]; if (!_disallowThumbnailImageUpdateNotifications) { [self postNotification_UpdatedDrawingLayerThumbnailImage]; } } - (void) updateDissolvedDrawingLayerBitmapInRect: (NSRect) updateRect { float drawingLayerOpacity = [_drawingLayer opacity]; if ([_drawingLayer isEnabled] && (drawingLayerOpacity > 0)) { [_dissolvedDrawingLayerBitmap ppSetAsCurrentGraphicsContext]; [_drawingLayerImage drawInRect: updateRect fromRect: updateRect operation: NSCompositeCopy fraction: drawingLayerOpacity]; [_dissolvedDrawingLayerBitmap ppRestoreGraphicsContext]; } else { [_dissolvedDrawingLayerBitmap ppClearBitmapInBounds: updateRect]; } [self recacheDissolvedDrawingLayerThumbnailImageInBounds: updateRect]; } - (void) insertArchivedLayer: (NSData *) archivedLayer atIndex: (int) index andSetAsDrawingLayer: (bool) shouldSetAsDrawingLayer { PPDocumentLayer *layer; if (!archivedLayer) goto ERROR; layer = [NSKeyedUnarchiver unarchiveObjectWithData: archivedLayer]; if (!layer || ![layer isKindOfClass: [PPDocumentLayer class]]) { goto ERROR; } [self insertLayer: layer atIndex: index andSetAsDrawingLayer: shouldSetAsDrawingLayer]; return; ERROR: return; } - (bool) setLayersWithArchivedLayersData: (NSData *) archivedLayersData { NSArray *layers; if (!archivedLayersData) goto ERROR; layers = [NSKeyedUnarchiver unarchiveObjectWithData: archivedLayersData]; if (!layers || ![layers isKindOfClass: [NSArray class]]) { goto ERROR; } return [self setLayers: layers]; ERROR: return NO; } - (void) setName: (NSString *) name forLayerAtIndex: (int) index { [[self layerAtIndex: index] setName: name]; } - (void) setEnabledFlag: (bool) isEnabled forLayerAtIndex: (int) index { [[self layerAtIndex: index] setEnabled: isEnabled]; } - (void) setOpacity: (float) opacity forLayerAtIndex: (int) index { [[self layerAtIndex: index] setOpacity: opacity]; } - (void) copyTIFFData: (NSData *) tiffData toLayerAtIndex: (int) index atPoint: (NSPoint) origin { [self copyImageBitmap: [NSBitmapImageRep imageRepWithData: tiffData] toLayerAtIndex: index atPoint: origin]; } // recacheMergedVisibleLayersThumbnailImageInBounds: // & recacheDissolvedDrawingLayerThumbnailImageInBounds: methods are patch targets on GNUstep // (PPGNUstepGlue_ImageRecacheSpeedups) - (void) recacheMergedVisibleLayersThumbnailImageInBounds: (NSRect) bounds { [_mergedVisibleLayersThumbnailImage recache]; } - (void) recacheDissolvedDrawingLayerThumbnailImageInBounds: (NSRect) bounds { [_dissolvedDrawingLayerThumbnailImage recache]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_MirroringRotating.m0000644000076500000240000005610313234403206024113 0ustar joshstaff/* PPDocument_MirroringRotating.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPDocumentLayer.h" #import "PPGeometry.h" #define kMirrorRotateOperationName_MirrorHorizontally @"Flip Horizontally" #define kMirrorRotateOperationName_MirrorVertically @"Flip Vertically" #if PP_SDK_ALLOWS_NONASCII_STRING_LITERALS # define kMirrorRotateOperationName_Rotate180 @"Rotate 180°" # define kMirrorRotateOperationName_Rotate90Clockwise @"Rotate 90° Clockwise" # define kMirrorRotateOperationName_Rotate90Counterclockwise @"Rotate 90° Counterclockwise" #else // SDK requires ASCII string literals # define kMirrorRotateOperationName_Rotate180 @"Rotate 180" # define kMirrorRotateOperationName_Rotate90Clockwise @"Rotate 90 Clockwise" # define kMirrorRotateOperationName_Rotate90Counterclockwise @"Rotate 90 Counterclockwise" #endif // PP_SDK_ALLOWS_NONASCII_STRING_LITERALS typedef enum { kPPMirrorRotateOperationType_MirrorHorizontally, kPPMirrorRotateOperationType_MirrorVertically, kPPMirrorRotateOperationType_Rotate180, kPPMirrorRotateOperationType_Rotate90Clockwise, kPPMirrorRotateOperationType_Rotate90Counterclockwise } PPMirrorRotateOperationType; static SEL NSBitmapImagRepPPUtilitiesSelectorForOperation( PPMirrorRotateOperationType operation); static bool OperationIsRotate90(PPMirrorRotateOperationType operation); static void GetCleanupRectsForRotate90InBounds(NSRect bounds, NSRect *returnedCleanupRect1, NSRect *returnedCleanupRect2); @interface PPDocument (MirroringRotatingPrivateMethods) - (void) performOperation: (PPMirrorRotateOperationType) operation onTarget: (PPLayerOperationTarget) operationTarget; - (bool) getDestinationOrigin: (NSPoint *) returnedDestinationOrigin preOperationCroppedMask: (NSBitmapImageRep **) returnedPreOperationCroppedMask andPostOperationCroppedMask: (NSBitmapImageRep **) returnedPostOperationCroppedMask forOperation: (PPMirrorRotateOperationType) operation; - (void) performOperationWithSelector: (SEL) operationSelector onLayerWithIndex: (int) index destinationOrigin: (NSPoint) destinationOrigin preOperationCroppedMask: (NSBitmapImageRep *) preOperationCroppedMask postOperationCroppedMask: (NSBitmapImageRep *) postOperationCroppedMask preAndPostCroppedMasksAreEqual: (bool) preAndPostCroppedMasksAreEqual operationIsRotate90: (bool) operationIsRotate90; - (bool) rotateNonsquareCanvas90WithOperationSelector: (SEL) operationSelector; - (void) setUndoActionNameForOperation: (PPMirrorRotateOperationType) operation withTargetName: (NSString *) targetName; @end @implementation PPDocument (MirroringRotating) - (void) mirrorHorizontallyWithTarget: (PPLayerOperationTarget) operationTarget { [self performOperation: kPPMirrorRotateOperationType_MirrorHorizontally onTarget: operationTarget]; } - (void) mirrorVerticallyWithTarget: (PPLayerOperationTarget) operationTarget { [self performOperation: kPPMirrorRotateOperationType_MirrorVertically onTarget: operationTarget]; } - (void) rotate180WithTarget: (PPLayerOperationTarget) operationTarget { [self performOperation: kPPMirrorRotateOperationType_Rotate180 onTarget: operationTarget]; } - (void) rotate90ClockwiseWithTarget: (PPLayerOperationTarget) operationTarget { [self performOperation: kPPMirrorRotateOperationType_Rotate90Clockwise onTarget: operationTarget]; } - (void) rotate90CounterclockwiseWithTarget: (PPLayerOperationTarget) operationTarget { [self performOperation: kPPMirrorRotateOperationType_Rotate90Counterclockwise onTarget: operationTarget]; } #pragma mark Private methods - (void) performOperation: (PPMirrorRotateOperationType) operation onTarget: (PPLayerOperationTarget) operationTarget { SEL operationSelector; bool operationIsRotate90, operationIsReversible, isMultilayerOperation; NSString *targetName; NSPoint destinationOrigin = NSZeroPoint; NSBitmapImageRep *preOperationCroppedMask = nil, *postOperationCroppedMask = nil; NSUndoManager *undoManager; int i; operationSelector = NSBitmapImagRepPPUtilitiesSelectorForOperation(operation); if (!operationSelector) goto ERROR; operationIsRotate90 = OperationIsRotate90(operation); if (operationTarget == kPPLayerOperationTarget_Canvas) { if (operationIsRotate90 && !PPGeometry_RectIsSquare(_canvasFrame)) { if ([self rotateNonsquareCanvas90WithOperationSelector: operationSelector]) { targetName = [self nameWithSelectionStateForLayerOperationTarget: operationTarget]; [self setUndoActionNameForOperation: operation withTargetName: targetName]; } return; } else { operationIsReversible = YES; } } else { if (_hasSelection) { if (![self getDestinationOrigin: &destinationOrigin preOperationCroppedMask: &preOperationCroppedMask andPostOperationCroppedMask: &postOperationCroppedMask forOperation: operation]) { goto ERROR; } operationIsReversible = [preOperationCroppedMask ppIsEqualToBitmap: postOperationCroppedMask]; } else { if (operationIsRotate90 && !PPGeometry_RectIsSquare(_canvasFrame)) { if (![self getDestinationOrigin: &destinationOrigin preOperationCroppedMask: NULL andPostOperationCroppedMask: NULL forOperation: operation]) { goto ERROR; } operationIsReversible = NO; } else { operationIsReversible = YES; } } } [self setupTargetLayerIndexesForOperationTarget: operationTarget]; if (!_numTargetLayerIndexes && !_hasSelection) { goto ERROR; } undoManager = [self undoManager]; if (operationIsReversible) { [undoManager disableUndoRegistration]; } isMultilayerOperation = (_numTargetLayerIndexes > 1) ? YES : NO; if (isMultilayerOperation) { [self beginMultilayerOperation]; } for (i=0; i<_numTargetLayerIndexes; i++) { [self performOperationWithSelector: operationSelector onLayerWithIndex: _targetLayerIndexes[i] destinationOrigin: destinationOrigin preOperationCroppedMask: preOperationCroppedMask postOperationCroppedMask: postOperationCroppedMask preAndPostCroppedMasksAreEqual: operationIsReversible operationIsRotate90: operationIsRotate90]; } if (isMultilayerOperation) { [self finishMultilayerOperation]; } if (_hasSelection) { if (operationTarget == kPPLayerOperationTarget_Canvas) { NSBitmapImageRep *postOperationSelectionMask = [_selectionMask performSelector: operationSelector]; if (![_selectionMask ppIsEqualToBitmap: postOperationSelectionMask]) { [self setSelectionMaskAreaWithBitmap: postOperationSelectionMask atPoint: NSZeroPoint]; } } else if (!operationIsReversible) { if (operationIsRotate90 && !PPGeometry_RectIsSquare(_selectionBounds)) { NSRect cleanupRects[2] = {NSZeroRect, NSZeroRect}; GetCleanupRectsForRotate90InBounds(_selectionBounds, &cleanupRects[0], &cleanupRects[1]); for (i=0; i<2; i++) { if (!NSIsEmptyRect(cleanupRects[i])) { [self setSelectionMaskAreaWithBitmap: [NSBitmapImageRep ppMaskBitmapOfSize: cleanupRects[i].size] atPoint: cleanupRects[i].origin]; } } } [self setSelectionMaskAreaWithBitmap: postOperationCroppedMask atPoint: destinationOrigin]; } } if (operationIsReversible) { PPMirrorRotateOperationType reverseOperation; [undoManager enableUndoRegistration]; if (operationIsRotate90) { reverseOperation = (operation == kPPMirrorRotateOperationType_Rotate90Clockwise) ? kPPMirrorRotateOperationType_Rotate90Counterclockwise : kPPMirrorRotateOperationType_Rotate90Clockwise; } else { reverseOperation = operation; } [[undoManager prepareWithInvocationTarget: self] performOperation: reverseOperation onTarget: operationTarget]; } if (_numTargetLayerIndexes > 0) { targetName = [self nameWithSelectionStateForLayerOperationTarget: operationTarget]; } else { targetName = @"Selection Outline"; } [self setUndoActionNameForOperation: operation withTargetName: targetName]; return; ERROR: return; } - (bool) getDestinationOrigin: (NSPoint *) returnedDestinationOrigin preOperationCroppedMask: (NSBitmapImageRep **) returnedPreOperationCroppedMask andPostOperationCroppedMask: (NSBitmapImageRep **) returnedPostOperationCroppedMask forOperation: (PPMirrorRotateOperationType) operation { SEL operationSelector; NSRect operationBounds; if (!returnedDestinationOrigin || (_hasSelection && (!returnedPreOperationCroppedMask || !returnedPostOperationCroppedMask))) { goto ERROR; } operationSelector = NSBitmapImagRepPPUtilitiesSelectorForOperation(operation); if (!operationSelector) goto ERROR; if (_hasSelection) { NSBitmapImageRep *preOperationCroppedMask, *postOperationCroppedMask; preOperationCroppedMask = [_selectionMask ppBitmapCroppedToBounds: _selectionBounds]; postOperationCroppedMask = [preOperationCroppedMask performSelector: operationSelector]; if (!preOperationCroppedMask || !postOperationCroppedMask) { goto ERROR; } *returnedPreOperationCroppedMask = preOperationCroppedMask; *returnedPostOperationCroppedMask = postOperationCroppedMask; operationBounds = _selectionBounds; } else { if (returnedPreOperationCroppedMask) { *returnedPreOperationCroppedMask = nil; } if (returnedPostOperationCroppedMask) { *returnedPostOperationCroppedMask = nil; } operationBounds = _canvasFrame; } if (OperationIsRotate90(operation)) { operationBounds = PPGeometry_CenterRectInRect(NSMakeRect(0.0f, 0.0f, operationBounds.size.height, operationBounds.size.width), operationBounds); } *returnedDestinationOrigin = operationBounds.origin; return YES; ERROR: return NO; } - (void) performOperationWithSelector: (SEL) operationSelector onLayerWithIndex: (int) index destinationOrigin: (NSPoint) destinationOrigin preOperationCroppedMask: (NSBitmapImageRep *) preOperationCroppedMask postOperationCroppedMask: (NSBitmapImageRep *) postOperationCroppedMask preAndPostCroppedMasksAreEqual: (bool) preAndPostCroppedMasksAreEqual operationIsRotate90: (bool) operationIsRotate90 { PPDocumentLayer *layer; NSBitmapImageRep *layerBitmap; if (!operationSelector) goto ERROR; layer = [self layerAtIndex: index]; layerBitmap = [layer bitmap]; if (!layer || !layerBitmap) { goto ERROR; } if (preOperationCroppedMask) { NSBitmapImageRep *updatedAreaBitmap, *operatedBitmap; if (!postOperationCroppedMask) goto ERROR; updatedAreaBitmap = [layerBitmap ppBitmapCroppedToBounds: _selectionBounds]; operatedBitmap = [updatedAreaBitmap performSelector: operationSelector]; if (!updatedAreaBitmap || !operatedBitmap) { goto ERROR; } if (!preAndPostCroppedMasksAreEqual) { [updatedAreaBitmap ppMaskedEraseUsingMask: preOperationCroppedMask]; } if (operationIsRotate90 && !PPGeometry_RectIsSquare(_selectionBounds)) { NSRect postOperationBounds; [self copyImageBitmap: updatedAreaBitmap toLayerAtIndex: index atPoint: _selectionBounds.origin]; postOperationBounds.origin = destinationOrigin; postOperationBounds.size = [postOperationCroppedMask ppSizeInPixels]; updatedAreaBitmap = [layerBitmap ppBitmapCroppedToBounds: postOperationBounds]; } [updatedAreaBitmap ppMaskedCopyFromImageBitmap: operatedBitmap usingMask: postOperationCroppedMask]; [self copyImageBitmap: updatedAreaBitmap toLayerAtIndex: index atPoint: destinationOrigin]; } else { NSBitmapImageRep *operatedBitmap; operatedBitmap = [layerBitmap performSelector: operationSelector]; if (!operatedBitmap) goto ERROR; [self copyImageBitmap: operatedBitmap toLayerAtIndex: index atPoint: destinationOrigin]; if (operationIsRotate90 && !PPGeometry_RectIsSquare(_canvasFrame)) { NSRect cleanupRects[2] = {NSZeroRect, NSZeroRect}; int i; GetCleanupRectsForRotate90InBounds(_canvasFrame, &cleanupRects[0], &cleanupRects[1]); for (i=0; i<2; i++) { if (!NSIsEmptyRect(cleanupRects[i])) { [self copyImageBitmap: [NSBitmapImageRep ppImageBitmapOfSize: cleanupRects[i].size] toLayerAtIndex: index atPoint: cleanupRects[i].origin]; } } } } return; ERROR: return; } - (bool) rotateNonsquareCanvas90WithOperationSelector: (SEL) operationSelector { NSMutableArray *rotatedLayers; NSEnumerator *layerEnumerator; PPDocumentLayer *layer, *rotatedLayer; NSSize layerSize; NSRect rotatedLayerFrame = NSZeroRect; NSBitmapImageRep *rotatedLayerBitmap, *rotatedSelectionMask = nil; if (!operationSelector) goto ERROR; rotatedLayers = [NSMutableArray array]; if (!rotatedLayers) goto ERROR; layerEnumerator = [_layers objectEnumerator]; while (layer = [layerEnumerator nextObject]) { layerSize = [layer size]; rotatedLayerFrame = NSMakeRect(0, 0, layerSize.height, layerSize.width); rotatedLayer = [[[PPDocumentLayer alloc] initWithSize: rotatedLayerFrame.size name: [layer name] tiffData: nil opacity: [layer opacity] isEnabled: [layer isEnabled]] autorelease]; rotatedLayerBitmap = [[layer bitmap] performSelector: operationSelector]; if (!rotatedLayer || !rotatedLayerBitmap) { goto ERROR; } [[rotatedLayer bitmap] ppCopyFromBitmap: rotatedLayerBitmap toPoint: NSZeroPoint]; [rotatedLayer handleUpdateToBitmapInRect: rotatedLayerFrame]; [rotatedLayers addObject: rotatedLayer]; } if ([rotatedLayers count] != _numLayers) { goto ERROR; } if (_hasSelection) { rotatedSelectionMask = [_selectionMask performSelector: operationSelector]; } [self setLayers: rotatedLayers]; if (rotatedSelectionMask) { [self setSelectionMask: rotatedSelectionMask]; } return YES; ERROR: return NO; } - (void) setUndoActionNameForOperation: (PPMirrorRotateOperationType) operation withTargetName: (NSString *) targetName { NSUndoManager *undoManager; NSString *operationName, *actionName = nil; undoManager = [self undoManager]; if ([undoManager isUndoing] || [undoManager isRedoing]) { return; } switch (operation) { case kPPMirrorRotateOperationType_MirrorHorizontally: { operationName = kMirrorRotateOperationName_MirrorHorizontally; } break; case kPPMirrorRotateOperationType_MirrorVertically: { operationName = kMirrorRotateOperationName_MirrorVertically; } break; case kPPMirrorRotateOperationType_Rotate180: { operationName = kMirrorRotateOperationName_Rotate180; } break; case kPPMirrorRotateOperationType_Rotate90Clockwise: { operationName = kMirrorRotateOperationName_Rotate90Clockwise; } break; case kPPMirrorRotateOperationType_Rotate90Counterclockwise: { operationName = kMirrorRotateOperationName_Rotate90Counterclockwise; } break; default: { operationName = @"Flip/Rotate"; } break; } if (targetName) { actionName = [NSString stringWithFormat: @"%@ (%@)", operationName, targetName]; } if (!actionName) { actionName = operationName; } [undoManager setActionName: actionName]; } @end #pragma mark Private functions static SEL NSBitmapImagRepPPUtilitiesSelectorForOperation(PPMirrorRotateOperationType operation) { SEL operationSelector; switch (operation) { case kPPMirrorRotateOperationType_MirrorHorizontally: { operationSelector = @selector(ppBitmapMirroredHorizontally); } break; case kPPMirrorRotateOperationType_MirrorVertically: { operationSelector = @selector(ppBitmapMirroredVertically); } break; case kPPMirrorRotateOperationType_Rotate180: { operationSelector = @selector(ppBitmapRotated180); } break; case kPPMirrorRotateOperationType_Rotate90Clockwise: { operationSelector = @selector(ppBitmapRotated90Clockwise); } break; case kPPMirrorRotateOperationType_Rotate90Counterclockwise: { operationSelector = @selector(ppBitmapRotated90Counterclockwise); } break; default: { operationSelector = NULL; } break; } return operationSelector; } static bool OperationIsRotate90(PPMirrorRotateOperationType operation) { if ((operation == kPPMirrorRotateOperationType_Rotate90Clockwise) || (operation == kPPMirrorRotateOperationType_Rotate90Counterclockwise)) { return YES; } return NO; } static void GetCleanupRectsForRotate90InBounds(NSRect bounds, NSRect *returnedCleanupRect1, NSRect *returnedCleanupRect2) { NSRect rotatedBounds, cleanupRects[2] = {NSZeroRect, NSZeroRect}; if (!returnedCleanupRect1 || !returnedCleanupRect2) { goto ERROR; } rotatedBounds = PPGeometry_CenterRectInRect(NSMakeRect(0.0f, 0.0f, bounds.size.height, bounds.size.width), bounds); if (bounds.size.width > rotatedBounds.size.width) { if (bounds.origin.x < rotatedBounds.origin.x) { cleanupRects[0].origin = bounds.origin; cleanupRects[0].size.width = rotatedBounds.origin.x - bounds.origin.x; cleanupRects[0].size.height = bounds.size.height; } if ((bounds.origin.x + bounds.size.width) > (rotatedBounds.origin.x + rotatedBounds.size.width)) { cleanupRects[1].origin.x = rotatedBounds.origin.x + rotatedBounds.size.width; cleanupRects[1].origin.y = bounds.origin.y; cleanupRects[1].size.width = bounds.origin.x + bounds.size.width - cleanupRects[1].origin.x; cleanupRects[1].size.height = bounds.size.height; } } else if (bounds.size.height > rotatedBounds.size.height) { if (bounds.origin.y < rotatedBounds.origin.y) { cleanupRects[0].origin = bounds.origin; cleanupRects[0].size.width = bounds.size.width; cleanupRects[0].size.height = rotatedBounds.origin.y - bounds.origin.y; } if ((bounds.origin.y + bounds.size.height) > (rotatedBounds.origin.y + rotatedBounds.size.height)) { cleanupRects[1].origin.x = bounds.origin.x; cleanupRects[1].origin.y = rotatedBounds.origin.y + rotatedBounds.size.height; cleanupRects[1].size.width = bounds.size.width; cleanupRects[1].size.height = bounds.origin.y + bounds.size.height - cleanupRects[1].origin.y; } } *returnedCleanupRect1 = cleanupRects[0]; *returnedCleanupRect2 = cleanupRects[1]; return; ERROR: if (returnedCleanupRect1) { *returnedCleanupRect1 = NSZeroRect; } if (returnedCleanupRect2) { *returnedCleanupRect2 = NSZeroRect; } } PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Moving.m0000644000076500000240000005256013234403206021675 0ustar joshstaff/* PPDocument_Moving.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_Notifications.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPDocumentLayer.h" #import "PPGeometry.h" @interface PPDocument (MovingPrivateMethods) - (void) handleUpdateToInteractiveMoveTargetBitmapInBounds: (NSRect) bounds; - (void) performMoveOnOperationTarget: (PPLayerOperationTarget) operationTarget moveType: (PPMoveOperationType) moveType moveOffset: (NSPoint) offset nudgeDirectionName: (NSString *) nudgeDirectionName; - (void) moveLayerAtIndex: (int) layerIndex byOffset: (NSPoint) offset andLeaveCopyInPlace: (bool) leaveCopyInPlace; - (void) moveSelectionMaskByOffset: (NSPoint) offset; - (NSPoint) moveOffsetForDirectionType: (PPDirectionType) directionType; - (NSString *) nameOfDirectionType: (PPDirectionType) directionType; - (bool) setupInteractiveMoveBitmaps; - (void) destroyInteractiveMoveBitmaps; - (void) setActionNameForMoveType: (PPMoveOperationType) moveType withTarget: (PPLayerOperationTarget) operationTarget nudgeDirectionName: (NSString *) nudgeDirectionName; @end @implementation PPDocument (Moving) - (void) nudgeInDirection: (PPDirectionType) directionType moveType: (PPMoveOperationType) moveType target: (PPLayerOperationTarget) operationTarget { if (!PPDirectionType_IsValid(directionType)) { goto ERROR; } if (moveType == kPPMoveOperationType_LeaveCopyInPlace) { // nudge doesn't allow leaving a copy in place goto ERROR; } [self performMoveOnOperationTarget: operationTarget moveType: moveType moveOffset: [self moveOffsetForDirectionType: directionType] nudgeDirectionName: [self nameOfDirectionType: directionType]]; return; ERROR: return; } - (void) beginInteractiveMoveWithTarget: (PPLayerOperationTarget) operationTarget canvasDisplayMode: (PPLayerDisplayMode) canvasDisplayMode moveType: (PPMoveOperationType) moveType { if (_isPerformingInteractiveMove) return; if (!PPLayerOperationTarget_IsValid(operationTarget) || !PPLayerDisplayMode_IsValid(canvasDisplayMode) || !PPMoveOperationType_IsValid(moveType)) { goto ERROR; } if ((operationTarget == kPPLayerOperationTarget_DrawingLayerOnly) || (canvasDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly)) { _interactiveMoveDisplayMode = kPPLayerDisplayMode_DrawingLayerOnly; } else { _interactiveMoveDisplayMode = kPPLayerDisplayMode_VisibleLayers; } _interactiveMoveOperationTarget = operationTarget; if (![self setupInteractiveMoveBitmaps]) { goto ERROR; } _interactiveMoveInitialSelectionBounds = _selectionBounds; if (moveType == kPPMoveOperationType_Normal) { [_interactiveMoveUnderlyingBitmap ppMaskedEraseUsingMask: _interactiveMoveInitialSelectionMask inBounds: _interactiveMoveInitialSelectionBounds]; } _lastInteractiveMoveType = moveType; _lastInteractiveMoveOffset = NSZeroPoint; _lastInteractiveMoveBounds = (_hasSelection) ? _selectionBounds : _canvasFrame; // improve drawing performance by disabling thumbnail updates until the move's done [self disableThumbnailImageUpdateNotifications: YES]; _isPerformingInteractiveMove = YES; return; ERROR: return; } - (void) setInteractiveMoveOffset: (NSPoint) offset andMoveType: (PPMoveOperationType) moveType { NSRect moveBounds = NSZeroRect, updateRect = NSZeroRect; if (!_isPerformingInteractiveMove) return; if (!PPMoveOperationType_IsValid(moveType)) { moveType = kPPMoveOperationType_Normal; } if (NSEqualPoints(offset, _lastInteractiveMoveOffset) && (moveType == _lastInteractiveMoveType)) { return; } if (_hasSelection) { NSPoint moveOrigin; if (moveType != _lastInteractiveMoveType) { if (moveType == kPPMoveOperationType_Normal) { [_interactiveMoveUnderlyingBitmap ppMaskedEraseUsingMask: _interactiveMoveInitialSelectionMask inBounds: _interactiveMoveInitialSelectionBounds]; } else { [_interactiveMoveUnderlyingBitmap ppCopyFromBitmap: _interactiveMoveFloatingBitmap toPoint: _interactiveMoveInitialSelectionBounds.origin]; } [_interactiveMoveTargetBitmap ppCopyFromBitmap: _interactiveMoveUnderlyingBitmap inRect: _interactiveMoveInitialSelectionBounds toPoint: _interactiveMoveInitialSelectionBounds.origin]; updateRect = NSUnionRect(updateRect, _interactiveMoveInitialSelectionBounds); } if (!NSIsEmptyRect(_lastInteractiveMoveBounds)) { if (_lastInteractiveMoveType != kPPMoveOperationType_SelectionOutlineOnly) { [_interactiveMoveTargetBitmap ppCopyFromBitmap: _interactiveMoveUnderlyingBitmap inRect: _lastInteractiveMoveBounds toPoint: _lastInteractiveMoveBounds.origin]; updateRect = NSUnionRect(updateRect, _lastInteractiveMoveBounds); } } moveOrigin = PPGeometry_PointSum(_interactiveMoveInitialSelectionBounds.origin, offset); moveBounds.origin = moveOrigin; moveBounds.size = _interactiveMoveInitialSelectionBounds.size; moveBounds = NSIntersectionRect(moveBounds, _canvasFrame); if (!NSIsEmptyRect(moveBounds)) { if (moveType != kPPMoveOperationType_SelectionOutlineOnly) { [_interactiveMoveTargetBitmap ppMaskedCopyFromImageBitmap: _interactiveMoveFloatingBitmap usingMask: _interactiveMoveFloatingMask toPoint: moveOrigin]; updateRect = NSUnionRect(updateRect, moveBounds); } } if (!NSEqualRects(_lastInteractiveMoveBounds, moveBounds)) { if (!NSIsEmptyRect(_lastInteractiveMoveBounds)) { [_selectionMask ppClearBitmapInBounds: _lastInteractiveMoveBounds]; } if (!NSIsEmptyRect(moveBounds)) { [_selectionMask ppCopyFromBitmap: _interactiveMoveFloatingMask toPoint: moveOrigin]; } _selectionBounds = [_selectionMask ppMaskBoundsInRect: moveBounds]; [self postNotification_UpdatedSelection]; } } else { if (_lastInteractiveMoveType != moveType) { _lastInteractiveMoveBounds = _canvasFrame; } if (moveType == kPPMoveOperationType_Normal) { [_interactiveMoveTargetBitmap ppClearBitmapInBounds: _lastInteractiveMoveBounds]; } else { [_interactiveMoveTargetBitmap ppCopyFromBitmap: _interactiveMoveUnderlyingBitmap inRect: _lastInteractiveMoveBounds toPoint: _lastInteractiveMoveBounds.origin]; } if (moveType != kPPMoveOperationType_SelectionOutlineOnly) { [_interactiveMoveTargetBitmap ppCopyFromBitmap: _interactiveMoveUnderlyingBitmap toPoint: offset]; } moveBounds = NSIntersectionRect(NSOffsetRect(_canvasFrame, offset.x, offset.y), _canvasFrame); updateRect = NSUnionRect(moveBounds, _lastInteractiveMoveBounds); } _lastInteractiveMoveType = moveType; _lastInteractiveMoveOffset = offset; _lastInteractiveMoveBounds = moveBounds; updateRect = NSIntersectionRect(updateRect, _canvasFrame); [self handleUpdateToInteractiveMoveTargetBitmapInBounds: updateRect]; } - (void) finishInteractiveMove { NSRect updateRect = NSZeroRect; if (!_isPerformingInteractiveMove) return; if (_hasSelection) { if (!NSIsEmptyRect(_lastInteractiveMoveBounds)) { [_interactiveMoveTargetBitmap ppCopyFromBitmap: _interactiveMoveUnderlyingBitmap inRect: _lastInteractiveMoveBounds toPoint: _lastInteractiveMoveBounds.origin]; [_selectionMask ppClearBitmapInBounds: _lastInteractiveMoveBounds]; updateRect = NSUnionRect(updateRect, _lastInteractiveMoveBounds); } if (_lastInteractiveMoveType == kPPMoveOperationType_Normal) { [_interactiveMoveTargetBitmap ppCopyFromBitmap: _interactiveMoveFloatingBitmap toPoint: _interactiveMoveInitialSelectionBounds.origin]; updateRect = NSUnionRect(updateRect, _interactiveMoveInitialSelectionBounds); } [_selectionMask ppCopyFromBitmap: _interactiveMoveFloatingMask toPoint: _interactiveMoveInitialSelectionBounds.origin]; _selectionBounds = _interactiveMoveInitialSelectionBounds; } else { updateRect = (_lastInteractiveMoveType == kPPMoveOperationType_Normal) ? _canvasFrame : _lastInteractiveMoveBounds; [_interactiveMoveTargetBitmap ppCopyFromBitmap: _interactiveMoveUnderlyingBitmap inRect: updateRect toPoint: updateRect.origin]; } updateRect = NSIntersectionRect(updateRect, _canvasFrame); [self handleUpdateToInteractiveMoveTargetBitmapInBounds: updateRect]; [self destroyInteractiveMoveBitmaps]; _isPerformingInteractiveMove = NO; [self disableThumbnailImageUpdateNotifications: NO]; if (NSEqualPoints(_lastInteractiveMoveOffset, NSZeroPoint)) { return; } [self performMoveOnOperationTarget: _interactiveMoveOperationTarget moveType: _lastInteractiveMoveType moveOffset: _lastInteractiveMoveOffset nudgeDirectionName: nil]; } #pragma mark Private methods // handleUpdateToInteractiveMoveTargetBitmapInBounds: method is a patch target on GNUstep // (PPGNUstepGlue_ImageRecacheSpeedups) - (void) handleUpdateToInteractiveMoveTargetBitmapInBounds: (NSRect) bounds { if (NSIsEmptyRect(bounds)) { return; } if (_interactiveMoveDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { [_drawingLayer handleUpdateToBitmapInRect: bounds]; [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: bounds]; } else { [_mergedVisibleLayersThumbnailImage recache]; [self postNotification_UpdatedMergedVisibleAreaInRect: bounds]; } } - (void) performMoveOnOperationTarget: (PPLayerOperationTarget) operationTarget moveType: (PPMoveOperationType) moveType moveOffset: (NSPoint) offset nudgeDirectionName: (NSString *) nudgeDirectionName { if (NSEqualPoints(offset, NSZeroPoint) || !PPMoveOperationType_IsValid(moveType)) { goto ERROR; } if (moveType != kPPMoveOperationType_SelectionOutlineOnly) { if (!PPLayerOperationTarget_IsValid(operationTarget)) { goto ERROR; } [self setupTargetLayerIndexesForOperationTarget: operationTarget]; if (!_numTargetLayerIndexes) { moveType = kPPMoveOperationType_SelectionOutlineOnly; } } if (moveType == kPPMoveOperationType_SelectionOutlineOnly) { if (!_hasSelection) goto ERROR; } else // (moveType != kPPMoveOperationType_SelectionOutlineOnly) { bool isMultilayerOperation, leaveCopyInPlace; int i; isMultilayerOperation = (_numTargetLayerIndexes > 1) ? YES : NO; if (isMultilayerOperation) { [self beginMultilayerOperation]; } leaveCopyInPlace = (moveType == kPPMoveOperationType_LeaveCopyInPlace) ? YES : NO; for (i=0; i<_numTargetLayerIndexes; i++) { [self moveLayerAtIndex: _targetLayerIndexes[i] byOffset: offset andLeaveCopyInPlace: leaveCopyInPlace]; } if (isMultilayerOperation) { [self finishMultilayerOperation]; } } if (_hasSelection) { [self moveSelectionMaskByOffset: offset]; } [self setActionNameForMoveType: moveType withTarget: operationTarget nudgeDirectionName: nudgeDirectionName]; return; ERROR: return; } - (void) moveLayerAtIndex: (int) layerIndex byOffset: (NSPoint) offset andLeaveCopyInPlace: (bool) leaveCopyInPlace { PPDocumentLayer *layer; NSBitmapImageRep *layerBitmap, *updateBitmap; NSRect updateBounds; layer = [self layerAtIndex: layerIndex]; layerBitmap = [layer bitmap]; if (!layer || !layerBitmap) { goto ERROR; } if (_hasSelection) { NSPoint updateCopyPoint; updateBounds.size = _selectionBounds.size; updateBounds.origin = PPGeometry_PointSum(_selectionBounds.origin, offset); if (!leaveCopyInPlace) { updateBounds = NSUnionRect(updateBounds, _selectionBounds); } updateBounds = NSIntersectionRect(updateBounds, _canvasFrame); if (NSIsEmptyRect(updateBounds)) { goto ERROR; } updateBitmap = [layerBitmap ppBitmapCroppedToBounds: updateBounds]; if (!updateBitmap) goto ERROR; if (!leaveCopyInPlace) { NSBitmapImageRep *updateMask = [_selectionMask ppShallowDuplicateFromBounds: updateBounds]; if (!updateMask) goto ERROR; [updateBitmap ppMaskedEraseUsingMask: updateMask]; } updateCopyPoint = PPGeometry_PointDifference(offset, updateBounds.origin); [updateBitmap ppMaskedCopyFromImageBitmap: layerBitmap usingMask: _selectionMask toPoint: updateCopyPoint]; } else { if (!leaveCopyInPlace) { updateBounds = _canvasFrame; updateBitmap = [NSBitmapImageRep ppImageBitmapOfSize: updateBounds.size]; [updateBitmap ppCopyFromBitmap: layerBitmap toPoint: offset]; } else { NSRect moveSourceBounds; updateBounds.size = _canvasFrame.size; updateBounds.origin = PPGeometry_PointSum(_canvasFrame.origin, offset); updateBounds = NSIntersectionRect(updateBounds, _canvasFrame); moveSourceBounds.size = updateBounds.size; moveSourceBounds.origin = PPGeometry_PointDifference(updateBounds.origin, offset); updateBitmap = [layerBitmap ppBitmapCroppedToBounds: moveSourceBounds]; } if (!updateBitmap) goto ERROR; } [self copyImageBitmap: updateBitmap toLayerAtIndex: layerIndex atPoint: updateBounds.origin]; return; ERROR: return; } - (void) moveSelectionMaskByOffset: (NSPoint) offset { NSRect updateBounds; NSBitmapImageRep *updateMask; NSPoint updateMaskSelectionBoundsOrigin; updateBounds.size = _selectionBounds.size; updateBounds.origin = PPGeometry_PointSum(_selectionBounds.origin, offset); updateBounds = NSIntersectionRect(NSUnionRect(updateBounds, _selectionBounds), _canvasFrame); updateMask = [NSBitmapImageRep ppMaskBitmapOfSize: updateBounds.size]; if (!updateMask) goto ERROR; updateMaskSelectionBoundsOrigin = NSMakePoint(_selectionBounds.origin.x + offset.x - updateBounds.origin.x, _selectionBounds.origin.y + offset.y - updateBounds.origin.y); [updateMask ppCopyFromBitmap: _selectionMask inRect: _selectionBounds toPoint: updateMaskSelectionBoundsOrigin]; [self setSelectionMaskAreaWithBitmap: updateMask atPoint: updateBounds.origin]; return; ERROR: return; } - (NSPoint) moveOffsetForDirectionType: (PPDirectionType) directionType { switch (directionType) { case kPPDirectionType_Left: return NSMakePoint(-1.0f, 0.0f); break; case kPPDirectionType_Right: return NSMakePoint(1.0f, 0.0f); break; case kPPDirectionType_Up: return NSMakePoint(0.0f, 1.0f); break; case kPPDirectionType_Down: return NSMakePoint(0.0f, -1.0f); break; default: return NSZeroPoint; break; } } - (NSString *) nameOfDirectionType: (PPDirectionType) directionType { switch (directionType) { case kPPDirectionType_Left: return @"Left"; break; case kPPDirectionType_Right: return @"Right"; break; case kPPDirectionType_Up: return @"Up"; break; case kPPDirectionType_Down: return @"Down"; break; default: return @""; break; } } - (bool) setupInteractiveMoveBitmaps { _interactiveMoveTargetBitmap = (_interactiveMoveDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) ? _drawingLayerBitmap : _mergedVisibleLayersBitmap; [_interactiveMoveTargetBitmap retain]; _interactiveMoveUnderlyingBitmap = [_interactiveMoveTargetBitmap copy]; if (!_interactiveMoveUnderlyingBitmap) goto ERROR; if (_hasSelection) { _interactiveMoveInitialSelectionMask = [_selectionMask copy]; _interactiveMoveFloatingBitmap = [[_interactiveMoveTargetBitmap ppBitmapCroppedToBounds: _selectionBounds] retain]; _interactiveMoveFloatingMask = [[_selectionMask ppBitmapCroppedToBounds: _selectionBounds] retain]; if (!_interactiveMoveInitialSelectionMask || !_interactiveMoveFloatingBitmap || !_interactiveMoveFloatingMask) { goto ERROR; } } return YES; ERROR: [self destroyInteractiveMoveBitmaps]; return NO; } - (void) destroyInteractiveMoveBitmaps { [_interactiveMoveTargetBitmap release]; _interactiveMoveTargetBitmap = nil; [_interactiveMoveUnderlyingBitmap release]; _interactiveMoveUnderlyingBitmap = nil; [_interactiveMoveInitialSelectionMask release]; _interactiveMoveInitialSelectionMask = nil; [_interactiveMoveFloatingBitmap release]; _interactiveMoveFloatingBitmap = nil; [_interactiveMoveFloatingMask release]; _interactiveMoveFloatingMask = nil; } - (void) setActionNameForMoveType: (PPMoveOperationType) moveType withTarget: (PPLayerOperationTarget) operationTarget nudgeDirectionName: (NSString *) nudgeDirectionName { NSUndoManager *undoManager; NSString *operationName = nil, *targetName = nil, *actionName; undoManager = [self undoManager]; if ([undoManager isUndoing] || [undoManager isRedoing]) { return; } if (nudgeDirectionName) { operationName = [NSString stringWithFormat: @"Nudge %@", nudgeDirectionName]; } if (!operationName) { operationName = @"Move"; } if (moveType == kPPMoveOperationType_SelectionOutlineOnly) { targetName = @"Selection Outline"; } else { targetName = [self nameWithSelectionStateForLayerOperationTarget: operationTarget]; if (!targetName) goto ERROR; if (moveType == kPPMoveOperationType_LeaveCopyInPlace) { targetName = [NSString stringWithFormat: @"Copy of %@", targetName]; if (!targetName) goto ERROR; } } actionName = [NSString stringWithFormat: @"%@ (%@)", operationName, targetName]; if (!actionName) goto ERROR; [undoManager setActionName: actionName]; return; ERROR: actionName = [NSString stringWithFormat: @"%@ (UNKNOWN)", operationName]; if (!actionName) { actionName = operationName; } [undoManager setActionName: actionName]; return; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_NativeFileFormat.h0000644000076500000240000000232413234403416023624 0ustar joshstaff/* PPDocument_NativeFileFormat.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" @interface PPDocument (NativeFileFormat) - (NSData *) nativeFileFormatData; + (PPDocument *) ppDocumentFromNativeFileFormatData: (NSData *) data returnedError: (NSError **) returnedError; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_NativeFileFormat.m0000644000076500000240000002124713234403206023633 0ustar joshstaff/* PPDocument_NativeFileFormat.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument_NativeFileFormat.h" #import "NSError_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" /* PikoPixel Native File Format v1 4 parts packed together: ----------- 1. Binary data (PNG of the merged visible image - allows for viewing/editing by other apps) ----------- 2. Binary data (NSKeyedArchive of PPDocument) ----------- 3. Descriptor (PPNativeFileFormatDataDescriptor - contains lengths of PNG & NSKeyedArchive data) ----------- 4. Trailer (PPNativeFileFormatDataTrailer - contains version info & length of descriptor) */ #define kPPNativeFileFormatVersion_1 1 /* PikoPixel Native File Format v2 (PikoPixel 1.0 BETA8) Used for documents with Layer Blending Mode set to Linear (documents with Standard blending mode are stored as v1 format for backwards compatibility) Aside from the additional Layer Blending Mode entry in the archived PPDocument data, format v2 is the same as v1 */ #define kPPNativeFileFormatVersion_2 2 #define kPPNativeFormatDataTrailerSignature 'ppDT' #define kPPNativeFormatDataDescriptorSignature 'ppDD' #define kMaxSupportedPPNativeFileFormatVersion kPPNativeFileFormatVersion_2 // Format versions used when writing data, based on whether linear blending is enabled #define kPPNativeFormatVersion_UsesLinearBlending kPPNativeFileFormatVersion_2 #define kPPNativeFormatVersion_UsesStandardBlending kPPNativeFileFormatVersion_1 typedef struct { uint32_t signature; uint32_t formatVersion; uint32_t minSupportedFormatVersion; uint32_t descriptorLength; } PPNativeFileFormatDataTrailer; typedef struct { uint32_t signature; uint32_t pngDataLength; uint32_t archivedDocumentDataLength; } PPNativeFileFormatDataDescriptor; static void SwapUInt32sWithByteCount(uint32_t *uint32sToSwap, unsigned byteCount); static void PPNativeFileFormatDataTrailer_FixByteOrder( PPNativeFileFormatDataTrailer *dataTrailer); static void PPNativeFileFormatDataDescriptor_FixByteOrder( PPNativeFileFormatDataDescriptor *dataDescriptor); @implementation PPDocument (NativeFileFormat) - (NSData *) nativeFileFormatData { NSData *pngData, *archivedDocumentData; NSMutableData *nativeFileFormatData; PPNativeFileFormatDataDescriptor dataDescriptor; PPNativeFileFormatDataTrailer dataTrailer; if (_saveFormat != kPPDocumentSaveFormat_Autosave) { pngData = [_mergedVisibleLayersBitmap ppCompressedPNGData]; } else { // in order to speed up autosaving, leave the PNG representation blank pngData = [NSData data]; } archivedDocumentData = [NSKeyedArchiver archivedDataWithRootObject: self]; nativeFileFormatData = [NSMutableData data]; if (!pngData || !archivedDocumentData || !nativeFileFormatData) { goto ERROR; } dataDescriptor.signature = kPPNativeFormatDataDescriptorSignature; dataDescriptor.pngDataLength = [pngData length]; dataDescriptor.archivedDocumentDataLength = [archivedDocumentData length]; dataTrailer.signature = kPPNativeFormatDataTrailerSignature; if (_layerBlendingMode == kPPLayerBlendingMode_Linear) { dataTrailer.formatVersion = kPPNativeFormatVersion_UsesLinearBlending; dataTrailer.minSupportedFormatVersion = kPPNativeFormatVersion_UsesLinearBlending; } else { dataTrailer.formatVersion = kPPNativeFormatVersion_UsesStandardBlending; dataTrailer.minSupportedFormatVersion = kPPNativeFormatVersion_UsesStandardBlending; } dataTrailer.descriptorLength = sizeof(PPNativeFileFormatDataDescriptor); PPNativeFileFormatDataDescriptor_FixByteOrder(&dataDescriptor); PPNativeFileFormatDataTrailer_FixByteOrder(&dataTrailer); [nativeFileFormatData appendData: pngData]; [nativeFileFormatData appendData: archivedDocumentData]; [nativeFileFormatData appendBytes: &dataDescriptor length: sizeof(dataDescriptor)]; [nativeFileFormatData appendBytes: &dataTrailer length: sizeof(dataTrailer)]; return nativeFileFormatData; ERROR: return archivedDocumentData; } + (PPDocument *) ppDocumentFromNativeFileFormatData: (NSData *) data returnedError: (NSError **) returnedError { const unsigned char *dataBytes; unsigned dataLength, numBytesFromEndOfData; NSError *error = nil; PPNativeFileFormatDataTrailer dataTrailer; PPNativeFileFormatDataDescriptor dataDescriptor; NSData *archivedDocumentData; PPDocument *document; dataBytes = [data bytes]; dataLength = [data length]; if (!data || (dataLength < sizeof(dataTrailer))) { goto ERROR; } numBytesFromEndOfData = sizeof(dataTrailer); memcpy(&dataTrailer, &dataBytes[dataLength - numBytesFromEndOfData], sizeof(dataTrailer)); PPNativeFileFormatDataTrailer_FixByteOrder(&dataTrailer); if (dataTrailer.signature != kPPNativeFormatDataTrailerSignature) { goto ERROR; } if (dataTrailer.minSupportedFormatVersion > kMaxSupportedPPNativeFileFormatVersion) { error = [NSError ppError_ImageFileVersionIsTooNew]; goto ERROR; } numBytesFromEndOfData += dataTrailer.descriptorLength; if (numBytesFromEndOfData >= dataLength) { goto ERROR; } memcpy(&dataDescriptor, &dataBytes[dataLength - numBytesFromEndOfData], sizeof(dataDescriptor)); PPNativeFileFormatDataDescriptor_FixByteOrder(&dataDescriptor); if (dataDescriptor.signature != kPPNativeFormatDataDescriptorSignature) { goto ERROR; } if ((dataDescriptor.pngDataLength + dataDescriptor.archivedDocumentDataLength + numBytesFromEndOfData) != dataLength) { goto ERROR; } if (!dataDescriptor.archivedDocumentDataLength) { goto ERROR; } numBytesFromEndOfData += dataDescriptor.archivedDocumentDataLength; archivedDocumentData = [NSData dataWithBytes: &dataBytes[dataLength - numBytesFromEndOfData] length: dataDescriptor.archivedDocumentDataLength]; if (!archivedDocumentData) goto ERROR; document = [NSKeyedUnarchiver unarchiveObjectWithData: archivedDocumentData]; if (![document isKindOfClass: [PPDocument class]]) { goto ERROR; } if (returnedError) { *returnedError = nil; } return document; ERROR: if (returnedError) { if (!error) { error = [NSError ppError_ImageFileIsCorrupt]; } *returnedError = error; } return nil; } @end #define macroSwapUInt32(uint32ToSwap) \ (((uint32ToSwap & 0xFF000000) >> 24) \ | ((uint32ToSwap & 0x00FF0000) >> 8) \ | ((uint32ToSwap & 0x0000FF00) << 8) \ | ((uint32ToSwap & 0x000000FF) << 24)) static void SwapUInt32sWithByteCount(uint32_t *uint32sToSwap, unsigned byteCount) { unsigned uint32Counter; if (!uint32sToSwap) return; uint32Counter = byteCount / sizeof(uint32_t); while (uint32Counter--) { *uint32sToSwap = macroSwapUInt32(*uint32sToSwap); uint32sToSwap++; } } static void PPNativeFileFormatDataTrailer_FixByteOrder( PPNativeFileFormatDataTrailer *dataTrailer) { if (NSHostByteOrder() == NS_BigEndian) { SwapUInt32sWithByteCount((uint32_t *) dataTrailer, sizeof(*dataTrailer)); } } static void PPNativeFileFormatDataDescriptor_FixByteOrder( PPNativeFileFormatDataDescriptor *dataDescriptor) { if (NSHostByteOrder() == NS_BigEndian) { SwapUInt32sWithByteCount((uint32_t *) dataDescriptor, sizeof(*dataDescriptor)); } } PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_NativeFileIcon.h0000644000076500000240000000211413234403416023261 0ustar joshstaff/* PPDocument_NativeFileIcon.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" @interface PPDocument (NativeFileIcon) - (NSImage *) nativeFileIconImage; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_NativeFileIcon.m0000644000076500000240000000700313234403206023265 0ustar joshstaff/* PPDocument_NativeFileIcon.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument_NativeFileIcon.h" #import "PPGeometry.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #define kMinDimensionForFileIcon 256 @implementation PPDocument (NativeFileIcon) - (NSImage *) nativeFileIconImage { float maxCanvasDimension, scalingFactor; NSSize iconSize, scaledImageSize; NSPoint scaledImageOrigin; NSBitmapImageRep *iconBitmap; NSImage *iconImage; // File icon image needs to be square (non-square file icons are distorted on 10.7+) // and contain transparency (opaque icons have display issues on 10.4/10.5) if (NSIsEmptyRect(_canvasFrame)) { goto ERROR; } maxCanvasDimension = MAX(_canvasFrame.size.width, _canvasFrame.size.height); if (maxCanvasDimension < kMinDimensionForFileIcon) { scalingFactor = ceilf(((float) kMinDimensionForFileIcon) / maxCanvasDimension); } else { scalingFactor = 1.0f; } iconSize = PPGeometry_SizeScaledByFactorAndRoundedToIntegerValues( NSMakeSize(maxCanvasDimension, maxCanvasDimension), scalingFactor); scaledImageSize = PPGeometry_SizeScaledByFactorAndRoundedToIntegerValues(_canvasFrame.size, scalingFactor); scaledImageOrigin = PPGeometry_OriginPointForCenteringSizeInSize(scaledImageSize, iconSize); iconBitmap = [NSBitmapImageRep ppImageBitmapOfSize: iconSize]; if (!iconBitmap) goto ERROR; [iconBitmap ppScaledCopyFromImageBitmap: _mergedVisibleLayersBitmap inRect: _canvasFrame toPoint: scaledImageOrigin scalingFactor: scalingFactor]; if (PPGeometry_RectIsSquare(_canvasFrame) && ![_mergedVisibleLayersBitmap ppImageBitmapHasTransparentPixels]) { // workaround for 10.4/10.5 issue where setting a file's icon to a completely-opaque // image results in a blank icon: if the image is square (leaves no transparent edges // when scaled & centered on the icon) and completely opaque, then force transparency // by decreasing the alpha value of one pixel (top-left corner) PPImageBitmapPixel *iconPixel = (PPImageBitmapPixel *) [iconBitmap bitmapData]; if (!iconPixel) goto ERROR; macroImagePixelComponent_Alpha(iconPixel) = kMaxImagePixelComponentValue - 1; } iconImage = [NSImage ppImageWithBitmap: iconBitmap]; if (!iconImage) goto ERROR; return iconImage; ERROR: return nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_NotificationOverrides.m0000644000076500000240000000365113234403206024744 0ustar joshstaff/* PPDocument_NotificationOverrides.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_Notifications.h" @implementation PPDocument (NotificationOverrides) // for better performance, operations that perform multiple quick updates to the document // bitmaps (interactive drawing, interactive moving, opacity sliders) should disable thumbnail // image update notifications to prevent the various thumbnail views from redrawing (each // different size forces a resample of the entire image: SLOW) until the end of the operation - (void) disableThumbnailImageUpdateNotifications: (bool) shouldDisableThumbnailImageUpdateNotifications { _disallowThumbnailImageUpdateNotifications = (shouldDisableThumbnailImageUpdateNotifications) ? YES : NO; } - (void) sendThumbnailImageUpdateNotifications { [self postNotification_UpdatedMergedVisibleThumbnailImage]; [self postNotification_UpdatedDrawingLayerThumbnailImage]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Notifications.h0000644000076500000240000000426213234403416023241 0ustar joshstaff/* PPDocument_Notifications.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" @interface PPDocument (Notifications) - (void) postNotification_UpdatedMergedVisibleAreaInRect: (NSRect) updateRect; - (void) postNotification_UpdatedDrawingLayerAreaInRect: (NSRect) updateRect; - (void) postNotification_UpdatedMergedVisibleThumbnailImage; - (void) postNotification_UpdatedDrawingLayerThumbnailImage; - (void) postNotification_UpdatedSelection; - (void) postNotification_SwitchedDrawingLayer; - (void) postNotification_ReorderedLayers; - (void) postNotification_PerformedMultilayerOperation; - (void) postNotification_ChangedAttributeOfLayerAtIndex: (int) layerIndex; - (void) postNotification_SwitchedLayerOperationTarget; - (void) postNotification_SwitchedLayerBlendingMode; - (void) postNotification_SwitchedSelectedTool; - (void) postNotification_SwitchedActiveTool; - (void) postNotification_ChangedFillColor; - (void) postNotification_UpdatedBackgroundSettings; - (void) postNotification_UpdatedGridSettings; - (void) postNotification_ReloadedDocument; - (void) postNotification_UpdatedSamplerImages; - (void) postNotification_SwitchedActiveSamplerImageForPanelType: (PPSamplerImagePanelType) panelType; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Notifications.m0000644000076500000240000002526313234403206023247 0ustar joshstaff/* PPDocument_Notifications.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument_Notifications.h" NSString *PPDocumentNotification_UpdatedMergedVisibleArea = @"PPDocumentNotification_UpdatedMergedVisibleArea"; NSString *PPDocumentNotification_UpdatedDrawingLayerArea = @"PPDocumentNotification_UpdatedDrawingLayerArea"; NSString *PPDocumentNotification_UpdatedMergedVisibleThumbnailImage = @"PPDocumentNotification_UpdatedMergedVisibleThumbnailImage"; NSString *PPDocumentNotification_UpdatedDrawingLayerThumbnailImage = @"PPDocumentNotification_UpdatedDrawingLayerThumbnailImage"; NSString *PPDocumentNotification_UpdatedSelection = @"PPDocumentNotification_UpdatedSelection"; NSString *PPDocumentNotification_SwitchedDrawingLayer = @"PPDocumentNotification_SwitchedDrawingLayer"; NSString *PPDocumentNotification_ReorderedLayers = @"PPDocumentNotification_ReorderedLayers"; NSString *PPDocumentNotification_PerformedMultilayerOperation = @"PPDocumentNotification_PerformedMultilayerOperation"; NSString *PPDocumentNotification_ChangedLayerAttribute = @"PPDocumentNotification_ChangedLayerAttribute"; NSString *PPDocumentNotification_SwitchedLayerOperationTarget = @"PPDocumentNotification_SwitchedLayerOperationTarget"; NSString *PPDocumentNotification_SwitchedLayerBlendingMode = @"PPDocumentNotification_SwitchedLayerBlendingMode"; NSString *PPDocumentNotification_SwitchedSelectedTool = @"PPDocumentNotification_SwitchedSelectedTool"; NSString *PPDocumentNotification_SwitchedActiveTool = @"PPDocumentNotification_SwitchedActiveTool"; NSString *PPDocumentNotification_ChangedFillColor = @"PPDocumentNotification_ChangedFillColor"; NSString *PPDocumentNotification_UpdatedBackgroundSettings = @"PPDocumentNotification_UpdatedBackgroundSettings"; NSString *PPDocumentNotification_UpdatedGridSettings = @"PPDocumentNotification_UpdatedGridSettings"; NSString *PPDocumentNotification_ReloadedDocument = @"PPDocumentNotification_ReloadedDocument"; NSString *PPDocumentNotification_UpdatedSamplerImages = @"PPDocumentNotification_UpdatedSamplerImages"; NSString *PPDocumentNotification_SwitchedActiveSamplerImage = @"PPDocumentNotification_SwitchedActiveSamplerImage"; NSString *PPDocumentNotification_UserInfoKey_UpdateAreaRect = @"PPDocumentNotification_UserInfoKey_UpdateAreaRect"; NSString *PPDocumentNotification_UserInfoKey_IndexOfChangedLayer = @"PPDocumentNotification_UserInfoKey_IndexOfChangedLayer"; NSString *PPDocumentNotification_UserInfoKey_SamplerImagePanelType = @"PPDocumentNotification_UserInfoKey_SamplerImagePanelType"; @implementation PPDocument (Notifications) - (void) postNotification_UpdatedMergedVisibleAreaInRect: (NSRect) updateRect { NSDictionary *userInfo; userInfo = [NSDictionary dictionaryWithObject: [NSValue valueWithRect: updateRect] forKey: PPDocumentNotification_UserInfoKey_UpdateAreaRect]; [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_UpdatedMergedVisibleArea object: self userInfo: userInfo]; } - (void) postNotification_UpdatedDrawingLayerAreaInRect: (NSRect) updateRect { NSDictionary *userInfo; userInfo = [NSDictionary dictionaryWithObject: [NSValue valueWithRect: updateRect] forKey: PPDocumentNotification_UserInfoKey_UpdateAreaRect]; [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_UpdatedDrawingLayerArea object: self userInfo: userInfo]; } - (void) postNotification_UpdatedMergedVisibleThumbnailImage { if (_disallowThumbnailImageUpdateNotifications) return; [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_UpdatedMergedVisibleThumbnailImage object: self]; } - (void) postNotification_UpdatedDrawingLayerThumbnailImage { if (_disallowThumbnailImageUpdateNotifications) return; [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: self]; } - (void) postNotification_UpdatedSelection { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_UpdatedSelection object: self]; } - (void) postNotification_SwitchedDrawingLayer { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_SwitchedDrawingLayer object: self]; } - (void) postNotification_ReorderedLayers { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_ReorderedLayers object: self]; } - (void) postNotification_PerformedMultilayerOperation { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_PerformedMultilayerOperation object: self]; } - (void) postNotification_ChangedAttributeOfLayerAtIndex: (int) layerIndex { NSDictionary *userInfo; userInfo = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: layerIndex] forKey: PPDocumentNotification_UserInfoKey_IndexOfChangedLayer]; [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_ChangedLayerAttribute object: self userInfo: userInfo]; } - (void) postNotification_SwitchedLayerOperationTarget { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_SwitchedLayerOperationTarget object: self]; } - (void) postNotification_SwitchedLayerBlendingMode { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_SwitchedLayerBlendingMode object: self]; } - (void) postNotification_SwitchedSelectedTool { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_SwitchedSelectedTool object: self]; } - (void) postNotification_SwitchedActiveTool { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_SwitchedActiveTool object: self]; } - (void) postNotification_ChangedFillColor { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_ChangedFillColor object: self]; } - (void) postNotification_UpdatedBackgroundSettings { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_UpdatedBackgroundSettings object: self]; } - (void) postNotification_UpdatedGridSettings { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_UpdatedGridSettings object: self]; } - (void) postNotification_ReloadedDocument { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_ReloadedDocument object: self]; } - (void) postNotification_UpdatedSamplerImages { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_UpdatedSamplerImages object: self]; } - (void) postNotification_SwitchedActiveSamplerImageForPanelType: (PPSamplerImagePanelType) panelType { NSDictionary *userInfo; userInfo = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: panelType] forKey: PPDocumentNotification_UserInfoKey_SamplerImagePanelType]; [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentNotification_SwitchedActiveSamplerImage object: self userInfo: userInfo]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Pasteboard.m0000644000076500000240000002305113234403206022513 0ustar joshstaff/* PPDocument_Pasteboard.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPGeometry.h" #import "PPDocumentLayer.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSPasteboard_PPUtilities.h" @interface PPDocument (PasteboardPrivateMethods) - (bool) getPasteboardImageBitmap: (NSBitmapImageRep **) returnedImageBitmap maskBitmap: (NSBitmapImageRep **) returnedMaskBitmap boundsOnCanvas: (NSRect *) returnedBoundsOnCanvas opacity: (float *) returnedOpacity; - (bool) cropImageBitmapToCanvasFrame: (NSBitmapImageRep **) inOutImageBitmap withMaskBitmap: (NSBitmapImageRep **) inOutMaskBitmap andAdjustBoundsOnCanvas: (NSRect *) inOutBoundsOnCanvas; @end @implementation PPDocument (Pasteboard) - (bool) canReadFromPasteboard { return [NSPasteboard ppPasteboardHasBitmap]; } - (bool) canWriteToPasteboard { return _hasSelection; } - (void) copySelectionToPasteboardFromTarget: (PPLayerOperationTarget) operationTarget { NSBitmapImageRep *targetBitmap, *croppedTargetBitmap, *croppedMask; float selectionOpacity; if (!_hasSelection) goto ERROR; if (operationTarget == kPPLayerOperationTarget_DrawingLayerOnly) { targetBitmap = _drawingLayerBitmap; selectionOpacity = [_drawingLayer opacity]; } else { targetBitmap = _mergedVisibleLayersBitmap; selectionOpacity = 1.0f; } croppedTargetBitmap = [targetBitmap ppBitmapCroppedToBounds: _selectionBounds]; croppedMask = [_selectionMask ppBitmapCroppedToBounds: _selectionBounds]; if (!croppedTargetBitmap || !croppedMask) { goto ERROR; } [NSPasteboard ppSetImageBitmap: croppedTargetBitmap maskBitmap: croppedMask bitmapOrigin: _selectionBounds.origin canvasSize: _canvasFrame.size andOpacity: selectionOpacity]; return; ERROR: return; } - (void) cutSelectionToPasteboardFromTarget: (PPLayerOperationTarget) operationTarget { [self copySelectionToPasteboardFromTarget: operationTarget]; [self noninteractiveEraseSelectedAreaInTarget: operationTarget andClearSelectionMask: YES]; } - (void) pasteNewLayerFromPasteboard { NSBitmapImageRep *pasteboardImageBitmap; NSRect pasteboardBoundsOnCanvas; float pasteboardOpacity; PPDocumentLayer *layer; if (![self getPasteboardImageBitmap: &pasteboardImageBitmap maskBitmap: NULL boundsOnCanvas: &pasteboardBoundsOnCanvas opacity: &pasteboardOpacity]) { goto ERROR; } layer = [PPDocumentLayer layerWithSize: _canvasFrame.size andName: @"Pasted Layer"]; if (!layer) return; [[layer bitmap] ppCopyFromBitmap: pasteboardImageBitmap toPoint: pasteboardBoundsOnCanvas.origin]; [layer handleUpdateToBitmapInRect: pasteboardBoundsOnCanvas]; [layer setOpacity: pasteboardOpacity]; [self insertLayer: layer atIndex: _indexOfDrawingLayer + 1 andSetAsDrawingLayer: YES]; [[self undoManager] setActionName: @"Paste as New Layer"]; return; ERROR: return; } - (void) pasteIntoDrawingLayerFromPasteboard { NSBitmapImageRep *pasteboardImageBitmap, *pasteboardMaskBitmap, *updateBitmap; NSRect pasteboardBoundsOnCanvas; if (![self getPasteboardImageBitmap: &pasteboardImageBitmap maskBitmap: &pasteboardMaskBitmap boundsOnCanvas: &pasteboardBoundsOnCanvas opacity: NULL]) { goto ERROR; } // returned pasteboardMaskBitmap can be nil if (!pasteboardMaskBitmap) { pasteboardMaskBitmap = [pasteboardImageBitmap ppMaskBitmapForVisiblePixelsInImageBitmap]; if (!pasteboardMaskBitmap) goto ERROR; } updateBitmap = [_drawingLayerBitmap ppBitmapCroppedToBounds: pasteboardBoundsOnCanvas]; if (!updateBitmap) goto ERROR; [updateBitmap ppMaskedCopyFromImageBitmap: pasteboardImageBitmap usingMask: pasteboardMaskBitmap]; [self copyImageBitmapToDrawingLayer: updateBitmap atPoint: pasteboardBoundsOnCanvas.origin]; if (_hasSelection) { [self deselectAll]; } [self setSelectionMaskAreaWithBitmap: pasteboardMaskBitmap atPoint: pasteboardBoundsOnCanvas.origin]; [[self undoManager] setActionName: @"Paste into Draw Layer"]; return; ERROR: return; } + (PPDocument *) ppDocumentFromPasteboard { NSBitmapImageRep *imageBitmap, *maskBitmap; float opacity; PPDocumentLayer *layer; NSArray *layersArray; PPDocument *ppDocument; if (![NSPasteboard ppGetImageBitmap: &imageBitmap maskBitmap: &maskBitmap bitmapOrigin: NULL canvasSize: NULL andOpacity: &opacity]) { goto ERROR; } layer = [[[PPDocumentLayer alloc] initWithSize: [imageBitmap ppSizeInPixels] name: @"Main Layer" tiffData: [imageBitmap TIFFRepresentation] opacity: opacity isEnabled: YES] autorelease]; if (!layer) goto ERROR; layersArray = [NSArray arrayWithObject: layer]; if (!layersArray) goto ERROR; ppDocument = [[[PPDocument alloc] init] autorelease]; if (!ppDocument) goto ERROR; [ppDocument setLayers: layersArray]; if (maskBitmap) { [ppDocument setSelectionMask: maskBitmap]; } [[ppDocument undoManager] removeAllActions]; return ppDocument; ERROR: return nil; } #pragma mark Private methods - (bool) getPasteboardImageBitmap: (NSBitmapImageRep **) returnedImageBitmap maskBitmap: (NSBitmapImageRep **) returnedMaskBitmap boundsOnCanvas: (NSRect *) returnedBoundsOnCanvas opacity: (float *) returnedOpacity { NSBitmapImageRep *imageBitmap; NSPoint bitmapOrigin; NSSize bitmapCanvasSize; if (![NSPasteboard ppGetImageBitmap: &imageBitmap maskBitmap: returnedMaskBitmap bitmapOrigin: &bitmapOrigin canvasSize: &bitmapCanvasSize andOpacity: returnedOpacity]) { goto ERROR; } if (returnedBoundsOnCanvas) { NSRect boundsOnCanvas; boundsOnCanvas.origin = bitmapOrigin; boundsOnCanvas.size = [imageBitmap ppSizeInPixels]; if (!NSEqualSizes(bitmapCanvasSize, _canvasFrame.size)) { boundsOnCanvas = PPGeometry_CenterRectInRect(boundsOnCanvas, _canvasFrame); } if (![self cropImageBitmapToCanvasFrame: &imageBitmap withMaskBitmap: returnedMaskBitmap andAdjustBoundsOnCanvas: &boundsOnCanvas]) { goto ERROR; } *returnedBoundsOnCanvas = boundsOnCanvas; } if (returnedImageBitmap) { *returnedImageBitmap = imageBitmap; } return YES; ERROR: return NO; } - (bool) cropImageBitmapToCanvasFrame: (NSBitmapImageRep **) inOutImageBitmap withMaskBitmap: (NSBitmapImageRep **) inOutMaskBitmap andAdjustBoundsOnCanvas: (NSRect *) inOutBoundsOnCanvas { NSBitmapImageRep *imageBitmap, *newImageBitmap; NSRect boundsOnCanvas, newBoundsOnCanvas, croppingBounds; if (!inOutImageBitmap || !inOutBoundsOnCanvas) { goto ERROR; } imageBitmap = *inOutImageBitmap; boundsOnCanvas = *inOutBoundsOnCanvas; if (!imageBitmap || NSIsEmptyRect(boundsOnCanvas)) { goto ERROR; } if (NSContainsRect(_canvasFrame, boundsOnCanvas)) { return YES; } newBoundsOnCanvas = NSIntersectionRect(_canvasFrame, boundsOnCanvas); if (NSIsEmptyRect(newBoundsOnCanvas)) { goto ERROR; } croppingBounds.size = newBoundsOnCanvas.size; croppingBounds.origin = PPGeometry_PointDifference(newBoundsOnCanvas.origin, boundsOnCanvas.origin); newImageBitmap = [imageBitmap ppBitmapCroppedToBounds: croppingBounds]; if (!newImageBitmap) goto ERROR; if (inOutMaskBitmap) { NSBitmapImageRep *maskBitmap = *inOutMaskBitmap; if (maskBitmap) { maskBitmap = [maskBitmap ppBitmapCroppedToBounds: croppingBounds]; if (!maskBitmap) goto ERROR; *inOutMaskBitmap = maskBitmap; } } *inOutImageBitmap = newImageBitmap; *inOutBoundsOnCanvas = newBoundsOnCanvas; return YES; ERROR: return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_PixelMatching.m0000644000076500000240000000600413234403206023162 0ustar joshstaff/* PPDocument_PixelMatching.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPGeometry.h" #import "NSBitmapImageRep_PPUtilities.h" @implementation PPDocument (PixelMatching) - (NSBitmapImageRep *) maskForPixelsMatchingColorAtPoint: (NSPoint) point colorMatchTolerance: (unsigned) colorMatchTolerance pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode shouldIntersectSelectionMask: (bool) shouldIntersectSelectionMask { NSBitmapImageRep *matchingMask, *sourceBitmap, *selectionMask; // this method can get called repeatedly, so instead of constructing a new bitmap each time, // use _drawingMask member as the returned matchingMask (ok as long as it's only used // temporarily) matchingMask = _drawingMask; point = PPGeometry_PointClippedToRect(PPGeometry_PointClippedToIntegerValues(point), _canvasFrame); sourceBitmap = [self sourceBitmapForLayerOperationTarget: _layerOperationTarget]; if (!sourceBitmap) goto ERROR; selectionMask = (_hasSelection && shouldIntersectSelectionMask) ? _selectionMask : nil; if (pixelMatchingMode == kPPPixelMatchingMode_Anywhere) { [matchingMask ppMaskAllPixelsMatchingColorAtPoint: point inImageBitmap: sourceBitmap colorMatchTolerance: colorMatchTolerance selectionMask: selectionMask selectionMaskBounds: _selectionBounds]; } else { bool matchDiagonally = (pixelMatchingMode == kPPPixelMatchingMode_BordersAndDiagonals) ? YES : NO; [matchingMask ppMaskNeighboringPixelsMatchingColorAtPoint: point inImageBitmap: sourceBitmap colorMatchTolerance: colorMatchTolerance selectionMask: selectionMask selectionMaskBounds: _selectionBounds matchDiagonally: matchDiagonally]; } return matchingMask; ERROR: return nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Resizing.m0000644000076500000240000001502313234403206022221 0ustar joshstaff/* PPDocument_Resizing.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocumentLayer.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" @interface PPDocument (ResizingPrivateMethods) - (NSBitmapImageRep *) selectionMaskResizedForCanvasSize: (NSSize) newSize shouldScale: (bool) shouldScale returnedMaskOrigin: (NSPoint *) returnedMaskOrigin; - (NSArray *) layersResizedToSize: (NSSize) newSize shouldScale: (bool) shouldScale; - (NSArray *) layersCroppedToBounds: (NSRect) croppingBounds andMaskedWithMask: (NSBitmapImageRep *) maskBitmap; @end @implementation PPDocument (Resizing) - (void) resizeToSize: (NSSize) newSize shouldScale: (bool) shouldScale { NSBitmapImageRep *resizedSelectionMask = nil; NSPoint resizedSelectionMaskOrigin = NSZeroPoint; NSArray *resizedLayers; newSize = PPGeometry_SizeClippedToIntegerValues(newSize); if (NSEqualSizes(newSize, _canvasFrame.size)) { return; } if (_hasSelection) { resizedSelectionMask = [self selectionMaskResizedForCanvasSize: newSize shouldScale: shouldScale returnedMaskOrigin: &resizedSelectionMaskOrigin]; } resizedLayers = [self layersResizedToSize: newSize shouldScale: shouldScale]; if (!resizedLayers) goto ERROR; [self setLayers: resizedLayers]; if (resizedSelectionMask) { [self setSelectionMaskAreaWithBitmap: resizedSelectionMask atPoint: resizedSelectionMaskOrigin]; } [[self undoManager] setActionName: (shouldScale) ? @"Scale Canvas" : @"Resize Canvas"]; return; ERROR: return; } - (void) cropToSelectionBounds { NSBitmapImageRep *croppedSelectionMask; NSArray *croppedLayers; if (!_hasSelection) goto ERROR; croppedSelectionMask = [_selectionMask ppBitmapCroppedToBounds: _selectionBounds]; if (!croppedSelectionMask) goto ERROR; croppedLayers = [self layersCroppedToBounds: _selectionBounds andMaskedWithMask: croppedSelectionMask]; if (!croppedLayers) goto ERROR; [self setLayers: croppedLayers]; [self setSelectionMask: croppedSelectionMask]; [[self undoManager] setActionName: @"Crop Canvas to Selection"]; return; ERROR: return; } #pragma mark Private methods - (NSBitmapImageRep *) selectionMaskResizedForCanvasSize: (NSSize) newSize shouldScale: (bool) shouldScale returnedMaskOrigin: (NSPoint *) returnedMaskOrigin { NSBitmapImageRep *resizedSelectionMask; NSRect resizedSelectionBounds; if (!_hasSelection || !returnedMaskOrigin) { goto ERROR; } resizedSelectionMask = [_selectionMask ppBitmapResizedToSize: newSize shouldScale: shouldScale]; if (shouldScale) { [resizedSelectionMask ppThresholdMaskBitmapPixelValues]; } resizedSelectionBounds = [resizedSelectionMask ppMaskBounds]; if (NSIsEmptyRect(resizedSelectionBounds)) { return nil; } resizedSelectionMask = [resizedSelectionMask ppBitmapCroppedToBounds: resizedSelectionBounds]; if (!resizedSelectionMask) goto ERROR; *returnedMaskOrigin = resizedSelectionBounds.origin; return resizedSelectionMask; ERROR: return nil; } - (NSArray *) layersResizedToSize: (NSSize) newSize shouldScale: (bool) shouldScale { NSMutableArray *resizedLayers; PPDocumentLayer *layer, *resizedLayer; int i; resizedLayers = [NSMutableArray array]; if (!resizedLayers) goto ERROR; for (i=0; i<_numLayers; i++) { layer = [_layers objectAtIndex: i]; resizedLayer = [layer layerResizedToSize: newSize shouldScale: shouldScale]; if (!resizedLayer) goto ERROR; [resizedLayers addObject: resizedLayer]; } return resizedLayers; ERROR: return nil; } - (NSArray *) layersCroppedToBounds: (NSRect) croppingBounds andMaskedWithMask: (NSBitmapImageRep *) maskBitmap { NSMutableArray *croppedLayers; NSBitmapImageRep *eraseMask = nil; NSRect eraseBounds; NSEnumerator *layerEnumerator; PPDocumentLayer *layer, *croppedLayer; croppingBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(croppingBounds), _canvasFrame); if (NSIsEmptyRect(croppingBounds) || !maskBitmap) { goto ERROR; } if (!NSEqualSizes(croppingBounds.size, [maskBitmap ppSizeInPixels])) { goto ERROR; } croppedLayers = [NSMutableArray array]; if (!croppedLayers) goto ERROR; if (![maskBitmap ppMaskCoversAllPixels]) { eraseMask = [[maskBitmap copy] autorelease]; if (!eraseMask) goto ERROR; [eraseMask ppInvertMaskBitmap]; eraseBounds = [eraseMask ppMaskBounds]; } layerEnumerator = [_layers objectEnumerator]; while (layer = [layerEnumerator nextObject]) { croppedLayer = [layer layerCroppedToBounds: croppingBounds]; if (!croppedLayer) goto ERROR; if (eraseMask) { [[croppedLayer bitmap] ppMaskedEraseUsingMask: eraseMask inBounds: eraseBounds]; [croppedLayer handleUpdateToBitmapInRect: eraseBounds]; } [croppedLayers addObject: croppedLayer]; } if ([croppedLayers count] != _numLayers) { goto ERROR; } return croppedLayers; ERROR: return nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_SamplerImages.m0000644000076500000240000003646213234403206023172 0ustar joshstaff/* PPDocument_SamplerImages.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocumentSamplerImage.h" #import "PPDocument_Notifications.h" #import "NSObject_PPUtilities.h" #define kSamplerImageChangeTypeMask_Add (1 << 0) #define kSamplerImageChangeTypeMask_Remove (1 << 1) #define kSamplerImageChangeTypeMask_Move (1 << 2) @interface PPDocument (SamplerImagesPrivateMethods) - (void) setSamplerImagesWithArchivedSamplerImagesData: (NSData *) archivedSamplerImagesData; - (bool) hasSamplerImageAtIndex: (int) index; - (void) insertSamplerImage: (PPDocumentSamplerImage *) samplerImage atIndex: (int) index; - (void) insertArchivedSamplerImage: (NSData *) archivedSamplerImageData atIndex: (int) index; - (void) moveSamplerImageAtIndex: (int) oldIndex toIndex: (int) newIndex; - (void) removeSamplerImageAtIndex: (int) index; - (void) removeAllSamplerImages; - (void) resetActiveSamplerImageIndexes; - (void) setActionNameForChangeTypesMask: (unsigned) changeTypesMask numImagesChanged: (unsigned) numImagesChanged; @end @implementation PPDocument (SamplerImages) - (void) setupSamplerImageIndexes { _samplerImageMinIndexValues[(int) kPPSamplerImagePanelType_PopupPanel] = -1; [self resetActiveSamplerImageIndexes]; } - (int) numSamplerImages { return _numSamplerImages; } - (NSArray *) samplerImages { return _samplerImages; } - (void) setSamplerImages: (NSArray *) newSamplerImages { unsigned changeTypesMask = 0, numImagesChanged = 0; NSUInteger numNewSamplerImages, index, oldIndex; PPDocumentSamplerImage *newSamplerImage; numNewSamplerImages = [newSamplerImages count]; if (numNewSamplerImages > 0) { if (_numSamplerImages > 0) { // disallow duplicate sampler images if ([[NSSet setWithArray: newSamplerImages] count] != numNewSamplerImages) { goto ERROR; } for (index=0; index 0) { for (index=0; index 0) { changeTypesMask |= kSamplerImageChangeTypeMask_Remove; numImagesChanged = _numSamplerImages; [self removeAllSamplerImages]; } [self setActionNameForChangeTypesMask: changeTypesMask numImagesChanged: numImagesChanged]; return; ERROR: return; } - (PPDocumentSamplerImage *) activeSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType { int samplerImageIndex; if (!PPSamplerImagePanelType_IsValid(samplerPanelType)) { goto ERROR; } samplerImageIndex = _activeSamplerImageIndexes[(int) samplerPanelType]; if (![self hasSamplerImageAtIndex: samplerImageIndex]) { goto ERROR; } return [_samplerImages objectAtIndex: samplerImageIndex]; ERROR: return nil; } - (void) activateNextSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType { int panelIndex, oldIndexValue; if (!PPSamplerImagePanelType_IsValid(samplerPanelType)) { goto ERROR; } panelIndex = (int) samplerPanelType; oldIndexValue = _activeSamplerImageIndexes[panelIndex]++; if (_activeSamplerImageIndexes[panelIndex] >= _numSamplerImages) { _activeSamplerImageIndexes[panelIndex] = _samplerImageMinIndexValues[panelIndex]; } if (_activeSamplerImageIndexes[panelIndex] != oldIndexValue) { [self postNotification_SwitchedActiveSamplerImageForPanelType: samplerPanelType]; } return; ERROR: return; } - (void) activatePreviousSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType { int panelIndex, oldIndexValue; if (!PPSamplerImagePanelType_IsValid(samplerPanelType)) { goto ERROR; } panelIndex = (int) samplerPanelType; oldIndexValue = _activeSamplerImageIndexes[samplerPanelType]--; if (_activeSamplerImageIndexes[panelIndex] < _samplerImageMinIndexValues[panelIndex]) { _activeSamplerImageIndexes[panelIndex] = _numSamplerImages - 1; } if (_activeSamplerImageIndexes[panelIndex] != oldIndexValue) { [self postNotification_SwitchedActiveSamplerImageForPanelType: samplerPanelType]; } return; ERROR: return; } - (bool) hasActiveSamplerImageForPanelType: (PPSamplerImagePanelType) samplerPanelType { if (!PPSamplerImagePanelType_IsValid(samplerPanelType)) { goto ERROR; } return [self hasSamplerImageAtIndex: _activeSamplerImageIndexes[(int) samplerPanelType]]; ERROR: return NO; } - (bool) shouldEnableSamplerImagePanel { return _shouldEnableSamplerImagePanel; } - (void) setShouldEnableSamplerImagePanel: (bool) shouldEnableSamplerImagePanel { _shouldEnableSamplerImagePanel = (shouldEnableSamplerImagePanel) ? YES : NO; } #pragma mark Private methods - (void) setSamplerImagesWithArchivedSamplerImagesData: (NSData *) archivedSamplerImagesData { NSArray *samplerImages = nil; if (archivedSamplerImagesData) { samplerImages = [NSKeyedUnarchiver unarchiveObjectWithData: archivedSamplerImagesData]; } [self setSamplerImages: samplerImages]; } - (bool) hasSamplerImageAtIndex: (int) index { return ((index >= 0) && (index < _numSamplerImages)) ? YES : NO; } - (void) insertSamplerImage: (PPDocumentSamplerImage *) samplerImage atIndex: (int) index; { int panelType; bool didSwitchActiveImageForPanel = NO; if (!samplerImage || ((index != _numSamplerImages) && ![self hasSamplerImageAtIndex: index]) || ([_samplerImages indexOfObject: samplerImage] != NSNotFound)) { goto ERROR; } if (_numSamplerImages) { for (panelType=0; panelType= index) && (index < _numSamplerImages)) { _activeSamplerImageIndexes[panelType]++; } } } else // !(_numSamplerImages) { didSwitchActiveImageForPanel = YES; } [_samplerImages insertObject: samplerImage atIndex: index]; _numSamplerImages = [_samplerImages count]; [[[self undoManager] prepareWithInvocationTarget: self] removeSamplerImageAtIndex: index]; if (didSwitchActiveImageForPanel) { [self postNotification_SwitchedActiveSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]; } [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(postNotification_UpdatedSamplerImages)]; return; ERROR: return; } - (void) insertArchivedSamplerImage: (NSData *) archivedSamplerImageData atIndex: (int) index { PPDocumentSamplerImage *samplerImage; if (!archivedSamplerImageData) goto ERROR; samplerImage = [NSKeyedUnarchiver unarchiveObjectWithData: archivedSamplerImageData]; if (![samplerImage isKindOfClass: [PPDocumentSamplerImage class]]) { goto ERROR; } [self insertSamplerImage: samplerImage atIndex: index]; return; ERROR: return; } - (void) moveSamplerImageAtIndex: (int) oldIndex toIndex: (int) newIndex { PPDocumentSamplerImage *samplerImage; int minIndex, maxIndex, indexOffset, panelType; if (![self hasSamplerImageAtIndex: oldIndex] || ![self hasSamplerImageAtIndex: newIndex] || (oldIndex == newIndex)) { goto ERROR; } samplerImage = [[[_samplerImages objectAtIndex: oldIndex] retain] autorelease]; [_samplerImages removeObjectAtIndex: oldIndex]; [_samplerImages insertObject: samplerImage atIndex: newIndex]; if (oldIndex < newIndex) { minIndex = oldIndex; maxIndex = newIndex; indexOffset = -1; } else { minIndex = newIndex; maxIndex = oldIndex; indexOffset = 1; } for (panelType=0; panelType= minIndex) && (_activeSamplerImageIndexes[panelType] <= maxIndex)) { _activeSamplerImageIndexes[panelType] += indexOffset; } } [[[self undoManager] prepareWithInvocationTarget: self] moveSamplerImageAtIndex: newIndex toIndex: oldIndex]; [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(postNotification_UpdatedSamplerImages)]; return; ERROR: return; } - (void) removeSamplerImageAtIndex: (int) index { NSData *oldSamplerImageData; int panelType; bool didSwitchActiveSamplerImageForPanelType[kNumPPSamplerImagePanelTypes]; if (![self hasSamplerImageAtIndex: index]) { goto ERROR; } oldSamplerImageData = [NSKeyedArchiver archivedDataWithRootObject: [_samplerImages objectAtIndex: index]]; [_samplerImages removeObjectAtIndex: index]; _numSamplerImages = [_samplerImages count]; for (panelType=0; panelType index) { _activeSamplerImageIndexes[panelType]--; } else if (_activeSamplerImageIndexes[panelType] == index) { if (index >= _numSamplerImages) { _activeSamplerImageIndexes[panelType] = _samplerImageMinIndexValues[panelType]; } didSwitchActiveSamplerImageForPanelType[panelType] = YES; } } [[[self undoManager] prepareWithInvocationTarget: self] insertArchivedSamplerImage: oldSamplerImageData atIndex: index]; for (panelType=0; panelType 1) ? YES : NO; switch (changeTypesMask) { case kSamplerImageChangeTypeMask_Add: { changeDescription = @"Add"; } break; case kSamplerImageChangeTypeMask_Remove: { changeDescription = @"Remove"; } break; case kSamplerImageChangeTypeMask_Move: { changeDescription = @"Reorder"; didChangeMultipleImages = YES; } break; default: { changeDescription = @"Edit"; } break; } actionName = [NSString stringWithFormat: @"%@ Sampler %@", changeDescription, (didChangeMultipleImages) ? @"Images" : @"Image"]; [[self undoManager] setActionName: actionName]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Saving.m0000644000076500000240000003221113234403206021654 0ustar joshstaff/* PPDocument_Saving.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPExportPanelAccessoryViewController.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSWindow_PPUtilities.h" #import "PPDocumentWindowController.h" #import "NSObject_PPUtilities.h" #import "PPDocument_NativeFileIcon.h" #define kAutosaveCompoundExtensionFormatString @"%@-%@" #define kAutosaveCompoundExtensionSeparatorCharString @"-" static inline bool IsAutosaveOperation(NSSaveOperationType saveOperation); static inline bool SaveOperationIsForDocumentFileOfCurrentWindow( NSSaveOperationType saveOperation); static bool gRuntimeRequiresManualSetupOfAutosaveFileExtensions = NO; @interface PPDocument (SavingPrivateMethods) - (PPDocumentSaveFormat) saveFormatForSaveOperation: (NSSaveOperationType) saveOperation; - (void) setupCustomFinderIconForSavedDocumentAtPath: (NSString *) filepath; - (void) cleanupAfterExportSave; - (bool) flattenedSaveWillLoseSettings; - (NSString *) autosaveFileExtensionForExtension: (NSString *) fileExtension; - (NSURL *) autosaveURLWithModifiedExtensionForSaveURL: (NSURL *) saveURL; @end @implementation PPDocument (Saving) + (void) load { gRuntimeRequiresManualSetupOfAutosaveFileExtensions = (PP_RUNTIME_CHECK__RUNTIME_REQUIRES_MANUAL_SETUP_OF_AUTOSAVE_FILE_EXTENSIONS) ? YES : NO; } - (void) disableAutosaving: (bool) disallowAutosaving { _disallowAutosaving = (disallowAutosaving) ? YES : NO; if (!_disallowAutosaving && _shouldAutosaveWhenAllowed) { [self autosaveDocumentWithDelegate: nil didAutosaveSelector: NULL contextInfo: NULL]; _shouldAutosaveWhenAllowed = NO; } } - (void) exportImage { _saveToOperationShouldUseExportSettings = YES; [super saveDocumentTo: self]; } #pragma mark NSDocument overrides - (IBAction) saveDocumentTo: (id) sender { _saveToOperationShouldUseExportSettings = NO; [super saveDocumentTo: sender]; } - (void) runModalSavePanelForSaveOperation: (NSSaveOperationType) saveOperation delegate: (id) delegate didSaveSelector: (SEL) didSaveSelector contextInfo: (void *) contextInfo { _savePanelShouldAttachExportAccessoryView = ((saveOperation == NSSaveToOperation) && _saveToOperationShouldUseExportSettings) ? YES : NO; [super runModalSavePanelForSaveOperation: saveOperation delegate: delegate didSaveSelector: didSaveSelector contextInfo: contextInfo]; } - (BOOL) shouldRunSavePanelWithAccessoryView { return (_savePanelShouldAttachExportAccessoryView) ? NO : YES; } - (BOOL) prepareSavePanel: (NSSavePanel *) savePanel { if (![super prepareSavePanel: savePanel]) { goto ERROR; } if (_savePanelShouldAttachExportAccessoryView) { if (!_exportPanelViewController) { _exportPanelViewController = [[PPExportPanelAccessoryViewController controllerForPPDocument: self] retain]; if (!_exportPanelViewController) goto ERROR; } [_exportPanelViewController setupWithSavePanel: savePanel]; _savePanelShouldAttachExportAccessoryView = NO; } return YES; ERROR: return NO; } - (BOOL) saveToURL: (NSURL *) absoluteURL ofType: (NSString *) typeName forSaveOperation: (NSSaveOperationType) saveOperation error: (NSError **) outError { bool didSaveSuccessfully; _saveFormat = [self saveFormatForSaveOperation: saveOperation]; if (_saveFormat == kPPDocumentSaveFormat_Autosave) { if (gRuntimeRequiresManualSetupOfAutosaveFileExtensions) { absoluteURL = [self autosaveURLWithModifiedExtensionForSaveURL: absoluteURL]; } } else if (_saveFormat == kPPDocumentSaveFormat_Export) { NSString *exportedTypeName = [_exportPanelViewController selectedFileTypeName]; if (exportedTypeName) { typeName = exportedTypeName; } } didSaveSuccessfully = [super saveToURL: absoluteURL ofType: typeName forSaveOperation: saveOperation error: outError]; if (didSaveSuccessfully && SaveOperationIsForDocumentFileOfCurrentWindow(saveOperation)) { if ([typeName isEqualToString: kNativeFileFormatTypeName]) { // native filetype: set up window titlebar icon [[self ppWindow] ppSetDocumentWindowTitlebarIcon: [self nativeFileIconImage]]; } else { // non-native filetypes: set up flattened-save notice if settings were lost if ([self flattenedSaveWillLoseSettings]) { [[self ppDocumentWindowController] ppPerformSelectorFromNewStackFrame: @selector(beginFlattenedSaveNoticeSheet)]; } } } if (_saveFormat == kPPDocumentSaveFormat_Export) { [self cleanupAfterExportSave]; } return didSaveSuccessfully; } - (BOOL) writeToURL: (NSURL *) absoluteURL ofType: (NSString *) typeName forSaveOperation: (NSSaveOperationType) saveOperation originalContentsURL: (NSURL *) absoluteOriginalContentsURL error: (NSError **) outError { BOOL didWriteSuccessfully = [super writeToURL: absoluteURL ofType: typeName forSaveOperation: saveOperation originalContentsURL: absoluteOriginalContentsURL error: outError]; if (didWriteSuccessfully && (_saveFormat != kPPDocumentSaveFormat_Autosave) && [typeName isEqualToString: kNativeFileFormatTypeName]) { // The custom finder icon for native-format files needs to be set here: The point where // the currently-set version of the document icon is cached by the Finder seems to be // from within NSDocument's writeSafelyToURL:... method (the caller of this method), // following this method's return. // Setting the icon after the writeSafelyToURL:... method call results in an incorrect, // out-of-date finder icon (and there's no API to manually update the Finder's cached // icon - would need to either resave the file or logout & login). [self setupCustomFinderIconForSavedDocumentAtPath: [absoluteURL path]]; } return didWriteSuccessfully; } - (NSString *) autosavingFileType { if (_disallowAutosaving) { _shouldAutosaveWhenAllowed = YES; return nil; } return kNativeFileFormatTypeName; } - (NSString *) fileNameExtensionForType: (NSString *) typeName saveOperation: (NSSaveOperationType) saveOperation { NSString *fileNameExtension = [super fileNameExtensionForType: typeName saveOperation: saveOperation]; if (IsAutosaveOperation(saveOperation)) { // OS X's autosave naming doesn't take the filetype extension into account, so if // editing two images with the same name but different types (i.e. A.piko & A.png), // they will share the same autosave URL (autosave files are always stored in .piko // format, regardless of document type); To prevent autosave overlapping, include the // document's file extension as part of the returned fileNameExtension when autosaving. // A.png -> A (Autosaved).piko-png (instead of the default: A (Autosaved).piko) fileNameExtension = [self autosaveFileExtensionForExtension: fileNameExtension]; } return fileNameExtension; } #pragma mark Private methods - (PPDocumentSaveFormat) saveFormatForSaveOperation: (NSSaveOperationType) saveOperation; { if (IsAutosaveOperation(saveOperation)) { return kPPDocumentSaveFormat_Autosave; } else if ((saveOperation == NSSaveToOperation) && _saveToOperationShouldUseExportSettings) { return kPPDocumentSaveFormat_Export; } return kPPDocumentSaveFormat_Normal; } - (void) setupCustomFinderIconForSavedDocumentAtPath: (NSString *) filepath { if (![filepath length]) goto ERROR; [[NSWorkspace sharedWorkspace] setIcon: [self nativeFileIconImage] forFile: filepath options: NSExcludeQuickDrawElementsIconCreationOption]; return; ERROR: return; } - (void) cleanupAfterExportSave { [_exportPanelViewController setupWithSavePanel: nil]; _saveToOperationShouldUseExportSettings = NO; } - (bool) flattenedSaveWillLoseSettings { return (([self numLayers] > 1) || [self hasSelection] || [self hasCustomCanvasSettings] || ([self numSamplerImages] > 0)) ? YES : NO; } // autosaveFileExtensionForExtension: returns an extension for use when autosaving files. // This is a workaround for OS X's autosave namespace issue, where editing two images in the // same directory with the same name but different types (i.e. A.piko & A.png) will currently // use the same autosave URL for both (autosave files are currently stored in .piko format, // regardless of document type, so the the default autosave extension would always be "piko"). // The returned autosave extension appends the type extension of the document's saved file: // "piko" fileExtension + "png" saved document type extension -> "piko-png" - (NSString *) autosaveFileExtensionForExtension: (NSString *) fileExtension { NSURL *savedDocumentURL = [self fileURL]; if (savedDocumentURL && [fileExtension length]) { NSString *savedDocumentExtension = [[savedDocumentURL path] pathExtension]; if ([savedDocumentExtension length] && ![savedDocumentExtension isEqualToString: fileExtension]) { NSString *autosaveExtension = [NSString stringWithFormat: kAutosaveCompoundExtensionFormatString, fileExtension, savedDocumentExtension]; if (autosaveExtension) { fileExtension = autosaveExtension; } } } return fileExtension; } // autosaveURLWithModifiedExtensionForSaveURL: is for setting up an autosave URL manually // on runtimes that don't support NSDocument's fileNameExtensionForType:saveOperation: (< 10.5) - (NSURL *) autosaveURLWithModifiedExtensionForSaveURL: (NSURL *) saveURL { NSString *savePath, *saveExtension, *autosaveExtension, *autosavePath; NSURL *autosaveURL; if (!saveURL) goto ERROR; savePath = [saveURL path]; saveExtension = [savePath pathExtension]; if (![saveExtension length]) { goto ERROR; } if ([saveExtension rangeOfString: kAutosaveCompoundExtensionSeparatorCharString].length) { // saveURL already has a compound extension, so just return it return saveURL; } autosaveExtension = [self autosaveFileExtensionForExtension: saveExtension]; if (![autosaveExtension length]) { goto ERROR; } if ([autosaveExtension isEqualToString: saveExtension]) { return saveURL; } autosavePath = [[savePath stringByDeletingPathExtension] stringByAppendingPathExtension: autosaveExtension]; if (!autosavePath) goto ERROR; autosaveURL = [NSURL fileURLWithPath: autosavePath]; if (!autosaveURL) goto ERROR; return autosaveURL; ERROR: return saveURL; } @end #pragma mark Private functions static inline bool IsAutosaveOperation(NSSaveOperationType saveOperation) { return ((saveOperation != NSSaveOperation) && (saveOperation != NSSaveAsOperation) && (saveOperation != NSSaveToOperation)) ? YES : NO; } static inline bool SaveOperationIsForDocumentFileOfCurrentWindow( NSSaveOperationType saveOperation) { return ((saveOperation == NSSaveOperation) || (saveOperation == NSSaveAsOperation)) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Selection.m0000644000076500000240000003747213234403206022370 0ustar joshstaff/* PPDocument_Selection.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocument_Notifications.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #import "PPGeometry.h" @interface PPDocument (SelectionPrivateMethods) - (void) updateSelectionMaskWithBitmap: (NSBitmapImageRep *) bitmap atPoint: (NSPoint) origin; - (void) updateSelectionMaskWithTIFFData: (NSData *) tiffData atPoint: (NSPoint) origin; - (void) selectPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode shouldAntialias: (bool) shouldAntialias; - (bool) validateSelectionMode: (PPSelectionMode *) inOutSelectionMode; - (bool) selectionMaskIsNotEmpty; - (void) handleSelectionMaskUpdateInBounds: (NSRect) bounds undoBitmap: (NSBitmapImageRep *) undoBitmap; - (NSString *) actionNameForSelectionMode: (PPSelectionMode) selectionMode; @end @implementation PPDocument (Selection) - (bool) setupSelectionMaskBitmapOfSize: (NSSize) maskSize { if (PPGeometry_IsZeroSize(maskSize)) { goto ERROR; } if (!_selectionMask || !NSEqualSizes([_selectionMask ppSizeInPixels], maskSize)) { NSBitmapImageRep *selectionMask = [NSBitmapImageRep ppMaskBitmapOfSize: maskSize]; if (!selectionMask) goto ERROR; [_selectionMask autorelease]; // use autorelease when releasing accessible members _selectionMask = [selectionMask retain]; } else { [_selectionMask ppClearBitmap]; } _selectionBounds = NSZeroRect; _hasSelection = NO; return YES; ERROR: return NO; } - (bool) hasSelection { return _hasSelection; } - (NSRect) selectionBounds { return _selectionBounds; } - (NSBitmapImageRep *) selectionMask { return _selectionMask; } - (void) setSelectionMask: (NSBitmapImageRep *) selectionMask { if (![selectionMask ppIsMaskBitmap] || !NSEqualSizes([_selectionMask ppSizeInPixels], [selectionMask ppSizeInPixels])) { return; } [self updateSelectionMaskWithBitmap: selectionMask atPoint: NSZeroPoint]; } - (void) setSelectionMaskAreaWithBitmap: (NSBitmapImageRep *) selectionMask atPoint: (NSPoint) origin { if (![selectionMask ppIsMaskBitmap]) { return; } [self updateSelectionMaskWithBitmap: selectionMask atPoint: origin]; } - (void) selectRect: (NSRect) rect selectionMode: (PPSelectionMode) selectionMode { rect = PPGeometry_PixelCenteredRect(rect); [self selectPath: [NSBezierPath bezierPathWithRect: rect] selectionMode: selectionMode shouldAntialias: NO]; } - (void) selectPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode { [self selectPath: path selectionMode: selectionMode shouldAntialias: YES]; } - (void) selectPixelsMatchingColorAtPoint: (NSPoint) point colorMatchTolerance: (unsigned) colorMatchTolerance pixelMatchingMode: (PPPixelMatchingMode) pixelMatchingMode selectionMode: (PPSelectionMode) selectionMode { NSBitmapImageRep *matchMask, *croppedMatchMask, *croppedSelectionMask; NSRect matchMaskBounds; bool matchMaskShouldIntersectSelectionMask; if (![self validateSelectionMode: &selectionMode]) { goto ERROR; } if ((selectionMode == kPPSelectionMode_Intersect) || (selectionMode == kPPSelectionMode_Subtract)) { matchMaskShouldIntersectSelectionMask = (_hasSelection && [_selectionMask ppMaskCoversPoint: point]) ? YES : NO; } else { matchMaskShouldIntersectSelectionMask = NO; } matchMask = [self maskForPixelsMatchingColorAtPoint: point colorMatchTolerance: colorMatchTolerance pixelMatchingMode: pixelMatchingMode shouldIntersectSelectionMask: matchMaskShouldIntersectSelectionMask]; if (!matchMask) goto ERROR; matchMaskBounds = [matchMask ppMaskBounds]; if (NSIsEmptyRect(matchMaskBounds)) { goto ERROR; } if (selectionMode == kPPSelectionMode_Intersect) { if (_hasSelection && !matchMaskShouldIntersectSelectionMask) { // matchMask wasn't intersected with the selection mask during construction by // the maskForPixelsMatchingColorAtPoint:... method, so intersect it manually here [matchMask ppIntersectMaskWithMaskBitmap: _selectionMask]; } selectionMode = kPPSelectionMode_Replace; } if (selectionMode == kPPSelectionMode_Replace) { if (_hasSelection) { matchMaskBounds = NSUnionRect(matchMaskBounds, _selectionBounds); } } croppedMatchMask = [matchMask ppShallowDuplicateFromBounds: matchMaskBounds]; if (!croppedMatchMask) goto ERROR; if (selectionMode == kPPSelectionMode_Subtract) { croppedSelectionMask = [_selectionMask ppBitmapCroppedToBounds: matchMaskBounds]; if (!croppedSelectionMask) goto ERROR; [croppedSelectionMask ppSubtractMaskBitmap: croppedMatchMask]; croppedMatchMask = croppedSelectionMask; } else if (selectionMode == kPPSelectionMode_Add) { croppedSelectionMask = [_selectionMask ppShallowDuplicateFromBounds: matchMaskBounds]; if (!croppedSelectionMask) goto ERROR; [croppedMatchMask ppMergeMaskWithMaskBitmap: croppedSelectionMask]; } [self updateSelectionMaskWithBitmap: croppedMatchMask atPoint: matchMaskBounds.origin]; [[self undoManager] setActionName: [self actionNameForSelectionMode: selectionMode]]; return; ERROR: return; } - (void) selectAll { [self selectRect: _canvasFrame selectionMode: kPPSelectionMode_Add]; [[self undoManager] setActionName: @"Select All"]; } - (void) selectVisibleTargetPixels { NSBitmapImageRep *visiblePixelsMask = [[self sourceBitmapForLayerOperationTarget: _layerOperationTarget] ppMaskBitmapForVisiblePixelsInImageBitmap]; if (!visiblePixelsMask) return; [self setSelectionMask: visiblePixelsMask]; [[self undoManager] setActionName: @"Select Visible Pixels"]; } - (void) deselectAll { if (!_hasSelection) return; [self selectRect: _selectionBounds selectionMode: kPPSelectionMode_Subtract]; [[self undoManager] setActionName: @"Deselect All"]; } - (void) deselectInvisibleTargetPixels { NSBitmapImageRep *workingMask, *croppedSelectionMask; if (!_hasSelection) return; // crop target bitmap to selection bounds & make a mask of its visible pixels workingMask = [[[self sourceBitmapForLayerOperationTarget: _layerOperationTarget] ppShallowDuplicateFromBounds: _selectionBounds] ppMaskBitmapForVisiblePixelsInImageBitmap]; if (!workingMask) goto ERROR; croppedSelectionMask = [_selectionMask ppShallowDuplicateFromBounds: _selectionBounds]; if (!croppedSelectionMask) goto ERROR; [workingMask ppIntersectMaskWithMaskBitmap: croppedSelectionMask]; if ([workingMask ppIsEqualToBitmap: croppedSelectionMask]) { return; } [self setSelectionMaskAreaWithBitmap: workingMask atPoint: _selectionBounds.origin]; [[self undoManager] setActionName: @"Deselect Invisible Pixels"]; return; ERROR: return; } - (void) invertSelection { NSUndoManager *undoManager = [self undoManager]; [undoManager disableUndoRegistration]; if (!_hasSelection) { [self selectAll]; } else { NSBitmapImageRep *invertedSelectionMask = [[_selectionMask copy] autorelease]; [invertedSelectionMask ppInvertMaskBitmap]; if (!invertedSelectionMask) goto ERROR; if ([invertedSelectionMask ppMaskIsNotEmpty]) { [self setSelectionMask: invertedSelectionMask]; } else { [self deselectAll]; } } [undoManager enableUndoRegistration]; [[undoManager prepareWithInvocationTarget: self] invertSelection]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Invert Selection"]; } return; ERROR: [undoManager enableUndoRegistration]; return; } - (void) closeHolesInSelection { NSBitmapImageRep *updatedMask; if (!_hasSelection) goto ERROR; updatedMask = [_selectionMask ppBitmapCroppedToBounds: _selectionBounds]; if (!updatedMask) goto ERROR; [updatedMask ppCloseHolesInMaskBitmap]; [self setSelectionMaskAreaWithBitmap: updatedMask atPoint: _selectionBounds.origin]; [[self undoManager] setActionName: @"Close Holes in Selection"]; return; ERROR: return; } - (PPDocument *) ppDocumentFromSelection { PPDocument *ppDocument; if (!_hasSelection || ![self layerOperationTargetHasEnabledLayer]) { goto ERROR; } ppDocument = [[[PPDocument alloc] init] autorelease]; if (!ppDocument) goto ERROR; [ppDocument loadFromPPDocument: self]; [ppDocument cropToSelectionBounds]; [ppDocument removeNontargetLayers]; [[ppDocument undoManager] removeAllActions]; return ppDocument; ERROR: return nil; } #pragma mark Private methods - (void) updateSelectionMaskWithBitmap: (NSBitmapImageRep *) bitmap atPoint: (NSPoint) origin { NSRect updateRect; NSBitmapImageRep *undoBitmap; updateRect.origin = origin; updateRect.size = [bitmap ppSizeInPixels]; updateRect = NSIntersectionRect(updateRect, _canvasFrame); if (NSIsEmptyRect(updateRect)) { return; } undoBitmap = [_selectionMask ppBitmapCroppedToBounds: updateRect]; [_selectionMask ppCopyFromBitmap: bitmap toPoint: origin]; [self handleSelectionMaskUpdateInBounds: updateRect undoBitmap: undoBitmap]; } - (void) updateSelectionMaskWithTIFFData: (NSData *) tiffData atPoint: (NSPoint) origin { if (!tiffData) return; [self updateSelectionMaskWithBitmap: [NSBitmapImageRep imageRepWithData: tiffData] atPoint: origin]; } - (void) selectPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode shouldAntialias: (bool) shouldAntialias { NSRect pathBounds, updateBounds; NSBitmapImageRep *undoBitmap; if (![self validateSelectionMode: &selectionMode]) { goto ERROR; } pathBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect([path bounds]), _canvasFrame); if (NSIsEmptyRect(pathBounds)) { goto ERROR; } if (((selectionMode == kPPSelectionMode_Replace) && _hasSelection) || (selectionMode == kPPSelectionMode_Intersect)) { updateBounds = NSUnionRect(pathBounds, _selectionBounds); undoBitmap = [_selectionMask ppBitmapCroppedToBounds: updateBounds]; [_selectionMask ppClearBitmapInBounds: updateBounds]; } else { updateBounds = pathBounds; undoBitmap = [_selectionMask ppBitmapCroppedToBounds: updateBounds]; } [_selectionMask ppSetAsCurrentGraphicsContext]; if (selectionMode == kPPSelectionMode_Subtract) { [[NSColor ppMaskBitmapOffColor] set]; } else { [[NSColor ppMaskBitmapOnColor] set]; } if (shouldAntialias) { // antialiasing is necessary when filling a non-rectangular path, otherwise the fill // will cover a larger area than the stroke (some curve edges will add a pixel); // make sure to correct the antialiasing afterwards by thresholding the mask's pixel // values to 0 & 255 [path ppAntialiasedFill]; } else { [path fill]; } [path stroke]; [_selectionMask ppRestoreGraphicsContext]; if (shouldAntialias) { [_selectionMask ppThresholdMaskBitmapPixelValuesInBounds: pathBounds]; } if (selectionMode == kPPSelectionMode_Intersect) { NSBitmapImageRep *croppedSelectionMask; croppedSelectionMask = [_selectionMask ppShallowDuplicateFromBounds: updateBounds]; // overwriting (intersecting) croppedSelectionMask also overwrites _selectionMask, // since they share bitmapData (ShallowDuplicate) [croppedSelectionMask ppIntersectMaskWithMaskBitmap: undoBitmap]; } [self handleSelectionMaskUpdateInBounds: updateBounds undoBitmap: undoBitmap]; [[self undoManager] setActionName: [self actionNameForSelectionMode: selectionMode]]; return; ERROR: return; } - (bool) validateSelectionMode: (PPSelectionMode *) inOutSelectionMode { PPSelectionMode selectionMode; if (!inOutSelectionMode) goto ERROR; selectionMode = *inOutSelectionMode; if (!PPSelectionMode_IsValid(selectionMode)) { goto ERROR; } if (!_hasSelection) { if ((selectionMode == kPPSelectionMode_Subtract) || (selectionMode == kPPSelectionMode_Intersect)) { goto ERROR; } selectionMode = kPPSelectionMode_Replace; } *inOutSelectionMode = selectionMode; return YES; ERROR: return NO; } - (bool) selectionMaskIsNotEmpty { return [_selectionMask ppMaskIsNotEmpty]; } - (void) handleSelectionMaskUpdateInBounds: (NSRect) bounds undoBitmap: (NSBitmapImageRep *) undoBitmap { NSUndoManager *undoManager; _hasSelection = [self selectionMaskIsNotEmpty]; if (_hasSelection) { _selectionBounds = [_selectionMask ppMaskBoundsInRect: NSUnionRect(_selectionBounds, bounds)]; } else { _selectionBounds = NSZeroRect; } [self postNotification_UpdatedSelection]; undoManager = [self undoManager]; [[undoManager prepareWithInvocationTarget: self] updateSelectionMaskWithTIFFData: [undoBitmap ppCompressedTIFFData] atPoint: bounds.origin]; if (![undoManager isUndoing] && ![undoManager isRedoing]) { [undoManager setActionName: @"Selection"]; } } - (NSString *) actionNameForSelectionMode: (PPSelectionMode) selectionMode { switch (selectionMode) { case kPPSelectionMode_Add: { return @"Add to Selection"; } break; case kPPSelectionMode_Subtract: { return @"Subtract from Selection"; } break; case kPPSelectionMode_Intersect: { return @"Intersect Selection"; } break; case kPPSelectionMode_Replace: default: { return @"Make Selection"; } break; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocument_Tiling.m0000644000076500000240000001311513234403206021655 0ustar joshstaff/* PPDocument_Tiling.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocument.h" #import "PPDocumentLayer.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" @interface PPDocument (TilingPrivateMethods) - (NSColor *) tilingPatternColorFromSelectionInBitmap: (NSBitmapImageRep *) sourceBitmap; - (bool) tileSelectionInBitmap: (NSBitmapImageRep *) sourceBitmap toBitmap: (NSBitmapImageRep *) destinationBitmap; - (bool) tileSelectionInLayerAtIndex: (int) index; @end @implementation PPDocument (Tiling) - (void) tileSelection { bool isMultilayerOperation; int i; NSString *actionName; if (!_hasSelection) goto ERROR; [self setupTargetLayerIndexesForOperationTarget: _layerOperationTarget]; if (!_numTargetLayerIndexes) goto ERROR; isMultilayerOperation = (_numTargetLayerIndexes > 1) ? YES : NO; if (isMultilayerOperation) { [self beginMultilayerOperation]; } for (i=0; i<_numTargetLayerIndexes; i++) { [self tileSelectionInLayerAtIndex: _targetLayerIndexes[i]]; } if (isMultilayerOperation) { [self finishMultilayerOperation]; } actionName = [NSString stringWithFormat: @"Tile Selection (%@)", [self nameOfLayerOperationTarget: _layerOperationTarget]]; [[self undoManager] setActionName: actionName]; return; ERROR: return; } - (void) tileSelectionAsNewLayer { PPDocumentLayer *layer; NSBitmapImageRep *sourceBitmap, *destinationBitmap; NSString *actionName; layer = [PPDocumentLayer layerWithSize: _canvasFrame.size andName: @"Tiled Layer from Selection"]; if (!layer) goto ERROR; sourceBitmap = [self sourceBitmapForLayerOperationTarget: _layerOperationTarget]; destinationBitmap = [layer bitmap]; if (!sourceBitmap || !destinationBitmap) { goto ERROR; } if (![self tileSelectionInBitmap: sourceBitmap toBitmap: destinationBitmap]) { goto ERROR; } [layer handleUpdateToBitmapInRect: _canvasFrame]; if (_layerOperationTarget == kPPLayerOperationTarget_DrawingLayerOnly) { [layer setOpacity: [_drawingLayer opacity]]; } [self insertLayer: layer atIndex: _indexOfDrawingLayer + 1 andSetAsDrawingLayer: YES]; actionName = [NSString stringWithFormat: @"Add Layer (Tiled %@ Selection)", [self nameOfLayerOperationTarget: _layerOperationTarget]]; [[self undoManager] setActionName: actionName]; return; ERROR: return; } #pragma mark Private methods - (NSColor *) tilingPatternColorFromSelectionInBitmap: (NSBitmapImageRep *) sourceBitmap { NSBitmapImageRep *tileBitmap, *tileInvertedSelectionMask; NSImage *tileImage; if (!sourceBitmap || !_hasSelection) { goto ERROR; } tileBitmap = [sourceBitmap ppBitmapCroppedToBounds: _selectionBounds]; tileInvertedSelectionMask = [_selectionMask ppBitmapCroppedToBounds: _selectionBounds]; [tileInvertedSelectionMask ppInvertMaskBitmap]; if (!tileBitmap || !tileInvertedSelectionMask) { goto ERROR; } if ([tileInvertedSelectionMask ppMaskIsNotEmpty]) { [tileBitmap ppMaskedEraseUsingMask: tileInvertedSelectionMask]; } tileImage = [NSImage ppImageWithBitmap: tileBitmap]; if (!tileImage) goto ERROR; return [NSColor colorWithPatternImage: tileImage]; ERROR: return nil; } - (bool) tileSelectionInBitmap: (NSBitmapImageRep *) sourceBitmap toBitmap: (NSBitmapImageRep *) destinationBitmap { NSColor *tilingPatternColor; if (!sourceBitmap || !destinationBitmap) { goto ERROR; } tilingPatternColor = [self tilingPatternColorFromSelectionInBitmap: sourceBitmap]; if (!tilingPatternColor) goto ERROR; [destinationBitmap ppSetAsCurrentGraphicsContext]; [tilingPatternColor set]; [[NSGraphicsContext currentContext] setPatternPhase: _selectionBounds.origin]; NSRectFill(_canvasFrame); [destinationBitmap ppRestoreGraphicsContext]; return YES; ERROR: return NO; } - (bool) tileSelectionInLayerAtIndex: (int) index { PPDocumentLayer *layer; NSBitmapImageRep *tiledBitmap; layer = [self layerAtIndex: index]; if (!layer) goto ERROR; tiledBitmap = [NSBitmapImageRep ppImageBitmapOfSize: _canvasFrame.size]; if (!tiledBitmap) goto ERROR; if (![self tileSelectionInBitmap: [layer bitmap] toBitmap: tiledBitmap]) { goto ERROR; } [self copyImageBitmap: tiledBitmap toLayerAtIndex: index atPoint: NSZeroPoint]; return YES; ERROR: return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentAnimationFileNoticeSheetController.h0000644000076500000240000000276213234403416027212 0ustar joshstaff/* PPDocumentAnimationFileNoticeSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPDocumentAnimationFileNoticeSheetController : NSObject { id _delegate; NSAlert *_alert; } + (bool) beginAnimationFileNoticeSheetForDocumentWindow: (NSWindow *) window delegate: (id) delegate; @end @interface NSObject (PPDocumentAnimationFileNoticeSheetDelegateMethods) - (void) documentAnimationFileNoticeSheetDidFinishAndShouldChangeSaveLocation: (bool) shouldChangeSaveLocation; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentAnimationFileNoticeSheetController.m0000644000076500000240000001155113234403205027207 0ustar joshstaff/* PPDocumentAnimationFileNoticeSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentAnimationFileNoticeSheetController.h" #define kAnimationFileAlertMessageText \ @"Warning: This file contains an animation with multiple images, " \ "however, only the first image was loaded, because PikoPixel " \ "currently only supports single-image editing.\n\nIf this image is " \ "later saved at the current file's location, the unloaded animation " \ "images will be overwritten (removed).\n\nTo preserve the animation " \ "in the original file, choose a new save location for the edited image." #define kAnimationFileAlertInformativeText @"" #define kAnimationFileAlertDefaultButtonText @"Choose a new save location..." #define kAnimationFileAlertAlternateButtonText @"Use the current save location" #define kChooseNewSaveLocationReturnCode NSAlertDefaultReturn @interface PPDocumentAnimationFileNoticeSheetController (PrivateMethods) - initWithDelegate: (id) delegate; - (bool) beginAlertModalForWindow: (NSWindow *) window; - (void) notifyDelegateSheetDidFinishAndShouldChangeSaveLocation: (bool) shouldChangeSaveLocation; @end @implementation PPDocumentAnimationFileNoticeSheetController + (bool) beginAnimationFileNoticeSheetForDocumentWindow: (NSWindow *) window delegate: (id) delegate { PPDocumentAnimationFileNoticeSheetController *controller; controller = [[[self alloc] initWithDelegate: delegate] autorelease]; if (![controller beginAlertModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - initWithDelegate: (id) delegate { NSAlert *alert; self = [super init]; if (!self) goto ERROR; if (!delegate) goto ERROR; alert = [NSAlert alertWithMessageText: kAnimationFileAlertMessageText defaultButton: kAnimationFileAlertDefaultButtonText alternateButton: kAnimationFileAlertAlternateButtonText otherButton: @"" informativeTextWithFormat: kAnimationFileAlertInformativeText]; if (!alert) goto ERROR; _delegate = delegate; _alert = [alert retain]; return self; ERROR: [self release]; return nil; } - init { return [self initWithDelegate: nil]; } - (void) dealloc { [_alert release]; [super dealloc]; } #pragma mark NSAlert sheet modal - (bool) beginAlertModalForWindow: (NSWindow *) window; { if (![window isVisible] || [[_alert window] isVisible]) { goto ERROR; } [_alert beginSheetModalForWindow: window modalDelegate: self didEndSelector: @selector(alertDidEnd:returnCode:contextInfo:) contextInfo: NULL]; [self retain]; return YES; ERROR: return NO; } - (void) alertDidEnd: (NSAlert *) alert returnCode: (int) returnCode contextInfo: (void *) contextInfo { bool shouldChangeSaveLocation = (returnCode == kChooseNewSaveLocationReturnCode) ? YES : NO; [self notifyDelegateSheetDidFinishAndShouldChangeSaveLocation: shouldChangeSaveLocation]; [self autorelease]; } #pragma mark Delegate notifiers - (void) notifyDelegateSheetDidFinishAndShouldChangeSaveLocation: (bool) shouldChangeSaveLocation { if ([_delegate respondsToSelector: @selector( documentAnimationFileNoticeSheetDidFinishAndShouldChangeSaveLocation:)]) { [_delegate documentAnimationFileNoticeSheetDidFinishAndShouldChangeSaveLocation: shouldChangeSaveLocation]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentBackgroundSettingsSheetController.h0000644000076500000240000001057513234403416027132 0ustar joshstaff/* PPDocumentBackgroundSettingsSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" @class PPBackgroundPattern; @interface PPDocumentBackgroundSettingsSheetController : PPDocumentSheetController { IBOutlet NSTextField *_patternDisplayField; IBOutlet NSMatrix *_patternTypeMatrix; IBOutlet NSColorWell *_patternColor1Well; IBOutlet NSColorWell *_patternColor2Well; IBOutlet NSSlider *_patternSizeSlider; IBOutlet NSMenu *_defaultPatternPresetsMenu; IBOutlet NSPopUpButton *_patternPresetsPopUpButton; IBOutlet NSImageView *_backgroundImageView; IBOutlet NSButton *_showImageCheckbox; IBOutlet NSButton *_imageSmoothingCheckbox; IBOutlet NSButton *_copyImageToPasteboardButton; IBOutlet NSButton *_removeImageButton; PPBackgroundPattern *_backgroundPattern; PPBackgroundPattern *_lastCustomBackgroundPattern; NSColor *_activePatternTypeCellColor; NSColor *_inactivePatternTypeCellColor; int _tagOfActivePatternTypeMatrixCell; int _indexOfPatternPresetsMenuItem_DefaultPattern; int _indexOfPatternPresetsMenuItem_CustomPattern; int _indexOfPatternPresetsMenuItem_FirstPatternPreset; } + (bool) beginBackgroundSettingsSheetForDocumentWindow: (NSWindow *) window backgroundPattern: (PPBackgroundPattern *) backgroundPattern backgroundImage: (NSImage *) backgroundImage backgroundImageVisibility: (bool) shouldDisplayBackgroundImage backgroundImageSmoothing: (bool) shouldSmoothenBackgroundImage delegate: (id) delegate; - (IBAction) patternSettingChanged: (id) sender; - (IBAction) patternPresetsMenuItemSelected_DefaultPattern: (id) sender; - (IBAction) patternPresetsMenuItemSelected_CustomPattern: (id) sender; - (IBAction) patternPresetsMenuItemSelected_PresetPattern: (id) sender; - (IBAction) patternPresetsMenuItemSelected_AddCurrentPatternToPresets: (id) sender; - (IBAction) patternPresetsMenuItemSelected_EditPresets: (id) sender; - (IBAction) patternPresetsMenuItemSelected_ExportPresetsToFile: (id) sender; - (IBAction) patternPresetsMenuItemSelected_ImportPresetsFromFile: (id) sender; - (IBAction) patternPresetsMenuItemSelected_SavePatternAsDefault: (id) sender; - (IBAction) patternPresetsMenuItemSelected_RestoreOriginalDefault: (id) sender; - (IBAction) backgroundImageViewUpdated: (id) sender; - (IBAction) showImageCheckboxClicked: (id) sender; - (IBAction) imageSmoothingCheckboxClicked: (id) sender; - (IBAction) setImageToFileButtonPressed: (id) sender; - (IBAction) setImageToPasteboardButtonPressed: (id) sender; - (IBAction) copyImageToPasteboardButtonPressed: (id) sender; - (IBAction) removeImageButtonPressed: (id) sender; @end @interface NSObject (PPDocumentBackgroundSettingsSheetDelegateMethods) - (void) backgroundSettingsSheetDidUpdatePattern: (PPBackgroundPattern *) backgroundPattern; - (void) backgroundSettingsSheetDidUpdateImage: (NSImage *) backgroundImage; - (void) backgroundSettingsSheetDidUpdateImageVisibility: (bool) shouldDisplayImage; - (void) backgroundSettingsSheetDidUpdateImageSmoothing: (bool) shouldSmoothenImage; - (void) backgroundSettingsSheetDidFinishWithBackgroundPattern: (PPBackgroundPattern *) backgroundPattern backgroundImage: (NSImage *) backgroundImage shouldDisplayImage: (bool) shouldDisplayImage shouldSmoothenImage: (bool) shouldSmoothenImage; - (void) backgroundSettingsSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentBackgroundSettingsSheetController.m0000644000076500000240000006250613234403205027134 0ustar joshstaff/* PPDocumentBackgroundSettingsSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentBackgroundSettingsSheetController.h" #import "PPDefines.h" #import "NSColor_PPUtilities.h" #import "PPUserDefaults.h" #import "PPBackgroundPattern.h" #import "PPBackgroundPatternPresets.h" #import "PPDocumentEditPatternPresetsSheetController.h" #import "PPUserDefaultsInitialValues.h" #import "NSImage_PPUtilities.h" #import "NSPasteboard_PPUtilities.h" #define kPatternPresetsMenuItemTag_DefaultPattern 1 #define kPatternPresetsMenuItemTag_CustomPattern 2 #define kPatternPresetsMenuItemTag_PatternPresetsInsertionPoint 3 #define kPatternPresetsMenuItemTag_ExportPresets 4 #define kDocumentBackgroundSettingsSheetNibName @"DocumentBackgroundSettingsSheet" #define kExportPresetsSaveFileName @"PikoPixel patterns" #define kBackgroundPatternTypeDisplayName @"Background" #define kUIColor_ActivePatternTypeCellGradientInnerColor \ [NSColor ppSRGBColorWithRed: 0.62f green: 0.78f blue: 0.96f alpha: 1.0f] #define kUIColor_ActivePatternTypeCellGradientOuterColor \ [NSColor ppSRGBColorWithRed: 0.87f green: 0.99f blue: 1.0f alpha: 1.0f] #define kUIColor_InactivePatternTypeCellGradientInnerColor \ [NSColor ppSRGBColorWithWhite: 0.90f alpha: 1.0f] #define kUIColor_InactivePatternTypeCellGradientOuterColor \ [NSColor ppSRGBColorWithWhite: 0.97f alpha: 1.0f] @interface PPDocumentBackgroundSettingsSheetController (PrivateMethods) - initWithBackgroundPattern: (PPBackgroundPattern *) backgroundPattern backgroundImage: (NSImage *) backgroundImage backgroundImageVisibility: (bool) shouldDisplayBackgroundImage backgroundImageSmoothing: (bool) shouldSmoothenBackgroundImage delegate: (id) delegate; - (void) addAsObserverForPPBackgroundPatternPresetsNotifications; - (void) removeAsObserverForPPBackgroundPatternPresetsNotifications; - (void) handlePPBackgroundPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification; - (void) setupMenuForPatternPresetsPopUpButton; - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern andSetupSheet: (bool) shouldSetupSheet; - (void) setupSheetWithCurrentBackgroundPattern; - (void) loadBackgroundPatternFromSheet; - (PPBackgroundPattern *) backgroundPatternFromSheet; - (void) setBackgroundImage: (NSImage *) image; - (void) updateEnabledStatesOfBackgroundImageControls; - (void) notifyDelegateDidUpdatePattern; - (void) notifyDelegateDidUpdateImage; - (void) notifyDelegateDidUpdateImageVisibility; - (void) notifyDelegateDidUpdateImageSmoothing; @end @implementation PPDocumentBackgroundSettingsSheetController + (bool) beginBackgroundSettingsSheetForDocumentWindow: (NSWindow *) window backgroundPattern: (PPBackgroundPattern *) backgroundPattern backgroundImage: (NSImage *) backgroundImage backgroundImageVisibility: (bool) shouldDisplayBackgroundImage backgroundImageSmoothing: (bool) shouldSmoothenBackgroundImage delegate: (id) delegate { PPDocumentBackgroundSettingsSheetController *controller; controller = [[[self alloc] initWithBackgroundPattern: backgroundPattern backgroundImage: backgroundImage backgroundImageVisibility: shouldDisplayBackgroundImage backgroundImageSmoothing: shouldSmoothenBackgroundImage delegate: delegate] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - initWithBackgroundPattern: (PPBackgroundPattern *) backgroundPattern backgroundImage: (NSImage *) backgroundImage backgroundImageVisibility: (bool) shouldDisplayBackgroundImage backgroundImageSmoothing: (bool) shouldSmoothenBackgroundImage delegate: (id) delegate { unsigned gradientHeight; self = [super initWithNibNamed: kDocumentBackgroundSettingsSheetNibName delegate: delegate]; if (!self) goto ERROR; if (!backgroundPattern) goto ERROR; gradientHeight = [_patternTypeMatrix cellSize].height; _activePatternTypeCellColor = [[NSColor ppCenteredVerticalGradientPatternColorWithHeight: gradientHeight innerColor: kUIColor_ActivePatternTypeCellGradientInnerColor outerColor: kUIColor_ActivePatternTypeCellGradientOuterColor] retain]; _inactivePatternTypeCellColor = [[NSColor ppCenteredVerticalGradientPatternColorWithHeight: gradientHeight innerColor: kUIColor_InactivePatternTypeCellGradientInnerColor outerColor: kUIColor_InactivePatternTypeCellGradientOuterColor] retain]; if (!_activePatternTypeCellColor || !_inactivePatternTypeCellColor) { goto ERROR; } [[_patternTypeMatrix cells] makeObjectsPerformSelector: @selector(setBackgroundColor:) withObject: _inactivePatternTypeCellColor]; [_patternSizeSlider setMinValue: kMinBackgroundPatternSize]; [_patternSizeSlider setMaxValue: kMaxBackgroundPatternSize]; [self setBackgroundPattern: backgroundPattern andSetupSheet: YES]; [self setupMenuForPatternPresetsPopUpButton]; [_backgroundImageView setImage: backgroundImage]; [_showImageCheckbox setIntValue: shouldDisplayBackgroundImage]; [_imageSmoothingCheckbox setIntValue: shouldSmoothenBackgroundImage]; [self updateEnabledStatesOfBackgroundImageControls]; [self addAsObserverForPPBackgroundPatternPresetsNotifications]; return self; ERROR: [self release]; return nil; } - init { return [self initWithBackgroundPattern: nil backgroundImage: nil backgroundImageVisibility: NO backgroundImageSmoothing: NO delegate: nil]; } - (void) dealloc { [self removeAsObserverForPPBackgroundPatternPresetsNotifications]; [_lastCustomBackgroundPattern release]; [_backgroundPattern release]; [_activePatternTypeCellColor release]; [_inactivePatternTypeCellColor release]; [super dealloc]; } #pragma mark Actions - (IBAction) patternSettingChanged: (id) sender { [self loadBackgroundPatternFromSheet]; if (sender == _patternTypeMatrix) { [self setupSheetWithCurrentBackgroundPattern]; } if ([_patternPresetsPopUpButton indexOfSelectedItem] != _indexOfPatternPresetsMenuItem_CustomPattern) { [_patternPresetsPopUpButton selectItemAtIndex: _indexOfPatternPresetsMenuItem_CustomPattern]; } } - (IBAction) patternPresetsMenuItemSelected_DefaultPattern: (id) sender { [self setBackgroundPattern: [PPUserDefaults backgroundPattern] andSetupSheet: YES]; } - (IBAction) patternPresetsMenuItemSelected_CustomPattern: (id) sender { if (!_lastCustomBackgroundPattern) return; [self setBackgroundPattern: _lastCustomBackgroundPattern andSetupSheet: YES]; } - (IBAction) patternPresetsMenuItemSelected_PresetPattern: (id) sender { int indexOfPattern; NSArray *presetPatterns; if (![sender isKindOfClass: [NSMenuItem class]]) { goto ERROR; } indexOfPattern = [((NSMenuItem *) sender) tag]; presetPatterns = [[PPBackgroundPatternPresets sharedPresets] patterns]; if ((indexOfPattern < 0) || (indexOfPattern >= [presetPatterns count])) { goto ERROR; } [self setBackgroundPattern: [presetPatterns objectAtIndex: indexOfPattern] andSetupSheet: YES]; return; ERROR: return; } - (IBAction) patternPresetsMenuItemSelected_AddCurrentPatternToPresets: (id) sender { [PPDocumentEditPatternPresetsSheetController beginEditPatternPresetsSheetForWindow: _sheet patternPresets: [PPBackgroundPatternPresets sharedPresets] patternTypeDisplayName: kBackgroundPatternTypeDisplayName currentPattern: [self backgroundPatternFromSheet] addCurrentPatternAsPreset: YES delegate: self]; } - (IBAction) patternPresetsMenuItemSelected_EditPresets: (id) sender { [PPDocumentEditPatternPresetsSheetController beginEditPatternPresetsSheetForWindow: _sheet patternPresets: [PPBackgroundPatternPresets sharedPresets] patternTypeDisplayName: kBackgroundPatternTypeDisplayName currentPattern: [self backgroundPatternFromSheet] addCurrentPatternAsPreset: NO delegate: self]; } - (IBAction) patternPresetsMenuItemSelected_ExportPresetsToFile: (id) sender { NSSavePanel *savePanel = [NSSavePanel savePanel]; [savePanel setAllowedFileTypes: [[PPBackgroundPatternPresets sharedPresets] presetsFiletypes]]; [savePanel beginSheetForDirectory: nil file: kExportPresetsSaveFileName modalForWindow: _sheet modalDelegate: self didEndSelector: @selector(exportPresetsSavePanelDidEnd:returnCode:contextInfo:) contextInfo: nil]; } - (IBAction) patternPresetsMenuItemSelected_ImportPresetsFromFile: (id) sender { [[NSOpenPanel openPanel] beginSheetForDirectory: nil file: nil types: [[PPBackgroundPatternPresets sharedPresets] presetsFiletypes] modalForWindow: _sheet modalDelegate: self didEndSelector: @selector(importPresetsOpenPanelDidEnd:returnCode: contextInfo:) contextInfo: nil]; } - (IBAction) patternPresetsMenuItemSelected_SavePatternAsDefault: (id) sender { [PPUserDefaults setBackgroundPattern: _backgroundPattern]; if ([_backgroundPattern isEqualToBackgroundPattern: [PPUserDefaults backgroundPattern]]) { [_patternPresetsPopUpButton selectItemAtIndex: _indexOfPatternPresetsMenuItem_DefaultPattern]; } } - (IBAction) patternPresetsMenuItemSelected_RestoreOriginalDefault: (id) sender { [PPUserDefaults setBackgroundPattern: kUserDefaultsInitialValue_BackgroundPattern]; [self setBackgroundPattern: [PPUserDefaults backgroundPattern] andSetupSheet: YES]; [_patternPresetsPopUpButton selectItemAtIndex: _indexOfPatternPresetsMenuItem_DefaultPattern]; } - (IBAction) backgroundImageViewUpdated: (id) sender { [self updateEnabledStatesOfBackgroundImageControls]; [self notifyDelegateDidUpdateImage]; } - (IBAction) showImageCheckboxClicked: (id) sender { [self updateEnabledStatesOfBackgroundImageControls]; [self notifyDelegateDidUpdateImageVisibility]; } - (IBAction) imageSmoothingCheckboxClicked: (id) sender { [self notifyDelegateDidUpdateImageSmoothing]; } - (IBAction) setImageToFileButtonPressed: (id) sender { [[NSOpenPanel openPanel] beginSheetForDirectory: nil file: nil types: [NSImage imageFileTypes] modalForWindow: _sheet modalDelegate: self didEndSelector: @selector(backgroundImageOpenPanelDidEnd: returnCode:contextInfo:) contextInfo: nil]; } - (IBAction) setImageToPasteboardButtonPressed: (id) sender { NSBitmapImageRep *imageBitmap; NSImage *image; if (![NSPasteboard ppGetImageBitmap: &imageBitmap]) { goto ERROR; } image = [NSImage ppImageWithBitmap: imageBitmap]; if (!image) goto ERROR; [self setBackgroundImage: image]; return; ERROR: return; } - (IBAction) copyImageToPasteboardButtonPressed: (id) sender { NSImage *backgroundImage = [_backgroundImageView image]; if (!backgroundImage) return; [NSPasteboard ppSetImageBitmap: [backgroundImage ppBitmap]]; } - (IBAction) removeImageButtonPressed: (id) sender { [self setBackgroundImage: nil]; } #pragma mark PPDocumentSheetController overrides - (void) endSheet { if ([_patternColor1Well isActive]) { [_patternColor1Well deactivate]; } if ([_patternColor2Well isActive]) { [_patternColor2Well deactivate]; } [super endSheet]; } #pragma mark PPDocumentSheetController overrides (delegate notifiers) - (void) notifyDelegateSheetDidFinish { if ([_delegate respondsToSelector: @selector(backgroundSettingsSheetDidFinishWithBackgroundPattern: backgroundImage:shouldDisplayImage: shouldSmoothenImage:)]) { [_delegate backgroundSettingsSheetDidFinishWithBackgroundPattern: _backgroundPattern backgroundImage: [_backgroundImageView image] shouldDisplayImage: ([_showImageCheckbox intValue]) ? YES : NO shouldSmoothenImage: ([_imageSmoothingCheckbox intValue]) ? YES : NO]; } } - (void) notifyDelegateSheetDidCancel { if ([_delegate respondsToSelector: @selector(backgroundSettingsSheetDidCancel)]) { [_delegate backgroundSettingsSheetDidCancel]; } } #pragma mark NSSavePanel delegate (export presets) - (void) exportPresetsSavePanelDidEnd: (NSSavePanel *) panel returnCode: (int) returnCode contextInfo: (void *) contextInfo { [panel orderOut: self]; if (returnCode == NSOKButton) { NSURL *presetsFileURL = [panel URL]; if ([presetsFileURL isFileURL]) { [[PPBackgroundPatternPresets sharedPresets] savePatternsToPresetsFile: [presetsFileURL path]]; } } [self setupMenuForPatternPresetsPopUpButton]; } #pragma mark NSOpenPanel delegate (import presets) - (void) importPresetsOpenPanelDidEnd: (NSOpenPanel *) panel returnCode: (int) returnCode contextInfo: (void *) contextInfo { [panel orderOut: self]; if (returnCode == NSOKButton) { NSURL *presetsFileURL = [[panel URLs] objectAtIndex: 0]; if ([presetsFileURL isFileURL]) { [[PPBackgroundPatternPresets sharedPresets] addPatternsFromPresetsFile: [presetsFileURL path]]; } } [self setupMenuForPatternPresetsPopUpButton]; } #pragma mark NSOpenPanel delegate (background image) - (void) backgroundImageOpenPanelDidEnd: (NSOpenPanel *) panel returnCode: (int) returnCode contextInfo: (void *) contextInfo { [panel orderOut: self]; if (returnCode == NSOKButton) { NSURL *imageURL; NSImage *image = nil; imageURL = [[panel URLs] objectAtIndex: 0]; if (imageURL) { image = [[[NSImage alloc] initWithContentsOfURL: imageURL] autorelease]; } [self setBackgroundImage: image]; } } #pragma mark PPDocumentEditPatternPresetsSheetController delegate methods - (void) editPatternPresetsSheetDidFinish { [self setupMenuForPatternPresetsPopUpButton]; } - (void) editPatternPresetsSheetDidCancel { [self setupMenuForPatternPresetsPopUpButton]; } #pragma mark PPBackgroundPatternPresets notifications - (void) addAsObserverForPPBackgroundPatternPresetsNotifications { PPBackgroundPatternPresets *backgroundPatternPresets = [PPBackgroundPatternPresets sharedPresets]; if (!backgroundPatternPresets) goto ERROR; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPBackgroundPatternPresetsNotification_UpdatedPresets:) name: PPPatternPresetsNotification_UpdatedPresets object: backgroundPatternPresets]; return; ERROR: return; } - (void) removeAsObserverForPPBackgroundPatternPresetsNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPPatternPresetsNotification_UpdatedPresets object: nil]; } - (void) handlePPBackgroundPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification { [self setupMenuForPatternPresetsPopUpButton]; } #pragma mark Private methods - (void) setupMenuForPatternPresetsPopUpButton { NSMenu *popUpButtonMenu; int insertionIndex, indexOfItemToSelect, numPresetPatterns, presetIndex; NSArray *presetPatterns; PPBackgroundPattern *presetPattern; NSString *presetTitle; NSMenuItem *presetItem; bool needToInsertMenuSeparator = NO; popUpButtonMenu = [[_defaultPatternPresetsMenu copy] autorelease]; presetPatterns = [[PPBackgroundPatternPresets sharedPresets] patterns]; numPresetPatterns = [presetPatterns count]; if (!numPresetPatterns) { // use PPSDKNativeType_NSMenuItemPtr for exportPresetsItem, as -[NSMenu itemWithTag:] // could return either (NSMenuItem *) or (id ), depending on the SDK PPSDKNativeType_NSMenuItemPtr exportPresetsItem = [popUpButtonMenu itemWithTag: kPatternPresetsMenuItemTag_ExportPresets]; [popUpButtonMenu removeItem: exportPresetsItem]; } insertionIndex = _indexOfPatternPresetsMenuItem_FirstPatternPreset = [popUpButtonMenu indexOfItemWithTag: kPatternPresetsMenuItemTag_PatternPresetsInsertionPoint]; indexOfItemToSelect = -1; for (presetIndex=0; presetIndex. */ #import "PPDocumentSheetController.h" @interface PPDocumentEditImageSizePresetsSheetController : PPDocumentSheetController { IBOutlet NSTableView *_presetsTable; IBOutlet NSTextField *_widthTextField; IBOutlet NSTextField *_heightTextField; NSMutableArray *_presetNameAndSizeStrings; NSMutableArray *_presetNameOnlyStrings; int _widthTextFieldValue; int _heightTextFieldValue; } + (bool) beginEditImageSizePresetsSheetForWindow: (NSWindow *) window delegate: (id) delegate; - (IBAction) addPresetButtonPressed: (id) sender; - (IBAction) deletePresetButtonPressed: (id) sender; - (IBAction) defaultListButtonPressed: (id) sender; @end @interface NSObject (PPDocumentEditImageSizePresetsSheetController) - (void) editImageSizePresetsSheetDidFinish; - (void) editImageSizePresetsSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentEditImageSizePresetsSheetController.m0000644000076500000240000004137113234403205027362 0ustar joshstaff/* PPDocumentEditImageSizePresetsSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentEditImageSizePresetsSheetController.h" #import "PPImageSizePresets.h" #import "NSTextField_PPUtilities.h" #import "PPDefines.h" #define kDocumentEditImageSizePresetsSheetNibName @"DocumentEditSizePresetsSheet" #define kSizePresetsTableDraggedDataType @"SizePresetsTableDraggedDataType" #define kNewPresetName @"New Preset" #define kNewPresetSize NSMakeSize(64, 64) @interface PPDocumentEditImageSizePresetsSheetController (PrivateMethods) - initWithDelegate: (id) delegate; - (void) addAsObserverForPPImageSizePresetsNotifications; - (void) removeAsObserverForPPImageSizePresetsNotifications; - (void) handlePPImageSizePresetsNotification_UpdatedPresets: (NSNotification *) notification; - (bool) setupPresetStringArraysWithPresetStrings: (NSArray *) presetStrings; - (void) destroyPresetStringArrays; - (void) selectPresetsTableRow: (unsigned) row; - (void) updateSizeFieldsForCurrentPresetsTableSelection; - (void) savePresetsTableEditing; - (void) updateSheetForChangedPresets; - (void) addNewPreset; - (void) deleteCurrentPreset; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPDocumentEditImageSizePresetsSheetController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPDocumentEditImageSizePresetsSheetController + (bool) beginEditImageSizePresetsSheetForWindow: (NSWindow *) window delegate: (id) delegate { PPDocumentEditImageSizePresetsSheetController *controller; controller = [[[self alloc] initWithDelegate: delegate] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - initWithDelegate: (id) delegate { self = [super initWithNibNamed: kDocumentEditImageSizePresetsSheetNibName delegate: delegate]; if (!self) goto ERROR; if (![self setupPresetStringArraysWithPresetStrings: [PPImageSizePresets presetStrings]]) { goto ERROR; } [_presetsTable setDataSource: self]; [_presetsTable setDelegate: self]; [_presetsTable registerForDraggedTypes: [NSArray arrayWithObject: kSizePresetsTableDraggedDataType]]; [_widthTextField setDelegate: self]; [_heightTextField setDelegate: self]; if ([_presetNameOnlyStrings count]) { [self selectPresetsTableRow: 0]; } else { [self addNewPreset]; } [self addAsObserverForPPImageSizePresetsNotifications]; return self; ERROR: [self release]; return nil; } - init { return [self initWithDelegate: nil]; } - (void) dealloc { [self removeAsObserverForPPImageSizePresetsNotifications]; [self destroyPresetStringArrays]; [super dealloc]; } #pragma mark Actions - (IBAction) addPresetButtonPressed: (id) sender { [self addNewPreset]; } - (IBAction) deletePresetButtonPressed: (id) sender { [self deleteCurrentPreset]; } - (IBAction) defaultListButtonPressed: (id) sender { [self setupPresetStringArraysWithPresetStrings: [PPImageSizePresets appDefaultPresetStrings]]; [self updateSheetForChangedPresets]; [self selectPresetsTableRow: 0]; } #pragma mark PPDocumentSheetController overrides (actions) - (IBAction) OKButtonPressed: (id) sender { [self removeAsObserverForPPImageSizePresetsNotifications]; [self savePresetsTableEditing]; [PPImageSizePresets setPresetStrings: _presetNameAndSizeStrings]; [super OKButtonPressed: sender]; } #pragma mark PPDocumentSheetController overrides (delegate notifiers) - (void) notifyDelegateSheetDidFinish { if ([_delegate respondsToSelector: @selector(editImageSizePresetsSheetDidFinish)]) { [_delegate editImageSizePresetsSheetDidFinish]; } } - (void) notifyDelegateSheetDidCancel { if ([_delegate respondsToSelector: @selector(editImageSizePresetsSheetDidCancel)]) { [_delegate editImageSizePresetsSheetDidCancel]; } } #pragma mark NSTableView data source (Presets table) - (NSInteger) numberOfRowsInTableView: (NSTableView *) aTableView { return [_presetNameOnlyStrings count]; } - (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row { if (tableView != _presetsTable) { return nil; } return [_presetNameOnlyStrings objectAtIndex: row]; } - (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row { NSString *nameOnlyString, *nameAndSizeString; if (tableView != _presetsTable) { return; } nameOnlyString = object; nameAndSizeString = PPImageSizePresets_PresetStringForNameAndSize(nameOnlyString, PPImageSizePresets_SizeForPresetString( [_presetNameAndSizeStrings objectAtIndex: row])); if (!nameAndSizeString) return; [_presetNameAndSizeStrings replaceObjectAtIndex: row withObject: nameAndSizeString]; [_presetNameOnlyStrings replaceObjectAtIndex: row withObject: nameOnlyString]; } - (BOOL) tableView: (NSTableView *) tableView writeRowsWithIndexes: (NSIndexSet *) rowIndexes toPasteboard: (NSPasteboard*) pasteboard { NSData *pasteboardData; pasteboardData = [NSKeyedArchiver archivedDataWithRootObject: rowIndexes]; [pasteboard declareTypes: [NSArray arrayWithObject: kSizePresetsTableDraggedDataType] owner: self]; [pasteboard setData: pasteboardData forType: kSizePresetsTableDraggedDataType]; return YES; } - (NSDragOperation) tableView: (NSTableView*) tableView validateDrop: (id ) info proposedRow: (NSInteger) newRow proposedDropOperation: (NSTableViewDropOperation) op { NSPasteboard *pasteboard; NSData *pasteboardData; NSIndexSet *rowIndexes; unsigned int selectedRow; pasteboard = [info draggingPasteboard]; pasteboardData = [pasteboard dataForType: kSizePresetsTableDraggedDataType]; rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData: pasteboardData]; selectedRow = [rowIndexes firstIndex]; if ((op == NSTableViewDropAbove) && (selectedRow != newRow) && (selectedRow != (newRow-1))) { return NSDragOperationEvery; } else { return NSDragOperationNone; } } - (BOOL) tableView: (NSTableView *) aTableView acceptDrop: (id ) info row: (NSInteger) destinationTableRow dropOperation: (NSTableViewDropOperation) operation { NSPasteboard *pboard; NSData *rowData; NSIndexSet *rowIndexes; int sourceTableRow; NSString *nameOnlyString, *nameAndSizeString; pboard = [info draggingPasteboard]; rowData = [pboard dataForType: kSizePresetsTableDraggedDataType]; rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData: rowData]; sourceTableRow = [rowIndexes firstIndex]; if (destinationTableRow > sourceTableRow) { destinationTableRow--; } nameOnlyString = [[[_presetNameOnlyStrings objectAtIndex: sourceTableRow] retain] autorelease]; nameAndSizeString = [[[_presetNameAndSizeStrings objectAtIndex: sourceTableRow] retain] autorelease]; [_presetNameOnlyStrings removeObjectAtIndex: sourceTableRow]; [_presetNameAndSizeStrings removeObjectAtIndex: sourceTableRow]; [_presetNameOnlyStrings insertObject: nameOnlyString atIndex: destinationTableRow]; [_presetNameAndSizeStrings insertObject: nameAndSizeString atIndex: destinationTableRow]; [_presetsTable reloadData]; [self selectPresetsTableRow: destinationTableRow]; return YES; } - (void) tableViewSelectionDidChange: (NSNotification *) notification { if ([_presetsTable numberOfSelectedRows] > 1) { [self selectPresetsTableRow: [_presetsTable selectedRow]]; } else { [self updateSizeFieldsForCurrentPresetsTableSelection]; } } #pragma mark NSControl delegate methods (width/height textfields) - (void) controlTextDidChange: (NSNotification *) notification { id notifyingObject; int newFieldValue; bool needToUpdatePresetString = NO; notifyingObject = [notification object]; if (notifyingObject == _widthTextField) { newFieldValue = [_widthTextField ppClampIntValueToMax: kMaxCanvasDimension min: kMinCanvasDimension defaultValue: _widthTextFieldValue]; if (_widthTextFieldValue != newFieldValue) { _widthTextFieldValue = newFieldValue; needToUpdatePresetString = YES; } } else if (notifyingObject == _heightTextField) { newFieldValue = [_heightTextField ppClampIntValueToMax: kMaxCanvasDimension min: kMinCanvasDimension defaultValue: _heightTextFieldValue]; if (_heightTextFieldValue != newFieldValue) { _heightTextFieldValue = newFieldValue; needToUpdatePresetString = YES; } } if (needToUpdatePresetString) { int selectedPresetIndex; NSString *nameAndSizeString; selectedPresetIndex = [_presetsTable selectedRow]; nameAndSizeString = PPImageSizePresets_PresetStringForNameAndSize( [_presetNameOnlyStrings objectAtIndex: selectedPresetIndex], NSMakeSize(_widthTextFieldValue, _heightTextFieldValue)); if (nameAndSizeString) { [_presetNameAndSizeStrings replaceObjectAtIndex: selectedPresetIndex withObject: nameAndSizeString]; } } } #pragma mark PPImageSizePresets notifications - (void) addAsObserverForPPImageSizePresetsNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPImageSizePresetsNotification_UpdatedPresets:) name: PPImageSizePresetsNotification_UpdatedPresets object: nil]; } - (void) removeAsObserverForPPImageSizePresetsNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPImageSizePresetsNotification_UpdatedPresets object: nil]; } - (void) handlePPImageSizePresetsNotification_UpdatedPresets: (NSNotification *) notification { if ([_presetsTable editedRow] >= 0) { [_presetsTable abortEditing]; } [self setupPresetStringArraysWithPresetStrings: [PPImageSizePresets presetStrings]]; [self updateSheetForChangedPresets]; [self selectPresetsTableRow: 0]; } #pragma mark Private methods - (bool) setupPresetStringArraysWithPresetStrings: (NSArray *) presetStrings { [self destroyPresetStringArrays]; _presetNameAndSizeStrings = [[NSMutableArray array] retain]; _presetNameOnlyStrings = [[NSMutableArray array] retain]; if (!_presetNameAndSizeStrings || !_presetNameOnlyStrings) { goto ERROR; } if ([presetStrings count]) { NSEnumerator *presetsEnumerator; NSString *nameAndSizeString, *nameOnlyString; presetsEnumerator = [presetStrings objectEnumerator]; while (nameAndSizeString = [presetsEnumerator nextObject]) { nameOnlyString = PPImageSizePresets_NameForPresetString(nameAndSizeString); if (nameOnlyString) { [_presetNameAndSizeStrings addObject: nameAndSizeString]; [_presetNameOnlyStrings addObject: nameOnlyString]; } } } if (![_presetNameOnlyStrings count]) { [self addNewPreset]; } return YES; ERROR: [self destroyPresetStringArrays]; return NO; } - (void) destroyPresetStringArrays { [_presetNameAndSizeStrings release]; _presetNameAndSizeStrings = nil; [_presetNameOnlyStrings release]; _presetNameOnlyStrings = nil; } - (void) selectPresetsTableRow: (unsigned) row { if (row < [_presetNameOnlyStrings count]) { [_presetsTable selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO]; } else { [_presetsTable deselectAll: self]; } [self updateSizeFieldsForCurrentPresetsTableSelection]; } - (void) updateSizeFieldsForCurrentPresetsTableSelection { int currentSelectionIndex; NSSize currentPresetSize = NSZeroSize; currentSelectionIndex = [_presetsTable selectedRow]; if ((currentSelectionIndex >= 0) && (currentSelectionIndex < [_presetNameAndSizeStrings count])) { currentPresetSize = PPImageSizePresets_SizeForPresetString( [_presetNameAndSizeStrings objectAtIndex: currentSelectionIndex]); } _widthTextFieldValue = currentPresetSize.width; [_widthTextField setIntValue: _widthTextFieldValue]; _heightTextFieldValue = currentPresetSize.height; [_heightTextField setIntValue: _heightTextFieldValue]; [_widthTextField selectText: self]; } - (void) savePresetsTableEditing { int editedRow; NSString *nameOnlyString, *nameAndSizeString; editedRow = [_presetsTable editedRow]; if ((editedRow < 0) || (editedRow >= [_presetNameOnlyStrings count])) { return; } nameOnlyString = [[_presetsTable currentEditor] string]; nameAndSizeString = PPImageSizePresets_PresetStringForNameAndSize( nameOnlyString, PPImageSizePresets_SizeForPresetString( [_presetNameAndSizeStrings objectAtIndex: editedRow])); if (!nameAndSizeString) return; [_presetNameAndSizeStrings replaceObjectAtIndex: editedRow withObject: nameAndSizeString]; [_presetNameOnlyStrings replaceObjectAtIndex: editedRow withObject: nameOnlyString]; } - (void) updateSheetForChangedPresets { [_presetsTable reloadData]; [self updateSizeFieldsForCurrentPresetsTableSelection]; } - (void) addNewPreset { NSString *nameOnlyString, *nameAndSizeString; int insertionIndex; nameOnlyString = kNewPresetName; nameAndSizeString = PPImageSizePresets_PresetStringForNameAndSize(nameOnlyString, kNewPresetSize); if (!nameOnlyString || !nameAndSizeString) { return; } insertionIndex = [_presetsTable selectedRow]; if (insertionIndex < 0) { insertionIndex = 0; } [_presetNameAndSizeStrings insertObject: nameAndSizeString atIndex: insertionIndex]; [_presetNameOnlyStrings insertObject: nameOnlyString atIndex: insertionIndex]; [self updateSheetForChangedPresets]; [_presetsTable editColumn: 0 row: insertionIndex withEvent: nil select: YES]; } - (void) deleteCurrentPreset { int deletionIndex, numPresets; deletionIndex = [_presetsTable selectedRow]; if (deletionIndex < 0) { return; } if ([_presetsTable editedRow] >= 0) { [_presetsTable abortEditing]; } [_presetNameAndSizeStrings removeObjectAtIndex: deletionIndex]; [_presetNameOnlyStrings removeObjectAtIndex: deletionIndex]; [self updateSheetForChangedPresets]; numPresets = [_presetNameOnlyStrings count]; if (!numPresets) { [self addNewPreset]; } else if (deletionIndex >= numPresets) { [self selectPresetsTableRow: numPresets-1]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentEditPatternPresetsSheetController.h0000644000076500000240000000452113234403416027115 0ustar joshstaff/* PPDocumentEditPatternPresetsSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" #import "PPPresettablePatternProtocol.h" @class PPPresettablePatternView, PPPatternPresets; @interface PPDocumentEditPatternPresetsSheetController : PPDocumentSheetController { IBOutlet NSTextField *_sheetTitleField; IBOutlet NSTableView *_editablePatternsTable; IBOutlet PPPresettablePatternView *_patternView; IBOutlet NSButton *_removePresetButton; IBOutlet NSButton *_removeAllPresetsButton; PPPatternPresets *_patternPresets; NSMutableArray *_editablePatterns; id _currentPattern; NSString *_editablePatternsTableDraggedDataType; } + (bool) beginEditPatternPresetsSheetForWindow: (NSWindow *) window patternPresets: (PPPatternPresets *) patternPresets patternTypeDisplayName: (NSString *) patternTypeDisplayName currentPattern: (id ) currentPattern addCurrentPatternAsPreset: (bool) addCurrentPatternAsPreset delegate: (id) delegate; - (IBAction) addCurrentPatternAsPresetButtonPressed: (id) sender; - (IBAction) removePresetButtonPressed: (id) sender; - (IBAction) removeAllPresetsButtonPressed: (id) sender; @end @interface NSObject (PPDocumentEditPatternPresetsSheetController) - (void) editPatternPresetsSheetDidFinish; - (void) editPatternPresetsSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentEditPatternPresetsSheetController.m0000644000076500000240000003726313234403205027127 0ustar joshstaff/* PPDocumentEditPatternPresetsSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentEditPatternPresetsSheetController.h" #import "PPPresettablePatternView.h" #import "PPPatternPresets.h" #import "NSMutableArray_PPUtilities.h" #define kDocumentEditPatternPresetsSheetNibName @"DocumentEditPatternPresetsSheet" #define kPresetsTableDraggedDataTypeFormatString @"EditPresetsTableDraggedDataType_%@" #define kSheetTitleFormatString @"Edit %@ Pattern Presets" #define kNewPresetName @"Untitled Preset" #define kEmptyPatternDisplayColor [NSColor lightGrayColor] @interface PPDocumentEditPatternPresetsSheetController (PrivateMethods) - initWithPatternPresets: (PPPatternPresets *) patternPresets patternTypeDisplayName: (NSString *) patternTypeDisplayName currentPattern: (id ) currentPattern delegate: (id) delegate; - (void) addAsObserverForPPPatternPresetsNotifications; - (void) removeAsObserverForPPPatternPresetsNotifications; - (void) handlePPPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification; - (void) loadEditablePatternsFromPresets; - (void) selectPatternsTableRow: (unsigned) row; - (void) updatePatternViewForCurrentPatternsTableSelection; - (void) savePatternsTableEditing; - (void) updateRemoveButtonsEnabledStates; - (void) setupSheetStateWithEditablePatterns; - (int) indexOfEditablePattern: (id ) pattern; - (void) addCurrentPatternToEditablePatterns; - (void) removeSelectedPatternFromEditablePatterns; - (void) removeAllEditablePatterns; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPDocumentEditPatternPresetsSheetController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPDocumentEditPatternPresetsSheetController + (bool) beginEditPatternPresetsSheetForWindow: (NSWindow *) window patternPresets: (PPPatternPresets *) patternPresets patternTypeDisplayName: (NSString *) patternTypeDisplayName currentPattern: (id ) currentPattern addCurrentPatternAsPreset: (bool) addCurrentPatternAsPreset delegate: (id) delegate { PPDocumentEditPatternPresetsSheetController *controller; controller = [[[self alloc] initWithPatternPresets: patternPresets patternTypeDisplayName: patternTypeDisplayName currentPattern: currentPattern delegate: delegate] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } if (addCurrentPatternAsPreset) { [controller addCurrentPatternToEditablePatterns]; } return YES; ERROR: return NO; } - initWithPatternPresets: (PPPatternPresets *) patternPresets patternTypeDisplayName: (NSString *) patternTypeDisplayName currentPattern: (id ) currentPattern delegate: (id) delegate { self = [super initWithNibNamed: kDocumentEditPatternPresetsSheetNibName delegate: delegate]; if (!self) goto ERROR; if (!patternPresets || ![patternTypeDisplayName length] || ![currentPattern conformsToProtocol: @protocol(PPPresettablePattern)]) { goto ERROR; } _patternPresets = [patternPresets retain]; _editablePatterns = [[NSMutableArray array] retain]; _currentPattern = [currentPattern copyWithZone: NULL]; _editablePatternsTableDraggedDataType = [[NSString stringWithFormat: kPresetsTableDraggedDataTypeFormatString, patternTypeDisplayName] retain]; if (!_patternPresets || !_editablePatterns || !_currentPattern || !_editablePatternsTableDraggedDataType) { goto ERROR; } [self loadEditablePatternsFromPresets]; [_currentPattern setPresetName: kNewPresetName]; [_sheetTitleField setStringValue: [NSString stringWithFormat: kSheetTitleFormatString, patternTypeDisplayName]]; [_editablePatternsTable setDataSource: self]; [_editablePatternsTable setDelegate: self]; [_editablePatternsTable registerForDraggedTypes: [NSArray arrayWithObject: _editablePatternsTableDraggedDataType]]; [self selectPatternsTableRow: 0]; [self setupSheetStateWithEditablePatterns]; [self addAsObserverForPPPatternPresetsNotifications]; return self; ERROR: [self release]; return nil; } - init { return [self initWithPatternPresets: nil patternTypeDisplayName: nil currentPattern: nil delegate: nil]; } - (void) dealloc { [self removeAsObserverForPPPatternPresetsNotifications]; [_patternPresets release]; [_editablePatterns release]; [_currentPattern release]; [_editablePatternsTableDraggedDataType release]; [super dealloc]; } #pragma mark Actions - (IBAction) addCurrentPatternAsPresetButtonPressed: (id) sender { [self addCurrentPatternToEditablePatterns]; } - (IBAction) removePresetButtonPressed: (id) sender { [self removeSelectedPatternFromEditablePatterns]; } - (IBAction) removeAllPresetsButtonPressed: (id) sender { [self removeAllEditablePatterns]; } #pragma mark PPDocumentSheetController overrides (actions) - (IBAction) OKButtonPressed: (id) sender { [self removeAsObserverForPPPatternPresetsNotifications]; [self savePatternsTableEditing]; [_patternPresets setPatterns: _editablePatterns]; [super OKButtonPressed: sender]; } #pragma mark PPDocumentSheetController overrides (delegate notifiers) - (void) notifyDelegateSheetDidFinish { if ([_delegate respondsToSelector: @selector(editPatternPresetsSheetDidFinish)]) { [_delegate editPatternPresetsSheetDidFinish]; } } - (void) notifyDelegateSheetDidCancel { if ([_delegate respondsToSelector: @selector(editPatternPresetsSheetDidCancel)]) { [_delegate editPatternPresetsSheetDidCancel]; } } #pragma mark NSTableView data source (Presets table) - (NSInteger) numberOfRowsInTableView: (NSTableView *) aTableView { return [_editablePatterns count]; } - (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row { id pattern = [_editablePatterns objectAtIndex: row]; return [pattern presetName]; } - (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row { id pattern = [_editablePatterns objectAtIndex: row]; [pattern setPresetName: object]; } - (BOOL) tableView: (NSTableView *) tableView writeRowsWithIndexes: (NSIndexSet *) rowIndexes toPasteboard: (NSPasteboard*) pasteboard { NSData *pasteboardData; pasteboardData = [NSKeyedArchiver archivedDataWithRootObject: rowIndexes]; [pasteboard declareTypes: [NSArray arrayWithObject: _editablePatternsTableDraggedDataType] owner: self]; [pasteboard setData: pasteboardData forType: _editablePatternsTableDraggedDataType]; return YES; } - (NSDragOperation) tableView: (NSTableView*) tableView validateDrop: (id ) info proposedRow: (NSInteger) newRow proposedDropOperation: (NSTableViewDropOperation) op { NSPasteboard *pasteboard; NSData *pasteboardData; NSIndexSet *rowIndexes; unsigned int selectedRow; pasteboard = [info draggingPasteboard]; pasteboardData = [pasteboard dataForType: _editablePatternsTableDraggedDataType]; rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData: pasteboardData]; selectedRow = [rowIndexes firstIndex]; if ((op == NSTableViewDropAbove) && (selectedRow != newRow) && (selectedRow != (newRow-1))) { return NSDragOperationEvery; } else { return NSDragOperationNone; } } - (BOOL) tableView: (NSTableView *) aTableView acceptDrop: (id ) info row: (NSInteger) destinationTableRow dropOperation: (NSTableViewDropOperation) operation { NSPasteboard *pboard; NSData *rowData; NSIndexSet *rowIndexes; int sourceTableRow; id pattern; pboard = [info draggingPasteboard]; rowData = [pboard dataForType: _editablePatternsTableDraggedDataType]; rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData: rowData]; sourceTableRow = [rowIndexes firstIndex]; if (destinationTableRow > sourceTableRow) { destinationTableRow--; } pattern = [[[_editablePatterns objectAtIndex: sourceTableRow] retain] autorelease]; [_editablePatterns removeObjectAtIndex: sourceTableRow]; [_editablePatterns insertObject: pattern atIndex: destinationTableRow]; [_editablePatternsTable reloadData]; [self selectPatternsTableRow: destinationTableRow]; return YES; } - (void) tableViewSelectionDidChange: (NSNotification *) notification { if ([_editablePatternsTable numberOfSelectedRows] > 1) { [self selectPatternsTableRow: [_editablePatternsTable selectedRow]]; } else { [self updatePatternViewForCurrentPatternsTableSelection]; } } #pragma mark PPPatternPresets notifications - (void) addAsObserverForPPPatternPresetsNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPPatternPresetsNotification_UpdatedPresets:) name: PPPatternPresetsNotification_UpdatedPresets object: _patternPresets]; } - (void) removeAsObserverForPPPatternPresetsNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPPatternPresetsNotification_UpdatedPresets object: _patternPresets]; } - (void) handlePPPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification { if ([_editablePatternsTable editedRow] >= 0) { [_editablePatternsTable abortEditing]; } [self loadEditablePatternsFromPresets]; [self setupSheetStateWithEditablePatterns]; [self selectPatternsTableRow: 0]; } #pragma mark Private methods - (void) loadEditablePatternsFromPresets { [_editablePatterns removeAllObjects]; // edit copies of pattern preset objects, not originals [_editablePatterns ppAddCopiesOfObjectsFromArray: [_patternPresets patterns]]; } - (void) selectPatternsTableRow: (unsigned) row { if (row < [_editablePatterns count]) { [_editablePatternsTable selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO]; } else { [_editablePatternsTable deselectAll: self]; } [self updatePatternViewForCurrentPatternsTableSelection]; } - (void) updatePatternViewForCurrentPatternsTableSelection { int currentSelectionIndex; id pattern = nil; currentSelectionIndex = [_editablePatternsTable selectedRow]; if ((currentSelectionIndex >= 0) && (currentSelectionIndex < [_editablePatterns count])) { pattern = [_editablePatterns objectAtIndex: currentSelectionIndex]; } [_patternView setPresettablePattern: pattern]; } - (void) savePatternsTableEditing { int editedRow; id pattern; editedRow = [_editablePatternsTable editedRow]; if ((editedRow < 0) || (editedRow >= [_editablePatterns count])) { return; } pattern = [_editablePatterns objectAtIndex: editedRow]; [pattern setPresetName: [[_editablePatternsTable currentEditor] string]]; } - (void) updateRemoveButtonsEnabledStates { bool shouldEnableRemoveButtons = ([_editablePatterns count] > 0) ? YES : NO; [_removePresetButton setEnabled: shouldEnableRemoveButtons]; [_removeAllPresetsButton setEnabled: shouldEnableRemoveButtons]; } - (void) setupSheetStateWithEditablePatterns { [_editablePatternsTable reloadData]; [self updatePatternViewForCurrentPatternsTableSelection]; [self updateRemoveButtonsEnabledStates]; } - (int) indexOfEditablePattern: (id ) pattern { int index; if (!pattern) { return -1; } for (index=[_editablePatterns count]-1; index>=0; index--) { if ([pattern isEqualToPresettablePattern: [_editablePatterns objectAtIndex: index]]) { return index; } } return -1; } - (void) addCurrentPatternToEditablePatterns { int editingIndex, existingIndex, insertionIndex; if (!_currentPattern) return; editingIndex = [_editablePatternsTable editedRow]; existingIndex = [self indexOfEditablePattern: _currentPattern]; if (editingIndex >= 0) { if (editingIndex == existingIndex) { return; } else { [_editablePatternsTable abortEditing]; } } if (existingIndex >= 0) { [self selectPatternsTableRow: existingIndex]; return; } insertionIndex = [_editablePatternsTable selectedRow]; if (insertionIndex < 0) { insertionIndex = 0; } [_editablePatterns insertObject: _currentPattern atIndex: insertionIndex]; [self setupSheetStateWithEditablePatterns]; [_editablePatternsTable editColumn: 0 row: insertionIndex withEvent: nil select: YES]; } - (void) removeSelectedPatternFromEditablePatterns { int deletionIndex, numPresets; deletionIndex = [_editablePatternsTable selectedRow]; if (deletionIndex < 0) { return; } if ([_editablePatternsTable editedRow] >= 0) { [_editablePatternsTable abortEditing]; } [_editablePatterns removeObjectAtIndex: deletionIndex]; [self setupSheetStateWithEditablePatterns]; numPresets = [_editablePatterns count]; if (deletionIndex >= numPresets) { [self selectPatternsTableRow: numPresets-1]; } } - (void) removeAllEditablePatterns { if ([_editablePatternsTable editedRow] >= 0) { [_editablePatternsTable abortEditing]; } [_editablePatterns removeAllObjects]; [self setupSheetStateWithEditablePatterns]; [self selectPatternsTableRow: -1]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentFlattenedSaveNoticeSheetController.h0000644000076500000240000000237113234403416027214 0ustar joshstaff/* PPDocumentFlattenedSaveNoticeSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" @interface PPDocumentFlattenedSaveNoticeSheetController : PPDocumentSheetController { IBOutlet NSButton *_dontShowAgainCheckbox; } + (bool) beginFlattenedSaveNoticeSheetForDocumentWindow: (NSWindow *) window; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentFlattenedSaveNoticeSheetController.m0000644000076500000240000000417213234403205027216 0ustar joshstaff/* PPDocumentFlattenedSaveNoticeSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentFlattenedSaveNoticeSheetController.h" #import "PPUserDefaults.h" #define kDocumentFlattenedSaveNoticeSheetNibName @"DocumentFlattenedSaveNoticeSheet" @implementation PPDocumentFlattenedSaveNoticeSheetController + (bool) beginFlattenedSaveNoticeSheetForDocumentWindow: (NSWindow *) window { PPDocumentFlattenedSaveNoticeSheetController *controller; if (![PPUserDefaults shouldDisplayFlattenedSaveNotice]) { return NO; } controller = [[[self alloc] init] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - init { self = [super initWithNibNamed: kDocumentFlattenedSaveNoticeSheetNibName delegate: self]; if (!self) goto ERROR; return self; ERROR: [self release]; return nil; } #pragma mark PPDocumentSheetController overrides (actions) - (IBAction) OKButtonPressed: (id) sender { [super OKButtonPressed: sender]; if ([_dontShowAgainCheckbox intValue]) { [PPUserDefaults setShouldDisplayFlattenedSaveNotice: NO]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentGridSettingsSheetController.h0000644000076500000240000000624213234403416025734 0ustar joshstaff/* PPDocumentGridSettingsSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" @class PPGridPattern; @interface PPDocumentGridSettingsSheetController : PPDocumentSheetController { IBOutlet NSButton *_showGridCheckbox; IBOutlet NSSegmentedControl *_gridTypeSegmentedControl; IBOutlet NSColorWell *_gridColorWell; IBOutlet NSButton *_showGuidelinesCheckbox; IBOutlet NSTextField *_guidelinesHorizontalSpacingTextField; IBOutlet NSTextField *_guidelinesVerticalSpacingTextField; IBOutlet NSColorWell *_guidelinesColorWell; IBOutlet NSMenu *_defaultPresetsMenu; IBOutlet NSPopUpButton *_presetsPopUpButton; PPGridPattern *_gridPattern; PPGridPattern *_lastCustomGridPattern; int _indexOfPresetsMenuItem_DefaultPattern; int _indexOfPresetsMenuItem_CustomPattern; int _indexOfPresetsMenuItem_FirstPatternPreset; bool _gridVisibility; } + (bool) beginGridSettingsSheetForDocumentWindow: (NSWindow *) window gridPattern: (PPGridPattern *) gridPattern gridVisibility: (bool) shouldDisplayGrid delegate: (id) delegate; - (IBAction) showGridCheckboxClicked: (id) sender; - (IBAction) gridSettingChanged: (id) sender; - (IBAction) presetsMenuItemSelected_DefaultPattern: (id) sender; - (IBAction) presetsMenuItemSelected_CustomPattern: (id) sender; - (IBAction) presetsMenuItemSelected_PresetPattern: (id) sender; - (IBAction) presetsMenuItemSelected_AddCurrentPatternToPresets: (id) sender; - (IBAction) presetsMenuItemSelected_EditPresets: (id) sender; - (IBAction) presetsMenuItemSelected_ExportPresetsToFile: (id) sender; - (IBAction) presetsMenuItemSelected_ImportPresetsFromFile: (id) sender; - (IBAction) presetsMenuItemSelected_SavePatternAsDefault: (id) sender; - (IBAction) presetsMenuItemSelected_RestoreOriginalDefault: (id) sender; @end @interface NSObject (PPDocumentGridSettingsSheetDelegateMethods) - (void) gridSettingsSheetDidUpdateGridPattern: (PPGridPattern *) gridPattern andVisibility: (bool) shouldDisplayGrid; - (void) gridSettingsSheetDidFinishWithGridPattern: (PPGridPattern *) gridPattern andVisibility: (bool) shouldDisplayGrid; - (void) gridSettingsSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentGridSettingsSheetController.m0000644000076500000240000004454713234403205025747 0ustar joshstaff/* PPDocumentGridSettingsSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentGridSettingsSheetController.h" #import "PPDefines.h" #import "PPGridPattern.h" #import "PPGridPatternPresets.h" #import "PPUserDefaults.h" #import "PPDocumentEditPatternPresetsSheetController.h" #import "PPUserDefaultsInitialValues.h" #import "NSTextField_PPUtilities.h" #define kDocumentGridSettingsSheetNibName @"DocumentGridSettingsSheet" #define kExportPresetsSaveFileName @"PikoPixel grid patterns" #define kGridPatternTypeDisplayName @"Grid" #define kPresetsMenuItemTag_DefaultPattern 1 #define kPresetsMenuItemTag_CustomPattern 2 #define kPresetsMenuItemTag_PatternPresetsInsertionPoint 3 #define kPresetsMenuItemTag_ExportPresets 4 @interface PPDocumentGridSettingsSheetController (PrivateMethods) - initWithGridPattern: (PPGridPattern *) gridPattern gridVisibility: (bool) shouldDisplayGrid delegate: (id) delegate; - (void) addAsObserverForPPGridPatternPresetsNotifications; - (void) removeAsObserverForPPGridPatternPresetsNotifications; - (void) handlePPGridPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification; - (void) setupMenuForPresetsPopUpButton; - (void) setGridPattern: (PPGridPattern *) gridPattern andGridVisibility: (bool) shouldDisplayGrid; - (void) loadGridSettingsFromSheetState; - (void) setupSheetStateWithGridSettings; - (void) notifyDelegateDidUpdateGridSettings; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPDocumentGridSettingsSheetController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPDocumentGridSettingsSheetController + (bool) beginGridSettingsSheetForDocumentWindow: (NSWindow *) window gridPattern: (PPGridPattern *) gridPattern gridVisibility: (bool) shouldDisplayGrid delegate: (id) delegate; { PPDocumentGridSettingsSheetController *controller; controller = [[[self alloc] initWithGridPattern: gridPattern gridVisibility: shouldDisplayGrid delegate: delegate] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - initWithGridPattern: (PPGridPattern *) gridPattern gridVisibility: (bool) shouldDisplayGrid delegate: (id) delegate; { self = [super initWithNibNamed: kDocumentGridSettingsSheetNibName delegate: delegate]; if (!self) goto ERROR; if (!gridPattern) goto ERROR; _gridPattern = [gridPattern retain]; _gridVisibility = (shouldDisplayGrid) ? YES : NO; [self setupSheetStateWithGridSettings]; [self setupMenuForPresetsPopUpButton]; [self addAsObserverForPPGridPatternPresetsNotifications]; [_guidelinesHorizontalSpacingTextField setDelegate: self]; [_guidelinesVerticalSpacingTextField setDelegate: self]; return self; ERROR: [self release]; return nil; } - init { return [self initWithGridPattern: nil gridVisibility: NO delegate: nil]; } - (void) dealloc { [self removeAsObserverForPPGridPatternPresetsNotifications]; [_lastCustomGridPattern release]; [_gridPattern release]; [super dealloc]; } #pragma mark Actions - (IBAction) showGridCheckboxClicked: (id) sender { _gridVisibility = ([_showGridCheckbox intValue]) ? YES : NO; [self notifyDelegateDidUpdateGridSettings]; } - (IBAction) gridSettingChanged: (id) sender { [self loadGridSettingsFromSheetState]; if ([_presetsPopUpButton indexOfSelectedItem] != _indexOfPresetsMenuItem_CustomPattern) { [_presetsPopUpButton selectItemAtIndex: _indexOfPresetsMenuItem_CustomPattern]; } } - (IBAction) presetsMenuItemSelected_DefaultPattern: (id) sender { [self setGridPattern: [PPUserDefaults gridPattern] andGridVisibility: [PPUserDefaults gridVisibility]]; } - (IBAction) presetsMenuItemSelected_CustomPattern: (id) sender; { if (!_lastCustomGridPattern) return; [self setGridPattern: _lastCustomGridPattern andGridVisibility: _gridVisibility]; } - (IBAction) presetsMenuItemSelected_PresetPattern: (id) sender { int indexOfPattern; NSArray *presetPatterns; if (![sender isKindOfClass: [NSMenuItem class]]) { goto ERROR; } indexOfPattern = [((NSMenuItem *) sender) tag]; presetPatterns = [[PPGridPatternPresets sharedPresets] patterns]; if ((indexOfPattern < 0) || (indexOfPattern >= [presetPatterns count])) { goto ERROR; } [self setGridPattern: [presetPatterns objectAtIndex: indexOfPattern] andGridVisibility: _gridVisibility]; return; ERROR: return; } - (IBAction) presetsMenuItemSelected_AddCurrentPatternToPresets: (id) sender { [PPDocumentEditPatternPresetsSheetController beginEditPatternPresetsSheetForWindow: _sheet patternPresets: [PPGridPatternPresets sharedPresets] patternTypeDisplayName: kGridPatternTypeDisplayName currentPattern: _gridPattern addCurrentPatternAsPreset: YES delegate: self]; } - (IBAction) presetsMenuItemSelected_EditPresets: (id) sender { [PPDocumentEditPatternPresetsSheetController beginEditPatternPresetsSheetForWindow: _sheet patternPresets: [PPGridPatternPresets sharedPresets] patternTypeDisplayName: kGridPatternTypeDisplayName currentPattern: _gridPattern addCurrentPatternAsPreset: NO delegate: self]; } - (IBAction) presetsMenuItemSelected_ExportPresetsToFile: (id) sender { NSSavePanel *savePanel = [NSSavePanel savePanel]; [savePanel setAllowedFileTypes: [[PPGridPatternPresets sharedPresets] presetsFiletypes]]; [savePanel beginSheetForDirectory: nil file: kExportPresetsSaveFileName modalForWindow: _sheet modalDelegate: self didEndSelector: @selector(exportPresetsSavePanelDidEnd:returnCode:contextInfo:) contextInfo: nil]; } - (IBAction) presetsMenuItemSelected_ImportPresetsFromFile: (id) sender { [[NSOpenPanel openPanel] beginSheetForDirectory: nil file: nil types: [[PPGridPatternPresets sharedPresets] presetsFiletypes] modalForWindow: _sheet modalDelegate: self didEndSelector: @selector(importPresetsOpenPanelDidEnd: returnCode:contextInfo:) contextInfo: nil]; } - (IBAction) presetsMenuItemSelected_SavePatternAsDefault: (id) sender { [PPUserDefaults setGridPattern: _gridPattern andGridVisibility: _gridVisibility]; if ([_gridPattern isEqualToGridPattern: [PPUserDefaults gridPattern]]) { [_presetsPopUpButton selectItemAtIndex: _indexOfPresetsMenuItem_DefaultPattern]; } } - (IBAction) presetsMenuItemSelected_RestoreOriginalDefault: (id) sender { [PPUserDefaults setGridPattern: kUserDefaultsInitialValue_GridPattern andGridVisibility: kUserDefaultsInitialValue_GridVisibility]; [self setGridPattern: [PPUserDefaults gridPattern] andGridVisibility: [PPUserDefaults gridVisibility]]; [_presetsPopUpButton selectItemAtIndex: _indexOfPresetsMenuItem_DefaultPattern]; } #pragma mark PPDocumentSheetController overrides - (void) endSheet { if ([_gridColorWell isActive]) { [_gridColorWell deactivate]; } if ([_guidelinesColorWell isActive]) { [_guidelinesColorWell deactivate]; } [super endSheet]; } #pragma mark PPDocumentSheetController overrides (delegate notifiers) - (void) notifyDelegateSheetDidFinish { if ([_delegate respondsToSelector: @selector(gridSettingsSheetDidFinishWithGridPattern:andVisibility:)]) { [_delegate gridSettingsSheetDidFinishWithGridPattern: _gridPattern andVisibility: _gridVisibility]; } } - (void) notifyDelegateSheetDidCancel { if ([_delegate respondsToSelector: @selector(gridSettingsSheetDidCancel)]) { [_delegate gridSettingsSheetDidCancel]; } } #pragma mark NSTextField delegate methods (guidelines horizontal/vertical spacing textfields) - (void) controlTextDidChange: (NSNotification *) notification { NSTextField *textField; int oldSpacingValue, newSpacingValue; textField = [notification object]; if (textField == _guidelinesHorizontalSpacingTextField) { oldSpacingValue = [_gridPattern guidelineSpacingSize].width; } else if (textField == _guidelinesVerticalSpacingTextField) { oldSpacingValue = [_gridPattern guidelineSpacingSize].height; } else { goto ERROR; } newSpacingValue = [textField ppClampIntValueToMax: kMaxGridGuidelineSpacing min: kMinGridGuidelineSpacing defaultValue: oldSpacingValue]; if (newSpacingValue != oldSpacingValue) { [self gridSettingChanged: self]; } return; ERROR: return; } #pragma mark NSSavePanel delegate (export presets) - (void) exportPresetsSavePanelDidEnd: (NSSavePanel *) panel returnCode: (int) returnCode contextInfo: (void *) contextInfo { [panel orderOut: self]; if (returnCode == NSOKButton) { NSURL *presetsFileURL = [panel URL]; if ([presetsFileURL isFileURL]) { [[PPGridPatternPresets sharedPresets] savePatternsToPresetsFile: [presetsFileURL path]]; } } [self setupMenuForPresetsPopUpButton]; } #pragma mark NSOpenPanel delegate (import presets) - (void) importPresetsOpenPanelDidEnd: (NSOpenPanel *) panel returnCode: (int) returnCode contextInfo: (void *) contextInfo { [panel orderOut: self]; if (returnCode == NSOKButton) { NSURL *presetsFileURL = [[panel URLs] objectAtIndex: 0]; if ([presetsFileURL isFileURL]) { [[PPGridPatternPresets sharedPresets] addPatternsFromPresetsFile: [presetsFileURL path]]; } } [self setupMenuForPresetsPopUpButton]; } #pragma mark PPDocumentEditPatternPresetsSheetController delegate methods - (void) editPatternPresetsSheetDidFinish { [self setupMenuForPresetsPopUpButton]; } - (void) editPatternPresetsSheetDidCancel { [self setupMenuForPresetsPopUpButton]; } #pragma mark PPGridPatternPresets notifications - (void) addAsObserverForPPGridPatternPresetsNotifications { PPGridPatternPresets *gridPatternPresets = [PPGridPatternPresets sharedPresets]; if (!gridPatternPresets) goto ERROR; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPGridPatternPresetsNotification_UpdatedPresets:) name: PPPatternPresetsNotification_UpdatedPresets object: gridPatternPresets]; return; ERROR: return; } - (void) removeAsObserverForPPGridPatternPresetsNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPPatternPresetsNotification_UpdatedPresets object: nil]; } - (void) handlePPGridPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification { [self setupMenuForPresetsPopUpButton]; } #pragma mark Private methods - (void) setupMenuForPresetsPopUpButton { NSMenu *popUpButtonMenu; int insertionIndex, indexOfItemToSelect, numPresetPatterns, presetIndex; NSArray *presetPatterns; PPGridPattern *presetPattern; NSString *presetTitle; NSMenuItem *presetItem; bool needToInsertMenuSeparator = NO; popUpButtonMenu = [[_defaultPresetsMenu copy] autorelease]; presetPatterns = [[PPGridPatternPresets sharedPresets] patterns]; numPresetPatterns = [presetPatterns count]; if (!numPresetPatterns) { // use PPSDKNativeType_NSMenuItemPtr for exportPresetsItem, as -[NSMenu itemWithTag:] // could return either (NSMenuItem *) or (id ), depending on the SDK PPSDKNativeType_NSMenuItemPtr exportPresetsItem = [popUpButtonMenu itemWithTag: kPresetsMenuItemTag_ExportPresets]; [popUpButtonMenu removeItem: exportPresetsItem]; } insertionIndex = _indexOfPresetsMenuItem_FirstPatternPreset = [popUpButtonMenu indexOfItemWithTag: kPresetsMenuItemTag_PatternPresetsInsertionPoint]; indexOfItemToSelect = -1; for (presetIndex=0; presetIndex. */ #import @interface PPDocumentLayer : NSObject { id _delegate; NSString *_name; NSBitmapImageRep *_bitmap; NSImage *_image; NSSize _size; float _opacity; float _lastOpacity; NSBitmapImageRep *_linearBlendingBitmap; bool _isEnabled; } + layerWithSize: (NSSize) size andName: (NSString *) name; + layerWithSize: (NSSize) size name: (NSString *) name tiffData: (NSData *) tiffData; - initWithSize: (NSSize) size name: (NSString *) name tiffData: (NSData *) tiffData opacity: (float) opacity isEnabled: (bool) isEnabled; - (NSBitmapImageRep *) bitmap; - (NSImage *) image; - (void) handleUpdateToBitmapInRect: (NSRect) updateRect; - (bool) isEnabled; - (void) setEnabled: (bool) enabled; - (NSString *) name; - (void) setName: (NSString *) name; - (float) opacity; - (void) setOpacity: (float) opacity; - (void) setOpacityWithoutRegisteringUndo: (float) opacity; - (void) increaseOpacity; - (bool) canIncreaseOpacity; - (void) decreaseOpacity; - (bool) canDecreaseOpacity; - (NSSize) size; - (PPDocumentLayer *) layerResizedToSize: (NSSize) newSize shouldScale: (bool) shouldScale; - (PPDocumentLayer *) layerCroppedToBounds: (NSRect) croppingBounds; - (bool) enableLinearBlendingBitmap: (bool) enableLinearBlendingBitmap; - (NSBitmapImageRep *) linearBlendingBitmap; - (id) delegate; - (void) setDelegate: (id) delegate; @end @interface NSObject (PPDocumentLayerDelegateMethods) - (void) layer: (PPDocumentLayer *) layer changedNameFromOldValue: (NSString *) oldName; - (void) layer: (PPDocumentLayer *) layer changedEnabledFlagFromOldValue: (bool) oldEnabledFlag; - (void) layer: (PPDocumentLayer *) layer changedOpacityFromOldValue: (float) oldOpacity shouldRegisterUndo: (bool) shouldRegisterUndo; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentLayer.m0000644000076500000240000003160213234403205021344 0ustar joshstaff/* PPDocumentLayer.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentLayer.h" #import "NSImage_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" #import "PPDefines.h" #define kDrawingLayerCodingKey_Size @"Size" #define kDrawingLayerCodingKey_Name @"Name" #define kDrawingLayerCodingKey_TIFFData @"TIFFData" #define kDrawingLayerCodingKey_Opacity @"Opacity" #define kDrawingLayerCodingKey_IsEnabled @"IsEnabled" #define kOpacityStepSize 0.1f @interface PPDocumentLayer (PrivateMethods) - (void) setOpacity: (float) opacity andRegisterUndo: (bool) shouldRegisterUndo; - (void) notifyDelegateDidChangeNameFromOldValue: (NSString *) oldName; - (void) notifyDelegateDidChangeEnabledFlagFromOldValue: (bool) oldEnabledFlag; - (void) notifyDelegateDidChangeOpacityAndShouldRegisterUndo: (bool) shouldRegisterUndo; @end @implementation PPDocumentLayer + layerWithSize: (NSSize) size andName: (NSString *) name { return [[[self alloc] initWithSize: size name: name tiffData: nil opacity: 1.0f isEnabled: YES] autorelease]; } + layerWithSize: (NSSize) size name: (NSString *) name tiffData: (NSData *) tiffData { return [[[self alloc] initWithSize: size name: name tiffData: tiffData opacity: 1.0f isEnabled: YES] autorelease]; } - initWithSize: (NSSize) size name: (NSString *) name tiffData: (NSData *) tiffData opacity: (float) opacity isEnabled: (bool) isEnabled { self = [super init]; if (!self) goto ERROR; if (![name length]) { goto ERROR; } size = PPGeometry_SizeClippedToIntegerValues(size); if ((size.width < kMinCanvasDimension) || (size.width > kMaxCanvasDimension) || (size.height < kMinCanvasDimension) || (size.height > kMaxCanvasDimension)) { goto ERROR; } _size = size; _name = [name copy]; _bitmap = [[NSBitmapImageRep ppImageBitmapOfSize: size] retain]; _image = [[NSImage ppImageWithBitmap: _bitmap] retain]; if (!_name || !_bitmap || !_image) { goto ERROR; } if (tiffData) { [_bitmap ppCenteredCopyFromBitmap: [NSBitmapImageRep ppImageBitmapWithImportedData: tiffData]]; } if (opacity > 1.0f) { opacity = 1.0f; } else if (opacity < 0.0f) { opacity = 0.0f; } _opacity = _lastOpacity = opacity; _isEnabled = (isEnabled) ? YES : NO; return self; ERROR: [self release]; return nil; } - init { return [self initWithSize: NSZeroSize name: nil tiffData: nil opacity: 1.0f isEnabled: YES]; } - (void) dealloc { [_name release]; [_bitmap release]; [_image release]; [_linearBlendingBitmap release]; [super dealloc]; } - (NSBitmapImageRep *) bitmap { return _bitmap; } - (NSImage *) image { return _image; } // handleUpdateToBitmapInRect: method is a patch target on GNUstep // (PPGNUstepGlue_ImageRecacheSpeedups) - (void) handleUpdateToBitmapInRect: (NSRect) updateRect { [_image recache]; if (_linearBlendingBitmap) { [_linearBlendingBitmap ppLinearCopyFromImageBitmap: _bitmap inBounds: updateRect]; } } - (bool) isEnabled { return _isEnabled; } - (void) setEnabled: (bool) enabled { if (enabled == _isEnabled) { return; } _isEnabled = (enabled) ? YES : NO; [self notifyDelegateDidChangeEnabledFlagFromOldValue: enabled ? NO : YES]; } - (NSString *) name { return _name; } - (void) setName: (NSString *) name { NSString *oldName; name = [[name copy] autorelease]; if (!name) { name = @""; } if ((_name == name) || [_name isEqualToString: name]) { return; } oldName = [[_name retain] autorelease]; [_name release]; _name = [name retain]; [self notifyDelegateDidChangeNameFromOldValue: oldName]; } - (float) opacity { return _opacity; } - (void) setOpacity: (float) opacity { [self setOpacity: opacity andRegisterUndo: YES]; } - (void) setOpacityWithoutRegisteringUndo: (float) opacity { [self setOpacity: opacity andRegisterUndo: NO]; } - (void) increaseOpacity { if (![self canIncreaseOpacity]) { return; } [self setOpacity: _opacity + kOpacityStepSize]; } - (bool) canIncreaseOpacity { return (_opacity < 1.0f) ? YES : NO; } - (void) decreaseOpacity { if (![self canDecreaseOpacity]) { return; } [self setOpacity: _opacity - kOpacityStepSize]; } - (bool) canDecreaseOpacity { return (_opacity > 0.0f) ? YES : NO; } - (NSSize) size { return _size; } - (PPDocumentLayer *) layerResizedToSize: (NSSize) newSize shouldScale: (bool) shouldScale { NSBitmapImageRep *resizedBitmap; NSData *resizedBitmapData; PPDocumentLayer *resizedLayer; newSize = PPGeometry_SizeClippedToIntegerValues(newSize); resizedBitmap = [_bitmap ppBitmapResizedToSize: newSize shouldScale: shouldScale]; if (!resizedBitmap) goto ERROR; resizedBitmapData = [resizedBitmap TIFFRepresentation]; if (!resizedBitmapData) goto ERROR; resizedLayer = [[[PPDocumentLayer alloc] initWithSize: newSize name: _name tiffData: resizedBitmapData opacity: _opacity isEnabled: _isEnabled] autorelease]; return resizedLayer; ERROR: return nil; } - (PPDocumentLayer *) layerCroppedToBounds: (NSRect) croppingBounds { NSData *croppedBitmapTIFFData; PPDocumentLayer *croppedLayer; croppingBounds = NSIntersectionRect(PPGeometry_PixelBoundsCoveredByRect(croppingBounds), [_bitmap ppFrameInPixels]); if (NSIsEmptyRect(croppingBounds)) { goto ERROR; } croppedBitmapTIFFData = [_bitmap ppCompressedTIFFDataFromBounds: croppingBounds]; if (!croppedBitmapTIFFData) goto ERROR; croppedLayer = [[[PPDocumentLayer alloc] initWithSize: croppingBounds.size name: _name tiffData: croppedBitmapTIFFData opacity: _opacity isEnabled: _isEnabled] autorelease]; return croppedLayer; ERROR: return nil; } - (bool) enableLinearBlendingBitmap: (bool) enableLinearBlendingBitmap { if (enableLinearBlendingBitmap) { if (!_linearBlendingBitmap) { _linearBlendingBitmap = [[_bitmap ppLinearRGB16BitmapFromImageBitmap] retain]; } return (_linearBlendingBitmap) ? YES : NO; } else // (!enableLinearBlendingBitmap) { if (_linearBlendingBitmap) { [_linearBlendingBitmap release]; _linearBlendingBitmap = nil; } return YES; } } - (NSBitmapImageRep *) linearBlendingBitmap { return _linearBlendingBitmap; } - (id) delegate { return _delegate; } - (void) setDelegate: (id) delegate { _delegate = delegate; } #pragma mark NSCoding protocol - (id) initWithCoder: (NSCoder *) aDecoder { return [self initWithSize: [aDecoder decodeSizeForKey: kDrawingLayerCodingKey_Size] name: [aDecoder decodeObjectForKey: kDrawingLayerCodingKey_Name] tiffData: [aDecoder decodeObjectForKey: kDrawingLayerCodingKey_TIFFData] opacity: [aDecoder decodeFloatForKey: kDrawingLayerCodingKey_Opacity] isEnabled: [aDecoder decodeBoolForKey: kDrawingLayerCodingKey_IsEnabled]]; } - (void) encodeWithCoder: (NSCoder *) coder { [coder encodeSize: _size forKey: kDrawingLayerCodingKey_Size]; [coder encodeObject: _name forKey: kDrawingLayerCodingKey_Name]; [coder encodeObject: [_bitmap ppCompressedTIFFData] forKey: kDrawingLayerCodingKey_TIFFData]; [coder encodeFloat: _opacity forKey: kDrawingLayerCodingKey_Opacity]; [coder encodeBool: _isEnabled forKey: kDrawingLayerCodingKey_IsEnabled]; } #pragma mark NSCopying protocol - (id) copyWithZone: (NSZone *) zone { PPDocumentLayer *layerCopy; bool needToCopyLayerBitmapData = YES; layerCopy = [[[self class] allocWithZone: zone] initWithSize: _size name: _name tiffData: nil opacity: _opacity isEnabled: _isEnabled]; if (!layerCopy) goto ERROR; layerCopy->_delegate = _delegate; if (zone && (zone != NSDefaultMallocZone())) { if ([layerCopy->_name zone] != zone) { NSString *zonedName = [[_name copyWithZone: zone] autorelease]; if (zonedName) { [layerCopy->_name release]; layerCopy->_name = [zonedName retain]; } } if (([layerCopy->_bitmap zone] != zone) || ([layerCopy->_image zone] != zone)) { NSBitmapImageRep *zonedBitmap = [[_bitmap copyWithZone: zone] autorelease]; NSImage *zonedImage = [[[NSImage allocWithZone: zone] initWithSize: _size] autorelease]; if (zonedBitmap && zonedImage) { [zonedImage addRepresentation: zonedBitmap]; [layerCopy->_bitmap release]; layerCopy->_bitmap = [zonedBitmap retain]; [layerCopy->_image release]; layerCopy->_image = [zonedImage retain]; needToCopyLayerBitmapData = NO; } } } if (needToCopyLayerBitmapData) { [layerCopy->_bitmap ppCopyFromBitmap: _bitmap toPoint: NSZeroPoint]; [layerCopy handleUpdateToBitmapInRect: PPGeometry_OriginRectOfSize(_size)]; } // Don't need to enable _linearBlendingBitmap in the copy - the linear bitmap will be // enabled automatically if the copy's added to a PPDocument that's in linear blending mode, // otherwise, the linear bitmap's currently unused in unattached layers. return layerCopy; ERROR: return nil; } #pragma mark Private methods - (void) setOpacity: (float) opacity andRegisterUndo: (bool) shouldRegisterUndo { if (opacity > 1.0f) { opacity = 1.0f; } else if (opacity < 0.0f) { opacity = 0.0f; } if (!shouldRegisterUndo && (_opacity == opacity)) { return; } _opacity = opacity; [self notifyDelegateDidChangeOpacityAndShouldRegisterUndo: shouldRegisterUndo]; if (shouldRegisterUndo) { _lastOpacity = _opacity; } } #pragma mark Delegate notifiers - (void) notifyDelegateDidChangeNameFromOldValue: (NSString *) oldName { if ([_delegate respondsToSelector: @selector(layer:changedNameFromOldValue:)]) { [_delegate layer: self changedNameFromOldValue: oldName]; } } - (void) notifyDelegateDidChangeEnabledFlagFromOldValue: (bool) oldEnabledFlag { if ([_delegate respondsToSelector: @selector(layer:changedEnabledFlagFromOldValue:)]) { [_delegate layer: self changedEnabledFlagFromOldValue: oldEnabledFlag]; } } - (void) notifyDelegateDidChangeOpacityAndShouldRegisterUndo: (bool) shouldRegisterUndo { if ([_delegate respondsToSelector: @selector(layer:changedOpacityFromOldValue: shouldRegisterUndo:)]) { [_delegate layer: self changedOpacityFromOldValue: _lastOpacity shouldRegisterUndo: shouldRegisterUndo]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentResizeSheetController.h0000644000076500000240000000324613234403416024570 0ustar joshstaff/* PPDocumentResizeSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" @interface PPDocumentResizeSheetController : PPDocumentSheetController { IBOutlet NSTextField *_widthTextField; IBOutlet NSTextField *_heightTextField; IBOutlet NSButton *_shouldScaleCheckbox; int _widthTextFieldValue; int _heightTextFieldValue; } + (bool) beginResizeSheetForDocumentWindow: (NSWindow *) window currentImageSize: (NSSize) currentImageSize delegate: (id) delegate; @end @interface NSObject (PPDocumentResizeSheetDelegateMethods) - (void) documentResizeSheetDidFinishWithNewImageSize: (NSSize) newImageSize shouldScale: (bool) shouldScale; - (void) documentResizeSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentResizeSheetController.m0000644000076500000240000001036713234403205024573 0ustar joshstaff/* PPDocumentResizeSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentResizeSheetController.h" #import "PPDefines.h" #import "NSTextField_PPUtilities.h" #define kDocumentResizeSheetNibName @"DocumentResizeSheet" @interface PPDocumentResizeSheetController (PrivateMethods) - initWithCurrentImageSize: (NSSize) currentImageSize andDelegate: (id) delegate; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPDocumentResizeSheetController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPDocumentResizeSheetController + (bool) beginResizeSheetForDocumentWindow: (NSWindow *) window currentImageSize: (NSSize) currentImageSize delegate: (id) delegate { PPDocumentResizeSheetController *controller; controller = [[[self alloc] initWithCurrentImageSize: currentImageSize andDelegate: delegate] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - initWithCurrentImageSize: (NSSize) currentImageSize andDelegate: (id) delegate { self = [super initWithNibNamed: kDocumentResizeSheetNibName delegate: delegate]; if (!self) goto ERROR; _widthTextFieldValue = currentImageSize.width; [_widthTextField setIntValue: _widthTextFieldValue]; [_widthTextField setDelegate: self]; _heightTextFieldValue = currentImageSize.height; [_heightTextField setIntValue: _heightTextFieldValue]; [_heightTextField setDelegate: self]; return self; ERROR: [self release]; return nil; } - init { return [self initWithCurrentImageSize: NSZeroSize andDelegate: nil]; } #pragma mark PPDocumentSheetController overrides (delegate notifiers) - (void) notifyDelegateSheetDidFinish { if ([_delegate respondsToSelector: @selector(documentResizeSheetDidFinishWithNewImageSize:shouldScale:)]) { NSSize newImageSize = NSMakeSize(_widthTextFieldValue, _heightTextFieldValue); bool shouldScale = [_shouldScaleCheckbox intValue] ? YES : NO; [_delegate documentResizeSheetDidFinishWithNewImageSize: newImageSize shouldScale: shouldScale]; } } - (void) notifyDelegateSheetDidCancel { if ([_delegate respondsToSelector: @selector(documentResizeSheetDidCancel)]) { [_delegate documentResizeSheetDidCancel]; } } #pragma mark NSTextField delegate methods (width/height textfields) - (void) controlTextDidChange: (NSNotification *) notification { id notifyingObject = [notification object]; if (notifyingObject == _widthTextField) { _widthTextFieldValue = [_widthTextField ppClampIntValueToMax: kMaxCanvasDimension min: kMinCanvasDimension defaultValue: _widthTextFieldValue]; } else if (notifyingObject == _heightTextField) { _heightTextFieldValue = [_heightTextField ppClampIntValueToMax: kMaxCanvasDimension min: kMinCanvasDimension defaultValue: _heightTextFieldValue]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentSamplerImage.h0000644000076500000240000000336713234403416022644 0ustar joshstaff/* PPDocumentSamplerImage.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPSamplerImagePanelType.h" @interface PPDocumentSamplerImage : NSObject { NSBitmapImageRep *_bitmap; NSImage *_image; NSData *_compressedBitmapData; NSUInteger _hash; float _scalingFactorsForPanels[kNumPPSamplerImagePanelTypes]; } + (PPDocumentSamplerImage *) samplerImageWithBitmap: (NSBitmapImageRep *) bitmap; - (PPDocumentSamplerImage *) initWithBitmap: (NSBitmapImageRep *) bitmap; - (NSBitmapImageRep *) bitmap; - (NSImage *) image; - (NSData *) compressedBitmapData; - (NSSize) size; - (float) scalingFactorForSamplerImagePanelType: (PPSamplerImagePanelType) panelType; - (void) setScalingFactor: (float) scalingFactor forSamplerImagePanelType: (PPSamplerImagePanelType) panelType; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentSamplerImage.m0000644000076500000240000000746713234403205022652 0ustar joshstaff/* PPDocumentSamplerImage.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSamplerImage.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #define kMaxSamplerImageDimension 800 #define kSamplerImageCodingKey_TIFFData @"TIFFData" @implementation PPDocumentSamplerImage + (PPDocumentSamplerImage *) samplerImageWithBitmap: (NSBitmapImageRep *) bitmap { return [[[self alloc] initWithBitmap: bitmap] autorelease]; } - (PPDocumentSamplerImage *) initWithBitmap: (NSBitmapImageRep *) bitmap { NSImage *image; NSData *compressedBitmapData; self = [super init]; if (!self) goto ERROR; bitmap = [bitmap ppImageBitmapWithMaxDimension: kMaxSamplerImageDimension]; image = [NSImage ppImageWithBitmap: bitmap]; compressedBitmapData = [bitmap ppCompressedTIFFData]; if (!bitmap || !image || !compressedBitmapData) { goto ERROR; } _bitmap = [bitmap retain]; _image = [image retain]; _compressedBitmapData = [compressedBitmapData retain]; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_bitmap release]; [_image release]; [_compressedBitmapData release]; [super dealloc]; } - (NSBitmapImageRep *) bitmap { return _bitmap; } - (NSImage *) image { return _image; } - (NSData *) compressedBitmapData { return _compressedBitmapData; } - (NSSize) size { return [_bitmap ppSizeInPixels]; } - (float) scalingFactorForSamplerImagePanelType: (PPSamplerImagePanelType) panelType { if (!PPSamplerImagePanelType_IsValid(panelType)) { goto ERROR; } return _scalingFactorsForPanels[(int) panelType]; ERROR: return 0.0f; } - (void) setScalingFactor: (float) scalingFactor forSamplerImagePanelType: (PPSamplerImagePanelType) panelType { if (!PPSamplerImagePanelType_IsValid(panelType)) { goto ERROR; } _scalingFactorsForPanels[(int) panelType] = scalingFactor; return; ERROR: return; } #pragma mark NSObject overrides - (BOOL) isEqual: (id) object { return [[object compressedBitmapData] isEqual: _compressedBitmapData]; } - (NSUInteger) hash { if (!_hash) { _hash = [_compressedBitmapData hash]; } return _hash; } #pragma mark NSCoding protocol - (id) initWithCoder: (NSCoder *) aDecoder { NSData *tiffData = [aDecoder decodeObjectForKey: kSamplerImageCodingKey_TIFFData]; NSBitmapImageRep *bitmap = [NSBitmapImageRep imageRepWithData: tiffData]; return [self initWithBitmap: bitmap]; } - (void) encodeWithCoder: (NSCoder *) aCoder { [aCoder encodeObject: _compressedBitmapData forKey: kSamplerImageCodingKey_TIFFData]; } #pragma mark NSCopying protocol - (id) copyWithZone: (NSZone *) zone { return [[[self class] allocWithZone: zone] initWithBitmap: [[_bitmap copyWithZone: zone] autorelease]]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentSamplerImagesSettingsSheetController.h0000644000076500000240000000405713234403416027602 0ustar joshstaff/* PPDocumentSamplerImagesSettingsSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" @interface PPDocumentSamplerImagesSettingsSheetController : PPDocumentSheetController { IBOutlet NSTableView *_samplerImagesTable; IBOutlet NSButton *_copyImageToClipboardButton; IBOutlet NSButton *_removeImageButton; IBOutlet NSButton *_removeAllImagesButton; NSMutableArray *_samplerImages; NSInteger _samplerImagesTableImageColumn; } + (bool) beginSamplerImagesSettingsSheetForWindow: (NSWindow *) window samplerImages: (NSArray *) samplerImages delegate: (id) delegate; - (IBAction) addImageFromClipboardButtonPressed: (id) sender; - (IBAction) addImageFromFileButtonPressed: (id) sender; - (IBAction) copyImageToClipboardButtonPressed: (id) sender; - (IBAction) removeImageButtonPressed: (id) sender; - (IBAction) removeAllImagesButtonPressed: (id) sender; @end @interface NSObject (PPDocumentSamplerImagesSettingsSheetDelegateMethods) - (void) samplerImagesSettingsSheetDidFinishWithSamplerImages: (NSArray *) samplerImages; - (void) samplerImagesSettingsSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentSamplerImagesSettingsSheetController.m0000644000076500000240000003154013234403205027600 0ustar joshstaff/* PPDocumentSamplerImagesSettingsSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSamplerImagesSettingsSheetController.h" #import "PPDocumentSamplerImage.h" #import "NSImage_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSPasteboard_PPUtilities.h" #import "PPGeometry.h" #define kDocumentSamplerImagesSettingsSheetNibName @"DocumentSamplerImagesSettingsSheet" #define kSamplerImagesTableDraggedDataType @"SamplerImagesTableDraggedDataType" #define kSamplerImagesTableImageColumnIdentifier @"Images" @interface PPDocumentSamplerImagesSettingsSheetController (PrivateMethods) - initWithSamplerImages: (NSArray *) samplerImages delegate: (id) delegate; - (void) updateButtonEnabledStates; - (NSImage *) imageForSamplerImageTableFromBitmap: (NSBitmapImageRep *) bitmap withCellSize: (NSSize) cellSize; - (void) selectSamplerImagesTableRow: (unsigned) row; - (void) addSamplerImage: (PPDocumentSamplerImage *) samplerImage; - (void) samplerImageOpenPanelDidEnd: (NSOpenPanel *) panel returnCode: (int) returnCode contextInfo: (void *) contextInfo; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPDocumentSamplerImagesSettingsSheetController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPDocumentSamplerImagesSettingsSheetController + (bool) beginSamplerImagesSettingsSheetForWindow: (NSWindow *) window samplerImages: (NSArray *) samplerImages delegate: (id) delegate { PPDocumentSamplerImagesSettingsSheetController *controller; controller = [[[self alloc] initWithSamplerImages: samplerImages delegate: delegate] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - initWithSamplerImages: (NSArray *) samplerImages delegate: (id) delegate { self = [super initWithNibNamed: kDocumentSamplerImagesSettingsSheetNibName delegate: delegate]; if (!self) goto ERROR; _samplerImages = [[NSMutableArray array] retain]; if (!_samplerImages) goto ERROR; if (samplerImages) { [_samplerImages addObjectsFromArray: samplerImages]; } [_sheet setDelegate: self]; [_samplerImagesTable setDataSource: self]; [_samplerImagesTable setDelegate: self]; [_samplerImagesTable registerForDraggedTypes: [NSArray arrayWithObject: kSamplerImagesTableDraggedDataType]]; _samplerImagesTableImageColumn = [_samplerImagesTable columnWithIdentifier: kSamplerImagesTableImageColumnIdentifier]; [self updateButtonEnabledStates]; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_samplerImages release]; [super dealloc]; } #pragma mark Actions - (IBAction) addImageFromClipboardButtonPressed: (id) sender { NSBitmapImageRep *imageBitmap; PPDocumentSamplerImage *samplerImage; if (![NSPasteboard ppGetImageBitmap: &imageBitmap]) { goto ERROR; } samplerImage = [PPDocumentSamplerImage samplerImageWithBitmap: imageBitmap]; if (!samplerImage) goto ERROR; [self addSamplerImage: samplerImage]; return; ERROR: return; } - (IBAction) addImageFromFileButtonPressed: (id) sender { [[NSOpenPanel openPanel] beginSheetForDirectory: nil file: nil types: [NSImage imageFileTypes] modalForWindow: _sheet modalDelegate: self didEndSelector: @selector(samplerImageOpenPanelDidEnd: returnCode:contextInfo:) contextInfo: nil]; } - (IBAction) copyImageToClipboardButtonPressed: (id) sender { unsigned indexOfSelectedImage; PPDocumentSamplerImage *samplerImage; indexOfSelectedImage = [_samplerImagesTable selectedRow]; if (indexOfSelectedImage >= [_samplerImages count]) { goto ERROR; } samplerImage = [_samplerImages objectAtIndex: indexOfSelectedImage]; if (!samplerImage) goto ERROR; [NSPasteboard ppSetImageBitmap: [samplerImage bitmap]]; [self updateButtonEnabledStates]; return; ERROR: return; } - (IBAction) removeImageButtonPressed: (id) sender { unsigned indexOfSelectedImage = [_samplerImagesTable selectedRow]; if (indexOfSelectedImage >= [_samplerImages count]) { goto ERROR; } [_samplerImages removeObjectAtIndex: indexOfSelectedImage]; [_samplerImagesTable reloadData]; [self updateButtonEnabledStates]; return; ERROR: return; } - (IBAction) removeAllImagesButtonPressed: (id) sender { [_samplerImages removeAllObjects]; [_samplerImagesTable reloadData]; [self updateButtonEnabledStates]; } #pragma mark PPDocumentSheetController overrides (delegate notifiers) - (void) notifyDelegateSheetDidFinish { if ([_delegate respondsToSelector: @selector(samplerImagesSettingsSheetDidFinishWithSamplerImages:)]) { [_delegate samplerImagesSettingsSheetDidFinishWithSamplerImages: _samplerImages]; } } - (void) notifyDelegateSheetDidCancel { if ([_delegate respondsToSelector: @selector(samplerImagesSettingsSheetDidCancel)]) { [_delegate samplerImagesSettingsSheetDidCancel]; } } #pragma mark NSWindow delegate - (void) windowDidBecomeKey: (NSNotification *) notification { [self updateButtonEnabledStates]; } #pragma mark NSTableView data source (Sampler images table) - (NSInteger) numberOfRowsInTableView: (NSTableView *) aTableView { return [_samplerImages count]; } - (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row { PPDocumentSamplerImage *samplerImage; NSSize cellSize; if (tableView != _samplerImagesTable) { return nil; } if (![[tableColumn identifier] isEqualToString: kSamplerImagesTableImageColumnIdentifier]) { return nil; } samplerImage = [_samplerImages objectAtIndex: row]; cellSize = [_samplerImagesTable frameOfCellAtColumn: _samplerImagesTableImageColumn row: row].size; return [self imageForSamplerImageTableFromBitmap: [samplerImage bitmap] withCellSize: cellSize]; } - (BOOL) tableView: (NSTableView *) tableView writeRowsWithIndexes: (NSIndexSet *) rowIndexes toPasteboard: (NSPasteboard*) pasteboard { NSData *pasteboardData; pasteboardData = [NSKeyedArchiver archivedDataWithRootObject: rowIndexes]; [pasteboard declareTypes: [NSArray arrayWithObject: kSamplerImagesTableDraggedDataType] owner: self]; [pasteboard setData: pasteboardData forType: kSamplerImagesTableDraggedDataType]; return YES; } - (NSDragOperation) tableView: (NSTableView*) tableView validateDrop: (id ) info proposedRow: (NSInteger) newRow proposedDropOperation: (NSTableViewDropOperation) op { NSPasteboard *pasteboard; NSData *pasteboardData; NSIndexSet *rowIndexes; unsigned int selectedRow; pasteboard = [info draggingPasteboard]; pasteboardData = [pasteboard dataForType: kSamplerImagesTableDraggedDataType]; rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData: pasteboardData]; selectedRow = [rowIndexes firstIndex]; if ((op == NSTableViewDropAbove) && (selectedRow != newRow) && (selectedRow != (newRow-1))) { return NSDragOperationEvery; } else { return NSDragOperationNone; } } - (BOOL) tableView: (NSTableView *) aTableView acceptDrop: (id ) info row: (NSInteger) destinationTableRow dropOperation: (NSTableViewDropOperation) operation { NSPasteboard *pboard; NSData *rowData; NSIndexSet *rowIndexes; int sourceTableRow; PPDocumentSamplerImage *samplerImage; pboard = [info draggingPasteboard]; rowData = [pboard dataForType: kSamplerImagesTableDraggedDataType]; rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData: rowData]; sourceTableRow = [rowIndexes firstIndex]; if (destinationTableRow > sourceTableRow) { destinationTableRow--; } samplerImage = [[[_samplerImages objectAtIndex: sourceTableRow] retain] autorelease]; [_samplerImages removeObjectAtIndex: sourceTableRow]; [_samplerImages insertObject: samplerImage atIndex: destinationTableRow]; [_samplerImagesTable reloadData]; [self selectSamplerImagesTableRow: destinationTableRow]; return YES; } - (void) tableViewSelectionDidChange: (NSNotification *) notification { if ([_samplerImagesTable numberOfSelectedRows] > 1) { [self selectSamplerImagesTableRow: [_samplerImagesTable selectedRow]]; } } #pragma mark NSOpenPanel delegate (Add image from file) - (void) samplerImageOpenPanelDidEnd: (NSOpenPanel *) panel returnCode: (int) returnCode contextInfo: (void *) contextInfo { NSURL *imageURL; NSImage *image; NSBitmapImageRep *imageBitmap; PPDocumentSamplerImage *samplerImage; [panel orderOut: self]; if (returnCode != NSOKButton) { return; } imageURL = [[panel URLs] objectAtIndex: 0]; if (!imageURL) goto ERROR; image = [[[NSImage alloc] initWithContentsOfURL: imageURL] autorelease]; if (!image) goto ERROR; imageBitmap = [image ppBitmap]; if (!imageBitmap) goto ERROR; samplerImage = [PPDocumentSamplerImage samplerImageWithBitmap: imageBitmap]; if (!samplerImage) goto ERROR; [self addSamplerImage: samplerImage]; return; ERROR: return; } #pragma mark Private methods - (void) updateButtonEnabledStates { bool hasSamplerImages = ([_samplerImages count]) ? YES : NO; [_copyImageToClipboardButton setEnabled: hasSamplerImages]; [_removeImageButton setEnabled: hasSamplerImages]; [_removeAllImagesButton setEnabled: hasSamplerImages]; } - (NSImage *) imageForSamplerImageTableFromBitmap: (NSBitmapImageRep *) bitmap withCellSize: (NSSize) cellSize { NSSize bitmapSize; float scale; bitmapSize = [bitmap ppSizeInPixels]; if (PPGeometry_IsZeroSize(bitmapSize)) { goto ERROR; } scale = MAX(ceilf(4.0f * cellSize.width / bitmapSize.width), ceilf(4.0f * cellSize.height / bitmapSize.width)); return [NSImage ppImageWithBitmap: [bitmap ppImageBitmapScaledByFactor: scale shouldDrawGrid: NO gridType: 0 gridColor: nil]]; ERROR: return nil; } - (void) selectSamplerImagesTableRow: (unsigned) row { if (row < [_samplerImages count]) { [_samplerImagesTable selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO]; } else { [_samplerImagesTable deselectAll: self]; } } - (void) addSamplerImage: (PPDocumentSamplerImage *) samplerImage { if (!samplerImage) return; if (![_samplerImages containsObject: samplerImage]) { int insertionIndex = [_samplerImagesTable selectedRow]; if (insertionIndex < 0) { insertionIndex = 0; } [_samplerImages insertObject: samplerImage atIndex: insertionIndex]; [_samplerImagesTable reloadData]; [self updateButtonEnabledStates]; } else { [self selectSamplerImagesTableRow: [_samplerImages indexOfObject: samplerImage]]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentScaleSheetController.h0000644000076500000240000000457013234403416024357 0ustar joshstaff/* PPDocumentScaleSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" typedef enum { kPPScalingType_Upscale, kPPScalingType_Downscale, kNumPPScalingTypes } PPScalingType; @interface PPDocumentScaleSheetController : PPDocumentSheetController { IBOutlet NSImageView *_previewImageView; IBOutlet NSTextField *_newSizeTextField; IBOutlet NSPopUpButton *_scalingFactorTypePopUpButton; IBOutlet NSTextField *_scalingFactorTextField; IBOutlet NSSlider *_scalingFactorSlider; NSBitmapImageRep *_canvasBitmap; NSImage *_canvasImage; NSSize _originalSize; NSSize _scaledSize; PPScalingType _scalingType; unsigned _scalingFactor; unsigned _maxScalingFactorForScalingType[kNumPPScalingTypes]; unsigned _minScalingFactorForScalingType[kNumPPScalingTypes]; NSRect _previewScrollViewInitialFrame; float _previewScrollerWidth; NSPoint _previewViewNormalizedCenter; bool _shouldPreservePreviewNormalizedCenter; } + (bool) beginScaleSheetForDocumentWindow: (NSWindow *) window canvasBitmap: (NSBitmapImageRep *) canvasBitmap delegate: (id) delegate; - (IBAction) scalingFactorTypePopUpButtonItemSelected: (id) sender; - (IBAction) scalingFactorSliderMoved: (id) sender; @end @interface NSObject (PPDocumentScaleSheetDelegateMethods) - (void) documentScaleSheetDidFinishWithNewImageSize: (NSSize) newImageSize; - (void) documentScaleSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentScaleSheetController.m0000644000076500000240000003516113234403205024360 0ustar joshstaff/* PPDocumentScaleSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentScaleSheetController.h" #import "PPDefines.h" #import "NSTextField_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #import "PPGeometry.h" #define kDocumentScaleSheetNibName @"DocumentScaleSheet" #define kMaxAllowedScalingFactor 50 #define kMinValidScalingFactor 2 #define kMarginPaddingForScrollerlessScrollView 2 @interface PPDocumentScaleSheetController (PrivateMethods) - initWithCanvasBitmap: (NSBitmapImageRep *) canvasBitmap andDelegate: (id) delegate; - (void) addAsObserverForNSViewNotificationsFromPreviewClipView; - (void) removeAsObserverForNSViewNotificationsFromPreviewClipView; - (void) handlePreviewClipViewNotification_BoundsDidChange: (NSNotification *) notification; - (void) setScalingType: (PPScalingType) scalingType; - (void) updateScalingFactorControlValues; - (void) updatePreviewImageForCurrentScaledSize; - (void) scrollPreviewToNormalizedCenter; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPDocumentScaleSheetController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPDocumentScaleSheetController + (bool) beginScaleSheetForDocumentWindow: (NSWindow *) window canvasBitmap: (NSBitmapImageRep *) canvasBitmap delegate: (id) delegate; { PPDocumentScaleSheetController *controller; controller = [[[self alloc] initWithCanvasBitmap: canvasBitmap andDelegate: delegate] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - initWithCanvasBitmap: (NSBitmapImageRep *) canvasBitmap andDelegate: (id) delegate { NSImage *canvasImage; float maxDimension; int scalingTypeCounter; self = [super initWithNibNamed: kDocumentScaleSheetNibName delegate: delegate]; if (!self) goto ERROR; if (!canvasBitmap) goto ERROR; canvasImage = [NSImage ppImageWithBitmap: canvasBitmap]; if (!canvasImage) goto ERROR; _canvasBitmap = [canvasBitmap retain]; _canvasImage = [canvasImage retain]; _originalSize = [_canvasBitmap ppSizeInPixels]; maxDimension = MAX(_originalSize.width, _originalSize.height); _maxScalingFactorForScalingType[kPPScalingType_Upscale] = MAX(MIN(kMaxAllowedScalingFactor, floorf(kMaxCanvasDimension / maxDimension)), 1); _maxScalingFactorForScalingType[kPPScalingType_Downscale] = MAX(MIN(kMaxAllowedScalingFactor, floorf(maxDimension / kMinCanvasDimension)), 1); for (scalingTypeCounter=0; scalingTypeCounter kMinValidScalingFactor) { _minScalingFactorForScalingType[scalingTypeCounter] = kMinValidScalingFactor; } else { _minScalingFactorForScalingType[scalingTypeCounter] = _maxScalingFactorForScalingType[scalingTypeCounter]; } } _previewScrollViewInitialFrame = [[_previewImageView enclosingScrollView] frame]; _previewScrollerWidth = _previewScrollViewInitialFrame.size.width - [[[_previewImageView enclosingScrollView] contentView] frame].size.width; _previewViewNormalizedCenter = NSMakePoint(0.5f, 0.5f); [_previewImageView setImage: [NSImage ppImageWithBitmap: canvasBitmap]]; [_previewImageView setImageScaling: NSScaleToFit]; [self addAsObserverForNSViewNotificationsFromPreviewClipView]; [_scalingFactorTextField setDelegate: self]; [self setScalingType: kPPScalingType_Upscale]; return self; ERROR: [self release]; return nil; } - init { return [self initWithCanvasBitmap: nil andDelegate: nil]; } - (void) dealloc { [self removeAsObserverForNSViewNotificationsFromPreviewClipView]; [_canvasImage release]; [_canvasBitmap release]; [super dealloc]; } #pragma mark Actions - (IBAction) scalingFactorTypePopUpButtonItemSelected: (id) sender { [self setScalingType: [[_scalingFactorTypePopUpButton selectedItem] tag]]; } - (IBAction) scalingFactorSliderMoved: (id) sender { unsigned newScalingFactor = [_scalingFactorSlider intValue]; if (newScalingFactor == _scalingFactor) { return; } _scalingFactor = newScalingFactor; [self updateScalingFactorControlValues]; } #pragma mark PPDocumentSheetController overrides (delegate notifiers) - (void) notifyDelegateSheetDidFinish { if (_scalingFactor < kMinValidScalingFactor) { [self notifyDelegateSheetDidCancel]; return; } if ([_delegate respondsToSelector: @selector(documentScaleSheetDidFinishWithNewImageSize:)]) { [_delegate documentScaleSheetDidFinishWithNewImageSize: _scaledSize]; } } - (void) notifyDelegateSheetDidCancel { if ([_delegate respondsToSelector: @selector(documentScaleSheetDidCancel)]) { [_delegate documentScaleSheetDidCancel]; } } #pragma mark NSTextField delegate methods (Scaling factor textfield) - (void) controlTextDidChange: (NSNotification *) notification { int newScalingFactor = [_scalingFactorTextField ppClampIntValueToMax: _maxScalingFactorForScalingType[_scalingType] min: _minScalingFactorForScalingType[_scalingType] defaultValue: _scalingFactor]; if (newScalingFactor != _scalingFactor) { _scalingFactor = newScalingFactor; [self updateScalingFactorControlValues]; } } #pragma mark NSView notifications (Preview imageview’s clipview) - (void) addAsObserverForNSViewNotificationsFromPreviewClipView { NSClipView *clipView = [[_previewImageView enclosingScrollView] contentView]; if (!clipView) return; [clipView setPostsBoundsChangedNotifications: YES]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector( handlePreviewClipViewNotification_BoundsDidChange:) name: NSViewBoundsDidChangeNotification object: clipView]; } - (void) removeAsObserverForNSViewNotificationsFromPreviewClipView { NSClipView *clipView = [[_previewImageView enclosingScrollView] contentView]; [[NSNotificationCenter defaultCenter] removeObserver: self name: NSViewBoundsDidChangeNotification object: clipView]; } - (void) handlePreviewClipViewNotification_BoundsDidChange: (NSNotification *) notification { NSRect documentVisibleRect; if (_shouldPreservePreviewNormalizedCenter) return; documentVisibleRect = [[_previewImageView enclosingScrollView] documentVisibleRect]; _previewViewNormalizedCenter = NSMakePoint(((documentVisibleRect.origin.x + documentVisibleRect.size.width / 2.0) / _scaledSize.width), ((documentVisibleRect.origin.y + documentVisibleRect.size.height / 2.0) / _scaledSize.height)); } #pragma mark Private methods - (void) setScalingType: (PPScalingType) scalingType { unsigned minScalingFactor, maxScalingFactor; if (((unsigned) scalingType) >= kNumPPScalingTypes) { goto ERROR; } _scalingType = scalingType; [_scalingFactorTypePopUpButton selectItemWithTag: (NSInteger) _scalingType]; minScalingFactor = _minScalingFactorForScalingType[_scalingType]; maxScalingFactor = _maxScalingFactorForScalingType[_scalingType]; [_scalingFactorSlider setMinValue: minScalingFactor]; [_scalingFactorSlider setMaxValue: maxScalingFactor]; if (_scalingFactor < minScalingFactor) { _scalingFactor = minScalingFactor; } else if (_scalingFactor > maxScalingFactor) { _scalingFactor = maxScalingFactor; } [self updateScalingFactorControlValues]; return; ERROR: return; } - (void) updateScalingFactorControlValues { unsigned maxScalingFactor, minScalingFactor; NSSize oldScaledSize = _scaledSize; bool scalingFactorIsValid = YES; NSString *scaledSizeString; maxScalingFactor = _maxScalingFactorForScalingType[_scalingType]; minScalingFactor = _minScalingFactorForScalingType[_scalingType]; if (_scalingFactor > maxScalingFactor) { _scalingFactor = maxScalingFactor; } else if (_scalingFactor < kMinValidScalingFactor) { // allow positive integers less than kMinValidScalingFactor, because the user might be // in the process of typing a larger number if (_scalingFactor > 0) { scalingFactorIsValid = NO; } else { _scalingFactor = minScalingFactor; } } if ([_scalingFactorTextField intValue] != _scalingFactor) { [_scalingFactorTextField setIntValue: _scalingFactor]; } if (scalingFactorIsValid) { if ([_scalingFactorSlider intValue] != _scalingFactor) { [_scalingFactorSlider setIntValue: _scalingFactor]; } if (_scalingType == kPPScalingType_Downscale) { _scaledSize.width = roundf(_originalSize.width / (float) _scalingFactor); if (_scaledSize.width < 1) { _scaledSize.width = 1; } _scaledSize.height = roundf(_originalSize.height / (float) _scalingFactor); if (_scaledSize.height < 1) { _scaledSize.height = 1; } } else // !(_scalingType == kPPScalingType_Downscale) { _scaledSize.width = _originalSize.width * _scalingFactor; _scaledSize.height = _originalSize.height * _scalingFactor; } if (!NSEqualSizes(_scaledSize, oldScaledSize)) { [self updatePreviewImageForCurrentScaledSize]; } scaledSizeString = [NSString stringWithFormat: @"%dx%d", (int) _scaledSize.width, (int) _scaledSize.height]; } else // !scalingFactorIsValid { scaledSizeString = @"-"; } [_newSizeTextField setStringValue: scaledSizeString]; } - (void) updatePreviewImageForCurrentScaledSize { NSScrollView *previewScrollView; NSSize contentViewSize; NSRect newPreviewScrollViewFrame; int viewMarginPadding; _shouldPreservePreviewNormalizedCenter = YES; previewScrollView = [_previewImageView enclosingScrollView]; [_previewImageView setFrameSize: _scaledSize]; [previewScrollView setFrame: _previewScrollViewInitialFrame]; contentViewSize = [[previewScrollView contentView] frame].size; newPreviewScrollViewFrame = _previewScrollViewInitialFrame; if (_scaledSize.width < contentViewSize.width) { if (_scaledSize.height > contentViewSize.height) { viewMarginPadding = _previewScrollerWidth; } else { viewMarginPadding = kMarginPaddingForScrollerlessScrollView; } newPreviewScrollViewFrame.size.width = _scaledSize.width + viewMarginPadding; } if (_scaledSize.height < contentViewSize.height) { if (_scaledSize.width > contentViewSize.width) { viewMarginPadding = _previewScrollerWidth; } else { viewMarginPadding = kMarginPaddingForScrollerlessScrollView; } newPreviewScrollViewFrame.size.height = _scaledSize.height + viewMarginPadding; } newPreviewScrollViewFrame = PPGeometry_CenterRectInRect(newPreviewScrollViewFrame, _previewScrollViewInitialFrame); [previewScrollView setFrame: newPreviewScrollViewFrame]; // Changing scrollview frame causes drawing artifacts (10.4) - fix by redrawing superview [[previewScrollView superview] setNeedsDisplayInRect: _previewScrollViewInitialFrame]; // NSImageView seems to ignore (non)antialiasing settings when drawing downsized images // (on 10.5+?), so when downscaling, have to set the preview to a manually-resized image if (_scalingType == kPPScalingType_Downscale) { // use a local autorelease pool to make sure old images & bitmaps get dealloc'd during // slider tracking NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init]; [_previewImageView setImage: [NSImage ppImageWithBitmap: [_canvasBitmap ppBitmapResizedToSize: _scaledSize shouldScale: YES]]]; [autoreleasePool release]; } else // !(_scalingType == kPPScalingType_Downscale) { // upscaling - let NSImageView handle the resizing [_previewImageView setImage: _canvasImage]; } [self scrollPreviewToNormalizedCenter]; _shouldPreservePreviewNormalizedCenter = NO; } - (void) scrollPreviewToNormalizedCenter { NSSize clipViewSize = [[[_previewImageView enclosingScrollView] contentView] bounds].size; NSPoint centerPoint = NSMakePoint(_previewViewNormalizedCenter.x * _scaledSize.width - clipViewSize.width / 2.0f, _previewViewNormalizedCenter.y * _scaledSize.height - clipViewSize.height / 2.0f); [_previewImageView scrollPoint: centerPoint]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentSheetController.h0000644000076500000240000000264513234403416023410 0ustar joshstaff/* PPDocumentSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPDocumentSheetController : NSObject { id _delegate; IBOutlet NSWindow *_sheet; } - initWithNibNamed: (NSString *) nibName delegate: (id) delegate; - (bool) beginSheetModalForWindow: (NSWindow *) window; - (void) endSheet; - (IBAction) OKButtonPressed: (id) sender; - (IBAction) cancelButtonPressed: (id) sender; - (void) notifyDelegateSheetDidFinish; - (void) notifyDelegateSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentSheetController.m0000644000076500000240000000522513234403206023407 0ustar joshstaff/* PPDocumentSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" @implementation PPDocumentSheetController - initWithNibNamed: (NSString *) nibName delegate: (id) delegate; { self = [super init]; if (!self) goto ERROR; if (!nibName || !delegate) { goto ERROR; } if (![NSBundle loadNibNamed: nibName owner: self]) { goto ERROR; } _delegate = delegate; return self; ERROR: [self release]; return nil; } - init { return [self initWithNibNamed: nil delegate: nil]; } - (void) dealloc { [_sheet release]; [super dealloc]; } - (bool) beginSheetModalForWindow: (NSWindow *) window { if (![window isVisible] || [_sheet isVisible]) { goto ERROR; } [NSApp beginSheet: _sheet modalForWindow: window modalDelegate: self didEndSelector: @selector(didEndSheet:returnCode:contextInfo:) contextInfo: nil]; [self retain]; return YES; ERROR: return NO; } - (void) endSheet { if (![_sheet isVisible]) { return; } [NSApp endSheet: _sheet]; [self autorelease]; } #pragma mark Actions - (IBAction) OKButtonPressed: (id) sender { [self endSheet]; [self notifyDelegateSheetDidFinish]; } - (IBAction) cancelButtonPressed: (id) sender { [self endSheet]; [self notifyDelegateSheetDidCancel]; } #pragma mark NSApplication sheet modal delegate - (void) didEndSheet: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo { [sheet orderOut: self]; } #pragma mark Delegate notifiers - (void) notifyDelegateSheetDidFinish { } - (void) notifyDelegateSheetDidCancel { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentSizeSheetController.h0000644000076500000240000000367313234403416024245 0ustar joshstaff/* PPDocumentSizeSheetController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSheetController.h" @class PPTitleablePopUpButton; @interface PPDocumentSizeSheetController : PPDocumentSheetController { IBOutlet PPTitleablePopUpButton *_sizePresetsTitleablePopUpButton; IBOutlet NSTextField *_widthTextField; IBOutlet NSTextField *_heightTextField; IBOutlet NSMenu *_defaultSizePresetsMenu; int _widthTextFieldValue; int _heightTextFieldValue; int _indexOfSizePresetsMenuItem_CustomDimensions; } + (bool) beginSizeSheetForDocumentWindow: (NSWindow *) window delegate: (id) delegate; - (IBAction) sizePresetsMenuItemSelected_CustomDimensions: (id) sender; - (IBAction) sizePresetsMenuItemSelected_PresetSize: (id) sender; - (IBAction) sizePresetsMenuItemSelected_EditSizePresets: (id) sender; @end @interface NSObject (PPDocumentSizeSheetDelegateMethods) - (void) documentSizeSheetDidFinishWithWidth: (int) width andHeight: (int) height; - (void) documentSizeSheetDidCancel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentSizeSheetController.m0000644000076500000240000002224713234403206024245 0ustar joshstaff/* PPDocumentSizeSheetController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentSizeSheetController.h" #import "PPDefines.h" #import "NSTextField_PPUtilities.h" #import "PPGeometry.h" #import "PPImageSizePresets.h" #import "PPDocumentEditImageSizePresetsSheetController.h" #import "PPTitleablePopUpButton.h" #define kDocumentSizeSheetNibName @"DocumentSizeSheet" #define kTagOfSizeMenuItem_CustomDimensions 900 #define kTagOfSizeMenuItem_InsertionPoint 1000 static int gLastSelectedWidth = kDefaultCanvasDimension; static int gLastSelectedHeight = kDefaultCanvasDimension; @interface PPDocumentSizeSheetController (PrivateMethods) - initWithDelegate: (id) delegate; - (void) addAsObserverForPPImageSizePresetsNotifications; - (void) removeAsObserverForPPImageSizePresetsNotifications; - (void) handlePPImageSizePresetsNotification_UpdatedPresets: (NSNotification *) notification; - (void) setupMenuForSizePresetsPopUpButton; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPDocumentSizeSheetController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPDocumentSizeSheetController + (bool) beginSizeSheetForDocumentWindow: (NSWindow *) window delegate: (id) delegate { PPDocumentSizeSheetController *controller; controller = [[[self alloc] initWithDelegate: delegate] autorelease]; if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } - initWithDelegate: (id) delegate { self = [super initWithNibNamed: kDocumentSizeSheetNibName delegate: delegate]; if (!self) goto ERROR; [_sizePresetsTitleablePopUpButton setDelegate: self]; _widthTextFieldValue = gLastSelectedWidth; [_widthTextField setIntValue: _widthTextFieldValue]; [_widthTextField setDelegate: self]; _heightTextFieldValue = gLastSelectedHeight; [_heightTextField setIntValue: _heightTextFieldValue]; [_heightTextField setDelegate: self]; [self setupMenuForSizePresetsPopUpButton]; [self addAsObserverForPPImageSizePresetsNotifications]; return self; ERROR: [self release]; return nil; } - init { return [self initWithDelegate: nil]; } - (void) dealloc { [_sizePresetsTitleablePopUpButton setDelegate: nil]; [self removeAsObserverForPPImageSizePresetsNotifications]; [super dealloc]; } #pragma mark Actions - (IBAction) sizePresetsMenuItemSelected_CustomDimensions: (id) sender { } - (IBAction) sizePresetsMenuItemSelected_PresetSize: (id) sender { NSSize presetSize = PPImageSizePresets_SizeForPresetString([sender title]); if (PPGeometry_IsZeroSize(presetSize)) { return; } _widthTextFieldValue = presetSize.width; [_widthTextField setIntValue: _widthTextFieldValue]; _heightTextFieldValue = presetSize.height; [_heightTextField setIntValue: _heightTextFieldValue]; [_widthTextField selectText: self]; } - (IBAction) sizePresetsMenuItemSelected_EditSizePresets: (id) sender { [PPDocumentEditImageSizePresetsSheetController beginEditImageSizePresetsSheetForWindow: _sheet delegate: self]; } #pragma mark PPDocumentSheetController overrides (actions) - (IBAction) OKButtonPressed: (id) sender { [super OKButtonPressed: sender]; gLastSelectedWidth = _widthTextFieldValue; gLastSelectedHeight = _heightTextFieldValue; } #pragma mark PPDocumentSheetController overrides (delegate notifiers) - (void) notifyDelegateSheetDidFinish { if ([_delegate respondsToSelector: @selector(documentSizeSheetDidFinishWithWidth:andHeight:)]) { [_delegate documentSizeSheetDidFinishWithWidth: _widthTextFieldValue andHeight: _heightTextFieldValue]; } } - (void) notifyDelegateSheetDidCancel { if ([_delegate respondsToSelector: @selector(documentSizeSheetDidCancel)]) { [_delegate documentSizeSheetDidCancel]; } } #pragma mark PPTitleablePopUpButton delegate methods - (NSString *) displayTitleForMenuItemWithTitle: (NSString *) itemTitle onTitleablePopUpButton: (PPTitleablePopUpButton *) button { return PPImageSizePresets_NameForPresetString(itemTitle); } #pragma mark NSTextField delegate methods (width/height textfields) - (void) controlTextDidChange: (NSNotification *) notification { id notifyingObject = [notification object]; if (notifyingObject == _widthTextField) { _widthTextFieldValue = [_widthTextField ppClampIntValueToMax: kMaxCanvasDimension min: kMinCanvasDimension defaultValue: _widthTextFieldValue]; } else if (notifyingObject == _heightTextField) { _heightTextFieldValue = [_heightTextField ppClampIntValueToMax: kMaxCanvasDimension min: kMinCanvasDimension defaultValue: _heightTextFieldValue]; } if ([_sizePresetsTitleablePopUpButton indexOfSelectedItem] != _indexOfSizePresetsMenuItem_CustomDimensions) { [_sizePresetsTitleablePopUpButton selectItemAtIndex: _indexOfSizePresetsMenuItem_CustomDimensions]; } } #pragma mark PPDocumentEditImageSizePresetsSheetController delegate methods - (void) editImageSizePresetsSheetDidFinish { [self setupMenuForSizePresetsPopUpButton]; } - (void) editImageSizePresetsSheetDidCancel { [self setupMenuForSizePresetsPopUpButton]; } #pragma mark PPImageSizePresets notifications - (void) addAsObserverForPPImageSizePresetsNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPImageSizePresetsNotification_UpdatedPresets:) name: PPImageSizePresetsNotification_UpdatedPresets object: nil]; } - (void) removeAsObserverForPPImageSizePresetsNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPImageSizePresetsNotification_UpdatedPresets object: nil]; } - (void) handlePPImageSizePresetsNotification_UpdatedPresets: (NSNotification *) notification { [self setupMenuForSizePresetsPopUpButton]; } #pragma mark Private methods - (void) setupMenuForSizePresetsPopUpButton { NSMenu *popUpButtonMenu; int insertionIndex, indexOfItemToSelect; NSSize currentSize, presetSize; NSEnumerator *presetEnumerator; NSString *presetTitle; NSMenuItem *presetItem; popUpButtonMenu = [[_defaultSizePresetsMenu copy] autorelease]; insertionIndex = [popUpButtonMenu indexOfItemWithTag: kTagOfSizeMenuItem_InsertionPoint]; indexOfItemToSelect = -1; currentSize = NSMakeSize(_widthTextFieldValue, _heightTextFieldValue); presetEnumerator = [[PPImageSizePresets presetStrings] objectEnumerator]; while (presetTitle = [presetEnumerator nextObject]) { presetSize = PPImageSizePresets_SizeForPresetString(presetTitle); if (!PPGeometry_IsZeroSize(presetSize)) { if (NSEqualSizes(presetSize, currentSize)) { indexOfItemToSelect = insertionIndex; } presetItem = [[[NSMenuItem alloc] initWithTitle: presetTitle action: @selector(sizePresetsMenuItemSelected_PresetSize:) keyEquivalent: @""] autorelease]; [presetItem setTarget: self]; [popUpButtonMenu insertItem: presetItem atIndex: insertionIndex++]; } } _indexOfSizePresetsMenuItem_CustomDimensions = [popUpButtonMenu indexOfItemWithTag: kTagOfSizeMenuItem_CustomDimensions]; if (indexOfItemToSelect < 0) { indexOfItemToSelect = _indexOfSizePresetsMenuItem_CustomDimensions; } [_sizePresetsTitleablePopUpButton setMenu: popUpButtonMenu]; [_sizePresetsTitleablePopUpButton selectItemAtIndex: indexOfItemToSelect]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentTypes.h0000644000076500000240000000533113234403416021373 0ustar joshstaff/* PPDocumentTypes.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import typedef enum { kPPPenMode_Fill, kPPPenMode_Erase } PPPenMode; typedef enum { kPPSelectionMode_Replace, kPPSelectionMode_Intersect, kPPSelectionMode_Add, kPPSelectionMode_Subtract, kNumPPSelectionModes } PPSelectionMode; typedef enum { kPPPixelMatchingMode_Borders, kPPPixelMatchingMode_BordersAndDiagonals, kPPPixelMatchingMode_Anywhere } PPPixelMatchingMode; typedef enum { kPPLayerOperationTarget_DrawingLayerOnly, kPPLayerOperationTarget_VisibleLayers, kPPLayerOperationTarget_Canvas, kNumPPLayerOperationTargets } PPLayerOperationTarget; typedef enum { kPPLayerBlendingMode_Standard, kPPLayerBlendingMode_Linear, kNumPPLayerBlendingModes } PPLayerBlendingMode; typedef enum { kPPMoveOperationType_Normal, kPPMoveOperationType_LeaveCopyInPlace, kPPMoveOperationType_SelectionOutlineOnly, kNumPPMoveOperationTypes } PPMoveOperationType; typedef enum { kPPDocumentSaveFormat_Normal, kPPDocumentSaveFormat_Export, kPPDocumentSaveFormat_Autosave } PPDocumentSaveFormat; static inline bool PPSelectionMode_IsValid(PPSelectionMode selectionMode) { return (((unsigned) selectionMode) < kNumPPSelectionModes) ? YES : NO; } static inline bool PPLayerOperationTarget_IsValid(PPLayerOperationTarget layerOperationTarget) { return (((unsigned) layerOperationTarget) < kNumPPLayerOperationTargets) ? YES : NO; } static inline bool PPLayerBlendingMode_IsValid(PPLayerBlendingMode layerBlendingMode) { return (((unsigned) layerBlendingMode) < kNumPPLayerBlendingModes) ? YES : NO; } static inline bool PPMoveOperationType_IsValid(PPMoveOperationType moveType) { return (((unsigned) moveType) < kNumPPMoveOperationTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindow.h0000644000076500000240000000204413234403416021534 0ustar joshstaff/* PPDocumentWindow.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPDocumentWindow : NSWindow { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindow.m0000644000076500000240000001105113234403206021534 0ustar joshstaff/* PPDocumentWindow.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentWindow.h" #import "PPModifierKeyMasks.h" #import "PPKeyConstants.h" #import "PPPopupPanelsController.h" #import "PPDocumentWindowController.h" static bool ShouldForwardKeyCharsToWindowController(NSString *keyChars); static NSCharacterSet *TabAndEscKeysCharSet(void); static NSCharacterSet *ArrowKeysCharSet(void); @implementation PPDocumentWindow #pragma mark NSWindow overrides - (void) sendEvent: (NSEvent *) theEvent { NSEventType eventType = [theEvent type]; // Intercept certain non-modifier key events & forward them directly to the // window controller, otherwise Cocoa handles them if (((eventType == NSKeyDown) || (eventType == NSKeyUp)) && !([theEvent modifierFlags] & kModifierKeyMask_RecognizedModifierKeys) && (ShouldForwardKeyCharsToWindowController([theEvent charactersIgnoringModifiers]))) { SEL eventHandlerSelector = (eventType == NSKeyDown) ? @selector(keyDown:) : @selector(keyUp:); [[self windowController] performSelector: eventHandlerSelector withObject: theEvent]; } else { [super sendEvent: theEvent]; } } - (BOOL) validateMenuItem: (PPSDKNativeType_NSMenuItemPtr) menuItem { PPDocumentWindowController *ppWindowController = [self windowController]; if ([ppWindowController isKindOfClass: [PPDocumentWindowController class]] && [ppWindowController isTrackingMouseInCanvasView]) { return NO; } return [super validateMenuItem: menuItem]; } @end #pragma mark Private functions static bool ShouldForwardKeyCharsToWindowController(NSString *keyChars) { static NSCharacterSet *tabAndEscKeysCharSet = nil, *arrowKeysCharSet = nil; if (!tabAndEscKeysCharSet) { tabAndEscKeysCharSet = [TabAndEscKeysCharSet() retain]; if (!tabAndEscKeysCharSet) goto ERROR; } if (!arrowKeysCharSet) { arrowKeysCharSet = [ArrowKeysCharSet() retain]; if (!arrowKeysCharSet) goto ERROR; } if (!keyChars) goto ERROR; // Always forward Tab or Esc keys, otherwise Cocoa intercepts them if ([keyChars rangeOfCharacterFromSet: tabAndEscKeysCharSet].length) { return YES; } // Forward arrow keys if a popup is visible, otherwise they may be intercepted as menu key // equivalents if ([keyChars rangeOfCharacterFromSet: arrowKeysCharSet].length && [[PPPopupPanelsController sharedController] hasActivePopupPanel]) { return YES; } return NO; ERROR: return NO; } static NSCharacterSet *TabAndEscKeysCharSet(void) { unichar tabAndEscKeyChars[] = {kTabKeyChar, kEscKeyChar}; NSString *tabAndEscKeysString = [NSString stringWithCharacters: tabAndEscKeyChars length: sizeof(tabAndEscKeyChars) / sizeof(*tabAndEscKeyChars)]; if (!tabAndEscKeysString) goto ERROR; return [NSCharacterSet characterSetWithCharactersInString: tabAndEscKeysString]; ERROR: return nil; } static NSCharacterSet *ArrowKeysCharSet(void) { unichar arrowKeyChars[] = {NSLeftArrowFunctionKey, NSRightArrowFunctionKey, NSUpArrowFunctionKey, NSDownArrowFunctionKey}; NSString *arrowKeysString = [NSString stringWithCharacters: arrowKeyChars length: sizeof(arrowKeyChars) / sizeof(*arrowKeyChars)]; if (!arrowKeysString) goto ERROR; return [NSCharacterSet characterSetWithCharactersInString: arrowKeysString]; ERROR: return nil; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindowController.h0000644000076500000240000001425413234403416023606 0ustar joshstaff/* PPDocumentWindowController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPLayerDisplayMode.h" @class PPDocument, PPCanvasView, PPPanelsController, PPPopupPanelsController; @interface PPDocumentWindowController : NSWindowController { PPDocument *_ppDocument; IBOutlet PPCanvasView *_canvasView; PPLayerDisplayMode _canvasDisplayMode; PPLayerDisplayMode _canvasDisplayModeToRestore; NSPoint _mouseDownLocation; NSPoint _lastMouseLocation; PPPanelsController *_panelsController; PPPopupPanelsController *_popupPanelsController; NSString *_pressedHotkeyForActivePopupPanel; NSTimer *_popupPanelHotkeyRepeatTimeoutTimer; unsigned _modifierKeyFlags; unsigned _lockedActiveToolModifierKeyFlags; bool _documentWindowIsKey; bool _isTrackingMouseInCanvasView; bool _shouldUseImageCoordinatesForMouseLocation; bool _shouldClipMouseLocationPointsToCanvasBounds; bool _activeToolCursorDependsOnModifierKeys; bool _shouldMatchCanvasDisplayModeToOperationTargetWhileTrackingMouse; bool _disallowMatchingCanvasDisplayModeToDrawLayerTarget; bool _shouldUpdateActiveToolOnMouseUp; } + controller; - (PPCanvasView *) canvasView; - (void) setCanvasDisplayMode: (PPLayerDisplayMode) canvasDisplayMode; - (void) toggleCanvasDisplayMode; - (PPLayerDisplayMode) canvasDisplayMode; - (bool) isTrackingMouseInCanvasView; @end @interface PPDocumentWindowController (Actions) // File - (IBAction) newDocumentFromSelection: (id) sender; - (IBAction) exportImage: (id) sender; // Edit - (IBAction) cut: (id) sender; - (IBAction) copy: (id) sender; - (IBAction) paste: (id) sender; - (IBAction) pasteIntoActiveLayer: (id) sender; - (IBAction) delete: (id) sender; - (IBAction) selectAll: (id) sender; - (IBAction) deselectAll: (id) sender; - (IBAction) selectVisibleTargetPixels: (id) sender; - (IBAction) deselectInvisibleTargetPixels: (id) sender; - (IBAction) invertSelection: (id) sender; - (IBAction) nudgeSelectionOutlineLeft: (id) sender; - (IBAction) nudgeSelectionOutlineRight: (id) sender; - (IBAction) nudgeSelectionOutlineUp: (id) sender; - (IBAction) nudgeSelectionOutlineDown: (id) sender; - (IBAction) closeHolesInSelection: (id) sender; - (IBAction) fillSelectedPixels: (id) sender; - (IBAction) eraseSelectedPixels: (id) sender; - (IBAction) tileSelection: (id) sender; - (IBAction) tileSelectionAsNewLayer: (id) sender; // Layer - (IBAction) newLayer: (id) sender; - (IBAction) duplicateActiveLayer: (id) sender; - (IBAction) deleteActiveLayer: (id) sender; - (IBAction) toggleActiveLayerEnabledFlag: (id) sender; - (IBAction) enableAllLayers: (id) sender; - (IBAction) disableAllLayers: (id) sender; - (IBAction) increaseActiveLayerOpacity: (id) sender; - (IBAction) decreaseActiveLayerOpacity: (id) sender; - (IBAction) makePreviousLayerActive: (id) sender; - (IBAction) makeNextLayerActive: (id) sender; - (IBAction) moveActiveLayerUp: (id) sender; - (IBAction) moveActiveLayerDown: (id) sender; - (IBAction) mergeWithLayerAbove: (id) sender; - (IBAction) mergeWithLayerBelow: (id) sender; - (IBAction) mergeAllLayers: (id) sender; - (IBAction) toggleLayerBlendingMode: (id) sender; // Canvas - (IBAction) toggleCanvasDisplayMode: (id) sender; - (IBAction) increaseZoom: (id) sender; - (IBAction) decreaseZoom: (id) sender; - (IBAction) zoomToFit: (id) sender; - (IBAction) editGridSettings: (id) sender; - (IBAction) toggleGridVisibility: (id) sender; - (IBAction) toggleGridType: (id) sender; - (IBAction) toggleGridGuidelinesVisibility: (id) sender; - (IBAction) editBackgroundSettings: (id) sender; - (IBAction) toggleBackgroundImageVisibility: (id) sender; - (IBAction) toggleBackgroundImageSmoothing: (id) sender; - (IBAction) flipCanvasHorizontally: (id) sender; - (IBAction) flipCanvasVertically: (id) sender; - (IBAction) rotateCanvas90Clockwise: (id) sender; - (IBAction) rotateCanvas90Counterclockwise: (id) sender; - (IBAction) rotateCanvas180: (id) sender; - (IBAction) resize: (id) sender; - (IBAction) scale: (id) sender; - (IBAction) cropToSelection: (id) sender; // Operation - (IBAction) toggleLayerOperationTarget: (id) sender; - (IBAction) flipHorizontally: (id) sender; - (IBAction) flipVertically: (id) sender; - (IBAction) rotate90Clockwise: (id) sender; - (IBAction) rotate90Counterclockwise: (id) sender; - (IBAction) rotate180: (id) sender; - (IBAction) nudgeLeft: (id) sender; - (IBAction) nudgeRight: (id) sender; - (IBAction) nudgeUp: (id) sender; - (IBAction) nudgeDown: (id) sender; // Panels - (IBAction) toggleToolsPanelVisibility: (id) sender; - (IBAction) toggleLayersPanelVisibility: (id) sender; - (IBAction) togglePreviewPanelVisibility: (id) sender; - (IBAction) toggleSamplerImagePanelVisibility: (id) sender; - (IBAction) toggleToolModifierTipsPanelVisibility: (id) sender; - (IBAction) toggleActivePanelsVisibility: (id) sender; - (IBAction) toggleColorPickerVisibility: (id) sender; - (IBAction) editSamplerImagesSettings: (id) sender; - (IBAction) nextSamplerPanelImage: (id) sender; - (IBAction) previousSamplerPanelImage: (id) sender; // Important: Keep IBAction method names in sync with relevant action name strings in // +setupHotkeyToActionSelectorNameDict class method (PPDocumentWindowController.m) @end extern NSString *PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode; PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindowController.m0000644000076500000240000012513513752024270023616 0ustar joshstaff/* PPDocumentWindowController.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentWindowController.h" #import "PPDocumentWindowController_Notifications.h" #import "PPModifierKeyMasks.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPDocumentWindowController_Sheets.h" #import "PPPanelsController.h" #import "PPPopupPanelsController.h" #import "PPToolbox.h" #import "PPTool.h" #import "PPModifiablePPToolTypesMasks.h" #import "NSColor_PPUtilities.h" #import "PPHotkeys.h" #import "PPGeometry.h" #import "PPDirectionType.h" #import "NSObject_PPUtilities.h" #import "PPCursorManager.h" #import "PPLayerControlButtonImagesManager.h" #define kWindowNibName @"DocumentWindow" #define kNewWindowScreenMargin_Sides 330 #define kNewWindowScreenMargin_Top 5 #define kNewWindowScreenMargin_Bottom 120 #define kHotkeyRepeatTimeoutInterval 0.7f static NSSize gNewWindowContentSize = {0,0}; static NSPoint gNewWindowCascadePoint = {0,0}; static NSDictionary *gHotkeyToActionSelectorNameDict = nil; @interface PPDocumentWindowController (PrivateMethods) - (void) addAsObserverForPPDocumentNotifications; - (void) removeAsObserverForPPDocumentNotifications; - (void) handlePPDocumentNotification_UpdatedMergedVisibleArea: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedDrawingLayerArea: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedSelection: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedSelectedTool: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedGridSettings: (NSNotification *) notification; - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedActiveSamplerImage: (NSNotification *) notification; - (void) addAsObserverForPPCanvasViewNotifications; - (void) removeAsObserverForPPCanvasViewNotifications; - (void) handlePPCanvasViewNotification_ChangedZoomFactor: (NSNotification *) notification; - (void) addAsObserverForNSWindowWillMoveNotifications; - (void) removeAsObserverForNSWindowWillMoveNotifications; - (void) handleNSWindowNotification_WillMove: (NSNotification *) notification; - (void) addAsObserverForNSMenuDidEndTrackingNotifications; - (void) removeAsObserverForNSMenuDidEndTrackingNotifications; - (void) handleNSMenuNotification_DidEndTracking: (NSNotification *) notification; + (void) addAsObserverForPPHotkeysNotifications; + (void) removeAsObserverForPPHotkeysNotifications; + (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification; - (void) startPopupPanelHotkeyRepeatTimeoutTimer; - (void) stopPopupPanelHotkeyRepeatTimeoutTimer; - (void) popupPanelHotkeyRepeatTimeoutTimerDidFire: (NSTimer *) timer; + (void) setupNewWindowGlobals; + (void) setupHotkeyToActionSelectorNameDict; - (void) positionNewWindow; - (void) setupWindowForCurrentPPDocument; - (void) setupCanvasViewForCurrentPPDocument; - (void) setupCanvasViewBitmap; - (void) matchCanvasDisplayModeToOperationTarget; - (void) restoreCanvasDisplayModeFromOperationTarget; - (void) setupPanelsWithPPDocument: (PPDocument *) ppDocument; - (void) setActivePopupPanelType: (PPPopupPanelType) popupPanelType withPressedHotkey: (NSString *) pressedHotkey; - (void) hideActivePopupPanel; - (bool) getDirectionType: (PPDirectionType *) returnedDirectionType forArrowKey: (NSString *) key; - (bool) handleActionKey: (NSString *) key; - (void) updateKeyboardStateForResumedKeyboardEvents; - (NSPoint) mouseLocationFromEvent: (NSEvent *) event clippedToCanvasBounds: (bool) shouldClipToCanvasBounds; - (void) updateModifierKeyFlags: (unsigned) modifierKeyFlags; - (void) updateModifierKeyFlagsFromCurrentKeyboardState; - (void) updateActiveTool; - (void) updateCanvasViewToolCursorForActiveTool; - (PPToolType) modifiedToolTypeForSelectedToolType: (PPToolType) selectedToolType; @end @implementation PPDocumentWindowController + (void) initialize { if ([self class] != [PPDocumentWindowController class]) { return; } [self setupNewWindowGlobals]; [PPHotkeys setupGlobals]; [self setupHotkeyToActionSelectorNameDict]; [self addAsObserverForPPHotkeysNotifications]; } + controller { return [[[self alloc] init] autorelease]; } - init { self = [super initWithWindowNibName: kWindowNibName]; if (!self) goto ERROR; _panelsController = [[PPPanelsController sharedController] retain]; _popupPanelsController = [[PPPopupPanelsController sharedController] retain]; if (!_panelsController || !_popupPanelsController) { goto ERROR; } return self; ERROR: [self release]; return nil; } - (void) dealloc { [self removeAsObserverForPPCanvasViewNotifications]; [self removeAsObserverForNSWindowWillMoveNotifications]; [self removeAsObserverForNSMenuDidEndTrackingNotifications]; [self hideActivePopupPanel]; [_panelsController release]; [_popupPanelsController release]; [super dealloc]; } - (PPCanvasView *) canvasView { return _canvasView; } - (void) setCanvasDisplayMode: (PPLayerDisplayMode) canvasDisplayMode { if (_isTrackingMouseInCanvasView) return; if (canvasDisplayMode != kPPLayerDisplayMode_DrawingLayerOnly) { canvasDisplayMode = kPPLayerDisplayMode_VisibleLayers; } if (_canvasDisplayMode == canvasDisplayMode) { return; } _canvasDisplayMode = canvasDisplayMode; [self setupCanvasViewBitmap]; [self postNotification_ChangedCanvasDisplayMode]; } - (void) toggleCanvasDisplayMode { PPLayerDisplayMode newDisplayMode; if (_canvasDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { newDisplayMode = kPPLayerDisplayMode_VisibleLayers; } else { newDisplayMode = kPPLayerDisplayMode_DrawingLayerOnly; } [self setCanvasDisplayMode: newDisplayMode]; } - (PPLayerDisplayMode) canvasDisplayMode { return _canvasDisplayMode; } - (bool) isTrackingMouseInCanvasView { return _isTrackingMouseInCanvasView; } #pragma mark NSWindowController overrides - (void) mouseDown: (NSEvent *) theEvent { if (![_canvasView windowPointIsInsideVisibleCanvas: [theEvent locationInWindow]]) { return; } [_ppDocument disableAutosaving: YES]; [self updateModifierKeyFlags: [theEvent modifierFlags]]; if (_shouldMatchCanvasDisplayModeToOperationTargetWhileTrackingMouse) { [self matchCanvasDisplayModeToOperationTarget]; } [_canvasView setIsDraggingTool: YES]; _isTrackingMouseInCanvasView = YES; _mouseDownLocation = _lastMouseLocation = [self mouseLocationFromEvent: theEvent clippedToCanvasBounds: YES]; [[_ppDocument activeTool] mouseDownForDocument: _ppDocument withCanvasView: _canvasView currentPoint: _mouseDownLocation modifierKeyFlags: _modifierKeyFlags]; [_canvasView setShouldAnimateSelectionOutline: NO]; } - (void) mouseDragged: (NSEvent *) theEvent { NSPoint mouseLocation; if (!_isTrackingMouseInCanvasView) return; mouseLocation = [self mouseLocationFromEvent: theEvent clippedToCanvasBounds: _shouldClipMouseLocationPointsToCanvasBounds]; if (NSEqualPoints(mouseLocation, _lastMouseLocation) && ![_canvasView isAutoscrolling]) { return; } [[_ppDocument activeTool] mouseDraggedOrModifierKeysChangedForDocument: _ppDocument withCanvasView: _canvasView currentPoint: mouseLocation lastPoint: _lastMouseLocation mouseDownPoint: _mouseDownLocation modifierKeyFlags: _modifierKeyFlags]; _lastMouseLocation = mouseLocation; } - (void) mouseUp: (NSEvent *) theEvent { NSPoint mouseLocation; [_canvasView setShouldAnimateSelectionOutline: [[self window] isKeyWindow]]; if (!_isTrackingMouseInCanvasView) return; [_canvasView setIsDraggingTool: NO]; _isTrackingMouseInCanvasView = NO; mouseLocation = [self mouseLocationFromEvent: theEvent clippedToCanvasBounds: _shouldClipMouseLocationPointsToCanvasBounds]; [[_ppDocument activeTool] mouseUpForDocument: _ppDocument withCanvasView: _canvasView currentPoint: mouseLocation mouseDownPoint: _mouseDownLocation modifierKeyFlags: _modifierKeyFlags]; if (_shouldMatchCanvasDisplayModeToOperationTargetWhileTrackingMouse) { [self restoreCanvasDisplayModeFromOperationTarget]; } _lockedActiveToolModifierKeyFlags = _modifierKeyFlags; if (_shouldUpdateActiveToolOnMouseUp) { [self updateActiveTool]; _shouldUpdateActiveToolOnMouseUp = NO; } [_ppDocument disableAutosaving: NO]; } - (void) keyDown: (NSEvent *) theEvent { NSString *key; unsigned modifierFlags; PPPopupPanelType popupPanelType; PPToolType toolType; PPDirectionType directionType; key = [theEvent charactersIgnoringModifiers]; modifierFlags = [theEvent modifierFlags]; [self updateModifierKeyFlags: modifierFlags]; if (_popupPanelHotkeyRepeatTimeoutTimer && [key rangeOfString: _pressedHotkeyForActivePopupPanel].length) { [self stopPopupPanelHotkeyRepeatTimeoutTimer]; } if (modifierFlags & kModifierKeyMask_RecognizedModifierKeys) { return; } // key commands that are permitted while tracking mouse if ([key isEqualToString: gHotkeys[kPPHotkeyType_BlinkDocumentLayers]]) { [_canvasView setDocumentLayersVisibility: NO]; return; } if (_isTrackingMouseInCanvasView) return; // key commands that are NOT permitted while tracking mouse if ([_popupPanelsController hasActivePopupPanel]) { if ([key isEqualToString: _pressedHotkeyForActivePopupPanel]) { return; } if ([_popupPanelsController handleActionKey: key]) { return; } } else if ([_popupPanelsController getPopupPanelType: &popupPanelType forKey: key]) { [self setActivePopupPanelType: popupPanelType withPressedHotkey: key]; return; } if ([PPToolbox getToolType: &toolType forKey: key]) { [_ppDocument setSelectedToolType: toolType]; return; } if ([self getDirectionType: &directionType forArrowKey: key]) { if ([_popupPanelsController hasActivePopupPanel]) { [_popupPanelsController handleDirectionCommand: directionType]; } return; } [self handleActionKey: key]; } - (void) keyUp: (NSEvent *) theEvent { NSString *eventChars = [theEvent charactersIgnoringModifiers]; if (_pressedHotkeyForActivePopupPanel && [eventChars rangeOfString: _pressedHotkeyForActivePopupPanel].length) { [self hideActivePopupPanel]; } if ([eventChars rangeOfString: gHotkeys[kPPHotkeyType_BlinkDocumentLayers]].length) { [_canvasView setDocumentLayersVisibility: YES]; } } - (void) flagsChanged: (NSEvent *) theEvent { [self updateModifierKeyFlags: [theEvent modifierFlags]]; } - (void) windowDidLoad { [super windowDidLoad]; [self positionNewWindow]; [self showWindow: self]; // window positioning may not take effect until the next stack frame, so delay any sheets // until a new stack frame as well, otherwise the window may temporarily remain in its // original position while the sheet's pulldown animation (which begins immediately) // displays if ([_ppDocument needToSetCanvasSize]) { [self ppPerformSelectorFromNewStackFrame: @selector(beginSizeSheet)]; } else { [self setupWindowForCurrentPPDocument]; if ([_ppDocument sourceBitmapHasAnimationFrames]) { [self ppPerformSelectorFromNewStackFrame: @selector(beginAnimationFileNoticeSheet)]; } } [self addAsObserverForPPCanvasViewNotifications]; } - (void) setDocument: (NSDocument *) document { if (_ppDocument) { [self removeAsObserverForPPDocumentNotifications]; } [super setDocument: document]; if ([document isKindOfClass: [PPDocument class]]) { _ppDocument = (PPDocument *) document; [self addAsObserverForPPDocumentNotifications]; [self updateActiveTool]; } else { _ppDocument = nil; } } - (NSString *) windowTitleForDocumentDisplayName: (NSString *) displayName { NSSize canvasSize = [_ppDocument canvasSize]; if (!PPGeometry_IsZeroSize(canvasSize)) { NSString *zoomSuffix = [NSString stringWithFormat: @" (%dx%d) (%dx)", (int) canvasSize.width, (int) canvasSize.height, (int) [_canvasView zoomFactor]]; displayName = [displayName stringByAppendingString: zoomSuffix]; } return displayName; } #pragma mark PPDocumentWindow delegate methods - (void) windowDidBecomeMain: (NSNotification *) notification { // need to know when any window is about to move, in order to disable any active popups // (no keyUp events are received while a window's being moved, so an active popup can get // stuck visible if the user releases the key while moving) [self addAsObserverForNSWindowWillMoveNotifications]; [self addAsObserverForNSMenuDidEndTrackingNotifications]; if (_ppDocument && ![_ppDocument needToSetCanvasSize]) { [self setupPanelsWithPPDocument: _ppDocument]; } } - (void) windowDidResignMain: (NSNotification *) notification { [self removeAsObserverForNSWindowWillMoveNotifications]; [self removeAsObserverForNSMenuDidEndTrackingNotifications]; [self setupPanelsWithPPDocument: nil]; } - (void) windowDidBecomeKey: (NSNotification *) notification { _documentWindowIsKey = YES; [[PPCursorManager sharedManager] setCurrentDocumentWindow: [self window]]; [_canvasView setShouldAnimateSelectionOutline: YES]; // clear _modifierKeyFlags so that _lockedActiveToolModifierKeyFlags is also cleared (don't // use locked-key flags held over from last time the window was key), and the active tool // is reset to the (unmodified) selected tool (ignore the modifier-key state until the // first state-change after becoming key) [self updateModifierKeyFlags: 0]; } - (void) windowDidResignKey: (NSNotification *) notification { _documentWindowIsKey = NO; [[PPCursorManager sharedManager] clearCurrentDocumentWindow: [self window]]; [_canvasView setShouldAnimateSelectionOutline: NO]; [_canvasView setDocumentLayersVisibility: YES]; // hide active popup from new stack frame - ColorPicker's ColorPanel can become // unresponsive if it becomes key and gets hidden in the same stack frame [self ppPerformSelectorFromNewStackFrame: @selector(hideActivePopupPanel)]; } - (void) windowWillClose: (NSNotification *) notification { if ([[self window] isMainWindow]) { [self setupPanelsWithPPDocument: nil]; } } #if PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY - (void) windowDidChangeBackingProperties: (NSNotification *) notification { [_canvasView setupRetinaDrawingForCurrentDisplay]; } #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY #pragma mark PPDocument notifications - (void) addAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; if (!_ppDocument) return; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedMergedVisibleArea:) name: PPDocumentNotification_UpdatedMergedVisibleArea object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedDrawingLayerArea:) name: PPDocumentNotification_UpdatedDrawingLayerArea object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedSelection:) name: PPDocumentNotification_UpdatedSelection object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedSelectedTool:) name: PPDocumentNotification_SwitchedSelectedTool object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedBackgroundSettings:) name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedGridSettings:) name: PPDocumentNotification_UpdatedGridSettings object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ReloadedDocument:) name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedActiveSamplerImage:) name: PPDocumentNotification_SwitchedActiveSamplerImage object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: nil object: _ppDocument]; } - (void) handlePPDocumentNotification_UpdatedMergedVisibleArea: (NSNotification *) notification { NSDictionary *userInfo; NSValue *updateRectValue; if (_canvasDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { return; } userInfo = [notification userInfo]; updateRectValue = [userInfo objectForKey: PPDocumentNotification_UserInfoKey_UpdateAreaRect]; if (!updateRectValue) return; [_canvasView handleUpdateToCanvasBitmapInRect: [updateRectValue rectValue]]; } - (void) handlePPDocumentNotification_UpdatedDrawingLayerArea: (NSNotification *) notification { NSDictionary *userInfo; NSValue *updateRectValue; if (_canvasDisplayMode != kPPLayerDisplayMode_DrawingLayerOnly) { return; } userInfo = [notification userInfo]; updateRectValue = [userInfo objectForKey: PPDocumentNotification_UserInfoKey_UpdateAreaRect]; if (!updateRectValue) return; [_canvasView handleUpdateToCanvasBitmapInRect: [updateRectValue rectValue]]; } - (void) handlePPDocumentNotification_UpdatedSelection: (NSNotification *) notification { [_canvasView setSelectionOutlineToMask: [_ppDocument selectionMask] maskBounds: [_ppDocument selectionBounds]]; } - (void) handlePPDocumentNotification_SwitchedSelectedTool: (NSNotification *) notification { [self updateActiveTool]; } - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification { [_canvasView setBackgroundImage: [_ppDocument backgroundImage] backgroundImageVisibility: [_ppDocument shouldDisplayBackgroundImage] backgroundImageSmoothing: [_ppDocument shouldSmoothenBackgroundImage] backgroundColor: [_ppDocument backgroundPatternAsColor]]; } - (void) handlePPDocumentNotification_UpdatedGridSettings: (NSNotification *) notification { [_canvasView setGridPattern: [_ppDocument gridPattern] gridVisibility: [_ppDocument shouldDisplayGrid]]; } - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification { [self setupWindowForCurrentPPDocument]; } - (void) handlePPDocumentNotification_SwitchedActiveSamplerImage: (NSNotification *) notification { PPPopupPanelType popupPanelTypeForPressedKey; NSNumber *samplerImagePanelTypeNumber; if (![_popupPanelsController hasActivePopupPanel] || ![_popupPanelsController getPopupPanelType: &popupPanelTypeForPressedKey forKey: _pressedHotkeyForActivePopupPanel] || (popupPanelTypeForPressedKey != kPPPopupPanelType_ColorPicker)) { return; } samplerImagePanelTypeNumber = [[notification userInfo] objectForKey: PPDocumentNotification_UserInfoKey_SamplerImagePanelType]; if (samplerImagePanelTypeNumber && ([samplerImagePanelTypeNumber intValue] != kPPSamplerImagePanelType_PopupPanel)) { return; } [_popupPanelsController setActivePopupPanel: kPPPopupPanelType_None]; // setActivePopupPanelType:... will switch the popup panel type from color picker to // sampler image if there's an active sampler image [self setActivePopupPanelType: kPPPopupPanelType_ColorPicker withPressedHotkey: _pressedHotkeyForActivePopupPanel]; } #pragma mark PPCanvasView notifications - (void) addAsObserverForPPCanvasViewNotifications { if (!_canvasView) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPCanvasViewNotification_ChangedZoomFactor:) name: PPCanvasViewNotification_ChangedZoomFactor object: _canvasView]; } - (void) removeAsObserverForPPCanvasViewNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPCanvasViewNotification_ChangedZoomFactor object: _canvasView]; } - (void) handlePPCanvasViewNotification_ChangedZoomFactor: (NSNotification *) notification { [self synchronizeWindowTitleWithDocumentName]; } #pragma mark NSWindow WillMove notifications - (void) addAsObserverForNSWindowWillMoveNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNSWindowNotification_WillMove:) name: NSWindowWillMoveNotification object: nil]; } - (void) removeAsObserverForNSWindowWillMoveNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSWindowWillMoveNotification object: nil]; } - (void) handleNSWindowNotification_WillMove: (NSNotification *) notification { // hide active popup from new stack frame to allow popup to cleanup first (ColorPicker) [self ppPerformSelectorFromNewStackFrame: @selector(hideActivePopupPanel)]; } #pragma mark NSMenu DidEndTracking notifications - (void) addAsObserverForNSMenuDidEndTrackingNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNSMenuNotification_DidEndTracking:) name: NSMenuDidEndTrackingNotification object: nil]; } - (void) removeAsObserverForNSMenuDidEndTrackingNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSMenuDidEndTrackingNotification object: nil]; } - (void) handleNSMenuNotification_DidEndTracking: (NSNotification *) notification { [self updateKeyboardStateForResumedKeyboardEvents]; } #pragma mark PPHotkeys notifications (Class object) + (void) addAsObserverForPPHotkeysNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPHotkeysNotification_UpdatedHotkeys:) name: PPHotkeysNotification_UpdatedHotkeys object: nil]; } + (void) removeAsObserverForPPHotkeysNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPHotkeysNotification_UpdatedHotkeys object: nil]; } + (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification { [self setupHotkeyToActionSelectorNameDict]; } #pragma mark Popup panel hotkey-repeat timeout timer - (void) startPopupPanelHotkeyRepeatTimeoutTimer { if (_popupPanelHotkeyRepeatTimeoutTimer) { [self stopPopupPanelHotkeyRepeatTimeoutTimer]; } if (!_pressedHotkeyForActivePopupPanel) return; _popupPanelHotkeyRepeatTimeoutTimer = [[NSTimer scheduledTimerWithTimeInterval: kHotkeyRepeatTimeoutInterval target: self selector: @selector(popupPanelHotkeyRepeatTimeoutTimerDidFire:) userInfo: nil repeats: NO] retain]; } - (void) stopPopupPanelHotkeyRepeatTimeoutTimer { if (!_popupPanelHotkeyRepeatTimeoutTimer) return; [_popupPanelHotkeyRepeatTimeoutTimer invalidate]; [_popupPanelHotkeyRepeatTimeoutTimer release]; _popupPanelHotkeyRepeatTimeoutTimer = nil; } - (void) popupPanelHotkeyRepeatTimeoutTimerDidFire: (NSTimer *) timer { [self hideActivePopupPanel]; } #pragma mark Private methods + (void) setupNewWindowGlobals { NSScreen *mainScreen; NSRect mainScreenFrame, mainScreenVisibleFrame, windowBounds; float distanceFromScreenEdge_Left, distanceFromScreenEdge_Right; mainScreen = [NSScreen mainScreen]; mainScreenFrame = [mainScreen frame]; mainScreenVisibleFrame = [mainScreen visibleFrame]; windowBounds = NSMakeRect(mainScreenVisibleFrame.origin.x + kNewWindowScreenMargin_Sides, mainScreenVisibleFrame.origin.y + kNewWindowScreenMargin_Bottom, mainScreenVisibleFrame.size.width - 2.0 * kNewWindowScreenMargin_Sides, mainScreenVisibleFrame.size.height - (kNewWindowScreenMargin_Top + kNewWindowScreenMargin_Bottom)); // crop width so (first, uncascaded) window is centered horizontally on the screen distanceFromScreenEdge_Left = NSMinX(windowBounds) - NSMinX(mainScreenFrame); distanceFromScreenEdge_Right = NSMaxX(mainScreenFrame) - NSMaxX(windowBounds); if (distanceFromScreenEdge_Left > distanceFromScreenEdge_Right) { windowBounds.size.width -= (distanceFromScreenEdge_Left - distanceFromScreenEdge_Right); } else if (distanceFromScreenEdge_Right > distanceFromScreenEdge_Left) { float widthAdjustment = distanceFromScreenEdge_Right - distanceFromScreenEdge_Left; windowBounds.size.width -= widthAdjustment; windowBounds.origin.x += widthAdjustment; } // don't allow initial window size to be taller than wide if (windowBounds.size.height > windowBounds.size.width) { windowBounds.origin.y += (windowBounds.size.height - windowBounds.size.width); windowBounds.size.height = windowBounds.size.width; } windowBounds = PPGeometry_PixelBoundsCoveredByRect(windowBounds); gNewWindowContentSize = windowBounds.size; gNewWindowCascadePoint = NSMakePoint(windowBounds.origin.x, NSMaxY(windowBounds)); } + (void) setupHotkeyToActionSelectorNameDict { [gHotkeyToActionSelectorNameDict release]; gHotkeyToActionSelectorNameDict = [[NSDictionary dictionaryWithObjectsAndKeys: // names must match IBAction methods @"toggleCanvasDisplayMode:", gHotkeys[kPPHotkeyType_SwitchCanvasViewMode], @"toggleLayerOperationTarget:", gHotkeys[kPPHotkeyType_SwitchLayerOperationTarget], @"toggleColorPickerVisibility:", gHotkeys[kPPHotkeyType_ToggleColorPickerPanel], @"toggleActivePanelsVisibility:", gHotkeys[kPPHotkeyType_ToggleActivePanels], @"increaseZoom:", gHotkeys[kPPHotkeyType_ZoomIn], @"decreaseZoom:", gHotkeys[kPPHotkeyType_ZoomOut], @"zoomToFit:", gHotkeys[kPPHotkeyType_ZoomToFit], nil] retain]; } - (void) positionNewWindow { NSWindow *window = [self window]; if (!PPGeometry_IsZeroSize(gNewWindowContentSize)) { [window setContentSize: gNewWindowContentSize]; } if (!NSEqualPoints(gNewWindowCascadePoint, NSZeroPoint)) { gNewWindowCascadePoint = [window cascadeTopLeftFromPoint: gNewWindowCascadePoint]; } } - (void) setupWindowForCurrentPPDocument { [self setupCanvasViewForCurrentPPDocument]; [self synchronizeWindowTitleWithDocumentName]; if ([[self window] isMainWindow]) { [self setupPanelsWithPPDocument: _ppDocument]; } } - (void) setupCanvasViewForCurrentPPDocument { [_canvasView setGridPattern: [_ppDocument gridPattern] gridVisibility: [_ppDocument shouldDisplayGrid]]; [self setupCanvasViewBitmap]; [_canvasView setBackgroundImage: [_ppDocument backgroundImage] backgroundImageVisibility: [_ppDocument shouldDisplayBackgroundImage] backgroundImageSmoothing: [_ppDocument shouldSmoothenBackgroundImage] backgroundColor: [_ppDocument backgroundPatternAsColor]]; [_canvasView setSelectionOutlineToMask: [_ppDocument selectionMask] maskBounds: [_ppDocument selectionBounds]]; [self updateCanvasViewToolCursorForActiveTool]; } - (void) setupCanvasViewBitmap { NSBitmapImageRep *displayBitmap; if (_canvasDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { displayBitmap = [_ppDocument dissolvedDrawingLayerBitmap]; } else { displayBitmap = [_ppDocument mergedVisibleLayersBitmap]; } [_canvasView setCanvasBitmap: displayBitmap]; } - (void) matchCanvasDisplayModeToOperationTarget { PPLayerDisplayMode newDisplayMode; _canvasDisplayModeToRestore = _canvasDisplayMode; if ([_ppDocument layerOperationTarget] == kPPLayerOperationTarget_DrawingLayerOnly) { if (_disallowMatchingCanvasDisplayModeToDrawLayerTarget) return; newDisplayMode = kPPLayerDisplayMode_DrawingLayerOnly; } else { newDisplayMode = kPPLayerDisplayMode_VisibleLayers; } if (_canvasDisplayMode == newDisplayMode) { return; } [self setCanvasDisplayMode: newDisplayMode]; } - (void) restoreCanvasDisplayModeFromOperationTarget { if (_canvasDisplayMode == _canvasDisplayModeToRestore) { return; } [self setCanvasDisplayMode: _canvasDisplayModeToRestore]; } - (void) setupPanelsWithPPDocument: (PPDocument *) ppDocument { [[PPLayerControlButtonImagesManager sharedManager] setPPDocument: ppDocument]; [_panelsController setPPDocument: ppDocument]; [self hideActivePopupPanel]; [_popupPanelsController setPPDocument: ppDocument]; } - (void) setActivePopupPanelType: (PPPopupPanelType) popupPanelType withPressedHotkey: (NSString *) pressedHotkey { if (_pressedHotkeyForActivePopupPanel != pressedHotkey) { [_pressedHotkeyForActivePopupPanel release]; _pressedHotkeyForActivePopupPanel = [pressedHotkey retain]; } if ((popupPanelType == kPPPopupPanelType_ColorPicker) && [_ppDocument hasActiveSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]) { popupPanelType = kPPPopupPanelType_SamplerImage; } [_popupPanelsController setActivePopupPanel: popupPanelType]; } - (void) hideActivePopupPanel { [self stopPopupPanelHotkeyRepeatTimeoutTimer]; [_pressedHotkeyForActivePopupPanel release]; _pressedHotkeyForActivePopupPanel = nil; [_popupPanelsController setActivePopupPanel: kPPPopupPanelType_None]; } - (bool) getDirectionType: (PPDirectionType *) returnedDirectionType forArrowKey: (NSString *) key { unichar keyChar; if (!returnedDirectionType || ![key length]) { return NO; } keyChar = [key characterAtIndex: 0]; switch (keyChar) { case NSLeftArrowFunctionKey: *returnedDirectionType = kPPDirectionType_Left; break; case NSRightArrowFunctionKey: *returnedDirectionType = kPPDirectionType_Right; break; case NSUpArrowFunctionKey: *returnedDirectionType = kPPDirectionType_Up; break; case NSDownArrowFunctionKey: *returnedDirectionType = kPPDirectionType_Down; break; default: *returnedDirectionType = kPPDirectionType_None; break; } return PPDirectionType_IsValid(*returnedDirectionType) ? YES : NO; } - (bool) handleActionKey: (NSString *) key { NSString *actionSelectorName; SEL actionSelector; actionSelectorName = [gHotkeyToActionSelectorNameDict objectForKey: key]; if (!actionSelectorName) goto ERROR; actionSelector = NSSelectorFromString(actionSelectorName); if (!actionSelector) goto ERROR; [self performSelector: actionSelector withObject: self]; return YES; ERROR: return NO; } - (void) updateKeyboardStateForResumedKeyboardEvents { if (_pressedHotkeyForActivePopupPanel) { [self startPopupPanelHotkeyRepeatTimeoutTimer]; } [self updateModifierKeyFlagsFromCurrentKeyboardState]; } - (NSPoint) mouseLocationFromEvent: (NSEvent *) event clippedToCanvasBounds: (bool) shouldClipToCanvasBounds { NSPoint mouseLocation; if (!event) goto ERROR; mouseLocation = [_canvasView convertPoint: [event locationInWindow] fromView: nil]; if (_shouldUseImageCoordinatesForMouseLocation) { mouseLocation = [_canvasView imagePointFromViewPoint: mouseLocation clippedToCanvasBounds: shouldClipToCanvasBounds]; } else if (shouldClipToCanvasBounds) { mouseLocation = [_canvasView viewPointClippedToCanvasBounds: mouseLocation]; } return mouseLocation; ERROR: return _lastMouseLocation; } - (void) updateModifierKeyFlags: (unsigned) modifierKeyFlags { modifierKeyFlags &= kModifierKeyMask_RecognizedModifierKeys; if (_modifierKeyFlags == modifierKeyFlags) { return; } _modifierKeyFlags = modifierKeyFlags; if (!_isTrackingMouseInCanvasView) { if (_lockedActiveToolModifierKeyFlags) { // clear locked-active-tool modifier flags of any modifier keys no longer held down _lockedActiveToolModifierKeyFlags &= _modifierKeyFlags; } [self updateActiveTool]; } else { [[_ppDocument activeTool] mouseDraggedOrModifierKeysChangedForDocument: _ppDocument withCanvasView: _canvasView currentPoint: _lastMouseLocation lastPoint: _lastMouseLocation mouseDownPoint: _mouseDownLocation modifierKeyFlags: _modifierKeyFlags]; if (_activeToolCursorDependsOnModifierKeys) { [self updateCanvasViewToolCursorForActiveTool]; } _shouldUpdateActiveToolOnMouseUp = YES; } // when the command or shift modifier keys are pressed, the system will swallow the // keyUp events for all other keys currently held down, even if the modifier keys are // released first - this can cause the popup panels to get stuck visible & the // hidden document layers to get stuck hidden, since the app won't be notified when the // hotkey is released; to prevent the popups & document layers from getting stuck, // preemptively hide the active popup & unhide the document layers when the command // & shift keys are pressed if (_modifierKeyFlags & (NSCommandKeyMask | NSShiftKeyMask)) { if (_pressedHotkeyForActivePopupPanel) { [self hideActivePopupPanel]; } if ([_canvasView documentLayersAreHidden]) { [_canvasView setDocumentLayersVisibility: YES]; } } } - (void) updateModifierKeyFlagsFromCurrentKeyboardState { [self updateModifierKeyFlags: [[NSApp currentEvent] modifierFlags]]; } - (void) updateActiveTool { unsigned toolAttributeFlags; if (_lockedActiveToolModifierKeyFlags) return; [_ppDocument setActiveToolType: [self modifiedToolTypeForSelectedToolType: [_ppDocument selectedToolType]]]; toolAttributeFlags = [[_ppDocument activeTool] toolAttributeFlags]; _shouldUseImageCoordinatesForMouseLocation = (toolAttributeFlags & kPPToolAttributeMask_RequiresPointsInViewCoordinates) ? NO : YES; _shouldClipMouseLocationPointsToCanvasBounds = (toolAttributeFlags & kPPToolAttributeMask_RequiresPointsCroppedToCanvasBounds) ? YES : NO; _activeToolCursorDependsOnModifierKeys = (toolAttributeFlags & kPPToolAttributeMask_CursorDependsOnModifierKeys) ? YES : NO; _shouldMatchCanvasDisplayModeToOperationTargetWhileTrackingMouse = (toolAttributeFlags & kPPToolAttributeMask_MatchCanvasDisplayModeToOperationTarget) ? YES : NO; _disallowMatchingCanvasDisplayModeToDrawLayerTarget = (toolAttributeFlags & kPPToolAttributeMask_DisallowMatchingCanvasDisplayModeToDrawLayerTarget) ? YES : NO; [self updateCanvasViewToolCursorForActiveTool]; [_canvasView enableSkippingOfMouseDraggedEvents: (toolAttributeFlags & kPPToolAttributeMask_DisableSkippingOfMouseDraggedEvents) ? NO : YES]; [_canvasView enableAutoscrolling: (toolAttributeFlags & kPPToolAttributeMask_DisableAutoscrolling) ? NO : YES]; } - (void) updateCanvasViewToolCursorForActiveTool { NSCursor *toolCursor; if (_activeToolCursorDependsOnModifierKeys) { toolCursor = [[_ppDocument activeTool] cursorForModifierKeyFlags: _modifierKeyFlags]; } else { toolCursor = [[_ppDocument activeTool] cursor]; } [_canvasView setToolCursor: toolCursor]; } - (PPToolType) modifiedToolTypeForSelectedToolType: (PPToolType) selectedToolType { PPToolType modifiedToolType; unsigned modifiableToolTypesMask, selectedToolTypeMask; if (!_modifierKeyFlags) { return selectedToolType; } switch (_modifierKeyFlags) { case kModifierKeyMask_SelectEraserTool: case kModifierKeyMask_SelectEraserToolWithFillShape: { modifiedToolType = kPPToolType_Eraser; modifiableToolTypesMask = kModifiablePPToolTypesMask_Eraser; } break; case kModifierKeyMask_SelectFillTool: { modifiedToolType = kPPToolType_Fill; modifiableToolTypesMask = kModifiablePPToolTypesMask_Fill; } break; case kModifierKeyMask_SelectColorSamplerTool: { modifiedToolType = kPPToolType_ColorSampler; modifiableToolTypesMask = kModifiablePPToolTypesMask_ColorSampler; } break; case kModifierKeyMask_SelectMoveTool: case kModifierKeyMask_SelectMoveToolWithSelectionOutlineOnly: case kModifierKeyMask_SelectMoveToolAndLeaveCopyInPlace: { modifiedToolType = kPPToolType_Move; modifiableToolTypesMask = kModifiablePPToolTypesMask_Move; } break; case kModifierKeyMask_SelectMagnifierTool: case kModifierKeyMask_SelectMagnifierToolWithZoomOut: case kModifierKeyMask_SelectMagnifierToolWithCenterShape: { modifiedToolType = kPPToolType_Magnifier; modifiableToolTypesMask = kModifiablePPToolTypesMask_Magnifier; } break; case kModifierKeyMask_SelectColorRampTool: { modifiedToolType = kPPToolType_ColorRamp; modifiableToolTypesMask = kModifiablePPToolTypesMask_ColorRamp; } break; default: modifiedToolType = selectedToolType; modifiableToolTypesMask = 0; break; } selectedToolTypeMask = PPToolTypeMaskForPPToolType(selectedToolType); if (!(selectedToolTypeMask & modifiableToolTypesMask)) { return selectedToolType; } return modifiedToolType; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindowController_Actions.m0000644000076500000240000003524613234403206025274 0ustar joshstaff/* PPDocumentWindowController_Actions.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentWindowController.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPDocumentLayer.h" #import "PPDocumentWindowController_Sheets.h" #import "PPPanelsController.h" #import "PPToolsPanelController.h" #import "NSDocumentController_PPUtilities.h" @implementation PPDocumentWindowController (Actions) #pragma mark File - (IBAction) newDocumentFromSelection: (id) sender { if (_isTrackingMouseInCanvasView) return; if (![_ppDocument hasSelection]) { goto ERROR; } [[NSDocumentController sharedDocumentController] ppOpenUntitledDuplicateOfPPDocument: [_ppDocument ppDocumentFromSelection]]; return; ERROR: return; } - (IBAction) exportImage: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument exportImage]; } #pragma mark Edit - (IBAction) cut: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument cutSelectionToPasteboardFromTarget: [_ppDocument layerOperationTarget]]; } - (IBAction) copy: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument copySelectionToPasteboardFromTarget: [_ppDocument layerOperationTarget]]; } - (IBAction) paste: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument pasteNewLayerFromPasteboard]; } - (IBAction) pasteIntoActiveLayer: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument pasteIntoDrawingLayerFromPasteboard]; } - (IBAction) delete: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument noninteractiveEraseSelectedAreaInTarget: [_ppDocument layerOperationTarget] andClearSelectionMask: YES]; } - (IBAction) selectAll: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument selectAll]; } - (IBAction) deselectAll: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument deselectAll]; } - (IBAction) selectVisibleTargetPixels: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument selectVisibleTargetPixels]; } - (IBAction) deselectInvisibleTargetPixels: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument deselectInvisibleTargetPixels]; } - (IBAction) invertSelection: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument invertSelection]; } - (IBAction) nudgeSelectionOutlineLeft: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument nudgeInDirection: kPPDirectionType_Left moveType: kPPMoveOperationType_SelectionOutlineOnly target: [_ppDocument layerOperationTarget]]; } - (IBAction) nudgeSelectionOutlineRight: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument nudgeInDirection: kPPDirectionType_Right moveType: kPPMoveOperationType_SelectionOutlineOnly target: [_ppDocument layerOperationTarget]]; } - (IBAction) nudgeSelectionOutlineUp: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument nudgeInDirection: kPPDirectionType_Up moveType: kPPMoveOperationType_SelectionOutlineOnly target: [_ppDocument layerOperationTarget]]; } - (IBAction) nudgeSelectionOutlineDown: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument nudgeInDirection: kPPDirectionType_Down moveType: kPPMoveOperationType_SelectionOutlineOnly target: [_ppDocument layerOperationTarget]]; } - (IBAction) closeHolesInSelection: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument closeHolesInSelection]; } - (IBAction) fillSelectedPixels: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument noninteractiveFillSelectedDrawingArea]; } - (IBAction) eraseSelectedPixels: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument noninteractiveEraseSelectedAreaInTarget: kPPLayerOperationTarget_DrawingLayerOnly andClearSelectionMask: NO]; } - (IBAction) tileSelection: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument tileSelection]; } - (IBAction) tileSelectionAsNewLayer: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument tileSelectionAsNewLayer]; } #pragma mark Layer - (IBAction) newLayer: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument createNewLayer]; } - (IBAction) duplicateActiveLayer: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument duplicateLayerAtIndex: [_ppDocument indexOfDrawingLayer]]; } - (IBAction) deleteActiveLayer: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument removeLayerAtIndex: [_ppDocument indexOfDrawingLayer]]; } - (IBAction) toggleActiveLayerEnabledFlag: (id) sender { PPDocumentLayer *drawingLayer; if (_isTrackingMouseInCanvasView) return; drawingLayer = [_ppDocument drawingLayer]; [drawingLayer setEnabled: ![drawingLayer isEnabled]]; } - (IBAction) enableAllLayers: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument setEnabledFlagForAllLayers: YES]; } - (IBAction) disableAllLayers: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument setEnabledFlagForAllLayers: NO]; } - (IBAction) increaseActiveLayerOpacity: (id) sender { if (_isTrackingMouseInCanvasView) return; [[_ppDocument drawingLayer] increaseOpacity]; } - (IBAction) decreaseActiveLayerOpacity: (id) sender { if (_isTrackingMouseInCanvasView) return; [[_ppDocument drawingLayer] decreaseOpacity]; } - (IBAction) makePreviousLayerActive: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument selectDrawingLayerAtIndex: [_ppDocument indexOfDrawingLayer] + 1]; } - (IBAction) makeNextLayerActive: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument selectDrawingLayerAtIndex: [_ppDocument indexOfDrawingLayer] - 1]; } - (IBAction) moveActiveLayerUp: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument moveDrawingLayerUp]; } - (IBAction) moveActiveLayerDown: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument moveDrawingLayerDown]; } - (IBAction) mergeWithLayerAbove: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument mergeDrawingLayerUp]; } - (IBAction) mergeWithLayerBelow: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument mergeDrawingLayerDown]; } - (IBAction) mergeAllLayers: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument mergeAllLayers]; } - (IBAction) toggleLayerBlendingMode: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument toggleLayerBlendingMode]; } #pragma mark Canvas - (IBAction) toggleCanvasDisplayMode: (id) sender { if (_isTrackingMouseInCanvasView) return; [self toggleCanvasDisplayMode]; } - (IBAction) increaseZoom: (id) sender { if (_isTrackingMouseInCanvasView) return; [_canvasView increaseZoomFactor]; } - (IBAction) decreaseZoom: (id) sender { if (_isTrackingMouseInCanvasView) return; [_canvasView decreaseZoomFactor]; } - (IBAction) zoomToFit: (id) sender { if (_isTrackingMouseInCanvasView) return; [_canvasView setZoomToFitCanvas]; } - (IBAction) editGridSettings: (id) sender { if (_isTrackingMouseInCanvasView) return; [self beginGridSettingsSheet]; } - (IBAction) toggleGridVisibility: (id) sender { [_ppDocument toggleGridVisibility]; } - (IBAction) toggleGridType: (id) sender { [_ppDocument togglePixelGridPatternType]; } - (IBAction) toggleGridGuidelinesVisibility: (id) sender { [_ppDocument toggleGridGuidelinesVisibility]; } - (IBAction) editBackgroundSettings: (id) sender { if (_isTrackingMouseInCanvasView) return; [self beginBackgroundSettingsSheet]; } - (IBAction) toggleBackgroundImageVisibility: (id) sender { [_ppDocument toggleBackgroundImageVisibility]; } - (IBAction) toggleBackgroundImageSmoothing: (id) sender { [_ppDocument toggleBackgroundImageSmoothing]; } - (IBAction) flipCanvasHorizontally: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument mirrorHorizontallyWithTarget: kPPLayerOperationTarget_Canvas]; } - (IBAction) flipCanvasVertically: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument mirrorVerticallyWithTarget: kPPLayerOperationTarget_Canvas]; } - (IBAction) rotateCanvas90Clockwise: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument rotate90ClockwiseWithTarget: kPPLayerOperationTarget_Canvas]; } - (IBAction) rotateCanvas90Counterclockwise: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument rotate90CounterclockwiseWithTarget: kPPLayerOperationTarget_Canvas]; } - (IBAction) rotateCanvas180: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument rotate180WithTarget: kPPLayerOperationTarget_Canvas]; } - (IBAction) resize: (id) sender { if (_isTrackingMouseInCanvasView) return; [self beginResizeSheet]; } - (IBAction) scale: (id) sender { if (_isTrackingMouseInCanvasView) return; [self beginScaleSheet]; } - (IBAction) cropToSelection: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument cropToSelectionBounds]; } #pragma mark Operation - (IBAction) toggleLayerOperationTarget: (id) sender { PPLayerOperationTarget newOperationTarget; if (_isTrackingMouseInCanvasView) return; if ([_ppDocument layerOperationTarget] == kPPLayerOperationTarget_DrawingLayerOnly) { newOperationTarget = kPPLayerOperationTarget_VisibleLayers; } else { newOperationTarget = kPPLayerOperationTarget_DrawingLayerOnly; } [_ppDocument setLayerOperationTarget: newOperationTarget]; } - (IBAction) flipHorizontally: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument mirrorHorizontallyWithTarget: [_ppDocument layerOperationTarget]]; } - (IBAction) flipVertically: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument mirrorVerticallyWithTarget: [_ppDocument layerOperationTarget]]; } - (IBAction) rotate90Clockwise: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument rotate90ClockwiseWithTarget: [_ppDocument layerOperationTarget]]; } - (IBAction) rotate90Counterclockwise: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument rotate90CounterclockwiseWithTarget: [_ppDocument layerOperationTarget]]; } - (IBAction) rotate180: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument rotate180WithTarget: [_ppDocument layerOperationTarget]]; } - (IBAction) nudgeLeft: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument nudgeInDirection: kPPDirectionType_Left moveType: kPPMoveOperationType_Normal target: [_ppDocument layerOperationTarget]]; } - (IBAction) nudgeRight: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument nudgeInDirection: kPPDirectionType_Right moveType: kPPMoveOperationType_Normal target: [_ppDocument layerOperationTarget]]; } - (IBAction) nudgeUp: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument nudgeInDirection: kPPDirectionType_Up moveType: kPPMoveOperationType_Normal target: [_ppDocument layerOperationTarget]]; } - (IBAction) nudgeDown: (id) sender { if (_isTrackingMouseInCanvasView) return; [_ppDocument nudgeInDirection: kPPDirectionType_Down moveType: kPPMoveOperationType_Normal target: [_ppDocument layerOperationTarget]]; } #pragma mark Panels - (IBAction) toggleToolsPanelVisibility: (id) sender { [_panelsController toggleEnabledStateForPanelOfType: kPPPanelType_Tools]; } - (IBAction) toggleLayersPanelVisibility: (id) sender { [_panelsController toggleEnabledStateForPanelOfType: kPPPanelType_Layers]; } - (IBAction) togglePreviewPanelVisibility: (id) sender { [_panelsController toggleEnabledStateForPanelOfType: kPPPanelType_Preview]; } - (IBAction) toggleSamplerImagePanelVisibility: (id) sender { [_panelsController toggleEnabledStateForPanelOfType: kPPPanelType_SamplerImage]; } - (IBAction) toggleToolModifierTipsPanelVisibility: (id) sender { [_panelsController toggleEnabledStateForPanelOfType: kPPPanelType_ToolModifierTips]; } - (IBAction) toggleActivePanelsVisibility: (id) sender { [_panelsController toggleEnabledStateForActivePanels]; } - (IBAction) toggleColorPickerVisibility: (id) sender { [[PPToolsPanelController sharedController] toggleFillColorWell]; } - (IBAction) editSamplerImagesSettings: (id) sender { if (_isTrackingMouseInCanvasView) return; [self beginSamplerImagesSettingsSheet]; } - (IBAction) nextSamplerPanelImage: (id) sender { [_ppDocument activateNextSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]; } - (IBAction) previousSamplerPanelImage: (id) sender { [_ppDocument activatePreviousSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindowController_MenuValidation.m0000644000076500000240000007461613242525437026631 0ustar joshstaff/* PPDocumentWindowController_MenuValidation.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentWindowController.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPDocumentLayer.h" #import "PPPanelsController.h" static void SetupGlobals(void); static SEL SelectorFromDictForMenuActionName(NSDictionary *selectorDict, NSString *actionName); static NSDictionary *MenuItemValidationSelectorDict(void); static NSDictionary *MenuItemModificationSelectorDict(void); static bool MenuActionNameIsAllowedDuringMouseTracking(NSString *actionName); static bool MenuActionNameIsAllowedDuringPopupPanel(NSString *actionName); static bool gNeedToSetupGlobals = YES; static NSDictionary *gMenuItemModificationSelectorDict = nil; static NSDictionary *gMenuItemValidationSelectorDict = nil; static NSNumber *gNumber_YES = nil, *gNumber_NO = nil; @interface PPDocumentWindowController (MenuValidationPrivateMethods) - (NSNumber *) documentIsValid; - (NSNumber *) documentHasSelection; - (NSNumber *) documentHasSelectionAndDrawLayerIsEnabled; - (NSNumber *) documentHasSelectionAndEnabledTargetLayer; - (NSNumber *) documentHasSelectionOrEnabledTargetLayer; - (NSNumber *) documentHasMultipleLayers; - (NSNumber *) documentHasValidLayerAboveDrawingLayer; - (NSNumber *) documentHasValidLayerBelowDrawingLayer; - (NSNumber *) documentActiveLayerCanIncreaseOpacity; - (NSNumber *) documentActiveLayerCanDecreaseOpacity; - (NSNumber *) documentHasVisibleGrid; - (NSNumber *) documentHasBackgroundImage; - (NSNumber *) documentHasVisibleBackgroundImage; - (NSNumber *) documentHasActiveSamplerImageForPanel; - (NSNumber *) documentHasMultipleSamplerImagesAndSamplerPanelIsVisible; - (NSNumber *) documentCanReadFromPasteboard; - (NSNumber *) canvasViewCanZoomIn; - (NSNumber *) canvasViewCanZoomOut; - (void) modifyMenuItemForLayerEnabled: (NSMenuItem *) menuItem; - (void) modifyMenuItemForCanvasDisplayMode: (NSMenuItem *) menuItem; - (void) modifyMenuItemForLayerBlendingMode: (NSMenuItem *) menuItem; - (void) modifyMenuItemForGridVisibilityStatus: (NSMenuItem *) menuItem; - (void) modifyMenuItemForGridType: (NSMenuItem *) menuItem; - (void) modifyMenuItemForGridGuidelinesVisibilityStatus: (NSMenuItem *) menuItem; - (void) modifyMenuItemForBackgroundImageVisibilityStatus: (NSMenuItem *) menuItem; - (void) modifyMenuItemForBackgroundImageSmoothingStatus: (NSMenuItem *) menuItem; - (void) modifyMenuItemForLayerOperationTarget: (NSMenuItem *) menuItem; - (void) modifyMenuItemForToolsPanelVisibilityStatus: (NSMenuItem *) menuItem; - (void) modifyMenuItemForLayersPanelVisibilityStatus: (NSMenuItem *) menuItem; - (void) modifyMenuItemForPreviewPanelVisibilityStatus: (NSMenuItem *) menuItem; - (void) modifyMenuItemForSamplerImagePanelVisibilityStatus: (NSMenuItem *) menuItem; - (void) modifyMenuItemForToolModifierTipsPanelVisibilityStatus: (NSMenuItem *) menuItem; @end @interface NSMenuItem (PPUtilities_MenuValidationPrivateMethods) - (void) ppSetTitleModeNameSuffix: (NSString *) modeName; @end @implementation PPDocumentWindowController (MenuValidation) - (BOOL) validateMenuItem: (PPSDKNativeType_NSMenuItemPtr) menuItem { SEL menuItemAction, modificationSelector, validationSelector; NSString *actionName; if (gNeedToSetupGlobals) { SetupGlobals(); } if (!_documentWindowIsKey) { return NO; } menuItemAction = [menuItem action]; if (!menuItemAction) goto ERROR; actionName = NSStringFromSelector(menuItemAction); if (!actionName) goto ERROR; modificationSelector = SelectorFromDictForMenuActionName(gMenuItemModificationSelectorDict, actionName); if (modificationSelector) { [self performSelector: modificationSelector withObject: menuItem]; } if (_isTrackingMouseInCanvasView && !MenuActionNameIsAllowedDuringMouseTracking(actionName)) { return NO; } if (_pressedHotkeyForActivePopupPanel && !MenuActionNameIsAllowedDuringPopupPanel(actionName)) { return NO; } validationSelector = SelectorFromDictForMenuActionName(gMenuItemValidationSelectorDict, actionName); if (validationSelector) { return [[self performSelector: validationSelector] boolValue]; } return NO; ERROR: return NO; } - (NSNumber *) documentIsValid { return ([_ppDocument numLayers]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasSelection { return ([_ppDocument hasSelection]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasSelectionAndDrawLayerIsEnabled { return ([_ppDocument hasSelection] && [[_ppDocument drawingLayer] isEnabled]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasSelectionAndEnabledTargetLayer { return ([_ppDocument hasSelection] && [_ppDocument layerOperationTargetHasEnabledLayer]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasSelectionOrEnabledTargetLayer { return ([_ppDocument hasSelection] || [_ppDocument layerOperationTargetHasEnabledLayer]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasMultipleLayers { return ([_ppDocument numLayers] > 1) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasValidLayerAboveDrawingLayer { return ([_ppDocument indexOfDrawingLayer] < ([_ppDocument numLayers] - 1)) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasValidLayerBelowDrawingLayer { return ([_ppDocument indexOfDrawingLayer] > 0) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentActiveLayerCanIncreaseOpacity { return ([[_ppDocument drawingLayer] canIncreaseOpacity]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentActiveLayerCanDecreaseOpacity { return ([[_ppDocument drawingLayer] canDecreaseOpacity]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasVisibleGrid { return ([_ppDocument shouldDisplayGrid]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasBackgroundImage { return ([_ppDocument backgroundImage]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasVisibleBackgroundImage { return ([_ppDocument backgroundImage] && [_ppDocument shouldDisplayBackgroundImage]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasActiveSamplerImageForPanel { return ([_ppDocument hasActiveSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentHasMultipleSamplerImagesAndSamplerPanelIsVisible { return (([_ppDocument numSamplerImages] > 1) && [_panelsController panelOfTypeIsVisible: kPPPanelType_SamplerImage]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) documentCanReadFromPasteboard { return ([_ppDocument canReadFromPasteboard]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) canvasViewCanZoomIn { return ([_canvasView canIncreaseZoomFactor]) ? gNumber_YES : gNumber_NO; } - (NSNumber *) canvasViewCanZoomOut { return ([_canvasView canDecreaseZoomFactor]) ? gNumber_YES : gNumber_NO; } #pragma mark Menu item modifications - (void) modifyMenuItemForLayerEnabled: (NSMenuItem *) menuItem { [menuItem setState: ([[_ppDocument drawingLayer] isEnabled]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForLayerBlendingMode: (NSMenuItem *) menuItem { NSString *modeName = nil; if ([self documentIsValid]) { if ([_ppDocument layerBlendingMode] == kPPLayerBlendingMode_Linear) { modeName = @"LINEAR"; } else { modeName = @"STANDARD"; } } [menuItem ppSetTitleModeNameSuffix: modeName]; } - (void) modifyMenuItemForCanvasDisplayMode: (NSMenuItem *) menuItem { NSString *modeName = nil; if ([self documentIsValid]) { if (_canvasDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { modeName = @"DRAW Layer"; } else { modeName = @"ENABLED Layers"; } } [menuItem ppSetTitleModeNameSuffix: modeName]; } - (void) modifyMenuItemForGridVisibilityStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_ppDocument shouldDisplayGrid]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForGridType: (NSMenuItem *) menuItem { NSString *modeName = nil; if ([self documentIsValid]) { switch ([_ppDocument pixelGridPatternType]) { case kPPGridType_Crosshairs: { modeName = @"Crosshairs"; } break; case kPPGridType_LargeDots: { modeName = @"Large Dots"; } break; case kPPGridType_Dots: { modeName = @"Dots"; } break; case kPPGridType_Lines: default: { modeName = @"Lines"; } break; } } [menuItem ppSetTitleModeNameSuffix: modeName]; } - (void) modifyMenuItemForGridGuidelinesVisibilityStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_ppDocument gridPatternShouldDisplayGuidelines]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForBackgroundImageVisibilityStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_ppDocument shouldDisplayBackgroundImage]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForBackgroundImageSmoothingStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_ppDocument shouldSmoothenBackgroundImage]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForLayerOperationTarget: (NSMenuItem *) menuItem { NSString *modeName = nil; if ([self documentIsValid]) { if ([_ppDocument layerOperationTarget] == kPPLayerOperationTarget_DrawingLayerOnly) { modeName = @"DRAW Layer"; } else { modeName = @"ENABLED Layers"; } } [menuItem ppSetTitleModeNameSuffix: modeName]; } - (void) modifyMenuItemForToolsPanelVisibilityStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_panelsController panelOfTypeIsVisible: kPPPanelType_Tools]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForLayersPanelVisibilityStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_panelsController panelOfTypeIsVisible: kPPPanelType_Layers]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForPreviewPanelVisibilityStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_panelsController panelOfTypeIsVisible: kPPPanelType_Preview]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForSamplerImagePanelVisibilityStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_panelsController panelOfTypeIsVisible: kPPPanelType_SamplerImage]) ? NSOnState : NSOffState]; } - (void) modifyMenuItemForToolModifierTipsPanelVisibilityStatus: (NSMenuItem *) menuItem { [menuItem setState: ([_panelsController panelOfTypeIsVisible: kPPPanelType_ToolModifierTips]) ? NSOnState : NSOffState]; } @end @implementation NSMenuItem (PPUtilities_MenuValidationPrivateMethods) - (void) ppSetTitleModeNameSuffix: (NSString *) modeName { NSString *currentTitle, *newTitle; NSRange colonRange; currentTitle = [self title]; if (!currentTitle) { currentTitle = @""; } colonRange = [currentTitle rangeOfString: @":"]; if (colonRange.length) { newTitle = [currentTitle substringToIndex: colonRange.location]; } else { newTitle = currentTitle; } if (modeName) { newTitle = [newTitle stringByAppendingFormat: @": %@", modeName]; } if (![newTitle isEqualToString: currentTitle]) { [self setTitle: newTitle]; } } @end #pragma mark Private functions static void SetupGlobals(void) { if (!gNeedToSetupGlobals) return; gMenuItemModificationSelectorDict = [MenuItemModificationSelectorDict() retain]; gMenuItemValidationSelectorDict = [MenuItemValidationSelectorDict() retain]; gNumber_YES = [[NSNumber numberWithBool: YES] retain]; gNumber_NO = [[NSNumber numberWithBool: NO] retain]; gNeedToSetupGlobals = NO; } static SEL SelectorFromDictForMenuActionName(NSDictionary *selectorDict, NSString *actionName) { NSString *dictSelectorName; if (!selectorDict || !actionName) { return NULL; } dictSelectorName = [selectorDict objectForKey: actionName]; if (!dictSelectorName) { return NULL; } return NSSelectorFromString(dictSelectorName); } static NSDictionary *MenuItemValidationSelectorDict(void) { return [NSDictionary dictionaryWithObjectsAndKeys: // File menu @"documentHasSelectionAndEnabledTargetLayer", @"newDocumentFromSelection:", @"documentIsValid", @"exportImage:", // Edit menu @"documentHasSelection", @"cut:", @"documentHasSelection", @"copy:", @"documentCanReadFromPasteboard", @"paste:", @"documentCanReadFromPasteboard", @"pasteIntoActiveLayer:", @"documentHasSelection", @"delete:", @"documentIsValid", @"selectAll:", @"documentHasSelection", @"deselectAll:", @"documentIsValid", @"selectVisibleTargetPixels:", @"documentHasSelection", @"deselectInvisibleTargetPixels:", @"documentIsValid", @"invertSelection:", @"documentHasSelection", @"nudgeSelectionOutlineLeft:", @"documentHasSelection", @"nudgeSelectionOutlineRight:", @"documentHasSelection", @"nudgeSelectionOutlineUp:", @"documentHasSelection", @"nudgeSelectionOutlineDown:", @"documentHasSelection", @"closeHolesInSelection:", @"documentHasSelectionAndDrawLayerIsEnabled", @"fillSelectedPixels:", @"documentHasSelectionAndDrawLayerIsEnabled", @"eraseSelectedPixels:", @"documentHasSelectionAndEnabledTargetLayer", @"tileSelection:", @"documentHasSelectionAndEnabledTargetLayer", @"tileSelectionAsNewLayer:", // Layer menu @"documentIsValid", @"newLayer:", @"documentIsValid", @"duplicateActiveLayer:", @"documentIsValid", @"deleteActiveLayer:", @"documentIsValid", @"toggleActiveLayerEnabledFlag:", @"documentIsValid", @"enableAllLayers:", @"documentIsValid", @"disableAllLayers:", @"documentActiveLayerCanIncreaseOpacity", @"increaseActiveLayerOpacity:", @"documentActiveLayerCanDecreaseOpacity", @"decreaseActiveLayerOpacity:", @"documentHasValidLayerAboveDrawingLayer", @"makePreviousLayerActive:", @"documentHasValidLayerBelowDrawingLayer", @"makeNextLayerActive:", @"documentHasValidLayerAboveDrawingLayer", @"moveActiveLayerUp:", @"documentHasValidLayerBelowDrawingLayer", @"moveActiveLayerDown:", @"documentHasValidLayerAboveDrawingLayer", @"mergeWithLayerAbove:", @"documentHasValidLayerBelowDrawingLayer", @"mergeWithLayerBelow:", @"documentHasMultipleLayers", @"mergeAllLayers:", @"documentIsValid", @"toggleLayerBlendingMode:", // Canvas menu @"documentHasMultipleLayers", @"toggleCanvasDisplayMode:", @"canvasViewCanZoomIn", @"increaseZoom:", @"canvasViewCanZoomOut", @"decreaseZoom:", @"documentIsValid", @"zoomToFit:", @"documentIsValid", @"editGridSettings:", @"documentIsValid", @"toggleGridVisibility:", @"documentHasVisibleGrid", @"toggleGridType:", @"documentHasVisibleGrid", @"toggleGridGuidelinesVisibility:", @"documentIsValid", @"editBackgroundSettings:", @"documentHasBackgroundImage", @"toggleBackgroundImageVisibility:", @"documentHasVisibleBackgroundImage", @"toggleBackgroundImageSmoothing:", @"documentIsValid", @"flipCanvasHorizontally:", @"documentIsValid", @"flipCanvasVertically:", @"documentIsValid", @"rotateCanvas90Clockwise:", @"documentIsValid", @"rotateCanvas90Counterclockwise:", @"documentIsValid", @"rotateCanvas180:", @"documentIsValid", @"resize:", @"documentIsValid", @"scale:", @"documentHasSelection", @"cropToSelection:", // Operation menu @"documentHasMultipleLayers", @"toggleLayerOperationTarget:", @"documentHasSelectionOrEnabledTargetLayer", @"flipHorizontally:", @"documentHasSelectionOrEnabledTargetLayer", @"flipVertically:", @"documentHasSelectionOrEnabledTargetLayer", @"rotate90Clockwise:", @"documentHasSelectionOrEnabledTargetLayer", @"rotate90Counterclockwise:", @"documentHasSelectionOrEnabledTargetLayer", @"rotate180:", @"documentHasSelectionOrEnabledTargetLayer", @"nudgeLeft:", @"documentHasSelectionOrEnabledTargetLayer", @"nudgeRight:", @"documentHasSelectionOrEnabledTargetLayer", @"nudgeUp:", @"documentHasSelectionOrEnabledTargetLayer", @"nudgeDown:", // Panels menu @"documentIsValid", @"toggleToolsPanelVisibility:", @"documentIsValid", @"toggleLayersPanelVisibility:", @"documentIsValid", @"togglePreviewPanelVisibility:", @"documentHasActiveSamplerImageForPanel", @"toggleSamplerImagePanelVisibility:", @"documentIsValid", @"toggleToolModifierTipsPanelVisibility:", @"documentIsValid", @"toggleActivePanelsVisibility:", @"documentIsValid", @"toggleColorPickerVisibility:", @"documentIsValid", @"editSamplerImagesSettings:", @"documentHasMultipleSamplerImagesAndSamplerPanelIsVisible", @"nextSamplerPanelImage:", @"documentHasMultipleSamplerImagesAndSamplerPanelIsVisible", @"previousSamplerPanelImage:", nil]; } static NSDictionary *MenuItemModificationSelectorDict(void) { return [NSDictionary dictionaryWithObjectsAndKeys: @"modifyMenuItemForLayerEnabled:", @"toggleActiveLayerEnabledFlag:", @"modifyMenuItemForLayerBlendingMode:", @"toggleLayerBlendingMode:", @"modifyMenuItemForCanvasDisplayMode:", @"toggleCanvasDisplayMode:", @"modifyMenuItemForGridVisibilityStatus:", @"toggleGridVisibility:", @"modifyMenuItemForGridType:", @"toggleGridType:", @"modifyMenuItemForGridGuidelinesVisibilityStatus:", @"toggleGridGuidelinesVisibility:", @"modifyMenuItemForBackgroundImageVisibilityStatus:", @"toggleBackgroundImageVisibility:", @"modifyMenuItemForBackgroundImageSmoothingStatus:", @"toggleBackgroundImageSmoothing:", @"modifyMenuItemForLayerOperationTarget:", @"toggleLayerOperationTarget:", @"modifyMenuItemForToolsPanelVisibilityStatus:", @"toggleToolsPanelVisibility:", @"modifyMenuItemForLayersPanelVisibilityStatus:", @"toggleLayersPanelVisibility:", @"modifyMenuItemForPreviewPanelVisibilityStatus:", @"togglePreviewPanelVisibility:", @"modifyMenuItemForSamplerImagePanelVisibilityStatus:", @"toggleSamplerImagePanelVisibility:", @"modifyMenuItemForToolModifierTipsPanelVisibilityStatus:", @"toggleToolModifierTipsPanelVisibility:", nil]; } static bool MenuActionNameIsAllowedDuringMouseTracking(NSString *actionName) { static NSSet *allowedMouseTrackingActionNamesSet = nil; if (!actionName) goto ERROR; if (!allowedMouseTrackingActionNamesSet) { allowedMouseTrackingActionNamesSet = [[NSSet setWithObjects: @"toggleGridVisibility:", @"toggleGridType:", @"toggleGridGuidelinesVisibility:", @"toggleBackgroundImageVisibility:", @"toggleBackgroundImageSmoothing:", @"toggleToolsPanelVisibility:", @"toggleLayersPanelVisibility:", @"togglePreviewPanelVisibility:", @"toggleSamplerImagePanelVisibility:", @"toggleToolModifierTipsPanelVisibility:", @"toggleActivePanelsVisibility:", @"toggleColorPickerVisibility:", @"nextSamplerPanelImage:", @"previousSamplerPanelImage:", nil] retain]; } return ([allowedMouseTrackingActionNamesSet containsObject: actionName]) ? YES : NO; ERROR: return NO; } static bool MenuActionNameIsAllowedDuringPopupPanel(NSString *actionName) { static NSSet *disallowedPopupPanelActionNamesSet = nil; if (!actionName) goto ERROR; if (!disallowedPopupPanelActionNamesSet) { disallowedPopupPanelActionNamesSet = [[NSSet setWithObjects: @"nextSamplerPanelImage:", @"previousSamplerPanelImage:", nil] retain]; } return ([disallowedPopupPanelActionNamesSet containsObject: actionName]) ? NO : YES; ERROR: return NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindowController_Notifications.h0000644000076500000240000000221313234403416026467 0ustar joshstaff/* PPDocumentWindowController_Notifications.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentWindowController.h" @interface PPDocumentWindowController (Notifications) - (void) postNotification_ChangedCanvasDisplayMode; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindowController_Notifications.m0000644000076500000240000000306613234403206026500 0ustar joshstaff/* PPDocumentWindowController_Notifications.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentWindowController_Notifications.h" NSString *PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode = @"PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode"; @implementation PPDocumentWindowController (Notifications) - (void) postNotification_ChangedCanvasDisplayMode { [[NSNotificationCenter defaultCenter] postNotificationName: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode object: self]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindowController_Sheets.h0000644000076500000240000000254113234403416025115 0ustar joshstaff/* PPDocumentWindowController_Sheets.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentWindowController.h" @interface PPDocumentWindowController (Sheets) - (void) beginSizeSheet; - (void) beginScaleSheet; - (void) beginResizeSheet; - (void) beginBackgroundSettingsSheet; - (void) beginGridSettingsSheet; - (void) beginSamplerImagesSettingsSheet; - (void) beginAnimationFileNoticeSheet; - (void) beginFlattenedSaveNoticeSheet; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPDocumentWindowController_Sheets.m0000644000076500000240000002305413234403206025121 0ustar joshstaff/* PPDocumentWindowController_Sheets.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentWindowController_Sheets.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPDocumentSizeSheetController.h" #import "PPDocumentScaleSheetController.h" #import "PPDocumentResizeSheetController.h" #import "PPDocumentBackgroundSettingsSheetController.h" #import "PPDocumentGridSettingsSheetController.h" #import "PPDocumentSamplerImagesSettingsSheetController.h" #import "PPDocumentAnimationFileNoticeSheetController.h" #import "PPDocumentFlattenedSaveNoticeSheetController.h" #import "PPBackgroundPattern.h" #import "NSObject_PPUtilities.h" @interface PPDocumentWindowController (SheetsPrivateMethods) - (void) ppCloseDocumentWithMessage: (NSString *) message; - (void) ppDocumentCloseAlertSheetDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo; @end @implementation PPDocumentWindowController (Sheets) - (void) beginSizeSheet { [PPDocumentSizeSheetController beginSizeSheetForDocumentWindow: [self window] delegate: self]; } - (void) beginScaleSheet { [PPDocumentScaleSheetController beginScaleSheetForDocumentWindow: [self window] canvasBitmap: [_ppDocument mergedVisibleLayersBitmap] delegate: self]; } - (void) beginResizeSheet { [PPDocumentResizeSheetController beginResizeSheetForDocumentWindow: [self window] currentImageSize: [_ppDocument canvasSize] delegate: self]; } - (void) beginBackgroundSettingsSheet { [PPDocumentBackgroundSettingsSheetController beginBackgroundSettingsSheetForDocumentWindow: [self window] backgroundPattern: [_ppDocument backgroundPattern] backgroundImage: [_ppDocument backgroundImage] backgroundImageVisibility: [_ppDocument shouldDisplayBackgroundImage] backgroundImageSmoothing: [_ppDocument shouldSmoothenBackgroundImage] delegate: self]; } - (void) beginGridSettingsSheet { [PPDocumentGridSettingsSheetController beginGridSettingsSheetForDocumentWindow: [self window] gridPattern: [_ppDocument gridPattern] gridVisibility: [_ppDocument shouldDisplayGrid] delegate: self]; } - (void) beginSamplerImagesSettingsSheet { [PPDocumentSamplerImagesSettingsSheetController beginSamplerImagesSettingsSheetForWindow: [self window] samplerImages: [_ppDocument samplerImages] delegate: self]; } - (void) beginAnimationFileNoticeSheet { [PPDocumentAnimationFileNoticeSheetController beginAnimationFileNoticeSheetForDocumentWindow: [self window] delegate: self]; } - (void) beginFlattenedSaveNoticeSheet { [PPDocumentFlattenedSaveNoticeSheetController beginFlattenedSaveNoticeSheetForDocumentWindow: [self window]]; } #pragma mark PPDocumentSizeSheetController delegate methods - (void) documentSizeSheetDidFinishWithWidth: (int) width andHeight: (int) height { if (![_ppDocument setupNewPPDocumentWithCanvasSize: NSMakeSize(width, height)]) { goto ERROR; } return; ERROR: [self ppCloseDocumentWithMessage: @"ERROR: Could not create document."]; } - (void) documentSizeSheetDidCancel { [_ppDocument close]; } #pragma mark PPDocumentScaleSheetController delegate methods - (void) documentScaleSheetDidFinishWithNewImageSize: (NSSize) newImageSize { [_ppDocument resizeToSize: newImageSize shouldScale: YES]; } - (void) documentScaleSheetDidCancel { } #pragma mark PPDocumentResizeSheetController delegate methods - (void) documentResizeSheetDidFinishWithNewImageSize: (NSSize) newImageSize shouldScale: (bool) shouldScale { [_ppDocument resizeToSize: newImageSize shouldScale: shouldScale]; } - (void) documentResizeSheetDidCancel { } #pragma mark PPDocumentBackgroundSettingsSheetController delegate methods - (void) backgroundSettingsSheetDidUpdatePattern: (PPBackgroundPattern *) backgroundPattern { [_canvasView setBackgroundColor: [backgroundPattern patternFillColor]]; } - (void) backgroundSettingsSheetDidUpdateImage: (NSImage *) backgroundImage { [_canvasView setBackgroundImage: backgroundImage]; } - (void) backgroundSettingsSheetDidUpdateImageVisibility: (bool) shouldDisplayImage { [_canvasView setBackgroundImageVisibility: shouldDisplayImage]; } - (void) backgroundSettingsSheetDidUpdateImageSmoothing: (bool) shouldSmoothenImage { [_canvasView setBackgroundImageSmoothing: shouldSmoothenImage]; } - (void) backgroundSettingsSheetDidFinishWithBackgroundPattern: (PPBackgroundPattern *) backgroundPattern backgroundImage: (NSImage *) backgroundImage shouldDisplayImage: (bool) shouldDisplayImage shouldSmoothenImage: (bool) shouldSmoothenImage { [_ppDocument setBackgroundPattern: backgroundPattern backgroundImage: backgroundImage shouldDisplayBackgroundImage: shouldDisplayImage shouldSmoothenBackgroundImage: shouldSmoothenImage]; // compressed background image data is not automatically set up by setBackgroundPattern:... // don't need to manually update it here, but doing so saves time during the next autosave if (backgroundImage) { [_ppDocument setupCompressedBackgroundImageData]; } } - (void) backgroundSettingsSheetDidCancel { [_canvasView setBackgroundImage: [_ppDocument backgroundImage] backgroundImageVisibility: [_ppDocument shouldDisplayBackgroundImage] backgroundImageSmoothing: [_ppDocument shouldSmoothenBackgroundImage] backgroundColor: [_ppDocument backgroundPatternAsColor]]; } #pragma mark PPDocumentGridSettingsSheetController delegate methods - (void) gridSettingsSheetDidUpdateGridPattern: (PPGridPattern *) gridPattern andVisibility: (bool) shouldDisplayGrid { [_canvasView setGridPattern: gridPattern gridVisibility: shouldDisplayGrid]; } - (void) gridSettingsSheetDidFinishWithGridPattern: (PPGridPattern *) gridPattern andVisibility: (bool) shouldDisplayGrid { [_ppDocument setGridPattern: gridPattern shouldDisplayGrid: shouldDisplayGrid]; } - (void) gridSettingsSheetDidCancel { [_canvasView setGridPattern: [_ppDocument gridPattern] gridVisibility: [_ppDocument shouldDisplayGrid]]; } #pragma mark PPDocumentSamplerImagesSettingsSheetController delegate methods - (void) samplerImagesSettingsSheetDidFinishWithSamplerImages: (NSArray *) samplerImages { [_ppDocument setSamplerImages: samplerImages]; } - (void) samplerImagesSettingsSheetDidCancel { } #pragma mark PPDocumentAnimationFileNoticeSheetController delegate methods - (void) documentAnimationFileNoticeSheetDidFinishAndShouldChangeSaveLocation: (bool) shouldChangeSaveLocation { if (shouldChangeSaveLocation) { [_ppDocument ppPerformSelectorFromNewStackFrame: @selector(saveDocumentAs:)]; } } #pragma mark Private methods - (void) ppCloseDocumentWithMessage: (NSString *) message { NSAlert *closeAlert; if (!message) goto ERROR; closeAlert = [NSAlert alertWithMessageText: message defaultButton: @"OK" alternateButton: nil otherButton: nil informativeTextWithFormat: @""]; if (!closeAlert) goto ERROR; [closeAlert beginSheetModalForWindow: [self window] modalDelegate: self didEndSelector: @selector(ppDocumentCloseAlertSheetDidEnd:returnCode:contextInfo:) contextInfo: NULL]; return; ERROR: [_ppDocument close]; } - (void) ppDocumentCloseAlertSheetDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo { [[alert window] orderOut: self]; [_ppDocument close]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPEraserTool.h0000644000076500000240000000212213234403416020642 0ustar joshstaff/* PPEraserTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPEraserTool : PPTool { NSBezierPath *_erasePath; bool _shouldFillErasePath; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPEraserTool.m0000644000076500000240000001055013234403206020650 0ustar joshstaff/* PPEraserTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPEraserTool.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "NSCursor_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #define kEraserToolAttributesMask \ (kPPToolAttributeMask_RequiresPointsCroppedToCanvasBounds \ | kPPToolAttributeMask_DisableSkippingOfMouseDraggedEvents \ | kPPToolAttributeMask_DisableAutoscrolling) @implementation PPEraserTool - init { self = [super init]; if (!self) goto ERROR; _erasePath = [[NSBezierPath bezierPath] retain]; if (!_erasePath) goto ERROR; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_erasePath release]; [super dealloc]; } - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSBitmapImageRep *eraseMask; NSRect eraseBounds; [_erasePath removeAllPoints]; [_erasePath ppAppendSinglePixelLineAtPoint: currentPoint]; [ppDocument beginDrawingWithPenMode: kPPPenMode_Erase]; [ppDocument drawPixelAtPoint: currentPoint]; if ([ppDocument getInteractiveEraseMask: &eraseMask andBounds: &eraseBounds]) { [canvasView setEraserToolOverlayToMask: eraseMask maskBounds: eraseBounds]; } _shouldFillErasePath = NO; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { bool shouldFillErasePath, shouldDrawAsBezierPath, mouseDidMoveToNewPoint; NSBitmapImageRep *eraseMask; NSRect eraseBounds; shouldFillErasePath = (modifierKeyFlags & kModifierKeyMask_FillShape) ? YES : NO; if (_shouldFillErasePath != shouldFillErasePath) { _shouldFillErasePath = shouldFillErasePath; shouldDrawAsBezierPath = YES; } else { shouldDrawAsBezierPath = _shouldFillErasePath; } mouseDidMoveToNewPoint = (!NSEqualPoints(lastPoint, currentPoint)) ? YES : NO; if (mouseDidMoveToNewPoint) { [_erasePath ppLineToPixelAtPoint: currentPoint]; } if (shouldDrawAsBezierPath) { [ppDocument undoCurrentDrawingAtNextDraw]; [ppDocument drawBezierPath: _erasePath andFill: _shouldFillErasePath]; } else if (mouseDidMoveToNewPoint) { [ppDocument drawLineFromPoint: lastPoint toPoint: currentPoint]; } if ([ppDocument getInteractiveEraseMask: &eraseMask andBounds: &eraseBounds]) { [canvasView setEraserToolOverlayToMask: eraseMask maskBounds: eraseBounds]; } } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [ppDocument finishDrawing]; [_erasePath removeAllPoints]; [canvasView clearEraserToolOverlay]; } - (NSCursor *) cursor { return [NSCursor ppEraserCursor]; } - (unsigned) toolAttributeFlags { return kEraserToolAttributesMask; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPExportPanelAccessoryViewController.h0000644000076500000240000000662413243240744025615 0ustar joshstaff/* PPExportPanelAccessoryViewController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @class PPDocument, PPTitleablePopUpButton, PPGridPattern, PPBackgroundPattern; @interface PPExportPanelAccessoryViewController : NSObject { IBOutlet NSView *_exportAccessoryView; IBOutlet NSImageView *_previewImageView; IBOutlet NSTextField *_exportSizeTextField; IBOutlet NSTextField *_scalingFactorTextField; IBOutlet NSSlider *_scalingFactorSlider; IBOutlet NSButton *_gridCheckbox; IBOutlet PPTitleablePopUpButton *_gridTitleablePopUpButton; IBOutlet NSButton *_backgroundPatternCheckbox; IBOutlet PPTitleablePopUpButton *_backgroundPatternTitleablePopUpButton; IBOutlet NSButton *_backgroundImageCheckbox; IBOutlet NSTextField *_backgroundImageTextField; IBOutlet NSPopUpButton *_fileFormatPopUpButton; NSSavePanel *_savePanel; PPDocument *_ppDocument; NSRect _previewScrollViewInitialFrame; float _previewScrollerWidth; NSSize _previewImageSize; NSPoint _previewViewNormalizedCenter; int _scalingFactor; int _maxScalingFactor; NSMenu *_gridPopUpDefaultMenu; int _selectedGridMenuItemType; NSMenu *_backgroundPatternPopUpDefaultMenu; int _selectedBackgroundPatternMenuItemType; PPGridPattern *_gridPattern; PPBackgroundPattern *_backgroundPattern; bool _shouldPreservePreviewNormalizedCenter; } + (PPExportPanelAccessoryViewController *) controllerForPPDocument: (PPDocument *) ppDocument; - (void) setupWithSavePanel: (NSSavePanel *) savePanel; - (NSString *) selectedFileTypeName; - (NSString *) selectedFileType; - (bool) getScalingFactor: (unsigned *) returnedScalingFactor gridPattern: (PPGridPattern **) returnedGridPattern backgroundPattern: (PPBackgroundPattern **) returnedBackgroundPattern backgroundImageFlag: (bool *) returnedBackgroundImageFlag; - (IBAction) scalingFactorSliderMoved: (id) sender; - (IBAction) canvasSettingCheckboxClicked: (id) sender; - (IBAction) gridPopUpMenuItemSelected_CurrentPattern: (id) sender; - (IBAction) gridPopUpMenuItemSelected_DefaultPattern: (id) sender; - (IBAction) gridPopUpMenuItemSelected_PresetPattern: (id) sender; - (IBAction) backgroundPatternPopUpMenuItemSelected_CurrentPattern: (id) sender; - (IBAction) backgroundPatternPopUpMenuItemSelected_DefaultPattern: (id) sender; - (IBAction) backgroundPatternPopUpMenuItemSelected_PresetPattern: (id) sender; - (IBAction) fileFormatPopupMenuItemSelected: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPExportPanelAccessoryViewController.m0000644000076500000240000010011413264230376025612 0ustar joshstaff/* PPExportPanelAccessoryViewController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPExportPanelAccessoryViewController.h" #import "PPDocument.h" #import "PPTitleablePopUpButton.h" #import "PPGridPattern.h" #import "PPBackgroundPattern.h" #import "NSImage_PPUtilities.h" #import "NSTextField_PPUtilities.h" #import "PPGeometry.h" #import "PPUserDefaults.h" #import "PPGridPatternPresets.h" #import "PPBackgroundPatternPresets.h" #define kExportPanelAccessoryViewNibName @"ExportPanelAccessoryView" #define kMinExportScalingFactor 1 #define kMaxExportScalingFactor (kMaxCanvasZoomFactor + 10.0f) #define kMarginPaddingForScrollerlessScrollView 2 #define kPatternPopUpMenuItemTitle_CurrentPattern @"Current Document Pattern" #define kPatternPopUpMenuItemTitle_DefaultPattern @"Default Pattern" #define kGridPopUpButtonTitle_CurrentPattern @"Grid Pattern" #define kGridPopUpButtonTitleFormat @"Grid: %@" #define kBackgroundPatternPopUpButtonTitle_CurrentPattern @"Background Pattern" #define kBackgroundPatternPopUpButtonTitleFormat @"Background: %@" typedef enum { kPatternMenuItemType_Current, kPatternMenuItemType_Default, kPatternMenuItemType_Preset } PPPatternMenuItemType; @interface PPExportPanelAccessoryViewController (PrivateMethods) - (id) initWithPPDocument: (PPDocument *) ppDocument; - (void) addAsObserverForNSWindowNotificationsFromPPDocumentWindow; - (void) removeAsObserverForNSWindowNotificationsFromPPDocumentWindow; - (void) handlePPDocumentWindowNotification_DidEndSheet: (NSNotification *) notification; - (void) addAsObserverForNSViewNotificationsFromPreviewClipView; - (void) removeAsObserverForNSViewNotificationsFromPreviewClipView; - (void) handlePreviewClipViewNotification_BoundsDidChange: (NSNotification *) notification; - (void) addAsObserverForPPGridPatternPresetsNotifications; - (void) removeAsObserverForPPGridPatternPresetsNotifications; - (void) handlePPGridPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification; - (void) addAsObserverForPPBackgroundPatternPresetsNotifications; - (void) removeAsObserverForPPBackgroundPatternPresetsNotifications; - (void) handlePPBackgroundPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification; - (void) setupMaxScalingFactorForCurrentDocumentSize; - (void) setupPopUpDefaultMenus; - (void) setupMenuForGridPopUpButton; - (void) setupMenuForBackgroundPatternPopUpButton; - (void) setGridPattern: (PPGridPattern *) gridPattern; - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern; - (void) setSavePanelRequiredFileTypeFromFileFormatPopUp; - (void) updateBackgroundImageControlsForCurrentDocument; - (void) updatePreviewImage; - (void) clearPreviewImage; - (void) resizePreviewViewForImageWithSize: (NSSize) previewImageSize; - (void) scrollPreviewToNormalizedCenter; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPExportPanelAccessoryViewController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPExportPanelAccessoryViewController + (PPExportPanelAccessoryViewController *) controllerForPPDocument: (PPDocument *) ppDocument { return [[[self alloc] initWithPPDocument: ppDocument] autorelease]; } - (id) initWithPPDocument: (PPDocument *) ppDocument { self = [super init]; if (!self) goto ERROR; if (!ppDocument || PPGeometry_IsZeroSize([ppDocument canvasSize])) { goto ERROR; } if (![NSBundle loadNibNamed: kExportPanelAccessoryViewNibName owner: self]) { goto ERROR; } _ppDocument = ppDocument; // unretained to prevent retain loop _gridPattern = [[ppDocument gridPattern] retain]; _backgroundPattern = [[ppDocument backgroundPattern] retain]; _previewScrollViewInitialFrame = [[_previewImageView enclosingScrollView] frame]; _previewScrollerWidth = _previewScrollViewInitialFrame.size.width - [[[_previewImageView enclosingScrollView] contentView] frame].size.width; _previewViewNormalizedCenter = NSMakePoint(0.5f, 0.5f); [self addAsObserverForNSViewNotificationsFromPreviewClipView]; _scalingFactor = kMinExportScalingFactor; _maxScalingFactor = kMaxExportScalingFactor; [_scalingFactorTextField setIntValue: _scalingFactor]; [_scalingFactorTextField setDelegate: self]; [_scalingFactorSlider setMinValue: kMinExportScalingFactor]; [_scalingFactorSlider setMaxValue: _maxScalingFactor]; [_scalingFactorSlider setIntValue: _scalingFactor]; [self setupPopUpDefaultMenus]; [_gridTitleablePopUpButton setDelegate: self]; [_backgroundPatternTitleablePopUpButton setDelegate: self]; return self; ERROR: [self release]; return nil; } - (id) init { return [self initWithPPDocument: nil]; } - (void) dealloc { [self setupWithSavePanel: nil]; [self removeAsObserverForNSViewNotificationsFromPreviewClipView]; [_exportAccessoryView release]; [_gridPopUpDefaultMenu release]; [_backgroundPatternPopUpDefaultMenu release]; [_gridPattern release]; [_backgroundPattern release]; [super dealloc]; } - (void) setupWithSavePanel: (NSSavePanel *) savePanel { if (_savePanel) { [_savePanel setAccessoryView: nil]; [_savePanel release]; _savePanel = nil; [self clearPreviewImage]; [self removeAsObserverForNSWindowNotificationsFromPPDocumentWindow]; [self removeAsObserverForPPGridPatternPresetsNotifications]; [self removeAsObserverForPPBackgroundPatternPresetsNotifications]; } if (savePanel) { _savePanel = [savePanel retain]; [self setupMaxScalingFactorForCurrentDocumentSize]; [self updateBackgroundImageControlsForCurrentDocument]; [self updatePreviewImage]; [self setupMenuForGridPopUpButton]; [self setupMenuForBackgroundPatternPopUpButton]; [_savePanel setAccessoryView: _exportAccessoryView]; [self setSavePanelRequiredFileTypeFromFileFormatPopUp]; [self addAsObserverForNSWindowNotificationsFromPPDocumentWindow]; [self addAsObserverForPPGridPatternPresetsNotifications]; [self addAsObserverForPPBackgroundPatternPresetsNotifications]; } } - (NSString *) selectedFileTypeName { return [[_fileFormatPopUpButton selectedItem] title]; } - (NSString *) selectedFileType { return [[_fileFormatPopUpButton selectedItem] toolTip]; } - (bool) getScalingFactor: (unsigned *) returnedScalingFactor gridPattern: (PPGridPattern **) returnedGridPattern backgroundPattern: (PPBackgroundPattern **) returnedBackgroundPattern backgroundImageFlag: (bool *) returnedBackgroundImageFlag { if (!returnedScalingFactor || !returnedGridPattern || !returnedBackgroundPattern || !returnedBackgroundImageFlag) { goto ERROR; } *returnedScalingFactor = _scalingFactor; *returnedGridPattern = ([_gridCheckbox intValue]) ? _gridPattern : nil; *returnedBackgroundPattern = ([_backgroundPatternCheckbox intValue]) ? _backgroundPattern : nil; *returnedBackgroundImageFlag = ([_backgroundImageCheckbox intValue]) ? YES : NO; return YES; ERROR: return NO; } #pragma mark Actions - (IBAction) scalingFactorSliderMoved: (id) sender { int sliderValue = [_scalingFactorSlider intValue]; if (_scalingFactor != sliderValue) { _scalingFactor = sliderValue; [_scalingFactorTextField setIntValue: _scalingFactor]; [self updatePreviewImage]; } } - (IBAction) canvasSettingCheckboxClicked: (id) sender { [self updatePreviewImage]; } - (IBAction) gridPopUpMenuItemSelected_CurrentPattern: (id) sender { [self setGridPattern: [_ppDocument gridPattern]]; _selectedGridMenuItemType = kPatternMenuItemType_Current; } - (IBAction) gridPopUpMenuItemSelected_DefaultPattern: (id) sender { [self setGridPattern: [PPUserDefaults gridPattern]]; _selectedGridMenuItemType = kPatternMenuItemType_Default; } - (IBAction) gridPopUpMenuItemSelected_PresetPattern: (id) sender { int indexOfPattern; NSArray *presetPatterns; if (![sender isKindOfClass: [NSMenuItem class]]) { goto ERROR; } indexOfPattern = [((NSMenuItem *) sender) tag]; presetPatterns = [[PPGridPatternPresets sharedPresets] patterns]; if ((indexOfPattern < 0) || (indexOfPattern >= [presetPatterns count])) { goto ERROR; } [self setGridPattern: [presetPatterns objectAtIndex: indexOfPattern]]; _selectedGridMenuItemType = kPatternMenuItemType_Preset; return; ERROR: return; } - (IBAction) backgroundPatternPopUpMenuItemSelected_CurrentPattern: (id) sender { [self setBackgroundPattern: [_ppDocument backgroundPattern]]; _selectedBackgroundPatternMenuItemType = kPatternMenuItemType_Current; } - (IBAction) backgroundPatternPopUpMenuItemSelected_DefaultPattern: (id) sender { [self setBackgroundPattern: [PPUserDefaults backgroundPattern]]; _selectedBackgroundPatternMenuItemType = kPatternMenuItemType_Default; } - (IBAction) backgroundPatternPopUpMenuItemSelected_PresetPattern: (id) sender { int indexOfPattern; NSArray *presetPatterns; if (![sender isKindOfClass: [NSMenuItem class]]) { goto ERROR; } indexOfPattern = [((NSMenuItem *) sender) tag]; presetPatterns = [[PPBackgroundPatternPresets sharedPresets] patterns]; if ((indexOfPattern < 0) || (indexOfPattern >= [presetPatterns count])) { goto ERROR; } [self setBackgroundPattern: [presetPatterns objectAtIndex: indexOfPattern]]; _selectedBackgroundPatternMenuItemType = kPatternMenuItemType_Preset; return; ERROR: return; } - (IBAction) fileFormatPopupMenuItemSelected: (id) sender { [self setSavePanelRequiredFileTypeFromFileFormatPopUp]; } #pragma mark NSControl delegate methods (Scaling factor textField) - (void) controlTextDidChange: (NSNotification *) notification { int newScalingFactor = [_scalingFactorTextField ppClampIntValueToMax: _maxScalingFactor min: kMinExportScalingFactor defaultValue: _scalingFactor]; if (newScalingFactor != _scalingFactor) { _scalingFactor = newScalingFactor; [_scalingFactorSlider setIntValue: _scalingFactor]; [self updatePreviewImage]; } } #pragma mark PPTitleablePopUpButton delegate methods - (NSString *) displayTitleForMenuItemWithTitle: (NSString *) itemTitle onTitleablePopUpButton: (PPTitleablePopUpButton *) button { NSString *displayTitle = itemTitle; bool itemTitleIsCurrentPattern = ([itemTitle isEqualToString: kPatternPopUpMenuItemTitle_CurrentPattern]) ? YES : NO; if (button == _gridTitleablePopUpButton) { if (itemTitleIsCurrentPattern) { displayTitle = kGridPopUpButtonTitle_CurrentPattern; } else { displayTitle = [NSString stringWithFormat: kGridPopUpButtonTitleFormat, itemTitle]; } } else if (button == _backgroundPatternTitleablePopUpButton) { if (itemTitleIsCurrentPattern) { displayTitle = kBackgroundPatternPopUpButtonTitle_CurrentPattern; } else { displayTitle = [NSString stringWithFormat: kBackgroundPatternPopUpButtonTitleFormat, itemTitle]; } } return displayTitle; } #pragma mark NSWindow notifications (PPDocument window) - (void) addAsObserverForNSWindowNotificationsFromPPDocumentWindow { NSWindow *window = [_ppDocument ppWindow]; if (!window) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector( handlePPDocumentWindowNotification_DidEndSheet:) name: NSWindowDidEndSheetNotification object: window]; } - (void) removeAsObserverForNSWindowNotificationsFromPPDocumentWindow { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSWindowDidEndSheetNotification object: [_ppDocument ppWindow]]; } - (void) handlePPDocumentWindowNotification_DidEndSheet: (NSNotification *) notification { [self setupWithSavePanel: nil]; } #pragma mark NSView notifications (Preview imageview’s clipview) - (void) addAsObserverForNSViewNotificationsFromPreviewClipView { NSClipView *clipView = [[_previewImageView enclosingScrollView] contentView]; if (!clipView) return; [clipView setPostsBoundsChangedNotifications: YES]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector( handlePreviewClipViewNotification_BoundsDidChange:) name: NSViewBoundsDidChangeNotification object: clipView]; } - (void) removeAsObserverForNSViewNotificationsFromPreviewClipView { NSClipView *clipView = [[_previewImageView enclosingScrollView] contentView]; [[NSNotificationCenter defaultCenter] removeObserver: self name: NSViewBoundsDidChangeNotification object: clipView]; } - (void) handlePreviewClipViewNotification_BoundsDidChange: (NSNotification *) notification { NSRect documentVisibleRect; if (_shouldPreservePreviewNormalizedCenter || PPGeometry_IsZeroSize(_previewImageSize)) { return; } documentVisibleRect = [[_previewImageView enclosingScrollView] documentVisibleRect]; _previewViewNormalizedCenter = NSMakePoint(((documentVisibleRect.origin.x + documentVisibleRect.size.width / 2.0) / _previewImageSize.width), ((documentVisibleRect.origin.y + documentVisibleRect.size.height / 2.0) / _previewImageSize.height)); } #pragma mark PPGridPatternPresets notifications - (void) addAsObserverForPPGridPatternPresetsNotifications { PPGridPatternPresets *gridPatternPresets = [PPGridPatternPresets sharedPresets]; if (!gridPatternPresets) goto ERROR; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPGridPatternPresetsNotification_UpdatedPresets:) name: PPPatternPresetsNotification_UpdatedPresets object: gridPatternPresets]; return; ERROR: return; } - (void) removeAsObserverForPPGridPatternPresetsNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPPatternPresetsNotification_UpdatedPresets object: [PPGridPatternPresets sharedPresets]]; } - (void) handlePPGridPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification { [self setupMenuForGridPopUpButton]; } #pragma mark PPBackgroundPatternPresets notifications - (void) addAsObserverForPPBackgroundPatternPresetsNotifications { PPBackgroundPatternPresets *backgroundPatternPresets = [PPBackgroundPatternPresets sharedPresets]; if (!backgroundPatternPresets) goto ERROR; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPBackgroundPatternPresetsNotification_UpdatedPresets:) name: PPPatternPresetsNotification_UpdatedPresets object: backgroundPatternPresets]; return; ERROR: return; } - (void) removeAsObserverForPPBackgroundPatternPresetsNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPPatternPresetsNotification_UpdatedPresets object: [PPBackgroundPatternPresets sharedPresets]]; } - (void) handlePPBackgroundPatternPresetsNotification_UpdatedPresets: (NSNotification *) notification { [self setupMenuForBackgroundPatternPopUpButton]; } #pragma mark Private methods - (void) setupMaxScalingFactorForCurrentDocumentSize { NSSize canvasSize; int maxScalingFactor; canvasSize = [_ppDocument canvasSize]; if (PPGeometry_IsZeroSize(canvasSize)) { goto ERROR; } maxScalingFactor = MIN(kMaxExportScalingFactor, floorf(kMaxCanvasExportDimension / MAX(canvasSize.width, canvasSize.height))); if (_maxScalingFactor != maxScalingFactor) { _maxScalingFactor = maxScalingFactor; if (_scalingFactor > _maxScalingFactor) { _scalingFactor = _maxScalingFactor; [_scalingFactorTextField setIntValue: _scalingFactor]; } [_scalingFactorSlider setMaxValue: _maxScalingFactor]; [_scalingFactorSlider setIntValue: _scalingFactor]; } return; ERROR: return; } - (void) setupPopUpDefaultMenus { NSMenuItem *currentPatternMenuItem, *defaultPatternMenuItem; // Grid popup button's default menu currentPatternMenuItem = [[[NSMenuItem alloc] initWithTitle: kPatternPopUpMenuItemTitle_CurrentPattern action: @selector(gridPopUpMenuItemSelected_CurrentPattern:) keyEquivalent: @""] autorelease]; if (!currentPatternMenuItem) goto ERROR; [currentPatternMenuItem setTarget: self]; defaultPatternMenuItem = [[[NSMenuItem alloc] initWithTitle: kPatternPopUpMenuItemTitle_DefaultPattern action: @selector(gridPopUpMenuItemSelected_DefaultPattern:) keyEquivalent: @""] autorelease]; if (!defaultPatternMenuItem) goto ERROR; [defaultPatternMenuItem setTarget: self]; [_gridPopUpDefaultMenu release]; _gridPopUpDefaultMenu = [[NSMenu alloc] initWithTitle: @""]; if (!_gridPopUpDefaultMenu) goto ERROR; [_gridPopUpDefaultMenu setAutoenablesItems: NO]; [_gridPopUpDefaultMenu addItem: currentPatternMenuItem]; [_gridPopUpDefaultMenu addItem: defaultPatternMenuItem]; // Background pattern popup button's default menu currentPatternMenuItem = [[[NSMenuItem alloc] initWithTitle: kPatternPopUpMenuItemTitle_CurrentPattern action: @selector(backgroundPatternPopUpMenuItemSelected_CurrentPattern:) keyEquivalent: @""] autorelease]; if (!currentPatternMenuItem) goto ERROR; [currentPatternMenuItem setTarget: self]; defaultPatternMenuItem = [[[NSMenuItem alloc] initWithTitle: kPatternPopUpMenuItemTitle_DefaultPattern action: @selector(backgroundPatternPopUpMenuItemSelected_DefaultPattern:) keyEquivalent: @""] autorelease]; if (!defaultPatternMenuItem) goto ERROR; [defaultPatternMenuItem setTarget: self]; [_backgroundPatternPopUpDefaultMenu release]; _backgroundPatternPopUpDefaultMenu = [[NSMenu alloc] initWithTitle: @""]; if (!_backgroundPatternPopUpDefaultMenu) goto ERROR; [_backgroundPatternPopUpDefaultMenu setAutoenablesItems: NO]; [_backgroundPatternPopUpDefaultMenu addItem: currentPatternMenuItem]; [_backgroundPatternPopUpDefaultMenu addItem: defaultPatternMenuItem]; return; ERROR: return; } - (void) setupMenuForGridPopUpButton { NSMenu *popUpButtonMenu; NSMenuItem *presetItem; int indexOfItemToSelect, numPresetPatterns, presetIndex; NSArray *presetPatterns; PPGridPattern *presetPattern; NSString *presetTitle; popUpButtonMenu = [[_gridPopUpDefaultMenu copy] autorelease]; if (!popUpButtonMenu) goto ERROR; if ((_selectedGridMenuItemType != kPatternMenuItemType_Current) && (_selectedGridMenuItemType != kPatternMenuItemType_Default)) { _selectedGridMenuItemType = kPatternMenuItemType_Preset; } presetPatterns = [[PPGridPatternPresets sharedPresets] patterns]; numPresetPatterns = [presetPatterns count]; if (numPresetPatterns > 0) { [popUpButtonMenu addItem: [NSMenuItem separatorItem]]; } indexOfItemToSelect = -1; for (presetIndex=0; presetIndex 0) { [popUpButtonMenu addItem: [NSMenuItem separatorItem]]; } indexOfItemToSelect = -1; for (presetIndex=0; presetIndex contentViewSize.height) { viewMarginPadding = _previewScrollerWidth; } else { viewMarginPadding = kMarginPaddingForScrollerlessScrollView; } newPreviewScrollViewFrame.size.width = previewImageSize.width + viewMarginPadding; } if (previewImageSize.height < contentViewSize.height) { if (previewImageSize.width > contentViewSize.width) { viewMarginPadding = _previewScrollerWidth; } else { viewMarginPadding = kMarginPaddingForScrollerlessScrollView; } newPreviewScrollViewFrame.size.height = previewImageSize.height + viewMarginPadding; } newPreviewScrollViewFrame = PPGeometry_CenterRectInRect(newPreviewScrollViewFrame, _previewScrollViewInitialFrame); [previewScrollView setFrame: newPreviewScrollViewFrame]; // Changing scrollview frame causes drawing artifacts (10.4) - fix by redrawing superview [[previewScrollView superview] setNeedsDisplayInRect: _previewScrollViewInitialFrame]; _previewImageSize = previewImageSize; [self scrollPreviewToNormalizedCenter]; _shouldPreservePreviewNormalizedCenter = NO; } - (void) scrollPreviewToNormalizedCenter { NSSize clipViewSize = [[[_previewImageView enclosingScrollView] contentView] bounds].size; NSPoint centerPoint = NSMakePoint(_previewViewNormalizedCenter.x * _previewImageSize.width - clipViewSize.width / 2.0f, _previewViewNormalizedCenter.y * _previewImageSize.height - clipViewSize.height / 2.0f); [_previewImageView scrollPoint: centerPoint]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPFilledRoundedRectView.h0000644000076500000240000000230513234403416022757 0ustar joshstaff/* PPFilledRoundedRectView.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPFilledRoundedRectView : NSImageView { NSColor *_color; } + viewWithFrame: (NSRect) frame andColor: (NSColor *) color; - initWithFrame: (NSRect) frame andColor: (NSColor *) color; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPFilledRoundedRectView.m0000644000076500000240000001636213721552475023007 0ustar joshstaff/* PPFilledRoundedRectView.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPFilledRoundedRectView.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" // distance from the shape's corner edge to begin the curve for the rounded corner #define kRoundedBackgroundShapeCurve_StartingDistanceFromEdge 15 // distance from the beginning of the curve to place the curve's control point // (higher -> corner is sharper, lower -> corner is more round) #define kRoundedBackgroundShapeCurve_ControlPointDistanceFromCurveStart 10 // for convenience when placing the control point, distance from the control point to the edge #define kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge \ (kRoundedBackgroundShapeCurve_StartingDistanceFromEdge \ - kRoundedBackgroundShapeCurve_ControlPointDistanceFromCurveStart) static NSBezierPath *RoundedRectPathOfSize(NSSize shapeSize); @interface PPFilledRoundedRectView (PrivateMethods) - (void) setupFilledRoundedRectImage; @end @implementation PPFilledRoundedRectView + viewWithFrame: (NSRect) frame andColor: (NSColor *) color { return [[[self alloc] initWithFrame: frame andColor: color] autorelease]; } - initWithFrame: (NSRect) frame andColor: (NSColor *) color { self = [super initWithFrame: frame]; if (!self) goto ERROR; if (!color) { color = [NSColor blackColor]; } _color = [color retain]; [self setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; [self setupFilledRoundedRectImage]; return self; ERROR: [self release]; return nil; } - initWithFrame: (NSRect) frame { return [self initWithFrame: frame andColor: nil]; } - (void) dealloc { [_color release]; [super dealloc]; } #pragma mark NSView overrides - (void) setFrameSize: (NSSize) newSize { [super setFrameSize: newSize]; [self setupFilledRoundedRectImage]; } #pragma mark Private methods - (void) setupFilledRoundedRectImage { NSSize backgroundImageSize; NSBitmapImageRep *backgroundBitmap; NSImage *backgroundImage; backgroundImageSize = [self frame].size; backgroundBitmap = [NSBitmapImageRep ppImageBitmapOfSize: backgroundImageSize]; if (!backgroundBitmap) goto ERROR; [backgroundBitmap ppSetAsCurrentGraphicsContext]; [_color set]; [RoundedRectPathOfSize(backgroundImageSize) fill]; [backgroundBitmap ppRestoreGraphicsContext]; backgroundImage = [NSImage ppImageWithBitmap: backgroundBitmap]; if (!backgroundImage) goto ERROR; [self setImage: backgroundImage]; return; ERROR: return; } @end #pragma mark Private functions static NSBezierPath *RoundedRectPathOfSize(NSSize shapeSize) { NSBezierPath *shape; float leftEdge, rightEdge, bottomEdge, topEdge; shape = [[[NSBezierPath alloc] init] autorelease]; if (!shape) goto ERROR; leftEdge = 0.5f; bottomEdge = 0.5f; rightEdge = ceilf(shapeSize.width) - 0.5f; topEdge = ceilf(shapeSize.height) - 0.5f; [shape moveToPoint: NSMakePoint(leftEdge + kRoundedBackgroundShapeCurve_StartingDistanceFromEdge, bottomEdge)]; [shape curveToPoint: NSMakePoint(leftEdge, bottomEdge + kRoundedBackgroundShapeCurve_StartingDistanceFromEdge) controlPoint1: NSMakePoint(leftEdge + kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge, bottomEdge) controlPoint2: NSMakePoint(leftEdge, bottomEdge + kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge)]; [shape lineToPoint: NSMakePoint(leftEdge, topEdge - kRoundedBackgroundShapeCurve_StartingDistanceFromEdge)]; [shape curveToPoint: NSMakePoint(leftEdge + kRoundedBackgroundShapeCurve_StartingDistanceFromEdge, topEdge) controlPoint1: NSMakePoint(leftEdge, topEdge - kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge) controlPoint2: NSMakePoint(leftEdge + kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge, topEdge)]; [shape lineToPoint: NSMakePoint(rightEdge - kRoundedBackgroundShapeCurve_StartingDistanceFromEdge, topEdge)]; [shape curveToPoint: NSMakePoint(rightEdge, topEdge - kRoundedBackgroundShapeCurve_StartingDistanceFromEdge) controlPoint1: NSMakePoint(rightEdge - kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge, topEdge) controlPoint2: NSMakePoint(rightEdge, topEdge - kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge)]; [shape lineToPoint: NSMakePoint(rightEdge, bottomEdge + kRoundedBackgroundShapeCurve_StartingDistanceFromEdge)]; [shape curveToPoint: NSMakePoint(rightEdge - kRoundedBackgroundShapeCurve_StartingDistanceFromEdge, bottomEdge) controlPoint1: NSMakePoint(rightEdge, bottomEdge + kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge) controlPoint2: NSMakePoint(rightEdge - kRoundedBackgroundShapeCurve_ControlPointDistanceFromEdge, bottomEdge)]; [shape closePath]; return shape; ERROR: return nil; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPFillTool.h0000644000076500000240000000217713234403416020321 0ustar joshstaff/* PPFillTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPFillTool : PPTool { NSPoint _mouseDownLocationInImage; unsigned _lastColorMatchTolerance; int _lastPixelMatchingMode; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPFillTool.m0000644000076500000240000001174713234403206020326 0ustar joshstaff/* PPFillTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPFillTool.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPGeometry.h" #import "PPToolUtilities.h" #import "NSCursor_PPUtilities.h" #define kFillToolAttributesMask \ (kPPToolAttributeMask_RequiresPointsInViewCoordinates \ | kPPToolAttributeMask_DisableAutoscrolling \ | kPPToolAttributeMask_MatchCanvasDisplayModeToOperationTarget) @implementation PPFillTool - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { unsigned colorMatchTolerance; PPPixelMatchingMode pixelMatchingMode; NSBitmapImageRep *matchMask; NSRect matchMaskBounds; // tool receives points in view coordinates, must convert to get image coordinates _mouseDownLocationInImage = [canvasView imagePointFromViewPoint: currentPoint clippedToCanvasBounds: YES]; colorMatchTolerance = 0; pixelMatchingMode = PPToolUtils_PixelMatchingModeForModifierKeyFlags(modifierKeyFlags); [ppDocument beginDrawingWithPenMode: kPPPenMode_Fill]; [ppDocument fillPixelsMatchingColorAtPoint: _mouseDownLocationInImage colorMatchTolerance: colorMatchTolerance pixelMatchingMode: pixelMatchingMode returnedMatchMask: &matchMask returnedMatchMaskBounds: &matchMaskBounds]; [canvasView beginFillToolOverlayForOperationTarget: [ppDocument layerOperationTarget] fillColor: [ppDocument fillColor]]; [canvasView setFillToolOverlayToMask: matchMask maskBounds: matchMaskBounds]; [canvasView showMatchToolToleranceIndicatorAtViewPoint: currentPoint]; _lastColorMatchTolerance = colorMatchTolerance; _lastPixelMatchingMode = pixelMatchingMode; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { unsigned mouseDistance, colorMatchTolerance; PPPixelMatchingMode pixelMatchingMode; NSBitmapImageRep *matchMask; NSRect matchMaskBounds; mouseDistance = PPGeometry_IntegerDistanceBetweenPoints(mouseDownPoint, currentPoint); colorMatchTolerance = PPToolUtils_ColorMatchToleranceForMouseDistance(mouseDistance); pixelMatchingMode = PPToolUtils_PixelMatchingModeForModifierKeyFlags(modifierKeyFlags); if ((colorMatchTolerance != _lastColorMatchTolerance) || (pixelMatchingMode != _lastPixelMatchingMode)) { [ppDocument undoCurrentDrawingAtNextDraw]; [ppDocument fillPixelsMatchingColorAtPoint: _mouseDownLocationInImage colorMatchTolerance: colorMatchTolerance pixelMatchingMode: pixelMatchingMode returnedMatchMask: &matchMask returnedMatchMaskBounds: &matchMaskBounds]; [canvasView setFillToolOverlayToMask: matchMask maskBounds: matchMaskBounds]; _lastColorMatchTolerance = colorMatchTolerance; _lastPixelMatchingMode = pixelMatchingMode; } [canvasView setMatchToolToleranceIndicatorRadius: mouseDistance]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [canvasView hideMatchToolToleranceIndicator]; [canvasView endFillToolOverlay]; [ppDocument finishDrawing]; } - (NSCursor *) cursor { return [NSCursor ppFillToolCursor]; } - (unsigned) toolAttributeFlags { return kFillToolAttributesMask; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPFramePinningType.h0000644000076500000240000000277513234403416022020 0ustar joshstaff/* PPFramePinningType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPFramePinningType_TopLeft, kPPFramePinningType_TopRight, kPPFramePinningType_CenterLeft, kPPFramePinningType_CenterRight, kPPFramePinningType_BottomLeft, kPPFramePinningType_BottomRight, // add new PPFramePinningType values above this line kNumPPFramePinningTypes, kPPFramePinningType_Invalid } PPFramePinningType; static inline bool PPFramePinningType_IsValid(PPFramePinningType framePinningType) { return (((unsigned) framePinningType) < kNumPPFramePinningTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPFreehandSelectTool.h0000644000076500000240000000210213234403416022273 0ustar joshstaff/* PPFreehandSelectTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPFreehandSelectTool : PPTool { NSBezierPath *_toolPath; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPFreehandSelectTool.m0000644000076500000240000001074313234403206022307 0ustar joshstaff/* PPFreehandSelectTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPFreehandSelectTool.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPToolUtilities.h" #import "PPGeometry.h" #import "NSCursor_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #define kFreehandSelectToolAttributesMask \ (kPPToolAttributeMask_RequiresPointsCroppedToCanvasBounds \ | kPPToolAttributeMask_DisableSkippingOfMouseDraggedEvents) @interface PPFreehandSelectTool (PrivateMethods) - (void) updateSelectionToolOverlayPathOnCanvasView: (PPCanvasView *) canvasView withModifierKeyFlags: (int) modifierKeyFlags forDocument: (PPDocument *) ppDocument; @end @implementation PPFreehandSelectTool - init { self = [super init]; if (!self) goto ERROR; _toolPath = [[NSBezierPath bezierPath] retain]; if (!_toolPath) goto ERROR; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_toolPath release]; [super dealloc]; } - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [_toolPath removeAllPoints]; [_toolPath ppAppendSinglePixelLineAtPoint: currentPoint]; [self updateSelectionToolOverlayPathOnCanvasView: canvasView withModifierKeyFlags: modifierKeyFlags forDocument: ppDocument]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [_toolPath ppLineToPixelAtPoint: currentPoint]; [self updateSelectionToolOverlayPathOnCanvasView: canvasView withModifierKeyFlags: modifierKeyFlags forDocument: ppDocument]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { PPSelectionMode selectionMode; [canvasView clearSelectionToolOverlay]; selectionMode = PPToolUtils_SelectionModeForModifierKeyFlags(modifierKeyFlags); if ((selectionMode == kPPSelectionMode_Replace) && !PPGeometry_RectCoversMultiplePoints([_toolPath bounds])) { [ppDocument deselectAll]; return; } [ppDocument selectPath: _toolPath selectionMode: selectionMode]; [_toolPath removeAllPoints]; } - (NSCursor *) cursor { return [NSCursor ppFreehandSelectCursor]; } - (unsigned) toolAttributeFlags { return kFreehandSelectToolAttributesMask; } #pragma mark Private methods - (void) updateSelectionToolOverlayPathOnCanvasView: (PPCanvasView *) canvasView withModifierKeyFlags: (int) modifierKeyFlags forDocument: (PPDocument *) ppDocument { PPSelectionMode selectionMode; NSBitmapImageRep *intersectMask; selectionMode = PPToolUtils_SelectionModeForModifierKeyFlags(modifierKeyFlags); intersectMask = (selectionMode == kPPSelectionMode_Intersect) ? [ppDocument selectionMask] : nil; [canvasView setSelectionToolOverlayToPath: _toolPath selectionMode: selectionMode intersectMask: intersectMask]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPGeometry.h0000644000076500000240000000747013732462242020376 0ustar joshstaff/* PPGeometry.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import NSPoint PPGeometry_CenterOfRect(NSRect rect); NSRect PPGeometry_OriginRectOfSize(NSSize frameSize); NSRect PPGeometry_CenterRectInRect(NSRect rectToBeCentered, NSRect centerRect); NSRect PPGeometry_PixelBoundsCoveredByRect(NSRect rect); NSRect PPGeometry_PixelBoundsWithCornerPoints(NSPoint corner1, NSPoint corner2); NSRect PPGeometry_PixelBoundsWithCenterAndCornerPoint(NSPoint center, NSPoint corner); NSRect PPGeometry_PixelCenteredRect(NSRect rect); NSRect PPGeometry_RectScaledByFactor(NSRect rect, float scalingFactor); bool PPGeometry_RectCoversMultiplePoints(NSRect rect); bool PPGeometry_RectIsSquare(NSRect rect); NSPoint PPGeometry_PointClippedToIntegerValues(NSPoint point); NSPoint PPGeometry_PointClippedToRect(NSPoint point, NSRect rect); NSPoint PPGeometry_PointSum(NSPoint point1, NSPoint point2); NSPoint PPGeometry_PointDifference(NSPoint point1, NSPoint point2); float PPGeometry_DistanceBetweenPoints(NSPoint point1, NSPoint point2); unsigned PPGeometry_IntegerDistanceBetweenPoints(NSPoint point1, NSPoint point2); NSPoint PPGeometry_PixelCenteredPoint(NSPoint point); bool PPGeometry_PointTouchesEdgePixelOfRect(NSPoint point, NSRect rect); NSSize PPGeometry_SizeClippedToIntegerValues(NSSize size); NSSize PPGeometry_SizeClampedToMinMaxValues(NSSize size, float minValue, float maxValue); NSSize PPGeometry_SizeSum(NSSize size1, NSSize size2); NSSize PPGeometry_SizeDifference(NSSize size1, NSSize size2); NSSize PPGeometry_SizeScaledByFactorAndRoundedToIntegerValues(NSSize size, float scalingFactor); bool PPGeometry_IsZeroSize(NSSize size); bool PPGeometry_SizeExceedsDimension(NSSize size, float dimension); NSPoint PPGeometry_OriginPointForCenteringRectAtPoint(NSRect rect, NSPoint centerPoint); NSPoint PPGeometry_OriginPointForCenteringSizeInSize(NSSize centeringSize, NSSize centerSize); NSRect PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(NSSize sourceSize, NSSize destinationSize); float PPGeometry_ScalingFactorOfSourceRectToDestinationRect(NSRect sourceRect, NSRect destinationRect); NSPoint PPGeometry_OriginPointForConfiningRectInsideRect(NSRect rect, NSRect confinementBounds); NSPoint PPGeometry_FarthestPointOnDiagonal(NSPoint originPoint, NSPoint point); NSPoint PPGeometry_NearestPointOnOneSixteenthSlope(NSPoint originPoint, NSPoint point); NSPoint PPGeometry_OffsetPointToNextNearestVertexOnGridWithSpacingSize(NSPoint point, NSSize spacingSize); NSRect PPGeometry_GridBoundsCoveredByRectOnCanvasOfSizeWithGridOfSpacingSize(NSRect rect, NSSize canvasSize, NSSize spacingSize); PikoPixel.Sources.1.0-b10b/PikoPixel/PPGeometry.m0000644000076500000240000004136513732462242020404 0ustar joshstaff/* PPGeometry.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPGeometry.h" // disable clang warnings about fabsf() truncating passed double-type values to float-type // (absolute-value warnings are enabled by default on Xcode 6.2 & later) #ifdef __clang__ # pragma clang diagnostic ignored "-Wabsolute-value" #endif // __clang__ NSPoint PPGeometry_CenterOfRect(NSRect rect) { return NSMakePoint(rect.origin.x + rect.size.width / 2.0f, rect.origin.y + rect.size.height / 2.0f); } NSRect PPGeometry_OriginRectOfSize(NSSize frameSize) { return NSMakeRect(0.0f, 0.0f, ceilf(frameSize.width), ceilf(frameSize.height)); } NSRect PPGeometry_CenterRectInRect(NSRect rectToBeCentered, NSRect centerRect) { NSPoint centerPoint = PPGeometry_CenterOfRect(centerRect); rectToBeCentered.origin = PPGeometry_OriginPointForCenteringRectAtPoint(rectToBeCentered, centerPoint); return rectToBeCentered; } NSRect PPGeometry_PixelBoundsCoveredByRect(NSRect rect) { NSRect coveredRect; if (NSIsEmptyRect(rect)) { return NSZeroRect; } coveredRect.origin = NSMakePoint(floorf(rect.origin.x), floorf(rect.origin.y)); coveredRect.size = NSMakeSize(ceilf(rect.origin.x + rect.size.width) - coveredRect.origin.x, ceilf(rect.origin.y + rect.size.height) - coveredRect.origin.y); return coveredRect; } NSRect PPGeometry_PixelBoundsWithCornerPoints(NSPoint corner1, NSPoint corner2) { NSRect rect; if (corner1.x < corner2.x) { rect.origin.x = corner1.x; rect.size.width = corner2.x - corner1.x + 1.0f; } else { rect.origin.x = corner2.x; rect.size.width = corner1.x - corner2.x + 1.0f; } if (corner1.y < corner2.y) { rect.origin.y = corner1.y; rect.size.height = corner2.y - corner1.y + 1.0f; } else { rect.origin.y = corner2.y; rect.size.height = corner1.y - corner2.y + 1.0f; } return PPGeometry_PixelBoundsCoveredByRect(rect); } NSRect PPGeometry_PixelBoundsWithCenterAndCornerPoint(NSPoint center, NSPoint corner) { float deltaX, deltaY; NSRect rect; deltaX = fabsf(corner.x - center.x); deltaY = fabsf(corner.y - center.y); rect.origin = NSMakePoint(center.x - deltaX, center.y - deltaY); rect.size = NSMakeSize(1.0f + 2.0f * deltaX, 1.0f + 2.0f * deltaY); return PPGeometry_PixelBoundsCoveredByRect(rect); } NSRect PPGeometry_PixelCenteredRect(NSRect rect) { if (NSIsEmptyRect(rect)) { return NSZeroRect; } rect = PPGeometry_PixelBoundsCoveredByRect(rect); rect.origin = PPGeometry_PixelCenteredPoint(rect.origin); if (rect.size.width > 1.0f) { rect.size.width -= 1.0f; } else { rect.size.width = 0.25f; } if (rect.size.height > 1.0f) { rect.size.height -= 1.0f; } else { rect.size.height = 0.25f; } return rect; } NSRect PPGeometry_RectScaledByFactor(NSRect rect, float scalingFactor) { return NSMakeRect(rect.origin.x * scalingFactor, rect.origin.y * scalingFactor, rect.size.width * scalingFactor, rect.size.height * scalingFactor); } bool PPGeometry_RectCoversMultiplePoints(NSRect rect) { if (NSIsEmptyRect(rect)) { return NO; } rect = PPGeometry_PixelBoundsCoveredByRect(rect); return ((rect.size.width > 1.0f) || (rect.size.height > 1.0f)) ? YES : NO; } bool PPGeometry_RectIsSquare(NSRect rect) { return ((rect.size.width > 0.0f) && (rect.size.width == rect.size.height)) ? YES : NO; } NSPoint PPGeometry_PointClippedToIntegerValues(NSPoint point) { return NSMakePoint(floorf(point.x), floorf(point.y)); } NSPoint PPGeometry_PointClippedToRect(NSPoint point, NSRect rect) { if (point.x < rect.origin.x) { point.x = rect.origin.x; } else if (point.x >= (rect.origin.x + rect.size.width)) { point.x = rect.origin.x + rect.size.width - 1.0f; } if (point.y < rect.origin.y) { point.y = rect.origin.y; } else if (point.y >= (rect.origin.y + rect.size.height)) { point.y = rect.origin.y + rect.size.height - 1.0f; } return point; } NSPoint PPGeometry_PointSum(NSPoint point1, NSPoint point2) { return NSMakePoint(point1.x + point2.x, point1.y + point2.y); } NSPoint PPGeometry_PointDifference(NSPoint point1, NSPoint point2) { return NSMakePoint(point1.x - point2.x, point1.y - point2.y); } float PPGeometry_DistanceBetweenPoints(NSPoint point1, NSPoint point2) { NSPoint deltaPoint = PPGeometry_PointDifference(point1, point2); return sqrtf(deltaPoint.x * deltaPoint.x + deltaPoint.y * deltaPoint.y); } unsigned PPGeometry_IntegerDistanceBetweenPoints(NSPoint point1, NSPoint point2) { return (unsigned) roundf(PPGeometry_DistanceBetweenPoints(point1, point2)); } NSPoint PPGeometry_PixelCenteredPoint(NSPoint point) { return NSMakePoint(floorf(point.x) + 0.5f, floorf(point.y) + 0.5f); } bool PPGeometry_PointTouchesEdgePixelOfRect(NSPoint point, NSRect rect) { if ((fabsf(point.y - NSMaxY(rect)) <= 1.0f) // top edge || (fabsf(point.y - NSMinY(rect)) <= 1.0f)) // bottom edge { // point.x between left & right edges? return ((point.x >= (NSMinX(rect) - 1.0f)) && (point.x <= (NSMaxX(rect) + 1.0f))) ? YES : NO; } if ((fabsf(point.x - NSMinX(rect)) <= 1.0f) // left edge || (fabsf(point.x - NSMaxX(rect)) <= 1.0f)) // right edge { // point.y between bottom & top edges? return ((point.y >= (NSMinY(rect) - 1.0f)) && (point.y <= (NSMaxY(rect) + 1.0f))) ? YES : NO; } return NO; } NSSize PPGeometry_SizeClippedToIntegerValues(NSSize size) { return NSMakeSize(floorf(size.width), floorf(size.height)); } NSSize PPGeometry_SizeClampedToMinMaxValues(NSSize size, float minValue, float maxValue) { if (size.width < minValue) { size.width = minValue; } else if (size.width > maxValue) { size.width = maxValue; } if (size.height < minValue) { size.height = minValue; } else if (size.height > maxValue) { size.height = maxValue; } return size; } NSSize PPGeometry_SizeSum(NSSize size1, NSSize size2) { return NSMakeSize(size1.width + size2.width, size1.height + size2.height); } NSSize PPGeometry_SizeDifference(NSSize size1, NSSize size2) { return NSMakeSize(size1.width - size2.width, size1.height - size2.height); } NSSize PPGeometry_SizeScaledByFactorAndRoundedToIntegerValues(NSSize size, float scalingFactor) { return NSMakeSize(roundf(size.width * scalingFactor), roundf(size.height * scalingFactor)); } bool PPGeometry_IsZeroSize(NSSize size) { return ((size.width <= 0.0f) || (size.height <= 0.0f)) ? YES : NO; } bool PPGeometry_SizeExceedsDimension(NSSize size, float dimension) { return ((size.width > dimension) || (size.height > dimension)) ? YES : NO; } NSPoint PPGeometry_OriginPointForCenteringRectAtPoint(NSRect rect, NSPoint centerPoint) { return NSMakePoint(roundf(centerPoint.x - (rect.size.width / 2.0f)), roundf(centerPoint.y - (rect.size.height / 2.0f))); } NSPoint PPGeometry_OriginPointForCenteringSizeInSize(NSSize centeringSize, NSSize centerSize) { NSPoint centerPoint; NSRect rectToBeCentered; centerPoint = NSMakePoint(centerSize.width / 2.0f, centerSize.height / 2.0f); rectToBeCentered = PPGeometry_OriginRectOfSize(centeringSize); return PPGeometry_OriginPointForCenteringRectAtPoint(rectToBeCentered, centerPoint); } NSRect PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(NSSize sourceSize, NSSize destinationSize) { float sourceAspectRatio, destinationAspectRatio; NSRect scaledBounds; if (PPGeometry_IsZeroSize(sourceSize) || PPGeometry_IsZeroSize(destinationSize)) { return NSZeroRect; } sourceAspectRatio = sourceSize.width / sourceSize.height; destinationAspectRatio = destinationSize.width / destinationSize.height; if (sourceAspectRatio == destinationAspectRatio) { scaledBounds = PPGeometry_OriginRectOfSize(destinationSize); } else if (sourceAspectRatio >= destinationAspectRatio) { float scaledHeight = roundf(destinationSize.width / sourceAspectRatio); if (scaledHeight < 1.0f) { scaledHeight = 1.0f; } scaledBounds.origin.x = 0.0f; scaledBounds.origin.y = roundf((destinationSize.height - scaledHeight) / 2.0f); scaledBounds.size.width = destinationSize.width; scaledBounds.size.height = scaledHeight; } else { float scaledWidth = roundf(destinationSize.height * sourceAspectRatio); if (scaledWidth < 1.0f) { scaledWidth = 1.0f; } scaledBounds.origin.x = roundf((destinationSize.width - scaledWidth) / 2.0f); scaledBounds.origin.y = 0.0f; scaledBounds.size.width = scaledWidth; scaledBounds.size.height = destinationSize.height; } return scaledBounds; } float PPGeometry_ScalingFactorOfSourceRectToDestinationRect(NSRect sourceRect, NSRect destinationRect) { if (sourceRect.size.width == 0) { return 0; } return (destinationRect.size.width / sourceRect.size.width); } NSPoint PPGeometry_OriginPointForConfiningRectInsideRect(NSRect rect, NSRect confinementBounds) { if (rect.origin.x < confinementBounds.origin.x) { rect.origin.x = confinementBounds.origin.x; } else { float maxAllowedX = confinementBounds.origin.x + confinementBounds.size.width; if ((rect.origin.x + rect.size.width) > maxAllowedX) { rect.origin.x = maxAllowedX - rect.size.width; } } if (rect.origin.y < confinementBounds.origin.y) { rect.origin.y = confinementBounds.origin.y; } else { float maxAllowedY = confinementBounds.origin.y + confinementBounds.size.height; if ((rect.origin.y + rect.size.height) > maxAllowedY) { rect.origin.y = maxAllowedY - rect.size.height; } } return rect.origin; } NSPoint PPGeometry_FarthestPointOnDiagonal(NSPoint originPoint, NSPoint point) { float deltaX, deltaY, delta; NSPoint nearestPoint; deltaX = fabsf(point.x - originPoint.x); deltaY = fabsf(point.y - originPoint.y); delta = (deltaX > deltaY) ? deltaX : deltaY; if (point.x >= originPoint.x) { nearestPoint.x = originPoint.x + delta; } else { nearestPoint.x = originPoint.x - delta; } if (point.y >= originPoint.y) { nearestPoint.y = originPoint.y + delta; } else { nearestPoint.y = originPoint.y - delta; } return PPGeometry_PointClippedToIntegerValues(nearestPoint); } NSPoint PPGeometry_NearestPointOnOneSixteenthSlope(NSPoint originPoint, NSPoint point) { float deltaX, deltaY, xSign, ySign, slope; NSPoint nearestPoint; deltaX = fabsf(point.x - originPoint.x); deltaY = fabsf(point.y - originPoint.y); if ((deltaX == 0.0f) || (deltaY == 0.0f) || ((deltaX <= 2.0f) && (deltaY <= 2.0f))) { return point; } xSign = (point.x >= originPoint.x) ? 1.0f : -1.0f; ySign = (point.y >= originPoint.y) ? 1.0f : -1.0f; nearestPoint = point; slope = deltaY / deltaX; if (slope >= 4.0f) { nearestPoint.x = originPoint.x; } else if (slope >= 2.0f) { // roundup by 1 to make line endpoints draw properly (lineshift after 2 pixels, not 1) nearestPoint.y = originPoint.y + ySign * (2.0f * deltaX + 1.0f); } else if (slope >= 4.0f/3.0f) { if (deltaY/2.0f != floorf(deltaY/2.0f)) { deltaY += 1.0f; nearestPoint.y += ySign; } nearestPoint.x = originPoint.x + xSign * (deltaY / 2.0f); nearestPoint.y += ySign; // roundup by 1 to make line endpoints draw properly } else if (slope >= 1.0f) { nearestPoint.y = originPoint.y + ySign * deltaX; } else if (slope >= 0.75f) { nearestPoint.x = originPoint.x + xSign * deltaY; } else if (slope >= 0.5f) { if (deltaX/2.0f != floorf(deltaX/2.0f)) { deltaX += 1.0f; nearestPoint.x += xSign; } nearestPoint.x += xSign; // roundup by 1 to make line endpoints draw properly nearestPoint.y = originPoint.y + ySign * deltaX / 2.0f; } else if (slope >= 0.25f) { // roundup by 1 to make line endpoints draw properly (lineshift after 2 pixels, not 1) nearestPoint.x = originPoint.x + xSign * (2.0f * deltaY + 1.0f); } else { nearestPoint.y = originPoint.y; } return PPGeometry_PointClippedToIntegerValues(nearestPoint); } NSPoint PPGeometry_OffsetPointToNextNearestVertexOnGridWithSpacingSize(NSPoint point, NSSize spacingSize) { int pointX, pointY, spacingWidth, spacingHeight, remainderX, remainderY; pointX = floorf(point.x); pointY = floorf(point.y); spacingWidth = floorf(spacingSize.width); spacingHeight = floorf(spacingSize.height); if ((spacingWidth <= 0) || (spacingHeight <= 0)) { goto ERROR; } if (pointX < 0) { pointX = spacingWidth + (pointX % spacingWidth); } if (pointY < 0) { pointY = spacingHeight + (pointY % spacingHeight); } remainderX = pointX % spacingWidth; remainderY = pointY % spacingHeight; return NSMakePoint((remainderX) ? spacingWidth - remainderX : 0.0f, (remainderY) ? spacingHeight - remainderY : 0.0f); ERROR: return NSZeroPoint; } NSRect PPGeometry_GridBoundsCoveredByRectOnCanvasOfSizeWithGridOfSpacingSize(NSRect rect, NSSize canvasSize, NSSize spacingSize) { NSPoint offsetToGridVertex, topRightPoint; NSRect gridAlignedRect; float gridlinesBottomGap; canvasSize = PPGeometry_SizeClippedToIntegerValues(canvasSize); spacingSize = PPGeometry_SizeClippedToIntegerValues(spacingSize); if (NSIsEmptyRect(rect) || PPGeometry_IsZeroSize(canvasSize) || PPGeometry_IsZeroSize(spacingSize)) { return rect; } rect = PPGeometry_PixelBoundsCoveredByRect(rect); // bottom-left offsetToGridVertex = PPGeometry_OffsetPointToNextNearestVertexOnGridWithSpacingSize( NSMakePoint(rect.origin.x, canvasSize.height - rect.origin.y), spacingSize); if (offsetToGridVertex.x) { offsetToGridVertex.x = spacingSize.width - offsetToGridVertex.x; } gridAlignedRect.origin = PPGeometry_PointDifference(rect.origin, offsetToGridVertex); // top-right topRightPoint = NSMakePoint(NSMaxX(rect), NSMaxY(rect)); gridlinesBottomGap = PPGeometry_OffsetPointToNextNearestVertexOnGridWithSpacingSize( NSMakePoint(0.0f, canvasSize.height), spacingSize).y; offsetToGridVertex = PPGeometry_OffsetPointToNextNearestVertexOnGridWithSpacingSize( NSMakePoint(topRightPoint.x, topRightPoint.y + gridlinesBottomGap), spacingSize); gridAlignedRect.size = NSMakeSize(topRightPoint.x + offsetToGridVertex.x - gridAlignedRect.origin.x, topRightPoint.y + offsetToGridVertex.y - gridAlignedRect.origin.y); return NSIntersectionRect(gridAlignedRect, PPGeometry_OriginRectOfSize(canvasSize)); } PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepDefaults_CustomTheme.plist0000644000076500000240000000243013354543561025034 0ustar joshstaff GSMenuBarHeight 24 NSMenuFontSize 14 GSMenuSeparatorHeight 10 GSScrollViewNoInnerBorder YES windowBackgroundColor 0.82 0.82 0.82 controlBackgroundColor 0.94 0.94 0.94 controlShadowColor 0.69 0.69 0.69 controlDarkShadowColor 0.24 0.24 0.24 controlColor 0.94 0.94 0.94 selectedControlColor 0.72 0.72 0.72 disabledControlTextColor 0.62 0.62 0.62 scrollBarColor 0.53 0.53 0.53 selectedMenuItemColor 0.58 0.58 0.58 selectedMenuItemTextColor 1.0 1.0 1.0 selectedTextBackgroundColor 0.7 0.84 1.0 PPBoldMenuTextColorWhiteValue 0.20 PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepFrameworksVersionCheck.h0000644000076500000240000000474413234417045024474 0ustar joshstaff/* PPGNUstepFrameworksVersionCheck.h Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP # define macroCheckGSFrameworkMinAllowedVersion(frameworkName, majorVersion, minorVersion,\ subminorVersion) \ \ (defined(GNUSTEP_##frameworkName##_MAJOR_VERSION) \ && defined(GNUSTEP_##frameworkName##_MINOR_VERSION) \ && defined(GNUSTEP_##frameworkName##_SUBMINOR_VERSION) \ && ((GNUSTEP_##frameworkName##_MAJOR_VERSION > majorVersion) \ || ((GNUSTEP_##frameworkName##_MAJOR_VERSION == majorVersion) \ && (GNUSTEP_##frameworkName##_MINOR_VERSION > minorVersion)) \ || ((GNUSTEP_##frameworkName##_MAJOR_VERSION == majorVersion) \ && (GNUSTEP_##frameworkName##_MINOR_VERSION == minorVersion) \ && (GNUSTEP_##frameworkName##_SUBMINOR_VERSION >= subminorVersion)))) // Required GNUstep framework versions: BASE 1.24.9, GUI 0.25.0 # if (!macroCheckGSFrameworkMinAllowedVersion(BASE, 1, 24, 9) \ || !macroCheckGSFrameworkMinAllowedVersion(GUI, 0, 25, 0)) # error GNUstep frameworks are too old; \ PikoPixel requires GNUstep Base v1.24.9 & GNUstep GUI/Back v0.25.0 (or later) # endif // macroChecks #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_BezierPathAliasing.m0000644000076500000240000002327613244114547024541 0ustar joshstaff/* PPGNUstepGlue_BezierPathAliasing.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // PPGNUstepGlue_BezierPathAliasing.m was initially meant as a workaround for GNUstep's // antialiasing setting (path drawing would always use antialiasing, even if the graphics // context's antialiasing setting was disabled). // The antialiasing setting has been since fixed for Cairo in the GNUstep trunk (2015-09-20), // however, un-antialiased Cairo paths are drawn in different shapes than on Mac OS X: some // pixels are missing, possibly due to roundoff. // Antialiased paths are also drawn differently between Cairo & OS X, however, the // workaround below accounted for those differences, so until a workaround is developed for the // unantialiased drawing differences, the current fix is to use antialiasing when drawing (set // in PPGNUstepGlue_BitmapGraphcisContext.m's ppGSPatch_SetAsCurrentGraphicsContext), and // continue to use the antialiasing workaround. #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "NSBezierPath_PPUtilities.h" #import "PPDocument.h" #import "PPGeometry.h" // disable clang warnings about fabsf() truncating passed double-type values to float-type #ifdef __clang__ # pragma clang diagnostic ignored "-Wabsolute-value" #endif // __clang__ @interface NSBezierPath (PPGNUstepGlue_BezierPathAliasingUtilities) - (NSBezierPath *) ppGSGlue_ResegmentedPathForDrawing; - (void) ppGSGlue_SegmentedLineToPoint: (NSPoint) endPoint lastPoint: (NSPoint) startPoint; @end @implementation NSObject (PPGNUstepGlue_BezierPathAliasing) + (void) ppGSGlue_BezierPathAliasing_InstallPatches { macroSwizzleInstanceMethod(NSBezierPath, ppAppendSinglePixelLineAtPoint:, ppGSPatch_AppendSinglePixelLineAtPoint:); macroSwizzleInstanceMethod(NSBezierPath, ppAppendLineFromPixelAtPoint:toPixelAtPoint:, ppGSPatch_AppendLineFromPixelAtPoint:toPixelAtPoint:); macroSwizzleInstanceMethod(PPDocument, drawBezierPath:andFill:pathIsPixelated:, ppGSPatch_BezierPathAliasing_DrawBezierPath:andFill: pathIsPixelated:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_BezierPathAliasing_InstallPatches); } @end @implementation NSBezierPath (PPGNUstepGlue_BezierPathAliasing) // PATCH: -[NSBezierPath (PPUtilities) ppAppendSinglePixelLineAtPoint:] // GNUstep's -[NSBezierPath stroke] always uses antialiasing (despite graphics context setting), // so override uses a different method for filling in a pixel (draw a centered, // half-pixel-length square) - (void) ppGSPatch_AppendSinglePixelLineAtPoint: (NSPoint) point { NSRect pixelRect; point = PPGeometry_PixelCenteredPoint(point); pixelRect = NSMakeRect(floorf(point.x) + 0.4, floorf(point.y) + 0.4, 0.2, 0.2); [self appendBezierPathWithRect: pixelRect]; [self lineToPoint: point]; } // PATCH: -[NSBezierPath (PPUtilities) ppAppendLineFromPixelAtPoint:toPixelAtPoint:] // Overridden to use -[NSBezierPath (PPUtilities) ppAppendSinglePixelLineAtPoint:] when // drawing a single pixel (both line endpoints are the same) in order to use the patched // implementation (original's method for filling a pixel doesn't work due to GNUstep's // antialiasing) - (void) ppGSPatch_AppendLineFromPixelAtPoint: (NSPoint) startPoint toPixelAtPoint: (NSPoint) endPoint { if (NSEqualPoints(startPoint, endPoint)) { [self ppAppendSinglePixelLineAtPoint: endPoint]; return; } [self ppGSPatch_AppendLineFromPixelAtPoint: startPoint toPixelAtPoint: endPoint]; } @end @implementation PPDocument (PPGNUstepGlue_BezierPathAliasing) // PATCH: -[PPDocument (DrawingPrivateMethods) drawBezierPath:andFill:pathIsPixelated:] // GNUstep's -[NSBezierPath stroke] always uses antialiasing (despite graphics context setting), // which can fill in extra pixels around the path - overridden to call local utility method // before drawing, -[NSBezierPath pGSGlue_ResegmentedPathForDrawing], which resegments the // lines in the path into a series of horizontal, vertical, or 1:1 diagonal lines, because // lines with those slopes are drawn with minimal antialiasing - (void) ppGSPatch_BezierPathAliasing_DrawBezierPath: (NSBezierPath *) path andFill: (bool) shouldFill pathIsPixelated: (bool) pathIsPixelated { if (!pathIsPixelated) { path = [path ppGSGlue_ResegmentedPathForDrawing]; } [self ppGSPatch_BezierPathAliasing_DrawBezierPath: path andFill: shouldFill pathIsPixelated: pathIsPixelated]; } @end @implementation NSBezierPath (PPGNUstepGlue_BezierPathAliasingUtilities) // ppGSGlue_ResegmentedPathForDrawing: Utility method for resegmenting the lines in a path into // a series of horizontal, vertical, or 1:1 diagonal lines, which minimizes antialiasing when // the path is drawn - (NSBezierPath *) ppGSGlue_ResegmentedPathForDrawing { NSBezierPath *resegmentedPath; NSInteger elementCount, elementIndex; NSPoint currentPoint, lastPoint, elementPoints[3], pointsDelta; resegmentedPath = [NSBezierPath bezierPath]; if (!resegmentedPath) return self; elementCount = [self elementCount]; for (elementIndex = 0; elementIndex < elementCount; elementIndex++) { switch ([self elementAtIndex: elementIndex associatedPoints: elementPoints]) { case NSMoveToBezierPathElement: { currentPoint = elementPoints[0]; [resegmentedPath moveToPoint: currentPoint]; lastPoint = currentPoint; } break; case NSLineToBezierPathElement: { currentPoint = elementPoints[0]; pointsDelta = PPGeometry_PointDifference(currentPoint, lastPoint); if (!pointsDelta.x || !pointsDelta.y || (pointsDelta.x == pointsDelta.y)) { [resegmentedPath lineToPoint: currentPoint]; } else { [resegmentedPath ppGSGlue_SegmentedLineToPoint: currentPoint lastPoint: lastPoint]; } lastPoint = currentPoint; } break; case NSCurveToBezierPathElement: { return self; } break; case NSClosePathBezierPathElement: { [resegmentedPath closePath]; } break; default: break; } } return resegmentedPath; } // ppGSGlue_SegmentedLineToPoint: Utility method to append a segmented line between // startPoint & endPoint, made up of a series of horizontal, vertical, or 1:1 diagonal lines, // in order to minimize antialiasing when drawing - used by ppGSGlue_ResegmentedPathForDrawing: // method above - (void) ppGSGlue_SegmentedLineToPoint: (NSPoint) endPoint lastPoint: (NSPoint) startPoint { NSPoint pointsDelta, absPointsDelta; CGFloat x, y, startX, startY, stepX, stepY, endX, endY, ratio; pointsDelta = PPGeometry_PointDifference(endPoint, startPoint); absPointsDelta = NSMakePoint(fabsf(pointsDelta.x), fabsf(pointsDelta.y)); if (absPointsDelta.x > absPointsDelta.y) { if (pointsDelta.y > 0) { startY = floor(startPoint.y + 1.0); stepY = 1.0; endY = floor(endPoint.y + 1.0); } else { startY = floorf(startPoint.y); stepY = -1.0; endY = floor(endPoint.y); } stepX = (pointsDelta.x > 0) ? 1.0 : -1.0; ratio = pointsDelta.x / pointsDelta.y; for (y = startY; y != endY; y += stepY) { x = round((y - startPoint.y) * ratio + startPoint.x) - stepX * 0.5; [self lineToPoint: NSMakePoint(x, y - stepY * 0.5)]; [self lineToPoint: NSMakePoint(x + stepX, y + stepY * 0.5)]; } [self lineToPoint: endPoint]; } else { if (pointsDelta.x > 0) { startX = floor(startPoint.x + 1.0); stepX = 1.0; endX = floor(endPoint.x + 1.0); } else { startX = floorf(startPoint.x); stepX = -1.0; endX = floor(endPoint.x); } stepY = (pointsDelta.y > 0) ? 1.0 : -1.0; ratio = pointsDelta.y / pointsDelta.x; for (x = startX; x != endX; x += stepX) { y = round((x - startPoint.x) * ratio + startPoint.y) - stepY * 0.5; [self lineToPoint: NSMakePoint(x - stepX * 0.5, y)]; [self lineToPoint: NSMakePoint(x + stepX * 0.5, y + stepY)]; } [self lineToPoint: endPoint]; } } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_BitmapGraphicsContext.m0000644000076500000240000010140213757513606025272 0ustar joshstaff/* PPGNUstepGlue_BitmapGraphicsContext.m Copyright 2014-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "PPBackgroundPattern.h" #import "PPThumbnailImageView.h" #import "PPLayerControlButtonImagesManager.h" #import "PPLayersPanelController.h" #import "PPLayerControlsPopupPanelController.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPFilledRoundedRectView.h" #import "PPGeometry.h" #import "PPDocumentLayer.h" // kGSMaskCutoffValue_Alpha is a "magic" number used as the threshold for a pixel's alpha value // that determines whether a drawn pixel is 'on' or 'off' when converting to a mask bitmap from // an image bitmap (following an antialiased stroke/fill of an NSBezierPath). // The current value (114) is an OK fit for Cairo (probably won't fit well with other backends, // as the value is dependent on the drawing library's antialiasing implementation); During // tests (Cairo), have seen drawn pixels that should be considered 'on' with alpha values as low // as 115, and 'off' pixels with alpha values as high as 113 (small margin for error - may // cause occasional incorrectly-masked pixels, but still better than turning off antialiasing on // Cairo, because that causes a different set of pixel-accuracy issues that don't seem to have // a simple workaround). #define kGSMaskCutoffValue_Alpha 114 // GNUstep (Cairo?) has an antialiasing issue when drawing paths to graphics contexts smaller // than 32x32: Drawing a path on a context smaller than 32x32 will result in different pixel // values than drawing the same path to a context larger-than or equal-to 32x32, and can cause // incorrect on/off pixels when thresholding to a mask bitmap. // Workaround is to construct all graphics contexts to be 32x32 or larger (using contexts that // are silently larger than the requested size doesn't seem to cause issues). #define kMinGraphicsContextDimension 32 #define kBitmapContextSetupStateStackSize 4 #define kMaxAllowedCachedOffscreenWindows 5 typedef struct { NSRect boundsToClearBeforeDraw; bool clearEntireContextBeforeDraw; bool copyBitmapToContextBeforeDraw; bool flushEntireContextAfterDraw; } BitmapContextSetupState; typedef struct { NSWindow *window; NSSize size; } CachedOffscreenWindow; static bool gCurrentContextHasTargetBitmap = NO, gDisallowMaskBitmapThresholding = NO; static NSBitmapImageRep *gContextTargetBitmap = nil; static NSRect gContextBounds, gContextDirtyBounds; static BitmapContextSetupState gBitmapContextSetupState, gBitmapContextSetupStateStack[kBitmapContextSetupStateStackSize]; static unsigned gBitmapContextSetupStateStackIndex = 0; static NSGraphicsContext *GraphicsContextOfSize(NSSize size); static inline bool CurrentContextIsTargettingBitmap(NSBitmapImageRep *bitmap); static inline void SetContextDirtyInBounds(NSRect dirtyBounds); static inline void PushDefaultBitmapContextSetupState(void); static inline void PopBitmapContextSetupState(void); static inline void ResetBitmapContextSetupState(void); @interface NSBitmapImageRep (PPGNUstepGlue_BitmapGraphicsContextUtilities) - (void) ppGSGlue_CopyFromCurrentGraphicsContextInBounds: (NSRect) bounds; - (void) ppGSGlue_MergeToMaskBitmapFromImageBitmap: (NSBitmapImageRep *) sourceBitmap atPoint: (NSPoint) targetPoint; @end @implementation NSObject (PPGNUstepGlue_BitmapGraphicsContext) + (void) ppGSGlue_BitmapGraphicsContext_InstallPatches { macroSwizzleInstanceMethod(NSBitmapImageRep, ppSetAsCurrentGraphicsContext, ppGSPatch_SetAsCurrentGraphicsContext); macroSwizzleInstanceMethod(NSBitmapImageRep, ppRestoreGraphicsContext, ppGSPatch_RestoreGraphicsContext); macroSwizzleInstanceMethod(NSBitmapImageRep, ppImageBitmapCompositedWithBackgroundColor: andBackgroundImage:backgroundImageInterpolation:, ppGSPatch_ImageBitmapCompositedWithBackgroundColor: andBackgroundImage:backgroundImageInterpolation:); macroSwizzleInstanceMethod(NSBitmapImageRep, ppImageBitmapDissolvedToOpacity:, ppGSPatch_ImageBitmapDissolvedToOpacity:); macroSwizzleInstanceMethod(NSBitmapImageRep, ppThresholdMaskBitmapPixelValuesInBounds:, ppGSPatch_ThresholdMaskBitmapPixelValuesInBounds:); macroSwizzleInstanceMethod(NSImage, drawInRect:fromRect:operation:fraction:, ppGSPatch_DrawInRect:fromRect:operation:fraction:); macroSwizzleInstanceMethod(NSColor, ppImageBitmapPixelValue, ppGSPatch_ImageBitmapPixelValue); macroSwizzleInstanceMethod(PPBackgroundPattern, setupPatternFillColor, ppGSPatch_SetupPatternFillColor); macroSwizzleInstanceMethod(PPThumbnailImageView, drawBackgroundBitmap, ppGSPatch_DrawBackgroundBitmap); macroSwizzleInstanceMethod(PPLayerControlButtonImagesManager, setupThumbnailBackgroundBitmap, ppGSPatch_SetupThumbnailBackgroundBitmap); macroSwizzleInstanceMethod(PPLayerControlButtonImagesManager, updateEnabledLayersCompositeThumbnails, ppGSPatch_UpdateEnabledLayersCompositeThumbnails); macroSwizzleInstanceMethod(PPLayerControlButtonImagesManager, updateDrawLayerCompositeThumbnails, ppGSPatch_UpdateDrawLayerCompositeThumbnails); macroSwizzleInstanceMethod(PPLayersPanelController, setupLayerThumbnailBackgroundBitmapForCurrentPPDocument, ppGSPatch_SetupLayerThumbnailBackgroundBitmapForCurrentPPDocument); macroSwizzleInstanceMethod(PPLayersPanelController, cachedThumbnailForLayerAtIndex:, ppGSPatch_CachedThumbnailForLayerAtIndex:); macroSwizzleInstanceMethod(PPLayerControlsPopupPanelController, setupPopupMenuThumbnailBackgroundBitmap, ppGSPatch_SetupPopupMenuThumbnailBackgroundBitmap); macroSwizzleInstanceMethod(PPLayerControlsPopupPanelController, popupMenuThumbnailImageForLayerImage:, ppGSPatch_PopupMenuThumbnailImageForLayerImage:); macroSwizzleInstanceMethod(PPDocument, mergedLayersBitmapFromIndex:toIndex:, ppGSPatch_MergedLayersBitmapFromIndex:toIndex:); macroSwizzleInstanceMethod(PPDocument, updateMergedVisibleLayersBitmapInRect:indexOfUpdatedLayer:, ppGSPatch_UpdateMergedVisibleLayersBitmapInRect: indexOfUpdatedLayer:); macroSwizzleInstanceMethod(PPDocument, updateDissolvedDrawingLayerBitmapInRect:, ppGSPatch_UpdateDissolvedDrawingLayerBitmapInRect:); macroSwizzleInstanceMethod(PPDocument, drawBezierPath:andFill:pathIsPixelated:, ppGSPatch_BitmapGraphicsContext_DrawBezierPath: andFill:pathIsPixelated:); macroSwizzleInstanceMethod(PPDocument, selectPath:selectionMode:shouldAntialias:, ppGSPatch_SelectPath:selectionMode:shouldAntialias:); macroSwizzleInstanceMethod(PPDocument, tileSelectionInBitmap:toBitmap:, ppGSPatch_TileSelectionInBitmap:toBitmap:); macroSwizzleInstanceMethod(PPCanvasView, updateVisibleBackground, ppGSPatch_UpdateVisibleBackground); macroSwizzleInstanceMethod(PPCanvasView, setSelectionToolOverlayToPath:selectionMode: intersectMask:toolPath:shouldAntialias:, ppGSPatch_SetSelectionToolOverlayToPath:selectionMode: intersectMask:toolPath:shouldAntialias:); macroSwizzleInstanceMethod(PPFilledRoundedRectView, setupFilledRoundedRectImage, ppGSPatch_SetupFilledRoundedRectImage); macroSwizzleInstanceMethod(NSBezierPath, ppAppendFillPathForMaskBitmap:inBounds:, ppGSPatch_AppendFillPathForMaskBitmap:inBounds:); } + (void) ppGSGlue_BitmapGraphicsContext_Install { ResetBitmapContextSetupState(); [self ppGSGlue_BitmapGraphicsContext_InstallPatches]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_BitmapGraphicsContext_Install); } @end @implementation NSBitmapImageRep (PPGNUstepGlue_BitmapGraphicsContext) // PATCHES: -[NSBitmapImageRep (PPUtilities) ppSetAsCurrentGraphicsContext] // -[NSBitmapImageRep (PPUtilities) ppRestoreGraphicsContext] // // GNUstep doesn't support setting an NSBitmapImageRep as the graphics context, so patches // override the PPUtilities methods to substitute an NSCachedImageRep & use lock/unlockFocus // on its window's contentView - (void) ppGSPatch_SetAsCurrentGraphicsContext { NSSize bitmapSize; NSGraphicsContext *bitmapContext; if (gCurrentContextHasTargetBitmap) { NSLog(@"ERROR: Unable to nest bitmap graphics contexts"); goto ERROR; } bitmapSize = [self ppSizeInPixels]; bitmapContext = GraphicsContextOfSize(bitmapSize); if (!bitmapContext) goto ERROR; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext: bitmapContext]; // Workaround for differences between Cairo & Mac OS X when drawing paths: // The antialiasing-setting issue is now fixed for Cairo in the GNUstep trunk (2015-09-20), // so PPGNUstepGlue_BezierPathAliasing.m is no longer needed as an antialiasing-setting // workaround. However there's currently no workaround for Cairo & OS X differences with // un-antialiased drawing, so for now, enable antialiasing when drawing, and continue using // the antialiasing workaround, because it makes up for Cairo's differences when drawing // antialiased paths. [[NSGraphicsContext currentContext] setShouldAntialias: YES]; gContextBounds = PPGeometry_OriginRectOfSize(bitmapSize); gContextDirtyBounds = NSZeroRect; gContextTargetBitmap = self; gCurrentContextHasTargetBitmap = YES; if (gBitmapContextSetupState.clearEntireContextBeforeDraw) { gBitmapContextSetupState.boundsToClearBeforeDraw = gContextBounds; } if (!NSIsEmptyRect(gBitmapContextSetupState.boundsToClearBeforeDraw)) { NSRect clearBounds = PPGeometry_PixelBoundsCoveredByRect( NSIntersectionRect(gBitmapContextSetupState.boundsToClearBeforeDraw, gContextBounds)); if (!NSIsEmptyRect(clearBounds)) { NSRectFillUsingOperation(clearBounds, NSCompositeClear); SetContextDirtyInBounds(clearBounds); } } if (gBitmapContextSetupState.copyBitmapToContextBeforeDraw) { [self drawAtPoint: NSZeroPoint]; } return; ERROR: return; } - (void) ppGSPatch_RestoreGraphicsContext { if (!CurrentContextIsTargettingBitmap(self)) { goto ERROR; } if (NSIsEmptyRect(gContextDirtyBounds) || gBitmapContextSetupState.flushEntireContextAfterDraw) { gContextDirtyBounds = gContextBounds; gBitmapContextSetupState.flushEntireContextAfterDraw = NO; } [self ppGSGlue_CopyFromCurrentGraphicsContextInBounds: gContextDirtyBounds]; [NSGraphicsContext restoreGraphicsState]; ResetBitmapContextSetupState(); gCurrentContextHasTargetBitmap = NO; gContextTargetBitmap = nil; return; ERROR: return; } - (NSBitmapImageRep *) ppGSPatch_ImageBitmapCompositedWithBackgroundColor: (NSColor *) backgroundColor andBackgroundImage: (NSImage *) backgroundImage backgroundImageInterpolation: (NSImageInterpolation) backgroundImageInterpolation { NSBitmapImageRep *bitmap; PushDefaultBitmapContextSetupState(); if (!backgroundColor) { gBitmapContextSetupState.clearEntireContextBeforeDraw = YES; } else { gBitmapContextSetupState.flushEntireContextAfterDraw = YES; } bitmap = [self ppGSPatch_ImageBitmapCompositedWithBackgroundColor: backgroundColor andBackgroundImage: backgroundImage backgroundImageInterpolation: backgroundImageInterpolation]; PopBitmapContextSetupState(); return bitmap; } - (NSBitmapImageRep *) ppGSPatch_ImageBitmapDissolvedToOpacity: (float) opacity { NSBitmapImageRep *bitmap; PushDefaultBitmapContextSetupState(); if (opacity < 1.0) { gBitmapContextSetupState.clearEntireContextBeforeDraw = YES; } bitmap = [self ppGSPatch_ImageBitmapDissolvedToOpacity: opacity]; PopBitmapContextSetupState(); return bitmap; } - (void) ppGSPatch_ThresholdMaskBitmapPixelValuesInBounds: (NSRect) bounds { if (gDisallowMaskBitmapThresholding) return; [self ppGSPatch_ThresholdMaskBitmapPixelValuesInBounds: bounds]; } @end @implementation NSImage (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_DrawInRect: (NSRect) destinationRect fromRect: (NSRect) sourceRect operation: (NSCompositingOperation) operation fraction: (CGFloat) fraction { [self ppGSPatch_DrawInRect: destinationRect fromRect: sourceRect operation: operation fraction: fraction]; if (gCurrentContextHasTargetBitmap) { SetContextDirtyInBounds(destinationRect); } } @end @implementation NSColor (PPGNUstepGlue_BitmapGraphicsContext) // PATCH: -[NSColor (PPUtilities) ppImageBitmapPixelValue] // GNUstep doesn't support -[NSGraphicsContext graphicsContextWithBitmapImageRep:] (called by // in the original implementation of ppImageBitmapPixelValue), so override uses now-patched // -[NSBitmapImageRep (PPUtilities) ppSetAsCurrentGraphicsContext] instead - (PPImageBitmapPixel) ppGSPatch_ImageBitmapPixelValue { static NSRect pixelBitmapBounds = {{0,0},{1,1}}; static NSBitmapImageRep *pixelBitmap = nil; PPImageBitmapPixel *pixelData; if (!pixelBitmap) { pixelBitmap = [[NSBitmapImageRep ppImageBitmapOfSize: pixelBitmapBounds.size] retain]; if (!pixelBitmap) goto ERROR; } [pixelBitmap ppSetAsCurrentGraphicsContext]; [self set]; NSRectFillUsingOperation(pixelBitmapBounds, NSCompositeCopy); [pixelBitmap ppRestoreGraphicsContext]; pixelData = (PPImageBitmapPixel *) [pixelBitmap bitmapData]; if (!pixelData) goto ERROR; return *pixelData; ERROR: [pixelBitmap release]; pixelBitmap = nil; return (PPImageBitmapPixel) 0; } @end @implementation PPBackgroundPattern (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_SetupPatternFillColor { PushDefaultBitmapContextSetupState(); [self ppGSPatch_SetupPatternFillColor]; PopBitmapContextSetupState(); } @end @implementation PPThumbnailImageView (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_DrawBackgroundBitmap { // make sure pattern bitmap is already generated, otherwise it may try to set bitmap // as context while there's already a bitmap graphics context [_scaledBackgroundPattern patternFillColor]; PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.flushEntireContextAfterDraw = YES; [self ppGSPatch_DrawBackgroundBitmap]; PopBitmapContextSetupState(); } @end @implementation PPLayerControlButtonImagesManager (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_SetupThumbnailBackgroundBitmap { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.clearEntireContextBeforeDraw = YES; [self ppGSPatch_SetupThumbnailBackgroundBitmap]; PopBitmapContextSetupState(); } - (void) ppGSPatch_UpdateEnabledLayersCompositeThumbnails { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.copyBitmapToContextBeforeDraw = YES; [self ppGSPatch_UpdateEnabledLayersCompositeThumbnails]; PopBitmapContextSetupState(); } - (void) ppGSPatch_UpdateDrawLayerCompositeThumbnails { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.copyBitmapToContextBeforeDraw = YES; [self ppGSPatch_UpdateDrawLayerCompositeThumbnails]; PopBitmapContextSetupState(); } @end @implementation PPLayersPanelController (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_SetupLayerThumbnailBackgroundBitmapForCurrentPPDocument { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.clearEntireContextBeforeDraw = YES; [self ppGSPatch_SetupLayerThumbnailBackgroundBitmapForCurrentPPDocument]; PopBitmapContextSetupState(); } - (NSImage *) ppGSPatch_CachedThumbnailForLayerAtIndex: (unsigned) index { NSImage *returnValue; PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.copyBitmapToContextBeforeDraw = YES; returnValue = [self ppGSPatch_CachedThumbnailForLayerAtIndex: index]; PopBitmapContextSetupState(); return returnValue; } @end @implementation PPLayerControlsPopupPanelController (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_SetupPopupMenuThumbnailBackgroundBitmap { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.clearEntireContextBeforeDraw = YES; [self ppGSPatch_SetupPopupMenuThumbnailBackgroundBitmap]; PopBitmapContextSetupState(); } - (NSImage *) ppGSPatch_PopupMenuThumbnailImageForLayerImage: (NSImage *) layerImage { NSImage *returnValue; PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.copyBitmapToContextBeforeDraw = YES; returnValue = [self ppGSPatch_PopupMenuThumbnailImageForLayerImage: layerImage]; PopBitmapContextSetupState(); return returnValue; } @end @implementation PPDocument (PPGNUstepGlue_BitmapGraphicsContext) - (NSBitmapImageRep *) ppGSPatch_MergedLayersBitmapFromIndex: (int) firstIndex toIndex: (int) lastIndex { NSBitmapImageRep *bitmap; PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.clearEntireContextBeforeDraw = YES; bitmap = [self ppGSPatch_MergedLayersBitmapFromIndex: firstIndex toIndex: lastIndex]; PopBitmapContextSetupState(); return bitmap; } - (void) ppGSPatch_UpdateMergedVisibleLayersBitmapInRect: (NSRect) rect indexOfUpdatedLayer: (int) indexOfUpdatedLayer { PushDefaultBitmapContextSetupState(); if (_layerBlendingMode != kPPLayerBlendingMode_Linear) { gBitmapContextSetupState.boundsToClearBeforeDraw = rect; } [self ppGSPatch_UpdateMergedVisibleLayersBitmapInRect: rect indexOfUpdatedLayer: indexOfUpdatedLayer]; PopBitmapContextSetupState(); } - (void) ppGSPatch_UpdateDissolvedDrawingLayerBitmapInRect: (NSRect) updateRect { float drawingLayerOpacity = [_drawingLayer opacity]; PushDefaultBitmapContextSetupState(); if ([_drawingLayer isEnabled] && (drawingLayerOpacity > 0.0) && (drawingLayerOpacity < 1.0)) { gBitmapContextSetupState.boundsToClearBeforeDraw = updateRect; } [self ppGSPatch_UpdateDissolvedDrawingLayerBitmapInRect: updateRect]; PopBitmapContextSetupState(); } - (void) ppGSPatch_BitmapGraphicsContext_DrawBezierPath: (NSBezierPath *) path andFill: (bool) shouldFillPath pathIsPixelated: (bool) pathIsPixelated { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.boundsToClearBeforeDraw = [path bounds]; // mask bitmaps are automatically thresholded due to patches calling through to the local // method, ppGSGlue_MergeToMaskBitmapFromImageBitmap:atPoint:, so disable unnecessary // additional thresholding (ppThresholdMaskBitmapPixelValuesInBounds:) gDisallowMaskBitmapThresholding = YES; [self ppGSPatch_BitmapGraphicsContext_DrawBezierPath: path andFill: shouldFillPath pathIsPixelated: pathIsPixelated]; gDisallowMaskBitmapThresholding = NO; PopBitmapContextSetupState(); } - (void) ppGSPatch_SelectPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode shouldAntialias: (bool) shouldAntialias { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.boundsToClearBeforeDraw = [path bounds]; // mask bitmaps are automatically thresholded due to patches calling through to the local // method, ppGSGlue_MergeToMaskBitmapFromImageBitmap:atPoint:, so disable unnecessary // additional thresholding (ppThresholdMaskBitmapPixelValuesInBounds:) gDisallowMaskBitmapThresholding = YES; [self ppGSPatch_SelectPath: path selectionMode: selectionMode shouldAntialias: shouldAntialias]; gDisallowMaskBitmapThresholding = NO; PopBitmapContextSetupState(); } - (bool) ppGSPatch_TileSelectionInBitmap: (NSBitmapImageRep *) sourceBitmap toBitmap: (NSBitmapImageRep *) destinationBitmap { bool returnValue; PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.clearEntireContextBeforeDraw = YES; returnValue = [self ppGSPatch_TileSelectionInBitmap: sourceBitmap toBitmap: destinationBitmap]; PopBitmapContextSetupState(); return returnValue; } @end @implementation PPCanvasView (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_UpdateVisibleBackground { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.flushEntireContextAfterDraw = YES; [self ppGSPatch_UpdateVisibleBackground]; PopBitmapContextSetupState(); } - (void) ppGSPatch_SetSelectionToolOverlayToPath: (NSBezierPath *) path selectionMode: (PPSelectionMode) selectionMode intersectMask: (NSBitmapImageRep *) intersectMask toolPath: (NSBezierPath *) toolPath shouldAntialias: (bool) shouldAntialias { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.boundsToClearBeforeDraw = [path bounds]; // mask bitmaps are automatically thresholded due to patches calling through to the local // method, ppGSGlue_MergeToMaskBitmapFromImageBitmap:atPoint:, so disable unnecessary // additional thresholding (ppThresholdMaskBitmapPixelValuesInBounds:) gDisallowMaskBitmapThresholding = YES; [self ppGSPatch_SetSelectionToolOverlayToPath: path selectionMode: selectionMode intersectMask: intersectMask toolPath: toolPath shouldAntialias: shouldAntialias]; gDisallowMaskBitmapThresholding = NO; PopBitmapContextSetupState(); } @end @implementation PPFilledRoundedRectView (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_SetupFilledRoundedRectImage { PushDefaultBitmapContextSetupState(); gBitmapContextSetupState.clearEntireContextBeforeDraw = YES; [self ppGSPatch_SetupFilledRoundedRectImage]; PopBitmapContextSetupState(); } @end @implementation NSBezierPath (PPGNUstepGlue_BitmapGraphicsContext) - (void) ppGSPatch_AppendFillPathForMaskBitmap: (NSBitmapImageRep *) maskBitmap inBounds: (NSRect) bounds { if (CurrentContextIsTargettingBitmap(maskBitmap)) { // target bitmap's data is out-of-date - update it from the current context's data [maskBitmap ppGSGlue_CopyFromCurrentGraphicsContextInBounds: bounds]; } [self ppGSPatch_AppendFillPathForMaskBitmap: maskBitmap inBounds: bounds]; } @end @implementation NSBitmapImageRep (PPGNUstepGlue_BitmapGraphicsContextUtilities) - (void) ppGSGlue_CopyFromCurrentGraphicsContextInBounds: (NSRect) bounds { NSDictionary *contextReadRectDict; unsigned char *contextBoundsBitmapData; NSBitmapImageRep *contextBoundsBitmap; bounds = NSIntersectionRect(bounds, [self ppFrameInPixels]); if (NSIsEmptyRect(bounds)) { return; } contextReadRectDict = [GSCurrentContext() GSReadRect: bounds]; if (!contextReadRectDict) goto ERROR; contextBoundsBitmapData = (unsigned char *) [[contextReadRectDict objectForKey: @"Data"] bytes]; if (!contextBoundsBitmapData) goto ERROR; contextBoundsBitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: &contextBoundsBitmapData pixelsWide: bounds.size.width pixelsHigh: bounds.size.height bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: NO isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: bounds.size.width * 4 bitsPerPixel: 0] autorelease]; if (!contextBoundsBitmap) goto ERROR; if ([self ppIsMaskBitmap]) { [self ppGSGlue_MergeToMaskBitmapFromImageBitmap: contextBoundsBitmap atPoint: bounds.origin]; } else { [self ppCopyFromBitmap: contextBoundsBitmap inRect: PPGeometry_OriginRectOfSize(bounds.size) toPoint: bounds.origin]; } return; ERROR: return; } - (void) ppGSGlue_MergeToMaskBitmapFromImageBitmap: (NSBitmapImageRep *) sourceBitmap atPoint: (NSPoint) targetPoint { NSRect destinationFrame, destinationRect, sourceFrame, sourceRect; unsigned char *destinationData, *destinationRow, *sourceData, *sourceRow; int destinationBytesPerRow, destinationDataOffset, sourceBytesPerRow, sourceDataOffset, rowOffset, rowCounter, pixelsPerRow, pixelCounter; PPMaskBitmapPixel *destinationPixel; PPImageBitmapPixel *sourcePixel; if (![self ppIsMaskBitmap] || ![sourceBitmap ppIsImageBitmap]) { goto ERROR; } destinationFrame = [self ppFrameInPixels]; sourceFrame = [sourceBitmap ppFrameInPixels]; targetPoint = PPGeometry_PointClippedToIntegerValues(targetPoint); sourceRect = sourceFrame; destinationRect.origin = targetPoint; destinationRect.size = sourceRect.size; destinationRect = NSIntersectionRect(destinationRect, destinationFrame); if (NSIsEmptyRect(destinationRect)) { goto ERROR; } if (!NSEqualSizes(destinationRect.size, sourceRect.size)) { sourceRect.origin.x += destinationRect.origin.x - targetPoint.x; sourceRect.origin.y += destinationRect.origin.y - targetPoint.y; sourceRect.size = destinationRect.size; } destinationData = [self bitmapData]; sourceData = [sourceBitmap bitmapData]; if (!destinationData || !sourceData) { goto ERROR; } destinationBytesPerRow = [self bytesPerRow]; rowOffset = destinationFrame.size.height - destinationRect.size.height - destinationRect.origin.y; destinationDataOffset = rowOffset * destinationBytesPerRow + destinationRect.origin.x * sizeof(PPMaskBitmapPixel); destinationRow = &destinationData[destinationDataOffset]; sourceBytesPerRow = [sourceBitmap bytesPerRow]; rowOffset = sourceFrame.size.height - sourceRect.size.height - sourceRect.origin.y; sourceDataOffset = rowOffset * sourceBytesPerRow + sourceRect.origin.x * sizeof(PPImageBitmapPixel); sourceRow = &sourceData[sourceDataOffset]; pixelsPerRow = destinationRect.size.width; rowCounter = destinationRect.size.height; while (rowCounter--) { destinationPixel = (PPMaskBitmapPixel *) destinationRow; sourcePixel = (PPImageBitmapPixel *) sourceRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (macroImagePixelComponent_Alpha(sourcePixel) > kGSMaskCutoffValue_Alpha) { *destinationPixel = macroImagePixelComponent_Red(sourcePixel); } destinationPixel++; sourcePixel++; } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; } return; ERROR: return; } @end #pragma mark Private functions static NSGraphicsContext *GraphicsContextOfSize(NSSize size) { static CachedOffscreenWindow cachedOffscreenWindows[kMaxAllowedCachedOffscreenWindows]; static int numCachedOffscreenWindows = 0; int i; if (PPGeometry_IsZeroSize(size)) { goto ERROR; } if (size.width < kMinGraphicsContextDimension) { size.width = kMinGraphicsContextDimension; } if (size.height < kMinGraphicsContextDimension) { size.height = kMinGraphicsContextDimension; } for (i=0; i= numCachedOffscreenWindows) { NSCachedImageRep *cachedImageRep = [[[NSCachedImageRep alloc] initWithSize: size depth: 0 separate: YES alpha: YES] autorelease]; NSWindow *offscreenWindow = [cachedImageRep window]; if (!offscreenWindow) goto ERROR; if (i >= kMaxAllowedCachedOffscreenWindows) { i = kMaxAllowedCachedOffscreenWindows - 1; [cachedOffscreenWindows[i].window release]; } else { numCachedOffscreenWindows++; } memmove(&cachedOffscreenWindows[1], &cachedOffscreenWindows[0], i * sizeof(*cachedOffscreenWindows)); cachedOffscreenWindows[0].window = [offscreenWindow retain]; cachedOffscreenWindows[0].size = size; } else if (i > 0) { CachedOffscreenWindow cachedOffscreenWindow = cachedOffscreenWindows[i]; memmove(&cachedOffscreenWindows[1], &cachedOffscreenWindows[0], i * sizeof(*cachedOffscreenWindows)); cachedOffscreenWindows[0] = cachedOffscreenWindow; } return [cachedOffscreenWindows[0].window graphicsContext]; ERROR: return nil; } static inline bool CurrentContextIsTargettingBitmap(NSBitmapImageRep *bitmap) { return (gCurrentContextHasTargetBitmap && (gContextTargetBitmap == bitmap)) ? YES : NO; } static inline void SetContextDirtyInBounds(NSRect dirtyBounds) { gContextDirtyBounds = NSIntersectionRect(gContextBounds, NSUnionRect(PPGeometry_PixelBoundsCoveredByRect(dirtyBounds), gContextDirtyBounds)); } static inline void PushDefaultBitmapContextSetupState(void) { if (gBitmapContextSetupStateStackIndex >= kBitmapContextSetupStateStackSize) { NSLog(@"ERROR: Overflowed bitmap graphics context state stack"); return; } memcpy(&gBitmapContextSetupStateStack[gBitmapContextSetupStateStackIndex++], &gBitmapContextSetupState, sizeof(gBitmapContextSetupState)); memset(&gBitmapContextSetupState, 0, sizeof(gBitmapContextSetupState)); } static inline void PopBitmapContextSetupState(void) { if ((gBitmapContextSetupStateStackIndex > kBitmapContextSetupStateStackSize) || !gBitmapContextSetupStateStackIndex) { return; } memcpy(&gBitmapContextSetupState, &gBitmapContextSetupStateStack[--gBitmapContextSetupStateStackIndex], sizeof(gBitmapContextSetupState)); } static inline void ResetBitmapContextSetupState(void) { memset(&gBitmapContextSetupState, 0, sizeof(gBitmapContextSetupState)); } #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_BitmapNonpremultipliedPNG.m0000644000076500000240000003212313234416764026064 0ustar joshstaff/* PPGNUstepGlue_BitmapNonpremultipliedPNG.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPApplication.h" #import "PPImagePixelAlphaPremultiplyTables.h" #import "NSBitmapImageRep_PPUtilities.h" static bool gAllowInPlaceUnpremultiply = NO, gBitmapSourceIsExternal = NO; @interface NSBitmapImageRep (PPGNUstepGlue_BitmapNonpremultipliedPNGUtilities) - (bool) ppGSGlue_CanPremultiplyImportedBitmap; - (bool) ppGSGlue_Premultiply; - (bool) ppGSGlue_Unpremultiply; - (NSBitmapImageRep *) ppGSGlue_UnpremultipliedBitmap; @end @interface NSImage (PPGNUstepGlue_BitmapNonpremultipliedPNGUtilities) - (void) ppGSGlue_PremultiplyBitmapRepresentations; @end @implementation NSObject (PPGNUstepGlue_BitmapNonpremultipliedPNG) + (void) ppGSGlue_AA_BitmapNonpremultipliedPNG_InstallPatches { macroSwizzleInstanceMethod(NSBitmapImageRep, _initBitmapFromPNG:, ppGSPatch_InitBitmapFromPNG:); macroSwizzleInstanceMethod(NSBitmapImageRep, _PNGRepresentationWithProperties:, ppGSPatch_PNGRepresentationWithProperties:); macroSwizzleInstanceMethod(NSBitmapImageRep, ppCompressedTIFFDataFromBounds:, ppGSPatch_CompressedTIFFDataFromBounds:); macroSwizzleClassMethod(NSBitmapImageRep, ppImageBitmapWithImportedData:, ppGSPatch_ImageBitmapWithImportedData:); } + (void) load { // AA_ was inserted into the name of the _InstallPatches method to make sure it gets called // before ppGSGlue_BitmapGraphicsContext_Install (AfterAppLoads selectors are called // alphabetically) - this is because installing the BitmapGraphicsContext patches causes // +[PPCanvasView initialize] to be called, which loads some PNG images (for selection-tool // overlay pattern colors) macroPerformNSObjectSelectorAfterAppLoads( ppGSGlue_AA_BitmapNonpremultipliedPNG_InstallPatches); } @end @implementation PPApplication (PPGNUstepGlue_BitmapNonpremultipliedPNG) // OVERRIDE: -[NSApplication setApplicationIconImage:] // GNUstep sets up the application icon before the app finishes launching (& before PikoPixel // installs its patches), so -[NSApplication setApplicationIconImage:] is "patched" by // implementing a subclass override method in PPApplication (PPApplication doesn't implement // this method elsewhere). // The override manually premultiplies the bitmap representations in the icon image, since // the -[NSBitmapImageRep initBitmapFromPNG:] patch that would automatically premultiply them // as they're initialized isn't installed yet. - (void) setApplicationIconImage: (NSImage *) anImage { [anImage ppGSGlue_PremultiplyBitmapRepresentations]; [super setApplicationIconImage: anImage]; } @end @implementation NSBitmapImageRep (PPGNUstepGlue_BitmapNonpremultipliedPNG) - (id) ppGSPatch_InitBitmapFromPNG: (NSData *) imageData { self = [self ppGSPatch_InitBitmapFromPNG: imageData]; [self ppGSGlue_Premultiply]; return self; } - (NSData *) ppGSPatch_PNGRepresentationWithProperties: (NSDictionary *) properties { if (gAllowInPlaceUnpremultiply) { [self ppGSGlue_Unpremultiply]; } else { self = [self ppGSGlue_UnpremultipliedBitmap]; } return [self ppGSPatch_PNGRepresentationWithProperties: properties]; } // PATCH: -[NSBitmapImageRep (PPUtilities) ppCompressedTIFFDataFromBounds:] // ppCompressedTIFFData (called by ppCompressedTIFFDataFromBounds:) is currently patched on // GNUstep to return PNG data (OS X had issues reading GNUstep-written TIFF data), and it uses // a temporary, single-use bitmap for constructing the PNG data, so unpremultiplying in-place // is quicker than allocating & converting an additional temporary bitmap. - (NSData *) ppGSPatch_CompressedTIFFDataFromBounds: (NSRect) bounds { NSData *returnedData; gAllowInPlaceUnpremultiply = YES; returnedData = [self ppGSPatch_CompressedTIFFDataFromBounds: bounds]; gAllowInPlaceUnpremultiply = NO; return returnedData; } + (NSBitmapImageRep *) ppGSPatch_ImageBitmapWithImportedData: (NSData *) importedData { NSBitmapImageRep *returnedBitmap; gBitmapSourceIsExternal = YES; returnedBitmap = [self ppGSPatch_ImageBitmapWithImportedData: importedData]; gBitmapSourceIsExternal = NO; return returnedBitmap; } @end @implementation NSBitmapImageRep (PPGNUstepGlue_BitmapNonpremultipliedPNGUtilities) - (bool) ppGSGlue_CanPremultiplyImportedBitmap { // Premultiply implementation only supports 4-channel bitmaps that have an alpha channel // and 8 bits-per-sample; For locally-created bitmaps, ppIsImageBitmap is enough for // verification, however, it only checks the number of channels, so external-source bitmaps // also need explicit alpha & bitsPerSample checks before allowing premultiply return (([self samplesPerPixel] == 4) && [self hasAlpha] && ([self bitsPerSample] == 8)) ? YES : NO; } - (bool) ppGSGlue_Premultiply { NSSize bitmapSize; unsigned char *bitmapRow, *premultiplyTable; int bytesPerRow, pixelsPerRow, rowCounter, pixelCounter; PPImageBitmapPixel *bitmapPixel; if (!(_format & NSAlphaNonpremultipliedBitmapFormat) || ![self ppIsImageBitmap] || (gBitmapSourceIsExternal && ![self ppGSGlue_CanPremultiplyImportedBitmap])) { return NO; } bitmapSize = [self ppSizeInPixels]; bitmapRow = [self bitmapData]; if (!bitmapRow) goto ERROR; bytesPerRow = [self bytesPerRow]; pixelsPerRow = bitmapSize.width; rowCounter = bitmapSize.height; while (rowCounter--) { bitmapPixel = (PPImageBitmapPixel *) bitmapRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if (macroImagePixelComponent_Alpha(bitmapPixel) == 255) { bitmapPixel++; } else if (macroImagePixelComponent_Alpha(bitmapPixel) == 0) { *bitmapPixel++ = 0; } else { premultiplyTable = macroAlphaPremultiplyTableForImagePixel(bitmapPixel); macroImagePixelComponent_Red(bitmapPixel) = premultiplyTable[macroImagePixelComponent_Red(bitmapPixel)]; macroImagePixelComponent_Green(bitmapPixel) = premultiplyTable[macroImagePixelComponent_Green(bitmapPixel)]; macroImagePixelComponent_Blue(bitmapPixel) = premultiplyTable[macroImagePixelComponent_Blue(bitmapPixel)]; bitmapPixel++; } } bitmapRow += bytesPerRow; } _format &= ~NSAlphaNonpremultipliedBitmapFormat; return YES; ERROR: return NO; } - (bool) ppGSGlue_Unpremultiply { NSSize bitmapSize; unsigned char *bitmapRow, *unpremultiplyTable; int bytesPerRow, pixelsPerRow, rowCounter, pixelCounter; PPImageBitmapPixel *bitmapPixel; if ((_format & NSAlphaNonpremultipliedBitmapFormat) || ![self ppIsImageBitmap]) { return NO; } bitmapSize = [self ppSizeInPixels]; bitmapRow = [self bitmapData]; if (!bitmapRow) goto ERROR; bytesPerRow = [self bytesPerRow]; pixelsPerRow = bitmapSize.width; rowCounter = bitmapSize.height; while (rowCounter--) { bitmapPixel = (PPImageBitmapPixel *) bitmapRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if ((macroImagePixelComponent_Alpha(bitmapPixel) == 255) || (macroImagePixelComponent_Alpha(bitmapPixel) == 0)) { bitmapPixel++; } else { unpremultiplyTable = macroAlphaUnpremultiplyTableForImagePixel(bitmapPixel); macroImagePixelComponent_Red(bitmapPixel) = unpremultiplyTable[macroImagePixelComponent_Red(bitmapPixel)]; macroImagePixelComponent_Green(bitmapPixel) = unpremultiplyTable[macroImagePixelComponent_Green(bitmapPixel)]; macroImagePixelComponent_Blue(bitmapPixel) = unpremultiplyTable[macroImagePixelComponent_Blue(bitmapPixel)]; bitmapPixel++; } } bitmapRow += bytesPerRow; } _format |= NSAlphaNonpremultipliedBitmapFormat; return YES; ERROR: return NO; } - (NSBitmapImageRep *) ppGSGlue_UnpremultipliedBitmap { NSSize bitmapSize; NSBitmapImageRep *destinationBitmap; unsigned char *destinationRow, *sourceRow, *unpremultiplyTable; int destinationBytesPerRow, sourceBytesPerRow, pixelsPerRow, rowCounter, pixelCounter; PPImageBitmapPixel *destinationPixel, *sourcePixel; if (([self bitmapFormat] & NSAlphaNonpremultipliedBitmapFormat) || ![self ppIsImageBitmap]) { return self; } bitmapSize = [self ppSizeInPixels]; destinationBitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: bitmapSize.width pixelsHigh: bitmapSize.height bitsPerSample: 8 samplesPerPixel: sizeof(PPImageBitmapPixel) hasAlpha: YES isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bitmapFormat: NSAlphaNonpremultipliedBitmapFormat bytesPerRow: 0 bitsPerPixel: 0] autorelease]; if (!destinationBitmap) goto ERROR; destinationRow = [destinationBitmap bitmapData]; sourceRow = [self bitmapData]; if (!destinationRow || !sourceRow) { goto ERROR; } destinationBytesPerRow = [destinationBitmap bytesPerRow]; sourceBytesPerRow = [self bytesPerRow]; pixelsPerRow = bitmapSize.width; rowCounter = bitmapSize.height; while (rowCounter--) { destinationPixel = (PPImageBitmapPixel *) destinationRow; sourcePixel = (PPImageBitmapPixel *) sourceRow; pixelCounter = pixelsPerRow; while (pixelCounter--) { if ((macroImagePixelComponent_Alpha(sourcePixel) == 255) || (macroImagePixelComponent_Alpha(sourcePixel) == 0)) { *destinationPixel++ = *sourcePixel++; } else { unpremultiplyTable = macroAlphaUnpremultiplyTableForImagePixel(sourcePixel); macroImagePixelComponent_Red(destinationPixel) = unpremultiplyTable[macroImagePixelComponent_Red(sourcePixel)]; macroImagePixelComponent_Green(destinationPixel) = unpremultiplyTable[macroImagePixelComponent_Green(sourcePixel)]; macroImagePixelComponent_Blue(destinationPixel) = unpremultiplyTable[macroImagePixelComponent_Blue(sourcePixel)]; macroImagePixelComponent_Alpha(destinationPixel) = macroImagePixelComponent_Alpha(sourcePixel); destinationPixel++; sourcePixel++; } } destinationRow += destinationBytesPerRow; sourceRow += sourceBytesPerRow; } return destinationBitmap; ERROR: return self; } @end @implementation NSImage (PPGNUstepGlue_BitmapNonpremultipliedPNGUtilities) - (void) ppGSGlue_PremultiplyBitmapRepresentations { NSEnumerator *repEnumerator; NSBitmapImageRep *bitmapRep; repEnumerator = [[self representations] objectEnumerator]; while (bitmapRep = [repEnumerator nextObject]) { if ([bitmapRep isKindOfClass: [NSBitmapImageRep class]] && ([bitmapRep bitmapFormat] & NSAlphaNonpremultipliedBitmapFormat)) { [bitmapRep ppGSGlue_Premultiply]; } } } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ColorPanel.m0000644000076500000240000001404113234416764023065 0ustar joshstaff/* PPGNUstepGlue_ColorPanel.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds/tweaks for several NSColorPanel issues on GNUstep: // - Automatically hide the color panel when there are no active color wells // - Fix inability to click on color panel's swatches (when using the color-picker popup-panel), // due to the NSColorWells being set up with the wrong target (now fixed in the GNUstep trunk // 2016-11-21) // - When the color panel becomes key, check if one of its textfields is being edited - if not, // automatically resign key & return key status to the current document window // - Workaround for issue where typing in one of the color panel's textfields would cause the // entire text to be selected after each keypress (causing the next keypress to replace all of // the current text) - this was due to the color panel text change causing an update to the // tools panel's color well, causing an update to the document's fill color, which then posted // a PPDocument notification that its fill color changed, which, when received by the tools // panel controller, would update the panel's color well's color, which updated the color // panel's color, interfering with in-progress text editing; Patched PPToolsPanelController to // prevent it from updating the color well with the document's new color when the new color was // the result of an update from the color well itself #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPToolsPanelController.h" #import "PPDocument.h" static bool gIsActivatingColorWell = NO, gDisallowToolsPanelColorWellUpdates = NO; @interface NSColorPanel (PPGNUstepGlue_ColorPanelUtilities) - (void) ppGSGlue_ResignKeyUnlessEditingText; @end @interface PPToolsPanelController (PPGNUstepGlue_ColorPanelUtilities) - (void) ppGSGlue_UpdateDocumentFillColorAndBlockColorWellUpdate; @end @implementation NSObject (PPGNUstepGlue_ColorPanel) + (void) ppGSGlue_ColorPanel_InstallPatches { macroSwizzleInstanceMethod(NSColorWell, activate:, ppGSPatch_Activate:); macroSwizzleInstanceMethod(NSColorWell, deactivate, ppGSPatch_Deactivate); macroSwizzleInstanceMethod(NSColorPanel, init, ppGSPatch_Init); macroSwizzleInstanceMethod(NSColorPanel, becomeKeyWindow, ppGSPatch_BecomeKeyWindow); macroSwizzleInstanceMethod(PPToolsPanelController, fillColorWellUpdated:, ppGSPatch_FillColorWellUpdated:); macroSwizzleInstanceMethod(PPToolsPanelController, updateFillColorWellColor, ppGSPatch_UpdateFillColorWellColor); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ColorPanel_InstallPatches); } @end @implementation NSColorWell (PPGNUstepGlue_ColorPanel) - (void) ppGSPatch_Activate: (BOOL) exclusive { gIsActivatingColorWell = YES; [self ppGSPatch_Activate: exclusive]; gIsActivatingColorWell = NO; } - (void) ppGSPatch_Deactivate { if (!gIsActivatingColorWell && [self isActive]) { [[NSColorPanel sharedColorPanel] orderOut: self]; } [self ppGSPatch_Deactivate]; } @end @implementation NSColorPanel (PPGNUstepGlue_ColorPanel) - (id) ppGSPatch_Init { Class colorWellClass; NSMutableArray *viewsToCheck; int viewIndex; NSView *view; NSColorWell *colorWell; self = [self ppGSPatch_Init]; colorWellClass = [NSColorWell class]; viewsToCheck = [NSMutableArray arrayWithArray: [[self contentView] subviews]]; viewIndex = 0; while (viewIndex < [viewsToCheck count]) { view = [viewsToCheck objectAtIndex: viewIndex]; if ([view isKindOfClass: colorWellClass]) { colorWell = (NSColorWell *) view; if (sel_isEqual([colorWell action], @selector(_bottomWellAction:)) && ![[colorWell target] respondsToSelector: @selector(_bottomWellAction:)]) { [colorWell setTarget: self]; } } [viewsToCheck addObjectsFromArray: [view subviews]]; viewIndex++; } return self; } - (void) ppGSPatch_BecomeKeyWindow { [self ppGSPatch_BecomeKeyWindow]; [self ppPerformSelectorFromNewStackFrame: @selector(ppGSGlue_ResignKeyUnlessEditingText)]; } - (void) ppGSGlue_ResignKeyUnlessEditingText { if (![self isKeyWindow]) { return; } if (![[self firstResponder] isKindOfClass: [NSText class]]) { [[NSApp mainWindow] makeKeyWindow]; } } @end @implementation PPToolsPanelController (PPGNUstepGlue_ColorPanel) - (IBAction) ppGSPatch_FillColorWellUpdated: (id) sender { [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(ppGSGlue_UpdateDocumentFillColorAndBlockColorWellUpdate)]; } - (void) ppGSPatch_UpdateFillColorWellColor { if (gDisallowToolsPanelColorWellUpdates) return; [_fillColorWell setColor: [_ppDocument fillColor]]; } - (void) ppGSGlue_UpdateDocumentFillColorAndBlockColorWellUpdate { gDisallowToolsPanelColorWellUpdates = YES; [_ppDocument setFillColor: [_fillColorWell color]]; gDisallowToolsPanelColorWellUpdates = NO; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ColorPickerPopupPanel.m0000644000076500000240000002707713234416764025264 0ustar joshstaff/* PPGNUstepGlue_ColorPickerPopupPanel.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGNUstepGlueUtilities.h" #import "PPColorPickerPopupPanelController.h" #import "PPColorPickerPopupPanel.h" #import "PPToolsPanelController.h" #import "PPGeometry.h" #import "PPUserDefaults.h" #define kWindowManagersIncompatibleWithNSWindowAboveOrderingForColorPanel \ (kPPGSWindowManagerTypeMask_Compiz) static bool gColorPanelIsAttachedToPopupPanel = NO, gAllowNSWindowAboveOrderingForColorPanel = YES; static NSRect gColorPanelFrameAtNextReveal = {{0,0},{0,0}}; static NSSize gColorPanelDefaultMaxSize, gColorPanelDefaultMinSize; static void SetupColorPanelSizeGlobals(void); @interface PPColorPickerPopupPanelController (PPGNUstepGlue_ColorPickerPopupPanelUtilities) - (void) ppGSGlue_HandleNSColorPanelNotification_DidMove: (NSNotification *) notification; @end @interface NSWindow (PPGNUstepGlue_ColorPickerPopupPanelUtilities) - (void) ppGSGlue_OrderBehindColorPanel; @end @implementation NSObject (PPGNUstepGlue_ColorPickerPopupPanel) + (void) ppGSGlue_ColorPickerPopupPanel_InstallPatches { macroSwizzleInstanceMethod(PPColorPickerPopupPanelController, windowDidLoad, ppGSPatch_WindowDidLoad); macroSwizzleInstanceMethod(PPColorPickerPopupPanelController, setPanelEnabled:, ppGSPatch_SetPanelEnabled:); macroSwizzleInstanceMethod(PPColorPickerPopupPanelController, colorPickerPopupPanelDidFinishHandlingMouseDownEvent:, ppGSPatch_ColorPickerPopupPanelDidFinishHandlingMouseDownEvent:); macroSwizzleInstanceMethod(NSColorPanel, canBecomeKeyWindow, ppGSPatch_CanBecomeKeyWindow); macroSwizzleInstanceMethod(NSColorPanel, orderFront:, ppGSPatch_OrderFront:); macroSwizzleInstanceMethod(PPColorPickerPopupPanel, sendEvent:, ppGSPatch_SendEvent:); } + (void) ppGSGlue_ColorPickerPopupPanel_Install { if (PPGSGlueUtils_WindowManagerMatchesTypeMask( kWindowManagersIncompatibleWithNSWindowAboveOrderingForColorPanel)) { gAllowNSWindowAboveOrderingForColorPanel = NO; } [self ppGSGlue_ColorPickerPopupPanel_InstallPatches]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ColorPickerPopupPanel_Install); } @end @implementation PPColorPickerPopupPanelController (PPGNUstepGlue_ColorPickerPopupPanel) - (void) ppGSPatch_WindowDidLoad { [self ppGSPatch_WindowDidLoad]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(ppGSGlue_HandleNSColorPanelNotification_DidMove:) name: NSWindowDidMoveNotification object: [NSColorPanel sharedColorPanel]]; SetupColorPanelSizeGlobals(); } - (void) ppGSPatch_SetPanelEnabled: (bool) enablePanel { static NSWindow *colorPanelInitialParentWindow = nil; bool popupPanelIsVisible = [self panelIsVisible]; if (enablePanel && !popupPanelIsVisible) { NSWindow *popupPanel; NSColorPanel *colorPanel; NSSize colorPanelFrameSize; NSPoint colorPanelCenteredOrigin; // make sure panel is loaded before accessing IBOutlets popupPanel = [self window]; colorPanel = [NSColorPanel sharedColorPanel]; if (!NSIsEmptyRect(gColorPanelFrameAtNextReveal)) { _oldColorPanelFrame = gColorPanelFrameAtNextReveal; gColorPanelFrameAtNextReveal = NSZeroRect; } else { _oldColorPanelFrame = [colorPanel frame]; } _oldColorPanelMode = [colorPanel mode]; [colorPanel setMode: _colorPanelMode]; colorPanelFrameSize = _oldColorPanelFrame.size; if (!NSEqualSizes(_colorPanelFrameSize, colorPanelFrameSize)) { _colorPanelFrameSize = colorPanelFrameSize; [self performSelector: @selector(updatePopupPanelSizeForColorPanelFrameSize)]; } // disable color panel resizing [colorPanel setMaxSize: colorPanelFrameSize]; [colorPanel setMinSize: colorPanelFrameSize]; [self performSelector: @selector(updateColorWellColor)]; [self performSelector: @selector(updateSamplerImageButtonsVisibility)]; [super setPanelEnabled: YES]; // If PPGNUstepGlue_WindowOrdering is installed, the color panel already has a parent // window, so preserve the parent window & detach from it before making the popup panel // the color panel's parent (initial parent is restored when the popup hides) colorPanelInitialParentWindow = [colorPanel parentWindow]; if (colorPanelInitialParentWindow) { [colorPanelInitialParentWindow retain]; [colorPanelInitialParentWindow removeChildWindow: colorPanel]; } [popupPanel addChildWindow: colorPanel ordered: NSWindowAbove]; gColorPanelIsAttachedToPopupPanel = YES; colorPanelCenteredOrigin = PPGeometry_CenterRectInRect(_oldColorPanelFrame, [popupPanel frame]).origin; [colorPanel setFrameOrigin: colorPanelCenteredOrigin]; _needToReactivateToolPanelColorWell = [[PPToolsPanelController sharedController] fillColorWellIsActive]; if (![colorPanel isVisible]) { [_colorWell activate: YES]; } [popupPanel ppGSGlue_OrderBehindColorPanel]; [self performSelector: @selector(addAsObserverForNSColorPanelNotifications)]; } else if (!enablePanel && popupPanelIsVisible) { NSColorPanel *colorPanel; int initialColorPanelMode; colorPanel = [NSColorPanel sharedColorPanel]; [self performSelector: @selector(removeAsObserverForNSColorPanelNotifications)]; [colorPanel endEditingFor: nil]; initialColorPanelMode = _colorPanelMode; _colorPanelMode = [colorPanel mode]; if (_colorPanelMode != initialColorPanelMode) { [PPUserDefaults setColorPickerPopupPanelMode: _colorPanelMode]; } [[self window] removeChildWindow: colorPanel]; gColorPanelIsAttachedToPopupPanel = NO; // restore color panel's initial parent window if it had one if (colorPanelInitialParentWindow) { [colorPanelInitialParentWindow addChildWindow: colorPanel ordered: NSWindowAbove]; [colorPanelInitialParentWindow autorelease]; colorPanelInitialParentWindow = nil; } [super setPanelEnabled: NO]; [colorPanel setMode: _oldColorPanelMode]; // reenable color panel resizing [colorPanel setMaxSize: gColorPanelDefaultMaxSize]; [colorPanel setMinSize: gColorPanelDefaultMinSize]; if (_needToReactivateToolPanelColorWell) { [colorPanel setFrameOrigin: _oldColorPanelFrame.origin]; [[PPToolsPanelController sharedController] activateFillColorWell]; } else if ([[PPToolsPanelController sharedController] fillColorWellIsActive]) { [colorPanel setFrameOrigin: _oldColorPanelFrame.origin]; [NSApp orderFrontColorPanel: self]; } else { if ([_colorWell isActive]) { [_colorWell deactivate]; } // let the color panel fade out before repositioning it to its old location - just // save the old frame and set it the next time the panel's ordered front gColorPanelFrameAtNextReveal = _oldColorPanelFrame; } } else { [super setPanelEnabled: enablePanel]; } } - (void) ppGSPatch_ColorPickerPopupPanelDidFinishHandlingMouseDownEvent: (PPColorPickerPopupPanel *) panel { // GNUstep version doesn't need to handle mouse clicks, so just ignore } @end @implementation NSColorPanel (PPGNUstepGlue_ColorPickerPopupPanel) - (BOOL) ppGSPatch_CanBecomeKeyWindow { if (gColorPanelIsAttachedToPopupPanel) { return NO; } return [self ppGSPatch_CanBecomeKeyWindow]; } - (void) ppGSPatch_OrderFront: (id) sender { if (!NSIsEmptyRect(gColorPanelFrameAtNextReveal)) { [self setFrameOrigin: gColorPanelFrameAtNextReveal.origin]; gColorPanelFrameAtNextReveal = NSZeroRect; } [self ppGSPatch_OrderFront: sender]; } @end @implementation PPColorPickerPopupPanel (PPGNUstepGlue_ColorPickerPopupPanel) - (void) ppGSPatch_SendEvent: (NSEvent *) theEvent { if (([theEvent type] == NSAppKitDefined) && ([theEvent subtype] == GSAppKitRegionExposed)) { [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(ppGSGlue_OrderBehindColorPanel)]; } [self ppGSPatch_SendEvent: theEvent]; } @end @implementation PPColorPickerPopupPanelController (PPGNUstepGlue_ColorPickerPopupPanelUtilities) - (void) ppGSGlue_HandleNSColorPanelNotification_DidMove: (NSNotification *) notification { if (gColorPanelIsAttachedToPopupPanel) { [[self window] ppPerformSelectorAtomicallyFromNewStackFrame: @selector(ppGSGlue_OrderBehindColorPanel)]; } } @end @implementation NSWindow (PPGNUstepGlue_ColorPickerPopupPanelUtilities) - (void) ppGSGlue_OrderBehindColorPanel { if (![self isVisible]) { return; } // NSWindowAbove-ordering for the color panel works on most window managers, except for // Compiz, where it causes the color panel to appear behind the target window if the panel // was already visible - workaround is to use NSWindowBelow ordering on the target window; // NSWindowBelow-ordering works on most window managers, except for Openbox, where it // messes up the ordering of the document window & moves it behind the next app's frontmost // window (failure-mode is worse than with NSWindowAbove, so use NSWindowAbove as default) if (gAllowNSWindowAboveOrderingForColorPanel) { [[NSColorPanel sharedColorPanel] orderWindow: NSWindowAbove relativeTo: [self windowNumber]]; } else { [self orderWindow: NSWindowBelow relativeTo: [[NSColorPanel sharedColorPanel] windowNumber]]; } } @end static void SetupColorPanelSizeGlobals(void) { NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel]; gColorPanelDefaultMaxSize = [colorPanel maxSize]; gColorPanelDefaultMinSize = [colorPanel minSize]; } #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_CustomTheme.m0000644000076500000240000011173313353503020023252 0ustar joshstaff/* PPGNUstepGlue_CustomTheme.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Customizations to the built-in GNUstep theme (disabled if GNUstep is using a different // theme, or if PPDisableGSThemeCustomizations == "YES" in the user defaults): // - Use NSWindows95InterfaceStyle (in-window menubars), except on Window Maker window manager // - Adjust UI colors // - Tweak menu dimensions (menu bar height, menu font size, separator height) // - Horizontal menubars: center-align item titles, increase spacing between items // - Remove the border frames around individual menu items // - Draw table headers using the table's background color // - Draw rounded-style & regular-square-style buttons as NeXT-style square buttons // - Disable focus ring around controls #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGNUstepGlueUtilities.h" #import "GNUstepGUI/GSTheme.h" #import "PPGeometry.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #import "NSColor_PPUtilities.h" #import "PPUIColors_Panels.h" #import "PPGNUstepUserDefaults.h" #define kCustomThemeName @"PikoStep" #define kCustomThemeDefaultsDictName @"PPGNUstepDefaults_CustomTheme" #define kPPGSUserDefaultsKey_DisableGSThemeCustomizations @"PPDisableGSThemeCustomizations" #define kPPGSUserDefaultsKey_BoldMenuTextColorWhiteValue @"PPBoldMenuTextColorWhiteValue" #define kVerticalMenubarItem_DefaultEdgePadding 4 // GNUstep default #define kHorizontalMenubarItem_CustomEdgePadding 9 // Custom theme padding static bool ShouldInstallThemeCustomizations(void); static void RecolorHorizontalSliderKnobImage(void); static void RecolorSwitchImages(void); static void RecolorReturnKeyButtonImage(void); static NSMenuItemCell *gAppMenuTitleItem = nil; static float gAppMenuTitleVerticalOffset = 0; static bool gIsDrawingTableView = NO, gIsDrawingCustomSliderFrame = NO; @interface NSUserDefaults (PPGNUstepGlue_CustomThemeUtilities) - (void) ppGSGlue_CustomTheme_SetupDefaults; @end @interface NSImage (PPGNUstepGlue_CustomThemeUtilities) + (bool) ppGSGlue_RecolorSystemImageNamed: (NSString *) imageName imageSize: (NSSize) imageSize bitmapSize: (NSSize) bitmapSize backgroundFillPoint: (NSPoint) backgroundFillPoint shadowFillPoint: (NSPoint) shadowFillPoint darkShadowFillPoint: (NSPoint) darkShadowFillPoint colorMatchTolerance: (unsigned) colorMatchTolerance matchAnywhere: (bool) matchAnywhere; @end @implementation NSObject (PPGNUstepGlue_CustomTheme) + (void) ppGSGlue_CustomTheme_InstallPatches { macroSwizzleInstanceMethod(GSTheme, drawBorderAndBackgroundForMenuItemCell:withFrame: inView:state:isHorizontal:, ppGSPatch_DrawBorderAndBackgroundForMenuItemCell:withFrame: inView:state:isHorizontal:); macroSwizzleInstanceMethod(GSTheme, drawTableHeaderCell:withFrame:inView:state:, ppGSPatch_DrawTableHeaderCell:withFrame:inView:state:); macroSwizzleInstanceMethod(GSTheme, drawTableViewRect:inView:, ppGSPatch_DrawTableViewRect:inView:); macroSwizzleInstanceMethod(GSTheme, drawButton:in:view:style:state:, ppGSPatch_DrawButton:in:view:style:state:); macroSwizzleInstanceMethod(GSTheme, drawSegmentedControlSegment:withFrame:inView:style: state:roundedLeft:roundedRight:, ppGSPatch_DrawSegmentedControlSegment:withFrame:inView:style: state:roundedLeft:roundedRight:); macroSwizzleInstanceMethod(GSTheme, drawSliderBorderAndBackground:frame:inCell: isHorizontal:, ppGSPatch_DrawSliderBorderAndBackground:frame:inCell: isHorizontal:); macroSwizzleInstanceMethod(GSTheme, drawBarInside:inCell:flipped:, ppGSPatch_DrawBarInside:inCell:flipped:); macroSwizzleInstanceMethod(GSTheme, drawFocusFrame:view:, ppGSPatch_DrawFocusFrame:view:); macroSwizzleInstanceMethod(GSTheme, scrollViewUseBottomCorner, ppGSPatch_ScrollViewUseBottomCorner); macroSwizzleInstanceMethod(GSTheme, menuBackgroundColor, ppGSPatch_MenuBackgroundColor); macroSwizzleInstanceMethod(GSTheme, menuSeparatorColor, ppGSPatch_MenuSeparatorColor); macroSwizzleInstanceMethod(GSTheme, menuBorderColorForEdge:isHorizontal:, ppGSPatch_MenuBorderColorForEdge:isHorizontal:); macroSwizzleInstanceMethod(GSTheme, tableHeaderTextColorForState:, ppGSPatch_TableHeaderTextColorForState:); macroSwizzleInstanceMethod(GSTheme, name, ppGSPatch_Name); macroSwizzleClassMethod(NSColor, scrollBarColor, ppGSPatch_ScrollBarColor); macroSwizzleClassMethod(NSColor, selectedMenuItemColor, ppGSPatch_SelectedMenuItemColor); macroSwizzleInstanceMethod(NSMenuView, setHorizontal:, ppGSPatch_SetHorizontal:); macroSwizzleInstanceMethod(NSPopUpButtonCell, drawTitleWithFrame:inView:, ppGSPatch_DrawTitleWithFrame:inView:); macroSwizzleInstanceMethod(NSMenuItemCell, drawTitleWithFrame:inView:, ppGSPatch_DrawTitleWithFrame:inView:); macroSwizzleInstanceMethod(NSMenuItemCell, drawKeyEquivalentWithFrame:inView:, ppGSPatch_DrawKeyEquivalentWithFrame:inView:); macroSwizzleInstanceMethod(NSMenuItemCell, textColor, ppGSPatch_TextColor); macroSwizzleInstanceMethod(NSTextFieldCell, titleRectForBounds:, ppGSPatch_TitleRectForBounds:); macroSwizzleInstanceMethod(NSSliderCell, drawWithFrame:inView:, ppGSPatch_DrawWithFrame:inView:); macroSwizzleInstanceMethod(NSScrollView, tile, ppGSPatch_CustomTheme_Tile); } + (void) ppGSGlue_CustomTheme_Install { if (!ShouldInstallThemeCustomizations()) { return; } [self ppGSGlue_CustomTheme_InstallPatches]; RecolorHorizontalSliderKnobImage(); RecolorSwitchImages(); RecolorReturnKeyButtonImage(); } + (void) load { PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads( @selector(ppGSGlue_CustomTheme_SetupDefaults)); macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_CustomTheme_Install); } @end @implementation GSTheme (PPGNUStepGlue_CustomTheme) // PATCH: -[GSTheme drawBorderAndBackgroundForMenuItemCell:withFrame:inView:state:isHorizontal:] // Overrides the default theme to draw all menu items with no borders (reduces visual clutter) - (void) ppGSPatch_DrawBorderAndBackgroundForMenuItemCell: (NSMenuItemCell *) cell withFrame: (NSRect) cellFrame inView: (NSView *) controlView state: (GSThemeControlState) state isHorizontal: (BOOL) isHorizontal { [[cell backgroundColor] set]; NSRectFill([cell drawingRectForBounds: cellFrame]); } // PATCH: -[GSTheme drawTableHeaderCell:withFrame:inView:state:] // #define kTableHeaderSeparatorVerticalMargin 2 #define kTableHeaderUnderlineOffset 1 - (void) ppGSPatch_DrawTableHeaderCell: (NSTableHeaderCell *) cell withFrame: (NSRect) cellFrame inView: (NSView *) controlView state: (GSThemeControlState) state { NSColor *tableBackgroundColor = nil; NSPoint separatorPoint1, separatorPoint2, underlinePoint1, underlinePoint2; bool shouldDrawVerticalSeparator; if ([controlView isKindOfClass: [NSTableHeaderView class]]) { tableBackgroundColor = [[((NSTableHeaderView *) controlView) tableView] backgroundColor]; } if (!tableBackgroundColor) { tableBackgroundColor = [NSColor windowBackgroundColor]; } [tableBackgroundColor set]; NSRectFill(cellFrame); [[NSColor windowBackgroundColor] set]; shouldDrawVerticalSeparator = (NSMaxX(cellFrame) < NSMaxX([controlView bounds])) ? YES : NO; if ([controlView isFlipped]) { if (shouldDrawVerticalSeparator) { separatorPoint1 = PPGeometry_PixelCenteredPoint( NSMakePoint(NSMaxX(cellFrame) - 1, NSMinY(cellFrame) + kTableHeaderSeparatorVerticalMargin)); separatorPoint2 = PPGeometry_PixelCenteredPoint( NSMakePoint(NSMaxX(cellFrame) - 1, NSMaxY(cellFrame) - 1 - kTableHeaderSeparatorVerticalMargin - kTableHeaderUnderlineOffset)); } underlinePoint1 = PPGeometry_PixelCenteredPoint( NSMakePoint(NSMinX(cellFrame), NSMaxY(cellFrame) - 1 - kTableHeaderUnderlineOffset)); underlinePoint2 = PPGeometry_PixelCenteredPoint( NSMakePoint(NSMaxX(cellFrame), NSMaxY(cellFrame) - 1 - kTableHeaderUnderlineOffset)); } else { if (shouldDrawVerticalSeparator) { separatorPoint1 = PPGeometry_PixelCenteredPoint( NSMakePoint(NSMaxX(cellFrame) - 1, NSMinY(cellFrame) + kTableHeaderSeparatorVerticalMargin + kTableHeaderUnderlineOffset)); separatorPoint2 = PPGeometry_PixelCenteredPoint( NSMakePoint(NSMaxX(cellFrame) - 1, NSMaxY(cellFrame) - 1 - kTableHeaderSeparatorVerticalMargin)); } underlinePoint1 = PPGeometry_PixelCenteredPoint( NSMakePoint(NSMinX(cellFrame), NSMinY(cellFrame) + kTableHeaderUnderlineOffset)); underlinePoint2 = PPGeometry_PixelCenteredPoint( NSMakePoint(NSMaxX(cellFrame), NSMinY(cellFrame) + kTableHeaderUnderlineOffset)); } if (shouldDrawVerticalSeparator) { [NSBezierPath strokeLineFromPoint: separatorPoint1 toPoint: separatorPoint2]; } [NSBezierPath strokeLineFromPoint: underlinePoint1 toPoint: underlinePoint2]; } - (void) ppGSPatch_DrawTableViewRect: (NSRect) aRect inView: (NSView *) view { gIsDrawingTableView = YES; [self ppGSPatch_DrawTableViewRect: aRect inView: view]; gIsDrawingTableView = NO; } // PATCH: -[GSTheme drawButton:in:view:style:state:] // Overrides the default theme's button drawing for rounded, regular-square, & circular // buttons to instead draw them as NeXT-style square buttons. (OS X has been drawing rounded // buttons as squares for the last several versions, and GNUstep's default theme currently // draws regular-square-style buttons with just a simple frame outline & no highlights or // shadows, so they look flat & different from other buttons). - (void) ppGSPatch_DrawButton: (NSRect)frame in: (NSCell*)cell view: (NSView*)view style: (int)style state: (GSThemeControlState)state { switch (style) { case NSRoundedBezelStyle: { style = NSNeXTBezelStyle; // tweak frame: RoundedBezel -> NeXT frame = NSInsetRect(frame, 3, 3); } break; case NSRegularSquareBezelStyle: { style = NSNeXTBezelStyle; // tweak frame: RegularSquare -> NeXT frame = NSInsetRect(frame, 2, 4); frame.size.height += 2; if (![view isFlipped]) { frame.origin.y -= 2; } } break; case NSCircularBezelStyle: { style = NSNeXTBezelStyle; // tweak frame: Circular -> NeXT frame = NSInsetRect(frame, 6, 6); } break; default: break; } [self ppGSPatch_DrawButton: frame in: cell view: view style: style state: state]; } - (void) ppGSPatch_DrawSegmentedControlSegment: (NSCell *) cell withFrame: (NSRect) cellFrame inView: (NSView *) controlView style: (NSSegmentStyle) style state: (GSThemeControlState) state roundedLeft: (BOOL) roundedLeft roundedRight: (BOOL) roundedRight { cellFrame = NSInsetRect(cellFrame, -2, -2); cellFrame.origin.y += ([controlView isFlipped]) ? -1 : 1; [self ppGSPatch_DrawSegmentedControlSegment: cell withFrame: cellFrame inView: controlView style: style state: state roundedLeft: roundedLeft roundedRight: roundedRight]; } - (void) ppGSPatch_DrawSliderBorderAndBackground: (NSBorderType) aType frame: (NSRect) cellFrame inCell: (NSCell *) cell isHorizontal: (BOOL) horizontal { if (gIsDrawingCustomSliderFrame) return; [self ppGSPatch_DrawSliderBorderAndBackground: aType frame: cellFrame inCell: cell isHorizontal: horizontal]; } - (void) ppGSPatch_DrawBarInside: (NSRect) rect inCell: (NSCell *) cell flipped: (BOOL) flipped { float leftX, rightX, bottomY, topY, verticalPixelOffset; NSPoint bottomLeftPoint, topLeftPoint, bottomRightPoint, topRightPoint; if (!gIsDrawingCustomSliderFrame) { [self ppGSPatch_DrawBarInside: rect inCell: cell flipped: flipped]; return; } rect = PPGeometry_PixelCenteredRect(rect); leftX = NSMinX(rect); rightX = NSMaxX(rect); if (flipped) { bottomY = NSMaxY(rect); topY = NSMinY(rect); verticalPixelOffset = -1; } else { bottomY = NSMinY(rect); topY = NSMaxY(rect); verticalPixelOffset = 1; } // scrollbar fill [[NSColor scrollBarColor] set]; NSRectFill(NSInsetRect(rect,1,1)); // outside edge highlight & shadow bottomLeftPoint = NSMakePoint(leftX, bottomY); bottomRightPoint = NSMakePoint(rightX, bottomY); topLeftPoint = NSMakePoint(leftX, topY); topRightPoint = NSMakePoint(rightX, topY); [[NSColor whiteColor] set]; [NSBezierPath strokeLineFromPoint: bottomLeftPoint toPoint: bottomRightPoint]; [NSBezierPath strokeLineFromPoint: bottomRightPoint toPoint: topRightPoint]; [[NSColor controlShadowColor] set]; [NSBezierPath strokeLineFromPoint: bottomLeftPoint toPoint: topLeftPoint]; [NSBezierPath strokeLineFromPoint: topLeftPoint toPoint: topRightPoint]; // inside edge highlight & shadow bottomLeftPoint = NSMakePoint(leftX + 1, bottomY + verticalPixelOffset); bottomRightPoint = NSMakePoint(rightX - 1, bottomY + verticalPixelOffset); topLeftPoint = NSMakePoint(leftX + 1, topY - verticalPixelOffset); topRightPoint = NSMakePoint(rightX - 1, topY - verticalPixelOffset); [NSBezierPath strokeLineFromPoint: bottomLeftPoint toPoint: bottomRightPoint]; [NSBezierPath strokeLineFromPoint: bottomRightPoint toPoint: topRightPoint]; [[NSColor controlDarkShadowColor] set]; [NSBezierPath strokeLineFromPoint: bottomLeftPoint toPoint: topLeftPoint]; [NSBezierPath strokeLineFromPoint: topLeftPoint toPoint: topRightPoint]; } - (void) ppGSPatch_DrawFocusFrame: (NSRect) frame view: (NSView *) view { // disable all focus rings } - (BOOL) ppGSPatch_ScrollViewUseBottomCorner { return NO; } - (NSColor *) ppGSPatch_MenuBackgroundColor { return [NSColor controlBackgroundColor]; } - (NSColor *) ppGSPatch_MenuSeparatorColor { return [NSColor disabledControlTextColor]; } - (NSColor *) ppGSPatch_MenuBorderColorForEdge: (NSRectEdge) edge isHorizontal: (BOOL) horizontal { if (horizontal && ((edge == NSMinXEdge) || (edge == NSMaxXEdge))) { return [NSColor controlBackgroundColor]; } return [self ppGSPatch_MenuBorderColorForEdge: edge isHorizontal: horizontal]; } - (NSColor *) ppGSPatch_TableHeaderTextColorForState: (GSThemeControlState) state { return [NSColor controlDarkShadowColor]; } - (NSString *) ppGSPatch_Name { return kCustomThemeName; } @end @implementation NSColor (PPGNUstepGlue_CustomTheme) + (NSColor *) ppGSPatch_ScrollBarColor { static NSColor *scrollBarPatternColor = nil; if (!scrollBarPatternColor) { scrollBarPatternColor = [[NSColor ppCheckerboardPatternColorWithBoxDimension: 1 color1: [NSColor windowBackgroundColor] color2: [self ppGSPatch_ScrollBarColor]] retain]; } return (scrollBarPatternColor) ? scrollBarPatternColor : [self ppGSPatch_ScrollBarColor]; } + (NSColor *) ppGSPatch_SelectedMenuItemColor { static NSColor *patternColor = nil; if (!patternColor) { patternColor = [[NSColor ppCenteredVerticalGradientPatternColorWithHeight: [[NSUserDefaults standardUserDefaults] integerForKey: @"NSMenuFontSize"] innerColor: kUIColor_ToolsPanel_ActiveToolCellGradientInnerColor outerColor: kUIColor_ToolsPanel_ActiveToolCellGradientOuterColor] retain]; } return (patternColor) ? patternColor : [self ppGSPatch_SelectedMenuItemColor]; } @end @implementation NSMenuView (PPGNUstepGlue_CustomTheme) // PATCH: -[NSMenuView setHorizontal:] // Horizontal menus' item titles are left-aligned instead of center-aligned, and are also too // close together. // Patch manually sets up menu items' text alignment & the menuview's horizontal edge padding // before calling through to original implementation. - (void) ppGSPatch_SetHorizontal: (BOOL) menuIsHorizontal { NSTextAlignment itemCellTextAlignment; float horizontalEdgePadding; int numMenuItems, itemIndex; [gAppMenuTitleItem release]; gAppMenuTitleItem = nil; if (menuIsHorizontal) { itemCellTextAlignment = NSCenterTextAlignment; horizontalEdgePadding = kHorizontalMenubarItem_CustomEdgePadding; } else { itemCellTextAlignment = NSLeftTextAlignment; horizontalEdgePadding = kVerticalMenubarItem_DefaultEdgePadding; } // item cells' text alignment numMenuItems = [[self menu] numberOfItems]; if (menuIsHorizontal && (numMenuItems > 0)) { NSFont *menuFont, *boldMenuFont; menuFont = [NSFont menuFontOfSize: 0]; boldMenuFont = [NSFont boldSystemFontOfSize: [menuFont pointSize]]; if (menuFont && boldMenuFont) { [gAppMenuTitleItem release]; gAppMenuTitleItem = [[self menuItemCellForItemAtIndex: 0] retain]; [gAppMenuTitleItem setFont: boldMenuFont]; gAppMenuTitleVerticalOffset = [boldMenuFont descender] - [menuFont descender]; } } for (itemIndex=0; itemIndex cellFrame.size.height) && ![self isBezeled]) ? YES : NO; if (gIsDrawingCustomSliderFrame) { cellFrame.origin.y += roundf((cellFrame.size.height - customSliderFrameHeight) / 2.0f); cellFrame.size.height = customSliderFrameHeight; } [self ppGSPatch_DrawWithFrame: cellFrame inView: controlView]; gIsDrawingCustomSliderFrame = NO; } @end @implementation NSScrollView (PPGNUstepGlue_CustomTheme) #define kMarginBetweenContentViewAndScroller 2 - (void) ppGSPatch_CustomTheme_Tile { NSView *contentView, *scrollerView; NSRect contentViewFrame, scrollerViewFrame; [self ppGSPatch_CustomTheme_Tile]; contentView = [self contentView]; contentViewFrame = [contentView frame]; if ([self hasHorizontalScroller]) { scrollerView = [self horizontalScroller]; scrollerViewFrame = [scrollerView frame]; if ([self isFlipped]) { contentViewFrame.size.height = NSMinY(scrollerViewFrame) - NSMinY(contentViewFrame) + 1 - kMarginBetweenContentViewAndScroller; } else { CGFloat maxY = NSMaxY(contentViewFrame); contentViewFrame.origin.y = NSMaxY(scrollerViewFrame) + kMarginBetweenContentViewAndScroller; contentViewFrame.size.height = maxY - contentViewFrame.origin.y; } if (contentViewFrame.size.height < 0) { contentViewFrame.size.height = 0; } } if ([self hasVerticalScroller]) { scrollerView = [self verticalScroller]; scrollerViewFrame = [scrollerView frame]; if (scrollerViewFrame.origin.x > contentViewFrame.origin.x) { // right-side vertical scroller contentViewFrame.size.width = NSMinX(scrollerViewFrame) - NSMinX(contentViewFrame) + 1 - kMarginBetweenContentViewAndScroller; } else { // left-side vertical scroller contentViewFrame.size.width = NSMaxX(contentViewFrame) - NSMaxX(scrollerViewFrame) + 1 - kMarginBetweenContentViewAndScroller; contentViewFrame.origin.x = NSMaxX(scrollerViewFrame) + kMarginBetweenContentViewAndScroller - 1; } if (contentViewFrame.size.width < 0) { contentViewFrame.size.width = 0; } } [contentView setFrame: contentViewFrame]; } @end @implementation NSUserDefaults (PPGNUstepGlue_CustomThemeUtilities) - (void) ppGSGlue_CustomTheme_SetupDefaults { if (!ShouldInstallThemeCustomizations()) { return; } // Register custom UI colors & menu dimensions from resource dict [NSUserDefaults ppGSGlueUtils_RegisterDefaultsFromDictionaryNamed: kCustomThemeDefaultsDictName]; // Register NSWindows95InterfaceStyle as the default style, unless the window manager is // Window Maker if (!PPGSGlueUtils_WindowManagerMatchesTypeMask(kPPGSWindowManagerTypeMask_WindowMaker)) { NSDictionary *defaultsDict = [NSDictionary dictionaryWithObject: kGSUserDefaultsValue_InterfaceStyleName_Windows95 forKey: kGSUserDefaultsKey_InterfaceStyleName]; if (defaultsDict) { [self registerDefaults: defaultsDict]; } } } @end @implementation NSImage (PPGNUstepGlue_CustomThemeUtilities) + (bool) ppGSGlue_RecolorSystemImageNamed: (NSString *) imageName imageSize: (NSSize) imageSize bitmapSize: (NSSize) bitmapSize backgroundFillPoint: (NSPoint) backgroundFillPoint shadowFillPoint: (NSPoint) shadowFillPoint darkShadowFillPoint: (NSPoint) darkShadowFillPoint colorMatchTolerance: (unsigned) colorMatchTolerance matchAnywhere: (bool) matchAnywhere { NSImage *oldImage, *newImage; NSBitmapImageRep *imageBitmap, *maskBitmap; NSRect bitmapFrame; if (!imageName) goto ERROR; oldImage = [self imageNamed: imageName]; if (!oldImage || !NSEqualSizes([oldImage size], imageSize)) { goto ERROR; } imageBitmap = [[oldImage bestRepresentationForDevice: nil] ppImageBitmap]; if (!imageBitmap || !NSEqualSizes([imageBitmap ppSizeInPixels], bitmapSize)) { goto ERROR; } maskBitmap = [NSBitmapImageRep ppMaskBitmapOfSize: bitmapSize]; if (!maskBitmap) goto ERROR; bitmapFrame = PPGeometry_OriginRectOfSize(bitmapSize); // control background color if (!NSEqualPoints(backgroundFillPoint, NSZeroPoint)) { if (matchAnywhere) { [maskBitmap ppMaskAllPixelsMatchingColorAtPoint: backgroundFillPoint inImageBitmap: imageBitmap colorMatchTolerance: colorMatchTolerance selectionMask: nil selectionMaskBounds: NSZeroRect]; } else { [maskBitmap ppMaskNeighboringPixelsMatchingColorAtPoint: backgroundFillPoint inImageBitmap: imageBitmap colorMatchTolerance: colorMatchTolerance selectionMask: nil selectionMaskBounds: NSZeroRect matchDiagonally: NO]; } [imageBitmap ppMaskedFillUsingMask: maskBitmap inBounds: bitmapFrame fillPixelValue: [[NSColor controlBackgroundColor] ppImageBitmapPixelValue]]; } // control shadow color if (!NSEqualPoints(shadowFillPoint, NSZeroPoint)) { if (matchAnywhere) { [maskBitmap ppMaskAllPixelsMatchingColorAtPoint: shadowFillPoint inImageBitmap: imageBitmap colorMatchTolerance: colorMatchTolerance selectionMask: nil selectionMaskBounds: NSZeroRect]; } else { [maskBitmap ppMaskNeighboringPixelsMatchingColorAtPoint: shadowFillPoint inImageBitmap: imageBitmap colorMatchTolerance: colorMatchTolerance selectionMask: nil selectionMaskBounds: NSZeroRect matchDiagonally: NO]; } [imageBitmap ppMaskedFillUsingMask: maskBitmap inBounds: bitmapFrame fillPixelValue: [[NSColor controlShadowColor] ppImageBitmapPixelValue]]; } // control dark shadow color if (!NSEqualPoints(darkShadowFillPoint, NSZeroPoint)) { if (matchAnywhere) { [maskBitmap ppMaskAllPixelsMatchingColorAtPoint: darkShadowFillPoint inImageBitmap: imageBitmap colorMatchTolerance: colorMatchTolerance selectionMask: nil selectionMaskBounds: NSZeroRect]; } else { [maskBitmap ppMaskNeighboringPixelsMatchingColorAtPoint: darkShadowFillPoint inImageBitmap: imageBitmap colorMatchTolerance: colorMatchTolerance selectionMask: nil selectionMaskBounds: NSZeroRect matchDiagonally: NO]; } [imageBitmap ppMaskedFillUsingMask: maskBitmap inBounds: bitmapFrame fillPixelValue: [[NSColor controlDarkShadowColor] ppImageBitmapPixelValue]]; } newImage = [NSImage ppImageWithBitmap: imageBitmap]; if (!newImage) goto ERROR; if (!NSEqualSizes(imageSize, bitmapSize)) { [newImage setSize: imageSize]; } [oldImage setName: nil]; [newImage setName: imageName]; return YES; ERROR: return NO; } @end #define kStandardGSThemeName @"GNUstep" #define kStandardGSThemeNameWithExtension @"GNUstep.theme" static bool ShouldInstallThemeCustomizations(void) { NSUserDefaults *userDefaults; NSString *currentGSThemeName; bool currentGSThemeIsStandardTheme, disallowThemeCustomizations; userDefaults = [NSUserDefaults standardUserDefaults]; currentGSThemeName = [userDefaults stringForKey: kGSUserDefaultsKey_ThemeName]; currentGSThemeIsStandardTheme = (!currentGSThemeName || [currentGSThemeName isEqualToString: kStandardGSThemeName] || [currentGSThemeName isEqualToString: kStandardGSThemeNameWithExtension]) ? YES : NO; disallowThemeCustomizations = ([userDefaults boolForKey: kPPGSUserDefaultsKey_DisableGSThemeCustomizations]) ? YES : NO; return (currentGSThemeIsStandardTheme && !disallowThemeCustomizations) ? YES : NO; } #define kSliderKnobImageName @"common_SliderHoriz" #define kSliderKnobImageSize NSMakeSize(19,14) #define kSliderKnobBitmapSize NSMakeSize(19,14) #define kSliderKnobBitmapColorFillPoint_ControlBackground NSMakePoint(3,3) #define kSliderKnobBitmapColorFillPoint_ControlShadow NSMakePoint(3,1) #define kSliderKnobBitmapColorFillPoint_ControlDarkShadow NSMakePoint(1,0) #define kSliderKnobBitmapColorMatchTolerance 0 #define kSliderKnobBitmapColorMatchAnywhere YES static void RecolorHorizontalSliderKnobImage(void) { [NSImage ppGSGlue_RecolorSystemImageNamed: kSliderKnobImageName imageSize: kSliderKnobImageSize bitmapSize: kSliderKnobBitmapSize backgroundFillPoint: kSliderKnobBitmapColorFillPoint_ControlBackground shadowFillPoint: kSliderKnobBitmapColorFillPoint_ControlShadow darkShadowFillPoint: kSliderKnobBitmapColorFillPoint_ControlDarkShadow colorMatchTolerance: kSliderKnobBitmapColorMatchTolerance matchAnywhere: kSliderKnobBitmapColorMatchAnywhere]; } #define kSwitchImageName @"GSSwitch" #define kHighlightedSwitchImageName @"GSSwitchSelected" #define kSwitchImageSize NSMakeSize(15,15) #define kSwitchBitmapSize NSMakeSize(60,60) #define kSwitchBitmapColorFillPoint_ControlBackground NSMakePoint(6,10) #define kSwitchBitmapColorFillPoint_ControlShadow NSMakePoint(6,5) #define kSwitchBitmapColorFillPoint_ControlDarkShadow NSMakePoint(1,0) #define kSwitchBitmapColorMatchTolerance 45 #define kSwitchBitmapColorMatchAnywhere YES static void RecolorSwitchImages(void) { [NSImage ppGSGlue_RecolorSystemImageNamed: kSwitchImageName imageSize: kSwitchImageSize bitmapSize: kSwitchBitmapSize backgroundFillPoint: kSwitchBitmapColorFillPoint_ControlBackground shadowFillPoint: kSwitchBitmapColorFillPoint_ControlShadow darkShadowFillPoint: kSwitchBitmapColorFillPoint_ControlDarkShadow colorMatchTolerance: kSwitchBitmapColorMatchTolerance matchAnywhere: kSwitchBitmapColorMatchAnywhere]; [NSImage ppGSGlue_RecolorSystemImageNamed: kHighlightedSwitchImageName imageSize: kSwitchImageSize bitmapSize: kSwitchBitmapSize backgroundFillPoint: kSwitchBitmapColorFillPoint_ControlBackground shadowFillPoint: kSwitchBitmapColorFillPoint_ControlShadow darkShadowFillPoint: NSZeroPoint colorMatchTolerance: kSwitchBitmapColorMatchTolerance matchAnywhere: YES]; [NSImage ppGSGlue_RecolorSystemImageNamed: kHighlightedSwitchImageName imageSize: kSwitchImageSize bitmapSize: kSwitchBitmapSize backgroundFillPoint: NSZeroPoint shadowFillPoint: NSZeroPoint darkShadowFillPoint: kSwitchBitmapColorFillPoint_ControlDarkShadow colorMatchTolerance: 0 matchAnywhere: NO]; } #define kReturnKeyImageName @"common_ret" #define kReturnKeyImageSize NSMakeSize(15,10) #define kReturnKeyBitmapSize NSMakeSize(15,10) #define kReturnKeyBitmapColorFillPoint_ControlBackground NSZeroPoint #define kReturnKeyBitmapColorFillPoint_ControlShadow NSMakePoint(4,4) #define kReturnKeyBitmapColorFillPoint_ControlDarkShadow NSZeroPoint #define kReturnKeyBitmapColorMatchTolerance 0 #define kReturnKeyBitmapColorMatchAnywhere NO static void RecolorReturnKeyButtonImage(void) { [NSImage ppGSGlue_RecolorSystemImageNamed: kReturnKeyImageName imageSize: kReturnKeyImageSize bitmapSize: kReturnKeyBitmapSize backgroundFillPoint: kReturnKeyBitmapColorFillPoint_ControlBackground shadowFillPoint: kReturnKeyBitmapColorFillPoint_ControlShadow darkShadowFillPoint: kReturnKeyBitmapColorFillPoint_ControlDarkShadow colorMatchTolerance: kReturnKeyBitmapColorMatchTolerance matchAnywhere: kReturnKeyBitmapColorMatchAnywhere]; } #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_DisableMenuKeysDuringTextEntry.m0000644000076500000240000001107613234416764027120 0ustar joshstaff/* PPGNUstepGlue_DisableMenuKeysDuringTextEntry.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // GNUstep workaround to prevent keys which have menu-key-equivalents (such as '0' & ) // from being intercepted while typing text in a textfield. #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPKeyCancellableWindow.h" @implementation NSObject (PPGNUstepGlue_DisableMenuKeysDuringTextEntry) + (void) ppGSGlue_DisableMenuKeysDuringTextEntry_InstallPatches { // Patch -[NSWindow performKeyEquivalent:] for all NSWindow subclasses that use textfields // in PikoPixel: NSOpenPanel, NSSavePanel, NSColorPanel, NSPanel, PPKeyCancellableWindow. // This used to be a patch on a single class (NSWindow), but subclass inheritance of // patched methods no longer seems to work on the gcc runtime (perhaps it never worked, or // perhaps it's an issue with recent versions) apparently due to subclasses not updating // their method tables when the patch is installed on a superclass (calling // performKeyEquivalent: on an NSWindow works fine, but calling it on an NSPanel jumps // directly to the original NSWindow method without calling the patch), so workaround is to // manually patch every class where the patched functionality is needed (don't assume it // inherits the patch correctly). // Subclasses should be patched before their parent classes, to prevent swapping methods // that are already swapped in the inherited method table (if patch inheritance is working // correctly). macroSwizzleInstanceMethod(NSOpenPanel, performKeyEquivalent:, ppGSPatch_DisableMenuKeysDuringTextEntry_PerformKeyEquivalent:); macroSwizzleInstanceMethod(NSSavePanel, performKeyEquivalent:, ppGSPatch_DisableMenuKeysDuringTextEntry_PerformKeyEquivalent:); macroSwizzleInstanceMethod(NSColorPanel, performKeyEquivalent:, ppGSPatch_DisableMenuKeysDuringTextEntry_PerformKeyEquivalent:); macroSwizzleInstanceMethod(NSPanel, performKeyEquivalent:, ppGSPatch_DisableMenuKeysDuringTextEntry_PerformKeyEquivalent:); macroSwizzleInstanceMethod(PPKeyCancellableWindow, performKeyEquivalent:, ppGSPatch_DisableMenuKeysDuringTextEntry_PerformKeyEquivalent:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads( ppGSGlue_DisableMenuKeysDuringTextEntry_InstallPatches); } @end @implementation NSWindow (PPGNUstepGlue_DisableMenuKeysDuringTextEntry) // PATCH: -[NSWindow performKeyEquivalent:] // Override prevents GNUstep from intercepting keypresses that are (non-modifier-key) menu-item // equivalents when editing text; For keyDown events, when there's no modifier key pressed, // if there's an active fieldEditor (window's firstResponder), the event's passed directly to it // via its keyDown: method - (BOOL) ppGSPatch_DisableMenuKeysDuringTextEntry_PerformKeyEquivalent: (NSEvent *) theEvent { static NSUInteger disallowedFieldEditorModifierFlags = NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask; if (([theEvent type] == NSKeyDown) && !([theEvent modifierFlags] & disallowedFieldEditorModifierFlags)) { NSText *fieldEditor = [self fieldEditor: NO forObject: nil]; if (fieldEditor && (fieldEditor == [self firstResponder])) { [fieldEditor keyDown: theEvent]; return YES; } } return [self ppGSPatch_DisableMenuKeysDuringTextEntry_PerformKeyEquivalent: theEvent]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_DocumentAutosaving.m0000644000076500000240000001733013234421465024644 0ustar joshstaff/* PPGNUstepGlue_DocumentAutosaving.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // 1) Workaround for GNUstep autosave-file-naming conflict: When creating the filename for // for a new autosave file, GNUstep doesn't check whether the filename is already in use by // another document, which can allow two documents to share the same autosave file location, // losing the autosave contents of whichever is less-recently saved; Fixed by patching // -[PPDocument autosavedContentsFileURL] to use a private local method, // ppGSGlue_UniqueAutosaveURL, which checks whether a file already exists at the URL's // location - if so, it tries different filenames until an unused name is found (or until a // maximum number of renaming attempts is reached). // 2) Autosave files now use the same naming & locating scheme as OS X: // ppGSGlue_UniqueAutosaveURL method returns URLs with the same filename as the document (with // an " (Autosaved)" suffix appended), and in the document's directory. #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPDocument.h" #import "PPUserFolderPaths.h" #define kAutosaveFolderName @"Autosave" #define kAutosaveFilenameSuffix @" (Autosaved)" #define kMaxAutosaveFileRenameAttempts 100 static NSString *DefaultAutosaveDirectory(void); static bool gIsAutosavingDocument = NO; @interface PPDocument (PPGNUstepGlue_DocumentAutosavingUtilities) - (NSURL *) ppGSGlue_UniqueAutosaveURL; @end @implementation NSObject (PPGNUstepGlue_DocumentAutosaving) + (void) ppGSGlue_DocumentAutosaving_InstallPatches { macroSwizzleInstanceMethod(PPDocument, autosaveDocumentWithDelegate:didAutosaveSelector: contextInfo:, ppGSPatch_AutosaveDocumentWithDelegate:didAutosaveSelector: contextInfo:); macroSwizzleInstanceMethod(PPDocument, autosavedContentsFileURL, ppGSPatch_AutosavedContentsFileURL); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_DocumentAutosaving_InstallPatches); } @end @implementation PPDocument (PPGNUstepGlue_DocumentAutosaving) - (void) ppGSPatch_AutosaveDocumentWithDelegate: (id) delegate didAutosaveSelector: (SEL) didAutosaveSelector contextInfo: (void *) context { gIsAutosavingDocument = YES; [self ppGSPatch_AutosaveDocumentWithDelegate: delegate didAutosaveSelector: didAutosaveSelector contextInfo: context]; gIsAutosavingDocument = NO; } - (NSURL *) ppGSPatch_AutosavedContentsFileURL { NSURL *autosaveFileURL = [self ppGSPatch_AutosavedContentsFileURL]; if (!autosaveFileURL && gIsAutosavingDocument) { autosaveFileURL = [self ppGSGlue_UniqueAutosaveURL]; } return autosaveFileURL; } - (NSURL *) ppGSGlue_UniqueAutosaveURL { NSFileManager *fileManager; NSString *documentPath, *autosaveRootFilename, *autosaveFileDirectory, *autosavingFileType, *autosaveFileExtension, *workingFilename, *autosavePath; int numRenameAttempts; fileManager = [NSFileManager defaultManager]; documentPath = [self fileName]; if ([documentPath length]) { autosaveRootFilename = [[documentPath lastPathComponent] stringByDeletingPathExtension]; autosaveFileDirectory = [documentPath stringByDeletingLastPathComponent]; if (![autosaveFileDirectory length] || ![fileManager isWritableFileAtPath: autosaveFileDirectory]) { autosaveFileDirectory = nil; } } else { autosaveRootFilename = nil; autosaveFileDirectory = nil; } if (!autosaveFileDirectory) { static NSString *defaultAutosaveDirectory = nil; if (!defaultAutosaveDirectory) { defaultAutosaveDirectory = [DefaultAutosaveDirectory() retain]; if (!defaultAutosaveDirectory) goto ERROR; } autosaveFileDirectory = defaultAutosaveDirectory; } if (![autosaveRootFilename length]) { autosaveRootFilename = [self displayName]; if (![autosaveRootFilename length]) { goto ERROR; } } autosaveRootFilename = [autosaveRootFilename stringByAppendingString: kAutosaveFilenameSuffix]; if (!autosaveRootFilename) goto ERROR; autosavingFileType = [self autosavingFileType]; if (!autosavingFileType) goto ERROR; autosaveFileExtension = [self fileNameExtensionForType: autosavingFileType saveOperation: NSAutosaveOperation]; if (![autosaveFileExtension length]) { goto ERROR; } workingFilename = [autosaveRootFilename stringByAppendingPathExtension: autosaveFileExtension]; if (!workingFilename) goto ERROR; autosavePath = [autosaveFileDirectory stringByAppendingPathComponent: workingFilename]; numRenameAttempts = 0; while (autosavePath && [fileManager fileExistsAtPath: autosavePath]) { autosavePath = nil; numRenameAttempts++; if (numRenameAttempts < kMaxAutosaveFileRenameAttempts) { workingFilename = [[NSString stringWithFormat: @"%@-%d", autosaveRootFilename, numRenameAttempts] stringByAppendingPathExtension: autosaveFileExtension]; if (!workingFilename) goto ERROR; autosavePath = [autosaveFileDirectory stringByAppendingPathComponent: workingFilename]; } } if (!autosavePath) goto ERROR; return [NSURL fileURLWithPath: autosavePath]; ERROR: return nil; } @end static NSString *DefaultAutosaveDirectory(void) { static bool didFailPreviously = NO; NSString *defaultAutosaveDirectory; NSFileManager *fileManager; BOOL isDirectory; if (didFailPreviously) goto ERROR; defaultAutosaveDirectory = [PPUserFolderPaths_ApplicationSupport() stringByAppendingPathComponent: kAutosaveFolderName]; if (![defaultAutosaveDirectory length]) { goto ERROR; } fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath: defaultAutosaveDirectory isDirectory: &isDirectory]) { if (![fileManager createDirectoryAtPath: defaultAutosaveDirectory withIntermediateDirectories: YES attributes: nil error: NULL]) { goto ERROR; } } else if (!isDirectory) { goto ERROR; } return defaultAutosaveDirectory; ERROR: didFailPreviously = YES; return nil; } #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_DocumentSheets.m0000644000076500000240000000520613234416764023764 0ustar joshstaff/* PPGNUstepGlue_DocumentSheets.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPDocumentSheetController.h" // Sheet header textfields that are the minimum correct size on OS X can crop their text // when displayed on GNUstep (bold system-font on GS is slightly bigger?), so manually increase // header textfield width #define kSheetHeaderTextFieldWidthPadding 25 @implementation NSObject (PPGNUstepGlue_DocumentSheets) + (void) ppGSGlue_DocumentSheets_InstallPatches { macroSwizzleInstanceMethod(PPDocumentSheetController, initWithNibNamed:delegate:, ppGSPatch_InitWithNibNamed:delegate:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_DocumentSheets_InstallPatches); } @end @implementation PPDocumentSheetController (PPGNUstepGlue_DocumentSheets) - ppGSPatch_InitWithNibNamed: (NSString *) nibName delegate: (id) delegate { self = [self ppGSPatch_InitWithNibNamed: nibName delegate: delegate]; if (self) { NSArray *controlViews = [[_sheet contentView] subviews]; NSEnumerator *controlViewsEnumerator = [controlViews objectEnumerator]; NSView *controlView; Class textFieldClass = [NSTextField class]; while (controlView = [controlViewsEnumerator nextObject]) { if ([controlView isKindOfClass: textFieldClass]) { NSRect controlFrame = [controlView frame]; controlFrame.size.width += kSheetHeaderTextFieldWidthPadding; [controlView setFrame: controlFrame]; } } [_sheet setTitle: @""]; } return self; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_DocumentWindow.m0000644000076500000240000001773413234416764024011 0ustar joshstaff/* PPGNUstepGlue_DocumentWindow.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds for several issues with PPDocumentWindows on GNUstep: // - PPDocumentWindows can become main without also becoming key (when a PPDocumentWindow // closes, key status might go to a panel instead of the now-main next PPDocumentWindow) // - A mouseclick on a background PPDocumentWindow that brings it to the front will also // register as a tool click on its canvas (ignores acceptsFirstMouse, which defaults to NO) // - When closing a PPDocumentWindow, its delegate doesn't receive the final // windowDidResignKey: & windowDidResignMain: messages // - GNUstep intercepts some events after they reach PPDocumentWindow, before they reach the // window's PPCanvasView #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPDocumentWindow.h" #import "PPDocumentWindowController.h" #import "NSWindow_PPUtilities.h" #define kTimeIntervalForIgnoringMouseDownEventsAfterBecomingKeyOrMainWindow (0.3f) static NSDate *gCutoffDateForIgnoringMouseDownEvents = nil; static void DequeueNextMouseDownEvent(void); static void SetupCutoffDateForIgnoringMouseDownEventsAfterBecomingKeyOrMain(void); static void ClearCutoffDateForIgnoringMouseDownEvents(void); @implementation NSObject (PPGNUstepGlue_DocumentWindow) + (void) ppGSGlue_DocumentWindow_InstallPatches { macroSwizzleInstanceMethod(PPDocumentWindow, becomeMainWindow, ppGSPatch_BecomeMainWindow); macroSwizzleInstanceMethod(PPDocumentWindow, becomeKeyWindow, ppGSPatch_BecomeKeyWindow); macroSwizzleInstanceMethod(PPDocumentWindow, close, ppGSPatch_Close); macroSwizzleInstanceMethod(PPDocumentWindow, mouseDown:, ppGSPatch_MouseDown:); macroSwizzleInstanceMethod(PPDocumentWindow, mouseDragged:, ppGSPatch_MouseDragged:); macroSwizzleInstanceMethod(PPDocumentWindow, mouseUp:, ppGSPatch_MouseUp:); macroSwizzleInstanceMethod(PPDocumentWindow, keyDown:, ppGSPatch_KeyDown:); macroSwizzleInstanceMethod(PPDocumentWindow, keyUp:, ppGSPatch_KeyUp:); macroSwizzleInstanceMethod(PPDocumentWindow, flagsChanged:, ppGSPatch_FlagsChanged:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_DocumentWindow_InstallPatches); } @end @implementation PPDocumentWindow (PPGNUstepGlue_DocumentWindow) // PATCH: -[PPDocumentWindow becomeMainWindow] // Workarounds for two issues: // - PPDocumentWindows can become main without also becoming key, so the patch forces the // window to become key // - A mouseclick on a background PPDocumentWindow that brings it to the front will also // register as a tool click on its canvas, so the patch dequeues the next mouseDown event (if // there is one), and sets up a cutoff date for ignoring subsequent mouseDown events, checked // within -[PPDocumentWindow ppGSPatch_MouseDown:] // // (Need to deal with mouseclicks in becomeMainWindow patch in addition to becomeKeyWindow // patch below, because becomeMain... is called later than becomeKey..., so cutoff date should // be set up at latest possible time - also, DequeueNextMouseDownEvent() can't be called from // within becomeKey...). - (void) ppGSPatch_BecomeMainWindow { [self ppGSPatch_BecomeMainWindow]; [self ppMakeKeyWindowIfMain]; DequeueNextMouseDownEvent(); // Sometimes the mouseDown event hasn't been enqueued yet, so also ignore subsequent // mouseDown events for a short interval SetupCutoffDateForIgnoringMouseDownEventsAfterBecomingKeyOrMain(); } // PATCH: -[PPDocumentWindow becomeKeyWindow] // - A mouseclick on a non-key PPDocumentWindow that makes it key will also register as a tool // click on its canvas, so set up a cutoff date for ignoring subsequent mouseDown events, // checked within -[PPDocumentWindow ppGSPatch_MouseDown:] // // (Can't call DequeueNextMouseDownEvent(), as in the becomeMainWindow patch above, because it // will block mouse clicks on panels - panels briefly become key when clicked, then return key // to the main PPDocumentWindow before the panel's mouseclick event is processed). - (void) ppGSPatch_BecomeKeyWindow { [self ppGSPatch_BecomeKeyWindow]; SetupCutoffDateForIgnoringMouseDownEventsAfterBecomingKeyOrMain(); } // PATCH: -[PPDocumentWindow close] // When closing a GNUstep window, its delegate (in this case, the window's controller) is // cleared before the window sends its final windowDidResignKey: & windowDidResignMain: // messages, so the patch manually sends those messages to the window controller - (void) ppGSPatch_Close { PPDocumentWindowController *windowController = [self windowController]; if ([self isKeyWindow]) { [windowController windowDidResignKey: nil]; } if ([self isMainWindow]) { [windowController windowDidResignMain: nil]; } [self ppGSPatch_Close]; } // PATCHES: -[PPDocumentWindow mouseDown:] // -[PPDocumentWindow mouseDragged:] // -[PPDocumentWindow mouseUp:] // -[PPDocumentWindow keyDown:] // -[PPDocumentWindow keyUp:] // -[PPDocumentWindow flagsChanged:] // // GNUstep's NSWindow event handling methods can prevent events from reaching the canvas view // (intercepted by backing window?), so event handler patches manually forward the event to the // next responder; // The mouseDown: patch also checks whether mouseDown events should currently be ignored // (during a short interval after the window becomes main, to prevent a click that brings a // window to focus from also registering as a tool click on the canvas) - (void) ppGSPatch_MouseDown: (NSEvent *) theEvent { if (gCutoffDateForIgnoringMouseDownEvents) { if ([gCutoffDateForIgnoringMouseDownEvents timeIntervalSinceNow] > 0.0f) { return; } else { ClearCutoffDateForIgnoringMouseDownEvents(); } } [[self nextResponder] mouseDown: theEvent]; } - (void) ppGSPatch_MouseDragged: (NSEvent *) theEvent { [[self nextResponder] mouseDragged: theEvent]; } - (void) ppGSPatch_MouseUp: (NSEvent *) theEvent { [[self nextResponder] mouseUp: theEvent]; } - (void) ppGSPatch_KeyDown: (NSEvent *) theEvent { [[self nextResponder] keyDown: theEvent]; } - (void) ppGSPatch_KeyUp: (NSEvent *) theEvent { [[self nextResponder] keyUp: theEvent]; } - (void) ppGSPatch_FlagsChanged: (NSEvent *) theEvent { [[self nextResponder] flagsChanged: theEvent]; } @end static void DequeueNextMouseDownEvent(void) { [NSApp nextEventMatchingMask: NSLeftMouseDownMask untilDate: nil inMode: NSEventTrackingRunLoopMode dequeue: YES]; } static void SetupCutoffDateForIgnoringMouseDownEventsAfterBecomingKeyOrMain(void) { [gCutoffDateForIgnoringMouseDownEvents release]; gCutoffDateForIgnoringMouseDownEvents = [[NSDate dateWithTimeIntervalSinceNow: kTimeIntervalForIgnoringMouseDownEventsAfterBecomingKeyOrMainWindow] retain]; } static void ClearCutoffDateForIgnoringMouseDownEvents(void) { [gCutoffDateForIgnoringMouseDownEvents release]; gCutoffDateForIgnoringMouseDownEvents = nil; } #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ImageRecacheSpeedups.m0000644000076500000240000001554713234416764025051 0ustar joshstaff/* PPGNUstepGlue_ImageRecacheSpeedups.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPDocumentLayer.h" #import "PPDocument_Notifications.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" // An NSImage with no cached native-format representations (such as an image that hasn't been // drawn yet or an image that's been sent an -[NSImage recache] message) needs a native-format // representation to be generated (internally) before it can be drawn to a graphics context. // The native-format representation is always generated for the entire image (and it's // relatively slow to generate on GNUstep, compared to OS X), even when only a small part of // the image is being drawn to the graphics context. It's also inefficient to delete & // regenerate the entire native representation when only a small part of the image's source // bitmap representation has changed (such as when dragging a drawing tool). // Workaround/speedup intercepts recache messages to prevent the cached native representation // from being deleted & regenerated, and instead updates the cached native representation // directly by drawing the updated area of the source bitmap representation onto it. (NSImage's // lockFocus sets the image's native representation to be the target graphics context). // For now, disable patch of -[PPDocument recacheDissolvedDrawingLayerThumbnailImageInBounds:], // because _dissolvedDrawingLayerThumbnailImage is currently only drawn in one place: on the // navigator popup when the canvas' view mode is set to draw-layer-only. // The recache speedup patch is most useful on images that are redrawn often, but the // additional slowdown (updating the native representation each time the image is recached) // probably isn't worth it for a rarely-drawn image like _dissolvedDrawingLayerThumbnailImage. #define SHOULD_PATCH_PPDOCUMENT_RECACHEDISSOLVEDDRAWINGLAYERTHUMBNAILIMAGEINBOUNDS (false) @implementation NSObject (PPGNUstepGlue_ImageRecacheSpeedups) + (void) ppGSGlue_ImageRecacheSpeedups_InstallPatches { macroSwizzleInstanceMethod(PPDocument, recacheMergedVisibleLayersThumbnailImageInBounds:, ppGSPatch_RecacheMergedVisibleLayersThumbnailImageInBounds:); #if SHOULD_PATCH_PPDOCUMENT_RECACHEDISSOLVEDDRAWINGLAYERTHUMBNAILIMAGEINBOUNDS macroSwizzleInstanceMethod(PPDocument, recacheDissolvedDrawingLayerThumbnailImageInBounds:, ppGSPatch_RecacheDissolvedDrawingLayerThumbnailImageInBounds:); #endif // SHOULD_PATCH_PPDOCUMENT_RECACHEDISSOLVEDDRAWINGLAYERTHUMBNAILIMAGEINBOUNDS macroSwizzleInstanceMethod(PPDocument, handleUpdateToInteractiveMoveTargetBitmapInBounds:, ppGSPatch_HandleUpdateToInteractiveMoveTargetBitmapInBounds:); macroSwizzleInstanceMethod(PPCanvasView, recacheZoomedVisibleCanvasImageInBounds:, ppGSPatch_RecacheZoomedVisibleCanvasImageInBounds:); macroSwizzleInstanceMethod(PPDocumentLayer, handleUpdateToBitmapInRect:, ppGSPatch_HandleUpdateToBitmapInRect:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ImageRecacheSpeedups_InstallPatches); } @end @implementation PPDocument (PPGNUstepGlue_ImageRecacheSpeedups) - (void) ppGSPatch_RecacheMergedVisibleLayersThumbnailImageInBounds: (NSRect) bounds { if (NSIsEmptyRect(bounds)) { return; } [_mergedVisibleLayersThumbnailImage lockFocus]; [[_mergedVisibleLayersBitmap ppShallowDuplicateFromBounds: bounds] drawInRect: bounds]; [_mergedVisibleLayersThumbnailImage unlockFocus]; } #if SHOULD_PATCH_PPDOCUMENT_RECACHEDISSOLVEDDRAWINGLAYERTHUMBNAILIMAGEINBOUNDS - (void) ppGSPatch_RecacheDissolvedDrawingLayerThumbnailImageInBounds: (NSRect) bounds { if (NSIsEmptyRect(bounds)) { return; } [_dissolvedDrawingLayerThumbnailImage lockFocus]; [[_dissolvedDrawingLayerBitmap ppShallowDuplicateFromBounds: bounds] drawInRect: bounds]; [_dissolvedDrawingLayerThumbnailImage unlockFocus]; } #endif // SHOULD_PATCH_PPDOCUMENT_RECACHEDISSOLVEDDRAWINGLAYERTHUMBNAILIMAGEINBOUNDS - (void) ppGSPatch_HandleUpdateToInteractiveMoveTargetBitmapInBounds: (NSRect) bounds { if (NSIsEmptyRect(bounds)) { return; } if (_interactiveMoveDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { [_drawingLayer handleUpdateToBitmapInRect: bounds]; [self handleUpdateToLayerAtIndex: _indexOfDrawingLayer inRect: bounds]; } else { // patch replaces original method's call to [_mergedVisibleLayersThumbnailImage recache] [_mergedVisibleLayersThumbnailImage lockFocus]; [[_mergedVisibleLayersBitmap ppShallowDuplicateFromBounds: bounds] drawInRect: bounds]; [_mergedVisibleLayersThumbnailImage unlockFocus]; [self postNotification_UpdatedMergedVisibleAreaInRect: bounds]; } } @end @implementation PPCanvasView (PPGNUstepGlue_ImageRecacheSpeedups) - (void) ppGSPatch_RecacheZoomedVisibleCanvasImageInBounds: (NSRect) bounds { if (NSIsEmptyRect(bounds)) { return; } [_zoomedVisibleCanvasImage lockFocus]; [[_zoomedVisibleCanvasBitmap ppShallowDuplicateFromBounds: bounds] drawInRect: bounds]; [_zoomedVisibleCanvasImage unlockFocus]; } @end @implementation PPDocumentLayer (PPGNUstepGlue_ImageRecacheSpeedups) - (void) ppGSPatch_HandleUpdateToBitmapInRect: (NSRect) updateRect { updateRect = NSIntersectionRect(PPGeometry_OriginRectOfSize(_size), updateRect); if (NSIsEmptyRect(updateRect)) { return; } [_image lockFocus]; [[_bitmap ppShallowDuplicateFromBounds: updateRect] drawInRect: updateRect]; [_image unlockFocus]; if (_linearBlendingBitmap) { [_linearBlendingBitmap ppLinearCopyFromImageBitmap: _bitmap inBounds: updateRect]; } } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_KeyCancellableWindow.m0000644000076500000240000000725713234416764025070 0ustar joshstaff/* PPGNUstepGlue_KeyCancellableWindow.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds for issues affecting PPKeyCancellableWindows on GNUstep: // - Windows loaded from nibs don't automatically set up their default button // - When using Win95 interface style, embedded menubars would appear on PPKeyCancellableWindows #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPKeyCancellableWindow.h" @implementation NSObject (PPGNUstepGlue_KeyCancellableWindow) + (void) ppGSGlue_KeyCancellableWindow_InstallPatches { macroSwizzleInstanceMethod(PPKeyCancellableWindow, awakeFromNib, ppGSPatch_AwakeFromNib); macroSwizzleInstanceMethod(PPKeyCancellableWindow, canBecomeMainWindow, ppGSPatch_CanBecomeMainWindow); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_KeyCancellableWindow_InstallPatches); } @end @implementation PPKeyCancellableWindow (PPGNUstepGlue_KeyCancellableWindow) // PATCH: -[PPKeyCancellableWindow awakeFromNib] // On GNUstep, windows loaded from nibs don't set up their default button (if it exists), so // the 'default' button looks the same as other buttons (no return-key icon). // Besides open/save panels (where the default button is set up correctly), default buttons // only appear in PikoPixel on PPKeyCancellableWindows, so patched this class directly instead // of NSWindow. (Sometimes there's issues inheriting patches from parent classes on GCC). // The patch manually sets up the window's default button by searching the window's top-level // views for a button with a return-key key-equivalent. #define kKeyEquivalent_DefaultButton @"\r" - (void) ppGSPatch_AwakeFromNib { Class buttonClass; NSEnumerator *viewEnumerator; NSView *view; NSButton *button; bool didSetDefaultButton = NO; [self ppGSPatch_AwakeFromNib]; buttonClass = [NSButton class]; viewEnumerator = [[[self contentView] subviews] objectEnumerator]; while (!didSetDefaultButton && (view = [viewEnumerator nextObject])) { if ([view isKindOfClass: buttonClass]) { button = (NSButton *) view; if ([[button keyEquivalent] isEqualToString: kKeyEquivalent_DefaultButton] && ![button keyEquivalentModifierMask]) { [self setDefaultButtonCell: [button cell]]; didSetDefaultButton = YES; } } } } // PATCH: -[PPKeyCancellableWindow canBecomeMainWindow] // When using Win95 interface style, embedded menubars would appear on PPKeyCancellableWindows. // Patching canBecomeMainWindow to return NO prevents GNUstep from embedding a window menubar. - (BOOL) ppGSPatch_CanBecomeMainWindow { return NO; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_KeyUpEvents.m0000644000076500000240000003262113234416764023255 0ustar joshstaff/* PPGNUstepGlue_KeyUpEvents.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPDocumentWindowController.h" #import "PPScreencastController.h" #import "PPHotkeys.h" #import "PPCanvasView.h" #define kKeyDownTimeoutInterval (3.0) #define kKeyUpTimeoutInterval (0.1) #define kKeyUpCheckTimerInterval (0.03) #define kKeyUpCheckSystemLagInterval (kKeyUpCheckTimerInterval + 0.015) #define kNumKeyUpChecksToSkipAfterSystemLag 3 static NSEvent *gKeyUpEvent_PopupHotkey = nil, *gKeyUpEvent_BlinkLayersHotkey = nil; static NSDate *gKeyUpDate_LastCheckTimerFire = nil, *gKeyUpDate_PopupHotkey = nil, *gKeyUpDate_BlinkLayersHotkey = nil; static bool gKeyUpCheckTimerIsRunning = NO; @interface PPDocumentWindowController (PPGNUstepGlue_KeyUpEventsUtilities) - (void) ppGSGlue_StartKeyUpCheckTimer; - (void) ppGSGlue_StopKeyUpCheckTimer: (NSTimer *) keyUpCheckTimer; - (void) ppGSGlue_KeyUpCheckTimerDidFire: (NSTimer *) timer; - (void) ppGSGlue_ClearKeyUpGlobals_PopupHotkey; - (void) ppGSGlue_ClearKeyUpGlobals_BlinkLayersHotkey; - (void) ppGSGlue_ClearKeyUpGlobals_AllHotkeys; @end #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING typedef struct { NSString *key; NSDate *date; } PPKeyUpDate; static NSDate *gScreencastKeyUpDate_LastCheckTimerFire = nil; static bool gScreencastKeyUpCheckTimerIsRunning = NO; static PPKeyUpDate gScreencastKeyUpDates[kScreencastMaxSimultaneousKeysAllowed]; static int gNumScreencastKeyUpDates = 0; @interface PPScreencastController (PPGNUstepGlue_KeyUpEventsUtilities) - (void) ppGSGlue_SetKeyUpDate: (NSDate *) date forKey: (NSString *) key; - (void) ppGSGlue_StartScreencastKeyUpCheckTimer; - (void) ppGSGlue_StopScreencastKeyUpCheckTimer: (NSTimer *) keyUpCheckTimer; - (void) ppGSGlue_ScreencastKeyUpCheckTimerDidFire: (NSTimer *) timer; @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING @implementation NSObject (PPGNUstepGlue_KeyUpEvents) + (void) ppGSGlue_KeyUpEvents_InstallPatches { macroSwizzleInstanceMethod(PPDocumentWindowController, keyDown:, ppGSPatch_KeyDown:); macroSwizzleInstanceMethod(PPDocumentWindowController, keyUp:, ppGSPatch_KeyUp:); #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING macroSwizzleInstanceMethod(PPScreencastController, handleKeyDown:, ppGSPatch_HandleKeyDown:); macroSwizzleInstanceMethod(PPScreencastController, handleKeyUp:, ppGSPatch_HandleKeyUp:); #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_KeyUpEvents_InstallPatches); } @end @implementation PPDocumentWindowController (PPGNUstepGlue_KeyUpEvents) - (void) ppGSPatch_KeyDown: (NSEvent *) theEvent { [self ppGSPatch_KeyDown: theEvent]; if (gKeyUpCheckTimerIsRunning) { NSString *eventChars = [theEvent charactersIgnoringModifiers]; if (gKeyUpEvent_PopupHotkey && _pressedHotkeyForActivePopupPanel && [eventChars rangeOfString: _pressedHotkeyForActivePopupPanel].length) { [gKeyUpDate_PopupHotkey release]; gKeyUpDate_PopupHotkey = [[NSDate dateWithTimeIntervalSinceNow: kKeyDownTimeoutInterval] retain]; } if (gKeyUpEvent_BlinkLayersHotkey && [eventChars rangeOfString: gHotkeys[kPPHotkeyType_BlinkDocumentLayers]].length && [_canvasView documentLayersAreHidden]) { [gKeyUpDate_BlinkLayersHotkey release]; gKeyUpDate_BlinkLayersHotkey = [[NSDate dateWithTimeIntervalSinceNow: kKeyDownTimeoutInterval] retain]; } } } - (void) ppGSPatch_KeyUp: (NSEvent *) theEvent { bool runKeyUpCheckTimer = NO; NSString *eventChars = [theEvent charactersIgnoringModifiers]; if (_pressedHotkeyForActivePopupPanel && [eventChars rangeOfString: _pressedHotkeyForActivePopupPanel].length) { [self ppGSGlue_ClearKeyUpGlobals_PopupHotkey]; gKeyUpEvent_PopupHotkey = [theEvent retain]; gKeyUpDate_PopupHotkey = [[NSDate date] retain]; runKeyUpCheckTimer = YES; } if ([eventChars rangeOfString: gHotkeys[kPPHotkeyType_BlinkDocumentLayers]].length && [_canvasView documentLayersAreHidden]) { [self ppGSGlue_ClearKeyUpGlobals_BlinkLayersHotkey]; gKeyUpEvent_BlinkLayersHotkey = [theEvent retain]; gKeyUpDate_BlinkLayersHotkey = [[NSDate date] retain]; runKeyUpCheckTimer = YES; } if (runKeyUpCheckTimer && !gKeyUpCheckTimerIsRunning) { [self ppGSGlue_StartKeyUpCheckTimer]; } } - (void) ppGSGlue_StartKeyUpCheckTimer { NSTimer *keyUpCheckTimer; if (gKeyUpCheckTimerIsRunning) return; keyUpCheckTimer = [NSTimer scheduledTimerWithTimeInterval: kKeyUpCheckTimerInterval target: self selector: @selector(ppGSGlue_KeyUpCheckTimerDidFire:) userInfo: nil repeats: YES]; gKeyUpCheckTimerIsRunning = (keyUpCheckTimer) ? YES : NO; [gKeyUpDate_LastCheckTimerFire release]; gKeyUpDate_LastCheckTimerFire = [[NSDate date] retain]; } - (void) ppGSGlue_StopKeyUpCheckTimer: (NSTimer *) keyUpCheckTimer { if (!keyUpCheckTimer || !gKeyUpCheckTimerIsRunning) { return; } [keyUpCheckTimer invalidate]; gKeyUpCheckTimerIsRunning = NO; } - (void) ppGSGlue_KeyUpCheckTimerDidFire: (NSTimer *) timer { static bool systemIsLagging = NO; static int numTimeoutChecksToSkip = 0; NSTimeInterval timeIntervalSinceLastFire; if (![[self window] isKeyWindow]) { systemIsLagging = NO; numTimeoutChecksToSkip = 0; [self ppGSGlue_ClearKeyUpGlobals_AllHotkeys]; [self ppGSGlue_StopKeyUpCheckTimer: timer]; return; } timeIntervalSinceLastFire = -[gKeyUpDate_LastCheckTimerFire timeIntervalSinceNow]; [gKeyUpDate_LastCheckTimerFire release]; gKeyUpDate_LastCheckTimerFire = [[NSDate date] retain]; if ((timeIntervalSinceLastFire > kKeyUpCheckSystemLagInterval) && !systemIsLagging) { systemIsLagging = YES; numTimeoutChecksToSkip = kNumKeyUpChecksToSkipAfterSystemLag; } if (numTimeoutChecksToSkip) { numTimeoutChecksToSkip--; return; } systemIsLagging = NO; if (gKeyUpEvent_PopupHotkey && (-[gKeyUpDate_PopupHotkey timeIntervalSinceNow] > kKeyUpTimeoutInterval)) { if (_pressedHotkeyForActivePopupPanel) { [self ppGSPatch_KeyUp: gKeyUpEvent_PopupHotkey]; } [self ppGSGlue_ClearKeyUpGlobals_PopupHotkey]; } if (gKeyUpEvent_BlinkLayersHotkey && (-[gKeyUpDate_BlinkLayersHotkey timeIntervalSinceNow] > kKeyUpTimeoutInterval)) { if ([_canvasView documentLayersAreHidden]) { [self ppGSPatch_KeyUp: gKeyUpEvent_BlinkLayersHotkey]; } [self ppGSGlue_ClearKeyUpGlobals_BlinkLayersHotkey]; } if (!gKeyUpEvent_PopupHotkey && !gKeyUpEvent_BlinkLayersHotkey) { [self ppGSGlue_StopKeyUpCheckTimer: timer]; } } - (void) ppGSGlue_ClearKeyUpGlobals_PopupHotkey { [gKeyUpEvent_PopupHotkey release]; gKeyUpEvent_PopupHotkey = nil; [gKeyUpDate_PopupHotkey release]; gKeyUpDate_PopupHotkey = nil; } - (void) ppGSGlue_ClearKeyUpGlobals_BlinkLayersHotkey { [gKeyUpEvent_BlinkLayersHotkey release]; gKeyUpEvent_BlinkLayersHotkey = nil; [gKeyUpDate_BlinkLayersHotkey release]; gKeyUpDate_BlinkLayersHotkey = nil; } - (void) ppGSGlue_ClearKeyUpGlobals_AllHotkeys { [self ppGSGlue_ClearKeyUpGlobals_PopupHotkey]; [self ppGSGlue_ClearKeyUpGlobals_BlinkLayersHotkey]; } @end #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING @implementation PPScreencastController (PPGNUstepGlue_KeyUpEvents) - (bool) ppGSPatch_HandleKeyDown: (NSString *) key { [self ppGSGlue_SetKeyUpDate: [NSDate dateWithTimeIntervalSinceNow: kKeyDownTimeoutInterval] forKey: key]; return [self ppGSPatch_HandleKeyDown: key]; } - (bool) ppGSPatch_HandleKeyUp: (NSString *) key { [self ppGSGlue_SetKeyUpDate: [NSDate date] forKey: key]; return NO; } - (void) ppGSGlue_SetKeyUpDate: (NSDate *) date forKey: (NSString *) key { int keyUpDateIndex; if (![key length]) { return; } for (keyUpDateIndex=0; keyUpDateIndex 0) && !gScreencastKeyUpCheckTimerIsRunning) { [self ppGSGlue_StartScreencastKeyUpCheckTimer]; } } - (void) ppGSGlue_StartScreencastKeyUpCheckTimer { NSTimer *keyUpCheckTimer; if (gScreencastKeyUpCheckTimerIsRunning) return; keyUpCheckTimer = [NSTimer scheduledTimerWithTimeInterval: kKeyUpCheckTimerInterval target: self selector: @selector(ppGSGlue_ScreencastKeyUpCheckTimerDidFire:) userInfo: nil repeats: YES]; gScreencastKeyUpCheckTimerIsRunning = (keyUpCheckTimer) ? YES : NO; [gScreencastKeyUpDate_LastCheckTimerFire release]; gScreencastKeyUpDate_LastCheckTimerFire = [[NSDate date] retain]; } - (void) ppGSGlue_StopScreencastKeyUpCheckTimer: (NSTimer *) keyUpCheckTimer { if (!keyUpCheckTimer || !gScreencastKeyUpCheckTimerIsRunning) { return; } [keyUpCheckTimer invalidate]; gScreencastKeyUpCheckTimerIsRunning = NO; } - (void) ppGSGlue_ScreencastKeyUpCheckTimerDidFire: (NSTimer *) timer { static bool systemIsLagging = NO; static int numTimeoutChecksToSkip = 0; NSTimeInterval timeIntervalSinceLastFire; int keyUpDateIndex; bool needToUpdateScreencastPopupStateString = NO; timeIntervalSinceLastFire = -[gScreencastKeyUpDate_LastCheckTimerFire timeIntervalSinceNow]; [gScreencastKeyUpDate_LastCheckTimerFire release]; gScreencastKeyUpDate_LastCheckTimerFire = [[NSDate date] retain]; if ((timeIntervalSinceLastFire > kKeyUpCheckSystemLagInterval) && !systemIsLagging) { systemIsLagging = YES; numTimeoutChecksToSkip = kNumKeyUpChecksToSkipAfterSystemLag; } if (numTimeoutChecksToSkip) { numTimeoutChecksToSkip--; return; } systemIsLagging = NO; for (keyUpDateIndex=0; keyUpDateIndex kKeyUpTimeoutInterval) { needToUpdateScreencastPopupStateString = [self ppGSPatch_HandleKeyUp: gScreencastKeyUpDates[keyUpDateIndex].key]; [self ppGSGlue_SetKeyUpDate: nil forKey: gScreencastKeyUpDates[keyUpDateIndex].key]; } } if (needToUpdateScreencastPopupStateString) { [self performSelector: @selector(updateScreencastPopupStateString)]; } if (!gNumScreencastKeyUpDates) { [self ppGSGlue_StopScreencastKeyUpCheckTimer: timer]; } } @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_LayerControlsPopupMenu.m0000644000076500000240000003110313234416764025476 0ustar joshstaff/* PPGNUstepGlue_LayerControlsPopupMenu.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds for issues affecting the layers popup menu & button on the Layer Controls popup // panel in GNUstep: // - Menu items' images were being drawn on the right side of the menu instead of the left // - Disabled menu items & disabled popup-button titles looked the same as enabled items/titles // (not grayed out, despite the title strings' attributes containing a gray foreground-color // entry) #ifdef GNUSTEP #import #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPLayerControlsPopupPanelController.h" #import "PPUIFontDefines.h" #import "PPTitleablePopUpButton.h" #import "PPDocument.h" #import "PPDocumentLayer.h" #define kLayersPopupMenuItemSignature (0x01234560) #define kLayersPopupMenuItemSignatureMask (0x0FFFFFF0) #define kLayersPopupMenuItemDisabledMask (0x00000001) #define macroTagValueContainsLayersPopupMenuItemSignature(tagValue) \ (((tagValue) & kLayersPopupMenuItemSignatureMask) \ == kLayersPopupMenuItemSignature) #define macroTagValueContainsDisabledFlag(tagValue) \ ((tagValue) & kLayersPopupMenuItemDisabledMask) // If an NSMenuItemCell's instance variable, _mcell_belongs_to_popupbutton, is YES, then // GNUstep displays its image (if it has one) on the right side, regardless of the cell's image // position setting. // In order for items in the layers popup menu to display images on the left, the values of // their _mcell_belongs_to_popupbutton ivars need to be manually set to NO. // Instead of clearing the NSMenuItemCell's ivar directly (which would cause issues if // future versions of GNUstep remove or rename the ivar), the ivar is cleared using the macro, // macroClearNSMenuItemCellIvar__mcell_belongs_to_popupbutton(), which accesses the ivar via // its pointer offset (obtained using the objc runtime api - if unable to find the ivar, its // offset will be zero - and stored in the global var, // gIvarOffset_NSMenuItemCell_mcell_belongs_to_popupbutton). #define macroClearNSMenuItemCellIvar__mcell_belongs_to_popupbutton(menuItemCell) \ if (menuItemCell && gIvarOffset_NSMenuItemCell_mcell_belongs_to_popupbutton) \ { \ unsigned char *menuItemCellPtr = (unsigned char *) menuItemCell; \ BOOL *menuItemCellIvar_mcell_belongs_to_popupbutton = \ (BOOL *) (&menuItemCellPtr[ \ gIvarOffset_NSMenuItemCell_mcell_belongs_to_popupbutton]); \ \ if (*menuItemCellIvar_mcell_belongs_to_popupbutton == YES) \ { \ *menuItemCellIvar_mcell_belongs_to_popupbutton = NO; \ } \ } static int gIvarOffset_NSMenuItemCell_mcell_belongs_to_popupbutton = 0; static NSPopUpButtonCell *gPopUpButtonCellWithDisabledTitle = nil; @interface NSMenuItemCell (PPGNUstepGlue_LayerControlsPopupMenuUtilities) - (NSDictionary *) ppGSGlue_NonAutoreleasedDisabledTextAttributes; @end @implementation NSObject (PPGNUstepGlue_LayerControlsPopupMenu) + (void) ppGSGlue_LayerControlsPopupMenu_SetupGlobals { Ivar ivar_mcell_belongs_to_popupbutton = class_getInstanceVariable([NSMenuItemCell class], "_mcell_belongs_to_popupbutton"); if (ivar_mcell_belongs_to_popupbutton) { gIvarOffset_NSMenuItemCell_mcell_belongs_to_popupbutton = (int) ivar_getOffset(ivar_mcell_belongs_to_popupbutton); } } + (void) ppGSGlue_LayerControlsPopupMenu_InstallPatches { macroSwizzleInstanceMethod(PPLayerControlsPopupPanelController, updateDrawingLayerAttributeControls, ppGSPatch_UpdateDrawingLayerAttributeControls); macroSwizzleInstanceMethod(PPLayerControlsPopupPanelController, updateDrawingLayerPopUpButtonMenu, ppGSPatch_UpdateDrawingLayerPopUpButtonMenu); macroSwizzleInstanceMethod(NSPopUpButtonCell, _nonAutoreleasedTypingAttributes, ppGSPatch_NSPopUpButtonCell__NonAutoreleasedTypingAttributes); macroSwizzleInstanceMethod(NSMenuItemCell, setImagePosition:, ppGSPatch_SetImagePosition:); macroSwizzleInstanceMethod(NSMenuItemCell, _nonAutoreleasedTypingAttributes, ppGSPatch_NSMenuItemCell__NonAutoreleasedTypingAttributes); } + (void) ppGSGlue_LayerControlsPopupMenu_Install { [self ppGSGlue_LayerControlsPopupMenu_SetupGlobals]; [self ppGSGlue_LayerControlsPopupMenu_InstallPatches]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_LayerControlsPopupMenu_Install); } @end @implementation PPLayerControlsPopupPanelController (PPGNUstepGlue_LayerControlsPopupMenu) // PATCH: -[PPLayerControlsPopupPanelController updateDrawingLayerAttributeControls] // This patch & the patch for -[NSPopUpButtonCell _nonAutoreleasedTypingAttributes] implement // the workaround for the layers-popup-button drawing a disabled title the same color as an // enabled title (not grayed out, ignoring the title string's foreground-color attribute). // If the current drawing layer is disabled, this patch stores the layers popup button's cell // in the global, gPopUpButtonCellWithDisabledTitle, which is checked by the // -[NSPopUpButtonCell _nonAutoreleasedTypingAttributes] patch when determining whether to // return normal text attributes or disabled-text attributes. - (void) ppGSPatch_UpdateDrawingLayerAttributeControls { [self ppGSPatch_UpdateDrawingLayerAttributeControls]; if (![_drawingLayerEnabledCheckbox intValue]) { gPopUpButtonCellWithDisabledTitle = [_drawingLayerTitleablePopUpButton cell]; } else { gPopUpButtonCellWithDisabledTitle = nil; } } // PATCH: -[PPLayerControlsPopupPanelController updateDrawingLayerPopUpButtonMenu] // This patch & the patches for -[NSMenuItemCell setImagePosition:] & // -[NSMenuItemCell _nonAutoreleasedTypingAttributes] implement the workaround for the // layers-popup-menu's items' images being drawn on the right side of the menu instead of the // left, and the workaround for disabled layers-popup-button menu-items appearing the same as // enabled items (not grayed out, ignoring the item-titles' string attribute for // foreground-color). // This patch sets the tag values of the popup button menu's items so they can be identified // later by the NSMenuItemCell patches as 1) items belonging to the layers popup menu and // 2) items that are disabled. - (void) ppGSPatch_UpdateDrawingLayerPopUpButtonMenu { NSArray *menuItemArray; int numMenuItems, itemIndex, menuItemTag; NSMenuItem *menuItem; [self ppGSPatch_UpdateDrawingLayerPopUpButtonMenu]; menuItemArray = [[_drawingLayerTitleablePopUpButton menu] itemArray]; numMenuItems = [menuItemArray count]; for (itemIndex=0; itemIndex. */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPLayersPanelController.h" #import "PPLayersTableView.h" #import "PPLayerOpacitySliderCell.h" #define kLayersTableColumnIndex_Name 2 #define kLayersTableColumnIndex_Opacity 3 #define kLayersTableColumnIdentifier_Opacity @"Opacity" static NSTableColumn *gLayersTableColumn_Opacity = nil; @interface PPLayersPanelController (PPGNUstepGlue_LayersTableUtilities) - (void) ppGSGlue_SetupTableHeaderView; - (void) ppGSGlue_SetupOpacitySliderTableColumnGlobals; - (void) ppGSGlue_AdjustTableWidthIfNeeded; @end @implementation NSObject (PPGNUstepGlue_LayersTable) + (void) ppGSGlue_LayersTable_InstallPatches { // Setup (Table header, Sliders globals) macroSwizzleInstanceMethod(PPLayersPanelController, windowDidLoad, ppGSPatch_LayersTable_WindowDidLoad); // Resizing macroSwizzleInstanceMethod(PPLayersTableView, superviewFrameChanged:, ppGSPatch_SuperviewFrameChanged:); // Text editing macroSwizzleInstanceMethod(PPLayersTableView, editColumn:row:withEvent:select:, ppGSPatch_EditColumn:row:withEvent:select:); macroSwizzleInstanceMethod(PPLayersTableView, textDidEndEditing:, ppGSPatch_TextDidEndEditing:); macroSwizzleInstanceMethod(PPLayersPanelController, windowDidResignKey:, ppGSPatch_WindowDidResignKey:); // Sliders macroSwizzleInstanceMethod(PPLayersPanelController, layersTableOpacitySliderMoved:, ppGSPatch_LayersTableOpacitySliderMoved:); macroSwizzleInstanceMethod(PPLayersTableView, mouseDown:, ppGSPatch_MouseDown:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_LayersTable_InstallPatches); } @end @implementation PPLayersPanelController (PPGNUstepGlue_LayersTable_Setup) - (void) ppGSPatch_LayersTable_WindowDidLoad { [self ppGSPatch_LayersTable_WindowDidLoad]; [self ppGSGlue_SetupTableHeaderView]; [self ppGSGlue_SetupOpacitySliderTableColumnGlobals]; [self ppGSGlue_AdjustTableWidthIfNeeded]; } @end @implementation PPLayersTableView (PPGNUstepGlue_LayersTable_Resizing) - (void) ppGSPatch_SuperviewFrameChanged: (NSNotification*) aNotification { [self ppGSPatch_SuperviewFrameChanged: aNotification]; [self sizeToFit]; } @end @implementation PPLayersTableView (PPGNUstepGlue_LayersTable_TextEditing) - (void) ppGSPatch_EditColumn: (NSInteger) columnIndex row: (NSInteger) rowIndex withEvent: (NSEvent *) theEvent select: (BOOL) flag { [self ppGSPatch_EditColumn: columnIndex row: rowIndex withEvent: theEvent select: flag]; if (columnIndex == kLayersTableColumnIndex_Name) { // On some platforms (ARM), double-clicking the layer name to start editing doesn't // automatically make the window key, so do it manually: [[self window] makeKeyWindow]; } } - (void) ppGSPatch_TextDidEndEditing: (NSNotification *) aNotification { // copy notification without userInfo to prevent text movement actions (return, tab) aNotification = [NSNotification notificationWithName: [aNotification name] object: [aNotification object]]; [self ppGSPatch_TextDidEndEditing: aNotification]; } @end @implementation PPLayersPanelController (PPGNUstepGlue_LayersTable_TextEditing) - (void) windowDidResignKey: (NSNotification *) notification { // This NSWindow delegate method is defined here because it's not implemented by // PPLayersPanelController or its ancestors; Undefined methods can't be swizzled, so the // alternative would be to move the contents of ppGSPatch_WindowDidResignKey: here, which // would make this "patch" hard to find if one were only looking at the swizzling calls in // +ppGSGlue_LayersTable_InstallPatches when searching for overridden functionality. } - (void) ppGSPatch_WindowDidResignKey: (NSNotification *) notification { NSWindow *layersPanel = [self window]; NSText *layersTableFieldEditor = [layersPanel fieldEditor: NO forObject: _layersTable]; if (layersTableFieldEditor && (layersTableFieldEditor == [layersPanel firstResponder])) { // layers table doesn't automatically end editing when the panel resigns key, so do it // manually: [layersPanel endEditingFor: _layersTable]; } } @end @implementation PPLayersPanelController (PPGNUstepGlue_LayersTable_Sliders) - (void) ppGSPatch_LayersTableOpacitySliderMoved: (id) sender { NSRect sliderCellFrame; [self ppGSPatch_LayersTableOpacitySliderMoved: sender]; // force slider to redraw immediately while it's being dragged sliderCellFrame = [_layersTable frameOfCellAtColumn: kLayersTableColumnIndex_Opacity row: [_layersTable clickedRow]]; [_layersTable setNeedsDisplayInRect: sliderCellFrame]; [_layersTable displayIfNeeded]; } @end @implementation PPLayersTableView (PPGNUstepGlue_LayersTable_Sliders) - (void) ppGSPatch_MouseDown: (NSEvent *) theEvent { NSPoint clickPoint; NSInteger clickedColumn; clickPoint = [self convertPoint: [theEvent locationInWindow] fromView: nil]; clickedColumn = [self columnAtPoint: clickPoint]; if (clickedColumn == kLayersTableColumnIndex_Opacity) { NSInteger clickedRow; PPLayerOpacitySliderCell *opacitySliderCell; NSRect cellFrame; id tableDataSource; id initialOpacityValue, finalOpacityValue; PPLayersPanelController *layersPanelController; clickedRow = [self rowAtPoint: clickPoint]; opacitySliderCell = (PPLayerOpacitySliderCell *) [self preparedCellAtColumn: clickedColumn row: clickedRow]; cellFrame = [self frameOfCellAtColumn: clickedColumn row: clickedRow]; tableDataSource = [self dataSource]; initialOpacityValue = [tableDataSource tableView: self objectValueForTableColumn: gLayersTableColumn_Opacity row: clickedRow]; [_selectedRowsAtMouseDown release]; _selectedRowsAtMouseDown = [[self selectedRowIndexes] retain]; _clickedColumn = clickedColumn; _clickedRow = clickedRow; layersPanelController = (PPLayersPanelController *) [opacitySliderCell target]; [layersPanelController setTrackingOpacitySliderCell: opacitySliderCell]; [opacitySliderCell trackMouse: theEvent inRect: cellFrame ofView: self untilMouseUp: YES]; [layersPanelController setTrackingOpacitySliderCell: nil]; _clickedColumn = _clickedRow = -1; finalOpacityValue = [tableDataSource tableView: self objectValueForTableColumn: gLayersTableColumn_Opacity row: clickedRow]; if ([initialOpacityValue floatValue] != [finalOpacityValue floatValue]) { // manually update the data source's value so it registers with the document's undo // manager (changing the value during slider dragging did not register undo) [tableDataSource tableView: self setObjectValue: finalOpacityValue forTableColumn: gLayersTableColumn_Opacity row: clickedRow]; } [self setNeedsDisplayInRect: cellFrame]; } else { [self ppGSPatch_MouseDown: theEvent]; } } @end @implementation PPLayersPanelController (PPGNUstepGlue_LayersTableUtilities) - (void) ppGSGlue_SetupTableHeaderView { NSTableHeaderView *headerView; NSRect headerViewFrame; NSView *contentView; headerView = [_layersTable headerView]; if ([headerView superview]) { return; } headerViewFrame = [headerView frame]; contentView = [[self window] contentView]; headerViewFrame.origin = [_canvasDisplayModeButton frame].origin; headerViewFrame.origin.y -= headerViewFrame.size.height; [headerView setFrame: headerViewFrame]; [contentView addSubview: headerView]; [headerView setAutoresizingMask: NSViewMinYMargin]; } - (void) ppGSGlue_SetupOpacitySliderTableColumnGlobals { gLayersTableColumn_Opacity = [_layersTable tableColumnWithIdentifier: kLayersTableColumnIdentifier_Opacity]; } - (void) ppGSGlue_AdjustTableWidthIfNeeded { const float maxAllowedWidthDifference = 0.01; NSView *tableEnclosingScrollView = [_layersTable enclosingScrollView]; CGFloat tableWidth = [_layersTable frame].size.width, tableVisibleWidth = [_layersTable convertRect: [tableEnclosingScrollView bounds] fromView: tableEnclosingScrollView].size.width; float widthDifference = (float) (tableVisibleWidth - tableWidth); if (fabsf(widthDifference) > maxAllowedWidthDifference) { [_layersTable sizeToFit]; } } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_MenuKeyEquivalents.m0000644000076500000240000003015113234421465024617 0ustar joshstaff/* PPGNUstepGlue_MenuKeyEquivalents.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #define kModifierNamesArraySize 16 #define macroModifierNamesIndexForModifierMask(mask) ((mask >> 17) & 0x0F) #define macroModifierMaskForModifierNamesIndex(index) (index << 17) static NSString *gModifierNamesArray[kModifierNamesArraySize]; static void DequeueKeyAutorepeatEventsForKeyChars(NSString *keyChars); static void SetupModifierNamesArray(void); static NSDictionary *KeyToDisplayKeyDict(void); @implementation NSObject (PPGNUstepGlue_MenuKeyEquivalents) + (void) ppGSGlue_MenuKeyEquivalents_InstallPatches { macroSwizzleInstanceMethod(NSMenu, performKeyEquivalent:, ppGSPatch_PerformKeyEquivalent:); macroSwizzleInstanceMethod(NSMenuItemCell, _keyEquivalentString, ppGSPatch_KeyEquivalentString); } + (void) ppGSGlue_MenuKeyEquivalents_Install { SetupModifierNamesArray(); [self ppGSGlue_MenuKeyEquivalents_InstallPatches]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_MenuKeyEquivalents_Install); } @end @implementation NSMenu (PPGNUstepGlue_MenuKeyEquivalents) - (BOOL) ppGSPatch_PerformKeyEquivalent: (NSEvent *) theEvent { static bool isRootCall = YES; BOOL didPerformKeyEquivalent; if (isRootCall) { NSString *eventChars = [theEvent charactersIgnoringModifiers]; // Delete key won't trigger the "Delete" menu item because the item's key equivalent is // the backspace, so substitute the delete key event with a backspace key event if ([eventChars length] && ([eventChars characterAtIndex: 0] == NSDeleteCharacter)) { NSEvent *backspaceKeyEvent = [NSEvent keyEventWithType: [theEvent type] location: [theEvent locationInWindow] modifierFlags: [theEvent modifierFlags] timestamp: [theEvent timestamp] windowNumber: [theEvent windowNumber] context: [theEvent context] characters: @"\b" charactersIgnoringModifiers: @"\b" isARepeat: [theEvent isARepeat] keyCode: [theEvent keyCode]]; if (backspaceKeyEvent) { theEvent = backspaceKeyEvent; } } isRootCall = NO; didPerformKeyEquivalent = [self ppGSPatch_PerformKeyEquivalent: theEvent]; isRootCall = YES; if (didPerformKeyEquivalent) { // after performing a menu item's action by pressing its key-equivalent, clear the // event queue of key-autorepeat events - this is so that when holding down a menu // item's key-equivalent, the automatic repetition of the item's action stops // quickly when the key is released - otherwise, a backlog of key-autorepeat events // can accumulate in the event queue (especially when the item's action is a slow // operation) and the app will temporarily become unresponsive after the key is // released, as the actions triggered by the remaining enqueued key events are // performed DequeueKeyAutorepeatEventsForKeyChars(eventChars); } } else { didPerformKeyEquivalent = [self ppGSPatch_PerformKeyEquivalent: theEvent]; } return didPerformKeyEquivalent; } @end @implementation NSMenuItemCell (PPGNUstepGlue_MenuKeyEquivalents) - (NSString *) ppGSPatch_KeyEquivalentString { static NSDictionary *keyToDisplayKeyDict = nil; static NSCharacterSet *uppercaseLetterCharacterSet = nil; NSMenuItem *menuItem; NSString *key, *displayKey; NSUInteger modifierKeyMask; menuItem = [self menuItem]; key = [menuItem keyEquivalent]; if (!key || ![key length]) { return nil; } modifierKeyMask = [menuItem keyEquivalentModifierMask]; if (!keyToDisplayKeyDict) { keyToDisplayKeyDict = [KeyToDisplayKeyDict() retain]; } if (!uppercaseLetterCharacterSet) { uppercaseLetterCharacterSet = [[NSCharacterSet uppercaseLetterCharacterSet] retain]; } displayKey = [keyToDisplayKeyDict objectForKey: key]; if (displayKey) { key = displayKey; } else if ([key rangeOfCharacterFromSet: uppercaseLetterCharacterSet].length) { modifierKeyMask |= NSShiftKeyMask; } return [gModifierNamesArray[macroModifierNamesIndexForModifierMask(modifierKeyMask)] stringByAppendingString: key]; } @end // DequeueKeyAutorepeatEventsForKeyChars(): // GNUstep currently doesn't set the repeat flag for key events (-[NSEvent isARepeat] always // returns NO), so need to manually determine whether key events are autorepeats (key is // held down) so that autorepeat events can be removed and normal key events (key is pressed & // released) are left alone: // - Group consecutive keyDown events (no keyUp events between them) into a single event // - Ignore keyUp events that are immediately followed by a keyDown event with an identical // timestamp (GNUstep can sometimes post keyUp events while a key is autorepeating, but in that // case, it will also post a second event (keyDown) with no elapsed time since the keyUp) #define kMinTimeBetweenNonAutorepeatKeyUpAndKeyDownEvents 0.005 static void DequeueKeyAutorepeatEventsForKeyChars(NSString *keyChars) { static NSMutableArray *dequeuedEvents = nil; NSUInteger keyEventsMask = NSKeyDownMask | NSKeyUpMask | NSFlagsChanged; NSEvent *dequeuedEvent, *lastDequeuedEvent; int dequeuedEventIndex; if (![keyChars length]) { return; } if (!dequeuedEvents) { dequeuedEvents = [[NSMutableArray array] retain]; if (!dequeuedEvents) return; } [dequeuedEvents removeAllObjects]; dequeuedEvent = [NSApp nextEventMatchingMask: keyEventsMask untilDate: nil inMode: NSEventTrackingRunLoopMode dequeue: YES]; while (dequeuedEvent) { if (![[dequeuedEvent charactersIgnoringModifiers] isEqualToString: keyChars] || ([dequeuedEvent type] == NSFlagsChanged)) { [NSApp postEvent: dequeuedEvent atStart: YES]; dequeuedEvent = nil; } else { [dequeuedEvents addObject: dequeuedEvent]; dequeuedEvent = [NSApp nextEventMatchingMask: keyEventsMask untilDate: nil inMode: NSEventTrackingRunLoopMode dequeue: YES]; } } dequeuedEventIndex = [dequeuedEvents count] - 1; if (dequeuedEventIndex >= 0) { NSEventType lastRequeuedEventType, dequeuedEventType; dequeuedEvent = [dequeuedEvents objectAtIndex: dequeuedEventIndex]; [NSApp postEvent: dequeuedEvent atStart: YES]; lastRequeuedEventType = [dequeuedEvent type]; lastDequeuedEvent = dequeuedEvent; dequeuedEventIndex--; while (dequeuedEventIndex >= 0) { dequeuedEvent = [dequeuedEvents objectAtIndex: dequeuedEventIndex]; dequeuedEventType = [dequeuedEvent type]; if ((lastRequeuedEventType != NSKeyDown) || ((dequeuedEventType == NSKeyUp) && (([lastDequeuedEvent timestamp] - [dequeuedEvent timestamp]) > kMinTimeBetweenNonAutorepeatKeyUpAndKeyDownEvents))) { [NSApp postEvent: dequeuedEvent atStart: YES]; lastRequeuedEventType = dequeuedEventType; } lastDequeuedEvent = dequeuedEvent; dequeuedEventIndex--; } } } static void SetupModifierNamesArray(void) { NSUInteger i, modifierKeyMask; for (i=0; i. */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPPopupPanelsController.h" #import "PPCanvasView.h" bool gHasActivePopupPanel = NO, gIsDraggingTool = NO; @implementation NSObject (PPGNUstepGlue_MenuUpdates) + (void) ppGSGlue_MenuUpdates_InstallPatches { macroSwizzleInstanceMethod(PPPopupPanelsController, setActivePopupPanel:, ppGSPatch_MenuUpdates_SetActivePopupPanel:); macroSwizzleInstanceMethod(PPCanvasView, setIsDraggingTool:, ppGSPatch_SetIsDraggingTool:); macroSwizzleInstanceMethod(NSMenu, update, ppGSPatch_Update); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_MenuUpdates_InstallPatches); } @end @implementation PPPopupPanelsController (PPGNUstepGlue_MenuUpdates) - (void) ppGSPatch_MenuUpdates_SetActivePopupPanel: (PPPopupPanelType) popupPanelType { [self ppGSPatch_MenuUpdates_SetActivePopupPanel: popupPanelType]; gHasActivePopupPanel = [self hasActivePopupPanel]; } @end @implementation PPCanvasView (PPGNUstepGlue_MenuUpdates) - (void) ppGSPatch_SetIsDraggingTool: (bool) isDraggingTool { [self ppGSPatch_SetIsDraggingTool: isDraggingTool]; gIsDraggingTool = _isDraggingTool; } @end @implementation NSMenu (PPGNUstepGlue_MenuUpdates) - (void) ppGSPatch_Update { if (gHasActivePopupPanel || gIsDraggingTool) { return; } [self ppGSPatch_Update]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_MenuView.m0000644000076500000240000002164013234416764022571 0ustar joshstaff/* PPGNUstepGlue_MenuView.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds for several issues with NSMenuViews on GNUstep: // - Submenus of document windows' horizontal menubars (Win95InterfaceStyle) appear at the // wrong location (top left of screen) - appears in GUI 0.25.1, now fixed in the GNUstep trunk // (2017-06-28) // - Menus with separator items appear with a black area at the top (menuview's window height // is too large) // - Disabled menu items & separators can be highlighted // - Menu items on menus that are attached to small-sized NSPopUpButtons use the wrong fontsize #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" static NSMenuView *gMenuViewToAttachSubmenu = nil; static bool gNSMenuViewPrivateMethodIsSupported_HeightForItem = NO; static inline void PPGSGlue_SetupMenuViewGlobals(void) { gNSMenuViewPrivateMethodIsSupported_HeightForItem = ([NSMenuView instancesRespondToSelector: @selector(heightForItem:)]) ? YES : NO; } @interface NSMenuView (PPGNUstep_NSMenuViewPrivate) // local declaration of private GNUstep GUI method, -[NSMenuView heightForItem:] - (CGFloat) heightForItem: (NSInteger) idx; @end @implementation NSObject (PPGNUstepGlue_MenuView) + (void) ppGSGlue_MenuView_InstallPatches { macroSwizzleInstanceMethod(NSMenuView, attachSubmenuForItemAtIndex:, ppGSPatch_AttachSubmenuForItemAtIndex:); macroSwizzleInstanceMethod(NSMenuView, locationForSubmenu:, ppGSPatch_LocationForSubmenu:); macroSwizzleInstanceMethod(NSMenuView, setWindowFrameForAttachingToRect:onScreen: preferredEdge:popUpSelectedItem:, ppGSPatch_SetWindowFrameForAttachingToRect:onScreen: preferredEdge:popUpSelectedItem:); macroSwizzleInstanceMethod(NSMenuView, setHighlightedItemIndex:, ppGSPatch_SetHighlightedItemIndex:); macroSwizzleInstanceMethod(NSPopUpButtonCell, setMenuView:, ppGSPatch_SetMenuView:); } + (void) ppGSGlue_MenuView_Install { PPGSGlue_SetupMenuViewGlobals(); [self ppGSGlue_MenuView_InstallPatches]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_MenuView_Install); } @end @implementation NSMenuView (PPGNUstepGlue_MenuView) // PATCHES: -[NSMenuView attachSubmenuForItemAtIndex:] // -[NSMenuView locationForSubmenu:] // In GNUstep GUI 0.25.1: When using Win95InterfaceStyle, the submenus of document windows' // horizontal menubars appear at the top left of the screen instead of under the menubar. (This // is now fixed in the current trunk). // The issue was due to calling -[NSMenuView locationForSubmenu:] on a shared main-menu // menuview (this works fine in non-Win95 styles, since the menubar is separate & shared by all // document windows) instead of the menuview that's attached to the top of the document window. // The patch for attachSubmenuForItemAtIndex: stores the menuview that's about to attach a // submenu (at that point, it's the correct menuview for getting the submenu location) to the // global var, gMenuViewToAttachSubmenu, and the patch for locationForSubmenu: directs its // callthrough to gMenuViewToAttachSubmenu instead of to self (since self may be the wrong // (shared) menuview to determine the submenu location). - (void) ppGSPatch_AttachSubmenuForItemAtIndex: (NSInteger) index { gMenuViewToAttachSubmenu = self; [self ppGSPatch_AttachSubmenuForItemAtIndex: index]; gMenuViewToAttachSubmenu = nil; } - (NSPoint) ppGSPatch_LocationForSubmenu: (NSMenu *) aSubmenu { NSMenuView *targetMenuView = self; if (gMenuViewToAttachSubmenu) { targetMenuView = gMenuViewToAttachSubmenu; } return [targetMenuView ppGSPatch_LocationForSubmenu: aSubmenu]; } // PATCH: -[NSMenuView setWindowFrameForAttachingToRect:onScreen:preferredEdge: // popUpSelectedItem:] // Menus containing separator items appear with a black area at the top. This is because // GNUstep's implementation of setWindowFrameForAttachingToRect:... doesn't account for the // difference in height between normal menu items & separator items. // The patch loops over the menu's items, summming up separator items' differences with normal // items' height, then the window frame's height is offet by the total height difference. - (void) ppGSPatch_SetWindowFrameForAttachingToRect: (NSRect) screenRect onScreen: (NSScreen*) screen preferredEdge: (NSRectEdge) edge popUpSelectedItem: (NSInteger) selectedItemIndex { NSWindow *window; NSRect windowFrame; int numMenuItems; CGFloat correctWindowHeight, separatorItemsHeightOffset = 0; [self ppGSPatch_SetWindowFrameForAttachingToRect: screenRect onScreen: screen preferredEdge: edge popUpSelectedItem: selectedItemIndex]; window = [self window]; windowFrame = [window frame]; numMenuItems = [[self menu] numberOfItems]; if (gNSMenuViewPrivateMethodIsSupported_HeightForItem && (selectedItemIndex > 0) && (numMenuItems > 1)) { float defaultMenuItemHeight; int itemIndex; defaultMenuItemHeight = [self heightForItem: 0]; // assume first item isn't separator for (itemIndex=1; itemIndex 0) && (menuItemCell = [menuView menuItemCellForItemAtIndex: 0]) && ([menuItemCell font] != buttonFont)) { [menuItemCell setFont: buttonFont]; [menuItemCell setNeedsSizing: YES]; for (itemIndex=1; itemIndex. */ // Workaround for a menu-windows issue in GNUstep when running on Budgie, Compiz, Gala, Muffin, // Mutter, or Xfwm window managers: Dragging the mouse quickly along a menu with submenus can // sometimes leave one or more of the submenus' windows stuck visible until the mouse is moved // back over the submenu's item in the parent menu. If the user released the mouse while there // were stuck submenu windows, they would remain visible & unresponsive until the user clicked // again on the parent menu & navigated to the stuck submenu's parent item. // Could be that the affected window managers can't handle rapid showing & hiding of multiple // windows from within an inner loop (menuview mouse tracking)? // The current workaround doesn't completely fix the issue - submenu windows can still get // stuck visible while the mouse is down, but they will now be automatically hidden when the // user releases the button. This is done by keeping track of the menus that are sent a 'close' // message during menu-view mouse-tracking, then resending the close messages once tracking // finishes. #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGNUstepGlueUtilities.h" // Install MenuWindowHiding glue only if the window manager is Budgie, Compiz, Gala, Muffin, // Mutter, or Xfwm #define kTargetWindowManagerTypesMask_MenuWindowHiding \ (kPPGSWindowManagerTypeMask_Budgie \ | kPPGSWindowManagerTypeMask_Compiz \ | kPPGSWindowManagerTypeMask_Gala \ | kPPGSWindowManagerTypeMask_Muffin \ | kPPGSWindowManagerTypeMask_Mutter \ | kPPGSWindowManagerTypeMask_Xfwm) static NSMutableSet *gMenusClosedDuringTracking = nil; static bool gIsTrackingMenu = NO; static inline void PPGSGlue_SetupMenuWindowHidingGlobals(void) { gMenusClosedDuringTracking = [[NSMutableSet alloc] init]; } @interface NSMenuView (PPGNUstepGlue_MenuWindowHidingUtilities) - (void) ppGSGlue_ResendCloseMessagesToMenusClosedDuringTracking; @end @implementation NSObject (PPGNUstepGlue_MenuWindowHiding) + (void) ppGSGlue_MenuWindowHiding_InstallPatches { macroSwizzleInstanceMethod(NSMenuView, trackWithEvent:, ppGSPatch_TrackWithEvent:); macroSwizzleInstanceMethod(NSMenu, close, ppGSPatch_Close); } + (void) ppGSGlue_MenuWindowHiding_Install { if (!PPGSGlueUtils_WindowManagerMatchesTypeMask( kTargetWindowManagerTypesMask_MenuWindowHiding)) { return; } PPGSGlue_SetupMenuWindowHidingGlobals(); [self ppGSGlue_MenuWindowHiding_InstallPatches]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_MenuWindowHiding_Install); } @end @implementation NSMenuView (PPGNUstepGlue_MenuWindowHiding) - (BOOL) ppGSPatch_TrackWithEvent: (NSEvent *) event { BOOL returnValue; gIsTrackingMenu = YES; returnValue = [self ppGSPatch_TrackWithEvent: event]; gIsTrackingMenu = NO; [self ppGSGlue_ResendCloseMessagesToMenusClosedDuringTracking]; return returnValue; } - (void) ppGSGlue_ResendCloseMessagesToMenusClosedDuringTracking { [gMenusClosedDuringTracking makeObjectsPerformSelector: @selector(close)]; [gMenusClosedDuringTracking removeAllObjects]; } @end @implementation NSMenu (PPGNUstepGlue_MenuWindowHiding) - (void) ppGSPatch_Close { if (gIsTrackingMenu) { [gMenusClosedDuringTracking addObject: self]; } [self ppGSPatch_Close]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_Miscellaneous.m0000644000076500000240000003202013264227727023631 0ustar joshstaff/* PPGNUstepGlue_Miscellaneous.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Miscellaneous standalone (single-method) GNUstep workarounds & tweaks #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPApplication.h" #import "NSFileManager_PPUtilities.h" #import "PPPopupPanel.h" #import "PPToolsPanelController.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPToolButtonMatrix.h" #import "NSPasteboard_PPUtilities.h" #import "NSDocumentController_PPUtilities.h" #import "PPUserFolderPaths.h" #import "PPGeometry.h" @implementation NSObject (PPGNUstepGlue_Miscellaneous) + (void) ppGSGlue_Miscellaneous_InstallPatches { macroSwizzleInstanceMethod(PPApplication, validateMenuItem:, ppGSPatch_ValidateMenuItem:); macroSwizzleInstanceMethod(NSFileManager, ppVerifySupportFileDirectory, ppGSPatch_VerifySupportFileDirectory); macroSwizzleInstanceMethod(NSBrowser, setMaxVisibleColumns:, ppGSPatch_SetMaxVisibleColumns:); macroSwizzleInstanceMethod(NSImage, copyWithZone:, ppGSPatch_CopyWithZone:); macroSwizzleInstanceMethod(PPPopupPanel, canBecomeKeyWindow, ppGSPatch_CanBecomeKeyWindow); macroSwizzleInstanceMethod(PPToolsPanelController, defaultPinnedWindowFrame, ppGSPatch_DefaultPinnedWindowFrame); macroSwizzleInstanceMethod(PPDocument, setupNewPPDocumentWithCanvasSize:, ppGSPatch_SetupNewPPDocumentWithCanvasSize:); macroSwizzleInstanceMethod(PPCanvasView, drawRect:, ppGSPatch_DrawRect:); macroSwizzleClassMethod(PPToolButtonMatrix, cellClass, ppGSPatch_CellClass); macroSwizzleInstanceMethod(NSColorWell, performClick:, ppGSPatch_PerformClick:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_Miscellaneous_InstallPatches); } @end @implementation PPApplication (PPGNUstepGlue_Miscellaneous) // PATCH: -[PPApplication validateMenuItem:] // GNUstep doesn't support comparing selectors with ==, so patched to use sel_isEqual(). - (BOOL) ppGSPatch_ValidateMenuItem: (id ) menuItem { SEL menuItemAction = [menuItem action]; if (sel_isEqual(menuItemAction, @selector(newDocumentFromPasteboard:))) { return [NSPasteboard ppPasteboardHasBitmap] ? YES : NO; } // printing is currently disabled, so both printing-related menu items (print & page setup) // use runPageLayout: as their action for convenience when invalidating them if (sel_isEqual(menuItemAction, @selector(runPageLayout:))) { return NO; } if (sel_isEqual(menuItemAction, @selector(activateNextDocumentWindow:)) || sel_isEqual(menuItemAction, @selector(activatePreviousDocumentWindow:))) { return [[NSDocumentController sharedDocumentController] ppHasMultipleDocuments]; } return YES; } @end @implementation NSFileManager (PPGNUstepGlue_Miscellaneous) // PATCH: -[NSFileManager ppVerifySupportFileDirectory] // On GNUstep, the ApplicationSupport directory may not exist yet, and if it's not there, then // creating the PikoPixel support folder (in the ApplicationSupport directory) will fail, // because ppVerifySupportFileDirectory calls -[NSFileManager createDirectoryAtPath:...] with // the createIntermediates parameter set to NO. // Patch calls -[NSFileManager createDirectoryAtPath:...] with the createIntermediates // parameter set to YES. - (bool) ppGSPatch_VerifySupportFileDirectory { NSString *supportFolderPath = PPUserFolderPaths_ApplicationSupport(); BOOL isDirectory = NO; if (![supportFolderPath length]) { goto ERROR; } if ([self fileExistsAtPath: supportFolderPath isDirectory: &isDirectory]) { if (!isDirectory) goto ERROR; return YES; } return [self createDirectoryAtPath: supportFolderPath withIntermediateDirectories: YES attributes: nil error: NULL]; ERROR: return NO; } @end @implementation NSBrowser (PPGNUstepGlue_Miscellaneous) // PATCH: -[NSBrowser setMaxVisibleColumns:] // Patch allows browser columns on NSSavePanels & NSOpenPanels to be wider than the default // max-width on GNUstep (140). #define kNSBrowserMaxColumnWidth 190 - (void) ppGSPatch_SetMaxVisibleColumns: (NSInteger) columnCount { static Class NSSavePanelClass = nil; if (!NSSavePanelClass) { NSSavePanelClass = [[NSSavePanel class] retain]; } if ([[self window] isKindOfClass: NSSavePanelClass]) { columnCount = [self frame].size.width / kNSBrowserMaxColumnWidth; if (columnCount < 1) { columnCount = 1; } } [self ppGSPatch_SetMaxVisibleColumns: columnCount]; } @end @implementation NSImage (PPGNUstepGlue_Miscellaneous) // PATCH: -[NSImage copyWithZone:] // GNUstep's implementation of copyWithZone: only copies image representations that are // non-cached, so if the source image only contains NSCachedImageReps, the copy will be empty. // Patch checks whether the copy is a valid image; If not - and the source image is valid - // a valid representation is created by manually drawing the source image into the copy. - (id) ppGSPatch_CopyWithZone: (NSZone *) zone { NSImage *copiedImage = [self ppGSPatch_CopyWithZone: zone]; if (copiedImage && ![copiedImage isValid] && [self isValid]) { NSRect imageFrame = PPGeometry_OriginRectOfSize([self size]); [copiedImage lockFocus]; [self drawInRect: imageFrame fromRect: imageFrame operation: NSCompositeCopy fraction: 1.0f]; [copiedImage unlockFocus]; } return copiedImage; } @end @implementation PPPopupPanel (PPGNUstepGlue_Miscellaneous) // PATCH: -[PPPopupPanel canBecomeKeyWindow] // GNUstep's implementation of -[NSWindow canBecomeKeyWindow] doesn't automatically return NO // when the window has no title bar or resize bar (as on OS X), so need PPPopupPanel override // to prevent popup panels from becoming key. - (BOOL) ppGSPatch_CanBecomeKeyWindow { return NO; } @end @implementation PPToolsPanelController (PPGNUstepGlue_Miscellaneous) // PATCH: -[PPToolsPanelController defaultPinnedWindowFrame] // Prevents the tools panel's default position from overlapping the main menu. #define kMinDistanceBetweenToolsPanelAndMainMenu 20 - (NSRect) ppGSPatch_DefaultPinnedWindowFrame { NSRect panelFrame, mainMenuFrame, mainMenuFrameMargin; panelFrame = [self ppGSPatch_DefaultPinnedWindowFrame]; mainMenuFrame = [[[NSApp mainMenu] window] frame]; mainMenuFrameMargin = NSInsetRect(mainMenuFrame, -kMinDistanceBetweenToolsPanelAndMainMenu, -kMinDistanceBetweenToolsPanelAndMainMenu); if (!NSIsEmptyRect(NSIntersectionRect(panelFrame, mainMenuFrameMargin))) { panelFrame.origin.y = NSMinY(mainMenuFrameMargin) - panelFrame.size.height; } return panelFrame; } @end @implementation PPDocument (PPGNUstepGlue_Miscellaneous) // PATCH: -[PPDocument setupNewPPDocumentWithCanvasSize:] // On GNUstep, closing a new, unmodified PPDocument will display a confirmation dialog, due to // unsaved changes (whereas OS X can close an unmodified PPDocument immediately). // This is because a document's change count isn't cleared when its undoManager is sent a // removeAllActions message (a new PPDocument is changed during setup, so removeAllActions is // called at the end of setupNewPPDocumentWithCanvasSize:). // The workaround is to manually clear the new document's change count. - (bool) ppGSPatch_SetupNewPPDocumentWithCanvasSize: (NSSize) canvasSize { bool returnValue = [self ppGSPatch_SetupNewPPDocumentWithCanvasSize: canvasSize]; if (returnValue) { [self updateChangeCount: NSChangeCleared]; } return returnValue; } @end @implementation PPCanvasView (PPGNUstepGlue_Miscellaneous) // PATCH: -[PPCanvasView drawRect:] // Fix for PPCanvasView zoomout artifacts that appear when there's only one scrollbar visible // (but not both) - workaround is to draw over the artifacts by manually filling the area // outside the visible canvas with the enclosing scrollview's background color (normally // the canvasview doesn't draw this area and the underlying scrollview's background shows // through automatically). - (void) ppGSPatch_DrawRect: (NSRect) rect { // redraw the background surrounding the visible canvas if: // - drawing is allowed (zoomed-images draw-mode is 0 (normal)) // - and the dirty-rect covers some area outside the visible canvas // - and at least one scrollbar is visible (should only be one at this point - if they were // both visible, the dirty-rect would not be outside the visible canvas) if ((_zoomedImagesDrawMode == 0) && (!NSContainsRect(_offsetZoomedVisibleCanvasBounds, rect)) && ((_offsetZoomedCanvasFrame.origin.x == 0.0) || (_offsetZoomedCanvasFrame.origin.y == 0.0))) { static NSColor *backgroundColor = nil; NSRect rect1 = NSZeroRect, rect2 = NSZeroRect; if (!backgroundColor) { backgroundColor = [[[self enclosingScrollView] backgroundColor] retain]; } if (_offsetZoomedCanvasFrame.origin.x == 0.0) { // horizontal scrollbar - background-fill areas are above & below visible canvas CGFloat canvasMaxY = NSMaxY(_offsetZoomedCanvasFrame); rect1 = NSMakeRect(rect.origin.x, canvasMaxY, rect.size.width, NSMaxY(rect) - canvasMaxY); rect2 = NSMakeRect(rect.origin.x, rect.origin.y, rect.size.width, _offsetZoomedCanvasFrame.origin.y - rect.origin.y); } else if (_offsetZoomedCanvasFrame.origin.y == 0.0) { // vertical scrollbar - background-fill areas are on left & right of visible canvas CGFloat canvasMaxX = NSMaxX(_offsetZoomedCanvasFrame); rect1 = NSMakeRect(canvasMaxX, rect.origin.y, NSMaxX(rect) - canvasMaxX, rect.size.height); rect2 = NSMakeRect(rect.origin.x, rect.origin.y, _offsetZoomedCanvasFrame.origin.x - rect.origin.x, rect.size.height); } [backgroundColor set]; NSRectFill(rect1); NSRectFill(rect2); } [self ppGSPatch_DrawRect: rect]; } @end @implementation PPToolButtonMatrix (PPGNUstepGlue_Miscellaneous) // PATCH: +[PPToolButtonMatrix cellClass] // GNUstep's nib loader has an issue when loading instances of NSMatrix subclasses (but not // instances of NSMatrix itself): All of the NSMatrix-subclass' cells become NSActionCells, // regardless of what their actual class is in the nib file. This is because the nib loader // mistakenly forces the loaded cells (which originally have the correct class) to be // reallocated by the class object returned by +cellClass (+[NSMatrix cellClass] returns // NSActionCell). // The patch returns the correct class for allocating PPToolButtonMatrix's cells: NSButtonCell. + (Class) ppGSPatch_CellClass { static Class buttonCellClass = NULL; if (!buttonCellClass) { buttonCellClass = [[NSButtonCell class] retain]; } return buttonCellClass; } @end @implementation NSColorWell (PPGNUstepGlue_Miscellaneous) // PATCH: -[NSColorWell performClick:] // On GNUstep, -[NSColorWell performClick:] is unimplemented (calling the method falls through // to inherited implementation which doesn't activate/deactivate the well). (This is now fixed // in the GNUstep trunk, 2016-11-21). // Patch implements correct behavior for color wells: clicking deactivates if it's already // active, & activates if it's not active. - (void) ppGSPatch_PerformClick: (id) sender { if ([self isActive]) { [self deactivate]; } else { [self activate: YES]; } } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ModalSessions.m0000644000076500000240000003651613757513555023633 0ustar joshstaff/* PPGNUstepGlue_ModalSessions.m Copyright 2014-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds for issues during GNUstep modal dialog sessions: // - During a modal session, should not be able to start a new modal session in a different // document window (new/open/save menu actions) // - Panels stay visible during save & alert dialogs because they're not sheets on GNUstep, so // manually post NSWindow willBeginSheet & didEndSheet notifications (triggers panel-hiding // logic), and add additonal logic to keep panels hidden during non-sheet modal sessions // - Screencasting implementation currently misses events during modal sessions, so manually // hide the screencasting popup when a modal session begins // - GNUstep doesn't prevent the window manager from bringing a different document window to // the front if a user clicks on it during a modal session, however the new frontmost window // won't respond to further user interaction because the app's still in a modal runloop, so // signal to the user that non-main windows are currently non-interactive by overlaying a // 'greyed-out' pattern over them #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPApplication.h" #import "PPPanelsController.h" #import "PPDocument.h" #import "PPDocumentWindow.h" #import "PPDocumentWindowController.h" #import "PPScreencastController.h" #import "PPGNUstepGlueUtilities.h" #import "PPCanvasView.h" #import "NSColor_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #define kMinTimeIntervalToAllowNewDocumentAfterModalSessionEnds (0.5) // kInactiveCanvasOverlayColor: the pattern color drawn on top of non-main canvas views during // a modal session; GNUstep's NSRectFill() - used when generating PikoPixel's pattern colors - // doesn't handle transparent colors correctly (doesn't use NSCompositeCopy mode), so in order // to make a partially-transparent pattern color, need to first make an opaque version with // non-transparent colors, then manually dissolve the pattern's bitmap to the correct opacity // (using local utility method, ppGSGlue_PatternColorDissolvedToOpacity:) #define kInactiveCanvasOverlayColor \ [[NSColor ppDiagonalCheckerboardPatternColorWithBoxDimension: 4 \ color1: [NSColor ppSRGBColorWithWhite: 0.333 alpha: 1.0] \ color2: [NSColor ppSRGBColorWithWhite: 0.0 alpha: 1.0]] \ ppGSGlue_PatternColorDissolvedToOpacity: 0.6] static int gModalSessionCount = 0; static NSTimeInterval gLastModalSessionEndTime = 0; static PPCanvasView *gMainCanvasViewDuringModalSession = nil; static bool gDisallowManualPostingOfSheetNotifications = NO, gScreencastingIsEnabled = NO, gCanvasViewDrawRectPatchIsInstalled = NO; static inline NSSet *DisallowedModalActionNamesSet(void) { return [NSSet setWithObjects: @"newDocument:", @"newDocumentFromSelection:", @"newDocumentFromPasteboard:", @"openDocument:", @"saveDocument:", @"saveDocumentAs:", @"saveDocumentTo:", @"editHotkeySettings:", nil]; } static void ToggleModalSessionCanvasViewDrawRectPatch(void); static void RedrawAllCanvasViews(void); static PPCanvasView *CurrentMainWindowCanvasView(void); @interface NSColor (PPGNUstepGlue_ModalSessionsUtilities) - (NSColor *) ppGSGlue_PatternColorDissolvedToOpacity: (float) opacity; @end @interface NSApplication (PPGNUstepGlue_ModalSessionsUtilities) - (void) ppGSGlue_IncrementModalSessionCount; - (void) ppGSGlue_DecrementModalSessionCount; @end @implementation NSObject (PPGNUstepGlue_ModalSessions) + (void) ppGSGlue_ModalSessions_InstallPatches { macroSwizzleInstanceMethod(PPApplication, beginSheet:modalForWindow:modalDelegate: didEndSelector:contextInfo:, ppGSPatch_BeginSheet:modalForWindow:modalDelegate: didEndSelector:contextInfo:); macroSwizzleInstanceMethod(PPApplication, runModalForWindow:, ppGSPatch_ModalSessions_RunModalForWindow:); macroSwizzleInstanceMethod(NSMenu, performActionForItemAtIndex:, ppGSPatch_PerformActionForItemAtIndex:); macroSwizzleInstanceMethod(NSDocumentController, newDocument:, ppGSPatch_NewDocument:); macroSwizzleInstanceMethod(PPPanelsController, updatePanelsVisibilityAllowedForWindow:, ppGSPatch_UpdatePanelsVisibilityAllowedForWindow:); } + (void) ppGSGlue_ModalSessions_Install { [self ppGSGlue_ModalSessions_InstallPatches]; #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING PPGSGlueUtils_PerformPPScreencastControllerSelectorOnEnableOrDisable( @selector(ppGSGlue_ModalSessions_HandleScreencastEnableOrDisable)); #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ModalSessions_Install); } @end @implementation PPApplication (PPGNUstepGlue_ModalSessions) - (void) ppGSPatch_BeginSheet: (NSWindow *) sheet modalForWindow: (NSWindow *) docWindow modalDelegate: (id) modalDelegate didEndSelector: (SEL) didEndSelector contextInfo: (void *) contextInfo { bool oldDisallowManualPostingOfSheetNotifications = gDisallowManualPostingOfSheetNotifications; gDisallowManualPostingOfSheetNotifications = YES; [self ppGSPatch_BeginSheet: sheet modalForWindow: docWindow modalDelegate: modalDelegate didEndSelector: didEndSelector contextInfo: contextInfo]; gDisallowManualPostingOfSheetNotifications = oldDisallowManualPostingOfSheetNotifications; } - (NSInteger) ppGSPatch_ModalSessions_RunModalForWindow: (NSWindow *) theWindow { NSInteger returnValue; NSWindow *notifyingWindow = nil; bool shouldSendSheetNotifications; [self ppGSGlue_IncrementModalSessionCount]; #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING if (gScreencastingIsEnabled) { [[PPScreencastController sharedController] performSelector: @selector(clearScreencastState)]; } #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING shouldSendSheetNotifications = (gDisallowManualPostingOfSheetNotifications) ? NO : YES; if (shouldSendSheetNotifications) { notifyingWindow = [theWindow parentWindow]; if (!notifyingWindow) { notifyingWindow = [self mainWindow]; } [[NSNotificationCenter defaultCenter] postNotificationName: NSWindowWillBeginSheetNotification object: notifyingWindow]; } returnValue = [self ppGSPatch_ModalSessions_RunModalForWindow: theWindow]; if (shouldSendSheetNotifications) { [[NSNotificationCenter defaultCenter] postNotificationName: NSWindowDidEndSheetNotification object: notifyingWindow]; } [self ppGSGlue_DecrementModalSessionCount]; gLastModalSessionEndTime = [NSDate timeIntervalSinceReferenceDate]; return returnValue; } @end @implementation NSMenu (PPGNUstepGlue_ModalSessions) - (void) ppGSPatch_PerformActionForItemAtIndex: (NSInteger) index { if (gModalSessionCount > 0) { static NSSet *disallowedModalActionNamesSet = nil; SEL action = [[self itemAtIndex: index] action]; NSString *actionName = (action) ? NSStringFromSelector(action) : nil; if (!disallowedModalActionNamesSet) { disallowedModalActionNamesSet = [DisallowedModalActionNamesSet() retain]; } if (actionName && [disallowedModalActionNamesSet containsObject: actionName]) { return; } } [self ppGSPatch_PerformActionForItemAtIndex: index]; } @end @implementation NSDocumentController (PPGNUstepGlue_ModalSessions) - (void) ppGSPatch_NewDocument: (id) sender { if (([NSDate timeIntervalSinceReferenceDate] - gLastModalSessionEndTime) < kMinTimeIntervalToAllowNewDocumentAfterModalSessionEnds) { return; } [NSApp ppGSGlue_IncrementModalSessionCount]; [self ppGSPatch_NewDocument: sender]; [NSApp ppPerformSelectorFromNewStackFrame: @selector(ppGSGlue_DecrementModalSessionCount)]; } @end @interface PPPanelsController (PPGNUstepGlue_ModalSessions_PrivateMethodDeclarations) // -[PPPanelsController updatePanelsVisibilityAllowedForWindow:] patch below needs to call // private PPPanelsController method: - (void) setPanelsVisibilityAllowed: (bool) panelsVisibilityAllowed; @end @implementation PPPanelsController (PPGNUstepGlue_ModalSessions) - (void) ppGSPatch_UpdatePanelsVisibilityAllowedForWindow: (NSWindow *) window { bool panelsVisibilityAllowed = NO; if (([window class] == [PPDocumentWindow class]) && ![window attachedSheet] && (gModalSessionCount <= 0)) { panelsVisibilityAllowed = YES; } [self setPanelsVisibilityAllowed: panelsVisibilityAllowed]; } @end #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING @implementation PPScreencastController (PPGNUstepGlue_ModalSessions) - (void) ppGSGlue_ModalSessions_HandleScreencastEnableOrDisable { gScreencastingIsEnabled = (_screencastingIsEnabled) ? YES : NO; } @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING @implementation NSColor (PPGNUstepGlue_ModalSessionsUtilities) - (NSColor *) ppGSGlue_PatternColorDissolvedToOpacity: (float) opacity { NSImage *patternImage, *dissolvedPatternImage; NSColor *dissolvedPatternColor; if (opacity >= 1.0) { return self; } else if (opacity <= 0.0) { return [NSColor clearColor]; } patternImage = [self patternImage]; if (!patternImage) goto ERROR; dissolvedPatternImage = [NSImage ppImageWithBitmap: [[patternImage ppBitmap] ppImageBitmapDissolvedToOpacity: opacity]]; if (!dissolvedPatternImage) goto ERROR; dissolvedPatternColor = [NSColor colorWithPatternImage: dissolvedPatternImage]; if (!dissolvedPatternColor) goto ERROR; return dissolvedPatternColor; ERROR: return [NSColor clearColor]; } @end @implementation NSApplication (PPGNUstepGlue_ModalSessionsUtilities) - (void) ppGSGlue_IncrementModalSessionCount { gModalSessionCount++; if (gModalSessionCount == 1) { gMainCanvasViewDuringModalSession = CurrentMainWindowCanvasView(); if (!gCanvasViewDrawRectPatchIsInstalled) { ToggleModalSessionCanvasViewDrawRectPatch(); gCanvasViewDrawRectPatchIsInstalled = YES; } } else if (gModalSessionCount > 1) { // when creating a new image, the new document window doesn't become main until // gModalSessionCount > 1, so need to check whether the main canvas view has changed PPCanvasView *currentMainCanvasView = CurrentMainWindowCanvasView(); if (gMainCanvasViewDuringModalSession != currentMainCanvasView) { PPCanvasView *lastMainCanvasView = gMainCanvasViewDuringModalSession; gMainCanvasViewDuringModalSession = currentMainCanvasView; [lastMainCanvasView setNeedsDisplay: YES]; [lastMainCanvasView displayIfNeeded]; [gMainCanvasViewDuringModalSession setNeedsDisplay: YES]; [gMainCanvasViewDuringModalSession displayIfNeeded]; } } } - (void) ppGSGlue_DecrementModalSessionCount { gModalSessionCount--; if (gModalSessionCount <= 0) { gMainCanvasViewDuringModalSession = nil; if (gCanvasViewDrawRectPatchIsInstalled) { ToggleModalSessionCanvasViewDrawRectPatch(); gCanvasViewDrawRectPatchIsInstalled = NO; } } } @end @implementation PPCanvasView (PPGNUstepGlue_ModalSessionsTemporaryPatch) // temporary patch for -[PPCanvasView drawRect:], installed during a modal session to draw a // 'disabled' pattern over non-main canvas views - GNUstep can't prevent the window manager // from bringing other document windows to the front during a modal session (though they won't // respond to user interaction while the app's in a modal runloop), so the disabled pattern // signals to the user that non-main windows aren't currently interactive - (void) ppGSPatch_ModalSessions_DrawRect: (NSRect) rect { static NSColor *inactiveCanvasOverlayColor = nil; if (!inactiveCanvasOverlayColor) { inactiveCanvasOverlayColor = [kInactiveCanvasOverlayColor retain]; } [self ppGSPatch_ModalSessions_DrawRect: rect]; if ((gModalSessionCount > 0) && (self != gMainCanvasViewDuringModalSession)) { [inactiveCanvasOverlayColor set]; [[NSBezierPath bezierPathWithRect: rect] fill]; } } @end static void ToggleModalSessionCanvasViewDrawRectPatch(void) { macroSwizzleInstanceMethod(PPCanvasView, drawRect:, ppGSPatch_ModalSessions_DrawRect:); // force all canvas views to redraw after toggling patch RedrawAllCanvasViews(); } static void RedrawAllCanvasViews(void) { static Class PPDocumentClass = nil; NSEnumerator *documentEnumerator; PPDocument *ppDocument; PPCanvasView *canvasView; if (!PPDocumentClass) { PPDocumentClass = [PPDocument class]; } documentEnumerator = [[[NSDocumentController sharedDocumentController] documents] objectEnumerator]; while (ppDocument = (PPDocument *) [documentEnumerator nextObject]) { if ([ppDocument isMemberOfClass: PPDocumentClass]) { canvasView = [[ppDocument ppDocumentWindowController] canvasView]; [canvasView setNeedsDisplay: YES]; [canvasView displayIfNeeded]; } } } static PPCanvasView *CurrentMainWindowCanvasView(void) { static Class PPDocumentWindowControllerClass = nil; PPDocumentWindowController *ppDocumentWindowController; if (!PPDocumentWindowControllerClass) { PPDocumentWindowControllerClass = [PPDocumentWindowController class]; } ppDocumentWindowController = [[NSApp mainWindow] windowController]; if (![ppDocumentWindowController isMemberOfClass: PPDocumentWindowControllerClass]) { return nil; } return [ppDocumentWindowController canvasView]; } #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ModalSheets.m0000644000076500000240000002143313234416764023242 0ustar joshstaff/* PPGNUstepGlue_ModalSheets.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPDocumentSizeSheetController.h" #import "PPDocumentBackgroundSettingsSheetController.h" #import "PPDocumentGridSettingsSheetController.h" #import "PPDocumentEditPatternPresetsSheetController.h" @interface NSObject (PPGNUstepGlue_ModalSheetsUtilities) - (void) ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: (SEL) selector; @end @implementation NSObject (PPGNUstepGlue_ModalSheets) + (void) ppGSGlue_ModalSheets_InstallPatches { macroSwizzleInstanceMethod(PPDocumentSizeSheetController, sizePresetsMenuItemSelected_EditSizePresets:, ppGSPatch_SizePresetsMenuItemSelected_EditSizePresets:); macroSwizzleInstanceMethod(PPDocumentBackgroundSettingsSheetController, patternPresetsMenuItemSelected_AddCurrentPatternToPresets:, ppGSPatch_PatternPresetsMenuItemSelected_AddCurrentPatternToPresets:); macroSwizzleInstanceMethod(PPDocumentBackgroundSettingsSheetController, patternPresetsMenuItemSelected_EditPresets:, ppGSPatch_PatternPresetsMenuItemSelected_EditPresets:); macroSwizzleInstanceMethod(PPDocumentBackgroundSettingsSheetController, patternPresetsMenuItemSelected_ExportPresetsToFile:, ppGSPatch_PatternPresetsMenuItemSelected_ExportPresetsToFile:); macroSwizzleInstanceMethod(PPDocumentBackgroundSettingsSheetController, patternPresetsMenuItemSelected_ImportPresetsFromFile:, ppGSPatch_PatternPresetsMenuItemSelected_ImportPresetsFromFile:); macroSwizzleInstanceMethod(PPDocumentGridSettingsSheetController, presetsMenuItemSelected_AddCurrentPatternToPresets:, ppGSPatch_PresetsMenuItemSelected_AddCurrentPatternToPresets:); macroSwizzleInstanceMethod(PPDocumentGridSettingsSheetController, presetsMenuItemSelected_EditPresets:, ppGSPatch_PresetsMenuItemSelected_EditPresets:); macroSwizzleInstanceMethod(PPDocumentGridSettingsSheetController, presetsMenuItemSelected_ExportPresetsToFile:, ppGSPatch_PresetsMenuItemSelected_ExportPresetsToFile:); macroSwizzleInstanceMethod(PPDocumentGridSettingsSheetController, presetsMenuItemSelected_ImportPresetsFromFile:, ppGSPatch_PresetsMenuItemSelected_ImportPresetsFromFile:); macroSwizzleClassMethod(PPDocumentEditPatternPresetsSheetController, beginEditPatternPresetsSheetForWindow:patternPresets: patternTypeDisplayName:currentPattern: addCurrentPatternAsPreset:delegate:, ppGSPatch_BeginEditPatternPresetsSheetForWindow:patternPresets: patternTypeDisplayName:currentPattern: addCurrentPatternAsPreset:delegate:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ModalSheets_InstallPatches); } @end @implementation PPDocumentSizeSheetController (PPGNUstepGlue_ModalSheets) - (IBAction) ppGSPatch_SizePresetsMenuItemSelected_EditSizePresets: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_SizePresetsMenuItemSelected_EditSizePresets:)]; } @end @implementation PPDocumentBackgroundSettingsSheetController (PPGNUstepGlue_ModalSheets) - (IBAction) ppGSPatch_PatternPresetsMenuItemSelected_AddCurrentPatternToPresets: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_PatternPresetsMenuItemSelected_AddCurrentPatternToPresets:)]; } - (IBAction) ppGSPatch_PatternPresetsMenuItemSelected_EditPresets: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_PatternPresetsMenuItemSelected_EditPresets:)]; } - (IBAction) ppGSPatch_PatternPresetsMenuItemSelected_ExportPresetsToFile: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_PatternPresetsMenuItemSelected_ExportPresetsToFile:)]; } - (IBAction) ppGSPatch_PatternPresetsMenuItemSelected_ImportPresetsFromFile: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_PatternPresetsMenuItemSelected_ImportPresetsFromFile:)]; } @end @implementation PPDocumentGridSettingsSheetController (PPGNUstepGlue_ModalSheets) - (IBAction) ppGSPatch_PresetsMenuItemSelected_AddCurrentPatternToPresets: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_PresetsMenuItemSelected_AddCurrentPatternToPresets:)]; } - (IBAction) ppGSPatch_PresetsMenuItemSelected_EditPresets: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_PresetsMenuItemSelected_EditPresets:)]; } - (IBAction) ppGSPatch_PresetsMenuItemSelected_ExportPresetsToFile: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_PresetsMenuItemSelected_ExportPresetsToFile:)]; } - (IBAction) ppGSPatch_PresetsMenuItemSelected_ImportPresetsFromFile: (id) sender { [self ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(ppGSPatch_PresetsMenuItemSelected_ImportPresetsFromFile:)]; } @end @interface PPDocumentEditPatternPresetsSheetController (PPGNUstepGlue_ModalSheetsPrivate) // mirror of private initializer declaration in PPDocumentEditPatternPresetsSheetController.m - initWithPatternPresets: (PPPatternPresets *) patternPresets patternTypeDisplayName: (NSString *) patternTypeDisplayName currentPattern: (id ) currentPattern delegate: (id) delegate; @end @implementation PPDocumentEditPatternPresetsSheetController (PPGNUstepGlue_ModalSheets) + (bool) ppGSPatch_BeginEditPatternPresetsSheetForWindow: (NSWindow *) window patternPresets: (PPPatternPresets *) patternPresets patternTypeDisplayName: (NSString *) patternTypeDisplayName currentPattern: (id ) currentPattern addCurrentPatternAsPreset: (bool) addCurrentPatternAsPreset delegate: (id) delegate { PPDocumentEditPatternPresetsSheetController *controller; controller = [[[self alloc] initWithPatternPresets: patternPresets patternTypeDisplayName: patternTypeDisplayName currentPattern: currentPattern delegate: delegate] autorelease]; if (!controller) goto ERROR; if (addCurrentPatternAsPreset) { [controller ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: @selector(addCurrentPatternToEditablePatterns)]; } if (![controller beginSheetModalForWindow: window]) { goto ERROR; } return YES; ERROR: return NO; } @end @implementation NSObject (PPGNUstepGlue_ModalSheetsUtilities) - (void) ppGSGlue_PerformSelectorFromNewStackFrameInModalMode: (SEL) selector { static NSArray *modes = nil; if (!modes) { modes = [[NSArray arrayWithObject: NSModalPanelRunLoopMode] retain]; } if (selector) { [self performSelector: selector withObject: nil afterDelay: 0.0f inModes: modes]; } } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ModifierKeys.m0000644000076500000240000004203213760250752023417 0ustar joshstaff/* PPGNUstepGlue_ModifierKeys.m Copyright 2014-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGNUstepGlueUtilities.h" #import "PPToolModifierTipsText.h" #import "PPGNUstepUserDefaults.h" // some desktop environments intercept the Super key when it's pressed by itself - the key // isn't passed to the application until another modifier key's also pressed, so the key name // strings on the Tool Modifier Tips panel that are just "Super" need to be renamed to a chord // of modifiers ("Super + Alt", except "Match Anywhere" should be "Cntrl + Super"); to be safe, // unless the window manager's known to be associated with a DE that *doesn't* intercept Super // (Plasma, LXDE, Xfce, WindowMaker), assume the key names should be renamed as chords #define kWindowManagersWhereSuperKeyMayNeedChording \ ~(kPPGSWindowManagerTypeMask_KWin \ | kPPGSWindowManagerTypeMask_Openbox \ | kPPGSWindowManagerTypeMask_Xfwm \ | kPPGSWindowManagerTypeMask_WindowMaker) static bool gShouldRenameToolModifierKeysWithChordForSuper = YES; static NSUInteger RemappedModifierKeyMaskForMenuItemAction(SEL menuItemAction); static inline NSUInteger RemappedModifierKeyMaskForMask(NSUInteger modifierKeyMask); static NSArray *RenamedToolModifierTipsTextModifierDictsArrayForArray(NSArray *modifierDicts); static NSDictionary *MenuItemSelectorNameToRemappedModifierKeysMaskDict(void); static void RemapMainMenuModifierKeys(void); @interface NSMenuItem (PPGNUstepGlue_ModifierKeysUtilities) - (void) ppGSGlue_RemapModifierKeys; @end @interface NSUserDefaults (PPGNUstepGlue_ModifierKeysUtilities) - (void) ppGSGlue_ModifierKeys_SetupDefaults; @end @implementation NSObject (PPGNUstepGlue_ModifierKeys) + (void) ppGSGlue_ModifierKeys_InstallPatches { macroSwizzleInstanceMethod(NSMenu, awakeFromNib, ppGSPatch_AwakeFromNib); macroSwizzleInstanceMethod(NSButtonCell, setKeyEquivalentModifierMask:, ppGSPatch_SetKeyEquivalentModifierMask:); macroSwizzleClassMethod(PPToolModifierTipsText, getModifierDescriptions:andModifierKeyNames: forToolWithName:usingModifierDicts:andTitlesDict:, ppGSPatch_GetModifierDescriptions:andModifierKeyNames: forToolWithName:usingModifierDicts:andTitlesDict:); } + (void) ppGSGlue_ModifierKeys_Install { RemapMainMenuModifierKeys(); [self ppGSGlue_ModifierKeys_InstallPatches]; gShouldRenameToolModifierKeysWithChordForSuper = PPGSGlueUtils_WindowManagerMatchesTypeMask(kWindowManagersWhereSuperKeyMayNeedChording); } + (void) load { PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads( @selector(ppGSGlue_ModifierKeys_SetupDefaults)); macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ModifierKeys_Install); } @end @implementation NSMenu (PPGNUstepGlue_ModifierKeys) - (void) ppGSPatch_AwakeFromNib { NSEnumerator *itemEnumerator; NSMenuItem *menuItem; [self ppGSPatch_AwakeFromNib]; itemEnumerator = [[self itemArray] objectEnumerator]; while (menuItem = [itemEnumerator nextObject]) { [menuItem ppGSGlue_RemapModifierKeys]; } } @end @implementation NSButtonCell (PPGNUstepGlue_ModifierKeys) - (void) ppGSPatch_SetKeyEquivalentModifierMask: (NSUInteger) mask { if (mask) { // Some buttons have their command-key equivalents in the title - need to manually // replace the clover character (Command modifier key) with its remapped control-key (^) if (mask & NSCommandKeyMask) { NSString *title = [self title]; if ([title length]) { title = [title stringByReplacingOccurrencesOfString: @"\u2318" // (clover) withString: @"\u2303"]; // (^) if ([title length]) { [self setTitle: title]; } } } mask = RemappedModifierKeyMaskForMask(mask); } [self ppGSPatch_SetKeyEquivalentModifierMask: mask]; } @end @implementation PPToolModifierTipsText (PPGNUstepGlue_ModifierKeys) + (bool) ppGSPatch_GetModifierDescriptions: (NSAttributedString **) returnedDescriptionsText andModifierKeyNames: (NSAttributedString **) returnedKeyNamesText forToolWithName: (NSString *) toolName usingModifierDicts: (NSArray *) modifierDicts andTitlesDict: (NSDictionary *) titlesDict { return [self ppGSPatch_GetModifierDescriptions: returnedDescriptionsText andModifierKeyNames: returnedKeyNamesText forToolWithName: toolName usingModifierDicts: RenamedToolModifierTipsTextModifierDictsArrayForArray(modifierDicts) andTitlesDict: titlesDict]; } @end @implementation NSMenuItem (PPGNUstepGlue_ModifierKeysUtilities) - (void) ppGSGlue_RemapModifierKeys { NSUInteger modifierKeyMask, remappedModifierKeyMask; modifierKeyMask = [self keyEquivalentModifierMask]; if (!modifierKeyMask) return; remappedModifierKeyMask = RemappedModifierKeyMaskForMenuItemAction([self action]); if (!remappedModifierKeyMask) { remappedModifierKeyMask = RemappedModifierKeyMaskForMask(modifierKeyMask); } if (remappedModifierKeyMask != modifierKeyMask) { [self setKeyEquivalentModifierMask: remappedModifierKeyMask]; } } @end @implementation NSUserDefaults (PPGNUstepGlue_ModifierKeysUtilities) - (void) ppGSGlue_ModifierKeys_SetupDefaults { NSDictionary *defaultsDict = [NSDictionary dictionaryWithObjectsAndKeys: // Control keys kGSUserDefaultsValue_ModifierKeyName_LeftCtrl, kGSUserDefaultsKey_FirstControlKey, kGSUserDefaultsValue_ModifierKeyName_RightCtrl, kGSUserDefaultsKey_SecondControlKey, // Option (Alternate) keys kGSUserDefaultsValue_ModifierKeyName_LeftAlt, kGSUserDefaultsKey_FirstAlternateKey, kGSUserDefaultsValue_ModifierKeyName_RightAlt, kGSUserDefaultsKey_SecondAlternateKey, // Command (Super) keys kGSUserDefaultsValue_ModifierKeyName_LeftSuper, kGSUserDefaultsKey_FirstCommandKey, kGSUserDefaultsValue_ModifierKeyName_RightSuper, kGSUserDefaultsKey_SecondCommandKey, nil]; if (defaultsDict) { [self registerDefaults: defaultsDict]; } } @end static NSUInteger RemappedModifierKeyMaskForMenuItemAction(SEL menuItemAction) { static NSDictionary *selectorNameToRemappedModifierKeysMaskDict = nil; NSString *selectorName; NSNumber *remappedModifierKeysNumber; if (!selectorNameToRemappedModifierKeysMaskDict) { selectorNameToRemappedModifierKeysMaskDict = [MenuItemSelectorNameToRemappedModifierKeysMaskDict() retain]; } if (!menuItemAction) return 0; selectorName = NSStringFromSelector(menuItemAction); if (!selectorName) return 0; remappedModifierKeysNumber = [selectorNameToRemappedModifierKeysMaskDict objectForKey: selectorName]; if (!remappedModifierKeysNumber) return 0; return [remappedModifierKeysNumber unsignedIntegerValue]; } static inline NSUInteger RemappedModifierKeyMaskForMask(NSUInteger modifierKeyMask) { NSUInteger remappedModifierKeyMask = 0; // Command -> Control if (modifierKeyMask & NSCommandKeyMask) { remappedModifierKeyMask |= NSControlKeyMask; } // Control -> Alternate if (modifierKeyMask & NSControlKeyMask) { remappedModifierKeyMask |= NSAlternateKeyMask; } // Alternate -> Command if (modifierKeyMask & NSAlternateKeyMask) { remappedModifierKeyMask |= NSCommandKeyMask; } // Shift -> Shift if (modifierKeyMask & NSShiftKeyMask) { remappedModifierKeyMask |= NSShiftKeyMask; } return remappedModifierKeyMask; } #define kModifiersDictKey_Modifiers_ModifierStringDicts @"ModifierStringDicts" #define kModifiersDictKey_ModifierStrings_KeyNames @"KeyNames" #define kModifiersDictKey_ModifierStrings_Description @"Description" static NSArray *RenamedToolModifierTipsTextModifierDictsArrayForArray(NSArray *modifierDicts) { NSMutableArray *renamedModifierDicts, *renamedModifierStringDicts; NSEnumerator *modifierDictsEnumerator, *modifierStringDictsEnumerator; NSArray *modifierStringDicts; NSDictionary *modifiersDict, *modifierStringsDict; NSMutableDictionary *renamedModifiersDict, *renamedModifierStringsDict; NSString *renamedKeyNames; if (![modifierDicts count]) { goto ERROR; } renamedModifierDicts = [NSMutableArray arrayWithCapacity: [modifierDicts count]]; if (!renamedModifierDicts) goto ERROR; modifierDictsEnumerator = [modifierDicts objectEnumerator]; while (modifiersDict = [modifierDictsEnumerator nextObject]) { renamedModifiersDict = [NSMutableDictionary dictionaryWithDictionary: modifiersDict]; if (!renamedModifiersDict) goto ERROR; modifierStringDicts = [modifiersDict objectForKey: kModifiersDictKey_Modifiers_ModifierStringDicts]; renamedModifierStringDicts = [NSMutableArray arrayWithCapacity: [modifierStringDicts count]]; if (!renamedModifierStringDicts) goto ERROR; modifierStringDictsEnumerator = [modifierStringDicts objectEnumerator]; while (modifierStringsDict = [modifierStringDictsEnumerator nextObject]) { renamedModifierStringsDict = [NSMutableDictionary dictionaryWithDictionary: modifierStringsDict]; if (!renamedModifierStringsDict) goto ERROR; renamedKeyNames = [modifierStringsDict objectForKey: kModifiersDictKey_ModifierStrings_KeyNames]; renamedKeyNames = [renamedKeyNames stringByReplacingOccurrencesOfString: @"Control" withString: @"Ctrl"]; renamedKeyNames = [renamedKeyNames stringByReplacingOccurrencesOfString: @"Option" withString: @"Alt"]; renamedKeyNames = [renamedKeyNames stringByReplacingOccurrencesOfString: @"Command" withString: @"Super"]; if (gShouldRenameToolModifierKeysWithChordForSuper && [renamedKeyNames isEqualToString: @"Super"]) { // by default, rename "Super" to "Super + Alt", except for "Match Anywhere", // where using Alt interferes with Magic Wand's "Subtract from Selection", so // use "Ctrl + Super" instead if ([[modifierStringsDict objectForKey: kModifiersDictKey_ModifierStrings_Description] isEqualToString: @"Match Anywhere"]) { renamedKeyNames = @"Ctrl + Super"; } else { renamedKeyNames = @"Super + Alt"; } } [renamedModifierStringsDict setObject: renamedKeyNames forKey: kModifiersDictKey_ModifierStrings_KeyNames]; [renamedModifierStringDicts addObject: renamedModifierStringsDict]; } [renamedModifiersDict setObject: renamedModifierStringDicts forKey: kModifiersDictKey_Modifiers_ModifierStringDicts]; [renamedModifierDicts addObject: renamedModifiersDict]; } return renamedModifierDicts; ERROR: return modifierDicts; } static NSDictionary *MenuItemSelectorNameToRemappedModifierKeysMaskDict(void) { return [NSDictionary dictionaryWithObjectsAndKeys: // Nudge Selection > Left: Super+Shift+Left -> Alt+Shift+Left [NSNumber numberWithUnsignedInteger: NSAlternateKeyMask | NSShiftKeyMask], @"nudgeSelectionOutlineLeft:", // Nudge Selection > Right: Super+Shift+Right -> Alt+Shift+Right [NSNumber numberWithUnsignedInteger: NSAlternateKeyMask | NSShiftKeyMask], @"nudgeSelectionOutlineRight:", // Nudge Selection > Up: Super+Shift+Up -> Alt+Shift+Up [NSNumber numberWithUnsignedInteger: NSAlternateKeyMask | NSShiftKeyMask], @"nudgeSelectionOutlineUp:", // Nudge Selection > Down: Super+Shift+Down -> Alt+Shift+Down [NSNumber numberWithUnsignedInteger: NSAlternateKeyMask | NSShiftKeyMask], @"nudgeSelectionOutlineDown:", // Erase Selected Pixels: Ctrl+Alt+L -> Alt+L [NSNumber numberWithUnsignedInteger: NSAlternateKeyMask], @"eraseSelectedPixels:", // Delete Layer: Ctrl+Alt+Delete -> Ctrl+Alt+Shift+Delete [NSNumber numberWithUnsignedInteger: NSControlKeyMask | NSAlternateKeyMask | NSShiftKeyMask], @"deleteActiveLayer:", // Merge with Layer Above: Ctrl+Alt+Up -> Ctrl+Super+Shift+Up [NSNumber numberWithUnsignedInteger: NSControlKeyMask | NSCommandKeyMask | NSShiftKeyMask], @"mergeWithLayerAbove:", // Merge with Layer Below: Ctrl+Alt+Down -> Ctrl+Super+Shift+Down [NSNumber numberWithUnsignedInteger: NSControlKeyMask | NSCommandKeyMask | NSShiftKeyMask], @"mergeWithLayerBelow:", // Next Window: Alt+Tab -> Ctrl+Tab [NSNumber numberWithUnsignedInteger: NSControlKeyMask], @"activateNextDocumentWindow:", // Previous Window: Alt+` -> Ctrl+` [NSNumber numberWithUnsignedInteger: NSControlKeyMask], @"activatePreviousDocumentWindow:", nil]; } static void RemapMainMenuModifierKeys(void) { NSMutableArray *menus; NSMenu *mainMenu, *currentMenu; int indexOfCurrentMenu; NSEnumerator *currentMenuItemEnumerator; NSMenuItem *currentMenuItem; menus = [NSMutableArray array]; if (!menus) goto ERROR; mainMenu = [NSApp mainMenu]; if (!mainMenu) goto ERROR; [menus addObject: mainMenu]; indexOfCurrentMenu = 0; while (indexOfCurrentMenu < [menus count]) { currentMenu = [menus objectAtIndex: indexOfCurrentMenu]; currentMenuItemEnumerator = [[currentMenu itemArray] objectEnumerator]; while (currentMenuItem = [currentMenuItemEnumerator nextObject]) { [currentMenuItem ppGSGlue_RemapModifierKeys]; if ([currentMenuItem hasSubmenu]) { [menus addObject: [currentMenuItem submenu]]; } } indexOfCurrentMenu++; } return; ERROR: return; } #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_PanelResizing.m0000644000076500000240000001345113234416764023605 0ustar joshstaff/* PPGNUstepGlue_PanelResizing.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPPanelController.h" #import "PPPreviewView.h" #import "PPLayersPanelController.h" #import "PPResizeControl.h" #define kMaxPanelSizeInitializer {5000,5000} @interface PPPanelController (PPGNUstepGlue_PanelResizingUtilities) - (void) setupPanelWithResizeControl; @end @implementation NSObject (PPGNUstepGlue_PanelResizing) + (void) ppGSGlue_PanelResizing_InstallPatches { macroSwizzleInstanceMethod(PPPanelController, windowDidLoad, ppGSPatch_PanelResizing_WindowDidLoad); macroSwizzleInstanceMethod(PPPreviewView, handleResizingEnd, ppGSPatch_HandleResizingEnd); macroSwizzleInstanceMethod(PPLayersPanelController, windowDidLoad, ppGSPatch_LayersPanelResizing_WindowDidLoad); macroSwizzleInstanceMethod(PPLayersPanelController, windowWillResize:toSize:, ppGSPatch_WindowWillResize:toSize:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_PanelResizing_InstallPatches); } @end @implementation PPPanelController (PPGNUstepGlue_PanelResizing) - (void) ppGSPatch_PanelResizing_WindowDidLoad { [self ppGSPatch_PanelResizing_WindowDidLoad]; if ([[self window] styleMask] & NSResizableWindowMask) { [self setupPanelWithResizeControl]; } } @end @implementation PPPreviewView (PPGNUstepGlue_PanelResizing) - (void) ppGSPatch_HandleResizingEnd { [self setFrameSize: [self frame].size]; // forces _scaledImageBounds to reposition [self setNeedsDisplay: YES]; [self ppGSPatch_HandleResizingEnd]; } @end @implementation PPLayersPanelController (PPGNUstepGlue_PanelResizing) static NSSize gLayersPanelMinSize = {0,0}, gLayersPanelMaxSize = kMaxPanelSizeInitializer; - (void) ppGSPatch_LayersPanelResizing_WindowDidLoad { NSWindow *layersPanel = [self window]; gLayersPanelMinSize = [layersPanel minSize]; gLayersPanelMaxSize = [layersPanel maxSize]; [self ppGSPatch_LayersPanelResizing_WindowDidLoad]; } - (NSSize) windowWillResize: (NSWindow *) sender toSize: (NSSize) frameSize { // This NSWindow delegate stub method is defined here because it's not implemented by // PPLayersPanelController or its ancestors; Undefined methods can't be swizzled, so the // alternative would be to move the contents of ppGSPatch_WindowWillResize: here, which // would make this "patch" hard to find if one were only looking at the swizzling calls in // +ppGSGlue_PanelResizing_InstallPatches when searching for overridden functionality. return frameSize; } - (NSSize) ppGSPatch_WindowWillResize: (NSWindow *) sender toSize: (NSSize) frameSize { if (frameSize.width < gLayersPanelMinSize.width) { frameSize.width = gLayersPanelMinSize.width; } else if (frameSize.width > gLayersPanelMaxSize.width) { frameSize.width = gLayersPanelMaxSize.width; } if (frameSize.height < gLayersPanelMinSize.height) { frameSize.height = gLayersPanelMinSize.height; } else if (frameSize.height > gLayersPanelMaxSize.height) { frameSize.height = gLayersPanelMaxSize.height; } return frameSize; } @end @implementation PPPanelController (PPGNUstepGlue_PanelResizingUtilities) - (void) setupPanelWithResizeControl { NSWindow *panel; NSSize panelSize, panelContentSize; NSImage *resizeControlImage; NSRect resizeControlFrame; PPResizeControl *resizeControl; panel = [self window]; panelSize = [panel frame].size; panelContentSize = [[panel contentView] bounds].size; resizeControlImage = [NSImage imageNamed: @"resize_control.png"]; resizeControlFrame.size = [resizeControlImage size]; resizeControlFrame.origin = NSMakePoint(panelContentSize.width - resizeControlFrame.size.width, 0); resizeControl = [[[PPResizeControl alloc] initWithFrame: resizeControlFrame] autorelease]; [resizeControl setImage: resizeControlImage]; [resizeControl setEnabled: YES]; [resizeControl setDelegate: self]; [resizeControl setAutoresizingMask: NSViewMinXMargin | NSViewMaxYMargin]; [[panel contentView] addSubview: resizeControl]; [panel setMinSize: panelSize]; [panel setMaxSize: panelSize]; } #pragma mark PPResizeControl delegate methods - (void) ppResizeControlDidBeginResizing: (PPResizeControl *) resizeControl { static NSSize maxPanelSize = kMaxPanelSizeInitializer; NSWindow *panel = [self window]; [panel setMinSize: NSZeroSize]; [panel setMaxSize: maxPanelSize]; } - (void) ppResizeControlDidFinishResizing: (PPResizeControl *) resizeControl { NSWindow *panel = [self window]; NSSize panelSize = [panel frame].size; [panel setMinSize: panelSize]; [panel setMaxSize: panelSize]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_PatternColorDrawingSpeedup.m0000644000076500000240000000724613234416764026316 0ustar joshstaff/* PPGNUstepGlue_PatternColorDrawingSpeedup.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Speedup for drawing small-image pattern colors on GNUstep (Cairo?) #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGeometry.h" #define kMinPatternImageDimension 32 @implementation NSObject (PPGNUstepGlue_PatternColorDrawingSpeedup) // AA_ was inserted into the name of the _InstallPatches method to make sure it gets called // before ppGSGlue_BitmapGraphicsContext_Install (AfterAppLoads selectors are called // alphabetically) - this is because installing the BitmapGraphicsContext patches causes // +[PPCanvasView initialize] to be called, which loads some pattern colors (selection-tool // overlay) + (void) ppGSGlue_AA_PatternColorDrawingSpeedup_InstallPatches { macroSwizzleClassMethod(NSColor, colorWithPatternImage:, ppGSPatch_ColorWithPatternImage:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads( ppGSGlue_AA_PatternColorDrawingSpeedup_InstallPatches); } @end @implementation NSColor (PPGNUstepGlue_PatternColorDrawingSpeedup) // PATCH: -[NSColor colorWithPatternImage:] // On GNUstep (Cairo?), pattern-colors made from small images (< 32x32) draw slowly. // The patch speeds up drawing by only returning pattern-colors with 32x32 (or larger) images; // When the passed image is too small, the returned pattern-color instead uses an upsized image, // drawn by tiling the original. + (NSColor *) ppGSPatch_ColorWithPatternImage: (NSImage *) image { NSColor *patternColor; NSSize imageSize, minPatternSize; patternColor = [self ppGSPatch_ColorWithPatternImage: image]; if (!patternColor) goto ERROR; imageSize = [image size]; if (PPGeometry_IsZeroSize(imageSize)) { goto ERROR; } minPatternSize = NSMakeSize(imageSize.width * ceilf(kMinPatternImageDimension / imageSize.width), imageSize.height * ceilf(kMinPatternImageDimension / imageSize.height)); if (!NSEqualSizes(imageSize, minPatternSize)) { NSImage *upsizedPatternImage; NSColor *upsizedPatternColor; upsizedPatternImage = [[[NSImage alloc] initWithSize: minPatternSize] autorelease]; if (!upsizedPatternImage) goto ERROR; [upsizedPatternImage lockFocus]; [patternColor set]; NSRectFill(PPGeometry_OriginRectOfSize(minPatternSize)); [upsizedPatternImage unlockFocus]; upsizedPatternColor = [self ppGSPatch_ColorWithPatternImage: upsizedPatternImage]; if (!upsizedPatternColor) goto ERROR; patternColor = upsizedPatternColor; } return patternColor; ERROR: return patternColor; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_PatternedLines.m0000644000076500000240000002001513234416764023746 0ustar joshstaff/* PPGNUstepGlue_PatternedLines.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // GNUstep currently doesn't support drawing 1-pixel-wide bezier paths using pattern colors, // so methods that draw patterned lines are overridden by patches that manually create the line // patterns using NSBezierPath lineDash settings instead (requires 2 draws, less efficient) #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPCanvasView.h" #import "NSColor_PPUtilities.h" // Selection outline colors #define kUIColor_SelectionOutline_DarkDashes \ [NSColor blackColor] #define kUIColor_SelectionOutline_LightDashes \ [NSColor whiteColor] // Eraser tool outline colors #define kUIColor_EraserToolOutline_DarkDots \ [NSColor ppSRGBColorWithWhite: 0 alpha: 0.64] #define kUIColor_EraserToolOutline_LightDots \ [NSColor ppSRGBColorWithWhite: 0.77 alpha: 0.64] // Color Ramp tool overlay defines #define kColorRampToolOverlay_MinZoomFactorToDrawXMarks 8 #define kColorRampToolOverlay_LineWidth_XMarkLine (0.0) #define kColorRampToolOverlay_LineWidth_XMarkHalo (2.0) #define kUIColor_ColorRampToolOverlay_XMarkLine \ [NSColor ppSRGBColorWithWhite: 0.6 alpha: 0.7] #define kUIColor_ColorRampToolOverlay_XMarkHalo \ [NSColor ppSRGBColorWithWhite: 0.85 alpha: 0.7] #define kUIColor_ColorRampToolOverlay_DarkDashes \ [NSColor ppSRGBColorWithWhite: 0.10 alpha: 1.0] #define kUIColor_ColorRampToolOverlay_LightDashes \ [NSColor ppSRGBColorWithWhite: 0.95 alpha: 1.0] @implementation NSObject (PPGNUstepGlue_PatternedLines) + (void) ppGSGlue_PatternedLines_InstallPatches { macroSwizzleInstanceMethod(PPCanvasView, drawSelectionOutline, ppGSPatch_DrawSelectionOutline); macroSwizzleInstanceMethod(PPCanvasView, drawEraserToolOverlay, ppGSPatch_DrawEraserToolOverlay); macroSwizzleInstanceMethod(PPCanvasView, drawColorRampToolOverlay, ppGSPatch_DrawColorRampToolOverlay); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_PatternedLines_InstallPatches); } @end @implementation PPCanvasView (PPGNUstepGlue_PatternedLines) - (void) ppGSPatch_DrawSelectionOutline { static NSColor *darkDashColor, *lightDashColor; static CGFloat dashValues[] = {3,3}; static int numDashValues = sizeof(dashValues)/sizeof(*dashValues); int dashPhase; if (!_hasSelectionOutline || _shouldHideSelectionOutline) { return; } if (!darkDashColor) { darkDashColor = [kUIColor_SelectionOutline_DarkDashes retain]; } if (!lightDashColor) { lightDashColor = [kUIColor_SelectionOutline_LightDashes retain]; } // the current implementation of the selection outline path allows the path to extend // one pixel beyond the right & bottom edges of the visible canvas; as a workaround, // set the clipping path to prevent drawing outside the canvas [NSGraphicsContext saveGraphicsState]; [NSBezierPath clipRect: _offsetZoomedVisibleCanvasBounds]; // dark dashes: draw as a solid line - will be overdrawn by light-dashes line [darkDashColor set]; [_zoomedSelectionOutlineTopRightPath setLineDash: NULL count: 0 phase: 0]; [_zoomedSelectionOutlineTopRightPath stroke]; [_zoomedSelectionOutlineBottomLeftPath setLineDash: NULL count: 0 phase: 0]; [_zoomedSelectionOutlineBottomLeftPath stroke]; // light dashes [lightDashColor set]; // selection outline pattern image is 8x8 dashPhase = 8 - _selectionOutlineTopRightAnimationPhase.x; [_zoomedSelectionOutlineTopRightPath setLineDash: dashValues count: numDashValues phase: dashPhase]; [_zoomedSelectionOutlineTopRightPath stroke]; [_zoomedSelectionOutlineBottomLeftPath setLineDash: dashValues count: numDashValues phase: dashPhase]; [_zoomedSelectionOutlineBottomLeftPath stroke]; [NSGraphicsContext restoreGraphicsState]; } - (void) ppGSPatch_DrawEraserToolOverlay { static NSColor *darkDotColor = nil, *lightDotColor = nil; static CGFloat dashValues[] = {1,2}; static int numDashValues = sizeof(dashValues)/sizeof(*dashValues); int dashPhase; if (!_shouldDisplayEraserToolOverlay) return; if (!darkDotColor) { darkDotColor = [kUIColor_EraserToolOutline_DarkDots retain]; } if (!lightDotColor) { lightDotColor = [kUIColor_EraserToolOutline_LightDots retain]; } // dark dots [darkDotColor set]; dashPhase = 0; [_eraserToolOverlayPath_Outline setLineDash: dashValues count: numDashValues phase: dashPhase]; [_eraserToolOverlayPath_Outline stroke]; // light dots [lightDotColor set]; dashPhase = 1; [_eraserToolOverlayPath_Outline setLineDash: dashValues count: numDashValues phase: dashPhase]; [_eraserToolOverlayPath_Outline stroke]; } - (void) ppGSPatch_DrawColorRampToolOverlay { static NSColor *xMarkHaloColor = nil, *xMarkLineColor = nil, *darkDashColor = nil, *lightDashColor = nil; static CGFloat dashValues[] = {1,1}; static int numDashValues = sizeof(dashValues)/sizeof(*dashValues); if (!_shouldDisplayColorRampToolOverlay) return; if (!xMarkHaloColor) { xMarkHaloColor = [kUIColor_ColorRampToolOverlay_XMarkHalo retain]; } if (!xMarkLineColor) { xMarkLineColor = [kUIColor_ColorRampToolOverlay_XMarkLine retain]; } if (!darkDashColor) { darkDashColor = [kUIColor_ColorRampToolOverlay_DarkDashes retain]; } if (!lightDashColor) { lightDashColor = [kUIColor_ColorRampToolOverlay_LightDashes retain]; } if (![_colorRampToolOverlayPath_XMarks isEmpty] && (_zoomFactor >= kColorRampToolOverlay_MinZoomFactorToDrawXMarks)) { [xMarkHaloColor set]; [_colorRampToolOverlayPath_XMarks setLineWidth: kColorRampToolOverlay_LineWidth_XMarkHalo]; [_colorRampToolOverlayPath_XMarks stroke]; [xMarkLineColor set]; [_colorRampToolOverlayPath_XMarks setLineWidth: kColorRampToolOverlay_LineWidth_XMarkLine]; [_colorRampToolOverlayPath_XMarks stroke]; } [darkDashColor set]; [_colorRampToolOverlayPath_Outline setLineDash: NULL count: 0 phase: 0]; [_colorRampToolOverlayPath_Outline stroke]; [lightDashColor set]; [_colorRampToolOverlayPath_Outline setLineDash: dashValues count: numDashValues phase: 0]; [_colorRampToolOverlayPath_Outline stroke]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_PopupPanelFrames.m0000644000076500000240000000471113234416764024253 0ustar joshstaff/* PPGNUstepGlue_PopupPanelFrames.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPPopupPanelController.h" #import "PPPopupPanel.h" #import "PPFilledRoundedRectView.h" static bool gDisallowPopupPanelFrameChange = NO; @implementation NSObject (PPGNUstepGlue_PopupPanelFrames) + (void) ppGSGlue_PopupPanelFrames_InstallPatches { macroSwizzleInstanceMethod(PPPopupPanelController, loadWindow, ppGSPatch_LoadWindow); macroSwizzleInstanceMethod(PPPopupPanel, setFrame:display:, ppGSPatch_SetFrame:display:); macroSwizzleInstanceMethod(PPFilledRoundedRectView, setFrame:, ppGSPatch_SetFrame:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_PopupPanelFrames_InstallPatches); } @end @implementation PPPopupPanelController (PPGNUstepGlue_PopupPanelFrames) - (void) ppGSPatch_LoadWindow { gDisallowPopupPanelFrameChange = YES; [self ppGSPatch_LoadWindow]; gDisallowPopupPanelFrameChange = NO; } @end @implementation PPPopupPanel (PPGNUstepGlue_PopupPanelFrames) - (void) ppGSPatch_SetFrame: (NSRect) windowFrame display: (BOOL) displayViews { if (gDisallowPopupPanelFrameChange) return; [self ppGSPatch_SetFrame: windowFrame display: displayViews]; } @end @implementation PPFilledRoundedRectView (PPGNUstepGlue_PopupPanelFrames) - (void) ppGSPatch_SetFrame: (NSRect) newFrame { [super setFrame: newFrame]; [self performSelector: @selector(setupFilledRoundedRectImage)]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_PopupPanelHidingOnWindowMove.m0000644000076500000240000001262713354102533026546 0ustar joshstaff/* PPGNUstepGlue_PopupPanelHidingOnWindowMove.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPDocumentWindowController.h" #import "PPPopupPanelsController.h" #import "PPSamplerImagePopupPanelController.h" static int gNumBlocksOnPopupPanelHiding = 0; @interface PPDocumentWindowController (PPGNUstepGlue_PopupPanelHidingOnWindowMoveUtilities) + (void) ppGSGlue_PopupPanelHidingOnWindowMove_Block; + (void) ppGSGlue_PopupPanelHidingOnWindowMove_Unblock; + (void) ppGSGlue_PopupPanelHidingOnWindowMove_UnblockFromNewStackFrame; @end @implementation NSObject (PPGNUstepGlue_PopupPanelHidingOnWindowMove) + (void) ppGSGlue_PopupPanelHidingOnWindowMove_InstallPatches { macroSwizzleInstanceMethod(PPDocumentWindowController, handleNSWindowNotification_WillMove:, ppGSPatch_HandleNSWindowNotification_WillMove:); macroSwizzleInstanceMethod(PPPopupPanelsController, setActivePopupPanel:, ppGSPatch_PopupPanelHidingOnWindowMove_SetActivePopupPanel:); macroSwizzleInstanceMethod(PPSamplerImagePopupPanelController, windowWillResize:toSize:, ppGSPatch_WindowWillResize:toSize:); macroSwizzleClassMethod(NSColorPanel, dragColor:withEvent:fromView:, ppGSPatch_DragColor:withEvent:fromView:); macroSwizzleInstanceMethod(NSPopUpButtonCell, attachPopUpWithFrame:inView:, ppGSPatch_AttachPopUpWithFrame:inView:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads( ppGSGlue_PopupPanelHidingOnWindowMove_InstallPatches); } @end @implementation PPDocumentWindowController (PPGNUstepGlue_PopupPanelHidingOnWindowMove) - (void) ppGSPatch_HandleNSWindowNotification_WillMove: (NSNotification *) notification { if (gNumBlocksOnPopupPanelHiding > 0) { return; } [self ppGSPatch_HandleNSWindowNotification_WillMove: notification]; } @end @implementation PPPopupPanelsController (PPGNUstepGlue_PopupPanelHidingOnWindowMove) - (void) ppGSPatch_PopupPanelHidingOnWindowMove_SetActivePopupPanel: (PPPopupPanelType) popupPanelType { [PPDocumentWindowController ppGSGlue_PopupPanelHidingOnWindowMove_Block]; [self ppGSPatch_PopupPanelHidingOnWindowMove_SetActivePopupPanel: popupPanelType]; [PPDocumentWindowController ppGSGlue_PopupPanelHidingOnWindowMove_UnblockFromNewStackFrame]; } @end @implementation PPSamplerImagePopupPanelController (PPGNUstepGlue_PopupPanelHidingOnWindowMove) - (NSSize) ppGSPatch_WindowWillResize: (NSWindow *) sender toSize: (NSSize) proposedFrameSize { NSSize newWindowSize; [PPDocumentWindowController ppGSGlue_PopupPanelHidingOnWindowMove_Block]; newWindowSize = [self ppGSPatch_WindowWillResize: sender toSize: proposedFrameSize]; [PPDocumentWindowController ppGSGlue_PopupPanelHidingOnWindowMove_UnblockFromNewStackFrame]; return newWindowSize; } @end @implementation NSColorPanel (PPGNUstepGlue_PopupPanelHidingOnWindowMove) + (BOOL) ppGSPatch_DragColor: (NSColor *) aColor withEvent: (NSEvent *) anEvent fromView: (NSView *) sourceView { BOOL returnVal; [PPDocumentWindowController ppGSGlue_PopupPanelHidingOnWindowMove_Block]; returnVal = [self ppGSPatch_DragColor: aColor withEvent: anEvent fromView: sourceView]; [PPDocumentWindowController ppGSGlue_PopupPanelHidingOnWindowMove_Unblock]; return returnVal; } @end @implementation NSPopUpButtonCell (PPGNUstepGlue_PopupPanelHidingOnWindowMove) - (void) ppGSPatch_AttachPopUpWithFrame: (NSRect) cellFrame inView: (NSView *) controlView { [PPDocumentWindowController ppGSGlue_PopupPanelHidingOnWindowMove_Block]; [self ppGSPatch_AttachPopUpWithFrame: cellFrame inView: controlView]; [PPDocumentWindowController ppGSGlue_PopupPanelHidingOnWindowMove_Unblock]; } @end @implementation PPDocumentWindowController (PPGNUstepGlue_PopupPanelHidingOnWindowMoveUtilities) + (void) ppGSGlue_PopupPanelHidingOnWindowMove_Block { gNumBlocksOnPopupPanelHiding++; } + (void) ppGSGlue_PopupPanelHidingOnWindowMove_Unblock { gNumBlocksOnPopupPanelHiding--; } + (void) ppGSGlue_PopupPanelHidingOnWindowMove_UnblockFromNewStackFrame { [self ppPerformSelectorFromNewStackFrame: @selector(ppGSGlue_PopupPanelHidingOnWindowMove_Unblock)]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_PreviewImageViewResizing.m0000644000076500000240000001647413264227761025775 0ustar joshstaff/* PPGNUstepGlue_PreviewImageViewResizing.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds for resizing issues with the preview image views on the Export & Scaling sheets // that caused scrollbars to remain visible when not needed #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPExportPanelAccessoryViewController.h" #import "PPDocumentScaleSheetController.h" #import "GNUstepGUI/GSTheme.h" #import "PPGeometry.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" @implementation NSObject (PPGNUstepGlue_PreviewImageViewResizing) + (void) ppGSGlue_PreviewImageViewResizing_InstallPatches { macroSwizzleInstanceMethod(PPExportPanelAccessoryViewController, resizePreviewViewForImageWithSize:, ppGSPatch_ResizePreviewViewForImageWithSize:); macroSwizzleInstanceMethod(PPDocumentScaleSheetController, updatePreviewImageForCurrentScaledSize, ppGSPatch_UpdatePreviewImageForCurrentScaledSize); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_PreviewImageViewResizing_InstallPatches); } @end @implementation PPExportPanelAccessoryViewController (PPGNUstepGlue_PreviewImageViewResizing) - (void) ppGSPatch_ResizePreviewViewForImageWithSize: (NSSize) previewImageSize { NSScrollView *previewScrollView; NSSize borderFramePadding; NSRect newPreviewScrollViewFrame; int viewMarginPadding; previewScrollView = [_previewImageView enclosingScrollView]; borderFramePadding = [[GSTheme theme] sizeForBorderType: [previewScrollView borderType]]; newPreviewScrollViewFrame = _previewScrollViewInitialFrame; if (previewImageSize.width < _previewScrollViewInitialFrame.size.width) { if (previewImageSize.height > _previewScrollViewInitialFrame.size.height) { viewMarginPadding = _previewScrollerWidth; } else { viewMarginPadding = 2 * borderFramePadding.width; } newPreviewScrollViewFrame.size.width = previewImageSize.width + viewMarginPadding; } if (previewImageSize.height < _previewScrollViewInitialFrame.size.height) { if (previewImageSize.width > _previewScrollViewInitialFrame.size.width) { viewMarginPadding = _previewScrollerWidth; } else { viewMarginPadding = 2 * borderFramePadding.height; } newPreviewScrollViewFrame.size.height = previewImageSize.height + viewMarginPadding; } newPreviewScrollViewFrame = PPGeometry_CenterRectInRect(newPreviewScrollViewFrame, _previewScrollViewInitialFrame); _shouldPreservePreviewNormalizedCenter = YES; // to set up previewScrollView's scrollbars correctly, first set _previewImageView's frame // to a small size [_previewImageView setFrameSize: NSMakeSize(1,1)]; [previewScrollView setFrame: newPreviewScrollViewFrame]; [_previewImageView setFrameSize: previewImageSize]; // Changing scrollview frame causes drawing artifacts (10.4) - fix by redrawing superview [[previewScrollView superview] setNeedsDisplayInRect: _previewScrollViewInitialFrame]; _previewImageSize = previewImageSize; [self performSelector: @selector(scrollPreviewToNormalizedCenter)]; _shouldPreservePreviewNormalizedCenter = NO; } @end @implementation PPDocumentScaleSheetController (PPGNUstepGlue_PreviewImageViewResizing) - (void) ppGSPatch_UpdatePreviewImageForCurrentScaledSize { NSScrollView *previewScrollView; NSSize borderFramePadding; NSRect newPreviewScrollViewFrame; int viewMarginPadding; previewScrollView = [_previewImageView enclosingScrollView]; borderFramePadding = [[GSTheme theme] sizeForBorderType: [previewScrollView borderType]]; newPreviewScrollViewFrame = _previewScrollViewInitialFrame; if (_scaledSize.width < _previewScrollViewInitialFrame.size.width) { if (_scaledSize.height > _previewScrollViewInitialFrame.size.height) { viewMarginPadding = _previewScrollerWidth; } else { viewMarginPadding = 2 * borderFramePadding.width; } newPreviewScrollViewFrame.size.width = _scaledSize.width + viewMarginPadding; } if (_scaledSize.height < _previewScrollViewInitialFrame.size.height) { if (_scaledSize.width > _previewScrollViewInitialFrame.size.width) { viewMarginPadding = _previewScrollerWidth; } else { viewMarginPadding = 2 * borderFramePadding.height; } newPreviewScrollViewFrame.size.height = _scaledSize.height + viewMarginPadding; } newPreviewScrollViewFrame = PPGeometry_CenterRectInRect(newPreviewScrollViewFrame, _previewScrollViewInitialFrame); _shouldPreservePreviewNormalizedCenter = YES; // to set up previewScrollView's scrollbars correctly, first set _previewImageView's frame // to a small size [_previewImageView setFrameSize: NSMakeSize(1,1)]; [previewScrollView setFrame: newPreviewScrollViewFrame]; [_previewImageView setFrameSize: _scaledSize]; // Changing scrollview frame causes drawing artifacts (10.4) - fix by redrawing superview [[previewScrollView superview] setNeedsDisplayInRect: _previewScrollViewInitialFrame]; // NSImageView seems to ignore (non)antialiasing settings when drawing downsized images // (on 10.5+?), so when downscaling, have to set the preview to a manually-resized image if (_scalingType == kPPScalingType_Downscale) { // use a local autorelease pool to make sure old images & bitmaps get dealloc'd during // slider tracking NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init]; [_previewImageView setImage: [NSImage ppImageWithBitmap: [_canvasBitmap ppBitmapResizedToSize: _scaledSize shouldScale: YES]]]; [autoreleasePool release]; } else // !(_scalingType == kPPScalingType_Downscale) { // upscaling - let NSImageView handle the resizing [_previewImageView setImage: _canvasImage]; } [self performSelector: @selector(scrollPreviewToNormalizedCenter)]; _shouldPreservePreviewNormalizedCenter = NO; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ResizeControl.m0000644000076500000240000000607513234416764023641 0ustar joshstaff/* PPGNUstepGlue_ResizeControl.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPResizeControl.h" #import "PPGeometry.h" #import "NSEvent_PPUtilities.h" @implementation NSObject (PPGNUstepGlue_ResizeControl) + (void) ppGSGlue_ResizeControl_InstallPatches { macroSwizzleInstanceMethod(PPResizeControl, mouseDown:, ppGSPatch_MouseDown:); macroSwizzleInstanceMethod(PPResizeControl, mouseDragged:, ppGSPatch_MouseDragged:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ResizeControl_InstallPatches); } @end @implementation PPResizeControl (PPGNUstepGlue_ResizeControl) - (void) ppGSPatch_MouseDown: (NSEvent *) theEvent { [self ppGSPatch_MouseDown: theEvent]; _mouseDownLocation = [NSEvent mouseLocation]; } - (void) ppGSPatch_MouseDragged: (NSEvent *) theEvent { NSWindow *window; NSRect windowFrame, newWindowFrame; NSPoint currentMouseLocation, mouseOffset; window = [self window]; windowFrame = [window frame]; // merging all mouseDragged events in the queue saves some redrawing (ignore the return val) [theEvent ppMouseDragDeltaPointByMergingWithEnqueuedMouseDraggedEvents]; currentMouseLocation = [NSEvent mouseLocation]; mouseOffset = PPGeometry_PointDifference(currentMouseLocation, _mouseDownLocation); newWindowFrame.size = NSMakeSize(_initialWindowSize.width + mouseOffset.x, _initialWindowSize.height - mouseOffset.y); newWindowFrame.size = [_windowDelegate windowWillResize: window toSize: newWindowFrame.size]; if (PPGeometry_IsZeroSize(newWindowFrame.size)) { goto ERROR; } newWindowFrame.origin = NSMakePoint(_initialWindowTopLeftPoint.x, _initialWindowTopLeftPoint.y - newWindowFrame.size.height); if (!NSEqualRects(windowFrame, newWindowFrame)) { [window setFrame: newWindowFrame display: YES]; } return; ERROR: return; } - (BOOL) acceptsFirstMouse: (NSEvent *) theEvent { return YES; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ScrollerAutohiding.m0000644000076500000240000000766413272454020024632 0ustar joshstaff/* PPGNUstepGlue_ScrollerAutohiding.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Fix for a scroller-autohiding issue that can cause the app to freeze: If the user resizes // the PPDocumentWindow to within a pixel or two of the actual width/height of the canvas, // sometimes this can cause an infinite-recursive loop that will eventually overflow the stack: // clipview resize -> hidden scroller is auto-shown -> scroller change causes clipview resize -> // visible scroller is auto-hidden -> scroller change causes clipview resize -> hidden scroller // is auto-shown -> etc. // This issue only appears on GNUstep (no freezes on OS X), but it's probably // PikoPixel-specific, due to the way PPCanvasView resizes itself in reponse to // enclosing-clipview notifications, as well as the way PikoPixel's custom GNUstep theme // resizes clipviews after -[NSScrollView tile] in order to maintain a custom gap between the // clipview & scrollers (2-pixels instead of 1-pixel). // The workaround is to break the cycle of hiding/showing/hiding scrollers by patching // -[NSScrollView tile] to keep track of its level of recursion, and disallowing the hiding of // visible scrollers from within recursive calls. (If the clipview is large enough so the // scrollers do need to be hidden, they will have been hidden from within the initial // (nonrecursive) call to -[NSScrollView tile], where scroller hiding is allowed). #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" static bool gDisallowScrollerHiding = NO; @implementation NSObject (PPGNUstepGlue_ScrollerAutohiding) + (void) ppGSGlue_ScrollerAutohiding_InstallPatches { macroSwizzleInstanceMethod(NSScrollView, tile, ppGSPatch_ScrollerAutohiding_Tile); macroSwizzleInstanceMethod(NSScrollView, setHasVerticalScroller:, ppGSPatch_SetHasVerticalScroller:); macroSwizzleInstanceMethod(NSScrollView, setHasHorizontalScroller:, ppGSPatch_SetHasHorizontalScroller:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ScrollerAutohiding_InstallPatches); } @end @implementation NSScrollView (PPGNUstepGlue_ScrollerAutohiding) - (void) ppGSPatch_ScrollerAutohiding_Tile { static int recursionCount = 0; bool oldDisallowScrollerHiding = gDisallowScrollerHiding; if (recursionCount > 0) { gDisallowScrollerHiding = YES; } recursionCount++; [self ppGSPatch_ScrollerAutohiding_Tile]; recursionCount--; gDisallowScrollerHiding = oldDisallowScrollerHiding; } - (void) ppGSPatch_SetHasVerticalScroller: (BOOL) flag { if (!flag && gDisallowScrollerHiding && [self hasVerticalScroller]) { flag = YES; } [self ppGSPatch_SetHasVerticalScroller: flag]; } - (void) ppGSPatch_SetHasHorizontalScroller: (BOOL) flag { if (!flag && gDisallowScrollerHiding && [self hasHorizontalScroller]) { flag = YES; } [self ppGSPatch_SetHasHorizontalScroller: flag]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_SegmentedCellTracking.m0000644000076500000240000000426013245375164025227 0ustar joshstaff/* PPGNUstepGlue_SegmentedCellTracking.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workaround for GNUstep issue which causes NSSegmentedControls to ignore mouseclicks // (as of 2018-02-27, the issue has been fixed in the GNUstep trunk) #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" @implementation NSObject (PPGNUstepGlue_SegmentedCellTracking) + (void) ppGSGlue_SegmentedCellTracking_InstallPatches { macroSwizzleInstanceMethod(NSSegmentedCell, startTrackingAt:inView:, ppGSPatch_StartTrackingAt:inView:); macroSwizzleInstanceMethod(NSSegmentedCell, continueTracking:at:inView:, ppGSPatch_ContinueTracking:at:inView:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_SegmentedCellTracking_InstallPatches); } @end @implementation NSSegmentedCell (PPGNUstepGlue_SegmentedCellTracking) - (BOOL) ppGSPatch_StartTrackingAt: (NSPoint) startPoint inView: (NSView *) controlView { return ([controlView mouse: startPoint inRect: [controlView bounds]]) ? YES : NO; } - (BOOL) ppGSPatch_ContinueTracking: (NSPoint) lastPoint at: (NSPoint) currentPoint inView: (NSView *) controlView { return YES; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_SliderDragging.m0000644000076500000240000001507313354101752023711 0ustar joshstaff/* PPGNUstepGlue_SliderDragging.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Three fixes for dragging sliders on GNUstep: // 1) Better responsiveness on sliders that control a slow operation (such as the navigator // popup's zoom slider); The fix works by processing only the last mouseDragged event in the // event queue (discarding earlier mouseDragged events) so the expensive operation can be // skipped for out-of-date events that correspond to an old mouse position. // 2) Make the mouse-tracking behavior the same as on OS X: When the dragging-mouse is moved // outside the bounds of the slider control, Macs continue sending the control's action message, // but GNUstep does not; The fix is to patch -[NSView mouse:inRect:] for the three NSView // subclasses that contain NSSliderCells in PikoPixel (PPParabolicSlider, NSSlider, // & PPLayersTableView), so they always return YES while tracking. When // -[NSCell trackMouse:inRect:ofView:untilMouseUp:] calls one of the patched methods to check // whether the mouse is still inside the rect, it will receive YES no matter where the mouse is, // so the control's action message will always be sent. // 3) Workaround for rare crash in GSHorizontalTypesetter while dragging a slider with an // empty title; Patched init & initWithCoder: methods to return a slider with its title cell // set to nil (so that when -[NSSliderCell drawInteriorWithFrame:...] calls // [_titleCell drawInteriorWithFrame:...], it's a no-op), and patched setTitle: so that when // setting a non-empty title, it first sets up a non-nil title cell. #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPApplication.h" #import "PPParabolicSlider.h" #import "PPLayersTableView.h" #import "NSEvent_PPUtilities.h" static bool gIsTrackingMouseInSlider = NO; @implementation NSObject (PPGNUstepGlue_SliderDragging) + (void) ppGSGlue_SliderDragging_InstallPatches { macroSwizzleInstanceMethod(NSSliderCell, init, ppGSPatch_Init); macroSwizzleInstanceMethod(NSSliderCell, initWithCoder:, ppGSPatch_InitWithCoder:); macroSwizzleInstanceMethod(NSSliderCell, setTitle:, ppGSPatch_SetTitle:); macroSwizzleInstanceMethod(NSSliderCell, startTrackingAt:inView:, ppGSPatch_StartTrackingAt:inView:); macroSwizzleInstanceMethod(NSSliderCell, stopTracking:at:inView:mouseIsUp:, ppGSPatch_StopTracking:at:inView:mouseIsUp:); macroSwizzleInstanceMethod(PPApplication, nextEventMatchingMask:untilDate:inMode:dequeue:, ppGSPatch_NextEventMatchingMask:untilDate:inMode:dequeue:); // Patch -[NSView mouse:inRect:] for all NSView subclasses that contain an NSSliderCell in // PikoPixel: PPParabolicSlider, NSSlider, PPLayersTableView macroSwizzleInstanceMethod(PPParabolicSlider, mouse:inRect:, ppGSPatch_Mouse:inRect:); macroSwizzleInstanceMethod(NSSlider, mouse:inRect:, ppGSPatch_Mouse:inRect:); macroSwizzleInstanceMethod(PPLayersTableView, mouse:inRect:, ppGSPatch_Mouse:inRect:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_SliderDragging_InstallPatches); } @end @implementation NSSliderCell (PPGNUstepGlue_SliderDragging) - (id) ppGSPatch_Init { self = [self ppGSPatch_Init]; [self setTitleCell: nil]; return self; } - (id) ppGSPatch_InitWithCoder: (NSCoder *) decoder { self = [self ppGSPatch_InitWithCoder: decoder]; [self setTitleCell: nil]; return self; } - (void) ppGSPatch_SetTitle: (NSString *) title { if (![self titleCell] && [title length]) { NSTextFieldCell *titleCell = [[[NSTextFieldCell alloc] init] autorelease]; [titleCell setTextColor: [NSColor controlTextColor]]; [titleCell setAlignment: NSCenterTextAlignment]; [self setTitleCell: titleCell]; } [self ppGSPatch_SetTitle: title]; } - (BOOL) ppGSPatch_StartTrackingAt: (NSPoint) startPoint inView: (NSView *) controlView { BOOL didStartTracking = [self ppGSPatch_StartTrackingAt: startPoint inView: controlView]; if (didStartTracking) { gIsTrackingMouseInSlider = YES; } return didStartTracking; } - (void) ppGSPatch_StopTracking: (NSPoint) lastPoint at: (NSPoint) stopPoint inView: (NSView *) controlView mouseIsUp: (BOOL) flag { gIsTrackingMouseInSlider = NO; [self ppGSPatch_StopTracking: lastPoint at: stopPoint inView: controlView mouseIsUp: flag]; } @end @implementation PPApplication (PPGNUstepGlue_SliderDragging) - (NSEvent *) ppGSPatch_NextEventMatchingMask: (NSUInteger) mask untilDate: (NSDate *) expiration inMode: (NSString *) mode dequeue: (BOOL) flag { static int recursionLevel = 0; NSEvent *event = [self ppGSPatch_NextEventMatchingMask: mask untilDate: expiration inMode: mode dequeue: flag]; if (gIsTrackingMouseInSlider && (recursionLevel == 0) && ([event type] == NSLeftMouseDragged)) { // -[NSEvent ppLatestMouseDraggedEventFromEventQueue] calls back to this method, so // keep track of recursion level to prevent recursing more than once recursionLevel++; event = [event ppLatestMouseDraggedEventFromEventQueue]; recursionLevel--; } return event; } @end @implementation NSView (PPGNUstepGlue_SliderDragging) - (BOOL) ppGSPatch_Mouse: (NSPoint) aPoint inRect: (NSRect) aRect { if (gIsTrackingMouseInSlider) { return YES; } return [self ppGSPatch_Mouse: aPoint inRect: aRect]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_TIFFRepresentations.m0000644000076500000240000000656013234416764024674 0ustar joshstaff/* PPGNUstepGlue_TIFFRepresentations.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds for two GNUstep issues with creating TIFF representations (NSData): // - Calling -[NSImage TIFFRepresentation] on (some) valid images causes a TIFF library error // - TIFF data written by GNUstep GUI 0.25.0 is incorrect (apparently fixed in GUI 0.25.1) #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" @implementation NSObject (PPGNUstepGlue_TIFFRepresentations) + (void) ppGSGlue_TIFFRepresentations_InstallPatches { macroSwizzleClassMethod(NSBitmapImageRep, TIFFRepresentationOfImageRepsInArray:, ppGSPatch_TIFFRepresentationOfImageRepsInArray:); macroSwizzleInstanceMethod(NSBitmapImageRep, ppCompressedTIFFData, ppGSPatch_CompressedTIFFData); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_TIFFRepresentations_InstallPatches); } @end @implementation NSBitmapImageRep (PPGNUstepGlue_TIFFRepresentations) // PATCH: +[NSBitmapImageRep TIFFRepresentationOfImageRepsInArray:] // Calling -[NSImage TIFFRepresentation] on some valid images causes a TIFF library error from // within +[NSBitmapImageRep TIFFRepresentationOfImageRepsInArray:]. Workaround is to patch // +[NSBitmapImageRep TIFFRepresentationOfImageRepsInArray:], and if the imageReps array just // contains a single bitmap (which should be the case for all NSImages in PikoPixel), call // -[NSBitmapImageRep TIFFRepresentation] instead (which seems to work correctly). + (NSData *) ppGSPatch_TIFFRepresentationOfImageRepsInArray: (NSArray *) anArray { if ([anArray count] == 1) { NSBitmapImageRep *bitmapRep = [anArray objectAtIndex: 0]; if ([bitmapRep isKindOfClass: [NSBitmapImageRep class]]) { NSData *tiffData = [bitmapRep TIFFRepresentation]; if (tiffData) { return tiffData; } } } return [self ppGSPatch_TIFFRepresentationOfImageRepsInArray: anArray]; } // PATCH: -[NSBitmapImageRep (PPUtilities) ppCompressedTIFFData] // GNUstep GUI 0.25.0 has issues reading back TIFF data that it wrote (OS X can't read the TIFF // data either), so patched to write PNG-format data instead. (This issue appears to have been // fixed in GUI 0.25.1). - (NSData *) ppGSPatch_CompressedTIFFData { return [self ppCompressedPNGData]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_TitleablePopUpButton.m0000644000076500000240000001235614370573400025114 0ustar joshstaff/* PPGNUstepGlue_TitleablePopUpButton.m Copyright 2014-2018,2023 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPTitleablePopUpButton.h" #define kTitlePrefixString @" " static NSArray *gDefaultRunLoopModes = nil, *gModalPanelRunLoopModes = nil; @implementation NSObject (PPGNUstepGlue_TitleablePopUpButton) + (void) ppGSGlue_TitleablePopUpButton_InstallPatches { macroSwizzleInstanceMethod(PPTitleablePopUpButton, awakeFromNib, ppGSPatch_AwakeFromNib); macroSwizzleInstanceMethod(PPTitleablePopUpButton, setTitle:, ppGSPatch_SetTitle:); macroSwizzleInstanceMethod(PPTitleablePopUpButton, setTitle:withTextAttributes:, ppGSPatch_SetTitle:withTextAttributes:); macroSwizzleInstanceMethod(PPTitleablePopUpButton, handleNSPopUpButtonNotification_WillPopUp:, ppGSPatch_HandleNSPopUpButtonNotification_WillPopUp:); macroSwizzleInstanceMethod(PPTitleablePopUpButton, handleNSMenuNotification_WillSendAction:, ppGSPatch_HandleNSMenuNotification_WillSendAction:); macroSwizzleInstanceMethod(PPTitleablePopUpButton, handleNSMenuNotification_DidEndTracking:, ppGSPatch_HandleNSMenuNotification_DidEndTracking:); } + (void) ppGSGlue_TitleablePopUpButton_Install { gDefaultRunLoopModes = [[NSArray arrayWithObject: NSDefaultRunLoopMode] retain]; gModalPanelRunLoopModes = [[NSArray arrayWithObject: NSModalPanelRunLoopMode] retain]; [self ppGSGlue_TitleablePopUpButton_InstallPatches]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_TitleablePopUpButton_Install); } @end @implementation PPTitleablePopUpButton (PPGNUstepGlue_TitleablePopUpButton) - (void) ppGSPatch_AwakeFromNib { [self ppGSPatch_AwakeFromNib]; // There's an issue with PPTitleablePopUpButtons loaded from nibs on recent versions of // GNUstep: The popup menu stays hidden when the button's clicked. // This is due to the menu's _popUpButtonCell member not being set (it should point to the // button's cell); The workaround is to set it manually: [[super menu] _setOwnedByPopUp: [self cell]]; } - (void) ppGSPatch_SetTitle: (NSString *) aString { if (aString) { aString = [kTitlePrefixString stringByAppendingString: aString]; } if (!aString) { aString = kTitlePrefixString; } [super removeAllItems]; [super addItemWithTitle: aString]; } - (void) ppGSPatch_SetTitle: (NSString *) title withTextAttributes: (NSDictionary *) textAttributes { [self setTitle: title]; } - (void) ppGSPatch_HandleNSPopUpButtonNotification_WillPopUp: (NSNotification *) notification { int numPopupMenuItems, itemIndex; NSMenu *realPopupMenu; id menuItemForRealPopupMenu; NSArray *runLoopModes; [self performSelector: @selector(notifyDelegateWillDisplayPopupMenu)]; [super removeAllItems]; realPopupMenu = [super menu]; numPopupMenuItems = [_popupMenu numberOfItems]; for (itemIndex=0; itemIndex < numPopupMenuItems; itemIndex++) { menuItemForRealPopupMenu = [[[_popupMenu itemAtIndex: itemIndex] performSelector: @selector(copy)] autorelease]; [realPopupMenu addItem: menuItemForRealPopupMenu]; } [super selectItemAtIndex: _indexOfSelectedPopupMenuItem]; [self performSelector: @selector(addAsObserverForNSMenuNotifications)]; runLoopModes = ([self window] == [NSApp modalWindow]) ? gModalPanelRunLoopModes : gDefaultRunLoopModes; [self performSelector: @selector(handleNSMenuNotification_DidEndTracking:) withObject: nil afterDelay: 0.0f inModes: runLoopModes]; } - (void) ppGSPatch_HandleNSMenuNotification_WillSendAction: (NSNotification *) notification { NSMenuItem *menuItem = [[notification userInfo] objectForKey: @"MenuItem"]; _indexOfSelectedPopupMenuItem = [super indexOfItem: menuItem]; } - (void) ppGSPatch_HandleNSMenuNotification_DidEndTracking: (NSNotification *) notification { [self performSelector: @selector(updateTitle)]; [self performSelector: @selector(removeAsObserverForNSMenuNotifications)]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_ViewDisplayCaching.m0000644000076500000240000000667713234416764024564 0ustar joshstaff/* PPGNUstepGlue_ViewDisplayCaching.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workaround for GNUStep issue where -[NSView cacheDisplayInRect:toBitmapImageRep:] doesn't // capture content from any of the view's subviews, only the view itself. #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" @interface NSView (PPGNUstepGlue_ViewDisplayCachingUtilities) - (NSImage *) ppGSGlue_ContentImage; @end @implementation NSObject (PPGNUstepGlue_ViewDisplayCaching) + (void) ppGSGlue_ViewDisplayCaching_InstallPatches { macroSwizzleInstanceMethod(NSView, cacheDisplayInRect:toBitmapImageRep:, ppGSPatch_CacheDisplayInRect:toBitmapImageRep:); } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_ViewDisplayCaching_InstallPatches); } @end @implementation NSView (PPGNUstepGlue_ViewDisplayCaching) // PATCH: -[NSView cacheDisplayInRect:toBitmapImageRep:] // GNUstep's implmentation only reads the top-level view's pixels, ignoring subviews - // override adds support for subviews (only first level, though) in order to work properly with // PPCompositeThumbnail - (void) ppGSPatch_CacheDisplayInRect: (NSRect) rect toBitmapImageRep: (NSBitmapImageRep *) bitmapImageRep { NSImage *contentImage; NSEnumerator *subviewsEnumerator; NSView *subview; [bitmapImageRep ppSetAsCurrentGraphicsContext]; contentImage = [self ppGSGlue_ContentImage]; [contentImage drawInRect: [self bounds] fromRect: [self bounds] operation: NSCompositeCopy fraction: 1.0]; subviewsEnumerator = [[self subviews] objectEnumerator]; while (subview = [subviewsEnumerator nextObject]) { contentImage = [subview ppGSGlue_ContentImage]; [contentImage drawInRect: [subview frame] fromRect: [subview bounds] operation: NSCompositeSourceOver fraction: 1.0]; } [bitmapImageRep ppRestoreGraphicsContext]; } // ppGSGlue_ContentImage returns an NSImage of a single view's drawn content (no content from // subviews) - (NSImage *) ppGSGlue_ContentImage { NSRect contentBounds; NSImage *contentImage; contentBounds = [self bounds]; contentImage = [[[NSImage alloc] initWithSize: contentBounds.size] autorelease]; [contentImage lockFocus]; [self drawRect: contentBounds]; [contentImage unlockFocus]; return contentImage; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_WindowOrdering.m0000644000076500000240000002403613752035764023777 0ustar joshstaff/* PPGNUstepGlue_WindowOrdering.m Copyright 2014-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Workarounds for several window-ordering issues in GNUstep affecting various window managers: // Document windows (NSNormalWindowLevel) can obscure higher-level windows that should always // stay in front. // // - Menus: On Compiz & Xfwm, the main menu's submenus can be obscured behind document windows. // The workaround is to set the window level of the main menu's submenu windows to // NSMainMenuWindowLevel. // // - Modals: On all window managers except WindowMaker, modal windows (open & save panels, etc.) // can be obscured behind document windows. The workaround is to make the modal window a child // window of the current main document window, ordered NSWindowAbove. // // - Panels: On Compiz & KWin, floating panels can be obscured behind document windows. The // workaround is to set all panels to be child windows of the current main document window, // ordered NSWindowAbove. #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGNUstepGlueUtilities.h" #import "PPApplication.h" #import "PPDocumentWindowController.h" #import "PPPanelController.h" #import "PPPanelsController.h" #import "PPPopupPanelsController.h" #import "PPScreencastController.h" #import "PPScreencastPopupPanelController.h" #define kTargetWindowManagerTypesMask_WindowOrdering_Menus \ (kPPGSWindowManagerTypeMask_Compiz \ | kPPGSWindowManagerTypeMask_Xfwm) #define kTargetWindowManagerTypesMask_WindowOrdering_Modals \ (~kPPGSWindowManagerTypeMask_WindowMaker) #define kTargetWindowManagerTypesMask_WindowOrdering_Panels \ (kPPGSWindowManagerTypeMask_Compiz \ | kPPGSWindowManagerTypeMask_KWin) @interface NSMenu (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetAllMenuWindowsToMainMenuLevel; @end @interface NSWindow (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupToRemainInFrontOfWindow: (NSWindow *) window; @end @interface PPPanelController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupPanelToRemainInFrontOfWindow: (NSWindow *) window; @end @interface PPPanelsController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupPanelsToRemainInFrontOfWindow: (NSWindow *) window; @end @interface PPPopupPanelsController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupPopupPanelsToRemainInFrontOfWindow: (NSWindow *) window; @end @interface PPDocumentWindowController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupAllPanelsToRemainInFrontOfWindow: (NSWindow *) window; @end #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING @interface PPScreencastController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_WindowOrdering_HandleScreencastEnableOrDisable; - (void) ppGSGlue_SetupScreencastPopupToRemainInFrontOfWindow: (NSWindow *) window; @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING @implementation NSObject (PPGNUstepGlue_WindowOrdering) + (void) ppGSGlue_WindowOrdering_Menus_Install { [[NSApp mainMenu] ppGSGlue_SetAllMenuWindowsToMainMenuLevel]; } + (void) ppGSGlue_WindowOrdering_Modals_Install { macroSwizzleInstanceMethod(PPApplication, runModalForWindow:, ppGSPatch_WindowOrdering_RunModalForWindow:); } + (void) ppGSGlue_WindowOrdering_Panels_Install { macroSwizzleInstanceMethod(PPDocumentWindowController, windowDidBecomeMain:, ppGSPatch_WindowDidBecomeMain:); #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING PPGSGlueUtils_PerformPPScreencastControllerSelectorOnEnableOrDisable( @selector(ppGSGlue_WindowOrdering_HandleScreencastEnableOrDisable)); #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING } + (void) ppGSGlue_WindowOrdering_Install { if (PPGSGlueUtils_WindowManagerMatchesTypeMask( kTargetWindowManagerTypesMask_WindowOrdering_Menus)) { [self ppGSGlue_WindowOrdering_Menus_Install]; } if (PPGSGlueUtils_WindowManagerMatchesTypeMask( kTargetWindowManagerTypesMask_WindowOrdering_Modals)) { [self ppGSGlue_WindowOrdering_Modals_Install]; } if (PPGSGlueUtils_WindowManagerMatchesTypeMask( kTargetWindowManagerTypesMask_WindowOrdering_Panels)) { [self ppGSGlue_WindowOrdering_Panels_Install]; } } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_WindowOrdering_Install); } @end @implementation PPApplication (PPGNUstepGlue_WindowOrdering_Modals) - (NSInteger) ppGSPatch_WindowOrdering_RunModalForWindow: (NSWindow *) theWindow { NSWindow *mainWindow; NSInteger returnValue; bool didManuallyOrderModalWindowToFront = NO; mainWindow = [self mainWindow]; [mainWindow orderFrontRegardless]; if (![theWindow parentWindow]) { [theWindow ppGSGlue_SetupToRemainInFrontOfWindow: mainWindow]; didManuallyOrderModalWindowToFront = YES; } returnValue = [self ppGSPatch_WindowOrdering_RunModalForWindow: theWindow]; if (didManuallyOrderModalWindowToFront) { [theWindow ppGSGlue_SetupToRemainInFrontOfWindow: nil]; } return returnValue; } @end @implementation PPDocumentWindowController (PPGNUstepGlue_WindowOrdering_Panels) - (void) ppGSPatch_WindowDidBecomeMain: (NSNotification *) notification { [self ppGSPatch_WindowDidBecomeMain: notification]; [self ppGSGlue_SetupAllPanelsToRemainInFrontOfWindow: [notification object]]; } @end @implementation NSMenu (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetAllMenuWindowsToMainMenuLevel { NSWindow *menuWindow; NSEnumerator *menuItemsEnumerator; NSMenuItem *menuItem; menuWindow = [self window]; if ([menuWindow level] != NSMainMenuWindowLevel) { [menuWindow setLevel: NSMainMenuWindowLevel]; } menuItemsEnumerator = [[self itemArray] objectEnumerator]; while (menuItem = [menuItemsEnumerator nextObject]) { if ([menuItem hasSubmenu]) { [[menuItem submenu] ppGSGlue_SetAllMenuWindowsToMainMenuLevel]; } } } @end @implementation NSWindow (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupToRemainInFrontOfWindow: (NSWindow *) window { NSWindow *currentParentWindow = [self parentWindow]; if (currentParentWindow == window) { return; } if (currentParentWindow) { [currentParentWindow removeChildWindow: self]; } if (window) { [window addChildWindow: self ordered: NSWindowAbove]; if ([self isVisible]) { [self orderWindow: NSWindowAbove relativeTo: [window windowNumber]]; } } } @end @implementation PPPanelController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupPanelToRemainInFrontOfWindow: (NSWindow *) window { [[self window] ppGSGlue_SetupToRemainInFrontOfWindow: window]; } @end @implementation PPPanelsController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupPanelsToRemainInFrontOfWindow: (NSWindow *) window { [_panelControllers makeObjectsPerformSelector: @selector(ppGSGlue_SetupPanelToRemainInFrontOfWindow:) withObject: window]; } @end @implementation PPPopupPanelsController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupPopupPanelsToRemainInFrontOfWindow: (NSWindow *) window { [_popupControllers makeObjectsPerformSelector: @selector(ppGSGlue_SetupPanelToRemainInFrontOfWindow:) withObject: window]; } @end #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING @implementation PPScreencastController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_WindowOrdering_HandleScreencastEnableOrDisable { NSWindow *window = (_screencastingIsEnabled) ? [NSApp mainWindow] : nil; [_screencastPopupController ppGSGlue_SetupPanelToRemainInFrontOfWindow: window]; } - (void) ppGSGlue_SetupScreencastPopupToRemainInFrontOfWindow: (NSWindow *) window { if (!_screencastingIsEnabled) return; [_screencastPopupController ppGSGlue_SetupPanelToRemainInFrontOfWindow: window]; } @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING @implementation PPDocumentWindowController (PPGNUstepGlue_WindowOrderingUtilities) - (void) ppGSGlue_SetupAllPanelsToRemainInFrontOfWindow: (NSWindow *) window { static NSWindow *previousWindow = nil; if (!window || (window == previousWindow)) { return; } [_panelsController ppGSGlue_SetupPanelsToRemainInFrontOfWindow: window]; [_popupPanelsController ppGSGlue_SetupPopupPanelsToRemainInFrontOfWindow: window]; [[NSColorPanel sharedColorPanel] ppGSGlue_SetupToRemainInFrontOfWindow: window]; #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING [[PPScreencastController sharedController] ppGSGlue_SetupScreencastPopupToRemainInFrontOfWindow: window]; #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING [previousWindow release]; previousWindow = [window retain]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_WindowPlacement.m0000644000076500000240000000746114374062105024127 0ustar joshstaff/* PPGNUstepGlue_WindowPlacement.m Copyright 2023 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Fix for an issue on Openbox WM (LXDE, LXQt) where PP's initial document window is placed // too high onscreen, obscuring its title bar behind the desktop's menu bar (if it's a top-edge // menu bar, as with Raspberry Pi OS). // Other WMs automatically reposition windows to prevent them from overlapping with the // desktop menu, but Openbox doesn't appear to do this, so when running on that WM, force the // initial document window to be positioned at a lower point that accounts for a top-edge menu. // The workaround temporarily patches -[NSScreen visibleFrame] while PikoPixel's setting up // its globals for positioning the initial document window (in // -[PPDocumentWindowController setupNewWindowGlobals]), so that visibleFrame returns a // modified screen frame with the top edge moved down by kTopEdgeMenuBarMargin. #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGNUstepGlueUtilities.h" #import "PPDocumentWindowController.h" #define kTargetWindowManagerTypesMask_WindowPlacement \ (kPPGSWindowManagerTypeMask_Openbox) #define kTopEdgeMenuBarMargin 32 @implementation NSObject (PPGNUstepGlue_WindowPlacement) + (void) ppGSGlue_WindowPlacement_InstallPatches { macroSwizzleClassMethod(PPDocumentWindowController, setupNewWindowGlobals, ppGSPatch_WindowPlacement_SetupNewWindowGlobals); } + (void) ppGSGlue_WindowPlacement_Install { if (!PPGSGlueUtils_WindowManagerMatchesTypeMask( kTargetWindowManagerTypesMask_WindowPlacement)) { return; } [self ppGSGlue_WindowPlacement_InstallPatches]; // +[PPDocumentWindowController setupNewWindowGlobals] will already have been called at // this point (from +[PPDocumentWindowController initialize]), so manually call it again // to have it run with the patches installed [PPDocumentWindowController performSelector: @selector(setupNewWindowGlobals)]; } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_WindowPlacement_Install); } @end @implementation PPDocumentWindowController (PPGNUstepGlue_WindowPlacement) + (void) ppGSPatch_WindowPlacement_SetupNewWindowGlobals { macroSwizzleInstanceMethod(NSScreen, visibleFrame, ppGSPatch_WindowPlacement_VisibleFrame); [self ppGSPatch_WindowPlacement_SetupNewWindowGlobals]; macroSwizzleInstanceMethod(NSScreen, visibleFrame, ppGSPatch_WindowPlacement_VisibleFrame); } @end @implementation NSScreen (PPGNUstepGlue_WindowPlacement) - (NSRect) ppGSPatch_WindowPlacement_VisibleFrame { NSRect visibleFrame = [self ppGSPatch_WindowPlacement_VisibleFrame]; if (visibleFrame.size.height > kTopEdgeMenuBarMargin) { visibleFrame.size.height -= kTopEdgeMenuBarMargin; } return visibleFrame; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_WindowStyleOffsets.m0000644000076500000240000004366613353510113024651 0ustar joshstaff/* PPGNUstepGlue_WindowStyleOffsets.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // - Workarounds for window style offsets issues on Compiz WM (cropped window content), // KWin, Marco, Openbox, Window Maker, & Xfwm WMs (drawing artifacts after maximizing or // switching resizeable/nonresizable), and Budgie, Gala, Muffin, & Mutter WMs (1. After // resizing a panel via a PPResizeControl, a transparent gap appears between the panel's // content & its titlebar, 2. Hiding & reshowing a panel can cause its position to shift // vertically towards the top of the screen) // // - Force GNUstep to ignore any cached style offset values stored in the root window, instead // check offsets manually (in case the window manager changed since the values were cached) #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGNUstepGlueUtilities.h" #import "GNUstepGUI/GSWindowDecorationView.h" #import "GNUstepGUI/GSDisplayServer.h" #import "PPToolsPanelController.h" #import "PPLayersPanelController.h" #import "PPPreviewPanelController.h" #import "PPSamplerImagePanelController.h" #import "PPToolModifierTipsPanelController.h" // Compiz defines #define kUserDefaultsKey_FallbackWindowStyleOffsets_Compiz \ @"GSGlue_FallbackWindowStyleOffsets_Compiz" #define kDefaultStyleOffsetValue_Compiz_Top 28 #define kDefaultStyleOffsetValue_Compiz_SidesAndBottom 0 #define kMinValidStyleOffsetValue_Compiz_Top 21 typedef unsigned long int PPXWindow; // local definition of libX11's Window type static NSString *gUserDefaultsKey_FallbackWindowStyleOffsets = kUserDefaultsKey_FallbackWindowStyleOffsets_Compiz; static float gFallbackStyleOffset_Top = kDefaultStyleOffsetValue_Compiz_Top, gFallbackStyleOffset_Bottom = kDefaultStyleOffsetValue_Compiz_SidesAndBottom, gFallbackStyleOffset_Left = kDefaultStyleOffsetValue_Compiz_SidesAndBottom, gFallbackStyleOffset_Right = kDefaultStyleOffsetValue_Compiz_SidesAndBottom; static PPXWindow gActiveResizingXWindow = 0; static float gXFrameVerticalOffset = 0; static bool gShouldCalculateXFrameVerticalOffset = NO; @interface GSDisplayServer (PPGNUstep_GSDisplayServerPrivate) - (void *) windowDevice: (int) win; @end @interface NSUserDefaults (PPGNUstepGlue_WindowStyleOffsetsUtilities) - (void) ppGSGlue_IgnoreRootWindowStyleOffsets; + (void) ppGSGlue_SetupFallbackStyleOffsetsFromDefaults; + (void) ppGSGlue_SaveFallbackStyleOffsetsToDefaults; @end @implementation NSObject (PPGNUstepGlue_WindowStyleOffsets) // Compiz WM + (void) ppGSGlue_WindowStyleOffsets_Compiz_InstallPatches { [NSClassFromString(@"XGServer") ppSwizzleInstanceMethodWithSelector: @selector(styleoffsets::::::) forInstanceMethodWithSelector: @selector(ppGSPatch_Compiz_Styleoffsets::::::)]; } + (void) ppGSGlue_WindowStyleOffsets_Compiz_Install { [NSUserDefaults ppGSGlue_SetupFallbackStyleOffsetsFromDefaults]; [self ppGSGlue_WindowStyleOffsets_Compiz_InstallPatches]; } // KWin, Marco, Openbox, Window Maker, or Xfwm WMs + (void) ppGSGlue_WindowStyleOffsets_KwinMrcoOpbxWmkrXfwm_InstallPatches { macroSwizzleInstanceMethod(NSClassFromString(@"XGServer"), styleoffsets::::::, ppGSPatch_KwinMrcoOpbxWmkrXfwm_Styleoffsets::::::); } // Budgie, Gala, Muffin, or Mutter WMs + (void) ppGSGlue_WindowStyleOffsets_BgieGalaMufnMutr_InstallPatches { Class XGServerClass = NSClassFromString(@"XGServer"); macroSwizzleInstanceMethod(XGServerClass, styleoffsets::::::, ppGSPatch_BgieGalaMufnMutr_Styleoffsets::::::); macroSwizzleInstanceMethod(XGServerClass, _XFrameToOSFrame:for:, ppGSPatch__XFrameToOSFrame:for:); // ppGSPatch_SetFrame: calls a private GNUstep method, -[GSDisplayServer windowDevice:], // so check that the private method is supported, in case a future version of GNUstep GUI // removes it. if ([GSDisplayServer instancesRespondToSelector: @selector(windowDevice:)]) { macroSwizzleInstanceMethod(GSWindowDecorationView, setFrame:, ppGSPatch_SetFrame:); } macroSwizzleInstanceMethod(PPToolsPanelController, showPanel, ppGSPatch_WindowStyleOffsets_ShowPanel); macroSwizzleInstanceMethod(PPLayersPanelController, showPanel, ppGSPatch_WindowStyleOffsets_ShowPanel); macroSwizzleInstanceMethod(PPPreviewPanelController, showPanel, ppGSPatch_WindowStyleOffsets_ShowPanel); macroSwizzleInstanceMethod(PPSamplerImagePanelController, showPanel, ppGSPatch_WindowStyleOffsets_ShowPanel); macroSwizzleInstanceMethod(PPToolModifierTipsPanelController, showPanel, ppGSPatch_WindowStyleOffsets_ShowPanel); } // All WMs + (void) ppGSGlue_WindowStyleOffsets_Install { if (PPGSGlueUtils_WindowManagerMatchesTypeMask(kPPGSWindowManagerTypeMask_Compiz)) { [self ppGSGlue_WindowStyleOffsets_Compiz_Install]; } else if (PPGSGlueUtils_WindowManagerMatchesTypeMask(kPPGSWindowManagerTypeMask_KWin | kPPGSWindowManagerTypeMask_Marco | kPPGSWindowManagerTypeMask_Openbox | kPPGSWindowManagerTypeMask_WindowMaker | kPPGSWindowManagerTypeMask_Xfwm)) { [self ppGSGlue_WindowStyleOffsets_KwinMrcoOpbxWmkrXfwm_InstallPatches]; } else if (PPGSGlueUtils_WindowManagerMatchesTypeMask(kPPGSWindowManagerTypeMask_Budgie | kPPGSWindowManagerTypeMask_Gala | kPPGSWindowManagerTypeMask_Muffin | kPPGSWindowManagerTypeMask_Mutter)) { [self ppGSGlue_WindowStyleOffsets_BgieGalaMufnMutr_InstallPatches]; } } + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_WindowStyleOffsets_Install); PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads( @selector(ppGSGlue_IgnoreRootWindowStyleOffsets)); } // PATCH: -[XGServer styleoffsets::::::] (Compiz) // When running on Compiz WM, the styleoffsets:::::: method can return garbage values for some // styles (and which style values return garbage may change each time the app runs); Workaround // patch checks whether the offsets returned by the original implementation appear invalid // (t <= 0) - if so, it replaces the returned values with valid fallback values (using the // first valid values found; saved in user defaults for future runs where the app hasn't yet // received valid values). - (void) ppGSPatch_Compiz_Styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b : (unsigned int) style : (PPXWindow) win { [self ppGSPatch_Compiz_Styleoffsets: l : r : t : b : style : win]; if (style & NSTitledWindowMask) { static bool didSaveValidFallbackOffsetsToDefaults = NO; bool styleOffsetsAreInvalid; styleOffsetsAreInvalid = (*t < kMinValidStyleOffsetValue_Compiz_Top) ? YES : NO; if (styleOffsetsAreInvalid) { *l = gFallbackStyleOffset_Left; *r = gFallbackStyleOffset_Right; *t = gFallbackStyleOffset_Top; *b = gFallbackStyleOffset_Bottom; } else if (!didSaveValidFallbackOffsetsToDefaults) { if ((*l != gFallbackStyleOffset_Left) || (*r != gFallbackStyleOffset_Right) || (*t != gFallbackStyleOffset_Top) || (*b != gFallbackStyleOffset_Bottom)) { gFallbackStyleOffset_Left = *l; gFallbackStyleOffset_Right = *r; gFallbackStyleOffset_Top = *t; gFallbackStyleOffset_Bottom = *b; [NSUserDefaults ppGSGlue_SaveFallbackStyleOffsetsToDefaults]; } didSaveValidFallbackOffsetsToDefaults = YES; } } } // PATCH: -[XGServer styleoffsets::::::] (KWin, Marco, Openbox, Window Maker, or Xfwm) // When running on KWin/Marco/Openbox/WindowMaker/Xfwm window managers, maximizing a titled // window or switching a titled window between resizable & non-resizable causes drawing // artifacts due to incorrect style offsets - this is because the affected WMs' window // decorations are different sizes for different window states, and when the decoration sizes // change on-the-fly, they no longer line up with GNUstep's drawing/graphics state (which seems // to use cached offset values); // Patch sets the win parameter to zero (if the window style is titled) before calling the // original styleoffsets:::::: implementation - this forces it to return cached offset values // (which should match the window's initial state & GNUstep's) instead of querying the window // directly for its current offsets (which may no longer match GNUstep's state). - (void) ppGSPatch_KwinMrcoOpbxWmkrXfwm_Styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b : (unsigned int) style : (PPXWindow) win { if (style & NSTitledWindowMask) { win = 0; } [self ppGSPatch_KwinMrcoOpbxWmkrXfwm_Styleoffsets: l : r : t : b : style : win]; } // PATCH: -[XGServer styleoffsets::::::] (Budgie, Gala, Muffin, or Mutter) // When running on Budgie/Gala/Muffin/Mutter window managers, resizing a panel by dragging a // PPResizeControl causes a transparent gap to appear between the titlebar & panel content. // This is due to GNUstep's -[NSWindow setFrame:display:] method calling through to // -[XGServer styleoffsets::::::] with the win parameter set to zero - on // Budgie/Gala/Muffin/Mutter, this returns a different style offset value for t (top) than when // calling the method with a nonzero win value (valid xwindow pointer); // Patch sets the win parameter on titled windows to a nonzero value (if a valid xwindow ptr is // found in the global, gActiveResizingXWindow - the global's value is set up inside the // -[GSWindowDecorationView ppGSPatch_SetFrame:] patch below). // Patch also sets up the value of the global, gXFrameVerticalOffset, which is used by the // -[XGServer _XFrameToOSFrame:for:] patch below to offset the vertical shift of panel windows // after hiding & reshowing them (the distance shifted happens to be the same as the difference // in the style offset value for t between calling styleoffsets:... with win containing a zero // and calling styleoffsets:... with win containing a valid xwindow pointer). - (void) ppGSPatch_BgieGalaMufnMutr_Styleoffsets: (float *) l : (float *) r : (float *) t : (float *) b : (unsigned int) style : (PPXWindow) win { if ((style & NSTitledWindowMask) && !win && gActiveResizingXWindow) { win = gActiveResizingXWindow; } [self ppGSPatch_BgieGalaMufnMutr_Styleoffsets: l : r : t : b : style : win]; if (gShouldCalculateXFrameVerticalOffset && (style & NSTitledWindowMask) && win) { float lt, rt, tp, bm; [self ppGSPatch_BgieGalaMufnMutr_Styleoffsets: < : &rt : &tp : &bm : style : 0]; gXFrameVerticalOffset = *t - tp; if (gXFrameVerticalOffset) { gShouldCalculateXFrameVerticalOffset = NO; } } } // PATCH: -[XGServer _XFrameToOSFrame:] (Budgie, Gala, Muffin, or Mutter) // Workaround for issue where hiding & reshowing panels can cause them to shift vertically; // Patch adds a vertical offset to the returned XFrame, by the amount contained in the global, // gXFrameVerticalOffset (set up in ppGSPatch_BgieGalaMufnMutr_Styleoffsets: above). - (NSRect) ppGSPatch__XFrameToOSFrame: (NSRect) x for: (void*)window { NSRect returnValue = [self ppGSPatch__XFrameToOSFrame: x for: window]; returnValue.origin.y += gXFrameVerticalOffset; return returnValue; } @end @implementation GSWindowDecorationView (PPGNUstepGlue_WindowStyleOffsets) // PATCH: -[GSWindowDecorationView setFrame:] // When setting the view's frame under Budgie/Gala/Muffin/Mutter WMs (called when dragging a // PPResizeControl), temporarily store the XWindow in the global, gActiveResizingXWindow, // so it can be used in the -[XGServer ppGSPatch_BgieGalaMufnMutr_Styleoffsets:...] patch above. - (void) ppGSPatch_SetFrame: (NSRect) frame { gActiveResizingXWindow = (PPXWindow) [GSCurrentServer() windowDevice: [[self window] windowNumber]]; [self ppGSPatch_SetFrame: frame]; gActiveResizingXWindow = 0; } @end @implementation PPPanelController (PPGNUstepGlue_WindowStyleOffsets) - (void) ppGSPatch_WindowStyleOffsets_ShowPanel { static bool didSetGShouldCalculateXFrameVerticalOffset = NO; [self ppGSPatch_WindowStyleOffsets_ShowPanel]; if (!didSetGShouldCalculateXFrameVerticalOffset) { gShouldCalculateXFrameVerticalOffset = YES; didSetGShouldCalculateXFrameVerticalOffset = YES; } } @end @implementation NSUserDefaults (PPGNUstepGlue_WindowStyleOffsets) - (void) ppGSGlue_IgnoreRootWindowStyleOffsets { NSDictionary *defaultsDict = [NSDictionary dictionaryWithObject: [NSNumber numberWithBool: YES] forKey: @"GSIgnoreRootOffsets"]; if (!defaultsDict) goto ERROR; [self registerDefaults: defaultsDict]; return; ERROR: return; } + (void) ppGSGlue_SetupFallbackStyleOffsetsFromDefaults { NSUserDefaults *userDefaults; NSArray *fallbackOffsets; // Currently only need fallback style offsets for one WM (Compiz); Leaving commented-out // functionality in case fallbacks are someday needed on multiple WMs again. (Global values // are already set up - initially defined with Compiz values). /* if (PPGSGlueUtils_WindowManagerMatchesTypeMask(kPPGSWindowManagerTypeMask_KWin)) { gUserDefaultsKey_FallbackWindowStyleOffsets = kUserDefaultsKey_FallbackWindowStyleOffsets_KWin; gFallbackStyleOffset_Left = kDefaultStyleOffsetValue_KWin_SidesAndBottom; gFallbackStyleOffset_Right = kDefaultStyleOffsetValue_KWin_SidesAndBottom; gFallbackStyleOffset_Top = kDefaultStyleOffsetValue_KWin_Top; gFallbackStyleOffset_Bottom = kDefaultStyleOffsetValue_KWin_SidesAndBottom; } else // !KWin WM - use Compiz default values { gUserDefaultsKey_FallbackWindowStyleOffsets = kUserDefaultsKey_FallbackWindowStyleOffsets_Compiz; gFallbackStyleOffset_Left = kDefaultStyleOffsetValue_Compiz_SidesAndBottom; gFallbackStyleOffset_Right = kDefaultStyleOffsetValue_Compiz_SidesAndBottom; gFallbackStyleOffset_Top = kDefaultStyleOffsetValue_Compiz_Top; gFallbackStyleOffset_Bottom = kDefaultStyleOffsetValue_Compiz_SidesAndBottom; } */ userDefaults = [NSUserDefaults standardUserDefaults]; fallbackOffsets = [NSArray arrayWithObjects: [NSNumber numberWithFloat: gFallbackStyleOffset_Left], [NSNumber numberWithFloat: gFallbackStyleOffset_Right], [NSNumber numberWithFloat: gFallbackStyleOffset_Top], [NSNumber numberWithFloat: gFallbackStyleOffset_Bottom], nil]; if (fallbackOffsets) { [userDefaults registerDefaults: [NSDictionary dictionaryWithObject: fallbackOffsets forKey: gUserDefaultsKey_FallbackWindowStyleOffsets]]; } fallbackOffsets = [userDefaults objectForKey: gUserDefaultsKey_FallbackWindowStyleOffsets]; if (![fallbackOffsets isKindOfClass: [NSArray class]] || ([fallbackOffsets count] < 4)) { goto ERROR; } gFallbackStyleOffset_Left = [[fallbackOffsets objectAtIndex: 0] floatValue]; gFallbackStyleOffset_Right = [[fallbackOffsets objectAtIndex: 1] floatValue]; gFallbackStyleOffset_Top = [[fallbackOffsets objectAtIndex: 2] floatValue]; gFallbackStyleOffset_Bottom = [[fallbackOffsets objectAtIndex: 3] floatValue]; return; ERROR: return; } + (void) ppGSGlue_SaveFallbackStyleOffsetsToDefaults { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; NSArray *fallbackOffsets = [NSArray arrayWithObjects: [NSNumber numberWithFloat: gFallbackStyleOffset_Left], [NSNumber numberWithFloat: gFallbackStyleOffset_Right], [NSNumber numberWithFloat: gFallbackStyleOffset_Top], [NSNumber numberWithFloat: gFallbackStyleOffset_Bottom], nil]; if (!fallbackOffsets) goto ERROR; [userDefaults setObject: fallbackOffsets forKey: gUserDefaultsKey_FallbackWindowStyleOffsets]; return; ERROR: return; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlue_Workspace.m0000644000076500000240000001656413264230151022764 0ustar joshstaff/* PPGNUstepGlue_Workspace.m Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // 1) Set up user default values for the app workspace: // - Allow only one running instance of PikoPixel at a time // - Suppress PikoPixel's app-icon desktop-window // - Prevent minimized document windows from appearing as an icon window on the desktop (they'll // still appear in the taskbar) // // 2) Workaround for issue when allowing only one running instance: Can't open image files from // the desktop/filebrowser when there's already an instance running because the second instance // (that receives the filepaths) quits immediately; Fixed by adding functionality to transmit // filepaths from the second instance to the first, and open them in the first instance #ifdef GNUSTEP #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPGNUstepGlueUtilities.h" #import "PPGNUstepUserDefaults.h" #import "GNUstepGUI/GSServicesManager.h" #import "PPApplication.h" #define kPPGSUserDefaultsKey_UseGSNativeWorkspaceDefaults @"PPUseGSNativeWorkspaceDefaults" @protocol PPAppProxyOpenFileAtPath - (oneway void) ppAppProxyOpenFileAtPath: (NSString *) filepath; @end @interface NSUserDefaults (PPGNUstepGlue_WorkspaceUtilities) - (void) ppGSGlue_Workspace_SetupAppDefaults; @end @interface GSServicesManager (PPGNUstepGlue_WorkspaceUtilities) - (void) ppGSGlue_HandleNSAppNotification_WillTerminate: (NSNotification *) notification; @end @interface PPApplication (PPGNUstepGlue_WorkspaceUtilities) @end @implementation NSObject (PPGNUstepGlue_Workspace) + (void) ppGSGlue_Workspace_InstallPatches { macroSwizzleInstanceMethod(GSServicesManager, registerAsServiceProvider, ppGSPatch_RegisterAsServiceProvider); } + (void) load { PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads( @selector(ppGSGlue_Workspace_SetupAppDefaults)); macroPerformNSObjectSelectorAfterAppLoads(ppGSGlue_Workspace_InstallPatches); } @end @implementation NSUserDefaults (PPGNUstepGlue_WorkspaceUtilities) - (void) ppGSGlue_Workspace_SetupAppDefaults { NSDictionary *defaultsDict; bool useRunningCopy = YES, // YES: allow only one running instance of the application suppressAppIcon = YES, // YES: suppress the app-icon desktop-window appOwnsMiniwindow = NO; // NO: suppress minimized-document desktop-windows if ([self boolForKey: kPPGSUserDefaultsKey_UseGSNativeWorkspaceDefaults]) { return; } if (PPGSGlueUtils_WindowManagerMatchesTypeMask(kPPGSWindowManagerTypeMask_WindowMaker)) { // If using WindowMaker WM, enable the app-icon & minimized-document desktop-windows // (Causes issues with WM if they're disabled) suppressAppIcon = NO; appOwnsMiniwindow = YES; } else if (![[self stringForKey: kGSUserDefaultsKey_InterfaceStyleName] isEqualToString: kGSUserDefaultsValue_InterfaceStyleName_Windows95]) { // If not using Windows95 interface style, enable the app-icon window (clicking on it // is the only way to bring a background app with no open document windows to the front) suppressAppIcon = NO; } defaultsDict = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool: useRunningCopy], kGSUserDefaultsKey_UseRunningCopy, [NSNumber numberWithBool: suppressAppIcon], kGSUserDefaultsKey_SuppressAppIcon, [NSNumber numberWithBool: appOwnsMiniwindow], kGSUserDefaultsKey_AppOwnsMiniwindow, nil]; if (defaultsDict) { [self registerDefaults: defaultsDict]; } } @end @implementation GSServicesManager (PPGNUstepGlue_Workspace) - (void) ppGSPatch_RegisterAsServiceProvider { NSNotificationCenter *notificationCenter = nil; bool useRunningCopy; useRunningCopy = [[NSUserDefaults standardUserDefaults] boolForKey: kGSUserDefaultsKey_UseRunningCopy]; if (useRunningCopy) { notificationCenter = [[NSNotificationCenter defaultCenter] retain]; [notificationCenter addObserver: self selector: @selector(ppGSGlue_HandleNSAppNotification_WillTerminate:) name: NSApplicationWillTerminateNotification object: NSApp]; } [self ppGSPatch_RegisterAsServiceProvider]; if (useRunningCopy) { [notificationCenter removeObserver: self name: NSApplicationWillTerminateNotification object: NSApp]; [notificationCenter release]; } } - (void) ppGSGlue_HandleNSAppNotification_WillTerminate: (NSNotification *) notification { NSArray *filesToOpen; NSString *processName, *filepath; NSDistantObject *runningAppProxy; NSEnumerator *filesEnumerator; // _openFiles & _openDocument: are private NSApplication methods, so manually check that // NSApp responds to them (in case they've been renamed or removed in a future version of // the gnustep-gui framework) if (![NSApp respondsToSelector: @selector(_openFiles)] || ![NSApp respondsToSelector: @selector(_openDocument:)]) { return; } filesToOpen = [NSApp performSelector: @selector(_openFiles)]; if (!filesToOpen || ![filesToOpen isKindOfClass: [NSArray class]] || ![filesToOpen count]) { return; } processName = [[NSProcessInfo processInfo] processName]; if (!processName) return; runningAppProxy = (NSDistantObject *) [NSConnection rootProxyForConnectionWithRegisteredName: processName host: @""]; if (!runningAppProxy) return; [runningAppProxy setProtocolForProxy: @protocol(PPAppProxyOpenFileAtPath)]; filesEnumerator = [filesToOpen objectEnumerator]; while (filepath = [filesEnumerator nextObject]) { [runningAppProxy ppAppProxyOpenFileAtPath: filepath]; } } @end @implementation PPApplication (PPGNUstepGlue_WorkspaceUtilities) - (oneway void) ppAppProxyOpenFileAtPath: (NSString *) filepath { [self performSelector: @selector(_openDocument:) withObject: filepath]; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlueUtilities.h0000644000076500000240000000421013272416760022631 0ustar joshstaff/* PPGNUstepGlueUtilities.h Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import // Window manager type masks #define kPPGSWindowManagerTypeMask_Budgie (1 << 0) // Budgie #define kPPGSWindowManagerTypeMask_Compiz (1 << 1) // Unity #define kPPGSWindowManagerTypeMask_Gala (1 << 2) // Pantheon #define kPPGSWindowManagerTypeMask_KWin (1 << 3) // KDE #define kPPGSWindowManagerTypeMask_Marco (1 << 4) // MATE #define kPPGSWindowManagerTypeMask_Muffin (1 << 5) // Cinnamon #define kPPGSWindowManagerTypeMask_Mutter (1 << 6) // GNOME Shell #define kPPGSWindowManagerTypeMask_Openbox (1 << 7) // LXDE #define kPPGSWindowManagerTypeMask_WindowMaker (1 << 8) // WindowMaker #define kPPGSWindowManagerTypeMask_Xfwm (1 << 9) // Xfce bool PPGSGlueUtils_WindowManagerMatchesTypeMask(unsigned typeMatchMask); bool PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads(SEL selector); bool PPGSGlueUtils_PerformPPScreencastControllerSelectorOnEnableOrDisable(SEL selector); @interface NSUserDefaults (PPGNUstepGlueUtilities) + (bool) ppGSGlueUtils_RegisterDefaultsFromDictionaryNamed: (NSString *) dictionaryName; @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepGlueUtilities.m0000644000076500000240000003335314400200504022625 0ustar joshstaff/* PPGNUstepGlueUtilities.m Copyright 2014-2018,2023 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP #import "PPGNUstepGlueUtilities.h" #import "NSObject_PPUtilities.h" #import "PPObjCUtilities.h" #import "PPApplication.h" #import "PPScreencastController.h" #define macroSystemHasProcessNamed(processName) \ ((system("pgrep -x " #processName " >/dev/null 2>&1") == 0) ? YES : NO) #define macroCheckWindowManager_Budgie macroSystemHasProcessNamed(budgie-wm) #define macroCheckWindowManager_Compiz macroSystemHasProcessNamed(compiz) #define macroCheckWindowManager_Gala macroSystemHasProcessNamed(gala) #define macroCheckWindowManager_KWin (macroSystemHasProcessNamed(kwin) \ || macroSystemHasProcessNamed(kwin_x11) \ || macroSystemHasProcessNamed(kwin_wayland)) #define macroCheckWindowManager_Marco macroSystemHasProcessNamed(marco) // Muffin WM (Cinnamon desktop) is a shared library and doesn't have its own process; // Check instead for the Cinnamon DE. #define macroCheckWindowManager_Muffin macroSystemHasProcessNamed(cinnamon) // Mutter WM (GNOME Shell desktop) is a shared library and doesn't have its own process; // Check instead for gnome-shell, however, if the display manager is gdm3, it may be running // its own additional gnome-shell process, so if gdm3 is discovered, check that either it // doesn't spawn an extra gnome-shell process (depends on gdm3's version), or there's at least // two gnome-shell processes running - otherwise the DE is probably not GNOME Shell. #define macroCheckWindowManager_Mutter (macroSystemHasProcessNamed(gnome-shell) \ && (!macroSystemHasProcessNamed(gdm3) \ || !GDM3SpawnsAnExtraGnomeShellProcess() \ || SystemHasMultipleGnomeShellProcesses())) #define macroCheckWindowManager_Openbox macroSystemHasProcessNamed(openbox) #define macroCheckWindowManager_WindowMaker macroSystemHasProcessNamed(wmaker) #define macroCheckWindowManager_Xfwm macroSystemHasProcessNamed(xfwm4) #define kMaxNumStoredSelectors 10 static void PerformUserDefaultsSelectors(void); static bool GDM3SpawnsAnExtraGnomeShellProcess(void); static bool SystemHasMultipleGnomeShellProcesses(void); static SEL *gUserDefaultsSelectors = NULL; static int gNumUserDefaultsSelectors = 0; static bool gGSBackendDidLoad = NO, gHadUserDefaultsSelectorError_UnableToAllocateMemoryForSelectors = NO, gHadUserDefaultsSelectorError_StoredSelectorsArrayTooSmall = NO; // Stored NSUserDefaults selectors are called from an overridden private NSApplication method, // _init, which is the last overrideable method call before the GNUstep backend is loaded @interface NSApplication (PPGNUstepGlueUtilities) - (void) _init; @end bool PPGSGlueUtils_WindowManagerMatchesTypeMask(unsigned typeMatchMask) { static unsigned windowManagerTypeMask = 0; static bool didCheckWindowManagerType = NO; if (!didCheckWindowManagerType) { if (macroCheckWindowManager_Budgie) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_Budgie; } else if (macroCheckWindowManager_Compiz) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_Compiz; } else if (macroCheckWindowManager_Gala) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_Gala; } else if (macroCheckWindowManager_KWin) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_KWin; } else if (macroCheckWindowManager_Marco) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_Marco; } else if (macroCheckWindowManager_Muffin) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_Muffin; } else if (macroCheckWindowManager_Openbox) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_Openbox; } else if (macroCheckWindowManager_WindowMaker) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_WindowMaker; } else if (macroCheckWindowManager_Xfwm) { windowManagerTypeMask = kPPGSWindowManagerTypeMask_Xfwm; } else if (macroCheckWindowManager_Mutter) // Most complicated check, so leave until last { windowManagerTypeMask = kPPGSWindowManagerTypeMask_Mutter; } else { windowManagerTypeMask = 0; } didCheckWindowManagerType = YES; } return (windowManagerTypeMask & typeMatchMask) ? YES : NO; } bool PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads(SEL selector) { // This function is called from +load methods, so don't use ObjC classes (may not be loaded) if (gGSBackendDidLoad) { goto ERROR; } if (!gUserDefaultsSelectors) { gUserDefaultsSelectors = (SEL *) malloc (kMaxNumStoredSelectors * sizeof(SEL)); if (!gUserDefaultsSelectors) { gHadUserDefaultsSelectorError_UnableToAllocateMemoryForSelectors = YES; goto ERROR; } } if (gNumUserDefaultsSelectors >= kMaxNumStoredSelectors) { gHadUserDefaultsSelectorError_StoredSelectorsArrayTooSmall = YES; goto ERROR; } gUserDefaultsSelectors[gNumUserDefaultsSelectors++] = selector; return YES; ERROR: return NO; } static void PerformUserDefaultsSelectors(void) { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; int selectorIndex; if (gHadUserDefaultsSelectorError_UnableToAllocateMemoryForSelectors) { NSLog(@"ERROR: Out of memory in " "PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads()"); } if (gHadUserDefaultsSelectorError_StoredSelectorsArrayTooSmall) { NSLog(@"ERROR: Selector array is full - unable to store all delayed selector(s) in " "PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads(); Need to " "increase kMaxNumStoredSelectors to more than (%d) in PPGNUstepGlueUtilities.m", (int) kMaxNumStoredSelectors); } if (!gUserDefaultsSelectors) return; // sort the stored selectors alphabetically by name so they're always called in the same // order instead of depending on the undefined order in which +load methods are called PPObjCUtils_AlphabeticallySortSelectorArray(gUserDefaultsSelectors, gNumUserDefaultsSelectors); for (selectorIndex = 0; selectorIndex < gNumUserDefaultsSelectors; selectorIndex++) { NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init]; SEL selector = gUserDefaultsSelectors[selectorIndex]; if (selector && [userDefaults respondsToSelector: selector]) { [userDefaults performSelector: selector]; } else { NSLog(@"ERROR: Invalid NSUserDefaults selector, %@, passed to " "PPGSGlueUtils_PerformNSUserDefaultsSelectorBeforeGSBackendLoads()", (selector) ? NSStringFromSelector(selector) : @"NULL"); } [autoreleasePool release]; } free(gUserDefaultsSelectors); gUserDefaultsSelectors = NULL; gNumUserDefaultsSelectors = 0; } @implementation PPApplication (PPGNUstepGlueUtilities) // Stored NSUserDefaults selectors are called from an overridden private NSApplication method, // _init, which is the last overrideable method call before the GNUstep backend is loaded - (void) _init { PerformUserDefaultsSelectors(); if ([[super class] instancesRespondToSelector: @selector(_init)]) { [super _init]; } gGSBackendDidLoad = YES; } @end #define kLastGDM3MinorVersionToSpawnAnExtraGnomeShellProcess 28 // GDM3 Version 3.28 static bool GDM3SpawnsAnExtraGnomeShellProcess(void) { const char *sysCmd_GDM3Version = "gdm3 --version", *sysOutputScanFormatStr = "GDM %i.%i"; const int numScannedValuesExpected = 2; FILE *sysOutputStream; int gdm3MajorVersion, gdm3MinorVersion; bool gdm3SpawnsAnExtraGnomeShellProcess = NO; sysOutputStream = popen(sysCmd_GDM3Version, "r"); if (sysOutputStream) { if (!feof(sysOutputStream) && (fscanf(sysOutputStream, sysOutputScanFormatStr, &gdm3MajorVersion, &gdm3MinorVersion) == numScannedValuesExpected)) { if ((gdm3MajorVersion == 3) && (gdm3MinorVersion <= kLastGDM3MinorVersionToSpawnAnExtraGnomeShellProcess)) { gdm3SpawnsAnExtraGnomeShellProcess = YES; } } pclose(sysOutputStream); } return gdm3SpawnsAnExtraGnomeShellProcess; } static bool SystemHasMultipleGnomeShellProcesses(void) { const char *sysCmd_CountGnomeShellProcesses = "pgrep -x gnome-shell | wc -l", *sysOutputScanFormatStr = "%d"; const int numScannedValuesExpected = 1; FILE *sysOutputStream; int numGnomeShellProcesses = 0; sysOutputStream = popen(sysCmd_CountGnomeShellProcesses, "r"); if (sysOutputStream) { if (!feof(sysOutputStream)) { if (fscanf(sysOutputStream, sysOutputScanFormatStr, &numGnomeShellProcesses) != numScannedValuesExpected) { numGnomeShellProcesses = 0; } } pclose(sysOutputStream); } return (numGnomeShellProcesses > 1) ? YES : NO; } #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING static SEL *gScreencastControllerSelectors = NULL; static int gNumScreencastControllerSelectors = 0; bool PPGSGlueUtils_PerformPPScreencastControllerSelectorOnEnableOrDisable(SEL selector) { static bool screencastControllerPatchIsInstalled = NO; if (!selector) { NSLog(@"ERROR: NULL selector in " "PPGSGlueUtils_PerformPPScreencastControllerSelectorOnEnableOrDisable()"); goto ERROR; } if (!gScreencastControllerSelectors) { gScreencastControllerSelectors = (SEL *) malloc (kMaxNumStoredSelectors * sizeof(SEL)); if (!gScreencastControllerSelectors) { NSLog(@"ERROR: Out of memory in " "PPGSGlueUtils_PerformPPScreencastControllerSelectorOnEnableOrDisable()"); goto ERROR; } } if (gNumScreencastControllerSelectors >= kMaxNumStoredSelectors) { NSLog(@"ERROR: Selector array is full - unable to store all delayed selector(s) in " "PPGSGlueUtils_PerformPPScreencastControllerSelectorOnEnableOrDisable(); Need " "to increase kMaxNumStoredSelectors to more than (%d) in " "PPGNUstepGlueUtilities.m", (int) kMaxNumStoredSelectors); goto ERROR; } gScreencastControllerSelectors[gNumScreencastControllerSelectors++] = selector; if (!screencastControllerPatchIsInstalled) { screencastControllerPatchIsInstalled = macroSwizzleInstanceMethod(PPScreencastController, setEnabled:, ppGSPatch_SetEnabled:); } return YES; ERROR: return NO; } @implementation PPScreencastController (PPGNUstepGlueUtilities) - (void) ppGSPatch_SetEnabled: (bool) enableScreencasting { bool screencastingWasEnabled, screencastingIsEnabled; int selectorIndex; screencastingWasEnabled = (_screencastingIsEnabled) ? YES : NO; [self ppGSPatch_SetEnabled: enableScreencasting]; screencastingIsEnabled = (_screencastingIsEnabled) ? YES : NO; if (screencastingWasEnabled == screencastingIsEnabled) { return; } for (selectorIndex = 0; selectorIndex < gNumScreencastControllerSelectors; selectorIndex++) { [self performSelector: gScreencastControllerSelectors[selectorIndex]]; } } @end #else // !PP_OPTIONAL__BUILD_WITH_SCREENCASTING void PPGSGlueUtils_PerformPPScreencastControllerSelectorOnEnableOrDisable(SEL selector) { } #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING @implementation NSUserDefaults (PPGNUstepGlueUtilities) + (bool) ppGSGlueUtils_RegisterDefaultsFromDictionaryNamed: (NSString *) dictionaryName { NSString *dictionaryPath; NSDictionary *dictionary; if (!dictionaryName) goto ERROR; dictionaryPath = [[NSBundle mainBundle] pathForResource: dictionaryName ofType: @"plist"]; if (!dictionaryPath) goto ERROR; dictionary = [NSDictionary dictionaryWithContentsOfFile: dictionaryPath]; if (!dictionary) goto ERROR; [[self standardUserDefaults] registerDefaults: dictionary]; return YES; ERROR: return NO; } @end #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepPrefix.h0000644000076500000240000000257013234417116021277 0ustar joshstaff/* PPGNUstepPrefix.h Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP # import "PPGNUstepFrameworksVersionCheck.h" // MinGW: May have #defined ERROR, so undefine it (PikoPixel uses ERROR as a goto label) # ifdef ERROR # undef ERROR # endif // Solaris: Define missing math functions # ifdef __sun # define floorf(x) floor(x) # define ceilf(x) ceil(x) # define roundf(x) round(x) # define round(x) floor(x + 0.5) # endif #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGNUstepUserDefaults.h0000644000076500000240000000473113234417116022451 0ustar joshstaff/* PPGNUstepUserDefaults.h Copyright 2014-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef GNUSTEP // Keys # define kGSUserDefaultsKey_UseRunningCopy @"NSUseRunningCopy" # define kGSUserDefaultsKey_SuppressAppIcon @"GSSuppressAppIcon" # define kGSUserDefaultsKey_AppOwnsMiniwindow @"GSAppOwnsMiniwindow" # define kGSUserDefaultsKey_ThemeName @"GSTheme" # define kGSUserDefaultsKey_InterfaceStyleName @"NSInterfaceStyleDefault" # define kGSUserDefaultsKey_FirstControlKey @"GSFirstControlKey" # define kGSUserDefaultsKey_SecondControlKey @"GSSecondControlKey" # define kGSUserDefaultsKey_FirstAlternateKey @"GSFirstAlternateKey" # define kGSUserDefaultsKey_SecondAlternateKey @"GSSecondAlternateKey" # define kGSUserDefaultsKey_FirstCommandKey @"GSFirstCommandKey" # define kGSUserDefaultsKey_SecondCommandKey @"GSSecondCommandKey" // Values # define kGSUserDefaultsValue_InterfaceStyleName_Windows95 @"NSWindows95InterfaceStyle" # define kGSUserDefaultsValue_ModifierKeyName_LeftCtrl @"Control_L" # define kGSUserDefaultsValue_ModifierKeyName_RightCtrl @"Control_R" # define kGSUserDefaultsValue_ModifierKeyName_LeftAlt @"Alt_L" # define kGSUserDefaultsValue_ModifierKeyName_RightAlt @"Alt_R" # define kGSUserDefaultsValue_ModifierKeyName_LeftSuper @"Super_L" # define kGSUserDefaultsValue_ModifierKeyName_RightSuper @"Super_R" #endif // GNUSTEP PikoPixel.Sources.1.0-b10b/PikoPixel/PPGridPattern.h0000644000076500000240000000470713234403416021021 0ustar joshstaff/* PPGridPattern.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPGridType.h" #import "PPPresettablePatternProtocol.h" @interface PPGridPattern : NSObject { PPGridType _pixelGridType; NSColor *_pixelGridColor; NSSize _guidelineSpacingSize; NSColor *_guidelineColor; NSString *_presetName; bool _shouldDisplayGuidelines; } + gridPatternWithPixelGridType: (PPGridType) pixelGridType pixelGridColor: (NSColor *) pixelGridColor guidelineSpacingSize: (NSSize) guidelineSpacingSize guidelineColor: (NSColor *) guidelineColor shouldDisplayGuidelines: (bool) shouldDisplayGuidelines; + gridPatternWithPixelGridType: (PPGridType) pixelGridType pixelGridColor: (NSColor *) pixelGridColor; - initWithPixelGridType: (PPGridType) pixelGridType pixelGridColor: (NSColor *) pixelGridColor guidelineSpacingSize: (NSSize) guidelineSpacingSize guidelineColor: (NSColor *) guidelineColor shouldDisplayGuidelines: (bool) shouldDisplayGuidelines; - (PPGridType) pixelGridType; - (NSColor *) pixelGridColor; - (NSSize) guidelineSpacingSize; - (NSColor *) guidelineColor; - (bool) shouldDisplayGuidelines; - (bool) isEqualToGridPattern: (PPGridPattern *) otherPattern; - (PPGridPattern *) gridPatternByTogglingPixelGridType; - (PPGridPattern *) gridPatternByTogglingGuidelinesVisibility; - (PPGridPattern *) gridPatternByEnablingGuidelinesVisibility; - (NSData *) archivedData; + (PPGridPattern *) gridPatternWithArchivedData: (NSData *) archivedData; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPGridPattern.m0000644000076500000240000003427413234403206021025 0ustar joshstaff/* PPGridPattern.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPGridPattern.h" #import "PPDefines.h" #import "NSColor_PPUtilities.h" #import "PPUserDefaultsInitialValues.h" #import "PPGeometry.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #define kGridPatternCodingVersion_Current kGridPatternCodingVersion_1 // Coding Version 1 // Added coding version, guideline members (spacing size, color, display flag), & preset name #define kGridPatternCodingVersion_1 1 #define kGridPatternCodingKey_CodingVersion @"CodingVersion" #define kGridPatternCodingKey_PixelGridType kGridPatternCodingKey_v0_PixelGridType #define kGridPatternCodingKey_PixelGridColor kGridPatternCodingKey_v0_PixelGridColor #define kGridPatternCodingKey_GuidelineSpacingSize @"GuidelineSpacingSize" #define kGridPatternCodingKey_GuidelineColor @"GuidelineColor" #define kGridPatternCodingKey_GuidelinesVisibility @"GuidelinesVisibility" #define kGridPatternCodingKey_PresetName @"PresetName" // Coding Version 0 // Used in PikoPixel 1.0 beta6 & earlier #define kGridPatternCodingVersion_0 0 #define kGridPatternCodingKey_v0_PixelGridType @"PixelGridType" #define kGridPatternCodingKey_v0_PixelGridColor @"PixelGridColor" #define kGridPatternPreviewForegroundImageResourceName @"gridpatternpreview_foreground.png" @interface PPGridPattern (PrivateMethods) - initWithPixelGridType: (PPGridType) pixelGridType pixelGridColor: (NSColor *) pixelGridColor; - (id) initWithCoder_v0: (NSCoder *) aDecoder; @end @implementation PPGridPattern + gridPatternWithPixelGridType: (PPGridType) pixelGridType pixelGridColor: (NSColor *) pixelGridColor guidelineSpacingSize: (NSSize) guidelineSpacingSize guidelineColor: (NSColor *) guidelineColor shouldDisplayGuidelines: (bool) shouldDisplayGuidelines; { return [[[self alloc] initWithPixelGridType: pixelGridType pixelGridColor: pixelGridColor guidelineSpacingSize: guidelineSpacingSize guidelineColor: guidelineColor shouldDisplayGuidelines: shouldDisplayGuidelines] autorelease]; } + gridPatternWithPixelGridType: (PPGridType) pixelGridType pixelGridColor: (NSColor *) pixelGridColor { return [[[self alloc] initWithPixelGridType: pixelGridType pixelGridColor: pixelGridColor] autorelease]; } - initWithPixelGridType: (PPGridType) pixelGridType pixelGridColor: (NSColor *) pixelGridColor guidelineSpacingSize: (NSSize) guidelineSpacingSize guidelineColor: (NSColor *) guidelineColor shouldDisplayGuidelines: (bool) shouldDisplayGuidelines { self = [super init]; if (!self) goto ERROR; if (!PPGridType_IsValid(pixelGridType)) { goto ERROR; } pixelGridColor = [pixelGridColor ppSRGBColor]; guidelineColor = [guidelineColor ppSRGBColor]; if (!pixelGridColor || !guidelineColor) { goto ERROR; } guidelineSpacingSize = PPGeometry_SizeClippedToIntegerValues( PPGeometry_SizeClampedToMinMaxValues(guidelineSpacingSize, kMinGridGuidelineSpacing, kMaxGridGuidelineSpacing)); _pixelGridType = pixelGridType; _pixelGridColor = [pixelGridColor retain]; _guidelineSpacingSize = guidelineSpacingSize; _guidelineColor = [guidelineColor retain]; _shouldDisplayGuidelines = (shouldDisplayGuidelines) ? YES : NO; return self; ERROR: [self release]; return nil; } - initWithPixelGridType: (PPGridType) pixelGridType pixelGridColor: (NSColor *) pixelGridColor { static NSColor *defaultGuidelineColor = nil; static NSSize defaultGuidelineSpacingSize = {0,0}; if (!defaultGuidelineColor) { PPGridPattern *defaultInitialGridPattern = kUserDefaultsInitialValue_GridPattern; if (defaultInitialGridPattern) { defaultGuidelineColor = [[defaultInitialGridPattern guidelineColor] retain]; defaultGuidelineSpacingSize = [defaultInitialGridPattern guidelineSpacingSize]; } else { defaultGuidelineColor = [[NSColor blackColor] retain]; defaultGuidelineSpacingSize = NSMakeSize(8,8); } } return [self initWithPixelGridType: pixelGridType pixelGridColor: pixelGridColor guidelineSpacingSize: defaultGuidelineSpacingSize guidelineColor: defaultGuidelineColor shouldDisplayGuidelines: NO]; } - init { return [self initWithPixelGridType: -1 pixelGridColor: nil guidelineSpacingSize: NSZeroSize guidelineColor: nil shouldDisplayGuidelines: NO]; } - (void) dealloc { [_pixelGridColor release]; [_guidelineColor release]; [_presetName release]; [super dealloc]; } - (PPGridType) pixelGridType { return _pixelGridType; } - (NSColor *) pixelGridColor { return _pixelGridColor; } - (NSSize) guidelineSpacingSize { return _guidelineSpacingSize; } - (NSColor *) guidelineColor { return _guidelineColor; } - (bool) shouldDisplayGuidelines { return _shouldDisplayGuidelines; } - (bool) isEqualToGridPattern: (PPGridPattern *) otherPattern { if (self == otherPattern) { return YES; } if (!otherPattern || (_pixelGridType != otherPattern->_pixelGridType) || ![_pixelGridColor ppIsEqualToColor: otherPattern->_pixelGridColor] || !NSEqualSizes(_guidelineSpacingSize, otherPattern->_guidelineSpacingSize) || ![_guidelineColor ppIsEqualToColor: otherPattern->_guidelineColor] || (_shouldDisplayGuidelines != otherPattern->_shouldDisplayGuidelines)) { return NO; } return YES; } - (PPGridPattern *) gridPatternByTogglingPixelGridType { PPGridType toggledPixelGridType; toggledPixelGridType = _pixelGridType + 1; if (!PPGridType_IsValid(toggledPixelGridType)) { toggledPixelGridType = 0; } return [[self class] gridPatternWithPixelGridType: toggledPixelGridType pixelGridColor: _pixelGridColor guidelineSpacingSize: _guidelineSpacingSize guidelineColor: _guidelineColor shouldDisplayGuidelines: _shouldDisplayGuidelines]; } - (PPGridPattern *) gridPatternByTogglingGuidelinesVisibility { return [[self class] gridPatternWithPixelGridType: _pixelGridType pixelGridColor: _pixelGridColor guidelineSpacingSize: _guidelineSpacingSize guidelineColor: _guidelineColor shouldDisplayGuidelines: (_shouldDisplayGuidelines) ? NO : YES]; } - (PPGridPattern *) gridPatternByEnablingGuidelinesVisibility { if (_shouldDisplayGuidelines) { return [[self retain] autorelease]; } else { return [self gridPatternByTogglingGuidelinesVisibility]; } } - (NSData *) archivedData { return [NSKeyedArchiver archivedDataWithRootObject: self]; } + (PPGridPattern *) gridPatternWithArchivedData: (NSData *) archivedData { PPGridPattern *pattern = [NSKeyedUnarchiver unarchiveObjectWithData: archivedData]; if (![pattern isKindOfClass: [PPGridPattern class]]) { goto ERROR; } return pattern; ERROR: return nil; } #pragma mark NSCoding protocol - (id) initWithCoder: (NSCoder *) aDecoder { int codingVersion = [aDecoder decodeIntForKey: kGridPatternCodingKey_CodingVersion]; if (codingVersion == kGridPatternCodingVersion_0) { return [self initWithCoder_v0: aDecoder]; } self = [self initWithPixelGridType: [aDecoder decodeIntForKey: kGridPatternCodingKey_PixelGridType] pixelGridColor: [aDecoder decodeObjectForKey: kGridPatternCodingKey_PixelGridColor] guidelineSpacingSize: [aDecoder decodeSizeForKey: kGridPatternCodingKey_GuidelineSpacingSize] guidelineColor: [aDecoder decodeObjectForKey: kGridPatternCodingKey_GuidelineColor] shouldDisplayGuidelines: [aDecoder decodeBoolForKey: kGridPatternCodingKey_GuidelinesVisibility]]; if ([aDecoder containsValueForKey: kGridPatternCodingKey_PresetName]) { [self setPresetName: [aDecoder decodeObjectForKey: kGridPatternCodingKey_PresetName]]; } return self; } - (void) encodeWithCoder: (NSCoder *) coder { [coder encodeInt: kGridPatternCodingVersion_Current forKey: kGridPatternCodingKey_CodingVersion]; [coder encodeInt: _pixelGridType forKey: kGridPatternCodingKey_PixelGridType]; [coder encodeObject: _pixelGridColor forKey: kGridPatternCodingKey_PixelGridColor]; [coder encodeSize: _guidelineSpacingSize forKey: kGridPatternCodingKey_GuidelineSpacingSize]; [coder encodeObject: _guidelineColor forKey: kGridPatternCodingKey_GuidelineColor]; [coder encodeBool: _shouldDisplayGuidelines forKey: kGridPatternCodingKey_GuidelinesVisibility]; if (_presetName) { [coder encodeObject: _presetName forKey: kGridPatternCodingKey_PresetName]; } } - (id) initWithCoder_v0: (NSCoder *) aDecoder { self = [self initWithPixelGridType: [aDecoder decodeIntForKey: kGridPatternCodingKey_v0_PixelGridType] pixelGridColor: [aDecoder decodeObjectForKey: kGridPatternCodingKey_v0_PixelGridColor]]; return self; } /* - (void) encodeWithCoder_v0: (NSCoder *) coder { [coder encodeInt: _pixelGridType forKey: kGridPatternCodingKey_v0_PixelGridType]; [coder encodeObject: _pixelGridColor forKey: kGridPatternCodingKey_v0_PixelGridColor]; } */ #pragma mark NSCopying protocol - (id) copyWithZone: (NSZone *) zone { PPGridPattern *copiedPattern; copiedPattern = [[[self class] allocWithZone: zone] initWithPixelGridType: _pixelGridType pixelGridColor: [[_pixelGridColor copyWithZone: zone] autorelease] guidelineSpacingSize: _guidelineSpacingSize guidelineColor: [[_guidelineColor copyWithZone: zone] autorelease] shouldDisplayGuidelines: _shouldDisplayGuidelines]; if (_presetName) { [copiedPattern setPresetName: [[_presetName copyWithZone: zone] autorelease]]; } return copiedPattern; } #pragma mark PPPresettablePattern protocol - (void) setPresetName: (NSString *) presetName { [_presetName autorelease]; _presetName = [presetName retain]; } - (NSString *) presetName { return _presetName; } - (bool) isEqualToPresettablePattern: (id ) pattern { if ([pattern isKindOfClass: [self class]]) { return [self isEqualToGridPattern: (PPGridPattern *) pattern]; } return NO; } - (NSColor *) patternColorForPresettablePatternViewOfSize: (NSSize) viewSize { static NSBitmapImageRep *foregroundBitmap = nil; static NSSize foregroundBitmapSize = {0,0}, guidelineSpacingSize = {0,0}; int viewSizeMinDimension, scalingFactor; NSBitmapImageRep *patternBitmap; NSImage *patternImage; if (!foregroundBitmap) { foregroundBitmap = [[NSBitmapImageRep ppImageBitmapFromImageResource: kGridPatternPreviewForegroundImageResourceName] retain]; if (!foregroundBitmap) goto ERROR; foregroundBitmapSize = [foregroundBitmap ppSizeInPixels]; guidelineSpacingSize = NSMakeSize(foregroundBitmapSize.width / 2, foregroundBitmapSize.height / 2); } viewSizeMinDimension = MIN(viewSize.width, viewSize.height); scalingFactor = viewSizeMinDimension / MAX(foregroundBitmapSize.width, foregroundBitmapSize.height); if (scalingFactor < kMinScalingFactorToDrawGrid) { goto ERROR; } patternBitmap = [foregroundBitmap ppImageBitmapScaledByFactor: scalingFactor shouldDrawGrid: YES gridType: _pixelGridType gridColor: _pixelGridColor]; if (!patternBitmap) goto ERROR; if (_shouldDisplayGuidelines) { [patternBitmap ppDrawImageGuidelinesInBounds: [patternBitmap ppFrameInPixels] topLeftPhase: NSMakePoint(guidelineSpacingSize.width * scalingFactor / 2, guidelineSpacingSize.height * scalingFactor / 2) unscaledSpacingSize: guidelineSpacingSize scalingFactor: scalingFactor guidelinePixelValue: [_guidelineColor ppImageBitmapPixelValue]]; } patternImage = [NSImage ppImageWithBitmap: patternBitmap]; if (!patternImage) goto ERROR; return [NSColor colorWithPatternImage: patternImage]; ERROR: return nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPGridPatternPresets.h0000644000076500000240000000207113234403416022357 0ustar joshstaff/* PPGridPatternPresets.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPatternPresets.h" @interface PPGridPatternPresets : PPPatternPresets { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPGridPatternPresets.m0000644000076500000240000000315313234403206022363 0ustar joshstaff/* PPGridPatternPresets.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPGridPatternPresets.h" #import "PPGridPattern.h" #define kStoredGridPatternPresetsFilename @"GridPatternPresets" #define kGridPatternPresetsFiletype @"pikogrid" @implementation PPGridPatternPresets + sharedPresets { static PPGridPatternPresets *sharedPresets = nil; if (!sharedPresets) { sharedPresets = [[self alloc] initWithPresettablePatternClass: [PPGridPattern class] storedPresetsFilename: kStoredGridPatternPresetsFilename presetsFiletype: kGridPatternPresetsFiletype]; } return sharedPresets; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPGridType.h0000644000076500000240000000243713234403416020323 0ustar joshstaff/* PPGridType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPGridType_Lines, kPPGridType_Crosshairs, kPPGridType_LargeDots, kPPGridType_Dots, // add new PPGridType values above this line kNumPPGridTypes } PPGridType; static inline bool PPGridType_IsValid(PPGridType gridType) { return (((unsigned) gridType) < kNumPPGridTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPHotkeyDisplayUtilities.h0000644000076500000240000000215713234403416023260 0ustar joshstaff/* PPHotkeyDisplayUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import NSString *PPDisplayKeyForHotkey(NSString *hotkey); NSString *PPHotkeyForDisplayKey(NSString *displayKey); PikoPixel.Sources.1.0-b10b/PikoPixel/PPHotkeyDisplayUtilities.m0000644000076500000240000000612213234403206023256 0ustar joshstaff/* PPHotkeyDisplayUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPHotkeyDisplayUtilities.h" #import "PPKeyConstants.h" NSString *PPDisplayKeyForHotkey(NSString *hotkey) { int hotkeyLength; unichar hotkeyChar, displayKeyChar = 0; hotkeyLength = [hotkey length]; if (hotkeyLength > 1) { hotkey = [hotkey substringFromIndex: hotkeyLength - 1]; hotkeyLength = [hotkey length]; } if (!hotkeyLength) goto ERROR; hotkeyChar = [hotkey characterAtIndex: 0]; switch (hotkeyChar) { case kTabKeyChar: { displayKeyChar = kTabKeyCharForDisplay; } break; case kReturnKeyChar: { displayKeyChar = kReturnKeyCharForDisplay; } break; case kSpaceKeyChar: { displayKeyChar = (PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_BOTTOM_SQUARE_BRACKET_UNICODE_CHAR) ? kBottomBracketCharForSpaceKeyDisplay : kSpaceKeyChar; } break; case kEscKeyChar: { displayKeyChar = kEscKeyCharForDisplay; } break; default: { return hotkey; } break; } return [NSString stringWithFormat: @"%C", displayKeyChar]; ERROR: return @""; } NSString *PPHotkeyForDisplayKey(NSString *displayKey) { unichar displayKeyChar, hotkeyChar = 0; if (![displayKey length]) { goto ERROR; } displayKeyChar = [displayKey characterAtIndex: 0]; switch (displayKeyChar) { case kTabKeyCharForDisplay: { hotkeyChar = kTabKeyChar; } break; case kReturnKeyCharForDisplay: { hotkeyChar = kReturnKeyChar; } break; case kBottomBracketCharForSpaceKeyDisplay: { hotkeyChar = kSpaceKeyChar; } break; case kEscKeyCharForDisplay: { hotkeyChar = kEscKeyChar; } break; default: { return displayKey; } break; } return [NSString stringWithFormat: @"%C", hotkeyChar]; ERROR: return @""; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPHotkeys.h0000644000076500000240000000266513234403416020225 0ustar joshstaff/* PPHotkeys.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPHotkeyType.h" @interface PPHotkeys : NSObject { } + (void) setupGlobals; + (NSArray *) availableKeyboardLayoutLanguageCodes; + (NSDictionary *) hotkeysDictForLanguageCode: (NSString *) languageCode; + (bool) setHotkeysFromDict: (NSDictionary *) hotkeysDict; + (NSString *) localizedBacktickKeyEquivalent; @end extern NSString *gHotkeys[]; extern NSArray *gHotkeyDictKeys; extern NSString *PPHotkeysNotification_UpdatedHotkeys; PikoPixel.Sources.1.0-b10b/PikoPixel/PPHotkeys.m0000644000076500000240000003647513234403206020235 0ustar joshstaff/* PPHotkeys.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPHotkeys.h" #import "PPKeyboardLayout.h" #import "PPDefines.h" #import "PPKeyConstants.h" #import "NSFileManager_PPUtilities.h" #define kHotkeysDictResourceType @"plist" #define kHotkeysDictResourcePrefix @"Hotkeys_" #define kApplicationSupportFolderName @"PikoPixel" #define kCustomHotkeysDictFilename @"CustomHotkeys.plist" #define kHotkeysDictKey_PencilTool @"PencilTool" #define kHotkeysDictKey_EraserTool @"EraserTool" #define kHotkeysDictKey_FillTool @"FillTool" #define kHotkeysDictKey_LineTool @"LineTool" #define kHotkeysDictKey_RectTool @"RectTool" #define kHotkeysDictKey_OvalTool @"OvalTool" #define kHotkeysDictKey_FreehandSelectTool @"FreehandSelectTool" #define kHotkeysDictKey_RectSelectTool @"RectSelectTool" #define kHotkeysDictKey_MagicWandTool @"MagicWandTool" #define kHotkeysDictKey_ColorSamplerTool @"ColorSamplerTool" #define kHotkeysDictKey_MoveTool @"MoveTool" #define kHotkeysDictKey_MagnifierTool @"MagnifierTool" #define kHotkeysDictKey_NavigatorPopup @"NavigatorPopup" #define kHotkeysDictKey_ToolsPopup @"ToolsPopup" #define kHotkeysDictKey_ColorPickerPopup @"ColorPickerPopup" #define kHotkeysDictKey_LayerControlsPopup @"LayerControlsPopup" #define kHotkeysDictKey_NavigatorPopupAlternate @"NavigatorPopup_Alternate" #define kHotkeysDictKey_ToolsPopupAlternate @"ToolsPopup_Alternate" #define kHotkeysDictKey_ColorPickerPopupAlternate @"ColorPickerPopup_Alternate" #define kHotkeysDictKey_LayerControlsPopupAlternate @"LayerControlsPopup_Alternate" #define kHotkeysDictKey_SwitchCanvasViewMode @"SwitchCanvasViewMode" #define kHotkeysDictKey_SwitchLayerOperationTarget @"SwitchLayerOperationTarget" #define kHotkeysDictKey_ToggleActivePanels @"ToggleActivePanels" #define kHotkeysDictKey_ToggleColorPickerPanel @"ToggleColorPickerPanel" #define kHotkeysDictKey_ZoomIn @"ZoomIn" #define kHotkeysDictKey_ZoomOut @"ZoomOut" #define kHotkeysDictKey_ZoomToFit @"ZoomToFit" #define kHotkeysDictKey_BlinkDocumentLayers @"BlinkDocumentLayers" NSString *gHotkeys[kNumPPHotkeyTypes]; NSArray *gHotkeyDictKeys = nil; NSString *PPHotkeysNotification_UpdatedHotkeys = @"PPHotkeysNotification_UpdatedHotkeys"; static NSDictionary *gDefaultHotkeysDict = nil; static NSString *gCustomHotkeysDictResourcePath = nil; static bool SetupHotkeyDictKeysArray(void); static bool SetupDefaultHotkeysDictForCurrentKeyboardLayout(void); static bool SetupCustomHotkeysDictResourcePath(void); static NSString *HotkeysDictResourcePathForLanguageCode(NSString *languageCode); static NSDictionary *HotkeysDictAtFilepath(NSString *filepath); static void LoadHotkeysArrayFromDict(NSDictionary *hotkeysDict); static void SaveCustomHotkeysDict(NSDictionary *hotkeysDict); static void DeleteCustomHotkeysDict(void); static NSString *ModifiedHotkeyForXMLKey(NSString *xmlKey); static NSString *ModifiedXMLKeyForHotkey(NSString *hotkey); @implementation PPHotkeys + (void) initialize { NSDictionary *hotkeysDict; if ([self class] != [PPHotkeys class]) { return; } SetupHotkeyDictKeysArray(); SetupDefaultHotkeysDictForCurrentKeyboardLayout(); SetupCustomHotkeysDictResourcePath(); hotkeysDict = HotkeysDictAtFilepath(gCustomHotkeysDictResourcePath); if (!hotkeysDict) { hotkeysDict = gDefaultHotkeysDict; } LoadHotkeysArrayFromDict(hotkeysDict); } + (void) setupGlobals { // this gets called multiple times when the classes that depend on gHotkeys[] are setting // up themselves - the actual setup is done in +initialize (called automatically the first // time a message is received) } + (NSArray *) availableKeyboardLayoutLanguageCodes { static NSMutableArray *languageCodes = nil; int resourcePrefixLength; NSArray *resourcePaths; NSEnumerator *resourcePathEnumerator; NSString *resourcePath, *resourceFilename; if (languageCodes) { return languageCodes; } languageCodes = [[NSMutableArray array] retain]; resourcePrefixLength = [kHotkeysDictResourcePrefix length]; resourcePaths = [NSBundle pathsForResourcesOfType: kHotkeysDictResourceType inDirectory: [[NSBundle mainBundle] resourcePath]]; resourcePathEnumerator = [resourcePaths objectEnumerator]; while (resourcePath = [resourcePathEnumerator nextObject]) { resourceFilename = [resourcePath lastPathComponent]; if ([resourceFilename hasPrefix: kHotkeysDictResourcePrefix]) { resourceFilename = [resourceFilename stringByDeletingPathExtension]; if ([resourceFilename length] > resourcePrefixLength) { [languageCodes addObject: [resourceFilename substringFromIndex: resourcePrefixLength]]; } } } [languageCodes sortUsingSelector: @selector(compare:)]; return languageCodes; } + (NSDictionary *) hotkeysDictForLanguageCode: (NSString *) languageCode { NSString *hotkeysDictResourcePath; NSDictionary *hotkeysDict = nil; hotkeysDictResourcePath = HotkeysDictResourcePathForLanguageCode(languageCode); if (hotkeysDictResourcePath) { hotkeysDict = HotkeysDictAtFilepath(hotkeysDictResourcePath); } if (!hotkeysDictResourcePath || !hotkeysDict) { hotkeysDictResourcePath = HotkeysDictResourcePathForLanguageCode(kDefaultKeyboardLayoutLanguageCode); if (!hotkeysDictResourcePath) goto ERROR; hotkeysDict = HotkeysDictAtFilepath(hotkeysDictResourcePath); if (!hotkeysDict) goto ERROR; } return hotkeysDict; ERROR: return gDefaultHotkeysDict; } + (bool) setHotkeysFromDict: (NSDictionary *) hotkeysDict { if (![hotkeysDict count]) { goto ERROR; } LoadHotkeysArrayFromDict(hotkeysDict); if (![hotkeysDict isEqualToDictionary: gDefaultHotkeysDict]) { SaveCustomHotkeysDict(hotkeysDict); } else { DeleteCustomHotkeysDict(); } return YES; ERROR: return NO; } + (NSString *) localizedBacktickKeyEquivalent { // gDefaultHotkeysDict is loaded from the presets matching the current keyboard language // layout, and the default 'switch canvas view mode' hotkey (almost) always matches // the key in the position directly above the Tab key (on US layouts, it's the backtick // key: `) return [gDefaultHotkeysDict objectForKey: kHotkeysDictKey_SwitchCanvasViewMode]; } @end #pragma mark Private functions static bool SetupHotkeyDictKeysArray(void) { NSArray *hotkeyDictKeys; if (gHotkeyDictKeys) { return YES; } hotkeyDictKeys = [NSArray arrayWithObjects: // Must match PPHotkeyType values kHotkeysDictKey_PencilTool, kHotkeysDictKey_EraserTool, kHotkeysDictKey_FillTool, kHotkeysDictKey_LineTool, kHotkeysDictKey_RectTool, kHotkeysDictKey_OvalTool, kHotkeysDictKey_FreehandSelectTool, kHotkeysDictKey_RectSelectTool, kHotkeysDictKey_MagicWandTool, kHotkeysDictKey_ColorSamplerTool, kHotkeysDictKey_MoveTool, kHotkeysDictKey_MagnifierTool, kHotkeysDictKey_ToolsPopup, kHotkeysDictKey_ColorPickerPopup, kHotkeysDictKey_LayerControlsPopup, kHotkeysDictKey_NavigatorPopup, kHotkeysDictKey_ToolsPopupAlternate, kHotkeysDictKey_ColorPickerPopupAlternate, kHotkeysDictKey_LayerControlsPopupAlternate, kHotkeysDictKey_NavigatorPopupAlternate, kHotkeysDictKey_SwitchCanvasViewMode, kHotkeysDictKey_SwitchLayerOperationTarget, kHotkeysDictKey_ToggleActivePanels, kHotkeysDictKey_ToggleColorPickerPanel, kHotkeysDictKey_ZoomIn, kHotkeysDictKey_ZoomOut, kHotkeysDictKey_ZoomToFit, kHotkeysDictKey_BlinkDocumentLayers, nil]; if ([hotkeyDictKeys count] != kNumPPHotkeyTypes) { goto ERROR; } gHotkeyDictKeys = [hotkeyDictKeys retain]; return YES; ERROR: return NO; } static bool SetupDefaultHotkeysDictForCurrentKeyboardLayout(void) { NSString *keyboardLayoutLanguageCode; if (gDefaultHotkeysDict) { return YES; } keyboardLayoutLanguageCode = PPKeyboardLayout_LanguageLocaleString(); if (![keyboardLayoutLanguageCode length]) { keyboardLayoutLanguageCode = kDefaultKeyboardLayoutLanguageCode; } gDefaultHotkeysDict = [[PPHotkeys hotkeysDictForLanguageCode: keyboardLayoutLanguageCode] retain]; if (!gDefaultHotkeysDict) { if ([keyboardLayoutLanguageCode isEqualToString: kDefaultKeyboardLayoutLanguageCode]) { goto ERROR; } gDefaultHotkeysDict = [[PPHotkeys hotkeysDictForLanguageCode: kDefaultKeyboardLayoutLanguageCode] retain]; if (!gDefaultHotkeysDict) goto ERROR; } return YES; ERROR: return NO; } static bool SetupCustomHotkeysDictResourcePath(void) { if (gCustomHotkeysDictResourcePath) { return YES; } gCustomHotkeysDictResourcePath = [[NSFileManager ppFilepathForSupportFileWithName: kCustomHotkeysDictFilename] retain]; if (!gCustomHotkeysDictResourcePath) goto ERROR; return YES; ERROR: return NO; } static NSString *HotkeysDictResourcePathForLanguageCode(NSString *languageCode) { NSString *filename; if (![languageCode length]) { goto ERROR; } filename = [NSString stringWithFormat: @"%@%@.%@", kHotkeysDictResourcePrefix, languageCode, kHotkeysDictResourceType]; if (!filename) goto ERROR; return [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: filename]; ERROR: return nil; } static NSDictionary *HotkeysDictAtFilepath(NSString *filepath) { NSDictionary *xmlKeysDict; NSMutableDictionary *hotkeysDict; int i; NSString *dictKey, *hotkey; if (![[NSFileManager defaultManager] isReadableFileAtPath: filepath]) { goto ERROR; } xmlKeysDict = [NSDictionary dictionaryWithContentsOfFile: filepath]; if (![xmlKeysDict count]) { goto ERROR; } hotkeysDict = [NSMutableDictionary dictionaryWithDictionary: xmlKeysDict]; if (!hotkeysDict) goto ERROR; for (i=0; i. */ #import @interface PPHotkeySettingsWindowController : NSObject { IBOutlet NSWindow *_window; IBOutlet NSMatrix *_toolFieldsMatrix1; IBOutlet NSMatrix *_toolFieldsMatrix2; IBOutlet NSMatrix *_popupPanelFieldsMatrix; IBOutlet NSMatrix *_actionFieldsMatrix; IBOutlet NSPopUpButton *_systemKeyPopUpButton; IBOutlet NSPopUpButton *_languagePopUpButton; NSArray *_keyFieldsMatrices; NSString *_previousKeyFieldValue; NSMutableSet *_currentHotkeysSet; } + (PPHotkeySettingsWindowController *) sharedController; - (void) showPanel; - (IBAction) insertSystemKeyButtonPressed: (id) sender; - (IBAction) loadDefaultsForLanguageButtonPressed: (id) sender; - (IBAction) OKButtonPressed: (id) sender; - (IBAction) cancelButtonPressed: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPHotkeySettingsWindowController.m0000644000076500000240000003417613234403206025023 0ustar joshstaff/* PPHotkeySettingsWindowController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPHotkeySettingsWindowController.h" #import "PPHotkeys.h" #import "PPHotkeyDisplayUtilities.h" #import "PPKeyboardLayout.h" #import "PPKeyConstants.h" #import "PPDefines.h" #define kHotkeySettingsWindowNibName @"HotkeySettings" #define kReturnMenuItemTitle @"Return" #define kTabMenuItemTitle @"Tab" #define kEscMenuItemTitle @"Esc" @interface PPHotkeySettingsWindowController (PrivateMethods) - (bool) setupKeyFieldsMatricesArray; - (bool) setupSystemKeyPopUpButtonMenu; - (bool) setupLanguagePopUpButtonMenu; - (void) saveKeyFieldsToHotkeys; - (void) loadKeyFieldsFromHotkeysArray; - (void) loadKeyFieldsFromHotkeysDict: (NSDictionary *) hotkeysDict; - (NSCell *) activeKeyFieldTextCell; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPHotkeySettingsWindowController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPHotkeySettingsWindowController + (PPHotkeySettingsWindowController *) sharedController { static PPHotkeySettingsWindowController *sharedController = nil; if (!sharedController) { sharedController = [[self alloc] init]; } return sharedController; } - init { self = [super init]; if (!self) goto ERROR; _currentHotkeysSet = [[NSMutableSet set] retain]; if (!_currentHotkeysSet) goto ERROR; if (![NSBundle loadNibNamed: kHotkeySettingsWindowNibName owner: self] || ![self setupKeyFieldsMatricesArray] || ![self setupSystemKeyPopUpButtonMenu] || ![self setupLanguagePopUpButtonMenu]) { goto ERROR; } [self loadKeyFieldsFromHotkeysArray]; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_keyFieldsMatrices release]; [_previousKeyFieldValue release]; [_currentHotkeysSet release]; [super dealloc]; } - (void) showPanel { [_window makeKeyAndOrderFront: self]; [_window makeMainWindow]; } #pragma mark Actions - (IBAction) insertSystemKeyButtonPressed: (id) sender { unichar hotkeyChar; NSString *hotkey, *displayKey; NSCell *activeKeyFieldCell; NSString *previousCellValue; hotkeyChar = [_systemKeyPopUpButton selectedTag]; hotkey = [NSString stringWithCharacters: &hotkeyChar length: 1]; displayKey = PPDisplayKeyForHotkey(hotkey); if (![displayKey length] || [_currentHotkeysSet containsObject: displayKey]) { goto ERROR; } activeKeyFieldCell = [self activeKeyFieldTextCell]; if (!activeKeyFieldCell) goto ERROR; previousCellValue = [activeKeyFieldCell stringValue]; if (previousCellValue) { [_currentHotkeysSet removeObject: previousCellValue]; } [_currentHotkeysSet addObject: displayKey]; [activeKeyFieldCell setStringValue: displayKey]; [_previousKeyFieldValue release]; _previousKeyFieldValue = [displayKey retain]; return; ERROR: NSBeep(); } - (IBAction) loadDefaultsForLanguageButtonPressed: (id) sender { NSDictionary *hotkeysDict = [PPHotkeys hotkeysDictForLanguageCode: [_languagePopUpButton titleOfSelectedItem]]; [self loadKeyFieldsFromHotkeysDict: hotkeysDict]; } - (IBAction) OKButtonPressed: (id) sender { [self saveKeyFieldsToHotkeys]; [_window orderOut: self]; } - (IBAction) cancelButtonPressed: (id) sender { [_window orderOut: self]; [self loadKeyFieldsFromHotkeysArray]; } #pragma mark NSMatrix delegate methods - (void) controlTextDidBeginEditing: (NSNotification *) notification { NSMatrix *activeKeyFieldsMatrix = [notification object]; [_previousKeyFieldValue release]; _previousKeyFieldValue = [[activeKeyFieldsMatrix stringValue] retain]; } - (void) controlTextDidChange: (NSNotification *) notification { NSMatrix *activeKeyFieldsMatrix; NSString *previousKeyFieldValue, *keyFieldValue; int previousKeyFieldValueLength, keyFieldValueLength; activeKeyFieldsMatrix = [notification object]; previousKeyFieldValue = _previousKeyFieldValue; previousKeyFieldValueLength = [previousKeyFieldValue length]; if (!previousKeyFieldValueLength) { previousKeyFieldValue = gHotkeys[[activeKeyFieldsMatrix tag]]; } else if (previousKeyFieldValueLength > 1) { previousKeyFieldValue = [previousKeyFieldValue substringToIndex: 1]; } keyFieldValue = [activeKeyFieldsMatrix stringValue]; keyFieldValueLength = [keyFieldValue length]; if (!keyFieldValueLength) { keyFieldValue = previousKeyFieldValue; } else if (keyFieldValueLength > 1) { if (![keyFieldValue hasSuffix: previousKeyFieldValue]) { keyFieldValue = [keyFieldValue substringFromIndex: keyFieldValueLength - 1]; } else { keyFieldValue = [keyFieldValue substringWithRange: NSMakeRange(keyFieldValueLength - 2, 1)]; } } keyFieldValue = PPDisplayKeyForHotkey(keyFieldValue); if (![keyFieldValue length] || [_currentHotkeysSet containsObject: keyFieldValue]) { if (_previousKeyFieldValue && ![keyFieldValue isEqualToString: _previousKeyFieldValue]) { NSBeep(); } keyFieldValue = _previousKeyFieldValue; } [activeKeyFieldsMatrix setStringValue: keyFieldValue]; [activeKeyFieldsMatrix selectText: self]; if ([_previousKeyFieldValue isEqualToString: keyFieldValue]) { return; } [_currentHotkeysSet addObject: keyFieldValue]; if (_previousKeyFieldValue) { [_currentHotkeysSet removeObject: _previousKeyFieldValue]; } [_previousKeyFieldValue release]; _previousKeyFieldValue = [keyFieldValue retain]; } #pragma mark Private methods - (bool) setupKeyFieldsMatricesArray { NSArray *matricesArray; NSEnumerator *matricesEnumerator, *cellsEnumerator; NSMatrix *matrix; int hotkeyIndex; NSCell *cell; matricesArray = [NSArray arrayWithObjects: _toolFieldsMatrix1, _toolFieldsMatrix2, _popupPanelFieldsMatrix, _actionFieldsMatrix, nil]; if ([matricesArray count] != 4) { goto ERROR; } matricesEnumerator = [matricesArray objectEnumerator]; while (matrix = [matricesEnumerator nextObject]) { [matrix setDelegate: self]; hotkeyIndex = [matrix tag]; cellsEnumerator = [[matrix cells] objectEnumerator]; while (cell = [cellsEnumerator nextObject]) { [cell setTag: hotkeyIndex++]; } } _keyFieldsMatrices = [matricesArray retain]; return YES; ERROR: return NO; } - (bool) setupSystemKeyPopUpButtonMenu { NSMenu *menu; NSString *menuItemTitle; NSMenuItem *menuItem; menu = [[[NSMenu alloc] init] autorelease]; if (!menu) goto ERROR; // Return menu item menuItemTitle = [NSString stringWithFormat: @"%C %@", kReturnKeyCharForDisplay, kReturnMenuItemTitle]; menuItem = [[[NSMenuItem alloc] initWithTitle: menuItemTitle action: NULL keyEquivalent: @""] autorelease]; if (!menuItem) goto ERROR; [menuItem setTag: kReturnKeyChar]; [menu addItem: menuItem]; // Tab menu item menuItemTitle = [NSString stringWithFormat: @"%C %@", kTabKeyCharForDisplay, kTabMenuItemTitle]; menuItem = [[[NSMenuItem alloc] initWithTitle: menuItemTitle action: NULL keyEquivalent: @""] autorelease]; if (!menuItem) goto ERROR; [menuItem setTag: kTabKeyChar]; [menu addItem: menuItem]; // Esc menu item menuItemTitle = [NSString stringWithFormat: @"%C %@", kEscKeyCharForDisplay, kEscMenuItemTitle]; menuItem = [[[NSMenuItem alloc] initWithTitle: menuItemTitle action: NULL keyEquivalent: @""] autorelease]; if (!menuItem) goto ERROR; [menuItem setTag: kEscKeyChar]; [menu addItem: menuItem]; [_systemKeyPopUpButton setMenu: menu]; return YES; ERROR: return NO; } - (bool) setupLanguagePopUpButtonMenu { NSMenu *menu; NSArray *availableLanguageCodes; int numAvailableLanguageCodes, i; NSString *keyboardLayoutLanguageCode; menu = [[[NSMenu alloc] init] autorelease]; availableLanguageCodes = [PPHotkeys availableKeyboardLayoutLanguageCodes]; numAvailableLanguageCodes = [availableLanguageCodes count]; if (![availableLanguageCodes count] || !menu) { goto ERROR; } for (i=0; i. */ typedef enum { // Must match array returned by PPHotkeys.m private function, SetupHotkeyDictKeysArray() kPPHotkeyType_Tool_Pencil, kPPHotkeyType_Tool_Eraser, kPPHotkeyType_Tool_Fill, kPPHotkeyType_Tool_Line, kPPHotkeyType_Tool_Rect, kPPHotkeyType_Tool_Oval, kPPHotkeyType_Tool_FreehandSelect, kPPHotkeyType_Tool_RectSelect, kPPHotkeyType_Tool_MagicWand, kPPHotkeyType_Tool_ColorSampler, kPPHotkeyType_Tool_Move, kPPHotkeyType_Tool_Magnifier, kPPHotkeyType_PopupPanel_Tools, kPPHotkeyType_PopupPanel_ColorPicker, kPPHotkeyType_PopupPanel_LayerControls, kPPHotkeyType_PopupPanel_Navigator, kPPHotkeyType_PopupPanel_ToolsAlternate, kPPHotkeyType_PopupPanel_ColorPickerAlternate, kPPHotkeyType_PopupPanel_LayerControlsAlternate, kPPHotkeyType_PopupPanel_NavigatorAlternate, kPPHotkeyType_SwitchCanvasViewMode, kPPHotkeyType_SwitchLayerOperationTarget, kPPHotkeyType_ToggleActivePanels, kPPHotkeyType_ToggleColorPickerPanel, kPPHotkeyType_ZoomIn, kPPHotkeyType_ZoomOut, kPPHotkeyType_ZoomToFit, kPPHotkeyType_BlinkDocumentLayers, kNumPPHotkeyTypes } PPHotkeyType; static inline bool PPHotkeyType_IsValid(PPHotkeyType hotkeyType) { return (((unsigned) hotkeyType) < kNumPPHotkeyTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPImagePixelAlphaPremultiplyTables.h0000644000076500000240000000440613234403416025166 0ustar joshstaff/* PPImagePixelAlphaPremultiplyTables.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPBitmapPixelTypes.h" // Lookup tables for premultiplying & unpremultiplying image bitmap pixels' color values with // their alpha values. (Table lookups are faster than multiplying/dividing+rounding-off). // // Tables are stored as a global array - one lookup table for each possible alpha value [0-255]; // Each lookup table contains entries for all possible color-channel values [0-255]. // // To premultiply an image pixel: // // premultiplyTable = gImageAlphaPremultiplyTables[imagePixel.alphaComponent] // premultipliedImagePixel.redComponent = premultiplyTable[imagePixel.redComponent] // premultipliedImagePixel.greenComponent = premultiplyTable[imagePixel.greenComponent] // premultipliedImagePixel.blueComponent = premultiplyTable[imagePixel.blueComponent] // // (Same process for unpremultiplying) extern PPImagePixelComponent *gImageAlphaPremultiplyTables[], *gImageAlphaUnpremultiplyTables[]; #define macroAlphaPremultiplyTableForImagePixel(imagePixel) \ gImageAlphaPremultiplyTables[macroImagePixelComponent_Alpha(imagePixel)] #define macroAlphaUnpremultiplyTableForImagePixel(imagePixel) \ gImageAlphaUnpremultiplyTables[macroImagePixelComponent_Alpha(imagePixel)] PikoPixel.Sources.1.0-b10b/PikoPixel/PPImagePixelAlphaPremultiplyTables.m0000644000076500000240000001031213234403206025161 0ustar joshstaff/* PPImagePixelAlphaPremultiplyTables.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPImagePixelAlphaPremultiplyTables.h" #define kNumLookupTables (kMaxImagePixelComponentValue+1) #define kSizeOfLookupTable ((kMaxImagePixelComponentValue+1) * sizeof(PPImagePixelComponent)) PPImagePixelComponent *gImageAlphaPremultiplyTables[kNumLookupTables], *gImageAlphaUnpremultiplyTables[kNumLookupTables]; static bool SetupImageAlphaPremultiplyTables(void); @implementation NSObject (PPImagePixelAlphaPremultiplyTables) + (void) load { SetupImageAlphaPremultiplyTables(); } @end #pragma mark Private functions static bool SetupImageAlphaPremultiplyTables(void) { int tablesBufferSize, alphaValue, colorValue; unsigned char *premultiplyTablesBuffer = NULL, *unpremultiplyTablesBuffer = NULL; PPImagePixelComponent *currentTable; tablesBufferSize = kNumLookupTables * kSizeOfLookupTable; premultiplyTablesBuffer = (unsigned char *) malloc (tablesBufferSize); unpremultiplyTablesBuffer = (unsigned char *) malloc (tablesBufferSize); if (!premultiplyTablesBuffer || !unpremultiplyTablesBuffer) { goto ERROR; } // alphaValue=[0] tables // premultiply currentTable = premultiplyTablesBuffer; premultiplyTablesBuffer += kSizeOfLookupTable; memset(currentTable, 0, kSizeOfLookupTable); gImageAlphaPremultiplyTables[0] = currentTable; // unpremultiply currentTable = unpremultiplyTablesBuffer; unpremultiplyTablesBuffer += kSizeOfLookupTable; memset(currentTable, 0, kSizeOfLookupTable); gImageAlphaUnpremultiplyTables[0] = currentTable; // alphaValue=[1..MAX] tables for (alphaValue=1; alphaValue<=kMaxImagePixelComponentValue; alphaValue++) { // premultiply currentTable = premultiplyTablesBuffer; premultiplyTablesBuffer += kSizeOfLookupTable; currentTable[0] = 0; for (colorValue=1; colorValue<=kMaxImagePixelComponentValue; colorValue++) { currentTable[colorValue] = (PPImagePixelComponent) roundf(((float) colorValue) * ((float) alphaValue) / ((float) kMaxImagePixelComponentValue)); } gImageAlphaPremultiplyTables[alphaValue] = currentTable; // unpremultiply currentTable = unpremultiplyTablesBuffer; unpremultiplyTablesBuffer += kSizeOfLookupTable; currentTable[0] = 0; for (colorValue=1; colorValue. */ #import @interface PPImageSizePresets : NSObject { } + (NSArray *) presetStrings; + (void) setPresetStrings: (NSArray *) presetStrings; + (NSArray *) appDefaultPresetStrings; @end extern NSString *PPImageSizePresets_PresetStringForNameAndSize(NSString *name, NSSize size); extern NSString *PPImageSizePresets_NameForPresetString(NSString *presetString); extern NSSize PPImageSizePresets_SizeForPresetString(NSString *presetString); extern NSString *PPImageSizePresetsNotification_UpdatedPresets; PikoPixel.Sources.1.0-b10b/PikoPixel/PPImageSizePresets.m0000644000076500000240000002057513234403206022024 0ustar joshstaff/* PPImageSizePresets.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPImageSizePresets.h" #import "PPDefines.h" #import "PPGeometry.h" #import "NSFileManager_PPUtilities.h" #define kCustomPresetsFilename @"ImageSizePresets.plist" #define kCustomPresetsDictKey_PresetStrings @"Preset Strings" #define kDefaultPresetStrings [NSArray arrayWithObjects: \ @"Small (32x32)", \ @"Medium (64x64)", \ @"Large (128x128)", \ @"Extra Large (256x256)", \ nil] NSString *PPImageSizePresetsNotification_UpdatedPresets = @"PPImageSizePresetsNotification_UpdatedPresets"; static NSString *gCustomPresetsFilePath = nil; static NSArray *gDefaultPresetStrings = nil, *gPresetStrings = nil; static bool SetupDefaultPresetStrings(void); static bool SetupCustomPresetsFilePath(void); static void LoadPresetStrings(void); static void SavePresetStrings(NSArray *presetStrings); static NSArray *VerifiedPresetStringsForPresetStrings(NSArray *presetStrings); @implementation PPImageSizePresets + (void) initialize { if ([self class] != [PPImageSizePresets class]) { return; } SetupDefaultPresetStrings(); LoadPresetStrings(); } + (NSArray *) presetStrings { return gPresetStrings; } + (void) setPresetStrings: (NSArray *) presetStrings { SavePresetStrings(presetStrings); LoadPresetStrings(); [[NSNotificationCenter defaultCenter] postNotificationName: PPImageSizePresetsNotification_UpdatedPresets object: nil]; } + (NSArray *) appDefaultPresetStrings { return gDefaultPresetStrings; } @end #pragma mark Public functions NSString *PPImageSizePresets_PresetStringForNameAndSize(NSString *name, NSSize size) { if (![name length] || PPGeometry_IsZeroSize(size)) { return nil; } return [NSString stringWithFormat: @"%@ (%dx%d)", name, (int) size.width, (int) size.height]; } NSString *PPImageSizePresets_NameForPresetString(NSString *presetString) { NSRange cutoffRange = [presetString rangeOfString: @" (" options: NSBackwardsSearch]; if (!cutoffRange.length) { goto ERROR; } return [presetString substringToIndex: cutoffRange.location]; ERROR: return nil; } NSSize PPImageSizePresets_SizeForPresetString(NSString *presetString) { NSRange range, replacementRange; NSMutableString *sizeString; NSSize presetSize; range = [presetString rangeOfString: @"(" options: NSBackwardsSearch]; if (!range.length) { goto ERROR; } sizeString = [NSMutableString stringWithString: [presetString substringFromIndex: range.location]]; replacementRange = NSMakeRange(0, [sizeString length]); if (!range.length) { goto ERROR; } [sizeString replaceOccurrencesOfString: @"(" withString: @"{" options: 0 range: replacementRange]; [sizeString replaceOccurrencesOfString: @")" withString: @"}" options: 0 range: replacementRange]; [sizeString replaceOccurrencesOfString: @"x" withString: @"," options: 0 range: replacementRange]; presetSize = NSSizeFromString(sizeString); if (PPGeometry_IsZeroSize(presetSize) || (presetSize.width > kMaxCanvasDimension) || (presetSize.height > kMaxCanvasDimension)) { goto ERROR; } return presetSize; ERROR: return NSZeroSize; } #pragma mark Private functions static bool SetupDefaultPresetStrings(void) { if (gDefaultPresetStrings) { return YES; } gDefaultPresetStrings = [VerifiedPresetStringsForPresetStrings(kDefaultPresetStrings) retain]; if (!gDefaultPresetStrings) goto ERROR; return YES; ERROR: return NO; } static bool SetupCustomPresetsFilePath(void) { if (gCustomPresetsFilePath) { return YES; } gCustomPresetsFilePath = [[NSFileManager ppFilepathForSupportFileWithName: kCustomPresetsFilename] retain]; if (!gCustomPresetsFilePath) goto ERROR; return YES; ERROR: return NO; } static void LoadPresetStrings(void) { NSDictionary *customPresetsDict; NSArray *customPresetStrings; [gPresetStrings autorelease]; gPresetStrings = nil; if (!gCustomPresetsFilePath && !SetupCustomPresetsFilePath()) { goto ERROR; } if (![[NSFileManager defaultManager] isReadableFileAtPath: gCustomPresetsFilePath]) { goto ERROR; } customPresetsDict = [NSDictionary dictionaryWithContentsOfFile: gCustomPresetsFilePath]; customPresetStrings = [customPresetsDict objectForKey: kCustomPresetsDictKey_PresetStrings]; if (![customPresetStrings isKindOfClass: [NSArray class]]) { goto ERROR; } gPresetStrings = [VerifiedPresetStringsForPresetStrings(customPresetStrings) retain]; if (![gPresetStrings count]) { goto ERROR; } return; ERROR: gPresetStrings = [gDefaultPresetStrings retain]; } static void SavePresetStrings(NSArray *presetStrings) { NSFileManager *fileManager; if (!gCustomPresetsFilePath && !SetupCustomPresetsFilePath()) { goto ERROR; } fileManager = [NSFileManager defaultManager]; presetStrings = VerifiedPresetStringsForPresetStrings(presetStrings); if (![presetStrings count] || [presetStrings isEqualToArray: gDefaultPresetStrings]) { [fileManager ppDeleteSupportFileAtPath: gCustomPresetsFilePath]; } else { NSDictionary *customPresetsDict; if (![fileManager ppVerifySupportFileDirectory]) { goto ERROR; } customPresetsDict = [NSDictionary dictionaryWithObject: presetStrings forKey: kCustomPresetsDictKey_PresetStrings]; [customPresetsDict writeToFile: gCustomPresetsFilePath atomically: YES]; } return; ERROR: return; } static NSArray *VerifiedPresetStringsForPresetStrings(NSArray *presetStrings) { NSMutableArray *verifiedPresetStrings; NSEnumerator *presetEnumerator; NSString *presetString; if (![presetStrings count]) { goto ERROR; } verifiedPresetStrings = [NSMutableArray array]; if (!verifiedPresetStrings) goto ERROR; presetEnumerator = [presetStrings objectEnumerator]; while (presetString = [presetEnumerator nextObject]) { if ([presetString isKindOfClass: [NSString class]] && !PPGeometry_IsZeroSize(PPImageSizePresets_SizeForPresetString(presetString))) { [verifiedPresetStrings addObject: presetString]; } } if ([presetStrings count] != [verifiedPresetStrings count]) { presetStrings = [NSArray arrayWithArray: verifiedPresetStrings]; if (!presetStrings) { presetStrings = verifiedPresetStrings; } } return presetStrings; ERROR: return nil; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPKeyboardLayout.h0000644000076500000240000000206413234403416021526 0ustar joshstaff/* PPKeyboardLayout.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import NSString *PPKeyboardLayout_LanguageLocaleString(void); PikoPixel.Sources.1.0-b10b/PikoPixel/PPKeyboardLayout.m0000644000076500000240000000715213234403206021533 0ustar joshstaff/* PPKeyboardLayout.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPKeyboardLayout.h" #import "PPDefines.h" #if PP_DEPLOYMENT_TARGET_SUPPORTS_CARBON #import #define kKeyboardNameToLocaleDictResourceName @"KeyboardNameToLocale" #if PP_DEPLOYMENT_TARGET_DEPRECATED_KEYBOARDLAYOUT NSString *PPKeyboardLayout_LanguageLocaleString(void) { static NSDictionary *keyboardNameToLocaleDict = nil; TISInputSourceRef inputSourceRef; NSString *keyboardName, *localeString; NSArray *languageNames; if (!keyboardNameToLocaleDict) { NSString *dictPath = [[NSBundle mainBundle] pathForResource: kKeyboardNameToLocaleDictResourceName ofType: @"plist"]; if (dictPath) { keyboardNameToLocaleDict = [[NSDictionary dictionaryWithContentsOfFile: dictPath] retain]; } } inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource(); if (!inputSourceRef) goto ERROR; keyboardName = (NSString *) TISGetInputSourceProperty(inputSourceRef, kTISPropertyLocalizedName); if (keyboardName) { localeString = [keyboardNameToLocaleDict objectForKey: keyboardName]; if (localeString) { return [NSString stringWithString: localeString]; } } languageNames = (NSArray *) TISGetInputSourceProperty(inputSourceRef, kTISPropertyInputSourceLanguages); if (![languageNames count]) { goto ERROR; } return [NSString stringWithString: [languageNames objectAtIndex: 0]]; ERROR: return kDefaultKeyboardLayoutLanguageCode; } #else // Deployment target supports keyboard layout NSString *PPKeyboardLayout_LanguageLocaleString(void) { OSStatus status; KeyboardLayoutRef keyboardLayout; CFStringRef stringRef; NSString *localeString; status = KLGetCurrentKeyboardLayout(&keyboardLayout); if (status != noErr) { goto ERROR; } status = KLGetKeyboardLayoutProperty(keyboardLayout, kKLLanguageCode, (const void **) &stringRef); if (status != noErr) { goto ERROR; } localeString = (NSString *) stringRef; if (![localeString length]) { goto ERROR; } return [NSString stringWithString: localeString]; ERROR: return kDefaultKeyboardLayoutLanguageCode; } #endif // PP_DEPLOYMENT_TARGET_DEPRECATED_KEYBOARDLAYOUT #else // Deployment target doesn't support Carbon NSString *PPKeyboardLayout_LanguageLocaleString(void) { return kDefaultKeyboardLayoutLanguageCode; } #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_CARBON PikoPixel.Sources.1.0-b10b/PikoPixel/PPKeyCancellableWindow.h0000644000076500000240000000212613234403416022615 0ustar joshstaff/* PPKeyCancellableWindow.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPKeyCancellableWindow : NSWindow { IBOutlet NSButton *_cancelButton; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPKeyCancellableWindow.m0000644000076500000240000000674213234403206022627 0ustar joshstaff/* PPKeyCancellableWindow.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPKeyCancellableWindow.h" #import "PPKeyConstants.h" #import "NSObject_PPUtilities.h" #define kHiddenButtonFrame NSMakeRect(-1,-1,1,1) @interface PPKeyCancellableWindow (PrivateMethods) - (void) addHiddenButtonWithKeyEquivalent: (NSString *) keyEquivalent modifierMask: (unsigned int) modifierMask actionSelector: (SEL) actionSelector; - (void) performCancelButtonClick: (id) sender; - (void) performCancelButtonClickAndTerminate: (id) sender; @end @implementation PPKeyCancellableWindow #pragma mark NSWindow overrides - (void) awakeFromNib { // check before calling [super awakeFromNib] - before 10.6, some classes didn't implement it if ([[PPKeyCancellableWindow superclass] instancesRespondToSelector: @selector(awakeFromNib)]) { [super awakeFromNib]; } [self addHiddenButtonWithKeyEquivalent: @"w" modifierMask: NSCommandKeyMask actionSelector: @selector(performCancelButtonClick:)]; [self addHiddenButtonWithKeyEquivalent: @"." modifierMask: NSCommandKeyMask actionSelector: @selector(performCancelButtonClick:)]; [self addHiddenButtonWithKeyEquivalent: kEscKey modifierMask: 0 actionSelector: @selector(performCancelButtonClick:)]; [self addHiddenButtonWithKeyEquivalent: @"q" modifierMask: NSCommandKeyMask actionSelector: @selector(performCancelButtonClickAndTerminate:)]; } #pragma mark Private methods - (void) addHiddenButtonWithKeyEquivalent: (NSString *) keyEquivalent modifierMask: (unsigned int) modifierMask actionSelector: (SEL) actionSelector { NSButton *button; if (![keyEquivalent length] || !actionSelector) { goto ERROR; } button = [[[NSButton alloc] initWithFrame: kHiddenButtonFrame] autorelease]; if (!button) goto ERROR; [button setKeyEquivalentModifierMask: modifierMask]; [button setKeyEquivalent: keyEquivalent]; [button setTarget: self]; [button setAction: actionSelector]; [[self contentView] addSubview: button]; return; ERROR: return; } - (void) performCancelButtonClick: (id) sender { [_cancelButton performClick: self]; } - (void) performCancelButtonClickAndTerminate: (id) sender { [self performCancelButtonClick: self]; [NSApp ppPerformSelectorFromNewStackFrame: @selector(terminate:)]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPKeyConstants.h0000644000076500000240000000472513234403416021223 0ustar joshstaff/* PPKeyConstants.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #define kTabKey @"\t" #define kTabKeyForXML @"\\T" #define kTabKeyChar '\t' #define kTabKeyCharForDisplay ((unichar) 0x21E5) #define kReturnKey @"\r" #define kReturnKeyForXML @"\\R" #define kReturnKeyChar '\r' #define kReturnKeyCharForDisplay ((unichar) 0x21A9) #define kEscKey @"\e" #define kEscKeyForXML @"\\E" #define kEscKeyChar '\e' #define kEscKeyCharForDisplay ((unichar) 0x238B) #define kSpaceKey @" " #define kSpaceKeyChar ' ' #define kBottomBracketCharForSpaceKeyDisplay ((unichar) 0x23B5) #define kDeleteKeyCharForDisplay ((unichar) 0x232B) // Modifier key chars for display #define kCommandKeyCharForDisplay ((unichar) 0x2318) #define kAlternateKeyCharForDisplay ((unichar) 0x2325) #define kControlKeyCharForDisplay ((unichar) 0x2303) #define kShiftKeyCharForDisplay ((unichar) 0x21E7) // Arrow key chars for display #define kLeftArrowKeyCharForDisplay ((unichar) 0x2190) #define kUpArrowKeyCharForDisplay ((unichar) 0x2191) #define kRightArrowKeyCharForDisplay ((unichar) 0x2192) #define kDownArrowKeyCharForDisplay ((unichar) 0x2193) PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerBlendingModeButton.h0000644000076500000240000000230713234403416023310 0ustar joshstaff/* PPLayerBlendingModeButton.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPDocumentTypes.h" @interface PPLayerBlendingModeButton : NSButton { PPLayerBlendingMode _layerBlendingMode; } - (void) setLayerBlendingMode: (PPLayerBlendingMode) layerBlendingMode; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerBlendingModeButton.m0000644000076500000240000001006513234403206023312 0ustar joshstaff/* PPLayerBlendingModeButton.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayerBlendingModeButton.h" #define kButtonIconName_Standard @"blend_mode_icon_standard" #define kButtonIconName_Linear @"blend_mode_icon_linear" #define kModeName_Standard @"STANDARD" #define kModeName_Linear @"LINEAR" #define kToolTipFormatString \ @"Layer Blending: %@\n\n" \ "Layer Blending determines how colors are calculated when compositing " \ "partially-transparent layers with visible lower layers:\n\n" \ "• STANDARD blending mixes colors in standard RGB colorspace (sRGB); Most " \ "software blends colors this way, however, the results can be visually " \ "incorrect (too dark & saturated) due to sRGB's non-linear gamma.\n\n" \ "• LINEAR blending produces visually-correct mixed colors; Color values are " \ "converted to linear-encoding before mixing." static NSImage *gIconImage_StandardMode = nil, *gIconImage_LinearMode = nil; static NSString *gToolTip_StandardMode = nil, *gToolTip_LinearMode = nil; @interface PPLayerBlendingModeButton (PrivateMethods) - (void) updateButtonAttributesForCurrentMode; @end @implementation PPLayerBlendingModeButton + (void) initialize { if ([self class] != [PPLayerBlendingModeButton class]) { return; } gIconImage_StandardMode = [[NSImage imageNamed: kButtonIconName_Standard] retain]; gIconImage_LinearMode = [[NSImage imageNamed: kButtonIconName_Linear] retain]; gToolTip_StandardMode = [[NSString stringWithFormat: kToolTipFormatString, kModeName_Standard] retain]; gToolTip_LinearMode = [[NSString stringWithFormat: kToolTipFormatString, kModeName_Linear] retain]; } - (void) setLayerBlendingMode: (PPLayerBlendingMode) layerBlendingMode { if (!PPLayerBlendingMode_IsValid(layerBlendingMode)) { goto ERROR; } if (_layerBlendingMode == layerBlendingMode) { return; } _layerBlendingMode = layerBlendingMode; [self updateButtonAttributesForCurrentMode]; return; ERROR: return; } #pragma mark NSButton overrides - (void) awakeFromNib { // check before calling [super awakeFromNib] - before 10.6, some classes didn't implement it if ([[PPLayerBlendingModeButton superclass] instancesRespondToSelector: @selector(awakeFromNib)]) { [super awakeFromNib]; } [self updateButtonAttributesForCurrentMode]; } #pragma mark Private methods - (void) updateButtonAttributesForCurrentMode { NSImage *iconImage; NSString *toolTip; if (_layerBlendingMode == kPPLayerBlendingMode_Linear) { iconImage = gIconImage_LinearMode; toolTip = gToolTip_LinearMode; } else { iconImage = gIconImage_StandardMode; toolTip = gToolTip_StandardMode; } [self setImage: iconImage]; [self setToolTip: toolTip]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerControlButtonImagesManager.h0000644000076500000240000000541513732534312025030 0ustar joshstaff/* PPLayerControlButtonImagesManager.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPDocumentTypes.h" #import "PPLayerDisplayMode.h" @class PPDocument, PPCompositeThumbnail; @interface PPLayerControlButtonImagesManager : NSObject { IBOutlet NSView *_displayModeDrawLayerView; IBOutlet NSView *_displayModeDrawLayerThumbnailView; IBOutlet NSView *_displayModeEnabledLayersView; IBOutlet NSView *_displayModeEnabledLayersThumbnailView; IBOutlet NSView *_operationTargetDrawLayerView; IBOutlet NSView *_operationTargetDrawLayerThumbnailView; IBOutlet NSView *_operationTargetEnabledLayersView; IBOutlet NSView *_operationTargetEnabledLayersThumbnailView; PPDocument *_ppDocument; NSSize _thumbnailFramesize; NSRect _thumbnailDrawSourceBounds; NSRect _thumbnailDrawDestinationBounds; NSImageInterpolation _thumbnailInterpolation; NSBitmapImageRep *_thumbnailBackgroundBitmap; NSBitmapImageRep *_drawLayerThumbnailBitmap; NSBitmapImageRep *_enabledLayersThumbnailBitmap; PPCompositeThumbnail *_displayModeDrawLayerCompositeThumbnail; PPCompositeThumbnail *_displayModeEnabledLayersCompositeThumbnail; PPCompositeThumbnail *_operationTargetDrawLayerCompositeThumbnail; PPCompositeThumbnail *_operationTargetEnabledLayersCompositeThumbnail; bool _thumbnailBackgroundBitmapIsDirty; bool _enabledLayersThumbnailsAreDirty; bool _drawLayerThumbnailsAreDirty; } + sharedManager; - (void) setPPDocument: (PPDocument *) ppDocument; - (NSImage *) buttonImageForDisplayMode: (PPLayerDisplayMode) displayMode; - (NSImage *) buttonImageForOperationTarget: (PPLayerOperationTarget) operationTarget; @end extern NSString *PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages; extern NSString *PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages; PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerControlButtonImagesManager.m0000644000076500000240000003434113732534210025032 0ustar joshstaff/* PPLayerControlButtonImagesManager.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayerControlButtonImagesManager.h" #import "PPLayerControlButtonImagesManager_Notifications.h" #import "PPDocument.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPCompositeThumbnail.h" #import "PPGeometry.h" #import "PPBackgroundPattern.h" #import "PPThumbnailUtilities.h" #define kLayerControlButtonImageViewsNibName @"LayerControlButtonImageViews" @interface PPLayerControlButtonImagesManager (PrivateMethods) - (void) addAsObserverForPPDocumentNotifications; - (void) removeAsObserverForPPDocumentNotifications; - (void) handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification; - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification; - (void) setupThumbnailDrawMembers; - (void) invalidateThumbnailsAndPostChangeNotifications; - (void) setupThumbnailBackgroundBitmap; - (void) updateEnabledLayersCompositeThumbnails; - (void) updateDrawLayerCompositeThumbnails; - (void) updateThumbnailBitmap: (NSBitmapImageRep *) thumbnailBitmap withSourceImage: (NSImage *) sourceImage; @end @implementation PPLayerControlButtonImagesManager + sharedManager { static PPLayerControlButtonImagesManager *sharedManager; if (!sharedManager) { sharedManager = [[self alloc] init]; } return sharedManager; } - init { self = [super init]; if (!self) goto ERROR; if (![NSBundle loadNibNamed: kLayerControlButtonImageViewsNibName owner: self]) { goto ERROR; } _thumbnailFramesize = [_displayModeDrawLayerThumbnailView frame].size; _thumbnailBackgroundBitmap = [[NSBitmapImageRep ppImageBitmapOfSize: _thumbnailFramesize] retain]; _drawLayerThumbnailBitmap = [[NSBitmapImageRep ppImageBitmapOfSize: _thumbnailFramesize] retain]; _enabledLayersThumbnailBitmap = [[NSBitmapImageRep ppImageBitmapOfSize: _thumbnailFramesize] retain]; if (!_thumbnailBackgroundBitmap || !_drawLayerThumbnailBitmap || !_enabledLayersThumbnailBitmap) { goto ERROR; } _displayModeDrawLayerCompositeThumbnail = [[PPCompositeThumbnail compositeThumbnailFromView: _displayModeDrawLayerView thumbnailOrigin: [_displayModeDrawLayerThumbnailView frame].origin] retain]; _displayModeEnabledLayersCompositeThumbnail = [[PPCompositeThumbnail compositeThumbnailFromView: _displayModeEnabledLayersView thumbnailOrigin: [_displayModeEnabledLayersThumbnailView frame].origin] retain]; _operationTargetDrawLayerCompositeThumbnail = [[PPCompositeThumbnail compositeThumbnailFromView: _operationTargetDrawLayerView thumbnailOrigin: [_operationTargetDrawLayerThumbnailView frame].origin] retain]; _operationTargetEnabledLayersCompositeThumbnail = [[PPCompositeThumbnail compositeThumbnailFromView: _operationTargetEnabledLayersView thumbnailOrigin: [_operationTargetEnabledLayersThumbnailView frame].origin] retain]; if (!_displayModeDrawLayerCompositeThumbnail || !_displayModeEnabledLayersCompositeThumbnail || !_operationTargetDrawLayerCompositeThumbnail || !_operationTargetEnabledLayersCompositeThumbnail) { goto ERROR; } return self; ERROR: [self release]; return nil; } - (void) dealloc { [self setPPDocument: nil]; [_thumbnailBackgroundBitmap release]; [_drawLayerThumbnailBitmap release]; [_enabledLayersThumbnailBitmap release]; [_displayModeDrawLayerCompositeThumbnail release]; [_displayModeEnabledLayersCompositeThumbnail release]; [_operationTargetDrawLayerCompositeThumbnail release]; [_operationTargetEnabledLayersCompositeThumbnail release]; [super dealloc]; } - (void) setPPDocument: (PPDocument *) ppDocument { if (_ppDocument == ppDocument) { return; } if (_ppDocument) { [self removeAsObserverForPPDocumentNotifications]; } [_ppDocument release]; _ppDocument = [ppDocument retain]; if (_ppDocument) { [self setupThumbnailDrawMembers]; [self invalidateThumbnailsAndPostChangeNotifications]; [self addAsObserverForPPDocumentNotifications]; } } - (NSImage *) buttonImageForDisplayMode: (PPLayerDisplayMode) displayMode { if (_thumbnailBackgroundBitmapIsDirty) { [self setupThumbnailBackgroundBitmap]; } if (displayMode == kPPLayerDisplayMode_DrawingLayerOnly) { if (_drawLayerThumbnailsAreDirty) { [self updateDrawLayerCompositeThumbnails]; } return [_displayModeDrawLayerCompositeThumbnail compositeImage]; } else { if (_enabledLayersThumbnailsAreDirty) { [self updateEnabledLayersCompositeThumbnails]; } return [_displayModeEnabledLayersCompositeThumbnail compositeImage]; } } - (NSImage *) buttonImageForOperationTarget: (PPLayerOperationTarget) operationTarget { if (_thumbnailBackgroundBitmapIsDirty) { [self setupThumbnailBackgroundBitmap]; } if (operationTarget == kPPLayerOperationTarget_DrawingLayerOnly) { if (_drawLayerThumbnailsAreDirty) { [self updateDrawLayerCompositeThumbnails]; } return [_operationTargetDrawLayerCompositeThumbnail compositeImage]; } else { if (_enabledLayersThumbnailsAreDirty) { [self updateEnabledLayersCompositeThumbnails]; } return [_operationTargetEnabledLayersCompositeThumbnail compositeImage]; } } #pragma mark PPDocument notifications - (void) addAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; if (!_ppDocument) return; [notificationCenter addObserver: self selector: @selector( handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage:) name: PPDocumentNotification_UpdatedMergedVisibleThumbnailImage object: _ppDocument]; [notificationCenter addObserver: self selector: @selector( handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage:) name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedBackgroundSettings:) name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ReloadedDocument:) name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedMergedVisibleThumbnailImage object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (void) handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage: (NSNotification *) notification { _enabledLayersThumbnailsAreDirty = YES; [self postNotification_ChangedEnabledLayersImages]; } - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification { _drawLayerThumbnailsAreDirty = YES; [self postNotification_ChangedDrawLayerImages]; } - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification { [self invalidateThumbnailsAndPostChangeNotifications]; } - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification { [self setupThumbnailDrawMembers]; [self invalidateThumbnailsAndPostChangeNotifications]; } #pragma mark Private methods - (void) setupThumbnailDrawMembers { _thumbnailDrawSourceBounds = PPGeometry_OriginRectOfSize([_ppDocument canvasSize]); _thumbnailDrawDestinationBounds = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(_thumbnailDrawSourceBounds.size, _thumbnailFramesize); _thumbnailInterpolation = PPThumbUtils_ImageInterpolationForSourceRectToDestinationRect( _thumbnailDrawSourceBounds, _thumbnailDrawDestinationBounds); } - (void) invalidateThumbnailsAndPostChangeNotifications { _thumbnailBackgroundBitmapIsDirty = YES; _enabledLayersThumbnailsAreDirty = YES; _drawLayerThumbnailsAreDirty = YES; [self postNotification_ChangedEnabledLayersImages]; [self postNotification_ChangedDrawLayerImages]; } - (void) setupThumbnailBackgroundBitmap { PPBackgroundPattern *documentBackgroundPattern, *thumbnailBackgroundPattern; float patternScalingFactor; NSColor *thumbnailBackgroundPatternColor; if (!_ppDocument || NSIsEmptyRect(_thumbnailDrawSourceBounds)) { goto ERROR; } documentBackgroundPattern = [_ppDocument backgroundPattern]; patternScalingFactor = kScalingFactorForThumbnailBackgroundPatternSize * _thumbnailDrawDestinationBounds.size.width / _thumbnailDrawSourceBounds.size.width; if (patternScalingFactor > 1.0f) { patternScalingFactor = 1.0f; } thumbnailBackgroundPattern = [documentBackgroundPattern backgroundPatternScaledByFactor: patternScalingFactor]; thumbnailBackgroundPatternColor = [thumbnailBackgroundPattern patternFillColor]; if (!thumbnailBackgroundPatternColor) goto ERROR; [_thumbnailBackgroundBitmap ppClearBitmap]; [_thumbnailBackgroundBitmap ppSetAsCurrentGraphicsContext]; [thumbnailBackgroundPatternColor set]; NSRectFill(_thumbnailDrawDestinationBounds); [_thumbnailBackgroundBitmap ppRestoreGraphicsContext]; _thumbnailBackgroundBitmapIsDirty = NO; return; ERROR: return; } - (void) updateEnabledLayersCompositeThumbnails { [self updateThumbnailBitmap: _enabledLayersThumbnailBitmap withSourceImage: [_ppDocument mergedVisibleLayersThumbnailImage]]; [_displayModeEnabledLayersCompositeThumbnail setThumbnailBitmap: _enabledLayersThumbnailBitmap]; [_operationTargetEnabledLayersCompositeThumbnail setThumbnailBitmap: _enabledLayersThumbnailBitmap]; _enabledLayersThumbnailsAreDirty = NO; } - (void) updateDrawLayerCompositeThumbnails { [self updateThumbnailBitmap: _drawLayerThumbnailBitmap withSourceImage: [_ppDocument drawingLayerThumbnailImage]]; [_displayModeDrawLayerCompositeThumbnail setThumbnailBitmap: _drawLayerThumbnailBitmap]; [_operationTargetDrawLayerCompositeThumbnail setThumbnailBitmap: _drawLayerThumbnailBitmap]; _drawLayerThumbnailsAreDirty = NO; } - (void) updateThumbnailBitmap: (NSBitmapImageRep *) thumbnailBitmap withSourceImage: (NSImage *) sourceImage { [thumbnailBitmap ppCopyFromBitmap: _thumbnailBackgroundBitmap toPoint: NSZeroPoint]; [thumbnailBitmap ppSetAsCurrentGraphicsContext]; [[NSGraphicsContext currentContext] setImageInterpolation: _thumbnailInterpolation]; [sourceImage drawInRect: _thumbnailDrawDestinationBounds fromRect: _thumbnailDrawSourceBounds operation: NSCompositeSourceOver fraction: 1.0]; [thumbnailBitmap ppRestoreGraphicsContext]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerControlButtonImagesManager_Notifications.h0000644000076500000240000000232413234403417027713 0ustar joshstaff/* PPLayerControlButtonImagesManager_Notifications.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayerControlButtonImagesManager.h" @interface PPLayerControlButtonImagesManager (Notifications) - (void) postNotification_ChangedDrawLayerImages; - (void) postNotification_ChangedEnabledLayersImages; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerControlButtonImagesManager_Notifications.m0000644000076500000240000000377513234403206027727 0ustar joshstaff/* PPLayerControlButtonImagesManager_Notifications.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayerControlButtonImagesManager_Notifications.h" NSString *PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages = @"PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages"; NSString *PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages = @"PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages"; @implementation PPLayerControlButtonImagesManager (Notifications) - (void) postNotification_ChangedDrawLayerImages { [[NSNotificationCenter defaultCenter] postNotificationName: PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages object: self]; } - (void) postNotification_ChangedEnabledLayersImages { [[NSNotificationCenter defaultCenter] postNotificationName: PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages object: self]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerControlsPopupPanelController.h0000644000076500000240000000515213732524507025451 0ustar joshstaff/* PPLayerControlsPopupPanelController.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanelController.h" #import "PPLayerDisplayMode.h" #import "PPDocumentTypes.h" @class PPThumbnailImageView, PPTitleablePopUpButton, PPDocumentWindowController; @interface PPLayerControlsPopupPanelController : PPPopupPanelController { IBOutlet NSButton *_canvasDisplayModeButton; IBOutlet NSButton *_layerOperationTargetButton; IBOutlet NSButton *_drawingLayerEnabledCheckbox; IBOutlet PPThumbnailImageView *_drawingLayerThumbnailView; IBOutlet PPTitleablePopUpButton *_drawingLayerTitleablePopUpButton; IBOutlet NSTextField *_drawingLayerOpacityTextField; IBOutlet NSSlider *_drawingLayerOpacitySlider; IBOutlet NSTextField *_backgroundFillTextField; PPDocumentWindowController *_ppDocumentWindowController; PPLayerDisplayMode _canvasDisplayMode; PPLayerOperationTarget _layerOperationTarget; NSBitmapImageRep *_popupMenuThumbnailBackgroundBitmap; NSRect _popupMenuThumbnailDrawSourceRect; NSRect _popupMenuThumbnailDrawDestinationRect; NSImageInterpolation _popupMenuThumbnailInterpolation; float _drawingLayerInitialOpacity; bool _needToUpdateLayerControlButtonImages; bool _needToUpdateDrawingLayerControls; bool _needToUpdateDrawingLayerPopupButtonMenu; bool _isTrackingOpacitySlider; bool _ignoreNotificationForChangedLayerAttribute; } - (IBAction) canvasDisplayModeButtonPressed: (id) sender; - (IBAction) layerOperationTargetButtonPressed: (id) sender; - (IBAction) drawingLayerEnabledCheckboxClicked: (id) sender; - (IBAction) drawingLayerPopupMenuItemSelected: (id) sender; - (IBAction) drawingLayerOpacitySliderMoved: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerControlsPopupPanelController.m0000644000076500000240000007133413732527554025470 0ustar joshstaff/* PPLayerControlsPopupPanelController.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayerControlsPopupPanelController.h" #import "PPDocument.h" #import "PPDocumentLayer.h" #import "PPDocumentWindowController.h" #import "PPThumbnailImageView.h" #import "NSObject_PPUtilities.h" #import "PPUIColors_Panels.h" #import "PPLayerControlButtonImagesManager.h" #import "PPTitleablePopUpButton.h" #import "PPGeometry.h" #import "PPBackgroundPattern.h" #import "PPTextAttributesDicts.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #import "PPThumbnailUtilities.h" #define kLayerControlsPopupPanelNibName @"LayerControlsPopupPanel" #define kPopupMenuThumbnailSize NSMakeSize(21.0f, 21.0f) #define kDrawingLayerOpacityFormatString @"%.1f%%" @interface PPLayerControlsPopupPanelController (PrivateMethods) - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedDrawingLayer: (NSNotification *) notification; - (void) handlePPDocumentNotification_ReorderedLayers: (NSNotification *) notification; - (void) handlePPDocumentNotification_ChangedLayerAttribute: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedLayerOperationTarget: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification; - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification; - (void) addAsObserverForPPDocumentWindowControllerNotifications; - (void) removeAsObserverForPPDocumentWindowControllerNotifications; - (void) handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode: (NSNotification *) notification; - (void) addAsObserverForPPLayerControlButtonImagesManagerNotifications; - (void) removeAsObserverForPPLayerControlButtonImagesManagerNotifications; - (void) handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages: (NSNotification *) notification; - (void) handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages: (NSNotification *) notification; - (void) handleOpacitySliderDidBeginTracking; - (void) handleOpacitySliderDidFinishTracking; - (void) setupWithPPDocumentWindowController: (PPDocumentWindowController *) ppDocumentWindowController; - (void) setupDrawingLayerThumbnailImage; - (void) setupDrawingLayerThumbnailImageBackground; - (void) setupPopupMenuThumbnailDrawMembers; - (void) setupPopupMenuThumbnailBackgroundBitmap; - (void) destroyPopupMenuThumbnailBackgroundBitmap; - (NSImage *) popupMenuThumbnailImageForLayerImage: (NSImage *) layerImage; - (void) updateCanvasDisplayMode; - (void) updateLayerOperationTarget; - (void) updateLayerControlButtonImages; - (void) updateCanvasDisplayModeButtonImage; - (void) updateLayerOperationTargetButtonImage; - (void) updateDrawingLayerControls; - (void) updateDrawingLayerControlsIfPanelIsVisible; - (void) updateDrawingLayerAttributeControls; - (void) updateDrawingLayerOpacityTextField; - (void) updateDrawingLayerPopUpButtonMenu; - (int) layerIndexForPopUpButtonMenuItemAtIndex: (int) itemIndex; - (int) popUpButtonMenuItemIndexForLayerAtIndex: (int) layerIndex; - (float) drawingLayerOpacitySliderQuantizedValue; @end @implementation PPLayerControlsPopupPanelController - (void) dealloc { [self removeAsObserverForPPLayerControlButtonImagesManagerNotifications]; [self setupWithPPDocumentWindowController: nil]; [self destroyPopupMenuThumbnailBackgroundBitmap]; [super dealloc]; } #pragma mark Actions - (IBAction) canvasDisplayModeButtonPressed: (id) sender { [_ppDocumentWindowController toggleCanvasDisplayMode: self]; } - (IBAction) layerOperationTargetButtonPressed: (id) sender { [_ppDocumentWindowController toggleLayerOperationTarget: self]; } - (IBAction) drawingLayerEnabledCheckboxClicked: (id) sender { [[_ppDocument drawingLayer] setEnabled: [_drawingLayerEnabledCheckbox intValue]]; } - (IBAction) drawingLayerPopupMenuItemSelected: (id) sender { int indexOfSelectedDrawingLayer = [self layerIndexForPopUpButtonMenuItemAtIndex: [_drawingLayerTitleablePopUpButton indexOfSelectedItem]]; [_ppDocument selectDrawingLayerAtIndex: indexOfSelectedDrawingLayer]; } - (IBAction) drawingLayerOpacitySliderMoved: (id) sender { if (!_isTrackingOpacitySlider) { [self handleOpacitySliderDidBeginTracking]; } _ignoreNotificationForChangedLayerAttribute = YES; [[_ppDocument drawingLayer] setOpacityWithoutRegisteringUndo: [self drawingLayerOpacitySliderQuantizedValue]]; _ignoreNotificationForChangedLayerAttribute = NO; [self updateDrawingLayerOpacityTextField]; } #pragma mark NSWindowController overrrides - (void) windowDidLoad { _needToUpdateLayerControlButtonImages = YES; _needToUpdateDrawingLayerControls = YES; _needToUpdateDrawingLayerPopupButtonMenu = YES; // [super windowDidLoad] calls [self setupPanelForCurrentPPDocument], so any preliminary // setup required before calling setupPanelForCurrentPPDocument should go before this call [super windowDidLoad]; [_backgroundFillTextField setBackgroundColor: [NSColor windowBackgroundColor]]; [_drawingLayerTitleablePopUpButton setDelegate: self]; [self addAsObserverForPPLayerControlButtonImagesManagerNotifications]; } #pragma mark PPPopupPanelController overrides + (NSString *) panelNibName { return kLayerControlsPopupPanelNibName; } - (void) setPPDocument: (PPDocument *) ppDocument { [super setPPDocument: ppDocument]; if (!_ppDocument) { [self setupWithPPDocumentWindowController: nil]; } } - (void) addAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; if (!_ppDocument) return; [notificationCenter addObserver: self selector: @selector( handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage:) name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedDrawingLayer:) name: PPDocumentNotification_SwitchedDrawingLayer object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ReorderedLayers:) name: PPDocumentNotification_ReorderedLayers object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ChangedLayerAttribute:) name: PPDocumentNotification_ChangedLayerAttribute object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedLayerOperationTarget:) name: PPDocumentNotification_SwitchedLayerOperationTarget object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedBackgroundSettings:) name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ReloadedDocument:) name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_SwitchedDrawingLayer object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ReorderedLayers object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ChangedLayerAttribute object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_SwitchedLayerOperationTarget object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (void) setupPanelForCurrentPPDocument { [super setupPanelForCurrentPPDocument]; [self setupWithPPDocumentWindowController: [_ppDocument ppDocumentWindowController]]; [self setupDrawingLayerThumbnailImage]; [self setupDrawingLayerThumbnailImageBackground]; [self setupPopupMenuThumbnailDrawMembers]; [self setupPopupMenuThumbnailBackgroundBitmap]; [self updateCanvasDisplayMode]; [self updateLayerOperationTarget]; [[PPLayerControlButtonImagesManager sharedManager] setPPDocument: _ppDocument]; [self updateDrawingLayerControlsIfPanelIsVisible]; _needToUpdateDrawingLayerPopupButtonMenu = YES; } - (void) setupPanelBeforeMakingVisible { [super setupPanelBeforeMakingVisible]; if (_needToUpdateLayerControlButtonImages) { [self updateLayerControlButtonImages]; } if (_needToUpdateDrawingLayerControls) { [self updateDrawingLayerControls]; } } - (NSColor *) backgroundColorForPopupPanel { return kUIColor_LayerControlsPopupPanel_Background; } - (void) handleDirectionCommand: (PPDirectionType) directionType { switch (directionType) { case kPPDirectionType_Left: { [_ppDocumentWindowController toggleCanvasDisplayMode: self]; } break; case kPPDirectionType_Right: { [_ppDocumentWindowController toggleLayerOperationTarget: self]; } break; case kPPDirectionType_Up: { [_ppDocumentWindowController makePreviousLayerActive: self]; } break; case kPPDirectionType_Down: { [_ppDocumentWindowController makeNextLayerActive: self]; } break; default: break; } } #pragma mark PPTitleablePopUpButton delegate methods - (NSDictionary *) titleTextAttributesForMenuItemAtIndex: (int) itemIndex onTitleablePopUpButton: (PPTitleablePopUpButton *) button { int layerIndex; bool layerIsEnabled; layerIndex = [self layerIndexForPopUpButtonMenuItemAtIndex: itemIndex]; layerIsEnabled = [[_ppDocument layerAtIndex: layerIndex] isEnabled]; return (layerIsEnabled) ? nil : PPTextAttributesDict_DisabledTitle_PopupButton(); } - (void) titleablePopUpButtonWillDisplayPopupMenu: (PPTitleablePopUpButton *) button { if (_needToUpdateDrawingLayerPopupButtonMenu) { [self updateDrawingLayerPopUpButtonMenu]; } } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification { [_drawingLayerThumbnailView handleUpdateToImage]; _needToUpdateDrawingLayerPopupButtonMenu = YES; } - (void) handlePPDocumentNotification_SwitchedDrawingLayer: (NSNotification *) notification { [self setupDrawingLayerThumbnailImage]; [self updateDrawingLayerControlsIfPanelIsVisible]; } - (void) handlePPDocumentNotification_ReorderedLayers: (NSNotification *) notification { [self setupDrawingLayerThumbnailImage]; [self updateDrawingLayerControlsIfPanelIsVisible]; _needToUpdateDrawingLayerPopupButtonMenu = YES; } - (void) handlePPDocumentNotification_ChangedLayerAttribute: (NSNotification *) notification { NSDictionary *userInfo; NSNumber *layerIndexNumber; int layerIndex = -1; if (_ignoreNotificationForChangedLayerAttribute) return; userInfo = [notification userInfo]; layerIndexNumber = [userInfo objectForKey: PPDocumentNotification_UserInfoKey_IndexOfChangedLayer]; if (layerIndexNumber) { layerIndex = [layerIndexNumber intValue]; } if (layerIndex == [_ppDocument indexOfDrawingLayer]) { if ([self panelIsVisible]) { [self updateDrawingLayerAttributeControls]; } else { _needToUpdateDrawingLayerControls = YES; } } _needToUpdateDrawingLayerPopupButtonMenu = YES; } - (void) handlePPDocumentNotification_SwitchedLayerOperationTarget: (NSNotification *) notification { [self updateLayerOperationTarget]; if ([self panelIsVisible]) { [self updateLayerOperationTargetButtonImage]; } else { _needToUpdateLayerControlButtonImages = YES; } } - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification { [self setupDrawingLayerThumbnailImageBackground]; [self setupPopupMenuThumbnailBackgroundBitmap]; _needToUpdateDrawingLayerPopupButtonMenu = YES; } - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification { [self setupPanelForCurrentPPDocument]; } #pragma mark PPDocumentWindowController notifications - (void) addAsObserverForPPDocumentWindowControllerNotifications { if (!_ppDocumentWindowController) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode:) name: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode object: _ppDocumentWindowController]; } - (void) removeAsObserverForPPDocumentWindowControllerNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode object: _ppDocumentWindowController]; } - (void) handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode: (NSNotification *) notification { [self updateCanvasDisplayMode]; if ([self panelIsVisible]) { [self updateCanvasDisplayModeButtonImage]; } else { _needToUpdateLayerControlButtonImages = YES; } } #pragma mark PPLayerControlButtonImagesManager notifications - (void) addAsObserverForPPLayerControlButtonImagesManagerNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver: self selector: @selector( handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages:) name: PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages object: nil]; [notificationCenter addObserver: self selector: @selector( handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages:) name: PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages object: nil]; } - (void) removeAsObserverForPPLayerControlButtonImagesManagerNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages object: nil]; [notificationCenter removeObserver: self name: PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages object: nil]; } - (void) handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages: (NSNotification *) notification { if (![self panelIsVisible]) { _needToUpdateLayerControlButtonImages = YES; return; } if (_canvasDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { [self updateCanvasDisplayModeButtonImage]; } if (_layerOperationTarget == kPPLayerOperationTarget_DrawingLayerOnly) { [self updateLayerOperationTargetButtonImage]; } } - (void) handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages: (NSNotification *) notification { if (![self panelIsVisible]) { _needToUpdateLayerControlButtonImages = YES; return; } if (_canvasDisplayMode != kPPLayerDisplayMode_DrawingLayerOnly) { [self updateCanvasDisplayModeButtonImage]; } if (_layerOperationTarget != kPPLayerOperationTarget_DrawingLayerOnly) { [self updateLayerOperationTargetButtonImage]; } } #pragma mark Opacity slider tracking - (void) handleOpacitySliderDidBeginTracking { if (_isTrackingOpacitySlider) return; _isTrackingOpacitySlider = YES; _drawingLayerInitialOpacity = [[_ppDocument drawingLayer] opacity]; [_ppDocument disableThumbnailImageUpdateNotifications: YES]; // won't return to the main run loop until the slider's done tracking, so post a message // in the next stack frame to serve as notification that tracking's finished [self ppPerformSelectorFromNewStackFrame: @selector(handleOpacitySliderDidFinishTracking)]; } - (void) handleOpacitySliderDidFinishTracking { float newOpacity = [self drawingLayerOpacitySliderQuantizedValue]; _isTrackingOpacitySlider = NO; [_ppDocument disableThumbnailImageUpdateNotifications: NO]; if (newOpacity != _drawingLayerInitialOpacity) { [[_ppDocument drawingLayer] setOpacity: newOpacity]; } } #pragma mark Private methods - (void) setupWithPPDocumentWindowController: (PPDocumentWindowController *) ppDocumentWindowController { if (_ppDocumentWindowController == ppDocumentWindowController) { return; } if (_ppDocumentWindowController) { [self removeAsObserverForPPDocumentWindowControllerNotifications]; } [_ppDocumentWindowController release]; _ppDocumentWindowController = [ppDocumentWindowController retain]; if (_ppDocumentWindowController) { [self addAsObserverForPPDocumentWindowControllerNotifications]; } } - (void) setupDrawingLayerThumbnailImage { [_drawingLayerThumbnailView setImage: [_ppDocument drawingLayerThumbnailImage]]; } - (void) setupDrawingLayerThumbnailImageBackground { [_drawingLayerThumbnailView setBackgroundPattern: [_ppDocument backgroundPattern]]; } - (void) setupPopupMenuThumbnailDrawMembers { _popupMenuThumbnailDrawSourceRect.size = [_ppDocument canvasSize]; _popupMenuThumbnailDrawDestinationRect = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize( _popupMenuThumbnailDrawSourceRect.size, kPopupMenuThumbnailSize); _popupMenuThumbnailInterpolation = PPThumbUtils_ImageInterpolationForSourceRectToDestinationRect( _popupMenuThumbnailDrawSourceRect, _popupMenuThumbnailDrawDestinationRect); } - (void) setupPopupMenuThumbnailBackgroundBitmap { PPBackgroundPattern *documentBackgroundPattern, *thumbnailBackgroundPattern; float patternScalingFactor; NSColor *thumbnailBackgroundPatternColor; NSBitmapImageRep *backgroundBitmap; [self destroyPopupMenuThumbnailBackgroundBitmap]; if (!_ppDocument || NSIsEmptyRect(_popupMenuThumbnailDrawSourceRect)) { goto ERROR; } documentBackgroundPattern = [_ppDocument backgroundPattern]; patternScalingFactor = kScalingFactorForThumbnailBackgroundPatternSize * _popupMenuThumbnailDrawDestinationRect.size.width / _popupMenuThumbnailDrawSourceRect.size.width; if (patternScalingFactor > 1.0f) { patternScalingFactor = 1.0f; } thumbnailBackgroundPattern = [documentBackgroundPattern backgroundPatternScaledByFactor: patternScalingFactor]; thumbnailBackgroundPatternColor = [thumbnailBackgroundPattern patternFillColor]; if (!thumbnailBackgroundPatternColor) goto ERROR; backgroundBitmap = [NSBitmapImageRep ppImageBitmapOfSize: kPopupMenuThumbnailSize]; if (!backgroundBitmap) goto ERROR; [backgroundBitmap ppSetAsCurrentGraphicsContext]; [thumbnailBackgroundPatternColor set]; NSRectFill(_popupMenuThumbnailDrawDestinationRect); [backgroundBitmap ppRestoreGraphicsContext]; _popupMenuThumbnailBackgroundBitmap = [backgroundBitmap retain]; return; ERROR: return; } - (NSImage *) popupMenuThumbnailImageForLayerImage: (NSImage *) layerImage { NSBitmapImageRep *thumbnailBitmap; if (!layerImage) goto ERROR; thumbnailBitmap = [[_popupMenuThumbnailBackgroundBitmap copy] autorelease]; if (!thumbnailBitmap) goto ERROR; [thumbnailBitmap ppSetAsCurrentGraphicsContext]; [[NSGraphicsContext currentContext] setImageInterpolation: _popupMenuThumbnailInterpolation]; [layerImage drawInRect: _popupMenuThumbnailDrawDestinationRect fromRect: _popupMenuThumbnailDrawSourceRect operation: NSCompositeSourceOver fraction: 1.0f]; [thumbnailBitmap ppRestoreGraphicsContext]; return [NSImage ppImageWithBitmap: thumbnailBitmap]; ERROR: return nil; } - (void) destroyPopupMenuThumbnailBackgroundBitmap { [_popupMenuThumbnailBackgroundBitmap release]; _popupMenuThumbnailBackgroundBitmap = nil; } - (void) updateCanvasDisplayMode { _canvasDisplayMode = [_ppDocumentWindowController canvasDisplayMode]; if (_canvasDisplayMode != kPPLayerDisplayMode_DrawingLayerOnly) { _canvasDisplayMode = kPPLayerDisplayMode_VisibleLayers; } } - (void) updateLayerOperationTarget { _layerOperationTarget = [_ppDocument layerOperationTarget]; if (_layerOperationTarget != kPPLayerOperationTarget_DrawingLayerOnly) { _layerOperationTarget = kPPLayerOperationTarget_VisibleLayers; } } - (void) updateLayerControlButtonImages { [self updateCanvasDisplayModeButtonImage]; [self updateLayerOperationTargetButtonImage]; _needToUpdateLayerControlButtonImages = NO; } - (void) updateCanvasDisplayModeButtonImage { NSImage *buttonImage = [[PPLayerControlButtonImagesManager sharedManager] buttonImageForDisplayMode: _canvasDisplayMode]; // button's current image may already be buttonImage, so force redraw by clearing the image // first [_canvasDisplayModeButton setImage: nil]; [_canvasDisplayModeButton setImage: buttonImage]; } - (void) updateLayerOperationTargetButtonImage { NSImage *buttonImage = [[PPLayerControlButtonImagesManager sharedManager] buttonImageForOperationTarget: _layerOperationTarget]; // button's current image may already be buttonImage, so force redraw by clearing the image // first [_layerOperationTargetButton setImage: nil]; [_layerOperationTargetButton setImage: buttonImage]; } - (void) updateDrawingLayerControls { [_drawingLayerThumbnailView handleUpdateToImage]; [self updateDrawingLayerAttributeControls]; _needToUpdateDrawingLayerControls = NO; } - (void) updateDrawingLayerControlsIfPanelIsVisible { if ([self panelIsVisible]) { [self updateDrawingLayerControls]; } else { _needToUpdateDrawingLayerControls = YES; } } - (void) updateDrawingLayerAttributeControls { PPDocumentLayer *drawingLayer; bool drawingLayerIsEnabled; NSDictionary *drawingLayerTitleAttributes; drawingLayer = [_ppDocument drawingLayer]; drawingLayerIsEnabled = [drawingLayer isEnabled]; [_drawingLayerEnabledCheckbox setIntValue: drawingLayerIsEnabled]; drawingLayerTitleAttributes = (drawingLayerIsEnabled) ? nil : PPTextAttributesDict_DisabledTitle_PopupButton(); [_drawingLayerTitleablePopUpButton setTitle: [drawingLayer name] withTextAttributes: drawingLayerTitleAttributes]; [self updateDrawingLayerOpacityTextField]; [_drawingLayerOpacitySlider setFloatValue: [drawingLayer opacity]]; } - (void) updateDrawingLayerOpacityTextField { float opacity = [[_ppDocument drawingLayer] opacity] * 100.0f; NSString *opacityString = [NSString stringWithFormat: kDrawingLayerOpacityFormatString, opacity]; [_drawingLayerOpacityTextField setStringValue: opacityString]; } - (void) updateDrawingLayerPopUpButtonMenu { NSMenu *layersMenu; int layerCounter; PPDocumentLayer *layer; NSString *layerName; // use PPSDKNativeType_NSMenuItemPtr for menuItem, as -[NSMenu addItemWithTitle:...] // could return either (NSMenuItem *) or (id ), depending on the SDK PPSDKNativeType_NSMenuItemPtr menuItem; layersMenu = [[[NSMenu alloc] init] autorelease]; layerCounter = [_ppDocument numLayers]; while (layerCounter--) { layer = [_ppDocument layerAtIndex: layerCounter]; layerName = [layer name]; if (!layerName) { layerName = @""; } menuItem = [layersMenu addItemWithTitle: layerName action: NULL keyEquivalent: @""]; [menuItem setImage: [self popupMenuThumbnailImageForLayerImage: [layer image]]]; if (![layer isEnabled]) { NSAttributedString *attributedTitle; attributedTitle = [[[NSAttributedString alloc] initWithString: layerName attributes: PPTextAttributesDict_DisabledTitle_PopupMenuItem()] autorelease]; [menuItem setAttributedTitle: attributedTitle]; } } [_drawingLayerTitleablePopUpButton setMenu: layersMenu]; [_drawingLayerTitleablePopUpButton selectItemAtIndex: [self popUpButtonMenuItemIndexForLayerAtIndex: [_ppDocument indexOfDrawingLayer]]]; _needToUpdateDrawingLayerPopupButtonMenu = NO; } - (int) layerIndexForPopUpButtonMenuItemAtIndex: (int) itemIndex { return [_ppDocument numLayers] - itemIndex - 1; } - (int) popUpButtonMenuItemIndexForLayerAtIndex: (int) layerIndex { return [_ppDocument numLayers] - layerIndex - 1; } - (float) drawingLayerOpacitySliderQuantizedValue { // roundoff slider value to nearest .5% (1/200) return roundf(200.0f * [_drawingLayerOpacitySlider floatValue]) / 200.0f; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerDisplayMode.h0000644000076500000240000000251313234403417021777 0ustar joshstaff/* PPLayerDisplayMode.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPLayerDisplayMode_VisibleLayers, kPPLayerDisplayMode_DrawingLayerOnly, // add new PPLayerDisplayMode values above this line kNumPPLayerDisplayModes } PPLayerDisplayMode; static inline bool PPLayerDisplayMode_IsValid(PPLayerDisplayMode displayMode) { return (((unsigned) displayMode) < kNumPPLayerDisplayModes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerEnabledButtonCell.h0000644000076500000240000000207013234403417023111 0ustar joshstaff/* PPLayerEnabledButtonCell.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPLayerEnabledButtonCell : NSButtonCell { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerEnabledButtonCell.m0000644000076500000240000000247513234403206023123 0ustar joshstaff/* PPLayerEnabledButtonCell.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayerEnabledButtonCell.h" #import "PPLayersTableView.h" @implementation PPLayerEnabledButtonCell - (BOOL) startTrackingAt: (NSPoint) startPoint inView: (NSView *) controlView { [((PPLayersTableView *) [self target]) restoreSelectionFromLastMouseDown]; return [super startTrackingAt: startPoint inView: controlView]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerOpacitySliderCell.h0000644000076500000240000000207013234403417023136 0ustar joshstaff/* PPLayerOpacitySliderCell.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPLayerOpacitySliderCell : NSSliderCell { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayerOpacitySliderCell.m0000644000076500000240000000343213234403207023143 0ustar joshstaff/* PPLayerOpacitySliderCell.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayerOpacitySliderCell.h" #import "PPLayersPanelController.h" @implementation PPLayerOpacitySliderCell - (BOOL) isContinuous { return YES; } - (BOOL) startTrackingAt: (NSPoint) startPoint inView: (NSView *) controlView { bool startedTracking = [super startTrackingAt: startPoint inView: controlView]; if (startedTracking) { [((PPLayersPanelController *) [self target]) setTrackingOpacitySliderCell: self]; } return startedTracking; } - (void) stopTracking: (NSPoint) lastPoint at: (NSPoint) stopPoint inView: (NSView *) controlView mouseIsUp: (BOOL) flag { [super stopTracking: lastPoint at: stopPoint inView: controlView mouseIsUp: flag]; [((PPLayersPanelController *) [self target]) setTrackingOpacitySliderCell: nil]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayersPanelController.h0000644000076500000240000000536013732522664023067 0ustar joshstaff/* PPLayersPanelController.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPanelController.h" #import "PPDefines.h" #import "PPLayerDisplayMode.h" #import "PPDocumentTypes.h" @class PPLayersTableView, PPLayerBlendingModeButton, PPDocumentWindowController, PPLayerOpacitySliderCell; @interface PPLayersPanelController : PPPanelController { IBOutlet NSButton *_canvasDisplayModeButton; IBOutlet NSButton *_layerOperationTargetButton; IBOutlet PPLayersTableView *_layersTable; IBOutlet PPLayerBlendingModeButton *_layerBlendingModeButton; PPDocumentWindowController *_ppDocumentWindowController; PPLayerOpacitySliderCell *_trackingOpacitySliderCell; NSTrackingRectTag _panelContentViewTrackingRectTag; NSImage *_cachedLayerThumbnailImages[kMaxLayersPerDocument]; NSBitmapImageRep *_layerThumbnailBackgroundBitmap; NSSize _layerThumbnailMaxSize; NSRect _layerThumbnailSourceRect; NSRect _layerThumbnailDestinationRect; NSImageInterpolation _layerThumbnailInterpolation; int _numCachedLayerThumbnails; NSMutableDictionary *_cachedDisabledLayerNameAttrStringsDict; PPLayerDisplayMode _canvasDisplayMode; PPLayerOperationTarget _layerOperationTarget; bool _ignoreNotificationForChangedLayerAttribute; bool _mouseIsInsideTrackingRect; bool _needToUpdateLayerControlButtonImages; } - (IBAction) canvasDisplayModeButtonPressed: (id) sender; - (IBAction) layerOperationTargetButtonPressed: (id) sender; - (IBAction) layersTableOpacitySliderMoved: (id) sender; - (IBAction) addLayerButtonPressed: (id) sender; - (IBAction) deleteLayerButtonPressed: (id) sender; - (IBAction) duplicateLayerButtonPressed: (id) sender; - (IBAction) layerBlendingModeButtonPressed: (id) sender; - (void) setTrackingOpacitySliderCell: (PPLayerOpacitySliderCell *) trackingOpacitySliderCell; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayersPanelController.m0000644000076500000240000012532613732543116023074 0ustar joshstaff/* PPLayersPanelController.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayersPanelController.h" #import "PPDocument.h" #import "PPDocumentWindowController.h" #import "PPDocumentLayer.h" #import "PPLayersTableView.h" #import "PPLayerBlendingModeButton.h" #import "PPLayerOpacitySliderCell.h" #import "PPGeometry.h" #import "PPBackgroundPattern.h" #import "PPLayerControlButtonImagesManager.h" #import "PPTextAttributesDicts.h" #import "PPPanelDefaultFramePinnings.h" #import "NSObject_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSImage_PPUtilities.h" #import "PPThumbnailUtilities.h" #define kLayersPanelNibName @"LayersPanel" #define kLayersTableColumnIdentifier_Enabled @"Enabled" #define kLayersTableColumnIdentifier_Thumbnail @"Thumbnail" #define kLayersTableColumnIdentifier_Name @"Name" #define kLayersTableColumnIdentifier_Opacity @"Opacity" #define kLayersTableDraggedDataType @"PPLayersTableDraggedDataType" #define kLayersTableColumnIndex_Thumbnail 1 @interface PPLayersPanelController (PrivateMethods) - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedDrawingLayer: (NSNotification *) notification; - (void) handlePPDocumentNotification_ReorderedLayers: (NSNotification *) notification; - (void) handlePPDocumentNotification_PerformedMultilayerOperation: (NSNotification *) notification; - (void) handlePPDocumentNotification_ChangedLayerAttribute: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedLayerOperationTarget: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedLayerBlendingMode: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification; - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification; - (void) addAsObserverForPPDocumentWindowControllerNotifications; - (void) removeAsObserverForPPDocumentWindowControllerNotifications; - (void) handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode: (NSNotification *) notification; - (void) addAsObserverForPPLayerControlButtonImagesManagerNotifications; - (void) removeAsObserverForPPLayerControlButtonImagesManagerNotifications; - (void) handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages: (NSNotification *) notification; - (void) handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages: (NSNotification *) notification; - (void) addAsObserverForPPLayersTableViewNotifications; - (void) removeAsObserverForPPLayersTableViewNotifications; - (void) handlePPLayersTableViewNotification_TextDidEndEditing: (NSNotification *) notification; - (void) setupLayerThumbnailsCacheForCurrentPPDocument; - (void) destroyLayerThumbnailsCache; - (void) destroyAllCachedLayerThumbnailsAndResizeCacheForCurrentPPDocument; - (void) setupLayerThumbnailDrawMembersForCurrentPPDocument; - (NSImage *) cachedThumbnailForLayerAtIndex: (unsigned) index; - (void) destroyCachedThumbnailForLayerAtIndex: (unsigned) index; - (void) destroyAllCachedLayerThumbnails; - (void) setupLayerThumbnailBackgroundBitmapForCurrentPPDocument; - (void) destroyLayerThumbnailBackgroundBitmap; - (id) cachedDisabledLayerNameAttrStringForLayerName: (NSString *) layerName; - (void) destroyAllCachedDisabledLayerNameAttrStrings; - (void) setupTrackingRectForPanelContentView: (NSView *) panelContentView; - (void) mouseEntered: (NSEvent *) theEvent; - (void) mouseExited: (NSEvent *) theEvent; - (void) handleResizedPanel; - (void) resizeLayerControlButtonsForPanelContentWidth: (float) contentWidth; - (void) setupWithPPDocumentWindowController: (PPDocumentWindowController *) ppDocumentWindowController; - (void) updateCanvasDisplayMode; - (void) updateLayerOperationTarget; - (void) updateCanvasDisplayModeButtonImage; - (void) updateLayerOperationTargetButtonImage; - (void) updateLayerControlButtonImages; - (void) updateLayerBlendingModeButtonWithCurrentMode; - (void) reloadLayersTableDataAndUpdateSelection; - (void) reloadLayersTableDataForLayerAtIndex: (unsigned) layerIndex; - (void) reloadLayersTableThumbnailDataForLayerAtIndex: (unsigned) layerIndex; - (void) updateLayersTableSelection; - (unsigned) tableRowIndexForLayerIndex: (unsigned) layerIndex; - (unsigned) layerIndexForTableRowIndex: (unsigned) rowIndex; - (bool) isEditingLayerNameText; - (void) endEditingForLayerNameText; - (void) resignKeyWindowUnlessEditingLayerNameText; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPLayersPanelController (RequiredProtocols) @end #endif // PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @implementation PPLayersPanelController - (void) dealloc { [self removeAsObserverForPPLayerControlButtonImagesManagerNotifications]; [self removeAsObserverForPPLayersTableViewNotifications]; [self setupWithPPDocumentWindowController: nil]; [self destroyLayerThumbnailsCache]; [_cachedDisabledLayerNameAttrStringsDict release]; [super dealloc]; } - (void) setTrackingOpacitySliderCell: (PPLayerOpacitySliderCell *) trackingOpacitySliderCell { bool shouldDisableThumbnailImageUpdateNotifications; [_layersTable restoreSelectionFromLastMouseDown]; if (_trackingOpacitySliderCell == trackingOpacitySliderCell) { return; } _trackingOpacitySliderCell = trackingOpacitySliderCell; shouldDisableThumbnailImageUpdateNotifications = (trackingOpacitySliderCell) ? YES : NO; // improve drawing performance by disabling thumbnail updates until finished tracking [_ppDocument disableThumbnailImageUpdateNotifications: shouldDisableThumbnailImageUpdateNotifications]; if (!shouldDisableThumbnailImageUpdateNotifications) { [_ppDocument sendThumbnailImageUpdateNotifications]; } } #pragma mark Actions - (IBAction) canvasDisplayModeButtonPressed: (id) sender { [_ppDocumentWindowController toggleCanvasDisplayMode]; } - (IBAction) layerOperationTargetButtonPressed: (id) sender { [_ppDocumentWindowController toggleLayerOperationTarget: self]; } - (IBAction) layersTableOpacitySliderMoved: (id) sender { int clickedRow; PPDocumentLayer *layer; if (sender != _layersTable) { return; } clickedRow = [_layersTable clickedRow]; if ((clickedRow == -1) || !_trackingOpacitySliderCell) { return; } layer = [_ppDocument layerAtIndex: [self layerIndexForTableRowIndex: clickedRow]]; _ignoreNotificationForChangedLayerAttribute = YES; [layer setOpacityWithoutRegisteringUndo: [_trackingOpacitySliderCell floatValue]]; _ignoreNotificationForChangedLayerAttribute = NO; } - (IBAction) addLayerButtonPressed: (id) sender { // end editing of layer name if necessary, otherwise the button's undoable action will // register before the layer name change registers (wrong order) [self endEditingForLayerNameText]; [_ppDocument createNewLayer]; } - (IBAction) deleteLayerButtonPressed: (id) sender { // end editing of layer name if necessary, otherwise the button's undoable action will // register before the layer name change registers (wrong order) [self endEditingForLayerNameText]; [_ppDocument removeLayerAtIndex: [_ppDocument indexOfDrawingLayer]]; } - (IBAction) duplicateLayerButtonPressed: (id) sender { // end editing of layer name if necessary, otherwise the button's undoable action will // register before the layer name change registers (wrong order) [self endEditingForLayerNameText]; [_ppDocument duplicateLayerAtIndex: [_ppDocument indexOfDrawingLayer]]; } - (IBAction) layerBlendingModeButtonPressed: (id) sender { [_ppDocument toggleLayerBlendingMode]; } #pragma mark NSWindowController overrides - (void) windowDidLoad { [_layersTable setDataSource: self]; [_layersTable setDelegate: self]; [_layersTable registerForDraggedTypes: [NSArray arrayWithObject: kLayersTableDraggedDataType]]; _layerThumbnailMaxSize = NSMakeSize( [[_layersTable tableColumnWithIdentifier: kLayersTableColumnIdentifier_Thumbnail] width], [_layersTable rowHeight] - 1.0f); _layerThumbnailDestinationRect.origin.y = 1.0f; _cachedDisabledLayerNameAttrStringsDict = [[NSMutableDictionary dictionary] retain]; // [super windowDidLoad] may show & resize the panel, so call as late as possible [super windowDidLoad]; [self handleResizedPanel]; [self addAsObserverForPPLayerControlButtonImagesManagerNotifications]; [self addAsObserverForPPLayersTableViewNotifications]; } - (NSUndoManager *) undoManager { return [_ppDocument undoManager]; } #pragma mark PPPanelController overrides + controller { PPLayersPanelController *layersPanelController = [super controller]; // on rare occasions, seeing a hard-to-repro crash - the stack trace suggests that it // may be due to the unloaded layers panel, so forcing the window to load (for now) [layersPanelController window]; return layersPanelController; } + (NSString *) panelNibName { return kLayersPanelNibName; } - (void) setPPDocument: (PPDocument *) ppDocument { [super setPPDocument: ppDocument]; if (!_ppDocument) { [self setupWithPPDocumentWindowController: nil]; } } - (void) addAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; if (!_ppDocument) return; [notificationCenter addObserver: self selector: @selector( handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage:) name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedDrawingLayer:) name: PPDocumentNotification_SwitchedDrawingLayer object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ReorderedLayers:) name: PPDocumentNotification_ReorderedLayers object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_PerformedMultilayerOperation:) name: PPDocumentNotification_PerformedMultilayerOperation object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ChangedLayerAttribute:) name: PPDocumentNotification_ChangedLayerAttribute object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedLayerOperationTarget:) name: PPDocumentNotification_SwitchedLayerOperationTarget object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedLayerBlendingMode:) name: PPDocumentNotification_SwitchedLayerBlendingMode object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedBackgroundSettings:) name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ReloadedDocument:) name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_SwitchedDrawingLayer object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ReorderedLayers object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_PerformedMultilayerOperation object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ChangedLayerAttribute object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_SwitchedLayerOperationTarget object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_SwitchedLayerBlendingMode object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (bool) allowPanelToBecomeKey { return YES; } - (bool) defaultPanelEnabledState { return YES; } - (PPFramePinningType) pinningTypeForDefaultWindowFrame { return kPPPanelDefaultFramePinning_Layers; } - (void) setupPanelForCurrentPPDocument { [self setupWithPPDocumentWindowController: [_ppDocument ppDocumentWindowController]]; [self updateCanvasDisplayMode]; [self updateLayerOperationTarget]; [self setupLayerThumbnailsCacheForCurrentPPDocument]; [self destroyAllCachedDisabledLayerNameAttrStrings]; [self reloadLayersTableDataAndUpdateSelection]; [self updateLayerBlendingModeButtonWithCurrentMode]; // [super setupPanelForCurrentPPDocument] may show the panel, so call as late as possible [super setupPanelForCurrentPPDocument]; if (_needToUpdateLayerControlButtonImages && [self panelIsVisible]) { [self updateLayerControlButtonImages]; } } - (void) setupPanelBeforeMakingVisible { [super setupPanelBeforeMakingVisible]; if (_needToUpdateLayerControlButtonImages) { [self updateLayerControlButtonImages]; } } #pragma mark NSWindow delegate methods - (void) windowDidResize: (NSNotification *) notification { [self handleResizedPanel]; } - (void) windowDidBecomeKey: (NSNotification *) notification { [self ppPerformSelectorFromNewStackFrame: @selector(resignKeyWindowUnlessEditingLayerNameText)]; } - (NSUndoManager *) windowWillReturnUndoManager: (NSWindow *) window { return [self undoManager]; } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification { unsigned layerIndex = [_ppDocument indexOfDrawingLayer]; [self destroyCachedThumbnailForLayerAtIndex: layerIndex]; [self reloadLayersTableThumbnailDataForLayerAtIndex: layerIndex]; } - (void) handlePPDocumentNotification_SwitchedDrawingLayer: (NSNotification *) notification { [self updateLayersTableSelection]; } - (void) handlePPDocumentNotification_ReorderedLayers: (NSNotification *) notification { [self destroyAllCachedLayerThumbnailsAndResizeCacheForCurrentPPDocument]; [self reloadLayersTableDataAndUpdateSelection]; } - (void) handlePPDocumentNotification_PerformedMultilayerOperation: (NSNotification *) notification { [self destroyAllCachedLayerThumbnailsAndResizeCacheForCurrentPPDocument]; [self reloadLayersTableDataAndUpdateSelection]; } - (void) handlePPDocumentNotification_ChangedLayerAttribute: (NSNotification *) notification { NSDictionary *userInfo; NSNumber *layerIndexNumber; int layerIndex = -1; if (_ignoreNotificationForChangedLayerAttribute) return; userInfo = [notification userInfo]; layerIndexNumber = [userInfo objectForKey: PPDocumentNotification_UserInfoKey_IndexOfChangedLayer]; if (layerIndexNumber) { layerIndex = [layerIndexNumber intValue]; } if (layerIndex >= 0) { [self reloadLayersTableDataForLayerAtIndex: layerIndex]; } else { [_layersTable reloadData]; } } - (void) handlePPDocumentNotification_SwitchedLayerOperationTarget: (NSNotification *) notification { [self updateLayerOperationTarget]; [self updateLayerOperationTargetButtonImage]; } - (void) handlePPDocumentNotification_SwitchedLayerBlendingMode: (NSNotification *) notification { [self updateLayerBlendingModeButtonWithCurrentMode]; } - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification { [self setupLayerThumbnailBackgroundBitmapForCurrentPPDocument]; [self destroyAllCachedLayerThumbnails]; [_layersTable reloadData]; } - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification { [self setupPanelForCurrentPPDocument]; } #pragma mark PPDocumentWindowController notifications - (void) addAsObserverForPPDocumentWindowControllerNotifications { if (!_ppDocumentWindowController) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode:) name: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode object: _ppDocumentWindowController]; } - (void) removeAsObserverForPPDocumentWindowControllerNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode object: _ppDocumentWindowController]; } - (void) handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode: (NSNotification *) notification { [self updateCanvasDisplayMode]; [self updateCanvasDisplayModeButtonImage]; } #pragma mark PPLayerControlButtonImagesManager notifications - (void) addAsObserverForPPLayerControlButtonImagesManagerNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver: self selector: @selector( handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages:) name: PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages object: nil]; [notificationCenter addObserver: self selector: @selector( handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages:) name: PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages object: nil]; } - (void) removeAsObserverForPPLayerControlButtonImagesManagerNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages object: nil]; [notificationCenter removeObserver: self name: PPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages object: nil]; } - (void) handlePPLayerControlButtonImagesManagerNotification_ChangedDrawLayerImages: (NSNotification *) notification { if (!_ppDocument || ![self panelIsVisible]) { _needToUpdateLayerControlButtonImages = YES; return; } if (_canvasDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { [self updateCanvasDisplayModeButtonImage]; } if (_layerOperationTarget == kPPLayerOperationTarget_DrawingLayerOnly) { [self updateLayerOperationTargetButtonImage]; } } - (void) handlePPLayerControlButtonImagesManagerNotification_ChangedEnabledLayersImages: (NSNotification *) notification { if (!_ppDocument || ![self panelIsVisible]) { _needToUpdateLayerControlButtonImages = YES; return; } if (_canvasDisplayMode != kPPLayerDisplayMode_DrawingLayerOnly) { [self updateCanvasDisplayModeButtonImage]; } if (_layerOperationTarget != kPPLayerOperationTarget_DrawingLayerOnly) { [self updateLayerOperationTargetButtonImage]; } } #pragma mark PPLayersTableView data source - (NSInteger) numberOfRowsInTableView: (NSTableView *) aTableView { return [_ppDocument numLayers]; } - (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row { NSString *identifier; unsigned layerIndex; PPDocumentLayer *layer; if (tableView != _layersTable) { return nil; } identifier = [tableColumn identifier]; layerIndex = [self layerIndexForTableRowIndex: row]; if ([identifier isEqualToString: kLayersTableColumnIdentifier_Thumbnail]) { return [self cachedThumbnailForLayerAtIndex: layerIndex]; } layer = [_ppDocument layerAtIndex: layerIndex]; if (!layer) { return nil; } if ([identifier isEqualToString: kLayersTableColumnIdentifier_Enabled]) { return [NSNumber numberWithBool: [layer isEnabled]]; } else if ([identifier isEqualToString: kLayersTableColumnIdentifier_Name]) { NSString *layerName = [layer name]; if ([layer isEnabled]) { return layerName; } else { return [self cachedDisabledLayerNameAttrStringForLayerName: layerName]; } } else if ([identifier isEqualToString: kLayersTableColumnIdentifier_Opacity]) { return [NSNumber numberWithFloat: [layer opacity]]; } else { return nil; } } - (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row { PPDocumentLayer *layer; NSString *identifier; if (tableView != _layersTable) { return; } layer = [_ppDocument layerAtIndex: [self layerIndexForTableRowIndex: row]]; if (!layer) return; identifier = [tableColumn identifier]; _ignoreNotificationForChangedLayerAttribute = YES; if ([identifier isEqualToString: kLayersTableColumnIdentifier_Enabled]) { [layer setEnabled: [object boolValue]]; // switching a layer's enabled state also switches the way its name is drawn (different // text attributes), so force the row to redisplay so the layer's name redraws: [_layersTable setNeedsDisplayInRect: [_layersTable rectOfRow: row]]; } else if ([identifier isEqualToString: kLayersTableColumnIdentifier_Name]) { NSUndoManager *undoManager = [self undoManager]; // Might be setting the layer name as the result of clicking a button that forces // editing to end before performing an additional undoable action (Layers panel buttons: // +, -, or Duplicate), so force the undo manager to group the name change as its own // undo grouping to prevent the actions from being merged (since they're both registered // under the same event). [undoManager setGroupsByEvent: NO]; [undoManager beginUndoGrouping]; [layer setName: object]; [undoManager endUndoGrouping]; [undoManager setGroupsByEvent: YES]; } else if ([identifier isEqualToString: kLayersTableColumnIdentifier_Opacity]) { [layer setOpacity: [object floatValue]]; } _ignoreNotificationForChangedLayerAttribute = NO; } - (BOOL) tableView: (NSTableView *) tableView writeRowsWithIndexes: (NSIndexSet *) rowIndexes toPasteboard: (NSPasteboard*) pasteboard { NSData *pasteboardData; pasteboardData = [NSKeyedArchiver archivedDataWithRootObject: rowIndexes]; [pasteboard declareTypes: [NSArray arrayWithObject: kLayersTableDraggedDataType] owner: self]; [pasteboard setData: pasteboardData forType: kLayersTableDraggedDataType]; return YES; } - (NSDragOperation) tableView: (NSTableView*) tableView validateDrop: (id ) info proposedRow: (NSInteger) newRow proposedDropOperation: (NSTableViewDropOperation) op { NSPasteboard *pasteboard; NSData *pasteboardData; NSIndexSet *rowIndexes; unsigned int selectedRow; pasteboard = [info draggingPasteboard]; pasteboardData = [pasteboard dataForType: kLayersTableDraggedDataType]; rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData: pasteboardData]; selectedRow = [rowIndexes firstIndex]; if ((op == NSTableViewDropAbove) && (selectedRow != newRow) && (selectedRow != (newRow-1))) { return NSDragOperationEvery; } else { return NSDragOperationNone; } } - (BOOL) tableView: (NSTableView *) aTableView acceptDrop: (id ) info row: (NSInteger) destinationTableRow dropOperation: (NSTableViewDropOperation) operation { NSPasteboard *pboard; NSData *rowData; NSIndexSet *rowIndexes; int sourceTableRow, oldLayerIndex, newLayerIndex; pboard = [info draggingPasteboard]; rowData = [pboard dataForType: kLayersTableDraggedDataType]; rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData: rowData]; sourceTableRow = [rowIndexes firstIndex]; oldLayerIndex = [self layerIndexForTableRowIndex: sourceTableRow]; newLayerIndex = [self layerIndexForTableRowIndex: destinationTableRow]; if (destinationTableRow > sourceTableRow) { newLayerIndex++; } [_ppDocument moveLayerAtIndex: oldLayerIndex toIndex: newLayerIndex]; return YES; } #pragma mark PPLayersTableView delegate methods - (void) tableViewSelectionDidChange: (NSNotification *) notification { if (!_ppDocument || ![_ppDocument numLayers]) { return; } if ([_layersTable numberOfSelectedRows] != 1) { [self updateLayersTableSelection]; } else { [_ppDocument selectDrawingLayerAtIndex: [self layerIndexForTableRowIndex: [_layersTable selectedRow]]]; } } #pragma mark PPLayersTableView notifications - (void) addAsObserverForPPLayersTableViewNotifications { NSText *layersTableFieldEditor = [[self window] fieldEditor: YES forObject: _layersTable]; if (!layersTableFieldEditor) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPLayersTableViewNotification_TextDidEndEditing:) name: NSTextDidEndEditingNotification object: layersTableFieldEditor]; } - (void) removeAsObserverForPPLayersTableViewNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSTextDidEndEditingNotification object: nil]; } - (void) handlePPLayersTableViewNotification_TextDidEndEditing: (NSNotification *) notification { [self ppPerformSelectorFromNewStackFrame: @selector(resignKeyWindowUnlessEditingLayerNameText)]; } #pragma mark Layers table thumbnails - (void) setupLayerThumbnailsCacheForCurrentPPDocument { [self destroyAllCachedLayerThumbnailsAndResizeCacheForCurrentPPDocument]; [self setupLayerThumbnailDrawMembersForCurrentPPDocument]; [self setupLayerThumbnailBackgroundBitmapForCurrentPPDocument]; } - (void) destroyLayerThumbnailsCache { [self destroyAllCachedLayerThumbnails]; [self destroyLayerThumbnailBackgroundBitmap]; } - (void) destroyAllCachedLayerThumbnailsAndResizeCacheForCurrentPPDocument { [self destroyAllCachedLayerThumbnails]; _numCachedLayerThumbnails = [_ppDocument numLayers]; } - (void) setupLayerThumbnailDrawMembersForCurrentPPDocument { _layerThumbnailSourceRect.size = [_ppDocument canvasSize]; _layerThumbnailDestinationRect.size = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(_layerThumbnailSourceRect.size, _layerThumbnailMaxSize).size; _layerThumbnailInterpolation = PPThumbUtils_ImageInterpolationForSourceRectToDestinationRect( _layerThumbnailSourceRect, _layerThumbnailDestinationRect); } - (NSImage *) cachedThumbnailForLayerAtIndex: (unsigned) index { NSImage *thumbnailImage; if (index >= _numCachedLayerThumbnails) { goto ERROR; } thumbnailImage = _cachedLayerThumbnailImages[index]; if (!thumbnailImage) { NSBitmapImageRep *thumbnailBitmap; NSImage *layerImage; layerImage = [[_ppDocument layerAtIndex: index] image]; thumbnailBitmap = [[_layerThumbnailBackgroundBitmap copy] autorelease]; if (!layerImage || !thumbnailBitmap) { goto ERROR; } [thumbnailBitmap ppSetAsCurrentGraphicsContext]; [[NSGraphicsContext currentContext] setImageInterpolation: _layerThumbnailInterpolation]; [layerImage drawInRect: _layerThumbnailDestinationRect fromRect: _layerThumbnailSourceRect operation: NSCompositeSourceOver fraction: 1.0f]; [thumbnailBitmap ppRestoreGraphicsContext]; thumbnailImage = [NSImage ppImageWithBitmap: thumbnailBitmap]; _cachedLayerThumbnailImages[index] = [thumbnailImage retain]; } return thumbnailImage; ERROR: return nil; } - (void) destroyCachedThumbnailForLayerAtIndex: (unsigned) index { if (index >= _numCachedLayerThumbnails) { return; } [_cachedLayerThumbnailImages[index] release]; _cachedLayerThumbnailImages[index] = nil; } - (void) destroyAllCachedLayerThumbnails { NSImage **currentThumbnail = &_cachedLayerThumbnailImages[0]; int thumbnailCounter = _numCachedLayerThumbnails; while (thumbnailCounter--) { if (*currentThumbnail) { [*currentThumbnail release]; *currentThumbnail = nil; } currentThumbnail++; } } - (void) setupLayerThumbnailBackgroundBitmapForCurrentPPDocument { PPBackgroundPattern *documentBackgroundPattern, *thumbnailBackgroundPattern; float patternScalingFactor; NSColor *thumbnailBackgroundPatternColor; NSSize backgroundImageSize; NSBitmapImageRep *backgroundBitmap; [self destroyLayerThumbnailBackgroundBitmap]; if (!_ppDocument || NSIsEmptyRect(_layerThumbnailSourceRect)) { goto ERROR; } documentBackgroundPattern = [_ppDocument backgroundPattern]; patternScalingFactor = kScalingFactorForThumbnailBackgroundPatternSize * _layerThumbnailDestinationRect.size.width / _layerThumbnailSourceRect.size.width; if (patternScalingFactor > 1.0f) { patternScalingFactor = 1.0f; } thumbnailBackgroundPattern = [documentBackgroundPattern backgroundPatternScaledByFactor: patternScalingFactor]; thumbnailBackgroundPatternColor = [thumbnailBackgroundPattern patternFillColor]; if (!thumbnailBackgroundPatternColor) goto ERROR; backgroundImageSize.width = _layerThumbnailDestinationRect.size.width; backgroundImageSize.height = NSMaxY(_layerThumbnailDestinationRect); if (PPGeometry_IsZeroSize(backgroundImageSize)) { goto ERROR; } backgroundBitmap = [NSBitmapImageRep ppImageBitmapOfSize: backgroundImageSize]; if (!backgroundBitmap) goto ERROR; [backgroundBitmap ppSetAsCurrentGraphicsContext]; [thumbnailBackgroundPatternColor set]; NSRectFill(_layerThumbnailDestinationRect); [backgroundBitmap ppRestoreGraphicsContext]; _layerThumbnailBackgroundBitmap = [backgroundBitmap retain]; return; ERROR: return; } - (void) destroyLayerThumbnailBackgroundBitmap { [_layerThumbnailBackgroundBitmap release]; _layerThumbnailBackgroundBitmap = nil; } #pragma mark Layers table disabled layer titles - (id) cachedDisabledLayerNameAttrStringForLayerName: (NSString *) layerName { id disabledLayerName; if (!layerName) { layerName = @""; } disabledLayerName = [_cachedDisabledLayerNameAttrStringsDict objectForKey: layerName]; if (!disabledLayerName) { disabledLayerName = [[[NSAttributedString alloc] initWithString: layerName attributes: PPTextAttributesDict_DisabledTitle_Table()] autorelease]; if (disabledLayerName) { [_cachedDisabledLayerNameAttrStringsDict setObject: disabledLayerName forKey: layerName]; } else { disabledLayerName = layerName; } } return disabledLayerName; } - (void) destroyAllCachedDisabledLayerNameAttrStrings { [_cachedDisabledLayerNameAttrStringsDict removeAllObjects]; } #pragma mark Panel content view mouse tracking - (void) setupTrackingRectForPanelContentView: (NSView *) panelContentView { if (_panelContentViewTrackingRectTag) { [panelContentView removeTrackingRect: _panelContentViewTrackingRectTag]; } _panelContentViewTrackingRectTag = [panelContentView addTrackingRect: [panelContentView bounds] owner: self userData: nil assumeInside: _mouseIsInsideTrackingRect]; } - (void) mouseEntered: (NSEvent *) theEvent { NSTrackingRectTag trackingRectTag = [theEvent trackingNumber]; if (trackingRectTag == _panelContentViewTrackingRectTag) { _mouseIsInsideTrackingRect = YES; } else { [super mouseEntered: theEvent]; } } - (void) mouseExited: (NSEvent *) theEvent { NSTrackingRectTag trackingRectTag = [theEvent trackingNumber]; if (trackingRectTag == _panelContentViewTrackingRectTag) { if (_mouseIsInsideTrackingRect) { _mouseIsInsideTrackingRect = NO; [_ppDocument ppMakeWindowKey]; } } else { [super mouseExited: theEvent]; } } #pragma mark Private methods - (void) handleResizedPanel { NSView *panelContentView = [[self window] contentView]; [self resizeLayerControlButtonsForPanelContentWidth: [panelContentView bounds].size.width]; [self setupTrackingRectForPanelContentView: panelContentView]; } - (void) resizeLayerControlButtonsForPanelContentWidth: (float) contentWidth { float halfContentWidth, displayModeButtonFrameWidth, operationTargetButtonFrameWidth; NSRect currentButtonFrame, newButtonFrame; halfContentWidth = contentWidth / 2.0f; displayModeButtonFrameWidth = floorf(halfContentWidth) + 1.0f; operationTargetButtonFrameWidth = ceilf(halfContentWidth) + 1.0f; currentButtonFrame = [_canvasDisplayModeButton frame]; newButtonFrame = currentButtonFrame; newButtonFrame.size.width = displayModeButtonFrameWidth; newButtonFrame.origin.x = 0.0f; if (!NSEqualRects(currentButtonFrame, newButtonFrame)) { [_canvasDisplayModeButton setFrame: newButtonFrame]; } currentButtonFrame = [_layerOperationTargetButton frame]; newButtonFrame = currentButtonFrame; newButtonFrame.size.width = operationTargetButtonFrameWidth; newButtonFrame.origin.x = contentWidth - newButtonFrame.size.width; if (!NSEqualRects(currentButtonFrame, newButtonFrame)) { [_layerOperationTargetButton setFrame: newButtonFrame]; } } - (void) setupWithPPDocumentWindowController: (PPDocumentWindowController *) ppDocumentWindowController { if (_ppDocumentWindowController == ppDocumentWindowController) { return; } if (_ppDocumentWindowController) { [self removeAsObserverForPPDocumentWindowControllerNotifications]; } [_ppDocumentWindowController release]; _ppDocumentWindowController = [ppDocumentWindowController retain]; if (_ppDocumentWindowController) { [self addAsObserverForPPDocumentWindowControllerNotifications]; } } - (void) updateCanvasDisplayMode { _canvasDisplayMode = [_ppDocumentWindowController canvasDisplayMode]; if (_canvasDisplayMode != kPPLayerDisplayMode_DrawingLayerOnly) { _canvasDisplayMode = kPPLayerDisplayMode_VisibleLayers; } } - (void) updateLayerOperationTarget { _layerOperationTarget = [_ppDocument layerOperationTarget]; if (_layerOperationTarget != kPPLayerOperationTarget_DrawingLayerOnly) { _layerOperationTarget = kPPLayerOperationTarget_VisibleLayers; } } - (void) updateCanvasDisplayModeButtonImage { NSImage *buttonImage = [[PPLayerControlButtonImagesManager sharedManager] buttonImageForDisplayMode: _canvasDisplayMode]; // button's current image may already be buttonImage, so force redraw by clearing the image // first [_canvasDisplayModeButton setImage: nil]; [_canvasDisplayModeButton setImage: buttonImage]; } - (void) updateLayerOperationTargetButtonImage { NSImage *buttonImage = [[PPLayerControlButtonImagesManager sharedManager] buttonImageForOperationTarget: _layerOperationTarget]; // button's current image may already be buttonImage, so force redraw by clearing the image // first [_layerOperationTargetButton setImage: nil]; [_layerOperationTargetButton setImage: buttonImage]; } - (void) updateLayerControlButtonImages { [self updateCanvasDisplayModeButtonImage]; [self updateLayerOperationTargetButtonImage]; _needToUpdateLayerControlButtonImages = NO; } - (void) updateLayerBlendingModeButtonWithCurrentMode { [_layerBlendingModeButton setLayerBlendingMode: [_ppDocument layerBlendingMode]]; } - (void) reloadLayersTableDataAndUpdateSelection { [_layersTable reloadData]; [self updateLayersTableSelection]; } - (void) reloadLayersTableDataForLayerAtIndex: (unsigned) layerIndex { NSRect updateRect; updateRect = [_layersTable rectOfRow: [self tableRowIndexForLayerIndex: layerIndex]]; if (NSIsEmptyRect(updateRect)) { return; } [_layersTable setNeedsDisplayInRect: updateRect]; } - (void) reloadLayersTableThumbnailDataForLayerAtIndex: (unsigned) layerIndex { NSRect updateRect; updateRect = [_layersTable frameOfCellAtColumn: kLayersTableColumnIndex_Thumbnail row: [self tableRowIndexForLayerIndex: layerIndex]]; if (NSIsEmptyRect(updateRect)) { return; } [_layersTable setNeedsDisplayInRect: updateRect]; } - (void) updateLayersTableSelection { if ([_ppDocument numLayers]) { unsigned int rowOfDrawingLayer; rowOfDrawingLayer = [self tableRowIndexForLayerIndex: [_ppDocument indexOfDrawingLayer]]; [_layersTable selectRowIndexes: [NSIndexSet indexSetWithIndex: rowOfDrawingLayer] byExtendingSelection: NO]; } else { [_layersTable deselectAll: self]; } } - (unsigned) tableRowIndexForLayerIndex: (unsigned) layerIndex { return [_ppDocument numLayers] - 1 - layerIndex; } - (unsigned) layerIndexForTableRowIndex: (unsigned) rowIndex { return [_ppDocument numLayers] - 1 - rowIndex; } - (bool) isEditingLayerNameText { NSWindow *layersPanel; NSText *layersTableFieldEditor; layersPanel = [self window]; if (![layersPanel isKeyWindow]) { return NO; } layersTableFieldEditor = [layersPanel fieldEditor: NO forObject: _layersTable]; if (!layersTableFieldEditor) { return NO; } return (layersTableFieldEditor == [layersPanel firstResponder]) ? YES : NO; } - (void) endEditingForLayerNameText { if ([self isEditingLayerNameText]) { [[self window] endEditingFor: _layersTable]; } } - (void) resignKeyWindowUnlessEditingLayerNameText { if ([[self window] isKeyWindow] && ![self isEditingLayerNameText]) { [_ppDocument ppMakeWindowKey]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayersTableView.h0000644000076500000240000000227213234403417021634 0ustar joshstaff/* PPLayersTableView.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPLayersTableView : NSTableView { NSIndexSet *_selectedRowsAtMouseDown; } - (void) restoreSelectionFromLastMouseDown; - (IBAction) layerEnabledButtonCellClicked: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLayersTableView.m0000644000076500000240000000372513234403207021642 0ustar joshstaff/* PPLayersTableView.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLayersTableView.h" @implementation PPLayersTableView - (void) dealloc { [_selectedRowsAtMouseDown release]; [super dealloc]; } - (void) restoreSelectionFromLastMouseDown { [self selectRowIndexes: _selectedRowsAtMouseDown byExtendingSelection: NO]; } #pragma mark Actions - (IBAction) layerEnabledButtonCellClicked: (id) sender { [self restoreSelectionFromLastMouseDown]; } #pragma mark NSTableView overrides - (BOOL) acceptsFirstMouse: (NSEvent *) theEvent { return YES; } - (void) mouseDown: (NSEvent *) theEvent { [_selectedRowsAtMouseDown release]; _selectedRowsAtMouseDown = [[self selectedRowIndexes] retain]; [super mouseDown: theEvent]; } - (NSUndoManager *) undoManager { // returning nil prevents the tableview's textfield editor from finding the document's // undoManager higher up in the responder chain (PPLayersPanelController), which prevents // undoing the document's non-text actions while editing a layer name return nil; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLineTool.h0000644000076500000240000000260513757513741020333 0ustar joshstaff/* PPLineTool.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPLineTool : PPTool { NSBezierPath *_drawPath; NSPoint _segmentStartPoint; NSPoint _segmentEndPoint; int _numSegments; bool _shouldFillDrawPath; bool _modifierKeyDown_NewSegment; bool _modifierKeyDown_DeleteSegment; #if PP_DEPLOYMENT_TARGET_ALLOWS_SYSTEM_INTERCEPTION_OF_COMMAND_KEY bool _commandKeyIsPressed; bool _disallowDeleteSegment; #endif } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPLineTool.m0000644000076500000240000001624213757356605020346 0ustar joshstaff/* PPLineTool.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPLineTool.h" #import "PPDocument.h" #import "PPGeometry.h" #import "NSCursor_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #define kLineToolAttributesMask (0) @interface PPLineTool (PrivateMethods) - (void) beginNewSegment; - (void) deleteLastSegment; @end @implementation PPLineTool - init { self = [super init]; if (!self) goto ERROR; _drawPath = [[NSBezierPath bezierPath] retain]; if (!_drawPath) goto ERROR; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_drawPath release]; [super dealloc]; } - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [_drawPath removeAllPoints]; [_drawPath ppAppendSinglePixelLineAtPoint: currentPoint]; _segmentStartPoint = _segmentEndPoint = currentPoint; _numSegments = 0; [self beginNewSegment]; _modifierKeyDown_NewSegment = (modifierKeyFlags & kModifierKeyMask_NewLineSegment) ? YES : NO; _modifierKeyDown_DeleteSegment = (modifierKeyFlags & kModifierKeyMask_DeleteLineSegment) ? YES : NO; #if PP_DEPLOYMENT_TARGET_ALLOWS_SYSTEM_INTERCEPTION_OF_COMMAND_KEY _commandKeyIsPressed = (modifierKeyFlags & NSCommandKeyMask) ? YES : NO; _disallowDeleteSegment = _commandKeyIsPressed; #endif _shouldFillDrawPath = NO; [ppDocument beginDrawingWithPenMode: kPPPenMode_Fill]; [ppDocument drawPixelAtPoint: currentPoint]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { bool modifierKeyDown_NewSegment, modifierKeyDown_DeleteSegment, allowDeleteSegment, shouldFillDrawPath, shouldRedrawLine = NO, endPointDidMove; // new/delete segment modifiers modifierKeyDown_NewSegment = (modifierKeyFlags & kModifierKeyMask_NewLineSegment) ? YES : NO; modifierKeyDown_DeleteSegment = (modifierKeyFlags & kModifierKeyMask_DeleteLineSegment) ? YES : NO; allowDeleteSegment = (!modifierKeyDown_NewSegment) ? YES : NO; #if PP_DEPLOYMENT_TARGET_ALLOWS_SYSTEM_INTERCEPTION_OF_COMMAND_KEY // some Linux/BSD desktop environments intercept the Command/Super key when it's pressed // by itself, so the user has to press Command+Option/Super+Alt in order to enable the // "Fill Drawn Shape" mode, however, this may interfere with the "Delete Segment" mode // (Option/Alt key); in order to avoid conflicts between the two modes, the "Delete Segment" // mode is disallowed as soon as the Command-key modifier flag's raised (the key may have // already been pressed for awhile, but doesn't pass through to PP until another modifier's // pressed), and "Delete Segment" is not allowed again until both the Command & Option keys // are up _commandKeyIsPressed = (modifierKeyFlags & NSCommandKeyMask) ? YES : NO; if (_commandKeyIsPressed) { _disallowDeleteSegment = YES; } else if (_disallowDeleteSegment && !modifierKeyDown_DeleteSegment) { _disallowDeleteSegment = NO; } if (_disallowDeleteSegment) { allowDeleteSegment = NO; } #endif // PP_DEPLOYMENT_TARGET_ALLOWS_SYSTEM_INTERCEPTION_OF_COMMAND_KEY if (_modifierKeyDown_NewSegment != modifierKeyDown_NewSegment) { _modifierKeyDown_NewSegment = modifierKeyDown_NewSegment; if (_modifierKeyDown_NewSegment && !modifierKeyDown_DeleteSegment) { [self beginNewSegment]; } } if (_modifierKeyDown_DeleteSegment != modifierKeyDown_DeleteSegment) { _modifierKeyDown_DeleteSegment = modifierKeyDown_DeleteSegment; if (_modifierKeyDown_DeleteSegment && allowDeleteSegment) { [self deleteLastSegment]; shouldRedrawLine = YES; } } // fill shape modifier if (_numSegments > 1) { shouldFillDrawPath = (modifierKeyFlags & kModifierKeyMask_FillShape) ? YES : NO; } else { shouldFillDrawPath = NO; } if (_shouldFillDrawPath != shouldFillDrawPath) { _shouldFillDrawPath = shouldFillDrawPath; shouldRedrawLine = YES; } // lock aspect ratio modifier if (modifierKeyFlags & kModifierKeyMask_LockAspectRatio) { currentPoint = PPGeometry_NearestPointOnOneSixteenthSlope(_segmentStartPoint, currentPoint); } // update draw path's end point endPointDidMove = (!NSEqualPoints(_segmentEndPoint, currentPoint)) ? YES : NO; if (endPointDidMove) { [_drawPath ppSetLastLineEndPointToPixelAtPoint: currentPoint]; _segmentEndPoint = currentPoint; shouldRedrawLine = YES; } // draw if (shouldRedrawLine) { [ppDocument undoCurrentDrawingAtNextDraw]; [ppDocument drawBezierPath: _drawPath andFill: _shouldFillDrawPath]; } } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [ppDocument finishDrawing]; [_drawPath removeAllPoints]; _numSegments = 0; } - (NSCursor *) cursor { return [NSCursor ppLineToolCursor]; } - (unsigned) toolAttributeFlags { return kLineToolAttributesMask; } #pragma mark Private methods - (void) beginNewSegment { [_drawPath ppAppendZeroLengthLineAtLastLineEndPoint]; _segmentStartPoint = _segmentEndPoint; _numSegments++; } - (void) deleteLastSegment { NSPoint previousStartPoint; if (_numSegments <= 1) { return; } if ([_drawPath ppRemoveLastLineStartPointAndGetPreviousStartPoint: &previousStartPoint]) { _segmentStartPoint = previousStartPoint; _numSegments--; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPMagicWandTool.h0000644000076500000240000000242113234403417021256 0ustar joshstaff/* PPMagicWandTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPMagicWandTool : PPTool { NSPoint _mouseDownLocationInImage; unsigned _lastColorMatchTolerance; int _lastPixelMatchingMode; int _lastSelectionMode; bool _selectionMaskCoversMouseDownPoint; bool _needToSetupValueOfSelectionMaskCoversMouseDownPoint; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPMagicWandTool.m0000644000076500000240000001614513234403207021270 0ustar joshstaff/* PPMagicWandTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPMagicWandTool.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPGeometry.h" #import "PPToolUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #import "NSCursor_PPUtilities.h" #define kWandToolAttributesMask \ (kPPToolAttributeMask_RequiresPointsInViewCoordinates \ | kPPToolAttributeMask_DisableAutoscrolling \ | kPPToolAttributeMask_MatchCanvasDisplayModeToOperationTarget) @interface PPMagicWandTool (PrivateMethods) - (void) updateSelectionToolOverlayOnCanvasView: (PPCanvasView *) canvasView withColorMatchTolerance: (unsigned) colorMatchTolerance andModifierKeyFlags: (int) modifierKeyFlags forDocument: (PPDocument *) ppDocument; - (void) setupValueOfSelectionMaskCoversMouseDownPointWithDocument: (PPDocument *) ppDocument; @end @implementation PPMagicWandTool - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { // tool receives points in view coordinates, must convert to get image coordinates _mouseDownLocationInImage = [canvasView imagePointFromViewPoint: currentPoint clippedToCanvasBounds: YES]; [canvasView showMatchToolToleranceIndicatorAtViewPoint: currentPoint]; _lastColorMatchTolerance = -1; // force update _needToSetupValueOfSelectionMaskCoversMouseDownPoint = YES; [self updateSelectionToolOverlayOnCanvasView: canvasView withColorMatchTolerance: 0 andModifierKeyFlags: modifierKeyFlags forDocument: ppDocument]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { unsigned mouseDistance, colorMatchTolerance; mouseDistance = PPGeometry_IntegerDistanceBetweenPoints(mouseDownPoint, currentPoint); colorMatchTolerance = PPToolUtils_ColorMatchToleranceForMouseDistance(mouseDistance); [self updateSelectionToolOverlayOnCanvasView: canvasView withColorMatchTolerance: colorMatchTolerance andModifierKeyFlags: modifierKeyFlags forDocument: ppDocument]; [canvasView setMatchToolToleranceIndicatorRadius: mouseDistance]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { unsigned colorMatchTolerance; PPPixelMatchingMode pixelMatchingMode; PPSelectionMode selectionMode; [canvasView hideMatchToolToleranceIndicator]; [canvasView clearSelectionToolOverlay]; colorMatchTolerance = PPToolUtils_ColorMatchToleranceForMouseDistance( PPGeometry_IntegerDistanceBetweenPoints(mouseDownPoint, currentPoint)); pixelMatchingMode = PPToolUtils_PixelMatchingModeForModifierKeyFlags(modifierKeyFlags); selectionMode = PPToolUtils_SelectionModeForModifierKeyFlags(modifierKeyFlags); [ppDocument selectPixelsMatchingColorAtPoint: _mouseDownLocationInImage colorMatchTolerance: colorMatchTolerance pixelMatchingMode: pixelMatchingMode selectionMode: selectionMode]; } - (NSCursor *) cursor { return [NSCursor ppMagicWandCursor]; } - (unsigned) toolAttributeFlags { return kWandToolAttributesMask; } #pragma mark Private methods - (void) updateSelectionToolOverlayOnCanvasView: (PPCanvasView *) canvasView withColorMatchTolerance: (unsigned) colorMatchTolerance andModifierKeyFlags: (int) modifierKeyFlags forDocument: (PPDocument *) ppDocument { PPPixelMatchingMode pixelMatchingMode; PPSelectionMode selectionMode; NSBitmapImageRep *matchMask, *intersectMask; bool matchMaskShouldIntersectSelectionMask; pixelMatchingMode = PPToolUtils_PixelMatchingModeForModifierKeyFlags(modifierKeyFlags); selectionMode = PPToolUtils_SelectionModeForModifierKeyFlags(modifierKeyFlags); if ((colorMatchTolerance == _lastColorMatchTolerance) && (pixelMatchingMode == _lastPixelMatchingMode) && (selectionMode == _lastSelectionMode)) { return; } intersectMask = (selectionMode == kPPSelectionMode_Intersect) ? [ppDocument selectionMask] : nil; if ((selectionMode == kPPSelectionMode_Subtract) || (selectionMode == kPPSelectionMode_Intersect)) { if (_needToSetupValueOfSelectionMaskCoversMouseDownPoint) { [self setupValueOfSelectionMaskCoversMouseDownPointWithDocument: ppDocument]; } matchMaskShouldIntersectSelectionMask = _selectionMaskCoversMouseDownPoint; } else { matchMaskShouldIntersectSelectionMask = NO; } matchMask = [ppDocument maskForPixelsMatchingColorAtPoint: _mouseDownLocationInImage colorMatchTolerance: colorMatchTolerance pixelMatchingMode: pixelMatchingMode shouldIntersectSelectionMask: matchMaskShouldIntersectSelectionMask]; [canvasView setSelectionToolOverlayToMask: matchMask maskBounds: [matchMask ppMaskBounds] selectionMode: selectionMode intersectMask: intersectMask]; _lastColorMatchTolerance = colorMatchTolerance; _lastPixelMatchingMode = pixelMatchingMode; _lastSelectionMode = selectionMode; } - (void) setupValueOfSelectionMaskCoversMouseDownPointWithDocument: (PPDocument *) ppDocument { _selectionMaskCoversMouseDownPoint = [[ppDocument selectionMask] ppMaskCoversPoint: _mouseDownLocationInImage]; _needToSetupValueOfSelectionMaskCoversMouseDownPoint = NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPMagnifierTool.h0000644000076500000240000000203313234403417021324 0ustar joshstaff/* PPMagnifierTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPMagnifierTool : PPTool { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPMagnifierTool.m0000644000076500000240000001002213234403207021323 0ustar joshstaff/* PPMagnifierTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPMagnifierTool.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPGeometry.h" #import "NSCursor_PPUtilities.h" #define kMagnifierToolAttributesMask (kPPToolAttributeMask_RequiresPointsInViewCoordinates) #define kMinMouseDraggedDistanceToUseZoomRect 15.0f @implementation PPMagnifierTool - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSRect rect; if (modifierKeyFlags & kModifierKeyMask_ZoomOut) { rect = NSZeroRect; } else if (modifierKeyFlags & kModifierKeyMask_CenterShapeAtMouseDown) { rect = PPGeometry_PixelBoundsWithCenterAndCornerPoint(mouseDownPoint, currentPoint); } else { rect = PPGeometry_PixelBoundsWithCornerPoints(mouseDownPoint, currentPoint); } [canvasView setMagnifierToolOverlayToViewRect: rect]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [canvasView clearMagnifierToolOverlay]; if (modifierKeyFlags & kModifierKeyMask_ZoomOut) { NSPoint imagePoint = [canvasView imagePointFromViewPoint: currentPoint clippedToCanvasBounds: YES]; [canvasView decreaseZoomFactor]; [canvasView centerEnclosingScrollViewAtImagePoint: imagePoint]; } else { if (PPGeometry_DistanceBetweenPoints(mouseDownPoint, currentPoint) >= kMinMouseDraggedDistanceToUseZoomRect) { NSRect rect; if (modifierKeyFlags & kModifierKeyMask_CenterShapeAtMouseDown) { rect = PPGeometry_PixelBoundsWithCenterAndCornerPoint(mouseDownPoint, currentPoint); } else { rect = PPGeometry_PixelBoundsWithCornerPoints(mouseDownPoint, currentPoint); } [canvasView setZoomToFitViewRect: rect]; } else { NSPoint imagePoint = [canvasView imagePointFromViewPoint: currentPoint clippedToCanvasBounds: YES]; [canvasView increaseZoomFactor]; [canvasView centerEnclosingScrollViewAtImagePoint: imagePoint]; } } } - (NSCursor *) cursor { return [NSCursor ppMagnifierCursor]; } - (unsigned) toolAttributeFlags { return kMagnifierToolAttributesMask; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPMiniColorWell.h0000644000076500000240000000230713234403417021310 0ustar joshstaff/* PPMiniColorWell.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPMiniColorWell : NSView { NSColor *_fillColor; NSColor *_outlineColor; bool _fillColorIsOpaque; } - (void) setColor: (NSColor *) color; - (void) setOutlineColor: (NSColor *) color; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPMiniColorWell.m0000644000076500000240000000705113234403207021313 0ustar joshstaff/* PPMiniColorWell.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPMiniColorWell.h" #import "PPGeometry.h" @interface PPMiniColorWell (PrivateMethods) - (void) drawTransparencyBackgroundInBounds: (NSRect) bounds; @end @implementation PPMiniColorWell - (void) dealloc { [_fillColor release]; [_outlineColor release]; [super dealloc]; } - (void) setColor: (NSColor *) color { if (_fillColor == color) { return; } [_fillColor release]; _fillColor = [color retain]; _fillColorIsOpaque = ([color alphaComponent] >= 1.0f) ? YES : NO; [self setNeedsDisplay: YES]; } - (void) setOutlineColor: (NSColor *) color { if (_outlineColor == color) { return; } [_outlineColor release]; _outlineColor = [color retain]; [self setNeedsDisplay: YES]; } #pragma mark NSView overrides - (void) drawRect: (NSRect) rect { NSRect viewDrawBounds = PPGeometry_PixelCenteredRect([self bounds]); if (_fillColor) { if (!_fillColorIsOpaque) { [self drawTransparencyBackgroundInBounds: viewDrawBounds]; } [_fillColor set]; [NSBezierPath fillRect: viewDrawBounds]; } if (_outlineColor) { [_outlineColor set]; [NSBezierPath strokeRect: viewDrawBounds]; if (!_fillColor) { NSBezierPath *xPath = [NSBezierPath bezierPath]; [xPath moveToPoint: viewDrawBounds.origin]; [xPath lineToPoint: NSMakePoint(viewDrawBounds.origin.x + viewDrawBounds.size.width, viewDrawBounds.origin.y + viewDrawBounds.size.height)]; [xPath moveToPoint: NSMakePoint(viewDrawBounds.origin.x, viewDrawBounds.origin.y + viewDrawBounds.size.height)]; [xPath lineToPoint: NSMakePoint(viewDrawBounds.origin.x + viewDrawBounds.size.width, viewDrawBounds.origin.y)]; [xPath stroke]; } } } #pragma mark Private methods - (void) drawTransparencyBackgroundInBounds: (NSRect) bounds { NSBezierPath *trianglePath = [NSBezierPath bezierPath]; [trianglePath moveToPoint: bounds.origin]; [trianglePath lineToPoint: NSMakePoint(bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height)]; [trianglePath lineToPoint: NSMakePoint(bounds.origin.x + bounds.size.width, bounds.origin.y)]; [trianglePath closePath]; [[NSColor blackColor] set]; NSRectFill(bounds); [[NSColor whiteColor] set]; [trianglePath fill]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPModifiablePPToolTypesMasks.h0000644000076500000240000000525013234403417023746 0ustar joshstaff/* PPModifiablePPToolTypesMasks.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPToolType.h" // A PPDocument's active tool can be 'modified': switched to a different tool by pressing one // or more modifier keys. // Modifier-switching to a specific tool is usually only allowed from a few initial tool types. // For instance, switching to the Eraser tool via modifier is only possible when the initial // tool is the Pencil or Line Tool. // For each modifier-switchable destination tool type, its kModifiablePPToolTypesMask_* define // determines the set of initial tool types that allow modifier-switching to it. #define kModifiablePPToolTypesMask_Eraser \ (kPPToolTypeMask_Pencil | kPPToolTypeMask_Line) #define kModifiablePPToolTypesMask_Fill \ (kPPToolTypeMask_Pencil | kPPToolTypeMask_Line | kPPToolTypeMask_Rect \ | kPPToolTypeMask_Oval) #define kModifiablePPToolTypesMask_ColorSampler \ (kPPToolTypeMask_Pencil | kPPToolTypeMask_Fill | kPPToolTypeMask_Line \ | kPPToolTypeMask_Rect | kPPToolTypeMask_Oval) #define kModifiablePPToolTypesMask_Move \ (kPPToolTypeMask_Pencil | kPPToolTypeMask_Eraser | kPPToolTypeMask_Fill \ | kPPToolTypeMask_Line | kPPToolTypeMask_FreehandSelect \ | kPPToolTypeMask_RectSelect) #define kModifiablePPToolTypesMask_Magnifier \ (~kPPToolTypeMask_Magnifier) #define kModifiablePPToolTypesMask_ColorRamp \ (kPPToolTypeMask_Line) PikoPixel.Sources.1.0-b10b/PikoPixel/PPModifierKeyMasks.h0000644000076500000240000000700713234403417022001 0ustar joshstaff/* PPModifierKeyMasks.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #define kModifierKeyMask_RecognizedModifierKeys \ (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask) #define kModifierKeyMask_SelectEraserTool (NSControlKeyMask) #define kModifierKeyMask_SelectFillTool (NSAlternateKeyMask | NSShiftKeyMask) #define kModifierKeyMask_SelectColorSamplerTool (NSAlternateKeyMask) #define kModifierKeyMask_SelectMoveTool (NSControlKeyMask | NSShiftKeyMask) #define kModifierKeyMask_SelectMagnifierTool (NSCommandKeyMask | NSAlternateKeyMask) #define kModifierKeyMask_SelectColorRampTool (NSControlKeyMask | NSAlternateKeyMask) #define kModifierKeyMask_DrawLineSegment (NSShiftKeyMask) #define kModifierKeyMask_NewLineSegment (NSControlKeyMask) #define kModifierKeyMask_DeleteLineSegment (NSAlternateKeyMask) #define kModifierKeyMask_IntersectSelection (NSAlternateKeyMask | NSShiftKeyMask) #define kModifierKeyMask_AddToSelection (NSShiftKeyMask) #define kModifierKeyMask_CutFromSelection (NSAlternateKeyMask) #define kModifierKeyMask_SnapSelectionToGuidelines (NSControlKeyMask) #define kModifierKeyMask_MoveACopy (NSCommandKeyMask) #define kModifierKeyMask_MoveSelectionOutlineOnly (NSAlternateKeyMask) #define kModifierKeyMask_MoveRectSelectionOutline (NSCommandKeyMask) #define kModifierKeyMask_MatchDiagonally (NSControlKeyMask) #define kModifierKeyMask_MatchGlobally (NSCommandKeyMask) #define kModifierKeyMask_LockAspectRatio (NSShiftKeyMask) #define kModifierKeyMask_CenterShapeAtMouseDown (NSControlKeyMask) #define kModifierKeyMask_FillShape (NSCommandKeyMask) #define kModifierKeyMask_ZoomOut (NSShiftKeyMask) #define kModifierKeyMask_SelectEraserToolWithFillShape \ (kModifierKeyMask_SelectEraserTool | kModifierKeyMask_FillShape) #define kModifierKeyMask_SelectMoveToolWithSelectionOutlineOnly \ (kModifierKeyMask_SelectMoveTool | kModifierKeyMask_MoveSelectionOutlineOnly) #define kModifierKeyMask_SelectMoveToolAndLeaveCopyInPlace \ (kModifierKeyMask_SelectMoveTool | kModifierKeyMask_MoveACopy) #define kModifierKeyMask_SelectMagnifierToolWithZoomOut \ (kModifierKeyMask_SelectMagnifierTool | kModifierKeyMask_ZoomOut) #define kModifierKeyMask_SelectMagnifierToolWithCenterShape \ (kModifierKeyMask_SelectMagnifierTool | kModifierKeyMask_CenterShapeAtMouseDown) PikoPixel.Sources.1.0-b10b/PikoPixel/PPMoveTool.h0000644000076500000240000000212513234403417020333 0ustar joshstaff/* PPMoveTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" #import "PPDocumentTypes.h" @interface PPMoveTool : PPTool { PPMoveOperationType _lastMoveType; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPMoveTool.m0000644000076500000240000001075613757360430020360 0ustar joshstaff/* PPMoveTool.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPMoveTool.h" #import "PPDocument.h" #import "PPDocumentWindowController.h" #import "PPToolUtilities.h" #import "PPCanvasView.h" #import "PPGeometry.h" #import "NSCursor_PPUtilities.h" #define kMoveToolAttributesMask \ (kPPToolAttributeMask_CursorDependsOnModifierKeys \ | kPPToolAttributeMask_MatchCanvasDisplayModeToOperationTarget \ | kPPToolAttributeMask_DisallowMatchingCanvasDisplayModeToDrawLayerTarget) @implementation PPMoveTool #pragma mark PPTool overrides - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { PPMoveOperationType moveType; moveType = PPToolUtils_InteractiveMoveTypeForModifierKeyFlags(modifierKeyFlags); [ppDocument beginInteractiveMoveWithTarget: [ppDocument layerOperationTarget] canvasDisplayMode: [[ppDocument ppDocumentWindowController] canvasDisplayMode] moveType: moveType]; if (moveType == kPPMoveOperationType_SelectionOutlineOnly) { [canvasView setSelectionToolOverlayToMask: [ppDocument selectionMask] maskBounds: [ppDocument selectionBounds] selectionMode: kPPSelectionMode_Replace intersectMask: nil]; } _lastMoveType = moveType; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSPoint moveOffset; PPMoveOperationType moveType; moveOffset = PPGeometry_PointDifference(currentPoint, mouseDownPoint); moveType = PPToolUtils_InteractiveMoveTypeForModifierKeyFlags(modifierKeyFlags); [ppDocument setInteractiveMoveOffset: moveOffset andMoveType: moveType]; if (moveType == kPPMoveOperationType_SelectionOutlineOnly) { [canvasView setSelectionToolOverlayToMask: [ppDocument selectionMask] maskBounds: [ppDocument selectionBounds] selectionMode: kPPSelectionMode_Replace intersectMask: nil]; } else if (_lastMoveType == kPPMoveOperationType_SelectionOutlineOnly) { [canvasView clearSelectionToolOverlay]; } _lastMoveType = moveType; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { if (_lastMoveType == kPPMoveOperationType_SelectionOutlineOnly) { [canvasView clearSelectionToolOverlay]; } [ppDocument finishInteractiveMove]; } - (NSCursor *) cursor { return [NSCursor ppMoveToolCursor]; } - (NSCursor *) cursorForModifierKeyFlags: (unsigned) modifierKeyFlags { PPMoveOperationType moveType; moveType = PPToolUtils_InteractiveMoveTypeForModifierKeyFlags(modifierKeyFlags); if (moveType == kPPMoveOperationType_SelectionOutlineOnly) { return [NSCursor ppMoveSelectionOutlineToolCursor]; } return [NSCursor ppMoveToolCursor]; } - (unsigned) toolAttributeFlags { return kMoveToolAttributesMask; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPNavigatorPopupPanelController.h0000644000076500000240000000322013234403417024566 0ustar joshstaff/* PPNavigatorPopupPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanelController.h" #import "PPLayerDisplayMode.h" @class PPNavigatorPopupView, PPDocumentWindowController, PPCanvasView; @interface PPNavigatorPopupPanelController : PPPopupPanelController { IBOutlet PPNavigatorPopupView *_navigatorView; IBOutlet NSButton *_decreaseZoomButton; IBOutlet NSButton *_increaseZoomButton; IBOutlet NSSlider *_zoomSlider; PPDocumentWindowController *_ppDocumentWindowController; PPCanvasView *_canvasView; PPLayerDisplayMode _navigatorViewImageDisplayMode; bool _disallowUpdatesToZoomSliderPosition; } - (IBAction) zoomButtonPressed: (id) sender; - (IBAction) zoomSliderMoved: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPNavigatorPopupPanelController.m0000644000076500000240000003266413234403207024606 0ustar joshstaff/* PPNavigatorPopupPanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPNavigatorPopupPanelController.h" #import "PPDocument.h" #import "PPNavigatorPopupView.h" #import "PPDocumentWindowController.h" #import "PPCanvasView.h" #import "PPUIColors_Panels.h" #import "PPCursorManager.h" #import "NSObject_PPUtilities.h" #define kNavigatorPopupPanelNibName @"NavigatorPopupPanel" @interface PPNavigatorPopupPanelController (PrivateMethods) - (void) addAsObserverForPPCanvasViewNotifications; - (void) removeAsObserverForPPCanvasViewNotifications; - (void) handlePPCanvasViewNotification_ChangedZoomFactor: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification; - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification; - (void) addAsObserverForPPDocumentWindowControllerNotifications; - (void) removeAsObserverForPPDocumentWindowControllerNotifications; - (void) handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode: (NSNotification *) notification; - (void) setupWithPPDocumentWindowController: (PPDocumentWindowController *) ppDocumentWindowController; - (void) setupWithCanvasView: (PPCanvasView *) canvasView; - (void) updateZoomSliderPosition; - (void) setupNavigatorViewImage; - (void) setupNavigatorViewImageBackground; - (void) disableNavigatorViewMouseTracking; - (void) enableNavigatorViewMouseTracking; @end @implementation PPNavigatorPopupPanelController - (void) dealloc { [self setupWithPPDocumentWindowController: nil]; [self setupWithCanvasView: nil]; [super dealloc]; } #pragma mark Actions - (IBAction) zoomButtonPressed: (id) sender { if (sender == _decreaseZoomButton) { [_canvasView decreaseZoomFactor]; } else if (sender == _increaseZoomButton) { [_canvasView increaseZoomFactor]; } } - (IBAction) zoomSliderMoved: (id) sender { NSAutoreleasePool *autoreleasePool; [self disableNavigatorViewMouseTracking]; [[PPCursorManager sharedManager] setCursor: [NSCursor arrowCursor] atLevel: kPPCursorLevel_PopupPanel isDraggingMouse: YES]; autoreleasePool = [[NSAutoreleasePool alloc] init]; _disallowUpdatesToZoomSliderPosition = YES; [_canvasView setZoomFactor: [_zoomSlider floatValue]]; _disallowUpdatesToZoomSliderPosition = NO; [autoreleasePool release]; [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(enableNavigatorViewMouseTracking)]; } #pragma mark NSWindowController overrides - (void) windowDidLoad { [_zoomSlider setMinValue: kMinCanvasZoomFactor]; [_zoomSlider setMaxValue: kMaxCanvasZoomFactor]; // [super windowDidLoad] calls [self setupPanelForCurrentPPDocument], so any preliminary // setup required before calling setupPanelForCurrentPPDocument should go before this call [super windowDidLoad]; } #pragma mark PPPopupPanelController overrides + (NSString *) panelNibName { return kNavigatorPopupPanelNibName; } - (void) setPPDocument: (PPDocument *) ppDocument { [super setPPDocument: ppDocument]; if (!_ppDocument) { [self setupWithPPDocumentWindowController: nil]; [self setupWithCanvasView: nil]; } } - (void) addAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; if (!_ppDocument) return; [notificationCenter addObserver: self selector: @selector( handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage:) name: PPDocumentNotification_UpdatedMergedVisibleThumbnailImage object: _ppDocument]; [notificationCenter addObserver: self selector: @selector( handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage:) name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedBackgroundSettings:) name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ReloadedDocument:) name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedMergedVisibleThumbnailImage object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedDrawingLayerThumbnailImage object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedBackgroundSettings object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (void) setupPanelForCurrentPPDocument { [super setupPanelForCurrentPPDocument]; [self setupWithPPDocumentWindowController: [_ppDocument ppDocumentWindowController]]; [self setupWithCanvasView: [_ppDocumentWindowController canvasView]]; [self setupNavigatorViewImage]; [self setupNavigatorViewImageBackground]; } - (void) setupPanelBeforeMakingVisible { [super setupPanelBeforeMakingVisible]; [_navigatorView handleWindowWillBecomeVisible]; } - (void) setupPanelAfterVisibilityChange { [super setupPanelAfterVisibilityChange]; [_navigatorView handleWindowVisibilityChange]; if (![self panelIsVisible]) { // if the navigator popup's controls were clicked, sometimes the canvas view won't // receive a mouseEntered event after the popup hides, leaving the wrong cursor, so // force the canvas view to update its cursor: [_canvasView updateCursorForCurrentMouseLocation]; } } - (NSColor *) backgroundColorForPopupPanel { return kUIColor_NavigatorPopupPanel_Background; } - (void) handleDirectionCommand: (PPDirectionType) directionType { switch (directionType) { case kPPDirectionType_Right: case kPPDirectionType_Up: { [_canvasView increaseZoomFactor]; } break; case kPPDirectionType_Left: case kPPDirectionType_Down: { [_canvasView decreaseZoomFactor]; } break; default: break; } } #pragma mark PPCanvasView notifications - (void) addAsObserverForPPCanvasViewNotifications { if (!_canvasView) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPCanvasViewNotification_ChangedZoomFactor:) name: PPCanvasViewNotification_ChangedZoomFactor object: _canvasView]; } - (void) removeAsObserverForPPCanvasViewNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPCanvasViewNotification_ChangedZoomFactor object: _canvasView]; } - (void) handlePPCanvasViewNotification_ChangedZoomFactor: (NSNotification *) notification { [self updateZoomSliderPosition]; } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage: (NSNotification *) notification { if (_navigatorViewImageDisplayMode == kPPLayerDisplayMode_VisibleLayers) { [_navigatorView handleUpdateToImage]; } } - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification { if (_navigatorViewImageDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { [_navigatorView handleUpdateToImage]; } } - (void) handlePPDocumentNotification_UpdatedBackgroundSettings: (NSNotification *) notification { [self setupNavigatorViewImageBackground]; } - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification { [self setupPanelForCurrentPPDocument]; } #pragma mark PPDocumentWindowController notifications - (void) addAsObserverForPPDocumentWindowControllerNotifications { if (!_ppDocumentWindowController) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode:) name: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode object: _ppDocumentWindowController]; } - (void) removeAsObserverForPPDocumentWindowControllerNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPDocumentWindowControllerNotification_ChangedCanvasDisplayMode object: _ppDocumentWindowController]; } - (void) handlePPDocumentWindowControllerNotification_ChangedCanvasDisplayMode: (NSNotification *) notification { [self setupNavigatorViewImage]; } #pragma mark Private methods - (void) setupWithPPDocumentWindowController: (PPDocumentWindowController *) ppDocumentWindowController { if (_ppDocumentWindowController == ppDocumentWindowController) { return; } if (_ppDocumentWindowController) { [self removeAsObserverForPPDocumentWindowControllerNotifications]; } [_ppDocumentWindowController release]; _ppDocumentWindowController = [ppDocumentWindowController retain]; if (_ppDocumentWindowController) { [self addAsObserverForPPDocumentWindowControllerNotifications]; } } - (void) setupWithCanvasView: (PPCanvasView *) canvasView { if (_canvasView == canvasView) { return; } if (_canvasView) { [self removeAsObserverForPPCanvasViewNotifications]; } [_canvasView release]; _canvasView = [canvasView retain]; if (_canvasView) { [self addAsObserverForPPCanvasViewNotifications]; } [_navigatorView setCanvasView: canvasView]; [self updateZoomSliderPosition]; } - (void) updateZoomSliderPosition { if (_disallowUpdatesToZoomSliderPosition) return; [_zoomSlider setFloatValue: [_canvasView zoomFactor]]; } - (void) setupNavigatorViewImage { NSImage *navigatorImage; _navigatorViewImageDisplayMode = [_ppDocumentWindowController canvasDisplayMode]; if (_navigatorViewImageDisplayMode == kPPLayerDisplayMode_DrawingLayerOnly) { navigatorImage = [_ppDocument dissolvedDrawingLayerThumbnailImage]; } else { navigatorImage = [_ppDocument mergedVisibleLayersThumbnailImage]; } [_navigatorView setImage: navigatorImage]; } - (void) setupNavigatorViewImageBackground { NSImage *backgroundImage; backgroundImage = ([_ppDocument shouldDisplayBackgroundImage]) ? [_ppDocument backgroundImage] : nil; [_navigatorView setBackgroundPattern: [_ppDocument backgroundPattern] andBackgroundImage: backgroundImage]; } - (void) disableNavigatorViewMouseTracking { [_navigatorView disableMouseTracking: YES]; } - (void) enableNavigatorViewMouseTracking { [_navigatorView disableMouseTracking: NO]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPNavigatorPopupView.h0000644000076500000240000000340113234403417022376 0ustar joshstaff/* PPNavigatorPopupView.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPThumbnailImageView.h" @class PPCanvasView; @interface PPNavigatorPopupView : PPThumbnailImageView { PPCanvasView *_canvasView; NSRect _visibleCanvasBounds; NSRect _viewBoundsTrackingRect; NSTrackingRectTag _viewBoundsTrackingRectTag; NSRect _visibleCanvasBoundsTrackingRect; NSTrackingRectTag _visibleCanvasBoundsTrackingRectTag; bool _windowIsVisible; bool _needToRedrawView; bool _mouseIsDraggingVisibleBounds; bool _mouseIsInsideViewBoundsTrackingRect; bool _mouseIsInsideVisibleCanvasTrackingRect; bool _disallowMouseTracking; } - (void) setCanvasView: (PPCanvasView *) canvasView; - (void) handleWindowWillBecomeVisible; - (void) handleWindowVisibilityChange; - (void) disableMouseTracking: (bool) shouldDisableTracking; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPNavigatorPopupView.m0000644000076500000240000003473213234403207022413 0ustar joshstaff/* PPNavigatorPopupView.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPNavigatorPopupView.h" #import "PPCanvasView.h" #import "NSObject_PPUtilities.h" #import "PPCursorManager.h" #import "PPGeometry.h" #import "NSEvent_PPUtilities.h" #define kUIColor_VisibleCanvasFrame [NSColor redColor] #define kVisibleCanvasFrameLineWidth 2 static NSColor *gVisibleCanvasFrameColor = nil; @interface PPNavigatorPopupView (PrivateMethods) - (void) addAsObserverForPPCanvasViewNotifications; - (void) removeAsObserverForPPCanvasViewNotifications; - (void) handlePPCanvasViewNotification_UpdatedNormalizedVisibleBounds: (NSNotification *) notification; - (void) setupVisibleCanvasBoundsAndTrackingRectForWindowVisibility; - (void) setupVisibleCanvasBounds; - (void) setupMouseTracking; - (void) setupViewBoundsTrackingRect; - (void) setupVisibleCanvasBoundsTrackingRect; - (void) setMouseIsDraggingVisibleBounds: (bool) mouseIsDraggingVisibleBounds; - (void) updateCursor; @end @implementation PPNavigatorPopupView + (void) initialize { if ([self class] != [PPNavigatorPopupView class]) { return; } gVisibleCanvasFrameColor = [kUIColor_VisibleCanvasFrame retain]; } - (void) dealloc { [self setCanvasView: nil]; [super dealloc]; } - (void) setCanvasView: (PPCanvasView *) canvasView { if (_canvasView == canvasView) { return; } if (_canvasView) { [self removeAsObserverForPPCanvasViewNotifications]; } [_canvasView release]; _canvasView = [canvasView retain]; if (_canvasView) { [self addAsObserverForPPCanvasViewNotifications]; [self setupVisibleCanvasBoundsAndTrackingRectForWindowVisibility]; } } - (void) handleWindowWillBecomeVisible { if (_needToRedrawView) { [self setNeedsDisplay: YES]; _needToRedrawView = NO; } [self setupVisibleCanvasBounds]; } - (void) handleWindowVisibilityChange { _windowIsVisible = [[self window] isVisible]; [self setupMouseTracking]; if (!_windowIsVisible) { if (_mouseIsDraggingVisibleBounds) { [self setMouseIsDraggingVisibleBounds: NO]; } // setupMouseTracking only updates the cursor when the window's visible, so update it // manually when hiding the window in order to reset from the hand cursor [self updateCursor]; } } - (void) disableMouseTracking: (bool) shouldDisableTracking { shouldDisableTracking = (shouldDisableTracking) ? YES : NO; if (_disallowMouseTracking == shouldDisableTracking) { return; } _disallowMouseTracking = shouldDisableTracking; [self setupMouseTracking]; } #pragma mark PPThumbnailImageView overrides - (void) setImage: (NSImage *) image { [super setImage: image]; [self setupVisibleCanvasBoundsAndTrackingRectForWindowVisibility]; } - (void) handleUpdateToImage { if (_windowIsVisible) { [super handleUpdateToImage]; } else { _needToRedrawView = YES; } } #pragma mark NSView overrides - (void) drawRect: (NSRect) rect { [super drawRect: rect]; if (!NSIsEmptyRect(_visibleCanvasBounds)) { [gVisibleCanvasFrameColor set]; NSFrameRectWithWidth(_visibleCanvasBounds, kVisibleCanvasFrameLineWidth); } } - (void) mouseDown: (NSEvent *) theEvent { NSPoint mouseLocationInView; [self setMouseIsDraggingVisibleBounds: YES]; mouseLocationInView = [self convertPoint: [theEvent locationInWindow] fromView: nil]; if (!NSPointInRect(mouseLocationInView, _visibleCanvasBounds)) { NSPoint mouseLocationInScaledImage, mouseLocationInImage; mouseLocationInScaledImage = PPGeometry_PointDifference(mouseLocationInView, _scaledThumbnailImageBounds.origin); mouseLocationInImage = NSMakePoint(mouseLocationInScaledImage.x / _thumbnailScale, mouseLocationInScaledImage.y / _thumbnailScale); [_canvasView centerEnclosingScrollViewAtImagePoint: mouseLocationInImage]; } } - (void) mouseDragged: (NSEvent *) theEvent { NSPoint mouseDragAmount, imageDragAmount, newCenterOfVisibleImage; if (!_mouseIsDraggingVisibleBounds) return; // merge event's deltaX/Y with other mouseDragged events in queue (saves some redrawing) mouseDragAmount = [theEvent ppMouseDragDeltaPointByMergingWithEnqueuedMouseDraggedEvents]; imageDragAmount.x = mouseDragAmount.x / _thumbnailScale; imageDragAmount.y = mouseDragAmount.y / _thumbnailScale; newCenterOfVisibleImage = PPGeometry_PointSum([_canvasView imagePointAtCenterOfVisibleCanvas], imageDragAmount); [_canvasView centerEnclosingScrollViewAtImagePoint: newCenterOfVisibleImage]; } - (void) mouseUp: (NSEvent *) theEvent { [self setMouseIsDraggingVisibleBounds: NO]; } - (void) mouseEntered: (NSEvent *) theEvent { NSTrackingRectTag trackingNumber = [theEvent trackingNumber]; if (trackingNumber == _viewBoundsTrackingRectTag) { if (!_mouseIsInsideViewBoundsTrackingRect) { _mouseIsInsideViewBoundsTrackingRect = YES; [self updateCursor]; } } else if (trackingNumber == _visibleCanvasBoundsTrackingRectTag) { if (!_mouseIsInsideVisibleCanvasTrackingRect) { _mouseIsInsideVisibleCanvasTrackingRect = YES; [self updateCursor]; } } else { [super mouseEntered: theEvent]; } } - (void) mouseExited: (NSEvent *) theEvent { NSTrackingRectTag trackingNumber = [theEvent trackingNumber]; if (trackingNumber == _viewBoundsTrackingRectTag) { if (_mouseIsInsideViewBoundsTrackingRect) { _mouseIsInsideViewBoundsTrackingRect = NO; [self updateCursor]; } } else if (trackingNumber == _visibleCanvasBoundsTrackingRectTag) { if (_mouseIsInsideVisibleCanvasTrackingRect) { _mouseIsInsideVisibleCanvasTrackingRect = NO; [self updateCursor]; } } else { [super mouseExited: theEvent]; } } - (BOOL) acceptsFirstMouse: (NSEvent *) theEvent { return YES; } #pragma mark PPCanvasView notifications - (void) addAsObserverForPPCanvasViewNotifications { if (!_canvasView) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPCanvasViewNotification_UpdatedNormalizedVisibleBounds:) name: PPCanvasViewNotification_UpdatedNormalizedVisibleBounds object: _canvasView]; } - (void) removeAsObserverForPPCanvasViewNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPCanvasViewNotification_UpdatedNormalizedVisibleBounds object: _canvasView]; } - (void) handlePPCanvasViewNotification_UpdatedNormalizedVisibleBounds: (NSNotification *) notification { if (_mouseIsDraggingVisibleBounds) { // while dragging, the cursor can forget its state and revert to an arrow, so refresh it [[PPCursorManager sharedManager] refreshCursorIfNeeded]; } [self setupVisibleCanvasBoundsAndTrackingRectForWindowVisibility]; } #pragma mark Private methods - (void) setupVisibleCanvasBoundsAndTrackingRectForWindowVisibility { if (_windowIsVisible) { [self setupVisibleCanvasBounds]; [self setupVisibleCanvasBoundsTrackingRect]; [self updateCursor]; } else // !(_windowIsVisible) { _visibleCanvasBounds = NSZeroRect; _needToRedrawView = YES; } } - (void) setupVisibleCanvasBounds { NSRect normalizedVisibleCanvasBounds, newVisibleCanvasBounds; normalizedVisibleCanvasBounds = [_canvasView normalizedVisibleBounds]; newVisibleCanvasBounds = NSMakeRect(normalizedVisibleCanvasBounds.origin.x * _scaledThumbnailImageBounds.size.width + _scaledThumbnailImageBounds.origin.x, normalizedVisibleCanvasBounds.origin.y * _scaledThumbnailImageBounds.size.height + _scaledThumbnailImageBounds.origin.y, normalizedVisibleCanvasBounds.size.width * _scaledThumbnailImageBounds.size.width, normalizedVisibleCanvasBounds.size.height * _scaledThumbnailImageBounds.size.height); newVisibleCanvasBounds = PPGeometry_PixelBoundsCoveredByRect( NSIntersectionRect(newVisibleCanvasBounds, [self bounds])); if (!NSEqualRects(_visibleCanvasBounds, newVisibleCanvasBounds)) { NSRect updateRect = NSUnionRect(_visibleCanvasBounds, newVisibleCanvasBounds); _visibleCanvasBounds = newVisibleCanvasBounds; [self setNeedsDisplayInRect: updateRect]; } } - (void) setupMouseTracking { [self setupViewBoundsTrackingRect]; [self setupVisibleCanvasBoundsTrackingRect]; if (_windowIsVisible) { [self updateCursor]; } } - (void) setupViewBoundsTrackingRect { NSRect newTrackingRect = NSZeroRect; bool mouseIsInsideNewTrackingRect = NO; if (_windowIsVisible && !_disallowMouseTracking) { newTrackingRect = [self bounds]; if (!NSIsEmptyRect(newTrackingRect)) { NSPoint mouseLocationInView = [self convertPoint: [[self window] mouseLocationOutsideOfEventStream] fromView: nil]; mouseIsInsideNewTrackingRect = (NSPointInRect(mouseLocationInView, newTrackingRect)) ? YES : NO; } } if (!NSEqualRects(newTrackingRect, _viewBoundsTrackingRect)) { if (_viewBoundsTrackingRectTag) { [self removeTrackingRect: _viewBoundsTrackingRectTag]; _viewBoundsTrackingRectTag = 0; _viewBoundsTrackingRect = NSZeroRect; } if (!NSIsEmptyRect(newTrackingRect)) { _viewBoundsTrackingRectTag = [self addTrackingRect: newTrackingRect owner: self userData: NULL assumeInside: mouseIsInsideNewTrackingRect]; if (_viewBoundsTrackingRectTag) { _viewBoundsTrackingRect = newTrackingRect; } else { mouseIsInsideNewTrackingRect = NO; } } } _mouseIsInsideViewBoundsTrackingRect = mouseIsInsideNewTrackingRect; } - (void) setupVisibleCanvasBoundsTrackingRect { NSRect newTrackingRect = NSZeroRect; bool mouseIsInsideNewTrackingRect = NO; if (_windowIsVisible && !_disallowMouseTracking) { newTrackingRect = _visibleCanvasBounds; if (!NSIsEmptyRect(newTrackingRect)) { NSPoint mouseLocationInView = [self convertPoint: [[self window] mouseLocationOutsideOfEventStream] fromView: nil]; mouseIsInsideNewTrackingRect = (NSPointInRect(mouseLocationInView, newTrackingRect)) ? YES : NO; } } if (!NSEqualRects(newTrackingRect, _visibleCanvasBoundsTrackingRect)) { if (_visibleCanvasBoundsTrackingRectTag) { [self removeTrackingRect: _visibleCanvasBoundsTrackingRectTag]; _visibleCanvasBoundsTrackingRectTag = 0; _visibleCanvasBoundsTrackingRect = NSZeroRect; } if (!NSIsEmptyRect(newTrackingRect)) { _visibleCanvasBoundsTrackingRectTag = [self addTrackingRect: newTrackingRect owner: self userData: NULL assumeInside: mouseIsInsideNewTrackingRect]; if (_visibleCanvasBoundsTrackingRectTag) { _visibleCanvasBoundsTrackingRect = newTrackingRect; } else { mouseIsInsideNewTrackingRect = NO; } } } if (_mouseIsInsideVisibleCanvasTrackingRect != mouseIsInsideNewTrackingRect) { _mouseIsInsideVisibleCanvasTrackingRect = mouseIsInsideNewTrackingRect; [self updateCursor]; } } - (void) setMouseIsDraggingVisibleBounds: (bool) mouseIsDraggingVisibleBounds { _mouseIsDraggingVisibleBounds = (mouseIsDraggingVisibleBounds) ? YES : NO; [self disableMouseTracking: _mouseIsDraggingVisibleBounds]; } - (void) updateCursor { NSCursor *cursor; if (_mouseIsDraggingVisibleBounds) { cursor = [NSCursor closedHandCursor]; } else if (_mouseIsInsideVisibleCanvasTrackingRect) { cursor = [NSCursor openHandCursor]; } else if (_mouseIsInsideViewBoundsTrackingRect) { cursor = [NSCursor pointingHandCursor]; } else { cursor = nil; } [[PPCursorManager sharedManager] setCursor: cursor atLevel: kPPCursorLevel_PopupPanel isDraggingMouse: _mouseIsDraggingVisibleBounds]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPObjCUtilities.h0000644000076500000240000000212413234403417021277 0ustar joshstaff/* PPObjCUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import void PPObjCUtils_AlphabeticallySortSelectorArray(SEL *selectorArray, int numSelectors); PikoPixel.Sources.1.0-b10b/PikoPixel/PPObjCUtilities.m0000644000076500000240000000305213234403207021302 0ustar joshstaff/* PPObjCUtilities.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPObjCUtilities.h" static int CompareSelectorNames(const void *selector1, const void *selector2); void PPObjCUtils_AlphabeticallySortSelectorArray(SEL *selectorArray, int numSelectors) { if (!selectorArray || (numSelectors <= 0)) { goto ERROR; } qsort(selectorArray, numSelectors, sizeof(SEL), CompareSelectorNames); return; ERROR: return; } #pragma mark Private functions static int CompareSelectorNames(const void *selector1, const void *selector2) { return strcmp(sel_getName(*((SEL *) selector1)), sel_getName(*((SEL *) selector2))); } PikoPixel.Sources.1.0-b10b/PikoPixel/PPOptional.h0000644000076500000240000000331513717263543020370 0ustar joshstaff/* PPOptional.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Modify __ENABLE_ defines below to enable/disable optional PikoPixel functionality: #define PP_OPTIONAL__ENABLE_SCREENCASTING (true) #define PP_OPTIONAL__ENABLE_CANVAS_SPEED_CHECK (false) // __BUILD_WITH_ defines are derived from __ENABLE_ flags and build-environment requirements #define PP_OPTIONAL__BUILD_WITH_SCREENCASTING \ (PP_OPTIONAL__ENABLE_SCREENCASTING) #define PP_OPTIONAL__BUILD_WITH_CANVAS_SPEED_CHECK \ (PP_OPTIONAL__ENABLE_CANVAS_SPEED_CHECK) // Screencasting functionality requires ObjC runtime API version 2 #define PP_RUNTIME_CHECK_OPTIONAL__RUNTIME_SUPPORTS_SCREENCASTING \ (PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_OBJC_RUNTIME_API_VERSION_2) PikoPixel.Sources.1.0-b10b/PikoPixel/PPOptional_CanvasSpeedCheck.m0000644000076500000240000002222113234403207023567 0ustar joshstaff/* PPOptional_CanvasSpeedCheck.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPOptional.h" #if PP_OPTIONAL__BUILD_WITH_CANVAS_SPEED_CHECK #import #import "PPAppBootUtilities.h" #import "PPApplication.h" #import "NSObject_PPUtilities.h" #import "PPDocumentWindowController.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPTool.h" #import "PPToolbox.h" #import "PPGeometry.h" #define kSpeedCheckMenuItem_Name @"Canvas Speed Check" #define kSpeedCheckMenuItem_KeyEquivalent @" " #define kSpeedCheckMenuItem_KeyEquivalentModifierMask \ (NSCommandKeyMask | NSShiftKeyMask | NSControlKeyMask) #define kNumSpeedCheckDragMovements 100 @interface PPApplication (PPOptional_CanvasSpeedCheck) - (void) ppMenuItemSelected_CanvasSpeedCheck: (id) sender; @end @implementation NSObject (PPOptional_CanvasSpeedCheck) + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppOptional_CanvasSpeedCheck_SetupMenuItem); } + (void) ppOptional_CanvasSpeedCheck_SetupMenuItem { NSMenu *canvasMenu; NSMenuItem *speedCheckItem; // use PPSDKNativeType_NSMenuItemPtr for separatorItem, as -[NSMenu separatorItem] // could return either (NSMenuItem *) or (id ), depending on the SDK PPSDKNativeType_NSMenuItemPtr separatorItem; canvasMenu = [[[NSApp mainMenu] itemWithTitle: @"Canvas"] submenu]; speedCheckItem = [[[NSMenuItem alloc] initWithTitle: kSpeedCheckMenuItem_Name action: @selector(ppMenuItemSelected_CanvasSpeedCheck:) keyEquivalent: kSpeedCheckMenuItem_KeyEquivalent] autorelease]; [speedCheckItem setTarget: NSApp]; [speedCheckItem setKeyEquivalentModifierMask: kSpeedCheckMenuItem_KeyEquivalentModifierMask]; separatorItem = [NSMenuItem separatorItem]; if (!canvasMenu || !speedCheckItem || !separatorItem) { goto ERROR; } [canvasMenu addItem: separatorItem]; [canvasMenu addItem: speedCheckItem]; return; ERROR: return; } @end @implementation PPApplication (PPOptional_CanvasSpeedCheck) - (void) ppMenuItemSelected_CanvasSpeedCheck: (id) sender { NSAutoreleasePool *autoreleasePool; PPDocumentWindowController *documentWindowController; PPDocument *ppDocument; PPCanvasView *canvasView; PPTool *lineTool; NSPoint point1, point2; NSTimeInterval totalTime; NSDate *startDate; int dragLoopCount = 0; NSRect drawRect; autoreleasePool = [[NSAutoreleasePool alloc] init]; documentWindowController = [[NSApp mainWindow] windowController]; if (![documentWindowController isKindOfClass: [PPDocumentWindowController class]]) { return; } ppDocument = [documentWindowController document]; canvasView = [documentWindowController canvasView]; lineTool = [[PPToolbox sharedToolbox] toolOfType: kPPToolType_Line]; // Line tool - corner to corner point1 = NSZeroPoint; point2 = NSMakePoint([ppDocument canvasSize].width - 1.0, [ppDocument canvasSize].height - 1.0); [canvasView setIsDraggingTool: YES]; [lineTool mouseDownForDocument: ppDocument withCanvasView: canvasView currentPoint: point1 modifierKeyFlags: 0]; startDate = [[NSDate date] retain]; totalTime = 0; dragLoopCount = kNumSpeedCheckDragMovements; while (dragLoopCount--) { [autoreleasePool release]; autoreleasePool = [[NSAutoreleasePool alloc] init]; totalTime -= [NSDate timeIntervalSinceReferenceDate]; [lineTool mouseDraggedOrModifierKeysChangedForDocument: ppDocument withCanvasView: canvasView currentPoint: point2 lastPoint: point1 mouseDownPoint: point1 modifierKeyFlags: 0]; [canvasView displayIfNeeded]; [lineTool mouseDraggedOrModifierKeysChangedForDocument: ppDocument withCanvasView: canvasView currentPoint: point1 lastPoint: point2 mouseDownPoint: point1 modifierKeyFlags: 0]; [canvasView displayIfNeeded]; totalTime += [NSDate timeIntervalSinceReferenceDate]; } [lineTool mouseUpForDocument: ppDocument withCanvasView: canvasView currentPoint: point1 mouseDownPoint: point1 modifierKeyFlags: 0]; [canvasView setIsDraggingTool: NO]; NSLog(@"Speed check: LINE TOOL, CORNERS - time elapsed: %f (%f)", (float) totalTime, (float) -[startDate timeIntervalSinceNow]); // Line tool - small draw drawRect = PPGeometry_CenterRectInRect(PPGeometry_OriginRectOfSize(NSMakeSize(8,8)), PPGeometry_OriginRectOfSize([ppDocument canvasSize])); point1 = drawRect.origin; point2 = NSMakePoint(point1.x + drawRect.size.width - 1, point1.y + drawRect.size.height - 1); [canvasView setIsDraggingTool: YES]; [lineTool mouseDownForDocument: ppDocument withCanvasView: canvasView currentPoint: point1 modifierKeyFlags: 0]; [startDate release]; startDate = [[NSDate date] retain]; totalTime = 0; dragLoopCount = kNumSpeedCheckDragMovements; while (dragLoopCount--) { [autoreleasePool release]; autoreleasePool = [[NSAutoreleasePool alloc] init]; totalTime -= [NSDate timeIntervalSinceReferenceDate]; [lineTool mouseDraggedOrModifierKeysChangedForDocument: ppDocument withCanvasView: canvasView currentPoint: point2 lastPoint: point1 mouseDownPoint: point1 modifierKeyFlags: 0]; [canvasView displayIfNeeded]; [lineTool mouseDraggedOrModifierKeysChangedForDocument: ppDocument withCanvasView: canvasView currentPoint: point1 lastPoint: point2 mouseDownPoint: point1 modifierKeyFlags: 0]; [canvasView displayIfNeeded]; totalTime += [NSDate timeIntervalSinceReferenceDate]; } [lineTool mouseUpForDocument: ppDocument withCanvasView: canvasView currentPoint: point1 mouseDownPoint: point1 modifierKeyFlags: 0]; [canvasView setIsDraggingTool: NO]; NSLog(@"Speed check: LINE TOOL, SMALL DRAW - time elapsed: %f (%f)", (float) totalTime, (float) -[startDate timeIntervalSinceNow]); // Zooming [startDate release]; startDate = [[NSDate date] retain]; totalTime = 0; int initialZoomFactor = [canvasView zoomFactor], zoomCounter; for (zoomCounter=1; zoomCounter<=kMaxCanvasZoomFactor; zoomCounter++) { [autoreleasePool release]; autoreleasePool = [[NSAutoreleasePool alloc] init]; totalTime -= [NSDate timeIntervalSinceReferenceDate]; [canvasView setZoomFactor: zoomCounter]; [canvasView displayIfNeeded]; totalTime += [NSDate timeIntervalSinceReferenceDate]; } [canvasView setZoomFactor: initialZoomFactor]; NSLog(@"Speed check: ZOOMING - time elapsed: %f (%f)", (float) totalTime, (float) -[startDate timeIntervalSinceNow]); // Redrawing background [startDate release]; startDate = [[NSDate date] retain]; totalTime = 0; dragLoopCount = kNumSpeedCheckDragMovements; while (dragLoopCount--) { [autoreleasePool release]; autoreleasePool = [[NSAutoreleasePool alloc] init]; totalTime -= [NSDate timeIntervalSinceReferenceDate]; [canvasView performSelector: @selector(updateVisibleBackground)]; [canvasView displayIfNeeded]; totalTime += [NSDate timeIntervalSinceReferenceDate]; } [canvasView setZoomFactor: initialZoomFactor]; NSLog(@"Speed check: REDRAW BACKGROUND - time elapsed: %f (%f)", (float) totalTime, (float) -[startDate timeIntervalSinceNow]); [startDate release]; } @end #endif // PP_OPTIONAL__BUILD_WITH_CANVAS_SPEED_CHECK PikoPixel.Sources.1.0-b10b/PikoPixel/PPOptional_Screencasting.m0000644000076500000240000001142213234403207023226 0ustar joshstaff/* PPOptional_Screencasting.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPOptional.h" #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING #import "PPAppBootUtilities.h" #import "PPScreencastController.h" #import "NSObject_PPUtilities.h" #import "PPApplication.h" #define kScreencastingMenuItemTitle @"Enable Screencast Popup Panel" static bool gScreencastingIsEnabled = NO; static PPScreencastController *gScreencastController = nil; @interface PPApplication (PPOptional_Screencasting) - (void) ppMenuItemSelected_EnableScreencasting: (id) sender; - (void) ppScreencasting_InstallPatches: (bool) installPatches; @end @implementation NSObject (PPOptional_Screencasting) + (void) load { macroPerformNSObjectSelectorAfterAppLoads(ppOptional_Screencasting_SetupMenuItem); } + (void) ppOptional_Screencasting_SetupMenuItem { NSMenu *panelMenu; NSMenuItem *screencastingItem; // use PPSDKNativeType_NSMenuItemPtr for separatorItem, as -[NSMenu separatorItem] // could return either (NSMenuItem *) or (id ), depending on the SDK PPSDKNativeType_NSMenuItemPtr separatorItem; if (!PP_RUNTIME_CHECK_OPTIONAL__RUNTIME_SUPPORTS_SCREENCASTING) { return; } panelMenu = [[[NSApp mainMenu] itemWithTitle: @"Panel"] submenu]; screencastingItem = [[[NSMenuItem alloc] initWithTitle: kScreencastingMenuItemTitle action: @selector(ppMenuItemSelected_EnableScreencasting:) keyEquivalent: @""] autorelease]; [screencastingItem setTarget: NSApp]; separatorItem = [NSMenuItem separatorItem]; if (!panelMenu || !screencastingItem || !separatorItem) { goto ERROR; } [panelMenu addItem: separatorItem]; [panelMenu addItem: screencastingItem]; return; ERROR: return; } @end @implementation PPApplication (PPOptional_Screencasting) - (void) ppMenuItemSelected_EnableScreencasting: (id) sender { // setup screencast controller if (!gScreencastController) { gScreencastController = [[PPScreencastController sharedController] retain]; if (!gScreencastController) goto ERROR; } // toggle screencasting gScreencastingIsEnabled = (gScreencastingIsEnabled) ? NO : YES; [self ppScreencasting_InstallPatches: gScreencastingIsEnabled]; [gScreencastController setEnabled: gScreencastingIsEnabled]; // update menu item state if ([sender isKindOfClass: [NSMenuItem class]]) { [((NSMenuItem *) sender) setState: (gScreencastingIsEnabled) ? NSOnState : NSOffState]; } return; ERROR: return; } - (void) ppScreencasting_InstallPatches: (bool) installPatches { static bool screencastPatchesAreInstalled = NO; installPatches = (installPatches) ? YES : NO; if ((screencastPatchesAreInstalled != installPatches) && macroSwizzleInstanceMethod( PPApplication, nextEventMatchingMask:untilDate:inMode:dequeue:, ppPatch_SCasting_NextEventMatchingMask:untilDate:inMode:dequeue:)) { screencastPatchesAreInstalled = installPatches; } } - (NSEvent *) ppPatch_SCasting_NextEventMatchingMask: (NSUInteger) mask untilDate: (NSDate *) expiration inMode: (NSString *) mode dequeue: (BOOL) dequeue { NSEvent *event = [self ppPatch_SCasting_NextEventMatchingMask: mask untilDate: expiration inMode: mode dequeue: dequeue]; if (gScreencastingIsEnabled && event && dequeue && (NSEventMaskFromType([event type]) & kScreencastEventsMask)) { [gScreencastController handleEvent: event]; } return event; } @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING PikoPixel.Sources.1.0-b10b/PikoPixel/PPOSXGlue_KeyUpDuringControlTracking.m0000644000076500000240000001303113234403207025367 0ustar joshstaff/* PPOSXGlue_KeyUpDuringControlTracking.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // On Sierra 10.12+ & Yosemite 10.10-10.10.2, keyboard events are intercepted by the system // while a control is tracking the mouse; If a key's held down before the user clicks on a // control, and the key's released while the mouse button is still down, the application won't // receive a keyUp event. // This can cause popup panels to remain visible after the user has released the popup's // hotkey, and can also cause the screencast popup to continue displaying a key that's no // longer pressed. // The workaround is to catch when mouse tracking begins, and manually post a delayed // notification (NSMenuDidEndTrackingNotification) that's received as soon as tracking // finishes - this allows classes that depend on the current keyboard state // (PPDocumentWindowController, PPScreencastController) to know to recheck the keyboard. // Patching -[NSActionCell startTrackingAt:inView:] catches mouse tracking for most controls, // however there's a few that don't call through to that method, requiring separate patches: // NSSliderCell, NSSegmentedControl, NSToolbarItemViewer. #ifdef __APPLE__ #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPLayerEnabledButtonCell.h" #import "PPLayerOpacitySliderCell.h" #define PP_RUNTIME_CHECK__RUNTIME_INTERCEPTS_KEYBOARD_EVENTS_WHEN_TRACKING_CONTROLS \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(12) \ || (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(10) \ && _PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_EARLIER_THAN_10_(10_3))) @interface NSNotificationCenter (PPOSXGlue_KeyUpDuringControlTrackingUtilities) + (void) ppOSXGlue_PostNotification_ControlDidEndTracking; + (void) ppOSXGlue_PostNotificationFromNewStackFrame_ControlDidEndTracking; @end @implementation NSObject (PPOSXGlue_KeyUpDuringControlTracking) + (void) ppOSXGlue_KeyUpDuringControlTracking_InstallPatches { // NSSliderCell doesn't call through to its superclass' implementation of // -[NSActionCell startTrackingAt:inView:], so need to patch NSSliderCell's implementation // directly in order to catch mouse tracking in sliders; Install NSSliderCell's patch // before installing its parent's patch, otherwise NSSliderCell will inherit a method table // where the patch method's implementation pointer points to the original implementation of // -[NSActionCell startTrackingAt:inView:]. macroSwizzleInstanceMethod(NSSliderCell, startTrackingAt:inView:, ppOSXPatch_StartTrackingAt:inView:); macroSwizzleInstanceMethod(NSActionCell, startTrackingAt:inView:, ppOSXPatch_StartTrackingAt:inView:); // NSSegmentedControl & NSToolbarItemViewer (a private class on OS X that handles mouse // interaction on NSToolbars) apparently don't use NSActionCells, so in order to catch when // the mouse tracks on them, patch their implementations of -[NSView mouseDown:]. macroSwizzleInstanceMethod(NSSegmentedControl, mouseDown:, ppOSXPatch_MouseDown:); macroSwizzleInstanceMethod(NSClassFromString(@"NSToolbarItemViewer"), mouseDown:, ppOSXPatch_MouseDown:); } + (void) load { if (PP_RUNTIME_CHECK__RUNTIME_INTERCEPTS_KEYBOARD_EVENTS_WHEN_TRACKING_CONTROLS) { macroPerformNSObjectSelectorAfterAppLoads( ppOSXGlue_KeyUpDuringControlTracking_InstallPatches); } } @end @implementation NSActionCell (PPOSXGlue_KeyUpDuringControlTracking) - (BOOL) ppOSXPatch_StartTrackingAt: (NSPoint) startPoint inView: (NSView *) controlView { [NSNotificationCenter ppOSXGlue_PostNotificationFromNewStackFrame_ControlDidEndTracking]; return [self ppOSXPatch_StartTrackingAt: startPoint inView: controlView]; } @end @implementation NSView (PPOSXGlue_KeyUpDuringControlTracking) - (void) ppOSXPatch_MouseDown: (NSEvent *) theEvent { [self ppOSXPatch_MouseDown: theEvent]; [NSNotificationCenter ppOSXGlue_PostNotificationFromNewStackFrame_ControlDidEndTracking]; } @end @implementation NSNotificationCenter (PPOSXGlue_KeyUpDuringControlTrackingUtilities) + (void) ppOSXGlue_PostNotification_ControlDidEndTracking { [[self defaultCenter] postNotificationName: NSMenuDidEndTrackingNotification object: nil]; } + (void) ppOSXGlue_PostNotificationFromNewStackFrame_ControlDidEndTracking { [self ppPerformSelectorFromNewStackFrame: @selector(ppOSXGlue_PostNotification_ControlDidEndTracking)]; } @end #endif // __APPLE__ PikoPixel.Sources.1.0-b10b/PikoPixel/PPOSXGlue_NavigatorSliderVisibility.m0000644000076500000240000001131613736744022025320 0ustar joshstaff/* PPOSXGlue_NavigatorSliderVisibility.m Copyright 2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // On OS X 10.10 Yosemite & later, the Navigator popup panel's zoom slider's bar doesn't appear. // This happens because the slider's bar is drawn with a dark, partially-transparent color that // won't show up over dark backgrounds. // Workaround is to manually insert a brightly-colored (white) view behind the slider bar, so // the transparent bar will appear lighter than the surrounding dark background. #ifdef __APPLE__ #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPNavigatorPopupPanelController.h" #import "PPSRGBUtilities.h" #define PP_SDK_HAS_NSSLIDERCELL_BARRECTFLIPPED_METHOD \ (_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(9)) #define PP_RUNTIME_CHECK__RUNTIME_HAS_TRANSPARENT_SLIDER_BARS \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(10)) #define PP_RUNTIME_CHECK__NSSLIDERCELL_BARRECTFLIPPED_HAS_OFFBYONE_BUG \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(12) \ && _PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_EARLIER_THAN_10_(14)) #define kBrightBackgroundViewColor \ [NSColor ppSRGBColorWithWhite: 1.0 alpha: 1.0] @interface NSSlider (PPOSXGlue_NavigatorSliderVisibilityUtilities) - (void) ppOSXGlue_AddBrightBackgroundViewUnderSliderBar; @end #if !PP_SDK_HAS_NSSLIDERCELL_BARRECTFLIPPED_METHOD @interface NSSliderCell (BarRectFlippedMethodForLegacySDKs) - (NSRect) barRectFlipped: (BOOL) flipped; @end #endif // !PP_SDK_HAS_NSSLIDERCELL_BARRECTFLIPPED_METHOD @implementation NSObject (PPOSXGlue_NavigatorSliderVisibility) + (void) ppOSXGlue_NavigatorSliderVisibility_InstallPatches { macroSwizzleInstanceMethod(PPNavigatorPopupPanelController, windowDidLoad, ppOSXPatch_WindowDidLoad); } + (void) load { if (PP_RUNTIME_CHECK__RUNTIME_HAS_TRANSPARENT_SLIDER_BARS) { macroPerformNSObjectSelectorAfterAppLoads( ppOSXGlue_NavigatorSliderVisibility_InstallPatches); } } @end @implementation PPNavigatorPopupPanelController (PPOSXGlue_NavigatorSliderVisibility) - (void) ppOSXPatch_WindowDidLoad { [self ppOSXPatch_WindowDidLoad]; [_zoomSlider ppOSXGlue_AddBrightBackgroundViewUnderSliderBar]; } @end @implementation NSSlider (PPOSXGlue_NavigatorSliderVisibilityUtilities) - (void) ppOSXGlue_AddBrightBackgroundViewUnderSliderBar { NSView *superView; NSRect sliderBarBounds, backgroundViewFrame; NSTextField *backgroundView; BOOL isFlipped; superView = [self superview]; if (!superView) goto ERROR; isFlipped = [self isFlipped]; sliderBarBounds = [[self cell] barRectFlipped: isFlipped]; if (NSIsEmptyRect(sliderBarBounds)) { goto ERROR; } if (PP_RUNTIME_CHECK__NSSLIDERCELL_BARRECTFLIPPED_HAS_OFFBYONE_BUG) { // On 10.12 & 10.13, barRectFlipped: returns a rect with an origin.y that's too high // (off by a pixel) sliderBarBounds.origin.y += (isFlipped) ? 1 : -1; } if (sliderBarBounds.size.height > 2) { sliderBarBounds = NSInsetRect(sliderBarBounds, 1, 1); } backgroundViewFrame = [self convertRect: sliderBarBounds toView: superView]; backgroundView = [[[NSTextField alloc] initWithFrame: backgroundViewFrame] autorelease]; if (!backgroundView) goto ERROR; [backgroundView setBordered: NO]; [backgroundView setEditable: NO]; [backgroundView setDrawsBackground: YES]; [backgroundView setBackgroundColor: kBrightBackgroundViewColor]; [superView addSubview: backgroundView positioned: NSWindowBelow relativeTo: self]; return; ERROR: return; } @end #endif // __APPLE__ PikoPixel.Sources.1.0-b10b/PikoPixel/PPOSXGlue_PatternPhaseGlitches.m0000644000076500000240000000570213234403207024224 0ustar joshstaff/* PPOSXGlue_PatternPhaseGlitches.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // On OS X 10.5 Leopard, an NSView area drawn by filling with a pattern-color can be // out-of-phase with an adjacent area already filled with the same pattern-color, giving the // appearance of video glitches where the different areas touch - the out-of-phase issue seems // to depend on the fill-rect's origin's x-coordinate (different areas whose fill-rect's left // edges are the same will have the patterns line up correctly). // Currently this issue only affects PPPreviewView, as it's the only view that uses // pattern-colors for partial redraws - everywhere else, pattern-colors are only used to fill // the entire context (no adjacent areas remain visible). // Workaround is to set the drawing context's pattern phase to a 'safe' value - somehow, // manually setting the pattern phase to a point with an x-value of 4n+1 (1,5,9...) seems to // resolve the issue (?). // The issue no longer appears as of 10.6. #ifdef __APPLE__ #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPPreviewView.h" #define PP_RUNTIME_CHECK__RUNTIME_HAS_PATTERN_PHASE_GLITCH_ISSUE \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(5) \ && _PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_EARLIER_THAN_10_(6)) @implementation NSObject (PPOSXGlue_PatternPhaseGlitches) + (void) ppOSXGlue_PatternPhaseGlitches_InstallPatches { macroSwizzleInstanceMethod(PPPreviewView, drawRect:, ppOSXPatch_DrawRect:); } + (void) load { if (PP_RUNTIME_CHECK__RUNTIME_HAS_PATTERN_PHASE_GLITCH_ISSUE) { macroPerformNSObjectSelectorAfterAppLoads(ppOSXGlue_PatternPhaseGlitches_InstallPatches); } } @end @implementation PPPreviewView (PPOSXGlue_PatternPhaseGlitches) - (void) ppOSXPatch_DrawRect: (NSRect) rect { static NSPoint unglitchedPatternPhase = {5.0f, 0.0f}; [[NSGraphicsContext currentContext] setPatternPhase: unglitchedPatternPhase]; [self ppOSXPatch_DrawRect: rect]; } @end #endif // __APPLE__ PikoPixel.Sources.1.0-b10b/PikoPixel/PPOSXGlue_PreserveDrawColorDuringAboutPanel.m0000644000076500000240000000567713234403207026712 0ustar joshstaff/* PPOSXGlue_PreserveDrawColorDuringAboutPanel.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // On OS X 10.5 Leopard & later, opening the About Panel or clicking on its text will change // the shared Color Panel's color to light blue - this affects any active color wells, so if the // shared Color Panel is visible in order to select a document's draw color, showing or clicking // the About Panel will cause the document's draw color to be set to light blue. // This happens because the About Panel's text views are set to use the Font Panel (even though // they're not editable), so any interactions with the views will automatically update the Font // Panel's settings, which includes updating the Color Panel with the Font Panel's current color. // Workaround prevents NSTextView instances from using the Font Panel by patching // -[NSTextView usesFontPanel] to always return NO. Note that this disables the Font Panel for // ALL text views, not just the About Panel's (figuring out which text views belong to the // system's About Panel would be a more complicated workaround), however, this doesn't appear to // cause any issues, since no current text view in PikoPixel needs to use the Font Panel. #ifdef __APPLE__ #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #define PP_RUNTIME_CHECK__ABOUT_PANEL_CAN_CAUSE_DRAW_COLOR_CHANGE \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(5)) @implementation NSObject (PPOSXGlue_PreserveDrawColorDuringAboutPanel) + (void) ppOSXGlue_PreserveDrawColorDuringAboutPanel_InstallPatches { macroSwizzleInstanceMethod(NSTextView, usesFontPanel, ppOSXPatch_UsesFontPanel); } + (void) load { if (PP_RUNTIME_CHECK__ABOUT_PANEL_CAN_CAUSE_DRAW_COLOR_CHANGE) { macroPerformNSObjectSelectorAfterAppLoads( ppOSXGlue_PreserveDrawColorDuringAboutPanel_InstallPatches); } } @end @implementation NSTextView (PPOSXGlue_PreserveDrawColorDuringAboutPanel) - (BOOL) ppOSXPatch_UsesFontPanel { return NO; } @end #endif // __APPLE__ PikoPixel.Sources.1.0-b10b/PikoPixel/PPOSXGlue_RetinaDrawingArtifacts.m0000644000076500000240000000743113234403207024543 0ustar joshstaff/* PPOSXGlue_RetinaDrawingArtifacts.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // On OS X retina displays, partial draws of NSViews (updating areas that don't cover the // entire view) can cause the pixel values on the edges of the updated area to bleed into // surrounding pixels outside the drawn area (antialiasing or roundoff-error when automatically // scaling from standard coordinates to retina coordinates?). This leaves drawing artifacts // behind: very thin lines (single retina-pixel width). // Workaround is to patch affected views' setNeedsDisplayInRect: methods, and pass the // original methods a dirty rect that's slightly larger than the one passed in - increased by a // standard-coordinate pixel-width along each side - so that the updated area has a margin of // pixel-values at the borders that are the same color as before the update. This causes the // line artifacts to disappear because the bleed from the 'new' pixel values will match the // (unchanged) colors already there. #if defined(__APPLE__) && (PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY) #import #import "NSObject_PPUtilities.h" #import "PPAppBootUtilities.h" #import "PPOSXGlueUtilities.h" #import "PPCanvasView.h" #import "PPPreviewView.h" @implementation NSObject (PPOSXGlue_RetinaDrawingArtifacts) + (void) ppOSXGlue_RetinaDrawingArtifacts_InstallPatches { macroSwizzleInstanceMethod(PPCanvasView, setNeedsDisplayInRect:, ppOSXPatch_SetNeedsDisplayInRect:); macroSwizzleInstanceMethod(PPPreviewView, setNeedsDisplayInRect:, ppOSXPatch_SetNeedsDisplayInRect:); } + (void) ppOSXGlue_RetinaDrawingArtifacts_Install { PPOSXGlueUtils_PerformNSObjectSelectorOnceWhenAnyDisplayIsRetina( @selector(ppOSXGlue_RetinaDrawingArtifacts_InstallPatches)); } + (void) load { if (PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_RETINA_DISPLAY) { macroPerformNSObjectSelectorAfterAppLoads(ppOSXGlue_RetinaDrawingArtifacts_Install); } } @end @implementation PPCanvasView (PPOSXGlue_RetinaDrawingArtifacts) - (void) ppOSXPatch_SetNeedsDisplayInRect: (NSRect) invalidRect { [self ppOSXPatch_SetNeedsDisplayInRect: NSInsetRect(invalidRect, -1.0f, -1.0f)]; } @end @implementation PPPreviewView (PPOSXGlue_RetinaDrawingArtifacts) - (void) ppOSXPatch_SetNeedsDisplayInRect: (NSRect) invalidRect { // only need to expand invalidRect within the bounds of _scaleImageBounds; area outside // _scaledImageBounds is always filled with the same color, so no drawing-artifacts there invalidRect = NSUnionRect(invalidRect, NSIntersectionRect(_scaledImageBounds, NSInsetRect(invalidRect, -1.0f, -1.0f))); [self ppOSXPatch_SetNeedsDisplayInRect: invalidRect]; } @end #endif // defined(__APPLE__) && (PP_DEPLOYMENT_TARGET_SUPPORTS_RETINA_DISPLAY) PikoPixel.Sources.1.0-b10b/PikoPixel/PPOSXGlueUtilities.h0000644000076500000240000000216013234403417021750 0ustar joshstaff/* PPOSXGlueUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef __APPLE__ #import bool PPOSXGlueUtils_PerformNSObjectSelectorOnceWhenAnyDisplayIsRetina(SEL selector); #endif // __APPLE__ PikoPixel.Sources.1.0-b10b/PikoPixel/PPOSXGlueUtilities.m0000644000076500000240000001472713721403365021774 0ustar joshstaff/* PPOSXGlueUtilities.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifdef __APPLE__ #import "PPOSXGlueUtilities.h" #import "PPObjCUtilities.h" #define kMaxNumStoredSelectors 3 @interface PPOSXGlueUtilsNotificationHandler : NSObject { } @end #if !PP_SDK_HAS_BACKINGSCALEFACTOR_METHODS @interface NSScreen (BackingScaleFactorMethodForLegacySDKs) - (CGFloat) backingScaleFactor; @end #endif static SEL *gStoredSelectors = NULL; static int gNumStoredSelectors = 0; static bool AnyScreenHasRetinaResolution(void); static bool AddSelectorToStoredSelectors(SEL selector); static void PerformAllStoredSelectorsAndClear(void); static bool RegisterForNSAppNotification_DidChangeScreenParameters(bool register); bool PPOSXGlueUtils_PerformNSObjectSelectorOnceWhenAnyDisplayIsRetina(SEL selector) { if (!PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_RETINA_DISPLAY || !selector || ![NSObject respondsToSelector: selector]) { goto ERROR; } if (AnyScreenHasRetinaResolution()) { [NSObject performSelector: selector]; return YES; } else { if (!AddSelectorToStoredSelectors(selector)) { goto ERROR; } RegisterForNSAppNotification_DidChangeScreenParameters(YES); } return YES; ERROR: return NO; } #pragma mark Private functions static bool AnyScreenHasRetinaResolution(void) { static bool needToCheckBackingScaleFactorSelector = YES, backingScaleFactorSelectorIsSupported = NO; NSEnumerator *screenEnumerator; NSScreen *screen; if (needToCheckBackingScaleFactorSelector) { backingScaleFactorSelectorIsSupported = ([NSScreen instancesRespondToSelector: @selector(backingScaleFactor)]) ? YES : NO; needToCheckBackingScaleFactorSelector = NO; } if (!backingScaleFactorSelectorIsSupported) return NO; screenEnumerator = [[NSScreen screens] objectEnumerator]; while (screen = [screenEnumerator nextObject]) { if ([screen backingScaleFactor] > 1.0f) { return YES; } } return NO; } static bool AddSelectorToStoredSelectors(SEL selector) { if (!gStoredSelectors) { gStoredSelectors = (SEL *) malloc (kMaxNumStoredSelectors * sizeof(SEL)); gNumStoredSelectors = 0; if (!gStoredSelectors) { NSLog(@"ERROR: Out of memory in " "PPOSXGlueUtils_PerformNSObjectSelectorOnceWhenAnyDisplayIsRetina()"); goto ERROR; } } if (gNumStoredSelectors >= kMaxNumStoredSelectors) { NSLog(@"ERROR: Selector array is full - unable to store all delayed selector(s) in " "PPOSXGlueUtils_PerformNSObjectSelectorOnceWhenAnyDisplayIsRetina(); Need to " "increase kMaxNumStoredSelectors to more than (%d) in PPOSXGlueUtilities.m", (int) kMaxNumStoredSelectors); goto ERROR; } gStoredSelectors[gNumStoredSelectors++] = selector; return YES; ERROR: return NO; } static void PerformAllStoredSelectorsAndClear(void) { int selectorIndex; if (!gStoredSelectors) return; // sort the stored selectors alphabetically by name so they're always called in the same // order PPObjCUtils_AlphabeticallySortSelectorArray(gStoredSelectors, gNumStoredSelectors); for (selectorIndex=0; selectorIndex. */ #ifdef __APPLE__ # import "PPXCConfigCheck.h" // Disable clang warnings that are now enabled by default on recent Xcode versions # if (defined(__clang__) && _PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(11)) # pragma clang diagnostic ignored "-Wnonnull" # pragma clang diagnostic ignored "-Wshorten-64-to-32" # pragma clang diagnostic ignored "-Wundeclared-selector" # endif #endif // __APPLE__ PikoPixel.Sources.1.0-b10b/PikoPixel/PPOvalTool.h0000644000076500000240000000202113234403417020321 0ustar joshstaff/* PPOvalTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPOvalTool : PPTool { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPOvalTool.m0000644000076500000240000000563513234403207020341 0ustar joshstaff/* PPOvalTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPOvalTool.h" #import "PPDocument.h" #import "PPGeometry.h" #import "NSCursor_PPUtilities.h" #define kOvalToolAttributesMask (0) @implementation PPOvalTool : PPTool - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [ppDocument beginDrawingWithPenMode: kPPPenMode_Fill]; [ppDocument drawPixelAtPoint: currentPoint]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSRect rect; bool shouldFillOval; if (modifierKeyFlags & kModifierKeyMask_LockAspectRatio) { currentPoint = PPGeometry_FarthestPointOnDiagonal(mouseDownPoint, currentPoint); } if (modifierKeyFlags & kModifierKeyMask_CenterShapeAtMouseDown) { rect = PPGeometry_PixelBoundsWithCenterAndCornerPoint(mouseDownPoint, currentPoint); } else { rect = PPGeometry_PixelBoundsWithCornerPoints(mouseDownPoint, currentPoint); } shouldFillOval = (modifierKeyFlags & kModifierKeyMask_FillShape) ? YES : NO; [ppDocument undoCurrentDrawingAtNextDraw]; [ppDocument drawOvalInRect: rect andFill: shouldFillOval]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [ppDocument finishDrawing]; } - (NSCursor *) cursor { return [NSCursor ppOvalToolCursor]; } - (unsigned) toolAttributeFlags { return kOvalToolAttributesMask; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPanelController.h0000644000076500000240000000434713234403417021702 0ustar joshstaff/* PPPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPFramePinningType.h" @class PPDocument; @interface PPPanelController : NSWindowController { PPDocument *_ppDocument; bool _panelDidLoad; bool _allowPanelVisibility; bool _panelIsEnabled; bool _shouldStorePanelStateInUserDefaults; } + controller; // designated initializer; don't use the other initializers inherited from NSWindowController - initWithWindowNibName: (NSString *) windowNibName; + (NSString *) panelNibName; // subclasses must override - (void) setPPDocument: (PPDocument *) ppDocument; - (void) setPanelVisibilityAllowed: (bool) allowPanelVisibility; - (void) setPanelEnabled: (bool) enabledPanel; - (void) togglePanelEnabledState; - (bool) panelIsVisible; - (bool) mouseLocationIsInsideVisiblePanel: (NSPoint) mouseLocation; - (void) addAsObserverForPPDocumentNotifications; - (void) removeAsObserverForPPDocumentNotifications; - (bool) allowPanelToBecomeKey; // Default: NO - (bool) shouldStorePanelStateInUserDefaults; // Default: YES - (bool) defaultPanelEnabledState; // Default: NO - (PPFramePinningType) pinningTypeForDefaultWindowFrame; - (void) setupPanelForCurrentPPDocument; - (void) setupPanelBeforeMakingVisible; - (void) setupPanelAfterVisibilityChange; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPanelController.m0000644000076500000240000003014413721520526021703 0ustar joshstaff/* PPPanelController.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPanelController.h" #import "PPUserDefaults.h" #import "PPDocument.h" #import "NSDocument_PPUtilities.h" #import "NSObject_PPUtilities.h" #import "NSWindow_PPUtilities.h" #import "PPGeometry.h" #import "PPSRGBUtilities.h" #define kScreenBoundsPinningMargin_Left 10.0f #define kScreenBoundsPinningMargin_Right 20.0f #define kScreenBoundsPinningMargin_Top 35.0f #define kScreenBoundsPinningMargin_Bottom 20.0f static NSRect ScreenBoundsForPinningDefaultWindowFrame(void); @interface PPPanelController (PrivateMethods) - (void) updatePanelVisibility; - (void) showPanel; - (void) hidePanel; - (void) hidePanelIfDocumentIsInvalid; - (void) disablePanel; - (void) setupPanelStateFromUserDefaults; - (NSRect) defaultPinnedWindowFrame; @end #if PP_SDK_REQUIRES_PROTOCOLS_FOR_DELEGATES_AND_DATASOURCES @interface PPPanelController (RequiredProtocols) @end #endif @implementation PPPanelController + controller { NSString *panelNibName = [self panelNibName]; if (!panelNibName) { return nil; } return [[[self alloc] initWithWindowNibName: panelNibName] autorelease]; } - (id) initWithWindowNibName: (NSString *) windowNibName { self = [super initWithWindowNibName: windowNibName]; if (!self) goto ERROR; _shouldStorePanelStateInUserDefaults = [self shouldStorePanelStateInUserDefaults]; if (_shouldStorePanelStateInUserDefaults) { [PPUserDefaults registerDefaultEnabledState: [self defaultPanelEnabledState] forPanelWithNibName: windowNibName]; if ([PPUserDefaults enabledStateForPanelWithNibName: windowNibName]) { // user defaults setting wants the panel enabled - requesting the window will // force the controller to load it immediately [self window]; } } return self; ERROR: [self release]; return nil; } - (void) dealloc { [self setPPDocument: nil]; [super dealloc]; } + (NSString *) panelNibName { return nil; } - (void) setPPDocument: (PPDocument *) ppDocument { if (_ppDocument == ppDocument) { return; } if (_ppDocument) { [self removeAsObserverForPPDocumentNotifications]; } [_ppDocument release]; _ppDocument = [ppDocument retain]; if (_ppDocument && _panelDidLoad) { [self addAsObserverForPPDocumentNotifications]; [self setupPanelForCurrentPPDocument]; } else { [self updatePanelVisibility]; } } - (void) setPanelVisibilityAllowed: (bool) allowPanelVisibility { allowPanelVisibility = (allowPanelVisibility) ? YES : NO; if (_allowPanelVisibility != allowPanelVisibility) { _allowPanelVisibility = allowPanelVisibility; if (_allowPanelVisibility) { // setPanelVisibilityAllowed: can be called while switching document windows, // so _ppDocument may not yet point to the new active document - if the panel // becomes visible immediately, it will briefly flicker the old document's state // before updating with the new document, so delay showing the panel until // _ppDocument is definitely valid (next stack frame) [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(updatePanelVisibility)]; } else { [self updatePanelVisibility]; } } } - (void) setPanelEnabled: (bool) enablePanel { enablePanel = (enablePanel) ? YES : NO; if (_panelIsEnabled == enablePanel) { return; } _panelIsEnabled = enablePanel; [self updatePanelVisibility]; if (_shouldStorePanelStateInUserDefaults) { [PPUserDefaults setEnabledState: _panelIsEnabled forPanelWithNibName: [self windowNibName]]; } } - (void) togglePanelEnabledState { [self setPanelEnabled: (_panelIsEnabled) ? NO : YES]; } - (bool) panelIsVisible { if (!_panelDidLoad) { return NO; } return [[self window] isVisible] ? YES : NO; } - (bool) mouseLocationIsInsideVisiblePanel: (NSPoint) mouseLocation { NSWindow *panel; if (!_panelDidLoad || !_ppDocument || !_allowPanelVisibility || !_panelIsEnabled) { return NO; } panel = [self window]; return ([panel isVisible] && NSMouseInRect(mouseLocation, [panel frame], NO)) ? YES : NO; } - (void) addAsObserverForPPDocumentNotifications { } - (void) removeAsObserverForPPDocumentNotifications { } - (bool) allowPanelToBecomeKey { return NO; } - (bool) shouldStorePanelStateInUserDefaults { return YES; } - (bool) defaultPanelEnabledState { return NO; } - (PPFramePinningType) pinningTypeForDefaultWindowFrame { return kPPFramePinningType_Invalid; } - (void) setupPanelForCurrentPPDocument { [self updatePanelVisibility]; } - (void) setupPanelBeforeMakingVisible { } - (void) setupPanelAfterVisibilityChange { } #pragma mark NSWindowController overrides - (void) windowDidLoad { NSPanel *panel; [super windowDidLoad]; panel = (NSPanel *) [self window]; [panel setDelegate: self]; [panel setBecomesKeyOnlyIfNeeded: YES]; [panel ppSetSRGBColorSpace]; [panel ppDisableWindowAnimation]; if (_shouldStorePanelStateInUserDefaults) { [self setupPanelStateFromUserDefaults]; } _panelDidLoad = YES; if (_ppDocument) { [self addAsObserverForPPDocumentNotifications]; [self setupPanelForCurrentPPDocument]; } } #pragma mark NSWindow delegate methods - (void) windowDidBecomeKey: (NSNotification *) notification { if (![self allowPanelToBecomeKey]) { [_ppDocument ppMakeWindowKey]; } } - (BOOL) windowShouldClose: (id) sender { [self ppPerformSelectorFromNewStackFrame: @selector(disablePanel)]; return NO; } #pragma mark Private methods - (void) updatePanelVisibility { bool panelIsVisible, panelShouldBeVisible; panelIsVisible = ([self panelIsVisible]) ? YES : NO; panelShouldBeVisible = (_allowPanelVisibility && _panelIsEnabled && _ppDocument) ? YES : NO; if (panelIsVisible == panelShouldBeVisible) { return; } if (panelShouldBeVisible) { [self showPanel]; } else { if (_ppDocument) { [self hidePanel]; } else { // when _ppDocument is invalid, delay hiding the panel until the next stack // frame - this keeps the panel from flickering off/on when switching to a // different document window (_ppDocument is nil temporarily, but will be valid // by the next frame) [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(hidePanelIfDocumentIsInvalid)]; } } } - (void) showPanel { NSWindow *panel; if ([self panelIsVisible]) { return; } panel = [self window]; // make sure window is loaded before setup [self setupPanelBeforeMakingVisible]; [panel orderFront: self]; [self setupPanelAfterVisibilityChange]; } - (void) hidePanel { if (![self panelIsVisible]) { return; } [[self window] orderOut: self]; [self setupPanelAfterVisibilityChange]; } - (void) hidePanelIfDocumentIsInvalid { if (!_ppDocument) { [self hidePanel]; } } - (void) disablePanel { [self setPanelEnabled: NO]; } - (void) setupPanelStateFromUserDefaults { NSRect defaultWindowFrame; NSString *windowNibName; if (!_shouldStorePanelStateInUserDefaults) return; defaultWindowFrame = [self defaultPinnedWindowFrame]; if (!NSIsEmptyRect(defaultWindowFrame)) { [[self window] setFrame: defaultWindowFrame display: NO]; } windowNibName = [self windowNibName]; [[self window] setFrameAutosaveName: windowNibName]; // Panel won't be visible after nib is loaded (set to remain hidden), so enable if needed if ([PPUserDefaults enabledStateForPanelWithNibName: windowNibName]) { [self setPanelEnabled: YES]; } } - (NSRect) defaultPinnedWindowFrame { NSRect screenBoundsForWindowFrame, windowFrame; PPFramePinningType framePinningType; screenBoundsForWindowFrame = ScreenBoundsForPinningDefaultWindowFrame(); windowFrame = [[self window] frame]; framePinningType = [self pinningTypeForDefaultWindowFrame]; if (!PPFramePinningType_IsValid(framePinningType)) { goto ERROR; } // horizontal pinning switch (framePinningType) { case kPPFramePinningType_TopLeft: case kPPFramePinningType_CenterLeft: case kPPFramePinningType_BottomLeft: { windowFrame.origin.x = screenBoundsForWindowFrame.origin.x; } break; case kPPFramePinningType_TopRight: case kPPFramePinningType_CenterRight: case kPPFramePinningType_BottomRight: { windowFrame.origin.x = screenBoundsForWindowFrame.origin.x + screenBoundsForWindowFrame.size.width - windowFrame.size.width; } break; default: break; } // vertical pinning switch (framePinningType) { case kPPFramePinningType_TopLeft: case kPPFramePinningType_TopRight: { windowFrame.origin.y = screenBoundsForWindowFrame.origin.y + screenBoundsForWindowFrame.size.height - windowFrame.size.height; } break; case kPPFramePinningType_CenterLeft: case kPPFramePinningType_CenterRight: { windowFrame.origin.y = roundf(screenBoundsForWindowFrame.origin.y + (screenBoundsForWindowFrame.size.height - windowFrame.size.height) / 2.0f); } break; case kPPFramePinningType_BottomLeft: case kPPFramePinningType_BottomRight: { windowFrame.origin.y = screenBoundsForWindowFrame.origin.y; } break; default: break; } return windowFrame; ERROR: if (!NSIsEmptyRect(screenBoundsForWindowFrame) && !NSIsEmptyRect(windowFrame)) { windowFrame.origin = PPGeometry_OriginPointForConfiningRectInsideRect(windowFrame, screenBoundsForWindowFrame); } return windowFrame; } @end #pragma mark Private functions static NSRect ScreenBoundsForPinningDefaultWindowFrame(void) { NSRect screenBounds = [[NSScreen mainScreen] visibleFrame]; screenBounds.origin.x += kScreenBoundsPinningMargin_Left; screenBounds.origin.y += kScreenBoundsPinningMargin_Bottom; screenBounds.size.width -= kScreenBoundsPinningMargin_Left + kScreenBoundsPinningMargin_Right; screenBounds.size.height -= kScreenBoundsPinningMargin_Top + kScreenBoundsPinningMargin_Bottom; return PPGeometry_PixelBoundsCoveredByRect(screenBounds); } PikoPixel.Sources.1.0-b10b/PikoPixel/PPPanelDefaultFramePinnings.h0000644000076500000240000000271513234403417023621 0ustar joshstaff/* PPPanelDefaultFramePinnings.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPFramePinningType.h" #define kPPPanelDefaultFramePinning_Tools kPPFramePinningType_TopLeft #define kPPPanelDefaultFramePinning_Layers kPPFramePinningType_BottomLeft #define kPPPanelDefaultFramePinning_Preview kPPFramePinningType_TopRight #define kPPPanelDefaultFramePinning_SamplerImage kPPFramePinningType_CenterRight #define kPPPanelDefaultFramePinning_ToolModifierTips kPPFramePinningType_BottomRight PikoPixel.Sources.1.0-b10b/PikoPixel/PPPanelsController.h0000644000076500000240000000273613234403417022065 0ustar joshstaff/* PPPanelsController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPPanelType.h" @class PPDocument; @interface PPPanelsController : NSObject { NSArray *_panelControllers; bool _toggledActivePanels[kNumPPPanelTypes]; bool _panelsVisibilityAllowed; } + sharedController; - (void) setPPDocument: (PPDocument *) document; - (void) toggleEnabledStateForPanelOfType: (PPPanelType) panelType; - (bool) panelOfTypeIsVisible: (PPPanelType) panelType; - (void) toggleEnabledStateForActivePanels; - (bool) mouseIsInsideVisiblePanel; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPanelsController.m0000644000076500000240000002465013234403207022066 0ustar joshstaff/* PPPanelsController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPanelsController.h" #import "PPToolsPanelController.h" #import "PPLayersPanelController.h" #import "PPPreviewPanelController.h" #import "PPSamplerImagePanelController.h" #import "PPToolModifierTipsPanelController.h" #import "NSObject_PPUtilities.h" #import "PPDocumentWindow.h" static NSArray *PanelControllersArray(void); @interface PPPanelsController (PrivateMethods) - (void) addAsObserverForNSWindowNotifications; - (void) removeAsObserverForNSWindowNotifications; - (void) handleNSWindowNotification_DidBecomeKey: (NSNotification *) notification; - (void) handleNSWindowNotification_DidBecomeMain: (NSNotification *) notification; - (void) handleNSWindowNotification_DidResignMain: (NSNotification *) notification; - (void) handleNSWindowNotification_WillBeginSheet: (NSNotification *) notification; - (void) handleNSWindowNotification_DidEndSheet: (NSNotification *) notification; - (void) resetToggledActivePanels; - (void) setPanelsVisibilityAllowed: (bool) panelsVisibilityAllowed; - (void) updatePanelsVisibilityAllowedForWindow: (NSWindow *) window; - (void) updatePanelsVisibilityAllowed; @end @implementation PPPanelsController + sharedController { static PPPanelsController *sharedController = nil; if (!sharedController) { sharedController = [[self alloc] init]; } return sharedController; } - init { self = [super init]; if (!self) goto ERROR; _panelControllers = [PanelControllersArray() retain]; if (!_panelControllers) goto ERROR; [self addAsObserverForNSWindowNotifications]; return self; ERROR: [self release]; return nil; } - (void) dealloc { [self removeAsObserverForNSWindowNotifications]; [_panelControllers release]; [super dealloc]; } - (void) setPPDocument: (PPDocument *) ppDocument { [_panelControllers makeObjectsPerformSelector: @selector(setPPDocument:) withObject: ppDocument]; } - (void) toggleEnabledStateForPanelOfType: (PPPanelType) panelType; { PPPanelController *panelController; if (!PPPanelType_IsValid(panelType)) { return; } panelController = (PPPanelController *) [_panelControllers objectAtIndex: panelType]; [panelController togglePanelEnabledState]; } - (bool) panelOfTypeIsVisible: (PPPanelType) panelType { PPPanelController *panelController; if (!PPPanelType_IsValid(panelType)) { return NO; } panelController = (PPPanelController *) [_panelControllers objectAtIndex: panelType]; return [panelController panelIsVisible]; } - (void) toggleEnabledStateForActivePanels { int i; PPPanelController *panelController; bool didTogglePanels = NO; for (i=0; i. */ typedef enum { kPPPanelType_Tools, kPPPanelType_Layers, kPPPanelType_Preview, kPPPanelType_SamplerImage, kPPPanelType_ToolModifierTips, // add new PPPanelType values above this line kNumPPPanelTypes } PPPanelType; static inline bool PPPanelType_IsValid(PPPanelType panelType) { return (((unsigned) panelType) < kNumPPPanelTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPParabolicSlider.h0000644000076500000240000000216113234403417021626 0ustar joshstaff/* PPParabolicSlider.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPParabolicSlider : NSSlider { double _ppMinValue; double _ppMaxValue; double _ppValueRange; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPParabolicSlider.m0000644000076500000240000000601713234403207021634 0ustar joshstaff/* PPParabolicSlider.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPParabolicSlider.h" @interface PPParabolicSlider (PrivateMethods) - (void) setupParabolicSlider; @end @implementation PPParabolicSlider #pragma mark NSSlider overrides - (id) initWithFrame: (NSRect) frameRect { self = [super initWithFrame: frameRect]; if (!self) goto ERROR; [self setupParabolicSlider]; return self; ERROR: [self release]; return nil; } - (void) awakeFromNib { // check before calling [super awakeFromNib] - before 10.6, some classes didn't implement it if ([[PPParabolicSlider superclass] instancesRespondToSelector: @selector(awakeFromNib)]) { [super awakeFromNib]; } [self setupParabolicSlider]; } - (double) minValue { return _ppMinValue; } - (void) setMinValue: (double) aDouble { _ppMinValue = aDouble; _ppValueRange = _ppMaxValue - _ppMinValue; } - (double) maxValue { return _ppMaxValue; } - (void) setMaxValue: (double) aDouble { _ppMaxValue = aDouble; _ppValueRange = _ppMaxValue - _ppMinValue; } - (int) intValue { return (int) round([self doubleValue]); } - (void) setIntValue: (int) anInt { [self setDoubleValue: (double) anInt]; } - (float) floatValue { return (float) [self doubleValue]; } - (void) setFloatValue: (float) aFloat { [self setDoubleValue: (double) aFloat]; } - (double) doubleValue { double sliderPosition = [super doubleValue]; return _ppMinValue + _ppValueRange * sliderPosition * sliderPosition; } - (void) setDoubleValue: (double) aDouble { double sliderPosition = 0.0; if ((aDouble > _ppMinValue) && (_ppValueRange != 0)) { sliderPosition = sqrt((aDouble - _ppMinValue) / _ppValueRange); } [super setDoubleValue: sliderPosition]; } #pragma mark Private methods - (void) setupParabolicSlider { double sliderPosition = [super doubleValue]; _ppMinValue = [super minValue]; _ppMaxValue = [super maxValue]; _ppValueRange = _ppMaxValue - _ppMinValue; [super setMinValue: 0.0]; [super setMaxValue: 1.0]; [self setDoubleValue: sliderPosition]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPatternPresets.h0000644000076500000240000000331213234403417021551 0ustar joshstaff/* PPPatternPresets.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPPatternPresets : NSObject { Class _patternClass; NSArray *_patterns; NSArray *_presetsFiletypes; NSString *_storedPresetsFilepath; } + sharedPresets; // must be overridden by subclasses - base implementation returns nil - initWithPresettablePatternClass: (Class) patternClass storedPresetsFilename: (NSString *) storedPresetsFilename presetsFiletype: (NSString *) presetsFiletype; - (NSArray *) patterns; - (void) setPatterns: (NSArray *) patterns; - (bool) savePatternsToPresetsFile: (NSString *) filepath; - (void) addPatternsFromPresetsFile: (NSString *) filepath; - (NSArray *) presetsFiletypes; @end extern NSString *PPPatternPresetsNotification_UpdatedPresets; PikoPixel.Sources.1.0-b10b/PikoPixel/PPPatternPresets.m0000644000076500000240000002170713234403207021563 0ustar joshstaff/* PPPatternPresets.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPatternPresets.h" #import "PPPresettablePatternProtocol.h" #import "NSFileManager_PPUtilities.h" #define kPatternPresetsDictKey_Patterns @"Patterns" NSString *PPPatternPresetsNotification_UpdatedPresets = @"PPPatternPresetsNotification_UpdatedPresets"; static NSString *StoredPresetsFilepathForFilenameAndFiletype(NSString *storedPresetsFilename, NSString *presetsFiletype); @interface PPPatternPresets (PrivateMethods) - (NSArray *) verifiedPatternsFromArray: (NSArray *) importedArray; - (bool) savePatterns: (NSArray *) patterns toFile: (NSString *) filepath; - (NSArray *) patternsFromFile: (NSString *) filepath; - (void) loadPatternsFromStoredPresets; - (void) savePatternsToStoredPresets; - (void) postNotification_UpdatedPresets; @end @implementation PPPatternPresets + sharedPresets { // must be overridden by subclasses - base implementation returns nil return nil; } - initWithPresettablePatternClass: (Class) patternClass storedPresetsFilename: (NSString *) storedPresetsFilename presetsFiletype: (NSString *) presetsFiletype { NSArray *presetsFiletypes; NSString *storedPresetsFilepath; self = [super init]; if (!self) goto ERROR; if (![patternClass conformsToProtocol: @protocol(PPPresettablePattern)] || ![storedPresetsFilename length] || ![presetsFiletype length]) { goto ERROR; } presetsFiletypes = [NSArray arrayWithObject: presetsFiletype]; storedPresetsFilepath = StoredPresetsFilepathForFilenameAndFiletype(storedPresetsFilename, presetsFiletype); if (![presetsFiletypes count] || ![storedPresetsFilepath length]) { goto ERROR; } _patternClass = [patternClass retain]; _presetsFiletypes = [presetsFiletypes retain]; _storedPresetsFilepath = [storedPresetsFilepath retain]; [self loadPatternsFromStoredPresets]; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_patternClass release]; [_patterns release]; [_presetsFiletypes release]; [_storedPresetsFilepath release]; [super dealloc]; } - (NSArray *) patterns { return _patterns; } - (void) setPatterns: (NSArray *) patterns { [_patterns autorelease]; _patterns = [[self verifiedPatternsFromArray: patterns] retain]; [self savePatternsToStoredPresets]; [self loadPatternsFromStoredPresets]; [self postNotification_UpdatedPresets]; } - (bool) savePatternsToPresetsFile: (NSString *) filepath { return [self savePatterns: _patterns toFile: filepath]; } - (void) addPatternsFromPresetsFile: (NSString *) filepath { NSArray *importedPatterns, *newPresets; int numPresets, presetIndex; NSMutableArray *patternsToAdd; NSEnumerator *importedPatternsEnumerator; id pattern; bool presetsContainPattern; importedPatterns = [self patternsFromFile: filepath]; if (![importedPatterns count]) { goto ERROR; } numPresets = [_patterns count]; if (!numPresets) { [self setPatterns: importedPatterns]; return; } patternsToAdd = [NSMutableArray array]; if (!patternsToAdd) goto ERROR; importedPatternsEnumerator = [importedPatterns objectEnumerator]; while (pattern = [importedPatternsEnumerator nextObject]) { presetsContainPattern = NO; presetIndex = numPresets - 1; while ((presetIndex >= 0) && !presetsContainPattern) { if ([pattern isEqualToPresettablePattern: [_patterns objectAtIndex: presetIndex]]) { presetsContainPattern = YES; } presetIndex--; } if (!presetsContainPattern) { [patternsToAdd addObject: pattern]; } } if (![patternsToAdd count]) { return; } newPresets = [_patterns arrayByAddingObjectsFromArray: patternsToAdd]; if (!newPresets) goto ERROR; [self setPatterns: newPresets]; return; ERROR: return; } - (NSArray *) presetsFiletypes { return _presetsFiletypes; } #pragma mark Private methods - (NSArray *) verifiedPatternsFromArray: (NSArray *) importedPatterns { int numImportedPatterns; NSMutableArray *verifiedPatterns; NSEnumerator *patternEnumerator; id pattern; NSArray *returnedPatterns; numImportedPatterns = [importedPatterns count]; if (!numImportedPatterns) goto ERROR; verifiedPatterns = [NSMutableArray array]; if (!verifiedPatterns) goto ERROR; patternEnumerator = [importedPatterns objectEnumerator]; while (pattern = [patternEnumerator nextObject]) { if ([pattern isKindOfClass: _patternClass]) { [verifiedPatterns addObject: pattern]; } } if ([verifiedPatterns count] == numImportedPatterns) { returnedPatterns = importedPatterns; } else { returnedPatterns = [NSArray arrayWithArray: verifiedPatterns]; if (!returnedPatterns) { returnedPatterns = verifiedPatterns; } } return returnedPatterns; ERROR: return nil; } - (bool) savePatterns: (NSArray *) patterns toFile: (NSString *) filepath { NSDictionary *presetsDict; patterns = [self verifiedPatternsFromArray: patterns]; if (![patterns count] || ![filepath length]) { goto ERROR; } presetsDict = [NSDictionary dictionaryWithObject: patterns forKey: kPatternPresetsDictKey_Patterns]; if (!presetsDict) goto ERROR; return [NSKeyedArchiver archiveRootObject: presetsDict toFile: filepath]; ERROR: return NO; } - (NSArray *) patternsFromFile: (NSString *) filepath; { NSDictionary *presetsDict; NSArray *patterns; if (![filepath length] || (![[NSFileManager defaultManager] isReadableFileAtPath: filepath])) { goto ERROR; } presetsDict = [NSKeyedUnarchiver unarchiveObjectWithFile: filepath]; if (![presetsDict isKindOfClass: [NSDictionary class]]) { goto ERROR; } patterns = [presetsDict objectForKey: kPatternPresetsDictKey_Patterns]; if (![patterns isKindOfClass: [NSArray class]]) { goto ERROR; } patterns = [self verifiedPatternsFromArray: patterns]; if (![patterns count]) { goto ERROR; } return patterns; ERROR: return nil; } - (void) loadPatternsFromStoredPresets { [_patterns release]; _patterns = [[self patternsFromFile: _storedPresetsFilepath] retain]; } - (void) savePatternsToStoredPresets { NSFileManager *fileManager = [NSFileManager defaultManager]; if ([_patterns count]) { if (![fileManager ppVerifySupportFileDirectory]) { goto ERROR; } [self savePatterns: _patterns toFile: _storedPresetsFilepath]; } else { [fileManager ppDeleteSupportFileAtPath: _storedPresetsFilepath]; } return; ERROR: return; } - (void) postNotification_UpdatedPresets { [[NSNotificationCenter defaultCenter] postNotificationName: PPPatternPresetsNotification_UpdatedPresets object: self]; } @end #pragma mark Private functions static NSString *StoredPresetsFilepathForFilenameAndFiletype(NSString *storedPresetsFilename, NSString *presetsFiletype) { if (![storedPresetsFilename length] || ![presetsFiletype length]) { goto ERROR; } if (![[storedPresetsFilename pathExtension] length]) { storedPresetsFilename = [storedPresetsFilename stringByAppendingPathExtension: presetsFiletype]; if (!storedPresetsFilename) goto ERROR; } return [NSFileManager ppFilepathForSupportFileWithName: storedPresetsFilename]; ERROR: return nil; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPPencilTool.h0000644000076500000240000000216113234403417020637 0ustar joshstaff/* PPPencilTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPPencilTool : PPTool { NSBezierPath *_drawPath; bool _shouldFillDrawPath; bool _isDrawingLineSegment; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPencilTool.m0000644000076500000240000001116113234403207020641 0ustar joshstaff/* PPPencilTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPencilTool.h" #import "PPDocument.h" #import "NSCursor_PPUtilities.h" #import "NSBezierPath_PPUtilities.h" #define kPencilToolAttributesMask \ (kPPToolAttributeMask_RequiresPointsCroppedToCanvasBounds \ | kPPToolAttributeMask_DisableSkippingOfMouseDraggedEvents \ | kPPToolAttributeMask_DisableAutoscrolling) @implementation PPPencilTool - init { self = [super init]; if (!self) goto ERROR; _drawPath = [[NSBezierPath bezierPath] retain]; if (!_drawPath) goto ERROR; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_drawPath release]; [super dealloc]; } - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [_drawPath removeAllPoints]; [_drawPath ppAppendSinglePixelLineAtPoint: currentPoint]; _isDrawingLineSegment = NO; _shouldFillDrawPath = NO; [ppDocument beginDrawingWithPenMode: kPPPenMode_Fill]; [ppDocument drawPixelAtPoint: currentPoint]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { bool isDrawingLineSegment, shouldFillDrawPath, shouldDrawAsBezierPath, mouseDidMoveToNewPoint; isDrawingLineSegment = (modifierKeyFlags & kModifierKeyMask_DrawLineSegment) ? YES : NO; if (_isDrawingLineSegment != isDrawingLineSegment) { _isDrawingLineSegment = isDrawingLineSegment; if (_isDrawingLineSegment) { // began drawing line segment, so append zero-length line element - its endpoint // will be updated by -[NSBezierPath ppSetLastLineEndPointToPixelAtPoint:] as // mouse moves [_drawPath ppAppendZeroLengthLineAtLastLineEndPoint]; } } shouldFillDrawPath = (modifierKeyFlags & kModifierKeyMask_FillShape) ? YES : NO; if (_shouldFillDrawPath != shouldFillDrawPath) { _shouldFillDrawPath = shouldFillDrawPath; shouldDrawAsBezierPath = YES; } else { shouldDrawAsBezierPath = _shouldFillDrawPath; } mouseDidMoveToNewPoint = (!NSEqualPoints(lastPoint, currentPoint)) ? YES : NO; if (mouseDidMoveToNewPoint) { if (_isDrawingLineSegment) { [_drawPath ppSetLastLineEndPointToPixelAtPoint: currentPoint]; shouldDrawAsBezierPath = YES; } else { [_drawPath ppLineToPixelAtPoint: currentPoint]; } } if (shouldDrawAsBezierPath) { [ppDocument undoCurrentDrawingAtNextDraw]; [ppDocument drawBezierPath: _drawPath andFill: _shouldFillDrawPath]; } else if (mouseDidMoveToNewPoint) { [ppDocument drawLineFromPoint: lastPoint toPoint: currentPoint]; } } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [ppDocument finishDrawing]; [_drawPath removeAllPoints]; } - (NSCursor *) cursor { return [NSCursor ppPencilCursor]; } - (unsigned) toolAttributeFlags { return kPencilToolAttributesMask; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPopupPanel.h0000644000076500000240000000203313234403417020650 0ustar joshstaff/* PPPopupPanel.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPPopupPanel : NSPanel { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPopupPanel.m0000644000076500000240000000633713234403207020665 0ustar joshstaff/* PPPopupPanel.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanel.h" #import "PPPopupPanelController.h" #import "PPFilledRoundedRectView.h" #import "PPUIColors_Panels.h" @interface PPPopupPanel (PrivateMethods) - (void) setupRoundedRectBackgroundView; - (NSColor *) backgroundColorForPopupPanelFromController; @end @implementation PPPopupPanel #pragma mark NSPanel overrides - (id) initWithContentRect: (NSRect) contentRect styleMask: (PPSDKNativeType_NSWindowStyleMask) styleMask backing: (NSBackingStoreType) bufferingType defer: (BOOL) deferCreation { self = [super initWithContentRect: contentRect styleMask: NSBorderlessWindowMask backing: bufferingType defer: deferCreation]; if (!self) goto ERROR; [self setBackgroundColor: [NSColor clearColor]]; [self setFloatingPanel: YES]; [self setOpaque: NO]; [self setHasShadow: NO]; return self; ERROR: [self release]; return nil; } - (void) awakeFromNib { // check before calling [super awakeFromNib] - before 10.6, some classes didn't implement it if ([[PPPopupPanel superclass] instancesRespondToSelector: @selector(awakeFromNib)]) { [super awakeFromNib]; } [self setupRoundedRectBackgroundView]; [self orderOut: nil]; } #pragma mark Private methods - (void) setupRoundedRectBackgroundView { NSView *contentView; PPFilledRoundedRectView *roundedRectBackgroundView; contentView = [self contentView]; roundedRectBackgroundView = [PPFilledRoundedRectView viewWithFrame: [contentView bounds] andColor: [self backgroundColorForPopupPanelFromController]]; if (!roundedRectBackgroundView) goto ERROR; [contentView addSubview: roundedRectBackgroundView positioned: NSWindowBelow relativeTo: nil]; [contentView setAutoresizesSubviews: YES]; return; ERROR: return; } - (NSColor *) backgroundColorForPopupPanelFromController { PPPopupPanelController *controller; controller = [self windowController]; if (![controller isKindOfClass: [PPPopupPanelController class]]) { return kUIColor_DefaultPopupPanelBackground; } return [controller backgroundColorForPopupPanel]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPopupPanelActionKeys.h0000644000076500000240000000220113234403417022637 0ustar joshstaff/* PPPopupPanelActionKeys.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPKeyConstants.h" #define kToolsPopupPanelActionKey_SelectLastTool kSpaceKey #define kColorsPopupPanelActionKey_NextSamplerImage kSpaceKey PikoPixel.Sources.1.0-b10b/PikoPixel/PPPopupPanelController.h0000644000076500000240000000261013234403417022715 0ustar joshstaff/* PPPopupPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPanelController.h" #import "PPDirectionType.h" @interface PPPopupPanelController : PPPanelController { NSPoint _panelOriginLockPoint; bool _hasPanelOriginLockPoint; } - (NSColor *) backgroundColorForPopupPanel; - (bool) handleActionKey: (NSString *) key; - (void) handleDirectionCommand: (PPDirectionType) directionType; - (NSPoint) panelOrigin; - (void) enablePanelAtOrigin: (NSPoint) origin; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPopupPanelController.m0000644000076500000240000001020713234403207022720 0ustar joshstaff/* PPPopupPanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanelController.h" #import "PPGeometry.h" #import "PPUIColors_Panels.h" #import "PPDocument.h" #import "PPDocumentWindowController.h" #import "PPCanvasView.h" static NSScreen *ScreenContainingDisplayLocation(NSPoint displayLocation); @interface PPPopupPanelController (PrivateMethods) - (void) setPanelOrigin: (NSPoint) origin; - (NSPoint) originPointForCenteringPanelAtCurrentMousePoint; @end @implementation PPPopupPanelController - (NSColor *) backgroundColorForPopupPanel { return kUIColor_DefaultPopupPanelBackground; } - (bool) handleActionKey: (NSString *) key { return NO; } - (void) handleDirectionCommand: (PPDirectionType) directionType { } - (NSPoint) panelOrigin { return [[self window] frame].origin; } - (void) enablePanelAtOrigin: (NSPoint) origin { _panelOriginLockPoint = origin; _hasPanelOriginLockPoint = YES; [self setPanelEnabled: YES]; _hasPanelOriginLockPoint = NO; } #pragma mark PPPanelController overrides - (bool) shouldStorePanelStateInUserDefaults { return NO; } - (void) setupPanelForCurrentPPDocument { // empty method - prevent passthrough to parent implementation (no need for super's setup, // which just updates the visiblity) } - (void) setupPanelBeforeMakingVisible { NSPoint panelOrigin; [super setupPanelBeforeMakingVisible]; panelOrigin = (_hasPanelOriginLockPoint) ? _panelOriginLockPoint : [self originPointForCenteringPanelAtCurrentMousePoint]; [self setPanelOrigin: panelOrigin]; } #pragma mark NSWindowController overrides - (void) scrollWheel: (NSEvent *) theEvent { [[[_ppDocument ppDocumentWindowController] canvasView] scrollWheel: theEvent]; } #pragma mark Private methods - (void) setPanelOrigin: (NSPoint) origin { NSWindow *panel; NSRect newWindowFrame; NSPoint anchorPoint; NSScreen *panelScreen; panel = [self window]; newWindowFrame = [panel frame]; newWindowFrame.origin = PPGeometry_PointClippedToIntegerValues(origin); anchorPoint = (_hasPanelOriginLockPoint) ? newWindowFrame.origin : PPGeometry_CenterOfRect(newWindowFrame); panelScreen = [NSScreen mainScreen]; if (!NSPointInRect(anchorPoint, [panelScreen frame])) { panelScreen = ScreenContainingDisplayLocation(anchorPoint); } origin = PPGeometry_OriginPointForConfiningRectInsideRect(newWindowFrame, [panelScreen visibleFrame]); [panel setFrameOrigin: origin]; } - (NSPoint) originPointForCenteringPanelAtCurrentMousePoint { return PPGeometry_OriginPointForCenteringRectAtPoint([[self window] frame], [NSEvent mouseLocation]); } @end #pragma mark Private functions static NSScreen *ScreenContainingDisplayLocation(NSPoint displayLocation) { NSEnumerator *screenEnumerator; NSScreen *screen; screenEnumerator = [[NSScreen screens] objectEnumerator]; while (screen = [screenEnumerator nextObject]) { if (NSPointInRect(displayLocation, [screen frame])) { return screen; } } return [NSScreen mainScreen]; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPPopupPanelsController.h0000644000076500000240000000341413234403417023103 0ustar joshstaff/* PPPopupPanelsController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPPopupPanelType.h" #import "PPDirectionType.h" @class PPDocument; @interface PPPopupPanelsController : NSObject { NSArray *_popupControllers; PPPopupPanelType _activePopupPanelType; NSPoint _lastPopupPanelOrigin; bool _useLastPopupPanelOriginForNextActivePopup; } + sharedController; - (void) setPPDocument: (PPDocument *) document; - (void) setActivePopupPanel: (PPPopupPanelType) popupPanelType; - (bool) hasActivePopupPanel; - (bool) mouseIsInsideActivePopupPanel; - (bool) getPopupPanelType: (PPPopupPanelType *) returnedPopupPanelType forKey: (NSString *) key; - (bool) handleActionKey: (NSString *) key; - (void) handleDirectionCommand: (PPDirectionType) directionType; - (void) positionNextActivePopupAtCurrentPopupOrigin; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPopupPanelsController.m0000644000076500000240000002332713234403207023112 0ustar joshstaff/* PPPopupPanelsController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanelsController.h" #import "PPNavigatorPopupPanelController.h" #import "PPToolsPopupPanelController.h" #import "PPColorPickerPopupPanelController.h" #import "PPSamplerImagePopupPanelController.h" #import "PPLayerControlsPopupPanelController.h" #import "PPHotkeys.h" static NSDictionary *gHotkeyToPopupPanelTypeMapping = nil; static NSArray *PopupControllersArray(void); @interface PPPopupPanelsController (PrivateMethods) + (void) addAsObserverForPPHotkeysNotifications; + (void) removeAsObserverForPPHotkeysNotifications; + (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification; + (bool) setupHotkeyToPopupPanelTypeMapping; - (PPPopupPanelController *) popupPanelControllerForActivePopupType; - (void) setVisibilityAllowedForAllPopups; @end @implementation PPPopupPanelsController + (void) initialize { if ([self class] != [PPPopupPanelsController class]) { return; } [PPHotkeys setupGlobals]; [self setupHotkeyToPopupPanelTypeMapping]; [self addAsObserverForPPHotkeysNotifications]; } + sharedController { static PPPopupPanelsController *sharedController = nil; if (!sharedController) { sharedController = [[self alloc] init]; } return sharedController; } - init { self = [super init]; if (!self) goto ERROR; _popupControllers = [PopupControllersArray() retain]; if (!_popupControllers) goto ERROR; [self setVisibilityAllowedForAllPopups]; _activePopupPanelType = kPPPopupPanelType_None; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_popupControllers release]; [super dealloc]; } - (void) setPPDocument: (PPDocument *) document { if (_activePopupPanelType != kPPPopupPanelType_None) { [self setActivePopupPanel: kPPPopupPanelType_None]; } [_popupControllers makeObjectsPerformSelector: @selector(setPPDocument:) withObject: document]; } - (void) setActivePopupPanel: (PPPopupPanelType) popupPanelType { if (!PPPopupPanelType_IsValid(popupPanelType)) { popupPanelType = kPPPopupPanelType_None; } if (popupPanelType == _activePopupPanelType) { return; } [[self popupPanelControllerForActivePopupType] setPanelEnabled: NO]; _activePopupPanelType = popupPanelType; if (_activePopupPanelType == kPPPopupPanelType_None) { return; } if (_useLastPopupPanelOriginForNextActivePopup) { [[self popupPanelControllerForActivePopupType] enablePanelAtOrigin: _lastPopupPanelOrigin]; _useLastPopupPanelOriginForNextActivePopup = NO; } else { [[self popupPanelControllerForActivePopupType] setPanelEnabled: YES]; } } - (bool) hasActivePopupPanel { return (_activePopupPanelType != kPPPopupPanelType_None) ? YES : NO; } - (bool) mouseIsInsideActivePopupPanel { NSWindow *panel; if (![self hasActivePopupPanel]) { return NO; } panel = [[self popupPanelControllerForActivePopupType] window]; return ([panel isVisible] && NSMouseInRect([NSEvent mouseLocation], [panel frame], NO)) ? YES : NO; } - (bool) getPopupPanelType: (PPPopupPanelType *) returnedPopupPanelType forKey: (NSString *) key { NSNumber *popupPanelTypeNumber; if (!returnedPopupPanelType || ([key length] != 1)) { goto ERROR; } popupPanelTypeNumber = [gHotkeyToPopupPanelTypeMapping objectForKey: key]; if (!popupPanelTypeNumber) goto ERROR; *returnedPopupPanelType = (PPPopupPanelType) [popupPanelTypeNumber intValue]; return YES; ERROR: return NO; } - (bool) handleActionKey: (NSString *) key { if (![self hasActivePopupPanel]) { return NO; } return [[self popupPanelControllerForActivePopupType] handleActionKey: key]; } - (void) handleDirectionCommand: (PPDirectionType) directionType { [[self popupPanelControllerForActivePopupType] handleDirectionCommand: directionType]; } - (void) positionNextActivePopupAtCurrentPopupOrigin { if (![self hasActivePopupPanel]) { return; } _lastPopupPanelOrigin = [[self popupPanelControllerForActivePopupType] panelOrigin]; _useLastPopupPanelOriginForNextActivePopup = YES; } #pragma mark PPHotkeys notifications + (void) addAsObserverForPPHotkeysNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPHotkeysNotification_UpdatedHotkeys:) name: PPHotkeysNotification_UpdatedHotkeys object: nil]; } + (void) removeAsObserverForPPHotkeysNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPHotkeysNotification_UpdatedHotkeys object: nil]; } + (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification { [self setupHotkeyToPopupPanelTypeMapping]; } #pragma mark Private methods + (bool) setupHotkeyToPopupPanelTypeMapping { NSDictionary *hotkeyToPopupPanelTypeMapping = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt: kPPPopupPanelType_Navigator], gHotkeys[kPPHotkeyType_PopupPanel_Navigator], [NSNumber numberWithInt: kPPPopupPanelType_Navigator], gHotkeys[kPPHotkeyType_PopupPanel_NavigatorAlternate], [NSNumber numberWithInt: kPPPopupPanelType_Tools], gHotkeys[kPPHotkeyType_PopupPanel_Tools], [NSNumber numberWithInt: kPPPopupPanelType_Tools], gHotkeys[kPPHotkeyType_PopupPanel_ToolsAlternate], [NSNumber numberWithInt: kPPPopupPanelType_ColorPicker], gHotkeys[kPPHotkeyType_PopupPanel_ColorPicker], [NSNumber numberWithInt: kPPPopupPanelType_ColorPicker], gHotkeys[kPPHotkeyType_PopupPanel_ColorPickerAlternate], // no direct mapping for color sampler image popup [NSNumber numberWithInt: kPPPopupPanelType_SamplerImage], @"no hotkey", [NSNumber numberWithInt: kPPPopupPanelType_SamplerImage], @"no hotkey alternate", [NSNumber numberWithInt: kPPPopupPanelType_LayerControls], gHotkeys[kPPHotkeyType_PopupPanel_LayerControls], [NSNumber numberWithInt: kPPPopupPanelType_LayerControls], gHotkeys[kPPHotkeyType_PopupPanel_LayerControlsAlternate], nil]; if ([hotkeyToPopupPanelTypeMapping count] != (2 * kNumPPPopupPanelTypes)) { goto ERROR; } [gHotkeyToPopupPanelTypeMapping release]; gHotkeyToPopupPanelTypeMapping = [hotkeyToPopupPanelTypeMapping retain]; return YES; ERROR: return NO; } - (PPPopupPanelController *) popupPanelControllerForActivePopupType { if (!PPPopupPanelType_IsValid(_activePopupPanelType)) { return nil; } return [_popupControllers objectAtIndex: _activePopupPanelType]; } - (void) setVisibilityAllowedForAllPopups { NSEnumerator *popupControllerEnumerator; PPPopupPanelController *popupController; popupControllerEnumerator = [_popupControllers objectEnumerator]; while (popupController = [popupControllerEnumerator nextObject]) { [popupController setPanelVisibilityAllowed: YES]; } } @end #pragma mark Private functions static NSArray *PopupControllersArray(void) { NSArray *popupControllers; popupControllers = [NSArray arrayWithObjects: // Must match order of PPPopupPanelType enum: [PPNavigatorPopupPanelController controller], [PPToolsPopupPanelController controller], [PPColorPickerPopupPanelController controller], [PPSamplerImagePopupPanelController controller], [PPLayerControlsPopupPanelController controller], nil]; if ([popupControllers count] != kNumPPPopupPanelTypes) { goto ERROR; } return popupControllers; ERROR: return nil; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPPopupPanelType.h0000644000076500000240000000267213234403417021523 0ustar joshstaff/* PPPopupPanelType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPPopupPanelType_Navigator, kPPPopupPanelType_Tools, kPPPopupPanelType_ColorPicker, kPPPopupPanelType_SamplerImage, kPPPopupPanelType_LayerControls, // add new PPPopupPanelType values above this line kNumPPPopupPanelTypes, kPPPopupPanelType_None, } PPPopupPanelType; static inline bool PPPopupPanelType_IsValid(PPPopupPanelType popupPanelType) { return (((unsigned) popupPanelType) < kNumPPPopupPanelTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPPresettablePatternProtocol.h0000644000076500000240000000245413234403417024126 0ustar joshstaff/* PPPresettablePatternProtocol.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @protocol PPPresettablePattern - (void) setPresetName: (NSString *) presetName; - (NSString *) presetName; - (bool) isEqualToPresettablePattern: (id ) pattern; - (NSColor *) patternColorForPresettablePatternViewOfSize: (NSSize) viewSize; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPresettablePatternView.h0000644000076500000240000000242013234403417023230 0ustar joshstaff/* PPPresettablePatternView.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPPresettablePatternProtocol.h" @interface PPPresettablePatternView : NSView { id _pattern; NSBitmapImageRep *_patternBitmap; NSRect _patternBitmapFrame; } - (void) setPresettablePattern: (id ) pattern; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPresettablePatternView.m0000644000076500000240000000522713234403207023242 0ustar joshstaff/* PPPresettablePatternView.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPresettablePatternView.h" #import "NSBitmapImageRep_PPUtilities.h" @interface PPPresettablePatternView (PrivateMethods) - (void) updatePatternBitmap; @end @implementation PPPresettablePatternView - (id) initWithFrame: (NSRect) frameRect { self = [super initWithFrame: frameRect]; if (!self) goto ERROR; _patternBitmap = [[NSBitmapImageRep ppImageBitmapOfSize: [self bounds].size] retain]; if (!_patternBitmap) goto ERROR; _patternBitmapFrame = [_patternBitmap ppFrameInPixels]; [self updatePatternBitmap]; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_pattern release]; [_patternBitmap release]; [super dealloc]; } - (void) setPresettablePattern: (id ) pattern { if (![pattern conformsToProtocol: @protocol(PPPresettablePattern)]) { pattern = nil; } if ((_pattern == pattern) || [_pattern isEqualToPresettablePattern: pattern]) { return; } [_pattern release]; _pattern = [pattern retain]; [self updatePatternBitmap]; } #pragma mark NSView overrides - (void) drawRect: (NSRect) dirtyRect { [_patternBitmap drawAtPoint: NSZeroPoint]; } #pragma mark Private methods - (void) updatePatternBitmap { NSColor *patternColor = [_pattern patternColorForPresettablePatternViewOfSize: _patternBitmapFrame.size]; if (!patternColor) { patternColor = [NSColor whiteColor]; } [_patternBitmap ppSetAsCurrentGraphicsContext]; [patternColor set]; NSRectFill(_patternBitmapFrame); [_patternBitmap ppRestoreGraphicsContext]; [self setNeedsDisplay: YES]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPreviewBackgroundType.h0000644000076500000240000000267413234403417023063 0ustar joshstaff/* PPPreviewBackgroundType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPPreviewBackgroundType_LightCheckerboard, kPPPreviewBackgroundType_SolidGrey, kPPPreviewBackgroundType_DarkCheckerboard, kPPPreviewBackgroundType_SolidBlack, kPPPreviewBackgroundType_SolidWhite, kNumPPPreviewBackgroundTypes } PPPreviewBackgroundType; static inline bool PPPreviewBackgroundType_IsValid(PPPreviewBackgroundType backgroundType) { return (((unsigned) backgroundType) < kNumPPPreviewBackgroundTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPPreviewPanelController.h0000644000076500000240000000240713234403417023237 0ustar joshstaff/* PPPreviewPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPanelController.h" @class PPPreviewView; @interface PPPreviewPanelController : PPPanelController { IBOutlet PPPreviewView *_previewView; unsigned _previewImageUpdateMode; NSSize _sizeDifferenceBetweenPanelAndPreviewView; bool _needToUpdatePreviewImage; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPreviewPanelController.m0000644000076500000240000002102713714431535023250 0ustar joshstaff/* PPPreviewPanelController.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPreviewPanelController.h" #import "PPDocument.h" #import "PPPreviewView.h" #import "PPDocumentWindowController.h" #import "PPPanelDefaultFramePinnings.h" #import "PPGeometry.h" #define kPreviewPanelNibName @"PreviewPanel" #define kMinScaleForContinousPreviewImageUpdateMode (0.5f) typedef enum { kPPPreviewImageUpdateMode_Continuous, kPPPreviewImageUpdateMode_ThumbnailUpdatesOnly } PPPreviewImageUpdateMode; @interface PPPreviewPanelController (PrivateMethods) - (void) handlePPDocumentNotification_UpdatedMergedVisibleArea: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedDrawingLayerArea: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedDrawingLayerThumbnailImage: (NSNotification *) notification; - (void) setupPreviewImage; - (void) clearPreviewImage; - (void) setupPreviewImageUpdateModeForScale: (float) scale; - (void) forceWindowTitleRedisplay; @end @implementation PPPreviewPanelController #pragma mark NSWindowController overrides - (void) windowDidLoad { NSWindow *window = [self window]; _sizeDifferenceBetweenPanelAndPreviewView = PPGeometry_SizeDifference([window frame].size, [_previewView frame].size); // PPreviewView handles minimum size, make sure window defaults don't interfere [window setContentMinSize: NSZeroSize]; [_previewView setDelegate: self]; // [super windowDidLoad] may show the panel, so call as late as possible [super windowDidLoad]; } #pragma mark PPPanelController overrides + (NSString *) panelNibName { return kPreviewPanelNibName; } - (void) addAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; if (!_ppDocument) return; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedMergedVisibleArea:) name: PPDocumentNotification_UpdatedMergedVisibleArea object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage:) name: PPDocumentNotification_UpdatedMergedVisibleThumbnailImage object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ReloadedDocument:) name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedMergedVisibleArea object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedMergedVisibleThumbnailImage object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ReloadedDocument object: _ppDocument]; } - (bool) defaultPanelEnabledState { return YES; } - (PPFramePinningType) pinningTypeForDefaultWindowFrame { return kPPPanelDefaultFramePinning_Preview; } - (void) setupPanelForCurrentPPDocument { [self setupPreviewImage]; // [super setupPanelForCurrentPPDocument] may show the panel, so call as late as possible [super setupPanelForCurrentPPDocument]; } - (void) setupPanelBeforeMakingVisible { [super setupPanelBeforeMakingVisible]; if (_needToUpdatePreviewImage) { [_previewView handleUpdateToImage]; _needToUpdatePreviewImage = NO; } } #pragma mark NSWindow delegate methods - (NSSize) windowWillResize: (NSWindow *) sender toSize: (NSSize) proposedFrameSize { NSSize proposedPreviewViewSize, newPreviewViewSize; proposedPreviewViewSize = PPGeometry_SizeDifference(proposedFrameSize, _sizeDifferenceBetweenPanelAndPreviewView); newPreviewViewSize = [_previewView prepareForNewFrameSize: proposedPreviewViewSize]; return PPGeometry_SizeSum(newPreviewViewSize, _sizeDifferenceBetweenPanelAndPreviewView); } #pragma mark PPPreviewView delegate methods - (void) ppPreviewView: (PPPreviewView *) previewView didChangeScale: (float) scale { int percentScale = roundf(100.0f * scale); [self setupPreviewImageUpdateModeForScale: percentScale / 100.0f]; [[self window] setTitle: [NSString stringWithFormat: @"%d%% Preview", percentScale]]; [self forceWindowTitleRedisplay]; } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_UpdatedMergedVisibleArea: (NSNotification *) notification { if (_previewImageUpdateMode == kPPPreviewImageUpdateMode_ThumbnailUpdatesOnly) { return; } if ([self panelIsVisible]) { NSValue *updateAreaRectValue = [[notification userInfo] objectForKey: PPDocumentNotification_UserInfoKey_UpdateAreaRect]; if (updateAreaRectValue) { [_previewView handleUpdateToImageInRect: [updateAreaRectValue rectValue]]; } } else { _needToUpdatePreviewImage = YES; } } - (void) handlePPDocumentNotification_UpdatedMergedVisibleThumbnailImage: (NSNotification *) notification { if (_previewImageUpdateMode != kPPPreviewImageUpdateMode_ThumbnailUpdatesOnly) { return; } if ([self panelIsVisible]) { [_previewView handleUpdateToImage]; } else { _needToUpdatePreviewImage = YES; } } - (void) handlePPDocumentNotification_ReloadedDocument: (NSNotification *) notification { // the document's thumbnail image may remain the same object, and -[PPPreviewView setImage:] // won't redraw the view unless it's passed a different object from its current image, so // clear the preview view's image first to force it to redraw [self clearPreviewImage]; [self setupPreviewImage]; } #pragma mark Private methods - (void) setupPreviewImage { [_previewView setImage: [_ppDocument mergedVisibleLayersThumbnailImage]]; _needToUpdatePreviewImage = NO; } - (void) clearPreviewImage { [_previewView setImage: nil]; } - (void) setupPreviewImageUpdateModeForScale: (float) scale { _previewImageUpdateMode = (scale >= kMinScaleForContinousPreviewImageUpdateMode) ? kPPPreviewImageUpdateMode_Continuous : kPPPreviewImageUpdateMode_ThumbnailUpdatesOnly; } - (void) forceWindowTitleRedisplay { NSView *contentView, *windowView; NSRect contentViewFrame, windowViewBounds, titleFrame; contentView = [[self window] contentView]; windowView = [contentView superview]; contentViewFrame = [contentView frame]; windowViewBounds = [windowView bounds]; titleFrame = windowViewBounds; titleFrame.size.height = windowViewBounds.size.height - contentViewFrame.size.height; titleFrame.origin.y = windowViewBounds.size.height - titleFrame.size.height; [windowView displayRect: titleFrame]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPreviewView.h0000644000076500000240000000354113234403417021046 0ustar joshstaff/* PPPreviewView.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPPreviewBackgroundType.h" @interface PPPreviewView : NSView { id _delegate; NSImage *_image; float _previewScale; float _minimumScaleForCurrentImage; NSRect _imageFrame; NSRect _scaledImageBounds; PPPreviewBackgroundType _backgroundType; NSColor *_backgroundFillColor; unsigned _resizableDirectionsMask; bool _viewIsResizing; } - (void) setImage: (NSImage *) image; - (void) handleUpdateToImage; - (void) handleUpdateToImageInRect: (NSRect) imageUpdateRect; - (NSSize) prepareForNewFrameSize: (NSSize) newFrameSize; - (void) setBackgroundType: (PPPreviewBackgroundType) backgroundType; - (void) toggleBackgroundType; - (void) setDelegate: (id) delegate; - (id) delegate; @end @interface NSObject (PPPreviewViewDelegateMethods) - (void) ppPreviewView: (PPPreviewView *) previewView didChangeScale: (float) scale; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPPreviewView.m0000644000076500000240000003047413234403207021055 0ustar joshstaff/* PPPreviewView.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPreviewView.h" #import "NSColor_PPUtilities.h" #import "PPGeometry.h" #import "PPResizableDirectionsMasks.h" #import "NSObject_PPUtilities.h" #define kMaxPreviewScale 12 #define kMaxContinuousScale (0.75f) #define kRoundoffLimitForMaxContinuousScale ((kMaxContinuousScale + 1.0f) / 2.0f) #define kMinAllowedViewDimension 128 #define kUIColor_LightCheckerboardPattern \ [NSColor ppCheckerboardPatternColorWithBoxDimension: 8.0f \ color1: [NSColor whiteColor] \ color2: [NSColor ppSRGBColorWithWhite: 0.90f alpha: 1.0f]] #define kUIColor_DarkCheckerboardPattern \ [NSColor ppCheckerboardPatternColorWithBoxDimension: 8.0f \ color1: [NSColor ppSRGBColorWithWhite: 0.35f alpha: 1.0f] \ color2: [NSColor blackColor]] static NSColor *gLightCheckerboardColor = nil, *gDarkCheckerboardColor = nil; @interface PPPreviewView (PrivateMethods) - (void) setScale: (float) scale; - (void) setScaleForSize: (NSSize) size isResizing: (bool) isResizing; - (float) dimensionScaleForImageWithLength: (float) imageLength onViewWithLength: (float) viewLength; - (void) handleResizingBegin; - (void) handleResizingEnd; - (void) notifyDelegateDidChangeScale; @end @implementation PPPreviewView + (void) initialize { if ([self class] != [PPPreviewView class]) { return; } gLightCheckerboardColor = [kUIColor_LightCheckerboardPattern retain]; gDarkCheckerboardColor = [kUIColor_DarkCheckerboardPattern retain]; } - (void) dealloc { [_image release]; [_backgroundFillColor release]; [super dealloc]; } - (void) setImage: (NSImage *) image { NSSize imageSize; if (_image == image) { return; } [_image release]; _image = [image retain]; imageSize = (image) ? [image size] : NSZeroSize; if (!NSEqualSizes(imageSize, _imageFrame.size)) { float maxDimension = (imageSize.width > imageSize.height) ? imageSize.width : imageSize.height; if (maxDimension < kMinAllowedViewDimension) { _minimumScaleForCurrentImage = kMaxContinuousScale; } else { _minimumScaleForCurrentImage = kMaxContinuousScale * kMinAllowedViewDimension / maxDimension; } _imageFrame.size = imageSize; [self setScaleForSize: [self frame].size isResizing: NO]; } [self setNeedsDisplay: YES]; } - (void) handleUpdateToImage { [self handleUpdateToImageInRect: _imageFrame]; } - (void) handleUpdateToImageInRect: (NSRect) imageUpdateRect { NSRect viewUpdateRect; imageUpdateRect = NSIntersectionRect(imageUpdateRect, _imageFrame); if (NSIsEmptyRect(imageUpdateRect)) { return; } viewUpdateRect = PPGeometry_RectScaledByFactor(imageUpdateRect, _previewScale); viewUpdateRect.origin = PPGeometry_PointSum(viewUpdateRect.origin, _scaledImageBounds.origin); if (_previewScale < 1.0f) { viewUpdateRect = PPGeometry_PixelBoundsCoveredByRect(viewUpdateRect); } [self setNeedsDisplayInRect: viewUpdateRect]; } - (NSSize) prepareForNewFrameSize: (NSSize) newFrameSize { float oldPreviewScale = _previewScale; NSSize oldFrameSize = [self frame].size; bool didChangePreviewScale, didChangeFrameSize; if (!_viewIsResizing) { [self handleResizingBegin]; [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(handleResizingEnd)]; } if (oldFrameSize.width != newFrameSize.width) { _resizableDirectionsMask |= kPPResizableDirectionsMask_Horizontal; } if (oldFrameSize.height != newFrameSize.height) { _resizableDirectionsMask |= kPPResizableDirectionsMask_Vertical; } [self setScaleForSize: newFrameSize isResizing: YES]; newFrameSize = _scaledImageBounds.size; if (newFrameSize.width < kMinAllowedViewDimension) { newFrameSize.width = kMinAllowedViewDimension; } if (newFrameSize.height < kMinAllowedViewDimension) { newFrameSize.height = kMinAllowedViewDimension; } didChangePreviewScale = (oldPreviewScale != _previewScale) ? YES : NO; didChangeFrameSize = (!NSEqualSizes(oldFrameSize, newFrameSize)) ? YES : NO; if (didChangePreviewScale && !didChangeFrameSize) { // On OS X, when the frame size doesn't change, there's a short delay between the call // to -[NSView setNeedsDisplay:] (called when scale changes) and the system's call // to -[NSView display] (takes about a second for the view to update - due to dragging?). // To avoid the delay, manually call displayIfNeeded to force an immediate redraw. [self displayIfNeeded]; } return newFrameSize; } - (void) setBackgroundType: (PPPreviewBackgroundType) backgroundType { NSColor *newBackgroundFillColor; if (!PPPreviewBackgroundType_IsValid(backgroundType)) { return; } switch (backgroundType) { case kPPPreviewBackgroundType_LightCheckerboard: { newBackgroundFillColor = gLightCheckerboardColor; } break; case kPPPreviewBackgroundType_DarkCheckerboard: { newBackgroundFillColor = gDarkCheckerboardColor; } break; case kPPPreviewBackgroundType_SolidGrey: { newBackgroundFillColor = [NSColor grayColor]; } break; case kPPPreviewBackgroundType_SolidWhite: { newBackgroundFillColor = [NSColor whiteColor]; } break; case kPPPreviewBackgroundType_SolidBlack: default: { newBackgroundFillColor = [NSColor blackColor]; } break; } if (!newBackgroundFillColor) return; _backgroundType = backgroundType; [_backgroundFillColor release]; _backgroundFillColor = [newBackgroundFillColor retain]; [self setNeedsDisplay: YES]; } - (void) toggleBackgroundType { PPPreviewBackgroundType newBackgroundType = _backgroundType + 1; if (newBackgroundType >= kNumPPPreviewBackgroundTypes) { newBackgroundType = 0; } [self setBackgroundType: newBackgroundType]; } - (void) setDelegate: (id) delegate { _delegate = delegate; } - (id) delegate { return _delegate; } #pragma mark NSView overrides - (void) awakeFromNib { // check before calling [super awakeFromNib] - before 10.6, some classes didn't implement it if ([[PPPreviewView superclass] instancesRespondToSelector: @selector(awakeFromNib)]) { [super awakeFromNib]; } [self setBackgroundType: 0]; } - (void) mouseDown: (NSEvent *) theEvent { [self toggleBackgroundType]; } - (BOOL) acceptsFirstMouse: (NSEvent *) theEvent { return YES; } - (void) drawRect: (NSRect) rect { NSImageInterpolation interpolationType; // gray margin surrounding image (if draw rect is outside image bounds) if (!NSContainsRect(_scaledImageBounds, rect)) { [[NSColor lightGrayColor] set]; NSRectFill(rect); } if (NSIsEmptyRect(_imageFrame)) { return; } // image background color/pattern [_backgroundFillColor set]; NSRectFill(_scaledImageBounds); // preview image interpolationType = (_previewScale < 1.0f) ? NSImageInterpolationLow : NSImageInterpolationNone; [[NSGraphicsContext currentContext] setImageInterpolation: interpolationType]; [_image drawInRect: _scaledImageBounds fromRect: _imageFrame operation: NSCompositeSourceOver fraction: 1.0f]; } - (void) setFrameSize: (NSSize) newSize { [super setFrameSize: newSize]; _scaledImageBounds = PPGeometry_CenterRectInRect(_scaledImageBounds, [self bounds]); } #pragma mark Private methods - (void) setScale: (float) scale { if (scale >= 1.0f) { scale = floorf(scale); if (scale > kMaxPreviewScale) { scale = kMaxPreviewScale; } } else if (scale > kMaxContinuousScale) { scale = kMaxContinuousScale; } else if (scale < _minimumScaleForCurrentImage) { scale = _minimumScaleForCurrentImage; } _scaledImageBounds.size = PPGeometry_SizeScaledByFactorAndRoundedToIntegerValues(_imageFrame.size, scale); _scaledImageBounds = PPGeometry_CenterRectInRect(_scaledImageBounds, [self bounds]); if (_previewScale != scale) { _previewScale = scale; [self setNeedsDisplay: YES]; [self notifyDelegateDidChangeScale]; } } - (void) setScaleForSize: (NSSize) size isResizing: (bool) isResizing { float horizontalScale = 0.0f, verticalScale = 0.0f, newScale; if (PPGeometry_IsZeroSize(_imageFrame.size)) { return; } if (isResizing && !(_resizableDirectionsMask & kPPResizableDirectionsMask_Both)) { return; } if (!isResizing || (_resizableDirectionsMask & kPPResizableDirectionsMask_Horizontal)) { horizontalScale = [self dimensionScaleForImageWithLength: size.width onViewWithLength: _imageFrame.size.width]; } if (!isResizing || (_resizableDirectionsMask & kPPResizableDirectionsMask_Vertical)) { verticalScale = [self dimensionScaleForImageWithLength: size.height onViewWithLength: _imageFrame.size.height]; } if (isResizing) { newScale = MAX(horizontalScale, verticalScale); if (newScale > 1.0f) { newScale = roundf(newScale); } else if (newScale > kRoundoffLimitForMaxContinuousScale) { newScale = 1.0f; } } else { newScale = MIN(horizontalScale, verticalScale); } [self setScale: newScale]; } - (float) dimensionScaleForImageWithLength: (float) imageLength onViewWithLength: (float) viewLength { float scale; if (viewLength <= 0.0f) { return _minimumScaleForCurrentImage; } if (imageLength >= kMinAllowedViewDimension) { scale = imageLength / viewLength; } else { // when size is less than the minimum allowed view dimension, the scale should shrink // to zero as the size approaches half the minimum (mouse is dragging towards the // view's center) scale = (kMinAllowedViewDimension - 2.0f * (kMinAllowedViewDimension - imageLength)) / viewLength; } if (scale < _minimumScaleForCurrentImage) { scale = _minimumScaleForCurrentImage; } else if (scale > kMaxPreviewScale) { scale = kMaxPreviewScale; } return scale; } - (void) handleResizingBegin { if (_viewIsResizing) return; _viewIsResizing = YES; _resizableDirectionsMask = kPPResizableDirectionsMask_None; } - (void) handleResizingEnd { _viewIsResizing = NO; } #pragma mark Delegate notifiers - (void) notifyDelegateDidChangeScale { if ([_delegate respondsToSelector: @selector(ppPreviewView:didChangeScale:)]) { [_delegate ppPreviewView: self didChangeScale: _previewScale]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPRectSelectTool.h0000644000076500000240000000220513234403417021461 0ustar joshstaff/* PPRectSelectTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPRectSelectTool : PPTool { NSRect _canvasBounds; NSPoint _rectMoveOffset; bool _shouldSnapSelectionToGridGuidelines; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPRectSelectTool.m0000644000076500000240000002023313234403207021464 0ustar joshstaff/* PPRectSelectTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPRectSelectTool.h" #import "PPDocument.h" #import "PPCanvasView.h" #import "PPGeometry.h" #import "PPGridPattern.h" #import "PPToolUtilities.h" #import "NSCursor_PPUtilities.h" #define kRectSelectToolAttributesMask (0) @interface PPRectSelectTool (PrivateMethods) - (NSRect) selectionRectForMouseDownPoint: (NSPoint) mouseDownPoint andCurrentPoint: (NSPoint) currentPoint; - (void) updateSelectionToolOverlayOnCanvasView: (PPCanvasView *) canvasView withSelectionRect: (NSRect) selectionRect andModifierKeyFlags: (int) modifierKeyFlags forDocument: (PPDocument *) ppDocument; - (void) forceGridGuidelinesEnabled: (bool) forceGridGuidelinesEnabled onCanvasView: (PPCanvasView *) canvasView withDocument: (PPDocument *) ppDocument; - (bool) shouldClearDocumentSelectionWithSelectionRect: (NSRect) selectionRect andSelectionMode: (PPSelectionMode) selectionMode; @end @implementation PPRectSelectTool - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSRect selectionRect; _canvasBounds = PPGeometry_OriginRectOfSize([ppDocument canvasSize]); _rectMoveOffset = NSZeroPoint; _shouldSnapSelectionToGridGuidelines = NO; selectionRect = [self selectionRectForMouseDownPoint: currentPoint andCurrentPoint: currentPoint]; [self updateSelectionToolOverlayOnCanvasView: canvasView withSelectionRect: selectionRect andModifierKeyFlags: modifierKeyFlags forDocument: ppDocument]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSRect selectionRect; if (modifierKeyFlags & kModifierKeyMask_MoveRectSelectionOutline) { _rectMoveOffset = PPGeometry_PointSum(_rectMoveOffset, PPGeometry_PointDifference(currentPoint, lastPoint)); } selectionRect = [self selectionRectForMouseDownPoint: mouseDownPoint andCurrentPoint: currentPoint]; [self updateSelectionToolOverlayOnCanvasView: canvasView withSelectionRect: selectionRect andModifierKeyFlags: modifierKeyFlags forDocument: ppDocument]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSRect selectionRect; PPSelectionMode selectionMode; [canvasView clearSelectionToolOverlay]; selectionRect = [self selectionRectForMouseDownPoint: mouseDownPoint andCurrentPoint: currentPoint]; if (_shouldSnapSelectionToGridGuidelines) { selectionRect = [ppDocument gridGuidelineBoundsCoveredByRect: selectionRect]; [self forceGridGuidelinesEnabled: NO onCanvasView: canvasView withDocument: ppDocument]; } selectionMode = PPToolUtils_SelectionModeForModifierKeyFlags(modifierKeyFlags); if ([self shouldClearDocumentSelectionWithSelectionRect: selectionRect andSelectionMode: selectionMode]) { [ppDocument deselectAll]; return; } if (!NSIsEmptyRect(selectionRect)) { [ppDocument selectRect: selectionRect selectionMode: selectionMode]; } } - (NSCursor *) cursor { return [NSCursor ppRectSelectCursor]; } - (unsigned) toolAttributeFlags { return kRectSelectToolAttributesMask; } #pragma mark Private methods - (NSRect) selectionRectForMouseDownPoint: (NSPoint) mouseDownPoint andCurrentPoint: (NSPoint) currentPoint { NSPoint pinnedCornerPoint; NSRect selectionRect; pinnedCornerPoint = PPGeometry_PointSum(mouseDownPoint, _rectMoveOffset); selectionRect = PPGeometry_PixelBoundsWithCornerPoints(pinnedCornerPoint, currentPoint); return NSIntersectionRect(selectionRect, _canvasBounds); } - (void) updateSelectionToolOverlayOnCanvasView: (PPCanvasView *) canvasView withSelectionRect: (NSRect) selectionRect andModifierKeyFlags: (int) modifierKeyFlags forDocument: (PPDocument *) ppDocument { PPSelectionMode selectionMode; NSBitmapImageRep *intersectMask; NSRect toolPathRect; bool shouldSnapSelectionToGridGuidelines; selectionMode = PPToolUtils_SelectionModeForModifierKeyFlags(modifierKeyFlags); intersectMask = (selectionMode == kPPSelectionMode_Intersect) ? [ppDocument selectionMask] : nil; shouldSnapSelectionToGridGuidelines = (modifierKeyFlags & kModifierKeyMask_SnapSelectionToGuidelines) ? YES : NO; if (_shouldSnapSelectionToGridGuidelines != shouldSnapSelectionToGridGuidelines) { _shouldSnapSelectionToGridGuidelines = shouldSnapSelectionToGridGuidelines; [self forceGridGuidelinesEnabled: shouldSnapSelectionToGridGuidelines onCanvasView: canvasView withDocument: ppDocument]; } toolPathRect = selectionRect; if (_shouldSnapSelectionToGridGuidelines) { selectionRect = [ppDocument gridGuidelineBoundsCoveredByRect: selectionRect]; } [canvasView setSelectionToolOverlayToRect: selectionRect selectionMode: selectionMode intersectMask: intersectMask toolPathRect: toolPathRect]; } - (void) forceGridGuidelinesEnabled: (bool) forceGridGuidelinesEnabled onCanvasView: (PPCanvasView *) canvasView withDocument: (PPDocument *) ppDocument { PPGridPattern *gridPattern; bool shouldDisplayCanvasGrid; if ([ppDocument shouldDisplayGridAndGridGuidelines]) { return; } gridPattern = [ppDocument gridPattern]; if (forceGridGuidelinesEnabled) { gridPattern = [gridPattern gridPatternByEnablingGuidelinesVisibility]; shouldDisplayCanvasGrid = YES; } else { shouldDisplayCanvasGrid = [ppDocument shouldDisplayGrid]; } [canvasView setGridPattern: gridPattern gridVisibility: shouldDisplayCanvasGrid]; } - (bool) shouldClearDocumentSelectionWithSelectionRect: (NSRect) selectionRect andSelectionMode: (PPSelectionMode) selectionMode { if (PPGeometry_RectCoversMultiplePoints(selectionRect)) { return NO; } if (!NSIsEmptyRect(selectionRect)) // selectionRect covers single point { if ((selectionMode == kPPSelectionMode_Replace) && NSEqualPoints(_rectMoveOffset, NSZeroPoint)) { return YES; } } else // selectionRect is empty { if ((selectionMode == kPPSelectionMode_Replace) || (selectionMode == kPPSelectionMode_Intersect)) { return YES; } } return NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPRectTool.h0000644000076500000240000000202113234403417020315 0ustar joshstaff/* PPRectTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @interface PPRectTool : PPTool { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPRectTool.m0000644000076500000240000000561613234403207020334 0ustar joshstaff/* PPRectTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPRectTool.h" #import "PPDocument.h" #import "PPGeometry.h" #import "NSCursor_PPUtilities.h" #define kRectToolAttributesMask (0) @implementation PPRectTool - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [ppDocument beginDrawingWithPenMode: kPPPenMode_Fill]; [ppDocument drawPixelAtPoint: currentPoint]; } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { NSRect rect; bool shouldFillRect; if (modifierKeyFlags & kModifierKeyMask_LockAspectRatio) { currentPoint = PPGeometry_FarthestPointOnDiagonal(mouseDownPoint, currentPoint); } if (modifierKeyFlags & kModifierKeyMask_CenterShapeAtMouseDown) { rect = PPGeometry_PixelBoundsWithCenterAndCornerPoint(mouseDownPoint, currentPoint); } else { rect = PPGeometry_PixelBoundsWithCornerPoints(mouseDownPoint, currentPoint); } shouldFillRect = (modifierKeyFlags & kModifierKeyMask_FillShape) ? YES : NO; [ppDocument undoCurrentDrawingAtNextDraw]; [ppDocument drawRect: rect andFill: shouldFillRect]; } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { [ppDocument finishDrawing]; } - (NSCursor *) cursor { return [NSCursor ppRectToolCursor]; } - (unsigned) toolAttributeFlags { return kRectToolAttributesMask; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPResizableDirectionsMasks.h0000644000076500000240000000226413234403417023536 0ustar joshstaff/* PPResizableDirectionsMasks.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #define kPPResizableDirectionsMask_None (0) #define kPPResizableDirectionsMask_Horizontal (1) #define kPPResizableDirectionsMask_Vertical (2) #define kPPResizableDirectionsMask_Both (3) PikoPixel.Sources.1.0-b10b/PikoPixel/PPResizeControl.h0000644000076500000240000000271013234403417021371 0ustar joshstaff/* PPResizeControl.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPResizeControl : NSImageView { id _delegate; NSPoint _mouseDownLocation; NSPoint _initialWindowTopLeftPoint; NSSize _initialWindowSize; id _windowDelegate; } - (void) setDelegate: (id) delegate; - (id) delegate; @end @interface NSObject (PPResizeControlDelegateMethods) - (void) ppResizeControlDidBeginResizing: (PPResizeControl *) resizeControl; - (void) ppResizeControlDidFinishResizing: (PPResizeControl *) resizeControl; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPResizeControl.m0000644000076500000240000000712013234403207021373 0ustar joshstaff/* PPResizeControl.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPResizeControl.h" #import "PPGeometry.h" @interface PPResizeControl (PrivateMethods) - (void) notifyDelegateDidBeginResizing; - (void) notifyDelegateDidFinishResizing; @end @implementation PPResizeControl - (void) setDelegate: (id) delegate { _delegate = delegate; } - (id) delegate { return _delegate; } #pragma mark NSImageView overrides - (void) mouseDown: (NSEvent *) theEvent { NSWindow *window; NSRect windowFrame; window = [self window]; windowFrame = [window frame]; _mouseDownLocation = [theEvent locationInWindow]; _mouseDownLocation.y += windowFrame.origin.y; _initialWindowTopLeftPoint = NSMakePoint(windowFrame.origin.x, windowFrame.origin.y + windowFrame.size.height); _initialWindowSize = windowFrame.size; _windowDelegate = [window delegate]; if (![_windowDelegate respondsToSelector: @selector(windowWillResize:toSize:)]) { _windowDelegate = nil; } [self notifyDelegateDidBeginResizing]; } - (void) mouseDragged: (NSEvent *) theEvent { NSWindow *window; NSRect windowFrame, newWindowFrame; NSPoint currentMouseLocation, mouseOffset; window = [self window]; windowFrame = [window frame]; currentMouseLocation = [theEvent locationInWindow]; currentMouseLocation.y += windowFrame.origin.y; mouseOffset = NSMakePoint(currentMouseLocation.x - _mouseDownLocation.x, currentMouseLocation.y - _mouseDownLocation.y); newWindowFrame.size = NSMakeSize(_initialWindowSize.width + mouseOffset.x, _initialWindowSize.height - mouseOffset.y); newWindowFrame.size = [_windowDelegate windowWillResize: window toSize: newWindowFrame.size]; if (PPGeometry_IsZeroSize(newWindowFrame.size)) { goto ERROR; } newWindowFrame.origin = NSMakePoint(_initialWindowTopLeftPoint.x, _initialWindowTopLeftPoint.y - newWindowFrame.size.height); [window setFrame: newWindowFrame display: YES]; return; ERROR: return; } - (void) mouseUp: (NSEvent *) theEvent { [self notifyDelegateDidFinishResizing]; } #pragma mark Delegate notifiers - (void) notifyDelegateDidBeginResizing { if ([_delegate respondsToSelector: @selector(ppResizeControlDidBeginResizing:)]) { [_delegate ppResizeControlDidBeginResizing: self]; } } - (void) notifyDelegateDidFinishResizing { if ([_delegate respondsToSelector: @selector(ppResizeControlDidFinishResizing:)]) { [_delegate ppResizeControlDidFinishResizing: self]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPRuntimeEnvironmentMacros.h0000644000076500000240000001022213735745060023612 0ustar joshstaff/* PPRuntimeEnvironmentMacros.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #if defined(__APPLE__) # import // macro duplicates of NSAppKitVersionNumber* constant values from NSApplication.h, to allow // referencing newer system versions when building on older SDKs # define _PP_NSAppKitVersionNumber10_5 949 # define _PP_NSAppKitVersionNumber10_6 1038 # define _PP_NSAppKitVersionNumber10_7 1138 # define _PP_NSAppKitVersionNumber10_8 1187 # define _PP_NSAppKitVersionNumber10_10 1343 # define _PP_NSAppKitVersionNumber10_10_3 1347 # define _PP_NSAppKitVersionNumber10_12 1504 # define _PP_NSAppKitVersionNumber10_14 1671 # define _PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(DOT_VERSION) \ (NSAppKitVersionNumber >= _PP_NSAppKitVersionNumber10_##DOT_VERSION) # define _PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_EARLIER_THAN_10_(DOT_VERSION) \ (NSAppKitVersionNumber < _PP_NSAppKitVersionNumber10_##DOT_VERSION) # define PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_OBJC_RUNTIME_API_VERSION_2 \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(5)) # define PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_BOTTOM_SQUARE_BRACKET_UNICODE_CHAR \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(5)) # define PP_RUNTIME_CHECK__RUNTIME_INTERCEPTS_INACTIVE_MENUITEM_KEY_EQUIVALENTS \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_EARLIER_THAN_10_(5)) # define PP_RUNTIME_CHECK__RUNTIME_REQUIRES_MANUAL_SETUP_OF_AUTOSAVE_FILE_EXTENSIONS \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_EARLIER_THAN_10_(5)) # define PP_RUNTIME_CHECK__DRAWING_TO_IMAGES_IS_FASTER_THAN_DRAWING_TO_BITMAPS \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_EARLIER_THAN_10_(6)) # define PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_RETINA_DISPLAY \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(7)) # define PP_RUNTIME_CHECK__RUNTIME_OVERRIDES_CURSOR_WHEN_DRAGGING_OVER_RESIZABLE_WINDOW_EDGES \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_AT_LEAST_10_(7)) # define PP_RUNTIME_CHECK__RUNTIME_ROUNDS_OFF_SUBPIXEL_MOUSE_COORDINATES \ (_PP_RUNTIME_CHECK__MAC_OS_X_VERSION_IS_EARLIER_THAN_10_(8)) #elif defined(GNUSTEP) // !defined(__APPLE__) # define PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_OBJC_RUNTIME_API_VERSION_2 (true) # define PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_BOTTOM_SQUARE_BRACKET_UNICODE_CHAR (true) # define PP_RUNTIME_CHECK__RUNTIME_INTERCEPTS_INACTIVE_MENUITEM_KEY_EQUIVALENTS (true) # define PP_RUNTIME_CHECK__RUNTIME_REQUIRES_MANUAL_SETUP_OF_AUTOSAVE_FILE_EXTENSIONS (false) # define PP_RUNTIME_CHECK__DRAWING_TO_IMAGES_IS_FASTER_THAN_DRAWING_TO_BITMAPS (true) # define PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_RETINA_DISPLAY (false) # define PP_RUNTIME_CHECK__RUNTIME_OVERRIDES_CURSOR_WHEN_DRAGGING_OVER_RESIZABLE_WINDOW_EDGES \ (false) # define PP_RUNTIME_CHECK__RUNTIME_ROUNDS_OFF_SUBPIXEL_MOUSE_COORDINATES (false) #endif // defined(GNUSTEP) PikoPixel.Sources.1.0-b10b/PikoPixel/PPSamplerImagePanelController.h0000644000076500000240000000322713234403417024165 0ustar joshstaff/* PPSamplerImagePanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPanelController.h" @class PPSamplerImageView, PPMiniColorWell; @interface PPSamplerImagePanelController : PPPanelController { IBOutlet PPSamplerImageView *_samplerImageView; IBOutlet PPMiniColorWell *_miniColorWell; IBOutlet NSButton *_previousSamplerImageButton; IBOutlet NSButton *_nextSamplerImageButton; NSSize _sizeDifferenceBetweenPanelAndSamplerImageView; NSColor *_initialDocumentFillColor; unsigned _panelResizableDirectionsMask; bool _panelIsResizing; bool _samplerImageViewIsBrowsingOutsideImage; } - (IBAction) previousSamplerImageButtonPressed: (id) sender; - (IBAction) nextSamplerImageButtonPressed: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPSamplerImagePanelController.m0000644000076500000240000003050413234403207024165 0ustar joshstaff/* PPSamplerImagePanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPSamplerImagePanelController.h" #import "PPUIColors_Panels.h" #import "PPDocument.h" #import "PPMiniColorWell.h" #import "PPSamplerImageView.h" #import "NSObject_PPUtilities.h" #import "PPDocumentWindowController.h" #import "PPDocumentSamplerImage.h" #import "PPGeometry.h" #import "PPPanelDefaultFramePinnings.h" #define kSamplerImagePanelNibName @"SamplerImagePanel" #define kMinAllowedSamplerViewDimension 128 #define kMaxAllowedSamplerViewDimension 600 #define kDefaultImageSizeDimension 200 @interface PPSamplerImagePanelController (PrivateMethods) - (void) handlePPDocumentNotification_ChangedFillColor: (NSNotification *) notification; - (void) handlePPDocumentNotification_UpdatedSamplerImages: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedActiveSamplerImage: (NSNotification *) notification; - (void) updateSamplerPanelStateForCurrentDocument; - (void) setupWithActiveSamplerImageFromCurrentDocument; - (void) updateArrowButtonsVisibility; - (void) handleResizingBegin; - (void) handleResizingEnd; @end @implementation PPSamplerImagePanelController #pragma mark Actions - (IBAction) previousSamplerImageButtonPressed: (id) sender { [_ppDocument activatePreviousSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]; } - (IBAction) nextSamplerImageButtonPressed: (id) sender { [_ppDocument activateNextSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]; } #pragma mark NSWindowController overrides - (void) windowDidLoad { NSWindow *window; NSRect windowFrame, imageViewFrame; window = [self window]; windowFrame = [window frame]; imageViewFrame = [_samplerImageView frame]; _sizeDifferenceBetweenPanelAndSamplerImageView = PPGeometry_SizeDifference(windowFrame.size, imageViewFrame.size); // minimum size handled manually - make sure window defaults don't interfere [window setContentMinSize: NSZeroSize]; [_miniColorWell setOutlineColor: kUIColor_SamplerImagePanel_ColorWellOutline]; [_samplerImageView setSamplerImagePanelType: kPPSamplerImagePanelType_Panel minViewDimension: kMinAllowedSamplerViewDimension maxViewDimension: kMaxAllowedSamplerViewDimension defaultImageDimension: kDefaultImageSizeDimension delegate: self]; // setupWithActiveSamplerImageFromCurrentDocument will resize the window frame so it has // the correct dimensions when the frame is pinned (in [super windowDidLoad]) [self setupWithActiveSamplerImageFromCurrentDocument]; // [super windowDidLoad] may show the panel, so call as late as possible [super windowDidLoad]; } #pragma mark PPPanelController overrides + (NSString *) panelNibName { return kSamplerImagePanelNibName; } - (void) setPanelEnabled: (bool) enablePanel { if (enablePanel && ![_ppDocument hasActiveSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]) { enablePanel = NO; } [_ppDocument setShouldEnableSamplerImagePanel: enablePanel]; [self updateSamplerPanelStateForCurrentDocument]; } - (void) addAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; if (!_ppDocument) return; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ChangedFillColor:) name: PPDocumentNotification_ChangedFillColor object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_UpdatedSamplerImages:) name: PPDocumentNotification_UpdatedSamplerImages object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedActiveSamplerImage:) name: PPDocumentNotification_SwitchedActiveSamplerImage object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPDocumentNotification_ChangedFillColor object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_UpdatedSamplerImages object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_SwitchedActiveSamplerImage object: _ppDocument]; } - (PPFramePinningType) pinningTypeForDefaultWindowFrame { return kPPPanelDefaultFramePinning_SamplerImage; } - (void) setupPanelForCurrentPPDocument { // [super setupPanelForCurrentPPDocument] may show the panel, so call as late as possible [super setupPanelForCurrentPPDocument]; [self updateSamplerPanelStateForCurrentDocument]; } #pragma mark NSWindow delegate methods - (NSSize) windowWillResize: (NSWindow *) sender toSize: (NSSize) proposedFrameSize { NSSize currentFrameSize, proposedSamplerImageViewSize, newSamplerImageViewSize; currentFrameSize = [[self window] frame].size; if (!_panelIsResizing) { [self handleResizingBegin]; [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(handleResizingEnd)]; } if (NSEqualSizes(currentFrameSize, proposedFrameSize)) { goto ERROR; } if (currentFrameSize.width != proposedFrameSize.width) { _panelResizableDirectionsMask |= kPPResizableDirectionsMask_Horizontal; } if (currentFrameSize.height != proposedFrameSize.height) { _panelResizableDirectionsMask |= kPPResizableDirectionsMask_Vertical; } proposedSamplerImageViewSize = PPGeometry_SizeDifference(proposedFrameSize, _sizeDifferenceBetweenPanelAndSamplerImageView); newSamplerImageViewSize = [_samplerImageView viewSizeForResizingToProposedViewSize: proposedSamplerImageViewSize resizableDirectionsMask: _panelResizableDirectionsMask]; if (PPGeometry_IsZeroSize(newSamplerImageViewSize)) { goto ERROR; } return PPGeometry_SizeSum(newSamplerImageViewSize, _sizeDifferenceBetweenPanelAndSamplerImageView); ERROR: return currentFrameSize; } #pragma mark PPSamplerImageView delegate methods - (void) ppSamplerImageView: (PPSamplerImageView *) samplerImageView didBrowseColor: (NSColor *) color { if (samplerImageView != _samplerImageView) { return; } if (!_initialDocumentFillColor) { _initialDocumentFillColor = [[_ppDocument fillColor] retain]; } _samplerImageViewIsBrowsingOutsideImage = (color) ? NO : YES; if (!color) { color = _initialDocumentFillColor; } [_ppDocument setFillColorWithoutUndoRegistration: color]; } - (void) ppSamplerImageView: (PPSamplerImageView *) samplerImageView didSelectColor: (NSColor *) color { if (samplerImageView != _samplerImageView) { return; } _samplerImageViewIsBrowsingOutsideImage = NO; [_ppDocument setFillColorWithoutUndoRegistration: _initialDocumentFillColor]; if (color) { [_ppDocument setFillColor: color]; } [_initialDocumentFillColor release]; _initialDocumentFillColor = nil; } - (void) ppSamplerImageViewDidCancelSelection: (PPSamplerImageView *) samplerImageView { if (samplerImageView != _samplerImageView) { return; } _samplerImageViewIsBrowsingOutsideImage = NO; [_ppDocument setFillColorWithoutUndoRegistration: _initialDocumentFillColor]; [_initialDocumentFillColor release]; _initialDocumentFillColor = nil; } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_ChangedFillColor: (NSNotification *) notification { NSColor *colorWellColor = nil; if (!_samplerImageViewIsBrowsingOutsideImage) { colorWellColor = [_ppDocument fillColor]; } [_miniColorWell setColor: colorWellColor]; } - (void) handlePPDocumentNotification_UpdatedSamplerImages: (NSNotification *) notification { [self updateSamplerPanelStateForCurrentDocument]; } - (void) handlePPDocumentNotification_SwitchedActiveSamplerImage: (NSNotification *) notification { NSNumber *samplerImagePanelTypeNumber; samplerImagePanelTypeNumber = [[notification userInfo] objectForKey: PPDocumentNotification_UserInfoKey_SamplerImagePanelType]; if (samplerImagePanelTypeNumber && ([samplerImagePanelTypeNumber intValue] != kPPSamplerImagePanelType_Panel)) { return; } [self setupWithActiveSamplerImageFromCurrentDocument]; } #pragma mark Private methods - (void) updateSamplerPanelStateForCurrentDocument { bool shouldDisplayPanel = ([_ppDocument shouldEnableSamplerImagePanel] && [_ppDocument hasActiveSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]); if (shouldDisplayPanel) { // make sure panel is loaded before accessing IBOutlets if (!_panelDidLoad) { [self window]; } _samplerImageViewIsBrowsingOutsideImage = NO; [_miniColorWell setColor: [_ppDocument fillColor]]; [self updateArrowButtonsVisibility]; [self setupWithActiveSamplerImageFromCurrentDocument]; } [super setPanelEnabled: shouldDisplayPanel]; if (!_panelDidLoad) return; [_samplerImageView setupMouseTracking]; if (!shouldDisplayPanel) { if ([_samplerImageView mouseIsSamplingImage]) { [_samplerImageView forceStopSamplingImage]; } [_samplerImageView setSamplerImage: nil]; } } - (void) setupWithActiveSamplerImageFromCurrentDocument { PPDocumentSamplerImage *samplerImage; NSSize samplerImageViewSize; NSRect newWindowFrame; samplerImage = [_ppDocument activeSamplerImageForPanelType: kPPSamplerImagePanelType_Panel]; [_samplerImageView setSamplerImage: samplerImage]; if (!samplerImage) return; samplerImageViewSize = [_samplerImageView viewSizeForScaledCurrentSamplerImage]; newWindowFrame = [[self window] frame]; newWindowFrame.size = PPGeometry_SizeSum(samplerImageViewSize, _sizeDifferenceBetweenPanelAndSamplerImageView); [[self window] setFrame: newWindowFrame display: NO]; } - (void) updateArrowButtonsVisibility { bool shouldHideButtons = ([_ppDocument numSamplerImages] < 2) ? YES : NO; [_previousSamplerImageButton setHidden: shouldHideButtons]; [_nextSamplerImageButton setHidden: shouldHideButtons]; } - (void) handleResizingBegin { if (_panelIsResizing) return; _panelIsResizing = YES; [_samplerImageView disableMouseTracking: YES]; _panelResizableDirectionsMask = kPPResizableDirectionsMask_None; } - (void) handleResizingEnd { if (!_panelIsResizing) return; _panelIsResizing = NO; [_samplerImageView disableMouseTracking: NO]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPSamplerImagePanelType.h0000644000076500000240000000254513234403417022765 0ustar joshstaff/* PPSamplerImagePanelType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPSamplerImagePanelType_Panel, kPPSamplerImagePanelType_PopupPanel, // add new PPSamplerImagePanelType values above this line kNumPPSamplerImagePanelTypes } PPSamplerImagePanelType; static inline bool PPSamplerImagePanelType_IsValid(PPSamplerImagePanelType panelType) { return (((unsigned) panelType) < kNumPPSamplerImagePanelTypes) ? YES : NO; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPSamplerImagePopupPanelController.h0000644000076500000240000000307613234403417025213 0ustar joshstaff/* PPSamplerImagePopupPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanelController.h" @class PPMiniColorWell, PPSamplerImageView, PPResizeControl; @interface PPSamplerImagePopupPanelController : PPPopupPanelController { IBOutlet PPMiniColorWell *_miniColorWell; IBOutlet PPSamplerImageView *_samplerImageView; IBOutlet PPResizeControl *_resizeControl; NSSize _sizeDifferenceBetweenPanelAndSamplerImageView; NSColor *_initialDocumentFillColor; bool _samplerImageViewIsBrowsingOutsideImage; } - (IBAction) previousSamplerImageButtonPressed: (id) sender; - (IBAction) nextSamplerImageButtonPressed: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPSamplerImagePopupPanelController.m0000644000076500000240000002210613234403207025210 0ustar joshstaff/* PPSamplerImagePopupPanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPSamplerImagePopupPanelController.h" #import "PPUIColors_Panels.h" #import "PPDocument.h" #import "PPMiniColorWell.h" #import "PPSamplerImageView.h" #import "PPResizeControl.h" #import "PPPopupPanelsController.h" #import "PPPopupPanelActionKeys.h" #import "PPGeometry.h" #define kSamplerImagePopupPanelNibName @"SamplerImagePopupPanel" #define kMinAllowedSamplerViewDimension 80 #define kMaxAllowedSamplerViewDimension 700 #define kDefaultImageSizeDimension 120 @interface PPSamplerImagePopupPanelController (PrivateMethods) - (void) handlePPDocumentNotification_ChangedFillColor: (NSNotification *) notification; - (void) setupWithActiveSamplerImageFromCurrentDocument; @end @implementation PPSamplerImagePopupPanelController #pragma mark Actions - (IBAction) previousSamplerImageButtonPressed: (id) sender { [[PPPopupPanelsController sharedController] positionNextActivePopupAtCurrentPopupOrigin]; [_ppDocument activatePreviousSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; } - (IBAction) nextSamplerImageButtonPressed: (id) sender { [[PPPopupPanelsController sharedController] positionNextActivePopupAtCurrentPopupOrigin]; [_ppDocument activateNextSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; } #pragma mark NSWindowController overrides - (void) windowDidLoad { NSRect windowFrame, imageViewFrame; [super windowDidLoad]; windowFrame = [[self window] frame]; imageViewFrame = [_samplerImageView frame]; _sizeDifferenceBetweenPanelAndSamplerImageView = PPGeometry_SizeDifference(windowFrame.size, imageViewFrame.size); [_miniColorWell setOutlineColor: kUIColor_SamplerImagePopupPanel_ColorWellOutline]; [_samplerImageView setSamplerImagePanelType: kPPSamplerImagePanelType_PopupPanel minViewDimension: kMinAllowedSamplerViewDimension maxViewDimension: kMaxAllowedSamplerViewDimension defaultImageDimension: kDefaultImageSizeDimension delegate: self]; [_resizeControl setDelegate: self]; } #pragma mark PPPopupPanelController overrides + (NSString *) panelNibName { return kSamplerImagePopupPanelNibName; } - (void) addAsObserverForPPDocumentNotifications { if (!_ppDocument) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPDocumentNotification_ChangedFillColor:) name: PPDocumentNotification_ChangedFillColor object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPDocumentNotification_ChangedFillColor object: _ppDocument]; } - (void) setupPanelBeforeMakingVisible { // call setupWithActiveSamplerImageFromCurrentDocument before calling // [super setupPanelBeforeMakingVisible], because // setupWithActiveSamplerImageFromCurrentDocument may resize the panel, and // [super setupPanelBeforeMakingVisible] repositions the panel based on its size (centering // at the current mouse position) [self setupWithActiveSamplerImageFromCurrentDocument]; [super setupPanelBeforeMakingVisible]; _samplerImageViewIsBrowsingOutsideImage = NO; [_miniColorWell setColor: [_ppDocument fillColor]]; } - (void) setupPanelAfterVisibilityChange { [super setupPanelAfterVisibilityChange]; [_samplerImageView setupMouseTracking]; if (![self panelIsVisible]) { if ([_samplerImageView mouseIsSamplingImage]) { [_samplerImageView forceStopSamplingImage]; } [_samplerImageView setSamplerImage: nil]; } } - (NSColor *) backgroundColorForPopupPanel { return kUIColor_SamplerImagePopupPanel_Background; } - (bool) handleActionKey: (NSString *) key { if ([key isEqualToString: kColorsPopupPanelActionKey_NextSamplerImage]) { [_ppDocument activateNextSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; return YES; } return NO; } - (void) handleDirectionCommand: (PPDirectionType) directionType { if (directionType == kPPDirectionType_Right) { [_ppDocument activateNextSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; } else if (directionType == kPPDirectionType_Left) { [_ppDocument activatePreviousSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]; } } #pragma mark NSWindow delegate methods - (NSSize) windowWillResize: (NSWindow *) sender toSize: (NSSize) proposedFrameSize { NSSize proposedSamplerImageViewSize, newSamplerImageViewSize; proposedSamplerImageViewSize = PPGeometry_SizeDifference(proposedFrameSize, _sizeDifferenceBetweenPanelAndSamplerImageView); newSamplerImageViewSize = [_samplerImageView viewSizeForResizingToProposedViewSize: proposedSamplerImageViewSize resizableDirectionsMask: kPPResizableDirectionsMask_Both]; return PPGeometry_SizeSum(newSamplerImageViewSize, _sizeDifferenceBetweenPanelAndSamplerImageView); } #pragma mark PPSamplerImageView delegate methods - (void) ppSamplerImageView: (PPSamplerImageView *) samplerImageView didBrowseColor: (NSColor *) color { if (samplerImageView != _samplerImageView) { return; } if (!_initialDocumentFillColor) { _initialDocumentFillColor = [[_ppDocument fillColor] retain]; } _samplerImageViewIsBrowsingOutsideImage = (color) ? NO : YES; if (!color) { color = _initialDocumentFillColor; } [_ppDocument setFillColorWithoutUndoRegistration: color]; } - (void) ppSamplerImageView: (PPSamplerImageView *) samplerImageView didSelectColor: (NSColor *) color { if (samplerImageView != _samplerImageView) { return; } _samplerImageViewIsBrowsingOutsideImage = NO; [_ppDocument setFillColorWithoutUndoRegistration: _initialDocumentFillColor]; if (color) { [_ppDocument setFillColor: color]; } [_initialDocumentFillColor release]; _initialDocumentFillColor = nil; } - (void) ppSamplerImageViewDidCancelSelection: (PPSamplerImageView *) samplerImageView { if (samplerImageView != _samplerImageView) { return; } _samplerImageViewIsBrowsingOutsideImage = NO; [_ppDocument setFillColorWithoutUndoRegistration: _initialDocumentFillColor]; [_initialDocumentFillColor release]; _initialDocumentFillColor = nil; } #pragma mark PPResizeControl delegate methods - (void) ppResizeControlDidBeginResizing: (PPResizeControl *) resizeControl { [_samplerImageView disableMouseTracking: YES]; } - (void) ppResizeControlDidFinishResizing: (PPResizeControl *) resizeControl { [_samplerImageView disableMouseTracking: NO]; } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_ChangedFillColor: (NSNotification *) notification { NSColor *colorWellColor = nil; if (!_samplerImageViewIsBrowsingOutsideImage) { colorWellColor = [_ppDocument fillColor]; } [_miniColorWell setColor: colorWellColor]; } #pragma mark Private methods - (void) setupWithActiveSamplerImageFromCurrentDocument { NSSize samplerImageViewSize; NSRect newWindowFrame; [_samplerImageView setSamplerImage: [_ppDocument activeSamplerImageForPanelType: kPPSamplerImagePanelType_PopupPanel]]; samplerImageViewSize = [_samplerImageView viewSizeForScaledCurrentSamplerImage]; newWindowFrame = [[self window] frame]; newWindowFrame.size = PPGeometry_SizeSum(samplerImageViewSize, _sizeDifferenceBetweenPanelAndSamplerImageView); [[self window] setFrame: newWindowFrame display: NO]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPSamplerImageView.h0000644000076500000240000000540413234403417021773 0ustar joshstaff/* PPSamplerImageView.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPSamplerImagePanelType.h" #import "PPResizableDirectionsMasks.h" @class PPDocumentSamplerImage; @interface PPSamplerImageView : NSView { PPSamplerImagePanelType _panelType; float _minViewDimension; float _maxViewDimension; float _defaultImageDimension; id _delegate; PPDocumentSamplerImage *_samplerImage; NSRect _imageFrame; NSRect _imageDrawBounds; NSRect _imageBoundsTrackingRect; NSTrackingRectTag _imageBoundsTrackingRectTag; float _minScaleForCurrentImage; float _maxScaleForCurrentImage; NSColor *_lastSampledColor; bool _mouseIsSamplingImage; bool _mouseIsInsideImageBoundsTrackingRect; bool _disallowMouseTracking; } - (void) setSamplerImagePanelType: (PPSamplerImagePanelType) panelType minViewDimension: (float) minViewDimension maxViewDimension: (float) maxViewDimension defaultImageDimension: (float) defaultImageDimension delegate: (id) delegate; - (void) setSamplerImage: (PPDocumentSamplerImage *) samplerImage; - (NSSize) viewSizeForResizingToProposedViewSize: (NSSize) proposedViewSize resizableDirectionsMask: (unsigned) resizableDirectionsMask; - (NSSize) viewSizeForScaledCurrentSamplerImage; - (void) setupMouseTracking; - (void) disableMouseTracking: (bool) shouldDisableTracking; - (bool) mouseIsSamplingImage; - (void) forceStopSamplingImage; @end @interface NSObject (PPSamplerImageViewDelegateMethods) - (void) ppSamplerImageView: (PPSamplerImageView *) samplerImageView didBrowseColor: (NSColor *) color; - (void) ppSamplerImageView: (PPSamplerImageView *) samplerImageView didSelectColor: (NSColor *) color; - (void) ppSamplerImageViewDidCancelSelection: (PPSamplerImageView *) samplerImageView; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPSamplerImageView.m0000644000076500000240000004412013234403207021773 0ustar joshstaff/* PPSamplerImageView.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPSamplerImageView.h" #import "PPGeometry.h" #import "PPDocumentSamplerImage.h" #import "NSCursor_PPUtilities.h" #import "NSObject_PPUtilities.h" #import "PPCanvasView.h" #import "PPCursorManager.h" #import "NSColor_PPUtilities.h" #import "NSBitmapImageRep_PPUtilities.h" #define kMinAllowedValueForMinViewDimension 30 #define kMaxAllowedValueForMaxViewDimension 1000 #define kUIColor_SamplerBackgroundPattern \ [NSColor ppDiagonalCheckerboardPatternColorWithBoxDimension: 2.0f \ color1: [NSColor ppSRGBColorWithWhite: 0.42f alpha: 1.0f] \ color2: [NSColor ppSRGBColorWithWhite: 0.53f alpha: 1.0f]] static NSColor *gSamplerBackgroundColor = nil; @interface PPSamplerImageView (PrivateMethods) - (void) addAsObserverForPPSamplerImageViewNotifications; - (void) removeAsObserverForPPSamplerImageViewNotifications; - (void) handlePPSamplerImageViewNotification_FrameDidChange: (NSNotification *) notification; - (void) resetImageBoundsTrackingRect; - (void) updateCursor; - (float) defaultScaleForCurrentImage; - (void) setupMinAndMaxScalesForImageFrame; - (void) setupDrawBoundsAndTrackingForImageAndViewFrames; - (void) setSamplerImageScaleWithImageDrawBoundsAndFrame; - (void) beginSamplingImageAtWindowPoint: (NSPoint) locationInWindow; - (void) continueSamplingImageAtWindowPoint: (NSPoint) locationInWindow; - (void) finishSamplingImage; - (NSColor *) colorAtWindowPoint: (NSPoint) windowLocation; - (void) setLastSampledColor: (NSColor *) color; - (void) notifyDelegateDidBrowseColor: (NSColor *) color; - (void) notifyDelegateDidSelectColor: (NSColor *) color; - (void) notifyDelegateDidCancelSelection; @end @implementation PPSamplerImageView + (void) initialize { if ([self class] != [PPSamplerImageView class]) { return; } gSamplerBackgroundColor = [kUIColor_SamplerBackgroundPattern retain]; } - (id) initWithFrame: (NSRect) frameRect { self = [super initWithFrame: frameRect]; if (!self) goto ERROR; _minViewDimension = kMinAllowedValueForMinViewDimension; _maxViewDimension = kMaxAllowedValueForMaxViewDimension; _defaultImageDimension = kMinAllowedValueForMinViewDimension; [self addAsObserverForPPSamplerImageViewNotifications]; return self; ERROR: [self release]; return nil; } - (void) dealloc { [self removeAsObserverForPPSamplerImageViewNotifications]; [_samplerImage release]; [_lastSampledColor release]; [super dealloc]; } - (void) setSamplerImagePanelType: (PPSamplerImagePanelType) panelType minViewDimension: (float) minViewDimension maxViewDimension: (float) maxViewDimension defaultImageDimension: (float) defaultImageDimension delegate: (id) delegate { if (minViewDimension < kMinAllowedValueForMinViewDimension) { minViewDimension = kMinAllowedValueForMinViewDimension; } if (maxViewDimension > kMaxAllowedValueForMaxViewDimension) { maxViewDimension = kMaxAllowedValueForMaxViewDimension; } if (maxViewDimension < minViewDimension) { maxViewDimension = minViewDimension; } if (defaultImageDimension < minViewDimension) { defaultImageDimension = minViewDimension; } else if (defaultImageDimension > maxViewDimension) { defaultImageDimension = maxViewDimension; } _panelType = panelType; _minViewDimension = minViewDimension; _maxViewDimension = maxViewDimension; _defaultImageDimension = defaultImageDimension; _delegate = delegate; if (_samplerImage) { [self setupMinAndMaxScalesForImageFrame]; } } - (void) setSamplerImage: (PPDocumentSamplerImage *) samplerImage { NSSize samplerImageSize; if (_samplerImage == samplerImage) { return; } [_samplerImage release]; _samplerImage = [samplerImage retain]; samplerImageSize = (samplerImage) ? [samplerImage size] : NSZeroSize; _imageFrame = PPGeometry_OriginRectOfSize(samplerImageSize); [self setupMinAndMaxScalesForImageFrame]; [self setupDrawBoundsAndTrackingForImageAndViewFrames]; } - (NSSize) viewSizeForResizingToProposedViewSize: (NSSize) proposedViewSize resizableDirectionsMask: (unsigned) resizableDirectionsMask { float horizontalScale = 0.0f, verticalScale = 0.0f, scale; NSSize viewSize; if (NSIsEmptyRect(_imageFrame)) { goto ERROR; } if (!(resizableDirectionsMask & kPPResizableDirectionsMask_Both)) { goto ERROR; } if (resizableDirectionsMask & kPPResizableDirectionsMask_Horizontal) { if (proposedViewSize.width >= _minViewDimension) { horizontalScale = proposedViewSize.width / _imageFrame.size.width; } else { if (proposedViewSize.width > _minViewDimension / 2.0f) { horizontalScale = (2.0f * proposedViewSize.width - _minViewDimension) / _imageFrame.size.width; } else { horizontalScale = _minScaleForCurrentImage; } } } if (resizableDirectionsMask & kPPResizableDirectionsMask_Vertical) { if (proposedViewSize.height >= _minViewDimension) { verticalScale = proposedViewSize.height / _imageFrame.size.height; } else { if (proposedViewSize.height > _minViewDimension / 2.0f) { verticalScale = (2.0f * proposedViewSize.height - _minViewDimension) / _imageFrame.size.height; } else { verticalScale = _minScaleForCurrentImage; } } } scale = MAX(horizontalScale, verticalScale); if (scale > _maxScaleForCurrentImage) { scale = _maxScaleForCurrentImage; } else if (scale < _minScaleForCurrentImage) { scale = _minScaleForCurrentImage; } viewSize = PPGeometry_SizeScaledByFactorAndRoundedToIntegerValues(_imageFrame.size, scale); if (viewSize.width < _minViewDimension) { viewSize.width = _minViewDimension; } if (viewSize.height < _minViewDimension) { viewSize.height = _minViewDimension; } return viewSize; ERROR: return NSZeroSize; } - (NSSize) viewSizeForScaledCurrentSamplerImage { float scale; NSSize viewSize; if (!_samplerImage) goto ERROR; scale = [_samplerImage scalingFactorForSamplerImagePanelType: _panelType]; if (scale < _minScaleForCurrentImage) { scale = (scale > 0.0f) ? _minScaleForCurrentImage : [self defaultScaleForCurrentImage]; } else if (scale > _maxScaleForCurrentImage) { scale = _maxScaleForCurrentImage; } viewSize = PPGeometry_SizeScaledByFactorAndRoundedToIntegerValues(_imageFrame.size, scale); if (viewSize.width < _minViewDimension) { viewSize.width = _minViewDimension; } if (viewSize.height < _minViewDimension) { viewSize.height = _minViewDimension; } return viewSize; ERROR: return NSMakeSize(_minViewDimension, _minViewDimension); } - (void) setupMouseTracking { [self resetImageBoundsTrackingRect]; [self updateCursor]; } - (void) disableMouseTracking: (bool) shouldDisableTracking { if (_mouseIsSamplingImage) { // disallow tracking while sampling shouldDisableTracking = YES; } else { shouldDisableTracking = (shouldDisableTracking) ? YES : NO; } if (_disallowMouseTracking == shouldDisableTracking) { return; } _disallowMouseTracking = shouldDisableTracking; [self setupMouseTracking]; } - (bool) mouseIsSamplingImage { return _mouseIsSamplingImage; } - (void) forceStopSamplingImage { if (_mouseIsSamplingImage) { [self finishSamplingImage]; } } #pragma mark NSView overrides - (BOOL) acceptsFirstMouse: (NSEvent *) theEvent { return YES; } - (void) drawRect: (NSRect) rect { [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationNone]; [gSamplerBackgroundColor set]; NSRectFill(_imageDrawBounds); [[_samplerImage image] drawInRect: _imageDrawBounds fromRect: _imageFrame operation: NSCompositeSourceOver fraction: 1.0f]; } - (void) mouseDown: (NSEvent *) theEvent { [self beginSamplingImageAtWindowPoint: [theEvent locationInWindow]]; } - (void) mouseDragged: (NSEvent *) theEvent { [self continueSamplingImageAtWindowPoint: [theEvent locationInWindow]]; } - (void) mouseUp: (NSEvent *) theEvent { [self finishSamplingImage]; } - (void) mouseEntered: (NSEvent *) theEvent { NSTrackingRectTag trackingRectTag = [theEvent trackingNumber]; if (trackingRectTag == _imageBoundsTrackingRectTag) { if (!_mouseIsInsideImageBoundsTrackingRect) { _mouseIsInsideImageBoundsTrackingRect = YES; [self updateCursor]; } } else { [super mouseEntered: theEvent]; } } - (void) mouseExited: (NSEvent *) theEvent { NSTrackingRectTag trackingRectTag = [theEvent trackingNumber]; if (trackingRectTag == _imageBoundsTrackingRectTag) { if (_mouseIsInsideImageBoundsTrackingRect) { _mouseIsInsideImageBoundsTrackingRect = NO; [self updateCursor]; } } else { [super mouseExited: theEvent]; } } #pragma mark PPSamplerImageView notifications - (void) addAsObserverForPPSamplerImageViewNotifications { [self setPostsFrameChangedNotifications: YES]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPSamplerImageViewNotification_FrameDidChange:) name: NSViewFrameDidChangeNotification object: self]; } - (void) removeAsObserverForPPSamplerImageViewNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSViewFrameDidChangeNotification object: self]; } - (void) handlePPSamplerImageViewNotification_FrameDidChange: (NSNotification *) notification { [self setupDrawBoundsAndTrackingForImageAndViewFrames]; [self setSamplerImageScaleWithImageDrawBoundsAndFrame]; } #pragma mark Mouse tracking - (void) resetImageBoundsTrackingRect { NSRect newTrackingRect = NSZeroRect; bool mouseIsInsideNewTrackingRect = NO; if ([[self window] isVisible] && !_disallowMouseTracking) { newTrackingRect = _imageDrawBounds; if (!NSIsEmptyRect(newTrackingRect)) { NSPoint mouseLocationInView = [self convertPoint: [[self window] mouseLocationOutsideOfEventStream] fromView: nil]; mouseIsInsideNewTrackingRect = (NSPointInRect(mouseLocationInView, newTrackingRect)) ? YES : NO; } } if (!NSEqualRects(newTrackingRect, _imageBoundsTrackingRect)) { if (_imageBoundsTrackingRectTag) { [self removeTrackingRect: _imageBoundsTrackingRectTag]; _imageBoundsTrackingRectTag = 0; _imageBoundsTrackingRect = NSZeroRect; } if (!NSIsEmptyRect(newTrackingRect)) { _imageBoundsTrackingRectTag = [self addTrackingRect: newTrackingRect owner: self userData: NULL assumeInside: mouseIsInsideNewTrackingRect]; if (_imageBoundsTrackingRectTag) { _imageBoundsTrackingRect = newTrackingRect; } else { mouseIsInsideNewTrackingRect = NO; } } } _mouseIsInsideImageBoundsTrackingRect = mouseIsInsideNewTrackingRect; } #pragma mark Cursor updates - (void) updateCursor { NSCursor *cursor; PPCursorLevel cursorLevel; cursor = (_mouseIsInsideImageBoundsTrackingRect || _mouseIsSamplingImage) ? [NSCursor ppColorSamplerToolCursor] : nil; cursorLevel = (_panelType == kPPSamplerImagePanelType_PopupPanel) ? kPPCursorLevel_PopupPanel : kPPCursorLevel_Panel; [[PPCursorManager sharedManager] setCursor: cursor atLevel: cursorLevel isDraggingMouse: _mouseIsSamplingImage]; } #pragma mark Private methods - (float) defaultScaleForCurrentImage { float maxImageDimension; if (!_samplerImage) goto ERROR; maxImageDimension = MAX(_imageFrame.size.width, _imageFrame.size.height); return _defaultImageDimension / maxImageDimension; ERROR: return 1.0f; } - (void) setupMinAndMaxScalesForImageFrame { float maxImageDimension; if (NSIsEmptyRect(_imageFrame)) { return; } maxImageDimension = MAX(_imageFrame.size.width, _imageFrame.size.height); _maxScaleForCurrentImage = _maxViewDimension / maxImageDimension; _minScaleForCurrentImage = _minViewDimension / maxImageDimension; } - (void) setupDrawBoundsAndTrackingForImageAndViewFrames { _imageDrawBounds = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(_imageFrame.size, [self bounds].size); if ([[self window] isVisible]) { [self setupMouseTracking]; } [self setNeedsDisplay: YES]; } - (void) setSamplerImageScaleWithImageDrawBoundsAndFrame { float scale = (_imageDrawBounds.size.width / _imageFrame.size.width + _imageDrawBounds.size.height / _imageFrame.size.height) / 2.0f; [_samplerImage setScalingFactor: scale forSamplerImagePanelType: _panelType]; } - (void) beginSamplingImageAtWindowPoint: (NSPoint) locationInWindow { NSPoint locationInView; NSColor *sampledColor; locationInView = [self convertPoint: locationInWindow fromView: nil]; if (!NSPointInRect(locationInView, _imageDrawBounds)) { return; } _mouseIsSamplingImage = YES; [self disableMouseTracking: YES]; sampledColor = [self colorAtWindowPoint: locationInWindow]; if (sampledColor) { [self notifyDelegateDidBrowseColor: sampledColor]; } [self setLastSampledColor: sampledColor]; } - (void) continueSamplingImageAtWindowPoint: (NSPoint) locationInWindow { NSColor *sampledColor; if (!_mouseIsSamplingImage) return; sampledColor = [self colorAtWindowPoint: locationInWindow]; if ((sampledColor && ![_lastSampledColor isEqual: sampledColor]) || (!sampledColor && _lastSampledColor)) { [self notifyDelegateDidBrowseColor: sampledColor]; [self setLastSampledColor: sampledColor]; } } - (void) finishSamplingImage { if (!_mouseIsSamplingImage) return; _mouseIsSamplingImage = NO; [self disableMouseTracking: NO]; if (_lastSampledColor) { [self notifyDelegateDidSelectColor: _lastSampledColor]; } else { [self notifyDelegateDidCancelSelection]; } [self setLastSampledColor: nil]; } - (NSColor *) colorAtWindowPoint: (NSPoint) windowLocation { float horizontalScale, verticalScale; NSPoint viewLocation, imageLocation; horizontalScale = _imageDrawBounds.size.width / _imageFrame.size.width; verticalScale = _imageDrawBounds.size.height / _imageFrame.size.height; viewLocation = [self convertPoint: windowLocation fromView: nil]; if (!NSPointInRect(viewLocation, _imageDrawBounds)) { goto ERROR; } imageLocation = NSMakePoint(floorf((viewLocation.x - _imageDrawBounds.origin.x) / horizontalScale), floorf((viewLocation.y - _imageDrawBounds.origin.y) / verticalScale)); if (!NSPointInRect(imageLocation, _imageFrame)) { goto ERROR; } return [[_samplerImage bitmap] ppImageColorAtPoint: imageLocation]; ERROR: return nil; } - (void) setLastSampledColor: (NSColor *) color { if (_lastSampledColor == color) { return; } [_lastSampledColor release]; _lastSampledColor = [color retain]; } #pragma mark Delegate notifiers - (void) notifyDelegateDidBrowseColor: (NSColor *) color { if ([_delegate respondsToSelector: @selector(ppSamplerImageView:didBrowseColor:)]) { [_delegate ppSamplerImageView: self didBrowseColor: color]; } } - (void) notifyDelegateDidSelectColor: (NSColor *) color { if (!color) return; if ([_delegate respondsToSelector: @selector(ppSamplerImageView:didSelectColor:)]) { [_delegate ppSamplerImageView: self didSelectColor: color]; } } - (void) notifyDelegateDidCancelSelection { if ([_delegate respondsToSelector: @selector(ppSamplerImageViewDidCancelSelection:)]) { [_delegate ppSamplerImageViewDidCancelSelection: self]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPScaledImageView.h0000644000076500000240000000205113234403417021556 0ustar joshstaff/* PPScaledImageView.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPScaledImageView : NSImageView { } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPScaledImageView.m0000644000076500000240000000317313234403207021566 0ustar joshstaff/* PPScaledImageView.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPScaledImageView.h" @implementation PPScaledImageView #pragma mark NSImageView overrides - (void) awakeFromNib { // check before calling [super awakeFromNib] - before 10.6, some classes didn't implement it if ([[PPScaledImageView superclass] instancesRespondToSelector: @selector(awakeFromNib)]) { [super awakeFromNib]; } [self setImageScaling: NSScaleToFit]; } - (void) drawRect: (NSRect) rect { NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; [graphicsContext setImageInterpolation: NSImageInterpolationNone]; [graphicsContext setShouldAntialias: NO]; [super drawRect: rect]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPScreencastController.h0000644000076500000240000000404013234403417022723 0ustar joshstaff/* PPScreencastController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPOptional.h" #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING #import #define kScreencastEventsMask (NSLeftMouseDownMask \ | NSLeftMouseUpMask \ | NSKeyDownMask \ | NSKeyUpMask \ | NSFlagsChangedMask) #define kScreencastMaxSimultaneousKeysAllowed 4 @class PPScreencastPopupPanelController; @interface PPScreencastController : NSObject { PPScreencastPopupPanelController *_screencastPopupController; unichar _keysDown[kScreencastMaxSimultaneousKeysAllowed]; unsigned _numKeysDown; unsigned _currentModifierFlags; bool _screencastingIsEnabled; bool _mouseIsDown; } + (PPScreencastController *) sharedController; - (void) setEnabled: (bool) enableScreencasting; - (void) handleEvent: (NSEvent *) event; @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING PikoPixel.Sources.1.0-b10b/PikoPixel/PPScreencastController.m0000644000076500000240000002761513234403207022742 0ustar joshstaff/* PPScreencastController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPOptional.h" #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING #import "PPScreencastController.h" #import "PPScreencastPopupPanelController.h" #import "PPKeyConstants.h" #import "PPModifierKeyMasks.h" #import "NSObject_PPUtilities.h" #define kMouseDownDisplayChar ((unichar) 0x25C9) // fisheye char #define kMaxCharsInStateString (kScreencastMaxSimultaneousKeysAllowed + 6) // +6: 4 modifier keys, mousedown char, & space static unichar DisplayCharForKeyChar(unichar keyChar); @interface PPScreencastController (PrivateMethods) - (void) addAsObserverForNSApplicationNotifications; - (void) removeAsObserverForNSApplicationNotifications; - (void) handleNSApplicationNotification_WillResignActive: (NSNotification *) notification; - (void) addAsObserverForNSMenuNotifications; - (void) removeAsObserverForNSMenuNotifications; - (void) handleNSMenuNotification_DidEndTracking: (NSNotification *) notification; - (bool) handleMouseDown; - (bool) handleMouseUp; - (bool) handleKeyDown: (NSString *) key; - (bool) handleKeyUp: (NSString *) key; - (bool) handleFlagsChanged: (unsigned) modifierFlags; - (void) checkCurrentEventModiferFlags; - (int) keysDownIndexForChar: (unichar) keyChar; - (void) clearScreencastState; - (void) updateScreencastPopupStateString; @end @implementation PPScreencastController + (PPScreencastController *) sharedController { static PPScreencastController *sharedController = nil; if (!sharedController) { sharedController = [[self alloc] init]; } return sharedController; } - init { self = [super init]; if (!self) goto ERROR; if (!PP_RUNTIME_CHECK_OPTIONAL__RUNTIME_SUPPORTS_SCREENCASTING) { goto ERROR; } _screencastPopupController = [[PPScreencastPopupPanelController controller] retain]; if (!_screencastPopupController) goto ERROR; return self; ERROR: [self release]; return nil; } - (void) dealloc { [self setEnabled: NO]; [_screencastPopupController release]; [super dealloc]; } - (void) setEnabled: (bool) enableScreencasting { enableScreencasting = (enableScreencasting) ? YES : NO; if (_screencastingIsEnabled == enableScreencasting) { return; } if (enableScreencasting) { [self addAsObserverForNSApplicationNotifications]; [self addAsObserverForNSMenuNotifications]; } else { [self removeAsObserverForNSApplicationNotifications]; [self removeAsObserverForNSMenuNotifications]; } _screencastingIsEnabled = enableScreencasting; } - (void) handleEvent: (NSEvent *) event { bool needToUpdateStateString; if (!_screencastingIsEnabled) return; switch ([event type]) { case NSLeftMouseDown: { needToUpdateStateString = [self handleMouseDown]; } break; case NSLeftMouseUp: { needToUpdateStateString = [self handleMouseUp]; } break; case NSKeyDown: { needToUpdateStateString = [self handleKeyDown: [event charactersIgnoringModifiers]]; } break; case NSKeyUp: { needToUpdateStateString = [self handleKeyUp: [event charactersIgnoringModifiers]]; } break; case NSFlagsChanged: { needToUpdateStateString = [self handleFlagsChanged: [event modifierFlags]]; } break; default: { needToUpdateStateString = NO; } break; } if (needToUpdateStateString) { [self updateScreencastPopupStateString]; } } #pragma mark NSApplication notifications - (void) addAsObserverForNSApplicationNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNSApplicationNotification_WillResignActive:) name: NSApplicationWillResignActiveNotification object: NSApp]; } - (void) removeAsObserverForNSApplicationNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSApplicationWillResignActiveNotification object: NSApp]; } - (void) handleNSApplicationNotification_WillResignActive: (NSNotification *) notification { [self clearScreencastState]; } #pragma mark NSMenu notifications - (void) addAsObserverForNSMenuNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNSMenuNotification_DidEndTracking:) name: NSMenuDidEndTrackingNotification object: nil]; } - (void) removeAsObserverForNSMenuNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSMenuDidEndTrackingNotification object: nil]; } - (void) handleNSMenuNotification_DidEndTracking: (NSNotification *) notification { bool needToUpdateStateString = NO; if (_numKeysDown) { _numKeysDown = 0; needToUpdateStateString = YES; } if (needToUpdateStateString) { [self updateScreencastPopupStateString]; } [self ppPerformSelectorFromNewStackFrame: @selector(checkCurrentEventModiferFlags)]; } #pragma mark Event handlers - (bool) handleMouseDown { if (_mouseIsDown) { return NO; } _mouseIsDown = YES; return YES; } - (bool) handleMouseUp { if (!_mouseIsDown) { return NO; } _mouseIsDown = NO; return YES; } - (bool) handleKeyDown: (NSString *) key { unichar keyDownChar; key = [key uppercaseString]; if (![key length] || (_numKeysDown >= kScreencastMaxSimultaneousKeysAllowed)) { return NO; } keyDownChar = [key characterAtIndex: 0]; if ([self keysDownIndexForChar: keyDownChar] >= 0) { return NO; } _keysDown[_numKeysDown++] = keyDownChar; return YES; } - (bool) handleKeyUp: (NSString *) key { unichar keyUpChar; int keyIndex; key = [key uppercaseString]; if (![key length]) { return NO; } keyUpChar = [key characterAtIndex: 0]; keyIndex = [self keysDownIndexForChar: keyUpChar]; if (keyIndex < 0) { return NO; } _numKeysDown--; while (keyIndex < _numKeysDown) { _keysDown[keyIndex] = _keysDown[keyIndex+1]; keyIndex++; } return YES; } - (bool) handleFlagsChanged: (unsigned) modifierFlags { modifierFlags &= kModifierKeyMask_RecognizedModifierKeys; if (modifierFlags == _currentModifierFlags) { return NO; } // if the shift key is released while there's other keys down, the remaining keys can // 'stick', since their keyUp event's char may not match the initial keyDown char (for // instance, shift+'1' will keyDown as '!', but lifting the shift key before the '1' key's // released will cause keyUp with '1' instead of '!'); // to prevent keys from getting stuck, clear keys down when the shift key is released if ((_currentModifierFlags & NSShiftKeyMask) && !(modifierFlags & NSShiftKeyMask)) { _numKeysDown = 0; } _currentModifierFlags = modifierFlags; return YES; } #pragma mark Private methods - (void) checkCurrentEventModiferFlags { if ([self handleFlagsChanged: [[NSApp currentEvent] modifierFlags]]) { [self updateScreencastPopupStateString]; } } - (int) keysDownIndexForChar: (unichar) keyChar { int index; for (index=0; index<_numKeysDown; index++) { if (_keysDown[index] == keyChar) { return index; } } return -1; } - (void) clearScreencastState { _numKeysDown = 0; _currentModifierFlags = 0; _mouseIsDown = NO; [self updateScreencastPopupStateString]; } - (void) updateScreencastPopupStateString { unichar stateChars[kMaxCharsInStateString]; unsigned numStateChars = 0, index; NSString *stateString = nil; if (_currentModifierFlags & NSControlKeyMask) { stateChars[numStateChars++] = kControlKeyCharForDisplay; } if (_currentModifierFlags & NSAlternateKeyMask) { stateChars[numStateChars++] = kAlternateKeyCharForDisplay; } if (_currentModifierFlags & NSShiftKeyMask) { stateChars[numStateChars++] = kShiftKeyCharForDisplay; } if (_currentModifierFlags & NSCommandKeyMask) { stateChars[numStateChars++] = kCommandKeyCharForDisplay; } for (index=0; index<_numKeysDown; index++) { stateChars[numStateChars++] = DisplayCharForKeyChar(_keysDown[index]); } if (_mouseIsDown) { if (numStateChars) { stateChars[numStateChars++] = ' '; } stateChars[numStateChars++] = kMouseDownDisplayChar; } if (numStateChars) { stateString = [NSString stringWithCharacters: stateChars length: numStateChars]; } [_screencastPopupController setStateString: stateString]; } @end #pragma mark Private functions static unichar DisplayCharForKeyChar(unichar keyChar) { if ((keyChar >= 'a') && (keyChar <= 'z')) { keyChar += ('A' - 'a'); } else { switch (keyChar) { case NSLeftArrowFunctionKey: { keyChar = kLeftArrowKeyCharForDisplay; } break; case NSRightArrowFunctionKey: { keyChar = kRightArrowKeyCharForDisplay; } break; case NSUpArrowFunctionKey: { keyChar = kUpArrowKeyCharForDisplay; } break; case NSDownArrowFunctionKey: { keyChar = kDownArrowKeyCharForDisplay; } break; case kTabKeyChar: { keyChar = kTabKeyCharForDisplay; } break; case kReturnKeyChar: { keyChar = kReturnKeyCharForDisplay; } break; case kSpaceKeyChar: { keyChar = (PP_RUNTIME_CHECK__RUNTIME_SUPPORTS_BOTTOM_SQUARE_BRACKET_UNICODE_CHAR) ? kBottomBracketCharForSpaceKeyDisplay : kSpaceKeyChar; } break; case kEscKeyChar: { keyChar = kEscKeyCharForDisplay; } break; case NSDeleteCharacter: { keyChar = kDeleteKeyCharForDisplay; } break; default: break; } } return keyChar; } #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING PikoPixel.Sources.1.0-b10b/PikoPixel/PPScreencastPopupPanelController.h0000644000076500000240000000246013234403417024733 0ustar joshstaff/* PPScreencastPopupPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPOptional.h" #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING #import "PPPopupPanelController.h" @interface PPScreencastPopupPanelController : PPPopupPanelController { IBOutlet NSTextField *_stateTextField; } - (void) setStateString: (NSString *) stateString; @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING PikoPixel.Sources.1.0-b10b/PikoPixel/PPScreencastPopupPanelController.m0000644000076500000240000000674513234403207024747 0ustar joshstaff/* PPScreencastPopupPanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPOptional.h" #if PP_OPTIONAL__BUILD_WITH_SCREENCASTING #import "PPScreencastPopupPanelController.h" #import "PPUIColors_Panels.h" #define kScreencastPopupPanelNibName @"ScreencastPopupPanel" #define kScreencastPopupPanelBottomMargin 17.0f @interface PPScreencastPopupPanelController (PrivateMethods) - (void) setupPanelPosition; - (void) increasePanelWindowLevel; @end @implementation PPScreencastPopupPanelController - initWithWindowNibName: (NSString *) windowNibName { self = [super initWithWindowNibName: windowNibName]; if (!self) goto ERROR; if (!PP_RUNTIME_CHECK_OPTIONAL__RUNTIME_SUPPORTS_SCREENCASTING) { goto ERROR; } return self; ERROR: [self release]; return nil; } - (void) setStateString: (NSString *) stateString { // method may be called before window's loaded, so check _panelDidLoad if (stateString) { if (!_panelDidLoad) { [self window]; // force load } [_stateTextField setStringValue: stateString]; [[self window] orderFront: self]; } else { if (!_panelDidLoad) { return; } [[self window] orderOut: self]; [_stateTextField setStringValue: @""]; } } #pragma mark NSWindowController overrides - (void) windowDidLoad { [super windowDidLoad]; [self setupPanelPosition]; [self increasePanelWindowLevel]; // make sure popup stays in front of other popups } #pragma mark PPPopupPanelController overrides + (NSString *) panelNibName { return kScreencastPopupPanelNibName; } - (NSColor *) backgroundColorForPopupPanel { return kUIColor_ScreencastPopupPanel_Background; } #pragma mark Private methods - (void) setupPanelPosition { NSScreen *mainScreen; NSRect screenFrame, screenVisibleFrame, panelFrame; NSWindow *panel; NSPoint panelOrigin; mainScreen = [NSScreen mainScreen]; screenFrame = [mainScreen frame]; screenVisibleFrame = [mainScreen visibleFrame]; panel = [self window]; panelFrame = [panel frame]; panelOrigin.x = roundf(screenFrame.origin.x + ((screenFrame.size.width - panelFrame.size.width) / 2.0f)); panelOrigin.y = roundf(screenVisibleFrame.origin.y + kScreencastPopupPanelBottomMargin); [panel setFrameOrigin: panelOrigin]; } - (void) increasePanelWindowLevel { NSWindow *panel = [self window]; [panel setLevel: [panel level] + 1]; } @end #endif // PP_OPTIONAL__BUILD_WITH_SCREENCASTING PikoPixel.Sources.1.0-b10b/PikoPixel/PPSDKNativeTypes.h0000644000076500000240000000453113717102157021412 0ustar joshstaff/* PPSDKNativeTypes.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import // NSInteger: Undefined in old SDKs #ifndef NSINTEGER_DEFINED typedef int NSInteger; typedef unsigned int NSUInteger; # define NSINTEGER_DEFINED 1 #endif // NSINTEGER_DEFINED // CGFloat: Undefined in old SDKs #ifndef CGFLOAT_DEFINED typedef float CGFloat; # define CGFLOAT_DEFINED 1 #endif // CGFLOAT_DEFINED // PPSDKNativeType_NSMenuItemPtr: SDKs where the NSMenuItem protocol is deprecated use the // type (NSMenuItem *) when passing menu items for method parameters & return values, but // old SDKs where the protocol is supported use the type (id ) #if PP_SDK_DEPRECATED_NSMENUITEM_PROTOCOL typedef NSMenuItem *PPSDKNativeType_NSMenuItemPtr; #else // !PP_SDK_DEPRECATED_NSMENUITEM_PROTOCOL typedef id PPSDKNativeType_NSMenuItemPtr; #endif // PP_SDK_DEPRECATED_NSMENUITEM_PROTOCOL // PPSDKNativeType_NSWindowStyleMask: Mac SDK versions 10.12 & later define NSWindowStyleMask // as a type, and the styleMask parameter for -[NSWindow initWithContentRect:...] uses the new // type; On older SDKs, the method's styleMask parameter is an NSUInteger #if PP_SDK_HAS_NSWINDOWSTYLEMASK_TYPE typedef NSWindowStyleMask PPSDKNativeType_NSWindowStyleMask; #else // !PP_SDK_HAS_NSWINDOWSTYLEMASK_TYPE typedef NSUInteger PPSDKNativeType_NSWindowStyleMask; #endif // PP_SDK_HAS_NSWINDOWSTYLEMASK_TYPE PikoPixel.Sources.1.0-b10b/PikoPixel/PPSRGBUtilities.h0000644000076500000240000000460213717273776021245 0ustar joshstaff/* PPSRGBUtilities.h Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface NSColor (PPSRGBUtilities) + (NSColor *) ppSRGBColorWithRed: (CGFloat) red green: (CGFloat) green blue: (CGFloat) blue alpha: (CGFloat) alpha; + (NSColor *) ppSRGBColorWithWhite: (CGFloat) white alpha: (CGFloat) alpha; - (NSColor *) ppSRGBColor; - (NSColor *) ppSRGBColorBlendedWithFraction: (CGFloat) fraction ofColor: (NSColor *) otherColor; @end @interface NSBitmapImageRep (PPSRGBUtilities) - (void) ppAttachSRGBColorProfile; @end @interface NSWindow (PPSRGBUtilities) - (void) ppSetSRGBColorSpace; @end // Macros for converting sRGB values <-> Linear values // (Conversion formulas found in http://www.w3.org/Graphics/Color/srgb.pdf , under headers: // "Color component transfer function", "Inverting the color component transfer function") #define macroSRGBUtils_LinearFloatValueFromSRGBFloatValue(sRGBValue) \ ((sRGBValue > 0.04045f) ? \ powf((sRGBValue + 0.055f) / 1.055f, 2.4f) : \ sRGBValue / 12.92f) #define macroSRGBUtils_SRGBFloatValueFromLinearFloatValue(linearValue) \ ((linearValue > 0.0031308f) ? \ 1.055f * powf(linearValue, 1.0f / 2.4f) - 0.055f : \ linearValue * 12.92f) PikoPixel.Sources.1.0-b10b/PikoPixel/PPSRGBUtilities.m0000644000076500000240000001566713721403307021243 0ustar joshstaff/* PPSRGBUtilities.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPSRGBUtilities.h" @interface NSColorSpace (PPSRGBUtilitiesPrivateMethods) + (NSColorSpace *) ppSRGBColorSpace; @end @interface NSData (PPSRGBUtilitiesPrivateMethods) + (NSData *) ppSRGB_ICCProfileFromSystemFile; @end #if !PP_SDK_HAS_NSWINDOW_SETCOLORSPACE_METHOD @interface NSWindow (SetColorSpaceMethodForLegacySDKs) - (void) setColorSpace: (NSColorSpace *) colorSpace; @end #endif @implementation NSColor (PPSRGBUtilities) + (NSColor *) ppSRGBColorWithRed: (CGFloat) red green: (CGFloat) green blue: (CGFloat) blue alpha: (CGFloat) alpha { CGFloat components[4] = {red, green, blue, alpha}; return [self colorWithColorSpace: [NSColorSpace ppSRGBColorSpace] components: components count: 4]; } + (NSColor *) ppSRGBColorWithWhite: (CGFloat) white alpha: (CGFloat) alpha { return [self ppSRGBColorWithRed: white green: white blue: white alpha: alpha]; } - (NSColor *) ppSRGBColor { static NSColorSpace *sRGBColorSpace = nil; NSColor *sRGBColor; if (!sRGBColorSpace) { sRGBColorSpace = [[NSColorSpace ppSRGBColorSpace] retain]; } sRGBColor = [self colorUsingColorSpace: sRGBColorSpace]; if (!sRGBColor) goto ERROR; return sRGBColor; ERROR: return nil; } - (NSColor *) ppSRGBColorBlendedWithFraction: (CGFloat) fraction ofColor: (NSColor *) otherColor { CGFloat color1Fraction, color2Fraction, color1Components_sRGB[4], color2Components_sRGB[4], color1Component_Linear, color2Component_Linear, blendedComponent_Linear, blendedComponents_sRGB[4]; int componentIndex; self = [self ppSRGBColor]; otherColor = [otherColor ppSRGBColor]; if (!self || !otherColor) { goto ERROR; } if (fraction >= 1.0) { return otherColor; } else if (fraction <= 0.0) { return self; } color1Fraction = 1.0 - fraction; color2Fraction = fraction; [self getComponents: color1Components_sRGB]; [otherColor getComponents: color2Components_sRGB]; // RGB channels for (componentIndex=0; componentIndex<3; componentIndex++) { color1Component_Linear = macroSRGBUtils_LinearFloatValueFromSRGBFloatValue( color1Components_sRGB[componentIndex]); color2Component_Linear = macroSRGBUtils_LinearFloatValueFromSRGBFloatValue( color2Components_sRGB[componentIndex]); blendedComponent_Linear = color1Fraction * color1Component_Linear + color2Fraction * color2Component_Linear; blendedComponents_sRGB[componentIndex] = macroSRGBUtils_SRGBFloatValueFromLinearFloatValue(blendedComponent_Linear); } // Alpha channel blendedComponents_sRGB[3] = color1Fraction * color1Components_sRGB[3] + color2Fraction * color2Components_sRGB[3]; return [NSColor ppSRGBColorWithRed: blendedComponents_sRGB[0] green: blendedComponents_sRGB[1] blue: blendedComponents_sRGB[2] alpha: blendedComponents_sRGB[3]]; ERROR: return nil; } @end @implementation NSBitmapImageRep (PPSRGBUtilities) - (void) ppAttachSRGBColorProfile { #if PP_DEPLOYMENT_TARGET_SUPPORTS_COLOR_MANAGEMENT static NSData *sRGB_ICCProfile = nil; if (!sRGB_ICCProfile) { sRGB_ICCProfile = [[[NSColorSpace ppSRGBColorSpace] ICCProfileData] retain]; } if (sRGB_ICCProfile) { [self setProperty: NSImageColorSyncProfileData withValue: sRGB_ICCProfile]; } #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_COLOR_MANAGEMENT } @end @implementation NSWindow (PPSRGBUtilities) - (void) ppSetSRGBColorSpace { #if PP_DEPLOYMENT_TARGET_SUPPORTS_COLOR_MANAGEMENT static bool needToCheckSetColorSpaceSelector = YES, setColorSpaceSelectorIsSupported = NO; if (needToCheckSetColorSpaceSelector) { setColorSpaceSelectorIsSupported = ([NSWindow instancesRespondToSelector: @selector(setColorSpace:)]) ? YES : NO; needToCheckSetColorSpaceSelector = NO; } if (setColorSpaceSelectorIsSupported) { [self setColorSpace: [NSColorSpace ppSRGBColorSpace]]; } #endif // PP_DEPLOYMENT_TARGET_SUPPORTS_COLOR_MANAGEMENT } @end @implementation NSColorSpace (PPSRGBUtilitiesPrivateMethods) + (NSColorSpace *) ppSRGBColorSpace { static NSColorSpace *sRGBColorSpace = nil; if (!sRGBColorSpace) { if ([[NSColorSpace class] respondsToSelector: @selector(sRGBColorSpace)]) { sRGBColorSpace = [[[NSColorSpace class] performSelector: @selector(sRGBColorSpace)] retain]; } if (!sRGBColorSpace) { NSData *sRGB_ICCProfile = [NSData ppSRGB_ICCProfileFromSystemFile]; if (sRGB_ICCProfile) { sRGBColorSpace = [[NSColorSpace alloc] initWithICCProfileData: sRGB_ICCProfile]; } } if (!sRGBColorSpace) { // can't get sRGB - just use generic RGB sRGBColorSpace = [[NSColorSpace genericRGBColorSpace] retain]; } } return sRGBColorSpace; } @end @implementation NSData (PPSRGBUtilitiesPrivateMethods) #if defined(__APPLE__) # define kFilepath_sRGB_ICCProfile @"/System/Library/ColorSync/Profiles/sRGB Profile.icc" #else // !defined(__APPLE__) # define kFilepath_sRGB_ICCProfile nil #endif // !defined(__APPLE__) + (NSData *) ppSRGB_ICCProfileFromSystemFile { NSData *iccProfile = nil; NSString *iccProfileFilepath = kFilepath_sRGB_ICCProfile; if (iccProfileFilepath) { iccProfile = [NSData dataWithContentsOfFile: iccProfileFilepath]; } return iccProfile; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPTextAttributesDicts.h0000644000076500000240000000266213234403417022557 0ustar joshstaff/* PPTextAttributesDicts.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import extern NSDictionary *PPTextAttributesDict_ToolModifierTips_Header(void); extern NSDictionary *PPTextAttributesDict_ToolModifierTips_Subheader(void); extern NSDictionary *PPTextAttributesDict_ToolModifierTips_Tips(void); extern NSDictionary *PPTextAttributesDict_DisabledTitle_Table(void); extern NSDictionary *PPTextAttributesDict_DisabledTitle_PopupButton(void); extern NSDictionary *PPTextAttributesDict_DisabledTitle_PopupMenuItem(void); PikoPixel.Sources.1.0-b10b/PikoPixel/PPTextAttributesDicts.m0000644000076500000240000001325413234403207022560 0ustar joshstaff/* PPTextAttributesDicts.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTextAttributesDicts.h" #import "PPUIFontDefines.h" NSDictionary *PPTextAttributesDict_ToolModifierTips_Header(void) { static NSDictionary *headerAttributesDict = nil; if (!headerAttributesDict) { NSFont *font = kUIFont_ToolModifierTips_Header; NSNumber *underlineNumber = [NSNumber numberWithInt: 1]; NSColor *color = kUIFontColor_ToolModifierTips_Header; if (!font || !underlineNumber) { goto ERROR; } headerAttributesDict = [[NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, underlineNumber, NSUnderlineStyleAttributeName, color, NSForegroundColorAttributeName, nil] retain]; } return headerAttributesDict; ERROR: return nil; } NSDictionary *PPTextAttributesDict_ToolModifierTips_Subheader(void) { static NSDictionary *subheaderAttributesDict = nil; if (!subheaderAttributesDict) { NSFont *font = kUIFont_ToolModifierTips_Subheader; NSColor *color = kUIFontColor_ToolModifierTips_Subheader; if (!font) goto ERROR; subheaderAttributesDict = [[NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, color, NSForegroundColorAttributeName, nil] retain]; } return subheaderAttributesDict; ERROR: return nil; } NSDictionary *PPTextAttributesDict_ToolModifierTips_Tips(void) { static NSDictionary *tipsAttributesDict = nil; if (!tipsAttributesDict) { NSFont *font = kUIFont_ToolModifierTips_Tips; NSColor *color = kUIFontColor_ToolModifierTips_Tips; if (!font) goto ERROR; tipsAttributesDict = [[NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, color, NSForegroundColorAttributeName, nil] retain]; } return tipsAttributesDict; ERROR: return nil; } NSDictionary *PPTextAttributesDict_DisabledTitle_Table(void) { static NSDictionary *tableAttributesDict = nil; if (!tableAttributesDict) { NSFont *font = kUIFont_DisabledTitle_Table; NSColor *color = kUIFontColor_DisabledTitle_Table; if (!font || !color) { goto ERROR; } tableAttributesDict = [[NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, color, NSForegroundColorAttributeName, nil] retain]; } return tableAttributesDict; ERROR: return nil; } NSDictionary *PPTextAttributesDict_DisabledTitle_PopupButton(void) { static NSDictionary *buttonAttributesDict = nil; if (!buttonAttributesDict) { NSFont *font = kUIFont_DisabledTitle_PopupButton; NSColor *color = kUIFontColor_DisabledTitle_PopupButton; if (!font || !color) { goto ERROR; } buttonAttributesDict = [[NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, color, NSForegroundColorAttributeName, nil] retain]; } return buttonAttributesDict; ERROR: return nil; } NSDictionary *PPTextAttributesDict_DisabledTitle_PopupMenuItem(void) { static NSDictionary *menuItemAttributesDict = nil; if (!menuItemAttributesDict) { NSFont *font = kUIFont_DisabledTitle_PopupMenuItem; NSColor *color = kUIFontColor_DisabledTitle_PopupMenuItem; if (!font || !color) { goto ERROR; } menuItemAttributesDict = [[NSDictionary dictionaryWithObjectsAndKeys: font, NSFontAttributeName, color, NSForegroundColorAttributeName, nil] retain]; } return menuItemAttributesDict; ERROR: return nil; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPThumbnailImageView.h0000644000076500000240000000361713234403417022317 0ustar joshstaff/* PPThumbnailImageView.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @class PPBackgroundPattern; @interface PPThumbnailImageView : NSView { NSImage *_sourceImage; PPBackgroundPattern *_sourceBackgroundPattern; PPBackgroundPattern *_scaledBackgroundPattern; NSImage *_sourceBackgroundImage; NSRect _sourceBackgroundImageFrame; NSRect _sourceBackgroundImageDrawBounds; NSImageInterpolation _backgroundImageInterpolationType; NSBitmapImageRep *_backgroundBitmap; NSSize _viewSize; NSRect _sourceImageFrame; NSRect _scaledThumbnailImageBounds; float _thumbnailScale; NSImageInterpolation _imageInterpolationType; bool _backgroundBitmapIsDirty; } - (void) setImage: (NSImage *) image; - (void) handleUpdateToImage; - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern; - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern andBackgroundImage: (NSImage *) backgroundImage; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPThumbnailImageView.m0000644000076500000240000001634513732522302022324 0ustar joshstaff/* PPThumbnailImageView.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPThumbnailImageView.h" #import "NSBitmapImageRep_PPUtilities.h" #import "PPGeometry.h" #import "PPBackgroundPattern.h" #import "PPDefines.h" #import "PPThumbnailUtilities.h" @interface PPThumbnailImageView (PrivateMethods) - (void) resizeBackgroundBitmapWithDestinationBounds; - (bool) setupScaledBackgroundPattern; - (void) setupBackgroundImageDrawMembers; - (void) drawBackgroundBitmap; @end @implementation PPThumbnailImageView - (id) initWithFrame: (NSRect) frameRect { self = [super initWithFrame: frameRect]; if (!self) goto ERROR; _viewSize = [self frame].size; return self; ERROR: [self release]; return nil; } - (void) dealloc { [_sourceImage release]; [_sourceBackgroundPattern release]; [_scaledBackgroundPattern release]; [_sourceBackgroundImage release]; [_backgroundBitmap release]; [super dealloc]; } - (void) setImage: (NSImage *) image { NSSize imageSize; if (_sourceImage == image) { return; } [_sourceImage release]; _sourceImage = [image retain]; imageSize = (image) ? [image size] : NSZeroSize; if (!NSEqualSizes(_sourceImageFrame.size, imageSize)) { _sourceImageFrame.size = imageSize; _scaledThumbnailImageBounds = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(imageSize, _viewSize); _thumbnailScale = PPGeometry_ScalingFactorOfSourceRectToDestinationRect(_sourceImageFrame, _scaledThumbnailImageBounds); _imageInterpolationType = PPThumbUtils_ImageInterpolationForScalingFactor(_thumbnailScale); [self setupScaledBackgroundPattern]; if (_sourceBackgroundImage) { [self setupBackgroundImageDrawMembers]; } [self resizeBackgroundBitmapWithDestinationBounds]; } [self setNeedsDisplay: YES]; } - (void) handleUpdateToImage { [self setNeedsDisplay: YES]; } - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern { [self setBackgroundPattern: backgroundPattern andBackgroundImage: nil]; } - (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern andBackgroundImage: (NSImage *) backgroundImage { if (![_sourceBackgroundPattern isEqualToBackgroundPattern: backgroundPattern]) { [_sourceBackgroundPattern release]; _sourceBackgroundPattern = [backgroundPattern retain]; if ([self setupScaledBackgroundPattern]) { _backgroundBitmapIsDirty = YES; } } if (_sourceBackgroundImage != backgroundImage) { [_sourceBackgroundImage release]; _sourceBackgroundImage = [backgroundImage retain]; [self setupBackgroundImageDrawMembers]; _backgroundBitmapIsDirty = YES; } if (_backgroundBitmapIsDirty) { [self setNeedsDisplay: YES]; } } #pragma mark NSView overrides - (void) drawRect: (NSRect) rect { if (_backgroundBitmapIsDirty) { [self drawBackgroundBitmap]; } [_backgroundBitmap drawInRect: _scaledThumbnailImageBounds]; [[NSGraphicsContext currentContext] setImageInterpolation: _imageInterpolationType]; [_sourceImage drawInRect: _scaledThumbnailImageBounds fromRect: _sourceImageFrame operation: NSCompositeSourceOver fraction: 1.0f]; } #pragma mark Private methods - (void) resizeBackgroundBitmapWithDestinationBounds { if (NSIsEmptyRect(_scaledThumbnailImageBounds)) { return; } if (_backgroundBitmap) { if (NSEqualSizes(_scaledThumbnailImageBounds.size, [_backgroundBitmap ppSizeInPixels])) { return; } [_backgroundBitmap release]; } _backgroundBitmap = [[NSBitmapImageRep ppImageBitmapOfSize: _scaledThumbnailImageBounds.size] retain]; _backgroundBitmapIsDirty = YES; [self setNeedsDisplay: YES]; } - (bool) setupScaledBackgroundPattern { float scalingFactor; PPBackgroundPattern *scaledBackgroundPattern; if (!_sourceBackgroundPattern || !_sourceImage) { goto ERROR; } scalingFactor = _thumbnailScale * kScalingFactorForThumbnailBackgroundPatternSize; if (scalingFactor > 1.0f) { scalingFactor = 1.0f; } scaledBackgroundPattern = [_sourceBackgroundPattern backgroundPatternScaledByFactor: scalingFactor]; if ([_scaledBackgroundPattern isEqualToBackgroundPattern: scaledBackgroundPattern]) { return NO; } [_scaledBackgroundPattern release]; _scaledBackgroundPattern = [scaledBackgroundPattern retain]; return YES; ERROR: return NO; } - (void) setupBackgroundImageDrawMembers { if (!_sourceBackgroundImage) goto ERROR; _sourceBackgroundImageFrame = PPGeometry_OriginRectOfSize([_sourceBackgroundImage size]); if (NSIsEmptyRect(_sourceBackgroundImageFrame)) { goto ERROR; } _sourceBackgroundImageDrawBounds = PPGeometry_ScaledBoundsForFrameOfSizeToFitFrameOfSize(_sourceBackgroundImageFrame.size, _scaledThumbnailImageBounds.size); _backgroundImageInterpolationType = PPThumbUtils_ImageInterpolationForSourceRectToDestinationRect( _sourceBackgroundImageFrame, _sourceBackgroundImageDrawBounds); return; ERROR: _sourceBackgroundImageDrawBounds = NSZeroRect; return; } - (void) drawBackgroundBitmap { [_backgroundBitmap ppSetAsCurrentGraphicsContext]; [[_scaledBackgroundPattern patternFillColor] set]; NSRectFill([_backgroundBitmap ppFrameInPixels]); if (_sourceBackgroundImage) { [[NSGraphicsContext currentContext] setImageInterpolation: _backgroundImageInterpolationType]; [_sourceBackgroundImage drawInRect: _sourceBackgroundImageDrawBounds fromRect: _sourceBackgroundImageFrame operation: NSCompositeSourceOver fraction: 1.0f]; } [_backgroundBitmap ppRestoreGraphicsContext]; _backgroundBitmapIsDirty = NO; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPThumbnailUtilities.h0000644000076500000240000000253613732466207022425 0ustar joshstaff/* PPThumbnailUtilities.h Copyright 2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import NSImageInterpolation PPThumbUtils_ImageInterpolationForScalingFactor(float thumbnailScale); NSImageInterpolation PPThumbUtils_ImageInterpolationForSourceRectToDestinationRect( NSRect sourceRect, NSRect destinationRect); PikoPixel.Sources.1.0-b10b/PikoPixel/PPThumbnailUtilities.m0000644000076500000240000000370413732466207022430 0ustar joshstaff/* PPThumbnailUtilities.m Copyright 2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPThumbnailUtilities.h" #import "PPDefines.h" #import "PPGeometry.h" NSImageInterpolation PPThumbUtils_ImageInterpolationForScalingFactor(float thumbnailScale) { if (thumbnailScale <= kMaxScaleForHighInterpolationOfThumbnailImages) { return NSImageInterpolationHigh; } else if (thumbnailScale <= kMaxScaleForLowInterpolationOfThumbnailImages) { return NSImageInterpolationLow; } else { return NSImageInterpolationNone; } } NSImageInterpolation PPThumbUtils_ImageInterpolationForSourceRectToDestinationRect( NSRect sourceRect, NSRect destinationRect) { return PPThumbUtils_ImageInterpolationForScalingFactor( PPGeometry_ScalingFactorOfSourceRectToDestinationRect(sourceRect, destinationRect)); } PikoPixel.Sources.1.0-b10b/PikoPixel/PPTitleablePopUpButton.h0000644000076500000240000000332713234403417022661 0ustar joshstaff/* PPTitleablePopUpButton.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @interface PPTitleablePopUpButton : NSPopUpButton { id _delegate; NSMenu *_popupMenu; NSInteger _indexOfSelectedPopupMenuItem; } - (void) setTitle: (NSString *) title withTextAttributes: (NSDictionary *) textAttributes; - (void) setDelegate: (id) delegate; @end @interface NSObject (PPTitleablePopUpButtonDelegateMethods) - (NSString *) displayTitleForMenuItemWithTitle: (NSString *) itemTitle onTitleablePopUpButton: (PPTitleablePopUpButton *) button; - (NSDictionary *) titleTextAttributesForMenuItemAtIndex: (int) itemIndex onTitleablePopUpButton: (PPTitleablePopUpButton *) button; - (void) titleablePopUpButtonWillDisplayPopupMenu: (PPTitleablePopUpButton *) button; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPTitleablePopUpButton.m0000644000076500000240000002131613234403207022661 0ustar joshstaff/* PPTitleablePopUpButton.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTitleablePopUpButton.h" #import "NSObject_PPUtilities.h" @interface PPTitleablePopUpButton (PrivateMethods) - (void) addAsObserverForNSPopUpButtonNotifications; - (void) removeAsObserverForNSPopUpButtonNotifications; - (void) handleNSPopUpButtonNotification_WillPopUp: (NSNotification *) notification; - (void) addAsObserverForNSMenuNotifications; - (void) removeAsObserverForNSMenuNotifications; - (void) handleNSMenuNotification_WillSendAction: (NSNotification *) notification; - (void) handleNSMenuNotification_DidEndTracking: (NSNotification *) notification; - (void) updateTitle; - (void) updateTitleFromNewStackFrame; - (NSString *) displayTitleFromDelegateForSelectedMenuItem; - (NSDictionary *) titleTextAttributesFromDelegateForSelectedMenuItem; - (void) notifyDelegateWillDisplayPopupMenu; @end @implementation PPTitleablePopUpButton - (void) dealloc { [self removeAsObserverForNSPopUpButtonNotifications]; [self removeAsObserverForNSMenuNotifications]; [_popupMenu release]; [super dealloc]; } - (void) setTitle: (NSString *) title withTextAttributes: (NSDictionary *) textAttributes { NSMenu *menu; NSMenuItem *menuItem; NSAttributedString *attributedTitle; if (!title) { title = @""; } if (!textAttributes) { [self setTitle: title]; return; } menu = [[[NSMenu alloc] init] autorelease]; menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease]; attributedTitle = [[[NSAttributedString alloc] initWithString: title attributes: textAttributes] autorelease]; if (!menu || !menuItem || !attributedTitle) { goto ERROR; } [menuItem setAttributedTitle: attributedTitle]; [menu addItem: menuItem]; [super setMenu: menu]; return; ERROR: [self setTitle: title]; return; } - (void) setDelegate: (id) delegate { _delegate = delegate; } #pragma mark NSPopUpButton overrides - (void) awakeFromNib { // check before calling [super awakeFromNib] - before 10.6, some classes didn't implement it if ([[PPTitleablePopUpButton superclass] instancesRespondToSelector: @selector(awakeFromNib)]) { [super awakeFromNib]; } [_popupMenu autorelease]; _popupMenu = [[super menu] copy]; _indexOfSelectedPopupMenuItem = [self indexOfSelectedItem]; [self updateTitle]; [self addAsObserverForNSPopUpButtonNotifications]; } - (void) setMenu: (NSMenu *) menu { if (_popupMenu) { [self removeAsObserverForNSMenuNotifications]; [_popupMenu autorelease]; } _popupMenu = [menu copy]; } - (NSMenu *) menu { return _popupMenu; } - (void) selectItemAtIndex: (NSInteger) index { _indexOfSelectedPopupMenuItem = index; [self updateTitle]; } - (void) setTitle: (NSString *) aString { if (!aString) { aString = @""; } [super removeAllItems]; [super addItemWithTitle: aString]; } - (NSInteger) indexOfSelectedItem { return _indexOfSelectedPopupMenuItem; } #pragma mark NSPopUpButton notifications - (void) addAsObserverForNSPopUpButtonNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNSPopUpButtonNotification_WillPopUp:) name: NSPopUpButtonWillPopUpNotification object: self]; } - (void) removeAsObserverForNSPopUpButtonNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: NSPopUpButtonWillPopUpNotification object: self]; } - (void) handleNSPopUpButtonNotification_WillPopUp: (NSNotification *) notification { [self notifyDelegateWillDisplayPopupMenu]; [super setMenu: [[_popupMenu copy] autorelease]]; [super selectItemAtIndex: _indexOfSelectedPopupMenuItem]; [self addAsObserverForNSMenuNotifications]; } #pragma mark NSMenu notifications - (void) addAsObserverForNSMenuNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; NSMenu *menu = [super menu]; [notificationCenter addObserver: self selector: @selector(handleNSMenuNotification_WillSendAction:) name: NSMenuWillSendActionNotification object: menu]; [notificationCenter addObserver: self selector: @selector(handleNSMenuNotification_DidEndTracking:) name: NSMenuDidEndTrackingNotification object: menu]; } - (void) removeAsObserverForNSMenuNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; NSMenu *menu = [super menu]; [notificationCenter removeObserver: self name: NSMenuWillSendActionNotification object: menu]; [notificationCenter removeObserver: self name: NSMenuDidEndTrackingNotification object: menu]; } - (void) handleNSMenuNotification_WillSendAction: (NSNotification *) notification { NSMenuItem *menuItem = [[notification userInfo] objectForKey: @"MenuItem"]; _indexOfSelectedPopupMenuItem = [super indexOfItem: menuItem]; // updateTitle will remove all menu items from the menu, so retain+autorelease menuItem // to prevent its (possible) deallocation before its action is sent [[menuItem retain] autorelease]; [self updateTitle]; [self removeAsObserverForNSMenuNotifications]; } - (void) handleNSMenuNotification_DidEndTracking: (NSNotification *) notification { [self updateTitleFromNewStackFrame]; [self ppPerformSelectorFromNewStackFrame: @selector(removeAsObserverForNSMenuNotifications)]; } #pragma mark Private methods - (void) updateTitle { NSString *title = [self displayTitleFromDelegateForSelectedMenuItem]; NSDictionary *titleAttributes = [self titleTextAttributesFromDelegateForSelectedMenuItem]; [self setTitle: title withTextAttributes: titleAttributes]; } - (void) updateTitleFromNewStackFrame { [self ppPerformSelectorFromNewStackFrame: @selector(updateTitle)]; } #pragma mark Delegate notifiers - (NSString *) displayTitleFromDelegateForSelectedMenuItem { NSString *itemTitle, *displayTitle; itemTitle = [[_popupMenu itemAtIndex: _indexOfSelectedPopupMenuItem] title]; if (!itemTitle) { itemTitle = @""; } if (![_delegate respondsToSelector: @selector(displayTitleForMenuItemWithTitle: onTitleablePopUpButton:)]) { return itemTitle; } displayTitle = [_delegate displayTitleForMenuItemWithTitle: itemTitle onTitleablePopUpButton: self]; if (!displayTitle) { displayTitle = itemTitle; } return displayTitle; } - (NSDictionary *) titleTextAttributesFromDelegateForSelectedMenuItem { if ([_delegate respondsToSelector: @selector(titleTextAttributesForMenuItemAtIndex: onTitleablePopUpButton:)]) { return [_delegate titleTextAttributesForMenuItemAtIndex: _indexOfSelectedPopupMenuItem onTitleablePopUpButton: self]; } else { return nil; } } - (void) notifyDelegateWillDisplayPopupMenu { if ([_delegate respondsToSelector: @selector(titleablePopUpButtonWillDisplayPopupMenu:)]) { [_delegate titleablePopUpButtonWillDisplayPopupMenu: self]; } } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPTool.h0000644000076500000240000000547513234403417017517 0ustar joshstaff/* PPTool.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPModifierKeyMasks.h" #define kPPToolAttributeMask_RequiresPointsInViewCoordinates (1 << 0) #define kPPToolAttributeMask_RequiresPointsCroppedToCanvasBounds (1 << 1) #define kPPToolAttributeMask_DisableSkippingOfMouseDraggedEvents (1 << 2) #define kPPToolAttributeMask_DisableAutoscrolling (1 << 3) #define kPPToolAttributeMask_CursorDependsOnModifierKeys (1 << 4) #define kPPToolAttributeMask_MatchCanvasDisplayModeToOperationTarget (1 << 5) #define kPPToolAttributeMask_DisallowMatchingCanvasDisplayModeToDrawLayerTarget (1 << 6) @class PPDocument, PPCanvasView; @interface PPTool : NSObject { } + tool; - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags; - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags; - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags; - (NSCursor *) cursor; // cursorForModifierKeyFlags: - for use when _CursorDependsOnModifierKeys is set in the // toolAttributeFlags; default implementation just passes through to cursor method - (NSCursor *) cursorForModifierKeyFlags: (unsigned) modifierKeyFlags; - (unsigned) toolAttributeFlags; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPTool.m0000644000076500000240000000414313234403207017510 0ustar joshstaff/* PPTool.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPTool.h" @implementation PPTool + tool { return [[[self alloc] init] autorelease]; } - (void) mouseDownForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint modifierKeyFlags: (unsigned) modifierKeyFlags { } - (void) mouseDraggedOrModifierKeysChangedForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint lastPoint: (NSPoint) lastPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { } - (void) mouseUpForDocument: (PPDocument *) ppDocument withCanvasView: (PPCanvasView *) canvasView currentPoint: (NSPoint) currentPoint mouseDownPoint: (NSPoint) mouseDownPoint modifierKeyFlags: (unsigned) modifierKeyFlags { } - (NSCursor *) cursor { return [NSCursor crosshairCursor]; } - (NSCursor *) cursorForModifierKeyFlags: (unsigned) modifierKeyFlags { return [self cursor]; } - (unsigned) toolAttributeFlags { return 0; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolbox.h0000644000076500000240000000241413234403417020216 0ustar joshstaff/* PPToolbox.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPToolType.h" @class PPTool; @interface PPToolbox : NSObject { PPTool *_tools[kNumPPToolTypes]; } + sharedToolbox; - (PPTool *) toolOfType: (PPToolType) toolType; + (bool) getToolType: (PPToolType *) returnedToolType forKey: (NSString *) key; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolbox.m0000644000076500000240000001537013234403207020225 0ustar joshstaff/* PPToolbox.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPToolbox.h" #import "PPPencilTool.h" #import "PPEraserTool.h" #import "PPFillTool.h" #import "PPLineTool.h" #import "PPRectTool.h" #import "PPOvalTool.h" #import "PPFreehandSelectTool.h" #import "PPRectSelectTool.h" #import "PPMagicWandTool.h" #import "PPColorSamplerTool.h" #import "PPMoveTool.h" #import "PPMagnifierTool.h" #import "PPColorRampTool.h" #import "PPHotkeys.h" static NSDictionary *gHotkeyToToolTypeMapping = nil; @interface PPToolbox (PrivateMethods) + (void) addAsObserverForPPHotkeysNotifications; + (void) removeAsObserverForPPHotkeysNotifications; + (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification; + (bool) setupHotkeyToToolTypeMapping; @end @implementation PPToolbox + (void) initialize { if ([self class] != [PPToolbox class]) { return; } [PPHotkeys setupGlobals]; [self setupHotkeyToToolTypeMapping]; [self addAsObserverForPPHotkeysNotifications]; } + sharedToolbox { static PPToolbox *sharedToolbox = nil; if (!sharedToolbox) { sharedToolbox = [[self alloc] init]; } return sharedToolbox; } - init { self = [super init]; if (!self) goto ERROR; _tools[kPPToolType_Pencil] = [[PPPencilTool tool] retain]; _tools[kPPToolType_Eraser] = [[PPEraserTool tool] retain]; _tools[kPPToolType_Fill] = [[PPFillTool tool] retain]; _tools[kPPToolType_Line] = [[PPLineTool tool] retain]; _tools[kPPToolType_Rect] = [[PPRectTool tool] retain]; _tools[kPPToolType_Oval] = [[PPOvalTool tool] retain]; _tools[kPPToolType_FreehandSelect] = [[PPFreehandSelectTool tool] retain]; _tools[kPPToolType_RectSelect] = [[PPRectSelectTool tool] retain]; _tools[kPPToolType_MagicWand] = [[PPMagicWandTool tool] retain]; _tools[kPPToolType_ColorSampler] = [[PPColorSamplerTool tool] retain]; _tools[kPPToolType_Move] = [[PPMoveTool tool] retain]; _tools[kPPToolType_Magnifier] = [[PPMagnifierTool tool] retain]; _tools[kPPToolType_ColorRamp] = [[PPColorRampTool tool] retain]; return self; ERROR: [self release]; return nil; } - (void) dealloc { int i; for (i=0; i. */ #import #import "PPToolType.h" @interface PPToolButtonMatrix : NSMatrix { NSColor *_activeToolCellColor; NSColor *_inactiveToolCellColor; NSButtonCell *_highlightedCell; } - (void) highlightCellWithToolType: (PPToolType) toolType; - (NSButtonCell *) highlightedCell; - (PPToolType) toolTypeOfSelectedCell; - (PPToolType) toolTypeOfCellAtRow: (NSInteger) row column: (NSInteger) col; - (PPToolType) toolTypeOfCell: (NSCell *) cell; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolButtonMatrix.m0000644000076500000240000000614613234403207022076 0ustar joshstaff/* PPToolButtonMatrix.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPToolButtonMatrix.h" #import "NSColor_PPUtilities.h" #import "PPUIColors_Panels.h" @implementation PPToolButtonMatrix - (void) dealloc { [_activeToolCellColor release]; [_inactiveToolCellColor release]; [super dealloc]; } - (void) highlightCellWithToolType: (PPToolType) toolType { NSButtonCell *cellToHighlight; if (toolType == kPPToolType_ColorRamp) { toolType = kPPToolType_Line; } cellToHighlight = [self cellWithTag: (NSInteger) toolType]; if (_highlightedCell != cellToHighlight) { [_highlightedCell setBackgroundColor: _inactiveToolCellColor]; [cellToHighlight setBackgroundColor: _activeToolCellColor]; [self selectCell: cellToHighlight]; _highlightedCell = cellToHighlight; } } - (NSButtonCell *) highlightedCell { return _highlightedCell; } - (PPToolType) toolTypeOfSelectedCell { return [self toolTypeOfCell: [self selectedCell]]; } - (PPToolType) toolTypeOfCellAtRow: (NSInteger) row column: (NSInteger) col { return [self toolTypeOfCell: [self cellAtRow: row column: col]]; } - (PPToolType) toolTypeOfCell: (NSCell *) cell { if (!cell) goto ERROR; return (PPToolType) [cell tag]; ERROR: // return invalid PPToolType value return (PPToolType) -1; } #pragma mark NSMatrix overrides - (void) awakeFromNib { // check before calling [super awakeFromNib] - before 10.6, some classes didn't implement it if ([[PPToolButtonMatrix superclass] instancesRespondToSelector: @selector(awakeFromNib)]) { [super awakeFromNib]; } _activeToolCellColor = [[NSColor ppCenteredVerticalGradientPatternColorWithHeight: [self cellSize].height innerColor: kUIColor_ToolsPanel_ActiveToolCellGradientInnerColor outerColor: kUIColor_ToolsPanel_ActiveToolCellGradientOuterColor] retain]; _inactiveToolCellColor = [kUIColor_ToolsPanel_InactiveToolCellColor retain]; [[self cells] makeObjectsPerformSelector: @selector(setBackgroundColor:) withObject: _inactiveToolCellColor]; [self deselectAllCells]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolModifierTipsPanelController.h0000644000076500000240000000247613234403417025060 0ustar joshstaff/* PPToolModifierTipsPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPanelController.h" @interface PPToolModifierTipsPanelController : PPPanelController { IBOutlet NSTextField *_typeModifierToolNamesTextField; IBOutlet NSTextField *_typeModifierKeysTextField; IBOutlet NSTextField *_actionModifierDescriptionsTextField; IBOutlet NSTextField *_actionModifierKeysTextField; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolModifierTipsPanelController.m0000644000076500000240000001657513234403207025067 0ustar joshstaff/* PPToolModifierTipsPanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPToolModifierTipsPanelController.h" #import "PPDocument.h" #import "PPToolModifierTipsText.h" #import "PPPanelDefaultFramePinnings.h" #define kToolModifierTipsPanelNibName @"ToolModifierTipsPanel" #define kMarginForTextFields (8.0f) @interface PPToolModifierTipsPanelController (PrivateMethods) - (void) handlePPDocumentNotification_SwitchedSelectedTool: (NSNotification *) notification; - (void) handlePPDocumentNotification_SwitchedActiveTool: (NSNotification *) notification; - (void) updateTypeModifierTextFields; - (void) updateActionModifierTextFields; @end @implementation PPToolModifierTipsPanelController #pragma mark NSWindowController overrides - (void) windowDidLoad { float maxTextWidth_ModifierDescriptions, maxTextWidth_ModifierKeyNames, maxTextHeight_TypeModifiers, maxTextHeight_ActionModifiers; NSRect typeModifierToolNamesFrame, typeModifierKeysFrame, actionModifierDescriptionsFrame, actionModifierKeysFrame; NSSize contentSize; if (![PPToolModifierTipsText getMaxTextWidthForModifierDescriptions: &maxTextWidth_ModifierDescriptions maxTextWidthForModifierKeyNames: &maxTextWidth_ModifierKeyNames maxTextHeightForTypeModifiersText: &maxTextHeight_TypeModifiers maxTextHeightForActionModifiersText: &maxTextHeight_ActionModifiers]) { goto ERROR; } actionModifierDescriptionsFrame = NSMakeRect(kMarginForTextFields, kMarginForTextFields, maxTextWidth_ModifierDescriptions + kMarginForTextFields, maxTextHeight_ActionModifiers); actionModifierKeysFrame = NSMakeRect(NSMaxX(actionModifierDescriptionsFrame), kMarginForTextFields, maxTextWidth_ModifierKeyNames + kMarginForTextFields, maxTextHeight_ActionModifiers); typeModifierToolNamesFrame = NSMakeRect(kMarginForTextFields, NSMaxY(actionModifierDescriptionsFrame) + kMarginForTextFields, maxTextWidth_ModifierDescriptions + kMarginForTextFields, maxTextHeight_TypeModifiers); typeModifierKeysFrame = NSMakeRect(NSMaxX(typeModifierToolNamesFrame), NSMaxY(actionModifierKeysFrame) + kMarginForTextFields, maxTextWidth_ModifierKeyNames + kMarginForTextFields, maxTextHeight_TypeModifiers); contentSize = NSMakeSize(NSMaxX(typeModifierKeysFrame), NSMaxY(typeModifierKeysFrame) + kMarginForTextFields); [_typeModifierToolNamesTextField setFrame: typeModifierToolNamesFrame]; [_typeModifierKeysTextField setFrame: typeModifierKeysFrame]; [_actionModifierDescriptionsTextField setFrame: actionModifierDescriptionsFrame]; [_actionModifierKeysTextField setFrame: actionModifierKeysFrame]; [[self window] setContentSize: contentSize]; // [super windowDidLoad] may show the panel, so call as late as possible [super windowDidLoad]; return; ERROR: [super windowDidLoad]; } #pragma mark PPPanelController overrides + (NSString *) panelNibName { return kToolModifierTipsPanelNibName; } - (void) addAsObserverForPPDocumentNotifications { if (!_ppDocument) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedSelectedTool:) name: PPDocumentNotification_SwitchedSelectedTool object: _ppDocument]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedActiveTool:) name: PPDocumentNotification_SwitchedActiveTool object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPDocumentNotification_SwitchedSelectedTool object: _ppDocument]; [[NSNotificationCenter defaultCenter] removeObserver: self name: PPDocumentNotification_SwitchedActiveTool object: _ppDocument]; } - (bool) defaultPanelEnabledState { return YES; } - (PPFramePinningType) pinningTypeForDefaultWindowFrame { return kPPPanelDefaultFramePinning_ToolModifierTips; } - (void) setupPanelForCurrentPPDocument { [self updateTypeModifierTextFields]; [self updateActionModifierTextFields]; // [super setupPanelForCurrentPPDocument] may show the panel, so call as late as possible [super setupPanelForCurrentPPDocument]; } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_SwitchedSelectedTool: (NSNotification *) notification { [self updateTypeModifierTextFields]; } - (void) handlePPDocumentNotification_SwitchedActiveTool: (NSNotification *) notification { [self updateActionModifierTextFields]; } #pragma mark Private methods - (void) updateTypeModifierTextFields { NSAttributedString *typeModifierDescriptions, *typeModifierKeyNames; if (![PPToolModifierTipsText getTypeModifierDescriptions: &typeModifierDescriptions andTypeModifierKeyNames: &typeModifierKeyNames forToolType: [_ppDocument selectedToolType]]) { goto ERROR; } [_typeModifierToolNamesTextField setAttributedStringValue: typeModifierDescriptions]; [_typeModifierKeysTextField setAttributedStringValue: typeModifierKeyNames]; return; ERROR: return; } - (void) updateActionModifierTextFields { NSAttributedString *actionModifierDescriptions, *actionModifierKeyNames; if (![PPToolModifierTipsText getActionModifierDescriptions: &actionModifierDescriptions andActionModifierKeyNames: &actionModifierKeyNames forToolType: [_ppDocument activeToolType]]) { goto ERROR; } [_actionModifierDescriptionsTextField setAttributedStringValue: actionModifierDescriptions]; [_actionModifierKeysTextField setAttributedStringValue: actionModifierKeyNames]; return; ERROR: return; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolModifierTipsText.h0000644000076500000240000000422113234403417022667 0ustar joshstaff/* PPToolModifierTipsText.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPToolType.h" @interface PPToolModifierTipsText : NSObject { // uninstantiated class - only declared in order to use ObjC message passing // (more descriptive) instead of C functions for modifier tips text procedures } + (bool) getMaxTextWidthForModifierDescriptions: (float *) returnedMaxTextWidth_ModifierDescriptions maxTextWidthForModifierKeyNames: (float *) returnedMaxTextWidth_ModifierKeyNames maxTextHeightForTypeModifiersText: (float *) returnedMaxTextHeight_TypeModifiers maxTextHeightForActionModifiersText: (float *) returnedMaxTextHeight_ActionModifiers; + (bool) getTypeModifierDescriptions: (NSAttributedString **) returnedTypeModifierDescriptions andTypeModifierKeyNames: (NSAttributedString **) returnedTypeModifierKeyNames forToolType: (PPToolType) toolType; + (bool) getActionModifierDescriptions: (NSAttributedString **) returnedActionModifierDescriptions andActionModifierKeyNames: (NSAttributedString **) returnedActionModifierKeyNames forToolType: (PPToolType) toolType; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolModifierTipsText.m0000644000076500000240000004147013234403207022700 0ustar joshstaff/* PPToolModifierTipsText.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPToolModifierTipsText.h" #import "PPTextAttributesDicts.h" #define kToolModifierTipsStringsResourceName @"ToolModifierTipsStrings" #define kModifiersDictKey_Root_TypeModifierTitlesDict @"TypeModifierTitlesDict" #define kModifiersDictKey_Root_ActionModifierTitlesDict @"ActionModifierTitlesDict" #define kModifiersDictKey_Root_ToolModifierDicts @"ToolModifierDicts" #define kModifiersDictKey_Titles_DescriptionPrefix @"DescriptionTitlePrefix" #define kModifiersDictKey_Titles_KeyNames @"KeyNamesTitle" #define kModifiersDictKey_Titles_DefaultDescriptionSubtitle @"DefaultDescriptionSubtitle" #define kModifiersDictKey_Titles_DefaultKeyNamesSubtitle @"DefaultKeyNamesSubtitle" #define kModifiersDictKey_ToolModifiers_ToolName @"ToolName" #define kModifiersDictKey_ToolModifiers_TypeModifierDicts @"TypeModifierDicts" #define kModifiersDictKey_ToolModifiers_ActionModifierDicts @"ActionModifierDicts" #define kModifiersDictKey_Modifiers_CustomDescriptionSubtitle @"CustomDescriptionSubtitle" #define kModifiersDictKey_Modifiers_CustomKeyNamesSubtitle @"CustomKeyNamesSubtitle" #define kModifiersDictKey_Modifiers_ModifierStringDicts @"ModifierStringDicts" #define kModifiersDictKey_ModifierStrings_Description @"Description" #define kModifiersDictKey_ModifierStrings_KeyNames @"KeyNames" static bool gGlobalsHaveBeenSetUp = NO; static NSAttributedString *gTypeModifierDescriptions[kNumPPToolTypes], *gTypeModifierKeyNames[kNumPPToolTypes], *gActionModifierDescriptions[kNumPPToolTypes], *gActionModifierKeyNames[kNumPPToolTypes]; // The getModifierDescriptions:... private method (called by setupGlobals private method) is a // patch target on GNUstep, so can't call setupGloblals from +initialize, because that would // occur before the patch is installed; Instead, setupGlobals is called from within the three // get*ModifierDecriptions:... public methods (whichever gets called first), using macro, // macroValidateGlobals. #define macroValidateGlobals \ ((gGlobalsHaveBeenSetUp || [PPToolModifierTipsText setupGlobals]) ? YES : NO) @interface PPToolModifierTipsText (PrivateMethods) + (bool) setupGlobals; + (bool) getModifierDescriptions: (NSAttributedString **) returnedDescriptionsText andModifierKeyNames: (NSAttributedString **) returnedKeyNamesText forToolWithName: (NSString *) toolName usingModifierDicts: (NSArray *) modifierDicts andTitlesDict: (NSDictionary *) titlesDict; @end @implementation PPToolModifierTipsText + (bool) getMaxTextWidthForModifierDescriptions: (float *) returnedMaxTextWidth_ModifierDescriptions maxTextWidthForModifierKeyNames: (float *) returnedMaxTextWidth_ModifierKeyNames maxTextHeightForTypeModifiersText: (float *) returnedMaxTextHeight_TypeModifiers maxTextHeightForActionModifiersText: (float *) returnedMaxTextHeight_ActionModifiers { static float maxTextWidth_ModifierDescriptions = 0.0f, maxTextWidth_ModifierKeyNames = 0.0f, maxTextHeight_TypeModifiers = 0.0f, maxTextHeight_ActionModifiers = 0.0f; if (!macroValidateGlobals) goto ERROR; if (!returnedMaxTextWidth_ModifierDescriptions || !returnedMaxTextWidth_ModifierKeyNames || !returnedMaxTextHeight_TypeModifiers || !returnedMaxTextHeight_ActionModifiers) { goto ERROR; } if (maxTextWidth_ModifierDescriptions == 0.0f) { int i; NSSize textSize; for (i=0; i. */ #import "PPPanelController.h" @class PPToolButtonMatrix; @interface PPToolsPanelController : PPPanelController { IBOutlet PPToolButtonMatrix *_toolButtonMatrix; IBOutlet NSColorWell *_fillColorWell; bool _needToReactivateFillColorWell; } + sharedController; - (IBAction) toolButtonMatrixClicked: (id) sender; - (IBAction) fillColorWellUpdated: (id) sender; - (bool) fillColorWellIsActive; - (void) activateFillColorWell; - (void) toggleFillColorWell; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolsPanelController.m0000644000076500000240000002710213234403207022717 0ustar joshstaff/* PPToolsPanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPToolsPanelController.h" #import "PPDocument.h" #import "PPDefines.h" #import "PPHotkeys.h" #import "PPToolButtonMatrix.h" #import "PPHotkeyDisplayUtilities.h" #import "NSObject_PPUtilities.h" #import "PPPanelDefaultFramePinnings.h" #define kToolsPanelNibName @"ToolsPanel" static NSString *DisplayKeyForToolType(PPToolType toolType); static NSString *UpdatedTooltipForTooltipAndDisplayKey(NSString *toolTip, NSString *displayKey); @interface PPToolsPanelController (PrivateMethods) - (void) handlePPDocumentNotification_SwitchedActiveTool: (NSNotification *) notification; - (void) handlePPDocumentNotification_ChangedFillColor: (NSNotification *) notification; - (void) addAsObserverForPPHotkeysNotifications; - (void) removeAsObserverForPPHotkeysNotifications; - (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification; - (void) updateDocumentFillColor; - (void) updateToolButtonMatrix; - (void) updateFillColorWellColor; - (void) updateFillColorWellActivation; - (void) setupToolTipsWithCurrentHotkeys; @end @implementation PPToolsPanelController + (void) initialize { if ([self class] != [PPToolsPanelController class]) { return; } [PPHotkeys setupGlobals]; } + sharedController { static PPToolsPanelController *sharedController = nil; if (!sharedController) { sharedController = [[super controller] retain]; } return sharedController; } - (void) dealloc { [self removeAsObserverForPPHotkeysNotifications]; [super dealloc]; } - (bool) fillColorWellIsActive { // method may be called before window's loaded if (!_panelDidLoad) { return NO; } return [_fillColorWell isActive]; } - (void) activateFillColorWell { // method may be called before window's loaded if (!_panelDidLoad) { [self window]; // force load } if (![_fillColorWell isActive]) { [_fillColorWell performClick: self]; } } - (void) toggleFillColorWell { // method may be called before window's loaded if (!_panelDidLoad) { [self window]; // force load } [_fillColorWell performClick: self]; } #pragma mark Actions - (IBAction) toolButtonMatrixClicked: (id) sender { [_ppDocument setSelectedToolType: [_toolButtonMatrix toolTypeOfSelectedCell]]; } - (IBAction) fillColorWellUpdated: (id) sender { [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(updateDocumentFillColor)]; } #pragma mark NSWindowController overrides - (void) windowDidLoad { [self setupToolTipsWithCurrentHotkeys]; [self addAsObserverForPPHotkeysNotifications]; // [super windowDidLoad] may show the panel, so call as late as possible [super windowDidLoad]; } #pragma mark PPPanelController overrides + controller { return [self sharedController]; } + (NSString *) panelNibName { return kToolsPanelNibName; } - (void) setPPDocument: (PPDocument *) ppDocument { bool initialPPDocumentIsValid, currentPPDocumentIsValid; initialPPDocumentIsValid = (_ppDocument) ? YES : NO; [super setPPDocument: ppDocument]; currentPPDocumentIsValid = (_ppDocument) ? YES : NO; if (initialPPDocumentIsValid != currentPPDocumentIsValid) { if (_ppDocument) { [self updateFillColorWellActivation]; } else { // document may only be invalid temporarily if switching windows, so wait until // a new stack frame to update the fill colorwell's activation [self ppPerformSelectorAtomicallyFromNewStackFrame: @selector(updateFillColorWellActivation)]; } } } - (void) setPanelVisibilityAllowed: (bool) allowPanelVisibility { bool initialAllowVisibility = _allowPanelVisibility; [super setPanelVisibilityAllowed: allowPanelVisibility]; if (_allowPanelVisibility != initialAllowVisibility) { [self updateFillColorWellActivation]; } } - (void) addAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; if (!_ppDocument) return; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedActiveTool:) name: PPDocumentNotification_SwitchedActiveTool object: _ppDocument]; [notificationCenter addObserver: self selector: @selector(handlePPDocumentNotification_ChangedFillColor:) name: PPDocumentNotification_ChangedFillColor object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter removeObserver: self name: PPDocumentNotification_SwitchedActiveTool object: _ppDocument]; [notificationCenter removeObserver: self name: PPDocumentNotification_ChangedFillColor object: _ppDocument]; } - (bool) defaultPanelEnabledState { return YES; } - (PPFramePinningType) pinningTypeForDefaultWindowFrame { return kPPPanelDefaultFramePinning_Tools; } - (void) setupPanelForCurrentPPDocument { [self updateToolButtonMatrix]; [self updateFillColorWellColor]; // [super setupPanelForCurrentPPDocument] may show the panel, so call as late as possible [super setupPanelForCurrentPPDocument]; } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_SwitchedActiveTool: (NSNotification *) notification { [self updateToolButtonMatrix]; } - (void) handlePPDocumentNotification_ChangedFillColor: (NSNotification *) notification { [self updateFillColorWellColor]; } #pragma mark PPHotkeys notifications - (void) addAsObserverForPPHotkeysNotifications { [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPHotkeysNotification_UpdatedHotkeys:) name: PPHotkeysNotification_UpdatedHotkeys object: nil]; } - (void) removeAsObserverForPPHotkeysNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPHotkeysNotification_UpdatedHotkeys object: nil]; } - (void) handlePPHotkeysNotification_UpdatedHotkeys: (NSNotification *) notification { [self setupToolTipsWithCurrentHotkeys]; } #pragma mark Private methods - (void) updateDocumentFillColor { [_ppDocument setFillColor: [_fillColorWell color]]; } - (void) updateToolButtonMatrix { [_toolButtonMatrix highlightCellWithToolType: [_ppDocument activeToolType]]; } - (void) updateFillColorWellColor { [_fillColorWell setColor: [_ppDocument fillColor]]; } - (void) updateFillColorWellActivation { bool canActivateFillColorWell = (_allowPanelVisibility && _ppDocument) ? YES : NO; if (canActivateFillColorWell) { if (_needToReactivateFillColorWell) { if (![_fillColorWell isActive]) { [_fillColorWell activate: YES]; } _needToReactivateFillColorWell = NO; } } else { if ([_fillColorWell isActive]) { [_fillColorWell deactivate]; _needToReactivateFillColorWell = YES; } } } - (void) setupToolTipsWithCurrentHotkeys { NSEnumerator *cellEnumerator; NSCell *cell; NSString *displayKey, *newToolTip; // tools matrix cellEnumerator = [[_toolButtonMatrix cells] objectEnumerator]; while (cell = [cellEnumerator nextObject]) { displayKey = DisplayKeyForToolType([_toolButtonMatrix toolTypeOfCell: cell]); newToolTip = UpdatedTooltipForTooltipAndDisplayKey([_toolButtonMatrix toolTipForCell: cell], displayKey); [_toolButtonMatrix setToolTip: newToolTip forCell: cell]; } // color well displayKey = PPDisplayKeyForHotkey(gHotkeys[kPPHotkeyType_ToggleColorPickerPanel]); newToolTip = UpdatedTooltipForTooltipAndDisplayKey([_fillColorWell toolTip], displayKey); [_fillColorWell setToolTip: newToolTip]; } @end #pragma mark Private functions static NSString *DisplayKeyForToolType(PPToolType toolType) { NSString *hotkey; switch (toolType) { case kPPToolType_Pencil: { hotkey = gHotkeys[kPPHotkeyType_Tool_Pencil]; } break; case kPPToolType_Fill: { hotkey = gHotkeys[kPPHotkeyType_Tool_Fill]; } break; case kPPToolType_Line: { hotkey = gHotkeys[kPPHotkeyType_Tool_Line]; } break; case kPPToolType_Rect: { hotkey = gHotkeys[kPPHotkeyType_Tool_Rect]; } break; case kPPToolType_Oval: { hotkey = gHotkeys[kPPHotkeyType_Tool_Oval]; } break; case kPPToolType_Eraser: { hotkey = gHotkeys[kPPHotkeyType_Tool_Eraser]; } break; case kPPToolType_ColorSampler: { hotkey = gHotkeys[kPPHotkeyType_Tool_ColorSampler]; } break; case kPPToolType_Magnifier: { hotkey = gHotkeys[kPPHotkeyType_Tool_Magnifier]; } break; case kPPToolType_RectSelect: { hotkey = gHotkeys[kPPHotkeyType_Tool_RectSelect]; } break; case kPPToolType_MagicWand: { hotkey = gHotkeys[kPPHotkeyType_Tool_MagicWand]; } break; case kPPToolType_FreehandSelect: { hotkey = gHotkeys[kPPHotkeyType_Tool_FreehandSelect]; } break; case kPPToolType_Move: { hotkey = gHotkeys[kPPHotkeyType_Tool_Move]; } break; default: { hotkey = @""; } break; } return PPDisplayKeyForHotkey(hotkey); } static NSString *UpdatedTooltipForTooltipAndDisplayKey(NSString *toolTip, NSString *displayKey) { if ([toolTip length]) { NSRange rangeOfParenthesis = [toolTip rangeOfString: @"("]; if (rangeOfParenthesis.length) { toolTip = [toolTip substringToIndex: rangeOfParenthesis.location]; } } if (!toolTip) { toolTip = @""; } if ([displayKey length]) { toolTip = [NSString stringWithFormat: @"%@(%C)", toolTip, [displayKey characterAtIndex: 0]]; } return toolTip; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolsPopupPanelController.h0000644000076500000240000000232713234403417023743 0ustar joshstaff/* PPToolsPopupPanelController.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPPopupPanelController.h" @class PPToolButtonMatrix; @interface PPToolsPopupPanelController : PPPopupPanelController { IBOutlet PPToolButtonMatrix *_toolButtonMatrix; } - (IBAction) toolButtonMatrixClicked: (id) sender; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolsPopupPanelController.m0000644000076500000240000001100713234403207023740 0ustar joshstaff/* PPToolsPopupPanelController.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPToolsPopupPanelController.h" #import "PPToolButtonMatrix.h" #import "PPDocument.h" #import "PPUIColors_Panels.h" #import "PPPopupPanelActionKeys.h" #define kToolsPopupPanelNibName @"ToolsPopupPanel" @interface PPToolsPopupPanelController (PrivateMethods) - (void) handlePPDocumentNotification_SwitchedActiveTool: (NSNotification *) notification; - (void) updateToolButtonMatrix; @end @implementation PPToolsPopupPanelController #pragma mark Actions - (IBAction) toolButtonMatrixClicked: (id) sender { [_ppDocument setSelectedToolType: [_toolButtonMatrix toolTypeOfSelectedCell]]; } #pragma mark PPPopupPanelController overrides + (NSString *) panelNibName { return kToolsPopupPanelNibName; } - (void) addAsObserverForPPDocumentNotifications { if (!_ppDocument) return; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handlePPDocumentNotification_SwitchedActiveTool:) name: PPDocumentNotification_SwitchedActiveTool object: _ppDocument]; } - (void) removeAsObserverForPPDocumentNotifications { [[NSNotificationCenter defaultCenter] removeObserver: self name: PPDocumentNotification_SwitchedActiveTool object: _ppDocument]; } - (void) setupPanelForCurrentPPDocument { [super setupPanelForCurrentPPDocument]; [self updateToolButtonMatrix]; } - (NSColor *) backgroundColorForPopupPanel { return kUIColor_ToolsPopupPanel_Background; } - (bool) handleActionKey: (NSString *) key { if ([key isEqualToString: kToolsPopupPanelActionKey_SelectLastTool]) { [_ppDocument setSelectedToolTypeToLastSelectedType]; return YES; } return NO; } - (void) handleDirectionCommand: (PPDirectionType) directionType { NSInteger numRows, numCols, cellRow, cellCol; NSCell *highlightedCell; [_toolButtonMatrix getNumberOfRows: &numRows columns: &numCols]; highlightedCell = [_toolButtonMatrix highlightedCell]; if (!highlightedCell || ![_toolButtonMatrix getRow: &cellRow column: &cellCol ofCell: highlightedCell]) { goto ERROR; } switch (directionType) { case kPPDirectionType_Left: { if (--cellCol < 0) { cellCol = numCols - 1; } } break; case kPPDirectionType_Right: { if (++cellCol >= numCols) { cellCol = 0; } } break; case kPPDirectionType_Up: { if (--cellRow < 0) { cellRow = numRows - 1; } } break; case kPPDirectionType_Down: { if (++cellRow >= numRows) { cellRow = 0; } } break; default: { goto ERROR; } break; } [_ppDocument setSelectedToolType: [_toolButtonMatrix toolTypeOfCellAtRow: cellRow column: cellCol]]; return; ERROR: return; } #pragma mark PPDocument notifications - (void) handlePPDocumentNotification_SwitchedActiveTool: (NSNotification *) notification { [self updateToolButtonMatrix]; } #pragma mark Private methods - (void) updateToolButtonMatrix { [_toolButtonMatrix highlightCellWithToolType: [_ppDocument activeToolType]]; } @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolType.h0000644000076500000240000000506413234403417020353 0ustar joshstaff/* PPToolType.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ typedef enum { kPPToolType_Pencil, kPPToolType_Eraser, kPPToolType_Fill, kPPToolType_Line, kPPToolType_Rect, kPPToolType_Oval, kPPToolType_FreehandSelect, kPPToolType_RectSelect, kPPToolType_MagicWand, kPPToolType_ColorSampler, kPPToolType_Move, kPPToolType_Magnifier, kPPToolType_ColorRamp, // not shown in Tools panel; activated via Line Tool + modifier keys // add new PPToolType values above this line kNumPPToolTypes } PPToolType; static inline bool PPToolType_IsValid(PPToolType toolType) { return (((unsigned) toolType) < kNumPPToolTypes) ? YES : NO; } // PPToolTypeMask #define kPPToolTypeMask_Pencil (1 << kPPToolType_Pencil) #define kPPToolTypeMask_Eraser (1 << kPPToolType_Eraser) #define kPPToolTypeMask_Fill (1 << kPPToolType_Fill) #define kPPToolTypeMask_Line (1 << kPPToolType_Line) #define kPPToolTypeMask_Rect (1 << kPPToolType_Rect) #define kPPToolTypeMask_Oval (1 << kPPToolType_Oval) #define kPPToolTypeMask_FreehandSelect (1 << kPPToolType_FreehandSelect) #define kPPToolTypeMask_RectSelect (1 << kPPToolType_RectSelect) #define kPPToolTypeMask_MagicWand (1 << kPPToolType_MagicWand) #define kPPToolTypeMask_ColorSampler (1 << kPPToolType_ColorSampler) #define kPPToolTypeMask_Move (1 << kPPToolType_Move) #define kPPToolTypeMask_Magnifier (1 << kPPToolType_Magnifier) #define kPPToolTypeMask_ColorRamp (1 << kPPToolType_ColorRamp) static inline unsigned PPToolTypeMaskForPPToolType(PPToolType toolType) { return (1 << toolType); } PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolUtilities.h0000644000076500000240000000253113234403417021401 0ustar joshstaff/* PPToolUtilities.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPDocumentTypes.h" PPSelectionMode PPToolUtils_SelectionModeForModifierKeyFlags(int modifierKeyFlags); PPPixelMatchingMode PPToolUtils_PixelMatchingModeForModifierKeyFlags(int modifierKeyFlags); PPMoveOperationType PPToolUtils_InteractiveMoveTypeForModifierKeyFlags(int modifierKeyFlags); unsigned PPToolUtils_ColorMatchToleranceForMouseDistance(unsigned mouseDistance); PikoPixel.Sources.1.0-b10b/PikoPixel/PPToolUtilities.m0000644000076500000240000000670413757346253021432 0ustar joshstaff/* PPToolUtilities.m Copyright 2013-2018,2020 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPToolUtilities.h" #import "PPDefines.h" #import "PPModifierKeyMasks.h" PPSelectionMode PPToolUtils_SelectionModeForModifierKeyFlags(int modifierKeyFlags) { if ((modifierKeyFlags & kModifierKeyMask_IntersectSelection) == kModifierKeyMask_IntersectSelection) { return kPPSelectionMode_Intersect; } else if (modifierKeyFlags & kModifierKeyMask_AddToSelection) { return kPPSelectionMode_Add; } else if (modifierKeyFlags & kModifierKeyMask_CutFromSelection) { return kPPSelectionMode_Subtract; } else { return kPPSelectionMode_Replace; } } PPPixelMatchingMode PPToolUtils_PixelMatchingModeForModifierKeyFlags(int modifierKeyFlags) { if (modifierKeyFlags & kModifierKeyMask_MatchGlobally) { return kPPPixelMatchingMode_Anywhere; } else if (modifierKeyFlags & kModifierKeyMask_MatchDiagonally) { return kPPPixelMatchingMode_BordersAndDiagonals; } else { return kPPPixelMatchingMode_Borders; } } PPMoveOperationType PPToolUtils_InteractiveMoveTypeForModifierKeyFlags(int modifierKeyFlags) { if (modifierKeyFlags & kModifierKeyMask_MoveACopy) { return kPPMoveOperationType_LeaveCopyInPlace; } else if (modifierKeyFlags & kModifierKeyMask_MoveSelectionOutlineOnly) { return kPPMoveOperationType_SelectionOutlineOnly; } else { return kPPMoveOperationType_Normal; } } unsigned PPToolUtils_ColorMatchToleranceForMouseDistance(unsigned mouseDistance) { // returns tolerance value, 0-255, calculated from the normalized square of the mouse // distance (normalized to kMatchToolToleranceIndicator_MaxRadius), with some biased // rounding (to reduce the range over which the tolerance stays at zero); // the normalized squaring is done to make the tolerance less sensitive to mouse movement // (more precise) at the lower end of the tolerance range, since that's where precision is // more likely to be needed (tolerance values around 0-50) if (mouseDistance > kMatchToolToleranceIndicator_MaxRadius) { mouseDistance = kMatchToolToleranceIndicator_MaxRadius; } return (unsigned) ceilf(-0.2f // -0.2 offset reduces bias of ceilf + (float) (255 * mouseDistance * mouseDistance) / ((float) (kMatchToolToleranceIndicator_MaxRadius * kMatchToolToleranceIndicator_MaxRadius))); } PikoPixel.Sources.1.0-b10b/PikoPixel/PPUIColors_Panels.h0000644000076500000240000000606613234403417021600 0ustar joshstaff/* PPUIColors_Panels.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPSRGBUtilities.h" // Popup Panel backgrounds #define kUIColor_ToolsPopupPanel_Background \ [NSColor ppSRGBColorWithRed: 0.0f green: 0.25f blue: 0.0f alpha: 0.85f] #define kUIColor_ColorPickerPopupPanel_Background \ [NSColor ppSRGBColorWithWhite: 0.2f alpha: 0.85f] #define kUIColor_SamplerImagePopupPanel_Background \ [NSColor ppSRGBColorWithWhite: 0.2f alpha: 0.95f] #define kUIColor_LayerControlsPopupPanel_Background \ [NSColor ppSRGBColorWithRed: 0.32f green: 0.0f blue: 0.0f alpha: 0.85f] #define kUIColor_NavigatorPopupPanel_Background \ [NSColor ppSRGBColorWithRed: 0.0f green: 0.0f blue: 0.26f alpha: 0.85f] #define kUIColor_ScreencastPopupPanel_Background \ [NSColor ppSRGBColorWithRed: 0.92f green: 0.96f blue: 1.0f alpha: 0.95f] #define kUIColor_DefaultPopupPanelBackground \ [NSColor ppSRGBColorWithWhite: 0.0f alpha: 0.85f] // Tools Panel & Popup Panel #define kUIColor_ToolsPanel_ActiveToolCellGradientInnerColor \ [NSColor ppSRGBColorWithRed: 0.63f green: 0.64f blue: 0.64f alpha: 1.0f] #define kUIColor_ToolsPanel_ActiveToolCellGradientOuterColor \ [NSColor ppSRGBColorWithRed: 0.52f green: 0.53f blue: 0.53f alpha: 1.0f] #define kUIColor_ToolsPanel_InactiveToolCellColor \ [NSColor ppSRGBColorWithWhite: 0.92f alpha: 1.0f] // Sampler Image Popup Panel #define kUIColor_SamplerImagePopupPanel_ColorWellOutline \ [NSColor ppSRGBColorWithWhite: 0.62f alpha: 1.0f] // Sampler Image Panel #define kUIColor_SamplerImagePanel_ColorWellOutline \ [NSColor ppSRGBColorWithWhite: 0.51f alpha: 1.0f] PikoPixel.Sources.1.0-b10b/PikoPixel/PPUIFontDefines.h0000644000076500000240000000504413234403417021234 0ustar joshstaff/* PPUIFontDefines.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import #import "PPSRGBUtilities.h" // Tool Modifier Tips // Header #define kUIFont_ToolModifierTips_Header \ [NSFont fontWithName: @"LucidaGrande" size: 11.0f] #define kUIFontColor_ToolModifierTips_Header \ [NSColor ppSRGBColorWithWhite: 0.0f alpha: 1.0f] // Subheader #define kUIFont_ToolModifierTips_Subheader \ [NSFont fontWithName: @"LucidaGrande" size: 9.0f] #define kUIFontColor_ToolModifierTips_Subheader \ [NSColor ppSRGBColorWithRed: 0.26f green: 0.06f blue: 0.01f alpha: 1.0f] // Tips #define kUIFont_ToolModifierTips_Tips \ [NSFont fontWithName: @"LucidaGrande-Bold" size: 11.0f] #define kUIFontColor_ToolModifierTips_Tips \ [NSColor ppSRGBColorWithRed: 0.02f green: 0.1f blue: 0.43f alpha: 1.0f] // Disabled Titles // Table #define kUIFont_DisabledTitle_Table \ [NSFont systemFontOfSize: 0.0] #define kUIFontColor_DisabledTitle_Table \ [NSColor ppSRGBColorWithWhite: 0.66f alpha: 1.0f] // Popup Button #define kUIFont_DisabledTitle_PopupButton \ [NSFont boldSystemFontOfSize: 0.0] #define kUIFontColor_DisabledTitle_PopupButton \ [NSColor ppSRGBColorWithWhite: 0.62f alpha: 1.0f] // Popup Menu Item #define kUIFont_DisabledTitle_PopupMenuItem \ [NSFont boldSystemFontOfSize: 0.0] #define kUIFontColor_DisabledTitle_PopupMenuItem \ [NSColor ppSRGBColorWithWhite: 0.73f alpha: 1.0f] PikoPixel.Sources.1.0-b10b/PikoPixel/PPUserDefaults.h0000644000076500000240000000373213234403417021202 0ustar joshstaff/* PPUserDefaults.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import @class PPBackgroundPattern, PPGridPattern; @interface PPUserDefaults : NSObject { } + (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern; + (PPBackgroundPattern *) backgroundPattern; + (void) setGridPattern: (PPGridPattern *) gridPattern andGridVisibility: (bool) shouldDisplayGrid; + (PPGridPattern *) gridPattern; + (bool) gridVisibility; + (void) setEnabledState: (bool) panelEnabledState forPanelWithNibName: (NSString *) nibName; + (bool) enabledStateForPanelWithNibName: (NSString *) nibName; + (void) registerDefaultEnabledState: (bool) panelEnabledState forPanelWithNibName: (NSString *) nibName; + (void) setShouldDisplayFlattenedSaveNotice: (bool) shouldDisplayFlattenedSaveNotice; + (bool) shouldDisplayFlattenedSaveNotice; + (void) setColorPickerPopupPanelMode: (int) panelMode; + (int) colorPickerPopupPanelMode; + (void) setColorPickerPopupPanelContentSize: (NSSize) size; + (NSSize) colorPickerPopupPanelContentSize; @end PikoPixel.Sources.1.0-b10b/PikoPixel/PPUserDefaults.m0000644000076500000240000002424613234403207021207 0ustar joshstaff/* PPUserDefaults.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPUserDefaults.h" #import "PPUserDefaultsInitialValues.h" #import "PPBackgroundPattern.h" #import "PPGridPattern.h" #import "NSColor_PPUtilities.h" #define kPPUserDefaultsKey_DefaultBackgroundPattern @"DefaultBackgroundPattern" #define kPPUserDefaultsKey_DefaultGridPattern @"DefaultGridPattern" #define kPPUserDefaultsKey_DefaultGridVisibility @"DefaultGridVisibility" #define kPPUserDefaultsKey_ShouldDisplayFlattenedSaveNotice @"ShouldDisplayFlattenedSaveNotice" #define kPPUserDefaultsKey_ColorPickerPopupPanelMode @"DefaultColorPickerPopupPanelMode" #define kPPUserDefaultsKey_ColorPickerPopupPanelContentSize \ @"DefaultColorPickerPopupPanelContentSize" static NSDictionary *DefaultsRegistrationDictionary(void); static NSString *EnabledStateDefaultsKeyForPanelWithNibName(NSString *nibName); @implementation PPUserDefaults + (void) initialize { if (self != [PPUserDefaults class]) { return; } [[NSUserDefaults standardUserDefaults] registerDefaults: DefaultsRegistrationDictionary()]; } + (void) setBackgroundPattern: (PPBackgroundPattern *) backgroundPattern { NSData *backgroundPatternArchivedData; NSUserDefaults *userDefaults; if (!backgroundPattern) goto ERROR; backgroundPatternArchivedData = [backgroundPattern archivedData]; if (!backgroundPatternArchivedData) goto ERROR; userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject: backgroundPatternArchivedData forKey: kPPUserDefaultsKey_DefaultBackgroundPattern]; [userDefaults synchronize]; return; ERROR: return; } + (PPBackgroundPattern *) backgroundPattern { NSData *backgroundPatternArchivedData = [[NSUserDefaults standardUserDefaults] objectForKey: kPPUserDefaultsKey_DefaultBackgroundPattern]; if (!backgroundPatternArchivedData) goto ERROR; return [PPBackgroundPattern backgroundPatternWithArchivedData: backgroundPatternArchivedData]; ERROR: return nil; } + (void) setGridPattern: (PPGridPattern *) gridPattern andGridVisibility: (bool) shouldDisplayGrid { NSData *gridPatternArchivedData; NSUserDefaults *userDefaults; if (!gridPattern) goto ERROR; gridPatternArchivedData = [gridPattern archivedData]; if (!gridPatternArchivedData) goto ERROR; userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setObject: gridPatternArchivedData forKey: kPPUserDefaultsKey_DefaultGridPattern]; [userDefaults setBool: (shouldDisplayGrid) ? YES : NO forKey: kPPUserDefaultsKey_DefaultGridVisibility]; [userDefaults synchronize]; return; ERROR: return; } + (PPGridPattern *) gridPattern { NSData *gridPatternArchivedData = [[NSUserDefaults standardUserDefaults] objectForKey: kPPUserDefaultsKey_DefaultGridPattern]; if (!gridPatternArchivedData) goto ERROR; return [PPGridPattern gridPatternWithArchivedData: gridPatternArchivedData]; ERROR: return nil; } + (bool) gridVisibility { return [[NSUserDefaults standardUserDefaults] boolForKey: kPPUserDefaultsKey_DefaultGridVisibility]; } + (void) setEnabledState: (bool) panelEnabledState forPanelWithNibName: (NSString *) nibName { NSString *panelEnabledStateDefaultsKey = EnabledStateDefaultsKeyForPanelWithNibName(nibName); if (!panelEnabledStateDefaultsKey) return; [[NSUserDefaults standardUserDefaults] setBool: (panelEnabledState) ? YES : NO forKey: panelEnabledStateDefaultsKey]; } + (bool) enabledStateForPanelWithNibName: (NSString *) nibName { NSString *panelEnabledStateDefaultsKey = EnabledStateDefaultsKeyForPanelWithNibName(nibName); if (!panelEnabledStateDefaultsKey) { return NO; } return [[NSUserDefaults standardUserDefaults] boolForKey: panelEnabledStateDefaultsKey]; } + (void) registerDefaultEnabledState: (bool) panelEnabledState forPanelWithNibName: (NSString *) nibName { NSString *panelEnabledStateDefaultsKey; NSNumber *panelEnabledStateNumber; NSDictionary *registrationDictionary; panelEnabledStateDefaultsKey = EnabledStateDefaultsKeyForPanelWithNibName(nibName); panelEnabledStateNumber = [NSNumber numberWithBool: (panelEnabledState) ? YES : NO]; if (!panelEnabledStateDefaultsKey || !panelEnabledStateNumber) { return; } registrationDictionary = [NSDictionary dictionaryWithObject: panelEnabledStateNumber forKey: panelEnabledStateDefaultsKey]; if (!registrationDictionary) return; [[NSUserDefaults standardUserDefaults] registerDefaults: registrationDictionary]; } + (void) setShouldDisplayFlattenedSaveNotice: (bool) shouldDisplayFlattenedSaveNotice { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setBool: (shouldDisplayFlattenedSaveNotice) ? YES : NO forKey: kPPUserDefaultsKey_ShouldDisplayFlattenedSaveNotice]; [userDefaults synchronize]; } + (bool) shouldDisplayFlattenedSaveNotice { NSNumber *displayFlagAsNumber = [[NSUserDefaults standardUserDefaults] objectForKey: kPPUserDefaultsKey_ShouldDisplayFlattenedSaveNotice]; if (!displayFlagAsNumber) { return kUserDefaultsInitialValue_ShouldDisplayFlattenedSaveNotice; } return [displayFlagAsNumber boolValue]; } + (void) setColorPickerPopupPanelMode: (int) panelMode { [[NSUserDefaults standardUserDefaults] setInteger: panelMode forKey: kPPUserDefaultsKey_ColorPickerPopupPanelMode]; } + (int) colorPickerPopupPanelMode { NSNumber *panelModeAsNumber = [[NSUserDefaults standardUserDefaults] objectForKey: kPPUserDefaultsKey_ColorPickerPopupPanelMode]; if (!panelModeAsNumber) { return kUserDefaultsInitialValue_ColorPickerPopupPanelMode; } return [panelModeAsNumber intValue]; } + (void) setColorPickerPopupPanelContentSize: (NSSize) size { NSString *sizeAsString = NSStringFromSize(size); if (!sizeAsString) return; [[NSUserDefaults standardUserDefaults] setObject: sizeAsString forKey: kPPUserDefaultsKey_ColorPickerPopupPanelContentSize]; } + (NSSize) colorPickerPopupPanelContentSize { NSString *sizeAsString; NSSize size; sizeAsString = [[NSUserDefaults standardUserDefaults] objectForKey: kPPUserDefaultsKey_ColorPickerPopupPanelContentSize]; if (sizeAsString) { size = NSSizeFromString(sizeAsString); } else { NSColorPanel *sharedColorPanel; int sharedColorPanelMode; sharedColorPanel = [NSColorPanel sharedColorPanel]; sharedColorPanelMode = [sharedColorPanel mode]; [sharedColorPanel setMode: [self colorPickerPopupPanelMode]]; size = [[NSColorPanel sharedColorPanel] frame].size; [sharedColorPanel setMode: sharedColorPanelMode]; } return size; } @end #pragma mark Private functions static NSDictionary *DefaultsRegistrationDictionary(void) { NSData *defaultBackgroundPatternArchivedData, *defaultGridPatternArchivedData; NSDictionary *defaultValues; defaultBackgroundPatternArchivedData = [kUserDefaultsInitialValue_BackgroundPattern archivedData]; defaultGridPatternArchivedData = [kUserDefaultsInitialValue_GridPattern archivedData]; defaultValues = [NSDictionary dictionaryWithObjectsAndKeys: defaultBackgroundPatternArchivedData, kPPUserDefaultsKey_DefaultBackgroundPattern, defaultGridPatternArchivedData, kPPUserDefaultsKey_DefaultGridPattern, [NSNumber numberWithBool: kUserDefaultsInitialValue_GridVisibility], kPPUserDefaultsKey_DefaultGridVisibility, [NSNumber numberWithBool: kUserDefaultsInitialValue_ShouldDisplayFlattenedSaveNotice], kPPUserDefaultsKey_ShouldDisplayFlattenedSaveNotice, [NSNumber numberWithInt: kUserDefaultsInitialValue_ColorPickerPopupPanelMode], kPPUserDefaultsKey_ColorPickerPopupPanelMode, // default value for ColorPickerPopupPanelContentSize is calculated // dynamically, so no entry here nil]; return defaultValues; } static NSString *EnabledStateDefaultsKeyForPanelWithNibName(NSString *nibName) { return [nibName stringByAppendingString: @"EnabledState"]; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPUserDefaultsInitialValues.h0000644000076500000240000000545613234403417023701 0ustar joshstaff/* PPUserDefaultsInitialValues.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPBackgroundPattern.h" #import "PPGridPattern.h" #import "PPSRGBUtilities.h" #define kUserDefaultsInitialValue_BackgroundPattern \ [PPBackgroundPattern \ backgroundPatternOfType: kPPBackgroundPatternType_IsometricLines \ patternSize: 11 \ color1: [NSColor ppSRGBColorWithWhite: 1.0f alpha: 1.0f] \ color2: [NSColor ppSRGBColorWithWhite: 0.92f alpha: 1.0f]] #define kUserDefaultsInitialValue_GridPattern \ [PPGridPattern gridPatternWithPixelGridType: kPPGridType_LargeDots \ pixelGridColor: \ [NSColor ppSRGBColorWithWhite: 0.73f alpha: 1.0f] \ guidelineSpacingSize: NSMakeSize(8,8) \ guidelineColor: \ [NSColor ppSRGBColorWithWhite: 0.23f alpha: 1.0f] \ shouldDisplayGuidelines: NO] #define kUserDefaultsInitialValue_GridVisibility YES #define kUserDefaultsInitialValue_ShouldDisplayFlattenedSaveNotice YES #if defined(__APPLE__) # define kUserDefaultsInitialValue_ColorPickerPopupPanelMode NSCrayonModeColorPanel #elif defined(GNUSTEP) // !defined(__APPLE__) // GNUstep's Crayon Mode is currently unimplemented; use color wheel instead # define kUserDefaultsInitialValue_ColorPickerPopupPanelMode NSWheelModeColorPanel #endif // defined(GNUSTEP) PikoPixel.Sources.1.0-b10b/PikoPixel/PPUserFolderPaths.h0000644000076500000240000000207313234403417021643 0ustar joshstaff/* PPUserFolderPaths.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import extern NSString *PPUserFolderPaths_ApplicationSupport(void); PikoPixel.Sources.1.0-b10b/PikoPixel/PPUserFolderPaths.m0000644000076500000240000000337613234403207021654 0ustar joshstaff/* PPUserFolderPaths.m Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X and GNUstep. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #import "PPUserFolderPaths.h" #define kAppFolderName @"PikoPixel" NSString *PPUserFolderPaths_ApplicationSupport(void) { static NSString *applicationSupportFolderPath = nil; NSArray *supportFolderPaths; if (applicationSupportFolderPath) { return applicationSupportFolderPath; } supportFolderPaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); if (![supportFolderPaths count]) { goto ERROR; } applicationSupportFolderPath = [[[supportFolderPaths objectAtIndex: 0] stringByAppendingPathComponent: kAppFolderName] retain]; return applicationSupportFolderPath; ERROR: return nil; } PikoPixel.Sources.1.0-b10b/PikoPixel/PPXCConfig_10.14sdk.xcconfig0000644000076500000240000000227713371615512023040 0ustar joshstaff// // PPXCConfig_10.14sdk.xcconfig // // Copyright 2013-2018 Josh Freeman // http://www.twilightedge.com // // This file is part of PikoPixel for Mac OS X. // PikoPixel is a graphical application for drawing & editing pixel-art images. // // PikoPixel is free software: you can redistribute it and/or modify it under // the terms of the GNU Affero General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version approved for PikoPixel by its copyright holder (or // an authorized proxy). // // PikoPixel 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 Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // // PikoPixel Xcode Configuration File for 10.14+ SDKs GCC_PREPROCESSOR_DEFINITIONS = $(inherited) PPXCCONFIG__10_14_SDK PPXCCONFIG__RELEASE_ARCHS = x86_64 MACOSX_DEPLOYMENT_TARGET = 10.7 ALWAYS_SEARCH_USER_PATHS = NO PikoPixel.Sources.1.0-b10b/PikoPixel/PPXCConfig_10.5sdk.xcconfig0000644000076500000240000000233013371615303022744 0ustar joshstaff// // PPXCConfig_10.5sdk.xcconfig // // Copyright 2013-2018 Josh Freeman // http://www.twilightedge.com // // This file is part of PikoPixel for Mac OS X. // PikoPixel is a graphical application for drawing & editing pixel-art images. // // PikoPixel is free software: you can redistribute it and/or modify it under // the terms of the GNU Affero General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version approved for PikoPixel by its copyright holder (or // an authorized proxy). // // PikoPixel 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 Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // // PikoPixel Xcode Configuration File for 10.5-10.13 SDKs GCC_PREPROCESSOR_DEFINITIONS = $(inherited) PPXCCONFIG__10_5_SDK PPXCCONFIG__RELEASE_ARCHS = ppc i386 x86_64 MACOSX_DEPLOYMENT_TARGET = 10.4 MACOSX_DEPLOYMENT_TARGET[arch=x86_64] = 10.5 PikoPixel.Sources.1.0-b10b/PikoPixel/PPXCConfigCheck.h0000644000076500000240000000371613371616453021204 0ustar joshstaff/* PPXCConfigCheck.h Copyright 2013-2018 Josh Freeman http://www.twilightedge.com This file is part of PikoPixel for Mac OS X. PikoPixel is a graphical application for drawing & editing pixel-art images. PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // Check that the active Xcode Config File is compatible with the current OS X SDK #ifdef __APPLE__ # if _PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(14) // Building on 10.14+ SDK: Require PPXCConfig_10.14sdk.xcconfig # ifndef PPXCCONFIG__10_14_SDK # error : To build PikoPixel with 10.14+ SDKs, you need to use a different Xcode Configuration File; \ Please update the PikoPixel project's build configuration settings to be based on the .xcconfig file, "PPXCConfig_10.14sdk". # endif # else // !_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(14) // Building on 10.5-10.13 SDK: Require PPXCConfig_10.5sdk.xcconfig # ifndef PPXCCONFIG__10_5_SDK # error : To build PikoPixel with 10.5-10.13 SDKs, you need to use a different Xcode Configuration File; \ Please update the PikoPixel project's build configuration settings to be based on the .xcconfig file, "PPXCConfig_10.5sdk". # endif # endif // !_PP_MAC_OS_X_SDK_VERSION_IS_AT_LEAST_10_(14) #endif // __APPLE__ PikoPixel.Sources.1.0-b10b/README.txt0000644000076500000240000000705714400242505015754 0ustar joshstaffPikoPixel Sources for Mac OS X & GNUstep Version 1.0 BETA10b (c) 2013-2018,2020,2023 Josh Freeman http://twilightedge.com ABOUT ----- PikoPixel is a free, open-source graphical application for drawing & editing pixel-art images. BUILDING ON OS X ---------------- Building PikoPixel 1.0 BETA10b for Mac OS X requires Xcode 3 or later. Open PikoPixel/PikoPixel.xcodeproj in Xcode to build & run the application. Xcode may warn about updating the project to use Xcode's recommended settings. PikoPixel should build successfully with its original project settings, so allowing Xcode to update the settings is not recommended, as it can cause build issues. If you're using Xcode 10 or later (10.14+ SDK), you'll need to switch the configuration settings file (.xcconfig) for the PikoPixel project's Debug & Release build configurations from "PPXCConfig_10.5sdk" to "PPXCConfig_10.14sdk"; For instructions on switching a build configuration's settings file, see the section, "Map a configuration settings file to a build configuration", in Apple's online Xcode help: https://help.apple.com/xcode/mac/current/#/deve97bde215 BUILDING ON GNUSTEP ------------------- Building PikoPixel 1.0 BETA10b for GNUstep requires a GNUstep development environment with either of GNUstep's supported compiler+runtime setups (GCC+gobjc or clang+objc2), and the following GNUstep library versions (or later): - GNUstep Base library version 1.24.9 (released Mar. 20, 2016) - GNUstep GUI & Back libraries version 0.25.0 (released Jun. 15, 2016) Your distro's repository may contain GNUstep development-environment packages with the required minimum library versions. For example, on Ubuntu 16.10+ or Debian 9+, the following set of packages contain all you need for building PikoPixel: build-essential libgnustep-gui-dev gnustep-examples More info on installing GNUstep: http://wiki.gnustep.org/index.php/User_Guides http://wiki.gnustep.org/index.php/Platform:Linux http://wiki.gnustep.org/index.php/GNUstep_under_Ubuntu_Linux With a compatible GNUstep development environment installed, your shell environment must be set up to run GNUstep-make; See "4.1 Environment Setup": http://www.gnustep.org/resources/documentation/User/GNUstep/gnustep-howto_4.html Once GNUstep-make is set up, PikoPixel can be built using the following commands: cd PikoPixel make sudo -E make install After installing, type the following to run PikoPixel: openapp PikoPixel PikoPixel can be added to your desktop environment's menus by copying its desktop-entry file (found in PikoPixel.app/Resources) to your desktop environment's entries directory (usually /usr/share/applications): sudo desktop-file-install --rebuild-mime-info-cache PikoPixel.app/Resources/PikoPixel.desktop Once its desktop-entry file is installed, PikoPixel should appear in your desktop applications list under 'Graphics'. LICENSE ------- PikoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version approved for PikoPixel by its copyright holder (or an authorized proxy). PikoPixel 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see .