diff options
author | Micksha <ms-shaman@gmx.de> | 2019-04-13 19:55:05 +0000 |
---|---|---|
committer | Micksha <ms-shaman@gmx.de> | 2019-04-13 19:55:05 +0000 |
commit | add8a9e8bc83fbf022c66001f2150d90a6f234ab (patch) | |
tree | b771ad105e5a73733ede7559e22467f13a2880a8 | |
parent | 8c75e651f00048dda32db85b2bff34e131960864 (diff) | |
parent | 168ad9d6c730e93d76c801da607df84355187a39 (diff) | |
download | evol-tools-s20190422.tar.gz evol-tools-s20190422.tar.bz2 evol-tools-s20190422.tar.xz evol-tools-s20190422.zip |
Merge branch 'saedit' into 'master's20190422
update saedit to saedit2
See merge request evol/evol-tools!23
61 files changed, 6390 insertions, 2670 deletions
diff --git a/saedit/.gitignore b/saedit/.gitignore new file mode 100644 index 0000000..e680e74 --- /dev/null +++ b/saedit/.gitignore @@ -0,0 +1,6 @@ +*~ +*.swp +*.o +*/*.o +glade/libsaedit.so +saedit diff --git a/saedit/.gitlab-ci.yml b/saedit/.gitlab-ci.yml new file mode 100644 index 0000000..0807941 --- /dev/null +++ b/saedit/.gitlab-ci.yml @@ -0,0 +1,6 @@ +before_script: + - apt-get update -qq && apt-get install -y -qq gtk+3.0 gtksourceview-3.0 + +saedit: + script: + - make all diff --git a/saedit/COPYING b/saedit/COPYING deleted file mode 100644 index e8b00c2..0000000 --- a/saedit/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/saedit/LICENSE b/saedit/LICENSE new file mode 100644 index 0000000..eb82ba2 --- /dev/null +++ b/saedit/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + saedit2 + Copyright (C) 2018 Danil Sagunov + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + saedit2 Copyright (C) 2018 Danil Sagunov + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/saedit/Makefile b/saedit/Makefile index 8d033f3..207eeaf 100644 --- a/saedit/Makefile +++ b/saedit/Makefile @@ -1,33 +1,33 @@ -ifndef CFLAGS - CFLAGS = -O2 -pipe -endif +CC ?= gcc -ifndef LDFLAGS - LDFLAGS = -endif +CFLAGS += `pkg-config --cflags gtk+-3.0 gtksourceview-3.0` +CFLAGS += -fPIC -Itreefolderview -Ispritedrawingarea +CFLAGS += -Wall -Wdeclaration-after-statement -ansi +CFLAGS += -Werror -Wextra -Wstrict-prototypes +CFLAGS += -Wno-unused-parameter -ifndef OUTPUT - OUTPUT = saedit -endif +LDFLAGS += `pkg-config --libs gtk+-3.0 gtksourceview-3.0` +LDFLAGS += -rdynamic -Ltreefolderview -Lspritedrawingarea -LDFLAGS += -export-dynamic +FLAGS = ${CFLAGS} ${LDFLAGS} -CFLAGS += `pkg-config --cflags gtk+-3.0 gtksourceview-3.0` +all: saedit glade/libsaedit.so -LDFLAGS += `pkg-config --libs gtk+-3.0 gtksourceview-3.0` +saedit: main.o treefolderview/treefolderview.o xml.o \ + spritedrawingarea/spritedrawingarea.o \ + context.o imageset.o action.o animation.o common.o \ + interactor.o callbacks.o errors.o config.o file.o \ + buffer.o spritedrawingarea/sdalayer.o xmlsetup.o \ + drawfuncs.o + ${CC} $^ -o saedit ${FLAGS} + +glade/libsaedit.so: treefolderview/treefolderview.o \ + spritedrawingarea/spritedrawingarea.o \ + spritedrawingarea/sdalayer.o + ${CC} $^ -o glade/libsaedit.so ${FLAGS} -shared + +%.o: %.c + ${CC} $^ -c -o $@ ${CFLAGS} -all:main.o search.o config.o xml.o sae.o compile clean -compile: main.o search.o config.o xml.o - gcc ${CFLAGS} -o '${OUTPUT}' main.o search.o config.o xml.o sae.o ${LDFLAGS} -main.o: main.c main.h search.h config.h common.h xml.h - gcc ${CFLAGS}-c -o main.o main.c -search.o: search.c search.h common.h - gcc ${CFLAGS} -c -o search.o search.c -xml.o: xml.c xml.h common.h - gcc ${CFLAGS} -c -o xml.o xml.c -config.o: config.c config.h common.h - gcc ${CFLAGS} -c -o config.o config.c -sae.o: sae.c sae.h common.h - gcc ${CFLAGS} -c -o sae.o sae.c clean: - rm -rfv *.o *~ + rm -f *.o */*.o *~ glade/libsaedit.so saedit diff --git a/saedit/action.c b/saedit/action.c new file mode 100644 index 0000000..a9b31e2 --- /dev/null +++ b/saedit/action.c @@ -0,0 +1,176 @@ +#include "action.h" +#include "animation.h" +#include "imageset.h" +#include "context.h" + +Action * +action_new ( + const SpriteContext *context, + const XMLNode *node, + gint included_from +) { + Action *action; + GList *list; + gchar *imgset_name; + gboolean fail = FALSE; + Imageset *imageset; + + g_return_val_if_fail (g_strcmp0 (node->name, "action") == 0, NULL); + + action = (Action *) g_new0 (Action, 1); + + action->name = xml_node_get_attr_value (node, "name"); + if (action->name == NULL) { + /* TODO: report error */ + fail = TRUE; + } + + imgset_name = xml_node_get_attr_value (node, "imageset"); + if (imgset_name == NULL) { + /* TODO: report error */ + fail = TRUE; + } else { + imageset = sprite_context_get_imageset (context, imgset_name); + if (imageset == NULL) { + /* TODO: report error */ + fail = TRUE; + } + } + + if (fail) { + g_free (action); + return NULL; + } + + action->hp = xml_node_get_int_attr_value (node, "hp", 100); + + list = node->sub_nodes; + while (list != NULL) { + XMLNode *current = (XMLNode *) list->data; + + if (g_strcmp0 (current->name, "animation") == 0) { + action_add_animation ( + action, + imageset, + current, + included_from + ); + } else { + /* TODO: action contains something unknown */ + } + + list = g_list_next (list); + } + + return action; +} + +void +action_add_animation ( + Action *action, + const Imageset *imageset, + const XMLNode *node, + gint included_from +) { + Animation *animation; + + g_return_if_fail (g_strcmp0 (node->name, "animation") == 0); + + animation = animation_new (imageset, node, included_from); + if (animation == NULL) + return; + + if (g_list_find_custom ( + action->animations, animation, + (GCompareFunc) animation_compare_by_direction) != NULL + ) { + animation_free (animation); + return; + } + + action->animations = g_list_append (action->animations, animation); +} + +void +action_free (Action *action) { + g_list_free_full ( + action->animations, + (GDestroyNotify) animation_free + ); + + g_free (action->name); + g_free (action); +} + +gint +action_compare_by_hp_and_name ( + const Action *first, + const Action *second +) { + if (first->hp != second->hp) { + return first->hp - second->hp; + } + return g_strcmp0 (first->name, second->name); +} + +gboolean +action_hp_and_name_equals ( + const Action *action, + gint hp, + const gchar *name +) { + return + action->hp == hp && + g_strcmp0 (action->name, name) == 0; +} + +const Animation * +action_get_animation ( + const Action *action, + const gchar *direction +) { + GList *animation = action->animations; + g_return_val_if_fail (animation != NULL, NULL); + + while (direction != NULL && animation != NULL) { + Animation *current = (Animation *) animation->data; + g_assert (current != NULL); + if (animation_direction_equals (current, direction)) + return current; + + animation = g_list_next (animation); + } + + return (Animation *) action->animations->data; +} + +void +action_get_hp_and_name ( + const Action *action, + gint *hp, + gchar **name +) { + if (hp != NULL) + *hp = action->hp; + if (name != NULL) + *name = action->name; +} + +GList * +action_get_directions (const Action *action) { + GList *result = NULL; + GList *animations = action->animations; + + while (animations != NULL) { + Animation *animation = (Animation *) animations->data; + result = g_list_append (result, animation->direction); + animations = g_list_next (animations); + } + + return result; +} + +gchar * +get_action_id (gint hp, const gchar *name) { + return g_strdup_printf ("%d:%s", hp, name); +} diff --git a/saedit/action.h b/saedit/action.h new file mode 100644 index 0000000..57da155 --- /dev/null +++ b/saedit/action.h @@ -0,0 +1,59 @@ +#ifndef ACTION_H +#define ACTION_H + +#include <glib.h> +#include "common.h" +#include "imageset.h" +#include "animation.h" +#include "xml.h" + +typedef struct { + gchar *name; + gint hp; + GList *animations; +} Action; + +void +action_free (Action *action); + +gint +action_compare_by_hp_and_name ( + const Action *first, + const Action *second +); + +gboolean +action_hp_and_name_equals ( + const Action *action, + gint hp, + const gchar *name +); + +void +action_add_animation ( + Action *action, + const Imageset *imageset, + const XMLNode *node, + gint included_from +); + +const Animation * +action_get_animation ( + const Action *action, + const gchar *direction +); + +void +action_get_hp_and_name ( + const Action *action, + gint *hp, + gchar **name +); + +GList * +action_get_directions (const Action *action); + +gchar * +get_action_id (gint hp, const gchar *name); + +#endif diff --git a/saedit/animation.c b/saedit/animation.c new file mode 100644 index 0000000..997b420 --- /dev/null +++ b/saedit/animation.c @@ -0,0 +1,386 @@ +#include "animation.h" +#include <string.h> + +static void +animation_add_element_pause ( + Animation *animation, + gint delay, + gint rand, + gint line_no +) { + AnimElement *elem = animation_element_new (); + elem->delay = delay; + elem->rand = rand; + elem->type = ELEMENT_PAUSE; + elem->line_no = line_no; + + animation->elements = g_list_append (animation->elements, elem); +} + +static void +animation_add_element_end ( + Animation *animation, + gint rand, + gint line_no +) { + AnimElement *elem = animation_element_new (); + elem->type = ELEMENT_END; + elem->rand = rand; + elem->line_no = line_no; + + animation->elements = g_list_append (animation->elements, elem); +} + +static void +animation_add_element_frame ( + Animation *animation, + const Imageset *imageset, + gint index, + gint offsetX, + gint offsetY, + gint delay, + gint rand, + gint line_no +) { + gint x, y; + AnimElement *elem = animation_element_new (); + + elem->type = ELEMENT_FRAME; + + imageset_get_offset (imageset, &x, &y); + offsetX += x; + offsetY += y; + + imageset_get_size (imageset, &x, &y); + offsetX -= x / 2; + offsetY -= y; + + elem->offsetX = offsetX; + elem->offsetY = offsetY; + + elem->delay = delay; + elem->rand = rand; + elem->line_no = line_no; + + elem->sprite = imageset_get_sprite_by_index (imageset, index); + if (elem->sprite == NULL) { + /* TODO: report this */ + g_free (elem); + return; + } + + animation->elements = g_list_append (animation->elements, elem); +} + +static void +animation_add_element_goto ( + Animation *animation, + gchar *label, + gint rand, + gint line_no +) { + AnimElement *elem = animation_element_new (); + elem->type = ELEMENT_GOTO; + elem->str = label; + elem->rand = rand; + elem->line_no = line_no; + + animation->elements = g_list_append (animation->elements, elem); +} + +static void +animation_add_element_jump ( + Animation *animation, + gchar *action, + gint rand, + gint line_no +) { + AnimElement *elem = animation_element_new (); + elem->type = ELEMENT_JUMP; + elem->str = action; + elem->rand = rand; + elem->line_no = line_no; + + animation->elements = g_list_append (animation->elements, elem); +} + +static void +animation_add_element_label ( + Animation *animation, + gchar *name, + gint line_no +) { + AnimElement *elem = animation_element_new (); + elem->type = ELEMENT_LABEL; + elem->str = name; + elem->line_no = line_no; + + animation->elements = g_list_append (animation->elements, elem); +} + +static void +animation_add_sequence ( + Animation *animation, + const Imageset *imageset, + const XMLNode *node, + gint offsetX, + gint offsetY, + gint delay, + gint rand, + gint line_no +) { + gchar *value, **tokens; + gint start = xml_node_get_int_attr_value (node, "start", -1); + gint end = xml_node_get_int_attr_value (node, "end", -1); + gint repeat = xml_node_get_int_attr_value_limited ( + node, "repeat", 1, 0, 100 + ); + + g_return_if_fail (g_strcmp0 (node->name, "sequence") == 0); + + if (repeat < 1) { + /* TODO: show error */ + return; + } + + value = xml_node_get_attr_value (node, "value"); + + if (value == NULL) { + if (start < 0 || end < 0) { + /* TODO: show error */ + return; + } + value = g_strdup_printf ("%d-%d", start, end); + } + + tokens = g_strsplit (value, ",", 0); + g_free (value); + + while (repeat > 0) { + gchar **token = tokens; + + while (*token != NULL) { + if (g_strcmp0 (*token, "p") == 0) { + animation_add_element_pause ( + animation, + delay, + rand, + line_no + ); + } else { + gint start = -1, end = -1, d; + gchar *delim = strchr (*token, '-'); + + if (delim == NULL) { + try_strtoint (*token, &start); + end = start; + } else { + *delim = 0; + try_strtoint ( *token, &start); + try_strtoint (delim + 1, &end); + *delim = '-'; + } + + if (start < 0 || end < 0) { + /* TODO: show error */ + g_strfreev (tokens); + return; + } + + d = start <= end ? +1 : -1; + end += d; + + while (start != end) { + animation_add_element_frame ( + animation, + imageset, + start, + offsetX, + offsetY, + delay, + rand, + line_no + ); + start += d; + } + } + ++token; + } + --repeat; + } + + g_strfreev (tokens); +} + +static void +animation_add_elements_from_node ( + Animation *animation, + const Imageset *imageset, + const XMLNode *node, + gint included_from +) { + gchar *name = node->name; + + gint offsetX, offsetY; + gint delay, rand; + gchar *str; + gint line_no; + + imageset_get_offset (imageset, &offsetX, &offsetY); + + offsetX += xml_node_get_int_attr_value (node, "offsetX", 0); + offsetY += xml_node_get_int_attr_value (node, "offsetY", 0); + + delay = xml_node_get_int_attr_value_limited ( + node, "delay", 0, + 0, 100000 + ); + + rand = xml_node_get_int_attr_value_limited ( + node, "rand", 100, + 0, 100 + ); + + line_no = included_from; + if (line_no == -1) + line_no = node->line_no; + + if (g_strcmp0 (name, "frame") == 0) { + gint index = xml_node_get_int_attr_value (node, "index", -1); + + if (index < 0) { + /* TODO: report error */ + return; + } + + animation_add_element_frame ( + animation, + imageset, + index, + offsetX, offsetY, + delay, rand, + line_no + ); + } else + + if (g_strcmp0 (name, "pause") == 0) { + animation_add_element_pause ( + animation, delay, rand, line_no + ); + } else + + if (g_strcmp0 (name, "end") == 0) { + animation_add_element_end (animation, rand, line_no); + } else + + if (g_strcmp0 (name, "jump") == 0) { + str = xml_node_get_attr_value (node, "action"); + animation_add_element_jump ( + animation, str, rand, line_no + ); + } else + + if (g_strcmp0 (name, "label") == 0) { + str = xml_node_get_attr_value (node, "name"); + if (str == NULL) { + /* TODO: report error */ + return; + } + + animation_add_element_label (animation, str, line_no); + } else + + if (g_strcmp0 (name, "goto") == 0) { + str = xml_node_get_attr_value (node, "label"); + if (str == NULL) { + /* TODO: report error */ + return; + } + + animation_add_element_goto ( + animation, str, rand, line_no + ); + } else + + if (g_strcmp0 (name, "sequence") == 0) { + animation_add_sequence ( + animation, + imageset, + node, + offsetX, offsetY, + delay, rand, + line_no + ); + } else + + { + /* TODO: unknown tag */ + return; + } +} + +Animation * +animation_new ( + const Imageset *imageset, + const XMLNode *node, + gint included_from +) { + Animation *animation; + gchar *dir; + GList *sub_node; + + g_return_val_if_fail (g_strcmp0 (node->name, "animation") == 0, NULL); + + dir = xml_node_get_attr_value (node, "direction"); + + if (dir == NULL) + dir = ""; + + animation = (Animation *) g_new0 (Animation, 1); + animation->direction = dir; + + sub_node = node->sub_nodes; + while (sub_node != NULL) { + animation_add_elements_from_node ( + animation, + imageset, + (XMLNode *) sub_node->data, + included_from + ); + sub_node = g_list_next (sub_node); + } + + return animation; +} + +gint +animation_compare_by_direction ( + const Animation *first, + const Animation *second +) { + return g_strcmp0 (first->direction, second->direction); +} + +gboolean +animation_direction_equals ( + const Animation *animation, + const gchar *direction +) { + return g_strcmp0 (animation->direction, direction) == 0; +} + +void +animation_free (Animation *animation) { + g_list_free_full ( + animation->elements, + (GDestroyNotify) g_free + ); + + g_free (animation->direction); + g_free (animation); +} + +AnimElement * +animation_element_new () { + return (AnimElement *) g_new0 (AnimElement, 1); +} diff --git a/saedit/animation.h b/saedit/animation.h new file mode 100644 index 0000000..6c4d05f --- /dev/null +++ b/saedit/animation.h @@ -0,0 +1,59 @@ +#ifndef ANIMATION_H +#define ANIMATION_H + +#include <gdk/gdk.h> +#include <glib.h> +#include "common.h" +#include "xml.h" +#include "imageset.h" + +typedef struct { + gchar *direction; + GList *elements; +} Animation; + +Animation * +animation_new ( + const Imageset *imageset, + const XMLNode *node, + gint included_from +); + +void +animation_free (Animation *animation); + +gint +animation_compare_by_direction ( + const Animation *first, + const Animation *second +); + +gboolean +animation_direction_equals ( + const Animation *animation, + const gchar *direction +); + +enum { + ELEMENT_END = 0, + ELEMENT_FRAME, + ELEMENT_JUMP, + ELEMENT_GOTO, + ELEMENT_PAUSE, + ELEMENT_LABEL, + ELEMENT_COUNT +}; + +typedef struct { + gint type; + gint delay; + gint offsetX, offsetY; + gint rand; + gchar *str; + gint line_no; + GdkPixbuf *sprite; +} AnimElement; + +AnimElement *animation_element_new (void); + +#endif diff --git a/saedit/bmake b/saedit/bmake deleted file mode 100755 index a1ecd7f..0000000 --- a/saedit/bmake +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -dir=`pwd` - -export LANG=C - -make clean - -#export CFLAGS="-std=c99 -Wvariadic-macros -Wvla -Wredundant-decls - -export CFLAGS="-std=gnu99 -Wvariadic-macros -Wvla -Wredundant-decls \ --Wpacked-bitfield-compat -Wtrampolines \ --Wsuggest-attribute=noreturn -Wstrict-aliasing=2 \ --fstrict-aliasing -Wunreachable-code -Wabi -Wdisabled-optimization \ --Wvolatile-register-var -Winvalid-pch -Wredundant-decls \ --Wnormalized=nfkc -Wmissing-format-attribute -Wmissing-noreturn \ --Wswitch-default -Waddress \ --Wlogical-op -Wcast-align -Wpointer-arith -Wundef \ --Wmissing-include-dirs -Winit-self -pedantic -Wall -ggdb3 -O2 -pipe \ --Wpacked -Wstrict-overflow=1 -Wunknown-pragmas -Wwrite-strings \ --Wstack-protector -Wshadow -Wunused-macros \ --Wbuiltin-macro-redefined -Wdeprecated \ --Wendif-labels -Wformat=1 -Wimport -Wpsabi \ --Wmissing-field-initializers -Wuninitialized \ --Wignored-qualifiers -Winit-self -Wempty-body -Wclobbered -Wtype-limits \ --Wsign-compare -Wwrite-strings" - -make 2>make.log diff --git a/saedit/buffer.c b/saedit/buffer.c new file mode 100644 index 0000000..5c51bcc --- /dev/null +++ b/saedit/buffer.c @@ -0,0 +1,87 @@ +#include <gtksourceview/gtksource.h> +#include "main.h" +#include "buffer.h" + +gchar * +buffer_get_text () { + GtkTextIter start, end; + GtkTextBuffer *buffer = + GTK_TEXT_BUFFER (gtk_text_view_get_buffer ( + GTK_TEXT_VIEW (source_view) + )); + + gtk_text_buffer_get_start_iter (buffer, &start); + gtk_text_buffer_get_end_iter (buffer, &end); + + return gtk_text_buffer_get_text (buffer, &start, &end, TRUE); +} + +void +buffer_set_text ( + const gchar *text, + const guint len +) { + GtkTextBuffer *buffer = + GTK_TEXT_BUFFER (gtk_text_view_get_buffer ( + GTK_TEXT_VIEW (source_view) + )); + + gtk_text_buffer_set_text (buffer, text, len); +} + +void +buffer_mark_line (gint line_no) { + GtkTextIter iter, end; + GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER ( + gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view)) + ); + + gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &iter); + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end); + + gtk_source_buffer_remove_source_marks ( + buffer, + &iter, + &end, + "active-line" + ); + + if (line_no == -1) + return; + + gtk_text_iter_set_line (&iter, line_no); + gtk_text_view_scroll_to_mark ( + GTK_TEXT_VIEW (source_view), + (GtkTextMark *) gtk_source_buffer_create_source_mark ( + buffer, + NULL, + "active-line", + &iter + ), + 0.0, + TRUE, + 0.0, + 0.5 + ); +} + + +void +buffer_set_modified (gboolean modified) { + GtkTextBuffer *buffer = + GTK_TEXT_BUFFER (gtk_text_view_get_buffer ( + GTK_TEXT_VIEW (source_view) + )); + + gtk_text_buffer_set_modified (buffer, modified); +} + +gboolean +buffer_get_modified () { + GtkTextBuffer *buffer = + GTK_TEXT_BUFFER (gtk_text_view_get_buffer ( + GTK_TEXT_VIEW (source_view) + )); + + return gtk_text_buffer_get_modified (buffer); +} diff --git a/saedit/buffer.h b/saedit/buffer.h new file mode 100644 index 0000000..2926687 --- /dev/null +++ b/saedit/buffer.h @@ -0,0 +1,22 @@ +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +gchar * +buffer_get_text (void); + +void +buffer_set_text ( + const gchar *text, + const guint len +); + +void +buffer_mark_line (gint line_no); + +void +buffer_set_modified (gboolean modified); + +gboolean +buffer_get_modified (void); + +#endif diff --git a/saedit/callbacks.c b/saedit/callbacks.c new file mode 100644 index 0000000..f27fc47 --- /dev/null +++ b/saedit/callbacks.c @@ -0,0 +1,432 @@ +#include "main.h" +#include "errors.h" +#include "config.h" +#include "file.h" +#include "buffer.h" +#include <string.h> + +void +store_append_action (const Action *action, gpointer user_data) { + int hp; + gchar *name; + GtkTreeIter iter; + + action_get_hp_and_name (action, &hp, &name); + gtk_list_store_append (store_actions, &iter); + + gtk_list_store_set ( + store_actions, + &iter, + 0, name, + 1, hp, + 2, get_action_id (hp, name), + -1 + ); +} + +void +parse_buffer_clicked_cb ( + GtkToolButton *button, + gpointer user_data +) { + gchar *buffer_text; + GError *error = NULL; + GList *actions; + + release_context (); + + buffer_text = buffer_get_text (); + + context = sprite_context_new ( + config_keys_get_data_folder_path () + ); + interactor = interactor_new (context); + + sprite_context_add_sprite ( + context, + xml_parse_buffer (buffer_text, &error), + -1 + ); + + if (error != NULL) { + post_error ("XML parser", error->message); + g_error_free (error); + } + + g_free (buffer_text); + + interactor_set_updated_callback (interactor, intr_updated); + + actions = sprite_context_get_actions (context); + g_list_foreach (actions, (GFunc) store_append_action, NULL); + g_list_free (actions); + + gtk_widget_queue_draw (d_area); +} + +void +append_direction (const gchar *direction, gpointer user_data) { + gchar *display; + + g_return_if_fail (direction != NULL); + + if (strlen (direction) == 0) + display = g_strdup ("<empty>"); + else + display = g_strdup (direction); + + gtk_combo_box_text_append ( + cb_directions, + direction, + display + ); + + g_free (display); +} + +void +action_changed_cb (GtkComboBox *cbox, gpointer user_data) { + GList *directions; + GtkTreeIter iter; + gint hp; + gchar *name; + const Action *action; + gboolean w_run; + + g_return_if_fail (cbox == cb_actions); + + if (interactor == NULL) + return; + + if (!gtk_combo_box_get_active_iter (cbox, &iter)) + return; + + gtk_tree_model_get ( + GTK_TREE_MODEL (store_actions), + &iter, + 0, &name, + 1, &hp, + -1 + ); + + w_run = interactor_loop_running (interactor); + if (w_run) + interactor_loop_stop (interactor); + + gtk_combo_box_text_remove_all (cb_directions); + + action = sprite_context_get_action (context, hp, name); + g_return_if_fail (action != NULL); + + directions = action_get_directions (action); + g_list_foreach (directions, (GFunc) append_direction, NULL); + g_list_free (directions); + + interactor_set_action (interactor, hp, name); + + if (w_run) + interactor_loop_start (interactor, 10, 10); +} + +void +direction_changed_cb (GtkComboBox *cbox, gpointer user_data) { + gchar *active_text; + + g_return_if_fail (cbox == GTK_COMBO_BOX (cb_directions)); + + if (interactor == NULL) + return; + + active_text = gtk_combo_box_text_get_active_text (cb_directions); + + if (active_text == NULL) + return; + + interactor_set_direction ( + interactor, + active_text + ); +} + +void +play_pause_clicked_cb ( + GtkToolButton *button, + gpointer user_data +) { + if (interactor == NULL) + return; + + if (interactor_loop_running (interactor)) + interactor_loop_stop (interactor); + else + interactor_loop_start (interactor, 10, 10); +} + +void +next_frame_clicked_cb ( + GtkToolButton *button, + gpointer user_data +) { + if (interactor == NULL) + return; + + interactor_skip_current_frame (interactor); +} + +void +first_frame_clicked_cb ( + GtkToolButton *button, + gpointer user_data +) { + if (interactor == NULL) + return; + + interactor_loop_stop (interactor); + interactor_reset_animation (interactor); +} + +void +choose_df_activated_cb ( + GtkMenuItem *item, + gpointer user_data +) { + TreeFolderView *tfview; + GtkWidget *dialog; + gint res; + gchar *filename; + + g_return_if_fail (IS_TREE_FOLDER_VIEW (user_data)); + + tfview = TREE_FOLDER_VIEW (user_data); + dialog = gtk_file_chooser_dialog_new ( + "Choose data folder", + GTK_WINDOW (main_window), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + "Cancel", GTK_RESPONSE_CANCEL, + "Open", GTK_RESPONSE_ACCEPT, + NULL + ); + + gtk_file_chooser_set_filename ( + GTK_FILE_CHOOSER (dialog), + tree_folder_view_get_filename (tfview) + ); + + res = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (res == GTK_RESPONSE_ACCEPT) { + filename = gtk_file_chooser_get_filename ( + GTK_FILE_CHOOSER (dialog) + ); + + config_keys_set_data_folder_path (filename); + config_keys_save (); + + tree_folder_view_set_filename ( + tfview, + filename + ); + + g_free (filename); + } + + gtk_widget_destroy (dialog); +} + +void +open_file_activated_cb ( + GtkMenuItem *item, + gpointer user_data +) { + GtkWidget *dialog; + GtkFileChooser *chooser; + gint res; + gchar *data_folder; + + dialog = gtk_file_chooser_dialog_new ( + NULL, + GTK_WINDOW (main_window), + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Open", GTK_RESPONSE_ACCEPT, + NULL + ); + + data_folder = config_keys_get_data_folder_path (); + + chooser = GTK_FILE_CHOOSER (dialog); + gtk_file_chooser_set_current_folder ( + chooser, + data_folder + ); + + res = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (res == GTK_RESPONSE_ACCEPT) { + gchar *filename = gtk_file_chooser_get_filename (chooser); + open_file (filename); + g_free (filename); + } + + gtk_widget_destroy (dialog); + g_free (data_folder); +} + +void save_file_as_activated_cb ( + GtkMenuItem *item, + gpointer user_data +) { + GtkWidget *dialog; + GtkFileChooser *chooser; + gint res; + gchar *data_folder; + + dialog = gtk_file_chooser_dialog_new ( + NULL, + GTK_WINDOW (main_window), + GTK_FILE_CHOOSER_ACTION_SAVE, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Save", GTK_RESPONSE_ACCEPT, + NULL + ); + + data_folder = config_keys_get_data_folder_path (); + + chooser = GTK_FILE_CHOOSER (dialog); + gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE); + + if (get_opened_file_name () != NULL) { + gtk_file_chooser_set_current_name ( + chooser, + get_opened_file_name () + ); + } else { + gtk_file_chooser_set_current_folder ( + chooser, + data_folder + ); + } + + res = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (res == GTK_RESPONSE_ACCEPT) { + gchar *filename = gtk_file_chooser_get_filename (chooser); + save_file (filename); + g_free (filename); + } + + gtk_widget_destroy (dialog); + g_free (data_folder); +} + +void +save_file_activated_cb ( + GtkMenuItem *item, + gpointer user_data +) { + const gchar *filename; + + filename = get_opened_file_name (); + + if (filename == NULL) { + save_file_as_activated_cb (item, user_data); + return; + } + + save_file (NULL); +} + +void +zoom_adjustment_value_changed_cb ( + GtkAdjustment *adjustment, + gpointer user_data +) { + sprite_drawing_area_set_scale_factor ( + SPRITE_DRAWING_AREA (user_data), + gtk_adjustment_get_value (adjustment) + ); + gtk_widget_queue_draw (GTK_WIDGET (user_data)); +} + +void +tfview_file_activated_cb ( + TreeFolderView *tfview, + gchar *filename, + gpointer user_data +) { + open_file (filename); +} + +void +sourceview_buffer_modified_changed_cb ( + GtkTextBuffer *textbuffer, + gpointer user_data +) { + update_window_title (); +} + +void +new_file_activated_cb ( + GtkMenuItem *item, + gpointer user_data +) { + open_file (NULL); +} + +void +view_reset_to_center_activate_cb ( + GtkMenuItem *item, + gpointer user_data +) { + sprite_drawing_area_set_center ( + SPRITE_DRAWING_AREA (d_area), + 0, 0 + ); + + gtk_widget_queue_draw (d_area); +} + +void +show_tile_grid_toggled_cb ( + GtkCheckMenuItem *item, + gpointer user_data +) { + sda_layer_set_visible ( + tile_grid_layer, + gtk_check_menu_item_get_active (item) + ); + + gtk_widget_queue_draw (d_area); +} + +void +show_pixel_grid_toggled_cb ( + GtkCheckMenuItem *item, + gpointer user_data +) { + sda_layer_set_visible ( + pixel_grid_layer, + gtk_check_menu_item_get_active (item) + ); + + gtk_widget_queue_draw (d_area); +} + +void +menuitem_about_activate_cb ( + GtkMenuItem *item, + gpointer user_data +) { + gtk_dialog_run (GTK_DIALOG (user_data)); +} + +void +about_dialog_response_cb ( + GtkDialog *dialog, + gint response_id, + gpointer user_data +) { + if (response_id == GTK_RESPONSE_DELETE_EVENT) { + gtk_widget_hide (GTK_WIDGET (dialog)); + } +} diff --git a/saedit/callbacks.h b/saedit/callbacks.h new file mode 100644 index 0000000..7107353 --- /dev/null +++ b/saedit/callbacks.h @@ -0,0 +1,96 @@ +#ifndef _CALLBACKS_H_ +#define _CALLBACKS_H_ + +void +parse_buffer_clicked_cb ( + GtkToolButton *button, + gpointer user_data +); + +void +action_changed_cb (GtkComboBox *cbox, gpointer user_data); + +void +direction_changed_cb (GtkComboBox *cbox, gpointer user_data) { + +void +play_pause_clicked_cb ( + GtkToolButton *button, + gpointer user_data +); + +void +first_frame_clicked_cb ( + GtkToolButton *button, + gpointer user_data +); + +void +choose_df_activated_cb ( + GtkMenuItem *item, + gpointer user_data +); + +void +open_file_activated_cb ( + GtkMenuIterm *item, + gpointer user_data +); + +void +save_file_activated_cb ( + GtkMenuIterm *item, + gpointer user_data +); + +void +zoom_adjustment_value_changed_cb ( + GtkAdjustment *adjustment, + gpointer user_data +); + +void +tfview_file_activated_cb ( + TreeFolderView *tfview, + gchar *filename, + gpointer user_data +); + +void +new_file_activated_cb ( + GtkMenuItem *item, + gpointer user_data +); + +void +save_file_as_activated_cb ( + GtkMenuItem *item, + gpointer user_data +); + +void +show_tile_grid_toggled_cb ( + GtkCheckMenuItem *item, + gpointer user_data +); + +void +show_pixel_grid_toggled_cb ( + GtkCheckMenuItem *item, + gpointer user_data +); + +void +menuitem_about_activate_cb ( + GtkMenuItem *item, + gpointer user_data +); + +void +about_dialog_response_cb ( + GtkDialog *dialog, + gint response_id, + gpointer user_data +); + +#endif diff --git a/saedit/common.c b/saedit/common.c new file mode 100644 index 0000000..9bb8a30 --- /dev/null +++ b/saedit/common.c @@ -0,0 +1,22 @@ +#include "common.h" + +#include <stdlib.h> +#include <errno.h> + +gboolean +try_strtoint ( + const gchar *str, + gint *result +) { + gchar *endptr; + gint retval; + + errno = 0; + retval = strtol (str, &endptr, 10); + + if (*endptr != 0 || errno != 0) + return FALSE; + + *result = retval; + return TRUE; +} diff --git a/saedit/common.h b/saedit/common.h index 21e6526..1715e41 100644 --- a/saedit/common.h +++ b/saedit/common.h @@ -1,24 +1,12 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - #ifndef COMMON_H #define COMMON_H -#include <glib/gi18n.h> +#include <glib.h> -#define POSTFIX_FOLDER "..." -#define SEPARATOR_SLASH "/" -#define GRID_SIZE 32 -#define SPRITE_WIDTH_DEFAULT 64 -#define SPRITE_HEIGHT_DEFAULT 64 -#define FILE_TEMPLATE "template.xml" +gboolean +try_strtoint ( + const gchar *str, + gint *result +); #endif diff --git a/saedit/config.c b/saedit/config.c index 67bb63d..1e20411 100644 --- a/saedit/config.c +++ b/saedit/config.c @@ -1,82 +1,191 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - #include "config.h" +#include "xml.h" +#include <unistd.h> +#include <sys/stat.h> + +static GKeyFile *_config_keyfile = NULL; + +gchar * +_config_get_config_folder (void) { + return g_strjoin ( + "/", + g_get_user_config_dir (), + "saedit2", + NULL + ); +} + +gchar * +_config_get_key_file_path (void) { + gchar *dir = _config_get_config_folder (); + gchar *result; + + result = g_strjoin ( + "/", + dir, + "config.ini", + NULL + ); -Options *config_options_new() { - return g_new0(Options, 1); + g_free (dir); + return result; } -void config_options_load_from_file(Options *options, - gchar *file, - gchar *data_folder) { - options->sprites = NULL; +void +config_keys_load () { + gchar *filename; + + _config_keyfile = g_key_file_new (); + + filename = _config_get_key_file_path (); + + g_key_file_load_from_file ( + _config_keyfile, + filename, + 0, + NULL + ); + + g_free (filename); +} + +gchar * +config_keys_get_data_folder_path () { + gchar *result; + + if (_config_keyfile == NULL) + config_keys_load (); + + result = g_key_file_get_value ( + _config_keyfile, + "Default", + "Data Folder", + NULL + ); + + if (result == NULL) + result = g_strdup (""); + + return result; +} + +void +config_keys_set_data_folder_path (const gchar *filename) { + if (_config_keyfile == NULL) + config_keys_load (); + + g_key_file_set_value ( + _config_keyfile, + "Default", + "Data Folder", + filename + ); +} + +gint +config_keys_get_tile_size () { + /* TODO */ + return 32; +} - XMLNode *node = xml_parse_file(file); +void +config_keys_save () { + gchar *filename; + if (_config_keyfile == NULL) + return; + + filename = _config_get_config_folder (); + mkdir (filename, S_IRWXU); + g_free (filename); + + filename = _config_get_key_file_path (); + + g_key_file_save_to_file ( + _config_keyfile, + filename, + NULL + ); + + g_free (filename); +} + +static XMLNode *_config_paths_xml_root = NULL; + +void +config_data_paths_load () { + gchar *filename; + gchar *df_path; + + df_path = config_keys_get_data_folder_path (); + + filename = g_strjoin ( + "/", + df_path, + "paths.xml", + NULL + ); + + _config_paths_xml_root = xml_parse_file (filename); + + g_free (df_path); + g_free (filename); +} + +gchar * +config_data_paths_get_sprites_path () { + XMLNode *node; + GList *list; + gchar *name; + + if (_config_paths_xml_root == NULL) + config_data_paths_load (); + + node = _config_paths_xml_root; + if (node != NULL) { - GList *list = node->sub_nodes; + list = node->sub_nodes; while (TRUE) { - list = g_list_find_custom(list, "option", xml_node_compare_with_name_func); + list = g_list_find_custom ( + list, + "option", + xml_node_compare_with_name_func + ); + if (list == NULL) break; - gchar *name_attr = xml_node_get_attr_value(list->data, "name"); - if (name_attr != NULL) { - if (g_strcmp0(name_attr, "sprites") == 0) - options->sprites = xml_node_get_attr_value(list->data, "value"); + + name = xml_node_get_attr_value (list->data, "name"); + if (name != NULL && g_strcmp0 (name, "sprites") == 0) { + g_free (name); + return xml_node_get_attr_value (list->data, "value"); } + + g_free(name); list = list->next; } } - if (options->sprites == NULL) options->sprites = (gchar *)OPTION_SPRITES_DEFAULT; - options->sprites = g_strjoin(SEPARATOR_SLASH, data_folder, options->sprites, NULL); + return g_strdup (""); } -Keys *config_keys_new() { - Keys *keys = g_new0(Keys, 1); - keys->clientdata_folder = (gchar *)KEY_CLIENTDATA_FOLDER_DEFAULT; - keys->show_grid = KEY_SHOW_GRID_DEFAULT; - return keys; -} +gchar * +config_data_path_get_full_sprite_path (const gchar *rel_path) { + gchar *data_folder, *sprites_path, *filename; -void config_keys_save(Keys *keys) { - GKeyFile *key_file = g_key_file_new(); - g_key_file_set_value(key_file, "General", "ClientdataFolder", - g_strjoin(SEPARATOR_SLASH, - keys->clientdata_folder, - POSTFIX_FOLDER, - NULL)); - g_key_file_set_boolean(key_file, "General", "ShowGrid", keys->show_grid); - - mkdir(KEYS_CONFIG_DIR, S_IRWXU); - int fd = g_creat(KEYS_CONFIG_FILE, S_IREAD | S_IWRITE); - gchar *buf = g_key_file_to_data(key_file, NULL, NULL); - write(fd, buf, strlen(buf)); - close(fd); - - g_key_file_free(key_file); -} + data_folder = config_keys_get_data_folder_path (); + sprites_path = config_data_paths_get_sprites_path (); -void config_keys_load(Keys *keys) { - GKeyFile *key_file = g_key_file_new(); + filename = g_strjoin ( + "/", + data_folder, + sprites_path, + rel_path, + NULL + ); - g_key_file_load_from_file(key_file, - KEYS_CONFIG_FILE, - 0, - NULL); - if (g_key_file_has_key(key_file, "General", "ClientdataFolder", NULL)) - keys->clientdata_folder = g_key_file_get_value(key_file, "General", "ClientdataFolder", NULL); - if (g_key_file_has_key(key_file, "General", "ShowGrid", NULL)) - keys->show_grid = g_key_file_get_boolean(key_file, "General", "ShowGrid", NULL); + g_free (sprites_path); + g_free (data_folder); - g_key_file_free(key_file); + return filename; } diff --git a/saedit/config.h b/saedit/config.h index ca43eed..cae98bd 100644 --- a/saedit/config.h +++ b/saedit/config.h @@ -1,51 +1,32 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - -#ifndef CONFIG_H -#define CONFIG_H +#ifndef _CONFIG_H_ +#define _CONFIG_H_ #include <glib.h> -#include <glib/gstdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <string.h> -#include <unistd.h> -#include "common.h" -#include "xml.h" - -#define OPTION_SPRITES_DEFAULT "graphics/sprites/" - -#define KEY_SHOW_GRID_DEFAULT TRUE -#define KEY_CLIENTDATA_FOLDER_DEFAULT "" -#define KEYS_CONFIG_DIR g_strjoin(SEPARATOR_SLASH, g_get_user_config_dir(), "saedit", NULL) -#define KEYS_CONFIG_FILE g_strjoin(SEPARATOR_SLASH, KEYS_CONFIG_DIR, "config.ini", NULL) - -typedef struct { - gchar *sprites; -} Options; - -Options *config_options_new(); -void config_options_load_from_file(Options *options, - gchar *file, - gchar *data_folder); - -typedef struct { - gchar *clientdata_folder; - gboolean show_grid; -} Keys; - -Keys *config_keys_new(); -void config_keys_load(Keys *keys); -void config_keys_save(Keys *keys); + +void +config_keys_load (void); + +void +config_keys_save (void); + +gchar * +config_keys_get_data_folder_path (void); + +void +config_keys_set_data_folder_path ( + const gchar *filename +); + +gint +config_keys_get_tile_size (void); + +void +config_data_paths_load (void); + +gchar * +config_data_paths_get_sprites_path (void); + +gchar * +config_data_path_get_full_sprite_path (const gchar *rel_path); #endif diff --git a/saedit/context.c b/saedit/context.c new file mode 100644 index 0000000..2a14de5 --- /dev/null +++ b/saedit/context.c @@ -0,0 +1,227 @@ +#include <gtk/gtk.h> +#include "context.h" +#include "imageset.h" +#include "action.h" +#include "animation.h" +#include "xml.h" +#include "config.h" +#include "xmlsetup.h" + +struct _SpriteContext { + gchar *cdf_filename; + GList *imagesets; + GList *actions; + GList *includes; +}; + +SpriteContext * +sprite_context_new ( + const gchar *cdf_filename +) { + SpriteContext *context = (SpriteContext *) g_new0 (SpriteContext, 1); + context->cdf_filename = g_strdup (cdf_filename); + return context; +} + +void +sprite_context_add_imageset ( + SpriteContext *context, + XMLNode *node +) { + Imageset *imgset; + + g_return_if_fail (g_strcmp0 (node->name, "imageset") == 0); + + imgset = imageset_new (node, context->cdf_filename); + if (imgset == NULL) + return; + + if (g_list_find_custom ( + context->imagesets, imgset, + (GCompareFunc) imageset_compare_by_name) != NULL + ) { + imageset_free (imgset); + return; + } + + context->imagesets = g_list_append (context->imagesets, imgset); +} + +void +sprite_context_add_action ( + SpriteContext *context, + XMLNode *node, + gint included_from +) { + Action *action; + + g_return_if_fail (g_strcmp0 (node->name, "action") == 0); + + action = action_new (context, node, included_from); + if (action == NULL) + return; + + if (g_list_find_custom ( + context->actions, action, + (GCompareFunc) action_compare_by_hp_and_name) != NULL + ) { + action_free (action); + return; + } + + context->actions = g_list_append (context->actions, action); +} + +void +sprite_context_add_sprite ( + SpriteContext *context, + XMLNode *node, + gint included_from +) { + GList *list; + g_return_if_fail (node != NULL); + g_return_if_fail (g_strcmp0 (node->name, "sprite") == 0); + + list = node->sub_nodes; + for (; list != NULL; list = g_list_next (list)) { + XMLNode *current = (XMLNode *) list->data; + gchar *name = current->name; + if (g_strcmp0 (name, "include") == 0) { + XMLNode *sprite; + gchar *filename, *file; + + file = xml_node_get_attr_value (current, "file"); + if (file == NULL) { + /* TODO: report error */ + continue; + } + + if (g_list_find_custom ( + context->includes, file, + (GCompareFunc) g_strcmp0) != NULL + ) { + /* TODO: such file was already included */ + g_free (file); + continue; + } + + context->includes = g_list_append ( + context->includes, file + ); + + filename = config_data_path_get_full_sprite_path (file); + + sprite = xml_parse_file (filename); + g_free (filename); + + if (sprite == NULL) { + /* TODO: report error */ + continue; + } + + if (g_strcmp0 (sprite->name, "sprite") != 0) { + /* TODO: report error */ + continue; + } + + if (included_from == -1) + included_from = current->line_no; + + sprite_context_add_sprite ( + context, + sprite, + included_from + ); + + xml_free (sprite); + } else + if (g_strcmp0 (name, "imageset") == 0) { + sprite_context_add_imageset (context, current); + } else + if (g_strcmp0 (name, "action") == 0) { + sprite_context_add_action (context, current, included_from); + } else + if (g_strcmp0 (name, "saedit") == 0) { + if (included_from == -1) { /* we are in the main context */ + xml_setup_setup (current); + } + } else { + /* TODO: sprite contains something unknown */ + } + } +} + +Action * +sprite_context_get_action ( + const SpriteContext *context, + gint hp, + const gchar *name +) { + GList *action = context->actions; + + while (action != NULL) { + if (action_hp_and_name_equals ( + (Action *) action->data, + hp, + name + )) { + return (Action *) action->data; + } + + action = g_list_next (action); + } + + return NULL; +} + +Imageset * +sprite_context_get_imageset ( + const SpriteContext *context, + const gchar *name +) { + GList *imageset = context->imagesets; + + while (imageset != NULL) { + if (imageset_name_equals ( + (Imageset *) imageset->data, + name + )) { + return (Imageset *) imageset->data; + } + + imageset = g_list_next (imageset); + } + + return NULL; +} + +GList * +sprite_context_get_actions ( + const SpriteContext *context +) { + return g_list_copy (context->actions); +} + +void +sprite_context_free ( + SpriteContext *context +) { + g_list_free_full ( + context->imagesets, + (GDestroyNotify) imageset_free + ); + + g_list_free_full ( + context->actions, + (GDestroyNotify) action_free + ); + + g_list_free_full ( + context->includes, + (GDestroyNotify) g_free + ); + + g_free (context->cdf_filename); + + g_free (context); +} diff --git a/saedit/context.h b/saedit/context.h new file mode 100644 index 0000000..9d41fde --- /dev/null +++ b/saedit/context.h @@ -0,0 +1,50 @@ +#ifndef CONTEXT_H +#define CONTEXT_H + +#include "xml.h" +#include "imageset.h" +#include "action.h" + +typedef struct _SpriteContext SpriteContext; + +SpriteContext * +sprite_context_new ( + const gchar *client_data_folder +); + +void +sprite_context_add_sprite ( + SpriteContext *context, + XMLNode *node, + gboolean is_include +); + +Action * +action_new ( + const SpriteContext *context, + const XMLNode *node, + gint included_from +); + +Action * +sprite_context_get_action ( + const SpriteContext *context, + gint hp, + const gchar *name +); + +Imageset * +sprite_context_get_imageset ( + const SpriteContext *context, + const gchar *name +); + +GList * +sprite_context_get_actions ( + const SpriteContext *context +); + +void +sprite_context_free (SpriteContext *context); + +#endif diff --git a/saedit/drawfuncs.c b/saedit/drawfuncs.c new file mode 100644 index 0000000..97a769e --- /dev/null +++ b/saedit/drawfuncs.c @@ -0,0 +1,107 @@ +#include "interactor.h" +#include "drawfuncs.h" +#include "spritedrawingarea.h" +#include "config.h" + +void +interactor_sprite_layer_draw_func ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +) { + const GdkPixbuf *sprite; + gint offsetX, offsetY; + Interactor *interactor = *((Interactor **) user_data); + + if (interactor == NULL) + return; + + sprite = interactor_get_sprite (interactor); + + if (sprite == NULL) + return; + + interactor_get_offset (interactor, &offsetX, &offsetY); + + gdk_cairo_set_source_pixbuf ( + cr, sprite, + offsetX, + offsetY + config_keys_get_tile_size () / 2 + ); + cairo_pattern_set_filter ( + cairo_get_source (cr), + CAIRO_FILTER_NEAREST + ); + cairo_paint (cr); +} + +void +background_layer_draw_func ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +) { + GdkRGBA *rgba = (GdkRGBA *) user_data; + + gdk_cairo_set_source_rgba (cr, rgba); + + cairo_rectangle ( + cr, + -SPRITE_DRAWING_AREA_FIELD_SIZE, + -SPRITE_DRAWING_AREA_FIELD_SIZE, + 2 * SPRITE_DRAWING_AREA_FIELD_SIZE, + 2 * SPRITE_DRAWING_AREA_FIELD_SIZE + ); + cairo_fill (cr); +} + +void +tile_grid_layer_draw_func ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +) { + gint x; + gint field_size = SPRITE_DRAWING_AREA_FIELD_SIZE; + gint tile_size = config_keys_get_tile_size (); + + cairo_set_line_width (cr, 1.0); + cairo_set_operator (cr, CAIRO_OPERATOR_XOR); + cairo_set_source_rgba (cr, 0, 0, 0, 0.5); + cairo_translate (cr, 0.5, 0.5); + + x = -tile_size / 2; + while (x >= -field_size) + x -= tile_size; + + for (; x <= field_size; x += tile_size) { + cairo_move_to (cr, x, -field_size); + cairo_line_to (cr, x, field_size); + cairo_move_to (cr, -field_size, x); + cairo_line_to (cr, field_size, x); + } + + cairo_stroke (cr); +} + +void +pixel_grid_layer_draw_func ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +) { + gint x; + gint field_size = SPRITE_DRAWING_AREA_FIELD_SIZE; + + cairo_set_line_width (cr, 0.1); + cairo_set_source_rgb (cr, 0, 0, 0); + + for (x = -field_size; x <= field_size; ++x) { + cairo_move_to (cr, x, -field_size); + cairo_line_to (cr, x, field_size); + cairo_move_to (cr, -field_size, x); + cairo_line_to (cr, field_size, x); + } + + cairo_stroke (cr); +} diff --git a/saedit/drawfuncs.h b/saedit/drawfuncs.h new file mode 100644 index 0000000..1c1154e --- /dev/null +++ b/saedit/drawfuncs.h @@ -0,0 +1,33 @@ +#ifndef _DRAW_FUNCS_H_ +#define _DRAW_FUNCS_H_ + +#include "spritedrawingarea.h" + +void +interactor_sprite_layer_draw_func ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +); + +void +background_layer_draw_func ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +); + +void +tile_grid_layer_draw_func ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +); + +void +pixel_grid_layer_draw_func ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +); +#endif diff --git a/saedit/errors.c b/saedit/errors.c new file mode 100644 index 0000000..ff3a710 --- /dev/null +++ b/saedit/errors.c @@ -0,0 +1,23 @@ +#include "errors.h" +#include "main.h" + +void +post_error ( + const gchar *error_context, + const gchar *error_message +) { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new_with_markup ( + GTK_WINDOW (main_window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "<b>%s error:</b> %s", + error_context, + error_message + ); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); +} diff --git a/saedit/errors.h b/saedit/errors.h new file mode 100644 index 0000000..58b12e6 --- /dev/null +++ b/saedit/errors.h @@ -0,0 +1,12 @@ +#ifndef _ERRORS_H_ +#define _ERRORS_H_ + +#include <glib.h> + +void +post_error ( + const gchar *error_context, + const gchar *error_message +); + +#endif diff --git a/saedit/file.c b/saedit/file.c new file mode 100644 index 0000000..5496c86 --- /dev/null +++ b/saedit/file.c @@ -0,0 +1,103 @@ +#include <gtksourceview/gtksource.h> +#include "errors.h" +#include "buffer.h" +#include "main.h" +#include "file.h" + +#include <string.h> + + +gchar *opened_file_name = NULL; + +gboolean +show_unsaved_changes_dialog () { + gint result; + GtkWidget *dialog; + + if (!buffer_get_modified ()) { + return FALSE; + } + + dialog = gtk_message_dialog_new ( + GTK_WINDOW (main_window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_YES_NO, + "There are unsaved changes in the current file. " + "Do you wish to proceed?" + ); + + result = gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + + return result == GTK_RESPONSE_NO; +} + +void +open_file ( + const gchar *filename +) { + gsize len; + gchar *text; + + if (show_unsaved_changes_dialog ()) + return; + + release_context (); + + if (filename != NULL) { + g_file_get_contents ( + filename, + &text, + &len, + NULL + ); + } else { + text = g_strdup (""); + len = 0; + } + + g_free (opened_file_name); + opened_file_name = g_strdup (filename); + + buffer_set_text (text, len); + buffer_set_modified (FALSE); + + update_window_title (); + + g_free (text); +} + +void +save_file (const gchar *filename) { + GError *error = NULL; + gboolean success; + gchar *text = buffer_get_text (); + + success = g_file_set_contents ( + filename == NULL ? opened_file_name : filename, + text, + strlen (text), + &error + ); + + if (!success) { + post_error ("Saving", error->message); + } else { + if (filename != NULL) { + g_free (opened_file_name); + opened_file_name = g_strdup (filename); + } + + buffer_set_modified (FALSE); + update_window_title (); + } + + g_free (text); +} + +const gchar * +get_opened_file_name () { + return opened_file_name; +} + diff --git a/saedit/file.h b/saedit/file.h new file mode 100644 index 0000000..9354879 --- /dev/null +++ b/saedit/file.h @@ -0,0 +1,16 @@ +#ifndef _FILE_H_ +#define _FILE_H_ + +gboolean +show_unsaved_changes_dialog (void); + +const gchar * +get_opened_file_name (void); + +void +open_file (const gchar *filename); + +void +save_file (const gchar *filename); + +#endif diff --git a/saedit/glade.sh b/saedit/glade.sh new file mode 100755 index 0000000..77f5b18 --- /dev/null +++ b/saedit/glade.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +GLADE_CATALOG_SEARCH_PATH=glade GLADE_MODULE_SEARCH_PATH=glade glade $* diff --git a/saedit/glade/saedit-catalog.xml b/saedit/glade/saedit-catalog.xml new file mode 100644 index 0000000..4f304a7 --- /dev/null +++ b/saedit/glade/saedit-catalog.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<glade-catalog name="saedit" library="saedit" depends="gtk+"> + <glade-widget-classes> + <glade-widget-class + name="TreeFolderView" + generic-name="treefolderview" + title="TreeFolderView" + /> + <glade-widget-class + name="SpriteDrawingArea" + generic-name="spritedrawingarea" + title="SpriteDrawingArea" + /> + <glade-widget-class + name="GtkSourceBuffer" + generic-name="sourcebuffer" + title="GtkSourceBuffer" + /> + </glade-widget-classes> + + <glade-widget-group name="saedit" title="SAEdit"> + <glade-widget-class-ref name="TreeFolderView"/> + <glade-widget-class-ref name="SpriteDrawingArea"/> + <glade-widget-class-ref name="GtkSourceBuffer"/> + </glade-widget-group> +</glade-catalog> diff --git a/saedit/grounds/earth.png b/saedit/grounds/earth.png Binary files differdeleted file mode 100644 index 9bdb25a..0000000 --- a/saedit/grounds/earth.png +++ /dev/null diff --git a/saedit/grounds/grass.png b/saedit/grounds/grass.png Binary files differdeleted file mode 100644 index a0f3ab5..0000000 --- a/saedit/grounds/grass.png +++ /dev/null diff --git a/saedit/grounds/sand.png b/saedit/grounds/sand.png Binary files differdeleted file mode 100644 index 31be5db..0000000 --- a/saedit/grounds/sand.png +++ /dev/null diff --git a/saedit/grounds/water.png b/saedit/grounds/water.png Binary files differdeleted file mode 100644 index 20da6b4..0000000 --- a/saedit/grounds/water.png +++ /dev/null diff --git a/saedit/iface.ui b/saedit/iface.ui new file mode 100644 index 0000000..dd1cab9 --- /dev/null +++ b/saedit/iface.ui @@ -0,0 +1,577 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface> + <requires lib="gtk+" version="3.12"/> + <requires lib="gtksourceview" version="3.0"/> + <requires lib="saedit" version="0.0"/> + <object class="GtkAccelGroup" id="accelgroup1"/> + <object class="GtkFileFilter" id="filefilter-xml"> + <patterns> + <pattern>*.xml</pattern> + </patterns> + </object> + <object class="GtkListStore" id="liststore-actions"> + <columns> + <!-- column-name name --> + <column type="gchararray"/> + <!-- column-name hp --> + <column type="gint"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkSourceBuffer" id="sourceview-buffer"> + <signal name="modified-changed" handler="sourceview_buffer_modified_changed_cb" swapped="no"/> + </object> + <object class="GtkAdjustment" id="zoom-adjustment"> + <property name="lower">1</property> + <property name="upper">10</property> + <property name="value">1</property> + <property name="step_increment">0.10000000000000001</property> + <property name="page_increment">0.5</property> + <signal name="value-changed" handler="zoom_adjustment_value_changed_cb" object="drawingarea-main" swapped="no"/> + </object> + <object class="GtkWindow" id="window-main"> + <property name="can_focus">False</property> + <property name="icon">logo.svg</property> + <signal name="delete-event" handler="window_main_delete_event_cb" swapped="no"/> + <signal name="destroy" handler="gtk_main_quit" swapped="no"/> + <child> + <placeholder/> + </child> + <child> + <object class="GtkBox" id="vbox1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkMenuBar" id="menubar3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkMenuItem" id="menuitem9"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu7"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="accel_group">accelgroup1</property> + <child> + <object class="GtkImageMenuItem" id="menuitem-file-new"> + <property name="label">gtk-new</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <signal name="activate" handler="new_file_activated_cb" swapped="no"/> + <accelerator key="n" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="menuitem-file-open"> + <property name="label">gtk-open</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <signal name="activate" handler="open_file_activated_cb" swapped="no"/> + <accelerator key="o" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="menuitem-file-save"> + <property name="label">gtk-save</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <signal name="activate" handler="save_file_activated_cb" swapped="no"/> + <accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="menuitem-file-save-as"> + <property name="label">gtk-save-as</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <signal name="activate" handler="save_file_as_activated_cb" swapped="no"/> + <accelerator key="s" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/> + </object> + </child> + <child> + <object class="GtkSeparatorMenuItem" id="<separator>"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + </child> + <child> + <object class="GtkMenuItem" id="menuitem-choose-df"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Choose data folder...</property> + <signal name="activate" handler="choose_df_activated_cb" object="treefolderview-main" swapped="no"/> + </object> + </child> + <child> + <object class="GtkSeparatorMenuItem" id="separatormenuitem3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem25"> + <property name="label">gtk-quit</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="GtkMenuItem" id="menuitem11"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">_View</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkMenuItem" id="menuitem-view-reset-to-center"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Reset to center</property> + <property name="use_underline">True</property> + <signal name="activate" handler="view_reset_to_center_activate_cb" swapped="no"/> + <accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </object> + </child> + <child> + <object class="GtkSeparatorMenuItem"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + </child> + <child> + <object class="GtkCheckMenuItem" id="menuitem-show-tile-grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Tile grid</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <signal name="toggled" handler="show_tile_grid_toggled_cb" swapped="no"/> + <accelerator key="g" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </object> + </child> + <child> + <object class="GtkCheckMenuItem" id="menuitem-show-pixel-grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Pixel grid</property> + <property name="use_underline">True</property> + <signal name="toggled" handler="show_pixel_grid_toggled_cb" swapped="no"/> + <accelerator key="g" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="GtkMenuItem" id="menuitem12"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu9"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkImageMenuItem" id="menuitem-about"> + <property name="label">gtk-about</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <signal name="activate" handler="menuitem_about_activate_cb" object="about-dialog" swapped="no"/> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkPaned" id="paned2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="position">1</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow"> + <property name="width_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="TreeFolderView" id="treefolderview-main"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="filter">filefilter-xml</property> + <property name="filename">/home/</property> + <signal name="file-activated" handler="tfview_file_activated_cb" object="sourceview-main" swapped="no"/> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="treeview-selection1"/> + </child> + </object> + </child> + </object> + <packing> + <property name="resize">False</property> + <property name="shrink">False</property> + </packing> + </child> + <child> + <object class="GtkPaned" id="paned3"> + <property name="width_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="orientation">vertical</property> + <property name="position">100</property> + <child> + <object class="GtkBox" id="box1"> + <property name="height_request">100</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="SpriteDrawingArea" id="drawingarea-main"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScale" id="zoom-scale"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="orientation">vertical</property> + <property name="adjustment">zoom-adjustment</property> + <property name="inverted">True</property> + <property name="restrict_to_fill_level">False</property> + <property name="round_digits">1</property> + <property name="has_origin">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Action:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="padding">5</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBox" id="cbox-actions"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="model">liststore-actions</property> + <property name="id_column">2</property> + <signal name="changed" handler="action_changed_cb" swapped="no"/> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"> + <property name="xalign">1</property> + <property name="alignment">right</property> + </object> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Direction: </property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="padding">5</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="cboxtext-directions"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="button_sensitivity">on</property> + <signal name="changed" handler="direction_changed_cb" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkToolbar" id="toolbar-animation"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkToolButton" id="button-parse-buffer"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Parse buffer</property> + <property name="stock_id">gtk-execute</property> + <signal name="clicked" handler="parse_buffer_clicked_cb" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkSeparatorToolItem" id="<separator>1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="button-anim-first"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">First frame</property> + <property name="stock_id">gtk-goto-first</property> + <signal name="clicked" handler="first_frame_clicked_cb" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="button-anim-prev"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Previous frame</property> + <property name="stock_id">gtk-go-back</property> + </object> + <packing> + <property name="expand">True</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="button-anim-play"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Play/Pause</property> + <property name="use_underline">True</property> + <property name="icon_name">media-playback-start</property> + <signal name="clicked" handler="play_pause_clicked_cb" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="button-anim-next"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Next frame</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-go-forward</property> + <signal name="clicked" handler="next_frame_clicked_cb" swapped="no"/> + </object> + <packing> + <property name="expand">True</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="button-anim-last"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Last frame</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-goto-last</property> + </object> + <packing> + <property name="expand">True</property> + <property name="homogeneous">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">False</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="width_request">100</property> + <property name="height_request">100</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkSourceView" id="sourceview-main"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="left_margin">2</property> + <property name="right_margin">2</property> + <property name="buffer">sourceview-buffer</property> + <property name="monospace">True</property> + <property name="show_line_numbers">True</property> + <property name="show_line_marks">True</property> + <property name="tab_width">4</property> + <property name="indent_width">4</property> + <property name="auto_indent">True</property> + <property name="insert_spaces_instead_of_tabs">True</property> + </object> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">False</property> + </packing> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">False</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkAboutDialog" id="about-dialog"> + <property name="can_focus">False</property> + <property name="destroy_with_parent">True</property> + <property name="type_hint">dialog</property> + <property name="transient_for">window-main</property> + <property name="program_name">Sprite Animation Editor</property> + <property name="version">alpha2</property> + <property name="copyright" translatable="yes">Copyleft (ɔ) Vasily_Makarov</property> + <property name="comments" translatable="yes">Editor, parser and player for the TMW/Evol project animations. Greatly inspired by the project developers team.</property> + <property name="authors">Danil "Vasily Makarov" Sagunov <vasily@evolonline.org></property> + <property name="logo">logo.svg</property> + <property name="license_type">gpl-3-0</property> + <signal name="response" handler="about_dialog_response_cb" swapped="no"/> + <child> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + </child> + </object> +</interface> diff --git a/saedit/imageset.c b/saedit/imageset.c new file mode 100644 index 0000000..9ae2ea0 --- /dev/null +++ b/saedit/imageset.c @@ -0,0 +1,130 @@ +#include "imageset.h" +#include <string.h> + +struct _Imageset { + gchar *name; + gint width, height; + gint offsetX, offsetY; + + GdkPixbuf *pixbuf; +}; + +Imageset * +imageset_new ( + const XMLNode *node, + const gchar *cdf_filename +) { + Imageset *imgset; + gchar *src, *filename; + GError *err = NULL; + gboolean fail = FALSE; + + g_return_val_if_fail (g_strcmp0 (node->name, "imageset") == 0, NULL); + + imgset = (Imageset *) g_new0 (Imageset, 1); + + imgset->name = xml_node_get_attr_value (node, "name"); + if (imgset->name == NULL) { + /* TODO: report error */ + fail = TRUE; + } + + src = xml_node_get_attr_value (node, "src"); + if (src == NULL) { + /* TODO: report error */ + fail = TRUE; + } else { + gchar *delim = strchr (src, '|'); + if (delim != NULL) + *delim = 0; + /* TODO: process palettes? */ + } + + imgset->width = xml_node_get_int_attr_value (node, "width", -1); + imgset->height = xml_node_get_int_attr_value (node, "height", -1); + if (imgset->width <= 0 || imgset->height <= 0) { + /* TODO: report error */ + fail = TRUE; + } + + imgset->offsetX = xml_node_get_int_attr_value (node, "offsetX", 0); + imgset->offsetY = xml_node_get_int_attr_value (node, "offsetY", 0); + + filename = g_strconcat (cdf_filename, "/", src, NULL); + imgset->pixbuf = gdk_pixbuf_new_from_file (filename, &err); + + if (imgset->pixbuf == NULL) { + /* TODO handle err and report error */ + fail = TRUE; + } + + if (fail) { + imageset_free (imgset); + return NULL; + } + + return imgset; +} + +gint +imageset_compare_by_name ( + const Imageset *first, + const Imageset *second +) { + return g_strcmp0 (first->name, second->name); +} + +GdkPixbuf * +imageset_get_sprite_by_index ( + const Imageset *imageset, + gint index +) { + gint w = gdk_pixbuf_get_width (imageset->pixbuf); + w /= imageset->width; + + g_return_val_if_fail (index >= 0, NULL); + + return gdk_pixbuf_new_subpixbuf ( + imageset->pixbuf, + (index % w) * imageset->width, + (index / w) * imageset->height, + imageset->width, + imageset->height + ); +} + +void +imageset_free (Imageset *imgset) { + g_free (imgset->name); + if (imgset->pixbuf != NULL) + g_object_unref (imgset->pixbuf); + g_free (imgset); +} + +gboolean +imageset_name_equals ( + const Imageset *imageset, + const gchar *name +) { + return g_strcmp0 (imageset->name, name) == 0; +} + +void +imageset_get_offset ( + const Imageset *imageset, + gint *offsetX, + gint *offsetY +) { + *offsetX = imageset->offsetX; + *offsetY = imageset->offsetY; +} + +void +imageset_get_size ( + const Imageset *imageset, + gint *width, + gint *height +) { + *width = imageset->width; + *height = imageset->height; +} diff --git a/saedit/imageset.h b/saedit/imageset.h new file mode 100644 index 0000000..3496d65 --- /dev/null +++ b/saedit/imageset.h @@ -0,0 +1,50 @@ +#ifndef IMAGESET_H +#define IMAGESET_H + +#include <gdk/gdk.h> +#include "common.h" +#include "xml.h" + +typedef struct _Imageset Imageset; + +Imageset * +imageset_new ( + const XMLNode *node, + const gchar *cdf_filename +); + +void +imageset_free (Imageset *imageset); + +gint +imageset_compare_by_name ( + const Imageset *first, + const Imageset *second +); + +GdkPixbuf * +imageset_get_sprite_by_index ( + const Imageset *imageset, + gint index +); + +gboolean +imageset_name_equals ( + const Imageset *imageset, + const gchar *name +); + +void +imageset_get_offset ( + const Imageset *imageset, + gint *offsetX, + gint *offsetY +); + +void +imageset_get_size ( + const Imageset *imageset, + gint *width, + gint *height +); +#endif diff --git a/saedit/interactor.c b/saedit/interactor.c new file mode 100644 index 0000000..85e55fa --- /dev/null +++ b/saedit/interactor.c @@ -0,0 +1,439 @@ +#include <glib.h> +#include <stdlib.h> + +#include "interactor.h" +#include "imageset.h" +#include "action.h" +#include "animation.h" +#include "errors.h" + +struct _Interactor { + const SpriteContext *context; + const Action *action; + const Animation *animation; + gchar *direction; + gboolean rand_checked; + GList *element; + gint delay; + + guint loop_tag; + guint tick_length; + + InteractionUpdatedFunc updated_cb; + + GList *repeaters; +}; + +static gboolean +interactor_updated_func (Interactor *interactor) { + g_return_val_if_fail (interactor->updated_cb != NULL, FALSE); + + interactor->updated_cb (interactor); + return FALSE; +} + +static void +interactor_updated (Interactor *interactor) { + if (interactor->updated_cb == NULL) + return; + + g_main_context_invoke ( + NULL, + (GSourceFunc) interactor_updated_func, + interactor + ); +} + +static AnimElement * +interactor_get_element (const Interactor *interactor) { + if (interactor->element == NULL) + return NULL; + return (AnimElement *) interactor->element->data; +} + +Interactor * +interactor_new ( + const SpriteContext *context +) { + Interactor *interactor = g_new0 (Interactor, 1); + + interactor->context = context; + interactor->repeaters = NULL; + return interactor; +} + +gboolean +interactor_reset_animation ( + Interactor *interactor +) { + GList *l; + + for (l = interactor->repeaters; l != NULL; l = l->next) + interactor_reset_animation ((Interactor *) l->data); + + if (interactor->action == NULL) + return FALSE; + + interactor->animation = action_get_animation ( + interactor->action, + interactor->direction + ); + + g_return_val_if_fail (interactor->animation != NULL, FALSE); + + interactor->element = interactor->animation->elements; + interactor->delay = 0; + interactor->rand_checked = TRUE; + interactor_updated (interactor); + interactor_play (interactor, 0); + + return TRUE; +} + +gboolean +interactor_set_action ( + Interactor *interactor, + gint hp, + const gchar *name +) { + Action *action; + GList *l; + + for (l = interactor->repeaters; l != NULL; l = l->next) + interactor_set_action ((Interactor *) l->data, hp, name); + + if ( + interactor->action != NULL && + action_hp_and_name_equals (interactor->action, hp, name) + ) + return FALSE; + + action = sprite_context_get_action ( + interactor->context, hp, name + ); + + if (action == NULL) + return FALSE; + + interactor->action = action; + return interactor_reset_animation (interactor); +} + +gboolean +interactor_set_direction ( + Interactor *interactor, + const gchar *direction +) { + GList *l; + + for (l = interactor->repeaters; l != NULL; l = l->next) + interactor_set_direction ((Interactor *) l->data, direction); + + if (g_strcmp0 (interactor->direction, direction) != 0) { + if (interactor->direction != NULL) + g_free (interactor->direction); + + interactor->direction = g_strdup (direction); + return interactor_reset_animation (interactor); + } + + return FALSE; +} + +static gboolean +_animation_element_rand_check ( + const AnimElement *element +) { + if (element->rand == 100) return TRUE; + if (element->rand == 0) return FALSE; + return rand() % 100 < element->rand; +} + +gboolean +interactor_play ( + Interactor *interactor, + gint time +) { + gboolean updated = FALSE; + GList *l; + + for (l = interactor->repeaters; l != NULL; l = l->next) + interactor_play ((Interactor *) l->data, time); + + g_return_val_if_fail (time >= 0, FALSE); + + if (interactor->action == NULL) + return FALSE; + if (interactor->animation == NULL) + return FALSE; + g_return_val_if_fail (interactor->element != NULL, FALSE); + + interactor->delay += time; + + while (TRUE) { + AnimElement *element = interactor_get_element (interactor); + gint e_delay = element->delay; + + if ( interactor->rand_checked || + _animation_element_rand_check (element) + ) { + interactor->rand_checked = TRUE; + + if (interactor->delay < e_delay) + break; + + interactor->delay -= e_delay; + interactor->rand_checked = FALSE; + updated = TRUE; + + if (element->type == ELEMENT_END) { + interactor_reset_animation (interactor); + return FALSE; + } else + + if (element->type == ELEMENT_FRAME) { + if (e_delay == 0) + break; + } else + + if (element->type == ELEMENT_PAUSE) { + if (e_delay == 0) + break; + } else + + if (element->type == ELEMENT_JUMP) { + gint delay = interactor->delay; + + gboolean found = interactor_set_action ( + interactor, + interactor->action->hp, + element->str + ); + + if (!found) { + /* TODO: report about this */ + return FALSE; + } + + return interactor_play ( + interactor, + delay + ); + } else + + if (element->type == ELEMENT_LABEL) { + + } else + + if (element->type == ELEMENT_GOTO) { + GList *nelem = + interactor->animation->elements; + + while (nelem != NULL) { + AnimElement *current = + (AnimElement *) nelem->data; + if (current->type == ELEMENT_LABEL) { + if (g_strcmp0 ( + current->str, + element->str) == 0 + ) + break; + } + + nelem = g_list_next (nelem); + } + + if (nelem != NULL) { + interactor->element = nelem; + continue; + } else { + post_error ("Playback", "Specified goto label not found"); + return FALSE; + } + } + } + + interactor->element = g_list_next (interactor->element); + if (interactor->element == NULL) + interactor->element = interactor->animation->elements; + } + + if (updated) + interactor_updated (interactor); + + return TRUE; +} + +const GdkPixbuf * +interactor_get_sprite (const Interactor *interactor) { + if (interactor->element == NULL) + return NULL; + return interactor_get_element (interactor)->sprite; +} + +void +interactor_get_offset ( + const Interactor *interactor, + gint *offsetX, + gint *offsetY +) { + AnimElement *element = interactor_get_element (interactor); + if (element == NULL) + return; + + *offsetX = element->offsetX; + *offsetY = element->offsetY; +} + +gboolean +interactor_loop_tick (Interactor *interactor) { + gboolean result = interactor_play ( + interactor, + interactor->tick_length + ); + + if (result == FALSE) { + interactor->loop_tag = 0; + interactor_updated (interactor); + } + + return result; +} + +void +interactor_loop_start ( + Interactor *interactor, + const guint interval, + const guint tick_length +) { + if (interactor->loop_tag != 0) + return; + + interactor->tick_length = tick_length; + interactor->loop_tag = g_timeout_add ( + interval, + (GSourceFunc) interactor_loop_tick, + interactor + ); + + interactor_updated (interactor); +} + +gboolean +interactor_loop_stop (Interactor *interactor) { + if (interactor->loop_tag == 0) + return FALSE; + + g_source_remove (interactor->loop_tag); + interactor->loop_tag = 0; + + interactor_updated (interactor); + + return TRUE; +} + +gboolean +interactor_loop_running ( + const Interactor *interactor +) { + if (interactor == NULL) + return FALSE; + return interactor->loop_tag != 0; +} + +void +interactor_free (Interactor *interactor) { + interactor_loop_stop (interactor); + g_list_free (interactor->repeaters); + g_free (interactor); +} + +void +interactor_free_with_repeaters (Interactor *interactor) { + interactor_loop_stop (interactor); + + g_list_free_full ( + interactor->repeaters, + (GDestroyNotify) interactor_free_with_repeaters + ); + + g_free (interactor); +} + +void +interactor_set_updated_callback ( + Interactor *interactor, + InteractionUpdatedFunc callback +) { + interactor->updated_cb = callback; +} + +gint +interactor_get_line_no ( + Interactor *interactor +) { + AnimElement *element = interactor_get_element (interactor); + + if (element == NULL) + return -1; + + return element->line_no; +} + +const gchar * +interactor_get_animation_direction ( + const Interactor *interactor +) { + if (interactor->animation == NULL) + return NULL; + return interactor->animation->direction; +} + +const gchar * +interactor_get_direction ( + const Interactor *interactor +) { + return interactor->direction; +} + +gboolean +interactor_get_action_hp_and_name ( + const Interactor *interactor, + gint *hp, + gchar **name +) { + if (interactor->action == NULL) + return FALSE; + + action_get_hp_and_name (interactor->action, hp, name); + return TRUE; +} + +void +interactor_skip_current_frame ( + Interactor *interactor +) { + AnimElement *element; + + interactor_loop_stop (interactor); + element = interactor_get_element (interactor); + + if (element != NULL) { + g_return_if_fail (interactor->delay <= element->delay); + interactor_play ( + interactor, + element->delay - interactor->delay + ); + } +} + +void +interactor_add_repeater ( + Interactor *interactor, + Interactor *repeater +) { + interactor->repeaters = g_list_append ( + interactor->repeaters, + repeater + ); +} diff --git a/saedit/interactor.h b/saedit/interactor.h new file mode 100644 index 0000000..5d0ddfc --- /dev/null +++ b/saedit/interactor.h @@ -0,0 +1,110 @@ +#ifndef _INTERACTOR_H_ +#define _INTERACTOR_H_ + +#include "context.h" + +typedef struct _Interactor Interactor; + +Interactor * +interactor_new ( + const SpriteContext *context +); + +gboolean +interactor_set_action ( + Interactor *interactor, + gint hp, + const gchar *name +); + +gboolean +interactor_reset_animation ( + Interactor *interactor +); + +gboolean +interactor_set_direction ( + Interactor *interactor, + const gchar *direction +); + +gboolean +interactor_play ( + Interactor *interactor, + gint time +); + +const GdkPixbuf * +interactor_get_sprite (const Interactor *interactor); + +void +interactor_loop_start ( + Interactor *interactor, + const guint interval, + const guint tick_length +); + +gboolean +interactor_loop_stop (Interactor *interactor); + +void +interactor_free (Interactor *interactor); + +void +interactor_free_with_repeaters (Interactor *interactor); + +typedef void +(*InteractionUpdatedFunc) (Interactor *interactor); + +void +interactor_set_updated_callback ( + Interactor *interactor, + InteractionUpdatedFunc callback +); + +void +interactor_get_offset ( + const Interactor *interactor, + gint *offsetX, + gint *offsetY +); + +gint +interactor_get_line_no ( + Interactor *interactor +); + +const gchar * +interactor_get_animation_direction ( + const Interactor *interactor +); + +const gchar * +interactor_get_direction ( + const Interactor *interactor +); + +gboolean +interactor_get_action_hp_and_name ( + const Interactor *interactor, + gint *hp, + gchar **name +); + +gboolean +interactor_loop_running ( + const Interactor *interactor +); + +void +interactor_skip_current_frame ( + Interactor *interactor +); + +void +interactor_add_repeater ( + Interactor *interactor, + Interactor *repeater +); + +#endif diff --git a/saedit/interface.c b/saedit/interface.c deleted file mode 100644 index 0984cbd..0000000 --- a/saedit/interface.c +++ /dev/null @@ -1,124 +0,0 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - -GtkWidget *reload_menu_item = NULL; -GtkWidget *find_dialog = NULL; -GtkWidget *toolbar = NULL; - -void find_menu_item_activate_callback(GtkWidget *menuitem, gpointer user_data) { - gtk_dialog_run(GTK_DIALOG(find_dialog)); -} - -void save_dialog_response_callback(GtkWidget *dialog, gint response_id, gpointer user_data) { - if (response_id == GTK_RESPONSE_ACCEPT) { - gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - if (filename != NULL) { - save_to_xml_file(filename); - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(xml_file_chooser_button), filename); - } - } - gtk_widget_destroy(dialog); -} - -void save_dialog_show() { - GtkDialog *dialog = GTK_DIALOG(gtk_file_chooser_dialog_new(_("Save file as..."), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL)); - g_signal_connect(dialog, "response", G_CALLBACK(save_dialog_response_callback), NULL); - gtk_dialog_run(dialog); -} - -void save_menu_item_activate_callback(GtkWidget *menuitem, GtkWidget *fsdialog) { - gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(xml_file_chooser_button)); - if (filename != NULL) - save_to_xml_file(filename); - else - save_dialog_show(); -} - -void xml_file_save_button_callback(GtkWidget *button, gpointer user_data) { - gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(xml_file_chooser_button)); - if (filename != NULL) - save_to_xml_file(filename); -} - -void file_new() { - GtkTextIter start, end; - gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(source_buffer), &start, &end); - gtk_text_buffer_delete(GTK_TEXT_BUFFER(source_buffer), &start, &end); - gchar *temp; - if (g_file_get_contents(FILE_TEMPLATE, &temp, NULL, NULL)) - gtk_text_buffer_set_text(GTK_TEXT_BUFFER(source_buffer), temp, -1); - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(xml_file_chooser_button), ""); - gtk_widget_set_sensitive(reload_menu_item, FALSE); - - free_current_info(); -} - -void set_up_interface() { - - GtkBuilder *builder = gtk_builder_new(); - gtk_builder_add_from_file(builder, "interface.ui", NULL); - gtk_builder_connect_signals(builder, NULL); - - //Setup main window - win = GTK_WIDGET(gtk_builder_get_object(builder, "win_main")); - - //Setup GtkSourceView - GtkSourceLanguageManager *langman = gtk_source_language_manager_get_default(); - source_buffer = gtk_source_buffer_new_with_language(gtk_source_language_manager_get_language(langman, "xml")); - - source_view = GTK_WIDGET(gtk_builder_get_object(builder, "source_view")); - gtk_text_view_set_buffer(GTK_TEXT_VIEW(source_view), GTK_TEXT_BUFFER(source_buffer)); - search_init(source_view); - - //Setup GtkScrolledWindow - GtkWidget *scrolled_window = NULL; - scrolled_window = GTK_WIDGET(gtk_builder_get_object(builder, "scrolledwindow1")); - gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolled_window), - gtk_text_view_get_hadjustment(GTK_TEXT_VIEW(source_view))); - gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolled_window), - gtk_text_view_get_vadjustment(GTK_TEXT_VIEW(source_view))); - - //Setup GtkDrawingArea - darea = GTK_WIDGET(gtk_builder_get_object(builder, "darea1")); - - //Setup GtkToolbar - toolbar = GTK_WIDGET(gtk_builder_get_object(builder, "toolbar")); - - reload_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "menuitem6")); - show_grid_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "menuitem11")); - imageset_preview_menu_item = GTK_WIDGET(gtk_builder_get_object(builder, "menuitem12")); - - data_folder_chooser_button = GTK_WIDGET(gtk_builder_get_object(builder, "datafcbutton")); - xml_file_chooser_button = GTK_WIDGET(gtk_builder_get_object(builder, "xmlfcbutton")); - xml_file_open_button = GTK_WIDGET(gtk_builder_get_object(builder, "xmlfobutton")); - xml_file_save_button = GTK_WIDGET(gtk_builder_get_object(builder, "xmlfsbutton")); - - gen_sae_info->imagesets_combo_box = GTK_WIDGET(gtk_builder_get_object(builder, "imagesetscbox")); - gen_sae_info->actions_combo_box = GTK_WIDGET(gtk_builder_get_object(builder, "actionscbox")); - gen_sae_info->animations_combo_box = GTK_WIDGET(gtk_builder_get_object(builder, "animationscbox")); - - //Setup GtkAboutDialog - about_dialog = GTK_WIDGET(gtk_builder_get_object(builder, "about_dialog")); - - //Setup GtkMessageDialog - parsing_error_dialog = GTK_WIDGET(gtk_builder_get_object(builder, "parsing-error-dialog")); - - //Setup Find dialog - find_dialog = GTK_WIDGET(gtk_builder_get_object(builder, "find_dialog")); - gtk_widget_hide(find_dialog); - - file_new(); - - gtk_widget_show_all(win); - gtk_widget_show_all(source_view); - - g_object_unref(builder); -} diff --git a/saedit/interface.ui b/saedit/interface.ui deleted file mode 100644 index dc83601..0000000 --- a/saedit/interface.ui +++ /dev/null @@ -1,852 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.18.3 --> -<interface> - <requires lib="gtk+" version="3.2"/> - <requires lib="gtksourceview" version="0.0"/> - <object class="GtkAccelGroup" id="accelgroup"/> - <object class="GtkFileChooserDialog" id="fcdialog1"> - <property name="can_focus">False</property> - <property name="border_width">5</property> - <property name="title" translatable="yes">Open file</property> - <property name="type_hint">dialog</property> - <child internal-child="vbox"> - <object class="GtkBox" id="dialog-vbox1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">2</property> - <child internal-child="action_area"> - <object class="GtkButtonBox" id="dialog-action_area1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="button1"> - <property name="label">gtk-open</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button2"> - <property name="label">gtk-cancel</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <placeholder/> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-3">button1</action-widget> - <action-widget response="0">button2</action-widget> - </action-widgets> - </object> - <object class="GtkWindow" id="win_main"> - <property name="width_request">600</property> - <property name="height_request">600</property> - <property name="can_focus">False</property> - <property name="title" translatable="yes">Sprite Animation Editor</property> - <property name="window_position">center</property> - <property name="default_width">600</property> - <property name="default_height">600</property> - <property name="icon">icon.svg</property> - <signal name="destroy" handler="save_config_and_quit" swapped="no"/> - <child> - <object class="GtkVBox" id="vbox1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkMenuBar" id="menubar1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkMenuItem" id="menuitem1"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_File</property> - <property name="use_underline">True</property> - <child type="submenu"> - <object class="GtkMenu" id="menu1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="accel_group">accelgroup</property> - <child> - <object class="GtkMenuItem" id="menuitem4"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_New</property> - <property name="use_underline">True</property> - <signal name="activate" handler="file_new" swapped="no"/> - <accelerator key="n" signal="activate" modifiers="GDK_CONTROL_MASK"/> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem5"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_Open...</property> - <property name="use_underline">True</property> - <signal name="activate" handler="open_menu_item_activate_callback" object="fcdialog1" swapped="no"/> - <accelerator key="o" signal="activate" modifiers="GDK_CONTROL_MASK"/> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem6"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_Reload</property> - <property name="use_underline">True</property> - <signal name="activate" handler="open_xml_file" swapped="no"/> - <accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/> - </object> - </child> - <child> - <object class="GtkSeparatorMenuItem" id="menuitem15"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem7"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_Save</property> - <property name="use_underline">True</property> - <signal name="activate" handler="save_menu_item_activate_callback" swapped="no"/> - <accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem8"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Save _as...</property> - <property name="use_underline">True</property> - <signal name="activate" handler="save_dialog_show" swapped="no"/> - <accelerator key="s" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/> - </object> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem2"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_Search</property> - <property name="use_underline">True</property> - <child type="submenu"> - <object class="GtkMenu" id="menu2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkMenuItem" id="menuitem9"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_Find...</property> - <property name="use_underline">True</property> - <signal name="activate" handler="find_menu_item_activate_callback" swapped="no"/> - <accelerator key="f" signal="activate" modifiers="GDK_CONTROL_MASK"/> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem10"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Find _Next</property> - <property name="use_underline">True</property> - <signal name="activate" handler="search_find_next" swapped="no"/> - <accelerator key="f" signal="activate" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/> - </object> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem3"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_View</property> - <property name="use_underline">True</property> - <child type="submenu"> - <object class="GtkMenu" id="menu3"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkCheckMenuItem" id="menuitem11"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Show _Grid</property> - <property name="use_underline">True</property> - <signal name="toggled" handler="show_grid_menu_item_toggled_callback" swapped="no"/> - <accelerator key="g" signal="activate" modifiers="GDK_CONTROL_MASK"/> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem12"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_Imageset view</property> - <property name="use_underline">True</property> - <signal name="activate" handler="show_imageset_dialog" swapped="no"/> - <accelerator key="i" signal="activate" modifiers="GDK_CONTROL_MASK"/> - </object> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkMenuItem" id="menuitem13"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_Help</property> - <property name="use_underline">True</property> - <child type="submenu"> - <object class="GtkMenu" id="menu4"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkMenuItem" id="menuitem14"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">_About</property> - <property name="use_underline">True</property> - <signal name="activate" handler="show_about_dialog" swapped="no"/> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkHBox" id="hbox1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkVBox" id="vbox4"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkLabel" id="label2"> - <property name="height_request">24</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Clientdata folder</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkFileChooserButton" id="datafcbutton"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="action">select-folder</property> - <property name="title" translatable="yes">Clientdata folder</property> - <signal name="selection-changed" handler="data_folder_set_callback" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label1"> - <property name="height_request">24</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">XML source file</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkFileChooserButton" id="xmlfcbutton"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="local_only">False</property> - <property name="dialog">fcdialog1</property> - <property name="title" translatable="yes">Select XML file</property> - <signal name="file-set" handler="open_xml_file" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkButton" id="xmlfobutton"> - <property name="label">gtk-open</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - <signal name="clicked" handler="open_xml_file" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">4</property> - </packing> - </child> - <child> - <object class="GtkButton" id="xmlfsbutton"> - <property name="label">gtk-save</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - <signal name="clicked" handler="xml_file_save_button_callback" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">5</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button3"> - <property name="label" translatable="yes">Parse XML Buffer</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="parse_xml_buffer" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">6</property> - </packing> - </child> - <child> - <object class="GtkSeparator" id="separator1"> - <property name="height_request">30</property> - <property name="can_focus">False</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">7</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label3"> - <property name="height_request">24</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Imagesets</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">8</property> - </packing> - </child> - <child> - <object class="GtkComboBoxText" id="imagesetscbox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="active">0</property> - <signal name="changed" handler="imagesets_combo_box_changed_callback" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">9</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label4"> - <property name="height_request">24</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Actions</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">10</property> - </packing> - </child> - <child> - <object class="GtkComboBoxText" id="actionscbox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="active">0</property> - <signal name="changed" handler="actions_combo_box_changed_callback" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">11</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label5"> - <property name="height_request">24</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Directions</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">12</property> - </packing> - </child> - <child> - <object class="GtkComboBoxText" id="animationscbox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="active">0</property> - <signal name="changed" handler="animations_combo_box_changed_callback" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">13</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSeparator" id="separator2"> - <property name="width_request">1</property> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkVPaned" id="vpaned1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <object class="GtkVBox" id="vbox2"> - <property name="can_focus">False</property> - <child> - <object class="GtkDrawingArea" id="darea1"> - <property name="height_request">120</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <signal name="draw" handler="darea_draw_event" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkToolbar" id="toolbar"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">False</property> - <child> - <object class="GtkToolButton" id="toolbar-to-first"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">First frame</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-goto-first</property> - <signal name="clicked" handler="toolbar_to_first_clicked_callback" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="toolbar-prev-frame"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Previous frame</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-go-back</property> - <signal name="clicked" handler="toolbar_prev_frame_clicked_callback" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="toolbar-play"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Continue sequencing</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-media-play</property> - <signal name="clicked" handler="toolbar_play_clicked_callback" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="toolbar-pause"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Pause sequencing</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-media-pause</property> - <signal name="clicked" handler="toolbar_pause_clicked_callback" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="toolbar-next-frame"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Next frame</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-go-forward</property> - <signal name="clicked" handler="toolbar_next_frame_clicked_callback" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="toolbar-to-last"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Last frame</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-goto-last</property> - <signal name="clicked" handler="toolbar_to_last_clicked_callback" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="homogeneous">True</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="resize">False</property> - <property name="shrink">True</property> - </packing> - </child> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <object class="GtkSourceView" id="source_view"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="left_margin">2</property> - <property name="right_margin">2</property> - <property name="show_line_numbers">True</property> - <property name="tab_width">4</property> - <property name="auto_indent">True</property> - <property name="highlight_current_line">True</property> - <property name="indent_on_tab">False</property> - </object> - </child> - </object> - <packing> - <property name="resize">True</property> - <property name="shrink">True</property> - </packing> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - <object class="GtkAboutDialog" id="about_dialog"> - <property name="can_focus">False</property> - <property name="border_width">5</property> - <property name="window_position">center</property> - <property name="icon">icon.svg</property> - <property name="type_hint">dialog</property> - <property name="transient_for">win_main</property> - <property name="program_name">Sprite Animation Editor</property> - <property name="version">⍺0.1.1</property> - <property name="copyright" translatable="yes">Copyleft ↄ Vasily_Makarov 2011-2015</property> - <property name="comments" translatable="yes">A simple tool to edit eAthena-based XML animation files</property> - <property name="authors">Vasily_Makarov <danilka.pro@gmail.com> -Reid Yaro <reidyaro@gmail.com></property> - <property name="logo">icon.svg</property> - <property name="license_type">gpl-2-0</property> - <child internal-child="vbox"> - <object class="GtkBox" id="dialog-vbox3"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">2</property> - <child internal-child="action_area"> - <object class="GtkButtonBox" id="dialog-action_area3"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <placeholder/> - </child> - </object> - </child> - </object> - <object class="GtkDialog" id="find_dialog"> - <property name="width_request">240</property> - <property name="height_request">80</property> - <property name="can_focus">False</property> - <property name="border_width">5</property> - <property name="title" translatable="yes">Find</property> - <property name="resizable">False</property> - <property name="type_hint">normal</property> - <property name="skip_taskbar_hint">True</property> - <property name="skip_pager_hint">True</property> - <property name="transient_for">win_main</property> - <signal name="response" handler="search_find_dialog_response_callback" object="find_dialog_entry" swapped="no"/> - <child internal-child="vbox"> - <object class="GtkBox" id="dialog-vbox4"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">2</property> - <child internal-child="action_area"> - <object class="GtkButtonBox" id="dialog-action_area4"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="button4"> - <property name="label">gtk-find</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="button5"> - <property name="label">gtk-cancel</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="find_dialog_entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">•</property> - <property name="primary_icon_activatable">False</property> - <property name="secondary_icon_activatable">False</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child> - <placeholder/> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-3">button4</action-widget> - <action-widget response="-6">button5</action-widget> - </action-widgets> - </object> - <object class="GtkListStore" id="liststore1"> - <columns> - <!-- column-name text --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkListStore" id="liststore2"> - <columns> - <!-- column-name text --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkListStore" id="liststore3"> - <columns> - <!-- column-name text --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkMessageDialog" id="parsing-error-dialog"> - <property name="can_focus">False</property> - <property name="border_width">5</property> - <property name="title" translatable="yes">Parsing error</property> - <property name="type_hint">dialog</property> - <property name="skip_taskbar_hint">True</property> - <property name="skip_pager_hint">True</property> - <property name="message_type">error</property> - <property name="buttons">close</property> - <property name="text" translatable="yes"><b>Bad source buffer!</b></property> - <property name="use_markup">True</property> - <signal name="response" handler="gtk_widget_hide" swapped="no"/> - <child internal-child="vbox"> - <object class="GtkBox" id="messagedialog-vbox"> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <property name="spacing">14</property> - <child internal-child="action_area"> - <object class="GtkButtonBox" id="messagedialog-action_area"> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - </object> - </child> - </object> -</interface> diff --git a/saedit/icon.svg b/saedit/logo.svg index 6a3bf35..a68864a 100644 --- a/saedit/icon.svg +++ b/saedit/logo.svg @@ -14,8 +14,8 @@ height="256" id="svg2" version="1.1" - inkscape:version="0.48.2 r9819" - sodipodi:docname="icon.svg"> + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="logo.svg"> <defs id="defs4"> <linearGradient @@ -585,16 +585,16 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1" - inkscape:cx="-79.999984" - inkscape:cy="276.83172" + inkscape:zoom="1.4142136" + inkscape:cx="33.799066" + inkscape:cy="114.6248" inkscape:document-units="px" - inkscape:current-layer="layer1" + inkscape:current-layer="g3107" showgrid="false" - inkscape:window-width="1680" - inkscape:window-height="1001" + inkscape:window-width="1366" + inkscape:window-height="704" inkscape:window-x="0" - inkscape:window-y="20" + inkscape:window-y="27" inkscape:window-maximized="1" /> <metadata id="metadata7"> @@ -604,6 +604,7 @@ <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> </cc:Work> </rdf:RDF> </metadata> @@ -627,17 +628,19 @@ <path inkscape:connector-curvature="0" id="path3105" - style="fill:#800000;font-family:Sans;-inkscape-font-specification:Sans" - d="m 110.87616,841.71545 0,3.39844 c -1.01564,-0.52081 -2.07033,-0.91144 -3.16406,-1.17187 -1.09377,-0.2604 -2.22658,-0.39061 -3.39844,-0.39063 -1.78386,2e-5 -3.12501,0.27346 -4.02344,0.82031 -0.885421,0.5469 -1.328129,1.36721 -1.328123,2.46094 -6e-6,0.83335 0.319004,1.4909 0.957031,1.97266 0.638012,0.46876 1.920562,0.91798 3.847652,1.34765 l 1.23047,0.27344 c 2.55207,0.54689 4.36197,1.32163 5.42969,2.32422 1.08071,0.98959 1.62108,2.37631 1.62109,4.16016 -1e-5,2.03125 -0.80731,3.63932 -2.42187,4.82422 -1.60158,1.18489 -3.80861,1.77734 -6.62109,1.77734 -1.17189,0 -2.39584,-0.11719 -3.671879,-0.35156 -1.263026,-0.22136 -2.59766,-0.5599 -4.003906,-1.01563 l 0,-3.71094 c 1.328121,0.69011 2.636714,1.21094 3.925781,1.5625 1.289054,0.33855 2.565094,0.50782 3.828124,0.50782 1.6927,0 2.99478,-0.28646 3.90625,-0.85938 0.91144,-0.58593 1.36717,-1.40624 1.36719,-2.46094 -2e-5,-0.97655 -0.33205,-1.72525 -0.9961,-2.24609 -0.65105,-0.52082 -2.08985,-1.02213 -4.3164,-1.50391 l -1.25,-0.29296 c -2.22657,-0.46874 -3.834642,-1.18489 -4.82422,-2.14844 -0.989586,-0.97655 -1.484378,-2.31119 -1.484375,-4.00391 -3e-6,-2.05727 0.729163,-3.64581 2.1875,-4.76562 1.458327,-1.11977 3.528635,-1.67967 6.210935,-1.67969 1.32812,2e-5 2.57811,0.0977 3.75,0.29297 1.17186,0.19533 2.25259,0.4883 3.24219,0.8789" /> + style="font-family:Sans;-inkscape-font-specification:Sans;fill:#800000" + d="m 110.87616,841.71545 v 3.39844 c -1.01564,-0.52081 -2.07033,-0.91144 -3.16406,-1.17187 -1.09377,-0.2604 -2.22658,-0.39061 -3.39844,-0.39063 -1.78386,2e-5 -3.12501,0.27346 -4.02344,0.82031 -0.885421,0.5469 -1.328129,1.36721 -1.328123,2.46094 -6e-6,0.83335 0.319004,1.4909 0.957031,1.97266 0.638012,0.46876 1.920562,0.91798 3.847652,1.34765 l 1.23047,0.27344 c 2.55207,0.54689 4.36197,1.32163 5.42969,2.32422 1.08071,0.98959 1.62108,2.37631 1.62109,4.16016 -1e-5,2.03125 -0.80731,3.63932 -2.42187,4.82422 -1.60158,1.18489 -3.80861,1.77734 -6.62109,1.77734 -1.17189,0 -2.39584,-0.11719 -3.671879,-0.35156 -1.263026,-0.22136 -2.59766,-0.5599 -4.003906,-1.01563 l -1.611767,-1.9132 c 1.328121,0.69011 1.846328,-1.14472 5.537548,-0.23524 1.289054,0.33855 2.565094,0.50782 3.828124,0.50782 1.6927,0 2.99478,-0.28646 3.90625,-0.85938 0.91144,-0.58593 1.36717,-1.40624 1.36719,-2.46094 -2e-5,-0.97655 -0.33205,-1.72525 -0.9961,-2.24609 -0.65105,-0.52082 -2.08985,-1.02213 -4.3164,-1.50391 l -1.25,-0.29296 c -2.22657,-0.46874 -3.834642,-1.18489 -4.82422,-2.14844 -0.989586,-0.97655 -1.484378,-2.31119 -1.484375,-4.00391 -3e-6,-2.05727 0.729163,-3.64581 2.1875,-4.76562 1.458327,-1.11977 3.528635,-1.67967 6.210935,-1.67969 1.32812,2e-5 2.57811,0.0977 3.75,0.29297 1.17186,0.19533 2.25259,0.4883 3.24219,0.8789" + sodipodi:nodetypes="ccccccccccccsccccsccccccccccc" /> </g> <g id="text3090" - style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#800000;fill-opacity:1;stroke:none;font-family:Cantarell;-inkscape-font-specification:Sans"> + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:125%;font-family:Cantarell;-inkscape-font-specification:Sans;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;fill:#800000;fill-opacity:1;stroke:none"> <path id="path3102" - style="fill:#800000;font-family:Sans;-inkscape-font-specification:Sans" - d="m 97.149544,871.06958 c -2.903657,10e-6 -4.915374,0.33204 -6.035156,0.99609 -1.119799,0.66408 -1.679694,1.79689 -1.679688,3.39844 -6e-6,1.27605 0.41666,2.29167 1.25,3.04688 0.846346,0.74219 1.992178,1.11328 3.4375,1.11328 1.992175,0 3.587225,-0.70312 4.785156,-2.10938 1.210924,-1.41926 1.816394,-3.30077 1.816404,-5.64453 l 0,-0.80078 -3.574216,0 m 7.167966,-1.48437 0,12.48046 -3.59375,0 0,-3.32031 c -0.820326,1.32813 -1.842461,2.3112 -3.066404,2.94922 -1.223971,0.625 -2.721365,0.9375 -4.492187,0.9375 -2.239591,0 -4.023443,-0.625 -5.351563,-1.875 -1.315107,-1.26302 -1.972658,-2.94921 -1.972656,-5.05859 -2e-6,-2.46093 0.820309,-4.3164 2.460938,-5.56641 1.653639,-1.24999 4.114574,-1.87499 7.382812,-1.875 l 5.03906,0 0,-0.35156 c -1e-5,-1.65363 -0.54689,-2.92967 -1.640622,-3.82813 -1.080744,-0.91144 -2.60418,-1.36717 -4.570313,-1.36718 -1.25001,1e-5 -2.467457,0.14975 -3.652344,0.44921 -1.184902,0.2995 -2.324224,0.74872 -3.417968,1.34766 l 0,-3.32031 c 1.315098,-0.50779 2.591139,-0.8854 3.828125,-1.13281 1.23697,-0.2604 2.441395,-0.39061 3.613281,-0.39063 3.164048,2e-5 5.527331,0.82033 7.089841,2.46094 1.56248,1.64064 2.34373,4.12762 2.34375,7.46094" - inkscape:connector-curvature="0" /> + style="font-family:Sans;-inkscape-font-specification:Sans;fill:#800000" + d="m 97.149544,871.06958 c -2.903657,10e-6 -4.915374,0.33204 -6.035156,0.99609 -1.119799,0.66408 -1.679694,1.79689 -1.679688,3.39844 -6e-6,1.27605 0.41666,2.29167 1.25,3.04688 0.846346,0.74219 1.992178,1.11328 3.4375,1.11328 1.992175,0 3.587225,-0.70312 4.785156,-2.10938 1.210924,-1.41926 1.816394,-3.30077 1.816404,-5.64453 v -0.80078 h -3.574216 m 7.167966,-1.48437 v 12.48046 h -3.59375 v -3.32031 c -0.820326,1.32813 -1.842461,2.3112 -3.066404,2.94922 -1.223971,0.625 -2.721365,0.9375 -4.492187,0.9375 -2.239591,0 -4.023443,-0.625 -5.351563,-1.875 -1.315107,-1.26302 -1.972658,-2.94921 -1.972656,-5.05859 -2e-6,-2.46093 0.820309,-4.3164 2.460938,-5.56641 1.653639,-1.24999 4.114574,-1.87499 7.382812,-1.875 h 5.03906 v -0.35156 c -1e-5,-1.65363 -0.54689,-2.92967 -1.640622,-3.82813 -1.080744,-0.91144 -2.60418,-1.36717 -4.570313,-1.36718 -1.25001,1e-5 -2.467457,0.14975 -3.652344,0.44921 -1.184902,0.2995 -2.324224,0.74872 -3.417968,1.34766 v -3.32031 c 1.315098,-0.50779 2.591139,-0.8854 3.828125,-1.13281 1.23697,-0.2604 2.441395,-0.39061 3.613281,-0.39063 3.180647,-0.20787 5.527331,0.82033 7.089841,2.46094 1.56248,1.64064 2.34373,4.12762 2.34375,7.46094" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccscccccccccsccccccccccccccc" /> </g> <g id="text3094" diff --git a/saedit/main.c b/saedit/main.c index d6c147a..103e0c4 100644 --- a/saedit/main.c +++ b/saedit/main.c @@ -1,609 +1,235 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ +#include <gtksourceview/gtksource.h> +#include "xml.h" +#include "config.h" +#include "spritedrawingarea.h" +#include "action.h" +#include "errors.h" +#include "file.h" +#include "buffer.h" +#include "xmlsetup.h" +#include "drawfuncs.h" #include "main.h" -#include "interface.c" - -//Cairo functions - -cairo_surface_t *get_grid_surface(int w, int h) { - cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (w + 2) * GRID_SIZE, (h + 2) * GRID_SIZE); - cairo_t *cr = cairo_create(surface); - int x, y; - - for (x = 0; x < w; x++) - for (y = 0; y < h; y++) { - gdk_cairo_set_source_pixbuf(cr, gen_sae_info->ground, x * GRID_SIZE, y * GRID_SIZE); - cairo_paint(cr); - } - - if (config->show_grid) { - cairo_surface_t *gridsurf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * GRID_SIZE + 1, h * GRID_SIZE + 1); - cairo_t *scr = cairo_create(gridsurf); - cairo_set_line_width(scr, 1); - cairo_set_source_rgba(scr, 0.5, 0.5, 0.5, 1); - for (x = 0; x < w; x++) - for (y = 0; y < h; y++) { - cairo_rectangle(scr, x*GRID_SIZE+0.5, y*GRID_SIZE+0.5, GRID_SIZE, GRID_SIZE); - cairo_stroke(scr); - } - cairo_set_source_surface(cr, gridsurf, GRID_SIZE, GRID_SIZE); - cairo_paint(cr); - cairo_destroy(scr); - cairo_surface_destroy(gridsurf); +#include <string.h> + +void +intr_updated (Interactor *interactor) { + gtk_widget_queue_draw (d_area); + + gtk_tool_button_set_icon_name ( + GTK_TOOL_BUTTON (tbtn_play), + interactor_loop_running (interactor) ? + "media-playback-pause" : + "media-playback-start" + ); + + if (interactor != NULL) { + gboolean result; + gint hp; + gchar *id, *name; + + buffer_mark_line ( + interactor_get_line_no (interactor) - 1 + ); + + result = interactor_get_action_hp_and_name ( + interactor, + &hp, &name + ); + + if (!result) + return; + + id = get_action_id (hp, name); + gtk_combo_box_set_active_id (cb_actions, id); + g_free (id); + + gtk_combo_box_set_active_id ( + GTK_COMBO_BOX (cb_directions), + interactor_get_animation_direction (interactor) + ); + } else + buffer_mark_line (-1); +} + +void +release_context () { + xml_setup_clear (); + + if (interactor != NULL) { + interactor_free (interactor); + interactor = NULL; + intr_updated (interactor); } - cairo_destroy(cr); - return surface; -} - -gboolean darea_draw_event(GtkWidget *widget, cairo_t *cr, SAEInfo *sae_info) { - - if (sae_info == NULL) - sae_info = gen_sae_info; - - int width = gtk_widget_get_allocated_width(widget), - height = gtk_widget_get_allocated_height(widget); + gtk_combo_box_text_remove_all (cb_directions); + gtk_list_store_clear (store_actions); - int w = 3, h = 3; - - //cairo_t *cr = gdk_cairo_create(gtk_widget_get_parent_window(widget)); - - cairo_surface_t *surface = get_grid_surface(w, h); - cairo_set_source_surface(cr, surface, width/2 - GRID_SIZE * (w + 2) * 0.5, height/2 - GRID_SIZE * (h + 2) * 0.5); - cairo_paint(cr); - - if (player != NULL) { - GdkPixbuf *pbuf = player->sprite->pixbuf; - if (pbuf == NULL) return FALSE; - gdk_cairo_set_source_pixbuf(cr, pbuf, - width/2 - player->imageset->width/2 + player->offsetX + player->sprite->offsetX + player->imageset->offsetX, - height/2 + GRID_SIZE/2 - player->imageset->height + player->offsetY + player->sprite->offsetY + player->imageset->offsetY); - cairo_paint(cr); + if (context != NULL) { + sprite_context_free (context); + context = NULL; } - - GdkPixbuf *pbuf = sae_info->sprite->pixbuf; - if (pbuf == NULL) return FALSE; - gdk_cairo_set_source_pixbuf(cr, pbuf, - width/2 - sae_info->imageset->width/2 + sae_info->offsetX + sae_info->sprite->offsetX + sae_info->imageset->offsetX, - height/2 +GRID_SIZE/2 - sae_info->imageset->height + sae_info->offsetY + sae_info->sprite->offsetY + sae_info->imageset->offsetY); - cairo_paint(cr); - - cairo_surface_destroy(surface); - return FALSE; -} - -//Common functions - -gchar *markup_bold(gchar *str) { - return g_strconcat("<b>", str, "</b>", NULL); -} - -void format_src_string(gchar *src) { - gchar *str = g_strrstr(src, "|"); - if (str == NULL) return; - strncpy(str, "\0", 1); -} - -GtkTextIter *gtk_source_buffer_highlight_line(GtkSourceBuffer *buffer, int line_number) { - GtkTextIter start; - gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(buffer), &start); - gtk_text_iter_set_line(&start, line_number); - gtk_text_buffer_place_cursor(GTK_TEXT_BUFFER(buffer), &start); - return gtk_text_iter_copy(&start); } -//File working - -void open_xml_file(GtkButton *button) { - gtk_widget_set_sensitive(xml_file_open_button, TRUE); - gtk_widget_set_sensitive(reload_menu_item, TRUE); - gchar *buf; - size_t len; - g_file_get_contents(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(xml_file_chooser_button)), &buf, &len, NULL); - if (g_utf8_validate(buf, len, NULL)) { - gtk_text_buffer_set_text(GTK_TEXT_BUFFER(source_buffer), buf, len); - gtk_widget_set_sensitive(xml_file_save_button, TRUE); +void +update_window_title () { + gchar *title, *data_folder, *file_name; + const gchar *opened_file_name; + + gboolean modified = buffer_get_modified (); + data_folder = config_keys_get_data_folder_path (); + opened_file_name = get_opened_file_name (); + + if ( + opened_file_name != NULL && + g_str_has_prefix (opened_file_name, data_folder) + ) { + file_name = g_strconcat ( + "<Data Folder>", + opened_file_name + strlen (data_folder), + NULL + ); } else { - gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(xml_file_chooser_button)); - } - - free_current_info(); -} - -void save_to_xml_file(gchar *filename) { - GtkTextIter start, end; - gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(source_buffer), &start); - gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(source_buffer), &end); - g_file_set_contents(filename, gtk_text_buffer_get_text(GTK_TEXT_BUFFER(source_buffer), &start, &end, TRUE), -1, NULL); -} - -//SAEInfo functions (must be ported to sae.c) - -void free_imagesets(SAEInfo *sae_info) { - free_imageset(sae_info); - sae_info->imagesets = NULL; - gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(sae_info->imagesets_combo_box)))); -} - -void free_imageset(SAEInfo *sae_info) { - sae_info->imageset = imageset_new(); - sae_info->ground = sae_info_ground_new(); - gtk_widget_set_sensitive(imageset_preview_menu_item, FALSE); - gtk_widget_set_sensitive(toolbar, FALSE); -} - -void free_actions(SAEInfo *sae_info) { - sae_info->actions = NULL; - if (sae_info->actions_combo_box != NULL) - gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(sae_info->actions_combo_box)))); -} - -void free_animations(SAEInfo *sae_info) { - sae_info->animations = NULL; - - if (sae_info->animations_combo_box != NULL) - gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(sae_info->animations_combo_box)))); - - kill_timeout(sae_info->anim_tag); - sae_info->anim_tag = 0; - sae_info->sprite = frame_new(-1, 0, 0, 0); - set_sprite_by_index(0, sae_info); -} - -void free_lists(SAEInfo *sae_info) { - free_imagesets(sae_info); - free_actions(sae_info); - free_animations(sae_info); -} - -void free_current_info() { - free_lists(gen_sae_info); - player = NULL; -} - -//Callbacks - -void data_folder_set_callback(GtkFileChooserButton *widget, gpointer data) { - config->clientdata_folder = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data_folder_chooser_button)); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(xml_file_chooser_button), gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget))); -} - -void show_grid_menu_item_toggled_callback(GtkCheckMenuItem *checkmenuitem, gpointer user_data) { - config->show_grid = gtk_check_menu_item_get_active(checkmenuitem); - gtk_widget_queue_draw(darea); -} - -void parsing_error_warning(SAEInfo *sae_info, const gchar *message) { - free_lists(sae_info); - gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(parsing_error_dialog), "%s", message); - gtk_dialog_run(GTK_DIALOG(parsing_error_dialog)); -} - -void actions_combo_box_changed_callback(GtkComboBoxText *widget, gpointer user_data) { - if (player != NULL) - set_up_action_by_name(gtk_combo_box_text_get_active_text(widget), player); - set_up_action_by_name(gtk_combo_box_text_get_active_text(widget), gen_sae_info); -} - -void animations_combo_box_changed_callback(GtkComboBoxText *widget, gpointer user_data) { - set_up_animation_by_direction(gen_sae_info, gtk_combo_box_text_get_active_text(widget)); - if (player != NULL) { - set_up_animation_by_direction(player, gtk_combo_box_text_get_active_text(widget)); - show_animation(player); - } - show_animation(gen_sae_info); -} - -void imagesets_combo_box_changed_callback(GtkComboBoxText *widget, gpointer user_data) { - if (gtk_combo_box_text_get_active_text(widget) != NULL) - set_up_imageset_by_name(gtk_combo_box_text_get_active_text(widget), gen_sae_info); -} - -gboolean frame_image_button_press_event_callback(GtkWidget *widget, GdkEventButton *button, int idx) { - gchar buf[10]; - gint len = g_sprintf(buf, "%d", idx); - gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(source_buffer), buf, len); - return FALSE; -} - -void open_menu_item_activate_callback(GtkMenuItem *menuitem, GtkFileChooserDialog *fcdialog) { - gtk_dialog_run(GTK_DIALOG(fcdialog)); -} - -//>Toolbar callbacks -void toolbar_to_first_clicked_callback(GtkToolButton *toolbutton, gpointer user_data) { - toolbar_pause_clicked_callback(toolbutton, user_data); - gen_sae_info->animation = g_list_first(gen_sae_info->animation); - show_sprite(gen_sae_info); -} - -void toolbar_prev_frame_clicked_callback(GtkToolButton *toolbutton, gpointer user_data) { - toolbar_pause_clicked_callback(toolbutton, user_data); - GList *prev = g_list_previous(gen_sae_info->animation); - if (prev == NULL) - return; - gen_sae_info->animation = prev; - show_sprite(gen_sae_info); -} - -void toolbar_play_clicked_callback(GtkToolButton *toolbutton, gpointer user_data) { - show_animation(gen_sae_info); -} - -void toolbar_pause_clicked_callback(GtkToolButton *toolbutton, gpointer user_data) { - int tag = gen_sae_info->anim_tag; - if (tag > 0) { - kill_timeout(tag); - GList *prev = g_list_previous(gen_sae_info->animation); - if (prev == NULL) - prev = g_list_last(gen_sae_info->animation); - gen_sae_info->animation = prev; - } - gen_sae_info->anim_tag = 0; -} - -void toolbar_next_frame_clicked_callback(GtkToolButton *toolbutton, gpointer user_data) { - toolbar_pause_clicked_callback(toolbutton, user_data); - GList *next = g_list_next(gen_sae_info->animation); - if (next == NULL) - return; - gen_sae_info->animation = next; - show_sprite(gen_sae_info); -} - -void toolbar_to_last_clicked_callback(GtkToolButton *toolbutton, gpointer user_data) { - toolbar_pause_clicked_callback(toolbutton, user_data); - gen_sae_info->animation = g_list_last(gen_sae_info->animation); - show_sprite(gen_sae_info); -} - -//Dialogs - -void show_about_dialog() { - gtk_dialog_run(GTK_DIALOG(about_dialog)); - gtk_widget_hide(about_dialog); -} - -void show_imageset_dialog() { - if (gen_sae_info->imageset->spriteset == NULL) return; - GtkWidget *dialog = gtk_dialog_new(); - GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - gtk_window_set_title(GTK_WINDOW(dialog), _("Imageset preview")); - gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(win)); - - int w = gen_sae_info->imageset->spriteset_width / gen_sae_info->imageset->width; - int h = gen_sae_info->imageset->spriteset_height / gen_sae_info->imageset->height; - - GtkWidget *hbox = NULL; - GtkWidget *image = NULL; - GtkWidget *event_box = NULL; - - int x, y; - for (y = 0; y < h; y++) { - hbox = gtk_hbox_new(TRUE, 2); - gtk_box_pack_start(GTK_BOX(content_area), hbox, TRUE, TRUE, 2); - for (x = 0; x < w; x++) { - unsigned long int id = w * y + x; - event_box = gtk_event_box_new(); - g_signal_connect(G_OBJECT(event_box), "button-press-event", G_CALLBACK(frame_image_button_press_event_callback), (gpointer)id); - gtk_box_pack_start(GTK_BOX(hbox), event_box, TRUE, TRUE, 0); - - image = gtk_image_new_from_pixbuf(get_sprite_by_index(w * y + x, gen_sae_info)); - gtk_widget_add_events(image, GDK_BUTTON_PRESS_MASK); - gtk_container_add(GTK_CONTAINER(event_box), image); - } - } - gtk_widget_show_all(dialog); -} - -//Main functions - -void set_sprite_by_index(size_t idx, SAEInfo *sae_info) { - sae_info->sprite->pixbuf = get_sprite_by_index(idx, sae_info); - gtk_widget_queue_draw(darea); -} - -void set_up_actions_by_imageset_name(gchar *imageset_name, SAEInfo *sae_info) { - free_actions(sae_info); - free_animations(sae_info); - GList *_actions_list = NULL; - GList *list = sae_info->root->sub_nodes; - XMLNode *node = NULL; - while (TRUE) { - list = g_list_find_custom(list, imageset_name, xml_node_compare_with_action_node_by_imageset_name_func); - if (list == NULL) - break; - if (_actions_list == NULL) { - _actions_list = g_list_alloc(); - sae_info->actions = _actions_list; - _actions_list->data = list->data; - } else - _actions_list = g_list_append(_actions_list, list->data); - node = list->data; - if (sae_info->actions_combo_box != NULL) - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sae_info->actions_combo_box), xml_node_get_attr_value(node, "name")); - list = g_list_next(list); - } - if (sae_info->actions_combo_box != NULL) - gtk_combo_box_set_active(GTK_COMBO_BOX(sae_info->actions_combo_box), 0); -} - -gboolean set_up_imagesets(SAEInfo *sae_info) { - GList *_imagesets_list = NULL; - free_lists(sae_info); - GList *list = sae_info->root->sub_nodes; - XMLNode *node = NULL; - while (TRUE) { - list = g_list_find_custom(list, "imageset", xml_node_compare_with_name_func); - if (list == NULL) - break; - if (_imagesets_list == NULL) { - _imagesets_list = g_list_alloc(); - _imagesets_list->data = list->data; - sae_info->imagesets = _imagesets_list; - } else - _imagesets_list = g_list_append(_imagesets_list, list->data); - node = list->data; - if (sae_info->imagesets_combo_box != NULL) - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sae_info->imagesets_combo_box), xml_node_get_attr_value(node, "name")); - list = g_list_next(list); - } - if (_imagesets_list == NULL) - return FALSE; - if (sae_info->imagesets_combo_box != NULL) - gtk_combo_box_set_active(GTK_COMBO_BOX(sae_info->imagesets_combo_box), 0); - return TRUE; -} - -void show_sprite(SAEInfo *sae_info) { - Frame *sprite = sae_info->animation->data; - gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(source_view), - gtk_source_buffer_highlight_line(source_buffer, sprite->line_number-1), - 0.25, - FALSE, - 0.0, - 0.0); - sae_info->sprite = sprite; - gtk_widget_queue_draw(darea); -} - -void show_animation(SAEInfo *sae_info) { - kill_timeout(sae_info->anim_tag); - if (sae_info->animation == NULL) - return; - - show_sprite(sae_info); - Frame *sprite = sae_info->animation->data; - - GList *next = g_list_next(sae_info->animation); - if (next == NULL) - next = g_list_first(sae_info->animation); - - if (!sprite->delay) - { - free_animations(sae_info); - return; - } - sae_info->animation = next; - sae_info->anim_tag = g_timeout_add(sprite->delay, (GSourceFunc)show_animation, sae_info); -} - -gboolean show_general_animation(SAEInfo *sae_info) { - XMLNode *node = sae_info->animations->data; - if (node == NULL) - return FALSE; - animations_combo_box_changed_callback(NULL, NULL); - return TRUE; -} - -gboolean set_up_action_by_name(const gchar *name, SAEInfo *sae_info) { - free_animations(sae_info); - GList *list = g_list_find_custom(sae_info->actions, - xml_attr_new("name", name), - (GCompareFunc)xml_node_compare_with_attr_func); - if (list == NULL) return FALSE; - list = ((XMLNode *)list->data)->sub_nodes; - gboolean was_direction = FALSE; - while (TRUE) { - list = g_list_find_custom(list, "animation", xml_node_compare_with_name_func); - if (list == NULL) - break; - if (sae_info->animations == NULL) { - sae_info->animations = g_list_alloc(); - sae_info->animations->data = list->data; - } else - sae_info->animations = g_list_append(sae_info->animations, list->data); - XMLNode *node = list->data; - gchar *direction = xml_node_get_attr_value(node, "direction"); - if (direction != NULL) { - if (sae_info->animations_combo_box != NULL) - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(sae_info->animations_combo_box), direction); - was_direction = TRUE; - } - list = g_list_next(list); - } - if (sae_info->animations == NULL) - return FALSE; - if (!was_direction) - show_general_animation(sae_info); - else if (sae_info->animations_combo_box != NULL) - gtk_combo_box_set_active(GTK_COMBO_BOX(sae_info->animations_combo_box), 0); - return TRUE; -} - -void set_up_imageset_by_name(const gchar *name, SAEInfo *sae_info) { - free_imageset(sae_info); - free_actions(sae_info); - free_animations(sae_info); - - GList *list = g_list_find_custom(sae_info->imagesets, - xml_attr_new("name", name), - (GCompareFunc)xml_node_compare_with_attr_func); - - if (list == NULL) - return; - - XMLNode *node = list->data; - if (node == NULL) - return; - - sae_info->imageset->node = node; - sae_info->imageset->offsetX = 0; - sae_info->imageset->offsetY = 0; - - gchar *offset_attr = xml_node_get_attr_value(sae_info->imageset->node, "offsetX"); - if (offset_attr != NULL) - sscanf(offset_attr, "%d", &sae_info->imageset->offsetX); - - offset_attr = xml_node_get_attr_value(sae_info->imageset->node, "offsetY"); - if (offset_attr != NULL) - sscanf(offset_attr, "%d", &sae_info->imageset->offsetY); - - gchar *imageset_name = xml_node_get_attr_value(sae_info->imageset->node, "name"); - - gchar *src = xml_node_get_attr_value(sae_info->imageset->node, "src"); - format_src_string(src); - gchar *datapath = config->clientdata_folder; - gchar *path = g_strjoin(SEPARATOR_SLASH, datapath, src, NULL); - - sae_info->imageset->spriteset = gdk_pixbuf_new_from_file(path, NULL); - if (sae_info->imageset->spriteset == NULL) { - parsing_error_warning(sae_info, "Wrong spriteset path!"); - return; + file_name = g_strdup (opened_file_name); } - gtk_widget_set_sensitive(imageset_preview_menu_item, TRUE); - gtk_widget_set_sensitive(toolbar, TRUE); - sae_info->imageset->spriteset_width = gdk_pixbuf_get_width(sae_info->imageset->spriteset); - sae_info->imageset->spriteset_height = gdk_pixbuf_get_height(sae_info->imageset->spriteset); - - gchar *width = xml_node_get_attr_value(sae_info->imageset->node, "width"); - sscanf(width, "%d", &sae_info->imageset->width); - gchar *height = xml_node_get_attr_value(sae_info->imageset->node, "height"); - sscanf(height, "%d", &sae_info->imageset->height); - - list = g_list_find_custom(sae_info->root->sub_nodes, "sae", xml_node_compare_with_name_func); - if (list != NULL) { - gchar *ground_attr = xml_node_get_attr_value((XMLNode *)list->data, "ground"); - if (ground_attr != NULL) { - ground_attr = g_strjoin(NULL, DIR_GROUNDS, SEPARATOR_SLASH, ground_attr, ".png", NULL); - GdkPixbuf *pbuf = gdk_pixbuf_new_from_file(ground_attr, NULL); - if(pbuf != NULL) - sae_info->ground = pbuf; - } - gchar *player_attr = xml_node_get_attr_value((XMLNode *)list->data, "player"); - if (player_attr != NULL && player == NULL) { - gchar *text; - gchar *sprites_path = paths->sprites; - gchar *player_file = g_strjoin(NULL, sprites_path, DIR_PLAYERS, player_attr, ".xml", NULL); - if (g_file_get_contents(player_file, &text, NULL, NULL)) { - player = sae_info_new(); - parse_xml_text(text, player); - set_up_imageset_by_name("base", player); - } - } + if (file_name == NULL) { + file_name = g_strdup ("New animation"); } - set_up_actions_by_imageset_name(imageset_name, sae_info); - if (sae_info->actions == NULL) - return; - set_sprite_by_index(0, sae_info); -} - -void load_options() { - gchar *datapath = config->clientdata_folder; - gchar *path = g_strjoin(SEPARATOR_SLASH, datapath, "paths.xml", NULL); - config_options_load_from_file(paths, path, datapath); -} - -void parse_xml_text(gchar *text, SAEInfo *sae_info) { - GError *error = NULL; - free_lists(sae_info); + title = g_strconcat ( + modified ? "*" : "", + file_name, + NULL + ); + + gtk_window_set_title (GTK_WINDOW (main_window), title); + g_free (title); + g_free (file_name); +} + +void +setup_source_view (GtkSourceView *source_view) { + GtkSourceLanguageManager *langman; + GtkSourceMarkAttributes *attrs; + + langman = gtk_source_language_manager_get_default(); + + gtk_source_buffer_set_language ( + GTK_SOURCE_BUFFER ( + gtk_text_view_get_buffer ( + GTK_TEXT_VIEW (source_view) + ) + ), + gtk_source_language_manager_get_language (langman, "xml") + ); + + attrs = gtk_source_mark_attributes_new (); + gtk_source_mark_attributes_set_icon_name (attrs, "media-record"); + gtk_source_view_set_mark_attributes ( + source_view, "active-line", attrs, 0 + ); + + gtk_widget_show_all (GTK_WIDGET (source_view)); +} + +GtkWidget * +gtk_builder_get_widget ( + GtkBuilder *builder, + const gchar *name +) { + return GTK_WIDGET ( + gtk_builder_get_object (builder, name) + ); +} + +gboolean +window_main_delete_event_cb ( + GtkWidget *widget, + GdkEvent *event, + gpointer user_data +) { + return show_unsaved_changes_dialog (); +} + +int +main (int argc, char *argv[]) { + GtkBuilder *builder; + gchar *path; + + gtk_init (&argc, &argv); + + builder = gtk_builder_new (); + gtk_builder_add_from_file (builder, "iface.ui", NULL); + gtk_builder_connect_signals (builder, NULL); + + main_window = gtk_builder_get_widget (builder, "window-main"); + tf_view = gtk_builder_get_widget (builder, "treefolderview-main"); + d_area = gtk_builder_get_widget (builder, "drawingarea-main"); + source_view = gtk_builder_get_widget (builder, "sourceview-main"); + tbtn_play = gtk_builder_get_widget (builder, "button-anim-play"); + + cb_actions = GTK_COMBO_BOX ( + gtk_builder_get_widget (builder, "cbox-actions") + ); + cb_directions = GTK_COMBO_BOX_TEXT ( + gtk_builder_get_widget (builder, "cboxtext-directions") + ); + + store_actions = GTK_LIST_STORE ( + gtk_builder_get_object (builder, "liststore-actions") + ); + + zoom_adj = GTK_ADJUSTMENT ( + gtk_builder_get_object (builder, "zoom-adjustment") + ); + + g_object_unref (builder); + + setup_source_view (GTK_SOURCE_VIEW (source_view)); + + update_window_title (); + + path = config_keys_get_data_folder_path (); + tree_folder_view_set_filename ( + TREE_FOLDER_VIEW (tf_view), + path + ); + g_free (path); + + sprite_drawing_area_add_layer ( + SPRITE_DRAWING_AREA (d_area), + sda_layer_new (interactor_sprite_layer_draw_func, &interactor) + ); + + tile_grid_layer = sda_layer_new ( + tile_grid_layer_draw_func, + NULL + ); - XMLNode *_root_node = xml_parse_buffer(text, &error); - sae_info->root = _root_node; - if (_root_node == NULL) { - parsing_error_warning(sae_info, error->message); - g_error_free(error); - return; - } + sda_layer_set_z_index (tile_grid_layer, 512); + + sprite_drawing_area_add_layer ( + SPRITE_DRAWING_AREA (d_area), + tile_grid_layer + ); + + pixel_grid_layer = sda_layer_new ( + pixel_grid_layer_draw_func, + NULL + ); - GList *list = g_list_find_custom(_root_node->sub_nodes, "include", xml_node_compare_with_name_func); - while (list != NULL) { - XMLNode *node = list->data; - gchar *file_attr = xml_node_get_attr_value(node, "file"); - if (file_attr != NULL) { - file_attr = g_strjoin(NULL, paths->sprites, file_attr, NULL); - gchar *buf; - if (g_file_get_contents(file_attr, &buf, NULL, NULL)) - _root_node->sub_nodes = g_list_concat(_root_node->sub_nodes, xml_parse_buffer(buf, &error)->sub_nodes); - } - GList *next = g_list_next(list); - if (next != NULL) - list = g_list_find_custom(next, "include", xml_node_compare_with_name_func); - else - list = NULL; - } + sda_layer_set_z_index (pixel_grid_layer, 512 + 1); + sda_layer_set_visible (pixel_grid_layer, FALSE); - sae_info->offsetX = 0; - sae_info->offsetY = 0; + sprite_drawing_area_add_layer ( + SPRITE_DRAWING_AREA (d_area), + pixel_grid_layer + ); - if (error != NULL) - g_error_free(error); - - if (!set_up_imagesets(sae_info)) { - parsing_error_warning(sae_info, "Bad data!"); - return; - } -} - -void parse_xml_buffer(GtkWidget *button, GtkSourceBuffer *buffer) { - if (buffer == NULL) - buffer = source_buffer; - - player = NULL; - load_options(); - - GtkTextIter beg, end; - gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(buffer), &beg); - gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(buffer), &end); - parse_xml_text(gtk_text_iter_get_text(&beg, &end), gen_sae_info); -} - -void load_config() { - config_keys_load(config); - gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(data_folder_chooser_button), config->clientdata_folder); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(show_grid_menu_item), config->show_grid); -} - -void save_config_and_quit() { - config_keys_save(config); - gtk_main_quit(); -} - -int main(int argc, char *argv[]) { - - gtk_init(&argc, &argv); - - icon = gdk_pixbuf_new_from_file(FILE_ICON, NULL); - - gen_sae_info = sae_info_new(); - config = config_keys_new(); - paths = config_options_new(); - - set_up_interface(); - load_config(); + gtk_widget_show_all (main_window); gtk_main(); - + return 0; } diff --git a/saedit/main.h b/saedit/main.h index 27367bd..1e482f3 100644 --- a/saedit/main.h +++ b/saedit/main.h @@ -1,119 +1,51 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ +#ifndef _MAIN_H_ +#define _MAIN_H_ -#ifndef MAIN_H -#define MAIN_H - -#include <stdlib.h> #include <gtk/gtk.h> -#include <gtksourceview/gtksourceview.h> -#include <gtksourceview/gtksourcelanguagemanager.h> -#include <cairo.h> -#include <glib/gi18n.h> - -#include "common.h" -#include "xml.h" -#include "config.h" -#include "sae.h" -#include "search.h" - -const int MIN_WIDTH = 600; -const int MIN_HEIGHT = 600; - -const gchar *DIR_GROUNDS = "grounds"; -const gchar *DIR_PLAYERS = "races/"; - -const gchar *FILE_ICON = "icon.svg"; - -const int IMAGESET_PREVIEW_WINDOW_WIDTH = 200; -const int IMAGESET_PREVIEW_WINDOW_HEIGHT = 300; - -GtkWidget *win = NULL; -GtkWidget *darea = NULL; -GtkWidget *data_folder_chooser_button = NULL; -GtkWidget *xml_file_chooser_button = NULL; -GtkWidget *xml_file_open_button = NULL; -GtkWidget *xml_file_save_button = NULL; -GtkWidget *imageset_preview_menu_item = NULL; -GtkWidget *show_grid_menu_item = NULL; -GtkWidget *source_view = NULL; -GtkWidget *about_dialog = NULL; -GtkWidget *parsing_error_dialog = NULL; +#include "treefolderview.h" +#include "context.h" +#include "interactor.h" +#include "spritedrawingarea.h" -GtkSourceBuffer *source_buffer = NULL; +GtkWidget *main_window; +GtkWidget *d_area; +GtkWidget *source_view; +GtkWidget *tf_view; +GtkWidget *tbtn_play; -SAEInfo *gen_sae_info = NULL; -SAEInfo *player = NULL; +GtkComboBox *cb_actions; +GtkComboBoxText *cb_directions; +GtkListStore *store_actions; +GtkAdjustment *zoom_adj; -GdkPixbuf *icon = NULL; +SpriteContext *context; +Interactor *interactor; -Options *paths; -Keys *config; +SDALayer *tile_grid_layer; +SDALayer *pixel_grid_layer; -//Cairo functions -cairo_surface_t *get_grid_surface(int w, int h); -gboolean darea_draw_event(GtkWidget *widget, cairo_t *cr, SAEInfo *sae_info); +void +buffer_set_modified (gboolean modified); -//Common functions -gchar *markup_bold(gchar *str); -void format_src_string(gchar *src); -GtkTextIter *gtk_source_buffer_highlight_line(GtkSourceBuffer *buffer, int line_number); +gboolean +buffer_get_modified (void); -//File working -void open_xml_file(GtkButton *button); -void save_to_xml_file(gchar *filename); +void +release_context (void); -//SAEInfo functions -void free_imagesets(SAEInfo *sae_info); -void free_actions(SAEInfo *sae_info); -void free_animations(SAEInfo *sae_info); -void free_imageset(SAEInfo *sae_info); -void free_lists(SAEInfo *sae_info); +void +intr_updated (Interactor *interactor); -void free_current_info(); +void +update_window_title (void); -//Callbacks -void data_folder_set_callback(GtkFileChooserButton *widget, gpointer data); -void parsing_error_warning(SAEInfo *sae_info, const gchar *message); -void show_grid_menu_item_toggled_callback(GtkCheckMenuItem *checkmenuitem, gpointer user_data); -void actions_combo_box_changed_callback(GtkComboBoxText *widget, gpointer user_data); -void imagesets_combo_box_changed_callback(GtkComboBoxText *widget, gpointer user_data); -void animations_combo_box_changed_callback(GtkComboBoxText *widget, gpointer user_data); -void open_menu_item_activate_callback(GtkMenuItem *menuitem, GtkFileChooserDialog *fcdialog); -gboolean frame_image_button_press_event_callback(GtkWidget *widget, GdkEventButton *button, int index); -//>Toolbar callbacks -void toolbar_to_first_clicked_callback(GtkToolButton *toolbutton, gpointer user_data); -void toolbar_prev_frame_clicked_callback(GtkToolButton *toolbutton, gpointer user_data); -void toolbar_play_clicked_callback(GtkToolButton *toolbutton, gpointer user_data); -void toolbar_pause_clicked_callback(GtkToolButton *toolbutton, gpointer user_data); -void toolbar_next_frame_clicked_callback(GtkToolButton *toolbutton, gpointer user_data); -void toolbar_to_last_clicked_callback(GtkToolButton *toolbutton, gpointer user_data); +GtkWidget * +window_main_get_source_view (void); -//Dialogs -void show_imageset_dialog(); -void show_about_dialog(); +void +update_window_title (void); -void set_sprite_by_index(size_t index, SAEInfo *sae_info); -void set_up_actions_by_imageset_name(gchar *imageset_name, SAEInfo *sae_info); -gboolean set_up_imagesets(SAEInfo *sae_info); -gboolean show_general_animation(SAEInfo *sae_info); -gboolean set_up_action_by_name(const gchar *name, SAEInfo *sae_info); -void set_up_imageset_by_name(const gchar* name, SAEInfo *sae_info); -void parse_xml_buffer(GtkWidget *button, GtkSourceBuffer *buffer); -void set_up_interface(); -void load_config(); -void save_config_and_quit(); -void load_options(); -void parse_xml_text(gchar *text, SAEInfo *sae_info); -void show_sprite(SAEInfo *sae_info); -void show_animation(SAEInfo *sae_info); +void +release_context (void); #endif diff --git a/saedit/sae.c b/saedit/sae.c deleted file mode 100644 index 70e7c7d..0000000 --- a/saedit/sae.c +++ /dev/null @@ -1,212 +0,0 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - -#include "sae.h" - -void kill_timeout(guint tag) { - if (tag > 0) - g_source_remove(tag); -} - -Frame *frame_new(int index1, int offsetX, int offsetY, int delay) { - Frame *res = g_new0(Frame, 1); - res->index = index1; - res->offsetX = offsetX; - res->offsetY = offsetY; - res->delay = delay; - return res; -} - -Imageset *imageset_new() { - Imageset *res = g_new0(Imageset, 1); - res->width = SPRITE_WIDTH_DEFAULT; - res->height = SPRITE_HEIGHT_DEFAULT; - return res; -} - -SAEInfo *sae_info_new() { - SAEInfo *res = g_new0(SAEInfo, 1); - res->ground = sae_info_ground_new(); - res->sprite = frame_new(-1, 0, 0, 0); - res->imageset = imageset_new(); - return res; -} - -GdkPixbuf *sae_info_ground_new() { - GdkPixbuf *ground = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, GRID_SIZE * 3, GRID_SIZE * 3); - gdk_pixbuf_fill(ground, 0x00000000); - return ground; -} - -GdkPixbuf* get_sprite_by_index(int index1, SAEInfo *sae_info) { - if (index1 == -1) { - GdkPixbuf *res = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, - sae_info->imageset->width, - sae_info->imageset->height); - gdk_pixbuf_fill(res, 0x00000000); - return res; - } - - if (index1 >= 0) { - size_t w = sae_info->imageset->spriteset_width/sae_info->imageset->width; - if (sae_info->imageset->spriteset == NULL) return NULL; - - return gdk_pixbuf_new_subpixbuf(sae_info->imageset->spriteset, - index1%w*sae_info->imageset->width, - index1/w*sae_info->imageset->height, - sae_info->imageset->width, - sae_info->imageset->height); - } - - return NULL; -} - -inline void _add_frame(SAEInfo *sae_info, int index1, int offsetX, int offsetY, int delay, int line) { - - Frame *sprite = frame_new(index1, offsetX, offsetY, delay); - sprite->line_number = line; - sprite->pixbuf = get_sprite_by_index(index1, sae_info); - - if (sae_info->animation != NULL) - sae_info->animation = g_list_append(sae_info->animation, sprite); - else { - sae_info->animation = g_list_alloc(); - sae_info->animation->data = sprite; - } -} - -gboolean set_up_animation_by_direction(SAEInfo *sae_info, const gchar *direction) { - if (sae_info->imageset->spriteset == NULL) - return FALSE; - sae_info->animation = NULL; - - GList *list = g_list_find_custom(sae_info->animations, - xml_attr_new("direction", direction), - (GCompareFunc)xml_node_compare_with_attr_func); - if (list == NULL) - return FALSE; - - XMLNode *anode = list->data; - list = anode->sub_nodes; - - while (list != NULL) { - XMLNode *node = list->data; - - //sequence tag attributes - int offsetX = 0, offsetY = 0, - delay = 0, - start = -1, end = -1, - repeat = 1; - gchar *value = NULL; - - gchar *ofX_attr, *ofY_attr; - ofX_attr = xml_node_get_attr_value(node, "offsetX"); - if (ofX_attr != NULL) - sscanf(ofX_attr, "%d", &offsetX); - - ofY_attr = xml_node_get_attr_value(node, "offsetY"); - if (ofY_attr != NULL) - sscanf(ofY_attr, "%d", &offsetY); - - gchar *delay_attr = xml_node_get_attr_value(node, "delay"); - if (delay_attr != NULL) - sscanf(delay_attr, "%d", &delay); - - if (g_str_equal(node->name, "frame")) { - - gchar *index_attr = xml_node_get_attr_value(node, "index"); - if (index_attr != NULL) { - sscanf(index_attr, "%d", &start); - end = start; - } - - } else if (g_str_equal(node->name, "sequence")) { - - gchar *start_attr = xml_node_get_attr_value(node, "start"); - if (start_attr != NULL) - sscanf(start_attr, "%d", &start); - - gchar *end_attr = xml_node_get_attr_value(node, "end"); - if (end_attr != NULL) - sscanf(end_attr, "%d", &end); - - value = xml_node_get_attr_value(node, "value"); - - gchar *repeat_attr = xml_node_get_attr_value(node, "repeat"); - if (repeat_attr != NULL) - sscanf(repeat_attr, "%d", &repeat); - - } else if (g_str_equal(node->name, "pause")) { - - value = (gchar *)"p"; - - gchar *repeat_attr = xml_node_get_attr_value(node, "repeat"); - if (repeat_attr != NULL) - sscanf(repeat_attr, "%d", &repeat); - - } - - if (start >= 0) { //start-end case - - int r = 0, i = 0; - for (r = 1; r <= repeat; r++) { - for (i = start; i <= end; i++) { - _add_frame(sae_info, i, offsetX, offsetY, delay, node->line_number); - } - } - - } else - if (value != NULL) { //value case - - gchar **values = g_strsplit(value, ",", 0); - - int r; - for (r = 0; r < repeat; r++) { //TODO: remove multiparsing - gchar **iter = values; - while (*iter != NULL) { - - if (g_str_equal(*iter, "p")) { //pause - - _add_frame(sae_info, -1, 0, 0, delay, node->line_number); - - } else { - - unsigned f, s; - - if (sscanf(*iter, "%u-%u", &f, &s) == 2) { - - int i; - for (i = f; i <= s; i++) { - _add_frame(sae_info, i, offsetX, offsetY, delay, node->line_number); - } - - } else if (sscanf(*iter, "%u", &f) == 1) { - - _add_frame(sae_info, f, offsetX, offsetY, delay, node->line_number); - - } - - } - iter++; - } - } - - g_strfreev(values); - - } - - list = g_list_next(list); - } - if (sae_info->animation == NULL) - return FALSE; - - return TRUE; -} diff --git a/saedit/sae.h b/saedit/sae.h deleted file mode 100644 index 51f45c1..0000000 --- a/saedit/sae.h +++ /dev/null @@ -1,69 +0,0 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - -#ifndef SAE_H -#define SAE_H - -#include <gtk/gtk.h> -#include "common.h" -#include "xml.h" - -void kill_timeout(guint tag); - -typedef struct { - int index; - int offsetX; - int offsetY; - int delay; - int line_number; - GdkPixbuf *pixbuf; - cairo_surface_t *surface; -} Frame; - -Frame *frame_new(int index, int offsetX, int offsetY, int delay); - -typedef struct { - XMLNode *node; - int offsetX; - int offsetY; - int width; - int height; - int spriteset_width; - int spriteset_height; - GdkPixbuf *spriteset; -} Imageset; - -Imageset *imageset_new(); - -typedef struct { - GList *imagesets; - GList *actions; - GList *animations; - GList *animation; - Imageset *imageset; - Frame *sprite; - guint anim_tag; - XMLNode *root; - GtkWidget *imagesets_combo_box; - GtkWidget *actions_combo_box; - GtkWidget *animations_combo_box; - GdkPixbuf *ground; - int offsetX; - int offsetY; -} SAEInfo; - -SAEInfo *sae_info_new(); -GdkPixbuf *sae_info_ground_new(); - -GdkPixbuf* get_sprite_by_index(int index, SAEInfo *sae_info); -gboolean set_up_animation_by_direction(SAEInfo *sae_info, const gchar *direction); - -#endif diff --git a/saedit/search.c b/saedit/search.c deleted file mode 100644 index df2970e..0000000 --- a/saedit/search.c +++ /dev/null @@ -1,74 +0,0 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - -#include "search.h" - -GtkWidget *search_text_view = NULL; -gchar *search_last_text = NULL; - -gboolean search_find_text(gchar *text) { - search_last_text = text; - - GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(search_text_view)); - if (!GTK_IS_TEXT_BUFFER(text_buffer)) - return FALSE; - - gboolean found; - - GtkTextIter m_start, m_end, start; - gtk_text_buffer_get_selection_bounds(text_buffer, NULL, &start); - found = gtk_text_iter_forward_search(&start, text, 4, &m_start, &m_end, NULL); - - if (!found) { - gtk_text_buffer_get_start_iter(text_buffer, &start); - found = gtk_text_iter_forward_search(&start, text, 4, &m_start, &m_end, NULL); - } - - if (found) { - gtk_text_buffer_place_cursor(text_buffer, &m_start); - gtk_text_buffer_move_mark_by_name(text_buffer, "selection_bound", &m_end); - gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW(search_text_view), - gtk_text_buffer_get_insert(text_buffer), - 0.25, - FALSE, - 0.0, - 0.0); - return TRUE; - } else - return FALSE; -} - -gboolean search_find_next() { - if (search_last_text != NULL) - search_find_text(search_last_text); - // here must return some thing -} - -void search_find_dialog_response_callback(GtkWidget *dialog, - gint response_id, - gpointer entry) { - - if (response_id == GTK_RESPONSE_CANCEL || response_id == GTK_RESPONSE_DELETE_EVENT) - gtk_widget_hide(dialog); - else { - - g_return_if_fail(response_id == GTK_RESPONSE_ACCEPT); - g_return_if_fail(GTK_IS_TEXT_VIEW(search_text_view)); - g_return_if_fail(GTK_IS_ENTRY(GTK_ENTRY(entry))); - - search_find_text(g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)))); - - } -} - -void search_init(GtkWidget *text_view) { - search_text_view = text_view; -} diff --git a/saedit/search.h b/saedit/search.h deleted file mode 100644 index faf412e..0000000 --- a/saedit/search.h +++ /dev/null @@ -1,26 +0,0 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - -#ifndef SEARCH_H -#define SEARCH_H - -#include <gtk/gtk.h> -#include <gtksourceview/gtksourceview.h> -#include "common.h" - -void search_init(GtkWidget *text_view); -gboolean search_find_text(gchar *text); -gboolean search_find_next(); -void search_find_dialog_response_callback(GtkWidget *dialog, - gint response_id, - gpointer entry); - -#endif diff --git a/saedit/spritedrawingarea/sdalayer.c b/saedit/spritedrawingarea/sdalayer.c new file mode 100644 index 0000000..9794b80 --- /dev/null +++ b/saedit/spritedrawingarea/sdalayer.c @@ -0,0 +1,271 @@ +#include "spritedrawingarea.h" +#include "sdalayer.h" +#include "sdalayerprivate.h" + +enum { + PROP_0, + PROP_VISIBLE, + PROP_OFFSET_X, + PROP_OFFSET_Y, + PROP_DRAW_FUNC, + PROP_USER_DATA, + PROP_Z_INDEX, + PROP_COUNT +}; + +static void +sda_layer_get_property ( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) { + SDALayer *layer = SDA_LAYER (object); + SDALayerPrivate *priv = layer->priv; + + switch (prop_id) { + case PROP_VISIBLE: + g_value_set_boolean ( + value, priv->visible + ); + break; + + case PROP_OFFSET_X: + g_value_set_int ( + value, priv->offset_x + ); + break; + + case PROP_OFFSET_Y: + g_value_set_int ( + value, priv->offset_y + ); + break; + + case PROP_Z_INDEX: + g_value_set_int ( + value, priv->z_index + ); + break; + + case PROP_DRAW_FUNC: + g_value_set_pointer ( + value, (gpointer) priv->draw_func + ); + break; + + case PROP_USER_DATA: + g_value_set_pointer ( + value, priv->user_data + ); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +sda_layer_set_property ( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) { + SDALayer *layer = SDA_LAYER (object); + SDALayerPrivate *priv = layer->priv; + + switch (prop_id) { + case PROP_VISIBLE: + priv->visible = g_value_get_boolean (value); + break; + + case PROP_OFFSET_X: + priv->offset_x = g_value_get_int (value); + break; + + case PROP_OFFSET_Y: + priv->offset_y = g_value_get_int (value); + break; + + case PROP_Z_INDEX: + priv->z_index = g_value_get_int (value); + break; + + case PROP_DRAW_FUNC: + priv->draw_func = (SDALayerDrawFunc) g_value_get_pointer (value); + break; + + case PROP_USER_DATA: + priv->user_data = g_value_get_pointer (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +void +sda_layer_init ( + SDALayer *layer, + SDALayerClass *class +) { + layer->priv = G_TYPE_INSTANCE_GET_PRIVATE ( + layer, + SDA_TYPE_LAYER, + SDALayerPrivate + ); + + layer->priv->draw_func = NULL; + layer->priv->user_data = NULL; +} + +void +sda_layer_class_init ( + SDALayerClass *klass, + gpointer class_data +) { + GObjectClass *object_class; + + g_type_class_add_private (klass, sizeof (SDALayerPrivate)); + + object_class = G_OBJECT_CLASS (klass); + object_class->set_property = sda_layer_set_property; + object_class->get_property = sda_layer_get_property; + + g_object_class_install_property ( + object_class, + PROP_VISIBLE, + g_param_spec_boolean ( + "visible", + "Visible", + "Whether this layer is visible", + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); + + g_object_class_install_property ( + object_class, + PROP_OFFSET_X, + g_param_spec_int ( + "offset-x", + "Offset X", + "The X coordinate of the layer offset", + -SPRITE_DRAWING_AREA_FIELD_SIZE, + SPRITE_DRAWING_AREA_FIELD_SIZE, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); + + g_object_class_install_property ( + object_class, + PROP_OFFSET_Y, + g_param_spec_int ( + "offset-y", + "Offset y", + "The Y coordinate of the layer offset", + -SPRITE_DRAWING_AREA_FIELD_SIZE, + SPRITE_DRAWING_AREA_FIELD_SIZE, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); + + g_object_class_install_property ( + object_class, + PROP_DRAW_FUNC, + g_param_spec_pointer ( + "draw-func", + "Draw function", + "A function invoked to draw the layer", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + ) + ); + + g_object_class_install_property ( + object_class, + PROP_USER_DATA, + g_param_spec_pointer ( + "user-data", + "User data", + "Data that will be propagated to the draw" + " function upon call", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); + + g_object_class_install_property ( + object_class, + PROP_Z_INDEX, + g_param_spec_int ( + "z-index", + "Z-index", + "Z-index of the layer", + -1024, 1024, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); +} + +GType +sda_layer_get_type (void) { + static GType sda_layer_type = 0; + + if (sda_layer_type == 0) { + const GTypeInfo sda_layer_info = { + sizeof (SDALayerClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) sda_layer_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (SDALayer), + 0, /* n_preallocs */ + (GInstanceInitFunc) sda_layer_init, + NULL, /* value_table */ + }; + + sda_layer_type = g_type_register_static ( + G_TYPE_OBJECT, + "SDALayer", + &sda_layer_info, + 0 + ); + } + + return sda_layer_type; +} + +SDALayer *sda_layer_new ( + SDALayerDrawFunc draw_func, + gpointer user_data +) { + return g_object_new ( + SDA_TYPE_LAYER, + "draw-func", draw_func, + "user-data", user_data, + NULL + ); +} + +gint +sda_layer_compare_by_z_index ( + const SDALayer *a, + const SDALayer *b +) { + return a->priv->z_index - b->priv->z_index; +} + +void +sda_layer_set_z_index (SDALayer *layer, gint z_index) { + g_object_set (layer, "z-index", z_index, NULL); +} + +void +sda_layer_set_visible (SDALayer *layer, gboolean visible) { + g_object_set (layer, "visible", visible, NULL); +} diff --git a/saedit/spritedrawingarea/sdalayer.h b/saedit/spritedrawingarea/sdalayer.h new file mode 100644 index 0000000..e1bac04 --- /dev/null +++ b/saedit/spritedrawingarea/sdalayer.h @@ -0,0 +1,54 @@ +#ifndef _SDALAYER_H_ +#define _SDALAYER_H_ + +#include <glib-object.h> +#include <cairo.h> + +G_BEGIN_DECLS + +#define SDA_TYPE_LAYER (sda_layer_get_type ()) +#define SDA_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SDA_TYPE_LAYER, SDALayer)) +#define SDA_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SDA_TYPE_LAYER, SDALayerClass)) +#define IS_SDA_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SDA_TYPE_LAYER)) +#define IS_SDA_LAYER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SDA_TYPE_LAYER)) +#define SDA_LAYER_GET_CLASS(obj) ((obj), SDA_TYPE_LAYER, SDALayerClass) + +typedef struct _SDALayer SDALayer; +typedef struct _SDALayerClass SDALayerClass; +typedef struct _SDALayerPrivate SDALayerPrivate; + +struct _SDALayerClass { + GObjectClass parent_class; +}; + +GType +sda_layer_get_type (void); + +typedef void +(* SDALayerDrawFunc) ( + SDALayer *layer, + cairo_t *cr, + gpointer user_data +); + +SDALayer * +sda_layer_new ( + SDALayerDrawFunc draw_func, + gpointer user_data +); + +gint +sda_layer_compare_by_z_index ( + const SDALayer *a, + const SDALayer *b +); + +void +sda_layer_set_z_index (SDALayer *layer, gint z_index); + +void +sda_layer_set_visible (SDALayer *layer, gboolean visible); + +G_END_DECLS + +#endif diff --git a/saedit/spritedrawingarea/sdalayerprivate.h b/saedit/spritedrawingarea/sdalayerprivate.h new file mode 100644 index 0000000..daf47bc --- /dev/null +++ b/saedit/spritedrawingarea/sdalayerprivate.h @@ -0,0 +1,19 @@ +#ifndef _SDALAYERPRIVATE_H_ +#define _SDALAYERPRIVATE_H_ + +struct _SDALayerPrivate { + gboolean visible; + gint offset_x, offset_y; + gint z_index; + + SDALayerDrawFunc draw_func; + gpointer user_data; +}; + +struct _SDALayer { + GObject object; + + SDALayerPrivate *priv; +}; + +#endif diff --git a/saedit/spritedrawingarea/spritedrawingarea.c b/saedit/spritedrawingarea/spritedrawingarea.c new file mode 100644 index 0000000..376c8e1 --- /dev/null +++ b/saedit/spritedrawingarea/spritedrawingarea.c @@ -0,0 +1,437 @@ +#include "spritedrawingarea.h" +#include "sdalayer.h" +#include "sdalayerprivate.h" + +struct _SpriteDrawingAreaPrivate { + gint center_x, center_y; + gdouble scale_factor; + + gboolean drag_active; + gdouble drag_x, drag_y; + + GList *layers; +}; + +enum { + PROP_0, + PROP_CENTER_X, + PROP_CENTER_Y, + PROP_SCALE_FACTOR, + PROP_COUNT +}; + +void +sprite_drawing_area_get_center ( + SpriteDrawingArea *sdarea, + gint *center_x, + gint *center_y +) { + g_object_get ( + sdarea, + "center-x", center_x, + "center-y", center_y, + NULL + ); +} + +void +sprite_drawing_area_set_center ( + SpriteDrawingArea *sdarea, + gint center_x, + gint center_y +) { + g_object_set ( + sdarea, + "center-x", center_x, + "center-y", center_y, + NULL + ); +} + +gdouble +sprite_drawing_area_get_scale_factor ( + SpriteDrawingArea *sdarea +) { + gdouble result; + + g_object_get ( + sdarea, + "scale-factor", &result, + NULL + ); + + return result; +} + +void +sprite_drawing_area_set_scale_factor ( + SpriteDrawingArea *sdarea, + gdouble scale_factor +) { + g_object_set ( + sdarea, + "scale-factor", scale_factor, + NULL + ); +} + +static gboolean +_sprite_drawing_area_draw_handler ( + GtkWidget *widget, + cairo_t *cr, + gpointer user_data +) { + SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (widget); + GList *l; + + gint width = gtk_widget_get_allocated_width (widget); + gint height = gtk_widget_get_allocated_height (widget); + + gdouble scale = sprite_drawing_area_get_scale_factor (sdarea); + + gint center_x, center_y; + + sprite_drawing_area_get_center (sdarea, ¢er_x, ¢er_y); + + cairo_translate ( + cr, + 0.5 * (gdouble) width, + 0.5 * (gdouble) height + ); + + cairo_scale (cr, scale, scale); + + cairo_translate ( + cr, + -center_x, + -center_y + ); + + sdarea->priv->layers = g_list_sort ( + sdarea->priv->layers, + (GCompareFunc) sda_layer_compare_by_z_index + ); + + for (l = sdarea->priv->layers; l != NULL; l = l->next) { + SDALayer *layer = SDA_LAYER (l->data); + + if (!layer->priv->visible) + continue; + + cairo_save (cr); + + cairo_translate ( + cr, + layer->priv->offset_x, + layer->priv->offset_y + ); + + if (layer->priv->draw_func != NULL) + layer->priv->draw_func (layer, cr, layer->priv->user_data); + + cairo_restore (cr); + } + + return FALSE; +} + +static void +sprite_drawing_area_get_property ( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) { + SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (object); + + switch (prop_id) { + case PROP_CENTER_X: + g_value_set_int ( + value, sdarea->priv->center_x + ); + break; + + case PROP_CENTER_Y: + g_value_set_int ( + value, sdarea->priv->center_y + ); + break; + + case PROP_SCALE_FACTOR: + g_value_set_double ( + value, sdarea->priv->scale_factor + ); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +sprite_drawing_area_set_property ( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) { + SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (object); + + switch (prop_id) { + case PROP_CENTER_X: + sdarea->priv->center_x = g_value_get_int (value); + break; + + case PROP_CENTER_Y: + sdarea->priv->center_y = g_value_get_int (value); + break; + + case PROP_SCALE_FACTOR: + sdarea->priv->scale_factor = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +gboolean +_sprite_drawing_area_drag_start_callback ( + GtkWidget *widget, + GdkEvent *event, + gpointer user_data +) { + SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (widget); + + if (event->button.button != 1) + return FALSE; + + sdarea->priv->drag_active = TRUE; + sdarea->priv->drag_x = event->button.x; + sdarea->priv->drag_y = event->button.y; + + return FALSE; +} + +gboolean +_sprite_drawing_area_drag_end_callback ( + GtkWidget *widget, + GdkEvent *event, + gpointer user_data +) { + SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (widget); + + if (event->button.button != 1) + return FALSE; + + sdarea->priv->drag_active = FALSE; + return FALSE; +} + +gboolean +_sprite_drawing_area_drag_motion_callback ( + GtkWidget *widget, + GdkEvent *event, + gpointer user_data +) { + SpriteDrawingArea *sdarea = SPRITE_DRAWING_AREA (widget); + + gdouble event_x, event_y; + + gint center_x, center_y; + gint delta_x, delta_y; + + gdouble scale_factor; + + if ((event->motion.state & GDK_BUTTON1_MASK) == 0) + return FALSE; + + if (!sdarea->priv->drag_active) + return FALSE; + + event_x = event->motion.x; + event_y = event->motion.y; + + sprite_drawing_area_get_center (sdarea, ¢er_x, ¢er_y); + + scale_factor = sprite_drawing_area_get_scale_factor (sdarea); + + delta_x = + (gint) (event_x / scale_factor + 0.5) - (gint) (sdarea->priv->drag_x / scale_factor + 0.5); + delta_y = + (gint) (event_y / scale_factor + 0.5) - (gint) (sdarea->priv->drag_y / scale_factor + 0.5); + + sprite_drawing_area_set_center ( + sdarea, + center_x - delta_x, + center_y - delta_y + ); + + sdarea->priv->drag_x = event_x; + sdarea->priv->drag_y = event_y; + + gtk_widget_queue_draw (widget); + return FALSE; +} + +static void +sprite_drawing_area_init ( + SpriteDrawingArea *sdarea, + SpriteDrawingAreaClass *klass +) { + /* Setting up private */ + sdarea->priv = G_TYPE_INSTANCE_GET_PRIVATE ( + sdarea, + TYPE_SPRITE_DRAWING_AREA, + SpriteDrawingAreaPrivate + ); + + sdarea->priv->layers = NULL; + + g_signal_connect ( + sdarea, + "button-press-event", + (GCallback) _sprite_drawing_area_drag_start_callback, + NULL + ); + + g_signal_connect ( + sdarea, + "button-release-event", + (GCallback) _sprite_drawing_area_drag_end_callback, + NULL + ); + + g_signal_connect ( + sdarea, + "motion-notify-event", + (GCallback) _sprite_drawing_area_drag_motion_callback, + NULL + ); +} + +static void +sprite_drawing_area_class_init ( + SpriteDrawingAreaClass *klass, + gpointer class_data +) { + GObjectClass *object_class; + + g_type_class_add_private (klass, sizeof (SpriteDrawingAreaPrivate)); + + object_class = G_OBJECT_CLASS (klass); + object_class->set_property = sprite_drawing_area_set_property; + object_class->get_property = sprite_drawing_area_get_property; + + g_signal_override_class_handler ( + "draw", + TYPE_SPRITE_DRAWING_AREA, + (GCallback) _sprite_drawing_area_draw_handler + ); + + g_object_class_install_property ( + object_class, + PROP_CENTER_X, + g_param_spec_int ( + "center-x", + "Center X", + "The X coordinate of the point on the field " + "camera is centered on, in pixels", + -SPRITE_DRAWING_AREA_FIELD_SIZE, + SPRITE_DRAWING_AREA_FIELD_SIZE, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); + + g_object_class_install_property ( + object_class, + PROP_CENTER_Y, + g_param_spec_int ( + "center-y", + "Center Y", + "The Y coordinate of the point on the field " + "camera is centered on, in pixels", + -SPRITE_DRAWING_AREA_FIELD_SIZE, + SPRITE_DRAWING_AREA_FIELD_SIZE, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); + + g_object_class_install_property ( + object_class, + PROP_SCALE_FACTOR, + g_param_spec_double ( + "scale-factor", + "Scale factor", + "The scaling factor that is used in making " + "the camera zooming effect", + 0.01, 100.0, 1.0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); +} + +GType +sprite_drawing_area_get_type (void) { + static GType sdarea_type = 0; + + if (sdarea_type == 0) { + const GTypeInfo sdarea_info = { + sizeof (SpriteDrawingAreaClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) sprite_drawing_area_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (SpriteDrawingArea), + 0, /* n_preallocs */ + (GInstanceInitFunc) sprite_drawing_area_init, + NULL, /* value_table */ + }; + + sdarea_type = g_type_register_static ( + GTK_TYPE_DRAWING_AREA, + "SpriteDrawingArea", + &sdarea_info, + 0 + ); + + } + + return sdarea_type; +} + +GtkWidget * +sprite_drawing_area_new (void) { + GtkWidget *sdarea = GTK_WIDGET ( + g_object_new (TYPE_SPRITE_DRAWING_AREA, NULL) + ); + return sdarea; +} + +void +sprite_drawing_area_add_layer ( + SpriteDrawingArea *sdarea, + SDALayer *layer +) { + sdarea->priv->layers = g_list_insert_sorted ( + sdarea->priv->layers, + layer, + (GCompareFunc) sda_layer_compare_by_z_index + ); +} + +void +sprite_drawing_area_remove_layer ( + SpriteDrawingArea *sdarea, + SDALayer *layer +) { + sdarea->priv->layers = g_list_remove ( + sdarea->priv->layers, + layer + ); +} diff --git a/saedit/spritedrawingarea/spritedrawingarea.h b/saedit/spritedrawingarea/spritedrawingarea.h new file mode 100644 index 0000000..ee3aa6d --- /dev/null +++ b/saedit/spritedrawingarea/spritedrawingarea.h @@ -0,0 +1,71 @@ +#ifndef __SPRITE_DRAWING_AREA_H__ +#define __SPRITE_DRAWING_AREA_H__ + +#include <gdk/gdk.h> +#include <gtk/gtk.h> +#include "sdalayer.h" + +G_BEGIN_DECLS + +#define TYPE_SPRITE_DRAWING_AREA (sprite_drawing_area_get_type ()) +#define SPRITE_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SPRITE_DRAWING_AREA, SpriteDrawingArea)) +#define SPRITE_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SPRITE_DRAWING_AREA, SpriteDrawingAreaClass)) +#define IS_SPRITE_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SPRITE_DRAWING_AREA)) +#define IS_SPRITE_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SPRITE_DRAWING_AREA)) +#define SPRITE_DRAWING_AREA_GET_CLASS(obj) ((obj), TYPE_SPRITE_DRAWING_AREA, SpriteDrawingAreaClass) + +typedef struct _SpriteDrawingArea SpriteDrawingArea; +typedef struct _SpriteDrawingAreaPrivate SpriteDrawingAreaPrivate; +typedef struct _SpriteDrawingAreaClass SpriteDrawingAreaClass; + +struct _SpriteDrawingArea { + GtkDrawingArea darea; + + SpriteDrawingAreaPrivate *priv; +}; + +struct _SpriteDrawingAreaClass { + GtkDrawingAreaClass darea_class; + + void (* draw_field) ( + GtkWidget *sdarea, + gpointer data + ); +}; + +static const gint SPRITE_DRAWING_AREA_FIELD_SIZE = 1024; + +GType +sprite_drawing_area_get_type (void); + +GtkWidget* +sprite_drawing_area_new (void); + +void +sprite_drawing_area_set_scale_factor ( + SpriteDrawingArea *sdarea, + gdouble scale_factor +); + +void +sprite_drawing_area_add_layer ( + SpriteDrawingArea *sdarea, + SDALayer *layer +); + +void +sprite_drawing_area_remove_layer ( + SpriteDrawingArea *sdarea, + SDALayer *layer +); + +void +sprite_drawing_area_set_center ( + SpriteDrawingArea *sdarea, + gint center_x, + gint center_y +); + +G_END_DECLS + +#endif diff --git a/saedit/template.xml b/saedit/template.xml deleted file mode 100644 index 3747c31..0000000 --- a/saedit/template.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0"?> -<!-- Original Author : -Copyright (C) 2012 --> -<sprite> - -</sprite> diff --git a/saedit/treefolderview/treefolderview.c b/saedit/treefolderview/treefolderview.c new file mode 100644 index 0000000..e1b02f0 --- /dev/null +++ b/saedit/treefolderview/treefolderview.c @@ -0,0 +1,400 @@ +#include "treefolderview.h" +#include "treefolderviewprivate.h" + +enum { + STORE_COLUMN_FILE_NAME, + STORE_COLUMN_IS_FOLDER, + STORE_COLUMN_FILE_ICON, + STORE_COLUMN_FILE_INFO, + STORE_COLUMN_WAS_EXPANDED, + STORE_COLUMN_COUNT +}; + +enum { + SIGNAL_FILE_ACTIVATED, + SIGNAL_COUNT +}; + +struct _TreeFolderViewPrivate { + gchar *filename; + GtkFileFilter *file_filter; +}; + +static guint tfview_signals [SIGNAL_COUNT] = { 0 }; + +static GtkTreeStore * +tree_folder_view_get_store (TreeFolderView *tfview) { + GtkTreeModelFilter *model; + + model = GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (tfview))); + return GTK_TREE_STORE (gtk_tree_model_filter_get_model (model)); +} + +static gboolean +file_filter_filter_file_info (GtkFileFilter *filter, GFileInfo *info) { + gboolean result; + gchar *mimetype = NULL; + GtkFileFilterFlags required; + GtkFileFilterInfo filter_info = { 0, }; + + if (filter == NULL) + return TRUE; + + required = gtk_file_filter_get_needed (filter); + + filter_info.contains |= GTK_FILE_FILTER_DISPLAY_NAME; + filter_info.display_name = g_file_info_get_display_name (info); + + if (required & GTK_FILE_FILTER_MIME_TYPE) { + const gchar *ctype = g_file_info_get_content_type (info); + if (ctype != NULL) { + mimetype = g_content_type_get_mime_type (ctype); + if (mimetype != NULL) { + filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE; + filter_info.mime_type = mimetype; + } + } + } + + if (required & GTK_FILE_FILTER_FILENAME) { + filter_info.filename = g_file_info_get_name (info); + filter_info.contains |= GTK_FILE_FILTER_FILENAME; + } + + result = gtk_file_filter_filter (filter, &filter_info); + + g_free(mimetype); + + return result; +} + +static gchar * +tree_folder_view_get_file_path_from_tree_path ( + TreeFolderView *tfview, + GtkTreePath *path +) { + GtkTreeIter iter; + GtkTreeModel *model; + + model = GTK_TREE_MODEL (tree_folder_view_get_store (tfview)); + gtk_tree_model_get_iter (model, &iter, path); + + return tree_folder_view_get_file_path_from_iter (tfview, &iter); +} + +static gchar * +tree_folder_view_get_file_path_from_iter ( + TreeFolderView *tfview, + GtkTreeIter *file_iter +) { + gchar *result, *data; + GPtrArray *names; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreePath *_path; + + model = GTK_TREE_MODEL (tree_folder_view_get_store (tfview)); + _path = gtk_tree_model_get_path (model, file_iter); + + names = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); + + while (gtk_tree_path_get_depth (_path) > 0) { + gtk_tree_model_get_iter (model, &iter, _path); + gtk_tree_model_get ( + model, &iter, + STORE_COLUMN_FILE_NAME, &data, -1 + ); + g_ptr_array_insert (names, 0, data); + gtk_tree_path_up (_path); + } + + g_ptr_array_insert (names, 0, g_strdup (tfview->priv->filename)); + g_ptr_array_add (names, NULL); + result = g_strjoinv ("/", (gchar **) names->pdata); + + g_ptr_array_free (names, TRUE); + gtk_tree_path_free (_path); + + return result; +} + +static void +tree_folder_view_row_expanded ( + GtkTreeView *tree_view, + GtkTreeIter *filter_iter, + GtkTreePath *path +) { + gboolean w_exp; + gchar *file_path; + GtkTreeIter iter, citer; + GtkTreeStore *store; + + gtk_tree_model_filter_convert_iter_to_child_iter ( + GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tree_view)), + &iter, + filter_iter + ); + + store = tree_folder_view_get_store ( + TREE_FOLDER_VIEW (tree_view) + ); + + gtk_tree_model_get ( + GTK_TREE_MODEL (store), &iter, + STORE_COLUMN_WAS_EXPANDED, &w_exp, + -1 + ); + + if (w_exp) + return; + + gtk_tree_store_set ( + store, &iter, + STORE_COLUMN_WAS_EXPANDED, TRUE, + -1 + ); + + if (!gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store), &iter)) + return; + + gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &citer, &iter); + do { + file_path = tree_folder_view_get_file_path_from_iter ( + TREE_FOLDER_VIEW (tree_view), + &citer + ); + + tree_store_append_file_children ( + store, + &citer, + file_path, + FALSE + ); + + g_free (file_path); + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &citer)); +} + +static gboolean +tree_model_filter_file_visible_func ( + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data +) { + gboolean is_folder; + GFileInfo *info; + GtkFileFilter *filter; + TreeFolderView *tfview; + + tfview = TREE_FOLDER_VIEW (data); + + gtk_tree_model_get ( + model, iter, + STORE_COLUMN_FILE_INFO, &info, + STORE_COLUMN_IS_FOLDER, &is_folder, + -1 + ); + + if (info == NULL) + return FALSE; + + if (g_file_info_get_is_hidden (info)) + return FALSE; + + if (is_folder) + return TRUE; + + filter = tree_folder_view_get_filter (tfview); + return file_filter_filter_file_info (filter, info); +} + +static void +tree_store_append_file_children ( + GtkTreeStore *store, + GtkTreeIter *iter, + const gchar *path, + gboolean expanded +) { + gchar *npath; + const gchar *name; + GDir *dir; + + dir = g_dir_open (path, 0, NULL); + + if (dir == NULL) + return; + + while ((name = g_dir_read_name (dir)) != NULL) { + npath = g_strconcat (path, "/", name, NULL); + + tree_store_append_file_recursive ( + store, + iter, + npath, + name, + expanded + ); + + g_free(npath); + } + + g_dir_close (dir); +} + +static gint +tree_store_append_file_recursive ( + GtkTreeStore *store, + GtkTreeIter *parent_iter, + const gchar *path, + const gchar *display_name, + gboolean append_children +) { + GFile *file; + GFileInfo *info; + GtkTreeIter iter; + + file = g_file_new_for_path (path); + info = g_file_query_info (file, "*", 0, NULL, NULL); + g_object_unref (file); + + gtk_tree_store_append (store, &iter, parent_iter); + gtk_tree_store_set ( + store, &iter, + STORE_COLUMN_FILE_NAME, display_name, + STORE_COLUMN_FILE_ICON, g_content_type_get_icon (g_file_info_get_content_type (info)), + STORE_COLUMN_FILE_INFO, info, + STORE_COLUMN_IS_FOLDER, FALSE, + STORE_COLUMN_WAS_EXPANDED, FALSE, + -1 + ); + + if (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY) + return 0; + + gtk_tree_store_set ( + store, &iter, + STORE_COLUMN_IS_FOLDER, TRUE, + STORE_COLUMN_FILE_ICON, g_themed_icon_new ("folder"), -1 + ); + + if (!append_children) + return 1; + + tree_store_append_file_children (store, &iter, path, FALSE); + + return 1; +} + +static gint +tree_store_iter_compare_func ( + GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data +) { + gboolean isf_a, isf_b; + gint cmp; + gchar *val_a, *val_b; + + gtk_tree_model_get (model, a, STORE_COLUMN_IS_FOLDER, &isf_a, -1); + gtk_tree_model_get (model, b, STORE_COLUMN_IS_FOLDER, &isf_b, -1); + + if (isf_a != isf_b) + return isf_b; + + gtk_tree_model_get (model, a, STORE_COLUMN_FILE_NAME, &val_a, -1); + gtk_tree_model_get (model, b, STORE_COLUMN_FILE_NAME, &val_b, -1); + + cmp = g_strcmp0 (val_a, val_b); + g_free (val_a); + g_free (val_b); + + return cmp; +} + +static void +tree_folder_view_row_activated ( + GtkTreeView *tree_view, + GtkTreePath *filter_path, + GtkTreeViewColumn *col +) { + gboolean is_folder; + GtkTreeIter iter; + GtkTreePath *path; + GtkTreeStore *store; + + path = gtk_tree_model_filter_convert_path_to_child_path ( + GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tree_view)), + filter_path + ); + + store = tree_folder_view_get_store (TREE_FOLDER_VIEW (tree_view)); + + gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path); + gtk_tree_model_get ( + GTK_TREE_MODEL (store), &iter, + STORE_COLUMN_IS_FOLDER, &is_folder, -1 + ); + + if (is_folder) + return; + + g_signal_emit ( + tree_view, + tfview_signals[SIGNAL_FILE_ACTIVATED], + 0, + tree_folder_view_get_file_path_from_tree_path ( + TREE_FOLDER_VIEW (tree_view), + path + ) + ); + + gtk_tree_path_free (path); +} + +void +tree_folder_view_set_filename ( + TreeFolderView *tfview, + const gchar *filename +) { + GtkTreeStore *store = tree_folder_view_get_store (tfview); + + /* TODO: values inside are not freed */ + gtk_tree_store_clear (store); + + g_free (tfview->priv->filename); + tfview->priv->filename = g_strdup (filename); + + if (filename != NULL) { + tree_store_append_file_children ( + store, + NULL, + filename, + TRUE + ); + } +} + +GtkFileFilter * +tree_folder_view_get_filter (TreeFolderView *tfview) { + return tfview->priv->file_filter; +} + +void +tree_folder_view_set_filter (TreeFolderView *tfview, GtkFileFilter *filter) { + if (G_IS_OBJECT (tfview->priv->file_filter)) + g_object_unref (tfview->priv->file_filter); + + tfview->priv->file_filter = filter; + g_object_ref (filter); + + gtk_tree_model_filter_refilter ( + GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (tfview)))); +} + +gchar * +tree_folder_view_get_filename (TreeFolderView *tfview) { + return g_strdup (tfview->priv->filename); +} + +#include "type.c" diff --git a/saedit/treefolderview/treefolderview.h b/saedit/treefolderview/treefolderview.h new file mode 100644 index 0000000..78aeefc --- /dev/null +++ b/saedit/treefolderview/treefolderview.h @@ -0,0 +1,64 @@ +#ifndef __TREE_FOLDER_VIEW_H__ +#define __TREE_FOLDER_VIEW_H__ + +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define TYPE_TREE_FOLDER_VIEW (tree_folder_view_get_type ()) +#define TREE_FOLDER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_TREE_FOLDER_VIEW, TreeFolderView)) +#define TREE_FOLDER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_TREE_FOLDER_VIEW, TreeFolderViewClass)) +#define IS_TREE_FOLDER_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_TREE_FOLDER_VIEW)) +#define IS_TREE_FOLDER_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_TREE_FOLDER_VIEW)) +#define TREE_FOLDER_VIEW_GET_CLASS(obj) ((obj), TYPE_TREE_FOLDER_VIEW, TreeFolderViewClass) + +typedef struct _TreeFolderView TreeFolderView; +typedef struct _TreeFolderViewPrivate TreeFolderViewPrivate; +typedef struct _TreeFolderViewClass TreeFolderViewClass; + +struct _TreeFolderView { + GtkTreeView tview; + + TreeFolderViewPrivate *priv; +}; + +struct _TreeFolderViewClass { + GtkTreeViewClass tview_class; + + void (* file_activated) ( + TreeFolderView *tfview, + gchar *filename + ); +}; + +GType +tree_folder_view_get_type (void); + +GtkWidget* +tree_folder_view_new (void); + +void +tree_folder_view_set_filename ( + TreeFolderView *tfview, + const gchar *filename +); + +GtkFileFilter* +tree_folder_view_get_filter (TreeFolderView *tfview); + +void +tree_folder_view_set_filter ( + TreeFolderView *tfview, + GtkFileFilter *filter +); + +gchar * +tree_folder_view_get_filename (TreeFolderView *tfview); + +gchar * +tree_folder_view_get_display_name (TreeFolderView *tfview); + +G_END_DECLS + +#endif diff --git a/saedit/treefolderview/treefolderviewprivate.h b/saedit/treefolderview/treefolderviewprivate.h new file mode 100644 index 0000000..01119fc --- /dev/null +++ b/saedit/treefolderview/treefolderviewprivate.h @@ -0,0 +1,45 @@ +#ifndef __TREE_FOLDER_VIEW_PRIVATE_H__ +#define __TREE_FOLDER_VIEW_PRIVATE_H__ + +enum { + PROP_0, + PROP_FILTER, + PROP_FILENAME, + PROP_MODEL, + PROP_COUNT +}; + +static GtkTreeStore * +tree_folder_view_get_store (TreeFolderView *tfview); + +static gchar * +tree_folder_view_get_file_path_from_tree_path ( + TreeFolderView *tfview, + GtkTreePath *path +); + +static gchar * +tree_folder_view_get_file_path_from_iter ( + TreeFolderView *tfview, + GtkTreeIter *file_iter +); + +static void +tree_store_append_file_children ( + GtkTreeStore *store, + GtkTreeIter *iter, + const gchar *path, + gboolean expanded +); + +static gint +tree_store_append_file_recursive ( + GtkTreeStore *store, + GtkTreeIter *parent_iter, + const gchar *path, + const gchar *display_name, + gboolean append_children +); + +#endif + diff --git a/saedit/treefolderview/type.c b/saedit/treefolderview/type.c new file mode 100644 index 0000000..fbb0f21 --- /dev/null +++ b/saedit/treefolderview/type.c @@ -0,0 +1,250 @@ +static void +tree_folder_view_init ( + TreeFolderView *tfview, + TreeFolderViewClass *klass +) { + GType *types; + GtkCellRenderer *renderer; + GtkTreeModel *model; + GtkTreeStore *store; + GtkTreeView *tview; + GtkTreeViewColumn *col; + + tview = GTK_TREE_VIEW (tfview); + + /* Setting up TreeView properties */ + gtk_tree_view_set_headers_visible (tview, FALSE); + gtk_tree_view_set_enable_tree_lines (tview, TRUE); + + /* Setting up only column */ + col = gtk_tree_view_column_new (); + + /* Filename renderer */ + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_end (col, renderer, TRUE); + gtk_tree_view_column_set_attributes ( + col, + renderer, + "text", STORE_COLUMN_FILE_NAME, + NULL + ); + + /* Filetype renderer */ + renderer = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_end (col, renderer, FALSE); + gtk_tree_view_column_set_attributes ( + col, + renderer, + "gicon", STORE_COLUMN_FILE_ICON, + NULL + ); + + gtk_tree_view_append_column (tview, col); + + /* Setting up TreeStore */ + types = g_new (GType, STORE_COLUMN_COUNT); + types [STORE_COLUMN_FILE_NAME] = G_TYPE_STRING; + types [STORE_COLUMN_FILE_ICON] = G_TYPE_ICON; + types [STORE_COLUMN_FILE_INFO] = G_TYPE_FILE_INFO; + types [STORE_COLUMN_IS_FOLDER] = G_TYPE_BOOLEAN; + types [STORE_COLUMN_WAS_EXPANDED] = G_TYPE_BOOLEAN; + + store = gtk_tree_store_newv (STORE_COLUMN_COUNT, types); + g_free(types); + + gtk_tree_sortable_set_sort_func ( + GTK_TREE_SORTABLE (store), + STORE_COLUMN_FILE_NAME, + (GtkTreeIterCompareFunc) tree_store_iter_compare_func, + NULL, + NULL + ); + + gtk_tree_sortable_set_sort_column_id ( + GTK_TREE_SORTABLE (store), + STORE_COLUMN_FILE_NAME, + GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID + ); + + /* Setting up TreeModelFilter */ + model = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL); + gtk_tree_model_filter_set_visible_func ( + GTK_TREE_MODEL_FILTER (model), + (GtkTreeModelFilterVisibleFunc) tree_model_filter_file_visible_func, + (gpointer) tview, + NULL + ); + gtk_tree_view_set_model (tview, model); + + /* Setting up private */ + tfview->priv = G_TYPE_INSTANCE_GET_PRIVATE ( + tfview, + TYPE_TREE_FOLDER_VIEW, + TreeFolderViewPrivate + ); +} + +static void +tree_folder_view_set_property ( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) { + TreeFolderView *tfview = TREE_FOLDER_VIEW (object); + + switch (prop_id) { + case PROP_FILTER: + tree_folder_view_set_filter ( + tfview, + GTK_FILE_FILTER (g_value_get_object (value)) + ); + break; + case PROP_FILENAME: + tree_folder_view_set_filename ( + tfview, + g_value_get_string (value) + ); + break; + case PROP_MODEL: + g_warning( + "\"model\" property of GtkTreeView is overriden " + "in TreeFolderView and shouldn't be changed" + ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +tree_folder_view_get_property ( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) { + TreeFolderView *tfview = TREE_FOLDER_VIEW (object); + + switch (prop_id) { + case PROP_FILTER: + g_value_set_object ( + value, tree_folder_view_get_filter (tfview) + ); + break; + case PROP_FILENAME: + g_value_set_string ( + value, tree_folder_view_get_filename (tfview) + ); + break; + case PROP_MODEL: + g_value_set_object ( + value, gtk_tree_view_get_model (GTK_TREE_VIEW (tfview)) + ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +tree_folder_view_class_init ( + TreeFolderViewClass *klass, + gpointer class_data +) { + GObjectClass *object_class; + GtkTreeViewClass *tree_view_class; + + object_class = G_OBJECT_CLASS (klass); + tree_view_class = GTK_TREE_VIEW_CLASS (klass); + + tree_view_class->row_activated = tree_folder_view_row_activated; + tree_view_class->row_expanded = tree_folder_view_row_expanded; + + tfview_signals [SIGNAL_FILE_ACTIVATED] = g_signal_new ( + "file-activated", + TYPE_TREE_FOLDER_VIEW, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (TreeFolderViewClass, file_activated), + NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_STRING + ); + + g_type_class_add_private (klass, sizeof (TreeFolderViewPrivate)); + + object_class->set_property = tree_folder_view_set_property; + object_class->get_property = tree_folder_view_get_property; + + g_object_class_install_property ( + object_class, + PROP_FILTER, + g_param_spec_object ( + "filter", + "File filter", + "File filter for selecting " + "which files should be displayed.", + GTK_TYPE_FILE_FILTER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); + + g_object_class_install_property ( + object_class, + PROP_FILENAME, + g_param_spec_string ( + "filename", + "Folder filename", + "Full path to a folder " + "which contents are displayed.", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT + ) + ); + + g_object_class_override_property ( + object_class, + PROP_MODEL, + "model" + ); +} + +GType +tree_folder_view_get_type (void) { + static GType tfview_type = 0; + + if (tfview_type == 0) { + const GTypeInfo tfview_info = { + sizeof (TreeFolderViewClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) tree_folder_view_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (TreeFolderView), + 0, /* n_preallocs */ + (GInstanceInitFunc) tree_folder_view_init, + NULL, /* value_table */ + }; + + tfview_type = g_type_register_static ( + GTK_TYPE_TREE_VIEW, + "TreeFolderView", + &tfview_info, + 0 + ); + + } + + return tfview_type; +} + +GtkWidget * +tree_folder_view_new (void) { + GtkWidget *tfview = GTK_WIDGET ( + g_object_new (TYPE_TREE_FOLDER_VIEW, NULL) + ); + return tfview; +} diff --git a/saedit/valg b/saedit/valg deleted file mode 100755 index 8726b81..0000000 --- a/saedit/valg +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -valgrind --read-var-info=yes --track-origins=yes --malloc-fill=11 --free-fill=55 --show-reachable=yes --leak-check=full --leak-resolution=high --partial-loads-ok=yes --error-limit=no --num-callers=30 "./saedit" 2>./valg.log diff --git a/saedit/xml.c b/saedit/xml.c index eefc536..90c4d76 100644 --- a/saedit/xml.c +++ b/saedit/xml.c @@ -1,49 +1,100 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ - #include "xml.h" +#include <string.h> -gchar** xml_attr_new(const gchar *name, const gchar *value) { +gchar ** +xml_attr_new ( + const gchar *name, + const gchar *value +) { gchar **attr = g_new0(gchar*, 2); attr[0] = g_strdup(name); attr[1] = g_strdup(value); return attr; } -gchar* xml_node_get_attr_value(const XMLNode *node, const gchar *attr_name) { +gchar * +xml_node_get_attr_value ( + const XMLNode *node, + const gchar *attr_name +) { gchar **attr = node->attributes; guint i; for (i = 0; i < g_strv_length(attr); i += 2) if (g_str_equal(attr[i], attr_name)) - return attr[i + 1]; + return g_strdup (attr[i + 1]); return NULL; } +gint +xml_node_get_int_attr_value ( + const XMLNode *node, + const gchar *attr_name, + gint retval +) { + gchar *val = xml_node_get_attr_value (node, attr_name); + + if (val != NULL) { + try_strtoint (val, &retval); + g_free (val); + } + + return retval; +} -gint xml_node_compare_with_name_func(gconstpointer a, gconstpointer b) { - return g_strcmp0((gchar *)b, ((XMLNode *)a)->name); +gint +xml_node_get_int_attr_value_limited ( + const XMLNode *node, + const gchar *attr_name, + gint retval, + gint lower, + gint upper +) { + g_assert (lower <= upper); + + retval = xml_node_get_int_attr_value ( + node, attr_name, retval + ); + + if (retval < lower) + retval = lower; + + if (retval > upper) + retval = upper; + return retval; } -gint xml_node_compare_with_action_node_by_imageset_name_func(gconstpointer a, gconstpointer b) { - return g_strcmp0("action", ((XMLNode *)a)->name) || - g_strcmp0((gchar *)b, xml_node_get_attr_value((XMLNode *)a, "imageset")); +gint +xml_node_compare_with_name_func ( + gconstpointer a, + gconstpointer b +) { + return g_strcmp0((gchar *) b, ((XMLNode *) a)->name); } -gint xml_node_compare_with_attr_func(const XMLNode *node, const gchar **attr) { +gint +xml_node_compare_with_action_node_by_imageset_name_func ( + gconstpointer a, + gconstpointer b +) { + return g_strcmp0("action", ((XMLNode *) a)->name) || + g_strcmp0((gchar *) b, xml_node_get_attr_value((XMLNode *) a, "imageset")); +} + +gint +xml_node_compare_with_attr_func ( + const XMLNode *node, + const gchar **attr +) { return g_strcmp0(attr[1], xml_node_get_attr_value(node, attr[0])); } static GMarkupParser parser; +void _xml_free_g_func (XMLNode *node, gpointer user_data) { + xml_free (node); +} + void xml_free (XMLNode *node) { g_free (node->name); @@ -51,7 +102,7 @@ void xml_free (XMLNode *node) { g_strfreev (node->attributes); - g_list_foreach (node->sub_nodes, (GFunc) xml_free, NULL); + g_list_foreach (node->sub_nodes, (GFunc) _xml_free_g_func, NULL); g_list_free (node->sub_nodes); g_slice_free (XMLNode, node); @@ -62,16 +113,18 @@ static void _start_root_element_cb ( GMarkupParseContext *context, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, - GError **error) { + GError **error +) { XMLNode **node = (XMLNode **) user_data; - g_assert (node != NULL); - - XMLNode *p = g_slice_new0 (XMLNode); + XMLNode *p; + GArray *attributes; + g_assert (node != NULL); + p = g_slice_new0 (XMLNode); p->name = g_strdup (element_name); - GArray *attributes = g_array_new (TRUE, TRUE, sizeof (gchar *)); + attributes = g_array_new (TRUE, TRUE, sizeof (gchar *)); while (*attribute_names != NULL && *attribute_values != NULL) { gchar *p2; p2 = g_strdup (*attribute_names++); @@ -87,28 +140,31 @@ static void _start_root_element_cb ( GMarkupParseContext *context, } -static void _start_element_cb ( GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) { - - XMLNode *node = (XMLNode *) user_data; +static void _start_element_cb ( + GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error +) { + XMLNode *p, *node = (XMLNode *) user_data; + GArray *attributes; + gint char_n, line_n; if (node->text) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, " "); return; } - XMLNode *p = g_slice_new0 (XMLNode); + p = g_slice_new0 (XMLNode); node->sub_nodes = g_list_append (node->sub_nodes, p); g_markup_parse_context_push (context, &parser, p); p->name = g_strdup (element_name); - GArray *attributes = g_array_new (TRUE, TRUE, sizeof (gchar *)); + attributes = g_array_new (TRUE, TRUE, sizeof (gchar *)); while (*attribute_names != NULL && *attribute_values != NULL) { gchar *p2; p2 = g_strdup (*attribute_names++); @@ -119,15 +175,17 @@ static void _start_element_cb ( GMarkupParseContext *context, p->attributes = (gchar **)g_array_free (attributes, FALSE); - gint char_n, line_n; g_markup_parse_context_get_position(context, &line_n, &char_n); - p->line_number = line_n - (char_n <= 1 ? 1 : 0); + p->line_no = line_n - (char_n <= 1 ? 1 : 0); } -static void _end_element_cb ( GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) { +static void +_end_element_cb ( + GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error +) { XMLNode *p = (XMLNode *) g_markup_parse_context_pop (context); if (p->text && p->sub_nodes) { @@ -139,8 +197,11 @@ static void _end_element_cb ( GMarkupParseContext *context, } } -static gboolean _is_space ( const gchar *text, - gsize text_len) { +static gboolean +_is_space ( + const gchar *text, + gsize text_len +) { gsize i = 0; for (i = 0; text[i] != '\0' && i < text_len; i++) { @@ -158,11 +219,14 @@ static gboolean _is_space ( const gchar *text, return TRUE; } -static void _text_cb ( GMarkupParseContext *context, - const gchar *text, - gsize text_len, - gpointer user_data, - GError **error) { +static void +_text_cb ( + GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error +) { XMLNode *p = (XMLNode *)user_data; if (_is_space (text, text_len)) { @@ -185,15 +249,10 @@ static GMarkupParser parser = { 0, }; -XMLNode *xml_parse_file (const gchar *filename) { +XMLNode * +xml_parse_file (const gchar *filename) { gboolean retval = FALSE; GError *error = NULL; - FILE *pf = fopen (filename, "r"); - - if (pf == NULL) { - return NULL; - } - GMarkupParseContext *context; XMLNode *node; @@ -205,6 +264,12 @@ XMLNode *xml_parse_file (const gchar *filename) { 0, }; + FILE *pf = fopen (filename, "r"); + + if (pf == NULL) { + return NULL; + } + do { context = g_markup_parse_context_new (&root_parser, 0, &node, 0); @@ -238,7 +303,8 @@ XMLNode *xml_parse_file (const gchar *filename) { return NULL; } -XMLNode *xml_parse_buffer (const gchar *buffer, GError **error) { +XMLNode * +xml_parse_buffer (const gchar *buffer, GError **error) { gboolean retval; GMarkupParseContext *context; @@ -266,7 +332,6 @@ XMLNode *xml_parse_buffer (const gchar *buffer, GError **error) { return node; } while (0); - //g_warning ("Parse buffer failed: %s", (*error)->message); g_markup_parse_context_free (context); return NULL; } @@ -279,7 +344,11 @@ static void output_indent (int level, GString *output) { } } -static void xml_output_indent (const XMLNode *node, int level, GString *output) { +static void xml_output_indent ( + const XMLNode *node, + int level, + GString *output +) { gchar **attrs; output_indent (level, output); @@ -293,8 +362,8 @@ static void xml_output_indent (const XMLNode *node, int level, GString *output) } if (node->sub_nodes != NULL) { - g_string_append (output, ">\n"); GList *sub_node; + g_string_append (output, ">\n"); for (sub_node = node->sub_nodes; sub_node != NULL; sub_node = sub_node->next) { xml_output_indent (sub_node->data, level + 1, output); diff --git a/saedit/xml.h b/saedit/xml.h index 584c568..2622f17 100644 --- a/saedit/xml.h +++ b/saedit/xml.h @@ -1,13 +1,3 @@ -/*=======================================*\ -| ____ ____ | -| / \ /\ | | -| \____ / \ |____ | -| \ /____\ | | -| \____/prite / \nimation |____ditor | -| | -| Copyleft Vasily_Makarov 2011 | -| | -\*=======================================*/ #ifndef XML_H #define XML_H @@ -18,25 +8,63 @@ typedef struct { gchar *name; gchar *text; - gchar **attributes; - int line_number; - GList *sub_nodes; + gchar **attributes; + gint line_no; + GList *sub_nodes; } XMLNode; -XMLNode *xml_parse_file (const gchar *name); +XMLNode * +xml_parse_file ( + const gchar *name +); -XMLNode *xml_parse_buffer (const gchar *buffer, GError **error); +XMLNode * +xml_parse_buffer ( + const gchar *buffer, + GError **error +); -void xml_free (XMLNode *node); +void xml_free (XMLNode *node); +void xml_output ( + const XMLNode *node, + GString *output +); + +gchar ** +xml_attr_new ( + const gchar *name, + const gchar *value +); + +gchar * +xml_node_get_attr_value ( + const XMLNode *node, + const gchar *attr_name +); + +gint +xml_node_get_int_attr_value ( + const XMLNode *node, + const gchar *attr_name, + gint retval +); + +gint +xml_node_get_int_attr_value_limited ( + const XMLNode *node, + const gchar *attr_name, + gint retval, + gint lower, + gint upper +); -void xml_output (const XMLNode *node, - GString *output); -gchar **xml_attr_new(const gchar *name, const gchar *value); -gchar *xml_node_get_attr_value(const XMLNode *node, const gchar *attr_name); gint xml_node_compare_with_name_func(gconstpointer a, gconstpointer b); + +/* gint xml_node_compare_with_action_node_by_imageset_name_func(gconstpointer a, gconstpointer b); gint xml_node_compare_with_attr_func(const XMLNode *node, const gchar **attr); +*/ #endif diff --git a/saedit/xmlsetup.c b/saedit/xmlsetup.c new file mode 100644 index 0000000..1036436 --- /dev/null +++ b/saedit/xmlsetup.c @@ -0,0 +1,165 @@ +#include "main.h" +#include "xml.h" +#include "xmlsetup.h" +#include "config.h" +#include "drawfuncs.h" + +GList *_xml_setup_layers = NULL; +GList *_xml_setup_interactors = NULL; + +void +xml_setup_setup (XMLNode *node) { + GList *l; + + g_return_if_fail (g_strcmp0 (node->name, "saedit") == 0); + + for (l = node->sub_nodes; l != NULL; l = l->next) { + XMLNode *current = (XMLNode *) l->data; + + if (g_strcmp0 (current->name, "layer") == 0) { + SDALayer *layer = NULL; + gint z_index = -1; + gint offset_x, offset_y; + gchar *type = xml_node_get_attr_value (current, "type"); + + if (type == NULL) { + /* TODO: layer type is not specified */ + continue; + } + + if (g_strcmp0 (type, "repeater") == 0) { + Interactor **repeater; + SpriteContext *repeater_context; + XMLNode *sprite = NULL; + gchar *file; + + file = xml_node_get_attr_value (current, "file"); + + if (file == NULL) { + /* TODO: file is not specified */ + } else { + gchar *filename = + config_data_path_get_full_sprite_path (file); + + sprite = xml_parse_file (filename); + + + g_free (file); + g_free (filename); + } + + repeater_context = sprite_context_new ( + config_keys_get_data_folder_path () + ); + + sprite_context_add_sprite (repeater_context, sprite, 0); + repeater = (Interactor **) g_new0 (gpointer, 1); + *repeater = interactor_new (repeater_context); + + layer = sda_layer_new ( + interactor_sprite_layer_draw_func, + repeater + ); + + interactor_add_repeater (interactor, *repeater); + + _xml_setup_interactors = g_list_append ( + _xml_setup_interactors, + repeater + ); + } else + if (g_strcmp0 (type, "background") == 0) { + GdkRGBA *rgba = (GdkRGBA *) g_new0 (GdkRGBA, 1); + gchar *color; + + color = xml_node_get_attr_value (current, "color"); + + if (color != NULL && gdk_rgba_parse (rgba, color)) { + layer = sda_layer_new ( + background_layer_draw_func, + rgba + ); + } else { + /* TODO: color not specified or wrong */ + } + } else { + /* TODO: unknown type of layer */ + } + + g_free (type); + + if (layer == NULL) { + continue; + } + + z_index = xml_node_get_int_attr_value ( + current, + "zindex", + z_index + ); + + offset_x = xml_node_get_int_attr_value ( + current, + "offsetX", + 0 + ); + + offset_y = xml_node_get_int_attr_value ( + current, + "offsetY", + 0 + ); + + g_object_set ( + G_OBJECT (layer), + "z-index", z_index, + "offset-x", offset_x, + "offset-y", offset_y, + NULL + ); + + sprite_drawing_area_add_layer ( + SPRITE_DRAWING_AREA (d_area), + layer + ); + + _xml_setup_layers = g_list_append ( + _xml_setup_layers, + layer + ); + } else { + /* TODO: unknown tag in the setup */ + } + } +} + +void +xml_setup_clear () { + GList *l; + + for (l = _xml_setup_interactors; l != NULL; l = l->next) { + Interactor **intr = (Interactor **) l->data; + interactor_free (*intr); + } + + for (l = _xml_setup_layers; l != NULL; l = l->next) { + SDALayer *layer = (SDALayer *) l->data; + gpointer user_data; + + g_object_get (layer, "user-data", &user_data, NULL); + g_free (user_data); + + sprite_drawing_area_remove_layer ( + SPRITE_DRAWING_AREA (d_area), + layer + ); + + g_object_unref (layer); + } + + g_list_free (_xml_setup_interactors); + g_list_free (_xml_setup_layers); + + _xml_setup_interactors = NULL; + _xml_setup_layers = NULL; +} diff --git a/saedit/xmlsetup.h b/saedit/xmlsetup.h new file mode 100644 index 0000000..37c9b65 --- /dev/null +++ b/saedit/xmlsetup.h @@ -0,0 +1,10 @@ +#ifndef _XML_SETUP_H_ +#define _XML_SETUP_H_ + +void +xml_setup_setup (XMLNode *node); + +void +xml_setup_clear (void); + +#endif |