pax_global_header00006660000000000000000000000064126067016710014520gustar00rootroot0000000000000052 comment=a033e70ed5737099ea7bbb29fde22d3659342681 tiled-0.14.2/000077500000000000000000000000001260670167100127055ustar00rootroot00000000000000tiled-0.14.2/AUTHORS000066400000000000000000000064721260670167100137660ustar00rootroot00000000000000Main developer and maintainer: Thorbjørn Lindeijer Other contributors: Stefan Beller Samuli Tuomola Erik Schilling Jeff Bland Petr Viktorin mauve Mamed Ibrahimov Martin Ziel Mauricio Muñoz Lucero Parker Miller seeseekey Yohann Ferreira Alex Vega (semtiko) Roderic Morris Hiroki Utsunomiya Porfírio Ribeiro Sean Humeniuk Ben Longbons Jonatas de Moraes Junior Manu Evans Mikolai Fajer zhaosting Alejandro Cámara Oskar Wiksten Tamir Atias (KonoM) Tim Baker Hendrik Brummermann Jake Petroules Mohammad Mehdi Salem Naraghi Omnomnobot Andrew G. Crowell Clint Bellanger Dennis Honeyman Michael Woerister Sebastian Pidek Yehnan Chiang Alexander Kuhrt Andreas Abraham Champi080 Christian Henz Christoph Schnackenberg Christophe Conceicao Dale Kim HenryJia Janis Kirsteins Kenney Phillis Maus Nathan Tolbert Pierre-David Bélanger Porfirio Wodann juniperbrew tolbert wayfu zigal Aban Adam Rippon Alessandro Portale Alex Koz Alexei Bratuhin Andrew Motrenko Antonio Ricci Bin Wu Brandon Dillon Dennis Hostetler Dmitry Marakasov Dobes Vandermeer Edward Hutchins Emmanuel Barroga Eric Kidd Firas Assaad Flyte Gornova Gregory Nickonov Hanmac Harri Berglund Harry Hsiao Ian Langworth Jared Adams Joel Leclerc Juan Rodriguez Justin Jacobs Kody Kurtz Kyle Delaney Lennert Raesch Ludolph Neethling MHendricks Mark van Rij Mattia Basaglia Michael Aquilina Michael Williams Oliver Zell Postremus Przemysław Grzywacz Roberto Raggi Seanba Sébastien BURILLARD Todd Carnes Vincent Petithory Vsevolod Klementjev Wade Brainerd Xenodora Ying-Chun Liu (PaulLiu) arntro-4 devnewton leeonix mhussa mogemimi Translators: Alex Vega (Russian) Antonio Ricci (Italian) Bin Wu (Chinese) Damene Abdelkader (Arabic, Algeria) Gornova (Italian) Hiroki Utsunomiya (Japanese) Jonatas de Moraes Junior (Portuguese, Brazil) jurkan (German) Jānis Kiršteins (Latvian) Laete Meireles (Portuguese, Brazil) Lyubomir Vasilev (Bulgarian) Mauricio Muñoz Lucero (Spanish) Petr Viktorin (Czech) Porfírio Ribeiro (Portuguese) Sebastian Grillmaier (German) Sébastien Burillard (French) seeseekey (German) Tamir Atias (KonoM) (Hebrew) Thorbjørn Lindeijer (Dutch) Tomasz Kubiak (Polish) Yohann Ferreira (French) Zhao Sting (Chinese) Acknowledgements: Most of the icons are from the GNOME and GIMP icon themes (GPL) Some Icons are Copyright (C) Yusuke Kamiyamane. All rights reserved. Licensed under a Creative Commons Attribution 3.0 license. See http://p.yusukekamiyamane.com/ The dice icon is based on an SVG by Steaphan Greene that I found on Wikipedia: http://en.wikipedia.org/wiki/File:2-Dice-Icon.svg The rename icon for tilesets is a strong modified version of the 'new Tileset' icon by Stefan Beller (GPL, CC-BY-SA3) Tilesets: perspective_walls.png - (C) Clint Bellanger, released as Public Domain isometric_grass_and_water.png - (C) Clint Bellanger, released as GPL2, GPL3, CC-BY-SA3 tmw_desert_spacing.png - (C) The Mana World Development Team, GPL sewer_tileset.png - (C) Blues Brothers RPG developers, GPL Replica Island - (C) Chris Pruett and Genki Mine, Apache (except hotspots.png) hexmini.png - Public Domain, http://opengameart.org/content/pixel-hex-tilesets-enhanced tiled-0.14.2/COPYING000066400000000000000000000017401260670167100137420ustar00rootroot00000000000000Several independent works are being distributed along with Tiled that fall under different licenses. You can find the license that applies to each file in the comment at the top, but for clarity they are also listed here: Software Directory License ------------------------------------------------------------------- Tiled src/tiled GPL Tiled plugins src/plugins GPL automappingconverter src/automappingconverter GPL libtiled src/libtiled BSD 2-clause license libtiled-java util/java/libtiled-java BSD 2-clause license qtpropertybrowser src/qtpropertybrowser BSD 3-clause license tmxrasterizer src/tmxrasterizer BSD 2-clause license tmxviewer src/tmxviewer BSD 2-clause license tmxviewer-java util/java/tmxviewer-java BSD 2-clause license The full text of each license is provided in the files LICENSE.GPL and LICENSE.BSD. tiled-0.14.2/Doxyfile000066400000000000000000000221101260670167100144070ustar00rootroot00000000000000# Doxyfile 1.6.1 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "Tiled (Qt)" PROJECT_NUMBER = OUTPUT_DIRECTORY = CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = NO REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = YES SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = src INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */moc_*.cpp \ */ui_*.h \ */qrc_*.cpp EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = NO GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = "../tiled-0.1.qch" QHP_NAMESPACE = org.mapeditor.tiled QHP_VIRTUAL_FOLDER = "tiled-0.1" QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = "qhelpgenerator" DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO USE_INLINE_TREES = NO TREEVIEW_WIDTH = 250 FORMULA_FONTSIZE = 10 SEARCHENGINE = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_FONTNAME = FreeSans DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = YES DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES tiled-0.14.2/LICENSE.APACHE000066400000000000000000000261351260670167100146410ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. tiled-0.14.2/LICENSE.BSD000066400000000000000000000023041260670167100143200ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. tiled-0.14.2/LICENSE.GPL000066400000000000000000000432541260670167100143430ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. tiled-0.14.2/NEWS000066400000000000000000000544501260670167100134140ustar00rootroot000000000000000.14.2 (12 October 2015) * Added Polish translation * Fixed layer offsets missing in the Lua export * Fixed JSON tileset format missing in 'Add External Tileset' action * Fixed language selection entries for Portuguese * Fixed an issue with copy/pasting when using image collection tilesets * Updated Brazilian Portuguese translation 0.14.1 (28 September 2015) * Added missing 'renderorder' property to the Lua export * Fixed editing of properties of tiles captured from the map 0.14.0 (21 September 2015) * Added support for custom external tileset formats (JSON format added) * Added support for shifting layers by some distance in pixels * Added back object name labels in a much improved form * Added tile stamp variation support to the fill tool * Synchronize tileset selection when capturing tiles from the map * Change tile in collision and animation editors based on selected tile object * Keep the active brush when switching maps * Python plugins can now add export-only map formats * Fixed updating of current tile when changing map * Fixed animated tile overlay to look less odd in some cases * Fixed Save As dialog popping up when saving fails * Fixed tilesets view collapsing when switching maps on OS X * Updated Russian, Spanish, Czech, French, Japanese, German, Dutch and Bulgarian translations 0.13.1 (6 September 2015) * Added Bulgarian translation (by Lyubomir Vasilev) * Updated Spanish, French and Dutch translations 0.13.0 (10 August 2015) * Added persistent Tile Stamps with support for variations (#969) * Added Select Same Tile tool (by Mamed Ibrahimov) * Added option to disable opening of last files on startup (by Mamed Ibrahimov) * Added tilecount property to TMX, JSON and Lua map formats (#806) * Added tileset properties to Properties view, as read-only (by Mamed Ibrahimov) * Added Save All action (by Mamed Ibrahimov) * Added translation of command line messages (by Mamed Ibrahimov) * Added menu item linking to online documentation * Object selection outlines are now drawn on top of everything * Select new objects after they have been created * Made the starting point for polylines and polygons visible * Use the tile probability property also in random mode * Ungrouped position and size properties (#892) * CSV plugin: Extended to export all tile layers (by Alejandro Cámara) * Lua and JSON plugins: Added support for layer data compression * Fixed crash when changing flipping flag for multiple objects (by Mamed Ibrahimov) * Fixed Ctrl+T causing a crash when no maps are open * Fixed availability of 'Execute in Terminal' command on Linux with Qt 5 * Fixed drag object mouse cursor to appear only when it should * Fixed selected file format when doing Save As with a non-TMX map * Fixed problems with infinate scaling factors when resizing objects * Require at least Qt 5.1.0 * Require compiler support for C++11 * Updated Russian, German, Czech and Italian translations 0.12.3 (1 June 2015) * Fixed updating of map view when rotating objects with Z key * Fixed updating of map view when joining, splitting or deleting polygon nodes * Fixed a crash when reading an invalid TMX file * Fixed live automapping updates when moving the mouse fast * Made Backspace work for deleting collision objects and animation frames 0.12.2 (22 May 2015) * Fixed updating of map view when moving objects with arrow keys * Fixed compatibility issue with tile objects affecting the JSON format 0.12.1 (19 May 2015) * Fixed updating of map view when changing objects from properties view * Fixed updating of Properties view while objects are moved/resized * Fixed terrain information getting lost when reading JSON maps 0.12.0 (14 May 2015) * Added support for resizing any object as well as multiselection (with mauve) * Added Control modifier for preserving aspect ratio while resizing * Added Shift modifier for resizing with origin in the middle * Added Alt modifier for suppressing selection changes when starting to drag * Added a Magic Wand selection tool (by Henry Jia) * Added tile probability attribute to tile properties view * Added a Donate button to the About dialog * Added a Patreon dialog to the Help menu * Added an --export-formats command line option * Remember the directory used for external tilesets (by Henry Jia) * Don't set a window icon on Mac OS X * Changed the way tile probability is applied (now it's relative) * Fixed a crash in the terrain brush * Fixed object selection behavior when Shift is held while clicking on nothing * Fixed grid snapping being applied for staggered maps even when not enabled * Fixed infinite memory allocation loop on invalid tile size in TMX file * Fixed file icon associated with TMX files on Windows * Fixed automapping of tile objects (by Seanba) * Fixed 'Export as Image' to handle out of memory errors * Fixed TMX files to be written in native line endings * Fixed .desktop file missing %f argument for passing files (by Ying-Chun Liu) * Fixed cursor position resetting when editing object type * Added Arabic (Algeria) translation (by Damene Abdelkader) * Updated, Czech, Dutch, French, German, Italian, Japanese, Portuguese, Russian and Spanish translations 0.11.0 (11 January 2015) * Added support for hexagonal maps (offset coordinates) * Added 'Export' action to repeat the last export * Added a shortcut for the Reload action (Ctrl+R) * Added ability to rename custom properties (by arn00d) * Added unique IDs to objects (by Mark van Rij) * Added a CSV export plugin * Added visual feedback when properties differ between multiple selected objects (by Parker Miller) * Added command-line export (by Brandon Dillon) * Allow dynamically changing the map orientation and grid size * Suppress the standard main window context menu in the collision editor * Lua plugin: Write out tile terrain information * Lua plugin: Include Tiled version in exported file * Flare plugin: Fixed ability to open maps with absolute paths * Fixed grid rendering for staggered maps * Fully support building and running Tiled with Qbs * Updated Czech, Dutch, French, German, Italian, Japanese, Portuguese and Spanish translations 0.10.2 (23 October 2014) * Fixed hit area for polygon nodes when editing polygons while zoomed in or out * Fixed another possible crash in the orthogonal renderer * Fixed Select All action to work for object layers * Fixed map pixel size preview for staggered maps * Fixed repainting issues when tiles extend beyond their layer boundaries * Fixed repainting issues when using tiles smaller than the grid size * Display errors non-modal when applying automatic automapping rules * Flare plugin: Fixed coordinate format for import and export (by Justin Jacobs) * Lua plugin: Write out Image layer position * Small updates to the Italian translation (by Omnomnobot) 0.10.1 (21 September 2014) * Fixed a crash that could happen when using the terrain tool * Fixed missing background color information from Lua export * Allow using up to 3 or 4 GB RAM on 32 or 64 bit Windows systems respectively 0.10.0 (14 September 2014) * Added object rotation (sponsored by Ben Wales) * Added support for explicit object ordering (sponsored by Ben Wales) * Added new Properties window with a rewritten properties editor * Added support for writing plugins in Python (by Samuli Tuomola) * Added image collection tilesets (sponsored by Jamie Rocks) * Added map file watching and automatic reloading (sponsored by FlatRedBall.com) * Added support for moving objects with arrow keys (sponsored by Ben Wales) * Added a 'snap to fine grid' option (by Xenodora) * Added support for JavaScript (JSONP) load/save (by Dobes Vandermeer) * Added more zoom levels (by Joel Leclerc) * Added shortcuts for finishing and canceling object creation * Added a tile collision editor for defining collision shapes on tiles * Added a tile animation editor and play defined animations * Allow changing properties of multiple objects/tiles simultanously (by Parker Miller) * Added tile rendering-order map property (by Lennert Raesch) * Added support for changing the object line width * Added support for CSV-encoded layers to libtiled-java (by Alexei Bratuhin) * Added support for ellipse and polygon objects to libtiled-java (by Hendrik Brummermann) * Added terrain properties to JSON export (by Dennis Hostetler) * Added support for moving image layers in the Properties window (by Michael Aquilina) * Added option to include background image when saving as image (by Sean Humeniuk) * Added options to control layer visibility to tmxrasterizer (by Nathan Tolbert) * Added display of tile ID in status bar (by Champi080) * Added support for objects on staggered isometric maps (by Remco Kuijper) * Added support for staggered maps to tmxviewer and tmxrasterizer * Added a tool for moving the image of an image layer (by Mattia Basaglia) * Added button to the tileset dock as shortcut to add a tileset (by Erik Schilling) * Allow changing order of open document tabs (by Sean Humeniuk) * Changed object position and size units from tiles to pixels (by mauve) * Allow adding multiple tilesets at once (by mauve) * Make highlighted grid cells outside map red (by Sean Humeniuk) * Allow changing the drawing offset of a tileset * Fixed hang on Mac OS X when drawing certain ellipse objects * Fixed removal of polygon/polyline objects when resizing a map * Fixed writing of tile offset in the Lua export * Fixed updating of image layer when changing its image * Fixed start drag distance check when editing polygons and moving objects * Fixed console output of tmxrasterizer on Windows * Raise the Layers dock for editing a new layer's name * Avoid saving truncated files when compiled against Qt 5.1 or higher (by Erik Schilling) * Made Tiled registering *.tmx as MIME-type (by Erik Schilling) * Added Traditional Chinese translation (by Yehnan Chiang) * Updated Czech, Dutch, French, German, Russian and Spanish translations 0.9.1 (27 July 2013) * Added saving of map background to JSON format (by Petr Viktorin) * Added saving of terrain information to JSON format (by Petr Viktorin) * Object Selection tool now always start selecting objects when holding Shift * Increased maximum for tileset margin and spacing to 9999 * Some updates to libtiled-java (by Oskar Wiksten) * Install the automappingconverter application (relevant on Linux) * Avoid using Windows 95 style (was used on some Linux desktop environments) * Removed layer name checks from the Flare export plugin (by Stefan Beller) * Double-clicking an object now opens the Object Properties dialog * Fixed Object Properties dialog not remembering its size * Fixed object drawing order for image saving and mini-map * Fixed some plurals in English translation * Fixed line widths when zooming in Qt 5 * Fixed updating of image layer when its opacity or image is changed * Fixed display of grid in tileset view on certain zoom levels * Fixed save in wrong format after opening a map with plugin (by Mike Hendricks) * Fixed closing Tiled being very slow with many maps * Fixed saving of image layer properties in the Lua format * Fixed escaping of special characters in the Lua format * Fixed handling of relative paths for image layers in the JSON plugin 0.9.0 (27 January 2013) * Added objects dock and per-object visibility toggle (by Tim Baker) * Added maps dock (by Tim Baker) * Added terrain tool for automatic terrain transitions (by Manu Evans) * Added a minimap (by Christoph Schnackenberg) * Added a staggered isometric map renderer, still without object layer support * Added basic image layer support (by Gregory Nickonov and Alexander Kuhrt) * Added display of current layer to the status bar (by Tim Baker) * Added editable combo box for changing the zoom level (by Tim Baker) * Added support for multiple input layers to automapping (by Stefan Beller) * Added option to apply automapping rules while editing (by Stefan Beller) * Added a converter to update old automapping rules (by Stefan Beller) * Added support for objects layers to automapping (by Stefan Beller) * Added support for random mode to the fill tool (by Stefan Beller) * Added Replica Island plugin (by Eric Kidd) * Added option to change the grid color (by Stefan Beller) * Added support for ellipse objects (by devnewton and Christoph Schnackenberg) * Added name labels for objects on isometric maps (by Andrew Motrenko) * Added map property for changing the background color (by Emmanuel Barroga) * Added shortcut to manually reload tilesets (Ctrl-T) (by Michael Williams) * Added toggle for showing tile object outlines * Added support for pinch zooming (by Pierre-David Bélanger) * Added initial (non-GUI) support for individual and/or embedded tile images (by Petr Viktorin) * Added reading support to Flare plugin (by Stefan Beller) * Added a TMX rasterizer command line tool (by Vincent Petithory) * Added man pages and desktop file (by Erik Schilling) * Made the size and position of most dialogs persistent * Respect the original layer data format of a loaded map (by Ben Longbons) * Marked Tiled as high-resolution capable on Mac OS X * Improved handling of external tilesets in Lua export * Reverted tilesets view back to tabs, but with menu button (by Stefan Beller) * Allowed plugins to support multiple file name filters (by Samuli Tuomola) * Allow saving in any format that can also be read (by Stefan Beller) * Fixed eraser skipping tiles when moving fast * Fixed bug in Flare plugin (by Clint Bellanger) * Fixed compile against Qt 5 (by Kenney Phillis) * Fixed resolving of symbolic links while loading map * Fixed a crash that could happen after trying to load a faulty map * Updated Portuguese, Dutch, German, Spanish, Russian, French, Japanese, Chinese, Brazilian Portuguese, Hebrew and Czech translations 0.8.1 (7 May 2012) * Added MacOS X Lion full screen support * Fixed crash that could happen when painting with a pasted stamp * Fixed zoom sensitivity for finer-resolution mouse wheels * Fixed issues when using quickstamps in combination with the fill tool * Fixed stamp tool not to miss tiles when drawing fast * Fixed automapping to work with external tilesets * Fixed crash in automapping when dealing with broken rule files * Fixed object type getting erased on pressing Enter * Changed the license of libtiled-java from LGPL to BSD * Updated Italian and Hebrew translations 0.8.0 (11 December 2011) * Added support for polygon and polyline objects * Added support for tile rotation * Added support for defining the color of custom object types * Added a Delete action to delete selected tiles or objects * Added random mode to the stamp brush * Added Flare export plugin * Added JSON plugin that supports both reading and writing * Added ability to rename tilesets * Added a mode in which the current layer is highlighted * Added support for specifying a tile drawing offset * Added a shortcut to copy the current tile position to clipboard (Alt+C) * Added a command line option to disable OpenGL * Allow custom properties on tilesets * Many automapping improvements * Improved tileset dock to handle a large amount of tilesets better * Made the 'Show Grid' option in the tileset view persistent * Raised the tile size limit in the New Tileset dialog from 999 to 9999 * Correctly handle changes in the width of a tileset image * Worked around a long standing crash bug * Added Russian translation * Updated the German, Japanese, Spanish, Chinese, Czech, Dutch, French and Brazilian Portuguese translations 0.7.1 (27 September 2011) * Select stamp tool when selecting tiles in tileset view * Enable anti-aliasing for OpenGL mode * Small improvement to the Lua export plugin (incompatible!) * Fixed a bug in the Create Object tool * Fixed reading of maps without tilesets but with a tile layer * Fixed position of tile objects to center on the mouse on insertion * Updated the Czech translation 0.7.0 (20 July 2011) * Added support for horizontal and vertical flipping of tiles * Added copy/paste support for objects * Added merge layer down action * Added Show or Hide all Other Layers action * Added actions to select the previous/next layer * Added Crop to Selection action * Added a Lua export plugin * Added Droidcraft plugin to read and export the map files * Added option to turn off grid in the tileset view * Added hand scrolling while holding the spacebar * Made the object context menu available in all object tools * Display tile coordinates also when using object tools * Various improvements to running external commands * Automapping stability and memory consumption improvements * Objects that fall outside of the map on resize are now removed * Fixed problems with watching tilesets multiple times * Fixed several issues related to restoring previously opened files * Updated Brazilian Portuguese, Chinese, German, Spanish, Japanese, Hebrew, Portuguese, Dutch and French translations 0.6.2 (2 May 2011) * Fixed object layers losing their color when resizing the map * Fixed the tabs in the Tilesets dock to use scroll buttons on MacOS X * Fixed window title to update when saving a map with a different name 0.6.1 (3 April 2011) * Added ability to open multiple files at once * Added Ctrl+PageUp/PageDown shortcuts to switch documents * Added an example to show how automatic mapping works * Fixed bugs, crashes and leaks in the automatic mapping feature * Fixed starting point for circles to be the click position * Fixed a memory leak when using lines or circles * Fixed layer opacity to be taken into account when saving as image * Fixed endless loop when tile size is set to 0 * Fixed crash when passing an empty string as command line parameter * Fixed problems with the tileset view after switching documents * Fixed tile objects to be removed when their tileset is removed 0.6.0 (26 January 2011) * Added support for opening multiple maps in one session * Added support for placing tiles as objects * Added automatic mapping feature, allowing placing of tiles based on rules * Added ability to save/restore up to 9 stamps with Ctrl+ * Added an object selection tool, allowing moving/deleting multiple objects * Added ability to run external commands * Added support for drawing lines and ellipses with the stamp brush * Added icons to distinguish tile layers from object layers * Added "Move To Layer" submenu to the context menu of objects * Added option to use hardware rendering based on OpenGL * Added a T-Engine4 map export plugin * Added a simple TMX viewer application (BSD licensed) * Added a New Layer dropdown menu to the layers dock * Added a checkbox that enables snap to grid permanently * Added an initial version of libtiled-java (LGPL licensed) * Added Chinese and Hebrew translations * Allowed dragging an image onto Tiled to add a tileset * Center the map when it is smaller than the map view * Remember the selected layer across restarts * Changed the default layer data format to use zlib rather than gzip * Store the tileset image width and height in the map file * Compile fixes related to linking zlib * Fixed the current stamp to get updated when switching tilesets * Fixed the maximum sizes of the resize map dialog * Fixed build issues when an older version of libtiled is installed * Fixed saving of property when clicking OK while editing on MacOS X * Allow Backspace to delete properties to make it easier on a MacBook * Associate tmx files with Tiled on MacOS X * Changed the license of libtiled from GPL to BSD * Updated Czech, Spanish, German, Brazilian Portuguese, Dutch and French translations 0.5.1 (2 September 2010) * Fixed saving of objects when tile width is different from tile height * Updated Czech translation 0.5.0 (30 June 2010) * Added support for import and export plugins * Added support for external tilesets * Added undo for adding tilesets and ability to remove tilesets * Added error handling to the New Tileset dialog * Added ability to change tileset order by dragging them around * Added option to draw the tile grid when saving as image * Added a context menu and tool buttons to the layer dock * Added Latvian translation * Added an install target to the Makefile * Open local files when they are dropped onto Tiled * Allow changing position and size of objects in the Object Properties dialog * Fixed rendering issues with tiles wider than the tile width of the map * Fixed eraser and fill tool working on invisible layers * Fixed a crash when using some tools when no map is loaded * Fixed compile errors related to detecting static builds * Fixed the Save dialog not suggesting any particular file extension * Updated Japanese, Dutch, German, Brazilian Portuguese, French, Portuguese and Spanish translations 0.4.1 (14 April 2010) * Added support for saving tile layer data as CSV * Added shift modifier to bucket fill tool for filling the selection * Added Brazilian Portugese, Japanese, French, Italian and Czech translations * Made values used in the New Map and New Tileset dialogs persistent * Fixed drawing selection highlight where brush is not painting * Fixed an incompatibility with Tiled Java in 'trans' attribute 0.4.0 (30 January 2010) * Added support for isometric maps * Added automatic reloading of tileset images when they change * Added Offset Map action that can shift a set of layers by a certain amount * Added a fill tool * Added ability to duplicate map objects * Added support for choosing the tile layer data format used when saving * Added mouse wheel zooming support to the tileset view * Added an object display color attribute to object groups * Added ability to edit tile properties through a context menu * Made writing out a DTD reference optional and disabled it by default * Made translations functional * Updated Dutch, Portuguese, Spanish and German translations 0.3.1 (22 November 2009) * Enabled undo command compression for stamp brush and eraser * Fixed reading of maps with non-binary-encoded layer data * Fixed a compile issue on Mac OS X related to QXmlStreamWriter * Fixed a crash when loading a map while holding Ctrl * Confirm overwrite on the right moment for 'Save as Image' dialog 0.3.0 (13 November 2009) * Added a tile selection tool * Added support for cut, copy and paste * Added current cursor position to the status bar * Added keyboard shortcuts to switch tools * Added scrolling the map view with middle mouse button * Snap objects to the grid when Ctrl is pressed 0.2.0 (1 October 2009) * Added support for zooming the map view * Added an eraser tool that allows you to erase tiles * Added ability to save a map as an image * Added support for masking tileset images based on a certain color * Added a slider to change the opacity of the current layer * Fixed the minimum row and column size in the tileset view * Fixed stamp creation when not dragging topleft to bottomright 0.1.0 (1 September 2009) tiled-0.14.2/README.md000066400000000000000000000056431260670167100141740ustar00rootroot00000000000000Tiled Map Editor - http://www.mapeditor.org/ About Tiled ------------------------------------------------------------------------------- Tiled is a general purpose tile map editor. It is meant to be used for editing maps of any tile-based game, be it an RPG, a platformer or a Breakout clone. Tiled is very flexible, for example there are no restrictions on map size, tile size or the number of layers or tiles. Also, it allows arbitrary properties to be set on the map, its layers, the tiles or on the objects. Its map format (TMX) is relatively easy to understand and allows a map to use multiple tilesets while also allowing each tileset to grow or shrink as necessary later. [![Build Status](http://img.shields.io/travis/bjorn/tiled.svg?style=plastic)](https://travis-ci.org/bjorn/tiled) [![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=52019)](https://www.bountysource.com/trackers/52019-tiled?utm_source=52019&utm_medium=shield&utm_campaign=TRACKER_BADGE) About the Qt Version ------------------------------------------------------------------------------- Tiled was originally written in Java. In 2008 the Qt version was started with the goal to replace the Java version with a faster, better looking and even easier to use map editor. Qt offered many opportunities to improve the performance and usability of the user interface, and has a more extensive feature set than the standard Java libraries. Compiling ------------------------------------------------------------------------------- Make sure the Qt (>= 5.1) development libraries are installed: * In Ubuntu/Debian: `apt-get install qt5-default qttools5-dev-tools zlib1g-dev` * In Fedora: `yum install qt-devel` * In Arch Linux: `pacman -S qt` * In Mac OS X with [Homebrew](http://brew.sh/): `brew install qt` Now you can compile by running: $ qmake (or qmake-qt5 on some systems) $ make To do a shadow build, you can run qmake from a different directory and refer it to tiled.pro, for example: $ mkdir build $ cd build $ qmake ../tiled.pro $ make You can now simply run Tiled using bin/tiled. Installing ------------------------------------------------------------------------------- For installing Tiled you can run `make install`. By default Tiled will install to `/usr/local`. You can change this prefix when running qmake, and/or you can change the install root when running make install, as follows: Use `/usr` instead of `/usr/local`: $ qmake -r PREFIX=/usr (Recursive needed when it's not the first time that you're running qmake, since this affects nested pro files) Install to some packaging directory: $ make install INSTALL_ROOT=/tmp/tiled-pkg By default, Tiled and its plugins are compiled with an Rpath so that they can find the shared libtiled library when running it straight after compile. When packaging for a distribution, this Rpath should generally be disabled by appending `RPATH=no` to the qmake command. tiled-0.14.2/appveyor.yml000066400000000000000000000037001260670167100152750ustar00rootroot00000000000000clone_depth: 200 environment: global: MINGW: C:\Qt\Tools\mingw492_32 matrix: - QTDIR: C:\Qt\5.5\mingw492_32 - QTDIR: C:\Qt\5.5\msvc2013_64 configuration: Release install: - choco install -y nsis - set PATH=%PATH%;%QTDIR%\bin;%MINGW%\bin;C:\Qt\Tools\QtCreator\bin build_script: - FOR /F "tokens=*" %%i in ('git describe') do SET COMMITNOW=%%i - if defined APPVEYOR_REPO_TAG_NAME set VERSION=%APPVEYOR_REPO_TAG_NAME:~1% - if defined APPVEYOR_REPO_TAG_NAME set BUILD_INFO_VERSION=%VERSION% - if defined APPVEYOR_REPO_TAG_NAME echo Building Tiled %VERSION%... (from %COMMITNOW%) - if not defined APPVEYOR_REPO_TAG_NAME set VERSION=%DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2% - if not defined APPVEYOR_REPO_TAG_NAME set BUILD_INFO_VERSION=%COMMITNOW% - if not defined APPVEYOR_REPO_TAG_NAME echo Building Tiled daily %VERSION%... (from %COMMITNOW%) - qbs setup-toolchains --detect - qbs config profiles.i686-w64-mingw32.cpp.archiverPath ar.exe - qbs config profiles.i686-w64-mingw32.cpp.nmPath nm.exe - qbs config profiles.i686-w64-mingw32.cpp.objcopyPath objcopy.exe - qbs config profiles.i686-w64-mingw32.cpp.stripPath strip.exe - qbs setup-qt %QTDIR%\bin\qmake.exe qt - qbs config defaultProfile qt - qbs install --all-products --install-root install-root release after_build: - cd qt-release - cd dist* - move tiled-*-setup.exe %APPVEYOR_BUILD_FOLDER% artifacts: - name: Installer path: 'tiled-*-setup.exe' deploy: - provider: GitHub release: Tiled $(VERSION) auth_token: secure: 57ahePdHlJPeOX8/MqsIg5ho4x512wvAbwRA7TkXAOav/JTHvkTG5gf8k37/883r artifact: /.*\.exe/ draft: true on: appveyor_repo_tag: true - provider: FTP protocol: sftp host: files.mapeditor.org username: bjorn password: secure: Hx5YfCOtpeBbftD4qnVCRLUGmMU9nogJTlSxq0xNbJQ= folder: public_html/files.mapeditor.org/public/daily on: branch: master appveyor_repo_tag: false tiled-0.14.2/dist/000077500000000000000000000000001260670167100136505ustar00rootroot00000000000000tiled-0.14.2/dist/make-dist-mac.rb000077500000000000000000000061541260670167100166220ustar00rootroot00000000000000#!/usr/bin/ruby # This script generates a mac release from an already compiled Tiled.app in # the bin folder. You should compile the release before running this: # tiled$ qmake -r -spec macx-g++ CONFIG+=release CONFIG+=x86_64 # tiled$ make # tiled$ ./dist/make-dist-mac.rb # Dependencies require 'tmpdir' # Get various directories baseDir = File.join File.dirname(__FILE__), '..' binDir = File.join baseDir, 'bin' binAppDir = File.join binDir, 'Tiled.app' raise "No application at #{binAppDir}" unless File.directory? binAppDir # Get the version from the info plist if ARGV[0] version = ARGV[0] else plistData = File.open(File.join(binAppDir, "Contents/Info.plist")).read version = plistData.match(/CFBundleVersion\<\/key>\s*\([\d\.]+)\<\/string\>/m)[1] end puts "Version is #{version}" # Create a temporary staging directory # This directory will serve as the content for the dmg file Dir.mktmpdir do |tempDir| # Copy things to temp directory puts "Copying files" ['LICENSE.GPL', 'LICENSE.BSD', 'AUTHORS', 'COPYING', 'NEWS', 'README.md'].each do |file| FileUtils.cp File.join(baseDir, file), tempDir end FileUtils.cp_r File.join(baseDir, 'examples'), tempDir FileUtils.cp_r binAppDir, tempDir FileUtils.cp File.join(binDir,'tmxrasterizer'), File.join(tempDir, 'Tiled.app/Contents/MacOS') FileUtils.ln_s '/Applications', File.join(tempDir, 'Applications') #Symlink to Applications for easy install FileUtils.cp File.join(baseDir, 'src/tiled/images/tmx-icon-mac.icns'), File.join(tempDir, 'Tiled.app/Contents/Resources') # Use macdeployqt to copy Qt frameworks to the app puts "Running macdeployqt" `#{ENV['HOME']}/Qt/5.5/clang_64/bin/macdeployqt "#{tempDir}/Tiled.app"` raise "macdeployqt error #{$?}" unless $? == 0 # Modify plugins to use Qt frameworks contained within the app bundle (is there some way to get macdeployqt to do this?) Dir["#{File.join tempDir, 'Tiled.app'}/**/*.dylib","#{File.join tempDir, 'Tiled.app'}/Contents/MacOS/tmxrasterizer"].each do |library| ["QtCore", "QtGui"].each do |qtlib| #find any qt dependencies within this library qtdependency = `otool -L "#{library}" | grep #{qtlib}`.split(' ')[0] next unless qtdependency #skip depedencies that are already using relative paths #macdeployqt seems to fix some of the plugins next if qtdependency.include? "@executable_path" #if we get here, this library has a dependency on a qtlib with a hard path on the build systems disk puts "Fixing library #{library} dependency on #{qtlib}" `install_name_tool -change "#{qtdependency}" "@executable_path/../Frameworks/#{qtlib}.framework/Versions/5/#{qtlib}" "#{library}"` raise "install_name_tool error #{$?}" unless $? == 0 end end # Create dmg from the temp directory dmgPath = File.join(baseDir, 'tiled-' + version + '.dmg') puts "Creating dmg at #{dmgPath}" `hdiutil create "#{dmgPath}" -srcfolder "#{tempDir}" -volname "Tiled #{version}"` raise "hdiutil error #{$?}" unless $? == 0 end puts "Done" tiled-0.14.2/dist/make-dist.sh000077500000000000000000000003201260670167100160600ustar00rootroot00000000000000#!/bin/bash if [ "$#" -eq "0" ]; then echo "Usage: make-dist.sh " exit 1 fi name="tiled-$1" git archive -v --prefix="$name/" HEAD | gzip > "$name.tar.gz" echo "Release ready as $name.tar.gz" tiled-0.14.2/dist/win/000077500000000000000000000000001260670167100144455ustar00rootroot00000000000000tiled-0.14.2/dist/win/FileAssociation.nsh000066400000000000000000000110461260670167100202350ustar00rootroot00000000000000/* _____________________________________________________________________________ File Association _____________________________________________________________________________ Based on code taken from http://nsis.sourceforge.net/File_Association Usage in script: 1. !include "FileAssociation.nsh" 2. [Section|Function] ${FileAssociationFunction} "Param1" "Param2" "..." $var [SectionEnd|FunctionEnd] FileAssociationFunction=[RegisterExtension|UnRegisterExtension] _____________________________________________________________________________ ${RegisterExtension} "[executable]" "[extension]" "[description]" "[executable]" ; executable which opens the file format ; "[extension]" ; extension, which represents the file format to open ; "[description]" ; description for the extension. This will be display in Windows Explorer. ; ${UnRegisterExtension} "[extension]" "[description]" "[extension]" ; extension, which represents the file format to open ; "[description]" ; description for the extension. This will be display in Windows Explorer. ; _____________________________________________________________________________ Macros _____________________________________________________________________________ Change log window verbosity (default: 3=no script) Example: !include "FileAssociation.nsh" !insertmacro RegisterExtension ${FileAssociation_VERBOSE} 4 # all verbosity !insertmacro UnRegisterExtension ${FileAssociation_VERBOSE} 3 # no script */ !ifndef FileAssociation_INCLUDED !define FileAssociation_INCLUDED !include Util.nsh !verbose push !verbose 3 !ifndef _FileAssociation_VERBOSE !define _FileAssociation_VERBOSE 3 !endif !verbose ${_FileAssociation_VERBOSE} !define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE` !verbose pop !macro FileAssociation_VERBOSE _VERBOSE !verbose push !verbose 3 !undef _FileAssociation_VERBOSE !define _FileAssociation_VERBOSE ${_VERBOSE} !verbose pop !macroend !macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION !verbose push !verbose ${_FileAssociation_VERBOSE} Push `${_DESCRIPTION}` Push `${_EXTENSION}` Push `${_EXECUTABLE}` ${CallArtificialFunction} RegisterExtension_ !verbose pop !macroend !macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION !verbose push !verbose ${_FileAssociation_VERBOSE} Push `${_EXTENSION}` Push `${_DESCRIPTION}` ${CallArtificialFunction} UnRegisterExtension_ !verbose pop !macroend !define RegisterExtension `!insertmacro RegisterExtensionCall` !define un.RegisterExtension `!insertmacro RegisterExtensionCall` !macro RegisterExtension !macroend !macro un.RegisterExtension !macroend !macro RegisterExtension_ !verbose push !verbose ${_FileAssociation_VERBOSE} Exch $R2 ;exe Exch Exch $R1 ;ext Exch Exch 2 Exch $R0 ;desc Exch 2 Push $0 Push $1 ReadRegStr $1 HKCR $R1 "" ; read current file association StrCmp "$1" "" NoBackup ; is it empty StrCmp "$1" "$R0" NoBackup ; is it our own WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value NoBackup: WriteRegStr HKCR $R1 "" "$R0" ; set our file association ReadRegStr $0 HKCR $R0 "" StrCmp $0 "" 0 Skip WriteRegStr HKCR "$R0" "" "$R0" WriteRegStr HKCR "$R0\shell" "" "open" WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0" Skip: WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"' WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0" WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"' Pop $1 Pop $0 Pop $R2 Pop $R1 Pop $R0 !verbose pop !macroend !define UnRegisterExtension `!insertmacro UnRegisterExtensionCall` !define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall` !macro UnRegisterExtension !macroend !macro un.UnRegisterExtension !macroend !macro UnRegisterExtension_ !verbose push !verbose ${_FileAssociation_VERBOSE} Exch $R1 ;desc Exch Exch $R0 ;ext Exch Push $0 Push $1 ReadRegStr $1 HKCR $R0 "" StrCmp $1 $R1 0 NoOwn ; only do this if we own it ReadRegStr $1 HKCR $R0 "backup_val" StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key DeleteRegKey HKCR $R0 Goto NoOwn Restore: WriteRegStr HKCR $R0 "" $1 DeleteRegValue HKCR $R0 "backup_val" DeleteRegKey HKCR $R1 ;Delete key with association name settings NoOwn: Pop $1 Pop $0 Pop $R1 Pop $R0 !verbose pop !macroend !endif # !FileAssociation_INCLUDEDtiled-0.14.2/dist/win/README.txt000066400000000000000000000043501260670167100161450ustar00rootroot00000000000000 How to create a Windows installer for Tiled =============================================================================== Prerequisites: * Qt is installed * MinGW is installed * NSIS is installed * Tiled executable in release mode has already been built Tiled's windows installer is created using NSIS. You thus need to install NSIS first if you want to build your custom windows installer for it. You can download the latest version of the installer from the NSIS project website located at http://nsis.sourceforge.net. Another requirement is that the project be already been built. The installer script is called "tiled.nsi" and is located in the dist/win directory. In order for the script to correctly produce binaries we do however need to modify the shell environment from which the script is run first. This is due to the fact that a successful compilation depends on some variables like the actual location of the Qt or MinGW installation path being correctly set. These values can not be automatically inferred by the installer script. Three mandatory variables "QTDIR", "MINGW" and "VERSION" need to be set to the correct paths of their respective packages. If VERSION is not set it will try to read the content of a file "version.txt" located in the root directory of tiled into that variable. The commands to set those may look like the following: set QTDIR="C:\Qt\4.8.6" set MINGW="C:\MinGW" set VERSION="0.12.0" Optionally you can also set the program architecture which is then used to deduce the resulting installer filename. It can either be 32 or 64 and defaults to 32: set ARCH="32" After setting the above variables to the correct values you can compile the NSIS installer script from the command line by executing the provided batch script "build_installer.bat". Make sure the nsis compiler is in PATH so it can be found by the command line interpreter. The resulting installer will be placed in the same directory where the nsis script was located and have a name similar to "setup-tiled--.exe", where is replaced with the value of the "VERSION" variable explained above and will - depending on the actual value of the "ARCH" variable - reflect the architecture (win32 or win64) for which the installer is built. tiled-0.14.2/dist/win/build-daily.bat000066400000000000000000000031201260670167100173300ustar00rootroot00000000000000@rem TILED DAILY BUILD SCRIPT @echo off rem The following assumes US date format! set VERSION=%DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2% set TILED_SOURCE_DIR=E:\Projects\tiled set TILED_BUILD_DIR=E:\Builds\tiled-daily-qt5 set QTDIR=E:\Qt\5.3\msvc2013_opengl set ARCH=32 set MAKE=E:\Qt\Tools\QtCreator\bin\jom.exe set GIT="C:\Program Files (x86)\Git\cmd\git.exe" set SCP="C:\Program Files (x86)\Git\bin\scp.exe" set DESTINATION=bjorn@files.mapeditor.org:public_html/files.mapeditor.org/public/daily/ echo Waiting a bit for the network to come up... ping -n 3 127.0.0.1 > nul pushd %TILED_SOURCE_DIR% %GIT% fetch %GIT% diff --quiet origin/master if %ERRORLEVEL% == 0 ( echo No change, nothing to do. popd goto done ) else if %ERRORLEVEL% == 1 ( %GIT% reset --hard origin/master ) popd FOR /F "tokens=*" %%i in ('%GIT% describe') do SET COMMITNOW=%%i echo Building Tiled daily %VERSION%... (from %COMMITNOW%) call %QTDIR%\bin\qtenv2.bat call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86 rem This allows the executable to run on Windows XP set LINK=/SUBSYSTEM:WINDOWS,5.01 mkdir %TILED_BUILD_DIR% pushd %TILED_BUILD_DIR% qmake.exe -r %TILED_SOURCE_DIR%\tiled.pro "CONFIG+=release" "QMAKE_CXXFLAGS+=-DBUILD_INFO_VERSION=%COMMITNOW%" %MAKE% popd echo Building Installer... pushd %TILED_SOURCE_DIR%\dist\win makensis.exe tiled-vs2013.nsi echo Uploading installer... %SCP% -B tiled-%VERSION%-win32-setup.exe %DESTINATION% popd :done echo Shutting down in 30 seconds... ping -n 31 127.0.0.1 > nul shutdown -s tiled-0.14.2/dist/win/dist.qbs000066400000000000000000000017661260670167100161310ustar00rootroot00000000000000import qbs import qbs.FileInfo NSISSetup { builtByDefault: false condition: qbs.toolchain.contains("mingw") || qbs.toolchain.contains("msvc") Depends { productTypes: ["application", "dynamiclibrary"] } type: base.concat(["installable"]) Depends { name: "cpp" } Depends { name: "Qt.core" } property int bits: { if (qbs.architecture === "x86_64") return 64; if (qbs.architecture === "x86") return 32; } targetName: "tiled-" + project.version + "-win" + bits + "-setup" nsis.defines: [ "QT_DIR=" + FileInfo.joinPaths(Qt.core.binPath, ".."), "MINGW_DIR=" + FileInfo.joinPaths(cpp.toolchainInstallPath, ".."), "V=" + project.version, "ARCH=" + bits, "ROOT_DIR=" + project.sourceDirectory, "BUILD_DIR=" + qbs.installRoot ] files: { if (qbs.toolchain.contains("mingw")) return ["tiled-mingw.nsi"] else return ["tiled-vs2013.nsi"] } } tiled-0.14.2/dist/win/gpl-2.0.rtf000066400000000000000000000400031260670167100162360ustar00rootroot00000000000000{\rtf1\ansi\ansicpg1250\deff0\deflang1033\deflangfe1060{\fonttbl{\f0\fswiss\fprq2\fcharset238 Verdana;}{\f1\fmodern\fprq1\fcharset238 Lucida Console;}} {\*\generator Msftedit 5.41.15.1507;}\viewkind4\uc1\pard\nowidctlpar\sb100\sa100\qc\lang1060\kerning36\b\f0\fs28 GNU General Public License\par \kerning0\b0\fs16 Version 2, June 1991\par \pard\nowidctlpar\f1\fs14\par Copyright (C) 1989, 1991 Free Software Foundation, Inc.\par 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\par \par Everyone is permitted to copy and distribute verbatim copies\par of this license document, but changing it is not allowed.\par \par \pard\keepn\nowidctlpar\sb100\sa100\qc\b\f0\fs20 Preamble\fs24\par \pard\nowidctlpar\fi142\sb100\sa100\b0\fs16 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. \par 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. \par 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. \par 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. \par 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. \par 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. \par 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. \par The precise terms and conditions for copying, distribution and modification follow. \par \pard\keepn\nowidctlpar\sb100\sa100\qc\b\fs20 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\par \pard\nowidctlpar\fi142\sb100\sa100\fs16 0.\b0 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". \par \pard\nowidctlpar\sb100\sa100 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. \par \pard\nowidctlpar\fi142\sb100\sa100\b 1.\b0 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. \par \pard\nowidctlpar\sb100\sa100 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. \par \pard\nowidctlpar\fi142\sb100\sa100\b 2.\b0 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: \par \pard\nowidctlpar\li284\sb100\sa100\b a)\b0 You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. \par \b b)\b0 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. \par \b c)\b0 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.) \par \pard\nowidctlpar\sb100\sa100 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. \par 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. \par 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. \par \pard\nowidctlpar\fi142\sb100\sa100\b 3.\b0 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: \v \v0\par \pard\nowidctlpar\li284\sb100\sa100\b a)\b0 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, \par \b b)\b0 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, \par \b c)\b0 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.) \par \pard\nowidctlpar\sb100\sa100 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. \par 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. \par \pard\nowidctlpar\fi142\sb100\sa100\b 4.\b0 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. \par \b 5.\b0 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. \par \b 6.\b0 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. \par \b 7.\b0 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. \par \pard\nowidctlpar\sb100\sa100 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. \par 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. \par This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. \par \pard\nowidctlpar\fi142\sb100\sa100\b 8.\b0 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. \par \b 9.\b0 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. \par \pard\nowidctlpar\sb100\sa100 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. \par \pard\nowidctlpar\fi142\sb100\sa100\b 10.\b0 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. \par \pard\nowidctlpar\sb100\sa100\qc\fs20 NO WARRANTY\par \pard\nowidctlpar\fi142\sb100\sa100\b\fs16 11.\b0 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. \par \b 12.\b0 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. \par \pard\keepn\nowidctlpar\sb100\sa100\qc\b END OF TERMS AND CONDITIONS\fs20\par } tiled-0.14.2/dist/win/headerimage.bmp000066400000000000000000001032621260670167100174040ustar00rootroot00000000000000BM6(9 |  PE/]ߗ7$nKR7J<'Ãэ. qMlIlIsMr5$khFĄ>pLmJmJmJmJlJnK1vok4#nKlImJmJmJmJmJnKnKfE"ؐsySH0nKlImJmJmJmJmJmJmJlInKlIJ1>E.[bEP7oLlIlJmJmJmJmJmJmJmJmJmJlInKfFb7'eZ[CZAoOnMmKmJmJmJnJmJmJmJmJmJmIlJmKmOrWSEUD*) X_WU;+*뤛飛뤛륛꣚頖鞒雍蘋斅擀}yvx|芀鉂臃烁肁rBAHHHmmm666.!!履짞咽﨟吏xё꣛颚꣛飙韕靑蚎痊疆撄撀}{}鋁錄ꊆ釄{zA10```===uuu((("咽륜lg6%#[?<{桗ꤚ颙蟕蜐蚍昉旆蔃蓂}~茀芃銄vrNMM---hhhNNNrrrF1.褐yTPmMH뤜꣛뤜栘|v [?;頖盐蚍瘉症蔃撁}{y{}}HCbbbccc TTT999SSSRKKbC@T;8f`즜뤛ꤛꢛ룜쥜ђbD@ um虋瘇畄擀zvst2дNNN___ppp222OOOWWWYJI`[2"!xr履륝뤜ꤚꢚgb-]>9瘈똆~wswaC:-ۮUUUJJJ===gggmmm HHH^^^tttiQM{u=+*Γ륜륝룚렗vmL2,>(#k[|UF`bLWWWFFF)))---MKKfaѕ/! 觠蘒꟔雎ꚈgA8 X\Iddd+++&&&cccFFF 2..yꨠ"列霍瘉֋y~js_/hМ###1#"Ж쟒€t 蔀yuploA442%З }}}EEEhffB-+vOKZ;7ꛌ藆~xsnjہdpW*~ivvvfff555ZSR]>;#wr획ꖆ摀ysnkjoqdOG485XXXbRQ_[㣜 ݛ횏ꕉ瑂|ustw{~|PO`HGccc777((([[[ooooVS{uup?-,얌ꑅ莀}~爀腀烀x=<]]] >>>!Ӗ픍됈ꍆ댆鉅膃ꆄrpD55SSS'&&so颛픎푌쎊ꊇ鈆ZY[[[AAA }x쎋6""ddd}}0Їfeecc nffF'%օ9tiled-0.14.2/dist/win/qt.conf000066400000000000000000000000661260670167100157420ustar00rootroot00000000000000[Paths] Plugins = plugins Translations = translations tiled-0.14.2/dist/win/tiled-mingw.nsi000066400000000000000000000244631260670167100174110ustar00rootroot00000000000000; NSIS installer script for Tiled ; --------------- Headers -------------- !include "MUI2.nsh" !include "FileAssociation.nsh" ; --------------- General -------------- CRCCheck force XPStyle on SetCompressor /FINAL /SOLID lzma !ifndef QT_DIR !define QT_DIR $%QTDIR% ; Qt Installation directory !endif !ifndef MINGW_DIR !define MINGW_DIR $%MINGW% ; MinGW Installation directory !endif !ifndef V !define V $%VERSION% ; Program version !endif !ifndef ARCH !define ARCH $%ARCH% ; Architecture 32 or 64 !endif !define P "Tiled" ; Program name !define P_NORM "tiled" ; Program name (normalized) !ifndef ROOT_DIR !define ROOT_DIR "..\.." ; Program root directory !endif !ifndef BUILD_DIR !define BUILD_DIR $%TILED_BUILD_DIR% ; Build dir !endif !define ADD_REMOVE "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tiled" !define PRODUCT_REG_KEY "Tiled Map Editor" InstallDir "$PROGRAMFILES\${P}" ; Default installation directory Name "${P}" ; Name displayed on installer OutFile "${P_NORM}-${V}-win${ARCH}-setup.exe" ; Resulting installer filename BrandingText /TRIMLEFT "${P_NORM}-${V}" RequestExecutionLevel admin ; ----------- Icon and Bitmap --------- ;!define MUI_ICON install.ico ; TODO: find suitable icon ;!define MUI_UNICON uninstall.ico ; TODO: find suitable icon !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP headerimage.bmp !define MUI_HEADERIMAGE_UNBITMAP headerimage.bmp !define MUI_HEADER_TRANSPARENT_TEXT ; ------------------------------------- !define MUI_ABORTWARNING ;------------- Language Selection Dialog Settings -------------- !define MUI_LANGDLL_REGISTRY_ROOT "HKCU" !define MUI_LANGDLL_REGISTRY_KEY "Software\${P}\${V}" !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" ;-------------- Install Pages ------------- !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE ${ROOT_DIR}\dist\win\gpl-2.0.rtf !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES ; These indented statements modify settings for MUI_PAGE_FINISH !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_FINISHPAGE_RUN "$INSTDIR\${P_NORM}.exe" !define MUI_FINISHPAGE_RUN_CHECKED !define MUI_FINISHPAGE_RUN_TEXT "Launch ${P}" !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt" !insertmacro MUI_PAGE_FINISH ;-------------- Uninstall Pages ------------- !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ; These indented statements modify settings for MUI_UNPAGE_FINISH !define MUI_UNFINISHPAGE_NOAUTOCLOSE !insertmacro MUI_UNPAGE_FINISH ;--------------- Languages --------------- !insertmacro MUI_LANGUAGE "English" !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "SpanishInternational" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Korean" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "NorwegianNynorsk" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Ukrainian" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Thai" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Macedonian" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Slovenian" !insertmacro MUI_LANGUAGE "Serbian" !insertmacro MUI_LANGUAGE "SerbianLatin" !insertmacro MUI_LANGUAGE "Arabic" !insertmacro MUI_LANGUAGE "Farsi" !insertmacro MUI_LANGUAGE "Hebrew" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Mongolian" !insertmacro MUI_LANGUAGE "Luxembourgish" !insertmacro MUI_LANGUAGE "Albanian" !insertmacro MUI_LANGUAGE "Breton" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Icelandic" !insertmacro MUI_LANGUAGE "Malay" !insertmacro MUI_LANGUAGE "Bosnian" !insertmacro MUI_LANGUAGE "Kurdish" !insertmacro MUI_LANGUAGE "Irish" !insertmacro MUI_LANGUAGE "Uzbek" !insertmacro MUI_LANGUAGE "Galician" !insertmacro MUI_LANGUAGE "Afrikaans" !insertmacro MUI_LANGUAGE "Catalan" !insertmacro MUI_LANGUAGE "Esperanto" ; ------------- Reserve Files --------------------- !insertmacro MUI_RESERVEFILE_LANGDLL ; ------------- Installer Functions --------------- Function .onInit !insertmacro MUI_LANGDLL_DISPLAY FunctionEnd Function checkAlreadyInstalled ; check for already installed instance ClearErrors ReadRegStr $R0 HKLM "SOFTWARE\${PRODUCT_REG_KEY}" "Version" StrCmp $R0 "" 0 +2 Return MessageBox MB_YESNO|MB_ICONQUESTION "${P} version $R0 seems \ to be installed on your system.$\nWould you like to \ uninstall that version first?" IDYES UnInstall Return UnInstall: ClearErrors ReadRegStr $R0 HKLM "${ADD_REMOVE}" "UninstallString" DetailPrint "Uninstalling previously installed version" ExecWait '$R0 _?=$INSTDIR' IfErrors OnError 0 Return OnError: MessageBox MB_OK|MB_ICONSTOP "Error while uninstalling \ previously installed version. Please uninstall it manually \ and start the installer again." Quit FunctionEnd ;-------------- Uninstaller Functions ------------- Function un.onInit !insertmacro MUI_UNGETLANGUAGE FunctionEnd ;-------------- Installer ------------------------- Section "" ; No components page, name is not important Call checkAlreadyInstalled SetOutPath $INSTDIR ; Set output path to the installation directory. WriteUninstaller $INSTDIR\uninstall.exe ; Location of the uninstaller File /oname=COPYING.txt ${ROOT_DIR}\COPYING File /oname=AUTHORS.txt ${ROOT_DIR}\AUTHORS File /oname=README.txt ${ROOT_DIR}\README.md File /oname=NEWS.txt ${ROOT_DIR}\NEWS File /oname=LICENSE.APACHE.txt ${ROOT_DIR}\LICENSE.APACHE File /oname=LICENSE.BSD.txt ${ROOT_DIR}\LICENSE.BSD File /oname=LICENSE.GPL.txt ${ROOT_DIR}\LICENSE.GPL File ${BUILD_DIR}\${P_NORM}.dll File ${BUILD_DIR}\${P_NORM}.exe File ${BUILD_DIR}\tmxviewer.exe File ${BUILD_DIR}\tmxrasterizer.exe File ${BUILD_DIR}\automappingconverter.exe File ${QT_DIR}\bin\Qt5Core.dll File ${QT_DIR}\bin\Qt5Gui.dll File ${QT_DIR}\bin\Qt5Widgets.dll File ${QT_DIR}\bin\Qt5OpenGL.dll File ${QT_DIR}\bin\icuin54.dll File ${QT_DIR}\bin\icuuc54.dll File ${QT_DIR}\bin\icudt54.dll File ${MINGW_DIR}\bin\libgcc_s_dw2-1.dll File ${MINGW_DIR}\bin\libstdc++-6.dll File ${MINGW_DIR}\bin\libwinpthread-1.dll File ${ROOT_DIR}\src\tiled\images\tiled-icon.ico File ${ROOT_DIR}\dist\win\qt.conf SetOutPath $INSTDIR\plugins\platforms File ${QT_DIR}\plugins\platforms\qwindows.dll SetOutPath $INSTDIR\plugins\imageformats File ${QT_DIR}\plugins\imageformats\qgif.dll File ${QT_DIR}\plugins\imageformats\qjpeg.dll File ${QT_DIR}\plugins\imageformats\qtiff.dll SetOutPath $INSTDIR\plugins\tiled File /r ${BUILD_DIR}\plugins\tiled\*.dll SetOutPath $INSTDIR\translations File ${BUILD_DIR}\translations\*.qm File ${QT_DIR}\translations\qt_cs.qm File ${QT_DIR}\translations\qt_de.qm File ${QT_DIR}\translations\qt_es.qm File ${QT_DIR}\translations\qt_fr.qm File ${QT_DIR}\translations\qt_he.qm File ${QT_DIR}\translations\qt_ja.qm File ${QT_DIR}\translations\qt_pt.qm File ${QT_DIR}\translations\qt_ru.qm File ${QT_DIR}\translations\qt_zh_CN.qm File ${QT_DIR}\translations\qt_zh_TW.qm SetOutPath $INSTDIR\examples File /r ${ROOT_DIR}\examples\*.* SetOutPath $INSTDIR\docs File /r ${ROOT_DIR}\docs\map.* SetOutPath $INSTDIR\util File /r /x .gitignore /x README /x README.txt ${ROOT_DIR}\util\*.* ; Shortcuts CreateDirectory "$SMPROGRAMS\${P}" CreateShortCut "$SMPROGRAMS\${P}\${P}.lnk" "$INSTDIR\${P_NORM}.exe" CreateShortCut "$SMPROGRAMS\${P}\uninstall.lnk" "$INSTDIR\uninstall.exe" ; File associations ${RegisterExtension} "$INSTDIR\${P_NORM}.exe" ".tmx" "Tiled.tmx" ; Add version number to Registry WriteRegStr HKLM "Software\${PRODUCT_REG_KEY}" "Version" "${V}" ; Add uninstall information to "Add/Remove Programs" WriteRegStr HKLM ${ADD_REMOVE} "DisplayName" "Tiled - Tiled Map Editor" WriteRegStr HKLM ${ADD_REMOVE} "DisplayIcon" "$INSTDIR\${P_NORM}-icon.ico" WriteRegStr HKLM ${ADD_REMOVE} "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr HKLM ${ADD_REMOVE} "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" WriteRegStr HKLM ${ADD_REMOVE} "Version" "${V}" SectionEnd ;------------ Uninstaller ------------- Section "uninstall" Delete $INSTDIR\COPYING.txt Delete $INSTDIR\AUTHORS.txt Delete $INSTDIR\README.txt Delete $INSTDIR\NEWS.txt Delete $INSTDIR\LICENSE.APACHE.txt Delete $INSTDIR\LICENSE.BSD.txt Delete $INSTDIR\LICENSE.GPL.txt Delete $INSTDIR\tiled.dll Delete $INSTDIR\tiled.exe Delete $INSTDIR\tmxviewer.exe Delete $INSTDIR\tmxrasterizer.exe Delete $INSTDIR\automappingconverter.exe Delete $INSTDIR\Qt5Core.dll Delete $INSTDIR\Qt5Gui.dll Delete $INSTDIR\Qt5Widgets.dll Delete $INSTDIR\Qt5OpenGL.dll Delete $INSTDIR\libEGL.dll Delete $INSTDIR\libGLESv2.dll Delete $INSTDIR\icuin54.dll Delete $INSTDIR\icuuc54.dll Delete $INSTDIR\icudt54.dll Delete $INSTDIR\libgcc_s_dw2-1.dll Delete $INSTDIR\libstdc++-6.dll Delete $INSTDIR\libwinpthread-1.dll Delete $INSTDIR\tiled-icon.ico Delete $INSTDIR\qt.conf Delete $INSTDIR\uninstall.exe RMDir /r $INSTDIR\plugins\platforms RMDir /r $INSTDIR\plugins\imageformats RMDir /r $INSTDIR\plugins\tiled RMDir $INSTDIR\plugins RMDir /r $INSTDIR\translations RMDir /r $INSTDIR\examples RMDir /r $INSTDIR\docs RMDir /r $INSTDIR\util RMDir $INSTDIR ; Removing shortcuts Delete "$SMPROGRAMS\${P}\${P}.lnk" Delete "$SMPROGRAMS\${P}\uninstall.lnk" RMDir "$SMPROGRAMS\${P}" ; Removing file associations ${UnRegisterExtension} ".tmx" "Tiled.tmx" ; Remove Procut Registry Entries DeleteRegKey HKLM "Software\${PRODUCT_REG_KEY}" ; Remove entry from "Add/Remove Programs" DeleteRegKey HKLM ${ADD_REMOVE} SectionEnd tiled-0.14.2/dist/win/tiled-vs2013.nsi000066400000000000000000000244621260670167100172250ustar00rootroot00000000000000; NSIS installer script for Tiled ; --------------- Headers -------------- !include "MUI2.nsh" !include "FileAssociation.nsh" ; --------------- General -------------- CRCCheck force XPStyle on SetCompressor /FINAL /SOLID lzma !ifndef QT_DIR !define QT_DIR $%QTDIR% ; Qt Installation directory !endif !ifndef V !define V $%VERSION% ; Program version !endif !ifndef ARCH !define ARCH $%ARCH% ; Architecture 32 or 64 !endif !define P "Tiled" ; Program name !define P_NORM "tiled" ; Program name (normalized) !ifndef ROOT_DIR !define ROOT_DIR "..\.." ; Program root directory !endif !ifndef BUILD_DIR !define BUILD_DIR $%TILED_BUILD_DIR% ; Build dir !endif !define ADD_REMOVE "Software\Microsoft\Windows\CurrentVersion\Uninstall\Tiled" !define PRODUCT_REG_KEY "Tiled Map Editor" !if ARCH == 32 !define SYSTEM_DIR "C:\windows\system32" InstallDir "$PROGRAMFILES\${P}" ; Default 32-bit installation directory !else !define SYSTEM_DIR "C:\windows\SysWOW64" InstallDir "$PROGRAMFILES64\${P}" ; Default 64-bit installation directory !endif Name "${P}" ; Name displayed on installer OutFile "${P_NORM}-${V}-win${ARCH}-setup.exe" ; Resulting installer filename BrandingText /TRIMLEFT "${P_NORM}-${V}" RequestExecutionLevel admin ; ----------- Icon and Bitmap --------- ;!define MUI_ICON install.ico ; TODO: find suitable icon ;!define MUI_UNICON uninstall.ico ; TODO: find suitable icon !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP headerimage.bmp !define MUI_HEADERIMAGE_UNBITMAP headerimage.bmp !define MUI_HEADER_TRANSPARENT_TEXT ; ------------------------------------- !define MUI_ABORTWARNING ;------------- Language Selection Dialog Settings -------------- !define MUI_LANGDLL_REGISTRY_ROOT "HKCU" !define MUI_LANGDLL_REGISTRY_KEY "Software\${P}\${V}" !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" ;-------------- Install Pages ------------- !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE ${ROOT_DIR}\dist\win\gpl-2.0.rtf !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES ; These indented statements modify settings for MUI_PAGE_FINISH !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_FINISHPAGE_RUN "$INSTDIR\${P_NORM}.exe" !define MUI_FINISHPAGE_RUN_CHECKED !define MUI_FINISHPAGE_RUN_TEXT "Launch ${P}" !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\README.txt" !insertmacro MUI_PAGE_FINISH ;-------------- Uninstall Pages ------------- !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ; These indented statements modify settings for MUI_UNPAGE_FINISH !define MUI_UNFINISHPAGE_NOAUTOCLOSE !insertmacro MUI_UNPAGE_FINISH ;--------------- Languages --------------- !insertmacro MUI_LANGUAGE "English" !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "SpanishInternational" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Korean" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "NorwegianNynorsk" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Ukrainian" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Thai" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Macedonian" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Slovenian" !insertmacro MUI_LANGUAGE "Serbian" !insertmacro MUI_LANGUAGE "SerbianLatin" !insertmacro MUI_LANGUAGE "Arabic" !insertmacro MUI_LANGUAGE "Farsi" !insertmacro MUI_LANGUAGE "Hebrew" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Mongolian" !insertmacro MUI_LANGUAGE "Luxembourgish" !insertmacro MUI_LANGUAGE "Albanian" !insertmacro MUI_LANGUAGE "Breton" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Icelandic" !insertmacro MUI_LANGUAGE "Malay" !insertmacro MUI_LANGUAGE "Bosnian" !insertmacro MUI_LANGUAGE "Kurdish" !insertmacro MUI_LANGUAGE "Irish" !insertmacro MUI_LANGUAGE "Uzbek" !insertmacro MUI_LANGUAGE "Galician" !insertmacro MUI_LANGUAGE "Afrikaans" !insertmacro MUI_LANGUAGE "Catalan" !insertmacro MUI_LANGUAGE "Esperanto" ; ------------- Reserve Files --------------------- !insertmacro MUI_RESERVEFILE_LANGDLL ; ------------- Installer Functions --------------- Function .onInit !insertmacro MUI_LANGDLL_DISPLAY FunctionEnd Function checkAlreadyInstalled ; check for already installed instance ClearErrors ReadRegStr $R0 HKLM "SOFTWARE\${PRODUCT_REG_KEY}" "Version" StrCmp $R0 "" 0 +2 Return MessageBox MB_YESNO|MB_ICONQUESTION "${P} version $R0 seems \ to be installed on your system.$\nWould you like to \ uninstall that version first?" IDYES UnInstall Return UnInstall: ClearErrors ReadRegStr $R0 HKLM "${ADD_REMOVE}" "UninstallString" DetailPrint "Uninstalling previously installed version" ExecWait '$R0 _?=$INSTDIR' IfErrors OnError 0 Return OnError: MessageBox MB_OK|MB_ICONSTOP "Error while uninstalling \ previously installed version. Please uninstall it manually \ and start the installer again." Quit FunctionEnd ;-------------- Uninstaller Functions ------------- Function un.onInit !insertmacro MUI_UNGETLANGUAGE FunctionEnd ;-------------- Installer ------------------------- Section "" ; No components page, name is not important Call checkAlreadyInstalled SetOutPath $INSTDIR ; Set output path to the installation directory. WriteUninstaller $INSTDIR\uninstall.exe ; Location of the uninstaller File /oname=COPYING.txt ${ROOT_DIR}\COPYING File /oname=AUTHORS.txt ${ROOT_DIR}\AUTHORS File /oname=README.txt ${ROOT_DIR}\README.md File /oname=NEWS.txt ${ROOT_DIR}\NEWS File /oname=LICENSE.APACHE.txt ${ROOT_DIR}\LICENSE.APACHE File /oname=LICENSE.BSD.txt ${ROOT_DIR}\LICENSE.BSD File /oname=LICENSE.GPL.txt ${ROOT_DIR}\LICENSE.GPL File ${BUILD_DIR}\${P_NORM}.dll File ${BUILD_DIR}\${P_NORM}.exe File ${BUILD_DIR}\tmxviewer.exe File ${BUILD_DIR}\tmxrasterizer.exe File ${BUILD_DIR}\automappingconverter.exe File ${QT_DIR}\bin\Qt5Core.dll File ${QT_DIR}\bin\Qt5Gui.dll File ${QT_DIR}\bin\Qt5Widgets.dll File ${QT_DIR}\bin\Qt5OpenGL.dll File ${QT_DIR}\bin\icuin54.dll File ${QT_DIR}\bin\icuuc54.dll File ${QT_DIR}\bin\icudt54.dll File ${SYSTEM_DIR}\MSVCP120.DLL File ${SYSTEM_DIR}\MSVCR120.DLL File ${ROOT_DIR}\src\tiled\images\tiled-icon.ico File ${ROOT_DIR}\dist\win\qt.conf SetOutPath $INSTDIR\plugins\platforms File ${QT_DIR}\plugins\platforms\qwindows.dll SetOutPath $INSTDIR\plugins\imageformats File ${QT_DIR}\plugins\imageformats\qgif.dll File ${QT_DIR}\plugins\imageformats\qjpeg.dll File ${QT_DIR}\plugins\imageformats\qtiff.dll SetOutPath $INSTDIR\plugins\tiled File /r ${BUILD_DIR}\plugins\tiled\*.dll SetOutPath $INSTDIR\translations File ${BUILD_DIR}\translations\*.qm File ${QT_DIR}\translations\qt_cs.qm File ${QT_DIR}\translations\qt_de.qm File ${QT_DIR}\translations\qt_es.qm File ${QT_DIR}\translations\qt_fr.qm File ${QT_DIR}\translations\qt_he.qm File ${QT_DIR}\translations\qt_ja.qm File ${QT_DIR}\translations\qt_pt.qm File ${QT_DIR}\translations\qt_ru.qm File ${QT_DIR}\translations\qt_zh_CN.qm File ${QT_DIR}\translations\qt_zh_TW.qm SetOutPath $INSTDIR\examples File /r ${ROOT_DIR}\examples\*.* SetOutPath $INSTDIR\docs File /r ${ROOT_DIR}\docs\map.* SetOutPath $INSTDIR\util File /r /x .gitignore /x README /x README.txt ${ROOT_DIR}\util\*.* ; Shortcuts CreateDirectory "$SMPROGRAMS\${P}" CreateShortCut "$SMPROGRAMS\${P}\${P}.lnk" "$INSTDIR\${P_NORM}.exe" CreateShortCut "$SMPROGRAMS\${P}\uninstall.lnk" "$INSTDIR\uninstall.exe" ; File associations ${RegisterExtension} "$INSTDIR\${P_NORM}.exe" ".tmx" "Tiled.tmx" ; Add version number to Registry WriteRegStr HKLM "Software\${PRODUCT_REG_KEY}" "Version" "${V}" ; Add uninstall information to "Add/Remove Programs" WriteRegStr HKLM ${ADD_REMOVE} "DisplayName" "Tiled - Tiled Map Editor" WriteRegStr HKLM ${ADD_REMOVE} "DisplayIcon" "$INSTDIR\${P_NORM}-icon.ico" WriteRegStr HKLM ${ADD_REMOVE} "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegStr HKLM ${ADD_REMOVE} "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" WriteRegStr HKLM ${ADD_REMOVE} "Version" "${V}" SectionEnd ;------------ Uninstaller ------------- Section "uninstall" Delete $INSTDIR\COPYING.txt Delete $INSTDIR\AUTHORS.txt Delete $INSTDIR\README.txt Delete $INSTDIR\NEWS.txt Delete $INSTDIR\LICENSE.APACHE.txt Delete $INSTDIR\LICENSE.BSD.txt Delete $INSTDIR\LICENSE.GPL.txt Delete $INSTDIR\tiled.dll Delete $INSTDIR\tiled.exe Delete $INSTDIR\tmxviewer.exe Delete $INSTDIR\tmxrasterizer.exe Delete $INSTDIR\automappingconverter.exe Delete $INSTDIR\Qt5Core.dll Delete $INSTDIR\Qt5Gui.dll Delete $INSTDIR\Qt5Widgets.dll Delete $INSTDIR\Qt5OpenGL.dll Delete $INSTDIR\libEGL.dll Delete $INSTDIR\libGLESv2.dll Delete $INSTDIR\icuin54.dll Delete $INSTDIR\icuuc54.dll Delete $INSTDIR\icudt54.dll Delete $INSTDIR\MSVCP120.DLL Delete $INSTDIR\MSVCR120.DLL Delete $INSTDIR\tiled-icon.ico Delete $INSTDIR\qt.conf Delete $INSTDIR\uninstall.exe RMDir /r $INSTDIR\plugins\platforms RMDir /r $INSTDIR\plugins\imageformats RMDir /r $INSTDIR\plugins\tiled RMDir $INSTDIR\plugins RMDir /r $INSTDIR\translations RMDir /r $INSTDIR\examples RMDir /r $INSTDIR\docs RMDir /r $INSTDIR\util RMDir $INSTDIR ; Removing shortcuts Delete "$SMPROGRAMS\${P}\${P}.lnk" Delete "$SMPROGRAMS\${P}\uninstall.lnk" RMDir "$SMPROGRAMS\${P}" ; Removing file associations ${UnRegisterExtension} ".tmx" "Tiled.tmx" ; Remove Procut Registry Entries DeleteRegKey HKLM "Software\${PRODUCT_REG_KEY}" ; Remove entry from "Add/Remove Programs" DeleteRegKey HKLM ${ADD_REMOVE} SectionEnd tiled-0.14.2/docs/000077500000000000000000000000001260670167100136355ustar00rootroot00000000000000tiled-0.14.2/docs/CNAME000066400000000000000000000000221260670167100143750ustar00rootroot00000000000000doc.mapeditor.org tiled-0.14.2/docs/css/000077500000000000000000000000001260670167100144255ustar00rootroot00000000000000tiled-0.14.2/docs/css/extra.css000066400000000000000000000003401260670167100162570ustar00rootroot00000000000000div.col-md-9 img { max-width: 100%; display: inline; padding: 4px; line-height: 1.428571429; background-color: #fff; border: 1px solid #ddd; border-radius: 4px; margin: 10px auto 10px auto; } tiled-0.14.2/docs/index.md000066400000000000000000000017431260670167100152730ustar00rootroot00000000000000# Tiled Documentation Welcome to the documentation pages for [Tiled](http://www.mapeditor.org), a flexible tile map editor! Here you will find the [Tiled User Manual](manual/index.md) and the [TMX Map Format](reference/tmx-map-format.md) reference. If you're not finding what you're looking for in these pages, please don't hesitate to ask questions on the [Tiled Forum](http://forum.mapeditor.org). *This documentation is currently work-in-progress. Initially the relevant pages from the wiki have been ported over, providing a limited amount of documentation for specific Tiled features. Over time, this should become the place to refer to for any details about using Tiled.* ## Index ### Tiled User Manual * [Using the Terrain Tool](manual/using-the-terrain-tool.md) * [Using Commands](manual/using-commands.md) ### Reference * [TMX Map Format](reference/tmx-map-format.md) * [TMX Changelog](reference/tmx-changelog.md) * [Libraries and Frameworks](reference/support-for-tmx-maps.md) tiled-0.14.2/docs/manual/000077500000000000000000000000001260670167100151125ustar00rootroot00000000000000tiled-0.14.2/docs/manual/images/000077500000000000000000000000001260670167100163575ustar00rootroot00000000000000tiled-0.14.2/docs/manual/images/terraintool/000077500000000000000000000000001260670167100207215ustar00rootroot00000000000000tiled-0.14.2/docs/manual/images/terraintool/01-newmap.png000066400000000000000000000410741260670167100231420ustar00rootroot00000000000000PNG  IHDRm!PS pHYs  tIME 00T IDATxw\G <:GoR"` HS, %`LbĆ]QG,`0 HJ/v?V/@,#@?xU:N2eWN8QQQ4u۷o;vl̘1ӧOOJJ:}kN:ն&++3g 2I\\v:::MMM {ӧO9RLLɓ'Gp8`j(""EZZڰarss"$$|rEE?!$$dժU!mmmǵB:$$$T[^^]]gjjJ'w޵mhhhWH```N -[c{˞={:bllXTTD FMLL>|Ң*,,]^^ARL&999:ӧO **ZRR-#֭r ?xcc##G^|͛kk넄0Y?KO\paΜ9|{!TUUwϩrrr 4l0ii㏶<Ν;&MB%&& NP(ӧ[ZZJJJKJJ644pBIKKdV_:dh<3ByСC镕?BPWWxVV֠A\&MDt.z?ݻnnn&F*++۷o_KKKXXLPEE\EE!T[[rp?p5rΝ?>?&^{{"A8pbR͛7,׃F|S^xMMMdd$knn쏐H$?1~sss333Bz l۶MDDdŠ#KGpOII?~*bl2uT}}}ss󚚚첲2߾}"**J̆ <Зt7o޴M|!CO~b_PGN:5~x2|޽gς@ .~Dlmm>L&.]{h>"C+#@/vA;=HBBB|#@G#Οq0Ϗ_t@Gt@G@GtzۏO %'N #_J\ᦦ&?#_N>vBC---t:HYPUs5ҥDbա8Y9![ u,XXWWf~#'Ohwinn8Z66/oKHp1322z!?JINZf^ h^^w3ǷrExxEe'=p8l6;̼DDD466qŚ5222` Gy >>>jkkk*)GUV#4! DJqq X"fxxWmݶ3ǎ?-******BψC,k\CqItCHƦ?YTT*a\6ʕ+!W0A)**۷ BBnj),, cYFF2 TW7ݻd2yɱ11`ՐlmmP\\ppiہ8Xq wٳUU @G@Gt@GAP x8CS="Tj#])..̨zRRF&FBBB#='R\\2qSB@=ͭ71$S:A@G efd㨥 tty<<-*CLDY jjk4)v}C͆qM/B$+u|8vHJJ:4>>S9/_+7QSS^SS#7nޜ8qe?onhX֭d٪3fxtgswsW^3fezzz~~ŋ,YaÆv[N࿈HsssAAAHI㡡+tǖQ۶o/,,DۏXnիI+W ;cL"?Ɇ&OvpTЙgMLLja1f'''qtbji)//o7`UUU- X\vKDl|b~7ðٳg]V]]N{{{DFF8>dȐp##}͟?XWWWWW޽{Nvޭ.''7o<C$>yANNNGGgӦM\.H9N4h^^^`0TUU̙;"}Ȑ!NNN 255z-kkk999%%iӦ|S |qMuuàA^x %%%wwv8FGrrr O&8e2wK.۷75塻`ݸ~gfaʕ+{{Ο!4y$/O?~q0UHhsԦ쬗RS9npHhK3ǷQjʃ**,X_նDPyy [#+++??[0q̙d2֭[ٳg={pݻw3l^LMM~ѣGB޽svvvtt,..>bbbYtuu]paEEŮ]/tƌϞ=KOO/++={6Յ 9?BBB111%%%ϟ?p8/k~ETTСC8''.kV{RQW< PUUE,zy{)**ڰ$11tyyyʕ+e!BYdeB΋WVV& 0 ,,ͽ?x0#4Bh?///'n*;-r1bii)q|rrD8?3ٸqJUWWsqqIMM9sƹs礥HHGG{ٲ{ɒΝUSS0ٳϞ=߾}%!!dnnQXX9>22{Xg__"++KGI\ɉ<ݏ (r@"~ B^*O/+--WQQ!+'K,(+0D"M<"&&V^^Nc-111PCCC[,0f"Hqq1J%"455DBGv0ߍE+ 2+//%)++c\'Dxqq aT5440 +**VWWoF쭰J2 bB !:N:997ðfp];USS;pJ0ٳ<o=B|9Qj z0#!XΝs3ҏ?F "f`0\nIɇyyyDbg}@WWW]]cԄS<a*D" n%UUF~~>?۷ q傂B~zAA>qEEE!CQp|l]]GR_|qT_~%ϏH͛9%::!!!,,<((P]](cǎ]tYqq11|]߾xkkEEE\oT6>X[ZzڵGj;h͚ϳqqq"7c˗/ VSU%2 WTT~c >v8p 7vluuulL,%˘Y8w(fff!6P]lVyʕcƌQTPh[~qz""6_vB8¯L 4wǏ47jq̙ӏim󃑑{6EF}vݿ>PcH7ntiS)d&Sfؾ}Nc'Ndhhl{8p`?L::]_븆eee[8c?'gϥ:LWOׯm"X#ሟdfGbΝ;{)S===.Z:=!UUS !=xB<|0KYY=ۭ[G=ՍhL~ͿEK.ݾ}bg/'Ҥ>m3ob%aw߰a[ #=LI0>>=22$Ri(5塕ҧ[aG"'3AGz*U}@ e@=3)iii!D@Gz:T6J 2L4W6^ E*! ma&t@Gt@G@Gt@Gtt@G ':zJVN^VN!7we:}@{ 7FFCBBĉ&wuuLMdr=MaV?QEEEͅED:Ю3|c܉A߿?vxUĉ`BYYYt:]SS!vZRWu{u\Cӫ;:xPKK Nmnnvss704RVa0TFt)Xu(.NVN~hC#-m յ-m^̙:zJ*&VUU׸ ?ݿ@CBCjkk]3_K~-I__!dooG,嗎G^cl2h[n={7J>P¾ܶ7ٗ|7!OkG9Ceddܽ{wȑ`CqFF۶nCs_v7 2T.Y"))vo"#B_ؿ8UU5k~I ͣP(o\U[[X[GWIYE}F^~>B%BCc R\ܺr &k0Kڽ˛0qRUU… V#JKKy<Bhzz&ZZZB`BaQ!Bzzzz;w"rs[jw,]:E[GwÆ0ڵ H=ˋgrss=w YYભ۶>sFWW_wIKIϟ_TTdWTTTTT(((df>#R VҜMQס6)..8qRYYܰ~=hCPx<޺u?\.O[[CPUUEk=$H?c)SVFD.[U?co|UwPƍ^^& kHƦ?YTT*a\6o5A%ZZZ""!yyVyf̜YXX(...,"2"!̙3߻wԩSݼuw=?wŋؤ]_=1wpɓ'AA ^AIJJ )--bLӧO>}ZE_Gۦ 4,liFFϞ?0P]޼X2"E]MFFG۷D"1'*{u-ii^M111v*3gkkkŭVSSSL[.03fI@gA%]8'₃C454?Nގx JG|f~WU t@G@GA&@l6oH$D"QVKU Ƽ/1?gA&z<wx&MQQa<~2p87n\FVSSgX%p8GR\&KKKѣqP)z< OMIaj逎 nyV*++"ߓ$~dJ_>1ӧO ^|)HP}%#8O3ףG~?ۥ`^#,KVN۷mWYZY_xmzmmmo:~x"؝;wͻ֭0Onjq3勗|Q?]Zkud}}bKK ͛T*u(YYvuuC gϞuwwQWWo666ƍKOOgddhjjZ[['$$gcc#(,,,X¢; ĠxѢEE/_2wORe2|0aٳۍd-޵:bg7zll(TQFDDJQHHի333<==kjjBuuu^^^vvvO?R\\\p6ZNN_ p{ڶÇ>}zueee~̦__ߛ7o^|Bxzzȍo}}}EEEKx<Ç&'kY vbl+MbbcyAC-,)?WUS8irii&ȑ#܈(Ǐ=zرAAA—.]B%&&`tȑVN6 !4e={kZu[֬Yciiidd4k,~ԎXYY뛚[% %--2`"=((UUUu!!!eeeMJJٴiӄ VZfZ~!y)xCÑ/^ ҍ)3D `>lCϲe |}}1 ͍JIIqwwn}/^433ѹvѣGfHKKSRRj*??N?S' IDAT>)))''gǎD߿yŊrrr6^wsh7l np!!aÆ޿Dnliر׭c0~ZW/OMQb/[tҥ]q,=mii醆"FӥaW\IKK#~:t(;;[BBLEEEfffUgO̤nӑ^VVVEEE7n <~ȝ;w\EEEp G-_<--ݽn tŻ\GWTTdgg'߻3{6B69B57Ҫ?VVVdj ⣢!qJw)4X[[K,F ʗSPP@"<<<)bbb#Fؽ{CBCC-[6jԨ8aiiiƹ^ ۷o}ꕎ?vttԌ\SPPx L&ݑnxҺ~FZZځnd ~H$%%/Gqw}033a 144LLL0dffaԟPsεOfO<3"vr[Q1"&ܹhѢOBQBB!'//OV\9k֬}uְ-ZL&1;ebbRYYyŶ#aݻltEEŪ*b1}<bq8⿀yƍ[n577ڵb3\.766׮]nO111}AL<Q[[{%.beeeI$.7Ώ:0lΝ^yhhL˗ϟcooOʧZr,$66t0, .**j…Cu#ݢ#v ں޾m`]]ݑ#ǎ+--e2D I&fJ8.+Hɓ'Lc2L&!++UV&%%ao޼ihhrʨ(kk붻 200 %66dN2EWW͛$bEGG߿_LLkXϹ_K]"##cڴi&&&>>>ZZZqqq$ !k׮GXmVVVNNNAAA(ŋI1uŻ5o1Cm EG͝!4c'N+W#,(o:%֯_þgq~|_QE,1߾cSyDI‰N~jF;`dh?& \}_DPl۫p򄑡!?52pvvAxdE|}WG&ЕNy%VVVee1 8}%]ĠM(..njfF HLMMqtvY#}%~ BJK{;?/gNPtYK++M&tDwZikkۯbfADKtAGkt@Gp!l6oH$D"QTQQQ]aqؘʊwt}* !4`} ]=þQ?qb#,+/+'L{xؑ!}yu5:<4]Xy(m~/9:JaxjJ SKtODw[ϳVQ^Pe]A8>=--̀>oq_x<L'ƿy˗/)*g.Xcy{ɘ1c^~=z/_qc[:"S\rbh66?;wͻ֭0Onjq3勗|mO\Zudi+#"StJn6ԗ(+'_PP_|Ywww"F O7n\zz:?=##ESSښ۶b -X¢; }ChѢ耀E"˗/  {K2L ?L0A__x'>vB 07߾zQHHի333<== Luuu^^^Dxڟ~),,,%%峥vh991 … %Vs ;;Ç?}>>>DzAA͛7/_LP<=={—nYGghnnnՉe١azzF&111V/^o~A#c@.0qBb_E>|ȑ#Tۄ/=zرc%%%/]JLL$4ȑ#%BM2fϞ=V5kXZZ͚5Ñ8`eeojjnݺ׹Đ!CUTTTTT0 WWWUUՁ6))fӦM&LpppXjF%''~!e˖%&&b7ŋttt]vѶ䔔ڮϧϟOJJ!*777XBNN.886kx-.SuuuF9 /_RW#DEE#V6csT'O͚ի^OT*F;ɓ'3gh[f+z4ѾFӥaW\IKK#Bχ:t(;;[BBLEEEfffUgO̤ԋVVVEEE7n <~ȝ;w\TTϏyBBB˗/OKKsww~zgE>~wL:%,4al_P^Qai!.ad2qr555bQDDDAAyy~NI "vB؇FUUU H$~Xyy#v}СP}}e˖5+.N>iGyZZ5<}ot QQQQQQ۷ھzJGGXFGG;::~jƍ_1JGPd_`` qH[;tDBBBEE($,LQSSUWWp^uI$baa!1`Xyo] 333.so  Geff~CU:w\l6ɓϞ=NnKsDv bD wYhQLĻD!TYY(!!˓'FUUU+W5k־}\]]:kX#ƍkhhЀxQQѵ[>m?6| <111F]9ůcXT{zz޸q֭[ͻvbXČ)ˍmnn}k׼ۭX Spp0q!tMNNfX²$?GzK`sW^?<44̌x&Ϗ'\S-~zURRKLc`ggpB^:?=uF]p>;;{&SktVyBCC,"/'`w۵k,^!twnUN>^FFy󦡡ʕ+6"""((fkX&9e]]]GGǛ7oH$mjjjhh~11~b~MuiӦhiiőH$Ю]|||yiWuuu+++'''KKˠ PLLLyyyTTBhĤIg)VKK u ##N:egLPF}mQs-hjjDM1}ĉryÇ?S}YPp]mm/:^IIIׯi^2''ښb^FK[@_E-X4š3<~;v>u?.+,ufXJ <ҙ>VX[W?VhS FӁ==]G Fݻ]ZBT޷oo724^Is ^[߶xLVTPWwuaNcmm!BJb=}%]ĠM(..njfF H]YLMMqtv!m_pxo_EP)Էyywo g) .kiedvbzp`^saut\?aJJlNa޳~q,O/o{(/+733t£uuT!jʪ]/,}r @GBZSCCFFFCSSRR5u;oǏ"28qrXt iǏ*.. hsHK_MJ,fۏطo?B7nm_R ++%())}o̙aarVV'N8qDRM6oܑFt 1頞 6?0'M6dbbaL-#cÇk8?acL6NK{lhh@211&cXYY:ڢDqvVysNNNlN j(((joMMM&gw1o۷6o|psss7o={F~:TCC" /UUUuv?A5 7GEm !~))6@ a׼ys;`~{/(~^hm`.{B^TB«ᶶKGݗ_P]]}⥓ ."?~=+6&‚b5bi^~]^^/̘1!dn>DYYy۶mq8;9*(!!!#=]6-ZKQ bn5&Ou۶Ǐ?A0&'N`P\\2rg;IOOqUKEDDddd(555yiKKx)'#,!%%6C[8pL2%*j5;;{235۶YYY RTT4bxbbϏFgqV?CS[˖]v]JJ*$$gV{(.[RRRW^UQQٺ5!q}gϝ lmmwkAA^޳233I$Ntt4/w;Cqqwލ;tW:гG]g3{vI#::#:##:@ca<`L D&nz B )Q :|3\$33?Pr+eU.,D^FL` Δ q)..NMI8FnxӾ{֍b*UOM=\_SB!>S|zMTVFefd㨥WHHHGWR2[5سY.jlB<7 Y6u4~=5[^v̳s8VS[կZ[G1 l.^YӨLuU+k_ZCP$Ry<Q2+4 wяÂzzr5CUMFf[غ%*??xۤc㴴7jkv]}0 q =z`" as}uiiӔ)S t:ѣG)))GE׏5JCCŋeee6mRG611y'OW\-'; c`id2۷ņzc\5@kx<.-KTTkjjr8<Х<cg2x<ܹ~[H:rԙ3g9sL&GFn$8 j:~JXY}֭Dݢ;A8NvYYBH^AU eUT-**u5áb#p ee劋Kݶa͚wijjP(MaN{ð#{@8a.jt:BHQII@xtq\C$0h\.g{.]s$sGa3''uu5}H׿yƍ벲!UUp h?,ox<2?|ԪܖԵq^UUU;pr` ~3g0oH#NP8o^WGF8a9mڴC-&Lpę3=qQWW88p?+G q|xzz4~K}}M1 +,,zj۝t<+.HhcԖG~߾usIqQMӧNDYll!|ǣ"sۮ"ڞ7M |ԩ؝V˗211Yp!aa/.!.n;VUUp~q$%$/]\j .kldpRRRr⥵?2dHcc2sL'GGbsfC5eШc'yvp8zGNAB8ۣ'Nhh 2dkkKpA6p6կC]ܤeJ,bpsR5{oMv1Q8:y~Ox7IDAT_"vFNSUUB=[P }9o[UYщ XM^I}! 2@&S!x͡R(~5rzRtLI3TUQ !yBJK*QK- !5'@GQj3`} 㕗UAAk׮}g0\p8=e988ݽ{… ӦMKHH| oݺM!,, !saйs޽{:vo!#F477WTT9r[nE-Y!tʕ7oB-q`ֻ|||O҆neeój*gϞ544!8wt@!H$vxRǗݻwoРAZZZ|||E~葽HFFFuuuQQoaŊ YbrPUd2|htt9s,--KJJTjM 줏?~⅑/BjݝE@?ԠKBy lѣGƍ311WUU!***0/:ёd>z!aZ:;):pqGlɁ1k׮pC>~(//omm]VV6xC}w _Cogii=zR7}1@  44AףAq;8L6`~ @  44 @@  4ohPAA,ׂR`ezzPTTɘдڍ6lذaxReӧϐ \5G544ljjBb 44o%@i W.'JH@PBVΛ7TIYΝXxQq354e)Z.BL&ĉV֊C B#,G&&%!N<)!) HGQQh7bMLrssN  hffƦ&P`5k?.RUU=ᅮ\'Sݔ tutΝ;P_{:uJh޵!a߿c6Q!qq1-m-g؎?ڸq9sMgff&''/[Iꓒff۶Ahз)-+Eeghh]!B(h%K?RQQt`X,ТEyݨQ4 H!mm[pY,6Btxڳ>|ŋN_@ XM6bLB@$b}s9}LNΛ3gU~bk;j''||UUBRRR3fL?w.رnnnhAhhA?N">|8pD"4B>|| -#=|P Sh8) `^MX,fA~DQ555} ӧ': 7dtB|*Ѡ;&a?}$ V?x}·GXsÇ8~][իfΜU^^ѣǚ~'O\YYYXXZ|yqqqlllFF'͎LOOAnnnLL.B˗/nnnZZZO>s۷oCCC$,,i& cǎ-Aɮ hH"Ǝ+((˻z/_cxyyjhdhj:ܜoY99t:!tрm<4|I\\CSSӞ={8Nyy۷;<46Aʼjkk݀QlǍ_QQA"~(5o BUVVsPƤO<ǘqaۧ:e 1cܾ}UVVjkk޽!$,,?rH--Yftx:__߄--ֽ<P [*@+ص.1i I}jPSߣ{ ܾ)))# l6GRclby oa29ٯDEz$́=i>>>abb/?߄@ HHHNuIm,l6F/h5l:S45hY 44 ނE? bX?DbI@ :N9ºCir8H,(/x*뇱7"":z:C(,_Ԣԇ?U}@ HH75:ԠכY,VyyT1ʪjc Nm6C& = Wh4ZqqqB|yyho@G,Ͽ(""~:+~9~ Y]c =yL")?}xpShl@g QRNZ^8v]} ~ҒK"\\\GAz IK.+fΜU__~h)))cTjs:FCSSGW/,,<&vÇNd5c'{ 6fff~JJJϟodd܌YC``>B133vaÆm۶YXX,\!doo)S=:???**ԔBau\]]m:thٝ]/455]\\ZJ_TGGã ?y򤙙BߴiSlhhPPP8~#/^xM a;i_2 ...!!!b ccc ++i``@P&Mغ/%;993MLKK3f Bqqqٷo_=S{{M6M6mܸqcǎMKKj.]joooaaq_Ξ=kffdɒe˖=<O ޿_SSpVX1mڴ3f]|VRRR]]=44dr8 .p8/_ ͝;Kvvp8w166Ž666._L&KKKO8x p-::ztfFz((g~g.jgм7Os۷oCCCB<͍'''kjjJKKoڴB?~رcK.mܸ1''GGGgܹIII7oތILLD9|wa;rn֬Y999[l9uˋccc322<==mKxɍ7>}1}t''Ǐ?~LIIxtttBBB~~޽{aÆ%&&nڴ)00ɓ'+**>xAAA?*))=f̘_X,Vtt4L|߱cO@@@QQQ^^Hp8^jll4000/w:+~~~/////… #""e"..Gemmc 녅D@̛7!$ 0rt 3f ZZZ3g:ݱ%+++x,F__!\|O0e`лa hkk+(( <ٳǏc2 f[[[c1]&**br-_ɓ ݻ =))q̙YY>f0輼99Et8A/..vZXb8Z.۷]_wzr5HVV 655!Co5`ٍ4:Ǐf --nMN=_OEEEUUfx(+/G***q8WGÇ:u* B,_ήlÒAq}ii骪*E =zϟ? Pii-PLL_[[$HmZl[\\u}ulٜ l)Daa斛7]\&=|@UUq \VVf-,FTVV߽{o߾}eeo߮"GFFNSS311y-_Í7TTThkk)?͓^`1G(p8RF>}-SEEοvttrrr\϶ -ZhQ}}͛W\3III t݄:뎽}6,,L^^~͚5W:۷oswɵk?Hrttttt_&Hf} wf@ /PUUJBKIIGFFFb:5|i)**^t qwC`i޾k3hTYYu!$)))**ٵkwllܒ%~qqN")pw8ITTTiiAyyٹsjjjgϞE>s4yI'&ޒls\+) ???.^U0y⹼6ǧ=xI531އf}cCCY(:]|*l:ޡ!D%%6Q__7DYTTPVV+~A? 6b Mȣ@¦ qx"@ w@$ 'jPh@/ct:Nop8D~~~(R ^P uԦLJPHHD" ҠAwhuuEEC $UU)+aq I ߆`TTʲX,݀@ !F(Ƥ-6 *)%_RDGx8Od<8 !!$|,4+B}%  #. AA]@zTDDE??% Р_ NJO}xxg!@zLEE嗫AA^<{dmdn\vs -PfϞZ~皚OE}+110pMF??WLBD"gW2I:\f)hoRSjd5ˑVu-F(ڍ~n+W?kllbllBӃ͟`H[ ,?DIҥK%$N81|d*ǎ742RQ%kR֭_ύcmlFOobP 62 nÇ36^]]YF{z.ZkmmcllrB%%+V'O亨x*y񍍍UjÆwؾcYM}7opM>sڵhI ,nJR ]8H$}v'N=z̙3ZZ[n͜9 Mvuly3ztpldMbbݻ?C[Ggvٳ<<<~Klٺ? 7nڔ|/_0)HK{~#&H$n y3>!$--}e%oN1S^^{!qjꭄآ.Ǐ,# b mlGRQQak?Ok_PMMM':;;Ox=d˗/BD"p2DвK=K+,,D8(+p8uuuSRR-]]U d2uMDp7DED-[KP->w./\zJ2˻&0!u6%/, l4?zD"lA!"6oڤ2k, EkjF44t9y7"''zCFo`hR6BJJCN8~]=GVk` Dg}C}ý]*qet q_uUYYCpޱRVV)//o_|ARAQQMug؋7;DR/PRRzwNIY!$..c۷̟o`Iaㆍ'NnNnSD:t8UuuuЬǎ;vX~9s7 HEY!TUUER?=ܹx#G^2p8dLq2Db6:B=Vޗ733EXRn%ԟ1czDddbRҗ/_***hhh 32B(++C cY`m۲8NKKÇKJ޷ISFF]g͎ʺ~WXXXx}+)!C@ `v]UUĄL&Sl6[OWԜ ,HLUWWu( cӦMMML&gNNuuNsZ@@Lw>vjO:nׯ"))!,,{P}, Iqc $EyyБ#G+()[8rh1&!445%$N8uAQQh7bMLrssN  hffƦ&h<@2q7 7<0p@635[lٜ9s***q Bqj*BGϟ1CZZZ[[Ó65598_Ϟ!.^~ґ#Gt){#Mu5Bkbڭ[g̘O6{ iׂ 233CBj-[PCCƨ:Ka9 uub_{:uJh޵!a߿c6Q!qq1-m-g !ht: 6zHSS3//Ǚ!k+8TO3GnrY۔)GFqp|EcZ RQQ_EЊ=ztF,{1B@RSS[tAh 7}}]z!wǃGiY)B(;;GCSUw!v풥KχGD\H&=ۂ!>^^QQZ,p fYQQfOBJJCTn{ffe!ll;;!,"R+BZ_]'--J$**`0˹---555!)IocKK-C,].guֺz2wgO_ʺzaÊN> Yn܈xBɑ1VBBž={9x .6 !8쨵5Bh޿9Έ#-ܹdݩ rpVmA!fgt_^^^kkPddTQq1kn3f7{oqqѽ{wCmc0a566v s>}&'͙gt?WxRB5Ǔd>^O!)))h3@p]eee؃em:bvK3r<|Qg抋kiQ,Gz=rrr?tIg?},22!++۶m}皑# ?UUa:s<mlIOϰ\W[go?MB9?'-#K$ڱbIJJHJ_;ufii-ɀ| B՝;w.o/^sN?ż|WZjj1tͺ!G70lُζl٢YUU'IPՠ27nܸݱKDDR6VVVgΜIOOOLLu]{zz޾};..@ ̜9&q))ɳg]~۟4#N~B('͖[z)N_hџ8kk5+x<@ YJ 204RSט>}Fii[WFJZ! I)lM^&6)=wh0UE--X$WDggcc>y2r$Iq$>|SRR' ȈL&ˋa+W0aDRRR/--՚ P[[ې:]By-ByԨQ;w1s~7!B YӧO> FXX`N9sZvEQ( קwr7l3~x;;sa;wkiiAkjj1i~EIr_kkk{xi$''#OVUUŶ_x ZG~AHȺC*|[`kg{,_111n:|iiiGGG'$$ݻ<==׮]+))zſ7 p #ڵ7|ө䚢@NN&&&z{{ƆٳUV577{{{/XʪW QV: Z{ĉ7orut[G2mڴAk׮Y$''[ZZOR/\8 [mʔSNuqkU(g͜};|ٲ˖|ƌcffVVVu+V\xьm۶߿c{yya] Y3ִ4gg窪 ,ըw4YwyyyQ?Ncc#BZf"""X` BrrrСC+Wr}CT=s<" vddimmmQQф wdWW6 WT88oa\..//m a {챴,((PWW={sΝ+&&FtUU"x<~޼y^^^+Vi9l7kiif˖.ݹkׄ R7ԧ444tL파 n-O0ɓQQQ=ukЇ4HDBJvTܼ̈DM\\܋/&{ӧ ~lc {޽ŋuxUUJBKIIPuuuPP'LSxKs?>>>!>.v{v"&&&+++###PaaassvC+GFDD rW H$''e˖#ꢣ3>!dcmuQiii2&Hl9===%׽tÇa`/((hll0002d6fmmMh4Zg͛7h}M:Kj_|neЎKK:|;t\1?Ǒ#G njnn8BYYY/_fϞ=zvݼy]֮]65&}?jdĉCmF&&%pbcm؈-miiցSܦqpرNC6_t*Ym]]\/υd233N7o<2|i,Sljj7oW]AAaȐ!fffAXXǏoߎZd6H{=KII9s챣GxxxB :|A܈{%lll6L0pg IDAT!%%E[[{ɒ%666حzڴix<)))mF$ Xф6$$$l޼ǽswn_pї/T4ӦMyil|+W7tw TݻTvz`y+O!o"ߺϞ=gQQ<{ 4hcCxy- +e{Ѓ9utt쵎X?~L^^.2⒎67 J5iӦ]~POeeJJJ()wAno>~ $.!Ev Ixxx$ <'ޕ|z$u#N5 0D8%nIqw\V@ KRPzFb F[fth6РweIPP 44 M0q&+nR'HФ؜'duР~Q`LGkI5G}Kd2fkhPbxŸ}lEzz֛7oZDu?jh/=۷oGM7ÁoGZ ]]ߠe˗͛,4 96'==~Lppp]m79oFghT,Hkv.2)ݧu￷ ~,--UUU333˗/P(]]ݹs Dx;w-]zժU+W F7gy${CCcbb>}J-Z'Z #J 204RSט>}Fiii2իUttN/7ÇNd5c}>LswWQ%75;5Y\Rb>>yڰa#בNdr &H$%%%6MHH uqq  -55a///ٝ;w ߹s]KK B(??_SS3%%5w oI.+.*NJZ[[cNAttY~^1-{˗-- ?w6,l_lll?~}3>>2*4{iϟ!?100PWWuGHKKmD\\<:::!!!??޽oܼvZIIիW/>z?BoooU+WOߍjkk+++ ]uuu1cccٓZjXPPPss z3ֻЇ(VTTfefHII!?q͛\61G2y2BvZFFʉ'&OvurrBQ(//ȨǏٳ ?|4;ndm̘1fffeee[n]bE{322m۶~<[??Bw…زΫVJKKsvvJLL݀b^:xIo(6(hmbRҥKBQK!$,, `nnnhhsuu&rpppvvƖMz\'O|sB%%>1t_n!!!nWH4{ LciiYPPz왧Ν;njYOHX,@Zb=sds\ܻ4WCC]TT'S֢Zȴ N<Sl}HI$P\\d)*444vrrT*ҲoT{0'۽wŋ: PUUJBKIIPuuuPP'LSxKs?]}ꕑBY[[}EEEr_MMMpww X/@"HNNN˖-///GEG_g2\#"" y: ZZZ>ٹs7Ӕlٲ5++3f_PPؘ```0dP\\OXX5Qκٛ7oh:u*}}}|A=ȹsׯtG),,ۺu9Ln-++l6ڻӸ&o' " [ D HE"eSZ6R+Bl AhZ+(EҪQ*}*#J AeK$ 315jH&̙_9tRaaapp0bz|P>=_qQֳ_?s,8;;}?r8ޘqmO_fssXqsxcy!ma}|cP)M咇'222߸R U]]tR.{!rvյtR'*++%Ù6mԩS;w677oݺ!rJEv)buؿ sN`{.Nִ{&%sp 0xZIh4%^g@ot>?3so\|}98(Cm߯7m QT& jfj_4Wὶ0>_~B(0LΞkoAʤ5iʔ"]] t&oDHTQQ#=."tƆFc0SMwauk=.60up[q\&A 5 2HUYOPI A  d@ 2A @d2 |2L& R(DtX2HIↆHԢq3U@1yJ# !JO7/- Kį]rogϜ70dz/̷144̅ /Npܖ;2{'[[,ٖ@ }?\Gd0JipUeeرckjjzA@E˞7oޜ3gNM5pdR)ؤ֥B' m OOk5rA!!LcC_46RO>d2ն Gp4 AvƦ ôYfE9@AYG(^f9^d2߽E""" Զ-[& 5-FQVVhBK@pqKs&ewcccMM BH*,ZP޽9&|(nn7nL Ɵ~T B.'rW }XPe+Vĸ͞p⭓'Off(pܹM6̼[OaasURr:*jyic)~&Μ9UTTt۷"㍌?~9k,7^9@i00Yx))Y[OFwʢC.ZhffF> 4i>wB3BrUU666w|M| sssh{ 455Sl`=}8adcm=~~zu??_466"$U$^/ݽwQb2::û4eM(Җ|^UU'߿???JUyా~ {Фi۷ 6L1E K=BGoV|pz֓-// KLLH$* D<~,m1_{KT*ÇG8?~ҥK/5M6_r1aRkJwՕ+W ptRaaapp0BH$ĤX4!A`BZZZnnnO 5! p1S__}KMG01aYDdGGzFFo i877wڵsyUheeeIIIBp8 77PЮ]<==srrUAJ>;74~~˗G\uvt|u}VJJX,޶m۫mi[#Hа)ÇȗGVŭho]O2aǎ\YH5V b7$' x \O  d 8.|2L& S( Pth$bqCCI$jѸ7uܿcdprr98 TK*64ԟ*n^[wZWG׮c\^w뷳gNZYqoP2HjBuy :fDEy-w4dOZ/4X-56A!}`=@i6 èT_UVV;@akTA8y9s\S '" B!?wt '*+<=BaۣGӫZ"dopb{’=y__ ռ Gp4 AvƦ ôYfE9@YT{\ 3f?`0Ν;gaj^FFF˖-{arrPYY)uh@ J@A~{,K[[EGGo% ,"u欃޽jY}_p匲uSm17ٛ6[3\gΜU^QAd>XosΩ'N$JIZEc)))~~~Gq ƴ4nPmm-+++Sy1Д 2663fLBB·}?uRIII̊gN䓴sΑYΒ%U7{hr˽}v6 ϻcjqq޽_1+KYi˿Z[gffިU5q̙Gn߾!odd㨨Yf1z-FPNϗ_ڽ5[l3&M 9fU5kwEmmSukN<6ccg'dbc&!+X)LLLrss?޺!a߽ۤ>k绸 X,VPPP^^F۳gw``i\\g){ 7$aRi~~길Q@)F337|2B+uRDB$Ik iqM܇N~qss9\[[T=ׄY03"߿???JU1'19@3bikk/\ի䐺^z Ж[ꊿzzzAP(6۲V]?*bfffooH*miQSI{UYON-// KLLH$* D<~,m11ꮮݾ}צVUU8^Qq1/??,, !αb2C#/[,}۶˗/}ɡ!!w|z}LiS?nڴʕ+.b äR\.'CαrJAA.]*,, FDt ? pX<*Ν;ZZZvvv{f̘A;/0 ))ɯZnmll#tg̘ZMbbMMM cM| ^d֭[1͍NZ=|+##79]|nkkz*xj4$CCCP8{l[hh(Bh׮]999* {Equu%pP(?۹s 'mk={qΎ]\β#JII۶m{[öWH$bPhXxXhIZ\|CYt<z:D|>_*n̵ؐ;b1mmmaYYYw(χVа:d w4鴉.&g"""R7i`dЖ> YZZrh~\tƍAt>?3so\|}98(Cm@=HMQT3SF(k!W @dp< R7ZZZL)).՝LkibSAD^>>r\@mmmI#e?dѸ7g컥`0=]bX2H`8fg0X/L*AۖQjd2 A  d@ 2A @d2 A  d@ A  d@7:P" p #b/)BAQT:ow"b Ӑ5N D\tGsXkii=wܸk(cFu&/,A@i5rO/Ok[;6W.78FpTӻRs'vaEEoLcâѨ@zcg;as5 Srðolwp͉CW I LqS~+99ܹsFŒq`0h?x&8?OJvvvD?gE 1jjcfn+#1 ml[~슞y_kLY^ dxAqs8VB޺u3L&!f[=w PS__agW3ҥOM/l\Ɋ|5a3g8Y&pݨw:F,W j!!!SL7oީSD"ѣG,x G8 bdԫ/ {6lHϷs˖-8߾}ԩS~ɯWуBA~}$k{w=,?&LXުx++'!9^lh?UA@!jШԂ><))16&^:sLW6M䨏br QtDRGG}Wt2Í'N% ,"?NQQ*k!>5Xa]] U_-Fquu%؃@ɤҼcQ+d2Z G=5ק/|,xMA@Y ʸ.VOO737A DZ-+.L69ǀFRpN|#`!J8stcK} 4:3jcUUmyi4CCC.:Ç?;]b˜<@PMGt]/sa\P&5(PDVNuv7(hvov/0fDDddIDD uafzZUy>:yߪz{cZn(C ~jYMjz+ b_}abرcH.SPPP {7)~~ RPPP.KD$).)+++?>2ڧOO?/d_f#e36nܸA' eSV63߿dtk^=GRSd{u: &˲+W"|[_4Cd{ʔ,}0E_xWtS(`1,}1#ȸcǎ{w4{rՔ_rIÆ_=5i+|)>4u3f^P(k/yNsED'=uI_=W۶QA18| 8^}=A%{Ɗȷj[w|=T(JSSӺ~헿|6mox? yyy8f矋8~)SPA1"o 4{&EZΝ1c/n⦿'Oo?1O?qk^GTa@ s{キljnWnSUUUTC n}/q˖-d۸/Ǡ%#~"no="jM7>4qbiYYs$`YGkk;;;ZQcRKA1Hǒzb`.]7^1kr<%nsǎ?͟Oιit,4L25MW/ %XD4r{uׂ67//믿pGal-[V+73 ۿuMrgΜXW]5jP ~q a/h2M.whARP6;vRr??E:Gvg;ă((((. KK/X4KAAAA_ dic/)(((F3hK9=pl')7ͬ*/Hoκ3 })4(zs>7+'SP\G[oΗ+@ "'wܜ/z{j)K/t(qO(.uK#g}(*[)?rRQ ËTߑP;/E *R!XJ?C$LAA_X5 tF"v⦯op)q>\^^>2_c*uV^}GW8&GC#W^y󻺺u[~mX#eT `clg k7!=|{8wD0H8oNX6aBԩӶn%9O;Wׅ g̘^d[oWL_v5\{-vmny3?s;K;w-y&뮻ٳ?G* _f{WU{-̜9/C~{SU ?߽{g=zO;wUWwo{S'_{?z_z*Pcǎeee?oYjG/_`] M01}#cpc^pA|x'57/oڵ ϷwgQ?aiSU` /w߽gX+x_yu+9nw?N8ljGe&ܹswύ/IU{0'OSرs͚Us0Lw7v??6=7/)SkٿhXQQA<~x 28vpM07|[o[bD|c'OY p&Uon7o~_5M,++~|yCYiS'7& P S\:&gLvevءMl٢ou u`ѨhG/Y.y|_[U'O7ޟL=dPWZW^y뭷$IF?ߵkW|ffee9rxD"4 DPK`Zn;/XH~sygً<ٻw[%,Jp~\~٬ee_yNJ_<ڏ>(,]=kG?:}bg{˿N2new>۫3i`0o=|g8;桻D<".[{f)FnlmzmRj/!lXv4_4ԠR ).@h%Zn㝩&j#K1/I@ORK1#cX;/wF_RPb0ťmiwd@Tc𵌊b࣏>Bj\wuTt@孿xގCgo}y(ZiV`TEfN)E4`xP&0<ꖥՙ& * Zύ 5=لb OwM]SSxoNot/v)F.6⧞/!O2hFE삪؜Bv!}w(wFPT5鷵9tbvK0:(]ټ3qM0{OSXtxtٵ>xSwMus]S]װ߽|G<[k=w͟2CMA՝NJ#{NguM,&GnQ;(va"'9ˤH&FZ*rpü~6`?(waq\ kxs"JK;ɑu u rF@ks#~y(ӧ/ŰApVt0,Ȓ"KPWkwI1no(, 8vPҨ0k_t"KߜټS߸ɕq3CUUy^Ϊ5䬞ͻu?wɶ~a΀iw80j^C~QEYlD9x@T xj0"**)HAE0I/"Y Ő4QW^ygOVװPp/pLckG5es<>}ڳڥ3l|3υmhp?4E(^n\d: S߸bdnvP0Rk,"1ŻnݰmSSPuEA_,i;rf;cA%9aq:l,BD|VٚuCfD1g>BZzU]gْӦmG^< k PR.15NI^TSRW>) =< o_Ӥ_:[Vdb,apulu ;ᰙfk LFq`Xp=Sdk>sT7|Vt7kq/փ$c ~Ìzdo^Yw/{Ww }vӇYvTTiRPbX~ YVp+b kR$McecN}Ck7 "KBHOG)Ū{Jɫ=Xd,>4Phu'Q䚚E(n|:\S]BtыkL'kӧ_XɀF++ }I I dYEc>}mb$b}ma Čo"6y`cSYzU{~PX4Kn8|"5Ś%׿r@ߩQw;M R "oXXd GB]$f)sڀ rxA,عE^qgӇė]:aOD2bAa=;?`6 rI.*E~Yq,4(4w<׆mVSfTS/)TEVM&/eR$ptW8"_7[m[Nq} U2. o-v[VTeP:2/{\K;ĠPT CEHcHxȮ4<kFd@9|| ڜv`/+ ӺM;o!)ES{8CR$0.p\ͩkPǙ> fƿ{6Flќ=1R)ERHNS);ϬYz6e0(E:6*^U"9a#A/]PԂRdI,g3E?\+ZK*'؜䎟8qBwwg=}K66!&vHu47 \8ifٜ`x`ꬔ"C-gmY}5č]:CQ~xAn)ԙE)DEE97v'x6}fq |mn? -hz1bt_3K֖-[***ȶq`mu;XgVKfyiSe)'}}݁&kM$m7[%;<)`le˞`2.NOJ =03NCMk ێY\Uװخ"qgN.)Ș[Jzx;ˮDtz|(0ߤ0& Ȉ" ]vktu{Y"?W {!XL6 KcuG,c2;XXRv5}5mw=}}m4јqbrp#bFEû!1ia8 Ó3A:-ZS Wr/QjĬ=?vd R[t?i&u .uPxO*rMMSP:E::fDT4{g/$r7k1hgCU㭯o"毳6@gglTY<Γ' 1mId'Hq~$'c{l3|tIcQ1i\ENf6*|eϋ\SN"S]3l SQԮ\"ԄE JMrq r0@]/Ű <0p>5`9aJ}@n)\$#8ZmHCݼ`g93Zks\o.Oz0|pWAiف']^G.EDB9vW &V?,ުqE(^/HinRNV/*,Ř{~;s]p/ɀFT qf+)rf'Om`n!6O%v|cFv% 6AXp$*QEXg% a<=YZJ{ ^q}A|&"ʻy^װVESI(*\ )R D TE~+}KK6b /paB@꬀7gE4 * vzbOOq1q_ay!cYaLQD(2pf+g oH8pϣ 1>Xpi;^͞D"_$GG%6pL"G)@CNb jR+* ;I7Ix|$B78ŚU)) aA4Y ;%ʰf* 4m-vEX7= //Os.\M%{l 6!Mhm}>0Y$bbIU-l腺H `6eH$#E:lMĥV?]SMyCb_!#0z''*)ڱ_>:TK5SN; -y#{{oBl0+o IDATzMAO}hפ8')JBɟIkhPu[g50sfLCdÏHHQ<>bɲaH#XB~%J .E?t1l}3PU2fnN o}}ӎOEkiiӃ9ٳ9w̪8b+'uh[79xVWt˛B'ϑ_M%8rmm,( 鳤t[0lG5WPRd S )ctW bQ\TPj=//4uT}#K1@]J֭[7߆/XH~sygY6uݻvꭒ7?|} /my|ܭ}}i {;Q`TEfN)E4$2bo~^!6ъCaq9K[G\0<ꖥՙ& * Zybх7kfAmvbAܨt)2)nSV8#ѽځP"oɇ"MAy?%q^]PA.Tb>ˠA= bsEY8.?GE!_ନ((з9%֏7?5Șc_W*jNsŞnP`2y~\ \]'pTovcqt9gD{k,D&.\&`1a< gC []f4 9abI_EFO(wxB/IC5՞ͻH~PTwL(wdJZP0j7]v-q5ՃBq)B XhMܢwP$E*Y) I|^bIbFv1*}kfY&E21ZUab?}ɭް{uKg9 **"C"'Rd"@5o?HNZPJK;ɑu u rؠP \ce \" +Ȓ"~R +PIDŽ.b&41E)R`YpVQ7gw^D:.R7x61 Rdz0o00 o\}| u{WWyi~8kOP TL&FŐ_dgl,BT xG h<04~A+RH9BBTd an)p] W^y)a?xAY~PdZuI "lsOE)RʽS0񎍯qT՚kjDiw y(Q}PWq.@Ii@O%^'8o-$lj@I SAR 8&(Vb4Hbo`3=/~;_T*έ{Y+M`LU` sL)2E SkWS`#+* 5 EBH!(dq7mUʈ.J1 ]Pb8`bQq;TEb4C~mD)n?E7o7d,Y `(0Ξ 3&[Zy_da_…~@9rAM 8r͙osi4gQ|ˍkLT+ooFA.,' ێk,":?` ێ_"7X4 [N1S/1"obXlg6Ȣ$Gþ",N Yh'wg!v8cҖ`r-};an{pdu¼g%~9Y"h,i/5%9  67Sua9pBdJ\0,W"ȟ6m;ioTw bL_BgYWd#g/a'!#ଂ*'NX͗YFړRS|=~ŅțֳS@4gO<{V/*'~6_XtPP ߻Xzab[-rM9gӇ95g? jök2/=@iwX"A,+8r]T15)1UBU21#I/Iڍ#3zX09cY;#TUTH" |\VSJx£\+(ם8FFu'M3PU!HشlTEjA}hn|=?6:d{R Yd@#Iþa$$,"vITO%$:Lc|~k|/S&SCI611@C`b`bl|yޟf;?Tk>mub+!B0PԚWսG|x|JifP \4Kț-R:`@HЖSLdoLȥYϣFV;5Ly*)yaVYQ>Y.}v?(2E g?ϵa[3;"V,)ٓ7;ͭ7M1h/ŐBUd+nR&EGOw#"oqU y,’Aĥ(3]-z2$HqͮqO6beAU;H/9*?`:(>IK=8 2(W dE;&L".Zctb*n֑dxu(kWzD[ PdaUDPH؋)%{l_~! 4ٓR$hsX׳vogY9Y|INXG5dvHv~-Q :q5*AQd("ogj+M's)5"(BӧrǏ:6*".fl*.)6l;fqUd_`5K2]8HF%Uȑ+5 D{_%n-[***ȶq`muw# 6zkA)$GE3ᙊۢ%l0|z\v:1)8I|94cqf pl"U_ 8A J)8r+<č]:CQ~k%Pٚ?_TC(l9E"] MY\%E_Ef. Bƙ"MAzDXPhfgH֋R$E®ǘ=3{"f1"Bv5SJ_?ΫP+mfD IPQovK<3#KKKn3J#l˞`2b\SW޵ApÈ9Yv "(}+Y|֢We1\'TN5R͇&l=yѕuqej=ǧЧ$=%4{aHGPڀ"KR"5A}ǖF Kz<@4 /ҫzza cJ&+曚iT֡fxplq!1 v338 恙<8/K;S=w?R{B|+`/ڋs )ffJED͇\W҂\(<3*(-;p()9&bz ,&-7՝Ͽz(!EV/*#poLh/RS$TF/p r_aVRO'|'9{?+º?!zz/co7} =iW?Sݪ _kI})WfۓU$9u]Q63U5tKᮩVk&jFm *eIjHY[(rMmm>4ܕTMa8(QψyĬ5_xFUQTw_ c/V]"CA-K)H佸ǖ#I  BrtX 062c-Go۳gC(bpjL$ߘS N /#0&("I{83[ J k"GHv5YuO)g[I"zW ^ZsBYB^/ .2MSIq& "sA|EJ bE uSbѴ fO"/8 &_#̔p!Y,5E_UK]O @1 |I+jbt%^5#dX^iK_ C.>E"]M`%z3=|$B7Z7֮[ G!Ufb(u{}s jE{(2V7gK((#(QPE u/cšh0+w(JaͰU @h[, e-1b c|H2e#~~B}"Krle3E.E`xo{/y1"+0yFEj-ôO9J(V/*'CLL"5K׭{Z jL-=^PdH"="K1LPdI fay2HGԒFA1y -9>o5oB/Y7,'>_l]N4AEƠ-μUw1kQ5+`Jm{^Һd^6wplX(2R7lq^A] (EL/Q {qV WQarUE#G$a+lY I3ec8 _c\x Mk5[W1,Zf9H7;rK#~6%YwQyI/2go2caIxAod|9YTB⌕%`(NdUH5fQ_\BT{2[xZ뮩&ijl.d6=\Qw_A] H@T9a/.n#0z''*)ڱ_>:4@aIZ֘{Ԍ`$Z #I6N(h9Ԧk;_✤(Qp6 &&&aAmgKou˜dJ̙M[Ԃ%Z eV[%Y_So},~[xAl/ҡ ԽHq4z, aaRKsΦk4RUBcyuc1_c^1S}[j =S_olupf \[D- " %i>c,)̟"Ƒzmr=//*ptT}#PbSzcB@uu"HGݣu֍ ]9xmonrV5,˦n{NU2=1x1ς;dMUdᄜRD اzoz_7=Hxs*5`x("1-K3L *U\R)2U7`&7_kUF_S讙M(6n;zQ9J0Bd 6]u/§v <(Uas An'Yh&[=Eו;ïs=9tZɞn/d!K0HALL^CZPw͇ Jˈ|rfq=/r/ֳ/?Y۲`jy?RPE9R׏bJ'÷S7IXMoBAXuMcޖ%ۃ]0ca~T^$l`3U5t~B;z"殩le=;5F o΢G]KA {sbCAs &*P=IQqLlTʴnI1|qGM>?fƜY]EN>K4['/.'`( U z/Rd$~ VH (LhnS7TƹPkد%[o5Z3 {(2ܴ{\ݣ4R…ښ4YRdIQjn?)eۛ4?¸gK=h"u$*FSguê<1!U z/R6MCݡP ^Pz^o`ހHG]ڥ3YݞNHPw}Uvzj "u/R{lߡ?6翼?L&FŐ_dgl,BT xGb[O8?'MhMWڞI ^BOR"KjR$ KPw;OU E/d$~j J+3i!1R$@V#+op3PװPp/pLckG5d;ڇ=>,HnBJT >zU˰<dbz̑,Q=U3e1\E6hl ;y))Lly yj{zd]`&ByKrWqnZ dq7mUʈ.--V/*'FpT&*sS"ǐK?L,*n(rT ubȯ͂j?E7oO:o=;ɢ8zKK?B0'eC6CIk6GS"iG.9m|b?OcW5HPw7 $]P5AiKmS(\5Kra IDAT b1=+M&m'A ێUBAzE/Ű@xrf;cA%9aq:l,BD|V>;Qۆ6RT_M +Wd¯1" @ć3AE3l?}ChP_#^Po ,,i{OUu kfKrt:lO}x47G G!JфHScߑBgYWd#g/a'!#ଂ*ןבNugS}c$`E6I¯pyzv I"iE& ?fx#{\Se,ΠY̟SgrSXt ێkːھd@,fzvMZL)"#uSbX"A,+8r]T15)1UBU21#ӤpƓpp7?Hξ(>@IYY5TUTH" |r%.Δh/b&>%heIpv݉ohSe\BO[uO)`GLPlz]I?mAE=&/)XɀF˙-Ph5 P%a2ap$1IoP$3$f=Ux!& V\=Jvnl%ʅ%aY>88EL{'ox#̈aǚz["vU6Wɧʅ%b+w.J/S;\4yf:W7)  )Xd GB]$\h)&8>n&N"k-q]:ǧ$ۃV Pڰ rxA,ع8CF1c7>=>"ke42+H1FPYyTFۗB|sm 5Q[ݣq?롃ȪW"L GDfY`)6>ּ 9YY4-W^𘘶gNv5!pJ]EN-+Vu>~9c,"a}]U^>s'Cݩe 8wYҤЫMC<voCb QYĐO Őrb͑hg7fxMIUdEu}X#(,)7^sLL IaI.6R3M⍎Bo$u IbHmvыqb%KjiiӋ#Pݩhß)Z~EHn! oUd7>RL~)Ia?շONm^2&Ɏ_ dV§  ya/٧*dB<dWc5#{2>qr]m΂' :q5JUE}`~'R/9rD("z)>5RM(96ӭw1-3ɰ[Ù{JENU_u  6zkA)$GE3ᙊۢ%CRl"R 8A J)8r5J(Z=JFHʁ?prH{H~SN/\׮˛HM՜*[O*4,q|4jw!{/fN[sg`sOcX.>V$la_-C:%HY 4Uwc^o3IVŐoJyY;)>9CU-)|ԇ AAAOt u/ߘzT{(F рч 1p'BG~-1QQ1$yrfJDqZ6V{z4a _BA@K2CJ {cU$9]QBArsu/xcc#wh{RlTeca4)K1\P:`>:+*$G;gE4 * /vY&(" 0]P"]QAmq YBm 3Խ!Փ]'Uw4KÁ`x5{ns\3[$/03@D1M&c͈"& Y`tPTT?'"6M2^đ _(0Uw(5 `Vd)P(Úa@дYcaԮX@Ue-a-zEs)3+سG .Rq-$7n#ߐ"a#'̂NiwȡȒi@^V>HےFaLb$%3A_[TQy%F_cP5Iݨy yi0А"!^Xwxc਺ӤC;^f-gX^UT1:x87[r% o[W1,Zf9:C-ڪ} C݋ƩnEڨW/.gG! ȊH)J/PcYpM,4.kXYR PHfX.A`}{$HmCBϗ{_#0z'(ڱ_>:4,IqNR(8υX_? t0Ѡw,A{](h9Ԧ’\m'^Đ:v*+H4KÄV_oz2ݜhbӴbX"ݢP"l= t5!r4Q[f,pNuw`[n`9P"OIbrgι @̜4)K1-Ek>%[1@qז]eפ;3_}.n񷩊0ShPfǛPDb["Vg>0ˠA= bsEqߡTCQդi=;ݮ 3 ( Ejn4 9*J}ͭ>Mcx-@$?Hv^z M()'^q/V61lb.*gRuIA{N!pV\%xz@GϴO)Ɇ^_ðZ ȩ`['/.'`,F5Z(tU9k{liL11+6g1LPYƤ2DeeSwO1_Za$qᠶKayLjWkno( jOa%;u8z(d,E `{4d^ D[S{ (F &CU9*Ksy1F{S_{oRrJ6r%6g͙[¶xtP9w볪.\&[xgC $*~t+${"#75>s]*YA6, &λuL)eqV'Ԭ\\6iÙ@Xnbe O?R6<$ld˳S{4w İΘmEI}EX?{EuK6 IH d7 w/(`)(֪k_k&Z۪6iy}OZ,X fo3qvONf/9g绿wVfG1#Wd̲G2;Ft VP;1 ΃ JLeCќqL{?E`b}+ )]8B_?<ƊWpNM۷p˯! ihpXZỚ~bg˾]\\\u|?GV ^۫@ߴM t-Cf;L8O%@ Vɞ+Y2)EZ2^H9rbA_itQ=ֽ1Sb/v\jK )K?-g|&-eϸn^Lu^eC8L)3o+pfNN>#nV-7?qf&AgWp@OM^e{dϕV!h ^=}qr3!`/*:Ֆ_spֲjO`G[gqlh!p<"혚d=8ޭE#мd/Ǟh4Yj%GVn-jnx) Kj{Z9#Q< R8gɸ;W4Q*ZEaNA>R%HtSڥ{EΣ@z?hX2](xi˦ܜ_cgx'_qqYy&C#>BN͙w]͡`rֿ67z6t,?+S0Ce,Q¾Ajuu=ɝU~c/Z8'Z]xܵMMMI"r9 q)>us >Dry2cRl`BpEw DsC;KlѼ7mm.>oml@LOw1Fl*ޅmxgjxpU;l!L 4QWl6[mg;yխe飽UW}w_8..n|%VVF',tC V0٣'.#5Х"o{Mz4v:]HOg/r9kkk=w]]K.Ppmm.sM/EP<wSS{FNMݸtˎW>BRgj* n {_)jZvV&I!%طxe%_%8*!l| Λ9 rH\2{/)ӗ.&d9OW!AB2< |z`[I 7=,G{z gL ^׫3jeXL̿pI˗9r}_c71}[qЃ̊'|KbOOr9 q555]'+WՎ13z Bnm󛯱g9zYpKJ@ HBB0%(D꺯_s*޶Ѷo {E7~B4. p\vtMS/9βNwXU h^p!wV4_&yq_Sr]J4eMTNӪOٳCV9k$xg$?Y mhOΕnx5FlhhDtH ce軱J;Xc?gSS~H O-Y"oB8tGcuL'ܐZj/QaL l~6eйg#l1tVGx1V%TسP?@u޾kx]2HyeYrՒ$_E*7v Kk<c+f[r \L5#ÿi쌇_~RZP0 zjQN#)ugkBjk2v{<n%g[B4668.zBuu#nnfh(O"J|$7 - 7 !>f]Py.PM7/BSL&qL2PG| 64fDzE 2ڻd_GddFNV9?mRC~aU'5CŌ/ccC_MhF,e[ #+HdLC9K#˒)v:],K?&NpYM#;mY13jkGax.K4"l`Gofd.\L٥9Bع’:$mOr JlCt 2t/^L6Pc!꾹?-P~NRϾN|!\Z$o܁Oq+|VRd#8zҋK"2^ =?~!u"XQ#ɧ;4DG4|bi4/ #R^D)! [@mmmccJКSb)@T692Ys7 R EC=[cVc֙?[[\jl{vM<44֟LuuzL1r^l;0TQMI2PY?#Y/^zk_iϼ2*j`ȌQ{@^Tx  ^fiA MI")LUq7Rcbb{t<' #n$,%_-) Bl|̋~2hsW/#"D^s8sI޵}OuzTYZep(H#AdA8 n{U s]B{{;sَk/Ғaޞ }\KKnt:+=l$ n{y[xe3i]tB]+**$IJ¿.L$Y^Zp&;ֶbi`ª#H~Jsi{;9 ZyO:P@PBDeW&?R-?޵^s~B E=(_$HSa|4y]U#.bw-\87xw*+v#,I7YY2#Y.WLHEҬYqYf\7n׿"َÇ;v[YYAyy--8r\>*\EGv=.eey(uEs*hq%HMP45uݚY5A YFeuBoz 'cŅ8)??v GCZ^uM{n"cn8?CfD5J=GC^n"%!&ҫ-ĔCKv$4ItZh,=;葶C \Kc'>X[ʳڧ:ݜU (?tཐ:(u|B,_q:%كw̿cekKqro>skfc67uTؐVup{eqy) U}^sM=99|Lbܖ!܍l͒~!!2/W ZlYZJn)]RnykDҞDۧ>Pe#Qn_ ۳Vktm܁:>!οלzkVqBwwO%:x.^K^ ,EQgD6\}uߞ`?ȟ[n.7cN4pA!]Sy$g!k|c[T!n|70o\Ipkkl갆-6A*KĽ„ rssJJJ$ ;::zzziӦWw-\x"tqՋ#Hq=^'ℶt]EgFƲi7QfuAӊP \.,[K=DzF8m5RYvK z{L&iHZfoOdQ/BUqO/&dO͞&Ks=fXJeƣ Qqh/z~@DT{i/۳[> pT}i/6̋eY6\U--*ҚH%n c qoxIzi5'';'KDMU4Ut:C~oynrs!w;U!'q !".iRB9b"15p^L"tOş>!@>}oy1@%<̳naQ>rbfU%B54ihzpm^v yt,-8~C~oHQC^՞d PڲzXi8I7?w%QB)س4ŧ *#JpDU>Ou|H ]s}57 yşo˻56yw gT|qj7*{~/{MjW0wmSwt9Ŕy5?\D!f~_m^t mtPpCS=Qp=ܱpyeQ*ӝvL Eha@_13D ˖NO vG6 J9}Bɯ@nO"I/lՑkuf^L o_ޭݣ7?7MXxu9j`ɗ  Ϲ/_RotU?=]?L.?z{ JH3am ,\~.R/oڦIx$\o }:$ԽbPojjr=$--L72٬6渑UC lKі]d,Wu}>wM/| g [P ຯHXP5ߗh(Dmxz˛wygwg"8}JSNWU]#=NW5$ohzj'Xu+p׷&o gvO^ߴ;62tqǛP0>b x$ZN3)qה$W '"#`I!AF8{*U/DEE|pX4ƅ`{ϯT &5} @y !Lඃ#ȧu6Z)V=[]'+ $e:JfIB_cPƦrM")JJ[@]=NzA t]4lϞvv=J8Q{~˓xhşS@OsdK ( 1a] )V;,_8:)/Ӄ ?H|;/lsw>wUCvçjhzʾ<%ſ,^d^$dY6ϚUC͗u:ǤoQ/ $Y u%:D e?^|%<2UU>3gց-WUUŅ0N7N[^SH\ݛ.RmDm)ӷKnۗ_q:}7vX?@8? /;o|9;eEؖLw9Dl֯^8W>^E9Gm]++kQ$HiJ7XfR@ OX*++_`$  e Rt$!B% =]alEtP$LY/"?(ᑑ@p( ;oܹsg ߸~ӷ x >{@Q9˾Gi8՝Q\vM?=]W/_Rct! Ϲ˯]s˛w ^lO<kh{  EA$"B4"@}w{qogeB0;xZF܆^FѨ;xThxzY0@^wեK\mKtp}B=Ҁ͛7S"G\(^`t&:z&>*۳E"^A"sQp՗:tSΊo%)" Ǎx=^IX 4nLA5;f7ࠄkphaiI| ***h@@uN¼ j#Kj=}K"(toy E.r@Q v.gK]FWq"; H]yi$YmdIkh;vI+_榥!.\ ~rw>_-nQh#/"48JdV$BSS3͛;]&z71k1DS#Wr@ #/]߸A{A]`"LTA6 agЭ[ffM8d|diovyN`%j~[wc>VG:7 %L~)ÒK=_o]Kx|J+iYCSDf"Ǩt'~Yΐ/ HtiS].gYY9H獥-BqɈ $ĸI@oj$AQ޸*ا744^^^8ŋD%K[/Lz g?);P7#+I!S&}l9Df=^A&p.uojlP0a 5\!~/oڎl"I/e7 )wֺN׎X,( qi4,%4E@.g,7!IV|}\ m:W,DSS\766aHa'I&lY_?>,TFZ[[,I?i& $*8//[$e3x=}}.T`9h@Q$iSi&B0}sH!jm ķ-/khOY_ Rh]!N'|uD) Ay2ϘFJK32$67)>OLK IMЋzp>Q#s+Kaeucjic:V \?ҥKAUES܁ڵ.#ā]vr³ 0l~D(1DPE!4#m/o޹f9fW~O gd͍;/_w~oY􉏉~-KR-q)z^ߴM ~$WmY ED$'Y3337nDE ltT;#H V13jkGaxnH3Oɏ aLIc y" [, VGGǴiqwL_v~QPKHWq](o8Ui{qJHИ_vFՆ72j}kלIe'tSO8cul/332Ӌ"&uO\1磶?;'~>g<|1"55 MI D;Ē͎ec'@P)#n/hۘq4).EAWhU_4|"Vv Ƥ}"-((t!٧#K^6M38@);D}i>1 5@˗loD\ rac{AN.BN¼cb{ܟdoڎGHc]t?|1OY5e$Z D2ӔpM0I`f&a8W9?3@0k[]$hQϷoe{jn/lo{}u[ywK^F)m?6Z&-BqEƙgݲvAQ4A4zAP/qCw}{[I16{^`i7NL2>DW!IċyB+AwpN8~ii6<[׎?|yhﯿ T=7?]vi>1s@Ƈ~{{K\`6$%xh iP8cZod.-!_1s@?j-Ľ%.0E_^s i3Kb{q[:x E=$[y=[0IfWyM = ;BʉN\rE1"Ŗǥj=x IDATAE[񂨆Cp%Hm.YGG;$ՈV^F(L}9$LwKxš h8A,=]E (ZJĤ@;!@H%]xyo:,jL,{- F$ BO$Ly3nZv^ߴM aBH 2 lh*Imllun[r!ec"|[+ #7yC/H1W +*"wٖ9Q s )E!$dEG*im}Ab%ӗ !=Cf޿{a$E|;ȟvÃ:ޡ zB輂ćCJWrÕűW]MzA*|H}v ;AX 6/2"ߩ0MU!iWIMp#SO\ebCz: NdzAR0B :tǴB6!E@{r"qrKKsu]B+%.I nAe.g~CmoApfiE5s Ze_s8RF{.Μ&V} @8Jyo,@WA6=˒SXE ՋkI/~L$]LA]2GmfkP]2%e^ߴMy{LRo:H諮olE%b>5b-nt`Saψ 1ABvC ^0/= &:fB\ybrՂzָ:>K@PaYEPF#._TU48㣛r)l}ퟒE~PUªU?z dY`6tUM"{k6LeuC2 s^o>tA^\ MgW-P5UShHrTE[[[ftɮō0Pb A$_^&Zmc)8@kn<"tkx<͢hJ}=Q8y[J}cN4eH, ʫbC~,8kѥ%lG(fQia/ 5@^4_)")1 o SS !*|\BR{ ͎:k!PȪ`32' DHbܹHQX@%Ԏ]YE&ҵg fi<痗JHgde2ra_JaY "jH Orb/NHőaނ(%;oӳ^pץG8mi3=j}.$֭[O47~fcIjHQÁOC0;VfGnkk̴K=8GVLƅHtV=``e{q ޙto}^\${q֭{ 0{ Gk7Ex?qǟqRo>+Lҁab3d/dV x0Yd9xC?bbCe)el!IB+b@LID &9g 7* !^C=:^yOH_y]]wOPg!JB~{MD(81DZMS lϮ|NS0d{w=uu.6?6G8.nlI0T2KJ=kRGQBPB؊2 9υA='w%_RoE0~Pt%0td0VOv 0pwW˯$jj]E%z+@ߴMY2rý& M I]x^ c$q:ԓb2.Wq0ٔ\9&먲Y/2 $!!^\N.R7oLoxM3b; ˶Qrhjr_pG6.|]GKK*UW(#D=UUU.v=2T\U73>{;>bZɏQ! ;4ɻ4xֱ5CIIiEEEss 8v mr,RPQ*7'.EekVDЃ//y'A]E3֯3[."[å8' Rd_ױtW}̈́%.egEEpzRY5bnH@DL6p:`i(;!$Dz\kJa#XZ}}"n@+R}ÀBK˗Zr͚y^T̍Es1e\cvOpMqa[c70@X+]|m[,YVCؖj%#:e˗GQ|=:FGobd"rMO7%RfIаO5AqDz n#tdw#oBHp71dhïQ{ʊn/q1/q!W q7fb!j#*W9AI8ø/Y `J<\B۶" ,,YVCV}10ȋl:|=Ovuokkk].'eR@g@2A&ڒ6IS{%8W^2Zq)ȵ|u]WU0PG{dnݶi& N 6N79&̻{ߦj51]4DQ"5H򁊅 TfGj sIc)B__>aXWwۖ=LSwoڎ1mL'}ȍk}Kr̉x!=i*h}`Ka NU{R@QBdfCU#t+lB+%yḨ@gL >? .]a#"kھdY*0]Kq=>Ԃ"b`|Ym,6755Qq jM hÆ$~FH7$'@)ZDބp&Yr%8^ Kpfr˿gzݩ)i˵6͒ L~LNNɒA=dX!P 2<7J,^%߾ ?u* ;mqXE%[.ڶeOBЂt o?AB 7Y.k4F@G KCnROn4pZst%Yd[OgmA;bѣ[GC5444BtUNC'JՕXo1'UU CdLQ wmb{A嬪f¿&<1}x1@f/=[j3nf( 祽`*I/hKC2[3Awwwf-nȹM7kF"b}сb _i#Ha|A_= \Y%${n$#O%HiST]UEوkkk\.DU<=#E\cGG!NJ"h{M՗^M,GYHe?dpK@ M;B{QSh׮߿9]aZ{?ŋܿi˗_vwiiznnM+, 1nהt0a^l;0TQCgdY`(]jLؖ;iK#_%őr!Tc¶E^DI;iI|[.X9+R¸YgZM#hO,17,.a:z+ MVh!YC/زyuI3Zͳ+E9[uTCUL̜9⒱_ V8E`BmLDAl6KwwȈ]_9mmIm2t]?4R*N;@G'3>4ԟa)-nڴAefVwپv̴7"(˧6ݬE"L, Ԏ7XVM@T%״0/HaܼA44UoVA8D/uldY%8^.2O0Ĕ}00#}a(IA eOvuME"MU&:({OD[Ds"yjC沬_4{nr_~_oR$-z8a^2.DM17MU!QTIXMp(rk6 FX|Ovd7t(i: ƽy7Ԃ= ?&كc R(j%I5wd"z5 `\]nI /YdWMT%\gxAu=H4ƅGtż=!y\ 顠}KuZl͐E^4, J#jJ좠7aV&m4-O l R=`0v}wN^x"*V{oC6,:dY5MWU s2xA(,z)2ٞ]egA@TMG+EjF*  ¾>]D.eti'6A#BD*.͹964ze&q<8?CfDM'|n%ЁB~o7]t]C%#)'  }&z!ӝtߴMɀb\FW6=,,Y,TR!PSl&N<$jeC36'-uB{2}o:37[ɒ'Dmmqd*"=ݩBߴM=أAH[NjM~&צiKf|zҖo6*-3Q#!8gӖߴ-mXXQ8?8.))#Y BPH״r[l IDAT9ǙL&R$ߴ%|[o{y96ozWVT.ikk۶uˡCCTRR:deeϙ;QpM[+=>⋈說4,*,X'p֦%98}['s?6eddoҖt](< QMBmB;o]fmUuMfY!>w**O`M?-mw[ƺIUUiD%_jNs``繓HHǡ}zD.@δHʔuVMQQf=~t3͜13;kڤ;vwk_tA-_:aО}Ad"- 9oY2R`7r]t]ӡsP9!' wp?(LvbA0z}sᰦi 8ۛc,eTUQUE(eܹxzo88q pJ/F&XPlok( bo%Ƃc k,QDEbW (w;(sw쌢\}pbeYMZzml\ߵ^*3'Oma*Gp;5)~mXbI*ƽ^˜F{yĞ"3.%pX@ ջz1ƜFqZQ,1JW۶{<BpNNR8 ˱Dz,|nN^Osa7jQtRY#P06LyQ NPlyy EZsc1.PXf9%zCQ !a=}tvv.c QeT^||˖'Ot hX(/q}vzll VXѴiӕ+Wٳ ";;O>}پ}s ԰k9uUVٳDiHj߰p,nZ`CĿ@RRR~~`m;|%T!XP>@980ƘǶv (́h܌V"W-]IJFa,1|&Ⱥr6W&i ն0D3ɄEwj1}(:XB}͛'GEE 3׍;v˖- F?֭[nz 7n3g''K?bN+~ azj`х( o<ϖc(BQ4"^l nm%\6)4]*5.5*dYvv(8.P&Mcbbnݺ5k֬N:3& ((]UYXXX֬YV >|8c DLMDGT S(=dBsB8(Bܼ+h oĪUW#]v]!:u^z{!ei5kRD/iaeO<1KO8YK%l 4(P8uRsIQ<ʹiDL4%QK¸.ۚ銾'yzzNjW7ojJH,SY!аaCccc?? yÇՈQ۫qF EPP˲r\xM8Bo?p0Zrrn=xp۶[ߧO`%>3K@Q5=k֬߾],B'PeW(y0 :i&W^1\ߨJ&QF@ M 4m"3dlZXf&14Xmii)/b6EaK\an^ϫW;مΟ߼~zǕ @1 ݴ9Ծ]2-,,ܪ8XM9Ν,_.n[|ԈƄq_Wj^+Wʲѣ/ qai@ eay^GS{Opo;[UvLy#exPWuFE7|cǎ &(---ϟ?uT(B!QQQaaaK. /AԥK\w^au޼yӦMiT!%!aOm+V_DQB, Y[-\Xrz>([;:{柂 UuvlނM5 Ǹ)ƏZ񋼚[ d>>ݸ56#).h x (AVx._&&~,EK9.rhVBl3vvիW^L֭[nJ5GvPE֯4K4j0k ?i޽GGeV'͝#} lrE<h-ܑIy, @QCLڶQnZp5zy[X衿 nzn+ p77WoGxWAȺ/^o)?IQTrr+}DG>+ ?T'jlx;ר^{Ŕ))ݧe2!j~q!dcm\5MMMĸ"7"r3bmڴ[w^fdy^yV"?r(lyg1-IJ)ϝ hHVUcDDCUp޽.]߿ɓ>>O<+TPQG(H|}k-ϭQ>*rv~w4X_6k䘫̭R^^cEۉj47osǎ~N kRA1vuu>ύ1VYzI/tf \sܵ+K:L h4&..n6lX|H||/R gYʘ«"󗈈 #quQeQ{5'G)SѨ+W >|Ŋ;owqaLe.usDҩDDzD1Sɸl.y*JV(… 'N\`4_Rb&/a.ϼ (|3f̜9s֭ 766ֱ?%"z(d6/  L0!*js}LFQJ &"/!0c̿ުђZ>uL&>|-QiS'K_"w$6|A@HT۷jժ@QD"۷-QjbF,n8+“BBqȑ͛7?^acllO4BDzXkêhD`v(`aAa*XbĐګx_<hРUVrrff9+cEW[o? #G6_LXʾpB`fiPGA~g^l$aa<== ԒM ]ѢǹZ'ӦM̟sNss._G"XV,3-eo'H TTƣU.8wu2T`ٳ>%[u ef_uk׮ +ĕ,iAh211!L& P*)TJ T7d2ڵk}ݢŋ/[Tb<|!jğ^&K7l",kj*\Cz@U7nolxgϞϝm~q_S寁x,[c=bZ? w*U^2g׮^e{'9y[ӦOII-5 ԕ+w[Swo3g΀>|2Nzxѧ^6=R>礞mܨ勱rƍۮmiZ7.9(J{V]F#HJk>cƢEBL:gӧM}*[ȑ#ƍyѵ_iiډWS4o^t:445dH>}ilŋwJߨaK$Ld++XZv޸qRǎ u3gKv O` ]zؒۡSr6 #95םKeq$Ri֚OH$2 ?~1j4nhLШɤ Dܶ%jaM7OKOa0?_?μyF&U~^ٳgݺi7nH{A5mZX:u|lȟ?NAFmX&p)ӧLoiڴi\u;;;H$4MG ]PPvBXlHkv1R>lȐڱT*) |;6_p֮=rK~ҍ$7TYbhȐ?SvuI5ofͯ]z#FSR>|0eCEh ^(ϋy.]mkԉcG DqnڤcTjuv%<ۿICs=Z~j8^bŗae2cH*#TXeh5)WXHLLMO7j5j?>?/PTFrs߅wN~k׬6ᇑO>ΟѰfEyzppѾ}XBBĉ 7Җ-յM36edeuݺC/_+l_׾r}wg瞽{MM} ;w޸}|| RYzŋ绺vs3x9b͘Cz;{Doct4s#Gq^rEPKgg2n4-H>,HƎ fƌ8Oc wfC|jaaz̒>AWYIDATj:߾cGNk(ɓ{yzzo_,][޶픸&#CyG!씴}ݹZ3f|jUtBB+ZJd#G~-FXhٲnO+ߠ:uTUszn(0ҥ!!-ټČ!ի;ԩ}6ne)F+kgV+[r=۷E(==fRʕ͵J*oh/IsJޓ'i..ElBXR0UR)sο?9.ZbsrT*C C;9YiT1wrrޞo ç#Xۜ9k"3(Zn%K-4hӧOo߾\؜BU9T&Eqtt\n۞ *Mk/q lnnnnem0 0eٹ˗J0f̘1cdff2?O9WuvYsѢ7eME%[Vѣ>}B"##gΜY;8*Je1<{Qz ҷN/Dmb.{PxУǬ3EQU 68''?wpǚѶmkK6lEXKII~Tptb7Hؒ}YY9t5mۺ-Z?`贛^+aԨU=z EBR6O?kW۾qe'y !DR# u+R9w\e.T# ̍}SJmߺLGUcc)rKժCˇjۤks32rBC׵jUOۥ1H[ (ϟ?YY oבOuڕKU_Y^,B.Oz@;GRy; B'M,ucL,pF}Xr4Q%\n~ѩSԪҮ}'O5*%%E*֮]{_u޽맟f :5CC'~~^^^m߾ҥ'N211iݺ K?试+\y@\]jL>A6M>|iÆ?K;ujgK36lؒkթS=:zOYvܹ[۴EY&>;7~u?REdc5i7۷[Biٲ&O^RmbzϞͣc{b'&ndӦɓ&Uk0EAu""{/~8]AǸYVSSS۴mԢ… \ }:}? -xbQh?1nkx9Å|9Xk4eYc5¢Fkx49*Ξ]LƟ4kmm}vۏ7nZ DcsW_VҢ]۶K.]v]YJ鱗yr?deeٳ{p]v֓׺~ʷ ,#>)X>ݒY*)FD9oTezZ+O^ KR9,WADD[_AK=<]ojck>A#cYjx i+~S"﫞|ZAGN1"_]Gpp6@gmmS˯g|233WgWZhynb˿ P!$$XźrlBwojIJP@_w_j\9?JOzŸ_3 v=(4N !0McH[*B,BCGsLs4N'8T1/*jx[l?Tծn[^vF.|5x/H8yy cX!eBE19<9NJoP/>kə$(;6}!0s0Pt{2 iq Ec?عKXs'4jJ~Q"wHW*kyTl[bswW!+3DD7Rů\<&K.* WImW$@jEKxhT*0@Hem<ŀWoy?7kuO*JKDDdE r~^^rriii˗Ewx~R66h455uusqta={BKDDTV"ah1˲)))<٪m{k+k\Ҫ[ĿExA=ϓ'.%,Iʥr +kkZmJ&%""*a>ucX@0q׮]nӶ5jTT{bjiJRT*Eufn%ܨgЋ/Qq.o V( 122zre!/{XD0jFBӴ.ҶvL#Z"'2 @I$CMK_"""]hi+"B+H ZÏ~W 4CK$RCĿDDDo6"y@y0BHbΏh  EIwtIKDDv@ Bˆ4223g(ʐ˗;88f2 c E c&%""bmku  kiiٯ_Yfŋ3f̈lԨѺu rQ\3lذݻ_>66vرUV#G(={ڵkٲe-%Kť_( o+9[ ߴS(y_})Q{```۶mrQ;0i=z\.oժUPPΝ;וEӴWrr2M.\HLLݻ7] TLPT&#/]҉\" U۝:un޽{awzyy|}}wżWzzznܸ!teJ5wUVK0 J}BlXX8a„իW3%\(ĿDD .gJTr "//\sssd BTZ6mnܸѣG[[ۙ3gFFFc#~;a=K}{\`PKZ.CE "@YM6tgԩSb˖-ٳgX=` b Ohkk3|^GyW.t:1LL0})?, p8$zxx7ٰaC== f~ ;=S~4ӳJW^I!*..k>nǬZ w[X~=_b~fcʕs: UU;n4inNy릿 /pꩧ-[XvmRoiyL8ŋxbn_ט2e 6/SUU?TTTկ~+ž={Xhwy{0zʗz(i9WvvvJ . r6ѧt&\pvPG}AYYݻwc6җぉlذ|+x<*++ihhO?Mޮ*V|;oiwߍ3غu+P(&TVVĔ)S5k=z}zn@UUӟĜ9sx<2eGUUfΜI^^梨к9̙Ûoi__Ҍ X,?e̘1\.:::m>,f0f̘SI;dggi&|M̙èQhlld娪ʒ%K7or {gy-[|r /ŋ9;v,nJ91 Û{! }gժUlܸ1f>AP(hΦOo:.N;''"cˋ9~ ӏnX9q1ǹnۓݷo іJ9#GСC(9rdJOfЍњUU/?)h+++p>ݨJiSUhS-ﯯ7~Ӧs| ۏ?xN?t:ի|q]8z2BcOiğ߻>AAhhhHc*[9Us_SϹ&B 9Ӎo裏hkk#//뮻/$mF?|M믿NmmmJ|@]]GSNadffrDzf͚>8"b%N'M7fGFLF !4jmġC9s&lj'Ȇ!20`F]a0 &FP:~r}P|P NAѦl0qf!dȾ?QpϘ|6,V+#ZgNNgر(Bff&cƍnL&l6=>oaPCT@UWmR+VNAuh WC㟘h>wv}7 M>\(8ލ/f7ql:m:w}\}s49BGgg<@~~>͌1;n 7٬u!:9:P.0X.vs|`Ga2%_pe?mi8S"0Ly饗Xv-۷ownwiӦSZZjߺu+پ};z\ve  [tbڸ xg3f&h tTSRf$iZ5m6F W^E%h׶ݛMgp6-qvyZ |deequqn7o?'O . 38{P[ 8q8q>M~&==ټ{`[1؁\|`VLYQWTj#sɪChox,3#8=/r2o /\vL2%կ{]w>\v&NdDN:K|'ڋ橧‰/`[oWz\p%_QQg9眃6vW^yW_}mFFFgugu=\b{cfΜ ̙37d\s5o~w}?쌶sz3Wa6g1J{.6PF;6mL^eÛo /op/g*N;4֯_o{.kvک|v~ }9_r+}sK ̘> M^?n7f ܽ{7 ̙3{P{|f#2Q:ڻDU 62_ch9^ W^yիWi[\x(7-ٹN?tfH>_H׈#qoiiirʗزe W^u7\`}~8/+#<ob2:u*,_Z-˖ jYɓhkk#`پmmm(=6oJKk+Nu_:AӦe |l>vM"cRU,nFn|֑\[o%CQz|x晵byCXxB}EEE1ovVܹc=ڃTUbڴL48W߽̘1s9/~q.ӟYy mmmxnV\ɣ>M7-% gmΌIL>|EL3Qc註WC9 & 9/8ogh=i7єܣeZ gp0f뺽87͙Fӑ&o~F19` |9ORn{L& yؼiޝwVa>}:~am6On߶m[{rwۙ?>.Ҥ]Q{Ӧ.hmmer`ak϶w?Ё#sӗ*8+a%py(],it#[ʯ^o;ʂ ()zɊپ};p;v0~L6UEU>w}{ᇹ)3P|+׈I:h%krϥxrk5ZvWD 7[1n=IӿKy}ɓO[__~vnfN=4\.N<Ę1n[l{gηM[3˖o~N'_(-(O`A>oju?$;;y??}:tiӦQQQAfdiCCEEwu|>ywٲe /G{AQ8㌘XpwJC4;{7\OQaEE\.,QAaവqwKa'\n$l}in֨ޠ޸𢋍!T5)Ralt),`mUcPU)S&3B}Ngi)xc| dKTj? $'g$S 6Aax߷U_,XLR|Ȗ GL>LU0'Oy &M iS?͜ϯR79}:9#ٷ 1rdyHKK;, vhoop(D86JL&bXX,8222?r$b |nX,á_2a Ұ0r=j*/cZzB˅ fܸbf3V3V4L8, iiidff BǙL&Cj% Y" ga2Ǟ={;eYCFQiI&&a =ٌfR1L[lFQf30:q%LݡlOt'-  0̬__?c̚'=]BfVv:cǍC6AAa%ĉ6}:f(lb gTU0% AAhAAhAAMAAMAAMAA6AAA6AAA6AA4"«xYrOpޅFAS1dF5 9/q<7sIQ0oGU˜VET0۴Ô`9&mIDv `co @olQiVRha,t|ƱeJ#Ǘh(_[ɍMPk> # }=*~NX  ˓sD_{J^B){HAg[#Adab Pd*4OxAXlQ)Sx{(_[RJ0xa7$)j3P̻? axi1av@a?VM{>xX{c յܰ%,L,jPk8VȞ•Y@gKAS}1 QFt{k+9i? àll\nxH,al ,>[>F3R]J٢RVTly\WE3[4#͜wfI7gA𪓂 F 3qFɘ|6o]QaF()`030)ALffIGզ# IDAT;l#C!FZ~eͧdL>?z" gMy+*h14}-*3K^[ axi1a8qi0[l(QRK[>vt =5v@8[Ӻ=7ic!JC|$&VTlc( ˾1ߡ|m%KLd|NyIj XӺҲQ;1WVm|p ai1a7Gx :=dX8]nltybIKK %E9>wS{O蚙w5𶋆8 eןH'RfmE6C@م &/TQT\eZYvMQ4b8 ;"c*cp ai$X% h*@ ŌauY-6 ChsZH1t&ހ8nk^A0ג;7cscO qʟy(Ŋg#s#+,|*~ 7\:ahXr8.>d,+Uq؜p,+dYvP1]]:~^W84 |P(S^|.J2-@IҔ4H}&A6AF[ k2[1] &Ó!iLsGb:Y8Qݱ6Y4h0Bg,<Ph6މ2Y~7^1h=oG 3F5ʲb([!q1O6v(.ݘƑOb/`m (_@3dNVV|3 1_y<#;U[%}íC>];{ZFW8kdm{-c[٢R{RAO 7%;W``RZ,'B s׌4 J·]/u%=fIM4KPJ䖫\vlCaE4Log#i@f JDajy}ȇDVTlcӍ.b=pOԇA&Èx _[a%H8z_{pPPm]6 :[ cn:[4ڌ8Y4DiX~85*v5ChcY@\.c+8T[>Uo7!U Ƙ( M iadpDf9 @HPΰo[ qeN5QBL}GJ#t6`wEU׼ex-m]\wa>޶FFdwk3\n2v3v4ޖC}a;VƳ]XtU M>{T%j۴gy8H-l7IcQ()/)`9qed( ڲO}۸~$ʮ;`ov XCP+Ҡ_l\T &Èp8D8$mՂvz`\Lmf1͆bc`0Q= c8 7]]ʊYr8\:Xz\|*]KCę}·35"w K}~'+G ~J XYpk֙ND h-WgϺ ~vN5|XzjH{<džl֮5<5Ol,1hI5o(7G ՇA-|yc=68u' h1al[ Fe(in]Ɔ~]{QvVzѿ jqzF1,y8ӯ´5-}ț ZaΈ;4}ŧuL..LpbE@çud4O^ Ah=2b|\?b"sawr>6ξ?V6s602'߲V6jhlhj0ڱ5s+P0(l#1տ5wfB/fOcuE%(ř0i($m~F KFjP0-3nR`,#0HAhˋ_,JC,V;m!} uLAA&+~G3:N׼+&wpڼ {t5,hkP}1aظشoIsdxN~_F͜ˑ#3x÷]mmddĆoޖ8)dEs~|:]?>TO5"ɔKRlub=s0ۍ(vk6R_{aXQ% &2ƎQSXVla !}ygM|/b٢R^F/ }͇d`RI5ZѠwGׇh[}[A*;JOZ=͍ӝ--'K`٢GKDc@aӛQ_89ǜcN0Ktg_ao%}n]7cİ-=B3B&\UcR}u[Z&egՋbV(͊) :h[RP0vcʟ~ij>P떎Ppxjh8eeՋ iC02y\Cj9DJLu/1v::}vٻ2=1K>-:==MC*t'4L=jRR4R+=gEYʟh]zYD/]uޙ%x ízvGL~?5 >ivSzՠlPP2G ,ReMox)+aH &ÉPcfukO soC7UGƆf&g$d{tx#Ύ>ˎNc@ݗkwLK m؜XvGzKj q<1(8ܢlߵ|wlYC@냮!' H/mdtfz0F4%&PkY5TB^n*j774qCaH &5gguu}s(jOÖ Nm40}xsO1gƑ;a|oov;di$:^;w|G5Xsb)!`8qg(Jln\cֵI]3I;{YD70PCgL_43]w |-hS c' hT%-W/[O,QB1^0AhƄ nԶS b"iC7D[MM}m /_x[SI?r{7ŠŎY Hy3t'O5y ;\n aue'- -cXRm& / )ʊ +U3b6lģ7>m02m#&cYJ8csP~̓/&1\O+U\kxâbHENuR{Za,vub;LG$vWN%uUFcв;yYX]0P`dFnPq6(u' 14,-aI\We\&* K4Ah--!vp_{l: /csk Y3luFS~H'cd۳]ƶ#G:~|q=gݻ6So{VQax!} ?Lc)_hΪW|@%K.׭,˜hh}1jQC AKΊ[k5Z'2_ˇ4,WA]30&V>J8dhXr80; >m0LPAȃ[낲@o%h! t5L0+ F޽X\IǓNkka9ҙRXtG~ub;[:qz2Ʊ.L6vŅ,[8l\`g²(a t0:;j JĮxnD!p%Ef MC_0B7?K  &GC|Z=]\l**Ov1fFܸteങ O["Uw7tI7 F$:[_5$_0[l1v;NO^d!v;" :zq +gR;1eqo5H#y&^^x}bfc/7|ikY,[8'_>uX|֍5[Qێ 6Af8YL~m +a+^VN-p,$b0%ڮ{npE{z2RՐH)%c򍙏: s u6* 6W1 򍲘hTl\\=i^A1Y̶lQkgܦeQ;FqEF5}k b 0`3X|sbiŏxҍqa55\ZfRYMC7¢ǻ̚tRL޵T4@zzpڣ&̭Q< V6Kn9.̡ήQ!^1^NWFWÞ,4 F}IÊ?bJe-ROm4Y +Uct_0`gQ0AzBG35vCxՄQ]sֽUjjc&2G0kI|y̚tRs5(jx#,:Ht:&c!~3~։Xftg˕BYh4]yjOc"G7Yb?0@5 >4ߣݓeh CA7zЗ([TxjţF},Y٢RʮǓ/V5 CQ!I'd,x߿eAA٧VsޅFAS /:VGhIvQ0oGU˜VErKtOhoF4 !~Gdr^Fo᠟4ONd9^Hޱ7Py4/l,V߫HPޑih}׽m%5-^!Q>xkY>nlBJSk7]k+TàAqD'AnUf([gdNf̧3$'CN\scߣOIFs!D'Ɔf-;'RM1 {G:fm&Ԙ>^< VV}RU$, _{Ӏ5 >dEm ianHJW׶r5z\[ܳD!y#G:cD}kE~t~ 3d1Y%S1m23v6RgDǮkob=w4ʟĵ8f6CP Ka JP]J(hH}H&o\ &E ͜wfɠi(&o{R-I}F]v-7peJT%_7$A&ÈL-4J㰙pgD}ko ;49{I,=Z|5X>_OC7n1鯆DJݯٞI b2[m%>ltu8bG{R"S2&e gb.C(*tFWdIG5@ %SzFPY}p}٢R^[i5RАjYޫOSVTlѠ3>m086 ņj-5#mg|NCۦy:2ɌS=^wbh3%Tˢ|m%KLd|H Mq[3~VÐAMysQ񀷝@0LCŏЌPu?i7cŇHeł[@D6(U vjYWAo[)Dl4f,E@CO'\l#AGdWdl쓆TʢBwծ{eה ^! 2M P ]( isZH1tuܘj+:cXůXSDF]x BuG 0{"55uڍj;7cs5-rCgdt+Z2>jgm?Օ=` h(>d,+Uq؜|2r{"s;vDMMM}7'>6{Oի"rHOh`'scu) #dcYQef4ڭIbkIjo}`vƬ:{X" KE!ЏY~7^1hH06mK80dAhCGs-mJ <Cvd ێ4N8Zc5ԷI8_^ OD{_KOgt nnb'=5jBۣ(_%3<1FpVkbz* ;_  U[ UC.ƐylxhKYh|,fʟdO[y F # Nw%n!:l!{*fB s׌H4"'&:Α#Fl5=ѥV&0[o1n5}=o8j%H#!M-I>pI@cqrՉg.[4'qY^ׇcU8 Kn+U*e8hH,]3;`+_[Ie* ]C@.iel6|m _a|M^ A@A l@R-ڳU\L|O-,~LOi$ DdOj4󢼒Z;&ѷFckkUrU3-үkFHtYVU t?5 >a]Ԇ2\4ZKˊgxϥ{ccVrŅ,Y0WNt CUA_o 򅣣Ǯ{)FXQlmLy]wk2e gb[G,FdwkC@Chur4R]%mɗc! 6AQ0ɆoӞ A9&]͞˵ IDAT+st1pl DFWd$Z [TpdƳHǕ -WCJ,)WTl(|ّ,a0C2 zןn|x4#݈MC0F_0 &Èp8D8$mՂz`\ȚL>&>ΜcNHzna;b0]ѡBOH eb2mдrK!8%1 @áuƤhPG?2'&VcC}kj˭bptłn;2'{mg_t8^pHpX_ikZ{8(O16ig)_zY|ZAF3!P[' KuU{@ٵB-ny^5,t#jX=^+*IFY arq &m|-~D@aÌK'%͓O|GJcC3c ^a+ӭEthDz>@ߕ~)4ڱ5s+P0(l#1տ5wfBfOpw}蘲\ 6p`?YF%r9&%ԐJ}(4-_iX~K4t6dc1ٞHgL%zПЍ5} P/.dEŶ+_C|X A,^ҢG( Cn $'6]N GhƎ2>tqoաxj҈?'':_nqqO8;˚W--'; W8Q= ;hnkbHZ,[8E TuŗEfh((bhHP0 I5 >$PX.ƕ=NXh·4,Vv݅r)[Tj\K5|o p{WRU-ޤ92lH<'?/fNHDT}DK;EbǍ5D6;ە4>M7{ ^;?ʓ6sFQǺ%_׈D{hOY^AT#JtT{R9>q $n#m2 Sz#{fli]7U/1 rbljkJ>>ȈlOp`4N-Ed!tàY<:J>,89-% ax-klų[c ʇ4,R 6A>*ao+ALD!3~`DkkHh|2Ǔ0pn'.>dG2oZ"'ï#&pn4&֪7iG`+%E#+zf^ܬ6Zח^]YBIض4 &C((b\v,m?)1jwP0q1=ׇ @YiA3T1 N'5,IJ\pFdw+Sk\)Cb˲{Y N m0u"OdG УȀ)Nn0% [SSυ_0[ѐJZxۻjatI^6lt,V;fLWfv];8&&(kdpME-3}k4 љ=j&D5z% EY݌3 Z-]5 3M^eW^'SɇG *O|m%g8Ki]V K.ڧ|HUCoe1:)b 0fYC]  ?{u~NAg ($UIIVɢ%Ue9Q"2wݼJn{sWBɑɑ8~qJLIdQ f08e fHeך3g}6f6 $F<Ż߽<zj {dSu<£% 6AloFuԂ6_~?{x2 hۀpEW<nUl6iMd#W6rj;F#Cʿe t|p,lvf\q?ʶ֔ІMۙ6ԅ9u8686v?$a^ ~|CH}upLlX9YņqVkÙ݋W8,Ԇmw\q89)!!IRC-XB:W$I_53եˈk6ɋ/j MIvRmxhLZt!лXIh1TaJ[{K**F:(N{B*N7ű#=}ދ@F*Nu|D5mv!ѸV(qWw`xІq:-ƽ?Uӆ( =MY90׽׆E@Ita6dta!sRBB6 A5pXT5lhӇ@mA8E5=h:jsij &\=Gy)PÓ٦9V };Xi|$(X烰J2`Ԗ0^ Jb~c] *n\f_?"A8Űpy5*5y>wxԆ3zj{6{6u)B椄$mKFүH XFbiOv!0F<-G.^xu׼Zu1I $.x?8)5+a.b_)IxfwnM"-p]xދ J.TIgyb #w󷴡j1ॲcqg.AᾯpІ/|xm [iVym89x|5EPiépj㰐9)!!Ip,mAŒo+c3IjJ4uԆ{*u`DhlݢE = Kf^3yٺpqOa lS[պoi,Sm_8YZ{ Ϟ|@dB 2헗',dNjbUM[mNņjsRBB6 %qt#QuT-0pNұ,fļ3^I,8)yRTx%hR_+eCey5iZכ|br1:W/ *8bnUKe|/|x-Ox ‡ע]m~Zn%nzϺІe[چ3iV_Y6jC,hՍu8椄$mK L#?/yG8P˚$Ns"KoT-iF#cg>j[M85+Z#B`a>"o[4EW{ZZ+ڹ`tfg*\[D|粡ׯ7[ɍN#]l h-~!n=jK8n[zY*cpa hὸaT+?6Ͻ?g'% ۗ 1'ˬy/*p6z I XIHC ,?`竭б[oС5T&6\ǦBbf Sl裲}tE+,Ԇ <1`6ھKfЗo"i$ոT\h Ҙ0L>|Cg20v? DlUz!I@OEφP$vذs^TmX8꜔ u]<^p~a>;JHT|?x85>ҹr{TBl/xCEP UI4a,5fS*28 ͫ7~z)H2⿭2Up|ˍÛeÙɠfKǺWYb9y. mw ms1kgӆ8{NoNJHI$$f?Kb1%]Pei dvɊFioÇ@2п2?* ¹W;*.^/#iȂ+Aw%0u:(7`C8 1'-nEtK1:}R?,nG 哥ۯU1kf.KDK?f%g݆ ?sFsRBB6 %'L#'̚82/F$#MJ$JPJ;r߾TR r *x}U VmWM҆Vz.ZU4\U5H5aGOvgkLd$v^lm3& oڳ|Cgy1z䒯|7o9_{}`y3G=ogC@.[o2 /I:eeNJHH&!n$k.\;:6O-=bXU GH\RYR8*{Ok^T-<ֹ2[*m0i:tf)Ÿ9sp&rqdպ ,/^ֶ;-ݟR=y헇[7{]9IY`CYo ++7I G%$Fzŷcp,BaS#0 9ֵ~[}skTY}х3 9a](_4#(q6a!tbBa1Jqb?@lǸ׹Sx>y?_h7Z0w~<_>7Ma9)!!IR˼@ȗYaZfn=N+HeBt,xOs*\ *=qsSiTYޤS#͆@X_#\OUXyo*e]Yikf!(qǡVgr/cN&",uKH4| >->-:Uz߻ҹ{^y>|/;?ӷ ^7WI4 &!Th>p±1 Sn40 9%,S#0ss#5m"e¹S'7]dpp{, D P)ޭv~^.ʜT P4ָu?C2‡׆^hݟӷ; T?LYh\gݿ sÙI IYi$2tf/q̃ 6L# \4/L]t_Řs/>[ckʼnUҾq[Ϩ$lm(yn|g#v5l~ϻ?ulX9)!!I+o m ±M(%镶Y^]jZ٢lZNCc낉N5QZy~%Ik3m;j󡳭(ҫaİ͒Y5`qxhau*X7 %Z}1'z/cƅO_UmGX )zй2Jwꚪ. 5W!8pDZ0 xi!ZukV5 WOZe]JVsEׄm=em#+ڹ[gPl"6Dep,4e\R~-dM/[-bx.C% _W,xٛn:Q088Ħjj-Ɯ\+\6쾐c~=ˆc} ΁ I iX"88\se=X: ~Sّf_ߗ>t\xIi=* r}>&ų!Yȡs-~GPEEmͦ˄gsE|[i|<>8DTUjZpOIO߬y/q{1 aCĆұ IH,!T (_'lA$N=*7]$`L8űsfentláIzJv* ~eeES) NCY3骞(Oo׏?{QӬhy/ڮlXȜMBb)"_W(d4V1O*fo(coOmq\p@fuǷ܆j-T[6_}܆_ϲa!gs霎SWA\0|xrQ3 I$$5?[؂님6-(Q1 SXqb:Xc:EX:4o ']F&iC`CT,H9!ӣ8BL\C4*a !!IĒqyLn\ IDATo0EHa܆Rta:FrE8ljw}r>,1$$j@ƴIH ? [$2hz58;hYOa3عsh1{v37,m:Қ5 EJϩ]꜏C ۂk:]kYlK iXZ0~MGbb&76TL{r1iO]]x[*JC3q4ɂ1Ny۷Мn7H%(xduUK`;mIH,%NP5XÅ1Fark)*L S( Gم"Mq,iC ̭_`jj*q6fY޶p~UXıLR2X`0 yUb*J]sب%jtik1Ydѡޢ҂6 +^;brޗ0z"KTI6 (FD"-L 04_V!\ E>4aL(* iC D-Rtan۪H̪ Zʣq 1F,B4l5yqn R˼1I|u,E-h\)#>߸YS3dufhjl ,s TAS/~¤EIHHP v}u_p.kf D"C!w=ՄFE@tSmCXe1 1Oi=UXs:rhėNX@QJ[$ 2Q$̣BiR+.Yӱ4=-pޏǙv,rZ ] 7~A7>}y܋dL!X.d:ZUSPU'uuNj\qu+]dΚQ5M+8|k)3LƩYǏ-xNJHHORc#ҨL$N6e/Ƴ+k!L|NUvH7+YWʎ=n~UˊȈםq<1\ˮt].Bwq]pQQ?hSg*0WB{p÷Nzl`#1_Ŏ?{o"r/:!/!XEgSĆwnGVm&ҘSWkxy!, ηe_A8^?}~'|4y~z3eYȭO Sţe{d=k`cruk 7}l?K"Osi^{Q0tŢ>@pe;uй r\G0x p=6?GL]QP\TG<ᆰIڪ{jjW;VIjN$i8g.7XwmG-7^|O6NyR n ͗P r?4б,#\/@H7MeVVR gbÙ|ŕ]k}W?~z'}cNӴW.mon:&&W/\LdΝ0ҬĆ.w=V{nGJ>x6#Cj0}'#,RU5p5ԕț: =co h'P/_?~'h2qh =ObK.×}" >R# sZ}pضmS(6\C7%t3l~:^z~?;4!3b11&ts` ~o|k"s߶e6HpDmGeߵR&qIHe.ҹ2F z4;XHͅAnEY==lٲ^nVJ-[W;^vdɯjHl깎'^x4$ma`a1m?/Ncx7{3)-Odv|h D9a9$]X5Ru*|tǫm*ܲeKM[vZPV?(]J:f2eEw=6K&O{Lo̓3/loO^@w}큧OoʮE*̌@jEŏƐ9p]Ƨ47dBMGظEi>w|a bc۴5lWt)Eꅋp\#7pvϚ'xvAc9=\^ca;^bG~F@+j:6H¦TcEEZu;48Ad-0J&!!1Py'L L_x-\٣O^KՇabQ~zaٹYeAG%akni8xqn\~- `Ç+HgP*PAY6fZrheqXDa;߿!\,ys;D՛aE+eLۜ(j] ύjY [%M6 s/ .JՎ-ػlc4 -DzVm7|]`۾lAiһ[~^-m}I ׷cǎp{Ck50 vV~78IeѹTiQ=3ѶU-gt-ygҩ 3ojjzq )h>%UD1yA2j^ACΡ_hu4d<=T,s*h1X!"WE5b&>ƲX"Uk$}Z)T5 p"{!{~NR 6XkWjke Q3vY4mk7LqZ<*S+c$$$`9.Nak[C!pk.x s *tO)֖h^ൊ$wegѝm۪ qV'0"јh\_p|V@zca,G@jht~q:QvΡCDjetb/﫞WGTϣ*ܐu6a1+z h8'(.Su±qGܱ^ Mh'Y\; )>8<9W8Z˪MlKܠc[NL3t$aj:LǟXA 33Q) ḭsS< %4• 6~afƿ/a(z !"ZdMQ28`+hp, oԷJl$mg4jYVZī.޽QUMSk7ŏ+( 躷xUWra\s]8r0k֬֞+ٽ{"ُu~;޳j^j[[BXf0H1T-^EVC QeiYQ"9Nt @&1}ʷ?7]j^"Adž 4=/@)hKI9 u>U8@ࠒ2?Q+V Q1_] T[Uo"ۯov9WtBL]G^lO{ښK!Dqɋz*iavzP`X# v;زW+ mMHj(~/K.EQ8p`Mou9p`#gvilڤby477MT~-燐΋'uzkUU9q(W]u5pa,K _{{;I&뙙817 90k!l02|㑱v˽OD. udy xl_MYjaqu%'qppVS N%$8p,P4T=齧h(<υ+@U<cBz7,-J**[p\z$$$JkC(Sq b>,(w&BAG;s4J0>>mǩKwU8pys-ނ:00@}}q:;ߞ@?L.y;; "C^`~vYu--| Uv. c!EG5N243 Jq7 doE]WU㖼g*JT !faMB\aP Уʶ6m-c|k]&,[Pxے8˗yܹ{n2$Z2J$bb:;wRa^6n<.z{ˎb:]]={x;/|?#ψ~66fM YFd``?%%7D+DDZ{Z+yT6~󵯓2 HWWOH2X^ [ U4Ds.5B5Yt+3 ;Qb>b:}T{tڗ[=p]mxuIW5gdc6g$u!aOa lS[YhTlrr:$VyOlYްhmW}d>%n+[ojF+9 mQ@.i=m'QϞ~2ru+'3c-MyZw4ϾyiT% "F 7I$$2rcэ8G--O{ۢ+\,t,K1b prAqĬ}$SE۟I9ӱ!K ]NIX.ƺV!TM/ 'Z=pUL"RYU $9LUՙ(84db޶hy0Ӂ9ITՈUj[qFEp=l㲮,;w{ln"㺮WJ6pgsywI^?_rM[<ΚwclyK}FcڪɅa{+@6 sDE#U(iUH~Glf``?u1 RQVUS3! YZ#B`a"|3m?{.f(z\Ǧ>2Wk«8qmp@:lBU>8{WҌNYlhK}rKq V|$/{1+oO`Do׮Or#ϼ8Q8=|G︰vyjh[0/+[_$N6 L,zTDXV(E㻢Dm>YEzS)S%h !y[}}ek-~qx=j%}j[syOP$hkhxTN{XvSU[Kpq1R1XiFp:, UOۚ CeǯiHJ[fc\{^#Išoc*7!FX1'\aŅdpMT\c2o yk64{##E^XY&S޳'\ О]G{deIZ_Ͼy:Z #E3rWX7/:zD6d]|x9' hyfA٤UY^u],l۶Q%TGB8Nm YU.*G|5&PEk|7ˍHx mp^:RUsf\cF78pٳ'\,Nh [iLUH\]Ml.$8%QZh_AM=בͦϸ}%rE+G_&ҏMGIhZ, ؏?Y`tXm𽘮8k8S{Ǹ`Mw]Ԅi GN~Uj=5i.nWF_ᅁI޻t\ d;%x`o:ή7>V6yW'G.;~=?;_bmkW~d:E;Ϝvgy}\C۴P)_v{4{O}Ό_;Ϝ!siTmNY|cQ8 )+ߴ{6qf=޵Uq6 M>ܴf[ [l Fw)b֭[N+MKk~/p;oL_ZGL?1U~(D>+E0+c lDZ׎ {= ?x$Pkk#؎K$3/{zGG ~(GPY"oq>o]s^e{ղ.l}ɱ-͚/N"3*HS|sKY{N;28/aŴlGPDx d ^>xdgi fk;:MSƠϟ?v\^=~/O΋yr(epS{Ji1>pr~6:A7I$$6^R7T pPUDjܳsoN[y {]֝G>?E]ke[-[ms&+cƢhG3OLlhiiX,i9x Ǐ_=WXEETmQWrη8, 9IlEŨ[SXmlo1lY/̊zp < ^bUfx]DT\ò:z,{o'Ey٘mfPqq DAW4q hn51~1.Wk@M&?ܲhp₊ I\b0 0tWWꩮp_~MwuU駞3<Z_mȧ( )Bhykzʼn-LY+tԖk+[=pweִd\GG]=m*gwڜ| D=mCz-8gvv &mv\}r0[=G=w{>Iq/35߲{n|uEy ɦ6Z:۞}8FEڗ+hݍaes 9WO ɌWw1aT ">}:CKhzr|Ɔ|qD X0m7HAwAnO\;rl]W6;6e1y$e> sk'ÿ.eΈ0:/#l<siӦdN ^xт_#bzEh}а3 6`֦ 3wnmQǛR[[C}}--b^lb~e)چ|eZ)aܶҢAnOY;o_6swXcFד|㲟{*SD۠cN\=i㍭|qϯ:fΜO?M\O±^ad$GA#^kTQ5P e #{d:έeRQ12/͗]`}*[w-ϟ U&sk;`YӧODz,䓺<}`_3/<+ʼnt6oκo/E #N5f-/fu+Wr?eum/,'WD ewoF Ԫ1ad1JTCg]mqDD:inn|_lunO {$ e}`&uuu<̳TWW]T5hs퓫/^`M[x]#jX`%65i*'Nioxw)>esemY7z|Ce&vnlv_ʹ]DoqlܸEQ0 /"a܂T(B 9Eq:[3mC62nx>@B:~"y='x C0Bw0-:Zvk;iD[vH贶vjxLMz'~LliȰґ<1ӵ[4  G9mٲep xlذx<n"a/c41 VodШRiа@ je̝;:ƍG}}=` =#q\sb$y-$޶cWuGފZ<~H?r֑ / `sq?$H$"A8 #T IDAT $;[۴H !a'%3oy2oaN?O9BoQsg[_K]Ն\ଘu{l5b ڷ0obo̝;s쫭I~lx˛d7o>ߧ!0dʏ g'r}E߸p*Y8t6^LBy_/ʍ. 8u{WD"\ym +"^fݎ8N6pP`@˘-،Xpjp9s1~^\giwNĈ![;d-$Cjv"bumtlM:a„%7źqVX;X;,}4ث!lm&{Ι_8>4.3wuuug_ߠ:7n4I$SO=śo'jHٳgSPPaia`Ȩa'Pq$3[s=L/fذx{~T.䷿'+"ܵüُiC^ M/ؕv[+ZZonoz"[}}]:\oRRR)O'LwT}vNjy ζH-.[O})+yF^+Ѯ.h5M#`***3o6~ 3f _|1_}mmmzjƍ~5װ#FpiO#0w\~iJJJXbmmm3l0>h}+lu:]mm \BabۜlB3'T> }!Øf`A9ױxey,X0?ԗT;[1^V'<:k?!Ul7kNOΈJ,̣Ϗ/Yguf &YVsqpgH$Bgg .~_v:M7{:*sFbΜ9=M$BH$w9 J1dyz!jjj7n---lٲh4J 6}R'~vLCǴqIn}^!ŋSsCek4C@x {^W0:HqRbeU`ıǣYq[? d`[`~Y!9sl]]=/aKy̛77tbeF{> 8oh#M=vmNxeɫ\DUU4-:y*ƍGyy93f`ڵƁhO?#8w}C9kS~SO:_)++OfŊs]}̚5;:<_WꫯrGSZZJmm-w_'|jz9կrI'0uTjjj;\]f ӦMR<@V\W.nj[oEss3mmm|;ߡxZ,"F þ뒊MdY0]W.۹ ǁ8EXCj zx=+ zLʯOQQP(HCCryz&i_;8Ky94nhbBe$;gS&U#sN[,ܹ32E3E]dnPsܹcO?Ͳe8#ٰa~8&LSOe̘1G}3fj*Mƈ#5k)..fi1ZTTҥK3£nz;u]رcyg|ǔouV֬YC8k׿5<_~9+WYO G a&Yո턢v2B;ڂ g]ѻwoPkf_96F¸zW/{+5o{}Rn]6l[bݺu9XO2gv:wic: ᩿!:Ss7egKӠ7lg~_2|pB7|3uuu0/+WdĈsGryq嗧߿K҂ ෿-_='N$s7Ϧ:u*Gi:zh.B~p=psgipx ~Чy06l`ժUL<Çkm66nGuK.;v( DB 0膅Ītad'[z&+Y nώiZ3W˽ܑw[6Snm[Dj1RlQwOah6u\7wFW9Ńɹ3x63o^ӧJ`u-;~j _ÛW;>Æ|_?#//s'vqA"իQSN9%c{,ctAM4%K )//~eeeeYlܸ 4MקEN0yr:x<ÇGӴ>\;93ikkoO{WIUپ};---|_˲hjj'? '|2pK.Œ"aol'R/Y[>y֚Us-~o mC^:D'V@U 46hV{-Ӿ~*D''rّv*p1/cO,]Ն<~''_{K1#& 1!#Μ˸{_;:~KoW?L'i۱(FK#F[0+Bee%k֬c0 ֮]˘1c\O&b{3ѓurϟillsn[o&:rX,}X~= ԰{Zg$<*{7)INBBgx=Hgnˎ[8YV-5j9lb,p឴/$:jLGv:RنDp;\Zm|-mћeKc{;l<,>,^_845oyǠ ;3o[όbgݧ>P{yy9h4{kjnnka͚5iSPP!@#cǎN8I& ㇈6ATDzGz$:\w]y{}s2^7푚>}zz'<@ڐ++F0\DdH%!Dbşwv³^O]6?xm ۡ|3Y;<;5׮zfΜI'Ĉ#x7x3Œ{./eee\x~v }wbC?Co[a'z-^;{yv-M^6 ˿{%^Zs.`G _2mkzqG"HqڴiB;;#я~.~8ٛnBr rKhΕ NkYgYgce]e]{s.B.ѣGg M-{QBNW.L3 6t#Iw)w1}t,b„5\O#'=9~Oׯ"i=9EusD J> WraY:k;߅@ L[vpιgca23YēMX|3;?AWK4mN*xw[c;b τNR?/w}\]O |2е!2LS쮗*@m^PTd-}9`ِO;x_YA 4 0loIH>Пg;\~3Sר`0>Y#o-HX{*yg ia)!cXXMI= hr 6Afg.vl`]]=/H{Ixhn>naq}h}=gίФcjP~)B5!|mo-\acyy_{AU5>+$ }_y<흄Qt$+4 !9m0HxT![27$;FͼUWWϡڵkҢͻ SDslxs{/HeZ,u ͫmcʆ|B/7*+r?fÆP;i,0F /eJb!F9cA\yjߚ} xX0̙rL0 $d0҅XD]׉]]]޽o|ҀO7n$DBD"pƶP(D8& _ h׊=FqYJxT6ߛ xv,@UDd ^_.f~gܸ)TW%oc L8ٝgӧey=7W6I6q*+G1vXB0DuozNSD=U퐤 1tiar_ZZZhj'D8ik֭k[DF#覉P4.E ى;[̡e7[(--󽃽w[lEh|֯_ǔ)ܱ)s܈YRMGkP`LJm3φ}aOuQVV<0}XPIm?~ea? +_>0,Dm0h1 jEmqF'0:(uxj efm-Q./ P]sQބS}w.U$=aCvHS6U RDG [03e@u(ԤĜ1 @L~prpr,_0c}dbXphD*A£ρ6A IeLSٱ 52{0uL 75e4-5H9ح#2&}m1żnݒMZtHv ~F PSS' ն`g=ƎΫro6f!]p% X4^ð`[IҴzraiA(;,HletiDg[iC3f Ǐɼ2/NXO=SȆ),%RX @x(le}a:ưz>U+y}S5NdG][lO 8iH먨Pj(FHղa )#HOb5k)))쓰+i'sؼGl0f"w^Ya mkS^^>0;Zô`kU[bR ;`l$"6AތUcbp=bwVR mt!%֖S""[ Gtä } uͺ e{X}maO ˲~6,\nrZv3#k-S]ǗX$u]禼[C&M {Uӈ2ԭD۵Ck&Xh*uu̝[#[{4%1!Gg |je"Ͷr{u=z+!\ka :-׵!T-L pn۔a q{~݊G"?"W_M[[o?%\† a-[0rHoСCVD I(êjA S'ٕ@ |ul߾Y@@vb+]^s +[9~o;P[;7SmEw]3j-W&"+κ]/oퟷ jkk;w^~˂Fb&My-|mAI=bqpӂ2mmo&ypUWquQ[[1VG?˖-JN8|};p뭷l2#䪫⨣z7,?y(JzPUUSvos^;+qGD |]nABp*CԨ=IalmTX 2id&MEQ5CĖ{nZfI! ~~aQ ӢeHAo !}/i]O8`]ʝ,nZ=@:h Pk':RM:;xBG*@.Ä#z՛)/)hkiiaƌ444P]]_1e1}tN)//_|3q/^3g|W^yqƱk.^|E-H0vX.b'5%r 6#&=1 VodШQiа@ qEMM-}'2iRml|'皛eH fbP)ALt~*znHU^Mel5k߱c0a Zk'8dTJ TsnzzEQB\v\p \}?m۶f͛GeeeCg:_~9<EEE'?+HwM7Caw͔)Shjjbذa_QF+pI'2{l$Kq=W⭚D IDAT\mϟ^XXȜ9s3gNzW_ƍ4+Wr)pꩧfG7o̥^ʲe˨?D[lm1$lIo"E3= =-!?AZ Yňߠ-[&3_ʻ9­&}@ِzl5b 7qsDys{|!Wy5|m9j몪46&OzһVT,*+[ki&I$ E +V`۶m|_`fނ `ذap̛7sraQG|A^{3fpꩧRSS7{^x馛8S)//fɒ%|[⥗^%K0{lz-TU}k֬ᢋ.}o~ᮨx+;l!1/p#sĄ6x*@mմ sۯ}=P]=!kVdZ%L[CaUvx @Q(((6q*fϞ+֭[{=zt^!Qs'rw0eƌýޛ '\@$NcҤI-_='N$s7p'd,YM7/eY,YO<1q}v'`Ĉ釛~i楡7x!1l0K~T~5-߰`o"a/QK Bj,}k6קy' (sEoKQK> =eCv `/Z9mYeaz f;dz楯o._^>}zy|$~w>ڡ0y}]HQ9HP(VnO[8Çg|ߧ뮻>KYY?xwؽ{7?O7o^u=zt1bY7nd„ קE/Ν;Ϧ%Kp'dtnܸ13`,X[fw^6l@aa!ÇwQuW}śGa¤Bv%!I8BPR|n[ZU? |>7 4 0 Q@ŔKF0 ?^E8z-ܡ}&T[> |>HtɴMI 7%5%Zwc`$^-2e > s^3\ T:n:ɿ@"Zf/NIg[[l~ڳl,H\x!a2CH!Ah*o5[c74M à3A8b9WvvX8̷7ĊH$ T=W_u K._۹۸ 8q"icvZ9昼qs뭷rG3zhnV,3 r1pwrM7oַ1b'N*^f͚E8K/ݻwk{VWWs1pmq7cwyD[_ycB6A.6V*ն H@H"!9# &kzxh\v,sHO o`"kgh! vw# 7nhbBe$;"aR55 !P0vмys3lS6QC-s[ 0qvӢ-{}Ҳ6>URC,)XqzDO(ڇn(|dݺuA&MC=ԩS:_atI477s衇/fjO>d^}t(O>;8 ^u?f9yw]?p饗r衇F5kO}ncu z~k0!33 `elx\Op Dw[y8 y67oLIIA΄z铖ށaZգCE6ezʔ) կ~sᄏǶP[n[n%9,mrGOiӦePYYs=5\#9Dwn[ 66A膅Ī"\d'[zL Cdqw%a|pdn?lP/ (x6,;S!3C+?-;7s ,2'+رcٸq#jP:u:uu:7a&SN]FiСeeh! K2]ɪE=d2ʖAN$*h_*u{Jh!d{FIPAҡ|G'v0aDa "W2 \vh(p12{6$ZԆ.:-O \6pXNH@#mC`W;dHQPewzjXf7ng͚XBYn3@eqA߾i?>Ҳ(UUvw ee%6%%XvUUc1 2s nBIIaz.[1>i=i!PK}8-0L SŰ /QY-0p։i lR`L"a/)T@$-4d@(Jv͘L!Lbz6z`!1!m7ͽƒ)!d]tt4եP\cRwaYcZB⤓NBȇv0NҀ3Wau@CjJK=.Ʈ];R"l%ÔĚho"ljwu"hZs7A7UB@')7}i*MD +g0J:q`H]SB5`kEBQ(,`ƛ!Jbbdž\덺 Q[h4Dmm-444KT]JHN;-;9"PǙg~˲hhh  (شi5mb (XKTk.Ap3- źU+hkC{]-޼!R0`&M @ bTWŊ+Ҟ }=C18sÇ]wmD -L(Z3$;P zm$V,$"6d@Zjgaj 7q TSSˤIٷ/ZV `./"55has=m|mpq2ֈq-dHr=VLq{ #憏J`hӟ$Dp zzn"A  A0 ]fU Ale"  E0Sti۳c?ok#RP"6iktp'58gņlBQ*]P{N l[bYTdLR0- T1.AWW;IS5HRO`9dsAC0Mdx 4/^l{MP4)P#i0dH;n0XfʅGi`qLڧ^ ?8l]ʯ[9ByBuQm0 #=%&T(Z.`F2-bC@5vBŒs;Itu).J $MJϺb[9a$=È}%L#P6v-,%iYD+֜h,A Ivt*UI{[3'-JtъLa$u`d0hMwf R(@ѸohA_5-j*񸎪]qԔ4 G҉*EP5˂h"= `YaTpAq߷fGC=g3wh3ps;qF{n BmYSg;%fImE 3\bh$_cm!&ڧ{ mQ@P#F9[ûF,۵H$;iXC#(Z9Z,bk0tIaX 3r =۶;bXPP,¨VTUcW{H)fŗC2i4 JFkLdM )uw EQ dPDCqH0",,FfJa$ZQ4 -HxM ePQF+(agMґ{ /[oOFe?]H^D D KvazgwǔM{1#++Hv4a&XA|w!ğo6єpobno[j ˂ L4Rv8#GU44Ma\0D;h9vd9]h*PApA ]1T%θXr$nT9LEMg^YQhCTO(ԈS"}jj%;bA[OO_2Ap;7t0 M2+"řM~GS3ڮe ԖjE F0ЉҀ:4UY>CMvtOWi#6hž,o-* ] MiY(VTP70nd aL$01 uC *](kBD'ZA!İTTD )):*eڟiZ1dj 0$JVpL#Z]-(Ecô0q9!%""C7s\olp-`sFE >QjԄdu=.i0VJ;+2sK(/6!WoK^^}t{ۆ\BIe(JHzp#2 !B8V4QDj@E5Uuh0 0R^.Ӵ0- Q4f@(rn3fh5%H Q@*@'wbbI ؂}  C{Hܲen:PDeql-|G 9 Xؐ ӧ> 6z-, LB,bZF~(3&ð3 T0 4MTD3MJyM2ξtӛ <+ _pkf p9l~n./MAIJnψ]k9NQ[B]FJi=D5-[Oй&٣ r@kݞ9UUĚ&'؜~Oe{xP{& +^_G9;a"7?m"ڲq&޼Bys"MA#i5q~W` 7Wy\}gm BU6ps -`睯'ԼMS 7߽ Z.6& iPup5sMZp1nO[./Vqsy6Ao2MA\nm}E o-KϒU` @N6ZWلX_/X므l%MA\8ps5̶MMyŕSmil}E6AS 5?DW lMDCem&}6As#ܲ ]g6&+r \,|'MA\ ě7||E B._Ai6[5aO $D 2 E&AA&  hAA&  hAAD  hAAD  "AAD  "AAD  "AAm  "AAm  6AAm  6AAAD  6AAAD  6AAAD   MAAD   MAA$i^H 7 gY8s }# %$<*  MAA&  MAA&  hAA&  hAAD  hAAD  hAAD  $>Wyt$\pR58A  gI=rq*lC/& '{-<4Lx+I$HJ  ^󴙆AgW8ab  gN&]qea"AAh{hI=\4,˲(-ޥ։bYDCXeYh*\48pY|GiX2%Lr|AA>%& i@, >\8i_L8a]33mJ&MD ebhA+DDZi٢ʹLLEKwע* e%=`&dih3#2ĝ  N)?>FiI EImC+aБHRRrdUȗTM6 >o~c8~OERp4m<kW@F݃Z]#5>1YsY]I؞ԥb7&"[ ~=.%p7Q߯9| Vr/+v]=I8ݥܜl}~9_>DF^ܹsuQ{F-^g۶jjXqmX1Wu_I9!WYYYԵn32nժ #Yf$|Mr5mZP5005۶8lۖm=12/u%[۲$XLܵh3(H͛p4w$7j(;;[|_x<"cH+'uXX͛7e[`S$7,8|L%iim[`Pe<% %?߾w\7luV0* ) q.JCfmuݡO Ϯ9,5,J-yc e +*RƗm CəP($qRK$kx_Z`1H2FBᰂ2Ȳ,5 mwhd4+5m3ɱ D D D A`I{rW/΀ܡHnX5sJ4ףnk:F~IQUH$ub?šrdP$!@z:}^{Re  S"7j"3&m2xҨ_1Y齡?` ql!#'5̴6{ˣ`LƘ<:00ӧܹszȿ3m`Jhllŋ|EQ߿_d!TР_|Q֭өSŴw^"x,ŋڹsۧM6DPHhTٳG-cР2E"-[LON=fKKz)PK,IڵkڼyTXXիW-c/]KD庮֮]TIDAT?~b;Ԥ>HXLhT+VP__$izWӣNm߾=uߍ7U'NP,SUUy?lj`L޲n)L6D֮]+uu]RqqJ$ԱctyI~ڷo>씪6p}y;6CmyRiiIz˲4{u}>ܤݻQ4@yyyڰa6o~M.]eY[5񳳳եJ 2K.=zTk֬3kO̙3vY ,$yeQee1:y}vTQQ!IjnX\S{f2wT[W_}M߯'O^uڳgZ[[500]v˗ippP$E"ٶYUWW^zYX1z9D"1"0QmL7oۺU:ڶmlVyy~^_GI37L&jӼyG[|-% 7'K~wڽ\R===WEZɲjkkSO Rב]/T<>ȀLo U=}ٳi`~N6c2t8 2mCoQmiոh DZ/M'&&?KI[r ?*ˀLPW XDHܐ9uZBlb`}~ѧ\'W~xⳕD‡עrퟗ p[a-)Wqa"9ϒT hz )@%K3¶ &lDWErIa8@h @h @h ~Vmm-"01@ v~,ZԅIENDB`tiled-0.14.2/docs/manual/images/terraintool/05-editterraindialog-edit.png000066400000000000000000001767111260670167100263030ustar00rootroot00000000000000PNG  IHDRms pHYs  tIME 9+`x IDATxwxT3l$%Z(XzE,D1;l-{sQDEzA-޳}9YHysvv̜;;쳁`0 Q!QXF0 Sl"@ii) `0=Ja`0 Q`02 t`0 ȕW^yKxdz"##o>}/o=2LGckdddxȓO>YVV>&!>!EQ! .LKK[t׿e6۟硇?~==+Wnܸh^x nZZZzyQ#t8qԸnz:{Ji%K:6f49ӧAe5M:$M:p`ݺuׯ9ԣG?]wަe~7&$$ڵr|r}w]w}_G? (.[ |bq5dffJTXX|LByۇ~Z>߯ &zwy6m֭VZ:KfϞ={ ʲ|WgffX^^f͚/W^իW_|F?/--5kn߼yoI;zj=:..G`/_ k2NUN:qDPU3 999v!t9焷Gןv=??o="½믿\'w} . 4Ό3o߮*<$!!!??)33sذa'vlڴigy޽{hMvdpTVVʲ`4555j-/򒒒Ϙ1:s9g׮];"Wiv}ݿw?CN(}{XQ1NTG !K,4mYYYm/rȑvZ!+//_z5 2dȑ֭qz뭟~)BOIIME?cƍ֭9rdlllCCŋ !s;v z._ߺuŋ~ǏOMMݲeKgwEB etSGİ|<+yTUU*eeeokd] &&sssqqqz6Cxk8 ժjZ=Ok(++#|>0.hP]]1J$%%%` #^F78u4''sz \p8h տQBͻxhOۣ˥i?I93&MT]]bŊ@  \~L[k;L^<yDP__ŇSӴ6uݹ#;j2'iӦM4{vrqqqr>|xj ]v׮][UUՅbر&11q„ 呑C]reZ=8"I҈#t0-iߝ$4|ǎ=PSSӘ1cTUs;,WGw7 ;b`0`=o`8bZ8ٳg56m7n\ͣ/"111===##cǎؙ{n 9rdss}ۈVgX~}VVֈ#~kDnwt$k0\dɵ^\XXhE:u= eo\]CI˝}`0  `\`0 a~]`02 t`0 `0e0 t`0~e`0aW6`0(`0LG `:`0 Q`02 `:`0 Q`02 t`0 Q`02 t`0Se`0,˲,O˻88Nt`0[RR~/uu'奦I"# oLG q%%˯:11$>x{|,gP`kE$%'A 8>(iSeS9 ""ⴼGQid3otT[mȳ]>|kۿMMMl\\>},fq<9ih!F1W`\[StN~}~B\7=6^5i9jH]Ѫ۷pq555֯7nj=.g>۲!i  J.yDF|q4 !d#53 Zxzt >3EZcTĒmO1uz㸸:k1Kic6ʇEZ @8  7'`{`<$g0qQSxh㕃&`|l,Җpw/ynzLLLyyyjj*822rرyyy"ljHJK];Ue|!Bli⼹e= FwNF"5iɞzDBls~]7|MdɜneKߩf1;nV=dG~fDΪʪFJonn5jԱH)B۷{iߋk䓴 *8C !Ϙv! ؿ)U C>4|?pAAA||g̘未Ο?h4LOO=u7x#%%4lⒼO|dK] :nM&7EEԭ$S]P__7tw=]544DDD1b gub=UA p$n 6Rml/X`hERz뭷> (-Y%Ibu蚨[n ߴi}/?^ׯ_rfΜ9sw}wÆ ~{JJʸq~gNoy/^/O?}M7" Ǹ.`;SmqAX9(>?'73I-_Ss_}ըQ׿M4yȑ̟o我#{g; 'ٱcԩ29rپ}Ǐ7 nOSss X,ǖ-=GCO=vI0 _+*OuZ<x==syd0E:uqg~73ffz.B}P3ѧٻw/u|qg;c7l` GΛ:ujrrrիWO<.Z%I/@-XfM2eʔ)of[M)-Fnll'N3O 00AlQ@eg#d2Mp֭[OoΌǎ=_}kF#7vwq܀wW5oQs݊,T{-59ve4jkj+*QҞQEzCk8--h Ϸa[믯nH7̌;.}:T2HUЯ_?_ .h̘_~՜9ڄcvv{xxhfvnvʔ)۷o~g}뮓en|W\q̙] 4C?#<3`=裁@G.[q\E: F[>ٳ̑c)ޚ^OE~;Ɵx*lwBSަe92E9,#Eu:LFSScTTVNr޻w=HMK_d{cSraO0!Svd2:t`0WVUM8:xS1`עT;QI䪪ޢ(}L~ӃĄ=9k߯m۶/4.ljn^ ,߿ҥ3g^,)R}},'WWWke 鬮9s^D[ 2e4aai>R1J1J9J9Z9ЬV@yU}J/%E$Api@M0:CmnvDG;UN' ˩Wd2<9ygvA ֭+-=ĪGӴ`0( _K. .RUUk~7pCg'O۷wGPQxf7wz&Ƅ xϰX,II_| w8}…GFF\;XWLlN+w{#j 堬]v(*{yَa%#Z$+,.:tz͒ .`0Z(+]O׶sy7l1uYz_֭[>4͓'Oods޼r8<;gaU q{w_sN1vؿ/ .8pի###n^G͍[xqI/:[lٺu5k%K<ɓ'SQ;3Z=\wg]uX[SksM~[E0)GX䆏8.++WLtYYECCd3Ln4U4pqGyy`zGGۘ25M=hL1c9eNg9b(u,k&$I)X )&E%`h89FDGL+o!BX~7/dCh#rǼ+4 ;`5(J& hnb5Hm~fCւXSHKO;OJ/h`koG3{tk83(gdά*WHoƐ: 22'+n`ll!`S@S>S+8I&;p< 'JFހD T7%fP@7M7>kxA,FA|2sL"!^h ~o ?LJsn?oW?E[p޹n1ލ$4ZFrfe_zAw'+`:R%K1QF#N @XxC'9r\b , ) bsǓdC`B0bUC5M >TmѴX;BMth36-]{AXS4:͹L;F^Yr_ݘj+PBf~`wL0Nqnر"3UW|M*%z.%I` :p *0.\`Mă(У H@CklC$` ΞCwZȹ,}e=wϹf gK+]"@ܕy2E=Jл7'&ր 7E@v!,a/L-]2FIhw)Qep- T6CUJqHUq )Z|,qnla$#ASoj X!,XxM/V&zmw䴌Ĩo̙ιfvUAl[RR34TXn-SEN V=28uTW72 IDATQ!O! $I4 d`.jkc#Bѡ4U^WdbÌ#`Z$UC}a%^"Lx Y X90 BI"h <%.}#uY.[+{`G^k0[-(%?T0gDBc3{ut&XqBƍ<5M"/ A9тe/JKK V%8I? t !no5Ra;8$`M h$A$h x^ZFBt`;p:Mh2iX2t9F( .n5ӟV~tk@K9p Tl ̛9IYvES\w&:Vg]s˙AFmm Ʃmi'b:cC`#`EŚw MQe0ɔbB`+0Fz/)a R> w 2 GpT;\aDsJ[Qi,OlՆy3~O\Qiά1W7nK и-y#BZ6WTMëoK?\lG' `297&N*XS4L@+`I o} &WcsBFf%/># h!ջ^E'#Xqd( $5a$5HV!A2ZE] `%$cB" @%`UUUU_5tf}^8)AMS*cb`BZ룖Q%ChrĊ˩j~3@4O0wХolŲxOh灏M\ur00"a3p *n OyZMd;^ݨ-{RB="!q8&},QzuS[*4>&4MoϹ*68zsfYh pH^ ,jMAl| }Bj@Q.7zD|Bm G&BHWg#SݯKZ ic@ R.Dp'"^\[IW嵗5IJw:24kBo}mJ0`L=敻| ̿b2Wr/$5V{G%c0Y_PfB?v#/Ha wAGU`Q-IF:۟M˛ .~_%oz;I P&POǵ*8p)^Y#@ "Khy]Sr&ź>owy3hRDT llmhsn7~ɹe֯Mq;˨Z[pxDd3S.:,n QR"o>>1H,"*H0o#42^<~)0u\ zW O+|8'3SV}_LO2(-/ uT?ǟ&=n7Oyeg$E$=i㰧Kqh+#\X *S[SL}h_]h0i2bϒAgᠷ}D>46S"28oXk1TrW M@PM:`zUP7*@s_inQ+ \Ńnb|yVd#hc¦6%]O>9GK*n_lE(OO r#~ŭz/x19} ܣf:ZV@O%D֧WpKPH"JW4sڭvX7ο>;ah܄!fO@~[ݵ<4D( כ+]IB7{sҌ"rQ9ɆCcG"x$ ZjUh .ojR I +Dh7+zpϖ}[*ݷi~HU,ߝ=DK.{6`D iGHCp>2MkأA#c-x`M 6"Cd{O)ݼ#C,Jg Y ? ֔ʒuEU>w%7=L|&[TTLb>iBܧuq_5WDߎL$)X$_pj5WΝ9k,*&|>A~3pwZoË{9yZ tt=+nik Q$%T5E5%h0G$Z@|XUhܥ|DZ|A_oy4s\=eθ(ţb8/Ԗ7 ya]aY 8)ԯFK5 cl5 FZ-FU `Y4?yi×o|!RYhgx{īooNMvi|0>_4wӄ]0ybr!g3Ž,z~|S FDbedzͻ#^5z#P Hrޠl*Bmosܕy9Vst9ּ E>AĈ8;}5c HĐ]a>A0:aɊ_'KY;&(tҥS a#ntsō8Z2ꐖhػ_z,iz nW*aċ EkHd?YFEqyCFT_hoQ}tdwάD_=v5z:pgÁM.]܌ǛQ9Q(~#D9Bh[yNOUxABK.RZ.m2[@OW<_LK=-WN;j`ԑC9L^iK.ƧE4<-EǷZM;0r DCZ`% Rۺ@ZЀ.l$"snh^Q/(Z7bԐ;pum5Ѯ,&~g?`Mƞ+VV #1"gVvΓZ=ҳGQ7qmDOܝNO=2&J!eo~ v5J4Ef+WwQp;Ⱏve{.ë FQk&8-Dtme%%Bh%h9&Dwː0ul5%͚e4Ljot3S' S5 : [淊L r9G`,-/BW.-KJ ފ<μo.8*{h&wsa=f)iſ5/z6&8[_͎{ل`˫*m#G}Z5Սԑx–􂌌;Ҫ} }TؕI듩JWC5ߙ"9vUlb}/zw-?*=6wfI+#9[ʇ=ײi.U*\|^^:3uFQt.22W#ԁmsW6&[ +f^q3Nn@˾X{h6w$ 8c2(0 ZJ@ë*(uԿ~,yoW+z_??Pƞ{i-CԪX hdg7\>rЀڔob:_jv$=쎉b.3rWtI7ę 1V"^8q|ιucy/ـĄՀWrjxkl56~$DwadW_Hl̈@ 7$FZ U>4ͼ$Oҋ2᭫ 3uFѶHv~2.~}̹*]nM?hYGLJmf:7ڴOzNg{h*\qQp9,@xTY xDOKTh#HnhtVE<`hm'+rxM(BCB)45^-5/?;oĒS׵=9U6q}=,~ i"&adƦQ G0TYM^8l%%kWۮLP2 qvlvI4uYdE9wc9_$8^BXP''ILƄsPqݬE`K]9){5iZzͨeH@hkM9zš~)~ظkTģ(nƩ #az_Gq@0Bn -CB`aƵ $QN~dw6ZNwB0@0qtpk^Ν:S%eۋ^)7(dI4:$Ƨtm"n:+}hux<qc'@"AtWek 8`-πP&0a̠NYF$sۼg|).vO<(5/_Rs846RSha_}8uXh&<976j3w~s  {%洓 cq Gx;IUT n" sJ3 )MDaM9?ҘLÚ*D7"AZ1ZazC3#o0R޹e-}bQ8,<.tϼo^3J5eލ#4TzsJ]\L4j^.yX{qZuC ЂqHC,= U `8Q47hHh0sH H]OneVMǵVԄ#{|3GZ-GMO寧nK%E7\)VA&ෝl6K5xAu)XxQ0t[tZe~oZXi4a"C\e^Da{SQwLt,8W^ǁX=mℌfn3Ψŭ\o,,qtn:3G̨"a{ʳ=^&9>d;f~hj*ϩQ2.LdD ?h1LTv $$$zp }v)q@LB)z5WyQhJPے*Uik`2G~6~H&kcP0mrԕKK0HR7Mt,"?>HF{_r~y7 z>{xHjb崱ۙdԼ^YS_naΓrfe/]{Do芛qzuCO:i4#PBH (9Vz^nލ~!>&R1 GG('xA42.얖aC!oVC f* @龭w!mDMm5( Eq١vmBPhewĕzXh2f1AXj5 t[QVlY--OC9G@rR-As}ՠA 70s> ×X 2H{sfecNZ!G`>A :, ɨ6RcʦAeb{c@Q75 $5W 1ƚTJg !X{EQ-&x[сA_b`Uˍ"4Ք]|]hdIIݴ^}˲}HP;M`X$z3 ԑPYe0Y#j56B0pB*x8R98Ƥ|Y>f[ l2 >wS=kj7Mt,{G&{H܂}0VA0w-R _FZFlz'kŧkֹcB[@ ~$y8$+ǚ*4ZQV%k+?g .vE'ƛoc`0WUS]~ѴGuzs=RDV~ X&y)[Gt;c;yiz 1[wn{j⡫V]Y#0pAO݊͹* ;(L,{b{Lh֔ț(vp+>(}F.Lt3rWmkӸ&˹򏋉c) V3LGs2q}+5/-IiصdP-Pߜ$A5WBp>h$4~xghc"|6A:˦U0^װi z`}ݿ*z׳/@X1|ʹ˹iDrfyE/}n"gV4ٙdTm8U4wS3k=FzY]q3N9l4^lЎC79:]]WKJz-ks} ~=XF}cp`ktӮІ'ĚJqҰ+ \z6<5V܀Ĝ٣+uM6!#S$ 'lQwΜbNY4!uQv3oGW鼑Yٹm{uq.2JZ%}|3h#5gVq1qi,'G9 ,~{?=~8]g0$@bDU 'ws6s7u$T4 C>y4ъ;R@TLtoZb }Č{‡|]wLtQt˅{羺\z7lv\Leqt8tj1X-i]hUW=zԔ_SS~g+1gh?>C?4ůXUFM^:|›ס4iD/GRIuV/ wϛ9kʼF羶YdwLW@>uM7+4" ^|ϋG&ΨUs#T~wm3徺1wVLı7.u TLVEyG\%1 >u:yQUv]`?`ŭg1@x[q'ʽj'M?䮨˰okfH z* *>۠p+UEenb$BMM0hBēcD6Omygq,‚4!/Xx²|P;+m1\' 'IXJۆ@d '(5a枲,p+Rl]M)6G%1a-kY0JRLV>PֳXiXĝ(|ʲT}|qm-D͑bmYeGqԟs7 0`Yay((D2X`+9f&֭n-4lL77E6ЮciZ! N=Z'#7ELQVS^:V%02 g!~]Y {^EEd) }ɇ _UURt-@shoŭcmMjg zLXe>۠^-b/O1('Nk{y~̤p<gmY0XcM`x@AҞ񎶯47y{UnYyN17C] "wA]gzpyŎKooX\8 "XqqۿOGieqRI:' kWfPڇaorl+k^ER$̟.蓸 W8z `8E0B`v1ǛC2Nb񦡢4]O+(Fyo;BE -Ww~o E@} s׌p;'qtaPp,0@ (6zov㓇\,!>h%MJ._|?oA^Fw$@dQ&ʂۆSS7:GTwXğ( Kze^9 U}A?L꣤E;f8>`T ՇF4c5ybHQY&D" BD@S C4qz @-]YE/"[@8t%: Z!ѕ:ܫ^ mYpP,}ƇT0eѴ9M||qdqBJW0z̼Te,s!:{"D-=j+4M|84[1-= ?轸 W9dXZQxh,I" ovϧ]UT[XҢ㘂ю5􍣏DP%L_HqX8E$~eW>-u~!mRw/ =_îRFi=:}?>Y.Bv(˄֕Dz<[xƛl?g|vuѥȣA4}O8nm6sǪŸʰ<<;g/|V˗<6W-1˖p|F& >J "BadI }~6Go-/.EAv E8jRilmd&nżXpМ ڣz>3EmPш&fΗeEەGd]ʹs1`ĉ<̩S'egg=z=]"Hda DB{-aEUG?IrZf-%NKN|Z˘LD^UƦӗe9c=3.j^z `XL {*||oCNYaƒԺ6  `d;Asɧj~/uwd!wEZuO`A;=*v_k"Q 4F]rE,z+n!|8}uٳgʕ|'+itާ[hԔ[w|~-ʍPNFo4Eu.@J#D'ihiD,4^[+c3NC^OV8,$b6ƺ+vAj9]Ő/sDp㄁m_l ̹^ >I8_]:f)6+: Q~ߌWP~EՔ@jN,qʨk|`!\L=(@?eQ_gˢ6Ig&#^>K̽<=[isP曟x zGQ@ssŋo0ĉDu8r 7w?ƍ`yy-[9sDko7oz?~:''ʕ+_|V=p, N2@SmmgQN/Pj$0z( LhZrd*|1RKf[NueA7y 2& ȱ؝^OkS}Ñ}|oV)~臞|(N@vłYEݏ=N3USG{!nl׳pǻcÉ`V7je.U (@[5 qp}4Qo|KkmņN7m L1-m۾ͮѣrK20O?T {ッ*mꫯ+Ç_z9svؑ ꫯfϞ7qDP(aÆ?eee7nyꩧlRXX8`͚5C ysss̚5~:tw`3,];^, C (_a,iVTuIuG+>/nݱS4fQDY6EZ)P,oFkN6cҲ_Qƺ+vMi֠t\iCl1\_4`wDI, ^]c﹣Ĭ>t;k|&_^1e2fHiHNgQjOabBW[0{s[Q1GNEPsz{U;3b۠~`/A'O@:rg}_\.=_~ĉ5kȑ#VTT|gpy͘1qn5kq>عsgZZzhժU튢޽;==t#L{ .dfС ,Xrs&O&=ia#$a?aO(Nhl]]i}A GAW`X )A ީ]Drpv QP ibl4B8.ZMVf]l8q"33Q`yH![b?9{U56} gʙ,,Ҏakv|IM^c"1|SBEy+&N7ϲ3LV`ݍ,L۠~`/A)))":vP&Ѽ#uϬef֬YzI&-_|ժU=аa+"}rssqz.55M=$'fu#ޙer UY [>o{gch;Bڄ1uM-9iI`y!!#fpdAv2$3b`&&( 'f2S8B";}^>>[+ϢņaqimӍ"ȉ꣸ G8zTTT[o;64++KLVF[WW7yG} `4eʔ)S7|lϞ=dee^[[=#6nf9DUҹ0iũcirTDb~i3O}UU!`XE3DD"t $pzY9he^KY~E3yfT=m,6(/) z^ewuR6.,z0Q*4YFMZ#&/6?9GYgyf޼ynɩ_fMqqǏe׿_NQiӆ kO:ߵk;su}k׮}첳|𩧞jkkONZ[[[WWw攔a8ZN|Zd?_VVVSS|;#LvNj[蹑YM_\z?i1k ig ?8չ5EZ\6&Rg0v-P:Xϩ]3 E?t5pdĈx씗k?>hh1OAN "f @ {2GB920T]ñde, ,гDEDVYZmfE|Pqä3P^^[ehZfO>|n())7oz|r&L0iҤdCiΜ9>éÑ]{߇~=<Ó&M`t҂oqȐ!'O0L(~7zÇ/]^Z}￿gMJJz׷l2r9sr-Ϗ?_(Uȡ^GTONѐИcoccDdBb33 B$AB+ƌ?9?Ehꫯwv8-Zh"} 6Dw3g>rf֭+W}}}yԱpu?Q̰-,0iꋮA`.@y}!ZLYߺ}_m_mւ>uwՠҮ,ok~gNa( Q!,@BBXNcGF:" fiU^:F!sF>\Udy]sIb $DZ39wCOX Ka)MVOf/<^ Uuh8.XV?${cq[\Gq Y1Y~BlpeA щ꛸ 8]OT3FK\]0LH}tMa@t=g57y0&ADiYvPϐEVI '8zt Bެ(2GۡzƩ?JZM"N eѱΓ6 "1 KĸME8z^jivl*=CGnol:UL,'+*>YI2 IDATDQcf }NoxH~u[6Qh$8Qg}A G^ X"Y + aR^˲y쪐]:L p8,v3?uLJRA?0OM2z Y' ]-;gi_@ֆ;`+ ˙hj1[pe?y~,&n3-EXvl6_9dx5Ps[+]gj #"=R,RkZf{G]W7Bd2'tU L]˞P+]V|8"e)D#>+0H9V-7rS7;N={胸MVvFqZAo !>EQomPs7 o@rXy^X:EQ3,r<Ù(N={NQmnBH##nbetq~u,28"Ae4?s>,9qw6½j9ԱgxK-uuZXwE+ N y^xfYMܬCEOXc9Iξ۠~`/oA.{GZP?M"Q=EuD <.=Ҝ_q(^'N:VB @ͻ.HF PTP;"#[\^:9Rt aLjmEMd0nsqԯp 2SVKC[z#]ΛDIspR#gٹE>OL&Q=@W6[{y~$4'Dcnu&cնk\yaaQuuUaa>STTXUUoV]]EUUUwS5dcǛrNI\UUaM`Rc8ll0pXOSa7nk=$P/~=ZokJϩQ槪 ", )Nܗ:룈ɢWgq>ڐOdrb^DQn]Yfޫ.S~6 +*獇돞9k&n~Gwj (Rj4hdUUuD @3 Vd1 |Du*m7PMC;~o#2'$'۴[qzd t^MjR,B"wa"pb,_oU꫙nrH_[e.]Bdq῍s鮨ST 7us[Վg۠~@Fh 5:u*>FZ(T{zy `aQ{_Y#8^\S%]i;ƸW~vVX pM+NqF 7nܨ}UUU%K TH6ð3x8SBf|1AoA_u9 11 4}yb@pzAE2m,'Ka}R޾YE.=ފwqץOS܏-sFoT]!Xϯ9~i5^YI^QsWo}w Do3XG(n>JB#&5} _T;15LVEQY&H%39$!I Lrp?9E<_D횚&ZOLH/h@WtzAuaUږd Gl?a d䆗h7f}>{5}w&o2z祧S: -38#veԲߔe w9E+V=ksv,%?UvA G)dO[XXq8\ÊkiI x ,$KaǚBUKp>/6'ui\ݨ3= 9*Kb$'';“y``8˝ l"f^Ml_Ͱ}+[+Vƍ@ ߪ,HJ-E gޠ7b u_UȽR-[O׆$*ܬ4镸 o8h"JPJ4"6 b*Y0 oRh6R7DҰ Y{zaacSR|{@Wַv}p:8 `Đd$yFHPE!-1LL<;~;wt] c>ҴvXk]RA4_{bGgKb&Ee96zL6Ck e4xFv: ;릲Z:d=F_ͭyy I!D?Q7nGA6i_(i_h NJkW6 ]VKۓ*/pãᮝEVHUN6g]=RE@4zA G3X+B[ZIeee=X Xj=G <ؐb&Es2HsU=b?:Uk'5-53ߕnu$s9tѪpЗ4QI%Dxgr2'X說(WE#0f+cIHz9,mB(>g9`0﷿͛^O+'N0 O_x믿N/|'`8Dݪ 0,x|AF@0%ˆ^] _ġCkj:pI=y[ҪE~P͒థλ0/nP%Џ7zfNN81_lr41*4c?c567[#(ՙ38cƑGu@miqc jO J!͕iEqJV.Nsf_VwFѝ 8wՌI#vE)**x<-JLLOʊG1k֬oѢE<x7ofa^~^ziʕCΝGeeeذas=3ϬY VX\ZZs=P(aÆ?eee7ndYM֮][o{_~ 77v3Q5q9=Fd#$aPeahFspQÇ6o^aѽbpQ4)z~XH6e7Y( ( Dj`t)).X/SGMV͕೦O*YE.>|}v$ ξTupaKV -?|4i`t;+MҕS{"n3"L ,#QX;ꋒv/˻VO>Y\\\\\LO:q;v1bĉ}SN=rΝ;{9/<@\uU?O6nXVVK.z?<{>}u444|;wLKKCZji~;Y'O|}555f,0,Kdfn F}! "iaY/^_hDI~δ6M-!fPW;0ὟllMen63o=4GH偿asT޽B+G85;Wn4R[} p""}L1cƃ>h^Xnɓ'9;uԐ!CpwM7SN}7'L(J]]~KUo7zhzzJٿկKBׯ_OΞ5gr-H]G`/.: v-Pz?Xh^Id [9yi(BӒ=_˩ SZƣקvTosFG҈i{ QBSN:u*͔U&EM}wK[[[bbb~~>ݻw:p<[͛f݊;vWvvUW];v_*IR.555lXdHzP##"Z}D:BB$I ZY~zdgڰS-{~eC3<fKaByW1jv]iwmPOS4# zG+qO^RRrWL>}Ŋ^z[n壏>>}ɤƥyϿǏ̿-]o2dɓEZfǍ9rذapGQB$Y "Q#p %:jF™DZQr!$YO,NRbDhhD^[.$ff(i;ju$|P_fz v]tIԡ^z#mth 7⸴;_"L&@noV3gΜ9s"Zj2>]Ϝ9s̙p,ZhѢE?Cl6׫{)))k׮5~d}&B$>vМ@Ga)@Q**]aXF!~igY`sZɳuLͰk6S$E |y!CeQ OjJvHNT r_|wYOp4f`hL8F~]bK']BhlF7+̸vc)Ha.fe %Db\XDd~W+}yRsT0"_cwxAMj:A}YC7\=]ϔz=mITC=faPQ=.m Mj5Fac2^}dX< ,nO⨖oԩn4jA0p+'ph0/!!,I"K$HA%QE8Mx|QN5;4[[}B HsAc P8 qAtu6ވ|z dPL~{"2XLhaؾ3*|G߲4*}z}! oAi=iH+}ᚭ;>Liɴ(!0hwȪƙA1,zB.;?QȾdJE$'(ҟKq3& ֒""NNg.XR@0ۏ \lńl&10 e@QV$]suWyΏcIkkHO_ccwE7N.4N Bt ê1v K%3;,*K!01@!;ˢLtԦP=q0(-gpcSUVFYOq=_ HKg!J47É:P DB)IR0 jo@DB tb^Ydgq/^MJ%Z+I.0l  ˲p!'n ~ UߺQ\ѹE*zqmmyk@ +.;|8xEJw "4bWoc/` 0Hd( C +,xZH`y Y R S@$BdY Gݒ a6E!4QH dlvm^<(>޻\h}{Jް(ͼB;|#iO<)ǃt<Ȧu_D Od'!,'ow,.{g%LIfS5 )UbX*@YVA̮X{䚩Uϻ.+X|8E+*.uν*c5xT%ux˟ؼk&F TRU;m&aAml e)pf"(^oaQL!Bd,RXδ!=@{_͙l98.ars߮9ơ4-\L+j% +otO1s08g)~mؤǩoWdz[duvjb\\XTVr ˲2L.8/>Nj5ݲ0?T\HyE gN%lie&'CDh3$,/srÖCT X5EQdYX"I4C}T EIŐ$ۃ MƱ|âIMx 2Y_4nM4h;u3/ pYE0nE*_R#r&!8Gpȿ !$ W 6~y6E:FvLeӧG+JA['b}/(sVW2s|!,f$gK}hKNYa, OޮP˲{.!TMtMfn.Rβ+?^vȺa!z*1H5,ObPky`"C0swsFefyv3e55MZlhCR3ѵYBW {^EQ4pE }C{mޘe!qp=x5 7y'1y MoiS=S)ni_-SfI5Jw1ETx.uؼ$"~ٹ1Y͹C*QҒb'{C.AIP~%w^"l^zz#8^\SU^:|8N1ƽ򳅳K^ }+>\>w]f˰okfH4; ?s =9w?yw[FUuw<ؐA)B`v1 &7,&&`X8r5]B,"_YЬvAAi l(<=3E;;>3-ZMOhW꯫ŕ~rőTgQ~\?̪d{JCNմ|tBɶflkjBO?ߔVў;mϫmc\MaQ?rPQ2%483qR7X52\'3$a+ nDꮨ,YH5BI,ۖOV=b1 fѓ$@QcЏۨbHQY&D" 3(DNZJ#I EZel}1&Mu4mxAN=oQ<>3/#;b"(}IZ's3QVg*U27q7ffxlj'~vʭWۼÒ_}g~a#\v)^6A#IΤ~I-"aY '= ~W]9Հ٣t(K<^a_\[}a@vZ^:]KCJwEeyau22p mae9֜R8Bb($0O욝mΨG(N}m:=oi5iF]C}!a洸L ;eTKBWk{ZOj9QH _Gr}L"jiS.)>珼8Jv~V0,'Lݲ풶_zŻ~T_SLE"ʗ [}K_VzM.t7>U&l(srդ糌=.th9??۠ysH8Y!AGHJ5oY^cpV=R^z84;tT޺gd"5) dMس^0a)B!=h'QNDMBdp%ȢG>hp<_ vWn{j72X$,(a8nNLKx|~ 2%#/|`8\֍9F?ElXԯp9DY5U/w@]QY%/s}& ,meQ+ qw\.hI]\K-Ukkkˣ}T"*JKU\PdIHB>s39 }K};wΝ= ;%1ު$jNI<9^tMT8#;:G}xorӗͺl .WO ~5x=:"zpŃ z3#w]Ͼ?RI hk]IմaRrGl\f[5G(C v|܌W2ph T1)ǟwzFzC$\SJQd@#):WB.Ԃ}.I𺯒>%?~IJX ԯK!HPEMJf7Bi7}{평XL[w_9jr\..mͿh&ֆщ0ѧ^ktx'n^4GK.\%WNXf2reGʠ?\PD+/V%%:Fh:j}λ+ cS7=E7d9J{.G R a* =a_D{YS,4CtG[xM4@g -Op޵wC$6>,J*3=lmmuh&sG+p4}a۶@;?пts͋Ow9w촳⼫.hi\sG UUٱ hm>k| Փ:smI΢#h+zkC*k!UocfX)C*G3~ޚ'TSgc~^rr嗟WVz.Iɬ:x@MXb6[w>㴳5慢vI 꿎zE^hBڧ?+Ǯ\=n~AJ5N6Ϻvj] ~xH%}Emذlϟ2eÉ'&T%K<OUPhԨQ}Yqqy~䇘>3*%$EnbC4[ܭ[քX( f4EEE՞DUe\V9jMԏ1,/h?o?O<%}fÆ{ ƖV02'o_$:Ժigöwn G vd;b@#GГl GP}އbw~M$]OVfX,L"sw# 믻ǁޮUۣ}m &߼<9"ҒmiEh&ͣ%>JIXw^YQiH=`*0ѥW}vˏO reU/yx9~ "F2@Kϗh5AsHOu]l2I_|?'p禎$l :tOU#]EDE8+ǬTE޳]ٴks災`ם۶׿^Դ//.:JFOhWZ۝'YMp:]$ʰ`aQ٠Aabfh>O hѡnxhnǃh4ִm88|y,:ܡS%#-fSJXEiK,@&W%qRfWe8Ye]_jT/Nl+lʣˉܡaqA7P>lUT;`db9}A[U&|~ KNꩫ{OE5[0'u~HR|_ڿ8D{2G9A{s=s8u|˗ϟ?wߵJ/"篾nM.0$E-`sXz*=P =ߟGS]tԼ3 NxzukkW$PWWG믢v{;::[sЉ!gvHY=ǚ[[[]5 M8*QUP>z!@PQ>@.:i3oL-^iiz(*qiQ# -"<|";* 7 %{|fwgϙ!Bl">tfBhBT_Gη1=TMSEcف>M3g7`qR,%+Ƭw^n:|х YݷxSS|w]W^1yP**f]RmԳ(YJc_e`׍7^_5?'U[bϞ={p娫%RJkjj(2]+jn `jʸ sa1 ?ή`l wfsE6 Ŝ63T:lU@5ѴMh.kMY-2_RS;Yۼ@尛-ɼPQ.|j;=;whb_}<oʘ uiȂ,xכֿs=Ĕ*93oqDQ7h[#ơ @[tٱNJ 5NEn:a)շک=Y"a̢ezh>@gggyv7`n&`Jk }~k1x{?Ŋ/]?,P]]My;n^\}ԋjݘ_S Bwxbkm5m0cVMsdo\L SP4r2剭8s^LIQD)?-(ynȶf94W?|Hඛڥ dZ(ޤC-7]_^cnZ ķ(|?ܮܡb{_H0xgrTAĹko|#$̿fGDy[S6oI,f 'Tj"&G1?Y8sONڥ#h7,,Ywe]\9;`=t~ذa<B_"RoT.iO߼gףtz{ͫ7͹$Sz rŊ:f﨩IVF=뫫_Ju=#(癰sÓUn-p^/:) IDqR ޽h IDAT[{M OIok?M?}ӒAjߴm.N%Q5MG # =ó.7>krJFXUٟp^v[S֥ B@V&:\6QSO[+{MPDn5}GkNGWU5,ɯWeNlfDڧ?YrG89pkVPPPQ$/!F=T$Xe ǹnu(D~fu DafB8'WRR8 8|I{hq̞]B{|I}נis;v8UۢiqM7]KQ&.w{sG˷=<*hʪ"^8q|ߜi\vKMp@V>J`./KC3vU%fhL %,ޫ8~\6U.6y,H?{##2yP5E = o릊o8޹ΦOB9߯9c4n4'6*9G dO< 'g<+Wob~coF ![V>0]ک '|@͵i,˲,777YfڵVJ6ju:?OI~ Gx*Ϲ(r~n~\rz~endY56qw3 !8555v,MMq\v99[ww:thN0qMM{N+Yf n̘q6!}'<nIJ|[G6W,}@0C. 4 bD:&o=3%oR=^ݬ:7q3M7]qz@DQ x̘LD5MS#.(u"=9.#*ڇ?ci!1>Ϝ{*%x$:TU#V`" iw1=>aܴ3?^M~]D_0QޤC hNNIʨoofTi>O?dׯ4ԻnD"_mf TUhOF#.X֣mcESuO,8bq^ftuuȲ鴝yMMMp99.99 hhhJp؞=mȡ\CCa-/p+|͛7(// gb1t\S%nvd2_ʼb矯P?}Ӆx!!A5%^%ijfc!}:&;NѤ~H&i2_Z6%~b5JqTބ߅w@*J0! 9J5T-IC#5 m"RB'64ןzLomz͏;_7 '5zIГfi< ѣ=7|L|}匧'L_QQа9sƈyv\;-]f#Pe#*s2t@i02퐩\I#8IiKR/#n7z4EO_*yyGqC-K{WU')F,;(}\}K/DEYx~+ UTO[dez[s)OduXƮH#259n#)1Lvm)cv+zbEę6"Mu=u$e9B@naהlA- "2/dG)312QgзQ|v fϋ<H v#=BjjXd) Rִ )؜fuʇ?hr䌈ۥXDLW{[Pm1;cSE^L-_w=H.K*AfɐÉ nl.{K( ʉ,C}j*CӮ͋.\円=99N2,$b1Aiuǵi\C};xKqq,4BDV `ǧ=Inw&1=AFN KLUT)쓦1"(KQV4Lwh*,hP"hXSE6d}y7`OWea2RM^R ţ|n۩L?%WOh3aa 9DZÈjK_G "/{jV ɓ艍g$JĤJ&B V#gf8ۮ:i;w$fi4JNSx^V&zf&j|UDKS\Avs]ʪ*+r\t,KQYU9y9ibs&&TûGX(2 P۷\i#ZduZ9 "ƣ1댩ft1; VsTU +rw6eRF KfυiW8~ S K}M EѰL_R҃.K&։[ĥX n)l=t#XD}G!qno7^?BؿʼnۮaaIagtŸ톅%hSoGRfҞjn9aRk\3 o1њk&inkx ݃$mWVR4lt85~8Ai:8XQC5Tk-SyYpo0(Cm2)yѨjG-<29iB`9 h)f9+Gr# "4M&\=aQ3j)+͙P7p>U/yO)W]׸+u3 nxU4%*LOzMf:ΌH$4ͬYі-#NaھO,='٘K'4Z2DFHUt&hqP$pҟkx 䈞"[fezygK`}/A[Ъ5Lo}%y(BP)Awdd)Um&rL4Y?AC7c}T_u3B?KV!K Z9g:_ "XӶ(/9;)y h 5``@f^qrc>Ky>M˔*g\fLz3W쓩1[AN6mZ FK!꽤,"4M;wnEEiwƓfL#}wsgʂ\_q3eSVK~> Jl 3gAkl\a [mp-Ԩ{^p{*ݞʚKg4Qyw=\Zts{aE=Lٔh(~gaQ@DqMI<@xqEUx+Q]]M$`Ǭέ+KOc)IG6G-MVT1mTDyyjw%ˊj7MZ`g~?q;~F%AߢnQv@KʠxgE)R@R)KܭwϻT5V$㸶d ]ҋ-e'?efa5pi"8M`hM?ẩ.+Hܒ!u2{Zjic*Bt3 *B4UF,ݹs׶myo X̣GWQfױsĔT.}@MXщpRG?)J srrEٺuرky2jԨ"\ b4.>réSf --(շP[.}]Ch- Ϣ^D{:>zH5K'M߸&zY.Kt҄uJӚSg{%7pMgM{I? |2[^TS9fG 4Y/Hh"  )(--8q$$M-;GTBaPLsXxM,E:~̂)В$B@<.;w?nܸ<'2l&g=ւET+ջB`A4W4Y~,vCO9CPRճ[.]o\Vfcͥ3j{1t҄wry'߰@HGY||3@4Z`r,X/D.);gaQM)b3p9GNi55KkkWX󖖖|>Qh}ݴ`O2=8TUwt"<Eh@+ՏtZEp BD bw<q}(++ݽ'|څTEq1QJk $R}Y#lE$;o֤{ w޳xFô^o획4Έ9M*(XezfP}Y#, Eݟ,EԜ@{/ Z|E[wu jo'xaYS赍^Vz褋mwu{gaG <8!;cD%?#D^?t,Ic쮩$y)WZD&\r. M/EP1=fTR۳!ᛨ_)G4M, QMFp`/lV]c\v!cf6v*?ʲ^ɝ{֓O:e֣ ng/;(k%صk^ѥ71(=$":wc$7+Ji(cJz@uSFVW IDATL#zm_6.ֽPSeֽ@zs#{se G <:8hPC(=MJi9/ =8:G 4fsv4KkVpp|q`Vi_C-]Ás.:ՙ;|؈Q.Ӗϟ{ĸˮBgNSN)++4 EDE}w)z5\|EJRrsBI77~h2Ļy鷖o2oC(R c;IIB( Vuֽ@{׭ŌJRTcESmoz=Y0xԀ(G[P#E-`sXz(-PS㭮ݞj"S ,CQ>XDHث oAUAxUBt>8uuuT+ӵ|qT;xyNSFU0rdE / KHẄ2j)))s:m&X_kZTMD;vPi3CIϬs\VXg?vaۧ?{c+ƍEHRL?q8dY~<*JyROU̙3n"Bڅ4 Jŋg=U(O2e&馌D9:Ĥ/Z0?[t^@^hl^Oݿk6κ3+͒$O:y۩ByMmeM=FT7e$ګ᪛G  a)+$SBܴv+'Sջ̗^64ΑEz8 kp*b[cǎMNkdg.=fOx{~'JPIv7+1w"Rv %TT=|շ|"3,g0+ [n]S۟-Z<$.EWVoXfP>mY|x{|)-J-.z~u}B>}[^:, tR )ug~~+Wg#7 008$HP@4-5ׂB&Eңȣcqʪ"^8q>^wP"考ag)~PNVU9r'!#Дm:",q8j--t;=Z =sg^(!, FiC ŗ^bzj[Gŗ^v+ULiv%NK?}W`'2FJklY[IL>.ȑi'MuCxQHFi#\[b[S[Gbk眑4 0pT jagm;O8*3#Eem^kV?TX8,H@dX(Q&5xuԏ9X w?>|.@4stq?; {&r-ث_P֤!Ek6RlPͥϿMadٳi; VHo}-Mqzc."9J3G/睕4 00PeH!v|%ځ>bGRL&6k3m8~Ѵp"r= /v D|7pVi𼼄YbLNXig-}^dh>LA[`sY? +ŗ^DM3GHZqBTE!{#OCLŤQ'-@ɵ4x TR}-{|{-gee9EayVj[ﺵT%g&s\?,-WLG * Ihj!5M\8M_/Q#=vlo!$24$E w"зNܹs?ЧGGTU\eҶ];xd**BpZHS/v + _Q3u\b(MR6TJuPJL1.=,NR2!3uF@1}Kv~gKo7xƦ41k4 OqZGf),ONL3]] IʦJxdc )%TI;?>3딴0`fQU4xvq|x4՚yiK&NE;IW=vz8#Z_71BEθMU[N# @Dq/XXv?˗^ãMCEEEpÍlô vUD5ѵo7һ]صo~3h8ל= ].$ *r]󊾖=?TbR𡪪GX0fYC,s\OW^ @Exf3pPkmZT !EHZ6WYK~E]u|Ǘ62T_˞z,MG aBS'5MSU%8,G:i/牝P2%)m\} V5uGi?-"2Y)n"^ߡ4Zꋋ|y$$8L}晗ƍ-eȀ v Tobhz$DcMi/cx,3ϳfEqEQpiORET';x$IVSu.^,;HxlyN>a|D85n.+ " fǻ\&+&@ǗF~a 0`c 4>U9Tړ7MǣdϞ=̂7@ MA'"o*QYT9 hP=dcG8&ښm"P079g^}X9=/l dp܍8{g 9 BQy4UV^zl["N>T91-i*&-/.fˊMUE=Y˻$moygG 8z^1iNԶ)6NR:RO@Da;wFW-DTEOEx.I>e08r <,.AN5֯6?uHP$IP lQQ5.huuMYeY "% "zSxӎ>'zU2(Dx=a ` ",.nG t߶$+UEs,֮T|z^Ұ7LMRNM\Eթ?pE 7`++Ek,vgcc.T~o37~۾Ѳy%#e.^t8Y/龁Q(}  \lus߬<knn2ĕh=ERUm'p\[ GrӸ/AyopC4YDD"X@D0;vLV5+€ w8Lj3AcɚDlˎEEEb /B,3!3**hi8+tŕHc 4U'qjdՓ3pBeIpk*(P yԿ[!=UEhvE0xԀAL n(p-3͢&(!ommm7nLz? H4wP"ִ+ #Eq:TEu7^E".ZH$<@ b+ȎMoɱй~Af9dʔ bPek,Cxp~~P=Nmާ8 }Z&s4%Zj EػY,H`" T8܍J% F }ԀAiHvQe>Y%X)tZ8u| l'0R$Lꤖ9p" Qo~/x@-h!D*BЀgѫ`0Eq/d.a =dH~JJi G9TU1 ~曯̊˴O*͕ksf~҉b!7$ p]9rfbU[9_.zCaG 8 .!GhU@LV 62ۦ,YٕD;_vݬ,GftM"EnOT| iWG[s/ѿr>=`*c sೠcʭtr@D d/wlza/^/IzSޡC3 Aj}?ɬR퓪j8D0VBOxN_d9?0 ocWľ\ '?y=/€ Ni*.F+s.W5N]nȶH)[2$vOKt"4 `)RS҉~M4UU@T6N,^ҥZ0`vr;?9YDRiŀ,(K^<ɻL4B8ro =Loe'='(2VTMJj"ϩT1O9(QtKxTERT RDp7E)ٞiM[hҁ0`5Eq<Up8Mj G}'߼SN}`6RsfY8*Wkkk w)%8CG8BHr/g?kZ1P7Ed؋v57B??˧OIK4444lʪ euvdN]`h>ԊP<EsCx$Zd$GxqT}o-ֿe GxuFzO7(D~>Lno{%i-@P/aQͣ'4R MTSd9}:]`p^٤lY\0SȲ#RnQT_/wwm;Z##$L~SBX<`(9,AkQ̢ȁwN1eKǞk2ܛe^k,߯,_ySޮyFz[ef:>J~^-2s躻*+uK\>;xzPlLQBXJc1~7,Z(SS6(!Z GF^8^ S䗉D< ɱƙ2bشI淶6Na*>hN#r_5)ĉS_5U(USﴞ*on|D !=;[6}+l6Z&h<'(L.*(E.ڒڳx Vhmm9ߗ?wΡsM7{ņ$5x:be~g9vl}ul/ۓ>;5hC~[vvU@xh.TgU42D ecg^㳥;AM匤;b[;&X͎͛Z hq$;P.N2;cr#NzP<9. o<~ݍOj6T6(q{'Ϧ}vneRuu՟nĥ0lʹJX*FBJA;NYR!\F+;;솆hCzֽiaj*?(?ihl?%.mm}EW^-P(={P~9t]Dg PIiZ~P:4YiV=7L˝U1҂vdij3Ԃ1^z;ADXBFO<#O-%jܼh @=DH8B)D<#sCDsKJ{vct;=~$XQQ~ŋΰp AR47e)Q.jdY|eiypwo~ȟ;vvr%55g5/*s>wSv+^WWO'J0f4r$;PFeQ[s;V1Hiɴ?u[-;N{& \iOٵnۭ+ķ&hң(1h~mt<'kWd.͜9ܚ6<  _U2k%9Jlo)sZ) #=`g/}i}eY[Oll\5.gYuƈsRTnfHpn'/`e"8e9۵~ 3<+ TTx&O~r}d__s=-zj; W9|d-{wRUEE&C9:y,3j..H7RpxPs¤躢%c |(Bӌljg>_hrYGcvY0x3/Ɏs`p:Ckg}e5PnC8 oXmV"Z$*8wKr` e1E'j!MъFf,'јHăAGW^|J+D"D"X̙0r0.19ZbvuhccHіi]:}n⦽M8YEOoeYlNzu~T΢(O:$Q͟^lvss>-s،ba"RuW.%z׉ҨoRd +:u|X)#s 8ќ_j Xdݏtoj<=k;~!JǫoPfs7>xg9 QKr`,~j\-ߞq"Q; 7n R,vʴxbF;ZZvʩ e WP(cGx<D"vb1ߴ,D0DA^wZ Y_3u:\Rt"QP:=g^oY"Csa;[H" re<>7b @Ih-V~,D"[lpk0ر9N뜢_:;KBAJ$ьb1K;(RSM,tJv{n߾?i眳U馡Emm mm?O BVWWb1EaBctᅗƈb{9^sι(/beeUq׭L>_hXJǧTatGo|Uڇ.3UνI 9wwǯF67tȰ2>25TMDM\һ\BƧ\PwFik7k7D#Hw/(Qɇ(1{3DhFoFE4:'QHQDĹ95"ʘ˜*iv)!")%4{Kp+7bKPSe  &LE%uesYtٴ{{{Rݻwtvz> :;A.Wz5/8yrI{Λ7JJ`[SScx_$[*)gOWMMe=+V\JJLyHQG̀=R~_kE'M=Qq.TRX#f:Jd~=D=ȭ>%칻UDM-݉ޞDD{wߝ}#þK=+ݧ=w*4hM-+Xm}K)QBQeF[LQ&_DTc$bXbBijB"x}bK؍]R{%UUnLD@&B!_yyڈEAPH,Y9%' }%ppÇQII`ʔItB4EaMP9!<2J f.D [t{\tɔəl97I+'VVt:W`5_4wc2kۛo>cH%w.'Vķķ (dm˞v4R @ &)2BD|)$`:c ^^(#MVTk(&@ڳd)յuE7#7D.]*%"z˅^So_2Fmmn7HĢѨD'+]"TK ZTEDy,l,0եwf3->D i'-@D,L]gv:voJ9k@M y33ui\hheى$gS+JzP&{d3ǬBX,TK=*%̜݀Z!n2pn4h%Qmm:g8N,ׯ߸񵆆h4MUUW744DUUKȧ8ם?ZPB>$/)nC:RtQR/O ZenRʹ-e[.kzDx9Tٔxuϰ?~y 2ro_.QTU%}3G)t_^BrIt^CD7l}wFeG,Q1"n)Bp SI#"5ѥ(*1yxTT>a IaQ+AÖ-H8F-̊/{bJR2\22Ü"_-fv4u]#*n&%&)H%~G 62Jn; CDDiU<ԷwfD[WZECvG-Qc53Xe#'Ɔ2IuL"RԡgnܲT]cNr p.';9W~q "9/D U\.#V5-:g6esO((Ct ~"TqNs-Z"#o#Ys7jJeTUqy=xR5" 32$A)S~EUjt%?:%78Y%Ӧ U )B˲InFsTUW(3f {I[Fss"Kz"Q \!s,N@}tr)99zElmУ&yMп\V.7k?̘{ꊪ&]B7 ɃF6uiMʦo UU%q ΅e1ƪNTTqNėcJtJ(H9Ayy!;w2%7I=j>: ?@x}܆[H/Tt"'QA'/֬;}+MT uߞ3Zӆ.9sD/Zl w2aUuUә=Bxss2sVCn1MܢSјTUW5W"lk aKqquMT&y8\:9?002>SD 母Ƅ)G`*ځWLc_Ֆ vwS\⨍H \cfo#0rtf2o]yRT]ncd9OsDKP=f(Q|(q,.&GV}RKYߐ?&׉SCeQ(rQ(rQ(r9 Q(r9 Q(r9 (r9 (r9 @r9 @r9 @ G#t3OI _IO GQ( GQ( GQ(E;/?trcaq]U^RgrX=/wiʮg_ݎ8g⹜Џtƌ'[|9:<5S9!ճrcaZBp!D8Iex2̈́X+B ]{XKABΏc-xm3<.wOf9kFKDBPb og]-zݚ$ '\sL{Q䨑339-y>8Ke oQc1iGkoﱄ1F[W LqOD2&.1FDĈer@uG#.g }^cL1bD$!JB3P DF;LSr]{K;yRU?_q5xb\qp"r+̼ni \O^&5jW '{r9eq΅D-ruy&((2ZD$89*0 #Nx,sKuGwD'#MUUrK!jGku6eiQ6gU3*t;BȖ(QEQt]gYeiZ͟lY\UOuu]UUMrv-{ y~TQq89*QEB.Y_\\WSU c<SdQgb1~)`irckt69i=:TQp d(r9 (r9 (rGGE C)`L1,cLS)aژVG@q}?%O[QX1*Q(⃄ճ[Mm}ٹ*Uu4 s{{ - z&UU(|t})޼s5;>r*_]6X\lxkgŤ(@9SKͨ}ƍ+//4g(D8'۷ϲ !,ڻwomm1V]}zww| _Wnwf]vx޽{Κ5 9 'p˒%K^|/| /-ADvZg;,D"BYf=SB-[X9sL>6lxO0JyFիՕJlٲjժ.;GV]}wttd2{Gt?GD)RU˾{_4 2(\;߻}{DZrTyUp.8[2M?<ֽ̗Ͽ|0p8|-7ł}{[lف_h/Fϗ~:ܯ_=7.岧?o҅gTF?+W7~/rFMqN*@呣01Jò|#GB֞hU;zW.!G`\J}lncڹ|JM9荿] ϞQC "&Esxg ''UUerhdriEPE0 -T^6̉ cl_)K"G`(c̕S @ GQ@ GQ@;)@|r6;IENDB`tiled-0.14.2/docs/manual/images/terraintool/06-editterraindialog-done.png000066400000000000000000001656001260670167100262770ustar00rootroot00000000000000PNG  IHDRms pHYs  tIME : % IDATxwTߩ;;[awAA%ƒMyQb&*}1&%1& Rv ˲L[y8ð Y3s{;9± p8B0g 8+k׮455gp88ۣR 8:p8Qpr8u99O9w}^V%K ]JKKEyG?䓉wQg~RC뮝;wI)eoocc(iRJ.]ZXXoذa@_Nsynx 3~'W^=BSN9nݺuMMM_:{pr8_mmm`bR~'MuAJKKܹ30 cIl9$3JTrrrXbʕ<ȗ:=r8<G#2_}@ˬK.4iҦM@O=(7x_ k/OF{(#xg~_QQj]]9ߟ|ɔқoyp_>uTD_z饶a/ 'x֭[O,l%\z饗^zҥK 8s***Einn~Wꆼ'xs=կ~U_㏟}Y&CѲe?{#\Ƙ*֩_5MQ+~ Xu}i644xǧG+W<^;;;m6NPJeYsrr>@ `oqҥX96l`YV2UjȤI֯_SQQ1sLdI'f͚;裏59B?-[q 7dgg̙3n;w5şy۷o>}yF~i&6:T32F~x}>7}zNNNsss= ''gƌg^bϿ{SCN˲$Izw~_8p8‹~edS!Gu… [[[X,dQ\򘵪!5~]$5x6u2SiKᎆ{};jr8_ gq… /iӦ`0~\2Nzwv=b}gmmm'O?~ss;C|ڵAX~xRrLK٧Ə& ۳o喞#<Ҳw}w4?G/c|WB}ƌ7pC2?iLusÚ8\.W,{.9sׯYf޼yC6׿N<>c݌h<=ٳgnݺuh y+WN6?}]6opyHx{7YQQ_WW?iBjpw4Se(?52O:±;ypE87_p8pp8(p8\G9pp8?*ጆ3<pp8(p8\G9:p8(p8\G9:p8Qp8\G9:p8Qp#p8h0 0 JȄ;A ,up8H8}+>h?/oʔ?ϗ~ieS+m:p8F<߾}ƙg3yrAx/k4MTMR6C'9`:jvƴ:gt4/\tE]t?//((7o^jڿ/}}}o˗?-[|Q_Wf{r}Osx9ypX?t4㔿y c5mΜ#~/Xٳ[زKeyg..)+X2g}vg͞=~1lذ;NӴ`0eOOoo,okow\~ڵ# [w/X.RĿ4Dfdn-'Iشrw~srWTկ~Iwyy畖M-)-;kjjXGʓ>dE+?/ΗN8Os-ZSOu?яTU}Enx<'|'Ԕӧ>}XK.Uѡk> )qMGcNQ)QgIڴ?J)@[FsEnmm۷?WXG|K_n/2}7Y-?3>Gٟ|FiS*9G¡Dw.@ȌuuNek}ߌhtL_[38o{nY`ŗ|;Za~^~MߓxG~?P _xEvE e˖-3gL(N>}˖-,|钔;sLJUUڵk !V wq?kmL|?OR_կKʎ{g0='.iߡtFIQ9%n&Z+%)9cƆNǯ[ ߿p޹Ν{s9w^{ TVV^sU>5W_=+/ MPTu` jrܣ(}imͻvܱe#O J{]J%;c@{u{VSOJ~hj]tE999,0???YǼkkk=PUS[vWUUN:ExGoZr!Lpꩧyo4pAכZhB!x^7 H{'oذ3]l=sqG":뢋F(c֐pv+!OSBo=vGy+LO(3|kY1{? ؙܶl)hAټjU͓79|{#S6ͽiNJ;z{ji9䓒%`׮]S l*}%==iiޖݹrϯ彞 رc靝-w?h :_ɽwKЯL;J"; BESXh+r,WL4) {{D$ID"].p(|iw;ws Çv/J8/-'$zL K,aǫV8ŋϝ;wѢEGqDEEp dvt{ 0.ꪫȁ8S՝Jynoּ֕ڣKv]R+IdH{u6SaaaccckwwwoooaQ7yr{m𼼝)ȶ7m/}}eCAUU[[[(;322ZZZDQj޵k" =ysH!"T"D$DlѶ%\zxݎ_;ME'rMNaۣ,_7نsݬi]|'}郿|HsUig|3/J8/-ӦM۸qc͛7O6o޼9[7ndCF.]\-[̛7tΚ5kpWۖ,Y/_~UW ?LJ/|mMEmaW'b+V45E 3m; ', /|Eч~8vi[_2;o_T>z˒nZ~=W]y(_@gԙmǦG?}>kE3oS49Ϸ{V3G>7>;-[l۶g޼/#Ę?%7sy.+/oWz* /K~|i|+b1+3#z<@Iqq[[ۖ[i ۝CM۴is}CCvV 'OFZl56 ;U?nW5Mu}O<{>_}[禛nꪫN8a^瞻z衜˗Xdڵ֭{W{o',Z(u25y˭ ]p&z_{szܒH$ɒDK 4 F*~_{̟u5:4MUU3NSQs:p=+'n޽Ƚ=;[>N$IUq8/!@W=-t9Hx.7FI<﮼懁8̳p{t:6B+D@nn)uul:n̈1|oH $P&aخ ʒMeffhE| 8dIȃE}׽?|Ui~avyyy(KKK -˲,sk!Ph/(_?i$;'#Ù2J&u5۶>M^|\ ?rI L6-+3c]]]###3';pps$? P(Dl˲mUAJ$Ii8#E|>HdA]DJ{8}:;͟]ia۶,˪*Ž,I.S4]XX$,˟_ Ip8|t2ԸlnYeY4MQp8G4`nnkkkOp_2 ӭ/Ɩ$I(*tRAXEIEB(Ri*Sp8>7W9s,Y>(W},:40_7_ ;%C*p8 M;l/=yg+2'؟3HKO?a)S¡0QHlbVM&bč1(Q Ji"N?pr8up8pp8up8pp8(p8cg?ʟ3o9.r CS/|'\MrN`bb`6zPH Cآ(|XBT$7 * #͸Û QAM@ġ\TUJzq˥؄Ҿzg*b69om&lu[34HQ;k"xK?,8e_ ݣ49X=7F7 -SfAaESE4Q_Bj_5U"i`6!~3Q4gG9,b"%fz5t'l/+m#dDa@D29)k[V*3Tw*+K|j{Jq( UeYJ =M)y=l.z4ǣ@I<Ʉdٸ;:hxE}5L6_)*N/@ f$޸+9 I{eIМi@l ٫It؂x%")Z_\>Lm UMSn@$Ou}GuCwUWAX4Ca8]Uϟa1[_ ݣnQ/WwCvjN &;dWQ%2옢Zڞp@fD$JmJmJaFbnˈgof9=*JN/䅤S#B!WUw9!QI&M4XMW ΐ QjSbѠضaSjڱ=a-aĂfux2YC,)iB$U5%Q$FP*WRG59 t,)%KCdE j0AT$FG_4+NaU F,L0US|Z%~ŢveUM>Rj=NgxJS.Q ˌAKGEIt24RDu2Fa"͟m Z=5/E46OtؐG}Qr&OԸ;P7X@bn(a tk˪{>p8;o޼￟gD X˶:f[QdOE] 8</R%I$ɈN(mViEwBpM^$(qjOQS2JI(j4ᚌAGcEH<^ D6mˀ(20g Cl?ٹs'x"77@yyyyy9iŊ˗/olley޼y˖-p'.\p s=Gu4^{M.iO9S q]d`[;f.dG[><$])M,euRU`r M*{*Wf@AĬ"0C) .M5'L\qhf޶] !;(MKn讚bqf7!:IN Rolthqb4l*T`@DY 7aЙ-u5!9DGwtK&i;} &fŽ%EԌmӐ4h"(Ê"933of̘QTTdyٲe3fB/[|Iӛo/gddk>#>ʕ+|͌;SJSt! Ñ,1 m '4 fEaNHM '6 门L|P7ټPaN),{ S4G" G/aS'ˑ\B`x5zz/@bdwgI8-;o dfb ń$]d?UmOz:[\#9DG,"k="W./c"ږ@v+:HBW^yG322|;Ν|믿sI 322tI]w]GGGVV֋/xwL<ҥK_x" R G6@ۺ^ն Uhq#DmDl`Uxuf[ͫ)%ѝ7 -nL,@8vĶdEU6mmFLjU <Vvi bY]{+9W6jvDm#>*qvw(NbHDu%=,#RQ/Eǜ9NgPo`}Q{{6j^۹;wnegvQS8<陓Ks {V#pT4<]'9DGM+NQ@RV9.3qzʋ|h0r7>G b( S9k|>ߍ7x7W^y妛n2eʂ ~mڴ4MBH04 CUU~2:p8֖l:N 9H%$dN'T_WVϳq}Msϖjs)I<-+9!J ¶ )zm[rSL;-f"t;dCm$!IzE#T~3F40fhy|snl~_0Ҷ7|SfĽ-ؐ&=mUb/!Vnk\m1یȊ nfZPxdQ^vYaδinWajSkzPل)A!g {P$E9..# 5P4yXN v5|'z\ Nz.Ɯݜ)OIV!*bѩև?6y9.NoDňh8Ѻ!*(ÊCHNov̑,ko}롇ڴiӂ E=Co޼Nb@ktt$v,#41`#DIL O3[=b(+kڕ ]3:@5L28mtZ2~j TÑJux>IQ`8[^NVwoJn]GU߶ڦPE+wlmAU>!DDQљ6ArԬ+# |^;ބJªopWT=vFf`ڪ +h*vp'%IăjktؾyUo94yi3+T%QmJm; h(D Eyzp@{=RL45J9~C97ԾC̟RudzVˮJw;Řsu?!LDc#`F4Woӛh.EsAT@LYi9ЖmlbO(MLݛ;> B`gmnn>#UTTnYc=K?s{10wD"=8eԎvjTp+@SqV/&QÉY_WVW4rȴzȑ,>7UD4Ģ y=*d ^6ŁnkBU~QRf6cB"}W9-nIhyu /^5Kt[l#S*W͚લe "J>sf\vG@Uľl8)5YH*Jj,E"=w 5Y TZYcɕ$=¤4 8=`e3}k7z+=F01d^؂t9}sƷ_5ԉYE̘ E KONz;J'SͬSSb']-LX5]8^fUi7áiEc^Yb#-3%9DGM@yaVb$Vò{MA5lo gyh{(r!/N8_ vovڕPUuٲeɟnv(US.UAPj[0nXPě3Xfbu78nD7z/^t̑Mg~(VeDhP]6|]ΗIa ~BlS[89ˏIUH8yz<8ɀ8ZZ8 q!UEs&RBm2J~JƼRJ*SA,y\H1b \~֢cfyqr[irtJlA B@)M;uSbmF)%C,&(7n^sW.&( gbD-ڿ\R,PZ]Bӄ(nwx> WN;Ug7g"$u&leDeա`E_Դ="* 1-f!q0L0[V nlm(I lbgj? ~  FS58BQp9?š $T :QRU P+ I '!VEDXj]^$5#R'%ޱ`ތsN9fT&&Y]0>"@ ؜؄Ȣ('5&ў#>dIfXWa8ےz( T)?@p/,;`9\Svs&N{ئ0HÈT=ӣ:ܒB=@a:#Ih$gq˔xg`]|J1 QJ-lmbZeUS]+0=l*(2e9$9)mĀk'R݋:}qYw[sК$Ȋ.΄VIQ(<{oִ4M2/>Zz$1EIћ]'{*˲l3; dhnZ8ISUf)l&gbW#Rv[mYJ55DPMA4Ve&fUzz|)ʄ.DNXqd7gІW&f4t$bPRf2H%Dq<#Е>EE16֞xa ʶ6lIV8l Κvζ}oy$BZ,> lVRMj_i3bTϦԆJ!F;\RHIʟQj. ,SJfT^Pfg^ÝkGx(%dQ3TLRk(;D=IĶjbBo u[ؘ(6K؁2 5[}Ǒݜ!3ɺWN!&=,?mbxK ;9* ;E+Dwrl݂9%3i‫舂[GT19k<(pI;pIF0]sV̬\@M@ )`Dߪg]l 8-۩,v 3D71ʼRYs{Gۢd ׾sk/;xP,8 :%ý5inVӹcn΄j2r`dE*HQvbJp1SH:lÌ =O ;k@}!71n9|I,?ĭXGg^yc$*^CU+?~0 qk8gLu8LA}&>z3[c뤉/`^krsƔݜּ|aϛ/9D9;a#l+2}M{b'L]}̗$R`R'<5c8al7hVZ JC 0G?}Q`OzQ5-+p2@I8nJy_ IDATfZ9+M2/s9ŗb 5aSu'{ƞɻ^z7db&St= &Y^$MǑݜ Y1Qk ١p:;,~jP8:8>HI;i*@l s| 2ءA'_ęY!='h<• L XW*ۃYt+eV#6%Y,=ޚ2)T55 7iQQl[bܠwn([.5=_m&H{9<1A1ly<YUJ ɵ.o"{cnQ&EEY^=#~wvwGRԘU{vIn̈ H5vTb}eH+ӝ(}xe,1y CjaRRuHi41с:0%砝8Ͼg!,,_$+Cfhٞ膥@:KA[k.4Na&P PPۊy:5?P&e7ax.aBB42udviɘvd=x 1YXFܲjlq: !M؀#K]RkwL QI;(@m6KV&:$(끚^B)1H,2B,ha쏫w( ZM+ AĦn Pb'{X {y}vi1Q]ױo?)JA(nT2:*R4ARGvs&H{4@ TĤdt,&kѲ&<_8祽7s Rz?Q{{tuҠ 'ᙯisRS[C:[Dw8t0mSѐ =3I-m IH^nΛ8՚~ׯ$TJ~OΎ_M"/R ƈKZf\ bn=Q_^~j m(cqB7s7Tu}gU)T7tn+/t bjE"cnibR, O! /53@)2cN2 q+2dR,&9;Xfdx rRGL[]]m3 ry,>Æ`{܎SqY*}[ݒLuN[R.Ui(Heenqg~`b_yǶRu?(.q,%Ym U+3lyF{)&jB61bW]Vevk ,$Qni쿉ԼHF_vs&B{Μz,'o%%09@gN=vC݊(kvVɧ  bٔѠ١d= ĔtuChhnmSWgplGål%i'GzojIYedll1CpaXC,_&a20L0f71l#ZlyվtݥRu-ɘΣGOuu]os9q-FF1d(Gs}9C"RTD=ZXqFV`r$q<9 Y/ 2J۟mM,bJM(o3rB2cTMUT%9 D(U9{eo|,s*ApK5ťDBNr6穃 ;#t&ܩ'DUd[{\S T1j-tėے)=-[>ٲ{Lg{{ zYr2hsl'R%UD ˧WS@^X8 p 2QɹJhc[ܹ@LyWEr-L2d('2ڦ ,MX|RSeZa'ba^@UEpNTtgLx>#wzyM*X& 2.XpzN<"xa_[5Jny_RBDt802bGw/ɭu//"Z̽)>پPۮK#|a%#D ׼onFpT8Yɩk*sR(W7~ PS<~]nK@\߈F5eR]Ozam/!<"h,2NKQpc٣&RXLvAcF;2=񦧖f6^G՝c3Xi\m|i4 #6PM oPUQ$;;?΁=O*/[$Ei-djXK 6gw}뭷O?tcyJxĘKUh"/dH7+LьFgKeÐSp2Axmmw 4}[_SP?wn )HNXPD\,%qG8eTa\#u[K{i$^𬆅 椫8m ~!CC &*eQ1k bk1dP&{TO1U] N?fCCCee… |I>}ӧcJ\V281?/G;Y`'!<ONN__ȘrLc[zfK*ՌPfJ4ԖkuU-Ah EB)U.[:S^_`R5b3(8\LzD{yoR=ΎWuw'W,Yp20"tT$ۤBwW_"I@ӴޑСSaZ XnK jK/e4⊲^xaݏ=t֭*N͏&N "q IƵxh$~)@QOdŽBjWjJ1ٝϘ*En^eS T%lH2KD%V .U@}TujjJO5+O&ʑثmW9uM:|ң$?]P[A*T%DKű' 0}nyߠ1xTpƵн]nK>or\myR=&cK=t/_rqfo{ٙe)Ͻw}[oEYp=%Q:::.Ɗ)/\MrssoUV[?O7nO?xc=~ppf\ꪫ\y<߸vuٳ'77ꫯw|0`08mڴ~(.KJt#Ip("zCk7ldYig_^ɝ}p(jL8Dǣcv;6;=UYYV@+^@v'+r^<DY-pThjޢTK/<lywi޼B;Hn%p$49`K<6\[Qb"Gt]cu3$Y=I֔,w`T`ܹUs eojOsc@"c(&hr[2up%}895籼R@ pw4vf,յ/~իW_~?O6mT]]D 瞫_ZZZ ```ꫯyo|(~;a?/ //>?<.,G p{%UKv1GXyz\G~$c6j*U$=#@GT%mx: CR*M8tSӪ9ASA{x,H" WhΪR8zg]'r99ngwN}uY1eqcYTjx2!Ll8*9Q AY\ֲ>8.Ɖ]XnKG9|mji:0=7ttt;۷ozEuwwgϞ {'^~kyV\ `W^ys=gѣG~ pm=.Rk׮B3wٸqcNN=BH]]w{LoQK,y衇誯??ܚ˫S@xߠH|@{G(5,&2Q=EooH ?j,4w~A3I9<*E5|U;Nu,Q~\Cn@ &45]'/A 4ДةjOpԸy˙Rp=]PUmr|cKw )E$`"qLT󾠾Y]y*;7(5Qr[25p4O5џe5M{(Y\\lzȑ# LVQQN2-++[=zϗ66kMZ?p8.GyfΜy7/^8~JKKIȑ p8EɎ4Y !Gp<$@wRgIr<{iZB:?:V~Q K504Yrx D\P_P= ꐩDMe_|F[[[x_||sO(h"fxg٣O>ye˖|/iڎ;~FuӧO_t魷Lɡk*޾m6Y%Iikkc}.]:88__DG׿e&u4x작*6jg(:;I[YDjΨ DtU͔9cS&(E8Suf5676{tH8[0E`V՜nQ. ړ GhBSC& }qr 08D%:Pye(s(HQ+>dnP[:4[SK)]tњ5kw嗟r)_=#<y]xyyy,xɪUYf#[b͛g͚u7~^xI?\YYyW.YW_%ȲlΜ9fz}Q;[_>36m={U}>Nf.aFY#@KD45~Nns$:"0v2_$PTMǣ!U)U +__`qC˜;M;а*yNM6M4MQ1MS(jEATs$CAǧ4ШFtJNGW&ƌ/ȴgEǜ޺ƶpS /TMh팜" DZ .%Sį;+@ߓ^Zdef`pis~W^p-3Pcǎ=wywilP__nݺV2f̙3^H+Çǯ˒"b'xKNPCK_Fjԝ?m޷sgkأ'}5;ũѴGkgL&RZ:ʂaJU`$Dg%czgʣ2&/_+%RmԭRM&S~fS 9H8p)ը;4J[衦>5MW1=hOEM3O-0QdQג?R]r[2p4OgL 5ReO%SA G%~Rh^b;g0,C͌p('WQȏ?x4JBhj>KCooC MSJxMQEx}aR2mCS@& N8 xB,(.MS:`SqI@DBt:̬R1FR[P1`@=N)dUGbmQTfٟ[;{W|+ر zc(;`6k],w`)z,7R`sS3p]su_w&1;(Qg2NQcx YUD =8j^Ud, u4 2>dKCM>j $a,5Ϝ3C JU40VД$ٵQD(tId,D x0>j塉.%SG3^I{{zE>jɘ] 5 9BJ86?{'/(UAdN{Ȼ\?F2Qcn(2bȮB&0џ5F DUEI.` qm jʜ{)@nKQͬS|j,c웚5}*.,UwUJ`/8^dwGq,8NTT&ܖLe;FCVZ?j%!!0G M*JQ+8A(5}'Ir1DMt= awn5uxTIE=U㱐JpiO ̩U_O5R-4%PJN:$rWS`}uTMv ,WKSQS)/r[2Ep&L5sC1vZKEE`Q$a5+Iv˥D@8$rL{4cҋ9rdǦ*L&{K7%\/Rq4C(>:Ukg6֖ ǥɯaܹ}{;YX %Ӯ&b{;BƲ'Z;! (H\qInUۢ_nKbql=#W IDATVCoO24"ڜ:*u@)joH1Llc^mb1YGfTջ.~o#MFr`yxRjd:@KCɪ:>ʂHRMuULdNddTeL؉.%SGM.{el6]N}zKK,INg|Rp ǗW1MR=Ge,pmFccjzP=}#9!GH (UI<=U*%Ɠ1)yAdT2 y]R cjʽ#p!mT٩UgBAP|~FE O+C'ܖL{1u3 u{Ԅc!%],$Ǘ0'{èU~O\9C@3M]Mgyh?t>s#Ǧ{@S@%eZ[߭FحNhLĴ .:3S1o)Y\QSEP .r[2up4ݵkM+EZ테]2%'\w5WN'DNe?yq{6=!(Re]F>O k$= :Qj/_ag.橋ARjhoI.3;b NT5JZ=_&4O[FemXh1&= cYL|NDoc`:xE^@USI(ƣ"*ƿ=r"y@EAY }u?/UgLh-:8j%'Z4{^B6gOH9->l˩X̅P8hxMD~&*o2D;KR Θb$>oc#r=Mѹ?9dz5 a-`O< ]O(2Nta͗_<4rb=STѲ#\_ᓉ()Q2}P G_)S'M Nh-${ukmmaHommAXɖVSK,1p'XD>ẺDt(6ܯ|wӛY.cRYzeW1V ́ɋIa3>#6>?Qd2Ήr{%U=I##!;Ý>Jm^=I*rm~TS7Vr[Q M$jb-[+0ldKNvLQⲢjSD 6g=VG=:-;KLO UTS`^Ț1Db.؉.wT+*9@5)@55YhS`O"5*)`-5J LxÞ$)iKnfU^cKϧBMS>rYnK~],[l P_^UK2 %0^{09Dl8~O__xB*vɀ1* P z~OyWUےf2aȬIyjDMv^twL-%Iɟ J)ՔD,+qYMݱYX8.&--fڥձl" 1nc3ކ0ˤ"{ ʒ):} {En[0!&pW E M$;?@K R}U^ TDR %qMmu3|@%˽LގaPE$<',-k~wi3~mGYHsZ WolY-dDXvBxFx R- )6 `ρnAcR<}ސ,ܓ%#7/:ͣ4mM>QdTa;宲Uu) @ v#!`T$chenS@}_Hjbm}&^hwr*k%*p}O{$ے) 2g ӭY~}Gŵ$$`r$q<9 Y/ И2 ohL5uɘqxg2(I5C8> * prP56¨5vl U$ Nx^B 3388qƮORđ>@7thfbz[J?e̩*tN|#XW飪*^!6(W_HFmeNBqfxchnd*ep_GozF@t"mQ=H, VSeKF(0jF"h,2NKQp=\rrPT%[X2ipC&PQ@e7bA! ,qt9G=eͤ_P)BJ$%>ћ+/;/}_nK=Þ1=с3}TG\pd)XmE Y8j<-lj<'jvƒ:b8D![Žíұph8ܪC,K/TߙC ӕM&zT0yOuP0GӍtv_'ؙ74oh:86n5 /3O?=y^[ ͝5/c*D8Q+g.AiRZԎaC#ZT‹nG$fpЀM(9 D0a&g0rh|okч9g4 u/r[2upK껞hMAٝ\s͖-[8_җ>ϓ{}׿>g9 n$$jhƫ@Fb3bYڧ_y*J\)4INawEFnӋȲNھMrH?8!Ohz3c(KEe٥Ht 1VYSUDwj́xsU^tʙܰ #7R֤%ˆʷ]Mmܾq˚nsn~.r[2Epw=3zL֪)j)^F?7kUUUY8p'ܽxa4Q]ɻ/?跻Yg]ȃBh88shGS>ؒ/Z\_Uh741Gqdj /ɂuM/^! x<~?7EEE7tWUMv^=ܯz sƌwug aݺu+))ϟOqp8|?%%%.ŋ݄xଳzyMӶo`֭(Z (G p{%UKvN#g*GJ5P=|)#QzF л#* ]Xrg:f N=xmac駲܅α&fo-ǹ޲c v99_ m_|}To?xiӮeQeEd1PȔ0;oӋug5k(555`;|[n]zu}}}CCW_}7y睂 xg*BG}{Wok֭[|n3<7soYu|_W^~=q6l/7t/?N^ l7h/)/+`cj""v6'8'TԞ*rg_)p$}Y9#QkdO)N?݉×]|e/o W޹zaf UlF>h_kr@)p r[25qgd2u41X5IIROoFﯯgo]tE .|.\+lٲ7 G}?!t38cWp֯~^[^^+x=z_~nonnfWkͺdɒo58dɢ 9y%ؽ: $TyK@LMpqzapJ0%6cͫ8Hh*gZd uAet9SQr[otɝw/B__xW.[g=󊋋)~saDž,ADQ,*Js:p!W_}~3h^^^IagWpxaTyn^9Y> ,b!Tp|瀖@dVy8T%=$=$G 6cY=䋍&cPGB\8 6w{窫\iUW]xwqBmrQl+t͚5pg}&-J\c"M)1nx2_ K=ێαEjM3Nq@TMJU !G;yF "h P)8o.Ar"ت"J*Xv&Kd)׈G EFg(XMf-DUX262oii5fDPkI,aB!0G M*J!%8A(Gci$zEGD\( (֭S@?ȨTDճ]MFr-"~]ݻkWXwM%.IX鹄R%cd\~Q<Xz>!7EZ83WYiө=ѣȨR1ZqdJ٣Fh3J*y-D9 mNRƓy,.G m0$QaJ`(65TdYVFU 2g0bDXZYnK8j bPBs`K9ODHi MetZG r4U%nj/T'|V㛗D;p/ e{:GJ1PcBgBQ(QJu{r*,nPdz#ܴdBkp| s7D^ wޙgN3QWhN(i5EO(jgp<HwܓSaѱ71j֞%뮱TX*,Lqe&S7FMo!{E,9 '>яZ'Naٴ}6Hq wRg ȋvp ]e3RE"YVdeT)p8rNtBG-&~T* \k~f;䬔 {B葷pzPFoh{R'Ek9UP(E5B@%SG-4ZfK )>Ňm9 pwP4kCDtBpz"îh% E%\L,$8b胃O"rzL%_xOXSfɧ(ces/4"ΜST t4Ւt 8/=yspJ`偌$jAEo?ѣHWj[,&\1(GeiӒ%4#}s$AC뱲ӼDphsW+iUyN|y6B( PJ95)WaGuςGk7X\EAo,=@rCnnc V,\}JΟ) M^:PyrLkmNvB$Y#ؐyѕN>Cr(EP C(gira* Cp +ؽuN6]mzK)( jB yxl>|5 /Jy>w$9P"Qhy6һ jc oFW.9@_qqM -o/vsۊŕ$^2s+MI~y<ۭ9酪/|Ngz+Q%'h^{mȻy!!Gx6TAN(y~gb~T8O\φ~-Vȓe@U YPv^n p|T".%[,<(]3 D|5$x * F#^ThDpك*,):?PX}~]֮:xg[[.prY%_pE ږ[ d")/ܸD<%6սbq-8n+M,d5nJV4+-0B %\vnQrx?;9v-AS_ko<N^O.nә‚IܼbP@~49eesx F-AtnP םcZCի/GLTDGA5!pO1ֻY n8K掿9/>uR4J()h B4(# DDQ#Yy9 ƪ8'7'0oܵ<'2* $7@Te ꊣ[Uk}zApΨ9%]%SGS |Q0bێ,9Aikzz `eht<'&hsxT%>Vћ~HG:5Ow 9.u, K> oxG@C!srbN[PPPP7Q({ZOVK67 Ӎm1hibTܜL)cf+4J|'5Q8K>,>QI3#2b߽?]6M}.3eœDFzv T\^# Wt{(M7,hH`g[ :I,TE^k_zn)-YZˊv}!m+Δ)IVn.soDJzBS5MEWt"K}ۛN)Yqmrs Uk}wnk?GB~0O֗ɗ7Ovwwc7oF*ˆjwbH4{]v.((Rg{x^r򄃪xUE –trԞLy_sOFJ'ޗnqF!xp (؜]gԕs#I qFLgWON濿x yy[P9Ǭbɗ.YfOZO%0헹KϧT3M[bTm: X\dL$l)mG-,[1.w;̄y`hqMFt4+3j>{`xy[,rM9~&+$畄(bN, Ѝ;:</qn AѮn#"vuu/^a3=!n͎عy悂:]\@{=a׮{89:}:UsdL&$ $rB4dw",F}UX#EEPnE˾rYd׈:5F%8#06s|mfTz>S {d.`,'Ns#QaJ)YMV o wc܋a; \!QSsfxef1Frl %s2+`]ScU'N87Vy~RG-< gu.]Y+нv%)DT8u#sxyǡ%ђFK0rgV"*-I"Cjw'~ /bW?~R@e}wz87ɴlaَiٖB9Y@nwrP˨7T1$6LbSyI]Au[%_{zHXi]czBIr&\9*Tc""WV@ [PE&Lm],ơwc$$r*[[p\c<OR[;gwepHE (dWf.#M?>@0|c{_^.hշcѦFup\նwaSW2S!gx_Tr&}U[}o4uLƚV}ѝ / ~<3V,N-}\)(ڥgo];3ڤ.1TLDtз9,#iկ6criߩ죿ј {zz֬X&Lb|ooo* U,#c(T --H&<̴e0 I-/B8%Jf L ]#S %_lc݇cfL vsމ%68W.is;=dAH&v̩ '919KΨuMIcCG2H"(ǻR.` ۜpSO.`{/cb(ܑe~݂>g-ϴg?~>:}o3Sh~Ew -݋αqC ݥNX84#i9XurGy5fȂ$/Q=n#5fD$͖̘},]ͣ# G>יEtcs+I9xg{3``8quCcr]@/.ԫD];{Yxd\~cĿǞjj ;j% =ΐ[LA( g"RW7W-Yy2?\}n2FzBՃL )<#tt%p˨u^9Of[dĐ'9%lNJ_eW$IbX{ϲ6|ݹ\>fM'cZ}h<%JOI ?qlSf*:cq7}y#N+i$i㒄U6v޼CCCK,044H@app(]N' 2wqI044*%K2&gϽE%I{ccC4:i~ӜEȂvs[ MtL{EgyCC/n"-]ϧOj~d0ϹCd%ҏ8} n$+&Un;^(Uq=gؖaiE/y]ȌZNWTr jU cn X)hY<Γ߿tv=\ZL \B-$J,*ZݎS)7?U4_W}])ķyXܡH3>zFm!﮿=^a~F s#8 12LzHؒR Quw1$I$DbbŊB5x"1ʭpr@> BP<߿P8O;c$AQr_L|t =t(Ԥ(JDH 5@b>[i0_#CCsqORĄ{KD$V>V I#$KP$ns.m4_Wk3e(~XP?˹1Q?d5;1(UfH2s?9Ʀ^xzOcӂ:Ǿ7U;x|zCuNZȉ+qm||(B{{){_n{8#/>޵/Kwy!$!Arv*-)r*QR⨦)55yz8TYGE޳gw(QD<mii CX\lQ9FEQZZZh;P(BW_ryƾpɭӭsC,Kh,QR6SDF]kYmH| r?6I Jxw8!?ۍmVͶMJO69v̅k?E ԄHY&K^/Wi2եf VJfMe5gLrَ<}ʡ7̴r/޸4捼u(Mg.|K.k}ziڕa4䵫ZID'1^2sy/ {ipn$+5"pp8E"aR&F"fIZ |O4iЮX,J~XssĭHs,e)LTSQdIp()iIݙpb8%Ium+ Iý~CC 4ocV4a4<Ι/eU]%_83LqnCRH2%EWPT9I8%3 6$GLۄ!r$F,t#|ZD!3o\2F>uy>85<_W<"k{i\ιkڞxjdɅunjeSLӟosN (eǶ\Bw(Ȃ$IeIrD3,\$0jNQH,\GI%7EWqD!tZ'\.d#4T]'m026?8wd$ɤ)qu)+ΊbC|>ERC43ݜےehgʱM;@V_E)ٖ=_d9I2332).5Bv IDAT^05+ >˯My5,I--`Z '~o=im7*x}p Mu[{xYzUM .uz*2y+%q- YF1Z,(z(H]P%FzEgbᵳTْP8xLDQR&aPv>nGCJvLnlT5]eS|Uğ |#F:hܭL7{0 R@=P Rfӟ@OhUĠMdKZ-1Jr-T/9VC/jQ4z2\W^rT<@Dˉ(n &> nleᜎ""\ȗ0-EU_BPyI_|TRK;rtж5)kled̄adm#QBU70#=P+plH=6I3$FDjjxgh7m;mvIjy;bx"`iMOf?(MdxG.Ψnwo;< ޡB唱 R 98o ZQӶ%.q>P} f> tN.ڂ0b[ ӌwozHQ+qp~~;$ ͯ|O68R+j* 6섡(2^C£88 ok]f"t<=kWe5La6ioE5{^?qĚw=ݚk|< w)r ^_;@G'S5ju>Qñ \&h>޷RN)Wnį_%yOK?=^~fفMĹc˲׵JجY;#=aYMH2d\7}BdGwCCI *=$vᖦ=Lk4X =%xMȻ7XƟV,YrIUAVXjπS Rɉ9s>M$ߕy!=G@E"\!H32Ufqݺ8Q$:LbDyAA%FZS(51jWCVa$R^"Pa R1۾~4::N}wI+ ĕkOk.)9{{琈R*!9@jN;̦T_ >a-Hj*Y\DɹcED"x,ɕY(fDT- 7EzTf`$3ͯFHSX]^-2d#zUlKaHܫ'n WG^+Em0^ooY&jL ƢTKȽTYBVm* _{#ͤ>4*#w_7[vEܗw;^މWW TeJ/^zzQ+!s[SC nLHڼ́hW.c ]EE2A~ = 1ɣ%aQGFQyjp fqfPTL[r <^7_C9ٲnl^ԴS@V!+Ҫ/x`nVc:{-[[{{R߱[Do{KP)* M*M/-2>8dma_W_p=HJW_p? 4jT_0 Lv=sQ>tˏ;#\m KzڛH[tș9_yX*P* 7=cs!)m^{?,UR523lHUZ[FHwwwoo_46UzZ1?xPg\*pyVJ֙stvvBMhtAnLIf/=ͭ͋|򣗑Ү̨`wP? [ض]m`J7pr~w,]ܱt+E{c) 47mzsq+6~=k`{@חOG=x9l*> I TT| ,32-SaZé IT<]yeK-Y()܆] m"9PQ459/8O̕Hg#Kn WҋEa+X .>DPÏ^+WR~ w+{+= +O,uL^ܠ],*60 oMxqFޢP}Und6K p,ѕpҸԨ`GIQT- _=nvD9744 D:c1z)I!3WշWLdAڇ?=Go^۟F_^̿~M 8Cnf 38&xlۮ $%}|bdRzZas lYlO{UOG=xSpfȊYlY)0јXŢJKK]Gx; YL8Jo+~a02dؔѷ,s9lf@qϝ28e9)Mn";31Hme?mՉy9W $47:4 ^~U/8IMeYa깕E7E+Co2ș D \~?}kI5w-K ci\rw֜Lu/,ZkN>8soテu6Cڛ*ƒ<ST:gIC+ii/&%466͛ת(;FY,7f􏣤0 piy"'ܱm0T*cYv&cΝ3E R 瓙SѝgU^ uŽ NR}A9{SペTRh\E!dP2?rɵ[رoK tq^so8mEVf /:%t`6P< ;ڲ'n^{ RR)7^]8 z0pvlkpܬR55EYW H$E;;;njE$I(Jj,0Ί(MɣA" gEQP2c )S[MCQXkh{chK˷wX,ɘK^(`:NplӶ a1PJ7חeW(j.ݭ+>|݆˷|7%;|Z浹ϖy-8#h*&Pnm1JTJh׋GYxtԃcF&75 J`}  |l-̗e%GFQr]]]zFNuxFgNRSOY=Ѯ^2:_8e͚JsM^X\ʮٶet eg_z/~X+%K~ WRixuL,ڨ3L+=.Iˢ[r1 0@Jl7`qǒض]Ǩ'֫ `ߵvw%\,?]?C+;H5%J+4뚅&x]oR.uR2YY2(Ӎuww755 ʇ)Ώ2]!Ho E,J5B HP,:$\diTG+i6 rw8/Pot: :40tOxy9W=^QzDTek*2zcgK}y?Ex6u^A1p˵mwɫB$2^dn^{D]QQ!٣<2$'*1[SS7wґp^ڌs)MF;~)*HC}l2dWQ]BI*G] 4{}H?sՉE]:YRJ_Ibz৴8>3g1 `,LYȫ-'9$)QlS!0w\{=wm:wD]!5o|-qƒgz0{or( +T0:T) gԸ9w! \1ߒ[x(i.?z07uJIqϾ4сCC]j{ɚR "T]ܱ6nKnK_ DF)M2@kRRC"zp|',iL (~[‡W}-J=O/?窳/=c֒O&_7 ?IAdT a,_in$4mط[Ѵ~iŏ8{Dy;RMB20":iꚅOG=xxCS}Ibd2O|,-Uz&Kj;+\M̴2fAy/:?E2{S(ܺD|S8 &bjKBQ`H}c$_}#:I}[5J!cIP%*KtO ̑\e9FϋQBXܱm.Mo~aN\WUzý~eA+O{s]mTؼns^%: %fQfDCN6l3>.3Ʌ=p!Zf(-@lDպ(]gh(.ҳ-nJ) \%+*֜TH$LIh eN/Y `X>OIAO/~{oԩjؼxQQR\fj"2Gif`qқymYuUp6Y u RHgO/t߹,i.5E5"*mn>;nϥB2i>O]u] ĩ9n:ұs'2FBJ<_mar"r ɧz[BT# ֚×]0/_1 R|p|痯hG>`<TFmLejXQ9‚vAyȂ*E-,Y0Nrn5y[WP-hcGn)./˥R[k5UOl;S쎇@I!E[A}s'!K{ *ܮ]*;<'~{{ ڛD6Nyǵ,B>З2G?pf, K[?{N(8rvMH:qoڂYxtԃsN /(eǶ(Ti.yxxp,c$WAA IDATmqJ(\VT>(|ga626?X*5OݵN?ag;f9.0wD_}Ͳlm-+T=,[cC2cې8I6[?a;K\G`~<-|.jۻOZVv}a~[,IX?m-&2ST_,+525 PL"zqWOG=xT_ "-^F.4BR~ H48glEڥ=jA39]yT5&نR)6綝bwzdd*܈&FQV|# Tئiy)||iO`rţ6/(Vp`˯]Z6 y5fXPfMd+ZLK!ffh@hcBԌFtv j PKA;3[BhӶYb8 s(Bf> tfEm{E˯s+h@ '<|!ɶqP"*ȉL(^|Jbcr 5xeU=ΰD6ŬPA]p c(6垇A(~_(~83J)<oU,d|e;V6!+.[cBdkKYX/kT}֭uǣ(9 68sOgm_p<>8ͽIbiAEf]q A;Ef6iĐN̄BTQY"HKjȪc c3ߘƒgz0SpBuIT`rrEё9sL[\W=poqť"*GIQ# ?c3bIq4@cc*a+cmiS/3~滗\uswϑ/kY$FU=誖Pl#zU:S fbPEBZnC =,9w,3S`,yh&9Rx<+;BKV-2#()Ӫ *Mbor%fLQ̈́hE,khht/$;mzH'e}⟅ O9nÉs&M@MSI0I`2db`20оA f2PU_kX0Wӟ7[gJG=x$1'1 esLOXP> e5lhhM"ѢR!5QFPe&ugBQNG|հ \9Y ܋p8<<< VliTVwmP> pLO@R!QBhJxT Y 6Lʌ j|5է~N}{`߉}v~˯tQHSxQf3%Hc,U4̦LTVּM*[`Z]bzSD"7UaH)^^ǒ*9ڟI?.I*AQ1Mu~]UˤO}yZ =,! 2 lYFckָVǢQ2W J5*98jQRLm˗/#5dl ܆MwQPaRٽtYۼ܅ӫ۫s#gH>IA|߲nf+WH!31ѰLz+?j&ԴǞE_۴82 ۯ8dwRҙPxtԃI$V6 @V`˒ \@$bc55s,G"\dYtV]q#3U(pt4bp7cd&$Ɍ)SU>:eZ#4 =#4RB&L R+bHMǍlXLeYa깕B Ǵ2 LӫN\λsS6YvEm]S> G@&sxauۭ5'n#K5(5#+(9ȹ maR /WMڹarJʺaMryջLPʬ(إ_[jiypu^bVZc)5_{h.i( "͚{#XKBؘ[``ŧTWPP2L^#`,)+ O1ŲyEG!dq|>0W>i)8+W-B&$ܱ}7W&wƒ<2$'j1CKŢzzcl6'uX,:[g<=P,z(4Fp9B-;Y;6umΜ9ſSHȫZBAmMzMDeP$dDRg_L!$T ;UXҧv>0`$$"Hة*/.۱}wI z0{or( +@,6ѡ 6l_: |U~jnFT_ AIo,B0ݲɍYH"ꈂMɲ@I:: PR%Y"߉DJR*-")5zxZ O},NIDxy""OG=x(n65IM,FPW8]˙hpmL< BQJG Sgψf\wwwIeLa[`m$d[فq6p{;c޾b->xzʳp)"Qş(29r:_3s@U=dUXY(5 l}pS(DQ80CQ87-\tgo'а2|W+YtfϞ۱};H8"'ؾ,OG=x)xn̦ȌYXjkDzh4ƄbPhy#3_!([hBܖHpP8)'Hoo:> a,_6hn$4H$fS2FepNLbS5#k?u|*@6.YEV6JZ.Js"ZJ)/W}WI J;?M@mtSQ'HByTmQn瞞!ߕ\*^ UXްÉPM4pKUTm,т[Jf$)-ӛȧtDɍ2飡&gpR9 7LXJԀű 2UQ -,6dY4mt4a`ccȒ%K8c:1Yu;:߯g2I]& 2*`ПɤÚ9C+V7>>E$sԗ>")Sk-P؜:"v صD}d;_|^x'?Iuwy^~O7m9xnudKPxtԃ#SIN(ȱMKsB $"6 Iog oE%IUL&ͦeUU$tr~z׻)?up0w P({Z*5TfF$I,(ԃDNH,#h~5*zU}.OԱ/7-tm$d0ǂZ(x] mim?]5wmX|+^WO۵7O}r[kN>8Nj2t;aG(V[\FX)f6ɖ}[/H R 59Cӝl㫮*G?1kT_RHٝ4~]u3RxtԃY8tlP8ls[MPc/0ǹ Iq NrȔ$p/,V{]!(*[p1D뷰USCDn:X)@sl3qKfmHrd;*混:)3Ff6 Y-G1W|}w$)N >P.tVHcL*}N LKQfm';|ܖien]ii4T]'126?X}}QO)%x jۂiZ)۴qU14ScdScF&TkJRdӿ/pLgK}{%dͯLUئ57R{(:(r>(39o\ЪRsH-ٻޚAPuJIbs4bC%тLbOJ3a^Ǣe=Poe}QŌrR#+tvH ğI_,3;Ȧw}BsoO/'_d1't 2S^H. 54i).,;>.*82< ϻu;mIZ"2c:} =,a^\\R)Pr2˸kL.<'P+-8fwhiG0@t3%>/XyP͓ uCe3+%E:Rm / 4$6d7q;sr2}MkmRj K[~?|[ J Ȟq6dWng阆-xB2 IDAT'kNyt7pKA8+tb˜Z3GvIYŠ^ C(CUJ a|{p޹cp⭎6fHjϲvZE R` i2wCddq8+|C8 i~Q7&mg:m-ntVN(unrSf0ї6oq9:??uJ"T:GCk\Ra"pẑ" 0kj(!"wM:S:C;=&.*b !Xni!0Ce(t: t: : @G@GQ@GQ(tQ(t: (t: : @G@GQpA=ϛ_ea ;p?i#@GQ@GQ(Q(tڗ{ÚwMc<] #Ŵeo~oQ@j㺞:qΡ+&w:ogFCp8-lwsI9c 8s*R+B+۶¡4[+ǃaaa$?"|&?Q뺝A|Wʷl;BiB iiF"P(4$c&?ўE;;; )J4:;;#4͡k)ia۶}u=/v^4i7v(ڶmeYD{cG Hr,AT0ֶmk_|oYʐFzz433#)K~K|2KzG{KJnvvRZ pjHnqW˲&?`t"`b1t: : @GpX@ߵMto2 ae Jtзɦ3=Tw껶ݜ Ađpկ?Ղ&ߒo)>zi}`ԢXIG]}eo+Q[}Ǥķ04 H^ՠ6(p8 ׍_}խ|~UUUeee䔖nڴ.: *++y˗߿_vȑ^xaƍ?hiimƍ}Xk8Neeĉcܹs<|{uuwߝ7{W8qb^^ޢE;\[v -[R^p!~֭~]]]ii[ZZ+Vx{>`MM޽{JJJ>U:^b?vhAAAi4uvq𡜜l!ijvƍ/))kR:y^n'Ok*^\k' _Rws]]Rj۶6XZ:=;;{ʕW?qQ)ey׉D"'N(..k2gΜDbۗ.]>B3رӧOB_[[WPP...~-Z}-YdҤIBݻ?ÿx0@E`Qaa5O=zmmm{{}***jkk;XK/k͛H$X̲,0Ǝ-(//_Ѻzٳg}wWeQ!Uz([vRѤW^}eݺua"WVjSOyp=---SLyoD"QU駟q]7;;'WhvVOaË ,hllə5s{꫱HΚ5+/yt$FԆ{͸}lh-OHG^. XѤʍЙF: H&;mj<=Q@j2M0FЙ?7!dɜ_79[]XvzȒt:yΏ-9i˜ C*jmwޖ>)8!#3sjч>m)ieϘZT4( )R˜zꋔ6t#w0R4cHuQ(tQ(t: (ɒfb/|: α իIENDB`tiled-0.14.2/docs/manual/images/terraintool/07-drawing-cobblestone.png000066400000000000000000002730431260670167100256140ustar00rootroot00000000000000PNG  IHDRXf pHYs  tIME %.7 IDATxwx϶r{% =zG;(*(EQX~` `]zS{$F)7m 74 py̞9sj߾=   /,4o AA,$&&bY  h@@AACAAACAAACAAy`T* O˗ĉ{K3hР_^vu"`4EA^\Zn믿>Ȝ9sjԨ_rENiyBH2*<_~OєN5k?;ED!CPEQTvZj_?x7`TpS6T*EQ5k;wL&0͕ǹSAc6mZ)O\A^@׫WaÆ,R֯_V-['N4L#Fڵn ?3Mӛ7oҥŋwQ,X'Om۶߿_>xƌӧO/:...C [BٸqcFF;;***??(rڵk{Rvޝk988;wn͚5֭[[wY`yDQ?|wq?Y&..Ne{=;Ey(R|Y" /"ξ&yOOOooo"IRyݚݺu;sLڶm{͓'O}̙Ci6Y/_iW^'ݻ7,,!22%zzz&'']<==6lVXXxbQ?2;X+_zŋ?sOO͛77Cϟv(ʕ+ǎ+!2h y}۶m7nxdCAr PphԨܐo "4M6qܹCRw=* .]jI4A䋆@} !`YW*:رc >SAgfN2 A'\blk2!Ej[OcY$̯D fff@jjN&...)e\Æ oݺ]խ*biݽ{}uPV[W [gϞ=>>>W^MMM>&/:thzrssoݺn4q5ogΜiӦMy9իN:QQQǎxb{uҥ'bc) 9_q%,/ʜKo߾2AA Dc)  `0            cc  sO AlDAy  h"  /5  -  /(OEȑ#O~%ѳѯ~gu?3f|Ȱ?7L5Μ>قii?>R%OqBAC[eYYnY3gVwF.]f}]O?_\˲/Z &OXbE$Y'~dIgÇ{&?\2'MаQcO˗<߿#FΙuJj V ȋs4q܈ßB^CBB(62`a|'i= pcǎuEN$i'N͛?_1((yyypa'Gǻw>O 4M4:6  cQ*%4˲uq& %$$}75c^O E)`F޳f-Z֪]݉ F FO۷[n}-[n٪l~;9:'bKʟ3dBg-xw+?=mt~7m&/#G=fɸua֭=z4\$%5uȑԬUw.\=Ǎ?zձSի' RY_ڵk\I?U;wyrL||;w+<OWtJV333# yn-}[lg ۡcY>6LAA;a>YzACB_8Gbn^`au\ĉΝenxK۷eFݫיӧΜ>q#_k1̔7׬Yۿ_?GGxǎ"#@aaׯIc";v0k׮s пėc^8_qoFy&Lx{6jɒGUov1l޿ի`A /_Y~Cǎ*~rN>o yxx<611e]>t+:zɒAy1Z DDDԫ"/biN4ݷgP*NNN3?^^pMu9x!dÆCnٲEQ lִǒ @*}ЪU7B1coӦMjjjBB?Ӵi]:;vd2={CY2@S.\Xn}4GѣZfYham6M6%x{y |lZWyʪ3)|&z3++UV _]å;آ޳ݻt,)(($)99СÏٟG$bl !C ݲukZZ!ҥKO܊% <~SC߾}?1#;;{ֽr!Tp:3224hf͚.*Bǎۗ/\?gggBHDDD^~>+W6o"3gn6lojͼ72L:N Pnzgm?-__U4b;z %J<33)))~ <,boom:ԭWԫcbbSA@>>}Q{^1 azfcfcIIIupҍ5$]rױC'Xaa͂K5N6-::nkկocCB&NB aG+yl߾d2AA>U,W"%5%)dum'^9 ,L\I;{<|Ft mR AA|\IiwAU]HIIa׺oV AA|l<|Eӆ.: OR8:6ox4A gLFvA0WQau !XY{>z}aV*А%IGA4+M}a2g cOa3~B@A4+yJ+1! rA ZM], D ã!  O男kOA4* e aj׮hB, yGU~H]7o\҆#b ]P>mCFKAj@4En5ѷ:u:zLܼq}Ælaa"I.5 s?ҺMۀ 5;7yXjUN,'$xxzݹsG[^ ?9`0@^^O?-[_6k\n|)35oyXazG,/ب!@`0(۷ou*5lh۶䩓ӊ#F[߽{w͚!%%"8XA '&o߶u}+WC'\TKuu:uh K#̛?"ϩS|bAAAy7mtje5n59ź-DTV 6;)B )1nFFmc$Ii[^Q#_ZHHӺ 5Ԩ`Ppy9FĂ R@$Rz3{ KZ% Ι=Hd[i t]D"vj tEm۶_?wxkc?s̘N}:|СW=zdR*n0XHQNݹΑJ2r((/m=;dh@cΟ;?w\٥cǎG]vceoM՚.]?a1E7L)E~ٳg7h {iպ]}睈5k-Z >[s^ZVP̝;aƍ5k֬Yv믿t2ɬP(<=VZ5lp/O)StԹ5{mV_?_B4/AU_ 믿믖#?~wsC ;7e˖b{{;?~Vzȑ#wV*Ficbbh_jZT7o\/3R+8^> A־"F >=jHF%bIWU99IDz.BHbRҼ񅼣0,!RZZZ H;;gY)!  C);;uZ$APpбcSL.G>!EޑMӄSF#<7lټtb'OTvvvnnc> Qco81;+Ӳ٠Aȡ :M#bEli߾XjFe3;'yTK|X"@B>j,X0TPoo dgeAJBɻ+&/M6ᅪF_BuFmoo]zgVVfnR w 7˄H>2XBbyuԨd2+Vy81),YR~kVȑ#k"*(!f9%%5%%d4Z{}M{hI! Ku waÉ;Q"&{K彏aJ.FhܨQV;uP{~>:qFCiԸѣGwɓ'=a_ІK.D|ьuk嗻֬YS>`e)˖a7,~znWoTypᅵ"$d֭Gn{n7! R&ѷnݸo׮/cQ վ}{ym;tf-w/qr3v}m_1?Caͺa(JOKoݲuPP0˲O(*;+kWT*Uy:?4~4GA+.tbͤ N D, :t$IUa5$mڴ-mټRjjܩsnn݌af$>AA̰9Y"RV ;GܜZ5e].-*r5 f6Yh4jiШ5~>$) FR*(U   c9wDXKkZ?*E>Z@QJBEQގBӴ%bGA G뻛vmGu7쪱 O'Zh9 R%85D|hyb0  nze_MjZ^ʧ 5  ȣ 4װ;LXYۏ(J$IUy v # R=$(Y%χ|CiRCEa AAAfdYrϩky@ IDAT_3 !$ i1")wnJso4O;hjNc*bC:u AmڴB@g`Jd6 z`(uiXO7;4*t:0Z]Q7_铝 3O3gNdy$0..[rC^@DQGӥ >y/-nq'O@8D l(AV (:|~*|B/󛨏o+Yk+??0(("IDB!RA~~bbѿt؂u佩S]Ey ;{6''wurrYwqܹV[W|$վ}{ym;;y^vح]+ynVYkxqUת(VDRn@4H@soS7gRh"cM>S8=yIPQQF#γڢE;($I$"LuI$ѷc|s|e^@gΜjɒs<_nw&=lذ'bNNN>~ȑ#ॗ-yAիV[P ̈́{]CK*(]ÅBD$/VDBQH40,˪T*Vh8xȞ;Ɔ sV:e(ѐuKÂhKPiAS4qi@s@1>75o#[c|-+7uP(|ef޼i{{C󵱯M2y:th欏'TKIh e~3>,jkjEEl6ͼ rJq"E4-40B`YVn xlV4Y2۩yu|FZ9Y WpG}G}'R,?}4k(,oJv횷'Vfaa]_W_Z7m4彩ϝԩsN-(( ,ZUق,˴mŋ===eϨUVrUrrƎcxիV;8k 55sfN]ussdf̙zqVE)MCU?FK,jI+oo;eaCR>P(8h XŢ+aɛ|_`h `G3$gONVUCAjU$ZLF}G}G}?BZJ#2 @G!C?ccƌ{:tѣ#F< q?_ԨQ#N7if|&wX矖/_ۯ͚5IIIV^pg[mظqIpѼ~;ǧbCPsvh %>#(Z[6KTvua|e6U1U9\htl8J]R$Q $: vBfBJ؂_1W/]HN\FPPU$Yc0GVVW\]sAAA{ymض8;;ч7gh޼9M}0|l]nС*j͕̿ģ݃l2 ։Fj1w}8{>4p,G Ri Vh@[+!nZlN4r9BmU99BIL56-4k[PŌ W7עfOO./OT)qG]2$I&Yq)5kլ|dzO>SN}ypo0 h b 'DA09Ap Nig} ih̕SbP˻PuV^P$o*8Nl_.+go=<.? U%dL:u7mfIܶ}(;u7-_ݖJչs (??߸ظ6((WT1| BCCC4h %h*2X6K[>Ͱ ;Z̋1? J^ 9{7ھQ/!ٹ[-.oSeӬEK$IbYqX2/|ܸ7\]]FF9|G3gM~@|̺jժ޽{@n^^zT* ?E7jɒ5m4;;;%%q5yz޾}:嵱c_zٳbXfC*ȹ[h EU߇3gɛW o,00=."X :Zr/!s\ 1*>>ꣾ [+ ej{c&Ulѽm[,~xnݺ.Ƹq>nܸAM?ӟEqݺw΄ ͼ;qRJJӧ0LԩVnҤm[vM7rAE2wS!f>όFRJs^kW՞_@T ʌ#XT1ʞ;IUۻ5@3M[:$`U- ?S΋#Zk(B}G}G}я1S'M6th&No9}TjJJmZm*男OM4Zꦨ9cAP F0 j >ꣾ?Ǎ;rN_>Z0am4 YEET*a4f>ꣾ( ;رժz*4\b?DzJ SR^ĭZիb gQ Q {EQsuA/c>aPe̚!vPQQF#QԷ;H$ !TBN) @'Bs L䤤'"Ú5jsrݸ+=zL&lԖփ,L&B73J;8EXѤ?lЙ :*7Ls( w/Y>>ꣾAl]7{宜8&;Opf~^ٹclKQ/aX]k\ڗSj@pEsfCoUwUԣaV볁Hp+!]m6#v #t m j2wACPxuH@ @%Qh_qy.>d >>ꣾ[FCA!Hw͢'5[X%͢%d.T*3vR94Zsd-#j|"os (m liL`& :`mQH}Dِ_E0<0ZHr"u- _ vg(H<>>ۖ~g|#HXKPvp./q e C@;''iP׭h .sB8"(:?%7H$<В ޵Ӻkxdc=ZLҒ,U`褬`/mq:,GS1f^PQQF^=;wĩ+AJlÁPȺySw~գoxJhR$uX уSګ|,(ZJ_o5BpK 04hͽ.fܑXJ7,bR2{v3H$R̽ԤԔnV37ê] vq)-8 PY MKcVc6]zAO3(. QQmGZ A륩?f;u˸ꖵ%NiOlΝ˰CrKjW8 uR6;I$4 bZ5b߼ s{y9M[ppq%bukvC3|}{#`6$I0J9xJ,Z)%Rc (*5 Kt6_}cqmmV{]'} ҴʳGGxc={26hͱM #XkՍ$tp @y  ҍ5W6v%::}KRע IES&&=M f8YQ0u$IN@KT rIg6Ur-$kPQQFwċ~e*đ6m7nܧsf2 ǿ>H^e֫2 ~3\~P[[nɂ؄,r#2@ۚ_g]R@Q0 (Ec羲wÉ yoFK 0Y>l-,thpD"fDEj\j4*v&i,i:D,ShL,T6_>%I*m&%%'<<̙3DJX;ahXZ˂ E:3 Y4B'M:C\A֨K#G胤."WiwY442wM_T_u%Q EGN-Hb'rI&iՠ>>ꣾL"%??ѱڵ۳s[%O|KqU^٩,8,ozx"yJ &$-zV־'(k"9Z0 ʳDb@b̧w)zZ>;N}{S'eșʁx9~Ս۵@t~PS`5k`ciPٗ =@QP{G}G}Է}jl,/d2)JyO>9sz)b9@$,HE5b| #̻Ac3 8|Og.,qEG;nH;?7 PwwII{8PwuF(B^Lx; ?wV~5>y12*Q"Q$Q@MS ×aYр˸x>Y}XEzXDܬ&7g Ϩ[S>󕝰P%F*E)ZP7fT`VأXp B}G}G}ӯޮ҉6molpɭ[nz=F7Zw ,C/uKo7rv,-7ƕY)D4r3$er>z-jګո{.DpqoLY6g#h x? 2IWƾw,LD&K4Lm' NyMH@Uw~@C}0sn-F=`¿|ћS;-\ul/i|vW QQmGZw Z/C&%%}V|bi^"IDeSDEDQ^L@M 9&Y}&A()%JK9FhKQ= 4r>:[o+!ԍ|cB[FL2Ǵk׎afNssz5Ď' rV X&{(ei9?mߝ,gu*qտw}\U~[*^H?}M,(F=EX)z3pv,E%rnJ5|NTj@ew>>ꣾGg/|si]_~/s1c/^l9fև>[_ vUgn faф>Wamg8skܿ^fn<~j%H;yR]z7ӷ_]?GK8ibnzƿ쏹kll%ۮf+ЇC}%\tvk /b[00EN#Fd@`Ѧ/׹/uR}+׽{u ,Kk9i`>EDс(b^,ڛL&u~&U2L*=rJ "@ ] Z@K&9qiԎo0rDKurF}G}G}ѿP^}upLlLt# AψPVwzY.T:m-g=,,ȑ#b GGG1>˯^l^f7[wt8{Mkt-厦a>E7GU@#W{-xKQQG.gJHvU7:_kO'}1.zK#q2LDՊ /Ӫ9zBxħR KS Oæ[d6nT`QN\Ґ)N`5,J1ZhŤAc-X|_Q"kP̏vN^:Yg*"Wex:r}EއES[ Niw'G vQQQf`pK rO @)0]7s{:FwwOH4t(.0 <kV2x'pHhirJEVDBJ oAZb: o;O?k nŻ+p7Xz*`}/F_W8]}sX5pK"/0d1tAnE6 `(,`E|`(w,_DQQmP .Mɱ؂?ey<8Vh=pl=hXN큀曷[ MrV4ԁ{fz!)ю;m)B;7o7wnQ8 >ۆ~R"(= iֳ<,|#\4?4 ߟף}Ꞽ7 N&n;Xԁ ).Nz[wwe3̂% -xK"=O=XM64MS4-{x_g\{9c9N*809Ipl*DKk@sf#=%z<2򁹆[hxyF)}Hr׃DѨRi Vhr IDATU'Eb8o6PNC}G}G}U}EN>0bKCA*>Kɟ-wCڭyz׭g/{O'#ZjM6vQUkDr aBf2]L &OL(zlԺ㙦*b 'DA09Ap ) ih̕SbP˻PuV^ʢě 5nD#;ۣ>>ꣾmWoGf^u=¥m{ t\JJZHeQv ͜0<n)/\GN9ex R@ h*D;'VaG+4 yQ0gA #gP/s$Z?l6b/7xNy|3-Ra P(Fݽ&ہRځV\dkAgԙUTAb@4j )oh"ȳl֭ZS4%z>//_Wpsf\2i*؛,5 ?f MLfNQQQߦ|{]m߲zK Gj8 lÄBQTW^j{{{g''g''w2yFQ*EY0 SD@s e9jBF y醂l}~B\ZGu8BBg f>>ێ~ACG ɹ(˽޳sǨF(}Q,MFecd^xМu΢@!&G}G}ԷsTy>[6m(5>TGPT urv>wlԵO6 8:9'0(PWhIO2{+Ysq5dtfeDM"ofd2k1@QQQQ߆&ACG,pV,"I@pڴlO I&;OOUTG܋&`+encu}ZFy3!RA@0XVoC/خ!H1LrSEp e82>ۊ>F1i[_f\>?S֪ΜIh:=S4y9Ͱ%k`GPsA}G}G}G CP"lȯS]^^0ĥ?PIP$/^ĥ?B-vg(H<>>ۖ> Mt lX6 QgA0@tRV8ՀdVT fCcX(-: >>ꣾ诽l]4\OZU.ɂ*Ԝ;zU@H-ZfA$dH*A-IpZ,)l_b#73G (FTț E(HH>ێ>zy3wu…;̙5cgΞ޼uK$bwǚrJ̰ %д$p1f5fQХ?{U{nI %+H) VĂk[,Uk]7ײ,`u]Wш"􄒐f23N& 8y ͝s큭,S>S>|#HE9vT~͎E9xD"H$ń!e۷kw/2Ա .+;J*9;ceX32 3/AXX,Кt1Wle())?>Uׯuٜ9kte \β,BHQ_XXUYUP7dPP8۷wח+ر}[CvN? .[nC ???O,_YN ~c …-_}ceesE/\?뺗?'S>S>S~"hȰNÇ b`۶mmi9\VVz ;PFGv*6ڸ؏ћo C7_tszhUlhllt>gܾcǠJS)\t >P"Cjb ̓ A] <5%S~d[0cۈo rȉ2XF4a/\YiOO:Ldh8ಯ3 Փ1ֲ,1~%njlO~z~ L E2M]sb9>~2$Xj#1栜T1eo:MJ' ΢|ʧ|ʧTTTIf [| & V_ܳ7aeEQa<i=HS0xקw߱}-@VAdƘn < '`b->"^dRaeYXٱ}[x85T &n0u g 1` PAH b٘m"m x ())?>-(MEu S b[䦛>Æ?n6a̱,1pL11Kn^r+XT"5eL%A9s .Vx kM]veOO TT#`;.[m˲,bia99iYrc9YbP.#XD0UJ^${3P\1c@Anځ)d87u`())?Ju-G;Ң]ùf!t`%7Xj6@0oKy#8n囆@OOeh UOn"F3İIg1+c1+chaY']+0  rʧ|ʧ|O혩D(^Sb#˭L`WOC ZxwUXfrxgKg=E-=_[ʧ|ʧ|O<"H+ad.ݼͧTiTT%Dh@vrZDf hh0^;euB, :JcjOOl6>1կ,Y^Ʈ84h/ 28+MKV#`ш9bnS){3/]ѭO.S>S>w&_,]åE#GK~u$v;#HEu:LGpiM5,[ 6pAAX&Vm%偂Ըa !pA򁘱JOO1?4u~]G0)r oMHܢI)7C_枍.^X RavO())k|**$PR8eJpH ٛX.b*%V&Aq7JʃejE@))§J%GۍZ|؂GL5;d[c."+Mb1X!ƹ7LkYR));⿾EzR^GJX3)ɦ`^\`FX1Xh[JWBu/KS>S>'혩Dɑ#8w& mhav3p$X+f#i:%,1 yIerGL1[t Q>S>S~|RQQGl@l~Q"D,U1u]5C픭3X2ut|ʧ|ʧӮ*y4u,t%DXX)^%C 3T0- %m U^tYpYc));1TT=dt,Sܱi`-SWC HHDX^r"]^ce"ܘ|ʧ|ʧ$a**:4;.+Uè5eۮN2 /9 .iub/z`EwP{ϼ())?A>zG! "E eHUSkCh&rA 3Rg.S>S>' e|E#h7:ô*ҞZrrb,uǮAy~ w !&`È mD.Xڭs)))=>a%ѣ9sfr;{wYܩqӦA`ȭJշYEUxɍFn+.6OV.\FOO>>U CÖeBn~诖Ml `CtIBšq=ܙ[u:¹0?m?_sW8m(<'NA` ,*;&侧`A.;Tcp`Vk6~/|#'\Lv? 6|,z ?yc̖7@-Cʩ7p2L";*>zG]& Ϙ>nN(D?ƶl?Fcsd7FK־w׬41A ._eyHt`EtPC +Ȏsa@5x=e 'apRP˾ʧ?':Ldhׯuٜ9 lߎrff vG6zWw$ ׎n9@#楒jMDT!e`m`@^RLKqAV$xxIEП`|Pp#q`[%~77m`_p٤)OR2lx fYӄe:PFG{}*6ڸ6?7O.Qiw} 1U5`ngsn)WJ f *vsjPx!A+ȂotiKKWeXhOOOǧJ%blߎzj~dƶFvOoZ?¡i .m% b%PTW+h:T(`9T/ AΤ̧?'+q{-7a_ @ێރ պڐW (eYӳbBWBaZ,z=&nNp+ $B T'6C!FXFlKC [4EG|ʧ|ʧSQQ%,l\{W❄[e:N3/Ӽ6v$Ң+A@ gE] JCVBXN5""0 #ZxC=ĉ.^(~O o<{+l%;d*aXkC߁ &`ӄmL7á1 aaYP\D,ԕ 0{-l|**#."d,~(kkZ;@loW#>p߻Ǝz=upWviܳY؈ ˴-n`0/yN!{'=+XZc:+dw"_jW4"qca6_YVVcwZPPCy[e2W#JH i%QbaV~XLOn`1OOOf~vuTTT'"h6{P甒@N3妧c;piC%Oc)lC2`-eK ΁]CeX&81)Md|zy e IDATS~ri7LE$J| qƂmrr d6k~{4AYxeh^ /y `iJRikbה1T>q<'[eX%7 .5u;ϝIOO2>zG#7ġPl zy pD0UJ^${3P\1c@Anځ)d87u;Vʧ?'rRQ%$ BP8LӲ,g8alfYeYA<OZZ'a/åE`FˢXc ,cK:kP\dw\|zS~eh կ2 #˲$M0 #QaBc a܅j-f(6,fe,5fe -l:d4kS@P\D #ʧ?', SQ%deY].WJ/###++++++'''+++;;;33333355I%//Fv[Y؟6Ϊ~{-Z"X?ٔߋSQQ%9诿y"p竆t)|Zv<\C4Z! 8Nmz ιҘ8cS>S>'Ɔ{#TŶmB~_j>i>1&yæں];w<8=߿?7777'_^z:n3rq'L<4]^|֖-<gOu打:r&fon%%HåEW84h/ 28+MKV#`ш9bnS){3 r<7_HOO67z2GVp$JjN45ռ/t5ΚkpH9\[]]}{Gq~5kd„ Fxtc]wB_egAN66)0Wh;nw0 yۉ8UZZxׁienmg|A 5hbq2X10Ɯ/L@IY]An*#1)#>0ߛP8dYiei۶`.+ڠE4^v .s)S4 zša[na5G@m`)8+Oy_}N ,RH*\ J#^rn?' QvC|{6x9bq[+C (K[ ;4{3aZeYV9D\qe V4y |@q$O2e߾uu0a/tYv111S0ԾǝSrޮw7$v}vyWʲeewڸI:fٷ'Kۣ`J m] 韁X.vRR,X8XFS,KbDg_1(cȢ˧?'#GA@B,*cZʝP:5wy˱z₿rm޼YNt|)شmښZDQm۶yׯw[I$ L>_K>1q}v/E*6+ݹ93_Ow=eԢ7f\L_o%,PNG|+V;Nz͛xbSWO04]lp0TjG#Ѧr)/p]#8.(9;Po$rffSM]Ĺ2cm>1Ѷ$01s˒D[_u|zS~Ay° Ƅ,1eJݾw-r H㏩>8" {:u_>???==v_~̘1N\pŊ@ZjBq={{p۽rݻwҤIuuu%%GJB/}.=.?>Z3򾇟O_J`lC [H#]i^K``iNI* @L Ftc%Je/wŸ;{3dnqØvBFjJ =N1tB;fqmmڵ OOO׮]W[[:cwJ(w+o{s_/Z*&Ͽ' #TVV]nYf]RQK ,XaCmm-xv]vM>;7S^~]dM:nhA1e:)v;ٲ,bvq6bb8ٶ !:f_&6,426(ic"D,~!@bm[C]mW .+;{+l?=YG鎻kl۲-wOW6򻫯~_|@s;vyOtD];wj>d萌t8_]mݻ-BKWUUo߾mĉ麮5z*󵵵W:tXVVf^~q+OϟHA9Uزfǣl۾-''&jȐw.c7MffQ:].WGhBǏGKLd#2,bF, L] 5b"!aIx"]^ce"ܘ|ʧ|ʧ$aLtA, 0`>#]ssoN?g֬w&Mԩ))ǏӦ_ZzZZחʴm{ժU'ONOO?S/_WZ5lĽha&8( o+Nf1Ͽn%ȑ#zI&=C{R7+y?3yCmx졧;(S>P}X͑gr}=.xn{c久@}饇+,޹w ׾$Ct. "1hVi }Ns3HM'˔OO<=ڿ8Nb' BÆam|,2y5\sO}Xj9ɱm'4555oV1"'''O~<}Zye]F\.8)wXo`ƚ5װ#Gy 8';XwۭܠA+;vlshLOOo磎ua*y7fQxM@֝%).XI&ՐaX*Ӱ3\,'`^rʜΘ8;?iS~o򓍿:_S0ME,بXb1^G'N5`cơMͿ_(#W wߍ927/:U}ߕUmn3NpQ߯YHAƏ|Z\ڍ  W^~E+Pmڳ?}޼DK`ޞ,e}1%WZo3 `FdFW1%7H+Z.В P ^N&'C:Gq{SS $QJ|&o}!V0_<Ö,0XG\Y¹9 :m|3nIs~^TЈ`R OiΝY-\ "[M|ͩbJ^pR(;)\lpLZpL`P¹дk=r}Rdgcߞ`W7@li^2{*y .` o:.(`( +Oy/]{!{]ߜ <ϏY^y-ۮ ӞK6{!0m] Bomt/3_ڟpsک=l K9TF/Q߾yii%$ vf n+uf7UB?lcSf/9%m&ԗjKK1%k߻kVwBhb<$OsM @b(jqp.Ďm7P9^D`,IX)\1Բ)򓓿/kcv ojlA606u a~XdFXǼ}6OH?_d**+9[LLRI&"h2r 0 D/a+h5\IEП`|Pp#q`[%~77m#_p٤)?~b,'T4<2H9 ` QQEhڋ8C _Q3cE,PBcRQ^Kvs۟od Ձ&"l,8%&a:UA= 1AotiKKWeXhOOݩVL0#y #6B#,34w9i.`0 9^Z~ *5G0#3-tp2X AlPMuO3*MF`)jcMbG<Lʧv`4! 1 1 MME}-45: Qg9g@n};8s\ٴ3,J% Y ] 醥j(90[\NJ 1R@ b%/ -lT])򻏟:&ibT,/E s"X`ID'iIl F,L  |,*yԵ"Ye'r+8rlG`?ek:f~m`Y|>~3k(P5SH, Ȉg95xA4q<#_ϣ|ONm;s`mSNv) ൴0X.m0gDyKEy9OwȦE~]ZNq@NďO4"Ȱ0,(."iJӕK7Օ!!R5e:,_ -,{lRZo=̤|OV>|!1 765a9)E5s=d[FeMS ,/e1Pϱ/5A+#?jSQQ[~Ulm۶O8~RK =؈ ˴-n`0/yXIOn . S~)c &6%LKb^`qVboV~?)ЭϑnF$"Vf/0Z+..߾Sjj(2 7X*` %7jPUdޝ2k2⬼jO+(򓖯u.0 $ :<aA`J XE4xi}q*jOc>կ93͹$ l p:;}ל"9^`E[1 ub9 ңVka@,0tC Z)?i1/yr\xl@@,CK> $3 }&4 SbJ=χڷTTT%G[6X'I@Tya!`y"D&rbލ?<AXb9> YDO/cA|OZ> #KWaXD "f!-E<_ 720jكX9K=χڷJu!Gж̬l˲6'hƥL>Ąs+;L3XX:5 H)}'zn@k%ElC 끗<)_nf1d^BL XaN utg3/b[y\=n|toi կ.m[7X` pp3؉qgbl11R%ٛπ"y@6V2\poʑηH|,oˬ2|A(_ a6^AB 9к߽o-0Ց4M3 6ܲ7k7W8&>qI,n߶upҢˏkV0# V+ql@P8#@\| 5}gCqihG4g߿s)S_rŖ} Ż_ w9{16LY}B'[/Z~>G~w#:=?D"NDp  vl_V#` 1l\JV–k (.@ӕ}E9/>Lp }0)O1~Xnmb`섑?ٔX֬.`aF@Ă0P~_G>X3kv̱޶^m945_E5ܣ#Ldeyq_.lƴ߾mkK-;3j#v@h-V& |1C:V&b S &J:Oqv MKfV6t|FޜOwEl 7O K|^;^`42*S 9:O?0oqYV۶644|M7WUy͢E ]K7WScO>v ? b+ 8+@vrZDf hh'y)Mb9WSg8:.YtGzmCcZzJg mO۷ig+}0r6L=d*X`*۝g|nJ^&MɧS?A#dF$EQD@4A4eDQd1,I\8w&` E͝84,s_t)7?7+MKٛE8a05޾RfKW|a|7)׺6k3oŔf?kWs" \x@y[J3Nx{P fV4]9V֋r.h?D :"c,˲m>/>a۶!m;Yp IDATjX5 @n\cZ%eu`F8>͌:>ccqL.&KQgO JVC>/YqrdYeYY }BHܢI)7CŬ  Zb@AX* G<]@vnvw:є#s9yɎws}Y(wN;15#sH!#'yd@ ? &`;N;SFr@t3Qg^Mb}d&9\V /ضpFQL"Xm&6q ۿKN GTWsj˼ _x*BB;nOG'߉^q ?R:N}YKl;;nMЙ#zU /+:|EiXEO `wŅg_pA}SMӏ?a,\ŗ̹+f='z9ʊ#hSR8vRtf2j -1'3J'X#Vqtg%Ώ؄#j]mcO;}sXs ]v5ڻp"_kF̘݊i{EEH|BӘ]gyuA#!TGX '%K+y8fP+0mx] `b%r.MWv6.ٮ [v 6o8p;^^7MKQuI ⷝ?@c6Ɓ\g|6b&b3h Qf[Tt-p|w,fO̲_ws]wNzb$d﮹LxB+xG:]: "vڵkOqjY>G#G#XpY/[^g`XSP< #10/ %- 3a.x{Y/ZQ[٦wvp  Fh_v;6Fwvp`"|_S c; acDLM ra`%V{W_-'pcYVӴ'|kCK8[ӦMl޼y`Yn)Vnjj̼kXZSS'm媪dfdޟ7XZZ/?G9_}]_>|ؼ[=DY~PAA_;wE昫= ćy=kn{86q@cė"ǂ| i}Q1u#G6 a Djzc ҧO>uƌ%s#ɚgd0>TUK/g>?~ƁD~A~an??% S&O>NwyWnuСÇsh韯²SO?s닻W38=/zRy[o/\aCz7XX{?zy!t=D"^}9''g},f\><[oϳ,kÆ|e>4w _-_اO;n7ܲaÏy=u_angm~.z|Р=ve٭[rn[nY۶sss_{ÇUB"q<'X̫HFW#<@7JX$TK,+:+ġD/\5~LϘb*;7׿~}v"dIM)wW~6+}̷mx=so<ڮۗh;،bJs"BL *EW_GaN.:c|ٜK,y0O?lΥ 8 DZ{83e[Aځ3 ses;n JKKA8emۜf AOv)~89EQ8_aC{{@ 3+yyyu(Wd8C!qWWW_oΖem}쩩>]?pa_]RRVZ?_M2,A^r#srZ1$ RVt5"z=kLb{Ssch*>)tθހ^ z]^+ ;@}}}02 bfe(HXu`&3ݒ#}$K"k4;von34 Xhl3԰k,;^nl[dV"=f=GƏ9-%$6[N9}UW^q߽0YN,KEgH ^zP__ϲaAbp-rUUUA~~`ZjjuuuUqnkV:餩yyyeyFP0 3lgzrݚx.vʃyxT߻Ν53!$" @"Vi֥.ŵj6U[E+Zź\낖b\A-dֻLnnf&!Arg;~fs{ ex Y:iԨ<>8{/矿81FZi1~J{nqI7n~b(=Mi.Dͧ`XU `ēO%Ez$Dr! n(.{'_g,~&7eCL!0OVq a X`a\ڠ ?CIDI`@3>p 7\ Ϗ7yи1 σqhcA2xxI_>jh䔔pM8#NXahH<\V|PU4Ѣ5q*ś*5^_.>-`O Z=֭UN?b}z6)@J`؀g7>zPYkhzf?k&v7A5֠WD> nI>'8xS 1[Z A㸼ѣGHrHK%۠)K9 qw晿:r'bʹ?ulE97S=GYn['x҄'-_~g?c ?G=ӭ[o v/s+>-eOc]E %tk|5xqN +-9jwB@[}@Kg `ەG? t9O 84!RwA3ZBaݚ:7? ?,TO sm˦̷GsUM{go$GGpKoxؓ?ܟ?ܖ8Mx)AdYX3?O)er|{q=3'9>|3òa&#N|?g9[n}?~DzТ]s4S+o߮(ʈ#=k|ݒ?O`rM0[nθ  st5y{Hys{#ж+zw׬7Ly٩Ws_}&'!֘+=FIjaƿ~e_;S'U5~wIBT|9ꨪf+!G?p^1;>';pAcF컥7Gy nb Lg"v&:9<8+΅?kflW7,|CK~/|+vL|+,ۋ߉g9.I wKc]eolB!G _W,gHK;kv>/|ȟ/!b_|o[ʧMFЙgM@%nJo+[{JX{_u7 ELN]Krţ!IV$ CRʟש Z|y#7\S]ߧHF$IPA\EjpF9"4O2["^8`a =W + ]#sS!YBۉ ,N >GjWvhlo6uR2S<{>Ոxz^tHܼ;T݃M?(8qbK.WD{) n9.Oz7쪨?@K:n%QjW[h6*T\6 rR0Ԑvh&*`o9Z)VQd'S]bF쁑])ևDǥ'BpoC*''gm>]f͚5}N;˯6.}'4怼Rg$W +jʊr`tNoCdi/Fm^!hOEmD5P>|v//@RS|jbF4JhT+-z %X5%3D] 7.Nn=l$DI 9vXK}@4uyiC7p 7ܐ,1; V^|ԮD/HЈj,\Yc ձX$9!:V5;"S'!ݰ=x߸S:!|.ca񧜐1>󿌅qUS~1%4:Lp"ӸL)@l~OmM5wrvXW[KlݲS%;5DZT|N@8ɣ( Bj~D!b-/B-D58O]|l)h/E &s־GuM}AR7c=e-%޿8 W=A7{9^SݱoGg};x?|?XOBwOkV~իVjw>! X xHT~ qW]i/HM9[)'+rp5O['' _Iv▝Nl;_{qq>˗|uȑ,sK߷Fq綏Rϑ('w_.+)`Xյy.b2)Qς ~7wz3iI)C:r pUV CCS¢WS~ev8~7@uݻ8jѫVEۀ{aGI? G ?e_ <o\B4z$5$Yr֧f'z'U #.O=>/L( x>xOj;?а];6sAU59uh8* ۬2aں Xd7 3~W;Wh zVDhEZYVAeeОkiIkZFiF@a} 'ZӬ ^~ԯlFv@ս{{]ugO8XS#]{ssZ AcO4M삡jnĂ*> EL0of0,-nݻ wUTT׻8#gC1~H[н{FAjsܨK i;X4J73خh^\*(N7T>ַ:;w !涊U9AWQas0xC<\W 8zK]&C,' :KԪj"fg ~~ ৉:Q39ElɪBt1AFѫkt G lSnR2*GHvej3W];?SW . Y3o;;x]% lv+@S8!w(ӄ7ٖӘqALh*wo{?|`Г*>6ڧw`?0;~*.$+ IDATX1~tɨR{`GE{{S,vޏ>㏦:k^8d-ͭѬ\BtBL@i]+ݾ1u9fcћxC(;@4= D'LMy64#Z@4TŋNAdX4T ɒ= >>R8O>7Cӗfc.ȗ$FiVF(Vg_b:IWV05 lD(4/Jܟh4!?0h4ҮuutJp$N Vj*)Cw\' IpGe!;=hZWc?uR{#N ygm>;\JN87Wg6[S,Q` ߂Xe!㲒w-]qxdW%QR6.'8! +cо0ӄg m2I$@Dd`FYbx]+Ѿ1A&C#Ԋ)2 #?@o[í%._~YQm@b˄ U}/|iOҷ^3ˇFgY~rMBԕ0w>K3,0cy{Uќ|WKpqUP0|] jB|m4 &8}\h/aϡ>`<ov! "B$Æ4ʧN=j:(WQE%=\|kb5aK/BO@Th+u[+]⼅|K;直}zAmmY]﷎=2 *CۑE_l)'XF0UvsA{TŴ0^[s0q$/{<do+:\wӛ6TB]館U\/hWvhloz_&Y6z)V? }嗊CytM3C=ؖd LCu['@B4p9MwDEQq\5EУ ^;7\F Vf9ֿtv-֭Ue,\]Ҧغv0~W[npZAD&AE!)ik֠˥,p/N*X烑d Zһ'8+־111uc-[ `Ƒ,)s={tMm>Q#k7WDCUӣxӯd2B1!Ҟ907ydvzⷢt8FR> e|>wqq fc VJ/&Ɗ r`.e8Š]?06_Jh y@T ~ev8~7&&&[sއs;_ lܹrX5swFb*qJу~EC6Xg\Pj[Ɲ+Sb=d+Ҿ 'pÏ+W`/wMo驻g{@.i`mmp(Nx5݆f/w:LBȀV^]XP:6#ꗹ&$jLtJjRx9ɛjRh]3שz ]5J){:>c'}$<[н{ƂP0 l VlMÀdQ^DDt㋝sOp".ҖTWZZ:r # |G`}:^B j>8>\^]y`KdMW-;2% u-9EV;? pTIÕ>wC%t]yޞRUUU3^z( ^y㲲݅\[tMN3'׳gaaziMZۂ/Ip ECUj}zI>klaժU믿38 ҍ3Xu[=FS [C!$9/wgܾm{?DKy>I?/,,gsFAF5n N'*??_̓ǎ]t\ÂVT/wM?AJi@ki)BTŧI*5hujwj, UE-ZClś*5^_.>>#Ԓ%.̝}\za{ gy "D:M4M[bť^znX.OD1+#V߽dVZ5D,OzgYn=C3?S0p`@z,3jK/qgKͬhJ#^=Nc ]./L*EiGp f/:]rYפIp8lΝ;\X_ӻwn`0WTU9s qݻ狢OC&l_Nm/@/=Qm4MަGX,ii(xNΨ%I$)$K>cGkhS> Yo&S(LOCr1W{0XÌ/:\S'g pS':1wʧN髼kx=s+(uQUqVC(v !cv|`Ow*ocU5e$Iz^?Ӯ6sbݒo{w[|遀K.kYG`; M4 C4zCE1u!+I/<ǵ>AJvF7GE#Ĭ;y*@(p<" Hn3jג~hHIBt脕'uj>߹k T)jqvvP^/0$?-39z@䐶#-Ҝ .{Y`>w!maZ2PFN;>Q7W +' sS!YBۉ ,N >GjWv 21~`+c? SBl6`eo^4BW C6M8#V MC!0w;pz:fQZ/hRySg/c~rj7YOܧwjkkZG35otNK3~o1>{|PC9~SS<p8V,z'Nx-qǵ= DQ{y7ME\ne]&bEƱd 0TBwy >냙:&g/@ZNHD 1 n١%yɘ5PE3kXS(bh?uR%fBFG)uvK'Z{SNG~Rk7x1]UU Ø7oޢE}뮻NQ{fڵ0lRILp"c9XB֯l.gbbb Z 5V5C W+$Grj3W []u;7Oro (XV#H~ߥ k_6Fj(+@?^hn) L?]6?{owK)SO>6

S6o}S"tհKLY3ЁBQ[ƛu{e.n^ItjQǁ@vh2nRg]++_\*ULLV?uo*BpCBtI˄~Dx` !H2k x3?R[vӆ3 Pc9^n)R>;0~s^?5햁)33Z YƗ0?_QGEa׮_~SO=r +s>,':v7Vej3W]eSV S8&/M! bɡ :si鏾ygs5iҕ_YVny06^^nr<`{BM:xg_|Q4MìGf-^xȑ^|u(wURgmVNh{b IDAT2 lftWoWೌ 6S2xC(;@4= D'LMy64#hDCU$j*IaOdj;X+{Wʗ_S]t)I)Œ|(n0!dMť}})kk'L0a„<_/O(Ӫ&%"EF3(;~ev>Pĺa&^P>uxIv8xA;= `$b A/=훬zlL95; bFCղُ;5.'XgkwUT7fx=ZqI)v)%m)9ԓwd0KSuu^ )[Y~AAN}|L =jAHF-łk"yy`@6*d81(;~e|21@0'&'A]ݲ'+l+2xㅔV@iQVv^Iu5&1 (;s{7hh;b)s Ǟt=hgÞ_V2dS²)?rU~U4wlj81-o=XNvsy(Zb?Wa_T:_&&4 Cc!xKz%У4KdT`2xIrHO&vv]|~.~ѯtW ;^q=tWV`I)/TnSO -)hyVw?!|m[~AdJTGȷ[/'D'N%1% nsP/O%ysYĔQ-MDiC kDhќE1Tgȣ|~:ޱ#CX_OeTy%|oYg]vIRy˷wOWdyFPp?Wo#ÿ9gbJӡ3/[dMCAzljeSj51쉔VCWm{?iok:;[&7m{H[p$v L[D^}|$ HDle|ˮ C =۳Ā'L{WoCf3S؁ /)2 #?@o[í%._~YQm@b˄ U}/;/8##0&~;xAv>-L[zkE͝{ rw 5!"iD>.Mf~_!ڟg]/SǑЧO[;$`OMZ8_k_[XCa 9_=$J; pٴ#I G_x G1>wPxr膮 yc>xUu(ɊG(3h1Bm{̿2=*e ><صӺeG)E֬N>z3'Oyd LCuIV lk,S^DQrz4s%w֔BJrҜb~es1>wt>Q(hrBa8s"L;ЌωvW |0ܼwOpA󙘘:"aվƜ믻N4I5oonn]~۞>y'Ic5n:fA5Brl5@OөF;&{,񝕵=rDyѶ 0I20uJ^i8n`Agog"LLz?sRф[-[p•+VܱiB 1M5*7ͻCZ$dž absE+:;_3;._'*;dH쮉4ƒQ!zG2JR@S619%--Zt*DR[Wcx<~I'q'Iҷ~1cZ_vڤMua|7Iz}PQE%D)GQ0ևAtZR0$@!Dq9߬}d|h|l0AN.) :1tCKCTr`$d}7Eob#u@O z$Dg=|YA9{5Ӧ*g$Tl@eeJKGys7/oOk_b1ѕ+ "@IUc#$'oDǁNM &3>wLΨ=>{LW`R^ -!(^Sךy z)} Dk|3›zVJ}2:#t0u$$I,K9S^[n3|i.xpO@eV-<1gKUz2S+2(/Hj˯XN0=헝^^%=s}.LLG#XYY駟-_|~u_|,A@pxq\"RaB3 )^t@0qA8^6Z"^DI;r@^0vg?9Dp]IE J'8L7q&ZDt Bl }.(:8߯uv{ܸq^x9jժ)SXhQ `ST;cXEEisTUU֛Hx폼[D.$ݸMiKs YaYR J鴕οc;,D67EؾRO$2p"'J{޽~QMX)"o]Ӂ{СCL9lkys~}7NI9뺮d\|+=H BtN֣5OpfOcUDae6oE aw&H!B *?7}2ppЌg |p-~Ϝ9-[}+V_}մOܱc߿|p8ӯ_3gϙ3gǎ@O^/g555W]uՒ%K/_>eʔW^y .LD`H+dk+Vcf Tz@T|˛lGblآ%"Z"שߩp4TFh JoӫxԾz}3~~t dŕL߶ku-uz"'q="-W:xS.'U_'躾})S|Æ 6nxW~?|ĈӦM0aB]]]$pꫯ^ve}fϞM9;i$zrʔ)^xAX8զ9tv 5k=|xK%̇n[AywxMixG'78AjU)RznBN 3>HaFFN8^t-yrH܅~߃?d*))j(zףhYY]wE{g};S(_VV6a„;}[nѣGO2eҤIVoN:$ʟ0a5>| \wul S .8o5wg}\t&^ؑʧN*-^|]0Mre*^P~ʟ|$+bL|$鏾):\S'g pS'): @#kx=swʯ{O; O8g @]feIwʟx {Ǟߝ?0h4b-[eUTTX~5E mh6}zF~}y'u]7 mfgn۶ O/Sk׮o~`…,`:IsrLvu~~_u59{=ޫm R>uؼ7u#<L N6N6GPVfr/ IlU1aΟ;'(:ا)S3nuw47eӹ~9s\/x?o7xc555^ɓˋ/^lټynVI2nAA5G>}<@LLM !i}Jl+8poۉmvYr_x  n1jUi$^rDk֖F\r+#=4Ls>UWWf]׏/s⋗^zLrhwui&Iңfqekn X#G3IM494\>ݏ=Dh$g@8kt:A@f3>wAfbbIHUꚚ>ookiD EǚxhqW]i@ҡ Jxbὢ+WyέIA55@jARܲ ^bØ_{Wjeڛ ~YNV24g_wm GOĦu5+ ɒm2 5;y߈=Z_qyA%E/L( xG$g|4 H9`bb:Aoգ{Oo}̼A]0TЍXPqP5z(; CfdXZ>]?O}.S}v(,#Ԯ _q_K'N<>mb!ۼ;qCTz鑑,dO^ᥦVvmHPǛa.f|gNoc0S+1u+@ibQA )ɓ.< 5ʔ^3wbhjhܽKa!3>wR~{ņĎ&<xC(;@4= D'LMy6tP/:I&DCU}У;}cGQyDAM^'5՘xS̮6uC L;jn~ >8n0at;{lVУ@ G+صl ?C4MR:Gɺv&[ڪtTz$&':`=^yN/}'`\QK/[ur$ɺcÛo'Ɔ&_~ahj,j, QһCb\/q%дDDVb$,N?yg|d04 :DFp{u!zM'جrѿDTnE1`y0>3~uCi~uLLmW#'9 Fo7HS+k51жQ(sLZ?p װ &/`}c?G0>3~/-#yՙ:UYw1DIc2JGc!&fY~['&h&e$@b  M4{}O8o/;8ߧ[ԧ z}i;([2rFzi- Vz>л 24l+omƒ@};g|=ۡh!!N,M/ͰTEV@^SOz Kޚ0TF+&w*5؝4mbl]Δ?ial`unxrp X*µD}2T\_vH`*>`ɡl &P==[t"DWaƻ™X86Hbvrه": p 1U=91n 0_l3#YÀq ECtɩHRb E#ږ *JrJaQͬ$L)i!Ea&1͝5%A`h5]4%]LL#x?rT8J?j0m#/?`*} 01Uһ8@L)bPL=i0-Gyb${7@_ňm5ud-ö 86~X%"qz#\`Ϯwu8 aI$/ W1L[}jEODrQ?6  Py^Г1AT$od:3<ǻF@ہ'tղdR0T2TATuϩ6< E% 5 ( g|~>x'PV -Ķ,C- aCMXĒM FR Ko﷪$=2Xڬr%zpȡ]3ÂؾDуMMU|חٽlD,COEm!' F˜c1^U^^O.rt( 5 _*W2>3A&#ص"8!=AA G1pÃ%>** /R'RbЃîPd:#<'F?΍pz@ IDAT VC(}!^%GغD@f%)[V ض H3>3>3~'ɗ֮qH򁭁 hDеDD4{D_pK 2@G q^z)[[78-[`?#ׯcA7` B,ċKt ѯI6pVx8 "^rƦ3Cl[Omg]>Ιc1+uʝ}G>Ss3 "A4b6qҙ.XўUfC0.Z?,#6mL= *>7=mZ"B@'I{ZJ,Y ?;%XI[k~A^AP1yNib}HPx,XBE,O/[5\ S(}Pm=taq ]mhnYΐ=~#,y [WBE`ؕ}R=O13>3iğܧ%I `Qx hH\֮'g a,bK$*>@8 uܫ577ysNEE_2;)˕-Aq_ [&61՚?T!x ӊ3םXV%&x0֣+@X- .g(kF#cq\Cqo.z7BP{{; &<1Qy fISOjѹPX_*4SЙ}!ZԞl_O#O-[liW>s?gXa: LoQe VV.$*>h yB<?8ĐK,3t"h3Y /D7,*XttJ' 519 D?J~~̙3~_#߽{{gwM6=3oU~z'?|iӦ?ϝ^a:CK~jU+*lU%~e!i9gu] uϮU+gׁc׭Z^$Oݪ5Uh]?b3_V!2|%Żjx@?|fx}meJ nAhNݳ3>Z~k'R1%0lE`a+0 dMY mm ̹k= ,O#^}՟=ܾ}}K_ /L7&yon-//xॗ^ZzԩS{o~f0M|L׾B×]v-[g;!lݪo@kbz]H@bvD-rtiA,=HE{L[;Y_O^K$@Yq*W^jj<>Ce_H(Z9P<3֝@'oiʒ$z뭥{7ܲeڵkq#zh8/p8L ee'޿{se_bZ9_hJqcz+2d.@M`|g|gOqhk-n ]7;9՞@ CbAFTFZІ(XTy3+i#500裏ڵ+H<|ŋ Μ9Se˲^xc7 //b*b x`yYycc _}\5n1]c]b%TU5(K4c??kuV@9)7^$Fgz>9 Fa#ӾsS`kPr8GQ͈dYNR_:::0ƕO?E]O>c=(~ӟ>?c=|r߿xrf0 AX~˯znh! 5Z {<Vr'2]BL@<0UG57ߪ' -q?/V'Gj,]uaZjkWlDCqx3VQ7:= q;){'|rܛ+JWodF;::(?? &L֯cbҎOwM4Y^kʁhYAT=Ec+*~@?kuoZgJc$$۞‚0&t<*ki1h<_Q>.x,SPX1f:t{ aF/$7Gy(zb[&x,ҖtH|0rlmXz{U5%@fïzpȡ]3>g;`|? +@i Cb2TAT/0jڰ 1Q@CM0≮`:k=Tj޽մU$ihh9sV pbݸׯoݲnU-8 Ӷl5jy0-4@%=ǾKld|Z>u:m$\i?!. EPO.B~+1Ƌ"dG :^fC0,xΝw} Hd```Ɲ;wΞ=Dk֮qH򁭁 hDеDD4{D_~zAxx 7 x,mg'ZĪv4M(z-ymҢZ"3w$0بQԸ+W+_^vL8\  pl@*>C!|lX:T"s󛮾|!3̚>y?惣{Q([гxsDT[ʷmB ,C'ys/Qԓh0 thG|_J(˲m4-"TWW77ۮBt]A8?S?:x J@LKK/ (Dz?a|?%#i}@¢smZ"B@'I{ZJY 䖌2db:K<!q <EEI$aO#X/]T xǢ0pؚ 2T,G[bEnv^'9{`|Z̦3g0`u~-eo0F8i4Ky,)H^xm`#x [E`jpw "2A@<A8e7Î4_ `rh?=,]}qZ`,Z|ˌg JȾPkTGT$b>NŴ+5=^X0" 7񽻯mPc0R)_X)xwg:M=iYF1+W G3YǟxBc r@u fISOjѹPX_*4SЙ}t&3BB6~b$BgD;~6mE|'3Ȩ8 V0]PT|G<^0!ȐYXAR]m3b6K[[ORbɋHl3'@P,5]€?Ogr4tw/*>/x_:t00.|C%s?N3116J1@A^`i<[^5'PPS:H@H;9_b17.c|g|glO蓤G;(U5|SyAQJG K6ԸÈlh=Š)~g]^׮g|?{"-%t? -L*Ne P;/hX4t@[Ꝝj; 8zx$zxJ@"?{1>㟅пtb,&Ģ):>sDZ 11:"V_p=&yXW`=/8ѳ 1C~+!Ґ9խ!FOhg0?K="$a~v@x&nJ2.ez}G4 /OauNڇTG0+EjfF'QR[b#f499Ktj-?'!(L7uz~\/,awdF)c/6e&^ia ܟ`i1b[ ml˰-& _"r!jpq˹tA3~}vUg|?{ GPf\*a,e61#L&uW`Ie'L2,t(>ENpfAdPQR41j 1G2`s ϣ(Yc|?P ݡ2yJ4KQ_уcO_DG]VvחٽlD,COEm!' F˜c1^U^^O.rt( 5J\wvR|r9!A_sƅ}vB2s}A:d:^,^lEGlǖz@ VҲ@ (3>gr*#zs/SV`*>M7{zm{ϩ^T>uN9@fNweMAClPXh*_lD r[/zƒwx2b|J~ݚ uV0>=ĉ#/M7+̆`:]4|*Di1|PqQ('$i}@ыMO#&o[b!)IhSHRQCK?eR>8)Y([ݯ08;h*X'"H3K *F͖2:аeYM[ZZa8cF8ninycY a/j':̿! 톚ӊ'waɫ,ݺ(۠ ~SO2>g97V'ˠ^1,`QQVq|?!4q1" Ό1'TUuH24 ^o^n^aaa___WwEsr}_zATkfdTJw McVJ 8`b|g|g,5 Uf@uY±!+3l2LqO>yښwmo:%%~QkJ7\:퉗XKeS,k6~}{"Yr.K/`⚚O$|^;v q|OQ:! 54$}0m["9O!]ǒ * g3>g-_tQ53ß"T tD i%+*^+ Uôu^{QUW zpgD5,r{pVdWDm=uTm۶m$7nzYF[bSC2A+UV`7W @?AQǥmq+u9Y4oI9^qQunTXx8ǻsqXd @SSSEE5+V 1ȫ;o޽PͷZQ[{LһZnՊ)5ng p~qw}Z)@}@ݳn uuV8|WSjpnFnU5Zz׏_V!2|%Żjx@?|fx}meJ nAhNݳ3~+_; 7~𗦀r0m{d#LOO.<-|ҭMHaK}^VM;4pJO;}TOɕcƺ?:ГL2ytLt]=ia}fԹ3{}x(0ҹ+TD޲[7wg`Պ*B4$ K*nmi 8"~|" Ѥ;єyk1qyy ~9Bm۶B6o~ׯoڷ?'.:&!N燶LwJDqe^s/HR1,Xۤ V]?._U1E*T>uN[ޞ/㺦4x酗D2EmA: Ω^itO), ~edVL$S4|XnՋro^?g7&WNsKg8ZV+¿+^8+v7Ywa%_z}{kdFkYfܱ\מO)  rټV$ap\uޔv$5gAehF?X6L8)x{WM՛mNskEƨ)۲swk (1#8q:wǛ8)i!Ep_1͝5%AH/RC͋*ҭ--KCa"Ã?k =QfTt tPO#gcB NjLC^Ǎt񉱔 qA_ΨSs=܀wM{ĴHbce os@ǝ{F@\wy1=;\'Y.P(PlY#8cy5r`fYցhT7斖+\z<5n1M.P*OߪAQ@@PX@;n6Xf IDATVpO& ]"6o4Kwhص\SOpΘhw8닪ںVg:B\ЃEu DwЏ~=򉑤Nkҫc:m%#DzWT03>37w-O&K٪OhJQe_FAόG~@oG|yZw’)>,HӎfɟЬ-Z,ԒKx\B `CSs'ufL;ڬYfϚݷw߾x<ʹpɅr+ǻqCk-8!=AA G1pÃ%>** /9@ z04{ug|gqKUCdO&B;tX. >˧f!82'ϩ90ɤN;GF=Lɸ,`HY~Ws=W?>>zw}W\Nfjq-iq$26O]KD4MG勊 /2GOv1ߐ?My=S Ω^?OJit`:` D5<|!4Nu7t*|:S8rxp$eK+>ͯfBmqЕˮx?3>3=xO&6qBÛsӖg/&eW~N-Qv)4,5uB@Mu͉ӳ3V0$''4K~T+eoiQN?Y~Ģl;3B'z3>x'?z_h,ؐIU`0ТӱNyp0ض --%9sJb612ո᫵p-ö $zB9!Y!'p@wXFq>ʕ(|yv 2;;>d4-7Y ]7^Q C tK&uM7SFU˘ thveٶeeB[mWTT! @ soS$8>tF4-wlI4xyY `ZlO*&G0\-\`8cGCƱñbb:uk1eYew9ΝnNNPx<"+$I'du6<#fhԓlIʁB,y1mۤǝ@P,5]€JƟl=hq8Z&s1cd跬kΌs'F<8r0kU`oyS@AMY꠩@H;9_b17.c|g|glO!v[[^nu^ tj뎧& ]VHuSϩ^Hx'|PJZ aC꠨GԻJG4td35@b? VL3>3>_]|?6=ڙFSYGpB"ԎC Z"< ]z'N(1A"F(+E7b|g|M=Fi=W'5|jո /k'e//z/xAYpe @ \Is nFg|gqK/C$O&B{ ?o!O7op#wG8.y&Gmiӯ n޼yӑKythOqS+8Q  ֮؈!4.@Nov@ egb@Lg|g#MWUU5innjnn<<`:y&3RYiMb@ȭ0XZVC[w@Z& _"r!jpq˹tA3>3G]w%2I67yyp87w8I%/Y$777ڏ>Rmmm8v577xzy `Vę Ȃ V $[* 19Uӆg$9$&X}Ea|g|?`w27nn?ܸqUSS3uUUU̪`:5r'}fjԓX&, ,SL "b">ROK~9D@T|7G_'?Ojqf8]q X[[KQ,j PK= +iO@xA~!bP,x C㔭^+xl[T`$?{x>3>g `cmc6n8-H@dbweCM$Aw";1t.F'waɫ,ݺ(۠ ~SO2>3>͛gIOΓŭY>fܪ17nc|QD&3X}lbSQ*zJ1NDVJ 8`b|g|g,57fŰsMݔwPVg}ūZs3>3~_i*¾3qzGgy歷zbXqq7;e:^~'|]_.//_zE]>H,\'(--jٲe;v8'Xdk|B}w0f: .iZ>r;wTTTZ*7/DI&jWxse_bZQ qc֠@6/kMs$;S]]p? >跾={-R__oYK/tMǽ?s=wx_rggg]~ٲew~o?~o߮Ozx_~ǎgϾ뮻!M6=3oU~n??dV٩0 hljڼysWgm>0K_E 1?o!6o<[ (z&M2Dy~:Ej2dDϵQd|g|g,O\'X?655:n7] v_ ,9s?Ϟ=oE]yW\qŇ~W\qooٲ妛n{gϞZ|E{KInd2yϘ1\rΝյaÆzmzꎎfb:a4𩧞&租EE' `GǓH$ݒ(JOOٳ 77e tlCk߾O~->^qqqþ?x=] r5wD*x3oN}jW䚉~|UK{e:`QXP3>go;RX+pM'q.䔕ݻ}ݪ UUUl;~0}yގ˗?uh4 EEE[nm:Lg*v֭ۚ-˶m{p0qpo߽{Okk[OOo"$ /}Gz//^ٟ/{-KN@1A{ ^+h4$-C2W0>3>3~V'Gn>xc]Gʕ+Νlٲ+W ]vY7|orJQLM{={^f7xSOUTTp 555W_}G2/??x, .Z"+8 V +AMh E MRpueG?/C+FyǺ FG-<_:";Vvm6"Bq_/Ih믿믧>~GNR҆$utt:ubu?HupgG rBP;:,bK/9:sk:>)SsA<8ᲥW3!6mciĝ~g|g|m$Oiƍr22#̴jkkj t(uO0q .˲<~О=#P('-L2k~A^AP1yG@$<2 ;;_1.f:3W PZZzzY僃hGé[N4$ ,*>Q/غVXN骵+ə*BXҭ;)N-Ce|g|gOfhxܔQݦ#Fƍ3Bw5[FS)dy=X ~=FAص݃ iqiڏ01.:^çPq%+Gx/Bw1Ρ+2ug|g|-v{uZnwo-8na&)[#U( !`D) OCnҙ;ؚ;˘z6 hwCX*U?`O“ύP3?)<0Y#XT\ dq)'c{x1Dݏ4d[ORbɋH^NuM-^d|g|gO\m"SOO(1mq6ahVy0>3>3~' N!G? 33>gq IDATcşY#x^Y>o >$Z@Pc53 <18́ 1?LLL١#xat( 1*`i1h<_Q>.x,eDzDK.Ǵ,g|g|vx'!47_=_8=rN)X<_b<nM] w.c 8fC0<>||ؙ#ِ;BPZ*WRJK[{hTE"hC(@$\1& Byk3&lyfgױ4|:H2F :Z Mfc9+eԠzT@o'Kя~-~%)ŕew)]zU,\v(e9x!(1~m9W,=T;.F({AZ>/Zu5j4oc-t 8zH*@ :aIN=~15O@|7UG?я~{rU,0nPsն=v/cTM {o;b  l+s¥;+lFisO \#`"x*YR r CYN,!T0&'kZ܈4el=1A-Ҍ~wg*)^SvLO٧ຫWeKP!4{e3^6t53z=4%BAXX}m  PbYGNעFt~wg?9_]$'/{j2[r֤|ध_GShNi!T@Wcps.O:kZj,cboGXɠV -ωbG?я~z:\6xC;[df(rdxS/WUg?s=T< X6yR\.ӔHh0N4UڵnF$W"OxW*EX޹5D1f "/Fu5~wo|3Y`Ws{S/W=QoDs{wgS/W͚G 7+}}b̜gҝw}+ob3匠 8f5+&ՕIy5NeR^#Џ~.3O}&Wξ弅/~Tw\dB>T{E+nq4=7;R굟5nLG[[IA. +;^;Wc2lP_W6X!?_}e3Ja=4 ŕMl4bq[?8F N5ZGieC g [6ot.* nxzuDR~'cJ)6az^,*RyAE?p2]( GKozlŕwO-z]߻uv侬 .|iC.:K@seH`Dݣi\hV'm婩SS(}韞EioVhI`dP/G?Bi4V`ֻ'{r߅Kwξ}3#faMe7NGMt]εÉ;WT,鋾/0I4`)S򗿴,. f͚1cپ@[AnОDjwEѧDqr IB2Y^5xy+H~ <я~%=P *oJ4dKwڕߊ6̙>xm5"y>>Qm;G'm୷ZTT:[oFr.Yfͽ[UUe#nϷoEM)o\r umkkݶs]yb( A jyMy{~I5㇩i6r/F|`Bʁtk5 ~G=SM$p]Eos.ϵS@̙,ٖ&O+V.Ӈ2ݐ'N}}=n322"[JûwEqUy[[ C-+qdH];++ح;wV(󊎎 ?]@xP8> d,t9>_&+KhGN' я~U P63}0lM?˻pNgO+e3JI |]e3..\诫+FO4keggkyPD3?h}nNo{Sh=ٰq})x\K."=6!qD>T-H>x- ,T+$Z:EFGuWvg?*Q٥KiJjV<(ʬY~NS(k+ ={ےK/= H'xGD$(KPQAv]±~HT"Џ~.@il_ڒ< '%7 l3}0~ewqQ5b9ԗeN\UqJ ߻7PJMÈǏW[hhx'H>`=X(SSsE_oQ p)G?я~{f7!e3JD*W9 mR6Nwŕڷ`6MU5vhOX\ig'5>A\U^LKkkkkmmUS3eA: >|Wr :2`Q-=QD0J~$2P {Zqjr5_9\残}jo4 l{xR+[[ӟ L=bj+,OOeYpL-Cہ6{ +x69|`ht&< BQ8jV~w L=ikE.i?2kR>'-\iٌR]cb?N69g`|A9J_`ZZ~ѣÆnlۉI۬x8_3 1lҬ&-ik|(F80bO=@?я~fӁo9cjϙ>8y{](H';G) s 4.**.޷Ag'w2]Ηh=^U/VMZ# Џ~n)=.i}p-x3K],'̹ٷjH[~(n Zzu}5 fM_d}>hċEs#xJHI:RKXN“ƺy{d\^Su ̻JT4TD=b<رQdя~.5g=V}?sːE/~v,/`_V88aU&+ W,2hӓmmm=rIJi %PR\rLGӴ@} (S`eP;>TvāG? }vN :=P lKLc@~5u!`:3‚~(:s2  HLi8+; /Lز쬜/!,r բUp D_R@( y=X\(Cu(M3 G?:i/oڈ|ٌҊ60uX\i.Xbq̩z6\5௟=++]rneA, W9@uGo5 ew~=AF| +; VT@N1@ Li4M4~Ha9e$Tia1:sSg#پ TE M~@X G?JoODJ'=G0MC àUCM(UU8r(vOݒlh 'H7 p^Q(C8ջҔz >YЏ~nwr9x^EQ}^:lhjj$˲$xN* {‰5]s:F =nq{$I eFbs$d'p H>ћ*G{E8²ljy@JJeYx8b'N Rh-/rGof ڥŘ5-nD2XayРhiF?я~Ǐ^q#4%BAXX=J퇀xL`APS7&! ӨΚQjO*(ؗw٨eb&Z<'G?]0ͥS])Da؝-jiRk݌"H>9(ET:skb L6D_0_4jG?*?z=匠 85+&ՕIy= zg'0b-GXG?]w#=G`ջ` @!p26\C҇ta~?~D/1w2ەef_fb#AqYD_Pe?XT':zrC?я~ [`c߻yڴ3wT7cGEn9v 䁊vɐ\NN/_|ƝW_:Ň~_j/p Shڍ;=Ƽ'cGCʟ\ֱÍ~wK=)8deg,KqNL;aGAen>KlqEiv?K̿ ZL?ɟ@:E<& V/1ZES 0/NSVʟxG?9, #KJnnd9 Rs9M*چpL F!]( aX@FvGKwa" vI_p"JJeC%y)I5P{iKCI_A?я~i"KAW\,RhV'm婩SS(}韞t7+J4e8)(FMG?B? g\55D MhE91gUQ/>I-)TW+TQSwըǕG?я~wq( !@u{E] rtbEѧDqr IB2Y^5xy+H~ <я~%XFOhep8\WW~O^ܿ@~f5 CS򃼦DX^H^e?P4E9QN#>t5*,,я~#Nh`UUUqq\PXXXt2PSSEU+^}l0qУ1<0̂>HXNVSI&p~1fo =oG?]AI1GFwy0̓Ƃ_s5[4=շ9#̷nbS A#*p(@e1`Z mfwق~wA3 [u]f췷PJuMt0.?/„zk1szcԒzɟnG KaB,pB҂`kj& +v粃ތ~wF:O߶Gq5J$z |,lh я~=~"{83,uԜ rss--0Ģ[j{`hutId@kf @xݢ :2 MA?я~A=|-\ 5MquР`FMMm~}2'#xv`=FŠ~`%MX*.c;G$Xp"Ԭ0tG?DJR !>G)}>u(3㲷Y-p`gr.:swFM]cFĢjVG?wNG%I }0`@^^^j0rUWmڼi7^v7>#ڷMT3FꀓD.z IDATK]j`T d/ vE- ~wA1$^촴4Q{y<ߟ+I $ PFV"{HW=ޒ~y+c&MhJ9ԭKbcu7'E+G[Epr=z,qa2L+reL~aSsn=Вhn&Wהv]9,H. 8Qb(2 rG?я~_ښ=ғGDǽrᶶiiNbG.x X^0M D٧΀Bx:5 t;Zq +E?я~ŏ= ^kr\szc˟\ChUm},$H>T1!>Hs& u2T0P8kЏ~#NܹKQٿc?ZKfwPj9hbQ;PSO2+jV$я~#N4|͢G!,aWƊxIISVY0a\@5QMiE/ 80Џ~./biAzS6GС&tbT5Z\TtR(`Ġ%Nxo1༢ޝQp@ wOI5%ћ*G{E>eo߾2 BO?tǎ?X/uqJ)ȁ d97PSbɚ7"G[FihP4E4G?]//#h5͸nH$zy<Dze9DΉ9NAS"ëD_~ƈdΆ2=rJ5}KG 8>AzS#haaPJjkk-~R4rgYanM1B8A{ΚQjO*(y iQ&n2Hsя~%~#\XVQdI}?!SSR>ETGiJ`4Qtv'ayZTc7ON+~'+","S W#ͺE?я~ʏ^q_aB=UТ/X@֬TWë:&ZGsD.蝝w?/ÈX8G? E%{O!=sTkO1V^(?p Rj'a5$}HvPG?я3Aas=FmCnWq"~Ʌ㲆-~&u OBuя~n#>}n6팼U}dw}ؑA|Ѫw9yb{]2$,_q՗dyצ//Zv+G17iؑ'WupcgG?ROJrvY, GǠ~Uء >wҍ-7uYe+Jõ^^bEEQԪ_gIt`E05)6az^,*RyAE?p2ݰRG?я~aiA\RvK`p#yD_`LHnR6eJ>0b aEAN Zt5&2:G?]_3ADK"iPbU(C-U*KIiw:K[Jrя~L?ODA\bE 8 @m#,OM:@ 5ӔHĤYQ(I`dP$G1jG?я~9'RhJDM-̉?xInIBmP]z䥮FM=$GG?я~Ï {pGix +:VLTx<.>%rXNꗑl򂮩 -΋^Aя~./041Y7ZSը_dMC,re[V{4D98¤ 7j7{dЏ~.a1>_[h0 !iecQCZ oQ0` CHbA˶dC,D-X5ˢ,/~w'q{i|*; O|zLU 5*-psLPSsE_oQ p)G?я~q sŻڞ("ZA%?]ZYq!l(y>rFCSЏ~P;_q eh;#foaE?&M6ڎG@x=2tY8jV~w "HOrAW۬x8_3 1l3'ʘq'j5h>jK,jIfя~]~0qnj .=ϿAg'w2]Ηh=^U/VMZ# Џ~n# PFV"{HW=ޒ~y+c&MhJ9ԭKbcu7'E+G[EGhGv @xR4X7Ox +kJ$yW Ze1wn9~GK/mMA$4IH`OW@uj avZ[*K;@V~wJ#{Aw|r բUp D_R@( y=+&4u2T0P8kЏ~#\RҔpI 9AX>ьb( .Ģv@7 jWլH> G?G4|q`yʂ@l_vNhJ;/zYN 膁~wIKғ}`RD0bђlh 'H7 p^Q(C8ջҔz >YЏ~nw\pD]XFG#7=ʤ2PNX>DAS2y_L8$Mя~=~"&GPoc @ ћYBvi1dMƣV#FX44(Eя~A܃k';EMPjVc}A! #ra:J,)]Zh.я~.a#hGSm] ϹAzcqE" C)Q=,,}D`0lX1fo =oG?]b" .I]#㑶چ003ȇ'q_ @x`0Uax-G?я~9GpjIO#ǁ !Nс E8sli d 5uZsAioF?я~ďk #H<GZXТm([$ XFв- 7Q!,&52uͲ(ˋ0 G?]5aI^._4q<$SUBJ{K,S:6\yx[c#H> |,lh я~=~+#{\.,j1'VwPO@jVpg-@A^#yG{A܂+zoLj[Xij+@S% x>+`NG?]~=ғGg69 C ̉2f܉25u;ZY~wL1#KpEo|#Bu]LhFu5Zw0*2y{K{UxS碖GEŮG-Թ V=?˫19Q/t尮RխK(5jӴ~wtp׎ ';%)%,'IDcUpE"XhU?_´8 8z<ϰP=Q${Epr7Џ~.jqi[U5~VՁ >Ϸ-̫:[H Rh-/rGof ڥŘ5-nD2XayРhiF?я~Ǐ#a~?le pStДa`=*11"sրe9K_%я~1viիW_t~. O|]^#{WsyC??ۊg"#hGSm H>v2Y6J IBYA9/Wc!-~;MiyNC?я~w?nٲe? M4~Mbj|}K?tDFEawJծ=ÊW"OxW*EX޹5D1f "/Fu5~wy٬Ǝ7˯8A4a+3/X@֬TWë:&ZGsD.蝝w?/ÈX8G? _#gyfYOߞ:+baZ`A-L3v9ܵ+lUSH )5y> D(GQ=)&-~~o6>=+V1}{e/r N%~nރ'O8i^#x%jIH],D02 &r,5<uG?я~(=k 5t Xg6oY3gN^SCK/8~GQ9?׍KXQ2A;rN8`ק 8G?я~7;R ( MX_P5y]wI&c/{?U{ Dp*<";o+ !7tcү]n@" )  _7x_oO7<vAI\yMM쀁L,10!t4M$‹.:U=88߃>p{#NۿÿC-^uU?(j{5-w߽׏|OUo~߿|ֶq?ugeege+**_ r{啕?tG}5ƆګGuӲK$5y%%~+1B~ |饗6i̘K>0wܸ#F\re&MׯnnUW]qF̛;o̙1c.yo} /袋Fn_k~ӧW_VnZ+2/-v68ww9`@?}^]ȟc捿V|^zqy1 cǎߟ3k]>ςǞ~^޽,o^9rĈkׯG9ALѿr[6o^fQlJjʕW]ݧO#M<~b_-ߏ~ûf*$IHd] /-} _{50horq,@CM{+).PRXLO {}ݷ OVi+Fs ˁ$e qUW_cv}9jw"4q6ߎa|xdY7wM'_{{<%w|v?}ǪKKKTНwޙ&L{ijjx~1IDAT?g4cY64o˾/I"D",ⴴw 4)Y֑gͼ{P(O˖ϛ,! n07ysطoߜ|~c"x*ٸaøq4Ȳ,4dZq\q  Dzĉ7^b"bf}ӧcPB% Լ{z\2A;t 0 y,Z~M7tCʣ1σ0d@ǫ1\s5鱊̜y, UU;H)))@eYn[osɘ+a]vEc jmm k LKE~-~1o͟?7}߿u5V,_by}eg3< `C8ꫯ7.555;+c9mdvb?_zowW^uM,ɞ2yW^qСs544 0daO=?g,`Μ3 3d&Lʫ \[>WM8eye͞= DTg?qit?Ϸesr G̟%N@{W֯_?sX tD wBy_n׏Oz!Gҗ/kG˲˾ٻwv{IǿX/ҏ0˯~ rj{j\>?Zgck~},n/xoH혋Gx־%g?ŏ4&=Uni]„i>#+K'Mv;=' 9rXDK._pʿA+:6.,(|ŗ=!-j6$YXPt|Ao~DdGNl;ZDt[[[w/ ;;9tb& 9&EU+WGO7MB.&`N д{W<``\QN"η8iE1 r. --8~ܸ**_0|ɧAw 5O-y옝noo?߻ϑuN QBkS'Mxj "ӰG9sAa"U?@ɡx@Mu>!].5iO\5|#E9 'N4я?^qʯ -g񓏉/)(.UC$%gU×_{-saA΍D3V\rРA=v:N'V$t ?|(_Vv9ۚ)6~mDl{(DWT\髆 x0 J"9>;S~gԣ2eUnZ:|OY !~hDЫWzCcq{3:4 ȹ,={2r14-苄Z2ՁCi)YYA`ҵgaAߺʫhCU\// ֞CntA7 8Sob޽]Uӎ*/o?hh<ΎaXkB6ٴsϺ_Kɗ^!  w:K\AA`p:AA  Yi}2  q(" u'޽toO_]<伢⁦i`"  UUw[jMݾbu}w]xOWUAAA%?/%M Oy"H#  قE顃YCQqÇOt<#  لigSj}յX3Mt7<#  5egk5^ K AA\uDǍ߻O̬#Fͻ7mt\E/ܶ~ٱiӦ[V\2 7/czW--=uŕWRe{ɿC?>2nuӦ}issVZ?1>] %xn#W^|1c?~Jg-[_|˖-;iƽ{utMw7_ۻר&<7rx*D$RK]AyCPVς@KgWZ[Z`UC_-.>qd}E l)K+;a͝{gϽ3wn߾&=5GIdo<~ yyZ- ?F_O7МOLJ|o~^~>wuu+(,!~\0щ朖!B擧-4ݻufMnnF{=޵u㒓+B LLYYmhh[Ox}߾}ǐcgD"!&I===Mj1j.wbs\## 6?~!DbJJ Lp8Ch!644tttƾ@ ]6''GWjrƍs6#]̹qư[e8q  RvTT|-#ĉĤsȏL&̯~iHH׮kooߔKռ7ZZN\*,(蘛ti¢j>߾+^.YN Z_^vM{[+sp]</3+Wj9ܰƨ]'\\\q Fx>F{ޱ ?cSSBhllttt޶m۰aLLL rssg[}}}[oק}4GGFFn=B#m{yΛ2ihhjΫ&gO8̌8t{ekV}l`!3lm }B||}}=BԴk]*-- _ﯧ7{Ą\[кk.j9.S[D"O&ƪ񌟟khh˗LfaaattT* rGv\> IU^PP%Ik֬))))..Zjj1:K#GL& BewaP|ήԖln{>3$v2Ewuv`T(D"O+'N ݝ"(BD-[D"aݵ'Ojdԩn^_ԯP(i4"?<< ?11iI^xfB||eeeuuL&n^~a]̺N&(Ic.].,2e˖:u̙3bxdɒ%]vghyqqᅬ \:c aPhYX̌مɫVj)6&,/fi"N.OfiOǎfVU3>x@a ch!n߱syԔ՟|~ zx% 0nX/Pf&VGǻ ZBul0L>zwϠE|֦}5WWKuvvVpH@+Wzy-k܊--ˢt:gWT'َ>.ɦ˗Z'$w}J2L6ʕ+IIIx(+++00Gh0pK3c媕ˌDD}CBOOO|G^lUUU/^ں3B]]W.aGh0>o\FKb^Cؖ׏/cV2rDxpHG_5BxWs``-?](G zY]$ֶ <Tr8Xu\hANp ̛.㔞\>0nA0/ hwEӵ'jW D ZLŧ/̍̽{L,07`y.t>u1l4D+\8oE2^:QV;4 ƍ &̝jbj^_w7كBk~QUVְK>!$ DCV B*Juğ;} +a|J-#0oCz $t(WIENDB`tiled-0.14.2/docs/manual/images/terraintool/08-drawing-dirt.png000066400000000000000000003550311260670167100242560ustar00rootroot00000000000000PNG  IHDRXf pHYs  tIME &m/ IDATxwxUƟiےlzBzB轃"Mz)"El, , z!RB*)6|Ll* !$w \3gs= վ}{@AA^>>fyOOO///q$fnݺ9sCm۶uɓ'O<+h˗/-y/˲3f<{lVVK/4s̏?2m4VEtǎQ \E :thtqqر/\pԩFhѢgϞǭ_emCɕ"";<1qg͚Ue0KV!Zj>}̙3aaajӦ͍7l |2Mӯ򊟟!d޽͚5j/_.`J限vZlРAfrrrZmFFƢEDQ|BCCl`-A/^===#""6oihh(`\\!$''bccJR>R;v_~pvvv>+E4#8m4/N\r:l6B(Rǧ Vc]$ȷD>|z2,pqq.z 888ܾ};--&U¦ݽ{xۻSN NNN 6߮_9~&M؞5kRSSxMQԄ T*o֪UlٲL9VRAȣlSmҥf޳,^XT>1.AArYroYV[n>}uPT]WgooW&%%\^_ 2nݺ͚5ȸ}M&7|3nܸ߽͛{̙3mڴ).%%^zթSǎxbzzuҥgb W gW\J5kfiR۷/bAA:a6iAAlFAA#  DAA"  hAA4  H1;؁ف  R@zAAA PAA  "M  /(X#   j9λ3\=z5QVY3s ,sppONJ'U-y?'Ay>Fp5˰#ꄄ̞5dRzxE%9\|BWWWN6 X|yf%I j;@= Z)PΙSZCAhаg˗<߿ ǟ؆뫯cq hOg7tsI8na! aJ8axaذ ;vK.r$I׭.\O^7n„ѳWNW o+ڵk\q&s[j]^s޽20##óƲe˻v}e>,G" OZoѲgݧOfl6AP| ֻpѿD޽;8щ'>3燥KoߺRo/}9^Μ>u)\G>tÇ5kQ[ رCDqɹDر;?F6jutY|I3z̅n{.]^dwzXE#kDݍܼeV^  ||:v[/SpG%n\\\vCYk|DA^Au_EXSB{83JӬ޷W=mܺuz޺BB9ݷOU믏8~boo߿uBAشykV/L矓BA 6\^)ydfwW1+AS">BCB yꤡz+2%%=ACeLlsro% }pРnM4=< ݺu{۲Hx"H[YYDXutrܶm[ $I=(.uQToRF3eK/\|iƻZߐ4isεk׍18?s;{&m;;;9 Ezڱ}ݻ#F ;u^<7RmU>@ ,wF;u<""*: ZE /.'O?ӧoX@ ~M*Roo׮^v]wlٲ%K8{C IH@⋣GsčEHLKII~,]:`_½ݻO20 U_~[7ߛ1cU5jxyӣϫ}ْ$)J_?_??J%RVffW{{zx׺`A(m$5 i:==}ڵ;ǟ~?Gewz/>KTTѣGfRpsuG*:uB|2ʈ#.P_)چU24EcΟ;?gKGǎ=ZV\cc"jM.]Ο0z\sG-[]裏W_ݪu띻vOz5k.\ ?S^XVP̙3aF7kڴiӦڵ_}ҥfEPxzXjajxzN6s%7{ێ>>i^ oiڥqA믿jHcvTF#0f'TeN2f'ww.8zTau`َ  Hi۟s@@r%f"R 0 c3  _3IQ*=G IDATɑwGPE3ы7ܻu;׽QXР(izΎei*ĩS0ѦM#(Ib1e8h֥c=;wh juɣFDQܸ.'->f B~gΜJOK/Ha\\\hx+W.)J ۢeKa4F$h`@wBC((fF@ADQJ1ʟܼnb/-%>]]UNnR?t{P,yd^@Ѻe(^ty/뱲|`֨VD`UZu @VLElț?Au-@&B~@[uyO~AEI" /B}s#>Qgz{sceeesZn]T嵝( CffVcw(M XZvGGGZͲl M{v>Ǭޮ*VA$vpF@x"ltg3pv,Er?~Kri2dq rV" 7>>WFpohѲ}N(J(I$IHf9w]$I:읻O(̙_-^|9CBBޞСC9!!#F ^:7uVZo:::BY&i&6FZ9YWpG}G}ԯdInV#|Hk7$]歉o?if]_W_Z7m4ϟ;שS玝:^~#;;pVZ@DDgDEE,Ӷm/-{FZ귕gxw֦?hZ} fϚձS׮Y3{,u0Fpʳhz4PE3=h 5E_-.rŖ&] R}B8N!2`3]'o~ݲ}f8I(Μ,X9-7T`j5 I]1$VF}G}G*" 7xd޹s'>ްa}ƶFyf6n:e =z433o߾nj.t}RD6ܺYxLvA l[X5RYV-f^,FWTr7Bup txsM3S%lA}G}G_2W/]HH\+ (OԴ4 d#55U|mknйs砠={3i?}su3g6o䪾3v7|+ 2DRmټ7y=Ha,f3`h2[#X&}qipjY$J7SX OAZ-fJ>S)_uj8||zzZb/ LO%''zAQSRR\\s<=jxz&%%U ?$);;l(8.!!fO@}?ӧԩS{߾>\0UFb Q;$Q,F_gb3SYKZ$2$*;T7($oht/] vv@}G}G_ .z{xָx,[)cԩif͚Ym.bN͘蘘= ׭{e?R]޹s (__6OQ`\R9|ֆ _?Lë/A @kEW5?M4E3ŽVh@`JRk&Mvg(@0ܭ֞._􋤆w-^$eFMbj(Zqpuuk̚Ǭ[o>aaaVJNN~W #3nݺ*J~*8~/Wn&M5j[ݻwmCƎ]Ϟ='75kZm~}KH[Ahz|Ţ\#hSfM&l&KK)@0/257U*-쁈 4 oK\!F)_>>Wa}[}DA~ڞXI+9ztmŋǟ Y`.o7o7(0p rk7_ɧ uz'243iDf(`MW^ݸq۶@ڵ7jtՁsGeڽۻd#>ӂ)JJO`oW֖_>[T곳G04T({vR'I&7P4mmtBhV7mip=K9/J@ 8^cv*>>W >tyC )SߠAS۴mkoo_Xnبe>-ehΔ* IBдdɦ.w!!ͪNa- Yie8r@}G}G*SQQQ;w<| :Тesg:tLUjuH)U@Ӱn>^@s RV h6fgE3'oki"]3wlڽt1C-JĐP/G}G}ԯ"qGC<iݦM2Ţ( (JR 4FbX,TO,tvP1g6"F_7F!j*()P@!/K 4GpBQQQP>zPi8;+ku/ܕSp`4c=;wif}S0h5@gE)5 OpEsc6oPwۢaVҀHp;FUD5GlF*4\|饗 qdw#LLGp Q$朼@%QhoI>.^d >>~UѷP T;f֦㛮+fVR-? YrnE'**{gNҺ4`;=; ͰK`oGMPs@>>~G P ́-7nCQH(iK8Dz {''zMU4zH@} 0t̹nEY1Z IL75!&{Nۦ k'#=) ħװ g5 YbTv UG}G}ԯ"k/UP;U 6,`aB@S)i{@h'6gG/l`E}\9H(f5Rh]BlJVwI,FVA00Bk24 ?Xd1$I^V>>~U{} H !$2@T40KzH8X9;h&MhV'ÄM%\j9BMސƛsy=jL &7SR-Q  V8zpJ^ehQQQWS\pRf#Xͷ)$R܉OTbjIZ{]3MFmM̈́SpA`5FQ/I(QʓW]@+Ebl^E1_sN/]>>~Яcqmmf{]'MI} ҴʳGxcn=_ZeslgD&!miegwp Ky FNYc+lZrNd g-zH_nH"/o64P 'AxF,&#Ih#Bmon6dZLA.e Yh]|>>W} l.)0߿2gJ]ȬM67ӏg1Ȓ;Nx}b=ey|VZD˂T>V3ۥEwkVyKEQ08@* WL7O΃yGo7[9ޠHb6޺'wFQ5.*9K^zh {g_>7>>~ү>%T[ӝ9sHR%Omjd]8aP Ii_\(ErM}E)Txm+`ՠrik3w yz'  *{:6DIxcUgNHbnO`N|C$NcQQ,DFڵkgRF|S8>S"8 oT۸Ox&i.JML}Ͽ}[~+&-@&; Qu?Ml@l?5ą#XV@V':&vPktP9T[3nѯ /E'$$ 2d˖-~)|XSd!D#xQQ% D';E@'ݺz >yh7")͘OJ!00#;y8p >|Kм;i3_‰!n>L2.JR3 yNp)zv1 C MSiwFW^ "QHF .g5ʱJrKZN>éyr]w$'پc} #Gl>Ǭޮ*V)U$D@0*-'IH6F8;"%oI5M,NTj@+v>?>H) W>~c.Xۆu?|7+Vt3aj%H̭{R]x5J7WhI'{n[297ъ2LixۿIiN_NZ ޠk/$OLq#@gi.~8l)Tã:=9h͕S@~ H/nb&#stKkis;@`b@4E'gzCvF(FnKӜɁ72hõ_o_ix~OStPIJ}_@<~xe7 O*t^-|c7X̭u TNT 8Xz$, iΟX&A2-6\gl1e x[]+%@}Ωs )+MJ^Z} s, ~R0rJ{bF}G}G*_}%{)">xpXP .'!%qﰢ}CQ@MKS"!҆T#X{XV0Y`O@`iiN @R% &G4I"@qdbAnI5fVi X9Wu8 W>" ;^o߾{JcA U|F pT>sP9&!2)|\5߼--&Z!͂(atc?w;iVNTB%ΜQn׳Oĵ#bNU+ H# حm?zie0戼D(f" ϑ,F=j0*ZMVHq*J"FHaхtV9)hGQV? & //xYφcԅeM Nᴼ~=чdܶq%HxBbu,ӃGF%!-xS"DуEڴiC4EEK.;Gq,ǩT'O |i wHKOQ~bk@s棽Gz8|nAA/M|,D*7=X#L&ިOa5.! Xulrf{' IDATT -fJ!S)@sO[~@7W>꧿N,r*'߈. \*9 ?/'=[lEe[yzԭ{O'Շ#}ZR He,bۤ+wB"wفcȀSS6r'fQ (3g1NaZ$2$*;T7HeU9{~~IΑiGSFOq[88(A'nݚiAӲ( j҆;jw>u•{˵λvs hq[w'N?}NĞ]%$B+4 ZxQPj5`L@ u"{ۺTl?S<_)x~E̮v)@;e߱o}l"?r=uFr:&-I BuP(o6%e3^ZJiX ~q FIoVRiAeD*H.|!HfXW>_58A_#ت5[!H`Uݴ~^Lܕ+WYVӰ,h4ɓ'mkIR;%M@3M[$`UM[n՗D>v1;Q?~ F[+Fpю _l5@% jZ-IR S'|iwQ狌qL. ^rKy3e %H`P34-Yi˝*)czHjSX&CCfNP˩*5_x~ Jo߲vK~G #0 PV9YI)Jy0lf4N޶@fnt1C-JĐP/G֗8dxA|N#s5M;-fZ]A1xxx曈H9;A<05ZwQ;XV4GLR}\-y^Z9ň_}"PV?}Z2Ѕ[uׯ }bhLEkm۷gWD,FŨF祱w >J( 5$9-K57VF}/~%Ű}?m:{ۡڿkJe0'gsg^vٞaG' XS^J9:ݪ<f9G-ܣRfA0r9_LҀC4 l@D??iY?+$I-.wvCGw1X2J̻l-b AN@z) `C_~ҦB}/3=P/T]#H1fyEn/p )e8ħyfF^' xco64 lNqmVD,+UMFLy?{v@0 k cQpJ \ќŘ3j|]hU4ck^On ԯ,}O5GGA'eGC!r3INa1̪ĩZH<˲<ٵjtBZ N;9,& G +So5Gj8*nɒs+:ɐPW;sj']i܏ [xv5/~'@[]A#(#b1f phYJ"$y ,`5GE} G}/>/~eT ymᕒ;oMTQ4Mi$ 8;(m$%­ZE,DD`K `1(osJF_Yx:uɱRK<,! f^Z&$Ѫ(4G;ʥ?:7+U g9VwI,FVA00Bk>4 i$gJ ~/e~e`fV5cGwݳi˦ۑ-/_7_vy $#J`12s<>mii!!*յ֟VY+t]uuueֵuֻ-Q0%IRj[HHHȅd.8!B q+9sSg_~_xPQ}EUl բlƦOwƢ*!t0ǿaqSkE#KDbLGlCRJ )j=}2{^O2<|_nl?}s}/~K}_ਫ}PӵU9I'LP`i SIj@(^ r|APʜ^fc`f5Y ?|??^_'OMkhOܼ@gwI?Ko,˶m4ymf?'nAJJJ\smgױkf:}} +JBN߰6߶Զg]hazkxhlazOkذix6Td/᛿nذ>6]j[|/h?t'vZP~O\w"ꆇl}=]Ily {-tpªc9zݚX>7|>*Ԏ-myJ4b2f>o| ,`L-6"]^vg6 βj()e:V/#Ժ2I89 |Ų/ D38uDžo sH],Pjj ^Il@F__(xc pI^me]LD/ @bf Lo3=e?tF<S8Sx'f l7d %"$lop 6t~__7;')E^`3*lKw9ɎY2\ïg.킯hcԶM#>d$ =1f1<l2 v}u];W/=@5ӥkEas`0LZ_? i[ qv+`$ciAA y]DIN ߙ$;`f fL-9>;qIJMGLIQQ`:'8Sh+,1p`jz"J}~<=yCîw>-((0  y^Eg%I3gؘ {arÇn/3"s_P 拲ٕqHƆMDtЈGɘ0-6 d4ˣ,E JP}%*eY6'IR=1Fqu8ՓTOgDTOD) t~__YU9%Ks̍b$ɲ,I e (JVV_~o<x̯Ǒ̢HF2ƋRCDζQFAZYr (K2/6;6lU=`Ls(Eo1zA@z Dtfl<>fi/2LRSY`Q${C3zKiiy++o95<W__v (iJ466mUU={O޲aC=۶mf0-j% ȡaRP D 3=dg{ 7zS"C]\g3 I8SZ ^|)nf.aFc}}=?Wxt)uc\u`ʺ4MuM$I$O|oy.05Qb#}QAPıÒkM$'S '{R v}bFro(qU0$ĺY`q0AԬIJJ!~}={js9@)Mj]/ B$Iz}?BNE T+]LxQ H|I'T/S04MԢ>nx+E27Jj$"٦nY%DԠf B̔*]9K ԤFI~}={Jynn[g?m~޺6OeI$Y%IeKF`>Q$̤Z /)T&O3 /*W=Dt*/JDt%Q zd_FyQN0c(‚e$A/p!B2_O$G9^&ۚFx rv;I#1#/4}t}ъ<S6G_Z6[wo_g/BP(>${9r0r-C?fj4|͟>z7cO.jxԎ]fSt#"ʻ52Qe?h$䨤O!(fb6pq_$8Mg>1twZ8N.054 /y?3cc;" ~Ge. XoAx@֟JD@cDMKAxXxjQgcLJ_7^<}}=`ۗ\Ts..li3eo(ުaONzUó m; Zl/Jrd]s;" YE'!"\Є(v4 . ^ѦMݟn6c}kmtnmV__\Xpʼngf|po>3qDak86%?<smmmmmm+V˭s۶mN766嶵UVVUŋ.0n\͌x򯾾QXߐB Q J}< ķ)"68LuQ6G>):#WxWw|^yn;V3~wQZ17o ?6:,$?\Qȱޱc͊9}BŇm4<G]EF__xwCODoOex=y:UWafF2h^S45&%f4{ho<LP;=3?6ww۶ʪ+VcN@ee[:>vǎ#'vv̔oX̧fz8ۙlg}C<[b[\s4-+,4W謴i Wl: ޼GZkveEvI?W :4/ ÏL{p 睆ᆵt>7~iٖӕ+~澛=[`K]fj IDATŁ_́&P#i$E e3MYږ>;e*accMG~ UNlό?t[}wȭr ,#XI i39oW1f3#. puY7bÏ'h7W/GiV^sQ2pB(2PVg 'I^sS#K*BD2zK$ɓg'%D,(NLIFRT_p 32sjI*#CQNՕhl?iJ!;΋וϧQ*[ny !|gg'!\NN镥KhNN8xኊ Ib*1y9oXxW7i3\SW`,Rr Bij@EHK]/Y!#r FMm"Jhʟǭ.W/=wU\dO`;.?Abf _z>@'OWȕȑ )[ (^ds'Y:-{|Ӕwn4AxѢ*iwǤnmmsPUn}} 4 @@u |{feYY];o*566[83m /Rlϖ 0f4b:3rDZzGx|XM5呖>-i _ؽ7vޚڹ_0r vrluYR'wQi- Z! EQ&ǼϏ?_wj#W 1^8QC1,9-jSDϴaؠqquU F l_ŋut|[[[UU=mmmU~r?3c~O]^7^MDl `jqj$mfb3̢vyeQmc7E9E:故- =O6>ƫڽ]M%9mۻ_ѺǺzoZ^0< )./Rxy|Qn6GOM 3/8O'3zKV {tu3D :Hj3E -6%r6Yܗ1CK($١2+tgu2v==˗_/N8Ա#|FpY%Dpֈ00qYg;\V`r#ͽkVUgtXrU7l:V{mpMv4fѝ{j\>=ǜY d.| 㣖mnxeލٓ'ohxRS#菧lCOi$cN˝HDٯ.IJș/&rؠǧ?Sx{,8Jdܡdgd-"txZ]x>337S=y|8^f65TO&9T$>IQY|+!]2t]Tʅfrlgӱpu .]5oc ED~dK'ڿ~M5nrm'ɗڂ 3-,ӯǿ|ӕ+%#rNvLh|;uaVj&rŜy' hbfL!˟mRޑmT/8Enrn"Aޙw&'5L%5X&z#SzYiOR+-n Wҝ\qBdOl{M\kB('v ٌ7*߽?Uf.' puYݲ"BHKE:kd1-jLeϗϻzA۶cֹ틛u_0⌙`8Sz\/X":H|e>bT9NQ'2v髆]S]=;Y)]CO]UUSJ9ݧ"?3SW/Oy')ԊZ¶Ξ>jjԌ8)$kW5lX_Qjxi ncmOm}( 6v6.Ⱦ aC@־+7wnPYYа{Sq㦆yyy~+,<ʪU6}yŊVlmmssO=msf:kkGΝecE[ϟϪb l uÆ&ύ6P ?|@M;2O/~9W7<fw6[y0|l~]si>)Kd֖G[1׆\~M-=<ŗ`nfGZzܴ+\]^8?\]۾kf~OmnÙ}}=WT}=yBĭ^i/α$co?w K?ذ6l[7?oȮcڱ-O)_1TL|5^e̝Fk_ԬYB-%ET|LgJC;߶PqN"UW_,v)z7>0}a[[UVϽg}f3wkR{N6-_Lv5 A98 GVܳzY p\gL6\]s5uRfwfypuY;\3 Tu/,x}O#EIT ,<5W/=˽,~(<ϟfҴ}Yn(~=oOsǝw0!;t| S.жO]l>'az+0)~BO&HT\ 惈-8lJjGl6^/D$a!0s NKUjQ{{g_t9>2&13'Zd$􍘺7d_8ab}CqAV~Hb[o(^pkWU7 G%棕Y-'om}).9 N>}Ԡ;/B>|%+ArIa(pj0Bc6N@<J6<4_>BxY&Lf#97>tH2vd2Tg伖&_eT9c9^;/0d,ij/V>3oX.N qB(cz|(=AdqVꞧ't]K rʟr+\]> Wjoy9{1Fj>‘g_8Z$8w^'jˋ4tSfb?0>~}=e{)s `wv< dexlr m B>Pؒ%dҲsӋ#nOa$ciAA y]DIN ߙ$;`f fL-9>;&rjut[nu;(1g/>U%n\~"p넨/|ĔUs*ˊ3Q2-+܍ҰVڮc_^Y#ͽ#%˷puifޮ=ueՙ1F-1j艨Sx{)󌠓j# kDlp8py{n1vΡF^gD(e?'^)% 1#31ÉaZl$%3}T__-{w_*g%noyt;qA JORQE`r,$IՓQʠ'ƨ6Nղ#׆۹5k 7P& oyt{ 8ołPxܦM֬y-Pt`ڠ÷-";mTzIꉨyAR~}=e{ tpz%&,c6 i<SEȼyFłc~=lgFd>ZF' VKD`F̶cVY&eF8Y5s C. վ_wc,XA@4[^qo5keѝFR#jQI;:q!-˘[2!55ٟ=J7ɓ+F-C7=jvwں4dd lwusk">¢P((O޲aC=۶mf0-j% ȡaRP D Rl4KncvӦz^w;m۶VVVZգGOݶζrnt*nݶ@\w[/0nԡP~W2Yh۶mDPL,)DԂeMDtk+̢c jYd2ʬ:ݰ^xi0\]L tpt JOj:_zc{+=y:T>|Ee58i8ۖЎI̙#I,rhSb#|EI >qxɘ!m "8> w)T;y:4<66q;.]wLw?3S~|ka C R^,P =i$M$ l NGݡBD~MBPݛe۵Us"-}R /^1I#i @HhYZB36 LHz˟['O.аcCg?}򣟽zzYVE9K.է%Sx6 3{/|䝙?WDMpBh.$5@` dtJDBye^yCl / M˾[VV/+ .\3uwim@ݍE3^:5ԛO0a[P 7ɓ 01@_:˖`sf`>Q$̤Z /)T&O3 / gzNXIDxQkSZ"MκֶAagnvЭ,s憾g}fd_FyQN0c(‚e$A/p!B؊z|e"eQ#9N"-=SoŒ=/-+~H\{`^mTS; ?\@>`3 K2SGOљ_z>P}=y0#6be%gv&Q _w~{Nvv~~(3;f._$'2 =w8;)!]U ^$+^8rSM9pMs/w2kޤxvOڕ c=E_ _߉_V$'3R9Q(Gfcfz=y0#^{ ~c!; 2!'*+kJJJB$t`3m}<5@dy `pd H "G) \Z`ID$(JHN_U5wӦ[nq㦶緵༣Ӛ9LT9^s[56lό6+g%LI-z|X/Ȓejy8~P+7W/ϊ4wɾepev5w!O7-+r?^ymbt`I~V[l1OA-S/5^ӕiy^ol{????!_zk_Ŀ,XPi@eF2Ԛ//S d&pd;/ad2M=nƩ5u|]N?A\M6nqt)̹:3g~̢T;@8'|u0FcΆ".pf|?PE9ӯǿ<|OaL2{QAx$gggfeez^.c;#: Ne_M=n*e(Jήq{ᝓZt3kz5Cԑqڅ?33f'=P| RSv|8%4ATAtv%vHKofndu+ IDATO{7bcŶ}RNჀm3l=RΦc+ AT 1Fw5w\riy95~tÜu2zSfe3 ϽkyR{3_HGD29QM--)Jn9s_L VVU_wSVVVV6{|峟jkjgƷ{{ڻzUȲez2o!J\!bV6g.=5lXMљ H?ke |HQI B)D DCPĐZ`CGBqYֶMZ*+ݯ(N:0XQ9iȩ|w\XT/4ni;2Ke&֋^'֟JŹ*ٟ NF1Ae:h" Zximu7PS+/~6+õ [$5oӡ t4svX[; QYSiiUy䇫Kw%~ٟj581"l%ԎV|y錾Rb9zeNvnAJ͡lj|̊hh@S|CCCǎuլ9pqyy[7͌W^>ys_GJ:v2)ki^ ]tv;L7q2S1褕(D=TQ %9|U A$0:]~ڄmm޼O#Gڦ 63{#H H 0ވ(Ee2khS?'k;2 kVqRq[|%b~dO{Hp`nYww_}3gz^={siǹ|77sfNi[4ߍ4 +"` }~< LќX&5vuuITWW{n ] L%l3_v6kj>O~#|g']cQa7.'[(*ֆ_n LBOs`WBF[aFDt@RJ GTP ^On /Le 4 wy\ub@aZni J>.n^rv̘]w3uQAV%5(Hɟ-)*uD.ʦJW;=9b[3/5|vO瞃ckj R`umuݲn;5s#-=7Ք?b/V8#iU6$Qt3Pb3zƿT2M `ZeYV`2:7_DoWw. !HPWW944|Q`MMAvvumn!n ̹-s{K5o>;ys9jO?ӁO|uzbu4ȣ1#8<]AfF2h^S45&%fN,39(3S+ԎlO fN?ޜ]UUSySe;KESs>w;P/(nM+Lg;R-o(^OsK1LQфNX 8^R`P^ե;¢7*w oRK^wu/'IMc-+ܽzy1x9#]YD{CyNJ?1->?|] c&*ĶY^,8<)i,6L=;1FSŗ_S;w~ǥWWԹۿuwm ;:4F{kdQäݴYY겶Q7P~e,7~'~zz|w!ӯǿK*jmYeQ,,Ƙm3Y-:TLX. +suzzz_GFFWƣygז| Y@&?ɏ\VrۿzJh_ oȖ[_N$Xs6W-10?]Čz;$Q˫U A1܌&01%IAREh$WWΙ}F92DbB Tu:Dv 5l{2 N tS& o,nOl:\d2u^% )NCƒY,8%!^R#ͽ+!Yc&y{µd>'-gi/~?t#BR8Bj$_4=G֬+j/uGӭ (^d~ 28|L z<0 *"gNI*I`̜ AR}YT$Pي/4M9G9rR@bqj/J>3oXajjX'բ(Փi`Ye_ac Ny5uU{dUT{,jjQE(io߾x}@c\dOG󦉚ŏ47Ȟ/x8|ًx_I+9}wxU;L%7JQDWPqu][,*+(ڰeQ$ PT4$$!=7mʙf2nʥ}3{s9sϼ0Ż0b9 Yh@t,IKK=uuuC. @v%Iy>77õuz`mmÇsssEQd0kS/`V{&rp,(=#tC5MPvxyyyrrKn4 -Nl1{?'wVElZUU!(AEQ B N -VFb:Q'fI(-UfŅ0*dFj _棑|+W2z 9{lh~)nYÇ%{׋_Y ,I0)v BR( +q7-QXTQXT )E' y*E#Q|Z&fx$w?8ܦǟ;>?yl\ YzT/B,QH.&tD@aFc96/lsխk/lB%+~iV1ni)+vhϞ2bcc***v]QQ3`@Fў=UUUn;2_WWDzKJJjjjdw~iG HyUU%*Q 4j 0B>!DG 5UU%>TйΈ|K3 a! 1YU$y~X`i C7, @^' m)e9nڸ@wGEE744Hކ9oVVVljC >v4&&&**8*W tĈz =Hy/L^{]vgYpFfj/v?iic Ό a=NErkFp"`O MjUٴ wlSdOjmEg|X1CW:ozʸʣÔAyB˲ced$[EJ VO~biڶr{YEsZ3 2:cw5f/xi?p|OHH*+%E{wOtFc#F3XD+,qcS}I5M1j.=o1EQ^:e싺"zbࠁqpСٳg۷/99bXLⒺP1E,VkjjEEn3gpWWWs΁Ycccozhbbbh!vIzy>]y]߻YQe[ =o"d"cU<-(HD0qoj+u%KYUfJ_IJ.TKi1cFt5 hWYPuOǽ?' =@`B,!*""52 in„["/epwI@[vh2l]>it׻ S IFA'|/{jxa&.Ԝtzpf&Ua04~B8aY_J411e'>hҭy%KκKpݺ'X)(""|q#~5cH||i۷o4iRLLfmٲYx۾}u a_Y 2O 6rOY6==;Bal"Du c1˵}{EZ$$$@Y~`{hty#œF4>TRJQx_4isvm4T NoKuӸN~6/1GG23 t4X^1= ǜKNW)<`BF4EUT`AV0 x^0,rbbpc]Ǩw`fn׻O=llp|ǘ.$}WV/{w3 _A2op9RnN vE?1 b˱,G61 ȲZÇ{fʉ'>}uAmZXSSٳyٺpРA B<mO>ʪna/Р"pе;o{Xaa?ǥKnu=F޷Oe9n]oo* uu uu 8_$,CFT+^ZъmD`;IOU\!9P|=}/àG<Ϭk|:=?w@VYH_:چ2-ffɄa wM Xj)E ۇHO9{>|->FI)VNVtb\͕=bÉǡi, wۉ|$cvhndY ~|~ɓ&-^_'5$&&jlZxQQQ [6,11PӧN>u:ʿp}zׂFha3"Q?YiFrnq9j].'uYHio }ZZ発qW\Eyb Q+GւtQ{|zw=׼=>ͼhej h*0͝Jϊu6y= 5\Nl]:5Ԝ¢GX1a0$,X[uuK_Ko,fy=TɅKѿ)`D=ov a,fp,6nA v5z)IICjG|yСC{;sꄍo~̩c[g t9ǩ-w49qrnMʎA|h)NK34BDlR9T_f+JE&+F"Ado$&[OD`? \KEt_壩u@`ϯD 2J A&D|^`aX@|cGE$r'U0ତk9F)ZfF^oҘݵcǎo=3rhCSb46ME+'.."+[cxB3Kbh{Z%ؠnMgv5uOL"l߶m„e $|} Op̌I+^@ün.,̌۲\xl wb[[}⦛n8vdҔ1<-?0l¢rQWuz?!3䬑eeKDh֔/Akd"诘D_*i^mF aa {HT=`r moGĎe1M Ddv5781En"9h h B,b͌0q$і֥u%<\b;"M7(+Fii9i:rs2gʸ/5y^b<(_|!CTQ|ɅET ==sz?#qx[ 5x*U&'K\v;}䛌蹊oo/ԇ0%Ԥ׋36ɢ vWzdNP p:& 7#Qp3{ >Bmh De4uJ4[wxi[<6̘tnȘ(na>xo/^c=Ê>2}|BR8eDZQg A$$rrg/|(tX`>SHIV:VahrpVBCR&5DvETY_R:Un-~Bk=zdvk1R 1۟'^0:PnE!ێyɼhb9T˰&AiQh@/Q=(!u9hOuw9$ҥ>ٳu-;K5B 7whȝG(~JMIh1R' N`#~3gI<2yw;t M1vd̬8ռi]הӋHĝg5N1zo4ח#!B4[Zd&:H`EP`i@yey U+33&MʵXLǎio\ͼlZ83R)((0S.r9K/ Z"He(zB#bE BTu*M"( 4􅓤`I?>ǧ\o-26qު Q.?24mr'@}M9÷"7'gg[%d }/$$gE1'[Y.hlJ=͞#' X›Eu?q\2ٷ}AǬIS&n-,y4wm{wt<؜;!*ug LUl]c'=~Bg?$! ə!mݪ=[Ma14ױDV<-yXh2FHsb%Ow9jk91,p|ȧ[Pf( 7X/M󂋋KNa}_?We:1>+9a%sJn@,XPB+(4{M ˂As C,SXTYQ+Ѫ~#w~W?yl*%wQ1gC5F Wwtw0EVM tMQe{[L?~?!ӏz$$4m UUNh*.]fy&2 5xu cLb!kj|@uY< C,ors҉<B%&9@ycdF|Ў0(+f@0?wBRgOP`=zCsj&ɲ#h@zKIL-쩾E#ifDPh;%dB:q ~ d$Gmi6@8^geٍ ˖ݱr*e%%iii%%%҅;$sel[rUAdeeBSiv_#*`10nd$R K8OB9@a Ę.t0,>ǷpDa߇o׫$F[c w fʸi?T! "f +p8 >OUoh(Mx>C?wakF4W#=0&4DqmҺ )7U˾"˖ݱl*EZ:ԽD=RX8=~^^^AAA[p/v>~x_̦;oR7Xd JhDW'om4Hʅ§wU 9N;^z嵠`~{׋ޱcGA@ݳ\.j3j\gĮy36 1PzA,#{,aHbAq 8ẁܱEy[w, c{Fg4 SI>YY=?_~-[9 Kׁ/Mݥny^mW@80rc! D@`^hk {Nz l!`w;)p|Û(~Ϸ~`.E'>wvOC??p~ʫy_Տ}7_# bf1ciC?a( Ď6K RC_~'.0$dd2B(&:_~)9mL ^__BO ]`H1"H"˲,˚fMÍ hF+BQ70K^/W\Y*>]GrXs3,̬OM@oo6[YlBfb o{a0t|@Ka Bdd%F$Ҥ`:,#su? ;ħJw2c1覦?>5/>9~BB]?#vl=VV~'L(Jm jkZ!D}UL4U4qUyNpKMscl>ۆJ41!j | {Z%!"z6E0?Ȁ`?!٢^w_)7z9>YL rU_܋3+k{]+9௯YAtL4ҳX/eu ֶ,N`@q"%w3'Z0#,8¬}EP|yyyI)ac49]ahZ:V{hϷӧ -3ftLy )"FTJ80`>Ң!Ȋ AQ4x~% @ }U0 ʒ1:) wBfTUz\"IE?-K{#n |~|?!'kxlY?~R=~~nsϮ~.hswotTԙuv}sFy%#F o=gLrzpQ 暫7Ud8lm2_D3.=Št֠!ɊfygŅYdke D!c QM@аd i~Zrb퐞?ߔ̉X-ݯuǭS;}$U(=I){>H\^PeZ1+"DU@cZVYJ%T,ˀyB4 Ab2g #!($!&:B[fwf`Ĥ #<{gor:Ĥ=9HO#n'H&==u /c|5WGdgy77w~?⛞{vĜ6*QFXNW;񢢢3g/ YD0'_|i.liZws<kecp81GD",oby,"ځߙFÇKxE*Vʈ?o?xXߺ/68zX_v:8ʠغZGGjor١a$,z=EV%I,L EMbY߰ OVe< E,QT WU`_!,J*I*TU5uz$DAk~P%Ò90`~~;| ]+W.v?8\01zՋs_~Փxzޥl޼nd?0^w̸ ~|o\t;v?qgWv8̝ӯxwwM-9gҔkWx<ظ{ǏW/"##߹ S~85߃?z(xz3O<(\gVjf5j䈇|0))ZZ}v-MMIIy䑍%%%O zx;wSOW 22|N5L0Lƒ$|@vh%d|e. F֌ r՟|aˌ׭+NHmw,7nxk'O4ctj{=w۶oqǝ ty)ځ{W1Ϭ\ux׻{۶9nE\>u}tqJ^}54x{ソ>+0ExO$m6۳ϭ^|テ\.kk_ILL,--,{v5\=yw.e?jڀ8vq6y?hajĈaVW\~x ***3sɓ~m{8e9i(rt_^QUtvv=.>yd;TWf \kڼ8bq_l??`6JKˎ;V[[yGZ~¿Vzk++,,/>ӥK޵_JG?oDGtO"xƄtMV9Ld* &NMm5.q0:˸ lQzm Zhk3fDהMiMᣏLPKKllE{h{Ao oYq"-鱅 hD:y)3E,+<6u;5UdB<+yZ"AS34Llv9_yuǟ444`2u~j5ݺ訨55M_JiJrJuu^a anݍ&cܿlwmsd |V]x|>.™3gn-,5j 7Ԉ'NHJJzӳ'LիW?ÇKdÆ[.eN:q'PQYY\\l8\N(g>\zx*=1zM_ʫ\Զ¯n\??.?*}_׶+(V >&Aۯ?6F$'1WU",qVy @ӈʱQV7
!֓2YtktsC_~A: |v B@ym@9 Bp(A:o=AaI~hn3O۶mg >nj1 ӫoiC'>;OTU=g>Zו|?tgi~ʋf_d䔔 fͺ K4-9%eƌj`c+*=FU]'--ظXؙ,dÆ+W]C~>}覛ƛСC,^E~{ӭO 6*:z޽{zC3"޵ha3"Q?N4J{$wQr9eW=;*#MMaDWKO <ϧ;SxڴW_7HvCk~ljJxaVC ?/60nW>}㵵#Ea 8ek׮ݼeq㢣O1cUY=?n6IDQ;v? ;{f.t#xfdMLdNFf/Kyx{Fx<_|LKh<Xd0(M$ M[d K23W\{mU\RR}б 巿[l#3KqGj՛QQԠH4X* RKJ&& R􍬲K?bS`})w||>zX l8w6ۯul~|R|}Rwt_?oK;D=,ֱNvYkyg0!{UUMwm!;~ -aa_yg#x%Q믘+_7^s h+/ 7^WUSkx坍uOv++ox{~v[_~};?Ez|he澽@B?;#yۿӒiYYYSϟjd|-7駞2c?とk;#lXHG͍SZH *aiN @/=-/ga @h8Dx\91 X32J_>U[Mhkl2d1z`Ѣ Ƃ#JgOIzܾzRyhv^#*Qڷی;,׾[в#Bx$E/G"I[b#.b᰷Lo{9?X@hhSKLъe9QM 5O+éُjb'X` *B@"ɚʼnBzN- a]׆ыAZҸ̌`pz~Q |~"{wo9;v#`Qa~XکKΘyn=wa#vAo/pCš5Q>|d577O>c.]$Uڿ-k.EW7dXg/l4#5DIZ4k\9H g].{5-yJ}L㊋KEQxHIV@_XFD?|c1 utGf,AE3@ZZ_FCkhp\ Y;6}ʠ팙9֤AwcX-"nnCw&;:,# fUr &w]>#aE&;4UU1au!Dᎋ496<g`xGFnt&@M{ÚjLs?+sVJxxx3u}LE$7mdʕ=\pM7*dk8gRn|O- )_$q 17%A_霾"dFͷ5`X= Yd}]=/1B[vV2}Y5]zl9Jc'mVa^'${=sj`^IUTjB & *`0U @Ux^qhc@Xx$-DnpUU!UQuvwGXC]chYGzZQ׃t4{/gR~#>`?*wk\Wu)Ҵ^a,_|A笡E:$p}uk6B!`MF9Dn㒻%=Lr7׹N35&#znwZr j >\B)^/n4ظ*Fp}~ y^6sWoqӧ *9 <\)cRdYxޭDL-9R"̔ My\p6׉i*TgeC5U"ؒ-,+zrvbta:~?ڻ5?,\{X u̦s6d/I [SŹvCM} 􋅴](z~:L. .-?"&Jð6fZA; 2yr!ɸ*)O Ԍnz& 2&x@MCWEQb t}`o@K>|o eAvK&:)8byoisWOlu0G+޶mݭk>a2!Kaht;聞)~AMݩQP mmGj+!U%{:+.)(ኊ^]";; 1q-AOڧf$Z|6i|[dL IW'MH\늦d"_yY!)sE/Jnj@ҦM쪒Ewए—2j?9M.hINulRt<!^n: H {;:93"I扮ǁ@9yJq!0WS}@E__rݬ9 9d  I$92iE &H H08.gC38fpZUf ݀C ^V  SM2L0%IiF @_ot L_hП )">$zT3K> 8%4骋n|ǟ}Ĭ!٦V죢v"Tkϗ:7˦ 9 x&xnжq <aBU`pՈ/DY@$@Vbzڂ3l})]:MOK?bcw&bXqZ]zVVztS9 $ 3|DpΩsN v`Bp=OpbS0T-K2L8Cx1kF@ /J4up({'Zѩ~hkRs!Ґ ˄22CTU ‹ ǐKw Z%ql&YFe!K}H*v5kj9y nhI>jD/s+#UU =?k 90G\cꖖH$ٳgP'{ [As /e-3TcQ>d\;Z2kQlj8TL'yb̶i˓bҠ9&9~3/43g$N[nty:Q4_7x2G08D"@ۑx2FNju0LSSuILdJ5ڟ$ -,<LLaWRDv1ux2Ou]u]QLav+|"Ur@mm;e`~ⳔTЗ?$:}?L`C'4DPL_eu4s$Q_;DCW@dn,P#SC`ccc0`I(vhQkRкX$h ?`Yc?mUXTs*Û#8'pD]FD)ӬxysZ,w{yiƒ>S||8F LtƟb Gp0(i2/,;YR3I@M$ D e>d: Et:*珈BAPު͹cC1qx'9,uuN* cN=ߟ 嗷WL+\~|N 8(FV /.\SS0 =^`yr ٬z0-s3uUvpL'>ՕnX< HssHd9w;yKJ>Rf`8q0!Τl+¢͙=VwЦUK!8@KNi /HD6}1uf [ NTRjWrxށ5n?8Qh23LbGaX2P5p( m!"O[E^CC0G09t\XtZq9e/`zMvdZҮ5LZzV)v”Ξ]:>%M7n:Ab9c}58BZvܪ7zŚ9cR^KH/ Gϯ&iUQ.uv$Ɓ^=֟!bP2g {'DÃ65}?Y0{mO^|E.{/o5w{?+&$x^LȻ֛Uj e6-]uSВ̟= C+2᯵Ūf̘8%Iܵ+`Ϻ@؊~93D2)l4|^ s_қZ[z]6{+5?s^vx2;9CRN]Ig^Xff;Ԧ(.iJdr놮뙴B7oIe;$(' ?sbNoD%IISgG: A99[iDa)DV  8ʼ)yxӍEe$>uH쭔n"2|x!7*)eӘd?ir67+C ?.LcZ?<r+h(jk+)V)Ξ]R/8h[v2@Y3BDΩ?.Y\KDd?uY2ix Μ=/$qж0$ USRɾj&a誕HᑓĄBXdc_ŘOۧ`ט#)3?3X䟡XGo홗- Z@\.!koZ?̤$$Q)s8îZ矗  N3I^%⇙tKriN'Uӧ9jd+1+i 0#81`=ztƌ(g~晿z˷Ȍ(X!В))ArJhI^ FN @. G1԰5z)`Y@:5fs& ͈GB; ~md֜Ϟ%|$q!O7< m$)Odhar@ҍmm_Qk?ܻ T* 'hʙ[wlu]RRi4v7>eT&(Jei(Z,MEw;yݭ(Leݽݺ7 $72 s_K ?q<_@*@Mo=H&N|p_*@pq.J&:O1x~<wtvP/;vw<vp:8+(?Eb#.0P(m'M6#T=dkzkaw%MI ΀ AL&:8S)`X ldo(DaKF@gaI8|ECY U䒋X> vvuo%dGbRmMM5тnd/)>>pYJ&:HO1nG0LZ <߿i W\q9dx?UW\9gw|aW% [~'(9P*ؙUDl wU>\gM3}S%9^T3 ~Ε;] h5&Ag tҜz;LI20'#OJƥ}򆆉3˷d۳2gFgGlBOd.SM%@FtrtZ6h$dWi. )F_oZˏ?`  Si ?jB oLf 7]w,SI|]e%?Ʊ'_{5w 6jq5($۴iӘ dxA%ݺ~sgvL}+7:HGYwS&OWd!-_ ->QDt'PIY$zT֓xN3t-!Tgv^ /5'reWYTъBի#4f"SB"9kG*O3F>>)szz(-Z ^ ewI_|Պr$ ՕCAcw:EA|>)|X!}r p宑*el4\BnN[v1# pO?ްgNQ|Xg >;8СC+z'_o7;7W^Qyk;?r˗~kgÃ.=vf]x-[x晿_S}_8s>xer?f 1 ㈝;w;ȃ*¡/ƈ_r F4MskVZmۻ.p;vL2)>#h語@$E2Py]S8 =84SI!Q& J&ǀ5G]N=ua[#1gSz`֗r*oїud%%UIZz(~].w~Q"LZEK&UIE$>p\.#Vq?C,84 <ϑ% #zcmP(C?,!&:)UTx2Xn;᧍9 ~]:!zWtZᖭ/O1#L-uL&//L&u՗'_$Ć?dK\s -W]}[^\s7Ux7u߻+\ӴW_{iq~[R;*CO(AF4M0nƅ M^lU]ʌvt >Y_R\I*d%$Ȳ0n써_ LZ!҄2v:E2'*p,XKZO#!>Lndeu(4jeb!&nQ|N-iC_" ¿|,ˁ@zCj9MT ^t$馛nL&;w+,YdGKkkAg0Z3ad5wo~hE ҉L 95?A-* z%Z@7tCMeͫ7-c*15d];sj2 Ct 8@-ɗf3̎VPA+Q>"+%b r;tAԛ Y d 5Jޢ4j|)C}H>}Au:='[;w޽/[o6ׅQ̛7_;wl}'Qً̢Bg{]1aatGA>d"%;;csbY簻> Vv7)L3iESÇa 8m%Otfuݰq|gg a<ﰻ9#'λ7C~JJNT~eKKx4?S\7<xwTGlUU mG\qŕTLA#h&T*,tvX̨DQE!E6 7?;YFNӪ nk~4]i7G4]w)6 '`M*ߓٴj)l\`kZν(W;PSS3+íѦ@0X>sꪫlu"`' 19O<75nm7ܰrŃ-_Çp8?1 ?190n-wky~mrw2>&̎19|K.(re0u5kqx+nlM_ko=`kZE"&p? /"h 7>?0>V|_.++?@[{˛)Sf___ݬַߢ{-D\B듉<묳~Ys[ ?s˿E +SN]r[oҗԸz51 c~|G`(miJ~4Mr'I(r.ev8IAww2pvw'iWzV,j.??rL \hWvsO-aay} Çǝ8Kf)7 G]H(P у]S@w:'?C/Ⱥ֖ZJuu^-z1}"t_:/-FHɡ,cr^k9jV>jF z )zX=[r`}_ I:|Yp;*Ѵv#Cp@ECW ]5LwI޶ IDATSR^wR`#r;0tuD Zf%Eg-LXLjǫaںvX{^N[~?S=3Q n+,>ZZg```BpէH⊪+NAztvMID"SR 5e}0a)CMY1o5t?Tꮵ5g%K|DDf~R>c|OkU֌NIb,g?nB6I%?~&^w) F嗝S!] iMݩxj T=;RIm%^^dx?Oa0}J\q?i!IkF Z;~LNhƑ3QSŇ_=Q 3000!hGRkJ_TRqbL]'q%ޙwujPN_Me眙ղO BS#cW[ `= Od:j}Yjz`9eP~E? #J?zN>Dx|ݯnhZF֡$'tE5=էu;(- N*۲eQȰim|q5]A|43q'uJaj0P1hAr_sw%KG|RJ>[$fb41O{u6 ZS~/T<@pȲC'ގ,/CKsfDC#azyTSS91֟O0qn#n~l{wjSE9^)_(U!EćD!^J ,N!xneSIm~+|US,筯.@T/ܦ7ϭelODX*">;nB A8<NAPt/0U Ŭ2d( +X (x~r-pQ:/mOʲ}9Dw":(L4;Hel} , ]{yS.G?Ҩ"`w40|~f(1ndɉ"=`xouuSTTv#}zmC7dS]wb10i*(jkg.Z@r@'`'_1>4#8upN o 8S޺sI1;䚚jG?|ng]/4LhfA4eϑԴ [k HDDuS˭^p")"C>-VnF[kkkѨ( dKbN1C?77D"m{T֞:l-`_=Bkґ.H[~(LC/.0|Η A nꅺjy˞5>$v`D:ޤI<'v1?н0kk}@8 9Un`i:n+H?ْ.T)C-SϚ´Ж/>:cOltiv韙:?<%/Ϊl?p/|7.)]aK7g:CA {;3u?&3`Љ` ʨ*< `h)#qX~ ^h" uƲ@Gñ+IA$G&? ZMxkzo_'Yfb^%/>>%uC/_/.!'tF /i(ىʓ F(hHv*250oɬ %Z?"HU NNF[s j&1qˉb1ȸH:.#`3g'ު=Y6QJ 8.dl% `{tfK$Z5իf'/a0UnxC?"a *"Bz C7窽|XO{W^\}tFnǃe a'%?@Ug]/É~/@js.`誦m6imuն.me.NTRh]>ArsO% {DA]v틫ځX8@$ټu {?\OOwCCCwvN'-Fc7 g/X8}FϺg=c!gws.z$98[<^5L2{Ikg`0#3 ޞޟM40D:%%2/䴻 bY5Yk{W(9g`h[&Xv̘1qJkW4g`/gPd:rf_?l3~ƟpB ǎ#]]VwCc7FMzPwL:$[vEOVN7F^VrR=Yˎ @fC GIvE4ܼ\@dqayX_5?g?C  Ӷ_ߴiַ޿oa*a'1M%QVk݇bD c]?Ca[gydu`|9`0Dy}F˯ꌟ3~,?É ~NEaOoogG'q(E>|0MVMZCsog$yAKДe/Ho&O3{v~V]n)gڍM?OuCA|xQ- @SӖ8C/j'd# ۵+*Iq9oݺHCCpDKFr_k{K>_1~?420 AEQ$2/~߹K/tܹPYZN4f48 ]93L1 %hIuMA Jx~"㨀knn.5+dH$?ϗs0Нif1cۇ3~Ϻ^#<|+JoO5\=z ^l6[&Sq0t{5EH8ix# &5ƉdIx *@<fC8tݺuPHy洵WTThk E]0DlID744lJnQ7x!?'o♏ 4 m믿~&K$ݻoҤQWU= :H7]f)xahᦗg}J:){=$$cazSOb1b̥.m`{E"9 ZW 󓽆^Rg ?0>ر.λꪫn ~i ?4|ȑT*JNe3~>s~Μ9 {GMUUe aB، Ix핕|1r\h\eB۵n膚aq<5hCDdw2sj2 CtUQ@8nmFWlܞ={$I,Ab6 ?<}?g<_ K4ݷ@Ӫ 0UKMø?vgӪqMk#iUνgIkjj"+Wlv۷= UU;ji0Z.! а!%Whiy((' Er3zO_<4uhW8^cK>o/M`&yei?K_w`迟w9hZ5][?gcܳ' z0@${A;w$CDz뭏=Q~ӧO5M#;i|V3<`‚abF69{;`SgLrbmE7n\0U0{j 2t0LtG.f&to7f1QE ]%VP ;$GGue1o<Lu"+Vijк(j(M/9{_5? 53g_.t,:YE~W7|˜Nd2Ar:K>E~n4m?ӟ>j;묳Huȑݻw777W_}u]wYg~M7q^]kkkMFu]gK۷o?`ӦM@ ˖;4L:twA6 9.V-3T2iTa0݇bÍ]eo$>C`':}Gadv股? >밯,Cݻa$ghёVX_5ڍ3~??$ "q/._sַiZMM I-_pܹGݺu?>S_o|Gz뭮.gٲez͛76l7Q,pҤI[o뮻HD SNUUa0{+W,i߻e.$ਫdmnd'ab.9Nj˪Һ֖zZ'pVa'Ë/~7ヘ7?I's|,ꫯ*n喲u=۶m ^p]QQ`aB ?QUUQin/uwPh˛O?/.((4 7-C) 3;))yhwHwBp8P򅬮Oÿv~2Gʸ(q /|Ζ!аu8&2Hd(>3}F"3~?[gha{{zinp]n׷/Kvk[ii Q}l2T\Qu%)^ne4%eLI1Ԕq Ä 5i*R$t5"~E}{& c%֍C^j8qۇ3~> 300 5|E~s>O~s.‚eDQwI@@UUAvlݳgϙg1p7\60gȄ聞rhwv'/HhaEeٝwBpd=]ڥ3~Ɵ/9``` ?GpxpxI1VA&'9+>v @Q5hipPdݖ-BMk#zH$B[ZЙgr9v<7>D"V~C`ssJq%nQ`3~mq;6G!c#8Rݮ|+UٟtgfniطSr%dt:-N]28e[ehcΌajCr:/0?A82cTRϨ?g H1U À+طHz_7 ^6 e_rWHv'x2uUUUtLQB; U{TᆆP׿3Z;?gG 640NJ8<NAPt/0U ŬsU˓NpD'$c'$ʞifTh?)sPh#cZ$)±տ3j~d3~z:fK>[O^> Ox+ϛ])~*CWeXǸ0É(aM43dAה=GR*No%f,Ʈ moyZ7ܚK˞'r(J*?.ml\`h6@&>s<]eHPc[}޷fXOr[>jy)'i8~m/Zh;_Evo:xt'g5ưf` [zZ*FgfO-]7Ɍ],`?f-v/ Ril\Unw%mEh^|~HR{[}hV+S$ih}~h*d IDAT,U( nHm|P(hon^ظtMpèoб*C9ZeVAsKo֬d@ oqϑCGCb!ۿ/ Jw2~G;4X0^Pг'C2}Q`ϑD}TeȮ歰? CFB$`ITOЉhk)Xj&1*|GԼrex Q^λIxEcol\aՔCGFoviH,Jp2~/8 `h_ 29N}Ӡ%s0 Cu5 >6~i&_l% `{tfK$Z5իf'/a0UnxC?"a !RoU!`hh|[v#mA7 X\LmjP5 ǂx/X|ۿ'gĥ o d0̃/SV*0_m|KRQ6+%J({Uld=&MBp % ڰԙ.No%8QI^qz+n?8Qh23LbGaXH$mll C`h˖7Yy2jy yeG>?x]5]2L5'XƑ?:jׅ %onnD"kء.i7ljKw2~Qs3}43٫.ӳHsXm>hIxUϓpydWP&{``Bp<0M2 EIdk 9_*XV}̶%`w?sK6M-f7AZ?xi#JڞV\Gk9=V9zhT9WaA"/\00|FRQ:(i}PgD pCm jNxsz|s0 aӱ)G&v~|NOX ff?N 3j8SU(Vt;@&9HXqa1"2+CE`-@I2pxahP%9׬|PP8Z# ~~eW2|{F".xB'N3OL}55L.reզMxsVn#-ֵi!O~8DZƣǬ$:UM$ğ iziC>@qH,&8(@7fP5**?ȉ!^8("фA!DTib"RUV_0;́"g+`0,M·c=#?^#˦<˕W^NL(i᰿ދ.r[w=455׸`w1Dfv*@ @@SSl6W^`MS` ͫ[[C] LS.Q q@ cd<q V"JdYdr+ylR:?v^@, "D2aJKKѧoi4VS57)++իO@=zhEj 7SiK"I" 2&PRޞo p8P;vNy̙3.ti0  NNDkjjt_id$+Qd{53:JJf,_::vtęL0KKZ[[XcYBMUU՗^?² ˲PUUU57,S\\\\\ 5G"ӊ/tissS(4EQ}ϲL,8jG͛wKcϳ|A p: а}XQƟ=4qs S5w~L1aalr 5eϱ/#9̄ж 'd1)dc+æ#ZES‡\4gA23C9Sd?4>?x`kk~Kѣυ~s.`Ly 2,OQT*QUUSPdh֢Q DR*ưEsm,b@sl4r܊=-ԃ(b~pv͎;< mi 9LE]ЃW8F; ۅ.f޿y]zx<DX?9ciӊM+i =}}E4x=HPTUU4MEEMM"d_3p_x"_,s\D(ia68^~C }v3qs r9БgFФP NfXL6(EMuq\,ಢrJ*߄9ˈT,*dt6TQd1UU62j x ɸ`CL<%YArAL;Z.pakʡUjSvOԍ/^IJhE Sqsfl"K880x\s gzܧp'z~|LcŜW Ɂn7*(04iU/Ghp<x 9a}?˿ Zو92%!߈hsg ,bam4i&!1EˊY&XLV;iQ^OEDQ昝vڗ9cUQ K̡8ɤYY$."GeSEM6LqtOO5}qIJrƛmTXb'hX f 6ɊL4tbb@n[`KoAdT 6Gf2*%ɫUWqUI{"лVMU9XKt%[1DR\.?'ÎvL9ȅeYnjjv8Pߠ5(ǚ -vLcES`-5a͝EfVCp'@sX J 3!*4BpjaÆK.7p8P3DF7oBQ`KG PAIX2+@LD㑮x<&{GZhMý??C"mL8ajZ2pJ!3^F[i;s_#O^pB''Ͱ'[ jkkko}}={655n)mnO]z?}}a /{Q>޽{(}pѵi[ؽݚ7EQ=T*W~~}y?֪bb}2Ȼm7{-8{ @yȣ> j4UyoUد?׮jq-">'ߵIx }ŋAbwa ͝QO> 瞯|+tRԦ[ 7ܠɬ/,,UV}*..~6o êghO5-#D6pyEX>ܘ{ck tӺ8qZS5*92 9GŠ>4 ~VpOU=)KnOooog17b<PNiKHqb65ioƳ''g d=h4dEDx1H ZbIJ,?}X8@S[ r 9,Ipzzz~[riK/-YAe:a׿/>S]v/8+DN3(hlcB_zU.ͼv{ot R4! TCQQjbXLAAк3("=9we(* ,Kk #&U2x<aY6}zEQEA0<e}S4=>?>pؕauk |h''|cxU5:K8Z2p4zat _t9׬|PPn(F&"B<{9ܺu%\=C=3<W7zիW-Y"UVZ5Q~C[b" ݬ`7+}`I簒A@.)Px>H nD4#&cE玟UFk~xFF-Ы&fLnTT)~Jȑ~ڵ׽NVZ%m)OMq`sL$\ßMID SN4uDőh*Y`шkvP0-j>cY;rʕ+Wͻ }x7v~uBd4S@׿/{yC yE C@Y%n1+܍-be>1,/$í__鉅~ed-z)+)tb]> |ub''dl4 y1!@NbI1S)QRgP Ad1? 8DsA,MMMp8@|{j̈ܩ*,&f;81e83Y6F d*Bݲ{fbs+[1PJ,"M=V\MiE$x<@,s )Hfx`sdG_斓3!mƩ^?Pf''`˛9k1q`{;YPeU22(pR,A9+)--EnM.TdP,KwwwyYdSK+*ei,Hp\L<ga@f`sV%ap`PEӑɗs}՜p: ر3繾^@b< LǃÁ@ ;+㮮_f@N3M.kaHbt"3ٸhDwrn>/k`>nzG2=pc}:? >?'V;JT ðIfhZURPˬZD1)Ge2?'@l.83YOF{.1-s;W 4 RDUd%~~ѡ݂5"gGPVYdYVUAUQ\.j*bY8axh.9&P%95&14( xf ׸xY9!/w|dZ%j`7o.NP}!4x}<:NMQg4 ,ztGX]=>2N|x>ifEn^>̛`@C$-y }e G*:K7}oroXY=5 .Xp<ϝ̵eM|v78~N$\ß[˙ZRt^j&I#˧6ڔ `o'@fEIq*E3PB"D5" yh3qY\wjV}96BF@h2oBiS'xY3X\VV KOO9|P&37C/ɼE4árRj@J`-|R!Tݵ@o#/h@ /1*/A * "SIuU#6m灮}2i"Za헁Mޭ6 CuVW}}="LaryLpRPшgGRϖ^7 I 9?/8nk Gp&!Dp +t C@ml=^1*{qUyH>l,xRoWUTR]g(]xǴA"Rg!ng^E)z!כ-x|Y{Ywd\JlL׳CmӦ ر2OrL$'^"D&޺5D% _%ӭ`͉)Ǜ,44,)`)ޣ+Tp1}Z-zkk=ng߾1H+'I55n+(J"!L3ۅ Q(ؗI뇴q~"9h2 Cz-: f֭;jkk%\?r+#͟gw 7? >?Ix~%sAS MCfdS)ܩx,8P@XKRCs*qJyP\Uh²< s`Uל)J; u %OoE3KL<wUhdBDpE;I슇ʾ& {(@qG}!E6@yuõI?>[6MwOOI_͚i4B_]^8K@!Diw\,-k0@SfXB\AIdQHdd /ҴGoommM֯K$UMLD;00S\ٻ_Sjzʕ_vtt[w̥9^GqQ5__NmhHBnw!4#X[=FZkU]Cd@˔Onk50`Y)Q? j| 3 &>ހClSUU]UU gO%Oy  W^^ȳL5Y]4ji߳b5<<hi""D&-KO]/<-=xe[/b"2Pl`s6)@Nb0)&KoLJŀ8uh1:~ۇ(EZ /\04dԫdQ_WoWa~ 볱44lkU׬iv{L%Y㯽~~,X8aFX(݉>ׯ]7~p*F$q6t̘>*dt6TQd1UU62j PQHܥx <#]ٝ%WVC /\zjۛ#d HүO%O|Ixv"JD) R9je{p8,i={8 c刺X64USCe,,yGs&y4῎(/ا""(osNEQXcD @z2 e`i>>S?tаe '|O,y^j20bP<8 >} # "gA#H$Q"޾X,&p,"-!1a #] KF^_O ?9eBD"1C/Q=|(L裏w\˗/GQ+Xȑ#'l &rq+W.//+٬4C mY+V\ⳟS)dzo$1CWY $˧Kf;}`sXs,qݞjjԸڿ~}-44lw: BA<ׯ>^s˲o}%//7x,k uO[G}iP#|ޯ~xvPkş)uߗ/3ۋvP޻ׂc'w-~2Ձ=(3JKbgMӾx>C5xw}˗{ނ, ]?%Kd2Y__;7r-z{^F]t#<2{lxg~龾>n`[o|O>ptMw}70Hd޼y?~H$2s-[̘1cs9%1oiS[6ھ}TUݻw}7zWvlz^[(̮TS jG䕛@T쉒ߪ68+KixNVOy(}p:gϜYpwt6Z֐E`|S 1)^Vz? lKOD__2>g?`'!}̯v ՑR(xڛ} fb5o{Ç_GY{썍+W|/̾p ?OE{hկ~W]uUww>;۷?_N<_?ڵk۷aÆzjz;3Jۿ[AAO~z󵴴\y啯㍍/bUUU_̙˖-kjj[u]]v˖-,~TUu˖-#kX"SXFI%4L`ZN ' HR6;x(2x*zCyE@s)* 6&U#ι4g@(P\ivK &fhf]şLTEbWeZoH㓖q_m ğ"/g[o}zӖ? tuwE+駼?P[o}}C҅ڣ6[~Cg?3H(zz!p86o?'M7ݴ`a/Ϛ5kh\%Kp owя~T\\qwÇ,i<00`X/^ٟ^{-??{8ݸq#˲jժ>hsuM Fj@{[#?ak Pia&WLUў|k(~tʹK[ d=V\v]Y\3 P *35>8 =BQ8-ޯb65w*㣗c[ZBMMAThFNȧ/LTn#[3}ܩ?iD__O T4)//FN?M?/j#iG}~"EQ~_?|饗TUݷo~/~ӕ^6R˲,755۩TB1yyy`z꾾m۶I|ɛoy\ECD /xɱc==ݍ~߷o߾}Ǐ˲jm޴Ym_אg5UƫL:KWęP0NV)A%aIx[6wcKQ1>1,/X"FmW]uH_5#ff>KZ? =Nzy}U:K?X ı zniΚbrʝ;w677]λ`O2 lٲ+V8N[n?_W>,21u]oΟ?ƍ25p[lq\7pCUUժU?PJ~/Zh[l/ yx^ r-_җկӲJ IDAT@Vkxڴu־k텅<(ImmmK/Yz R BpȲDxT5iMJOSn=3f9@Nέ:YEz$yԻ9sTTM&ӈ*3J3!to ~ + P<U?ӆ?5_r}$T,t bZZ2sD|Yc$+//nit//:'ok؏sdrM\Vfy^yo}Eceooo\Da/:'msΝ7wn42?=x%:0p,YzM_Zp{ldi<|hK/b9Βϲ qQ3PlQofXD:7=B"K'__[q:ӯbp8a(L a^KCBYQyc ^Ng!DNN:e@MMM8+㮮<]qzӅ?ח̟S5w~L1a&"9ކ偲肋|ȳ3j2Mdi::/Ynx__įC9Sd?4>?˜Mz[bw޹yq]Y6V4)96uD(M6P \#oJF{$Yx[oUO /3 ' JjXe9},~u 68#k੉?ToF)r{O S gK vsgY$C-n֙ --]X LZ9'M$?rpA@3*s. *0iCiK]A`P ")9ܸMCPDm wclgjkksd4]fpg"D&}!IOr}}w tO\3⤻+w6<dz66EȹNp_UU{S5V@s^%Y$'f$Uqft20xf cxY9!/w|@Tqcӧ677,TNOi ڵLG=|.|N75=MH)=?˚,4O\3do ʄJD.(Yc93pee%lC͘>smukxf86PPR~hR0K_:"Y,$r$O3+tg$XPujEQaJ8K_#i)9>"'9㾾)?]}}9'*'8w J. ;LYNyGϘ>]U/ jFYlL.2[P;YhưPJi8D fVDw_m-I*tO\3x~vkKKjRz!(`&,"gP˖aw3cEQ%Lȷ3,sYffPr+v 1^1s~#q#9} !} SR?McֆQr%ki!wCTMO4 P.QNzwnk?$wo]# /?gS^?,Zq +>jʭ݉> 'm4'Hl$nB!|!)?m}_nAYQdIeYUUUEq\TeY8fL\;ibmebAgxQxR1ET $*F 'h>@4}Zmz·cΔYAuӦzC=z;1 &Yd?WXŸ*/g>Lu-a6T!DH䬔1a8AAYm p‚|b1d2 Z2)bR*8xT*D) Ƃ].Z} ]M^Q̩hjYmgkw?ӈ?E_r}$T .+Ca #tC2H"D\ 04@)s+@ԅn0<ӭR*nWRqfO*rBlcGo]WfA>^5 mӝY'9}} >'Sro<`q@/Dn[eb5}=!D੕Wv"QK< K88hNL H>ޜ*hxh*n9fOs6լR[fe5tٞGaGoʊGp5'9㾾z{ŸKه#H!)AӐ}!T %wj ^PhTeY.r4Mm='q7WW̓*?!g[Of`FnPpAtoA ll$)G5H7iغA/)yOEO'D__2R|"D`W6qEcĤie0hJvcT" 炿{iS=Iϐ /}3wƓ# ņx㮯o(XߎxBW$(FctO%v? Q"oWzrvMC!S#HUY1V^2DSG5>h*ZeTEү2-G#مJ5ȰR[=lidUwCV5}xDn38L(XψrՎxkO~}}%K?{̚EnϘ!B4'yQ =Jb,4vf؆PEA@bb ӌ HLbOk 'GI| Xo7d E4DFT @f0, 7sb |UfAUɘJLDzTUf1 Y?5t|2a!'s,РVZA3WRn:-=h<|hKߑ mRe1WfUi@ń(10IJ~ +'gy5 ?W^\ 'Z5w~L1aa3moG@YtEoxX'n'g*p8¬FALp< z)"@sZ~%J[` 6&iUIANZD1)GeqL9N3"Av|O >:x%J/kV|̏(S%>A)GX 6:4cBíڤ%G;)jȡD%_Q*ftIR|޺5tCNJ?9Q>_Ιu cC06+77A"gL<*7I TQd1UU62j x ɸ`CL<%Y"|O>@M@[E4#"JQ(`ȣ W|O >bf_8P,bH/O&0pO0Ekʕ+NJ-+.xָfڽvZ[i_)x=x޺5])޺5`&n Pwy?NV|֭Ad٧|wC*mV{ C7PV}_l/n @y^ 'vPg> $̟)ZrqAlŵs?\8l(L<_r_s5?{oGyzZdmrk &YLX8C3dc $o&L&'3gd&$ 0Fƀ1 %,kiٲ}muwOTԒKsNuuէ >{{|[[}1d25>11obU9wH͉}}}{ߺ[eWMM{%q9cz4???UUU.R>:L&H m;='{+*(V:/G+CK QFX)!@ypDXNPxI*٘Vf22J(7|#W%iWkGeq}Os7 TVV?ܵk믿L&KJJ//~;}}{o&lٲ?E{[nq[[[#ȷ}k]]]W~0o<HwcǎT*r|;p=:thhh|;G{`y׾k <1ko~3<<9yx<#̋1ҩ)-sY I/ǯ) +\h?5ՠF re хPx 9|#wO/(X]]А[DƟ/<ݛs{uݚ+WKmmm7|ٶmgy8?O<w}G/涶9rG?O~rA0_^>zC-YcW/W_}Gҗ'6mаw޽{S[o;300 `߸b7Gvni6k^0 mjfMKg5F޵6~s,#ȿj{/IoGGWGo@}۷{dCCC̾znao/Y䳟lAA!䮻; wy'_'N۷_W,YBY~U{Xf>P(iӦt:~v…Hdƍm۶}-**k_ZwwcJooݺuNkXX  /+tz[Ni7{Y|O~_WEQO<_jttR:66V[[ gihhxgn2u{{{wm:^|yv??;r %%%GEQRp`N18Y,YAI~|([e !=5!HaQ GUŦ?(dS:㢐_C2Α,_|'xgv]ںu__q{9 AOѱc9s~nZD3.{cy"3&&'R.8 6`j)*-F{I('mKӊ^[[$L^i%ZಓcN<A>*oιuϯ#Gٳzauu˿򕯤R)?mw`e˖q U^^~~[VV699gϞϱ~w}렮V@sxdĶq&&Ok?x#o'݃Ct1nZ8zًpbXJJ'캓PD E hb!*8.r3Q|#w%/Yg>xܻmܸqҥ7nO~r~OW_ݸq(fM/|_|G,Yr7o޼_q.uֽ+ǝO~뮻4MpF ৏m;wÔX,͋cyyQ]u]fYQURd2^O)/r0aͫ- eI2"5kuT[uG>j~z˿"07'{4Q9)O=Ԝ#(KzOC=C͊q>}ss dhO}Sԧ}UUo|ߘs*%븇BN͛ wt]wdd޾Sp~,?ṁ`Qܶ#p- (.řFU.9\ls!4N#ȿ*}WoKPG_qs&zN{ C8hʕ`@OOωox,ˏ+(*,ZI"S#fz (/kQB9E-F0dÄ )&(H#ȿ|H`u`o֧aaա\[ouӃ6~bv}9ו BZ#^qK>㒑9y~FsB?ЯAVPY-[Cs{]rkLe=UJfs n}B@DԐ|#j*]Y7. 7d}/?WJ5||g3*E5Ç,crKLtNw]Ͷe GU؟߲4ܺЧ{~wT}3F #O$NBEkkj3bKC1C38oe,#X&2h@G>'3O s F>? 5bN/ >nAr痔@UUM9q]d~qTcFLv̲2GH[F{0-EPXDwܭLSK"|#oDW7;x,B3(:並,]w=6>>>::zXÇ,YF>Ľy9HEȫ!H[FFk+&2aSKZȓD0{`B>|uey${̭sƼN_k2}-]Aql˲m1VSS'ca<4<Ϯ\{S@4 Cjvkߠ7V"@w4^^vFeU@D`6|_|P~ѧ71*y;<y۶^eRJ !<)!glxx/Է\P(H|0MX)sO%p `!^t1@.|_#3W$"+w?P2 ^`kjڅE #Z?7>"˼5ẖrdb0+Bm`|_| s%/xJ~3‚7u7-3nt19x:sW$mj6%Haʋ|eG>UQtÕPf*~z>ղ3X_g;^X cNhL48(vD̶D%%ܳ\^Z]8u>K K}Br'y L$ۦƋ.;Cyfͬ%L-5ʘ 2|_Y%]>/ހiL4]gl"-;p lX_]۲3-; w5]ƻMRo R -6mU-#m2LllK-+I08 ,xQVPD/yeU KJG>Z#^q;ӛw꩖իiyN y^ p\ G^] ``oheήX>޺{Z^jrlCÿQp ަ^l~AWn^W@Ijb0ǀ)M^1MN l=P cP}A>|i@oJoǛCJ cZ[$7706]=pq;@0>zEw澃?~:yKgyd#g> irSGsbNHɛcvD>ߴy[#^Y-/^T:o}[׸3;4JwR'fo_\eyZA?HKf`BxQV",ئg&| 4_nd&M=#E#$mF }+|#"Fs_ -;]=o3 7IߤҎ{qKmVS,lyKlC-O>EC1Edio? x_󳦖Lg&TpkZ[ /EU`D$|*[J1=`JTcFj2G>8E mLxG;^`5-Wxw"CK%X2uhyuh{>k4q-gyd2#(Z5'_alV۩skJrNٙQ1A  G>"' fS72橴DÝ ' ޳ԫ}; b۽im|!*QkgQ3y#*s Ph{guE $.b^xB]p gY(#ȿM?z{,E(ۿ`Llu*9w_SH!+hb^5̭;Ӹn 8wζw ]i6PAVA4TevX> rB8eLR4<삼EG>/nhxځZxǛC3<͡Z 6/;Ngt|})ATe, ]`˳Xۗ}ckW"vXj1ٺYV+M?غ{=7n6{2~G-{t]Uizb֮^  G>6ooz6o;|ghڼ}ΛYzO+=ȵɎ;֮^ 7?}vݲHv\ 7u-%%^}z2hJW[ܱw>DhizddzG8{^`[wdq<㱖;, ,tLvɋuYR T`EʙĜ駟 Ph8﹯o'U|d: Y}{H))gSϳgAtб6Wg( RxKXiG>/^hx>𳞇o߻v=^Zo]wJ߆2"z({֯)&.^wn/?ғ|&K)Wh8(9ʇ$52JR$(OV *ЙVf22J(7|#kGsGAqz]=޷ wVF^x5^s?;0wp`+JRn-酉[NۿӺO\ MNߘ~ 198ax֖GѩiOtoO_IflZPC#;N'@%v%2̅ξ򼜉P_^kK[2+G>o^DGp^l,Mǽe"pG=}n+ )yP|c˓Omh%pk47&7A8[qq6_-) ̝Q]%H.+\\.[Qe4|C E_uk'h*J*Ԉj#[wxsW{^`Eqsx**/,6NSϼϼq/޸]؍o=xɾAf&̆ ;YuCU^GY^GSX6p.I+3I/,ʖhbL RX#@#G~@[K.^h7r@ww Z~Ιޫjٕ4 7]-tlkA`m듿hh[h Ebt|АKHâ-zzG?_x(1q{\M\כNW7p[b2mbbjχ#855ѣt6axddɌm}ty]˲.]Z\\|n*9mj1RTs[OPO081bW5^HIV.;9c#G~yFП`LN x}乀yz֯)޾2.0c wUrS's~Ȝs}E2;Cia{s! u$v?awLNNqĉn馉 VVrήoprr‡Osϭ8APxgVz,c!QNP(ؼJj(OTGP)3]~܂|#&̖^@/o] 5:u cyb{b잛c.ǶXawOWO/쬮.eVd}ּ({y'¼$S-vmaXw Lza$h~x_X6I\;7cׂr̞#8>>o~]VZ?GVXQQQ4J&`*ڷ^Xo)u37|YO'9#!xIleUCO. rD*YG|#_A7pԵX7mc׶Bc}[v&u ggY}cy.7w6Z]8JyPW808}K37s Sn]M<d[ +++e%HN:%IkkoJ}rг!~Ё%8S4udgx˾#G~@pvP۴k^ GRn˄sb/?啎T=t?U%ap;ٽ#[c}cu6]y01q01/jAJvPt<Z%%JK痛]=Zjq^/zCuEHϳ$VoG7_V^4U\s ī1Ƕu!5m1yQVEYp mr@$O2_&1AP!QVmjG>/MlaJegxc}X\{hٙ8?Һ[#bYWx^WAegA3Crb o5gyb F;}K_Xb(//^d=טl{P(h,\]bFLwzneve\mhegˬ洼=rԺg ̘˜ʜuE.-gY5BccU>u_[ .|w}&3O ٙq"@eTCPP7tb@3#Uٶ #G~@[q/4x|eg2Nv{[ IHݾxc}ܶtL ^~Yf-iy膻xɪl^`%] *Њo^^G~RٟFf$p4̷23& @3XlSK5:G>[r.#ʶOxӁ w.ΖrVk{cwU(ᙹ{ -;>2jX9gWuMS{ߘ+d2ҖLKb!9s,[ e[˖0@>|1mx߾o] Zv&̤e1[_M)7|c)SO_Sܲ3U^7-ec}!T+61-T<2{9y\#99sW {[FFVMxOpk#O234ŝpxy{10p.q5"ȭz$wd]6UEH +G([>&M/D rR+pES Q̪whKVf+yp-F|#H wx[ׯ)n,`Ý vbbByJy5?L@otgᖝU+˳l߮#!Y16PAV_2G0H1͋Ԟ#hY&zj : ZFzƠ#k蛌f|#?(ZP]p^IS к'[:xǘ9񭯴{>"i{"׿/)rTSSnlzEf}(|)Z$)*䖹s ^Ug G>8E {o=!#|c}-eg lӲ32ۘr'U#{9-;-/(֪-Dɽgyd>#VKGGGGk?|%K25d"%Z4SYeA $ t9YI-B>|=A?oo'w!߸nImE Jބ_=u/.kxӮ$Ahb~yvAq(K.8}ԩSNZrR49_7P/1B-q¤35 >iڻ'M- ôXY>veZfr2̱r9G> /8nx?6zsߟ-^p7 /w~޵,{X;6}u?? pGsmDZ-˶m۶ b(:lE| ?%65^p;Gcf3+)LmJŽebAUdG>_?ǘBі)A$I԰zuˮ_~}~~(,K nU-#m2$M-52:ؖn[Waq"0;;Qb!EDYE>|2 }0yIj8婪( tbsWW3ͫ("IQ^ Y#Ry4u;5pE@E3 mB}fjG>>(Tp:b&TWyUc 9٩Awt]'XFznK#G~| Q EX1 ^1zQVi̢mql(K(Ff3R4YLrfnܷbG>0:B]ɡ gM-=?L24^2(JBIHBa?&T(E烓]tҟX4|#?P|zQ((3_ aڅ9?9L5%y'ʋ̨˘VG> #8GUf8I],ZŘ "&HᲹβPG>ABU~2^G,v1e\RcJEL|y"0 ʵbG>Q(TPD,Xmzrھ?[& 5m޶{Uo֝~gͲ2^)l;}HuS״߼9?jscHw=vb_@>|-%%RBgbTY+VЎB<>O?pbs_0OtAs:J9RT`~BO>ڟ!s^6Wg( RxKXiG>14B$4CK QFX)@n GO'+e(џFQ+3j%Z4sG>֎rtQ(tg9 TblWi+\웬-ˉiOZ[Z+#GW G0E6o6ecP9s,6?5zR nMKg /gwyZ1XG>Q(eW`V _ -L1S#PCRT!8A尗, d.0KcV92ҎkSG>`Q(Tpj8:wŲUJuIRXI xxdeQT=D4@CffJ¢" G>^a* s,L&R)V-Z5QlfضU 9 IDATSKQAmy>5KB>lĈ]]Vz"'YFZE|#PxUUUZQJJJ ~VG (y<3+=1ݐ('(l^R%5V'S^*ek=R>0;M?nA>|bAR,uiF0ΔKnݺC4KS}S4^Ba3+WZJO˒Ifyeڠ73`볎 G>GPW#wz#1˴L gy(ذc/z-uNɑBRrA\Lx#t*a.@6a\M G>^(%և%B3vH YPH7 [\ ;GlA0S@E x\)Bl1V&&LѷM0!<DA G>(ǁ ί|,+c2B tLDMyF x^yAUQVCЦF3aW?IjLD!tHU B&9b|#?8|zQfeEsddxxrr;26:FWRR򾙿3r 1 "fVQ(+"Xy^"pα2/wAmSC>|F(TPt~9(7M zOdIضՕXX u.9~ hΌ{G* 4|" ={D-a39j#t5ۖ|#>sQK #(AB7D·~{MEAW=#F4ī3/:󭌣V2ҎeR/V,Ԓ@W3|#?X|pp`F $Yc… /^\^^swyGDB36bxe?ZF2݃i)Z,‚ z]/n'fZ|#B] !( HTXX8  E"Ⲳ2YEQ o3y3dipme9XD&9lj)SKq`y231f̱VG>qE7Rd>gcʶm َ֯4;Ƚpxd7G+7E/"To>nBHLm&D92U6a/YQ-J8^A>|#y#B]J%G\{mh}ᅉႂyX+l *1(Df18njo2^^pڋ G>>FSh8V~oS+g7="3mLrXUI r-rl!\+,偣CE>|BsZ5hѢm^NE~s]SK.,"T_xitƚ3(̱rdb0+B95|#BC>3%w7-? 1'`Ih3y)IئfjSHhX|#Ca PRɉ _S]}^+K`g`:%65^pʋpm53VlfuIM-5ʘ 2|#?(|BD]V^VPQQr˗_|+VPVVP>kմyTm=rʌZFګ;0mzdu-ݶt$D`60+EY+B)\AU)/)Q#G~p8PW#(u-=zC&''''';v*n^W@Ijb0ǘb+۩3*!Tpl3S#G>qE#h6s0y[UJvI()%uW UrS7PNHɛbvD>|cPK #h;m۶m3ƪ PY9iy%Gs,‹J 3:I(, ISHшge2aтrߊ!G>0 u%yJEQdYHDe-[Vp8,IR(:///YSKuA*5 󄗌"ʪRPR"@PX ?%J?% #5bi#G~8P\5L!@z%5V@v5fiUSd3ה,*/3.c^A>|f?(TPs/frbT#B]b}sL̇9+x 8[PU~rI)k%.3dL9{#G~P(*( ,6=ecm_~쟎]U6o۽c 7e_fY6`ܾ ێ$ko^9бvU p[z1p/ G>?GjCJpt:ˀ|JQ9:|駟vN{I2Hcn^'R)G J̏SqqY ypX^I $Hp,/aG#G>߲0 pPrIj,1dF9GUcI*GP]Y5<%pķ2-LR4B IQPlSU^J 46t,YX~KH;Mf#G>GPQ0Bë]0hyj<^F`V+]%IRCR`e& 0ET-A )A r|#k{ QQ>fy{a(slHG$ئ2ʋ3csNX HJ+yQ6XR8&J VG>>A.R>&`sϭ8APxgVz,c!QNP(ؼJj(OTG&X$lq |#? A* ` r-}JO'Ǒ $L*u]ET E9"r #G>Q(U r#p- (.řFU.9\lŠKA>|QK AOqsmmSw'!-F0N.!f.G(mt,u$8A|#;0 u)pmC!x^eUU!&LrO*eQm eIئ|#Ge*8q.s95A* e%Z CW3ϋ@9VN>^;# mjG> #맀̸wJ@s*!(>{ §[Uٶ #G~@[q#B]J%G03=#F4ī338oe,#X&2hŲM- t5#G>f* Dߘ+d2ҖLKb!zw>1+a|#B#x{99sW =C VMdæ27Ƒ'3>ak|# ^*8 Ff_By@7{7r!W6eiU*0̨%Z/ G><D.is~%z=5TIQ-#=cPbqܜDdY|#?(|,(B F'^df-їI*1AΗEBn{*eos ^Ug G>8> 25d"%ZDMFDr5qgPB/ 0B95|#BC oZx~7ώ,z{F%q^fJڔ )/9m#G>PC(ԥTX^;)ɶ,P^k2f3knI*SK`2f*|# 80PQ`z Wm=rʌZFګ;0mzdu-ݶt$D`60P!{(+yB("嗋<*%%|#^  Dp󪼲JHRcC%9Ƭc^1MN l=P cP}A>|C/  t0c6"АWJRcW@BpvjfJ\ )yZNG>| uAς80XF^Uyczj10 ʪ4xV&-(|#? |P_󳦖Lg&TpkZ[ /EU`D$|*[J1=`JTcFj2G>@qEJjj9jTʾ2d3ה,*/3.cJX!G>_*( R\USLG;+bX&Ivhc6"^8B!G>/?sQK5Te^Yb$*?Ɣ5RlD`kŐ|#P.Xڏ}:7vUM,jڼm3 ;ΚeeR􃭻ws**Ho;^;:i y)sԲ@U5'~{lk|# p[KJ(Dߩ^ (Wġy|~o'ľ羾aT d1u"r 8}? B\`U除 J^V~<|#? -y P %G0=1@CFisQ5V b8A;,Q pʌZFF@>|A Y`/Xf(ەh0:&krbӯ֖k G>o#B L6ecP9s,6?5zR nMKg /gwyZ1XG>Q(eW`V _ -L1S#PCRT!8A尗, d.0KcV92ҎkSG>`Q(Tpj8:wŲUJuIRXI xxdeQT=D4@CffJ¢" G>^a* @Y^A^;2:麌oeF{mF̘Ü#V+< ca^9 !RwƢDD>|cPK #skl#D<˘nH 6/+ʓ)/Ѳ E|`w0 y~܂|#p?EG #AKS$q$/ `q]EABQ@Ept\3>|#?| uykHg)\KB9B Kxqli: a0 e.ҦF|#ca+9*CDSc\fq] .sqdK$J}dd&t]F 8Ne#G~@E14B]J=4ܴyghPDYeh1mj4)}%J~ABaoHDY"d#!G>Q @܅\Npl6BY"#txӭΈh|#?87pE@~)!;3R,\A0| Ϟ="gfFj-G>}PRg Č`ψ/ jl q4̷2[H;I3ZlSK]G>` #7fld7,+3eRXA^zݪO4J G>GP{y9HEȫ`=C-waQ\kf, wAT $R,J1&6Qȍ1Fc4X7Es5hT@-*vDTEQ)q);;s\A~><3g9gv89#ص왢RJ\V1+3hZ Έ(5@}G}G}mohǻ՟%.HJZtNpE2_WTmF%p i1Z[&"G}G}mGAF#%FRDJ%eBVJ 9Ah<}$q4T [_F}G}G}mo yU#F+n}$-- <}cPԧ2j2, @CW@ >>k> ZVF.+u5&9<#P/kf+ZPer:XG1h>>k <~X7cy[hEhxTW)W,PK ~\!r@\&8\>Q(( QQD?J;U5'QA 0P ]IxF&ATeK2%qv@I9\>;YeH.МJ.+) uuQQQ_[f\if*X̙3xGGA+`7(04;(sGPᓴhEUuH^;])W^G}G}}nϊ GSYE߉{'nf]2 }UԖ8zb($Ř+˟Sk8|$􁼼QQGo5!Z>#kO[Pti"9|谓W W@(ʟ˹F#4֯BMǰ}J%MݫH$bC>pRRb>Aw-Od--# B`|]=c ?/)R=4jJD\*}CKU-Z`Y`˗-۱cH"yzzo#-hMj\V~IEUСchF^)y'O.+g@(HN;]HS} }SPYrتHQYZ_׽655}X_ww˗5xa04a5ЖAEVȪ&z1tJC+z";X;4 M+D}G}G}?UPǍ@ ظqcDdի?15XXE3x+H )=hQAM*ާF'+1(r4wi B<4wVC>>ׯ ;ST*}nxhhX[~k˵+` B^1nA#Re\(ۙTň5* BZ.^= r:{G}G}zDk(hy Ȉ&RеW;5??m_e& -8yrp@14F|QeC:5\qd,5>>ꣾ6KL&&:;_uurᰰ5}5dHPyE4:ɓ>w?hԁ&&&H V;M6܄*c B @A<.S?ŋ< EAj>p^CQI$2V&2zn@ѵ/.r̓>HO?{ȡ>M.??W^r9~_O&ry`*cIDAT|#G*r}}SVY{=X<.|쨑.\XRO@P[lE3 cfjb2''Gn[$Amʕ_P(jM@+ ߽{* k?59uƌ2(HD"ֿ]v-*,ӧo耀{n?_keemcc;`@FVُB4v%46?>~BC{߮^C}3@sgOoۚFĭ[&M"2bS'׭]aχ^cjjz@)=w_fyΞN_jCí .Amaop^vǠV6%*1GoڴI&}<~|tL̊}O:uQU{O333x |y\V5:5ݪW0CON>֡C-[LƎ3וOZ;_ުy\qd.]%xx<HO믾=_WW;tfnnnnn~>tHРAͭ))\>- ^h:tR4ɛ"g[% -0er dM&1PtUkX#"y~;| 1!+W`>}jOƏgݒF̞f͚lOOOx~5accc2d>DGG';;ѣG} oyQD "?aaal d!JJJz{{}3sC~[٪rښR#8w߭ldT:xofË`#ۻzό,M :uKAZL5'ҊsgOuhm,’>y[n*DdEEjYyytt*R#J`;t0buuP^^njjk%Kzy{?䓯M yYM#fCUac+KK++ FF|!&,Y2{NԮYZZ:99Dk䐤1c?x/ӆ_ONj`SqB@@0J ͔=Z!p h? 3@^&gϜzM#mHN $ $.B/W.\s###07`#j8Ao2CD'DaΞ=ҹsZKABɗH{ǐA]fw""& ‚7o=w@Y/s8$njާo?__ ܹS!ӭiI?eep@Z׮],,,Ć./^hb{GGR4bvx%(iJv\ H5,NNN(!HAIÆ-\0>.~ԩzzzl$H _@݅]}왭qcظqD"! wQо}{3S3.rUxꓼ_Dm[,]T*577`p??ߧOFG<.'K.7j9sqttAxt4t_?R~׮-/-- ҤI8.`S*)v/WbVh5#vyٕ+Wjᐜ@ A%0P o͛׹KTjiiX/Q} yQ'Fxy{ =kkkAu۶3gR%g̜SW)zUGW׼{9[|ivyݪv6߯_{hpphppM>^}}%Kw3/i4n4ݕKe{(jՄnܽ#k]hvO H+yU}]xWXh `゗/6vtpܶuFCR}Kƅ ꫎;Z]]uP%R`3Ҷ` µKJQ J#^ a!j.4sՉNAVajuԔzM{ $ eSJwH6˫?pv\&5T(˛}5+AZ:֬]n ޔj<}EiF_>;YX)H99|ӣ"8jAb_NшQۃ."]@aswv=S-.$ID.F`dԡc[#ZՉaAZl~^kC zbKS{>~jlh`bbjbbWg7Ͽstpٍm ? HVx="Zk1ʼ~3<~޿;v&$Zi{ԅkz5-~K{2qU )wl?m^\eQP(r>"XZYUVVDAP(Ν;3tXkGV_^Qd.?gFK AACO}իWwQS)S <8$$$77XVVtj1̚UPPpY;wQ;}QsOȺo [n+#G jkkߝى0̱52rU-Ν;G=iӦٳ-\bO#? Ainbĉ4;wn̙3f̳gtر޵kbccg͚u}'H>ÄvŋǏommʍY!fffB㋊.U(:;;GG?~M#FE}2aBDddw[hQjjj=Hh( ѭGYd2H$F7n8p^ޡa X7n.XУGO&L\?˻].]cbb L3w*͖-[{6ئԣgMP3'NUr::::::<t|vpʥohhUWAAaÆYYYilOJJӛ>}:߿?$''$9c H4hРA%&&j웗l`zzzNNθqEk N:5&&ߜ:tȞ=.[lLLFƅM'm۶_~?x]/Ɔ%"G=mꗷo%%n^zMrr2F=pu6z T.A*vZewH#++T;ڵ+]77 Ϝ9VQQrKi߾}\\\lliӦ_^,Tj465US;|P||\\||zzzi1Rw׻w/ժP(rrJ ˝3{@ 044;g]S¶ |ҥW:hHHA'L8qO,ʕ+G7p:v1qNjlMq5zʅ  ZEYYj.T44hPCBB.^8wѣGÇ'%MR(5?QQs̙=_~ׯ_tOR- wϾu];͉AO5뿃Q# |rMگ_Z@AA嫽F;O>ͮ4MdEEjdh.x[ ֮fnzע˅  MH$*--UJ$6|,TKKK}! AfbϜ9sƍEW^^^={tuumL6hi֯IHXaF\^ZZdIɓJ&`qqŋF.\…5aש+wCc xqJqIQתͩb I6>տ23njj\ܺ%~tsm_?I2Ťמ0q|v mfai5J=*Ai;l߾!""BT:88888ײe͛Ծ}{OJJ:|ܹskegd\t)22]]d󃂂oT̙;gO'L9Ugi?Mߧ־6zyWBAסh!kWg򦈌muS,mDszh88j7+=9((Z.Ay0|*"\kh?+qʕ!Cmۺ˅  H>~FPZ"~ 3\ H(T1tEa_պFAA A&l-WbCC~Śa # Ҳx{LKM ]==\Ay iZsgOP_aI͈pa4 tttu^ltm[<66u8N{֦5:jX+L  !:$&qEӴR.o\s w  uVE=a5  ehAAiS`  AAA- *IENDB`tiled-0.14.2/docs/manual/index.md000066400000000000000000000006251260670167100165460ustar00rootroot00000000000000# Tiled User Manual *This documentation is currently work-in-progress. Initially the relevant pages from the wiki have been ported over, providing a limited amount of documentation for specific Tiled features. Over time, this should become the place to refer to for any details about using Tiled.* ## Contents * [Using the Terrain Tool](using-the-terrain-tool.md) * [Using Commands](using-commands.md) tiled-0.14.2/docs/manual/using-commands.md000066400000000000000000000040301260670167100203550ustar00rootroot00000000000000# Using Commands The Command Button allows you to create and run shell commands (other programs) from Tiled. You may setup as many commands as you like. This is useful if you edit maps for multiple games and you want to set up a command for each game. Or you could setup multiple commands for the same game that load different checkpoints or configurations. ## The Command Button It is located on the main toolbar to the right of the redo button. Clicking on it will run the default command (the first command in the command list). Clicking the arrow next to it will bring down a menu that allows you to run any command you have set up, as well as an option to open the Edit Commands dialog. You can press F5 as a shortcut to clicking the button to run the default command. ## Editing Commands The 'Edit Commands' dialog contains a list of commands. Each command has several properties: * **Name**: The name of the command as it will be shown in the drop down list, so you can easily identify it. * **Command**: The actual shell command to execute. This probably starts with an executable program followed by arguments. + The token `%mapfile` is replaced with the current maps full path. + The token `%objecttype` is replaced with the type of the currently selected object, if any. (since Tiled 0.12) * **Enabled**: A quick way to disable commands and remove them from the drop down list. + The default command is the first enabled command. You can also change whether or not it should save the current map before running commands. ## Example Commands Launching a custom game called "mygame" with a -loadmap parameter and the mapfile: mygame -loadmap %mapfile On Mac, remember that Apps are folders, so you need to run the actual executable from within the `Contents/MacOS` folder: /Applications/TextEdit.app/Contents/MacOS/TextEdit %mapfile Some OS's also have a command to open files in the appropriate program: * OSX: `open %mapfile` * GNOME systems like Ubuntu: `gnome-open %mapfile` * FreeDesktop.org standard: `xdg-open %mapfile` tiled-0.14.2/docs/manual/using-the-terrain-tool.md000066400000000000000000000133611260670167100217600ustar00rootroot00000000000000# Using the Terrain Tool Starting with Tiled 0.9.0, a new tool was added specifically to make editing tile maps easier when using terrain transitions. There are of course multiple ways to do transitions between tiles. The Terrain tool in Tiled supports transition tiles that have a well-defined terrain type at each of their 4 corners, which seems to be the most common method. To demonstrate how to use this tool I will describe the steps necessary to reproduce the `desert.tmx` example map, which now also includes terrain information in its tileset. ## Create a New Map and Add a Tileset ## First of all create a new orthogonal map with a tile size of 32x32 pixels. ![Create Map Dialog](images/terraintool/01-newmap.png) Then, add the `tmw_desert_spacing.png` example tileset. This tileset uses a margin and spacing of 1 pixel (which is only to test if this functionality works, not because I'd recommend doing that). ![Add Tileset Dialog](images/terraintool/02-newtileset.png) This tileset has 4 different terrain types. Traditionally editing a map with these tiles meant that you had to carefully connect the right transitions to avoid broken edges. Now we will define the terrain information for this tileset, which the Terrain tool will use to automatically place the right transitions. ## Define the Terrain Information ## Click the small "Edit Terrain Information" button. ![Edit Terrain Information button](images/terraintool/03-editterrainbutton.png) This dialog displays the list of terrain types in the tileset and allows you to mark corners of the tiles in your tileset as belonging to a certain terrain type. To start with, add each of the 4 terrain types. The fastest way is by right-clicking on a tile representing a certain terrain and choosing "Add Terrain Type". This automatically sets the tile as the image representing the terrain. ![Edit Terrain Dialog](images/terraintool/04-editterraindialog-add.png) Give each of the terrains an appropriate name. Once you're done, select the sand terrain and mark all corners in the tileset with this type of terrain. When you're done it should look like this: ![Mark Sand Terrain](images/terraintool/05-editterraindialog-edit.png) If you make a mistake, just use Undo (or press `Ctrl+Z`). Or if you notice a mistake later, either use the eraser to clear a terrain type from a corner or select the correct terrain type and paint over it. Do the same for each of the other terrain types. Eventually you'll have marked all tiles apart from the special objects. ![Done Marking Terrain](images/terraintool/06-editterraindialog-done.png) Now close the dialog so we can start trying out the Terrain tool. ## Editing with the Terrain Tool ## Switch from the Tilesets to the Terrains window. You should see the 4 terrain types represented in a list. Click on the sand terrain and start painting. You may immediately notice that nothing special is happening. This is because there are no other tiles on the map yet so the terrain tool doesn't really know how to help (because we have no transitions to "nothing" in our tileset). Assuming we're out to create a desert map, it's better to start by filling your entire map with sand. Just switch back to the Tilesets window for a moment, select the sand tile and then use the Fill tool. Let's switch back to the Terrains window and draw some cobblestones. Now you can see the tool in action! ![Drawing Cobblestone](images/terraintool/07-drawing-cobblestone.png) Try holding `Control` (`command` on a Mac) while drawing. This reduces the modified area to just the closest corner to the mouse, allowing for precision work. Finally, see what happens when you try drawing some dirt on the cobblestone. Because there are no transitions from dirt directly to cobblestone, the Terrain tool first inserts transitions to sand and from there to cobblestone. Neat! ![Drawing Dirt](images/terraintool/08-drawing-dirt.png) ## Final Words ## Now you should have a pretty good idea about how to use this tool in your own project. A few things to keep in mind: * Currently the tool requires all terrain types to be part of the same tileset. You can have multiple tilesets with terrain in your map, but the tool can't perform automatic transitions from a terrain from one tileset to a terrain in another tileset. This usually means you may have to combine several tiles into one image. * Since defining the terrain information can be somewhat laboursome, you'll want to use the external tilesets feature of Tiled to share not only the image but also the terrain information among several maps. Note however, that it is not possible to edit the terrain information while the tileset is external. To work around this problem just temporarily import the tileset and then export it again. * The Terrain tool works fine with isometric maps as well (though not with the new "staggered" isometric maps). However, the Edit Terrain Information dialog is currently not able to render the overlay correctly for isometric tiles. When defining terrain for isometric tiles, imagine the top-left corner applies to the top of your isometric tile, the top-right corner applies to the right corner of your tile, etc. Check out the `isometric_grass_and_water.tmx` example when in doubt. * The tool will handle any number of terrain types and each corner of a tile can have a different type of terrain. Still, there are other ways of dealing with transitions that this tool can't handle. Also, it is not able to edit multiple layers at the same time. For a more flexible, but also more complicated way of automatic tile placement, check out [[Automapping]]. * I'm maintaining a [collection of tilesets](http://opengameart.org/content/terrain-transitions) that contain transitions that are compatible with this tool on [OpenGameArt.org](http://opengameart.org/). tiled-0.14.2/docs/map.dtd000066400000000000000000000063361260670167100151170ustar00rootroot00000000000000 tiled-0.14.2/docs/map.xsd000066400000000000000000000176171260670167100151460ustar00rootroot00000000000000 tiled-0.14.2/docs/reference/000077500000000000000000000000001260670167100155735ustar00rootroot00000000000000tiled-0.14.2/docs/reference/CC-BY-SA.png000066400000000000000000000117331260670167100174040ustar00rootroot00000000000000PNG  IHDRXc pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FIDATxZKl!2"v}JtuyJ,iSe-vԤ  rH([ڡ1&h0WjZmRpFP$J[awA;;wCq1 Ț !aq:X˲8,ˁcYyeY0 a0 0@':tHW]uD ! 0.qFbR:3Af0_XSdkNu]ځ~@8x]d2T*¬CQ;w>24˪ƀh,0XڦNs1{o, clQx uǖU^[TVFwSSSRvv삪i4j&Mjᕘ\1x^d2Pi‰ 6Ȳ ˅޾e)u 55/ӛ7WX-8 +#pid2IAd  ;b1xˊ b,s]L޾y^Z[kS 6Xw588$k>ӗ6eL5= %fz n0xy@%/ ȦK?sx0Uw2kWSo!SDA#>55kW &’JO$YHm{5?e?~%@PTl)LRpBm( ~?|>|>ut䭤%0M7). x]utR6>Znc0`Tp$( |>(PP~^8]%IB"@*2v6`%+T\,y,$5<'޾M5(k*dz䇗럜DwW0z{Π ::NZ`Rng r9Zgm>$Iu~џ%_L: 9x9bV?x8Ǐ70mK+Y˝};\.~?e<~?rp"tb_IqZ[in^~`\u-b||6D"6mrge2yuX\u Ķ5ݼ{}e,CEA( %J1뭟ۣwGaDdigi"Pq^xG/B<͡XCQ-XTYq ]4_S6+if> ߄0ꥭ },~g7s+(eW|,zv<6VhRnb\<Nthqv1j|of]+l QE<^GFtq@:"d^dɫ|Z($NJ.#(_"i2v/Ezz{hw(noȝ|!_ n2== Ӥ@ع!w2c#]0NigxDž G+>2醪M^_ i}Y~Vϰ߯DSg`4H|@nGv$s?Md{yo, ,VR\5- _JrW\]~^o =kr*FϮ~bn3*b֭۶3҅mp#~'Sx| ##k @\kӰг{lɮ]سwm߆\Z}U(qƚM1x)? C0@ B E|IENDB`tiled-0.14.2/docs/reference/support-for-tmx-maps.md000066400000000000000000000336041260670167100221670ustar00rootroot00000000000000# Libraries and Frameworks There are many libraries available for reading and/or writing maps stored in the [TMX map format](../reference/tmx-map-format.md) as well as many development frameworks that include support for TMX maps. This list is divided into two sections: - [Support by Language](#support-by-language) - [Support by Framework](#support-by-framework) First list is for developers who plan on implementing their own renderer. Second list is for developers already using (or considering) a particular game engine / graphics library who would rather pass on having to write their own tilemap renderer. *For updates to this page please open a pull request or issue [on github](https://github.com/bjorn/tiled/issues), thanks!* ## Support by Language These libraries typically include only a TMX parser, but no rendering support. They can be used universally and should not require a specific game engine or graphics library. ### C * [TMX](https://github.com/baylej/tmx/) - XML and JSON map loader with Allegro5 and SDL2 examples (BSD). ### C++ * [C++/Boost](http://www.catnapgames.com/blog/2011/10/10/simple-tmx-tilemap-parser.html) by Tomas Andrle (limited functionality, single cpp file) * [C++/TinyXML based tmx-parser](https://github.com/andrewrk/tmxparser) (BSD) - [Original version](http://code.google.com/p/tmx-parser/) by KonoM is discontinued. * C++/Qt based libtiled, used by Tiled itself and included at [src/libtiled](https://github.com/bjorn/tiled/tree/master/src/libtiled) (BSD) * [C++11x/TinyXml2 libtmx-parser](https://github.com/halsafar/libtmx-parser) by halsafar. (zlib/tinyxml2) * [C++11/TinyXml2 libtmx](https://github.com/jube/libtmx) by jube, for reading only (ISC licence). See [documentation](http://jube.github.io/libtmx/index.html). * [TMXParser](https://github.com/solar-storm-studios/TMXParser) General *.tmx tileset data loader. Intended to be used with TSXParser for external tileset loading. (No internal tileset support) * [TSXParser](https://github.com/solar-storm-studios/TSXParser) General *.tsx tileset data loader. Intended to be used with TMXParser. ### C#/.NET ### * [XNA map loader](https://github.com/zachmu/tiled-xna) by Kevin Gadd, extended by Stephen Belanger and Zach Musgrave (has dependency on XNA but supposedly can be turned into a standalone parser easily) * [TiledSharp](https://github.com/marshallward/TiledSharp): Yet another C# TMX importer library, with Tiled 0.11 support. TiledSharp is a generic parser which can be used in any framework, but it cannot be used to render the maps. Available via NuGet. * [NTiled](https://github.com/patriksvensson/ntiled): Generic parser for 0.9.1 tiled maps. Available via NuGet. * [TmxCSharp](https://github.com/gwicksted/TmxCSharp): Useful for multi-layer orthographic tile engines. No framework dependencies, used with a custom OpenTK tile engine soon to be open source, tested with Tiled 0.8.1 (multiple output formats). MIT license. * [tmx-mapper-pcl](https://github.com/aalmik/tmx-mapper-pcl): PCL library for parsing Tiled map TMX files. This library could be used with MonoGame and Windows Runtime Universal apps. ### D * [tiledMap.d](https://gist.github.com/gdm85/9896961) simple single-layer and single-tileset example to load a map and its tileset in [D language](http://dlang.org/). It also contains basic rendering logic using [DSFML](https://github.com/Jebbs/DSFML/) ### Go * [github.com/salviati/go-tmx/tmx](https://github.com/salviati/go-tmx) ### Haskell * [htiled](http://hackage.haskell.org/package/htiled) by [Christian Rødli Amble](https://github.com/chrra). ### Java * A library for loading TMX files is included with Tiled at [util/java/libtiled-java](https://github.com/bjorn/tiled/tree/master/util/java/libtiled-java). * Android-Specific: - [AndroidTMXLoader](https://github.com/davidmi/Android-TMX-Loader) loads TMX data into an object and renders to an Android Bitmap (limited functionality) - [libtiled-java port](http://chiselapp.com/user/devnewton/repository/libtiled-android/index) is a port of the libtiled-java to be used on Android phones. ### Objective-C & Swift * [TilemapKit](http://tilemapkit.com) is an actively maintained TMX loader and hierarchical tilemap object model for use with iOS projects. Can be integrated with any C/C++/Objective-C/Swift codebase and used for custom renderers. ### PHP * [PHP TMX Viewer](https://github.com/sebbu2/php-tmx-viewer) by sebbu : render the map as an image (allow some modifications as well) ### Pike * [TMX parser](https://gitorious.org/tmx-parser): a simple loader for TMX maps (CSV format only). ### Python * [pytmxlib](http://pytmxlib.readthedocs.org/en/latest/): library for programmatic manipulation of TMX maps * [python-tmx](http://python-tmx.nongnu.org): a simple library for reading and writing TMX files. ### Ruby * [tmx gem](https://github.com/shawn42/tmx) by erisdiscord ### Vala * [librpg](https://github.com/JumpLink/librpg) A library to load and handle spritesets (own format) and orthogonal TMX maps. ## Support by Framework Following entries are integrated solutions for specific game engines. They are typically of little to no use if you're not using said game engine. ### AndEngine * [AndEngine](http://www.andengine.org/) by Nicolas Gramlich supports [rendering TMX maps](http://www.andengine.org/blog/2010/07/andengine-tiledmaps-in-the-tmx-format/) ### Allegro * [allegro_tiled](https://github.com/dradtke/allegro_tiled) integrates Tiled support with [Allegro 5](http://alleg.sourceforge.net/). ### cocos2d * [cocos2d (Python)](http://python.cocos2d.org/) supports loading [Tiled maps](http://python.cocos2d.org/doc/programming_guide/tiled_map.html) through its `cocos.tiles` module. * [cocos2d-x (C++)](http://www.cocos2d-x.org/) supports loading TMX maps through the [CCTMXTiledMap](http://www.cocos2d-x.org/reference/native-cpp/V2.1.4/da/d68/classcocos2d_1_1_c_c_t_m_x_tiled_map.html) class. * [cocos2d-objc (Objective-C, Swift)](http://www.cocos2d-objc.org/) (previously known as: cocos2d-iphone, cocos2d-swift, cocos2d-spritebuilder) supports loading TMX maps through [CCTiledMap](http://cocos2d.spritebuilder.com/docs/api/Classes/CCTiledMap.html) * [TilemapKit](http://tilemapkit.com) is an actively maintained tilemapping framework for Cocos2D. It supports all TMX tilemap types, including staggered iso and all hex variations. ### Construct 2 - Scirra * [Construct 2](http://www.scirra.com), since the Beta Release 149, officially supports TMX maps, and importing it by simple dragging the file inside the editor. [Official Note](https://www.scirra.com/construct2/releases/r149) ### Corona SDK * [Lime](https://github.com/OutlawGameTools/Lime2DTileEngine) is a 2D engine for making tile-based games with Corona SDK and Tiled ### Flixel * Lithander demonstrated his [Flash TMX parser combined with Flixel rendering](http://blog.pixelpracht.net/?p=59) ### Game Maker * [Tiled2GM Converter](http://gmc.yoyogames.com/index.php?showtopic=539494) by Dmi7ry ### Haxe * [HaxePunk](https://github.com/HaxePunk/tiled) Tiled Loader for HaxePunk * [HaxeFlixel](https://github.com/HaxeFlixel/flixel-addons/tree/dev/flixel/addons/editors/tiled) * [OpenFL](https://github.com/Kasoki/openfl-tiled) "openfl-tiled" is a library, which gives OpenFL developers the ability to use the Tiled Map Editor. * [OpenFL + Tiled + Flixel](https://github.com/kasoki/openfl-tiled-flixel) Experimental glue to use "openfl-tiled" with HaxeFlixel ### HTML5 (multiple engines) * [Canvas Engine](http://canvasengine.net) A framework to create video games in HTML5 Canvas * [chesterGL](https://github.com/funkaster/ChesterGL) A simple WebGL/canvas game library * [KineticJs-Ext](https://github.com/Wappworks/kineticjs-ext) A multi-canvas based game rendering library * [melonJS](http://www.melonjs.org) A lightweight HTML5 game engine * [Platypus Engine](https://github.com/PBS-KIDS/Platypus/) A robust orthogonal tile game engine with game entity library. * [sprite.js](https://github.com/batiste/sprite.js) A game framework for image sprites. * [TMXjs](https://github.com/cdmckay/tmxjs) A JavaScript, jQuery and RequireJS-based TMX (Tile Map XML) parser and renderer. * [chem-tmx](https://github.com/andrewrk/chem-tmx) Plugin for [chem](https://github.com/andrewrk/chem/) game engine. * [GameJs](http://gamejs.org) JavaScript library for game programming; a thin wrapper to draw on HTML5 canvas and other useful modules for game development * [Crafty](http://craftyjs.com) JavaScript HTML5 Game Engine; supports loading Tiled maps through an external component [TiledMapBuilder](https://github.com/Kibo/TiledMapBuilder). * [Phaser](http://www.phaser.io) A fast, free and fun open source framework supporting both JavaScript and TypeScript ([Tiled tutorial](http://www.gamedevacademy.org/html5-phaser-tutorial-top-down-games-with-tiled/)) ### indielib-crossplatform * [indielib cross-platform](http://www.indielib.com) supports loading TMX maps through the [C++/TinyXML based tmx-parser](http://code.google.com/p/tmx-parser/) by KonoM (BSD) ### LibGDX * [libgdx](http://libgdx.badlogicgames.com/), a Java-based Android/desktop/HTML5 game library, [provides](https://github.com/libgdx/libgdx/wiki/Tile-maps) a packer, loader and renderer for TMX maps ### LÖVE * [Simple Tiled Implementation](https://github.com/Karai17/Simple-Tiled-Implementation) Lua loader for the LÖVE (Love2d) game framework. ### MOAI SDK * [Hanappe](https://github.com/makotok/Hanappe) Framework for MOAI SDK. * [Rapanui](https://github.com/ymobe/rapanui) Framework for MOAI SDK. ### Monkey X * [bit.tiled](https://github.com/bitJericho/bit.tiled) Loads TMX file as objects. Aims to be fully compatible with native TMX files. * [Diddy](https://code.google.com/p/diddy/) is an extensive framework for Monkey X that contains a module for loading and rendering TMX files. Supports orthogonal and isometric maps as both CSV and Base64 (uncompressed). ### Node.js * [node-tmx-parser](https://github.com/andrewrk/node-tmx-parser) - loads the TMX file into a JavaScript object ### Pygame * [Pygame map loader](http://www.pygame.org/project/1158/) by dr0id * [PyTMX](https://github.com/bitcraft/PyTMX) by Leif Theden (bitcraft) * [tmx.py](https://bitbucket.org/r1chardj0n3s/pygame-tutorial/src/a383dd24790d/tmx.py) by Richard Jones, from his [2012 PyCon 'Introduction to Game Development' talk](http://pyvideo.org/video/615/introduction-to-game-development). * [TMX](https://github.com/renfredxh/tmx), a fork of tmx.py and a port to Python3. A demo called pylletTown can be found [here](https://github.com/renfredxh/pylletTown). ### Pyglet * [JSON map loader/renderer for pyglet](https://github.com/reidrac/pyglet-tiled-json-map) by Juan J. Martínez (reidrac) * [PyTMX](https://github.com/bitcraft/PyTMX) by Leif Theden (bitcraft) ### PySDL2 * [PyTMX](https://github.com/bitcraft/PyTMX) by Leif Theden (bitcraft) ### SDL * [C++/TinyXML/SDL based loader](http://usefulgamedev.weebly.com/c-tiled-map-loader.html) example by Rohin Knight (limited functionality) ### SFML * [STP](https://github.com/edoren/STP) (SFML TMX Parser) by edoren * [C++/SFML Tiled map loader](http://trederia.blogspot.co.uk/2013/05/tiled-map-loader-for-sfml.html) by fallahn. (Zlib/libpng) * [C++/SfTileEngine](https://github.com/Tresky/sf_tile_engine) by Tresky (currently limited functionality) ### Slick2D * [Slick2D](http://slick.ninjacave.com) supports loading TMX maps through [TiledMap](http://slick.ninjacave.com/javadoc/org/newdawn/slick/tiled/TiledMap.html). ### Sprite Kit Framework * [TilemapKit](http://tilemapkit.com) is an actively maintained tilemapping framework for Sprite Kit. It supports all TMX tilemap types, including staggered iso and all hex variations. * [JSTileMap](https://github.com/slycrel/JSTileMap) is a lightweight SpriteKit implementation of the TMX format supporting iOS 7 and OS X 10.9 and above. ### TERRA Engine (Delphi/Pascal) * [TERRA Engine](http://pascalgameengine.com/) supports loading and rendering of TMX maps. ### Unity 3D * [Orthello Pro](http://www.wyrmtale.com/products/unity3d-components/orthello-pro) (2D framework) offers [Tiled map support](http://www.wyrmtale.com/orthello-pro/tilemaps). * [Tiled Tilemaps](http://karnakgames.com/wp/unity-tiled-tilemaps/) library by Karnak Games adds support for Orthogonal TMX maps to Unity, with automatic collision detection. * [Tiled To Unity](https://www.assetstore.unity3d.com/#/content/17260/) is a 3D pipeline for Tiled maps. It uses prefabs as tiles, and can place decorations dynamically on tiles. Supports multiple layers (including object layers). * [Tiled2Unity](http://www.seanba.com/introtiled2unity.html) exports TMX files to Unity with support for (non-simple) collisions. * [UniTMX](https://bitbucket.org/PolCPP/unitmx/overview) imports TMX files into a mesh. * [X-UniTMX](https://bitbucket.org/Chaoseiro/x-unitmx) supports almost all Tiled 0.10 features. Imports TMX/XML files into Sprite Objects or Meshes. ### Unreal Engine 4 * [Paper2D](https://forums.unrealengine.com/showthread.php?3539-Project-Paper2D) provides built-in support for tile maps and tile sets, importing JSON exported from Tiled. ### Urho3D * [Urho3D](http://urho3d.github.io/) natively supports loading Tiled maps as part of the [Urho2D](http://urho3d.github.io/documentation/1.4/_urho2_d.html) sublibrary ([Documentation](http://urho3d.github.io/documentation/1.4/class_urho3_d_1_1_tile_map2_d.html), [HTML5 example](http://urho3d.github.io/samples/36_Urho2DTileMap.html)). ### XNA * [FlatRedBall Engine TMXGlue tool](http://www.flatredball.com/frb/docs/index.php?title=Kain%27s_Tavern#Tiled_Map_Editor.2C_TMX.2C_Glue_and_you.) by Domenic Datti loads TMX maps into the FlatRedBall engine, complete with node networks, pathfinding, and shapecollection support via object layers. * [TiledMax](http://tiledmax.xpod.be/) by Aimee Bailey, a .NET library for parsing TMX maps without dependencies on Windows or XNA * [XTiled](https://bitbucket.org/vinull/xtiled) by Michael C. Neel and Dylan Wolf, XNA library for loading and rendering TMX maps * [XNA map loader](https://github.com/zachmu/tiled-xna) by Kevin Gadd, extended by Stephen Belanger and Zach Musgrave tiled-0.14.2/docs/reference/tmx-changelog.md000066400000000000000000000124451260670167100206600ustar00rootroot00000000000000--- # TMX Changelog # Below are described the changes/additions that were made to the [TMX format](tmx-map-format.md) for recent versions of Tiled. ## Tiled 0.14 ## * Added optional `offsetx` and `offsety` attributes to the `layer` and `objectgroup` elements. These specify an offset in pixels that is to be applied when rendering the layer. The default values are 0. ## Tiled 0.13 ## * Added an optional `tilecount` attribute to the `tileset` element, which is written by Tiled to help parsers determine the amount of memory to allocate for tile data. ## Tiled 0.12 ## * Previously tile objects never had `width` and `height` properties, though the format technically allowed this. Now these properties are used to store the size the image should be rendered at. The default values for these attributes are the dimensions of the tile image. ## Tiled 0.11 ## * Added `hexagonal` to the supported values for the `orientation` attribute on the `map` element. This also adds `staggerindex` (`even` or `odd`) and `staggerdirection` (`rows` or `columns`) and `hexsidelength` (integer value) attributes to the `map` element, in order to support the many variations of staggered hexagonal. The `staggerindex` attribute is now also supported when using the `staggered` map orientation. * Added an `id` attribute to the `object` element, which stores a map-unique ID of the object. ## Tiled 0.10 ## * Tile objects can now be horizontally or vertically flipped. This is stored in the `gid` attribute using the same mechanism as for regular tiles. The image is expected to be flipped without affecting its position, same way as flipped tiles. * Objects can be rotated freely. The rotation is stored in degrees as a `rotation` attribute, with positive rotation going clockwise. * The render order of the tiles on tile layers can be configured in a number of ways through a new `renderorder` property on the `map` element. Valid values are `right-down` (the default), `right-up`, `left-down` and `left-up`. In all cases, the map is drawn row-by-row. This is only supported for orthogonal maps at the moment. * The render order of objects on object layers can be configured to be either sorted by their y-coordinate (previous behavior and still the default) or simply the order of appearance in the map file. The latter enables manual control over the drawing order with actions that "Raise" and "Lower" selected objects. It is controlled by the `draworder` property on the `objectgroup` element, which can be either `topdown` (default) or `index`. * Tiles can have an `objectgroup` child element, which can contain objects that define the collision shape to use for that tile. This information can be edited in the new Tile Collision Editor. * Tiles can have a single looping animation associated with them using an `animation` child element. Each frame of the animation refers to a local tile ID from this tileset and defines the frame duration in milliseconds. Example: ```xml ... ``` ## Tiled 0.9 ## * Per-object visibility flag is saved (defaults to 1): ```xml ``` * Terrain information was added to tileset definitions (this is generally not very relevant for games): ```xml ... ... ``` * There is preliminary support for a "staggered" (isometric) projection (new value for the `orientation` attribute of the `map` element). * A basic image layer type was added: ```xml ``` * Added ellipse object shape. Same parameters as rectangular objects, but marked as ellipse with a child element: ```xml ``` * Added map property for specifying the background color: ```xml ``` * Added initial (non-GUI) support for individual and/or embedded tile images (since there is no way to set this up in Tiled Qt but only in Tiled Java or with [pytmxlib](https://github.com/encukou/pytmxlib), this is not very important to support at the moment): ```xml ... ... ``` ## Tiled 0.8 ## * Tilesets can now have custom properties (using the `properties` child element, just like everything else). * Tilesets now support defining a drawing offset in pixels, which is to be used when drawing any tiles from that tileset. Example: ```xml ... ``` * Support for tile rotation in 90-degree increments was added by using the third most significant bit in the global tile id. This new bit means "anti-diagonal flip", which swaps the x and y axis when rendering a tile. tiled-0.14.2/docs/reference/tmx-map-format.md000066400000000000000000000404611260670167100207730ustar00rootroot00000000000000# TMX Map Format # The TMX (Tile Map XML) map format used by [Tiled](http://www.mapeditor.org) is a flexible way to describe a tile based map. It can describe maps with any tile size, any amount of layers, any number of tile sets and it allows custom properties to be set on most elements. Beside tile layers, it can also contain groups of objects that can be placed freely. Note that there are many [libraries and frameworks](support-for-tmx-maps.md) available that can work with TMX maps. In this document we'll go through each element found in this map format. The elements are mentioned in the headers and the list of attributes of the elements are listed right below, followed by a short explanation. Attributes or elements that are deprecated or unsupported by the current version of Tiled are formatted in italics. Have a look at the [changelog](tmx-changelog.md) when you're interested in what changed between Tiled versions. *A DTD-file (Document Type Definition) is served at . This file is not up-to-date but might be useful for XML-namespacing anyway.* ## <map> ## * version: The TMX format version, generally 1.0. * orientation: Map orientation. Tiled supports "orthogonal", "isometric" and "staggered" (since 0.9) at the moment. * width: The map width in tiles. * height: The map height in tiles. * tilewidth: The width of a tile. * tileheight: The height of a tile. * backgroundcolor: The background color of the map. (since 0.9, optional) * renderorder: The order in which tiles on tile layers are rendered. Valid values are `right-down` (the default), `right-up`, `left-down` and `left-up`. In all cases, the map is drawn row-by-row. (since 0.10, but only supported for orthogonal maps at the moment) The `tilewidth` and `tileheight` properties determine the general grid size of the map. The individual tiles may have different sizes. Larger tiles will extend at the top and right (anchored to the bottom left). A map contains three different kinds of layers. Tile layers were once the only type, and are simply called `layer`, object layers have the `objectgroup` tag and image layers use the `imagelayer` tag. The order in which these layers appear is the order in which the layers are rendered by Tiled. Can contain: [properties](#properties), [tileset](#tileset), [layer](#layer), [objectgroup](#objectgroup), [imagelayer](#imagelayer) ## <tileset> ## * firstgid: The first global tile ID of this tileset (this global ID maps to the first tile in this tileset). * source: If this tileset is stored in an external TSX (Tile Set XML) file, this attribute refers to that file. That TSX file has the same structure as the `` element described here. (There is the firstgid attribute missing and this source attribute is also not there. These two attributes are kept in the TMX map, since they are map specific.) * name: The name of this tileset. * tilewidth: The (maximum) width of the tiles in this tileset. * tileheight: The (maximum) height of the tiles in this tileset. * spacing: The spacing in pixels between the tiles in this tileset (applies to the tileset image). * margin: The margin around the tiles in this tileset (applies to the tileset image). * tilecount: The number of tiles in this tileset (since 0.13) If there are multiple `` elements, they are in ascending order of their `firstgid` attribute. The first tileset always has a `firstgid` value of 1 and it can be assumed that there are no gaps in the valid range of global tile IDs. Can contain: [tileoffset](#tileoffset) (since 0.8), [properties](#properties) (since 0.8), [image](#image), [terraintypes](#terraintypes) (since 0.9), [tile](#tile) ### <tileoffset>#### * x: Horizontal offset in pixels * y: Vertical offset in pixels (positive is down) This element is used to specify an offset in pixels, to be applied when drawing a tile from the related tileset. When not present, no offset is applied. ### <image> #### * format: Used for embedded images, in combination with a `data` child element. Valid values are file extensions like `png`, `gif`, `jpg`, `bmp`, etc. (since 0.9) * id: Used by some versions of Tiled Java. Deprecated and unsupported by Tiled Qt. * source: The reference to the tileset image file (Tiled supports most common image formats). * trans: Defines a specific color that is treated as transparent (example value: "#FF00FF" for magenta). Up until Tiled 0.12, this value is written out without a `#` but this is planned to change. * width: The image width in pixels (optional, used for tile index correction when the image changes) * height: The image height in pixels (optional) Can contain: [data](#data) (since 0.9) ### <terraintypes> ### This element defines an array of terrain types, which can be referenced from the `terrain` attribute of the `tile` element. Can contain: [terrain](#terrain) #### <terrain> #### * name: The name of the terrain type. * tile: The local tile-id of the tile that represents the terrain visually. Can contain: [properties](#properties) ### <tile> ### * id: The local tile ID within its tileset. * terrain: Defines the terrain type of each corner of the tile, given as comma-separated indexes in the terrain types array in the order top-left, top-right, bottom-left, bottom-right. Leaving out a value means that corner has no terrain. (optional) (since 0.9) * probability: A percentage indicating the probability that this tile is chosen when it competes with others while editing with the terrain tool. (optional) (since 0.9) Can contain: [properties](#properties), [image](#image) (since 0.9), [objectgroup](#objectgroup) (since 0.10), [animation](#animation) (since 0.10) #### <animation> #### Contains a list of animation frames. As of Tiled 0.10, each tile can have exactly one animation associated with it. In the future, there could be support for multiple named animations on a tile. Can contain: [frame](#frame) ##### <frame> ##### * tileid: The local ID of a tile within the parent [tileset](#tileset). * duration: How long (in milliseconds) this frame should be displayed before advancing to the next frame. ## <layer> ## All `` tags shall occur before the first `` tag so that parsers may rely on having the tilesets before needing to resolve tiles. * name: The name of the layer. * x: The x coordinate of the layer in tiles. Defaults to 0 and can no longer be changed in Tiled Qt. * y: The y coordinate of the layer in tiles. Defaults to 0 and can no longer be changed in Tiled Qt. * width: The width of the layer in tiles. Traditionally required, but as of Tiled Qt always the same as the map width. * height: The height of the layer in tiles. Traditionally required, but as of Tiled Qt always the same as the map height. * opacity: The opacity of the layer as a value from 0 to 1. Defaults to 1. * visible: Whether the layer is shown (1) or hidden (0). Defaults to 1. * offsetx: Rendering offset for this layer in pixels. Defaults to 0. (since 0.14) * offsety: Rendering offset for this layer in pixels. Defaults to 0. (since 0.14) Can contain: [properties](#properties), [data](#data) ### <data> ### * encoding: The encoding used to encode the tile layer data. When used, it can be "base64" and "csv" at the moment. * compression: The compression used to compress the tile layer data. Tiled Qt supports "gzip" and "zlib". When no encoding or compression is given, the tiles are stored as individual XML `tile` elements. Next to that, the easiest format to parse is the "csv" (comma separated values) format. The base64-encoded and optionally compressed layer data is somewhat more complicated to parse. First you need to base64-decode it, then you may need to decompress it. Now you have an array of bytes, which should be interpreted as an array of unsigned 32-bit integers using little-endian byte ordering. Whatever format you choose for your layer data, you will always end up with so called "global tile IDs" (gids). They are global, since they may refer to a tile from any of the tilesets used by the map. In order to find out from which tileset the tile is you need to find the tileset with the highest `firstgid` that is still lower or equal than the gid. The tilesets are always stored with increasing `firstgid`s. Can contain: [tile](#tile_1) #### Tile flipping #### When you use the tile flipping feature added in Tiled Qt 0.7, the highest two bits of the gid store the flipped state. Bit 32 is used for storing whether the tile is horizontally flipped and bit 31 is used for the vertically flipped tiles. And since Tiled Qt 0.8, bit 30 means whether the tile is flipped (anti) diagonally, enabling tile rotation. These bits have to be read and cleared before you can find out which tileset a tile belongs to. When rendering a tile, the order of operation matters. The diagonal flip (x/y axis swap) is done first, followed by the horizontal and vertical flips. The following C++ pseudo-code should make it all clear: // Bits on the far end of the 32-bit global tile ID are used for tile flags const unsigned FLIPPED_HORIZONTALLY_FLAG = 0x80000000; const unsigned FLIPPED_VERTICALLY_FLAG = 0x40000000; const unsigned FLIPPED_DIAGONALLY_FLAG = 0x20000000; ... // Extract the contents of the element string tile_data = ... unsigned char *data = decompress(base64_decode(tile_data)); unsigned tile_index = 0; // Here you should check that the data has the right size // (map_width * map_height * 4) for (int y = 0; y < map_height; ++y) { for (int x = 0; x < map_width; ++x) { unsigned global_tile_id = data[tile_index] | data[tile_index + 1] << 8 | data[tile_index + 2] << 16 | data[tile_index + 3] << 24; tile_index += 4; // Read out the flags bool flipped_horizontally = (global_tile_id & FLIPPED_HORIZONTALLY_FLAG); bool flipped_vertically = (global_tile_id & FLIPPED_VERTICALLY_FLAG); bool flipped_diagonally = (global_tile_id & FLIPPED_DIAGONALLY_FLAG); // Clear the flags global_tile_id &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG); // Resolve the tile for (int i = tileset_count - 1; i >= 0; --i) { Tileset *tileset = tilesets[i]; if (tileset->first_gid() <= global_tile_id) { tiles[y][x] = tileset->tileAt(global_tile_id - tileset->first_gid()); break; } } } } (Since the above code was put together on this wiki page and can't be directly tested, please make sure to report any errors you encounter when basing your parsing code on it, thanks.) ### <tile> ### * gid: The global tile ID. Not to be confused with the `tile` element inside a `tileset`, this element defines the value of a single tile on a tile layer. This is however the most inefficient way of storing the tile layer data, and should generally be avoided. ## <objectgroup> ## * name: The name of the object group. * color: The color used to display the objects in this group. * x: The x coordinate of the object group in tiles. Defaults to 0 and can no longer be changed in Tiled Qt. * y: The y coordinate of the object group in tiles. Defaults to 0 and can no longer be changed in Tiled Qt. * width: The width of the object group in tiles. Meaningless. * height: The height of the object group in tiles. Meaningless. * opacity: The opacity of the layer as a value from 0 to 1. Defaults to 1. * visible: Whether the layer is shown (1) or hidden (0). Defaults to 1. * offsetx: Rendering offset for this object group in pixels. Defaults to 0. (since 0.14) * offsety: Rendering offset for this object group in pixels. Defaults to 0. (since 0.14) * draworder: Whether the objects are drawn according to the order of appearance ("index") or sorted by their y-coordinate ("topdown"). Defaults to "topdown". The object group is in fact a map layer, and is hence called "object layer" in Tiled Qt. Can contain: [properties](#properties), [object](#object) ### <object> ### * id: Unique ID of the object. Each object that is placed on a map gets a unique id. Even if an object was deleted, no object gets the same ID. Can not be changed in Tiled Qt. (since Tiled 0.11) * name: The name of the object. An arbitrary string. * type: The type of the object. An arbitrary string. * x: The x coordinate of the object in pixels. * y: The y coordinate of the object in pixels. * width: The width of the object in pixels (defaults to 0). * height: The height of the object in pixels (defaults to 0). * rotation: The rotation of the object in degrees clockwise (defaults to 0). (since 0.10) * gid: An reference to a tile (optional). * visible: Whether the object is shown (1) or hidden (0). Defaults to 1. (since 0.9) While tile layers are very suitable for anything repetitive aligned to the tile grid, sometimes you want to annotate your map with other information, not necessarily aligned to the grid. Hence the objects have their coordinates and size in pixels, but you can still easily align that to the grid when you want to. You generally use objects to add custom information to your tile map, such as spawn points, warps, exits, etc. When the object has a `gid` set, then it is represented by the image of the tile with that global ID. Currently that means `width` and `height` are ignored for such objects. The image alignment currently depends on the map orientation. In orthogonal orientation it's aligned to the bottom-left while in isometric it's aligned to the bottom-center. Can contain: [properties](#properties), [ellipse](#ellipse) (since 0.9), [polygon](#polygon), [polyline](#polyline), image ### <ellipse> ### Used to mark an object as an ellipse. The existing `x`, `y`, `width` and `height` attributes are used to determine the size of the ellipse. ### <polygon> ### * points: A list of x,y coordinates in pixels. Each `polygon` object is made up of a space-delimited list of x,y coordinates. The origin for these coordinates is the location of the parent `object`. By default, the first point is created as 0,0 denoting that the point will originate exactly where the `object` is placed. ### <polyline> ### * points: A list of x,y coordinates in pixels. A `polyline` follows the same placement definition as a `polygon` object. ## <imagelayer> ## * name: The name of the image layer. * x: The x position of the image layer in pixels. * y: The y position of the image layer in pixels. * width: The width of the image layer in tiles. Meaningless. * height: The height of the image layer in tiles. Meaningless. * opacity: The opacity of the layer as a value from 0 to 1. Defaults to 1. * visible: Whether the layer is shown (1) or hidden (0). Defaults to 1. A layer consisting of a single image. Can contain: [properties](#properties), [image](#image) ## <properties> ## Can contain: [property](#property) Wraps any number of custom properties. Can be used as a child of the `map`, `tile` (when part of a `tileset`), `layer`, `objectgroup` and `object` elements. ### <property> ### * name: The name of the property. * value: The value of the property. When the property spans contains newlines, the current versions of Tiled Java and Tiled Qt will write out the value as characters contained inside the `property` element rather than as the `value` attribute. However, it is at the moment not really possible to edit properties consisting of multiple lines with Tiled. It is possible that a future version of the TMX format will switch to always saving property values inside the element rather than as an attribute. --- ![Creative Commons License](CC-BY-SA.png) The **TMX Map Format** by is licensed under a [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/). tiled-0.14.2/examples/000077500000000000000000000000001260670167100145235ustar00rootroot00000000000000tiled-0.14.2/examples/desert.tmx000066400000000000000000000013161260670167100165440ustar00rootroot00000000000000 eJztmNkKwjAQRaN9cAPrAq5Yq3Xf6v9/nSM2VIbQJjEZR+nDwQZScrwztoORECLySBcIgZ7nc2y4KfyWDLx+Jb9nViNgDEwY+KioAXUgQN4+zpoCMwPmQAtoAx2CLFbA2oDEo9+hwG8DnIDtF/2K8ks086Tw2zH0uyMv7HcRr/6/EvvhnsPrsrxwX7rwU/0ODig/eV3mh3N1ld8eraWPaX6+64s9McesfrqcHfg1MpoifxcVEWjukyw+9AtFPl/I71pER3Of6j4bv7HI54s+MChhqLlPdZ/P3qMmFuo5h5NnTOhjM5tReN2yT51n5/v7J3F0vi46fk+ne7aX0i9l6If7mpufTX3f5wsqv9TAD2fJLT9VrTn7UeZnM5tR+v0LMQOHXwFnxe2/warGFRWf8QDjOLfP tiled-0.14.2/examples/desert.tsx000066400000000000000000000042241260670167100165530ustar00rootroot00000000000000 tiled-0.14.2/examples/hexagonal-mini.tmx000066400000000000000000000014761260670167100201650ustar00rootroot00000000000000 eJyl1FEKhDAMBNBSt6jVaL3/Za2QwDAkVdiPQda2zyTonimlU1N6Ws+lkZ6l56AUXcPY2qlniv5uL5Z5BdyDvFXXMoX3Rp44axl6nqFejj3LLK6xgmf3Zg06Qs+O+qiaDOZOVgXPs7jfCme8Hkce1+fNlGdlM3myDTzc580fz1htW2Baj15/R/J72wLvcVZN5HnzGnmVPJ5hNH+0dt33j4ex91TARUs+WjNZz/fewKvJfy+/1naR+dX7OfdEnUYefyOeZZ7Vht/b5HjefxJbO1iTE7YWuEpg5hfPzi8D782x3Mg7DV4= tiled-0.14.2/examples/hexmini.png000066400000000000000000000132301260670167100166710ustar00rootroot00000000000000PNG  IHDRjHE` pHYs  tIME '3D7IDATx}lg?󶳯kvM@ڐB["R݉CtHT=N!z:@wSÝګ4ΛNw:3;3z&Y{7Iyog<۶ٴ!xyKWԄ}w~ŸB{ߝAE\"UE1SϮ\:Q-__']?oKOmusB+QL|(1MJ [ןý½{5g (Po2@ cL@xU0 Ԋ20ț:P"n1p)`'ȤtJZ\@QeJz [)QȚ| pW-=W07y\񚝯_pC?.z@VIC ܎VIc~!0/j% P""f-u}s{D5T,l:ADJtxBE+srƑX(2Ԗd2P[i`?{fk]wh7{&GIaF P{mTϳ@4 ' ,ʮ?h~6JzԜ(Uሂ@goXBPfn"O (  ~uLh g@Psgs% _`f*[w^5UW7cvam_?s 5Drá0WP" Dž 7cfz=5"ҮPX,`F7L$5v2GLfj, TQ w]X~~zvsn3OW'~;sƏ*i5 F1n?SUlvA8ee˅%ƒ nNnxstb^wT(%B6eI:QCVP̚:%v2Ԗd-R[zp0]pu~Cm/?&CmIf'Gfvy7wh?Q shVfHߖfk*slfnðW~͂kmwuUuvHj"+ eP%%̲(Z iTwN#ؙK͟G_\{>WM%_r۞x걋|C Q@&Y>PQ3'9TUiafpԣ%S*dV*ŜmY@GO^AB5eEs&r@jx/:p9 p!&v"jyf_} mjn_si3;|Kr-62)s8`Nonk-ú뮻j>_b˰q>sWsO}?(L6u,@6u,O?ęɖ@u]M7T裏6  [p9כuU%Ԝ{ۚ{nEמtta,9I{LbC\8K ^־׾;f411ѰzV!7t^Lr\W wܳSXz.Jh >gy?l;_Vw ?É|3"*qgNuddsJ2o߾=[o3::at 9VfMb(sN= V=HB@d$yu鶭 kG80lMaGIQ٦&Zloݖ 4ˎ7S,  9zP[ F?oȏ?P^0uፎ兔,MVLBqBh2IMSO.Ϝ rJ%e>uujk)F4V?siB{hds viM̚H!kMNB?l?Gfv}^]k9iLnؕ2S'{`'K3-JKtڣ ^I4̬}v]ӧ> ʌ;% bjBqS*c0DzJ#U*_=44L@J(]mXKYA"LQH5!l׹:rI),1c1vDPc'+@8]dpn(n{;mGg՟qJLD-< KU1lzxM5sч?a>پ}xxp4MdgʴJHbXF0ĩ.QJ(muUi(a.Ma7zw&rQt\2bmn[ڡv!9o>].y=Q{n@BI (WHhQP Pv²- QPQ gڱcG3hʄ SHOiDAJqi"n|]mPbTDc䙥8y)@5JFb(dkXX!fd(v4 gC ``tm j E숅)h%L$W KT̼])!U%eD";8^033&q||׶=wVʗ/\%eD~AgXZX4pwjܤAt$Geab aEQ|Uoεzk9J7 b66($)+6^&b"h[(M)jtto&耚a=zt9̞RUP~䂉&{=!{yxl- "ajX(tBgiy5!ŵ+l 6@'"hA8א%Y oHKTUĬPQ^!йrffc.gґng<ij۫PLmXW M8jS :sUط=_JK/J⫢Rֿ J6Sb T&, H-#I2bh[d͍riѨ k~jvgr `r=!rk y%\`ۖy " 9nΨ 9:,0*ghV ìi&6bnq vBfy~:qb/$"\pH* f{ZUXPWoR=yU^YJ EA@Jl[r;/nF9o4p` 𽟜~\y5ˈF<%#a; Ȼ'6."K"+jN,Ϟx}[{׷C=bO+/ѯ S${8$Y r{ԜmC9tjr|)cK{Eϧ)dB\KٞsJwN~K >uo~r陦LtY߱e.jc`/rrqIbk Oe.`fYwѻ5G~Y@=oG JT nh\[}*?G{hǾgzo}B먯Tiu P\ P%pr؃8 SHNsOgg9|4 \4)-Q7Y9V"is4&Wqif|4̩7֙9}jv&Wu vB rTLa9N_xRu۶mt: /pδmܡw3uKޅP[n,ia}4T@y}¾졭Wb:ɭJ3K5 _ۏr&E"b(rcJe=C,`}UC@:ݰxA9**ϡ-hV 3yڮi'(墉a[z{-{]k9ה'3Y8w\)s{7͇onik6PkCiT_QcE```~jTTvf;;;z tBzE|'T )(# ^E\Gܴ}'nARE"UQljoeoC8[ީۻMUx5h=`|h4njegRdڙCTxٙhX8t 襪6+֔mMP jT}mN`3O>:FB]öߦz }lAnW۶9Qn>\c1erG~Ƹw ۛZ=цꁭ>6ϦfF6PmZmZ ZY+MkԋO$jzުհϦ5)ʣ׼~Ϧ5Wy<-8oM_ ?T@7[ygw`_,?6+/ ?狦r)MIENDB`tiled-0.14.2/examples/isometric_grass_and_water.png000066400000000000000000003145741260670167100224700ustar00rootroot00000000000000PNG  IHDRB¼sRGBbKGD pHYs  tIME#Yw IDATxy$Gy&DDfVfeU}TsfF3ͩ˒8Vl~j, ??~x>keɲ`d. GH33=S]]ufUVҠ[ꨈx'x7x^E{^E{^E{^E1ۑsƑsڋ3sÎܝc/Ϟvg. #ws^,>=`g.8g<_##?09|.{/mwO ʂ:Aۢ?Qy6I/O˘U щ}}H ?+ׂRYl~n;sbSx&JCmԠNPgqOaV}uw=[(wʌ f|*n3ץ폄aä?5o+!1vߎfiN;Z K5}{ iL+ ̰m?ry@kflEŏߗߕ^ 4]Wٙn 8v<"G@v|oߟ[2hس۷_j|sw\?MR9h+Fӧxa,~/lB=ҿ./cܙHt끭k<g‘t%:mexM B:1_C%Z1~˅ dZO[2&YI V֢k`~-<\(ϲ'%bgD1rmO$Xri%Hwn#$G?}5~GϺZES aAZUuà#wRGΥ^@(7ݷ9*㟾 >%ˍ_Zkɡ"#e>TR'𝽮@zΟt2Y 3-qG%핿E 5\M$fܶmUWwnv4J2q΂}\q$Mߕq;2}_]fٗc=ůƦ`{Ƕ nc|Vj0QkҺv\X1c>WaQ<:ny t'w7{j.U›&2]['O]w?m`H?{y,i8r0MƮPn{-qvd|q]xlduNKѫO Fɞv=ad_0.8]e6h܋2q×鲌P<6hdT.m7NΑJ $>.~f'1J|\tE[L)xXZQnU<ƕz;Nm5{`34͋-:BzC\N.V/~s >WR@և>W[_+HX6db&l@vUGWV ;=r׿Zr=]:bV]]oM.ǜz_{[Gw~yPC  Oͅ7Є1 \H w$߿KG$;~Aqm}:ᑬs;Uܧڭ|{?ZDAVb9]V:W?5;@)ƎO+-5_>yn&R{E{&zOr=J>[)ch4Bs,4z9Ys?r ?4~tO}bC~Dt=n@?up EWY OnݶcYveh'OzῼK Ax076>yk磁ِTJg8G'H<?ٶsysq!ҲW-4󷞜;6epVP]{ꢩ1vsp^ȡqrz+~jJ J4vݍ)+$ZfRLRdW}q iz=p&&7oIN2OP/to3ɐ`t{/j\zgһkr{iY<(~D 4^G#w__3ͳT}fㆡm0<|\qk*5G0_{d??&P.-/R̩ڡn-qG漝U>e%5jѳ;SOܫMu]߰ 䊱m/N qWĘI3H9{n|oιb~\ gVR¡6=lA۳򚣏L o)ع.cƯ ,? -f8fè>؏(L7&C;rOa~ ,TK:tдMze$aOsfzT^ӃZƌ%uMeUr/dzcC ֛KG{f_VHN47l`3p.l8k3?8SGOo)-RWNG]7nN5_78@d6o]:haNءVn95NOzV[>3/KbP\}.mxCwIyjǑ*&:j9*Q(8$AmY]}d.(mLݦdW͉dJ#A;`gܛ<s%N gxn}}h[}'1'\<8ۿ@8ў."[)L˒-Ǻo{"vd}ih&װi?mLd~UF{rπsy iEP߰.h-1]`#ȊIg07o c/J%` P$EpA\5pXaKᦓOȨo38(1fg?ǜvp ||}UR$#ww>$Gp~H&..1$w%x"Vs'˫JS;#![YfNsc䶻r&YFG4]1b`VtAWQis/4J=:㴔FgWMQ Z2:\s|(QP;8E;j7X) 9>fUjdҲ$:xs'00?Dz&|[zz#g.y\,JP>s9+SqM{0Q1h7$@?.`SJcqxwigS#z|qAL@p21fVG䙊s'ŧ!;\Soϵ?s'9p7&#"9<;fj+aᵚ|<Ňl+knV(ܫ0nf\C]KF-X` ZG@ 6uStX*E]o:*5B92QJd4y(![nDM܎hũ A)ƿ\\-91Ռ0vcJ emzk4& 8priN^[;%Yc1,Bh)A>8w$B)+Ua9q;_qv+첕q<ϐՍ:}_]ԼgH ;ɍ1FQlgנu^ӫ֢?ܨktĶiLI\_|_D d|BGsc={E6HnߙMV7Ef;gB˧Rkh%Ia'Ay#!"iw,Av-T`g^(d]=7:J}4ptߓŹR~o78ڮi`4QF(>RfRbcpew)cz]N$ɱW*ڇIsm)$VLW6J4 lEL@]^ 9'2}jlo^}ċ؅Q]fM[ҸKQ):." ÐbB #kQR/iOL-hEFW~qNi#C +bݟY,_t[ؾx>dS;W0Mzx>٦40*"s; .[~ϛ훘1^д˅//r70&6Vyg1Uum{V4A n3B3)@ XX㙮ZdFP}޼]yb{T7RA'Cյ\u{ uYU]Iޭ_sC:p>(N307 R*uZ( h|)&BINw36vR/N#;ߏ| 2d~J &k@AEq!C\F[M&* {\#պxUa]!8*WԎOD,"D3(turEx;a!tSڬښ@qGOS6 9j':ZGjh6 ue{D`)@ ç^& %X%I2Rc :AtkΆ!7>2pj:h8w|Ԟg5u|g+ג6n_^f]G]O[ʫߔz\vM8ɯձ R.W(K^;~ObbxQs0 Bj`X <  W::dٔӡE8}n1Uj!oeæxI઩6_]75IJ fgc<-UsNv;"bR'FGp0H 9i  lCJDG2/1J/i2K]tY%7w8T8:ظ5`1l٢|Wq8>G` a|#XAѬ2y V׏FFRt4pt~S xxʇrq$*kSٍ?yv)B$2)?JkF>5Dr+X,zK}C}hG>xuQGm -^_ӵ8Y# Dz!2R(/ 0¯SmE :x<$A`IiJFf-%,M}z=ommuIm5s=ei#}_^K=uZΗqR}҅Jm׎eGFNڪ %~&7n$}Gw\t~K+plqEKbj])J3Э\Ug]i8ded" H@$S')x0ff ̢[ $S:Y%_]hArz{<0fr{Nɳa0Ukufmܢr}q1w]q WD>Ua!ڊ:XI:J{.bTeV=G 梭 ]uuZ KQf=W!W` CՍPX=V ()̄=iR6m/{cJLe6B~E }u·kMyC$ٵxLVB3ObS&^:4@PftevcSOȟ{iH hE29IS++Z (d I̜ ʢbX]pmRBBfuk ɩ+6ˎv18u'|̀n_N]T9Ƴ+g>;=ȩuU+$ :FֶN#$te,o>[Z pJ: Ar40\ )"0R`H:D|.NME\F"8\e6l}HԌ3JVC&Gt-ӗ dG TO0O%-|G+А09C4͢B b"x265";%w}GoM$򬞍jul@YyUοW1:$ bөԹ%9vSany5:@aHCcUlU ̆>d1BZOd) Y$ND1PW1Bt ytԦ$w-e|$fVU[jnB Ǣ;+krd)J򲰹U~T|Z^"C/ۖbn8:eH aX n`CPZZ_H$ p+mj] 45`dAtvC> ]HqMKʝ#7+ OߣZuqte*/jux}-`1 C6f(<&9.08#gt">8D:p  ! d/R3>Ln.Y#{--d{&w=)CI}w}jf8ș#Ù~}4HDz;o:s*k,[0;:N#lm,Xb2g"1d &ldS^@LMGz:3T"&@EAR:rY]+ꨬHdAaw% ErH!5lYm &jYxҶyOέVm{} P\I@v}9H810X` ЦiGPP i- LJAS>?B.A@*PK:/DmZt(6R$R4VoJضiI ԓDѲI}ضڢ4qR{_3 Ș舆T5@"=k = & AJJp!vQxk{i6A SctRֳNH,F6TY!ҰBrW:q>@βD$0BF y@C̑Ȅ0$ARo:@b Rh8 `|HC(7B&&XK(A;kI)LΫqMr`[@=[K d݆.]ŁupW9aEv*76+تS@ #t[ .D@Pjx$pFLBbguf lu TP0$PR"oSd@ $)|" 0;䴾DJ1YuȀnTcX*Xc!KZ8'A$l!he#Z҈mQ8]upA)b(UtqT2&0%H)!QX U@J X^@iDp%tf"2^diQf#hVyM|mp4<"I&&} ?1;nm….l t>M3V*d!pD8c=̐Y%0 m衄IL˃k;XJk^d&.$EĀP_06Y.RBlI;~GŮvWx\#kҜ`&`=UHc,d{`0o~Uʆ)ߑ* !-?ݨZt 5D*M k1Q4ۖH1cb#XE U#H Gq!ˢp˫:ah 8`"LMyBXQC2^5=l4Dr0K6( ۢ-W˸QQǭ&ɆRY8#|mͥ?y<B՟~з~fkݰhAC32UE!3@Z0u"Nز@\!0PY?@׉c:D$yCSX9t5B S8Am^bAO3tx&Bו6Ȩ"@ӑTL42}0)D2jTAwۯ-p&A5%X'1,wSFL2-( U{6!QeSe&$ΑTpi@z}a#n'`6TM1\ Q0c硂N|Y$bn/4 w}[~bot.42,b;c FiCJcaݛ3q$#VD2TJ+>$E>r,*HlڂV"! zkHL/* =dh" T{(0O%@yv" a\ia8: k}{6(/Wdluz](~8ŚފN}| *JE&Ő$a1"pBF^CA F{@<'ap4"IfFAa2XC*%U59[Z[c;lv/!Xs]QO4vx.s6T68i3CI@X:(ܾh6`5 aHH b;a@Gqm*zѲgzbT&^VgnIܢ p٠0RZM h2d 3[lpFq ep /0>aıu @.E@bH|W !88Ghu(aS8BjbðN(!juQH0E:mTyNXia;a$^B)*J!>w'{y8OGJI )8jYW@VHKF$ xCg@uMRF_W4l@He),GqXC:k i x &4B2T[vIdvcYDP k;׷rBz*v 6j_bܴV,&i`)V}^,`, ̢P3 1!ҐHx1Y!N! @G$%aJP=F[ M]@{%BpjZۦf|ss#{0лE)JYm%ӵe\aMl`W9ACqX(nKq$ ɰTv y deSU˕K׏ȆP>稕% X Mj!sM xL!CUXX(((I((ZϤ >5.gbgL42ѻۍ(kTsR/!P='5 A6zzO"Pa@ni!(/*a[0INKj-d&11`'ju3r~$*I Whh$)FƀB 1)VPP,!""dF,f9࿪@@1R$.eg2ϦŬ͈#}B HB"T  :" 8_I: u 6d)! Z+$ i1ub- p 2 ї!cN!Ӡ4 $PB(VkV@narD-,ͯy ;v'G4AeIu$lL^bA< 59FFJeͺ=L, b@1)P]r5."96KB٨GshUK|LZe!DBYDP.RS` })P)8a@PTz!D PvJ "(n-3WWhw%$M`(`qdK1B\) ru9 ) P>#yCLĴ8icF)>pdFw Y%Ғ@O,"-M! D:F=&=Vt[K |@6B9C"H}Qj,@S0Ț r4w2ɁL! e6 CѐjuBDP Tc NaLBV*Zz[&0Dp äh6$ "402EP9`錎Μ@{hKy_ի]UE ̀Yc,ݓ>S$& MZYMq`@tO `32Pj86%ylU8߉ <+)Ȓui wQu{`&2)UGeyK zH+, 2!GرW0ɱNЉR,-3o1*fsS$FYjPB.{D>\b5LU1uaA(3I֢fN ӊKRoiI" ~u|j7Jȋ0:ZC:C$uTb!Eևou,-ZB)Q`c`e#T 92Vd<ð`<%'}C$GT>h ǡPr~^ r,Ok{aNg!k|d "BBaC'fOQ74(eG%&і#!r(H1*{ĎezDA;GuDQPҏBl[u.4F$yR-Y xIa%{uNI+R1Egn}|㨦?VxM!ί9 B?5Ȓi(=Cm'%Ŕ2ngeÈhOR Ն"~mH q N{ $1bL ؘ3UhMLDAcPJ8ZuF'#XM%\BfW`T9/\ E+-g8S_(]8PDXoϦ5W$'|V7,.{u 3YDE0,,-8(%7dܴDaFIet%P[M-"?|J}G9 1ce=B0l%'|E$))lnnUSrHD@P^D@AקI}zѨYp$P+80SS5JRk{C60A L<uK%*zYv8tP)} mCm\1U0ؚ#(TGQH)e5dbRS9o#} hÜVF{^It4%r*,T%aa,0j٥80Q A%iߡ >'\)1X0 a&$a(pFR|6ڐu=zYFⴅ+ 4CInF_w!\P,el`mTr&)_lA:')*vyw b (~ Ȝ%B 2 < %X>Py!?t'@5P%AC G RTa;>EMoN #饟[+ҧ(M % _2%͜v?DmpMB7T>~QhT:D;gǎ рHۖv cew JUKkt3Gԁ R8q9i*l+cDހ$">+e\A)Q%ZrR~yL?ql5ҢGzJhaE. $ K.8"eY_2̟HVW(3rh)>%k;~+IUR5VeNBg#Od$!b73吪*1Wܺ=ËG'뽀>Mo}vSDU-E#Pz }VnZgsօF6-K 0)F*tZ2I#%#$/i (M -G*[^S $&W4 Z5Z Y]&e PvH\P6cMڸ˾8x- +q .{>1KfJtGrE(N&Sd/n *VsL +i$"K&vJRRH 2:d)aOó!3q`ZW, Y ˀ΂ Тr*D"(*SmԔB"?R%ƸKe02K@ﴢܴtV5~z z.'Ӳ@izajhYܜ`M`Saib|G屹!e4W4vX\"SE}*'ސXCaXhg;Fw{n 0ce`GwcKl –BUldzAMqݑMyf^q\#e7/>\@=-rHs\Nj֠xCëPMA.T Q#r ! -gg)P.*, o=84ī !׊BYh0Ȁzii;yM"i{\Dɷ:>wUWݱm-m/d<);s oYenjz:vdbY!HZ/cczD>IGg1. IDAT?R'gHPl1EGВa`(x{ {}69)B\O2X$9#JʙTj8Ah*5}ok. B C}o3u]KQ!jDXШJ_(VB@Ҽ8h;2b1dn` ґ+AhKXXIA/2 *v/!wxPR!9abQAP`M1mqpʹa {~ޣ/)X1I 8')ΈSx,4uTjA9O; 9] +dWX]0<")/pK9b Af(C({8c`-ŞA>b µ7Z(!0Z㧿A&gwN:?$XA#ad\&}o%;GA\NJ:K9 zk9wk(Afȅڐh(X4ICPy8 TPd|,w, ޺j?]+1S7CcёA$f 1~$I|h+D9]>g e MIkO[04&4^5?)XX .>Z)9i/|39b((&heo{KٿV 鸴.]A]24.w\g^j(3TI3i\Tfu3v,uSͩ22 b@XM%堀ٔȒsHZYEbՁ"R(J <Y?!/9UgSfoW-~0t*ogjLkhc\`7!Uƣ vt#CrOز%f<7,,B( V=XSbK9md+o;$Y{҇Zӵ~ݍ֜g22j]oi& ?wTsI`L1P$,u "$]3m-nn(=Ǿufv:ήeX_qג(%Ԍ ٦C Q+Xd -0_dHjC -hq%ޱ K&Kj,N)J9x/@:E9 2(=9Ъ,Ь%9̢#UEBFQ jѱ@ }TQ(OG}IDzq;%0+J0 {{\'ao)xK C+, M!גs(]थV-8և9@3Tc/R_w`b/+T]2ߊFԠru$ztSA\AkA j{v 9kK!K3Yr1Z ďa#`2bra1hH*4S#O]/}I=]Q?$oyI, !$P$}Ң;鐒/i IU1,l bO*{$Rю8t-Tn򷿴uO_f}_E( P7MhD~Ւ~I#Hɘ*hmG<̩WYbC˜5 i6q%OD9X |J vQ:w<i}7pջG-R[Ԋ -Yʑ]b&,҃!C2P䓖'iXCq4?(G[h%b0&epR%D "PGO^[e=ǧG3C߿$8bl)T$Ɔ%v@<3hg$7ڐTH,JKblЉ,VaP \ARԒfAb S7ikxJ|~񷦈B/}Dc'%H/ z9eXcЗ2%$:sqNU/$*+"OlL-STV\ѱ -\GfG<W8n?W5{BS8\)'!Aϐ'aۢ"@\8>2Y/(%0\#1L{[YQYJR|) `I;V/} \7Y&ʭ=ث2A"^d1O$qbP5:+ѩE 9 Do 6\2=+)3pGJ>9X[rqj*@FRKɝ`,JN2k )u_K$^川il'jzB?}XKVW ]$[118 QeBF5b(T;`[!FRfHDZk^uBV#}T9p{|+q[CA")$@;KqÓҘ$hZԒG!0<*h3 Z5s|ߤ{-g;o]awʸ2A*i8|Uac3" 5V9r&z+[3[!vX&xW.}Srpl{c%6|/)c%>SLWYzp4a2uE4PXpx۪\2c+o]Q/w*>ssqQ}R:l-Џ@i7%P3fBV\Jqi+y$o|C\e|PBBf>b}՗:o[>N>[]gS)|@ qdqLsJ}N[oMAiǖ]ius [BAF)z&cSmIG}_}c.\GB^#I ! }Y_[K$I[[_Aʙ%=)_$t%ԐЫBIxN@PHqNI)~B9^wbHGO\jCRge*H0D VHmG[TnY~_|/tI)_hjGBHFiͧV,@ _,x׻'!cBVk;K!J+ `gDb$7@=s/0te# }+3MZ%E$0JR6`h~ '+G%U 4 ORF5͞GX2c?.3o[ݾ7lգޞ5qh 89#`1(ҩC3'dե8 )H ,heӕcr\c׾@"%+tFԟ#PcHR<57~ݭ+;!E5%ő ؘO޶6g5hmnO_<ӾG˦+8ۊSd87~L? ?ww0oEEV뿰UpeMVG+vT/bGW/y3~T?>]=v|#;fmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfmfm.0n6kv|y{[oķ'o~_Kj"@d=C>ԏ^)?Pw{xc߻֣i9-_[;n e[fbQ CBߑo~7>4/ESAUy`yݔ{0.=wޗU~כ;&wO/q眺h}~t..U- S5ofOe6Y]E~⌾5١y3, f3̾l%ZuV}W\.vK:8Z+W"ه@[m{ CԅR;ͣ#2nOs|_ `;]}C]=ySݾRfr']g]uI~k /?iϺnyDc=4P&8ct{vBhSqs"eϹLj],;|)|jyڴnZ6v?ۼhmD6u'N }~~Jӏڈ77)5PG+/ikt7Us.gs@L~"s'GZ)7zѯVw=.~ٽBnl=Wf Kvⰼv}pvA]߿]VoR(r'ܢ~-hJ{yu#)0rz.!ؘ=JW}iq?x3m30?yh<7JaWҲgYX/헭D1W]9`ϑgwos.<L'ه' Gx ;?7Z&IB.T/ԬYRjg 13'}f?-O}=:^PB~*yfceQ8=vM͹>0y"s1CI[A/ߟ]חDZWlɛ>:ꥅyw߿c we_'9rp;)/H7;^7V-3^0^G&^QQ(ί#!n%qWN;=[]$1QN4 '}{v9H)Uf6+ĭw4N]cF^OϿ5ꩌ oV>-&/y*?lo% 1?l5d\0BqH?Wꁓ@E%EE=sT<[%GKŞg149*};n@1FJJVUrJ^tv5*_9QRӳ=p?sF 4*;<`~I'q/:ks gŕ{.* F>%mW+\4W: f]vh{c麟kk0]ܻ?1ܒ$_2;z??^ciDne/ɻ ^xp*7s~'g}-4Hᜁ0,';^bv؛pC{M5^ 5 T]<ߎB!knǶb鳝pQ]/hOapw'37^^7zxa]EyЍ D;ns➬xlTX5cXH2{H.D/f@hm_}@7:ߑ237qQXw}~{*ap׏y->ș?F:9a"fGueK SJxTz+)TMJ&ͫ\[MustqoC}>xJ:Hzx1djxy8EyJ. k ݆<ٓckefa-{an}_{ǵzRcBE183O?h?&j#ScVՁUa6j!|ķa(ZGWgnv/F=0*҉}hj<U,2{~`0(8@zh$kdN<2Y{Eu)<)7hJI)/wğ&_O⣟O^/" (&8NDsB({$ћo=@Q-Z=_6$I"/)*j'ӌ0&Z/©KKO] x^@beGy/+5Y66{F'KMW--kJR1>wC,fB)?r53qޭ%! fi59(k xW~?gR{b?6U_*aĂD}T9Wqm|O<9&;巟k.g# ș}N4ˑz^p{$0T =2DLLFyo4E MⰦjmGWVV7׽t=X]akտYog݃%KOfgz[ٷ3h$0 yØ]vYـm`mm0y Fi,#! f4tOwYVթ:uy2sB@qi|w>}>?'僅{ܹV{G[\{Ys;W$mxq87;sIV{}H aRPldf^b\^şgW]v/=K{~[;xn) 測}|/Fн$o]zr@P@ATkwI=ýR#Q0Z/$rsN·j~? iν3J7S>.mri:;o@˾]l UUSj*rK$$AqyA- 'ÌqZ,t۞wޢyr" !_klr<5Qݑ+Oz]Zgt~g\xɲKV?V}Nݾgxk[?3/;BmSU߫$x3 `oZ WZ-t8ǯ]ô r1l fGPWș wZGX{5V`1O=]uCE߹o؞3| y>:J??1}t~@w%ݾ]BzҼڲ:EAf zM184DƎ Jz-A4bR7E<7?ΣHNӉU#pS\7n=G/yߗQvf}s`?}x~tUݩ_Օ oC#ėnj/4$nIJI%$@1V0ցagb[qGIml[7үxas6;Qz3/`cs-̧9r1܁w|RD 8A=B'g4Gc*mlGS? Oi[?wz}#O쫮_ iVMb珫f6\7?|Fo)j'wj~:ľyGckyyXBȍ;5wb<6$0;v#6?h}w5O\1wszUjR i`a˖v'ݞY~_ nԟV_:ȷi8`]c6[ڧ= FTWU}W*㶌_^xA]]35Tݐd*8m}dbپ0V6}J0dd;|-Q*^_'nϧ4? ݛWݭξ龸iyg4C2X,=zE\Hqk9:r_VZEmdCq`8˖.ՎouA]9‰⤶޶DmC 8  c~$ 0ȈQd~^{\k5g_trR,Wo啖|c>oOܾg?t{#6.\~ݽQtԂ+6"5PɁ14=5Q1Q9G\G)Y4` IttΗ'a`,sjqKI[u kzz Nxe囗\i xG;Gw|fqn#T|}$get+4Ϩ}wn 3̙- d!ڏl޿z[ 1DWkP^V kgǘeMuK/ɶ{U]>}j?mՙ'>O{+7>~ pN?\@TZ`kB\ޑm _*c*$]4'-F[*\p%q%PPR5v*996уI3x I"ԱOXHVqj{\;x PePEѶ!ڰ"&=QࠡlŊs uaZM<}?g>q#_M_O@c~O_zfn-i+owCެMvk"+ʨ\i/}mo7c}K:!JvN X[OZp[xz/ ԯF>|#ܟUCIV/Z=9=% ~o5V[1Yo 'o᡻)`l›-|g[yE\xTntX-FojeֹPZ?e1 )Y}Z zIA+b5 F3^PqѤ''J%=m_w|++r<[ng6:C[9GW8 Ia 4 CU"!ԡI#d'[Qg0 Цb-1T仚EpUw%AƝm{r7w~.+ߚO<f^}޲|_oOSz{u?Oܨtkl/iW!-[!mҼʵխlYPwqKK@FH*6 ) E5v#!66,_5x;|gC)r2ROJy'Zwk קvWO(\Gr+p73_ܮ$fR]ɽ;ʦ lT2k㓊ՀL'eMڬ ISenV\c*,EK@*{ FʁNf o,D zd|ݚ='/}-A,ij /Q%EXHUV0}AX$V2/ Lw`A0PEU%Ñ@[K8 TShILd>2BxTrDNc(FAPJfwQ ?XKD.7"|ݒsv7vd1wWtvVi.2iFit!Yiǂdrg4S,(ٺe]`-._z#z]I]B>R@TH0VpGq-4`ǀW!$IhIJR5}F(+C5"ȴG}\c4=j?_xφ+gZ3ӣc3 `g{׮`ch}b+H"r[WzTV{uPMVa桳 ^x٘RdE#PTy : IDATyǟ.;ŸCy@C,ԂWHtG$A@k/]]ֻѫB»Sk4$"f GtU7ڷ()ξz>|a4v[SGw욓HsJCd AAө% U]MB xMs>r@llT| )i5BY  6B 㔦>RX!jzKSYҮSYQ&Fh  佚0\,,b"mzM61wS<D{HV +F.UI?kese:_@iTInH6;ԖTsr YgJ#YWcKR5z1_vTz՚ !YpV)'gyM^]z=!zW,B!nC&fu5g^ -\U;X ByƬ.>Hɺh-ohQRt,flgk-ZʬilZ1htxl2̤[Xvj 5̋ _YB)i+2 OƨRL,iJ9@JY&ԍ4v 2dQأZ/k]~R{F(F(T,g$EI"!hdP}ȴrRRQ5gEE"#j2~t#g~S1x +56;#F'HU @1 fFg3) Gb|dz˃w7ʟ՚n#G+\!UehJީ@" ̰iy$[X+ U3ms9{~O"KXxQW\'Lmd4RtF R Yka N%Rjch@Ւj/G~ 1T3F%( sRS`P3MZ yk};;hM4rZL}\fda0d/S(G" CkAD5TR-Q Xь+9H;PNah;̆3sF*tcvCvb3A#WW>=A6,&az5,iH'CsL ̒(`~Zo.(isnVX^SbvJj@1t^z>1(~JIҰؒf)3G,58J9"55dx` 6%Nl\ST#pV13ai:sI<>-# 9z>?UޛwT?5JHJEMS$q&F0LwMlu}NiF0548ilQȌe>T&-])[0Mxd?2 N,KDŖ MIZatNXn;}EVv%0xuBa4ّB"Я$ƧZ]?>s&èCd]ZvkԴ Iy"'xdO w " Q@hp;e,)PT ^r±( {T(_vꡏg^K沑 A\XtY(-zjOwD}L%q' ST Q0(r] "=rc + 9c0EO-Ր騼/AYY`Go"u" OIVh"lk=g^ǵ>ٛWyS KT(!5㝂Pя#jB'N eb5ܛg4u`aݤ]||8Aw) JO|'PNhZ' UH"%I qlYL*zDK/OG 6 _'?7BKdkq׼0zN:gÚ4X!ѮČ, [C %eqE2=QKOl(yl ͥEfv-Q౵8K,3`X^ Bf%=L9[ߔڽf???٬Ϋ^ W bШZ-gxWLPXK83NAS'R!vrrˣ҂;5^ñ䇤wK.>st3OQ _\nR 'Y:(g5 RG9#%J`گnC{Yuֿ_m\W|!e(ƒʫ)S陶dRrU ڄ,8k8 pfka`<]մ|A6 P}3N%SWRFS\Z-V8epVfJ#@;^ԑJ9LMHSY&&vqF#lHҬ=Nzd_5dӊT ER~p^WIzQt`m+3!NYk-Z<^h$zW=d-$O!`i<0e_լu<6mK䥊k[GE6*kƪeqKyţpG5R&^HT|8x$}F Ls*!ŁwiY8ItxD2蔊ܠ|͡фd2$ˎ3#"<`sXS3wcq&d9ޕ4DFKYM>A)?xhdj TZVS*H}0o~{iyٮS@x[_k] a#EXXH:#AkYaH=nWP0,r `_Kk(N@! 6r4ĶGD">suO !%P߈vkeV!wOm5˲~7A:ڲ-I0%'Sڲ~9bvYc*cQ׆,|#Y[E[V?mFJgH|%%jl&qRӮD5m{f?;+TG g qj4qNIyqgOVx8oFB>&'X@c,JÚLmɒ:A+i@fpkN nM`=јK+N&#P3ˎѬEp2FѠkC(S`/>r?hu}C^O5 Y1=C56#:t5*wQOY`7jV a0 P +jA Ğa %hV:֣g$6K?7yu߳{6:/]m.UDi02`-f,hu=DhJ`i ac|(3G҇u#kLb z:4.K/X'Ӄ6D 4pSSS'sܧ? >uvrxui;EU# =uΊ(A$~FGzܛq$ Cjkk퓜$O2]Th4&,R @ (5BB4|S1 x'٬-.⢒gO=/ sXkR!"P݄ 2BI? Sx-Emʳvd£8VL嬯z\OyB{QeŪF C#2ȁ|} YkvrJg"CJZSnHYЯC, \š@h1(iM_BxQ~ĤgL,P,ݴZ6P!5R*%T"KA“|Ks~eXxh1ӄB3*CNgM0jAXނxdR G( Au$ZIRk1(+q|(JH2H%POգonItU:oA*P狝p"i\sG,I[m m`R\A%r@hA)wD"?){ϴ߳7ӡ@u-X5.,L(E/i'z 8乧7h=pcGrtiw4#BJ (-Jg]6M޸}wDe9ߑTfTϩ(H!!ԑ9,I^b(8 AEjy,GkEDzrȬ9GJ dZ<ya<ԇ*i^5;@0_] EgE%2D;Ya"U7PҋsJO<*IREԗv *3-O5h#Ɖ7~l*Wάά>0UVفXGr@(iԴrV@S!*$S:qIJԓ+EuբsǨUX?j}ε8ۊ/tҥNvo(M$#)h ݒ΢dgM&4:T[" i,0VVgNHXA$&(wx8BMo\.-|COUӕ}QK+$B q:T/ gQiUs4-j͹6%%$$yF$J+{$On g M9ZOv/|<2agUJhNȸrX'%Owy^Tzw hl .O-ȞI<\4K (ֿK:NBq^\f4Tܣwʂ %HeIL&=y#G[O#ԌF8>;5{8k"h&.?S >$? 1 Ku=2XxF9wPKtĒzHJSc2>rA RjVHYvw ꞿ |[n1ʀTWIUH:G:PK1Gv1.EHG!UT9RW IDAT8eQ))YAR[KYwJ❣lO~L{CΡ̝:*49Z^ЍO ~K7~vD)eЕD=h7bFTh,鋆r/j(>߼ [BjYR$z* dŰ25(p֑'F_qFJP/RFC'id c}IG.HxgٓF}}?@ q[c:H7(eGw!u+{SI"]-Bޤ¦1Z9pĶؘ !‘!PTZm, 2*cF%M3,4.Zֻ}vxF/1qD8oٻ,&~ߕ}ި;}hnĝJg-Ri>K ]ZT1C ߲yTRPmӻ>W'{bk?ReZ*,Dٳk}VzBxqz> Gog}N?Ԟ>tpR&bnBlKx *9Y~Wf6}I}| |Lu]|t=kx>x蛄x.ULbHu&eLqqsօ|^b\RGw IJIx[, U.Zt҆ks4f wn,}Y>ITNiC^e@K_|.y9Z{O?9^Uyt¢?uϽTᗊƟZeq߫/Ȩ[ؖr|N*#OX!91GuxFs*lsx"?yjoؖK:k?;?{kgdzkx>8fwLV-Y'oH'*_JJ+4ʮAP_WՆ+*T-0zJRn򻚄O32Vcެ Ԅb%wO#j^]wݿәY7'oZ[½E7ްq Y0U4_x-lF䳮vbd6P"$K1&^{ |x{%;>9`[b͋k=)Ƀ.zS;??tmzޔޞ_͉*5;y})8"^Թ L>a$ /~4`1]y#dD?xfrU÷F'q/tGey?-o˖:xȟРċ~Өv]p.*-gyܶZGiŋ=EZnψ5Yڨy^)n ڢ`z.qjA+SH$"Nd鷛@tSeMsV&ߜPAaa͟T Yxy۝3`'vy7[3`E+ZbvaX50k֢𥜊:zBWwuQM9#k^\x>n];8[Jm@H (=uwi-<;2&|43[aKO*ES9<80gqD>{%zVOՐ_Q}7Kd&k\K[=+0>BC4C)I)T&$tHd=KcrYjYX>@RNAp>(kߚ N:o:9u[M\}hd+bO>j]棸u\пfYj!&\eQBRwu'/4YG'NŇGb?w}G @}+y r6$'=z4sZ;?4|UsfIt}Ï۫ΰA2?(R8iSQěh߱#ח3/SrUp`M VՏo}A/v^0Qb *: "^w% uo%#kz)AO2^*q4biams^_Ӈѝ>8w#,ca2'.1/FpLs4UJ+Yg"ovdLJW_Tཫad'O~ߟ~&x+_2Jb6*4=W)k;sw_K̳[/KIY˷_~̛W՛~:[}N=nO{>}>a نd QSJ߱G&ڼ;yͣ{+J3ՔgG_`AMKz%A>ƫDZ6-t2V+Q!e3@3Tjɜ'ݥ2~M`!ZQ_Uϖ-{wBrKnޏJ,HPAp9}ڷpeK+(]$?׏4E #C9Ta$v'FH_?O^:e_Z`ӧ^Vo@|MmRB3axgW_K)s);n9sw!d,cڹWs %v?LD|:Ou_о@ʹ 63%J,o17X[O1oBa]4'<{tZP$UKNLL%Wocsd8'Fl9 ߷#t)yl FmAf|8Jon]H{c?]܏{6OS[͕M>FLJYj^^xm*m7^oT>91 =]:<ڊ#?^4ZWv_/?r&tĩ׿`${Zw?@m5.a-327&nU&T\Ȳet+wC{?kf_03gJSϖZN@e3M&j>GufTsf3M?v/MsJJ)2wx)J JwҜ>t3W_]Wâľ$@L?ɿzZr!0"9+>\2 =2ԕ)ıƖ[&[)[b5Ns b3E+VG#߾}J>f8 zt Z*[j3^zov4E69;oӲji,x9 L\Zbbb T>/zg#3ةd; ݾxzZ}RoR { S8 $HrJWGޱ?9uƎ|y6'Ί%!(}d!ݽ ( 1q|{^V Ij_A}`L?JQ/316pG BC0[ۜ>|G+lEg i]~ڟi%ЀւN$N'fo%k]V[]V{1 @"b똩U(Xlu3K$ǦjeWZ_꟒^r{})J9n8k9669f)fnTw??TID lnDi"im;om@_Mߞ19:j̗|eLw>~&Gz_&9t rK.Yg8H@J9u9qE)(eշn>4Br-zܝdk.*l*ZSutmaɾ̯Y#F\DTgTo3=?;XaY@ ft,G((R6<`tI?&pxsɝ# I+%bkQth>V#Hݔ^7%(R]3,("?rl|`;sWJ rn_;PQT&xd{4ȍw0|!R+F6$ h^&W_VeCc5?n#@P>_y;g4?gge=?Vfi.>M_Fɗ֍x\6/r$%Rpd@z6lLI.B(ќ9|;{25%?GW~_/~ș^4n8J%UktoOcuv!$GӤ8!LIƽw1 A8*!" Jk2HR"B( { J >#w\g=n SLM%H$4em5eGF6#%CP6,!I-F*Tݰ^gZd΁PJNNUMҮKuz?3W_wGR[^eq :ZnZH5)$KesQHTv MJ9*qlCV1\AWpl͵7H)|P{s?vWse˹e~V>SrdFl_Z< p:;OqS qH%H͙Go~h -?ΤV#%gy^˽OyI) ?pnTLuHIU€s0Zs`^Pi iLwzsћGw>=x.6wOq,$stmFf=H)AIr,cWQ~(8eΛXS5 DKRP3Vac[Jn3Qml }7VmIg63y QBl>fB.Cs#>>!FB| Mi}E[{-50ꕆ6sQ^ԶIH{[|U1,jp#>1owK.TēC.# $I DXb$)]Bcd RH8gB*6MoNnKfw+<~Wb0!w,&c(Hfy=]EIgl &aQNUz E%^ho5Iu4G Q96F;Ph> !RƜRIj,/Ϫ(G73W@iǑ]SGnYWH*NQQk%릜IҜhƄaG-+=JJȬ#NsSҚ#Hg*!9r}2sy|r{k · ʓRuT,tx) E?Ƚ#PF8/HLp-Չdt{Z gg"^HͦIqtYFӋl|QoRWzo!ByLP+/H'$%'P.BFtlT "K;gP?J'Eɓ:{֢!Z0*KDg˸"VjUbZ&&0h5[F!|z0IuPTby2&|{Vܖ}o[$||[GFyUkqVL'Ț9c*]tLW5^jN iɱD8eWѦ ړ6%;t_(l~x@Q;wCTA6YPJ0:᝻264﹧t>Z `_/KIc#4) <uJub]+#2S"!ԌD!r(fNI3J[P8!H:iu&(!B2{kR*eyRؖԷzJ-mݵJZim6X.)zpv S!73@KYo2Yv 3`U@.9 _XZu }ŖgH@PO)8 Am{Y(w=ތ[t٘ydFDžvӰRfmÉ;z&W \@0:N`HF!0.dk˳%fR\>_!HyJLp;؄s3[Z+9 Fg&:~5uz:cbFǷ.xV2UAѳLcL64ŽZ:K1I4e7Y>Gl)` dN(Dh@ *xZ\G)cN4:>4fvӾx!+\r6tN*{e8QG :'vR4"Q%z ab$OYF7S *o꬘ .SQz~㐛AVTHLQ#٤?]VG<j3rtqriҀlQ_u{=^(;ӭLJ IDATd.bYP`.Җ]\C-" Ң3Gִh6 Q mY9b`cOY=0(r'ы)A3# PMNnS&:DžY;_Re1i+Ghk6&w=TAFY:ck,.kI&rbF饫JS8C=0M=KvT"*^-m;=ܳvo8{*?!g"CIAuyc*5WEHtB=%48([R\AXYpźjyHYdyOH3h$ĖwrrP.nL$7 q#jmNجHJ=>tmy=;g AUb sC:=$֓XOQƒQJu@[V*.*8]ӠˬQ/򐳎uX ox#=9Ye!axY{Kub[رY#fJܳ F&ח$w v)7!/f8IrKOAf;`ω#iZJҵʨ!_u !} XwSL&(!#Ҝz"R0Go?s1Y-*' YQħ`ZB-'p>%w}|߳mODE0`KntY$I]vN:#OѪD}Hvzdj8IqSTI}K}z6us&C_le,C*GdKO7IPiD^: {g1ĽZ[h (9"d(@D>Q ŢP!M6d!p6/'RܖLg^#ZIǝ:87ΥY*!yG/( ~La-qt3OIz9Ĺy~C`r}(pKFHmZR:7pMZYMIq͠_\)\ݭR#=~3=V^ $ 9) -D[zmK͌s҆ 7 !FT$RB 6I=ǧ~\Ki}Y'T6mÆ;AUd1H! .w~SňܤڬҸO2[fyzQB4h-+ӔtL$ooηo`pԘqОށ̅Aw bR\%9AB!]ԸxPr ȓݳ$Z,L (m8wZPD{l̦c.H26%vj4UBڔ %87WnL兿ybmMZ{)ynAEzO= y.ILN*uw,wX TPll6c#os!$2(EFʢ|J)e g-靹[~[M 7~D"4lE倰/l[{xS͝XuiYdgrZk}\K,,[cǶl+q !! !.tMr d悘p}\rQBn01!ĶlYJ5WSgZ8J؉ȡISZ{{{.)FH}MmSepWlgIхWJН,c5&(Gyו>&IH87NӳhJGT71v1sͽEuM.p=);gzIPN*sO3.fIM# "Z; %'YVl `G)v-:ks-%$:DI Aѩ<D1ТiNJfAڌ!Z,-k7J"TU KU^q6qIF1(% Zd! t6n1=g]yz\s|p{Aml6xJ)$Ҡcð4$A9g(n{]1kW ==@\tWUcإv kCwO#1 ^S{Lt1|8~1m&ؼUUBl0BLw/smB(Ct{Bv&ʬ5n@V]ǬVN:ŦqίJb1Zct3:@Ylvۇk:ڮ\DuNtW7ƚij}__BkZ~i Fw! 1@ِ<&WTD!4 Ak4 )IV|$M$rB]@<=ea=i&XہܶC\Oeܣ2ꪥ4 ]ʗ4ۚ Cf*$U$a_ִK'הۭ3$>>9⯔YD-X7O 4JBE@(<+I)AvR5Wt;LPd( ;a %#wR^GSp=\/hj]=7y䈗;"Y"U5M iXȸͅ*mz0L"Y;T¾GB'-XkN;Yr|VJN݋O?Ț_=krRxpw@h{|ct >wA4%T9|k B Ʋ& ģ 0%1Vܙyٹo)(d)QU_Eu"Gج b ar]ms9$lRrJɱQYTM_4H$$ |c5fuR(AI{Gy!-TmfJ= I Jha6Q:]ӤR{kbBTʻX3( :Ce?I#;H] IM{G.4-4yq|GN.U%.ud{6zUs©#b(Ip$n - m5K',p߁Y,Ju(Foj,=sb[+ ? XsPr3Ccz" $DW\+Ԉl~2s^˩E\]c Id\*ѡ5X򮃣cNbG'^]]\h,y~x# tv;vMM&Xu)Ҭ.`H 2QB ւWHr\+qxac'SKetJw1CcPN]>Mi| ^Hu,n'[̺n @GQc[|Zs߈/d`ra IʼH)%VaH;AĚva:Z= -tWfyME[matEGoy \,}'%r>": ,~Z).2]\u:.ǵ:zD pt X뎢3 8d5tR=#/(힜(;܇|d%;Vf| Gu\q\%_ bK(ix#WNExkhrv]g_Ooq;Q&uA⵲NpiOә{K 4iurDHyؑ^LW,=dw ^^fWĐ' f gYcVw}WE]l4VF@J iEO|c7~G^=$tnv=!O2Mҹk O4kܚd5i#HQBR*"#9o}?pg''AqaD'1Ѻ8@P)UFƆu<␙,-%?B*#%ZQ>4~@i<%XR2>Ru:NqNat#j8kLB'~1qjS+ۥ:9#R>+PJ SޙMwy:/㲠 MfB+Ȁ%-u|%7MWCr'$j3ѱZʰW<3C.М;؞d (=Tsqˎ#yK64_l+;H|_,UgD ݎ^eVb0#M{]Nj}N|CÃXsD*y)0Iza[T4 {{F*1]7z%< "y+_Tpb{VSw*Aw *W-yti颪oy3x$5*Ĵ3_myc|ϵtRU' 8*jk 3UZ&$* 10ImbH_b3Z%lus % #a1'|R,p9pLiDQ~G^-g}bRoQދz}\/9$>*/ 帇1ݧt zPP;Q^| (T)z E{[ ǘKU#Ra!{ 7-Z0IyZ/, d ~7#tNuUE> >^q=}ރQ:xyN޼xr?- !`uȐdq 6񏞙N139Tv\ ǤyK_~)?oJ(A$􏊯հ렓kA$.Fo]M =E^͘Gk\tx&4V= $}E ޢU j EX9Mz-_=`(;Op]Jӱ-w/8ԅ]kPٟ5sgA7^O׏{fX^ 6(C9/@+f}٬'o͟CЄ0q$蚁Tlyg 7rs=e Ifxqc`} :'yR2{Yu~W']@/{V+Fuʮc!xb 7~kNOxPWr2mv!Ҵ^fD?8( (WC=}}g~ĵ&ءΆ /lvC)>~l=ȣ'|+US7:lckG;_B)Jз効ܯereEg RQyJȝǟippTʾޒWμ,/+2y Ϧ麼W6`䗗np*f8s*vn:-~9g;6x;^׵mfWrZn޷UZ05uyUUƓSI_Z^MwXq?ц#rL6zElQU=I_d>xK۟:^dQȍ =Gگf{-sсi[pr*ٸmP=PZ$I]OGE݃XK ৏ί4.oqL<!%yݤw!^},;o0sx<5Wo<3ku]Jwmo"z.Թ9ȿޗb fe~?i4`b IDAToۜH|rwm+{H^ӱaG;oxG^M?xB^?]7OϥfҤaQ7~Am_o rr}~0 hf3|_lCB|]O/c:Qɪ W;'TF'nZU{-奣 ;8MovnE07k⃭.UW>Im/ 4nyhu7io1*j zdΏYhיVgr#_5Zoi}ӳXthfH_~O]Vy9#2"8p}j[/sl@(m{!"q.ň{t:ġJL,w+R͎}+}y.(.,1  -w [.<9{XSn- UvCaNǞNx`4}@A;?%kDnʪ4=8=o, `b^SAoNY69;8;oJB!veW5 O^vg׵p(OkX+addAFYcP߇-x@אyoU sڵ%e7y}6[z{fZ 'mn5: >k qKI.%Uvl̊ѹWgZ,\y)@HSD<P7][$h=!(&lNyt3uV[4d pv[*oUΝ蠝 vm_JZڵMq3g21|팝 {Iz)/6O/v_¤Ge1L/H(C_'V{}ۉRjөDrv'Ҳi]c=<⍬}+?7'Zn #s޻O'$B&qBdy]~)<+kf/;.*pTol\mƌ uI Wj%[7q6|e@]x҃^[汩`|v%Nk2'qF_g VB毭xFwѮ I]_V[պݚr|rcbx3ɕ: #gkѡ~w5]H @n#!73mWF0S[\{(TK8-*skVtv %*xI94o ̹iWeUKVe^"͟'\dP)z~#z79b(2 B4z8E Nh-e3 M3]-SպwgdG 5sK2QZ/(C.2p`q.g3 qgO>鈜ztEĂv3:g1u/k-s׬B iaS2#pJ+2",b aW>8׮eF^ln?oONM{͈4#U$ ^>ZX*ɸ;lϵDAra0 e&`.  D Kp:̕9ЎjΠ>,!/qSlLW"7rJ~|za,7Y]/p_",%!8dxlm{"*-4FknƲC/q'$߇܊T9wfGLvnk.s޻AMS+:w~onU!OA4ٷiѶ+kH}7nr16  xB0v [)<ԥ3 sfj:^oIKfkwz皫!Vl>gñJSV۪+:ֳz+_Ngj5bj2\OFԆb<0$ı&I5鈿vC.&78ebaPe$ũ tD>O~Y1)zJ21 čhBhiCiģPQχz_59s<|i0^ϞcObUeVW;]x)Bњ6=50cKrawo{-wN>! _}*2m f[|ޔQχ7L# CYcGGgK֯gV\C\44d:я[щy%zx{8=8G+AkefCC)Po;VӠg-՚2NdOW~^%d8sL|1)I!Bg˗Wvx[8@%eȐws~߾qh岡=SHn_(aD$$nV Q7f! z-A+ eiu:eME휡^CyBR@**J;^O^5V8:v\72V͗ϨWSbvѩZ8ʚm!PA * SC*|Ga+IKIӾxT,C#q#b,}MvKUsSS'?x 6A-:j&+>=ewɳmAT5k yt\=DJNFB^MTJ\ϵ^Dlۣ?}$%d")v]r(jw] G>̶X:b`L2*8x ~Yc2FXC:o C2c=lx.oxtp-OmV)=qNa&F)hcEK#zOwJj2WҾLx_^uj-=XOzl{n3W&g+'Nm?NறטwQ^vn+|H; ,=1+c= v~|#bcKٛci)\$a0Z#]@i $I B*2#ލ4G?556xy欑y;-S?9p;;7fNiB,5FB)h CפS̆+(i : 0fk1Ų@YW7Pº&N4/] s%߷MO_^|ǮWr/cqDB`!҆v$D1_ "ɻK""T4B`Aa%kīf)-2Jzգ^ (YM-f18 f xz춁Ge'"Cٲճq߼x,CP8^V=+ M|BrWJ]p?/,n.ĸAqCѠq0ȗ=gmrU%|sQ-WH>-~'np͖]VBFVUeϜLػG9&;7/ږS'ȣ18eIcss[WL-ߙpp<ֶ5ze.Mʑ1}zrU~xiiN3P 'W"(1e|o+2P6uP{ÕmMGfEesguK>tIʨj-SJɕy`Q1hd)>QWPh˒|aii܊b)"q*6I$(lhC$ؒ!@6C%hl!P$Hj0Nu )PRjMx4F5BZ2jюcQZVr^ZyRSwHՖ+2goLӤ&]a5ƅּTJnn3f5Vw~pr{Cy % @I8*Eںl`(d RdbL C1EVI?y??GrfS vRs_Gfj[ϴ"R5_1}6=||*_PuTMk@y>P \%zSڳl6uuuI!1 Elxq[-{˦:\zLYJ4 rKdIIu29$`$Iu⸎%CS^:nw7VLA P''g^nECEqhJIiZS Q|H@D=Pq |E> [T&v;趡ގ纐WD֐I=Ri۞p'l>p,[ݸ8NU-IS0))qm JC&ZxxF1%UO74i#\L$}hiCDSX]FA45ӨWfo[e͡My}4Í'|C1'GvϽb%(L12HtBFZV3R(LLE'_cD}N^dR. "~N`R$̜<#R5RJcӝi8hdֲXWlAiDfbgZ#Eym-_8>5#v)˚RpIR* y0Q*8^unB (wxͪ\ʙhJth[:Wqi068eñ9) vT$hDmi1X$R)y CcQyö _05sF3;c@UxnQRH dx@rv!]ЃzxFTiyma<- a"z*X  $ŗu%F m)9\B1`%- lnO|ax,?ZK/i|!Yj1%ŭhi(MXL-J'E`%h,#Ehxy2ҡR5`ޭi) 5D%TP$Qu`5Zƨ(ChA% G;Yefo,{dJfc1fd X$:Ƥ]VՐĒ #F02a! *x,!V̜I$P^$vs.?˭Ke{|JO#o]hYiK 2 EvnS!U1Ҙ3K) LSnjI`yV3aI@̶] 3gd ϯP_YȸC!HEHdW(bH1qB63cR`AIܩhTPc'm;[3e&#P&QRe5#5%M5, h XbqYOFCa_KX)(̶[hmH)PBƚ8Ğ`#Cia&kYʲ;`RsIrc_,>V5+K5I1[F4h1) @w2E 2"`uaǣ!;gܠK{(YN"6,Q ni Za7NhCqa&dޠ@xlOHTe)-Cb6)5=z_X)ʡ-{ ~V!ԩ!UmG;!qG7<۷/YhbZ>uHaz1%N RAsՐݨټ'Ԃ|!)Mqfɥ!XmAKų1Dmb[D& IDATnM ;Kٟ0ꕢmĪZMZXkȱ 쳴OHm@y SW$]66PsQ⡄G:uP('G}e_u`8)9;N@ G;4%vR!;@ Jb!RsN CcQahCM)7I>i'TО1h)ȦbeK&E`YN\O C+%M-C aHXY%c2؊"_S,!X 9RZ6EtPV3 d ư&EXJ:;t*m(D6ԿYJ}Lέ&MetLjs78ZP -J ĄS00xXmiC^8hQ43g6,ϡ&l+8_k39:`I#D% mi fԥ&!v%>~ːg`ףϳ~yzq:n_Q<^:(zc5,C$P`Cu1p9nXd"v/#p(d"r0I$'=})utClHdZJVvO2^ihy XiZ%IþdRX>k ˖J@Jփ2&X;JUKx^f2gVp=Dx%,oBH8kB*/Ƽ::5&+Ԕ?:Ig]D#@ zG' 9AC*xITU2b# Rr*=\ T%Y"ϧX64*asjGC9Β4^PF%Ħ l\JkcSߒ㺃rb5zL*PyEX$8b&I!08Y&.qmQLg9#p$Z3- זH*{)YB )>jL1)#zXFxH`P#j?PHL}?Y1S]]oAҸ?&qyz(bz1(]ыD;tŠ4 6B$W?߻Kg֯WR]3ۂcLHʞ%B)Js=E0g1 U)":f.ٵpҎ4]axr@|!M^c48DahɱlYKf)wK^ۯ {v'uS/8P2e,An8iwX4J +I7Xňh_르PH|Ofvi˜~yR FJ!ȣrDQ*q0?Wإq&,BwOI ԴyBis[P}LCHQ?BT!d(~X&M(3iKcO*cv8ċ D֙]IВ)CiF=N8LU]43qNk11H(ۃ0\P=GXJ 5X9]aRţ=~MiX#K[ziw )g=R\ B @kXD+SAݡޛ+#Tܓu;l;T=(i8oWHCl)e_%"m֌hfVRF*ג8X +yF"M{A JI,ÄĹ&srƐ8E`>X#wN3J j\#/@'q"d}r ;LVF;i/He7BwzAiSʵ.@bB* x#Q(!qm Xe@y^O+ʨԂՊfZR>Fe !an.儩ZHh siIx͗ά\ѧ(Yd1,(ؕ*V!! C ϣ iS(08\\ !:L#=Ow1ygi;n+}0y0Hǡ8g4"rk}_I grv XM3PGB!w]>#@7ƶEoʵ&ma_P،AhaL^P~|N``9ꌡ(^fmF@ϣiÔ,yWRbeWfR\91@)Ɍ%Zޗaixu3 :W#E:I2vgA*V}Zg_5*Y b-/8ZVA-J*b-7*%UxiC70 &Iϰ4Hۖ|K]yXџXO_i|Akj#5 "acۋߐҥK!n6k0X,G(>0xRkÕ_ ˑ<5zp8@aQ>GJ,FFHg *ҝ5(|O\.j;7E$Ȓ,zsw8R <()1Xg6#REDCL_)hEbe1w0RPBqfRaa|qq|%a)A B |@8"ϛg}mpJLo:/V,XRK8&4O1sǔS,Ce{@e,d,L^1M{Ck@1GsM<'/9.)L'h Ԣ k쏑E"G/Lvr^| *o(!٘ɨg28o9c*̞ͯRI-X$)Z֩G`bG4; Vc]Q+$k7u)(r P*@xRww~T73Ĭt{ϭu{'vƐ @AXNVq*gc`zT:΋>JGUPehk͌Sg8)զa=cH "[k^p䫿YjR^}R1§ЎFXXFY*ZI ֖X[s9\!΋1H;(_,v 7 P(B>RBmz[]*8RcLA%h!6K C! ק ֥a̮Qq) Z/%,hF*EW^Ɍ!_z$%AE)JF8g?F^0wHA!TqPE]!}dC0@]mg6QL*IjNNTF,Y-K- t4bTOcTQc|Z~龥}\xe#qνt *?&1F0i+!a%*n\[+C.Μ.N@0 JFJiλh{?7V Kfy/?%hPwujՊYFLR c1ڊR_>-.|or9P>ʏp&=0RݹO8oxޫ`!H ߜ9;/:Eb@žm"xqK ơEBBjB*a02=TU7pFRBuҿ.a%BB=GTC%"|e0¡bApIH$ȱ@A+n*P3BK_8avE<ɉ9Y0!J6UW4%X> +4&.G*y EN>B*#ԷE桑GEK2I;FZFXTD`LY$͔y3F:GzeHN1w.=r7}#J!dž`t֏dyy#7;4ŀL_IObQELAH5(kϻ& >S,S{ NI )L}a4nq 1\/1P)Q |LYGڵPR|4>˨ "a7?|iv< $/zoR_R@<պWwv BqϪ745YL}{l0 ?,rćw.=75o\=WRb:L0r':8[!]!Tyi|VzZG;Oq^TRȥ2vmx=dñ/n5z~yO4rR! ?8T棌cg龳/,Upz9M z[ls!}%Rzܗ=|;G_n>,}_|څН8%e`/JnF 3b 'VC4)Eaoҳve?W8T"a΅}Ko,A!&e cS,BCP>U~cRI%[3J_w/gSؿ~E4bfخ,͹  $dn>۹PJ'J`bMiv RB2Jrg\} %bxE1;0&![ ǿ`ޫ3Aו Xtm:T>Jy+as͹r,5NTQ*wtkF&Qh$9.RA|3(.t5Os9q\0KoS*݇atvXHu9l5N~7u<ӵֹCD! |ꥈ8ӟJ wϷ@8QR{#%v(+ Fݧo8~d Gԁ`!RGo}A>;(:TQC@sbaۨ/tʦ&09k♚ :  B,F' DyFgS nla #{<;(4gЯ[tvܹpѸ3=^pPAl4yFla #8ppP%Ҡhvyk"Fw? B.槳sk [8S<{ߖƵ-la [-la [-la [-la [-la [-la [³[;ܚ-lq~[` [-4 l` dY }[6:!5oT c0dɞǟ TJVc 'NJ+suycR' IDAT@ +~A]kw>{'N뻱^O^eB[x#۲ ϳw! q4F(eL(Ko/|vϘ7uYAeq]o#d@|+Qu ؃ښAzUR2ゲ;/91_O}9B'߱]pww|HSFW +w9˴'F~PyZ˹؃P1v5x۟ңUNNgO wtN~qj@U-'Y.9wWԥ7n >Ū/ .>{78xb{ti/8g{is_?2w}LPG/,[ov>O.k2ݞc'M`-ۧĕ9m6׫IAcJ,?׼m}nrGOtcyr>uCZt}Q=Ғnjp>3&]g7o-0g7~5H~KqwgJa۔աmyi ڕp gDݮ\vyᑣ7^\"LgM F~=~tqI;VWŖ<3:&ج.HzMͦ}Y~MndfWkM~RjS@ѩes`]FnϳU/97Noqi3Di$??2$ϿW#ə|fC*yt68-FCzsNLn+V(7׳P^ӷWbW}qu8}ݏw+w=;}v y;\SC_>XhZX_cldycV2Fթ_$4:"XG[5%u~$<;Z{N͙9l8tEo.X]xQ-/\-OWO8F{#d.dɄ}֗ =`G_{\s{7sCU[m誰.9}ƅã8ZfUW\V۝َ7-H5;:]lXͯ|ծq5?dGIu+@\wf}PҬu$ UT,k?33n4Tr;74J|mʑo͞jhӏDC-sr3֑m^GU6S_t&/&@=q-0q^xx?FtRz2'K8"dpί2ئX`ۖVbkfĂg?zdVZ1.=uVmn;2JͦE]i:2VN3N-g?7N_++.=UV5k km$f& ~G>rhU.8]f2xdye,f&'j|m$Ҩ`UrÕF+m&:'N羯 Wt[4x{?us̢;P׿5B5=vJW :8.&60@q0 bk ;<,1oK6W4ˏϑ[r^s8?m>z켫1>F6Sپ?{pu3@Ym-3HK 2*O=yz{#'C>pn˺Q/$u\7-~Uuoe]{ҿ+_7``GfZ?1wp]ҪkT~$4EiiH*G%ە$ 9JCZ*d XCrtp$1ǥGx+gw\*ĈPuAzK`b~ղ2~S.su2$9۽wM/Vln^U7ZV#oً%/xSɦ8lvl^scy\ddDij_-)Xn|Ϥ;8qy /ىf3P7ӁO컶 :2QJE-1)u%N/TNNMoW~HT6n] _ܙ$$)NJq 8ȳ^v#yZD_Ļ?>Ry *7{6ox3੽Y\gѿ-v~tZTs` N:5ܠ4RAw=e5ъ3>eʍe&EZz嚤ΑXCϗmC2TKt"@ )L ˊN,G V# EC3*McV3 ڋ # bG)tQlYYIf4BV[鶡q 9}vv.__/|:jU3Y1Zwq`&u zh慪f$ǒ0w7z=0gh&t&M|u% B';ߓve?zžQ_>rpk?27μԉ,ƯC?˶wݧw9'ຫ\N.SyyRGfp6)Ajwtmfw2qQj wPkY I FЌ*ra\a(/*r^&AK9F޽Vb'Hۗ>|\ɧB(|[e~.ۡ2ر+[a,QI+g0&ǮTBpq L`]Gh%/(c8BGA& J<_e"?{ 7j45[}9m6iK5UDڣ#5VJ]!x 2UрZ.;LKcֻ 9$cx{j?{omUy~gsI%Kd 񄌍 !(TTH:IЫ:鮕Tzi(hRɲ˩D*IURUJCIHA `cl˒-ӽ3?}W1pkiIz7|odSlxpYOj_kf}sg ͋ .FL\Str,9r}Itv!; SZAiKJ"mr u2(㬗ᇔo_ڴq[_=/{nl$G|T=j^j~"d7'$Eט:uxV?xMK|.}wK;-Lsu:ͣ+}0 浪M) EEMq[wG-p 8J[yKRa)%)QQs#sGNmltXgN^92Uc 4K V!I;kJh̖bc%Ҏ%Y`Ԗ8j,04E(ԛb]CZ~LOK}X^/玞ߟ)JH)%;wHԐJP"J#FXP~Bs܇t<16_('4k 'T?mX5m?fզR1.>:۱~HԢ837,_̝?wx+y>S츅q}qݴy ٖlY [yP{Nv{Q?v+g')! ↥ށu%E==(!dA]'6y͡$!14'J/ f VAo@ f%q@$IVflN c ӄd/pӉ_oJf%Լzb%<5 pd~,8=+E{M6 ϵmNLLֹR,+-Sh+jM{}^뷬Xa+=~Yѓrȉ;dtv @* DBDQB]T 籮,Tpe.z[O\$l}b¹lK(CK\2[[ZG[# [gu~kP~t(_lSc|0oayX-ʒ² &v,-\#ԝ>yO֓U)Hޔ8]B-h3syH(l$Cw)M9ɑPޙ;zm{u،U.`2`n>=Rv!='#^+Bo6< Y^! *>n92!E@4A*}ey!Q]Hm,oo,{[_qdv#q',Vc'm8F)Q[l\ŤJ@55""֚B;tlQ4\fcQD;Ҵ$ Pq4 ؉& XՓdG6IUG"q x#DeZ*jۛy{nݵW,R6&gܭRB yTY rRl!D HD=x%$޲Mxm͔;Zt%sqQSD\דx ;I\?e揝?tΝOe{nauwEz5/@*5LT8,q;+s/rmx_Lc p"Ձ"D > St7pN`l?n!rLhF- iv6Cz]f},9\`B;쟟e;+i7b W@?îV2"!mEޘe -zݫ\'ݸ(o[1*N0*ݜ@tFR |uf|.%"$XL^L1e3dSئN*+I,d!*rM[RK9`猪 $#x\6W[3{=\( {OJfܡAo8YGh o@!J *Z 5aiLo"eV2AO= IsG')"bf.ecHbJ=>䅧H@KUeS#v]:|j?"~jˉYJtbX9gD mlHU+[PiraꊭN_>ᆣcdclmb !,hM΂> fX[x :Kx\7ucJ.DH98K!T AҬb2* kIޘ]tU 87_Exq աif(shCy vJCȰb³iVjā4gIkӸ0dBRHD]1H*,+?TA B NpQ%/htx[7f޼7ljY{& [QU 2jfMjXe1(  7)q:n"{H4UW 눨AM#$ k ЁB VN{bP( TZ[>}iKy:g_jM͟qtNAmuU0eXi |+VmO>(MW0t}FJ| HGv.H{Ll%zFIIH\,hQMP$v[(=JRi#58rr~lKb}k~k_=}q:6 C.ZA)VC\JpDZ`Ī3-7)^Z'> ͽdk4F9Y`cm7Y !n(AM@T*Nn  6ksڥ~@S7ԝ6 m 46'oRdR 7g!gk3NNfI*BꝫlS@QgdsSuϴ\5cFQξlex" .%@\˩zXcM8 0*fQN5ɪ$;[d]ю}tIDXI$ӳ~UI-\1%¸?"w'>s_?}{}˽7;&C)ـ@!`jGK  SIhKRa:+-tw4BdSg}G1z, 6a@YXaM U5T伭lsPpC@1QL7>qB-|%>c,VZ:yB3do4HDHGg⺡ T]{RpdV8` _ :"ˏ-]"ٓ3Uwjo}wA@SU~@1῝ K\UHu\ B "ݝ>Y%&yNVZR ѳo}[_^M6V~1= * PHdPTzۥpIL6K0̎HNHZ NQgT2mYtv$sa"HYr<Ҥ*:= ZcYoIZF \I~|:|o6C G0hQDfT DQ%Ut=/4JzEI-,>ըh1 O[G @PfeGU Jaǿyow]r8'VPR3a*9zVh`y4Fwl?i}"*qII@U0sUm{P !>$eA! D28S־uϽ<7WWߩM}9{P⠔Rr*`';xn~PUer(VB*2.*[]]ٶ㘕^YzYlF;(7_j;Y_^M֗>9o0:*U&TJ]ϒȽt8<yI5^1DBL,="r #a IM{%q! X#-'V`][O.z]8 \-f\l9Z $mC4k1M+)8llu,ZHGGY%[Tg_f1T:F[g5o]yB;zT+â8Nji_iVB΂T0SJCf,j06#/Amѕ \:ĶB cPCQ&Rj=}u- +a֘3/sƣû,5PVCA OJ1TB[S%H%jV_~+B;o~5RA*K%gX{g\~ܑi)) **ߚ)o)j Yy!/ה:LaBd209JiEi2#JGaJ\D+`cyH;<\j eN+L(dM=Q {AcYH TAmiT@9O.w?7j/NG*NSb%4D,J. hje$؁z],0aÖ揽KB=ٰN%ĉV?C(AkM)4=Y4dTv{p?lSBWA@j AnbU_"Q5_dgw=гZ䢐T-LC W"1.=AQ~im",iK`ә?=wdqi)AoYMyys' okaoֲ Y]& eN,w8]%c84ꝟY>7!n-Hhrᘙڒ} RSvl:@(!?w}ɝ0&g^]GJcs}{]߻WEz"%D~#{"RO'l+{ǎ#9o,K;%e]S߷ܽqy\)qZEC@lf%K%#-+N` g?uޣۓEgH^zн:qM7w|/,uLQe*UIa׬eJYa" je-+qKsGO. N)ƕ;S`MqHuY~P6a_$@jdֽ{/4]:W;f7J7@-[mhl72}|j9qZ|$ƲE](Omֿ]W^5/jQbO !N<+0a1BB7F 5z4g_TAxZlQ fTF[Ȫ\v@v](b=c̷fҷԻoATzӿ5ѓqZju ;_/?[_ ݬr|Q9P0\wlQ SB l">ԁ!ձe9JCFUw{"RVB AZ_ 4X^ !̋3Hٿx7bw@SJ< ڹd5b0ou#( ݴ=:%]2~Cs%֔g_yڈR[;8 e6T|/|O ĕ?Y(D{+5SBլYz!V#T=Ew N )ز'eׄPKG7/:k !/~#aFaFaFaFaFaFaFaFaFaFaFaFaFaFa^Tx'wiKPaEpRC] [4߬]Ow{Zn{ơ?o=b{#p]:?5G~uO]CqUJ=r5ɫg nF/d7o{lK+njʱmJH adoD9 i/n3yO|EfQ4ʉ9t{^nc#޶c++e[}ö-v^WxbVLܑޞCÎVǾ `1șqB נ(o ?y7hg^U_qļR.4&0wRs˨ cANq% xָ[Kq^g]]q1]ZOh U{rlfdj2&.6UWx.e&~.7]wߦkgk>=јƛRyER"5xT9w|E2g7虬վz(4𔼎i%160P%RUD#?wtɋ*M .=ut&PCx,uaxR~]nC-9:~M .[y.բ0{K-z6 ZU]}cy%:~' O%}ØK`MCp.Mm~lxA~G\ =/^ua}X6bյXR2AC4߻ZK6\27ݳsmZx`˫05G%d߬8~p_c5s4mtl}ݿy-^ͯA^0ûSr-wVv7*5o{|29|m{_¨ěo_]u+dž ̌}5XIRNZatFl Aנ q256OgD)~1 U۬+GIgaι;t R{7uDR1L^ҽD;E0lA{)%E*+W* ގ A]R'~/5;F{ KwoK޷13aHԐ0HN\^ $eyP-bJ.*%**)%=*fI,4i ,6}.rq{b%ݧЃoGy'&=q9c RJeޖER*Q؞?q摅SgeGgf7~ѩ4o!%Q,NR:`gJF(C[ʾCZIDTK-UHe2&̃wX frΖ8p8p Z*NړpC3ڪmNGرۜݰļlp6 6'ī+fK9+SNyc}83_z˷yп֫u/>-Nӛ>9)O>*tZ{T*y ނ)4Y<q[NF'˅g˺ۅGNE-KxXx1yT_S\w#f1 4&p^$?3 q:Uy B* rpT/Bjd:-,yHu>Vg~6}/=}u;d&rrHW7Mӱv`Zu'/hnc-]ދf ۫.n=wƗJ5)g?ſݟZCn3Ʉ#"/)b˘Hh ^zcfaE"8ØOȅf^CcMb&wjSəAM~ÏStؽOMɯZ^ec6Л:yAm+L98~ ʺً&qv7HZ91ۑvnS_ S@@HR-ǃ) -fچ~mCG$bNıFK*r(`W"`,hM+vL~eovz"g]"輳F:c*XT2l`@J R*HwPR4U`#҈!p!Rq\4eq15xW\8uJvMGygt W;\z/<1L?>w 8sl-|EZsEWK9=Dwcż 93%g9}%c=Q 걦TYУlY .[OVxX2"𤉦/P=EQ04+`'p s/לYىoMbg'c@{˵pVg( c.N]u75ן^a!`0B59KCj=[!%R& pΏ 1|U0H !DE:k Bbz?-kSW הVqNZc.}!,PռBQf{MTc6\<o ZRJ'E\p|F&$kQi<x>Zҋ5q|v<Ɔa\b)#8>1Ccΰ3i}B[EA~f䐊Ly oN52QB M%Z%JFE__i'K?=8N IɅYh 'uszdfkA ~\3 =Gς@I&ii, :JkNCX<,#2MK&ZPpG@.s FSKXi{OIv6r\С/䑣_ah19pZaWrWͷ 6lAB! ]d$+ 8_Mr`CJT_tԘYm蹏tlJw) t{h‡*%{| .~H|r UBW%B]E)T]E~9=/~bgyK +6\S>w(pz[Pvlݲ01.Ҩ YIyuj[1=YN"Nh}$+ΐ參"dJ]A$;4DTȟx!jy0 2v:QdXsH_ou+Pa$ fS[cpO>YǡFřb2z_6"m&ey]:m`,2b{VAlFS-D-P'+vIfͷoov^N:~EE鵸6qBVJ ?T*$E@ZR*J5Zc>y)L<*\ENBL9LBp!D> !kJPi&U*9HW=&U ![Ri]eHj f?qɻv{'MYTF JȐs/to"eN2cHtSi .Q{,=%)"c2Dcnx2&s@U]Hm]hi^d j;Ә9FBkC&P*ڭZW*ɠJz^b}A!!$]kiLF;XIKe$WZ :QZ .ڭϽ/:'3WqMEy@:A +#kCqy>T+v+TjB :x Sf"ֆ/FEPzK;*ΎlIDAT|Olz %{OʱWT\Gɀl|բsC!/P Àx^/!!E|ŤFȰp`?/KGT!#"n[7:a$A[F_s;BJT>J"cJ>, A*T/:._P}$ai۸)YRtw/GwEM٬SsV}7[X2'k;,(%HU+Kot4'~X sCޏ(Rv/ϕ?'7ᤐDVQqgvͫUMJ*`;o8Rà1EqE;{ mpe9*g@W$rdnz582޺&QUeFC^ YŖ#{8U]ei8ⴁNQd+}`&=H\ 2)w[~&T`u#gvf;"3@W;'ϠSTUh@RRZ{ḽ4-V(+]3a1<4A[OgV݀AtlYKT-$.<ڨE_6b g nK*B 4W0G&زXκYs,/,v XTh 9" 97^VPzL,?ehqqc]J(> yۧI3/IdL Q E2)p$/Hfư(\,מ7ͿcM-Q3w}JPB%Rı" yYsU;0 * [7' 8$n*M=,^[ D-̖1MhgYWn>էO{z )*.@a%U 1wԐW!'eU}(1Aݑ[0>?wATn=TH WFe/]^S{O-WU\JpdG>;;ȃ #ǚr8/9pH ]TTw.7(EYZg=M>$WU f',[ppqAhRnPAOMm' RLiaKu5Epg"9͋y"@(AGz;}`O$[B˷䓼 Ce'V܊KZV|q Lo7 eD*^] ::siBAoF˥L,QT(zm3pΰvci[(pJ`|k/<Ã0GJr`z{ Q{@Pt#G0wdC*U5qC`PBo*'HϿ]7>9bi (]QP,xDu! [SHBQRd=݄a͹].>P߭v$u! >]7|k? T!& %mFJao~;흚ɇ\J]6ZgZx<1ڄ8r-v w F6ǫ S1QsXƹ7ۺNpZsUE S{:d:oQzÛ|{[Uv;%*=J{%UbzYFx]J^PJ;d6Wnֶw+2/%JJX6%H6,5%eM1U?~kʿ8sG"'mhMv޷߱QZ7',;)B1TjMw^5ޥrC,#AKZTn۳_Z=N]JHy1kpkO; *Hka[QT*U{r(޶,o?wtpFJ^DȈw"huh_kfL[BFşo+/g?7)WOc1lO;j[|E2#<#tL@1+L޷w͛A>u.{@o%eY 6zؼ\ϕ%{l.ChЋ>9tD!?O+~7pܒRpزVW[5# 5 " P~w B[?? r9ʊ=!iliڳ=_RزXYz˟py?h]o驒vi劸Xwɕ KVygR82t!+fw jdװ*V nYI{ )Bʰ˷'/:使T2φ,g]8>3pAhkw ij%g(IИ4<+00H2"p@EJ܋0e[EɇG~NG;Y?>6?#@cU*uA]ugBqƖH>T)2kK,J!ء*]2P_Ά"Wibr,)e{B`l؃ `qk3MSFuO}h~:i_}ο'd{zIFU! nH yۻcZ ︼'|?ę%P-wa={t԰JZkv_ŁU|,.|k8%W C[ڡP@=;W-M!ڙ2˖mON%O/IU TvX'^T@)$B)*/( BŁЈF0symn;@]rx$0r6 1$IHz,TtƓ_~G濟5(D>Wef]3Dp%઎ \ek ToXSKHy5 Bl]/F8dfe8O4p7[d{SbYcWF%oko d_-e$מ{'j -* >|@'1R%X[. .Wޕ'W.(+[Qٲ7mw.8҇W+eD Uw(/-!D۳ P] ~TBѥO}􇖬-~kw'AD@WHuc?c?c?c?c?ǏP1mIENDB`tiled-0.14.2/examples/isometric_grass_and_water.tmx000066400000000000000000000040251260670167100224770ustar00rootroot00000000000000 eJx1lttywjAMROVgyqVtAoFC/v9L68xoh5PFPGhIYktrrVYyS0QszZ7Nvpvd0n7y24L1Q7MhrTSreN/le821HZ7lv9qYa6sdE0cYs/kX7PXYwtfaevYp7WDrd+SnHByjYr/npP1zZ4/elcuM71rjeckdc5KNHX75fMwc9s2uzb6AsYstJzwrv5/Tz89SLIZy8v203llV8xl7yMU+462/v81OqA114/UhrzUxRqwprnh6ZGzp2PNQfPqRu/X9hnMV8F/xLg1L42erDf2oaa2RI2qPtbgbhmw2H69nMUxx/gVccXdC3AW/o/HV60vW59Lhu8arDxmfGIPFUV1qbLVQEIs4PlOeHQxqVjmzr5mLYsmf+5Qj5yM1r3Ne4p1D5VcMh3qWZibLx2fYkBhPYOv81I9wbrGd45zFU7zrndpwDjkHXXfej9zHc3EG+D3AWcCZMJif7hTnVxr6i9edtoBDz8N7kxqbY6sN9gJnsnqIOqCme7Un76579sIV8dccHvHqZefH76BP9wjzkVapM2rL+5/8cR6QS9eh8p2AT12y5oO9+7yh5hzLZypnHX29/pzB9PE7bOg8Mza5KvGu4R7mp/89zqvr7x+TnxEn tiled-0.14.2/examples/perspective_walls.png000066400000000000000000000071641260670167100207740ustar00rootroot00000000000000PNG  IHDR\rfsRGBbKGDC pHYs  tIMEnp IDATxQ8 EmUĚk5kb>:b &[uTEUfǕ6;,G1bkߏ@JǣFbYK!֋~m Dј)*~P'E~P'E~P'.C!Z"mq?7 S'֜鼘sF/9QMR]+T1Ƭ {} E@ws|"@?p @9("@?p  ?4,%"@$~ IB?~'$ OHW#߷KWSϾmj̷̷*O룦bq> P@s=v|r}X<h8Z4py%C9Oj `S2@>i -}R@;D@i)y/MuF q<"m;,~>L;c!p TXc|rmp@g%Jg8_û#@{RK$@H -Km@; @-@}H @9c8:D[&Zod F49  " PbI$@?ĚH @=E@:"!E ;B&@@9H "e!@iI$@^Hk"#{^mxKvϬ&[kU\Ϭ6|\37?)}1F]l"isX>?y47~m"h}0G%[9󠩰2Oڻ>-!ʫzz$/$}ǯ~! #?~ I@_Hȏ_BG~>W$/$}ǯ~! #?~ I@0M]oQγrߒ+NǾ*˂2cI- UB! @ _H~/$_$CB0 %ZMs8:o= /$~@$ B! @ _H~/$_ I@$ B! @oC{U^m8*l1 I8s '}U۩ Ba;_jtwx]ט82*qi}w`L~BOm! '~_H - xrS$[23!k0'}a[!{O=U_b⦮g}`q"˲{}0 !.ڏzd&i0 J )u (z N@`G  1Fs!|.-͓ iw~`xx%^E~GO`1dlЙ8X2ηwre1_='*i ð@xmL@o/z @x @ 60sX@m{cX% ðj> 4V[ pCP{lx総 HqmR{n=\_Z[?{*z5xnOW' ^F뺮Mx|PKV@؛)6S0!x 6*L @(;y  @ @5ċ=@C~   ]v *Wh/w7rDO6Ub xvyx6r1-  j\e@C@[\+k;鷡|^ {Q~=r,,g]8akc0Vz垀a'DOn_r`@Ø n=2AN{s kz A@waaPn47S,i}!lCR_}ąTIENDB`tiled-0.14.2/examples/perspective_walls.tmx000066400000000000000000000015121260670167100210070ustar00rootroot00000000000000 eJztlOkKgCAQhLfb7vd/24SUBqMMNevHfDB4LczusihCCCHkTzRay4XaDP7rxf1882ZpzBqTp/Wo4c7ulRy96LUKRx3EFYF5+GpESpA9V845pT/Oxijn+luIw36k8vf1Rpk1xPepx9vczV+O3GL6n4JJ9vkSOf8/Qwb/r+vHP8ZVzFwTQshf2AA5owLB eJztzgEJAAAIA7CD/Tsb4yJbgiUA8MO0AwAAhy0rhAAE eJztzjENAAAIA7Al+PeMgz0cPK2CJgBwN98BAACqBS0QAAQ= tiled-0.14.2/examples/perspective_walls.tsx000066400000000000000000000007341260670167100210220ustar00rootroot00000000000000 tiled-0.14.2/examples/sewer_automap/000077500000000000000000000000001260670167100173765ustar00rootroot00000000000000tiled-0.14.2/examples/sewer_automap/rule_001.tmx000066400000000000000000000020651260670167100214620ustar00rootroot00000000000000 eJxjYMAPPHHQ+AAAJfgA3A== eJxjYMAPPKG0F5T2JqAeBAAmbADf eJxjYMAPeKG0DJRWIqAeBAAMkABM tiled-0.14.2/examples/sewer_automap/rule_002.tmx000066400000000000000000000016451260670167100214660ustar00rootroot00000000000000 eJxjYCAMfLDQPnjkiTGPWLUA1AACYQ== eJxjYCAMvKG0FxLfC0neC00dIeBFgloAz9QCVQ== eJxjYCAMtND4yjjUSRFhFgwoEqkOADFsAIk= tiled-0.14.2/examples/sewer_automap/rule_003.tmx000066400000000000000000000021451260670167100214630ustar00rootroot00000000000000 eJxjYCAMfLDQPnjkydVPDgAAZj8DRQ== eJxjYCAMPAmIYZPHphadpgYAAL88Abc= eJxjYCAMmLCI8SCxuQjoF0Lj8xFhJ7EAABfQADk= eJxjYCAesBKQ5yXBLGoBAAmIABM= tiled-0.14.2/examples/sewer_automap/rule_004.tmx000066400000000000000000000020341260670167100214610ustar00rootroot00000000000000 eJxjYMAPfKAYnU0rOVwAAJk3BME= eJxjYMAPPKEYnU2pHLodhAAAb/8D/w== eJxjYMAPePHI8aHxeYiUIwcAABkoAEI= eJxjYMAPOND47ATU0woAAAgwABA= tiled-0.14.2/examples/sewer_automap/rule_005.tmx000066400000000000000000000021251260670167100214630ustar00rootroot00000000000000 eJxjYCAP+BDgk6LHBwcbnxy19ZAKAMzFByE= eJxjYCAPeBLgD6QeYsyj1BwAd2cCSQ== eJxjYCAPiKHxRYjQw43G5yRCjzAaX5AIPfQAAE2oAGM= eJxjYBgcgAVKs5GghwdK81HZLcQAABQQACU= tiled-0.14.2/examples/sewer_automap/rule_006.tmx000066400000000000000000000025431260670167100214700ustar00rootroot00000000000000 eJxjYMAPfKAYnU2JHC4AAAEbA5E= eJxjYKAMeKLRyOKeWNj4AABbzAG3 eJxjYCAfeBLgkwoAKZwAkw== eJxjYKAM8KLRlAAAB9wAGw== eJxjYCAMeNFoWgEACrQAGw== eJxjYCAM5KG0AhFqKQEAGSQAQA== tiled-0.14.2/examples/sewer_automap/rule_007.tmx000066400000000000000000000023351260670167100214700ustar00rootroot00000000000000 eJxjYMAPfKAYnU1Ijp5mAgDb0wTB eJxjYKAMeKPRtNaHDQAAdfQBLQ== eJxjYMAPvKEYnc2AxsbGx2cmLj4++3ABAGBjA4U= eJxjYCAMPNFodHFcfELmEeITax4A5OQCSQ== eJxjYKAMSEJpaRL1aUJpbQrtBwEAMlQAiQ== tiled-0.14.2/examples/sewer_automap/rule_008.tmx000066400000000000000000000023761260670167100214760ustar00rootroot00000000000000 eJxjYCAMfKAYGwAAD7AAmQ== eJxjYMAEPljEcAEADVAATQ== eJxjYCAMWICYF4ccAAHoABI= tiled-0.14.2/examples/sewer_automap/rule_009.tmx000066400000000000000000000021541260670167100214710ustar00rootroot00000000000000 eJxjYMAEPlCMDQAAD6AAmQ== eJxjYMAESkCshUUcBAAH2ABN tiled-0.14.2/examples/sewer_automap/rules.txt000066400000000000000000000107421260670167100212750ustar00rootroot00000000000000# rules.txt # Copyright 2011, Stefan Beller # # This file is part of the sewers example for automapping for Tiled. # # 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, see . # lines starting with # or // are comments # all other lines will be parsed and treated as filenames. # Feel free to comment out certain rules, to see if and how they are working. # So have fun experimenting with this bunch of rules :) # First apply only one tile rules to fill the regions # # We mark the place, where rules are defined, with the RuleRegion layer. # So whereever there are tiles at the ruleRegion layer, it will be used as a rule. # In the RuleSet layer we can define, which combination of tiles must occur # to trigger the specific rule. # The layers Rule_Ground, Rule_Over and Rule_Over2 define the output of the rules. # # Which tiles should I use in the regions layer? # Actually there can be any tiles, but it should be the same tiles for one rule. # So use whatever you want, maybe a colorful tile so you can see easily that these # tiles are used for defining the rule region. # # In the very first rulefile used for Automapping it might be useful to define # some map properties: # "DeleteTiles" = "true", "false" - This property determines if all tiles in the # whole region where Automapping takes place # are deleted. # That is useful, when not all layers are covered # at all places. (Check the Over and Over2 layer!) # "AutoMappingRadius" = 0,1,2... - This property determines which regions are # automatically remapped at live Automapping. # When you draw directly into the map, # not the whole map is remapped, but only a little # place around. Here you can specify how many # tiles at least should be remapped. ./rule_001.tmx # Setup the right transition tiles at the border of light blue stone tiles # # Basically it is the same as the first rule, we are just using bigger rules. # Whenever there is a light blue tile beside a grey tile, one of these rules # will apply. ./rule_002.tmx # Now put straight walls # # Note: Compare the regions and the set layer! # Not at all places where a rule is defined, there is a tile in the input_set layer. # This means that there can be any tiles except those used by the rule. # So there are no black tiles allowed, when there are no tiles in the input_set # layer. ./rule_003.tmx # Now we add inner corners for walls # # (No new features introduced) ./rule_004.tmx # Now we add the corners for walls # # (No new features introduced) ./rule_005.tmx # Correct the error we got in the two previous rulefiles (overwrite it once more) # # Here we can see the use of input_set and input_NotSet # With the input_NotSet we can define which tiles must not be used at certain places # Important sideeffect: the empty regions in ruleSet can be anything now, including # black tiles as used here! # # So when you use both input_Set and input_NotSet, you need to specify exactly what # is allowed at which places. ./rule_006.tmx # Setup the corner stones for light blue stone tiles # # Hey, there are multiple layers called input_NotSet! # Yes, when you need to specify multiple allowed or disallowed tiles per # position, you can use multiple layers of input_Set and input_NotSet ./rule_007.tmx # Setup objects now # The objects '1' will be placed. They will be placed based on the # Over layer, which was created by previous rules. # The placement of objects is done in south-east corners. ./rule_008.tmx # Setup another object. # This object is based on input from the Ground layer. # It will put objects to borderstones which are near an end of that borderline. # ./rule_009.tmx tiled-0.14.2/examples/sewer_automap/rules_sewers.png000066400000000000000000000004721260670167100226310ustar00rootroot00000000000000PNG  IHDRH0<sRGBbKGD pHYs  tIME/#tEXtCommentCreated with GIMPWIDATh 0DёpInBq]¤ʐKAnKyS'$mg=yz= @d @ @`,ە1h->qB$&1ILb|$&1ILbHLb(N eeIENDB`tiled-0.14.2/examples/sewer_automap/sewers.tmx000066400000000000000000000014271260670167100214440ustar00rootroot00000000000000 eJztlUEOwCAIBLH+/8/eDSBQ1jTNHuZiDKOGxSEigxDyCWYRtPsx6HBH74hyn2r9zT2T7uj+jPemW+sfrRai16K1ut1ebtEZ8+aFdxaU27qj5a7O1FOfRd1v86XlZc+T9RZVt3aG6FrX/0UIIVkWa5oFDA== tiled-0.14.2/examples/sewer_tileset.png000066400000000000000000000533511260670167100201160ustar00rootroot00000000000000PNG  IHDRgbKGD pHYs  tIME  4@ IDATx[q&Ed99} 93$EYz)JbY$w5 7 0h iWKQpȕ4953"WLpN5:zzN*"3##ˠ˗/Yw7?< xn@sz>|<7= xn@܀|<7=G0~}—'aӾS7q_@0D9#<BcD0" a3u7vBNr ;`vu/u"{ n۾vQ}y)fH^0fٴ[ն,QDβ (%9S]OG7b+tgp_R}# !p+挈YUlm;GUBHJ&eSaXdgYE$  sȲ̲2k(f>}(Ff9 TQ%JITc3|{#D0s˲R޼xE$V\Žle)uwk7';͚~H>c菟8eu~X|_??|q'ox:8wF߀Vw9B6_aLyN= p>gaB ~pTWD͋NWðdV?S;_*1w", iRLY(9VE)ʒ$hFD.Uy\^qs 1y޻q{o<wHnD.eZ)5Y6#Jy+yUi5/H:\ev;;WbL5w㯫|{2ʼ2`Cpn֔|YMSe\>,˪m@zg(;oF;sbwXHy""F0텐3{cښ`3O0 > }:#7*l:1熤t`s*Y@ Xbc6M1dry>gٷ4|)B&RU9׹o}ƭ@7ndOϞsi_|0' S۶;Q.ϋmBpy|r>id|}c{o_\:d0IJ(,[5cnxCp}Ϫ2 mQd݁">0t]_U{CVQL}}),(QUm1<޽lv7f)jǁnնY0,~|:#'rY/*Dn;"#""sNU@L{v"2&Vfd0{Gnsps!_]cղl֋g:wy@<96syw>Gqbs"mW#vDn^gW.qu41R{ݢ(wnV[[4~ZL&[nl_Lc>Vs@S7fYi&"zq (ƺ(򔺦y@y<2MwyQc8|{(te1BpmwyKUM6^t:_,ny< b}>jޱij%! w6 |!.S1fn:u[߹|/-Nx8G/tC$݁,'ʈ/WdYQSۻ}߭VI>,K_TCYVxMU\Um9Gw\/ yM RJ¦2e>F/2^g6%s7lwǵdV!fjާ}EC ES1Uu fwq hsӔsL`Vbj0v Q8m+]wP 떪vq =i<`)s<>%$0St]}PMiH^!{3M*"c!"\MIј6|(fQ7\sXU] H!t3z<۷|(vm۵O0'{*Ӷ_|iϹelzpqw D`R"<~ksΠ !m)YCYȽwmb r9E@1v!87Dpq Hu;¹uV`fa6穪fuòh6͉19$*0|px'Di!=ZރOߜN>@a1D"6f޹"0tyd2޾}cL}dYp 5bqeYєTι$ceEӴ"q6v.Lj.h`C&]3xG9 cwEADž(8+i4E6:b`pV[7 G]0\׀lKaGyz#9[%aM#T 3\.hND16]wQ (fy=^tg:wy|,>|Bybr|8D0b݁T{չuFRU*eMTM`D9Um}Osf9NI7Xaw.yr߳`֟^gBdXz{8YBvJCLd1;f9@7]AJٹ504)ufN9wUTcm$3Qf"cZ1DѸ 0y5KQ{)8ib0,NBL)u]\?Pj)adS!3|r qvc<!q5/{aKe9my|rʬDv}I$@DfzULBw,-˒6m1 ̕LD]\rڲ D9?wy&2"L&`L2m;0O$"uΕTg 26mߋ;wluk@f(7;ŹuFLfJa&f9bNIDR'llt*/PY^Qs3q.;׹㛦_=wjǹR[Й]D5^YzO&lV}TI!W5hTMDLXU3&BY3 T"Cm.tMtJD5@]3x@=GѶysLC`2f}4Kf0M#"†j$:LUU["f]3xU#f "}٥4}A$XaJE6b EB`esY{s躣IsdFY$kMᓿ$YUͦ)-gݶ2![.HPJ2cv")<,_?_/<*ﺡm?ilX=z*gCui26c qbdH,bLL2mk,lm%H)Cv̺acYnL(f1)y}D\u6}|&*c>,tI2dټjәemȲN5ER\?*ER,U%%23f 7MMa"cv}f!@ckp{_{c\uЫ_]<;;xmk'\~?=MY:h RHȹE,+fv!xU2KDL8 Ȳ67JeFf!7aHu,2%1ZQFfK}DRF Oi1 fq1%Y@# #,OvXwcYWuuA8ʲ(2"Ld(ˌ4c{su]_yJɹB`UKIz]}YD_Z=E 5 261sgf*cy"r9G$D6m]瓵A۸HD6q܅Yw2f㟊 dD1q-7'a]}5f郶q4 їa<6բbL'3Qs{w'?_3bk_ GU(A14L,clo 7.p }RϜT$3O㳱':6Fh~?\^oz"ڿ[G?zk2!~- s9oxUˋ21[,x^:q,? 4aCpRR|_UrVNZ1mDb"h7uҩ'33;C֢׺oxa`o r{5313#fJdU`{fN)oZFd]!3#i-L1@zU!Z^ZMqRRUYJ`޻!`p"c:y)&C$0іcL5D4@T7.l]#H(}.i<@k]7¼)//,\\n\3O)&Qv{6M2 92Lj*D,˲< F7R* 2  Ar31QұgދyƺY= ;lL`֏ #vqg}0!*T))Li9Q8fL;+ ff^:`J0pșy6i pDIm]zk6hXS&"9wRdsZ`JTRL;"6qclp%KwP- ,x!:s89L혉r^̘3UzƦ˜؁64<~z2_Ώ vb'!2(U +P31;R3fj͈:1O:>^˘d6掎.WWc< s䅩rץfEAD؇L j 0B9bZ=%!< }0)sc &D6g 36NP:6p,D3֥NǼ,߀#^$bJDFDc2 Q3191Y{/XUydcspƄ-=NTs0i!l|I* D@LDS%ϺoxaԔwvg S3 wqHf .9}qspy0m3EATy׋10UޙI&0 Κg}>І˜h>YU SAP˱C  @3 q2I!8%*h0SfDs0^TkQh扼' V]^{l/8z=b_,G"ͩN>$5SI!&IkWzќݔi˱#Z5Itc֌P'M'b^^ZS^9˜3(1S"(N%ΛFscT1Ù\9ǪJo N+Baq ZE9$~ęŔ ΂cA,slfDw0^ `|s^Tc"s3 3:"xhC0vߋPl4V$0d;%!g(&3rϽHm "}0#Ib@gll 9cfysĹZjѱlhP]%Q03]^#/`#/%Cgd4d!s4 v*w "rcfn1LD$HjV9P1-" yfGdC7t76QqCyaY{ߊJ D옐g@C@|1cRæ8PR%fgfc5!@::3G&&j6Sk}xOIhgfF4>x lh0DR !$$-π(%Ĵ9LRySZ&QfDC f>"/0S8RUcڏwD @Z$9v إ4ံ“<95l>IFӟ"ǫV)&f>ΚSJk+yn_ (NWNi`f1!Hd=Lkg6DiUF7 }o2B&Y`"-&瓘ڻwl;uC(+`uR0ALg.k^^aMxGά"7lon:r}?$սXDRfdly 53km[Qe&%%s; D`&"jm>dSfȟeͧϨ׺94Jf_۶n\:Ãa[L>x$ 񅽽|n:ԝ9GGK aն0ԷoNASXm&1%;O$LAy<U|gct>< fY^嗾J 3)·_zj5۞ 0V eYwpLRtp/\-~nhӫ/̾k00E m=Xbf\)fEygbmzI&K; zm ;>0d|2Fޓ&>=ú<[^ItE+s'?^ws|[T+pMgbml-d^|o|ܒt\z޽{Ⱦτ3| ˂'9&by1 ! '`=a%ظt,ҢFNs?>&FY^뒇X,?fՏKҲ7߼qƥKN(T~Z=|9(/l' P$)*I(4AEyspLu]ּ.%bqi7nΧ(0cc8=ժ~zy,γ [5Kusi0 >|뭷~ڶ}6٬at38Uu兩*NUK FF?J1.y|c/|9WmwY>5 XlT.yR-]>dYUk6 GTc)%Uiŧp.s>Ÿ!0@0R03Y^O!dWiGÃM}v3Z/lp:0skήYT3z pL̼wkEk+) a|UU Sev4 7y|J,;N׭rzrԼ"*bf;҃cHFTec{w޻̃cʲ,.ʲ`b(yEyg'6W_bg?;s uQ,ݽ,F{ 5oz2/O~nd”wJ)iMŒw`v# o"ius ׯ_4PU~>EIW_Dʕ+V}vgVzـm Iay][u('h3#κ|y&ITo/eYey: 9vw.Of1e?_/|*0:w{fyaky*4zS5?7[7o8\eʃbb80@K|[zɄx׿ |L#~/۶~7ߜJQs=Xޏ/Y{pfm`823f23kx KB~"o~s\>涗7|Υ=&}ֈYDe9MB8ߍݻp-@7jkBDcrϱ0ֺVHLc1J$/C ieY0W_}ã(WСwG~vIMI;'𧺏O-?ğe9qVKiyX_ꗖܷ8?~g2,2]huԵ]6M۶}w}}[o|82gojGLHNѽ\S'7I N<c [eYtz \PQva 8̶fGCWb-qޣ?i兕 "p" @sy pzi!C8dTLNgEͻ+rG>#80#0 qq+"] L C/2,/, ̶+0Ph؎"ˡ@᪊UcKNi /#8CL\3eY6:k$HCXZVΆ0 BY6i9]:GFp@;d1.ITr68(gǼPE}?"7݀U^xX2=rJfKN"]-c JՖĘ̳"J|n޼_yEe2g3}4Mc':=<D?ꃂtz!pxrcX>#f " )|oɲMqOvlmTl1jA{ҦA,/l\te15Fp+t8񟗧/0e3ͦR}Z,G*U`:9>j7Lڮ%<ПG;OD?c(b D[.7n}t6o߾똀Rzrlcb2K`lvDTuU 2m4M~a .0 UըtT%Ghh&([V-ZtG6#mI$ޱ@vTlzVձ0.PQ]5PH]76`IuVSޯ|7gSSN~srbE!~9Nk~o)"/{z`RU@ZPt6Xwl481z]UZj͹Z)2jY6VKw?sMӬV/]}rqV,K6t:þ%E S0t@WM08WI庚 ȉ\o7zVyajz0l' :V:212)Kiw: 1ĸ@0 nݺuG^r~ ;oիWGޕ+W޹qr:4MTnPbE LXbߧ| Y兵mwس!* o-wDhԗ=ZU1I{if>d%GWb#ʁ*w٩κUՂWPһ_DB؝;Ɖ)m7f(lڇy7}5N`J [qBapVƲM,˗^><) ".rUg"KHRJ; }1˦zfya h'61!G;59 y~rþ~Nc?ϲl$)1]GG[9tXE;Krob70;l;vY3{{~8bZ Q1wvG^$I$ə(1sSw1&ՔH"8=%3$¦:fcOFd!DN,@{:~~*Uݞ7 id1scġ BQߏ}]N9:`W}ww߯px!d~ګj:ۚ:ͮ0=%uS"CȅPˇ0 'z>y𡯪0VU㈤<-?-εү?; |q~ڵ_ۿۿ{^jy4VEQdYgl[U Y9βO__.h-t;_V)ţ53kl6cM8n_Z/}LRz, XJQ;'=QO xhZyӐeQMD·h2X$Ɲc?_~Z+|耙wMd/_?|gW/‹۷u]FJόm[UUiwgko}3+٤^V퍛7o<=f?W6e9&3KQD"iqP3|Q8vah9dL9s#"63Y"?Ej;G_~ /ϯ^|g]<!+_~]ׇ݋1-cf\1뺾}M</J9bu+/bu0!c䔀DNyX{<,&>~tʟ:wb/`!jP wS&ˀ |˰zZ.1r\.qem֫zڶ}"?_sUG)]15u\.?Z.KPM=q?,VFДstbrR'gmmN.ϽO}_ <7+po(S v\L&bqXU|6[m[]\R)%!{fn;5<ϧiN/Ms*cr"T3R#P5߬EleBUTͲofլHۣu~?>ϿOWnmUlrRV 5mjۈQgaAC繈[(ʲرU-y (x?+K۫ OsUU>WUWC?DJ&awٹu22 B3- @Q-hM1Gp(XW)h=p gBfCC+jyQN&}4?¤:+W+O߻ܱ nmm-ˮb1%ry&^-Iթ\ŭ[Cc=k ⸏)gNs4̇e{cuw=U}qǎ$pIHexC#a$f bx?%C@ü h`$386}9wٷa.WUWe.~gUo/2˲ZkLBeYVB`QB(B !A  EVXRB*uRŸJiP* `=܅* ŨBH)93LYfF#3imhbȵQF2)!eYwT{?fVZy^ ;p%JmJ)cZmbp\ <$uIA꤄?v;TK ]+ڦ7T9RRXD)dBIϣ Pˢ1bm98MjۖawMZQpaFHyNJS =M3O,$R֚SYum'RREQhcR%uA+줔Yf}&1}J9o vE[MAl:/ urŸB N:.}Ddy!гfbbŬw1F@As3q9罏1B:w]}! p)NP=MRQO`/N&bf3}eYh! |1HL$APr1H{Dn]63Z;?_1BxA5;QR@4b,2kh/etenxCC^b D#N扌sC- ;HuXNNS=m niN DUEMc$ cohK*ˈĄ!$4x爈B &e%@vc;C/s=Egm$3{ڶ۾}pduuR>:@9iAjQ8 (G 8!.6Z@R[[Dl)dd4aqmv~CĮ* :bm40Rضv{sgt~ 7:)H𑃞DØ *Fb}~ {`K-.󒙜M9Rd٤,u@;8 3{g{1B}Qr"ĝ;t=P:5\uR1:!R0i#6XE]x< ۨt ѝ[Rb/e2CR*Q;D1 0sR1@o{Zho$(9d&uƝLF(꤄?|t:ʉ(24xX2f7AN)o]쥂g>^iJq6 #N떤JL$0Fnc"+Nqߡ:-^t 1DuR>:4 H1D ,ӼTZ.u}5'8Rw.>~L,|ȑ8ˣq *oNS+<!щh{t"@jBv.ZB @eL&`k=Nל֑eɕ*2:uݤkjZ=B#b!2@Y;pBdpJYVLvxf8~%Ie|1JpW31QecqޑAb#[ۏnÛp?3H)$qrƊBTXU F#(%Ku}O1DB{ Z{7JN(K63J-w#1$EuLQ  XM*]ltzN>l(H!Fd"n|TDlQLKHP{)# %bZ!#)3-ʳ';V(ʡ}on2NʳUq' i̺.j=_sBfF3px P* @DԱAJ΁"% RD Hk wMeEKml8ܺ5m5:a`Z ry}߫@d ,dCۦ84D .kp/:ɫF{imOYಐh/t63ܼUuewy6@DHLL8ݙy6]5s#LTJܼ= ,RUV"|h\>r# o&z:PLf %'&=(Ijs۞\F0ٯn ɤ4`dՔw( $#h|1wcf A dq:DxVژ<3.k]oBN}Ԁ ZT1' znmR=~0T/D, }LIYz +ݼd|ljB x@2ZP! GwN;EQdyKvY:m>ŧ_/ݧ UMf, Ц.AVh۞dX/5F Rvoq݄FT/e\sdLpgO_Ͽث^IDATi"2y\d{< 2 y!xh<\%օVZckmܮ(T2K-pw:`vWl3bv`w`J0̧͈ݸ7CG! Qhm]HQJBιgyٳ 3677!PK%4y2CD)eY6M1Ʈ׷6/B^f*XAr2,m.W..pd7K`*#o*Ue)X%\ۂރČ^$>5:DxJ<3!x"JF}'4->0 1%\*b"b)T$R?"J,\3{s>8(j(Q(BhH,2efR0tn_Rd'Gݯ J.v'Gvˊ *Sd,!͞dBDιb"2B40NB FqhOޘ*Vjkk 1*>BHcV VeID12TP׃wN`eb0n'/U'594wάa !]Fm1D)EX2R \rT)W__=Dxʒhk+)=,;)RtR֚)+R=(aKż<w;yx|R_rn-wV{2A c&BTN 5ATp1y)6C: q?} z,yY.PGB)|t}'M*b`0~{ک~So= =>, wu *aZ)"q:Vwhw9y|R_#M`rHpS5tgOc/? yש/_n&MQSQҖO|=~~< nRTqQI./44ꟜHĮA#=2~`=jpn8_8N&x4׮5M@oM۶u6yt/|emm- D8ї孭dmy~,X{`|b_B1+n`8I~@7?^?0ٟ]z1RZ8y1I9!ݠ(<S0{}0bu}џ~}ec}p{/=}Im;SXs a"?)/۹#A38n쁓EٹjDֹ QupPx( > 7~w~[[ׯ^?)/"\zb.LTb6lQ:(?),;= JZmL'н2b}ng̬LFDV㚦e6 RB/ vu J i0td?cMb L^#_R.c3Å,  erG#徛ֽ6MxHuBEQOWo_yʭ[wNmc{NZ{d7! :?JX;M/ͮ|{dbtVV¹ܰ6H](F"͢ǣ LKi C% hm&}g)Lc*)b0W1vtK\̥_{}2_oV= nʈ]f] <:\oRf Q$bf)δzs!7ooJOd|g!RcZ|ⓟgH2^C7E; }ā)`o_sQ3EAp_L[}fF[#TïeYi{z='&dT6 ЙAw}h|Y)1 "ʙḁ2-C9&>$fӾ^ןi3b w]Xl ϬkiCD|!˜Xb ⭭ c2#ʪJ:޷m;.~G`aMm1̀U]5,/ ò@fe zYd` &-f,+}ޒ(TB JsD$ֹt!R @Bc%>@'ъ]4B:Acf%5dFhLE]11!Dl#EDl/D `}xmvu5dIy)˲ k]^bpJ)7n6:/|._B@ᓟY]gJ'+`@cLADcU8)& 97u{B:g΢GD<7kE<3++ob nx0>?Ȳ,<7gb$Άh  H1Fʪg -3&(Ȋ"BZTXJTϝ>sgSD"*mߛM߭UCkFyQɍ)[ ):kJ졇h̀g Kޖ߼2+{~2:kj37k7_Y)<sqXa9,@]{0>6XDT )<cׯ0T[/^>ٹay;^x=q/M+WdY6 \v,Qk\,~qTEn<@RK`0c^1ǣqy^=R^~0߹:K_nݴho޼)ܼz x!]q ;1]~0>f;Jꤖ~Q,[s*[o+SO=eL?NYK}y晕7oDȏ>z8,'&Їj7]F lmm}{{~?9?vq(V_gou]u×W_1;w͛ L&.I3z.q&ZiCjo`Gc~[lm;o@۶ =[]UcloBumW֭1xN'ι7H̭7hexry'N9>$΃ ![Ο?wwTr.X\8\~Od)8ۯ.~|WVV~2`P9綶+|ǩ*3_|j9&9wڵk׮S 333I3glm4tSlݽGY{ $ܢ(S%p`lj`ZI z/E-fG/ln93/*ɔ %㜙YXqq>\iie`M2"+Wc/?UUљ!|᩟RbjPZDN8m{=qa)g+V<{F/.#d[B)5TUe֚vw9/}K/RӪͭsgם67V>u[)SՃ}e] fpvf(666-.g;fvvyO\Jq~8b8\Ҿ(ze2x7.iXD.>?IxPt777_וj~~1˴snGu˗/?/"]}j2vƘ3DOVh.vS[?b$/T/_}G~(jmc? ;.\PEQ Ku=H_DC+jv uWZ "˥sj= xT-nlXc̀LwROZm:0cdveI!w0\!&K&3KlBpipյpavTJ3ַ̅y`ҿW߼ۿ߀p.7uk9aA׿ a&;6ڨ;w밴}@LUIENDB`tiled-0.14.2/examples/sewers.tmx000066400000000000000000000020631260670167100165660ustar00rootroot00000000000000 eJzt19kKwjAQBdDim0sFqwguL3Vf/sP//ySnkIFhSGrSdEnxPhyQxqJ32kySPMuyJTkZC5KLa2dyNEo1Lsds3wkl/4f+7V/0/f+Y40Je5GpUn2+J5NiQCdmO/HlMyYzMI3JwLUJx7drIsSIFWUfk4FrY3GvGuHb8vr4jcmhNcnAtpIflmmar3VA5nqaWMUKeQ1d9dyht59iRPTmMPEdpua8Put/Frh88P5q84zFkv/NZP2TOlOaH7Hc+64fMmdL8cPVbV9+tcn5MzpTmR0gv12uDbQ4MNT8AIA73Uq3v3hqLe2ldTx4D21k1tf2ubw59Vk1tX+KbQ59VXfuSlMn9SJHV70tS5jqrYu8BAAAAAAAAAABd+wIHfQq1 eJzt1jsKgDAQQEELtVKvYuGvEDvvfya3MBeQQAzMwCPdsum2af5lL71AJv7xL7X+Y46WtzXayq7z2RGd0f2+V6a5bdRFfaZ5pQzRGE2lFwEAoArpDk7Veg+nOzjlHgYAAAAAIIcHvboDlQ== tiled-0.14.2/examples/tmw_desert_spacing.png000066400000000000000000001117061260670167100211200ustar00rootroot00000000000000PNG  IHDR  sRGBbKGD pHYs  tIME8 RtEXtCommentCreated with The GIMPd%n IDATx{tՕ/ztW?zXd;Bp 冗3!q@eoM5_B ΚrɊ,;@DtO IBc[֫ϪSuUndu%9{*ʭʭ\.o3PA&> U0 $k Ó)y]bj?\͐UP% , ~y[6 $pȞy Pu*l*D:>6d̛: _1H7@<cld fO ;?dS{=]I~k=] W} VL=߼O@AOޟi`(@ 9Ԋt|0t>T2qx> EȤp C#1x! `*DO0C#1f%>@U3 9u‒1 2;[}Oq:J=X:ݽ 8*qw>=>Ȓl{z p}Mz 5itw#_ZPp0EOLay(D~T 55鱓SqrtTEq~_6:lz1lv*(m߼O޾rWk9MMGW: .8?z~!{>, FWR$⤳t_!~VLÇ P0!h5 -$0,tN1hא'Oޠh{AlJ %#d>rz#V^Eڏ>=L1=c[00ptˢd-4UayE"ì :0<|mu^YP?$1CO+P`7,O֛oE۟ў]=96,RLdQðeC+Q,{\ ر{no/Ϗ-( e}XjtjP(rbj- ~`^@0p,P5"!r*&G/PUe )ۀ^/Sd Hw㏕1.`pϔ^`kJ1YBL} ѿND38f u7]s1_/80N2Tͱs}9!h%é U0> ~Y-0;:C!(c0y7,m&u]8e15TF,o#Ƣ1̦uw]0ƽ㥒/ޏ^LAYs|/]6(l3A+,{ײ\ۚ]14Cѹ*dG}6#P74 E!Fq1ӇB0pۍv0@V 8 Lp H$EOEU}&KT cIC@IH$ /8(2}\jmxo>,UT} !&=} Ջ`lr'#E1u,j[;g=QP>-*L%Y,L:d? ߌF嬣,tuL %  =jg@HO zg8 8Rr jR&#gv mo{yWYiHɒ0f chlŽ&'غR&/F#}Um.4CmJA4Gd@D \ j'DjTTלZ>3k!3kg~kg@e=Щ1&{tWXfXDOwquc'x|/Qs1" C)A7zrK];v7sg.badRɱ l02]JP>0M8 Zb!Z-`Xn0V E1+.8v r̳b;^K ;b>5kY1B;,L$S1,od zʦn@QtsO89G"F0`;N8>ǖN:}tL ~BcI>Ce+}Lc{ާޤG ]-7Fi Ӆbd;.h~,1:3qQ߾bF F91\^ y1* (&B1  k)D0/@l [3Gib<9z"dN$N~y$'2=/NH(a3aݏ,v p,<4.+ A ˱$ojgu޿~pfcjdSkYC'iYe5 ꃎ ،Lj MUA U~c)ァPY{-[k)\o 0[6;x'Nt#IVLlM\ұxxv>$GGc9 }ywn}Eb`!d (Y(쾘1(J]!LlEuc­-g$}p` E&Bdڸ Ak#BeUEC\~ JֲK/ s$tPmP { +k0Y)jhkQ秳>;} k6jj,s F!ut 5>(@LsK?R&oAJ(w Ըʂ+JP>I Caax|e>1̥>ı=C\F"D%S Eΐxgܖօ䫭 ['z[[}ڛ'~>v >]B1kf7͚̰%}m|:[:ͻ| D\6nl"Kr7!(Aj$*݋51=}yZ2oc }ȇͪxnA:tP!EoSPFOw9+9и\u(SݿDGKh>Az7^m7+Y0  ;؍t|L2F101&mR=Yt70E$a.! C1Ѓa) ~ꄔ`BFl!N9h[,X8<4`0gO C1"ņDbAu[@Owz_C] s$^nVnz` xBUd0 E[uTzO#)Z13v7Q,.­- ~G۲m_X0J˞˶9iJSYzq:ºRA0cHG,@W9qHG빓Wa6{?X ;0Z.}--Wd!@Rgm Z?McI,m搚h&)9_o6 t}"p_>$ o4eHN 2x  YIQO,ʑE:>{KP>T/^#kYJ1$~zy9zz =]ޟ2`H'0q|E0bepw.zOY a>.rP5g!jaȠS rd)A1Ǔ}ۿ [({[/V@#+0<UcHNFu'zøD F'NGcdFbh[ ?uxPs$FhTN*C[C%c(Tf!4]pCA_Gl18y=VH0,}-6l4x_g>d鳈,iWY UY(*4D CcdE~ %Ƹ.rМaq P,-ԛ-k|?lLay(2I@jjc'!h5Oi6I+ 7ѝv"`psP%8cNR!ݽ}ITQTd C> (H!GKBP,z`]hh?(JhKz\냱H_A T$CG aTSd;WN>IFdan)H)(߃‹"%ɠ2tihгlF 4Yp C> 4jzR&ad2yP,zY0aI |-uA0̥>pq"k@Zchi V<ЬR[[à?|y2|D)E*_sې@G@B>:{HDC:> ^ZH,?yVDo4Lyp1`|'Iyc6^≟W [6R/C! x+_ K>x0̵>0v3*P,4Zy6 kz8x'> ]]E"x.mmu9'd~xxn!Jٿ7;J|,xY㕔@ T zjp-Z Υ^Ks?*2I>Rc3Z,RSH0 R$AѸuc'b[y°Ea(DZ)6tЧOP {ud0̗>xǡUU`@!Yȩ)!"6QʒD dI=0̇>pyqfE1 O r#q? CIglXA$é܄3fa\#>t}[6' U,N>H' {Y`(Y4 #Kw>2!g`(F3X09uksae! T1 0,<Ԭ%uXưjt I:s!tASnIcflпC?dJ_j "KH0wl VC8[u_,m %a(Y4 uiàgXvw߷00* vz~(sQz/ s௨Ft"AΦG:>ILARY(PiO:cfnwA؟n|3p`oCdr(LX=`<9o1;+-LÅYlm>C#1dϐ0_P=<4݊HOO!B;׃!PՔ# {BHRnc an-p- tBjsV1 !e|Ub }p`a.}΄a6@+' IDATMٌBl]e b*F*8оֲx D?n,f[}k̯|SY|+$°ӊl֜{lЊ-ZIn{$d12c(U0Xlƽ޾C1x]&X(I"eYl!ND3X|cm\)6KS{)#7Q50ٷ$!k)Sǟ+QXKrBӖR&Q2R!lNE`O2̓3ea2 b10 ˇ'u]8e Pa8O":%G+V+6:@EvT%Bad֍.z}JW`I3C~F  מzx]s!8,ok.I'9FeM'Σ>)D \7c>|-zʚOb\n3"NJ' ȗO$M\8ԪNd>臢Ȁ".g=pu]zq.)]Z,XVRjӧPx#gQ鈡}h켌aDZu#3z'?NN23a,AЯۼӏ 8"a -h[!^ԨuÕO\;A)އ[dvY;XM_AIǤ>(p@6pp;LG"^lem,__ݽ <YiHIxmhlUJ7 =1'$TXyzy1Fx}At'fb04InWT #(b&C>jU': Y)Mu+*yC͜:0m}}2 9t΁ ;o͛vzK4i8tjS~:W,3`Ȗ? ݢn?He^0bE9bhX]]F ˫b޴}Rݛ3 ,d P,QЄ+(f 0YmS?<`g@V"(VHivVLn|ynw x<豑J\b"SaGϦmȂa9- h;3b P/ӧYQ4_|7~}O ,d2n }Ө.kEpgq ]J$BNŌb'`6^'ݭV9EL.d;-濝Bu.ݫ%q cL E֔90z*3Y9tM1L_~4v\Jf<vy-٘`{-땓4[I@y1#uR}:'(ΖkXlz u-Kqh0()hЉa7kdz.Ruqx0+Y|mzk7o4 [64bWW5bI$G|- 'NtcQVLl\ұx8MM8䈸s4L<|f╷E__7kl0'y;ʡp`t_A3s$/&޳}/T bUHO Z+Y'0afP,LM8A;yICC: 6@U˄彆9KVv<';g2DGc<윉h "smݓ} F!ut 5>(@L\nAM$->Hɱe|p V2 0|W5 8+s,sjKL} ` xX/?+UOctRǐO3bYȱ_}8Ic8`x ˬ2Qd l$B3`8?|fφ|v9z N}EOP!fM&3,)?|& S~֞:0FDyGo2!ew۾0EcP ]\0ǖ'k,sJI.Wt,`k Xq(D'-{:ޯq"z@ [c{ q Oհ׹pRw]3bN9|ƒaOЗTU/PI{4R&AB2I^ y}3֋HUd 2<;P,Š%/AgI~l#PNm,tB17$g˙QdK, AD'5x nCGNOzKɃOb0}Em;wL"z$ T(pMc\ܼb*n J(RrV4E$(غ-eYwem!`(E'Y%4\Y|ơ NPN28 1GtK'\v?3)2jY 7;%x.6v LjjLbI[ TOx= >p}* v.蹗ꄔ;1ma.tRDWY|\ơX q(D'Fb6zIJFb#\Zϯp乼D'炰(?͓^ vO\tt  ^@PBVcSYofC:Y)g}M-M?tw5$9P0)`Β0̅Neqb12ꤵ|[}v( `BUF8?칸 9s6 L5 v#2$+ԶW756ՁZt7I&mo5 BuX$ Eb*Q!ƣ0* @fʊ)7i#ѾN"2VO:cbڇ{ RjNRPοE%EJA_~R$ KipDž>J\t ZN@)Yͭg5| HzY0aI {-Eg C:ѭXBOO T14auW+BhIpjŐ왥"LA}I/):0<|mu=I$OjC:> ^Z"J 61Yyp|'Ķc6^≟z~4Uc3F-_]rlXJD Ö tP,ouA0N2v3*P,4Zy6;D<1E2>6NzL _Gi7o;LrdsPh+%UCj R`Zµ}AK, Dq C) f-`9".lIeʂ<,z}DzD0-V k 8&a6:VUY$g! ‡pXE)K}0 SGUUFE>Xt`Ǎ'QІ%KBowWko_k e<]< ʓ(M'TBda0f@rHr;onXN1}|kJEJ0|`\ӭ>߲0!80, !TH\IaQ$f%<,2T3'Na`Q-0tnFA}8=p{b[1c<ͫ6,AVT@"\'jIxn%Sאߗ,Yt~t~E: |`]žEJON- DoQogsiJIHEB6qX"N[CttFW~ޭR/LZ%c`8?h:C'c4W#/TAfo DrWv>7 t~m>@"N rwؼb!@Q]1;>D3n:S јsF`0 R$maj_bI478fb0 `ɒ\N}Y^_l!d22!+*(BL] f5^s=m&M,6߹^!ha;lJfNx;ڥMHMTX1;[o`Cd!q`աg \$ RdL[ΥR'T֛c{iu=UuO,'Y쟷OJ{^}c=s&|_l35Z6AX:]SA!sW1X4.3-bnBeOW{.1TdиSph fVe1L]G :j.1 r,ALY%Xڗ4"8Zvz/usJRo KqťWk[ Kqڍ9&R10vàL$ Қ;"&RCRqz`ĺwf҆ieFDr)bfcڙ,TtknE> 1r zb09/|:hF8s$UT_StĮ[?yrbNNf7i}ts; a8XyO%c)f&1$aܓtNNq9l|΅й:bbr 2B' sPtũ R,,f`? In38 uUS@eBBx"7٥Qꂠk"Q%+8w792afSJo/:Ԣ16X&n,p6`3\qݼ Z) "K`y[, 0vBWvPpy!eݯJ&isǡVuBU( (""x[M~jƛr<9wfac|o0ڕ~Y%BrZ۪JE}EV3 1m0D3SBbjRj^G'jS cP2 >-c8=<ɋ:n\e}X8]QU+TCF±=P:0Eu9_Y C& tW,/ DW \qpkNAan9-p00vE8g\`00 *T [ dS)PE4)!ЙQhE,n lts]v|؜|e}X8q#!tcpXXdxrD}ESFe4x!"vWVCN)[U=W|=, < FD7d8|&%Kr}J$+0RXZf2xW]UiQ?i[//8~yֹ e}X8 C: 6@UD:'aRڶ˩QHTε[ %3p gX@8r(7`o >ep09.j2r(B,Oh;9k4y`@6 4OCr ?ua"oS/8`E8ݫ6Qև'^(2)(Y0 ~  ٢xXU Ts)ID_Axj< z:x8z9:y1pf>H2^bMU$rV4F!QINAL'!+(dlYEE9ge+c0K1 H`k|91̻'eYg!\\v?3)lvV[kYl_n^l4P|tQ,Wd0YҐ`TEZ 4e 37{>OǶ!-ۜ#_y>, q7 nSݿDG ʒ&v Jxqp\ lԈdFnAr$铨GF- DCR\A9 +ͩ wYⵎ5_mbz_FV*-BPLC!L#md NmEbsO慸k":;S%A0˭ʭܜv,6dP AjV%mUD5 YU( -e b $EkPբ*ڢ`7^qO`+P)B@TSo0?o IDAT!{-@UUQiH'݆BVXyS V"9=fXLU<cld$#o;. j,?z=Nؒ@`v0fje}X"!Z)b|d 6}@`xR ـxHFޡ9{PV fh$F H 9@JC,Ig.6Mݸ^.x<6e}X2XYQ9?"K$σM Y<3̈́E )z:37l Nˈa5܈T⢏L1{>s=" xPU##TGBUȒ`n#vc&+3-1詩LpHFi1o -9$WB[s/5xq!/68rwe}õ=j*j͵"k$4U˨hPTp؃u[_LIg(8! <  VGVLÇ ڃ>ݲ0˿BIR&a!xu^C~l =qՇ/×_}~ ƫ 5UAi{I @+R1 ĉ4xzj,ˍg!T<@ x  ԁsh3J!7{}H' Ay`Tl\qMkk.}o—_} Շzփ̈́e-5hPqv¾ ן_rN0Y a kѢHNf+>75v7[g@  9 15jb*nX=M N!CGa8jUVCUkׂq.L2k[h™:?X,Xy7vr"}\a oqn */2 ıS+ymY n\{_}_~~xwoaQc8?o{F,]p XKZa44,oEJL#DWBƏ8zXp o0,ұC8DpM_O :# Ys?e d Z2jj\'#﫸vܰ'ɛxf"fn\c,v`ǿ,YvLML` S{\10A:><_rC"t|t^>oHSE"["SL:[oHV`lΘg=.~n v>}q/7O{A2J:ٛN*eg~qbFSĺmv<>g;VՠzQ!X="W8s<cg>Bmb4ֵ"p抁!_BUI*׬$`BD2dӅ͚Sɨ$IALC .qR@ b ,VO<Pb載ohs#pC;qMo8~[˝{oʼnS+nD}ȏ/d3; %Λ&K/_pcg!JN?UU ?>LtY/se+j$=l:=bU%&KK$钌|`{r AO/\cҫgJ}Qٲ3{<>2i;=Xq瓈Im/P{+?8VZE|y|z ,mЉ4~µ*~+Ѿ {umȤxﭏH`֊K盠 N*+;BUx_R0` f{_܇nƂ!1猖FV.W˫kt Hb[ubb}q{(rUM졑"M&#aY?9.m"+8?.b123-`B~ú}ᚩN,oqt/I"~<:::0K_']jӞ B2Ǒ+Ap 1pl--8wjum`<*^~~?ĹYşKK(y)P.Ǽ00g ;Eܝ{\ OM;~EN%Մ5/?P<⁇ B]=yI@1$S1`ơA NBfjQW7㧀7qf=8~Sth5w6|{7ԧ` ( )-A0H3WwO}Im A#GqQd,gz|0X̤@V fi3W bxRbO܎NM|~mGY}Ggg֭[5zl>7Jl ( W' Aub( 5; }Um99, e(Ww;.UahVvPpjIZci~kT39\'=n<ˑXT[Ux~2k4z*d{}R&@=HIqU CT!և`?=AUA&"7(HR0/#URZv(2<+>Ç'{= 8s])6HآuA`xIeۮo7H>f1XG{cMv3Kn3)95)O%9a%3FNN"3F"`@@UU@{C!9G: r 15 )5 F}Njc;³L܌-㈎9v^mfMjd7\R ?lo\w5al9R;ܺ4D"#ÈVCU ݶ*]A,@8jU'Æא韡=pcZD/ND!TLU0f33# ʆ/+`åpjfTCɧa͌ܔQVLzv(Ֆm|[*e͆ 6z}8x`CYDfj;N;]]ݐe V1{֍N; YVy_f**jel6v\sځ`djMC! #J֔^2 GnT< A#8xq<ϙˁpЌ1<هbs|=qii.L0YM[T *fK+у3a=|odA/)a(E߽y\z o{wauO`WXS( C.#MMXMHknF{{/l6/_  t `юZh`fC~<9}ԩup9mQl+V@x,]MpÇNՍXFɦ͝p0::8f^4D(8Vt DͿ#i [f_Mn#CJ"!fߓ7GY1>á|Or vدDI˚ņW5;5BC%ty7R0kf/Zѐ^nб`* Spgm.V D[6 9%:E{W&p8v99n}Jpp  "` Rk+d@__/*+If ^*+}%ݻw),[Y Rʫ5,| g}aZq68,*R)I0{Eee%v%5R ]8' jH"%ho?;~oKA6{ύgXy{? ~ǚT!6NRNRu\dhjMA/ڊ`jM͘ZX Q*&s I p"<EHHJt\!D\%x_$Dp(*cZ{ÿ竂%=Nv|~88@3jj9.;ΝK?Ϗsx &.(ѣn|*5$… U VfYI|,܈FGG +Y`XzD!#W ֞: ?[X~)MUѕQCt(hp#u#:2$ ;! ݍsk0wn :;afǁ9px^-9V7g^ȿ99Cq)DpaaGwwΝk]/+6{Sqqjuc%G8=y4IZ}-ޯWOӟBe840rDIIs^R~ݥ-?hzAY_RO.a 8Ћh8#Tq.!K20t(LeG BJbi2RBkfxX0dn8s -(A$ؗ, *Q &[h%\~mţy>+2]vK q"ܺo߿2Q=SxF'Μc3pD0xNҧ\GcFA<@0BOQo_x&ttb"|eYu/꜕ +Qr`6 J a?}_ 6 llF$,r?!?5(ʧ'./Epz . ;7֬&֬_5dCq|OB$ ,%q%@<\!܂aZ19sPg:7E~FF2=w< vhݻ1eu`9#qypmU_k9L$I@69 cSgQ [ q98KNe08$ȇrʕ ީ m~ Wt! 8 Ŗ.zaV +[gX00Xi__?ADQLYB!4TJs"L䯵&5y]NgnWB: z 0\i_0j/'% 8h2Q$\c{[JPxNjhgۋ CCFq"1XԀDs #4xfͥha1d\ۇCt/x3_yxF"};z @үW On^TB_sH Be&IZ.FAXQ] NjI>YYc0X[pUtxu4Jua20XY/o60V\v2{85܅b_!]uuVsӯGK~ gᕝ)Q޷Y#⛷jA9v\qe }2Y HB) *@x](2dql6-t1)[~}ЫFT60 'U9(v0#L!ÚG_E-wJ5~my.2`;:~}ʾx-4G3эt74=Gɢ-T7oxk+UZ(L >\ڇD øuӟ6[UK7M:{ج`. O&CXb/0;jL IDAT8Gtt6% IBwq݅j~ cͦ3P+DOwlm. EЯ.{ʋ<W7]N;jz%s0㖻P-7k= k/GC.-QCa,ްU Q|qW?͈A*xB[rf`+vZN|a)$DOle'bͦ3(YdcSP2: z`M 7ҥ(W+wW'8E'48`ds Xa+%hA!DiC{)ӝ pFP0-ּuJ-41ГKЪgNn ^$=!>3M(KvYz ,c͚5*!2"U&ɦ{f)اk)YkFR完sb(Xv%wm{=j~ݥ 4PS<*Tҥh?x{5~ $}pڹ`1 zrlT e^߶V,ΡAHgIB|F ɌWv6co=/]]GCs?|nYr dtݡTwUmvc9RtлMzc t:0wn %^7\o7z֛F`8t0~ZPtF.r  D~ϟCZժai1I?چKVx,-\w-"f uނj#\1ߏhEP_w)/= _k ! SȂ^x%v$-ԯ/)r N͖Oѽ*~bXCJ/PArjqDDA"!&)/E ` yFZ(O-W}20X($vvM| IFhvk/ʅ(0<ƾ}`A-jkkrUWcœOаgYT|hB`1?ll'ŒK[x~'/];81YbKqݩx}A<6Î+IJаgI)T>?TlD=D'7[5rPxI E $Dv8p 5j1C?#f $jnK):DJ7Ju_h 1etxqA_`i N$i(Z6ķAqlJ*vbFHg4mh1mZ@N]]=܀ngF"ڟ*a=?W̊ſ|L`k67~>.Z]h<^|% qtFR ͅѾ` ?H X'Qb^j$U|?i"GɭJ}2[5 IxVy |kA. q,ް5Ɂξ.wz ]^wԔSB-FplF]]=***LZ ,NOR{F5zfD`0imVL@V0t`^#fsƇW/>*n4}JۇoRcoA1'K]x ^|!5۟/`HG;F⯯ߗ"ۋތآD,T?dsbb%C})9oiD[{hH%㕝͚ o؊Wv6c9trR⢜ -Zl* N> ,}mtoOF!]΍Rt#2audÊMeAor` VljZFdLOmǎ6z kr߽cœO`x{q݅hBv/O53B$/>G]#]3B&`݊$  9'_͂%Vn=6cgpɪC5φB1jM6_Q W#< tKKByyFE&2!1NR͈|,Bz:vO2U zVH30د ֺz444AeTT(UB]$zkj5} B.k6A 6*b6}o|PJh֠Χx|k?u 0OI֠As(,ްD.\#9$iA«J|-Q,TyIw뛱v>\N"vcm8+Lo`Sn1Ɂu扮|#D,9;}\4jQfB^Q$^י8fC[[+\.;xL6zqRK7j/ og8B\ 4~q s%skz`1럏ϧjR?^L5ۮmQtu~-=EA ,S!wxюh$ gU~ܘa*."0O0#>H vr :v"sz wOWH.Ŵ! 5XlANv.5ƍX| JFDA75*XU;,}*5{ȣM(NC$JՎK(\q;{G&F̻> 5!P+BX þ>2 Ck"ذ'kVm\TWœם11XIzOQ698P}2P&T ǍbS[>mG˟AXBF"tM&N_/>jn O=  N_$7aj4k`,Yhx~SsrT~ )/BI*H+h?"\emϦ)$Ɏ]ٸ.߼PҕYq`ƣavrԨ)j{ daRfl# ! @DWdO͌ԛ۱ \$]#Mg_ w HV~)d;y~x2Uxbkr`z8:o:wHYqzmh milG|u!ϟmrn9 K1/ړ^ho@v;#`3*jύȴ Nj!>R|ݥfq=NHA@P2NJAo(!FV1u=7ӳe?NJ[hҪI{_jDGg_ 9!K !Aw Gxl"Bq[UBgNc?R(:{bFlz-7IvC<C@ .?GqŕT'JܖOC5_XCSor7޼huv%"GԅvW\Hģ4ٟюO\hW@Ob2:#fo$BV C&9h9CCGdN +aXƺ2]6XVm> (~E žB K)ر$nA$ìS!IJjj( y- oxs{*>xvb4C% ۣuQz570< 8^; addT}CuZe%FqE%9Gð;)r8}6@*gD2ǶjgWb=OW_7޾her[Pl:Q3#ǛMT44$k@YٌF=˥19X1>#9<}{(z+ƅiiҘ=?./ZhjOXdxRb`d v(5._F5P.x0Sjq"9po|Z#5h6(?%H8a)A](e;Ϟ=ZAjY#2]cZ X s -[CcidaCKK3f--C n~p$$hF_/&&Z# >h[ 8nTi=1nLM"epvctKD@ڮϑ[ jfB|jUIl cz@_IoUa2CU]:ZHîo9h0PF( 5 `9~m1K~G >6k!?y`VOޝF84̣rF.lrxt7%|IDAT<b4̱n3L1 X L4lL%=8da0LzPa:0.Z1PhT)50`0X 9^XE3b?J62υrU |G(ͅ!u Vc _h4I$yA$$ѡ cI=%ufkȢG5HH΅(\ʯ)o򃗧B$`w(՝GUGݩLxNYdI=#GzQT4mm~5}7>H6;xdH z9(uȆz3ǔp`ГArTM3νre *S cΜsa!`5 #rxF (5:'H3nZϼ=J~1W_Y=pՄ`TkxՏqh*Rr$Pn MPٍg =v{\?!-)n3sa2VUҧ$IQc21 =h(wM| IFhvgBM:SN6K[:;;;p pa-vZ-ݚ4VP3gd\S9֭\5X2fvu kBco.p*\?5ع}% /)2*p%.%Ul5xaXU_Cuu5x:۬~HH J] ƩDž!c&lB5#*V`$2TVV"hղhM5ȁ%55E4Dcjj[9W^'ym1MzJrO^x|;$'Sr"DhHCފ_hn59 VA ]F?5d9ܾKP2D신rŋSK;gT@u)56Q5+$X{,@}7m3GKę6Qpi'X-8FӝOΌ 'SaJ+;5Vh8d.0N'!}]czR3;:<#Yty2n|!bع}Ity ux~S BJ\@tPK-@^a.@vo IYyc!gL4tQXd¼ax33oHdY$Isװ6dAS"9\7ϟgwI]Z7ycd8sS |me.0D@d5 Vw(D !B ,X%iE?Q9Pȫ " _Aa0lkadtte1"> IJRg*lG>0ҽFHHؿ\dTVR4:kR$a -@逜n.  @X$7`AOs3tPV'R5 YP"{hC:7aHJ UG%Wk*<@4,9D/J[ M zͳL0h&!rP? "# 3pz$IH$p8촴I=HRMeUaC[[ QT45#fcFF<ϰwPZZleجYݭ:4~Z 掏`8b '0aNOΓL6Yp-<<zz02F[[~v㬳D{{dە7\ggYpVaɒSkZrr\(+&W;`Ô)yo9DYY) ]]X^y/_Ǵ&nD@13FuCdS#M: cNA;hrChtm O02bn%څKV%/eIlC91vn߇KV%ޥkL1tG.z{e^ԘKO ֯t4u7%j`3HyS7B1:jCn,H3zXj2Jۉ'.NƳ> D І\10ЧEESC!T!ksa0/cq8vDCaMÌ1XZ$j=)ITDsЦi+&:%`'N(vDh4mxmʟR^@ qڱzjgxǕD Ќ .XYr9`%qP7|*3MpUʇ@ bkLtݱ΅~$$ݻ0 A ǍxBe*`}=xϸEГP mth05ׅPGB$6_N_jzRЛY5KSδ$xDy>jБBHKϟe͍ht|d0RJE<{q : i(D xO2HC$t!/;BU?h yoy^x今&O`Z|7%j-cyxn vjE2~/!9 LQgYu I1x49Q|KJ=GOh9t2BCGdN1n>U82rfofIT*`v.Rr$.pv;b0xAv⃷߆ãj|o3(xDx(^%D,YEy8xx!2(!,0I@ppmGJ\Q!ɈFAv)eps9\5zv8sYU -(A$ؗ,yanyے6divL㫀!۹x3 RF0緑F1oɘI[Ո#=pz=8: -HȊH$ȉl6JQ45ϣѼү,W{u  lL#iWT9)+fMC<ԯnAsCkT,La7lV7'ʙ0BCU,[\koAD \89ɇK1@J6_4!A,2>B4DhBBj{ݕ Oq 1f4J!71k)`D&Bp|=|u0KɮԱ .,bwy"z:/F9 =wCŘVg84{a8k1h{q|H< >IENDB`tiled-0.14.2/man/000077500000000000000000000000001260670167100134605ustar00rootroot00000000000000tiled-0.14.2/man/automappingconverter.1000066400000000000000000000012021260670167100200110ustar00rootroot00000000000000.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "AUTOMAPPINGCONVERTER" "1" "July 2013" "" "" . .SH "NAME" \fBautomappingconverter\fR \- a converter for old Tiled automapping rules . .SH "SYNOPSIS" \fBautomappingconverter\fR . .SH "DESCRIPTION" This converter is used to convert automapping rules of the Tiled map editor from version 0\.8\.x and lower to 0\.9\.0 and later\. . .SH "AUTHORS" \fIhttps://github\.com/bjorn/tiled/blob/master/AUTHORS\fR . .SH "SEE ALSO" tiled(1), \fIhttp://www\.mapeditor\.org/\fR, \fIhttps://github\.com/bjorn/tiled/wiki/Automapping#wiki\-Converting_rules_from_08_and_below\fR tiled-0.14.2/man/automappingconverter.1.ronn000066400000000000000000000007631260670167100207770ustar00rootroot00000000000000automappingconverter(1) -- a converter for old Tiled automapping rules ======================================== ## SYNOPSIS `automappingconverter` ## DESCRIPTION This converter is used to convert automapping rules of the Tiled map editor from version 0.8.x and lower to 0.9.0 and later. ## AUTHORS ## SEE ALSO tiled(1), , tiled-0.14.2/man/tiled.1000066400000000000000000000021071260670167100146430ustar00rootroot00000000000000.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "TILED" "1" "May 2015" "" "" . .SH "NAME" \fBtiled\fR \- tile map editor . .SH "SYNOPSIS" \fBtiled\fR [\fIOPTIONS\fR] [FILES\.\.\.] . .SH "DESCRIPTION" Tiled is a general purpose tile map editor\. It\'s built to be easy to use, yet flexible enough to work with varying game engines, whether your game is an RPG, platformer or Breakout clone\. Tiled is free software and written in C++, using the Qt application framework\. . .SH "OPTIONS" . .TP \fB\-h\fR \fB\-\-help\fR Displays the help . .TP \fB\-v\fR \fB\-\-version\fR Displays the version . .TP \fB\-\-quit\fR Only check validity of arguments . .TP \fB\-\-disable\-opengl\fR Disables hardware accelerated rendering . .TP \fB\-\-export\-map\fR [format] \fItmx file\fR \fItarget file\fR Exports the specified tmx file to target . .TP \fB\-\-export\-formats\fR Prints a list of supported export formats . .SH "AUTHORS" \fIhttps://github\.com/bjorn/tiled/blob/master/AUTHORS\fR . .SH "SEE ALSO" tmxviewer(1), tmxrasterizer(1), \fIhttp://www\.mapeditor\.org/\fR tiled-0.14.2/man/tiled.1.ronn000066400000000000000000000016211260670167100156160ustar00rootroot00000000000000tiled(1) -- tile map editor =========================== ## SYNOPSIS `tiled` [] [FILES...] ## DESCRIPTION Tiled is a general purpose tile map editor. It's built to be easy to use, yet flexible enough to work with varying game engines, whether your game is an RPG, platformer or Breakout clone. Tiled is free software and written in C++, using the Qt application framework. ## OPTIONS * `-h` `--help`: Displays the help * `-v` `--version`: Displays the version * `--quit`: Only check validity of arguments * `--disable-opengl`: Disables hardware accelerated rendering * `--export-map` [format] : Exports the specified tmx file to target * `--export-formats`: Prints a list of supported export formats ## AUTHORS ## SEE ALSO tmxviewer(1), tmxrasterizer(1), tiled-0.14.2/man/tmxrasterizer.1000066400000000000000000000026331260670167100164710ustar00rootroot00000000000000.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "TMXRASTERIZER" "1" "April 2014" "" "" . .SH "NAME" \fBtmxrasterizer\fR \- renders a tile map to an image . .SH "SYNOPSIS" \fBtmxrasterizer\fR [\fIOPTIONS\fR] [INPUT FILE] [OUTPUT FILE] . .SH "DESCRIPTION" This application can be used to render maps created by the Tiled Map Editor to an image\. This is very helpful for creating small\-scale previews, such as mini\-maps\. . .SH "OPTIONS" . .TP \fB\-h\fR \fB\-\-help\fR Displays the help . .TP \fB\-v\fR \fB\-\-version\fR Displays the version . .TP \fB\-s\fR \fB\-\-scale\fR SIZE The scale of the output image . .TP \fB\-t\fR \fB\-\-tilesize\fR SIZE The requested size in pixels at which a tile is rendered\. Overrides the \-\-scale option\. . .TP \fB\-a\fR \fB\-\-anti\-aliasing\fR Smooth the output image using anti\-aliasing . .TP \fB\-\-ignore\-visibility\fR Ignore all layer visibility flags in the map file and render all layers in the output (default is to omit invisible layers)\. . .TP \fB\-\-hide\-layer\fR Specifies a layer to omit from the output image\. Can be repeated to hide multiple layers\. The layername is case insensitive\. . .IP \fIExample\fR: . .IP \fBtmxrasterizer\fR \-\-hide\-layer collision \-\-hide\-layer otherlayer [\.\.\.] . .SH "AUTHOR" Vincent Petithory <\fIvincent\.petithory@gmail\.com\fR> . .SH "SEE ALSO" tiled(1), tmxviewer(1), \fIhttp://www\.mapeditor\.org/\fR tiled-0.14.2/man/tmxrasterizer.1.ronn000066400000000000000000000023241260670167100174410ustar00rootroot00000000000000tmxrasterizer(1) -- renders a tile map to an image ======================================== ## SYNOPSIS `tmxrasterizer` [] [INPUT FILE] [OUTPUT FILE] ## DESCRIPTION This application can be used to render maps created by the Tiled Map Editor to an image. This is very helpful for creating small-scale previews, such as mini-maps. ## OPTIONS * `-h` `--help`: Displays the help * `-v` `--version`: Displays the version * `-s` `--scale` SIZE: The scale of the output image * `-t` `--tilesize` SIZE: The requested size in pixels at which a tile is rendered. Overrides the --scale option. * `-a` `--anti-aliasing`: Smooth the output image using anti-aliasing * `--ignore-visibility`: Ignore all layer visibility flags in the map file and render all layers in the output (default is to omit invisible layers). * `--hide-layer`: Specifies a layer to omit from the output image. Can be repeated to hide multiple layers. The layername is case insensitive. *Example*: `tmxrasterizer` --hide-layer collision --hide-layer otherlayer [...] ## AUTHOR Vincent Petithory <> ## SEE ALSO tiled(1), tmxviewer(1), tiled-0.14.2/man/tmxviewer.1000066400000000000000000000011641260670167100155760ustar00rootroot00000000000000.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "TMXVIEWER" "1" "January 2013" "" "" . .SH "NAME" \fBtmxviewer\fR \- a simple tile map viewer . .SH "SYNOPSIS" \fBtmxviewer\fR [\fIOPTIONS\fR] [FILES\.\.\.] . .SH "DESCRIPTION" This application can be used to quickly view a map that was created by the Tiled Map Editor\. . .SH "OPTIONS" . .TP \fB\-h\fR \fB\-\-help\fR Displays the help . .TP \fB\-v\fR \fB\-\-version\fR Displays the version . .SH "AUTHORS" \fIhttps://github\.com/bjorn/tiled/blob/master/AUTHORS\fR . .SH "SEE ALSO" tiled(1), tmxrasterizer(1), \fIhttp://www\.mapeditor\.org/\fR tiled-0.14.2/man/tmxviewer.1.ronn000066400000000000000000000007311260670167100165500ustar00rootroot00000000000000tmxviewer(1) -- a simple tile map viewer ======================================== ## SYNOPSIS `tmxviewer` [] [FILE] ## DESCRIPTION This application can be used to quickly view a map that was created by the Tiled Map Editor. ## OPTIONS * `-h` `--help`: Displays the help * `-v` `--version`: Displays the version ## AUTHORS ## SEE ALSO tiled(1), tmxrasterizer(1), tiled-0.14.2/mime/000077500000000000000000000000001260670167100136345ustar00rootroot00000000000000tiled-0.14.2/mime/tiled.xml000066400000000000000000000005211260670167100154550ustar00rootroot00000000000000 Tiled map tiled-0.14.2/mkdocs.yml000066400000000000000000000007541260670167100147160ustar00rootroot00000000000000site_name: Tiled Documentation repo_url: https://github.com/bjorn/tiled theme: cerulean google_analytics: ['UA-380618-1', 'mapeditor.org'] pages: - Home: index.md - Manual: - Contents: manual/index.md - Using the Terrain Tool: manual/using-the-terrain-tool.md - Using Commands: manual/using-commands.md - Reference: - TMX Map Format: reference/tmx-map-format.md - TMX Changelog: reference/tmx-changelog.md - Libraries and Frameworks: reference/support-for-tmx-maps.md tiled-0.14.2/qbs/000077500000000000000000000000001260670167100134725ustar00rootroot00000000000000tiled-0.14.2/qbs/imports/000077500000000000000000000000001260670167100151675ustar00rootroot00000000000000tiled-0.14.2/qbs/imports/TiledPlugin.qbs000066400000000000000000000013311260670167100201140ustar00rootroot00000000000000import qbs 1.0 DynamicLibrary { Depends { name: "libtiled" } Depends { name: "cpp" } Depends { name: "Qt"; submodules: "gui" } cpp.cxxLanguageVersion: "c++11" cpp.visibility: "minimal" bundle.isBundle: false Properties { condition: qbs.targetOS.contains("osx") cpp.cxxFlags: ["-Wno-unknown-pragmas"] } Group { qbs.install: true qbs.installDir: { if (qbs.targetOS.contains("windows")) return "plugins/tiled" else if (qbs.targetOS.contains("osx")) return "Tiled.app/Contents/PlugIns" else return "lib/tiled/plugins" } fileTagsFilter: "dynamiclibrary" } } tiled-0.14.2/qbs/imports/TiledQtGuiApplication.qbs000066400000000000000000000011761260670167100221020ustar00rootroot00000000000000import qbs QtGuiApplication { cpp.rpaths: qbs.targetOS.contains("darwin") ? ["@loader_path/../Frameworks"] : ["$ORIGIN/../lib"] cpp.cxxLanguageVersion: "c++11" Properties { condition: qbs.targetOS.contains("osx") cpp.cxxFlags: ["-Wno-unknown-pragmas"] } Group { qbs.install: true qbs.installDir: { if (qbs.targetOS.contains("windows")) return ""; else if (qbs.targetOS.contains("darwin")) return "Tiled.app/Contents/MacOS"; else return "bin"; } fileTagsFilter: product.type } } tiled-0.14.2/src/000077500000000000000000000000001260670167100134745ustar00rootroot00000000000000tiled-0.14.2/src/automappingconverter/000077500000000000000000000000001260670167100177505ustar00rootroot00000000000000tiled-0.14.2/src/automappingconverter/automappingconverter.pro000066400000000000000000000020551260670167100247500ustar00rootroot00000000000000include(../../tiled.pri) include(../libtiled/libtiled.pri) win32 { DESTDIR = ../.. } else { DESTDIR = ../../bin } macx { QMAKE_LIBDIR += $$OUT_PWD/../../bin/Tiled.app/Contents/Frameworks } else:win32 { LIBS += -L$$OUT_PWD/../../lib } else { QMAKE_LIBDIR = $$OUT_PWD/../../lib $$QMAKE_LIBDIR } # Make sure the executable can find libtiled !win32:!macx:contains(RPATH, yes) { QMAKE_RPATHDIR += \$\$ORIGIN/../lib # It is not possible to use ORIGIN in QMAKE_RPATHDIR, so a bit manually QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$$join(QMAKE_RPATHDIR, ":")\' QMAKE_RPATHDIR = } QT += widgets TARGET = automappingconverter TEMPLATE = app target.path = $${PREFIX}/bin INSTALLS += target SOURCES += main.cpp \ converterdatamodel.cpp \ convertercontrol.cpp \ converterwindow.cpp HEADERS += \ converterdatamodel.h \ convertercontrol.h \ converterwindow.h FORMS += \ converterwindow.ui manpage.path = $${PREFIX}/share/man/man1/ manpage.files += ../../man/automappingconverter.1 INSTALLS += manpage tiled-0.14.2/src/automappingconverter/automappingconverter.qbs000066400000000000000000000011501260670167100247300ustar00rootroot00000000000000import qbs 1.0 TiledQtGuiApplication { name: "automappingconverter" targetName: name Depends { name: "libtiled" } Depends { name: "Qt"; submodules: ["widgets"] } cpp.includePaths: ["."] consoleApplication: false files: [ "convertercontrol.cpp", "convertercontrol.h", "converterdatamodel.cpp", "converterdatamodel.h", "converterwindow.cpp", "converterwindow.h", "converterwindow.ui", "main.cpp", ] Properties { condition: qbs.targetOS.contains("osx") targetName: "Automapping Converter" } } tiled-0.14.2/src/automappingconverter/convertercontrol.cpp000066400000000000000000000067461260670167100241010ustar00rootroot00000000000000/* * convertercontrol.cpp * Copyright 2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of the AutomappingConverter, which converts old rulemaps * of Tiled to work with the latest version of Tiled. * * 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, see . */ #include "convertercontrol.h" #include "map.h" #include "layer.h" #include "tileset.h" #include "mapreader.h" #include "mapwriter.h" #include #include using namespace Tiled; ConverterControl::ConverterControl() { } QString ConverterControl::automappingRuleFileVersion(const QString &fileName) { Tiled::MapReader reader; Tiled::Map *map = reader.readMap(fileName); if (!map) return versionNotAMap(); // version 1 check bool hasonlyruleprefix = true; foreach (Tiled::Layer *layer, map->layers()) { if (!layer->name().startsWith("rule", Qt::CaseInsensitive)) hasonlyruleprefix = false; } if (hasonlyruleprefix) return version1(); // version 2 check bool hasrule = false; bool hasoutput = false; bool hasregion = false; bool allused = true; foreach (Tiled::Layer *layer, map->layers()) { bool isunused = true; if (layer->name().startsWith("input", Qt::CaseInsensitive)) { hasrule = true; isunused = false; } if (layer->name().startsWith("output", Qt::CaseInsensitive)) { hasoutput = true; isunused = false; } if (layer->name().toLower() == "regions") { hasregion = true; isunused = false; } if (isunused) allused = false; } if (allused && hasoutput && hasregion && hasrule) return version2(); return versionUnknown(); } void ConverterControl::convertV1toV2(const QString &fileName) { Tiled::MapReader reader; QScopedPointer map(reader.readMap(fileName)); if (!map) { qWarning() << "Error at conversion of " << fileName << ":\n" << reader.errorString(); return; } foreach (Tiled::Layer *layer, map->layers()) { if (layer->name().startsWith("ruleset", Qt::CaseInsensitive)) { layer->setName("Input_set"); } else if (layer->name().startsWith("rulenotset", Qt::CaseInsensitive)) { layer->setName("InputNot_set"); } else if (layer->name().startsWith("ruleregions", Qt::CaseInsensitive)) { layer->setName("Regions"); } else if (layer->name().startsWith("rule", Qt::CaseInsensitive)) { const QString newname = layer->name().right(layer->name().length() - 4); layer->setName("Output" + newname); } else { qWarning() << QString("Warning at conversion of") << fileName << QString("unused layers found"); } } Tiled::MapWriter writer; writer.writeMap(map.data(), fileName); } tiled-0.14.2/src/automappingconverter/convertercontrol.h000066400000000000000000000026641260670167100235410ustar00rootroot00000000000000/* * convertercontrol.h * Copyright 2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of the AutomappingConverter, which converts old rulemaps * of Tiled to work with the latest version of Tiled. * * 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, see . */ #ifndef CONVERTERCONTROL_H #define CONVERTERCONTROL_H #include #include class ConverterControl { public: ConverterControl(); QString version1() const { return QObject::tr("v0.8 and before"); } QString version2() const { return QObject::tr("v0.9 and later"); } QString versionUnknown() const { return QObject::tr("unknown"); } QString versionNotAMap() const { return QObject::tr("not a map"); } QString automappingRuleFileVersion(const QString &fileName); void convertV1toV2(const QString &fileName); }; #endif // CONVERTERCONTROL_H tiled-0.14.2/src/automappingconverter/converterdatamodel.cpp000066400000000000000000000063051260670167100243420ustar00rootroot00000000000000/* * converterdatamodel.cpp * Copyright 2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of the AutomappingConverter, which converts old rulemaps * of Tiled to work with the latest version of Tiled. * * 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, see . */ #include "converterdatamodel.h" #include "convertercontrol.h" #include ConverterDataModel::ConverterDataModel(ConverterControl *control, QObject *parent) : QAbstractListModel(parent) { mControl = control; } int ConverterDataModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : mFileNames.count(); } int ConverterDataModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : 2; } QVariant ConverterDataModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); const int rowIndex = index.row(); const int columnIndex = index.column(); if (rowIndex < 0 || rowIndex > mFileNames.count()) return QVariant(); switch (role) { case Qt::DisplayRole: { const QString fileName = mFileNames.at(rowIndex); if (columnIndex == 0) return fileName; else if (columnIndex == 1) return mFileVersions[fileName]; else return QVariant(); } default: return QVariant(); } } QVariant ConverterDataModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole) { switch (section) { case 0: return tr("File"); break; case 1: return tr("Version"); break; } } return QAbstractListModel::headerData(section, orientation, role); } void ConverterDataModel::insertFileNames(const QStringList &fileNames) { const int row = mFileNames.size(); beginInsertRows(QModelIndex(), row, row + fileNames.count() - 1); mFileNames.append(fileNames); foreach (const QString &fileName, fileNames) mFileVersions[fileName] = mControl->automappingRuleFileVersion(fileName); endInsertRows(); } void ConverterDataModel::updateVersions() { for (int i = 0; i < count(); ++i) { const QString fileName = mFileNames.at(i); const QString version = mFileVersions[fileName]; qWarning() << "processing" << fileName << "at version" << version; if (version == mControl->version1()) { mControl->convertV1toV2(fileName); mFileVersions[fileName] = mControl->version2(); } } emit dataChanged(index(0), index(count())); } tiled-0.14.2/src/automappingconverter/converterdatamodel.h000066400000000000000000000040021260670167100237770ustar00rootroot00000000000000/* * converterdatamodel.h * Copyright 2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of the AutomappingConverter, which converts old rulemaps * of Tiled to work with the latest version of Tiled. * * 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, see . */ #ifndef CONVERTERDATAMODEL_H #define CONVERTERDATAMODEL_H #include #include #include #include #include class ConverterControl; class ConverterDataModel : public QAbstractListModel { Q_OBJECT public: ConverterDataModel(ConverterControl *control, QObject *parent = nullptr); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; void insertFileNames(const QStringList &fileNames); int count() const { return mFileNames.count(); } QString fileName(int i) const { return mFileNames.at(i); } QString versionOfFile(const QString &fileName) const { return mFileVersions[fileName]; } public slots: void updateVersions(); private: ConverterControl *mControl; QList mFileNames; QMap mFileVersions; }; #endif // CONVERTERDATAMODEL_H tiled-0.14.2/src/automappingconverter/converterwindow.cpp000066400000000000000000000044171260670167100237210ustar00rootroot00000000000000/* * converterwindow.cpp * Copyright 2011, 2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of the AutomappingConverter, which converts old rulemaps * of Tiled to work with the latest version of Tiled. * * 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, see . */ #include "converterwindow.h" #include "ui_converterwindow.h" #include #include ConverterWindow::ConverterWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { mControl = new ConverterControl; mDataModel = new ConverterDataModel(mControl, this); ui->setupUi(this); ui->saveButton->setText(tr("Save all as %1").arg(mControl->version2())); connect(ui->addbutton, SIGNAL(clicked()), this, SLOT(addRule())); connect(ui->saveButton, SIGNAL(clicked()), mDataModel, SLOT(updateVersions())); ui->treeView->setModel(mDataModel); QHeaderView *header = ui->treeView->header(); header->setSectionResizeMode(0, QHeaderView::Stretch); header->setSectionResizeMode(1, QHeaderView::ResizeToContents); } ConverterWindow::~ConverterWindow() { delete ui; delete mControl; } void ConverterWindow::addRule() { QString filter = tr("All Files (*)"); filter += QLatin1String(";;"); QString selectedFilter = tr("Tiled map files (*.tmx)"); filter += selectedFilter; QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open Map"), QString(), filter, &selectedFilter); if (fileNames.isEmpty()) return; mDataModel->insertFileNames(fileNames); ui->saveButton->setEnabled(true); } tiled-0.14.2/src/automappingconverter/converterwindow.h000066400000000000000000000026541260670167100233670ustar00rootroot00000000000000/* * converterwindow.h * Copyright 2011, 2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of the AutomappingConverter, which converts old rulemaps * of Tiled to work with the latest version of Tiled. * * 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, see . */ #ifndef CONVERTERWINDOW_H #define CONVERTERWINDOW_H #include "converterdatamodel.h" #include "convertercontrol.h" #include #include #include namespace Ui { class MainWindow; } class ConverterWindow : public QMainWindow { Q_OBJECT public: explicit ConverterWindow(QWidget *parent = nullptr); ~ConverterWindow(); public slots: void addRule(); private: Ui::MainWindow *ui; QString getVersion(QString filename); ConverterDataModel *mDataModel; ConverterControl *mControl; }; #endif // CONVERTERWINDOW_H tiled-0.14.2/src/automappingconverter/converterwindow.ui000066400000000000000000000037071260670167100235550ustar00rootroot00000000000000 MainWindow 0 0 576 264 Tiled Automapping Rule Files Converter false true false false Add new Automapping rules Qt::Horizontal 40 20 false Save all as v0.8.0 compatible tiled-0.14.2/src/automappingconverter/main.cpp000066400000000000000000000020311260670167100213740ustar00rootroot00000000000000/* * main.cpp * Copyright 2011, Stefan Beller, stefanbeller@googlemail.com * * This file is part of the AutomappingConverter, which converts old rulemaps * of Tiled to work with the latest version of Tiled. * * 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, see . */ #include "converterwindow.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); ConverterWindow w; w.show(); return a.exec(); } tiled-0.14.2/src/libtiled/000077500000000000000000000000001260670167100152645ustar00rootroot00000000000000tiled-0.14.2/src/libtiled/compression.cpp000066400000000000000000000113241260670167100203320ustar00rootroot00000000000000/* * compression.cpp * Copyright 2008, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "compression.h" #ifdef Q_OS_WIN #include #else #include #endif #include #include #ifdef Z_PREFIX #undef compress #endif using namespace Tiled; // TODO: Improve error reporting by showing these errors in the user interface static void logZlibError(int error) { switch (error) { case Z_MEM_ERROR: qDebug() << "Out of memory while (de)compressing data!"; break; case Z_VERSION_ERROR: qDebug() << "Incompatible zlib version!"; break; case Z_NEED_DICT: case Z_DATA_ERROR: qDebug() << "Incorrect zlib compressed data!"; break; default: qDebug() << "Unknown error while (de)compressing data!"; } } QByteArray Tiled::decompress(const QByteArray &data, int expectedSize) { QByteArray out; out.resize(expectedSize); z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.next_in = (Bytef *) data.data(); strm.avail_in = data.length(); strm.next_out = (Bytef *) out.data(); strm.avail_out = out.size(); int ret = inflateInit2(&strm, 15 + 32); if (ret != Z_OK) { logZlibError(ret); return QByteArray(); } do { ret = inflate(&strm, Z_SYNC_FLUSH); switch (ret) { case Z_NEED_DICT: case Z_STREAM_ERROR: ret = Z_DATA_ERROR; case Z_DATA_ERROR: case Z_MEM_ERROR: inflateEnd(&strm); logZlibError(ret); return QByteArray(); } if (ret != Z_STREAM_END) { int oldSize = out.size(); out.resize(out.size() * 2); strm.next_out = (Bytef *)(out.data() + oldSize); strm.avail_out = oldSize; } } while (ret != Z_STREAM_END); if (strm.avail_in != 0) { logZlibError(Z_DATA_ERROR); return QByteArray(); } const int outLength = out.size() - strm.avail_out; inflateEnd(&strm); out.resize(outLength); return out; } QByteArray Tiled::compress(const QByteArray &data, CompressionMethod method) { QByteArray out; out.resize(1024); int err; z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.next_in = (Bytef *) data.data(); strm.avail_in = data.length(); strm.next_out = (Bytef *) out.data(); strm.avail_out = out.size(); const int windowBits = (method == Gzip) ? 15 + 16 : 15; err = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY); if (err != Z_OK) { logZlibError(err); return QByteArray(); } do { err = deflate(&strm, Z_FINISH); Q_ASSERT(err != Z_STREAM_ERROR); if (err == Z_OK) { // More output space needed int oldSize = out.size(); out.resize(out.size() * 2); strm.next_out = (Bytef *)(out.data() + oldSize); strm.avail_out = oldSize; } } while (err == Z_OK); if (err != Z_STREAM_END) { logZlibError(err); deflateEnd(&strm); return QByteArray(); } const int outLength = out.size() - strm.avail_out; deflateEnd(&strm); out.resize(outLength); return out; } tiled-0.14.2/src/libtiled/compression.h000066400000000000000000000052131260670167100177770ustar00rootroot00000000000000/* * compression.h * Copyright 2008, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef COMPRESSION_H #define COMPRESSION_H #include "tiled_global.h" class QByteArray; namespace Tiled { enum CompressionMethod { Gzip, Zlib }; /** * Decompresses either zlib or gzip compressed memory. Returns a null * QByteArray if decompressing failed. * * Needed because qUncompress does not support gzip compressed data. Also, * this method does not need the expected size to be prepended to the data, * but it can be passed as optional parameter. * * @param data the compressed data * @param expectedSize the expected size of the uncompressed data in bytes * @return the uncompressed data, or a null QByteArray if decompressing failed */ QByteArray TILEDSHARED_EXPORT decompress(const QByteArray &data, int expectedSize = 1024); /** * Compresses the give data in either gzip or zlib format. Returns a null * QByteArray if compression failed. * * Needed because qCompress does not support gzip compression. * * @param data the uncompressed data * @return the compressed data, or a null QByteArray if compression failed */ QByteArray TILEDSHARED_EXPORT compress(const QByteArray &data, CompressionMethod method = Zlib); } // namespace Tiled #endif // COMPRESSION_H tiled-0.14.2/src/libtiled/gidmapper.cpp000066400000000000000000000165651260670167100177550ustar00rootroot00000000000000/* * gidmapper.cpp * Copyright 2011, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "gidmapper.h" #include "compression.h" #include "tile.h" #include "tileset.h" using namespace Tiled; // Bits on the far end of the 32-bit global tile ID are used for tile flags const int FlippedHorizontallyFlag = 0x80000000; const int FlippedVerticallyFlag = 0x40000000; const int FlippedAntiDiagonallyFlag = 0x20000000; /** * Default constructor. Use \l insert to initialize the gid mapper * incrementally. */ GidMapper::GidMapper() : mInvalidTile(0) { } /** * Constructor that initializes the gid mapper using the given \a tilesets. */ GidMapper::GidMapper(const QVector &tilesets) : mInvalidTile(0) { unsigned firstGid = 1; foreach (const SharedTileset &tileset, tilesets) { insert(firstGid, tileset.data()); firstGid += tileset->tileCount(); } } /** * Returns the cell data matched by the given \a gid. The \a ok parameter * indicates whether an error occurred. */ Cell GidMapper::gidToCell(unsigned gid, bool &ok) const { Cell result; // Read out the flags result.flippedHorizontally = (gid & FlippedHorizontallyFlag); result.flippedVertically = (gid & FlippedVerticallyFlag); result.flippedAntiDiagonally = (gid & FlippedAntiDiagonallyFlag); // Clear the flags gid &= ~(FlippedHorizontallyFlag | FlippedVerticallyFlag | FlippedAntiDiagonallyFlag); if (gid == 0) { ok = true; } else if (isEmpty()) { ok = false; } else { // Find the tileset containing this tile QMap::const_iterator i = mFirstGidToTileset.upperBound(gid); if (i == mFirstGidToTileset.begin()) { // Invalid global tile ID, since it lies before the first tileset ok = false; } else { --i; // Navigate one tileset back since upper bound finds the next int tileId = gid - i.key(); const Tileset *tileset = i.value(); const int columnCount = mTilesetColumnCounts.value(tileset); if (columnCount > 0 && columnCount != tileset->columnCount()) { // Correct tile index for changes in image width const int row = tileId / columnCount; const int column = tileId % columnCount; tileId = row * tileset->columnCount() + column; } result.tile = tileset->tileAt(tileId); ok = true; } } return result; } /** * Returns the global tile ID for the given \a cell. Returns 0 when the cell is * empty or when its tileset isn't known. */ unsigned GidMapper::cellToGid(const Cell &cell) const { if (cell.isEmpty()) return 0; const Tileset *tileset = cell.tile->tileset(); // Find the first GID for the tileset QMap::const_iterator i = mFirstGidToTileset.begin(); QMap::const_iterator i_end = mFirstGidToTileset.end(); while (i != i_end && i.value() != tileset) ++i; if (i == i_end) // tileset not found return 0; unsigned gid = i.key() + cell.tile->id(); if (cell.flippedHorizontally) gid |= FlippedHorizontallyFlag; if (cell.flippedVertically) gid |= FlippedVerticallyFlag; if (cell.flippedAntiDiagonally) gid |= FlippedAntiDiagonallyFlag; return gid; } /** * This sets the original tileset width. In case the image size has changed, * the tile indexes will be adjusted automatically when using gidToCell(). */ void GidMapper::setTilesetWidth(const Tileset *tileset, int width) { if (tileset->tileWidth() == 0) return; mTilesetColumnCounts.insert(tileset, tileset->columnCountForWidth(width)); } /** * Encodes the tile layer data of the given \a tileLayer in the given * \a format. This function should only be used for base64 encoding, with or * without compression. */ QByteArray GidMapper::encodeLayerData(const TileLayer &tileLayer, Map::LayerDataFormat format) const { Q_ASSERT(format != Map::XML); Q_ASSERT(format != Map::CSV); QByteArray tileData; tileData.reserve(tileLayer.height() * tileLayer.width() * 4); for (int y = 0; y < tileLayer.height(); ++y) { for (int x = 0; x < tileLayer.width(); ++x) { const unsigned gid = cellToGid(tileLayer.cellAt(x, y)); tileData.append((char) (gid)); tileData.append((char) (gid >> 8)); tileData.append((char) (gid >> 16)); tileData.append((char) (gid >> 24)); } } if (format == Map::Base64Gzip) tileData = compress(tileData, Gzip); else if (format == Map::Base64Zlib) tileData = compress(tileData, Zlib); return tileData.toBase64(); } GidMapper::DecodeError GidMapper::decodeLayerData(TileLayer &tileLayer, const QByteArray &layerData, Map::LayerDataFormat format) const { Q_ASSERT(format != Map::XML); Q_ASSERT(format != Map::CSV); QByteArray decodedData = QByteArray::fromBase64(layerData); const int size = (tileLayer.width() * tileLayer.height()) * 4; if (format == Map::Base64Gzip || format == Map::Base64Zlib) decodedData = decompress(decodedData, size); if (size != decodedData.length()) return CorruptLayerData; const unsigned char *data = reinterpret_cast(decodedData.constData()); int x = 0; int y = 0; bool ok; for (int i = 0; i < size - 3; i += 4) { const unsigned gid = data[i] | data[i + 1] << 8 | data[i + 2] << 16 | data[i + 3] << 24; const Cell result = gidToCell(gid, ok); if (!ok) { mInvalidTile = gid; return isEmpty() ? TileButNoTilesets : InvalidTile; } tileLayer.setCell(x, y, result); x++; if (x == tileLayer.width()) { x = 0; y++; } } return NoError; } tiled-0.14.2/src/libtiled/gidmapper.h000066400000000000000000000063711260670167100174140ustar00rootroot00000000000000/* * gidmapper.h * Copyright 2011, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TILED_GIDMAPPER_H #define TILED_GIDMAPPER_H #include "map.h" #include "tilelayer.h" #include namespace Tiled { /** * A class that maps cells to global IDs (gids) and back. */ class TILEDSHARED_EXPORT GidMapper { public: GidMapper(); GidMapper(const QVector &tilesets); void insert(unsigned firstGid, Tileset *tileset); void clear(); bool isEmpty() const; Cell gidToCell(unsigned gid, bool &ok) const; unsigned cellToGid(const Cell &cell) const; void setTilesetWidth(const Tileset *tileset, int width); QByteArray encodeLayerData(const TileLayer &tileLayer, Map::LayerDataFormat format) const; enum DecodeError { NoError = 0, CorruptLayerData, TileButNoTilesets, InvalidTile }; DecodeError decodeLayerData(TileLayer &tileLayer, const QByteArray &layerData, Map::LayerDataFormat format) const; unsigned invalidTile() const; private: QMap mFirstGidToTileset; QMap mTilesetColumnCounts; mutable unsigned mInvalidTile; }; /** * Insert the given \a tileset with \a firstGid as its first global ID. */ inline void GidMapper::insert(unsigned firstGid, Tileset *tileset) { mFirstGidToTileset.insert(firstGid, tileset); } /** * Clears the gid mapper, so that it can be reused. */ inline void GidMapper::clear() { mFirstGidToTileset.clear(); } /** * Returns true when no tilesets are known to this gid mapper. */ inline bool GidMapper::isEmpty() const { return mFirstGidToTileset.isEmpty(); } /** * Returns the GID of the invalid tile in case decodeLayerData() returns * the InvalidTile error. */ inline unsigned GidMapper::invalidTile() const { return mInvalidTile; } } // namespace Tiled #endif // TILED_GIDMAPPER_H tiled-0.14.2/src/libtiled/hexagonalrenderer.cpp000066400000000000000000000470171260670167100214760ustar00rootroot00000000000000/* * hexagonalrenderer.cpp * Copyright 2011-2014, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "hexagonalrenderer.h" #include "map.h" #include "mapobject.h" #include "tile.h" #include "tilelayer.h" #include "tileset.h" #include #include #include using namespace Tiled; HexagonalRenderer::RenderParams::RenderParams(const Map *map) : tileWidth(map->tileWidth() & ~1) , tileHeight(map->tileHeight() & ~1) , sideLengthX(0) , sideLengthY(0) , staggerX(map->staggerAxis() == Map::StaggerX) , staggerEven(map->staggerIndex() == Map::StaggerEven) { if (map->orientation() == Map::Hexagonal) { if (staggerX) sideLengthX = map->hexSideLength(); else sideLengthY = map->hexSideLength(); } sideOffsetX = (tileWidth - sideLengthX) / 2; sideOffsetY = (tileHeight - sideLengthY) / 2; columnWidth = sideOffsetX + sideLengthX; rowHeight = sideOffsetY + sideLengthY; } QSize HexagonalRenderer::mapSize() const { const RenderParams p(map()); // The map size is the same regardless of which indexes are shifted. if (p.staggerX) { QSize size(map()->width() * p.columnWidth + p.sideOffsetX, map()->height() * (p.tileHeight + p.sideLengthY)); if (map()->width() > 1) size.rheight() += p.rowHeight; return size; } else { QSize size(map()->width() * (p.tileWidth + p.sideLengthX), map()->height() * p.rowHeight + p.sideOffsetY); if (map()->height() > 1) size.rwidth() += p.columnWidth; return size; } } QRect HexagonalRenderer::boundingRect(const QRect &rect) const { const RenderParams p(map()); QPoint topLeft = tileToScreenCoords(rect.topLeft()).toPoint(); int width, height; if (p.staggerX) { width = rect.width() * p.columnWidth + p.sideOffsetX; height = rect.height() * (p.tileHeight + p.sideLengthY); if (rect.width() > 1) { height += p.rowHeight; if (p.doStaggerX(rect.x())) topLeft.ry() -= p.rowHeight; } } else { width = rect.width() * (p.tileWidth + p.sideLengthX); height = rect.height() * p.rowHeight + p.sideOffsetY; if (rect.height() > 1) { width += p.columnWidth; if (p.doStaggerY(rect.y())) topLeft.rx() -= p.columnWidth; } } return QRect(topLeft.x(), topLeft.y(), width, height); } void HexagonalRenderer::drawGrid(QPainter *painter, const QRectF &exposed, QColor gridColor) const { QRect rect = exposed.toAlignedRect(); if (rect.isNull()) return; const RenderParams p(map()); // Determine the tile and pixel coordinates to start at QPoint startTile = screenToTileCoords(rect.topLeft()).toPoint(); QPoint startPos = tileToScreenCoords(startTile).toPoint(); /* Determine in which half of the tile the top-left corner of the area we * need to draw is. If we're in the upper half, we need to start one row * up due to those tiles being visible as well. How we go up one row * depends on whether we're in the left or right half of the tile. */ const bool inUpperHalf = rect.y() - startPos.y() < p.sideOffsetY; const bool inLeftHalf = rect.x() - startPos.x() < p.sideOffsetX; if (inUpperHalf) startTile.ry()--; if (inLeftHalf) startTile.rx()--; startTile.setX(qMax(0, startTile.x())); startTile.setY(qMax(0, startTile.y())); startPos = tileToScreenCoords(startTile).toPoint(); const QPoint oct[8] = { QPoint(0, p.tileHeight - p.sideOffsetY), QPoint(0, p.sideOffsetY), QPoint(p.sideOffsetX, 0), QPoint(p.tileWidth - p.sideOffsetX, 0), QPoint(p.tileWidth, p.sideOffsetY), QPoint(p.tileWidth, p.tileHeight - p.sideOffsetY), QPoint(p.tileWidth - p.sideOffsetX, p.tileHeight), QPoint(p.sideOffsetX, p.tileHeight) }; QVector lines; lines.reserve(8); gridColor.setAlpha(128); QPen gridPen(gridColor); gridPen.setCosmetic(true); gridPen.setDashPattern(QVector() << 2 << 2); painter->setPen(gridPen); if (p.staggerX) { // Odd row shifting is applied in the rendering loop, so un-apply it here if (p.doStaggerX(startTile.x())) startPos.ry() -= p.rowHeight; for (; startPos.x() <= rect.right() && startTile.x() < map()->width(); startTile.rx()++) { QPoint rowTile = startTile; QPoint rowPos = startPos; if (p.doStaggerX(startTile.x())) rowPos.ry() += p.rowHeight; for (; rowPos.y() <= rect.bottom() && rowTile.y() < map()->height(); rowTile.ry()++) { lines.append(QLine(rowPos + oct[1], rowPos + oct[2])); lines.append(QLine(rowPos + oct[2], rowPos + oct[3])); lines.append(QLine(rowPos + oct[3], rowPos + oct[4])); const bool isStaggered = p.doStaggerX(startTile.x()); const bool lastRow = rowTile.y() == map()->height() - 1; const bool lastColumn = rowTile.x() == map()->width() - 1; const bool bottomLeft = rowTile.x() == 0 || (lastRow && isStaggered); const bool bottomRight = lastColumn || (lastRow && isStaggered); if (bottomRight) lines.append(QLine(rowPos + oct[5], rowPos + oct[6])); if (lastRow) lines.append(QLine(rowPos + oct[6], rowPos + oct[7])); if (bottomLeft) lines.append(QLine(rowPos + oct[7], rowPos + oct[0])); painter->drawLines(lines); lines.resize(0); rowPos.ry() += p.tileHeight + p.sideLengthY; } startPos.rx() += p.columnWidth; } } else { // Odd row shifting is applied in the rendering loop, so un-apply it here if (p.doStaggerY(startTile.y())) startPos.rx() -= p.columnWidth; for (; startPos.y() <= rect.bottom() && startTile.y() < map()->height(); startTile.ry()++) { QPoint rowTile = startTile; QPoint rowPos = startPos; if (p.doStaggerY(startTile.y())) rowPos.rx() += p.columnWidth; for (; rowPos.x() <= rect.right() && rowTile.x() < map()->width(); rowTile.rx()++) { lines.append(QLine(rowPos + oct[0], rowPos + oct[1])); lines.append(QLine(rowPos + oct[1], rowPos + oct[2])); lines.append(QLine(rowPos + oct[3], rowPos + oct[4])); const bool isStaggered = p.doStaggerY(startTile.y()); const bool lastRow = rowTile.y() == map()->height() - 1; const bool lastColumn = rowTile.x() == map()->width() - 1; const bool bottomLeft = lastRow || (rowTile.x() == 0 && !isStaggered); const bool bottomRight = lastRow || (lastColumn && isStaggered); if (lastColumn) lines.append(QLine(rowPos + oct[4], rowPos + oct[5])); if (bottomRight) lines.append(QLine(rowPos + oct[5], rowPos + oct[6])); if (bottomLeft) lines.append(QLine(rowPos + oct[7], rowPos + oct[0])); painter->drawLines(lines); lines.resize(0); rowPos.rx() += p.tileWidth + p.sideLengthX; } startPos.ry() += p.rowHeight; } } } void HexagonalRenderer::drawTileLayer(QPainter *painter, const TileLayer *layer, const QRectF &exposed) const { const RenderParams p(map()); QRect rect = exposed.toAlignedRect(); if (rect.isNull()) rect = boundingRect(layer->bounds()); QMargins drawMargins = layer->drawMargins(); drawMargins.setBottom(drawMargins.bottom() + p.tileHeight); drawMargins.setRight(drawMargins.right() - p.tileWidth); rect.adjust(-drawMargins.right(), -drawMargins.bottom(), drawMargins.left(), drawMargins.top()); // Determine the tile and pixel coordinates to start at QPoint startTile = screenToTileCoords(rect.topLeft()).toPoint(); // Compensate for the layer position startTile -= layer->position(); QPoint startPos = tileToScreenCoords(startTile + layer->position()).toPoint(); /* Determine in which half of the tile the top-left corner of the area we * need to draw is. If we're in the upper half, we need to start one row * up due to those tiles being visible as well. How we go up one row * depends on whether we're in the left or right half of the tile. */ const bool inUpperHalf = rect.y() - startPos.y() < p.sideOffsetY; const bool inLeftHalf = rect.x() - startPos.x() < p.sideOffsetX; if (inUpperHalf) startTile.ry()--; if (inLeftHalf) startTile.rx()--; CellRenderer renderer(painter); if (p.staggerX) { startTile.setX(qMax(-1, startTile.x())); startTile.setY(qMax(-1, startTile.y())); startPos = tileToScreenCoords(startTile + layer->position()).toPoint(); startPos.ry() += p.tileHeight; bool staggeredRow = p.doStaggerX(startTile.x() + layer->x()); for (; startPos.y() < rect.bottom() && startTile.y() < layer->height();) { QPoint rowTile = startTile; QPoint rowPos = startPos; for (; rowPos.x() < rect.right() && rowTile.x() < layer->width(); rowTile.rx() += 2) { if (layer->contains(rowTile)) { const Cell &cell = layer->cellAt(rowTile); if (!cell.isEmpty()) renderer.render(cell, rowPos, QSizeF(0, 0), CellRenderer::BottomLeft); } rowPos.rx() += p.tileWidth + p.sideLengthX; } if (staggeredRow) { startTile.rx() -= 1; startTile.ry() += 1; startPos.rx() -= p.columnWidth; staggeredRow = false; } else { startTile.rx() += 1; startPos.rx() += p.columnWidth; staggeredRow = true; } startPos.ry() += p.rowHeight; } } else { startTile.setX(qMax(0, startTile.x())); startTile.setY(qMax(0, startTile.y())); startPos = tileToScreenCoords(startTile + layer->position()).toPoint(); startPos.ry() += p.tileHeight; // Odd row shifting is applied in the rendering loop, so un-apply it here if (p.doStaggerY(startTile.y() + layer->y())) startPos.rx() -= p.columnWidth; for (; startPos.y() < rect.bottom() && startTile.y() < layer->height(); startTile.ry()++) { QPoint rowTile = startTile; QPoint rowPos = startPos; if (p.doStaggerY(startTile.y() + layer->y())) rowPos.rx() += p.columnWidth; for (; rowPos.x() < rect.right() && rowTile.x() < layer->width(); rowTile.rx()++) { const Cell &cell = layer->cellAt(rowTile); if (!cell.isEmpty()) renderer.render(cell, rowPos, QSizeF(0, 0), CellRenderer::BottomLeft); rowPos.rx() += p.tileWidth + p.sideLengthX; } startPos.ry() += p.rowHeight; } } } void HexagonalRenderer::drawTileSelection(QPainter *painter, const QRegion ®ion, const QColor &color, const QRectF &exposed) const { painter->setBrush(color); painter->setPen(Qt::NoPen); foreach (const QRect &r, region.rects()) { for (int y = r.top(); y <= r.bottom(); ++y) { for (int x = r.left(); x <= r.right(); ++x) { const QPolygonF polygon = tileToScreenPolygon(x, y); if (QRectF(polygon.boundingRect()).intersects(exposed)) painter->drawConvexPolygon(polygon); } } } } QPointF HexagonalRenderer::tileToPixelCoords(qreal x, qreal y) const { return HexagonalRenderer::tileToScreenCoords(x, y); } QPointF HexagonalRenderer::pixelToTileCoords(qreal x, qreal y) const { return HexagonalRenderer::screenToTileCoords(x, y); } /** * Converts screen to tile coordinates. Sub-tile return values are not * supported by this renderer. */ QPointF HexagonalRenderer::screenToTileCoords(qreal x, qreal y) const { const RenderParams p(map()); if (p.staggerX) x -= p.staggerEven ? p.tileWidth : p.sideOffsetX; else y -= p.staggerEven ? p.tileHeight : p.sideOffsetY; // Start with the coordinates of a grid-aligned tile QPoint referencePoint = QPoint(qFloor(x / (p.tileWidth + p.sideLengthX)), qFloor(y / (p.tileHeight + p.sideLengthY))); // Relative x and y position on the base square of the grid-aligned tile const QVector2D rel(x - referencePoint.x() * (p.tileWidth + p.sideLengthX), y - referencePoint.y() * (p.tileHeight + p.sideLengthY)); // Adjust the reference point to the correct tile coordinates int &staggerAxisIndex = p.staggerX ? referencePoint.rx() : referencePoint.ry(); staggerAxisIndex *= 2; if (p.staggerEven) ++staggerAxisIndex; // Determine the nearest hexagon tile by the distance to the center QVector2D centers[4]; if (p.staggerX) { const int left = p.sideLengthX / 2; const int centerX = left + p.columnWidth; const int centerY = p.tileHeight / 2; centers[0] = QVector2D(left, centerY); centers[1] = QVector2D(centerX, centerY - p.rowHeight); centers[2] = QVector2D(centerX, centerY + p.rowHeight); centers[3] = QVector2D(centerX + p.columnWidth, centerY); } else { const int top = p.sideLengthY / 2; const int centerX = p.tileWidth / 2; const int centerY = top + p.rowHeight; centers[0] = QVector2D(centerX, top); centers[1] = QVector2D(centerX - p.columnWidth, centerY); centers[2] = QVector2D(centerX + p.columnWidth, centerY); centers[3] = QVector2D(centerX, centerY + p.rowHeight); } int nearest = 0; qreal minDist = std::numeric_limits::max(); for (int i = 0; i < 4; ++i) { const QVector2D ¢er = centers[i]; const qreal dc = (center - rel).lengthSquared(); if (dc < minDist) { minDist = dc; nearest = i; } } static const QPoint offsetsStaggerX[4] = { QPoint( 0, 0), QPoint(+1, -1), QPoint(+1, 0), QPoint(+2, 0), }; static const QPoint offsetsStaggerY[4] = { QPoint( 0, 0), QPoint(-1, +1), QPoint( 0, +1), QPoint( 0, +2), }; const QPoint *offsets = p.staggerX ? offsetsStaggerX : offsetsStaggerY; return referencePoint + offsets[nearest]; } /** * Converts tile to screen coordinates. Sub-tile return values are not * supported by this renderer. */ QPointF HexagonalRenderer::tileToScreenCoords(qreal x, qreal y) const { const RenderParams p(map()); const int tileX = qFloor(x); const int tileY = qFloor(y); int pixelX, pixelY; if (p.staggerX) { pixelY = tileY * (p.tileHeight + p.sideLengthY); if (p.doStaggerX(tileX)) pixelY += p.rowHeight; pixelX = tileX * p.columnWidth; } else { pixelX = tileX * (p.tileWidth + p.sideLengthX); if (p.doStaggerY(tileY)) pixelX += p.columnWidth; pixelY = tileY * p.rowHeight; } return QPointF(pixelX, pixelY); } QPoint HexagonalRenderer::topLeft(int x, int y) const { if (map()->staggerAxis() == Map::StaggerY) { if ((y & 1) ^ map()->staggerIndex()) return QPoint(x, y - 1); else return QPoint(x - 1, y - 1); } else { if ((x & 1) ^ map()->staggerIndex()) return QPoint(x - 1, y); else return QPoint(x - 1, y - 1); } } QPoint HexagonalRenderer::topRight(int x, int y) const { if (map()->staggerAxis() == Map::StaggerY) { if ((y & 1) ^ map()->staggerIndex()) return QPoint(x + 1, y - 1); else return QPoint(x, y - 1); } else { if ((x & 1) ^ map()->staggerIndex()) return QPoint(x + 1, y); else return QPoint(x + 1, y - 1); } } QPoint HexagonalRenderer::bottomLeft(int x, int y) const { if (map()->staggerAxis() == Map::StaggerY) { if ((y & 1) ^ map()->staggerIndex()) return QPoint(x, y + 1); else return QPoint(x - 1, y + 1); } else { if ((x & 1) ^ map()->staggerIndex()) return QPoint(x - 1, y + 1); else return QPoint(x - 1, y); } } QPoint HexagonalRenderer::bottomRight(int x, int y) const { if (map()->staggerAxis() == Map::StaggerY) { if ((y & 1) ^ map()->staggerIndex()) return QPoint(x + 1, y + 1); else return QPoint(x, y + 1); } else { if ((x & 1) ^ map()->staggerIndex()) return QPoint(x + 1, y + 1); else return QPoint(x + 1, y); } } QPolygonF HexagonalRenderer::tileToScreenPolygon(int x, int y) const { const RenderParams p(map()); const QPointF topRight = tileToScreenCoords(x, y); QPolygonF polygon(8); polygon[0] = topRight + QPoint(0, p.tileHeight - p.sideOffsetY); polygon[1] = topRight + QPoint(0, p.sideOffsetY); polygon[2] = topRight + QPoint(p.sideOffsetX, 0); polygon[3] = topRight + QPoint(p.tileWidth - p.sideOffsetX, 0); polygon[4] = topRight + QPoint(p.tileWidth, p.sideOffsetY); polygon[5] = topRight + QPoint(p.tileWidth, p.tileHeight - p.sideOffsetY); polygon[6] = topRight + QPoint(p.tileWidth - p.sideOffsetX, p.tileHeight); polygon[7] = topRight + QPoint(p.sideOffsetX, p.tileHeight); return polygon; } tiled-0.14.2/src/libtiled/hexagonalrenderer.h000066400000000000000000000073541260670167100211430ustar00rootroot00000000000000/* * staggeredrenderer.h * Copyright 2011-2014, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HEXAGONALRENDERER_H #define HEXAGONALRENDERER_H #include "orthogonalrenderer.h" namespace Tiled { /** * A hexagonal renderer. * * Only pointy-topped hexagons are supported at the moment, shifting either the * odd or the even rows to the right. * * The same problems as present when using the StaggeredRenderer happen with * this renderer. */ class TILEDSHARED_EXPORT HexagonalRenderer : public OrthogonalRenderer { protected: struct RenderParams { RenderParams(const Map *map); bool doStaggerX(int x) const { return staggerX && (x & 1) ^ staggerEven; } bool doStaggerY(int y) const { return !staggerX && (y & 1) ^ staggerEven; } const int tileWidth; const int tileHeight; int sideLengthX; int sideOffsetX; int sideLengthY; int sideOffsetY; int rowHeight; int columnWidth; const bool staggerX; const bool staggerEven; }; public: HexagonalRenderer(const Map *map) : OrthogonalRenderer(map) {} QSize mapSize() const override; QRect boundingRect(const QRect &rect) const override; void drawGrid(QPainter *painter, const QRectF &exposed, QColor gridColor) const override; void drawTileLayer(QPainter *painter, const TileLayer *layer, const QRectF &exposed = QRectF()) const override; void drawTileSelection(QPainter *painter, const QRegion ®ion, const QColor &color, const QRectF &exposed) const override; using OrthogonalRenderer::pixelToTileCoords; QPointF pixelToTileCoords(qreal x, qreal y) const override; using OrthogonalRenderer::tileToPixelCoords; QPointF tileToPixelCoords(qreal x, qreal y) const override; using OrthogonalRenderer::screenToTileCoords; QPointF screenToTileCoords(qreal x, qreal y) const override; using OrthogonalRenderer::tileToScreenCoords; QPointF tileToScreenCoords(qreal x, qreal y) const override; // Functions specific to this type of renderer QPoint topLeft(int x, int y) const; QPoint topRight(int x, int y) const; QPoint bottomLeft(int x, int y) const; QPoint bottomRight(int x, int y) const; QPolygonF tileToScreenPolygon(int x, int y) const; }; } // namespace Tiled #endif // HEXAGONALRENDERER_H tiled-0.14.2/src/libtiled/imagelayer.cpp000066400000000000000000000051241260670167100201110ustar00rootroot00000000000000/* * imagelayer.cpp * Copyright 2011, Gregory Nickonov * Copyright 2012, Alexander Kuhrt * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "imagelayer.h" #include "map.h" #include using namespace Tiled; ImageLayer::ImageLayer(const QString &name, int x, int y, int width, int height): Layer(ImageLayerType, name, x, y, width, height) { } ImageLayer::~ImageLayer() { } void ImageLayer::resetImage() { mImage = QPixmap(); mImageSource.clear(); } bool ImageLayer::loadFromImage(const QImage &image, const QString &fileName) { mImageSource = fileName; if (image.isNull()) { mImage = QPixmap(); return false; } mImage = QPixmap::fromImage(image); if (mTransparentColor.isValid()) { const QImage mask = image.createMaskFromColor(mTransparentColor.rgb()); mImage.setMask(QBitmap::fromImage(mask)); } return true; } bool ImageLayer::isEmpty() const { return mImage.isNull(); } Layer *ImageLayer::clone() const { return initializeClone(new ImageLayer(mName, mX, mY, mWidth, mHeight)); } ImageLayer *ImageLayer::initializeClone(ImageLayer *clone) const { Layer::initializeClone(clone); clone->mImageSource = mImageSource; clone->mTransparentColor = mTransparentColor; clone->mImage = mImage; return clone; } tiled-0.14.2/src/libtiled/imagelayer.h000066400000000000000000000100151260670167100175510ustar00rootroot00000000000000/* * imagelayer.h * Copyright 2011, Gregory Nickonov * Copyright 2012, Alexander Kuhrt * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef IMAGELAYER_H #define IMAGELAYER_H #include "tiled_global.h" #include "layer.h" #include #include class QImage; namespace Tiled { /** * An image on a map. */ class TILEDSHARED_EXPORT ImageLayer : public Layer { public: /** * Constructor. */ ImageLayer(const QString &name, int x, int y, int width, int height); /** * Destructor. */ ~ImageLayer(); QSet usedTilesets() const override { return QSet(); } bool referencesTileset(const Tileset *) const override { return false; } void replaceReferencesToTileset(Tileset *, Tileset *) override {} bool canMergeWith(Layer *) const override { return false; } Layer *mergedWith(Layer *) const override { return nullptr; } /** * Returns the transparent color, or an invalid color if no transparent * color is used. */ const QColor &transparentColor() const { return mTransparentColor; } /** * Sets the transparent color. Pixels with this color will be masked out * when loadFromImage() is called. */ void setTransparentColor(const QColor &c) { mTransparentColor = c; } /** * Sets image source file name */ void setSource(const QString &source) { mImageSource = source; } /** * Returns the file name of the layer image. */ const QString &imageSource() const { return mImageSource; } /** * Returns the image of this layer. */ const QPixmap &image() const { return mImage; } /** * Sets the image of this layer. */ void setImage(const QPixmap &image) { mImage = image; } /** * Resets layer image. */ void resetImage(); /** * Load this layer from the given \a image. This will replace the existing * image. The \a fileName becomes the new imageSource, regardless of * whether the image could be loaded. * * @param image the image to load the layer from * @param fileName the file name of the image, which will be remembered * as the image source of this layer. * @return true if loading was successful, otherwise * returns false */ bool loadFromImage(const QImage &image, const QString &fileName); /** * Returns true if no image source has been set. */ bool isEmpty() const override; Layer *clone() const override; protected: ImageLayer *initializeClone(ImageLayer *clone) const; private: QString mImageSource; QColor mTransparentColor; QPixmap mImage; }; } // namespace Tiled #endif // IMAGELAYER_H tiled-0.14.2/src/libtiled/isometricrenderer.cpp000066400000000000000000000456571260670167100215360ustar00rootroot00000000000000/* * isometricrenderer.cpp * Copyright 2009-2011, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "isometricrenderer.h" #include "map.h" #include "mapobject.h" #include "tile.h" #include "tilelayer.h" #include "tileset.h" #include using namespace Tiled; QSize IsometricRenderer::mapSize() const { // Map width and height contribute equally in both directions const int side = map()->height() + map()->width(); return QSize(side * map()->tileWidth() / 2, side * map()->tileHeight() / 2); } QRect IsometricRenderer::boundingRect(const QRect &rect) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); const int originX = map()->height() * tileWidth / 2; const QPoint pos((rect.x() - (rect.y() + rect.height())) * tileWidth / 2 + originX, (rect.x() + rect.y()) * tileHeight / 2); const int side = rect.height() + rect.width(); const QSize size(side * tileWidth / 2, side * tileHeight / 2); return QRect(pos, size); } QRectF IsometricRenderer::boundingRect(const MapObject *object) const { if (!object->cell().isEmpty()) { const QPointF bottomCenter = pixelToScreenCoords(object->position()); const Tile *tile = object->cell().tile; const QSize imgSize = tile->image().size(); const QPoint tileOffset = tile->offset(); const QSizeF objectSize = object->size(); const QSizeF scale(objectSize.width() / imgSize.width(), objectSize.height() / imgSize.height()); return QRectF(bottomCenter.x() + (tileOffset.x() * scale.width()) - objectSize.width() / 2, bottomCenter.y() + (tileOffset.y() * scale.height()) - objectSize.height(), objectSize.width(), objectSize.height()).adjusted(-1, -1, 1, 1); } else if (!object->polygon().isEmpty()) { qreal extraSpace = qMax(objectLineWidth(), qreal(1)); // Make some more room for the starting dot extraSpace += objectLineWidth() * 4; const QPointF &pos = object->position(); const QPolygonF polygon = object->polygon().translated(pos); const QPolygonF screenPolygon = pixelToScreenCoords(polygon); return screenPolygon.boundingRect().adjusted(-extraSpace, -extraSpace - 1, extraSpace, extraSpace); } else { // Take the bounding rect of the projected object, and then add a few // pixels on all sides to correct for the line width. const QRectF base = pixelRectToScreenPolygon(object->bounds()).boundingRect(); const qreal extraSpace = qMax(objectLineWidth() / 2, qreal(1)); return base.adjusted(-extraSpace, -extraSpace - 1, extraSpace, extraSpace); } } QPainterPath IsometricRenderer::shape(const MapObject *object) const { QPainterPath path; if (!object->cell().isEmpty()) { path.addRect(boundingRect(object)); } else { switch (object->shape()) { case MapObject::Ellipse: case MapObject::Rectangle: path.addPolygon(pixelRectToScreenPolygon(object->bounds())); break; case MapObject::Polygon: case MapObject::Polyline: { const QPointF &pos = object->position(); const QPolygonF polygon = object->polygon().translated(pos); const QPolygonF screenPolygon = pixelToScreenCoords(polygon); if (object->shape() == MapObject::Polygon) { path.addPolygon(screenPolygon); } else { for (int i = 1; i < screenPolygon.size(); ++i) { path.addPolygon(lineToPolygon(screenPolygon[i - 1], screenPolygon[i])); } path.setFillRule(Qt::WindingFill); } break; } } } return path; } void IsometricRenderer::drawGrid(QPainter *painter, const QRectF &rect, QColor gridColor) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); QRect r = rect.toAlignedRect(); r.adjust(-tileWidth / 2, -tileHeight / 2, tileWidth / 2, tileHeight / 2); const int startX = qMax(qreal(0), screenToTileCoords(r.topLeft()).x()); const int startY = qMax(qreal(0), screenToTileCoords(r.topRight()).y()); const int endX = qMin(qreal(map()->width()), screenToTileCoords(r.bottomRight()).x()); const int endY = qMin(qreal(map()->height()), screenToTileCoords(r.bottomLeft()).y()); gridColor.setAlpha(128); QPen gridPen(gridColor); gridPen.setCosmetic(true); gridPen.setDashPattern(QVector() << 2 << 2); painter->setPen(gridPen); for (int y = startY; y <= endY; ++y) { const QPointF start = tileToScreenCoords(startX, y); const QPointF end = tileToScreenCoords(endX, y); painter->drawLine(start, end); } for (int x = startX; x <= endX; ++x) { const QPointF start = tileToScreenCoords(x, startY); const QPointF end = tileToScreenCoords(x, endY); painter->drawLine(start, end); } } void IsometricRenderer::drawTileLayer(QPainter *painter, const TileLayer *layer, const QRectF &exposed) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); if (tileWidth <= 0 || tileHeight <= 1) return; QRect rect = exposed.toAlignedRect(); if (rect.isNull()) rect = boundingRect(layer->bounds()); QMargins drawMargins = layer->drawMargins(); drawMargins.setTop(drawMargins.top() - tileHeight); drawMargins.setRight(drawMargins.right() - tileWidth); rect.adjust(-drawMargins.right(), -drawMargins.bottom(), drawMargins.left(), drawMargins.top()); // Determine the tile and pixel coordinates to start at QPointF tilePos = screenToTileCoords(rect.x(), rect.y()); QPoint rowItr = QPoint((int) std::floor(tilePos.x()), (int) std::floor(tilePos.y())); QPointF startPos = tileToScreenCoords(rowItr); startPos.rx() -= tileWidth / 2; startPos.ry() += tileHeight; // Compensate for the layer position rowItr -= QPoint(layer->x(), layer->y()); /* Determine in which half of the tile the top-left corner of the area we * need to draw is. If we're in the upper half, we need to start one row * up due to those tiles being visible as well. How we go up one row * depends on whether we're in the left or right half of the tile. */ const bool inUpperHalf = startPos.y() - rect.y() > tileHeight / 2; const bool inLeftHalf = rect.x() - startPos.x() < tileWidth / 2; if (inUpperHalf) { if (inLeftHalf) { --rowItr.rx(); startPos.rx() -= tileWidth / 2; } else { --rowItr.ry(); startPos.rx() += tileWidth / 2; } startPos.ry() -= tileHeight / 2; } // Determine whether the current row is shifted half a tile to the right bool shifted = inUpperHalf ^ inLeftHalf; CellRenderer renderer(painter); for (int y = startPos.y(); y - tileHeight < rect.bottom(); y += tileHeight / 2) { QPoint columnItr = rowItr; for (int x = startPos.x(); x < rect.right(); x += tileWidth) { if (layer->contains(columnItr)) { const Cell &cell = layer->cellAt(columnItr); if (!cell.isEmpty()) { renderer.render(cell, QPointF(x, y), QSizeF(0, 0), CellRenderer::BottomLeft); } } // Advance to the next column ++columnItr.rx(); --columnItr.ry(); } // Advance to the next row if (!shifted) { ++rowItr.rx(); startPos.rx() += tileWidth / 2; shifted = true; } else { ++rowItr.ry(); startPos.rx() -= tileWidth / 2; shifted = false; } } } void IsometricRenderer::drawTileSelection(QPainter *painter, const QRegion ®ion, const QColor &color, const QRectF &exposed) const { painter->setBrush(color); painter->setPen(Qt::NoPen); foreach (const QRect &r, region.rects()) { QPolygonF polygon = tileRectToScreenPolygon(r); if (QRectF(polygon.boundingRect()).intersects(exposed)) painter->drawConvexPolygon(polygon); } } void IsometricRenderer::drawMapObject(QPainter *painter, const MapObject *object, const QColor &color) const { painter->save(); QPen pen(Qt::black); pen.setCosmetic(true); const Cell &cell = object->cell(); if (!cell.isEmpty()) { const Tile *tile = cell.tile; const QSize imgSize = tile->size(); const QPointF pos = pixelToScreenCoords(object->position()); const QPointF tileOffset = tile->offset(); CellRenderer(painter).render(cell, pos, object->size(), CellRenderer::BottomCenter); if (testFlag(ShowTileObjectOutlines)) { QRectF rect(QPointF(pos.x() - imgSize.width() / 2 + tileOffset.x(), pos.y() - imgSize.height() + tileOffset.y()), imgSize); pen.setStyle(Qt::SolidLine); painter->setPen(pen); painter->drawRect(rect); pen.setStyle(Qt::DotLine); pen.setColor(color); painter->setPen(pen); painter->drawRect(rect); } } else { const qreal lineWidth = objectLineWidth(); const qreal scale = painterScale(); const qreal shadowOffset = (lineWidth == 0 ? 1 : lineWidth) / scale; QColor brushColor = color; brushColor.setAlpha(50); QBrush brush(brushColor); pen.setJoinStyle(Qt::RoundJoin); pen.setCapStyle(Qt::RoundCap); pen.setWidth(lineWidth); QPen colorPen(pen); colorPen.setColor(color); painter->setPen(pen); painter->setRenderHint(QPainter::Antialiasing); // TODO: Do something sensible to make null-sized objects usable switch (object->shape()) { case MapObject::Ellipse: { QPolygonF polygon = pixelRectToScreenPolygon(object->bounds()); float tw = map()->tileWidth(); float th = map()->tileHeight(); QPointF transformScale(1, 1); if (tw > th) transformScale = QPointF(1, th/tw); else transformScale = QPointF(tw/th, 1); QPointF l1 = polygon.at(1) - polygon.at(0); QPointF l2 = polygon.at(3) - polygon.at(0); QTransform trans; trans.scale(transformScale.x(), transformScale.y()); trans.rotate(45); QTransform iTrans = trans.inverted(); QPointF l1x = iTrans.map(l1); QPointF l2x = iTrans.map(l2); QSizeF ellipseSize(l1x.manhattanLength(), l2x.manhattanLength()); if (ellipseSize.width() > 0 && ellipseSize.height() > 0) { painter->save(); painter->setPen(pen); painter->translate(polygon.at(0)); painter->scale(transformScale.x(), transformScale.y()); painter->rotate(45); painter->drawEllipse(QRectF(QPointF(0, 0), ellipseSize)); painter->restore(); } painter->setBrush(Qt::NoBrush); painter->drawPolygon(polygon); painter->setPen(colorPen); painter->setBrush(Qt::NoBrush); painter->translate(QPointF(0, -shadowOffset)); painter->drawPolygon(polygon); painter->setBrush(brush); if (ellipseSize.width() > 0 && ellipseSize.height() > 0) { painter->save(); painter->translate(polygon.at(0)); painter->scale(transformScale.x(), transformScale.y()); painter->rotate(45); painter->drawEllipse(QRectF(QPointF(0, 0), ellipseSize)); painter->restore(); } break; } case MapObject::Rectangle: { QPolygonF polygon = pixelRectToScreenPolygon(object->bounds()); painter->drawPolygon(polygon); painter->setPen(colorPen); painter->setBrush(brush); polygon.translate(0, -shadowOffset); painter->drawPolygon(polygon); break; } case MapObject::Polygon: { const QPointF &pos = object->position(); const QPolygonF polygon = object->polygon().translated(pos); QPolygonF screenPolygon = pixelToScreenCoords(polygon); QPen thickPen(pen); QPen thickColorPen(colorPen); thickPen.setWidthF(thickPen.widthF() * 4); thickColorPen.setWidthF(thickColorPen.widthF() * 4); painter->drawPolygon(screenPolygon); painter->setPen(thickPen); painter->drawPoint(screenPolygon.first()); painter->setPen(colorPen); painter->setBrush(brush); screenPolygon.translate(0, -shadowOffset); painter->drawPolygon(screenPolygon); painter->setPen(thickColorPen); painter->drawPoint(screenPolygon.first()); break; } case MapObject::Polyline: { const QPointF &pos = object->position(); const QPolygonF polygon = object->polygon().translated(pos); QPolygonF screenPolygon = pixelToScreenCoords(polygon); QPen thickPen(pen); QPen thickColorPen(colorPen); thickPen.setWidthF(thickPen.widthF() * 4); thickColorPen.setWidthF(thickColorPen.widthF() * 4); painter->drawPolyline(screenPolygon); painter->setPen(thickPen); painter->drawPoint(screenPolygon.first()); pen.setColor(color); painter->setPen(pen); screenPolygon.translate(0, -shadowOffset); painter->drawPolyline(screenPolygon); painter->setPen(thickColorPen); painter->drawPoint(screenPolygon.first()); break; } } } painter->restore(); } QPointF IsometricRenderer::pixelToTileCoords(qreal x, qreal y) const { const int tileHeight = map()->tileHeight(); return QPointF(x / tileHeight, y / tileHeight); } QPointF IsometricRenderer::tileToPixelCoords(qreal x, qreal y) const { const int tileHeight = map()->tileHeight(); return QPointF(x * tileHeight, y * tileHeight); } QPointF IsometricRenderer::screenToTileCoords(qreal x, qreal y) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); x -= map()->height() * tileWidth / 2; const qreal tileY = y / tileHeight; const qreal tileX = x / tileWidth; return QPointF(tileY + tileX, tileY - tileX); } QPointF IsometricRenderer::tileToScreenCoords(qreal x, qreal y) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); const int originX = map()->height() * tileWidth / 2; return QPointF((x - y) * tileWidth / 2 + originX, (x + y) * tileHeight / 2); } QPointF IsometricRenderer::screenToPixelCoords(qreal x, qreal y) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); x -= map()->height() * tileWidth / 2; const qreal tileY = y / tileHeight; const qreal tileX = x / tileWidth; return QPointF((tileY + tileX) * tileHeight, (tileY - tileX) * tileHeight); } QPointF IsometricRenderer::pixelToScreenCoords(qreal x, qreal y) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); const int originX = map()->height() * tileWidth / 2; const qreal tileY = y / tileHeight; const qreal tileX = x / tileHeight; return QPointF((tileX - tileY) * tileWidth / 2 + originX, (tileX + tileY) * tileHeight / 2); } QPolygonF IsometricRenderer::pixelRectToScreenPolygon(const QRectF &rect) const { QPolygonF polygon; polygon << QPointF(pixelToScreenCoords(rect.topLeft())); polygon << QPointF(pixelToScreenCoords(rect.topRight())); polygon << QPointF(pixelToScreenCoords(rect.bottomRight())); polygon << QPointF(pixelToScreenCoords(rect.bottomLeft())); return polygon; } QPolygonF IsometricRenderer::tileRectToScreenPolygon(const QRect &rect) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); const QPointF topRight = tileToScreenCoords(rect.topRight()); const QPointF bottomRight = tileToScreenCoords(rect.bottomRight()); const QPointF bottomLeft = tileToScreenCoords(rect.bottomLeft()); QPolygonF polygon; polygon << QPointF(tileToScreenCoords(rect.topLeft())); polygon << QPointF(topRight.x() + tileWidth / 2, topRight.y() + tileHeight / 2); polygon << QPointF(bottomRight.x(), bottomRight.y() + tileHeight); polygon << QPointF(bottomLeft.x() - tileWidth / 2, bottomLeft.y() + tileHeight / 2); return polygon; } tiled-0.14.2/src/libtiled/isometricrenderer.h000066400000000000000000000070041260670167100211630ustar00rootroot00000000000000/* * isometricrenderer.h * Copyright 2009-2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ISOMETRICRENDERER_H #define ISOMETRICRENDERER_H #include "maprenderer.h" namespace Tiled { /** * An isometric map renderer. * * Isometric maps have diamond shaped tiles. This map renderer renders them in * such a way that the map will also be diamond shaped. The X axis points to * the bottom right while the Y axis points to the bottom left. */ class TILEDSHARED_EXPORT IsometricRenderer : public MapRenderer { public: IsometricRenderer(const Map *map) : MapRenderer(map) {} QSize mapSize() const override; QRect boundingRect(const QRect &rect) const override; QRectF boundingRect(const MapObject *object) const override; QPainterPath shape(const MapObject *object) const override; void drawGrid(QPainter *painter, const QRectF &rect, QColor grid) const override; void drawTileLayer(QPainter *painter, const TileLayer *layer, const QRectF &exposed = QRectF()) const override; void drawTileSelection(QPainter *painter, const QRegion ®ion, const QColor &color, const QRectF &exposed) const override; void drawMapObject(QPainter *painter, const MapObject *object, const QColor &color) const override; using MapRenderer::pixelToTileCoords; QPointF pixelToTileCoords(qreal x, qreal y) const override; using MapRenderer::tileToPixelCoords; QPointF tileToPixelCoords(qreal x, qreal y) const override; using MapRenderer::screenToTileCoords; QPointF screenToTileCoords(qreal x, qreal y) const override; using MapRenderer::tileToScreenCoords; QPointF tileToScreenCoords(qreal x, qreal y) const override; using MapRenderer::screenToPixelCoords; QPointF screenToPixelCoords(qreal x, qreal y) const override; using MapRenderer::pixelToScreenCoords; QPointF pixelToScreenCoords(qreal x, qreal y) const override; private: QPolygonF pixelRectToScreenPolygon(const QRectF &rect) const; QPolygonF tileRectToScreenPolygon(const QRect &rect) const; }; } // namespace Tiled #endif // ISOMETRICRENDERER_H tiled-0.14.2/src/libtiled/layer.cpp000066400000000000000000000054221260670167100171070ustar00rootroot00000000000000/* * layer.cpp * Copyright 2008-2010, Thorbjørn Lindeijer * Copyright 2009, Jeff Bland * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "layer.h" #include "imagelayer.h" #include "objectgroup.h" #include "tilelayer.h" using namespace Tiled; Layer::Layer(TypeFlag type, const QString &name, int x, int y, int width, int height) : Object(LayerType), mName(name), mLayerType(type), mX(x), mY(y), mWidth(width), mHeight(height), mOpacity(1.0f), mVisible(true), mMap(nullptr) { } /** * A helper function for initializing the members of the given instance to * those of this layer. Used by subclasses when cloning. * * Layer name, position and size are not cloned, since they are assumed to have * already been passed to the constructor. Also, map ownership is not cloned, * since the clone is not added to the map. * * \return the initialized clone (the same instance that was passed in) * \sa clone() */ Layer *Layer::initializeClone(Layer *clone) const { clone->mOffset = mOffset; clone->mOpacity = mOpacity; clone->mVisible = mVisible; clone->setProperties(properties()); return clone; } TileLayer *Layer::asTileLayer() { return isTileLayer() ? static_cast(this) : nullptr; } ObjectGroup *Layer::asObjectGroup() { return isObjectGroup() ? static_cast(this) : nullptr; } ImageLayer *Layer::asImageLayer() { return isImageLayer() ? static_cast(this) : nullptr; } tiled-0.14.2/src/libtiled/layer.h000066400000000000000000000152721260670167100165600ustar00rootroot00000000000000/* * layer.h * Copyright 2008-2010, Thorbjørn Lindeijer * Copyright 2009, Jeff Bland * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LAYER_H #define LAYER_H #include "object.h" #include "tileset.h" #include #include #include #include #include namespace Tiled { class Map; class ImageLayer; class ObjectGroup; class TileLayer; /** * A map layer. */ class TILEDSHARED_EXPORT Layer : public Object { public: enum TypeFlag { TileLayerType = 0x01, ObjectGroupType = 0x02, ImageLayerType = 0x04 }; enum { AnyLayerType = 0xFF }; /** * Constructor. */ Layer(TypeFlag type, const QString &name, int x, int y, int width, int height); /** * Returns the type of this layer. */ TypeFlag layerType() const { return mLayerType; } /** * Returns the name of this layer. */ const QString &name() const { return mName; } /** * Sets the name of this layer. */ void setName(const QString &name) { mName = name; } /** * Returns the opacity of this layer. */ float opacity() const { return mOpacity; } /** * Sets the opacity of this layer. */ void setOpacity(float opacity) { mOpacity = opacity; } /** * Returns the visibility of this layer. */ bool isVisible() const { return mVisible; } /** * Sets the visibility of this layer. */ void setVisible(bool visible) { mVisible = visible; } /** * Returns the map this layer is part of. */ Map *map() const { return mMap; } /** * Sets the map this layer is part of. Should only be called from the * Map class. */ void setMap(Map *map) { mMap = map; } /** * Returns the x position of this layer (in tiles). */ int x() const { return mX; } /** * Sets the x position of this layer (in tiles). */ void setX(int x) { mX = x; } /** * Returns the y position of this layer (in tiles). */ int y() const { return mY; } /** * Sets the y position of this layer (in tiles). */ void setY(int y) { mY = y; } /** * Returns the position of this layer (in tiles). */ QPoint position() const { return QPoint(mX, mY); } /** * Sets the position of this layer (in tiles). */ void setPosition(QPoint pos) { setPosition(pos.x(), pos.y()); } void setPosition(int x, int y) { mX = x; mY = y; } /** * Returns the width of this layer. */ int width() const { return mWidth; } /** * Returns the height of this layer. */ int height() const { return mHeight; } /** * Returns the size of this layer. */ QSize size() const { return QSize(mWidth, mHeight); } void setSize(const QSize &size); /** * Returns the bounds of this layer. */ QRect bounds() const { return QRect(mX, mY, mWidth, mHeight); } void setOffset(const QPointF &offset); QPointF offset() const; virtual bool isEmpty() const = 0; /** * Computes and returns the set of tilesets used by this layer. */ virtual QSet usedTilesets() const = 0; /** * Returns whether this layer is referencing the given tileset. */ virtual bool referencesTileset(const Tileset *tileset) const = 0; /** * Replaces all references to tiles from \a oldTileset with tiles from * \a newTileset. */ virtual void replaceReferencesToTileset(Tileset *oldTileset, Tileset *newTileset) = 0; /** * Returns whether this layer can merge together with the \a other layer. */ virtual bool canMergeWith(Layer *other) const = 0; /** * Returns a newly allocated layer that is the result of merging this layer * with the \a other layer. Where relevant, the other layer is considered * to be on top of this one. * * Should only be called when canMergeWith returns true. */ virtual Layer *mergedWith(Layer *other) const = 0; /** * Returns a duplicate of this layer. The caller is responsible for the * ownership of this newly created layer. */ virtual Layer *clone() const = 0; // These functions allow checking whether this Layer is an instance of the // given subclass without relying on a dynamic_cast. bool isTileLayer() const { return mLayerType == TileLayerType; } bool isObjectGroup() const { return mLayerType == ObjectGroupType; } bool isImageLayer() const { return mLayerType == ImageLayerType; } // These actually return this layer cast to one of its subclasses. TileLayer *asTileLayer(); ObjectGroup *asObjectGroup(); ImageLayer *asImageLayer(); protected: Layer *initializeClone(Layer *clone) const; QString mName; TypeFlag mLayerType; int mX; int mY; int mWidth; int mHeight; QPointF mOffset; float mOpacity; bool mVisible; Map *mMap; }; /** * Sets the size of this layer. */ inline void Layer::setSize(const QSize &size) { mWidth = size.width(); mHeight = size.height(); } /** * Sets the drawing offset in pixels of this layer. */ inline void Layer::setOffset(const QPointF &offset) { mOffset = offset; } /** * Returns the drawing offset in pixels of this layer. */ inline QPointF Layer::offset() const { return mOffset; } } // namespace Tiled #endif // LAYER_H tiled-0.14.2/src/libtiled/libtiled.pri000066400000000000000000000000451260670167100175670ustar00rootroot00000000000000INCLUDEPATH += $$PWD LIBS *= -ltiled tiled-0.14.2/src/libtiled/libtiled.pro000066400000000000000000000034221260670167100175770ustar00rootroot00000000000000include(../../tiled.pri) TEMPLATE = lib TARGET = tiled target.path = $${LIBDIR} INSTALLS += target macx { DESTDIR = ../../bin/Tiled.app/Contents/Frameworks QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../Frameworks/ } else { DESTDIR = ../../lib } DLLDESTDIR = ../.. win32 { QMAKE_PROJECT_NAME = libtiled } else { # On other platforms it is necessary to link to zlib explicitly LIBS += -lz } DEFINES += QT_NO_CAST_FROM_ASCII \ QT_NO_CAST_TO_ASCII DEFINES += TILED_LIBRARY contains(QT_CONFIG, reduce_exports): CONFIG += hide_symbols SOURCES += compression.cpp \ gidmapper.cpp \ hexagonalrenderer.cpp \ imagelayer.cpp \ isometricrenderer.cpp \ layer.cpp \ map.cpp \ mapobject.cpp \ mapreader.cpp \ maprenderer.cpp \ maptovariantconverter.cpp \ mapwriter.cpp \ objectgroup.cpp \ orthogonalrenderer.cpp \ plugin.cpp \ pluginmanager.cpp \ properties.cpp \ staggeredrenderer.cpp \ tile.cpp \ tilelayer.cpp \ tileset.cpp \ tilesetformat.cpp \ varianttomapconverter.cpp HEADERS += compression.h \ gidmapper.h \ hexagonalrenderer.h \ imagelayer.h \ isometricrenderer.h \ layer.h \ logginginterface.h \ map.h \ mapformat.h \ mapobject.h \ mapreader.h \ maprenderer.h \ maptovariantconverter.h \ mapwriter.h \ object.h \ objectgroup.h \ orthogonalrenderer.h \ plugin.h \ pluginmanager.h \ properties.h \ staggeredrenderer.h \ terrain.h \ tile.h \ tiled.h \ tiled_global.h \ tilelayer.h \ tileset.h \ tilesetformat.h \ varianttomapconverter.h contains(INSTALL_HEADERS, yes) { headers.files = $${HEADERS} headers.path = $${PREFIX}/include/tiled INSTALLS += headers } tiled-0.14.2/src/libtiled/libtiled.qbs000066400000000000000000000046721260670167100175740ustar00rootroot00000000000000import qbs 1.0 DynamicLibrary { targetName: "tiled" Depends { name: "cpp" } Depends { name: "Qt"; submodules: "gui" } Properties { condition: !qbs.targetOS.contains("windows") cpp.dynamicLibraries: base.concat(["z"]) } cpp.cxxLanguageVersion: "c++11" cpp.visibility: "minimal" cpp.defines: [ "TILED_LIBRARY", "QT_NO_CAST_FROM_ASCII", "QT_NO_CAST_TO_ASCII" ] Properties { condition: qbs.targetOS.contains("osx") cpp.cxxFlags: ["-Wno-unknown-pragmas"] } bundle.isBundle: false cpp.installNamePrefix: "@rpath" files: [ "compression.cpp", "compression.h", "gidmapper.cpp", "gidmapper.h", "hexagonalrenderer.cpp", "hexagonalrenderer.h", "imagelayer.cpp", "imagelayer.h", "isometricrenderer.cpp", "isometricrenderer.h", "layer.cpp", "layer.h", "logginginterface.h", "map.cpp", "map.h", "mapformat.h", "mapobject.cpp", "mapobject.h", "mapreader.cpp", "mapreader.h", "maprenderer.cpp", "maprenderer.h", "maptovariantconverter.cpp", "maptovariantconverter.h", "mapwriter.cpp", "mapwriter.h", "objectgroup.cpp", "objectgroup.h", "object.h", "orthogonalrenderer.cpp", "orthogonalrenderer.h", "plugin.cpp", "plugin.h", "pluginmanager.cpp", "pluginmanager.h", "properties.cpp", "properties.h", "staggeredrenderer.cpp", "staggeredrenderer.h", "tile.cpp", "tiled_global.h", "tiled.h", "tile.h", "tilelayer.cpp", "tilelayer.h", "tileset.cpp", "tileset.h", "tilesetformat.cpp", "tilesetformat.h", "varianttomapconverter.cpp", "varianttomapconverter.h", ] Export { Depends { name: "cpp" } Depends { name: "Qt" submodules: ["gui"] } cpp.includePaths: "." } Group { qbs.install: true qbs.installDir: { if (qbs.targetOS.contains("windows")) return "" else if (qbs.targetOS.contains("darwin")) return "Tiled.app/Contents/Frameworks" else return "lib" } fileTagsFilter: "dynamiclibrary" } } tiled-0.14.2/src/libtiled/logginginterface.h000066400000000000000000000041531260670167100207470ustar00rootroot00000000000000/* * logginginterface.h * Copyright 2013, Samuli Tuomola * Copyright 2015, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LOGGINGINTERFACE_H #define LOGGINGINTERFACE_H #include "tiled_global.h" #include class QString; namespace Tiled { /** * An object to be added by classes that want to signal the debug console. */ class TILEDSHARED_EXPORT LoggingInterface : public QObject { Q_OBJECT public: enum OutputType { INFO, ERROR }; void log(OutputType type, const QString &message) { if (type == INFO) emit info(message); else if (type == ERROR) emit error(message); } signals: void info(const QString &message); void error(const QString &message); }; } // namespace Tiled #endif // LOGGINGINTERFACE_H tiled-0.14.2/src/libtiled/map.cpp000066400000000000000000000247771260670167100165660ustar00rootroot00000000000000/* * map.cpp * Copyright 2008-2010, Thorbjørn Lindeijer * Copyright 2008, Roderic Morris * Copyright 2010, Andrew G. Crowell * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "map.h" #include "layer.h" #include "objectgroup.h" #include "tile.h" #include "tilelayer.h" #include "mapobject.h" #include using namespace Tiled; Map::Map(Orientation orientation, int width, int height, int tileWidth, int tileHeight): Object(MapType), mOrientation(orientation), mRenderOrder(RightDown), mWidth(width), mHeight(height), mTileWidth(tileWidth), mTileHeight(tileHeight), mHexSideLength(0), mStaggerAxis(StaggerY), mStaggerIndex(StaggerOdd), mLayerDataFormat(Base64Zlib), mNextObjectId(1) { } Map::Map(const Map &map): Object(map), mOrientation(map.mOrientation), mRenderOrder(map.mRenderOrder), mWidth(map.mWidth), mHeight(map.mHeight), mTileWidth(map.mTileWidth), mTileHeight(map.mTileHeight), mHexSideLength(map.mHexSideLength), mStaggerAxis(map.mStaggerAxis), mStaggerIndex(map.mStaggerIndex), mBackgroundColor(map.mBackgroundColor), mDrawMargins(map.mDrawMargins), mTilesets(map.mTilesets), mLayerDataFormat(map.mLayerDataFormat), mNextObjectId(1) { foreach (const Layer *layer, map.mLayers) { Layer *clone = layer->clone(); clone->setMap(this); mLayers.append(clone); } } Map::~Map() { qDeleteAll(mLayers); } static QMargins maxMargins(const QMargins &a, const QMargins &b) { return QMargins(qMax(a.left(), b.left()), qMax(a.top(), b.top()), qMax(a.right(), b.right()), qMax(a.bottom(), b.bottom())); } void Map::adjustDrawMargins(const QMargins &margins) { // The TileLayer includes the maximum tile size in its draw margins. So // we need to subtract the tile size of the map, since that part does not // contribute to additional margin. mDrawMargins = maxMargins(QMargins(margins.left(), margins.top() - mTileHeight, margins.right() - mTileWidth, margins.bottom()), mDrawMargins); } /** * Computes the extra margins due to layer offsets. These need to be taken into * account when determining the bounding rect of the map for example. */ QMargins Map::computeLayerOffsetMargins() const { QMargins offsetMargins; for (const Layer *layer : mLayers) { const QPointF offset = layer->offset(); offsetMargins = maxMargins(QMargins(std::ceil(-offset.x()), std::ceil(-offset.y()), std::ceil(offset.x()), std::ceil(offset.y())), offsetMargins); } return offsetMargins; } /** * Recomputes the draw margins for this map and each of its tile layers. Needed * after the tile offset of a tileset has changed for example. * * \sa TileLayer::recomputeDrawMargins */ void Map::recomputeDrawMargins() { mDrawMargins = QMargins(); foreach (Layer *layer, mLayers) if (TileLayer *tileLayer = layer->asTileLayer()) tileLayer->recomputeDrawMargins(); } int Map::layerCount(Layer::TypeFlag type) const { int count = 0; foreach (Layer *layer, mLayers) if (layer->layerType() == type) count++; return count; } QList Map::layers(Layer::TypeFlag type) const { QList layers; foreach (Layer *layer, mLayers) if (layer->layerType() == type) layers.append(layer); return layers; } QList Map::objectGroups() const { QList layers; foreach (Layer *layer, mLayers) if (ObjectGroup *og = layer->asObjectGroup()) layers.append(og); return layers; } QList Map::tileLayers() const { QList layers; foreach (Layer *layer, mLayers) if (TileLayer *tl = layer->asTileLayer()) layers.append(tl); return layers; } void Map::addLayer(Layer *layer) { adoptLayer(layer); mLayers.append(layer); } int Map::indexOfLayer(const QString &layerName, unsigned layertypes) const { for (int index = 0; index < mLayers.size(); index++) if (layerAt(index)->name() == layerName && (layertypes & layerAt(index)->layerType())) return index; return -1; } void Map::insertLayer(int index, Layer *layer) { adoptLayer(layer); mLayers.insert(index, layer); } void Map::adoptLayer(Layer *layer) { layer->setMap(this); if (TileLayer *tileLayer = layer->asTileLayer()) adjustDrawMargins(tileLayer->drawMargins()); if (ObjectGroup *group = layer->asObjectGroup()) { foreach (MapObject *o, group->objects()) { if (o->id() == 0) o->setId(takeNextObjectId()); } } } Layer *Map::takeLayerAt(int index) { Layer *layer = mLayers.takeAt(index); layer->setMap(nullptr); return layer; } void Map::addTileset(const SharedTileset &tileset) { mTilesets.append(tileset); } void Map::addTilesets(const QSet &tilesets) { for (const SharedTileset &tileset : tilesets) addTileset(tileset); } void Map::insertTileset(int index, const SharedTileset &tileset) { mTilesets.insert(index, tileset); } int Map::indexOfTileset(const SharedTileset &tileset) const { return mTilesets.indexOf(tileset); } void Map::removeTilesetAt(int index) { mTilesets.remove(index); } void Map::replaceTileset(const SharedTileset &oldTileset, const SharedTileset &newTileset) { const int index = mTilesets.indexOf(oldTileset); Q_ASSERT(index != -1); foreach (Layer *layer, mLayers) layer->replaceReferencesToTileset(oldTileset.data(), newTileset.data()); mTilesets.replace(index, newTileset); } bool Map::isTilesetUsed(const Tileset *tileset) const { foreach (const Layer *layer, mLayers) if (layer->referencesTileset(tileset)) return true; return false; } QString Tiled::staggerAxisToString(Map::StaggerAxis staggerAxis) { switch (staggerAxis) { default: case Map::StaggerY: return QLatin1String("y"); break; case Map::StaggerX: return QLatin1String("x"); break; } } Map::StaggerAxis Tiled::staggerAxisFromString(const QString &string) { Map::StaggerAxis staggerAxis = Map::StaggerY; if (string == QLatin1String("x")) staggerAxis = Map::StaggerX; return staggerAxis; } QString Tiled::staggerIndexToString(Map::StaggerIndex staggerIndex) { switch (staggerIndex) { default: case Map::StaggerOdd: return QLatin1String("odd"); break; case Map::StaggerEven: return QLatin1String("even"); break; } } Map::StaggerIndex Tiled::staggerIndexFromString(const QString &string) { Map::StaggerIndex staggerIndex = Map::StaggerOdd; if (string == QLatin1String("even")) staggerIndex = Map::StaggerEven; return staggerIndex; } QString Tiled::orientationToString(Map::Orientation orientation) { switch (orientation) { default: case Map::Unknown: return QLatin1String("unknown"); break; case Map::Orthogonal: return QLatin1String("orthogonal"); break; case Map::Isometric: return QLatin1String("isometric"); break; case Map::Staggered: return QLatin1String("staggered"); break; case Map::Hexagonal: return QLatin1String("hexagonal"); break; } } Map::Orientation Tiled::orientationFromString(const QString &string) { Map::Orientation orientation = Map::Unknown; if (string == QLatin1String("orthogonal")) { orientation = Map::Orthogonal; } else if (string == QLatin1String("isometric")) { orientation = Map::Isometric; } else if (string == QLatin1String("staggered")) { orientation = Map::Staggered; } else if (string == QLatin1String("hexagonal")) { orientation = Map::Hexagonal; } return orientation; } QString Tiled::renderOrderToString(Map::RenderOrder renderOrder) { switch (renderOrder) { default: case Map::RightDown: return QLatin1String("right-down"); break; case Map::RightUp: return QLatin1String("right-up"); break; case Map::LeftDown: return QLatin1String("left-down"); break; case Map::LeftUp: return QLatin1String("left-up"); break; } } Map::RenderOrder Tiled::renderOrderFromString(const QString &string) { Map::RenderOrder renderOrder = Map::RightDown; if (string == QLatin1String("right-up")) { renderOrder = Map::RightUp; } else if (string == QLatin1String("left-down")) { renderOrder = Map::LeftDown; } else if (string == QLatin1String("left-up")) { renderOrder = Map::LeftUp; } return renderOrder; } Map *Map::fromLayer(Layer *layer) { Map *result = new Map(Unknown, layer->width(), layer->height(), 0, 0); result->addLayer(layer); return result; } tiled-0.14.2/src/libtiled/map.h000066400000000000000000000316621260670167100162220ustar00rootroot00000000000000/* * map.h * Copyright 2008-2010, Thorbjørn Lindeijer * Copyright 2008, Roderic Morris * Copyright 2010, Andrew G. Crowell * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAP_H #define MAP_H #include "layer.h" #include "object.h" #include "tileset.h" #include #include #include #include namespace Tiled { class Tile; class ObjectGroup; /** * A tile map. Consists of a stack of layers, each can be either a TileLayer * or an ObjectGroup. * * It also keeps track of the list of referenced tilesets. */ class TILEDSHARED_EXPORT Map : public Object { public: /** * The orientation of the map determines how it should be rendered. An * Orthogonal map is using rectangular tiles that are aligned on a * straight grid. An Isometric map uses diamond shaped tiles that are * aligned on an isometric projected grid. A Hexagonal map uses hexagon * shaped tiles that fit into each other by shifting every other row. */ enum Orientation { Unknown, Orthogonal, Isometric, Staggered, Hexagonal }; /** * The different formats in which the tile layer data can be stored. */ enum LayerDataFormat { XML = 0, Base64 = 1, Base64Gzip = 2, Base64Zlib = 3, CSV = 4 }; /** * The order in which tiles are rendered on screen. */ enum RenderOrder { RightDown = 0, RightUp = 1, LeftDown = 2, LeftUp = 3 }; /** * Which axis is staggered. Only used by the isometric staggered and * hexagonal map renderers. */ enum StaggerAxis { StaggerX, StaggerY }; /** * When staggering, specifies whether the odd or the even rows/columns are * shifted half a tile right/down. Only used by the isometric staggered and * hexagonal map renderers. */ enum StaggerIndex { StaggerOdd = 0, StaggerEven = 1 }; /** * Constructor, taking map orientation, size and tile size as parameters. */ Map(Orientation orientation, int width, int height, int tileWidth, int tileHeight); /** * Copy constructor. Makes sure that a deep-copy of the layers is created. */ Map(const Map &map); /** * Destructor. */ ~Map(); /** * Returns the orientation of the map. */ Orientation orientation() const { return mOrientation; } /** * Sets the orientation of the map. */ void setOrientation(Orientation orientation) { mOrientation = orientation; } /** * Returns the render order of the map. */ RenderOrder renderOrder() const { return mRenderOrder; } /** * Sets the render order of the map. */ void setRenderOrder(RenderOrder renderOrder) { mRenderOrder = renderOrder; } /** * Returns the width of this map in tiles. */ int width() const { return mWidth; } /** * Sets the width of this map in tiles. */ void setWidth(int width) { mWidth = width; } /** * Returns the height of this map in tiles. */ int height() const { return mHeight; } /** * Sets the height of this map in tiles. */ void setHeight(int height) { mHeight = height; } /** * Returns the size of this map. Provided for convenience. */ QSize size() const { return QSize(mWidth, mHeight); } /** * Returns the tile width of this map. */ int tileWidth() const { return mTileWidth; } /** * Sets the width of one tile. */ void setTileWidth(int width) { mTileWidth = width; } /** * Returns the tile height used by this map. */ int tileHeight() const { return mTileHeight; } /** * Sets the height of one tile. */ void setTileHeight(int height) { mTileHeight = height; } /** * Returns the size of one tile. Provided for convenience. */ QSize tileSize() const { return QSize(mTileWidth, mTileHeight); } int hexSideLength() const; void setHexSideLength(int hexSideLength); StaggerAxis staggerAxis() const; void setStaggerAxis(StaggerAxis staggerAxis); StaggerIndex staggerIndex() const; void setStaggerIndex(StaggerIndex staggerIndex); /** * Adjusts the draw margins to be at least as big as the given margins. * Called from tile layers when their tiles change. */ void adjustDrawMargins(const QMargins &margins); /** * Returns the margins that have to be taken into account when figuring * out which part of the map to repaint after changing some tiles. * * @see TileLayer::drawMargins */ QMargins drawMargins() const { return mDrawMargins; } QMargins computeLayerOffsetMargins() const; void recomputeDrawMargins(); /** * Returns the number of layers of this map. */ int layerCount() const { return mLayers.size(); } /** * Convenience function that returns the number of layers of this map that * match the given \a type. */ int layerCount(Layer::TypeFlag type) const; int tileLayerCount() const { return layerCount(Layer::TileLayerType); } int objectGroupCount() const { return layerCount(Layer::ObjectGroupType); } int imageLayerCount() const { return layerCount(Layer::ImageLayerType); } /** * Returns the layer at the specified index. */ Layer *layerAt(int index) const { return mLayers.at(index); } /** * Returns the list of layers of this map. This is useful when you want to * use foreach. */ const QList &layers() const { return mLayers; } QList layers(Layer::TypeFlag type) const; QList objectGroups() const; QList tileLayers() const; /** * Adds a layer to this map. */ void addLayer(Layer *layer); /** * Returns the index of the layer given by \a layerName, or -1 if no * layer with that name is found. * * The second optional parameter specifies the layer types which are * searched. */ int indexOfLayer(const QString &layerName, unsigned layerTypes = Layer::AnyLayerType) const; /** * Adds a layer to this map, inserting it at the given index. */ void insertLayer(int index, Layer *layer); /** * Removes the layer at the given index from this map and returns it. * The caller becomes responsible for the lifetime of this layer. */ Layer *takeLayerAt(int index); /** * Adds a tileset to this map. The map does not take ownership over its * tilesets, this is merely for keeping track of which tilesets are used by * the map, and their saving order. * * @param tileset the tileset to add */ void addTileset(const SharedTileset &tileset); /** * Convenience function to be used together with Layer::usedTilesets() */ void addTilesets(const QSet &tilesets); /** * Inserts \a tileset at \a index in the list of tilesets used by this map. */ void insertTileset(int index, const SharedTileset &tileset); /** * Returns the index of the given \a tileset, or -1 if it is not used in * this map. */ int indexOfTileset(const SharedTileset &tileset) const; /** * Removes the tileset at \a index from this map. * * \warning Does not make sure that this map no longer refers to tiles from * the removed tileset! * * \sa addTileset */ void removeTilesetAt(int index); /** * Replaces all tiles from \a oldTileset with tiles from \a newTileset. * Also replaces the old tileset with the new tileset in the list of * tilesets. */ void replaceTileset(const SharedTileset &oldTileset, const SharedTileset &newTileset); /** * Returns the number of tilesets of this map. */ int tilesetCount() const { return mTilesets.size(); } /** * Returns the tileset at the given index. */ SharedTileset tilesetAt(int index) const { return mTilesets.at(index); } /** * Returns the tilesets that the tiles on this map are using. */ const QVector &tilesets() const { return mTilesets; } /** * Returns the background color of this map. */ const QColor &backgroundColor() const { return mBackgroundColor; } /** * Sets the background color of this map. */ void setBackgroundColor(QColor color) { mBackgroundColor = color; } /** * Returns whether the given \a tileset is used by any tile layer of this * map. */ bool isTilesetUsed(const Tileset *tileset) const; /** * Creates a new map that contains the given \a layer. The map size will be * determined by the size of the layer. * * The orientation defaults to Unknown and the tile width and height will * default to 0. In case this map needs to be rendered, these properties * will need to be properly set. */ static Map *fromLayer(Layer *layer); LayerDataFormat layerDataFormat() const { return mLayerDataFormat; } void setLayerDataFormat(LayerDataFormat format) { mLayerDataFormat = format; } /** * Sets the next id to be used for objects on this map. */ void setNextObjectId(int nextId) { Q_ASSERT(nextId > 0); mNextObjectId = nextId; } /** * Returns the next object id for this map. */ int nextObjectId() const { return mNextObjectId; } /** * Returns the next object id for this map and allocates a new one. */ int takeNextObjectId() { return mNextObjectId++; } private: void adoptLayer(Layer *layer); Orientation mOrientation; RenderOrder mRenderOrder; int mWidth; int mHeight; int mTileWidth; int mTileHeight; int mHexSideLength; StaggerAxis mStaggerAxis; StaggerIndex mStaggerIndex; QColor mBackgroundColor; QMargins mDrawMargins; QList mLayers; QVector mTilesets; LayerDataFormat mLayerDataFormat; int mNextObjectId; }; inline int Map::hexSideLength() const { return mHexSideLength; } inline void Map::setHexSideLength(int hexSideLength) { mHexSideLength = hexSideLength; } inline Map::StaggerAxis Map::staggerAxis() const { return mStaggerAxis; } inline void Map::setStaggerAxis(StaggerAxis staggerAxis) { mStaggerAxis = staggerAxis; } inline Map::StaggerIndex Map::staggerIndex() const { return mStaggerIndex; } inline void Map::setStaggerIndex(StaggerIndex staggerIndex) { mStaggerIndex = staggerIndex; } TILEDSHARED_EXPORT QString staggerAxisToString(Map::StaggerAxis); TILEDSHARED_EXPORT Map::StaggerAxis staggerAxisFromString(const QString &); TILEDSHARED_EXPORT QString staggerIndexToString(Map::StaggerIndex staggerIndex); TILEDSHARED_EXPORT Map::StaggerIndex staggerIndexFromString(const QString &); /** * Helper function that converts the map orientation to a string value. Useful * for map writers. * * @return The map orientation as a lowercase string. */ TILEDSHARED_EXPORT QString orientationToString(Map::Orientation); /** * Helper function that converts a string to a map orientation enumerator. * Useful for map readers. * * @return The map orientation matching the given string, or Map::Unknown if * the string is unrecognized. */ TILEDSHARED_EXPORT Map::Orientation orientationFromString(const QString &); TILEDSHARED_EXPORT QString renderOrderToString(Map::RenderOrder renderOrder); TILEDSHARED_EXPORT Map::RenderOrder renderOrderFromString(const QString &); } // namespace Tiled #endif // MAP_H tiled-0.14.2/src/libtiled/mapformat.h000066400000000000000000000135461260670167100174340ustar00rootroot00000000000000/* * mapformat.h * Copyright 2008-2015, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAPFORMAT_H #define MAPFORMAT_H #include "pluginmanager.h" #include #include #include namespace Tiled { class Map; class TILEDSHARED_EXPORT FileFormat : public QObject { Q_OBJECT public: enum Capability { NoCapability = 0x0, Read = 0x1, Write = 0x2, ReadWrite = Read | Write }; Q_DECLARE_FLAGS(Capabilities, Capability) explicit FileFormat(QObject *parent = nullptr) : QObject(parent) {} /** * Returns whether this format has Read and/or Write capabilities. */ virtual Capabilities capabilities() const { return ReadWrite; } /** * Returns whether this format has all given capabilities. */ bool hasCapabilities(Capabilities caps) const { return (capabilities() & caps) == caps; } /** * Returns the absolute paths for the files that will be written by * the map writer. */ virtual QStringList outputFiles(const Map *, const QString &fileName) const { return QStringList(fileName); } /** * Returns name filter for files in this map format. */ virtual QString nameFilter() const = 0; /** * Returns whether this map format supports reading the given file. * * Generally would do a file extension check. */ virtual bool supportsFile(const QString &fileName) const = 0; /** * Returns the error to be shown to the user if an error occured while * trying to read a map. */ virtual QString errorString() const = 0; }; /** * An interface to be implemented for adding support for a map format to Tiled. * It can implement support for either loading or saving to a certain map * format, or both. */ class TILEDSHARED_EXPORT MapFormat : public FileFormat { public: explicit MapFormat(QObject *parent = nullptr) : FileFormat(parent) {} /** * Reads the map and returns a new Map instance, or 0 if reading failed. */ virtual Map *read(const QString &fileName) = 0; /** * Writes the given \a map based on the suggested \a fileName. * * This function may write to a different file name or may even write to * multiple files. The actual files that will be written to can be * determined by calling outputFiles(). * * @return true on success, false when an error * occurred. The error can be retrieved by errorString(). */ virtual bool write(const Map *map, const QString &fileName) = 0; }; } // namespace Tiled Q_DECLARE_INTERFACE(Tiled::MapFormat, "org.mapeditor.MapFormat") Q_DECLARE_OPERATORS_FOR_FLAGS(Tiled::FileFormat::Capabilities) namespace Tiled { /** * Convenience class for adding a format that can only be read. */ class TILEDSHARED_EXPORT ReadableMapFormat : public MapFormat { Q_OBJECT Q_INTERFACES(Tiled::MapFormat) public: Capabilities capabilities() const override { return Read; } bool write(const Map *, const QString &) override { return false; } }; /** * Convenience class for adding a format that can only be written. */ class TILEDSHARED_EXPORT WritableMapFormat : public MapFormat { Q_OBJECT Q_INTERFACES(Tiled::MapFormat) public: Capabilities capabilities() const override { return Write; } Map *read(const QString &) override { return nullptr; } bool supportsFile(const QString &) const override { return false; } }; /** * Convenience class that can be used when implementing file dialogs. */ template class FormatHelper { public: FormatHelper(FileFormat::Capabilities capabilities, const QString &initialFilter) : mFilter(initialFilter) { PluginManager::each([this,capabilities](Format *format) { if (format->hasCapabilities(capabilities)) { const QString nameFilter = format->nameFilter(); mFilter += QLatin1String(";;"); mFilter += nameFilter; mFormats.append(format); mFormatByNameFilter.insert(nameFilter, format); } }); } const QString &filter() const { return mFilter; } const QList &formats() const { return mFormats; } Format *formatByNameFilter(const QString &nameFilter) const { return mFormatByNameFilter.value(nameFilter); } private: QString mFilter; QList mFormats; QMap mFormatByNameFilter; }; } // namespace Tiled #endif // MAPFORMAT_H tiled-0.14.2/src/libtiled/mapobject.cpp000066400000000000000000000102171260670167100177350ustar00rootroot00000000000000/* * mapobject.cpp * Copyright 2008-2013, Thorbjørn Lindeijer * Copyright 2008, Roderic Morris * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mapobject.h" #include "map.h" #include "objectgroup.h" #include "tile.h" using namespace Tiled; MapObject::MapObject(): Object(MapObjectType), mId(0), mSize(0, 0), mShape(Rectangle), mObjectGroup(nullptr), mRotation(0.0f), mVisible(true) { } MapObject::MapObject(const QString &name, const QString &type, const QPointF &pos, const QSizeF &size): Object(MapObjectType), mId(0), mName(name), mType(type), mPos(pos), mSize(size), mShape(Rectangle), mObjectGroup(nullptr), mRotation(0.0f), mVisible(true) { } QRectF MapObject::boundsUseTile() const { if (mCell.isEmpty()) { // No tile so just use regular bounds return bounds(); } // Using the tile for determing boundary // Note the position given is the bottom-left corner so correct for that return QRectF(QPointF(mPos.x(), mPos.y() - mCell.tile->height()), mCell.tile->size()); } /* * This is somewhat of a workaround for dealing with the ways different objects * align. * * Traditional rectangle objects have top-left alignment. * Tile objects have bottom-left alignment on orthogonal maps, but * bottom-center alignment on isometric maps. * * Eventually, the object alignment should probably be configurable. For * backwards compatibility, it will need to be configurable on a per-object * level. */ Alignment MapObject::alignment() const { if (mCell.isEmpty()) { return TopLeft; } else if (mObjectGroup) { if (Map *map = mObjectGroup->map()) if (map->orientation() == Map::Isometric) return Bottom; } return BottomLeft; } void MapObject::flip(FlipDirection direction) { if (!mCell.isEmpty()) { if (direction == FlipHorizontally) mCell.flippedHorizontally = !mCell.flippedHorizontally; else if (direction == FlipVertically) mCell.flippedVertically = !mCell.flippedVertically; } if (!mPolygon.isEmpty()) { const QPointF center2 = mPolygon.boundingRect().center() * 2; if (direction == FlipHorizontally) { for (int i = 0; i < mPolygon.size(); ++i) mPolygon[i].setX(center2.x() - mPolygon[i].x()); } else if (direction == FlipVertically) { for (int i = 0; i < mPolygon.size(); ++i) mPolygon[i].setY(center2.y() - mPolygon[i].y()); } } } MapObject *MapObject::clone() const { MapObject *o = new MapObject(mName, mType, mPos, mSize); o->setProperties(properties()); o->setPolygon(mPolygon); o->setShape(mShape); o->setCell(mCell); o->setRotation(mRotation); return o; } tiled-0.14.2/src/libtiled/mapobject.h000066400000000000000000000166371260670167100174160ustar00rootroot00000000000000/* * mapobject.h * Copyright 2008-2013, Thorbjørn Lindeijer * Copyright 2008, Roderic Morris * Copyright 2009, Jeff Bland * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAPOBJECT_H #define MAPOBJECT_H #include "object.h" #include "tiled.h" #include "tilelayer.h" #include #include #include #include namespace Tiled { class ObjectGroup; class Tile; /** * An object on a map. Objects are positioned and scaled using floating point * values, ensuring they are not limited to the tile grid. They are suitable * for adding any kind of annotation to your maps, as well as free placement of * images. * * Common usages of objects include defining portals, monsters spawn areas, * ambient effects, scripted areas, etc. */ class TILEDSHARED_EXPORT MapObject : public Object { public: /** * Enumerates the different object shapes. Rectangle is the default shape. * When a polygon is set, the shape determines whether it should be * interpreted as a filled polygon or a line. */ enum Shape { Rectangle, Polygon, Polyline, Ellipse }; MapObject(); MapObject(const QString &name, const QString &type, const QPointF &pos, const QSizeF &size); /** * Returns the id of this object. Each object gets an id assigned that is * unique for the map the object is on. */ int id() const { return mId; } /** * Sets the id of this object. */ void setId(int id) { mId = id; } /** * Returns the name of this object. The name is usually just used for * identification of the object in the editor. */ const QString &name() const { return mName; } /** * Sets the name of this object. */ void setName(const QString &name) { mName = name; } /** * Returns the type of this object. The type usually says something about * how the object is meant to be interpreted by the engine. */ const QString &type() const { return mType; } /** * Sets the type of this object. */ void setType(const QString &type) { mType = type; } /** * Returns the position of this object. */ const QPointF &position() const { return mPos; } /** * Sets the position of this object. */ void setPosition(const QPointF &pos) { mPos = pos; } /** * Returns the x position of this object. */ qreal x() const { return mPos.x(); } /** * Sets the x position of this object. */ void setX(qreal x) { mPos.setX(x); } /** * Returns the y position of this object. */ qreal y() const { return mPos.y(); } /** * Sets the x position of this object. */ void setY(qreal y) { mPos.setY(y); } /** * Returns the size of this object. */ const QSizeF &size() const { return mSize; } /** * Sets the size of this object. */ void setSize(const QSizeF &size) { mSize = size; } void setSize(qreal width, qreal height) { setSize(QSizeF(width, height)); } /** * Returns the width of this object. */ qreal width() const { return mSize.width(); } /** * Sets the width of this object. */ void setWidth(qreal width) { mSize.setWidth(width); } /** * Returns the height of this object. */ qreal height() const { return mSize.height(); } /** * Sets the height of this object. */ void setHeight(qreal height) { mSize.setHeight(height); } /** * Sets the polygon associated with this object. The polygon is only used * when the object shape is set to either Polygon or Polyline. * * \sa setShape() */ void setPolygon(const QPolygonF &polygon) { mPolygon = polygon; } /** * Returns the polygon associated with this object. Returns an empty * polygon when no polygon is associated with this object. */ const QPolygonF &polygon() const { return mPolygon; } /** * Sets the shape of the object. */ void setShape(Shape shape) { mShape = shape; } /** * Returns the shape of the object. */ Shape shape() const { return mShape; } /** * Shortcut to getting a QRectF from position() and size(). */ QRectF bounds() const { return QRectF(mPos, mSize); } /** * Shortcut to getting a QRectF from position() and size() that uses cell tile if present. */ QRectF boundsUseTile() const; /** * Sets the tile that is associated with this object. The object will * display as the tile image. * * \warning The object shape is ignored for tile objects! */ void setCell(const Cell &cell) { mCell = cell; } /** * Returns the tile associated with this object. */ const Cell &cell() const { return mCell; } /** * Returns the object group this object belongs to. */ ObjectGroup *objectGroup() const { return mObjectGroup; } /** * Sets the object group this object belongs to. Should only be called * from the ObjectGroup class. */ void setObjectGroup(ObjectGroup *objectGroup) { mObjectGroup = objectGroup; } /** * Returns the rotation of the object in degrees. */ qreal rotation() const { return mRotation; } /** * Sets the rotation of the object in degrees. */ void setRotation(qreal rotation) { mRotation = rotation; } Alignment alignment() const; bool isVisible() const { return mVisible; } void setVisible(bool visible) { mVisible = visible; } /** * Flip this object in the given \a direction. This doesn't change the size * of the object. */ void flip(FlipDirection direction); /** * Returns a duplicate of this object. The caller is responsible for the * ownership of this newly created object. */ MapObject *clone() const; private: int mId; QString mName; QString mType; QPointF mPos; QSizeF mSize; QPolygonF mPolygon; Shape mShape; Cell mCell; ObjectGroup *mObjectGroup; qreal mRotation; bool mVisible; }; } // namespace Tiled #endif // MAPOBJECT_H tiled-0.14.2/src/libtiled/mapreader.cpp000066400000000000000000001022261260670167100177330ustar00rootroot00000000000000/* * mapreader.cpp * Copyright 2008-2014, Thorbjørn Lindeijer * Copyright 2010, Jeff Bland * Copyright 2010, Dennis Honeyman * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mapreader.h" #include "compression.h" #include "gidmapper.h" #include "imagelayer.h" #include "objectgroup.h" #include "map.h" #include "mapobject.h" #include "tile.h" #include "tilelayer.h" #include "tilesetformat.h" #include "terrain.h" #include #include #include #include #include #include using namespace Tiled; using namespace Tiled::Internal; namespace Tiled { namespace Internal { class MapReaderPrivate { Q_DECLARE_TR_FUNCTIONS(MapReader) friend class Tiled::MapReader; public: MapReaderPrivate(MapReader *mapReader): p(mapReader), mMap(nullptr), mReadingExternalTileset(false) {} Map *readMap(QIODevice *device, const QString &path); SharedTileset readTileset(QIODevice *device, const QString &path); bool openFile(QFile *file); QString errorString() const; private: void readUnknownElement(); Map *readMap(); SharedTileset readTileset(); void readTilesetTile(SharedTileset &tileset); void readTilesetImage(SharedTileset &tileset); void readTilesetTerrainTypes(SharedTileset &tileset); QImage readImage(); TileLayer *readLayer(); void readLayerData(TileLayer *tileLayer); void decodeBinaryLayerData(TileLayer *tileLayer, const QByteArray &data, Map::LayerDataFormat format); void decodeCSVLayerData(TileLayer *tileLayer, const QString &text); /** * Returns the cell for the given global tile ID. Errors are raised with * the QXmlStreamReader. * * @param gid the global tile ID * @return the cell data associated with the given global tile ID, or an * empty cell if not found */ Cell cellForGid(unsigned gid); ImageLayer *readImageLayer(); void readImageLayerImage(ImageLayer *imageLayer); ObjectGroup *readObjectGroup(); MapObject *readObject(); QPolygonF readPolygon(); QVector readAnimationFrames(); Properties readProperties(); void readProperty(Properties *properties); MapReader *p; QString mError; QString mPath; Map *mMap; GidMapper mGidMapper; bool mReadingExternalTileset; QXmlStreamReader xml; }; } // namespace Internal } // namespace Tiled Map *MapReaderPrivate::readMap(QIODevice *device, const QString &path) { mError.clear(); mPath = path; Map *map = nullptr; xml.setDevice(device); if (xml.readNextStartElement() && xml.name() == QLatin1String("map")) { map = readMap(); } else { xml.raiseError(tr("Not a map file.")); } mGidMapper.clear(); return map; } SharedTileset MapReaderPrivate::readTileset(QIODevice *device, const QString &path) { mError.clear(); mPath = path; SharedTileset tileset; mReadingExternalTileset = true; xml.setDevice(device); if (xml.readNextStartElement() && xml.name() == QLatin1String("tileset")) tileset = readTileset(); else xml.raiseError(tr("Not a tileset file.")); mReadingExternalTileset = false; return tileset; } QString MapReaderPrivate::errorString() const { if (!mError.isEmpty()) { return mError; } else { return tr("%3\n\nLine %1, column %2") .arg(xml.lineNumber()) .arg(xml.columnNumber()) .arg(xml.errorString()); } } bool MapReaderPrivate::openFile(QFile *file) { if (!file->exists()) { mError = tr("File not found: %1").arg(file->fileName()); return false; } else if (!file->open(QFile::ReadOnly | QFile::Text)) { mError = tr("Unable to read file: %1").arg(file->fileName()); return false; } return true; } void MapReaderPrivate::readUnknownElement() { qDebug().nospace() << "Unknown element (fixme): " << xml.name() << " at line " << xml.lineNumber() << ", column " << xml.columnNumber(); xml.skipCurrentElement(); } Map *MapReaderPrivate::readMap() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("map")); const QXmlStreamAttributes atts = xml.attributes(); const int mapWidth = atts.value(QLatin1String("width")).toInt(); const int mapHeight = atts.value(QLatin1String("height")).toInt(); const int tileWidth = atts.value(QLatin1String("tilewidth")).toInt(); const int tileHeight = atts.value(QLatin1String("tileheight")).toInt(); const int hexSideLength = atts.value(QLatin1String("hexsidelength")).toInt(); const QString orientationString = atts.value(QLatin1String("orientation")).toString(); const Map::Orientation orientation = orientationFromString(orientationString); if (orientation == Map::Unknown) { xml.raiseError(tr("Unsupported map orientation: \"%1\"") .arg(orientationString)); } const QString staggerAxisString = atts.value(QLatin1String("staggeraxis")).toString(); const Map::StaggerAxis staggerAxis = staggerAxisFromString(staggerAxisString); const QString staggerIndexString = atts.value(QLatin1String("staggerindex")).toString(); const Map::StaggerIndex staggerIndex = staggerIndexFromString(staggerIndexString); const QString renderOrderString = atts.value(QLatin1String("renderorder")).toString(); const Map::RenderOrder renderOrder = renderOrderFromString(renderOrderString); const int nextObjectId = atts.value(QLatin1String("nextobjectid")).toInt(); mMap = new Map(orientation, mapWidth, mapHeight, tileWidth, tileHeight); mMap->setHexSideLength(hexSideLength); mMap->setStaggerAxis(staggerAxis); mMap->setStaggerIndex(staggerIndex); mMap->setRenderOrder(renderOrder); if (nextObjectId) mMap->setNextObjectId(nextObjectId); QStringRef bgColorString = atts.value(QLatin1String("backgroundcolor")); if (!bgColorString.isEmpty()) mMap->setBackgroundColor(QColor(bgColorString.toString())); while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("properties")) mMap->mergeProperties(readProperties()); else if (xml.name() == QLatin1String("tileset")) mMap->addTileset(readTileset()); else if (xml.name() == QLatin1String("layer")) mMap->addLayer(readLayer()); else if (xml.name() == QLatin1String("objectgroup")) mMap->addLayer(readObjectGroup()); else if (xml.name() == QLatin1String("imagelayer")) mMap->addLayer(readImageLayer()); else readUnknownElement(); } // Clean up in case of error if (xml.hasError()) { delete mMap; mMap = nullptr; } return mMap; } SharedTileset MapReaderPrivate::readTileset() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("tileset")); const QXmlStreamAttributes atts = xml.attributes(); const QString source = atts.value(QLatin1String("source")).toString(); const unsigned firstGid = atts.value(QLatin1String("firstgid")).toUInt(); SharedTileset tileset; if (source.isEmpty()) { // Not an external tileset const QString name = atts.value(QLatin1String("name")).toString(); const int tileWidth = atts.value(QLatin1String("tilewidth")).toInt(); const int tileHeight = atts.value(QLatin1String("tileheight")).toInt(); const int tileSpacing = atts.value(QLatin1String("spacing")).toInt(); const int margin = atts.value(QLatin1String("margin")).toInt(); if (tileWidth < 0 || tileHeight < 0 || (firstGid == 0 && !mReadingExternalTileset)) { xml.raiseError(tr("Invalid tileset parameters for tileset" " '%1'").arg(name)); } else { tileset = Tileset::create(name, tileWidth, tileHeight, tileSpacing, margin); while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("tile")) { readTilesetTile(tileset); } else if (xml.name() == QLatin1String("tileoffset")) { const QXmlStreamAttributes oa = xml.attributes(); int x = oa.value(QLatin1String("x")).toInt(); int y = oa.value(QLatin1String("y")).toInt(); tileset->setTileOffset(QPoint(x, y)); xml.skipCurrentElement(); } else if (xml.name() == QLatin1String("properties")) { tileset->mergeProperties(readProperties()); } else if (xml.name() == QLatin1String("image")) { if (tileWidth == 0 || tileHeight == 0) { xml.raiseError(tr("Invalid tileset parameters for tileset" " '%1'").arg(name)); tileset.clear(); break; } else { readTilesetImage(tileset); } } else if (xml.name() == QLatin1String("terraintypes")) { readTilesetTerrainTypes(tileset); } else { readUnknownElement(); } } } } else { // External tileset const QString absoluteSource = p->resolveReference(source, mPath); QString error; tileset = p->readExternalTileset(absoluteSource, &error); if (!tileset) { xml.raiseError(tr("Error while loading tileset '%1': %2") .arg(absoluteSource, error)); } xml.skipCurrentElement(); } if (tileset && !mReadingExternalTileset) mGidMapper.insert(firstGid, tileset.data()); return tileset; } void MapReaderPrivate::readTilesetTile(SharedTileset &tileset) { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("tile")); const QXmlStreamAttributes atts = xml.attributes(); const int id = atts.value(QLatin1String("id")).toInt(); if (id < 0) { xml.raiseError(tr("Invalid tile ID: %1").arg(id)); return; } const bool hasImage = !tileset->imageSource().isEmpty(); if (hasImage && id >= tileset->tileCount()) { xml.raiseError(tr("Tile ID does not exist in tileset image: %1").arg(id)); return; } if (id > tileset->tileCount()) { xml.raiseError(tr("Invalid (nonconsecutive) tile ID: %1").arg(id)); return; } // For tilesets without image source, consecutive tile IDs are allowed (for // tiles with individual images) if (id == tileset->tileCount()) tileset->addTile(QPixmap()); Tile *tile = tileset->tileAt(id); // Read tile quadrant terrain ids QString terrain = atts.value(QLatin1String("terrain")).toString(); if (!terrain.isEmpty()) { QStringList quadrants = terrain.split(QLatin1String(",")); if (quadrants.size() == 4) { for (int i = 0; i < 4; ++i) { int t = quadrants[i].isEmpty() ? -1 : quadrants[i].toInt(); tile->setCornerTerrainId(i, t); } } } // Read tile probability QStringRef probability = atts.value(QLatin1String("probability")); if (!probability.isEmpty()) tile->setProbability(probability.toFloat()); while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("properties")) { tile->mergeProperties(readProperties()); } else if (xml.name() == QLatin1String("image")) { QString source = xml.attributes().value(QLatin1String("source")).toString(); if (!source.isEmpty()) source = p->resolveReference(source, mPath); tileset->setTileImage(id, QPixmap::fromImage(readImage()), source); } else if (xml.name() == QLatin1String("objectgroup")) { tile->setObjectGroup(readObjectGroup()); } else if (xml.name() == QLatin1String("animation")) { tile->setFrames(readAnimationFrames()); } else { readUnknownElement(); } } // Temporary code to support TMW-style animation frame properties if (!tile->isAnimated() && tile->hasProperty(QLatin1String("animation-frame0"))) { QVector frames; for (int i = 0; ; i++) { QString frameName = QLatin1String("animation-frame") + QString::number(i); QString delayName = QLatin1String("animation-delay") + QString::number(i); if (tile->hasProperty(frameName) && tile->hasProperty(delayName)) { Frame frame; frame.tileId = tile->property(frameName).toInt(); frame.duration = tile->property(delayName).toInt() * 10; frames.append(frame); } else { break; } } tile->setFrames(frames); } } void MapReaderPrivate::readTilesetImage(SharedTileset &tileset) { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("image")); const QXmlStreamAttributes atts = xml.attributes(); QString source = atts.value(QLatin1String("source")).toString(); QString trans = atts.value(QLatin1String("trans")).toString(); if (!trans.isEmpty()) { if (!trans.startsWith(QLatin1Char('#'))) trans.prepend(QLatin1Char('#')); tileset->setTransparentColor(QColor(trans)); } if (!source.isEmpty()) source = p->resolveReference(source, mPath); // Set the width that the tileset had when the map was saved const int width = atts.value(QLatin1String("width")).toInt(); mGidMapper.setTilesetWidth(tileset.data(), width); if (!tileset->loadFromImage(readImage(), source)) xml.raiseError(tr("Error loading tileset image:\n'%1'").arg(source)); } QImage MapReaderPrivate::readImage() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("image")); const QXmlStreamAttributes atts = xml.attributes(); QString source = atts.value(QLatin1String("source")).toString(); QString format = atts.value(QLatin1String("format")).toString(); if (source.isEmpty()) { while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("data")) { const QXmlStreamAttributes atts = xml.attributes(); QString encoding = atts.value(QLatin1String("encoding")) .toString(); QByteArray data = xml.readElementText().toLatin1(); if (encoding == QLatin1String("base64")) { data = QByteArray::fromBase64(data); } xml.skipCurrentElement(); return QImage::fromData(data, format.toLatin1()); } else { readUnknownElement(); } } } else { xml.skipCurrentElement(); source = p->resolveReference(source, mPath); QImage image = p->readExternalImage(source); if (image.isNull()) xml.raiseError(tr("Error loading image:\n'%1'").arg(source)); return image; } return QImage(); } void MapReaderPrivate::readTilesetTerrainTypes(SharedTileset &tileset) { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("terraintypes")); while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("terrain")) { const QXmlStreamAttributes atts = xml.attributes(); QString name = atts.value(QLatin1String("name")).toString(); int tile = atts.value(QLatin1String("tile")).toInt(); Terrain *terrain = tileset->addTerrain(name, tile); while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("properties")) terrain->mergeProperties(readProperties()); else readUnknownElement(); } } else { readUnknownElement(); } } } static void readLayerAttributes(Layer *layer, const QXmlStreamAttributes &atts) { const QStringRef opacityRef = atts.value(QLatin1String("opacity")); const QStringRef visibleRef = atts.value(QLatin1String("visible")); bool ok; const float opacity = opacityRef.toFloat(&ok); if (ok) layer->setOpacity(opacity); const int visible = visibleRef.toInt(&ok); if (ok) layer->setVisible(visible); const QPointF offset(atts.value(QLatin1String("offsetx")).toDouble(), atts.value(QLatin1String("offsety")).toDouble()); layer->setOffset(offset); } TileLayer *MapReaderPrivate::readLayer() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("layer")); const QXmlStreamAttributes atts = xml.attributes(); const QString name = atts.value(QLatin1String("name")).toString(); const int x = atts.value(QLatin1String("x")).toInt(); const int y = atts.value(QLatin1String("y")).toInt(); const int width = atts.value(QLatin1String("width")).toInt(); const int height = atts.value(QLatin1String("height")).toInt(); TileLayer *tileLayer = new TileLayer(name, x, y, width, height); readLayerAttributes(tileLayer, atts); while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("properties")) tileLayer->mergeProperties(readProperties()); else if (xml.name() == QLatin1String("data")) readLayerData(tileLayer); else readUnknownElement(); } return tileLayer; } void MapReaderPrivate::readLayerData(TileLayer *tileLayer) { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("data")); const QXmlStreamAttributes atts = xml.attributes(); QStringRef encoding = atts.value(QLatin1String("encoding")); QStringRef compression = atts.value(QLatin1String("compression")); Map::LayerDataFormat layerDataFormat; if (encoding.isEmpty()) { layerDataFormat = Map::XML; } else if (encoding == QLatin1String("csv")) { layerDataFormat = Map::CSV; } else if (encoding == QLatin1String("base64")) { if (compression.isEmpty()) { layerDataFormat = Map::Base64; } else if (compression == QLatin1String("gzip")) { layerDataFormat = Map::Base64Gzip; } else if (compression == QLatin1String("zlib")) { layerDataFormat = Map::Base64Zlib; } else { xml.raiseError(tr("Compression method '%1' not supported") .arg(compression.toString())); return; } } else { xml.raiseError(tr("Unknown encoding: %1").arg(encoding.toString())); return; } mMap->setLayerDataFormat(layerDataFormat); int x = 0; int y = 0; while (xml.readNext() != QXmlStreamReader::Invalid) { if (xml.isEndElement()) { break; } else if (xml.isStartElement()) { if (xml.name() == QLatin1String("tile")) { if (y >= tileLayer->height()) { xml.raiseError(tr("Too many elements")); continue; } const QXmlStreamAttributes atts = xml.attributes(); unsigned gid = atts.value(QLatin1String("gid")).toUInt(); tileLayer->setCell(x, y, cellForGid(gid)); x++; if (x >= tileLayer->width()) { x = 0; y++; } xml.skipCurrentElement(); } else { readUnknownElement(); } } else if (xml.isCharacters() && !xml.isWhitespace()) { if (encoding == QLatin1String("base64")) { decodeBinaryLayerData(tileLayer, xml.text().toLatin1(), layerDataFormat); } else if (encoding == QLatin1String("csv")) { decodeCSVLayerData(tileLayer, xml.text().toString()); } } } } void MapReaderPrivate::decodeBinaryLayerData(TileLayer *tileLayer, const QByteArray &data, Map::LayerDataFormat format) { GidMapper::DecodeError error = mGidMapper.decodeLayerData(*tileLayer, data, format); switch (error) { case GidMapper::CorruptLayerData: xml.raiseError(tr("Corrupt layer data for layer '%1'").arg(tileLayer->name())); return; case GidMapper::TileButNoTilesets: xml.raiseError(tr("Tile used but no tilesets specified")); return; case GidMapper::InvalidTile: xml.raiseError(tr("Invalid tile: %1").arg(mGidMapper.invalidTile())); return; case GidMapper::NoError: break; } } void MapReaderPrivate::decodeCSVLayerData(TileLayer *tileLayer, const QString &text) { QString trimText = text.trimmed(); QStringList tiles = trimText.split(QLatin1Char(',')); if (tiles.length() != tileLayer->width() * tileLayer->height()) { xml.raiseError(tr("Corrupt layer data for layer '%1'") .arg(tileLayer->name())); return; } for (int y = 0; y < tileLayer->height(); y++) { for (int x = 0; x < tileLayer->width(); x++) { bool conversionOk; const unsigned gid = tiles.at(y * tileLayer->width() + x) .toUInt(&conversionOk); if (!conversionOk) { xml.raiseError( tr("Unable to parse tile at (%1,%2) on layer '%3'") .arg(x + 1).arg(y + 1).arg(tileLayer->name())); return; } tileLayer->setCell(x, y, cellForGid(gid)); } } } Cell MapReaderPrivate::cellForGid(unsigned gid) { bool ok; const Cell result = mGidMapper.gidToCell(gid, ok); if (!ok) { if (mGidMapper.isEmpty()) xml.raiseError(tr("Tile used but no tilesets specified")); else xml.raiseError(tr("Invalid tile: %1").arg(gid)); } return result; } ObjectGroup *MapReaderPrivate::readObjectGroup() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("objectgroup")); const QXmlStreamAttributes atts = xml.attributes(); const QString name = atts.value(QLatin1String("name")).toString(); const int x = atts.value(QLatin1String("x")).toInt(); const int y = atts.value(QLatin1String("y")).toInt(); const int width = atts.value(QLatin1String("width")).toInt(); const int height = atts.value(QLatin1String("height")).toInt(); ObjectGroup *objectGroup = new ObjectGroup(name, x, y, width, height); readLayerAttributes(objectGroup, atts); const QString color = atts.value(QLatin1String("color")).toString(); if (!color.isEmpty()) objectGroup->setColor(color); if (atts.hasAttribute(QLatin1String("draworder"))) { QString value = atts.value(QLatin1String("draworder")).toString(); ObjectGroup::DrawOrder drawOrder = drawOrderFromString(value); if (drawOrder == ObjectGroup::UnknownOrder) { delete objectGroup; xml.raiseError(tr("Invalid draw order: %1").arg(value)); return nullptr; } objectGroup->setDrawOrder(drawOrder); } while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("object")) objectGroup->addObject(readObject()); else if (xml.name() == QLatin1String("properties")) objectGroup->mergeProperties(readProperties()); else readUnknownElement(); } return objectGroup; } ImageLayer *MapReaderPrivate::readImageLayer() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("imagelayer")); const QXmlStreamAttributes atts = xml.attributes(); const QString name = atts.value(QLatin1String("name")).toString(); const int x = atts.value(QLatin1String("x")).toInt(); const int y = atts.value(QLatin1String("y")).toInt(); const int width = atts.value(QLatin1String("width")).toInt(); const int height = atts.value(QLatin1String("height")).toInt(); ImageLayer *imageLayer = new ImageLayer(name, x, y, width, height); readLayerAttributes(imageLayer, atts); while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("image")) readImageLayerImage(imageLayer); else if (xml.name() == QLatin1String("properties")) imageLayer->mergeProperties(readProperties()); else readUnknownElement(); } return imageLayer; } void MapReaderPrivate::readImageLayerImage(ImageLayer *imageLayer) { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("image")); const QXmlStreamAttributes atts = xml.attributes(); QString source = atts.value(QLatin1String("source")).toString(); QString trans = atts.value(QLatin1String("trans")).toString(); if (!trans.isEmpty()) { if (!trans.startsWith(QLatin1Char('#'))) trans.prepend(QLatin1Char('#')); imageLayer->setTransparentColor(QColor(trans)); } source = p->resolveReference(source, mPath); const QImage imageLayerImage = p->readExternalImage(source); if (!imageLayer->loadFromImage(imageLayerImage, source)) xml.raiseError(tr("Error loading image layer image:\n'%1'").arg(source)); xml.skipCurrentElement(); } MapObject *MapReaderPrivate::readObject() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("object")); const QXmlStreamAttributes atts = xml.attributes(); const int id = atts.value(QLatin1String("id")).toInt(); const QString name = atts.value(QLatin1String("name")).toString(); const unsigned gid = atts.value(QLatin1String("gid")).toUInt(); const qreal x = atts.value(QLatin1String("x")).toDouble(); const qreal y = atts.value(QLatin1String("y")).toDouble(); const qreal width = atts.value(QLatin1String("width")).toDouble(); const qreal height = atts.value(QLatin1String("height")).toDouble(); const QString type = atts.value(QLatin1String("type")).toString(); const QStringRef visibleRef = atts.value(QLatin1String("visible")); const QPointF pos(x, y); const QSizeF size(width, height); MapObject *object = new MapObject(name, type, pos, size); object->setId(id); bool ok; const qreal rotation = atts.value(QLatin1String("rotation")).toDouble(&ok); if (ok) object->setRotation(rotation); if (gid) { object->setCell(cellForGid(gid)); if (!object->cell().isEmpty()) { const QSizeF &tileSize = object->cell().tile->size(); if (width == 0) object->setWidth(tileSize.width()); if (height == 0) object->setHeight(tileSize.height()); } } const int visible = visibleRef.toInt(&ok); if (ok) object->setVisible(visible); while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("properties")) { object->mergeProperties(readProperties()); } else if (xml.name() == QLatin1String("polygon")) { object->setPolygon(readPolygon()); object->setShape(MapObject::Polygon); } else if (xml.name() == QLatin1String("polyline")) { object->setPolygon(readPolygon()); object->setShape(MapObject::Polyline); } else if (xml.name() == QLatin1String("ellipse")) { xml.skipCurrentElement(); object->setShape(MapObject::Ellipse); } else { readUnknownElement(); } } return object; } QPolygonF MapReaderPrivate::readPolygon() { Q_ASSERT(xml.isStartElement() && (xml.name() == QLatin1String("polygon") || xml.name() == QLatin1String("polyline"))); const QXmlStreamAttributes atts = xml.attributes(); const QString points = atts.value(QLatin1String("points")).toString(); const QStringList pointsList = points.split(QLatin1Char(' '), QString::SkipEmptyParts); QPolygonF polygon; bool ok = true; foreach (const QString &point, pointsList) { const int commaPos = point.indexOf(QLatin1Char(',')); if (commaPos == -1) { ok = false; break; } const qreal x = point.left(commaPos).toDouble(&ok); if (!ok) break; const qreal y = point.mid(commaPos + 1).toDouble(&ok); if (!ok) break; polygon.append(QPointF(x, y)); } if (!ok) xml.raiseError(tr("Invalid points data for polygon")); xml.skipCurrentElement(); return polygon; } QVector MapReaderPrivate::readAnimationFrames() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("animation")); QVector frames; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("frame")) { const QXmlStreamAttributes atts = xml.attributes(); Frame frame; frame.tileId = atts.value(QLatin1String("tileid")).toInt(); frame.duration = atts.value(QLatin1String("duration")).toInt(); frames.append(frame); xml.skipCurrentElement(); } else { readUnknownElement(); } } return frames; } Properties MapReaderPrivate::readProperties() { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("properties")); Properties properties; while (xml.readNextStartElement()) { if (xml.name() == QLatin1String("property")) readProperty(&properties); else readUnknownElement(); } return properties; } void MapReaderPrivate::readProperty(Properties *properties) { Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("property")); const QXmlStreamAttributes atts = xml.attributes(); QString propertyName = atts.value(QLatin1String("name")).toString(); QString propertyValue = atts.value(QLatin1String("value")).toString(); while (xml.readNext() != QXmlStreamReader::Invalid) { if (xml.isEndElement()) { break; } else if (xml.isCharacters() && !xml.isWhitespace()) { if (propertyValue.isEmpty()) propertyValue = xml.text().toString(); } else if (xml.isStartElement()) { readUnknownElement(); } } properties->insert(propertyName, propertyValue); } MapReader::MapReader() : d(new MapReaderPrivate(this)) { } MapReader::~MapReader() { delete d; } Map *MapReader::readMap(QIODevice *device, const QString &path) { return d->readMap(device, path); } Map *MapReader::readMap(const QString &fileName) { QFile file(fileName); if (!d->openFile(&file)) return nullptr; return readMap(&file, QFileInfo(fileName).absolutePath()); } SharedTileset MapReader::readTileset(QIODevice *device, const QString &path) { return d->readTileset(device, path); } SharedTileset MapReader::readTileset(const QString &fileName) { QFile file(fileName); if (!d->openFile(&file)) return SharedTileset(); SharedTileset tileset = readTileset(&file, QFileInfo(fileName).absolutePath()); if (tileset) tileset->setFileName(fileName); return tileset; } QString MapReader::errorString() const { return d->errorString(); } QString MapReader::resolveReference(const QString &reference, const QString &mapPath) { if (QDir::isRelativePath(reference)) return mapPath + QLatin1Char('/') + reference; else return reference; } QImage MapReader::readExternalImage(const QString &source) { return QImage(source); } SharedTileset MapReader::readExternalTileset(const QString &source, QString *error) { return Tiled::readTileset(source, error); } tiled-0.14.2/src/libtiled/mapreader.h000066400000000000000000000100521260670167100173730ustar00rootroot00000000000000/* * mapreader.h * Copyright 2008-2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAPREADER_H #define MAPREADER_H #include "tiled_global.h" #include "tileset.h" #include class QFile; namespace Tiled { class Map; namespace Internal { class MapReaderPrivate; } /** * A fast QXmlStreamReader based reader for the TMX and TSX formats. * * Can be subclassed when special handling of external images and tilesets is * needed. */ class TILEDSHARED_EXPORT MapReader { public: MapReader(); virtual ~MapReader(); /** * Reads a TMX map from the given \a device. Optionally a \a path can * be given, which will be used to resolve relative references to external * images and tilesets. * * Returns 0 and sets errorString() when reading failed. * * The caller takes ownership over the newly created map. */ Map *readMap(QIODevice *device, const QString &path = QString()); /** * Reads a TMX map from the given \a fileName. * \overload */ Map *readMap(const QString &fileName); /** * Reads a TSX tileset from the given \a device. Optionally a \a path can * be given, which will be used to resolve relative references to external * images. * * Returns 0 and sets errorString() when reading failed. * * The caller takes ownership over the newly created tileset. */ SharedTileset readTileset(QIODevice *device, const QString &path = QString()); /** * Reads a TSX tileset from the given \a fileName. * \overload */ SharedTileset readTileset(const QString &fileName); /** * Returns the error message for the last occurred error. */ QString errorString() const; protected: /** * Called for each \a reference to an external file. Should return the path * to be used when loading this file. \a mapPath contains the path to the * map or tileset that is currently being loaded. */ virtual QString resolveReference(const QString &reference, const QString &mapPath); /** * Called when an external image is encountered while a tileset is loaded. */ virtual QImage readExternalImage(const QString &source); /** * Called when an external tileset is encountered while a map is loaded. * The default implementation just calls readTileset() on a new MapReader. * * If an error occurred, the \a error parameter should be set to the error * message. */ virtual SharedTileset readExternalTileset(const QString &source, QString *error); private: friend class Internal::MapReaderPrivate; Internal::MapReaderPrivate *d; }; } // namespace Tiled #endif // MAPREADER_H tiled-0.14.2/src/libtiled/maprenderer.cpp000066400000000000000000000150471260670167100203030ustar00rootroot00000000000000/* * maprenderer.cpp * Copyright 2011, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "maprenderer.h" #include "imagelayer.h" #include "tile.h" #include "tilelayer.h" #include #include #include using namespace Tiled; QRectF MapRenderer::boundingRect(const ImageLayer *imageLayer) const { return QRectF(imageLayer->position(), imageLayer->image().size()); } void MapRenderer::drawImageLayer(QPainter *painter, const ImageLayer *imageLayer, const QRectF &exposed) { Q_UNUSED(exposed) painter->drawPixmap(imageLayer->position(), imageLayer->image()); } void MapRenderer::setFlag(RenderFlag flag, bool enabled) { if (enabled) mFlags |= flag; else mFlags &= ~flag; } /** * Converts a line running from \a start to \a end to a polygon which * extends 5 pixels from the line in all directions. */ QPolygonF MapRenderer::lineToPolygon(const QPointF &start, const QPointF &end) { QPointF direction = QVector2D(end - start).normalized().toPointF(); QPointF perpendicular(-direction.y(), direction.x()); const qreal thickness = 5.0f; // 5 pixels on each side direction *= thickness; perpendicular *= thickness; QPolygonF polygon(4); polygon[0] = start + perpendicular - direction; polygon[1] = start - perpendicular - direction; polygon[2] = end - perpendicular + direction; polygon[3] = end + perpendicular + direction; return polygon; } static bool hasOpenGLEngine(const QPainter *painter) { const QPaintEngine::Type type = painter->paintEngine()->type(); return (type == QPaintEngine::OpenGL || type == QPaintEngine::OpenGL2); } CellRenderer::CellRenderer(QPainter *painter) : mPainter(painter) , mTile(nullptr) , mIsOpenGL(hasOpenGLEngine(painter)) { } /** * Renders a \a cell with the given \a origin at \a pos, taking into account * the flipping and tile offset. * * For performance reasons, the actual drawing is delayed until a different * kind of tile has to be drawn. For this reason it is necessary to call * flush when finished doing drawCell calls. This function is also called by * the destructor so usually an explicit call is not needed. */ void CellRenderer::render(const Cell &cell, const QPointF &pos, const QSizeF &cellSize, Origin origin) { if (mTile != cell.tile) flush(); const QPixmap &image = cell.tile->currentFrameImage(); const QSizeF size = image.size(); const QSizeF objectSize = (cellSize == QSizeF(0,0)) ? size : cellSize; const QSizeF scale(objectSize.width() / size.width(), objectSize.height() / size.height()); const QPoint offset = cell.tile->offset(); const QPointF sizeHalf = QPointF(objectSize.width() / 2, objectSize.height() / 2); QPainter::PixmapFragment fragment; fragment.x = pos.x() + (offset.x() * scale.width()) + sizeHalf.x(); fragment.y = pos.y() + (offset.y() * scale.height()) + sizeHalf.y() - objectSize.height(); fragment.sourceLeft = 0; fragment.sourceTop = 0; fragment.width = size.width(); fragment.height = size.height(); fragment.scaleX = cell.flippedHorizontally ? -1 : 1; fragment.scaleY = cell.flippedVertically ? -1 : 1; fragment.rotation = 0; fragment.opacity = 1; bool flippedHorizontally = cell.flippedHorizontally; bool flippedVertically = cell.flippedVertically; if (origin == BottomCenter) fragment.x -= sizeHalf.x(); if (cell.flippedAntiDiagonally) { fragment.rotation = 90; flippedHorizontally = cell.flippedVertically; flippedVertically = !cell.flippedHorizontally; // Compensate for the swap of image dimensions const qreal halfDiff = sizeHalf.y() - sizeHalf.x(); fragment.y += halfDiff; if (origin != BottomCenter) fragment.x += halfDiff; } fragment.scaleX = scale.width() * (flippedHorizontally ? -1 : 1); fragment.scaleY = scale.height() * (flippedVertically ? -1 : 1); if (mIsOpenGL || (fragment.scaleX > 0 && fragment.scaleY > 0)) { mTile = cell.tile; mFragments.append(fragment); return; } // The Raster paint engine as of Qt 4.8.4 / 5.0.2 does not support // drawing fragments with a negative scaling factor. flush(); // make sure we drew all tiles so far const QTransform oldTransform = mPainter->transform(); QTransform transform = oldTransform; transform.translate(fragment.x, fragment.y); transform.rotate(fragment.rotation); transform.scale(fragment.scaleX, fragment.scaleY); const QRectF target(fragment.width * -0.5, fragment.height * -0.5, fragment.width, fragment.height); const QRectF source(0, 0, fragment.width, fragment.height); mPainter->setTransform(transform); mPainter->drawPixmap(target, image, source); mPainter->setTransform(oldTransform); } /** * Renders any remaining cells. */ void CellRenderer::flush() { if (!mTile) return; mPainter->drawPixmapFragments(mFragments.constData(), mFragments.size(), mTile->currentFrameImage()); mTile = nullptr; mFragments.resize(0); } tiled-0.14.2/src/libtiled/maprenderer.h000066400000000000000000000207701260670167100177470ustar00rootroot00000000000000/* * maprenderer.h * Copyright 2009-2011, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAPRENDERER_H #define MAPRENDERER_H #include "tiled_global.h" #include namespace Tiled { class Cell; class Layer; class Map; class MapObject; class Tile; class TileLayer; class ImageLayer; enum RenderFlag { ShowTileObjectOutlines = 0x1 }; Q_DECLARE_FLAGS(RenderFlags, RenderFlag) /** * This interface is used for rendering tile layers and retrieving associated * metrics. The different implementations deal with different map * orientations. */ class TILEDSHARED_EXPORT MapRenderer { public: MapRenderer(const Map *map) : mMap(map) , mFlags(nullptr) , mObjectLineWidth(2) , mPainterScale(1) {} virtual ~MapRenderer() {} /** * Returns the map this renderer is associated with. */ const Map *map() const; /** * Returns the size in pixels of the map associated with this renderer. */ virtual QSize mapSize() const = 0; /** * Returns the bounding rectangle in pixels of the given \a rect given in * tile coordinates. * * This is useful for calculating the bounding rect of a tile layer or of * a region of tiles that was changed. */ virtual QRect boundingRect(const QRect &rect) const = 0; /** * Returns the bounding rectangle in pixels of the given \a object, as it * would be drawn by drawMapObject(). */ virtual QRectF boundingRect(const MapObject *object) const = 0; /** * Returns the bounding rectangle in pixels of the given \a imageLayer, as * it would be drawn by drawImageLayer(). */ QRectF boundingRect(const ImageLayer *imageLayer) const; /** * Returns the shape in pixels of the given \a object. This is used for * mouse interaction and should match the rendered object as closely as * possible. */ virtual QPainterPath shape(const MapObject *object) const = 0; /** * Draws the tile grid in the specified \a rect using the given * \a painter. */ virtual void drawGrid(QPainter *painter, const QRectF &rect, QColor gridColor = Qt::black) const = 0; /** * Draws the given \a layer using the given \a painter. * * Optionally, you can pass in the \a exposed rect (of pixels), so that * only tiles that can be visible in this area will be drawn. */ virtual void drawTileLayer(QPainter *painter, const TileLayer *layer, const QRectF &exposed = QRectF()) const = 0; /** * Draws the tile selection given by \a region in the specified \a color. * * The implementation can be optimized by taking into account the * \a exposed rectangle, to avoid drawing too much. */ virtual void drawTileSelection(QPainter *painter, const QRegion ®ion, const QColor &color, const QRectF &exposed) const = 0; /** * Draws the \a object in the given \a color using the \a painter. */ virtual void drawMapObject(QPainter *painter, const MapObject *object, const QColor &color) const = 0; /** * Draws the given image \a layer using the given \a painter. */ void drawImageLayer(QPainter *painter, const ImageLayer *imageLayer, const QRectF &exposed = QRectF()); /** * Returns the tile coordinates matching the given pixel position. */ virtual QPointF pixelToTileCoords(qreal x, qreal y) const = 0; inline QPointF pixelToTileCoords(const QPointF &point) const { return pixelToTileCoords(point.x(), point.y()); } QPolygonF pixelToScreenCoords(const QPolygonF &polygon) const { QPolygonF screenPolygon(polygon.size()); for (int i = polygon.size() - 1; i >= 0; --i) screenPolygon[i] = pixelToScreenCoords(polygon[i]); return screenPolygon; } /** * Returns the pixel coordinates matching the given tile coordinates. */ virtual QPointF tileToPixelCoords(qreal x, qreal y) const = 0; inline QPointF tileToPixelCoords(const QPointF &point) const { return tileToPixelCoords(point.x(), point.y()); } inline QRectF tileToPixelCoords(const QRectF &area) const { return QRectF(tileToPixelCoords(area.topLeft()), tileToPixelCoords(area.bottomRight())); } /** * Returns the tile coordinates matching the given screen position. */ virtual QPointF screenToTileCoords(qreal x, qreal y) const = 0; inline QPointF screenToTileCoords(const QPointF &point) const; /** * Returns the screen position matching the given tile coordinates. */ virtual QPointF tileToScreenCoords(qreal x, qreal y) const = 0; inline QPointF tileToScreenCoords(const QPointF &point) const; /** * Returns the pixel position matching the given screen position. */ virtual QPointF screenToPixelCoords(qreal x, qreal y) const = 0; inline QPointF screenToPixelCoords(const QPointF &point) const; /** * Returns the screen position matching the given pixel position. */ virtual QPointF pixelToScreenCoords(qreal x, qreal y) const = 0; inline QPointF pixelToScreenCoords(const QPointF &point) const; qreal objectLineWidth() const { return mObjectLineWidth; } void setObjectLineWidth(qreal lineWidth) { mObjectLineWidth = lineWidth; } void setFlag(RenderFlag flag, bool enabled = true); bool testFlag(RenderFlag flag) const { return mFlags.testFlag(flag); } qreal painterScale() const { return mPainterScale; } void setPainterScale(qreal painterScale) { mPainterScale = painterScale; } RenderFlags flags() const { return mFlags; } void setFlags(RenderFlags flags) { mFlags = flags; } static QPolygonF lineToPolygon(const QPointF &start, const QPointF &end); private: const Map *mMap; RenderFlags mFlags; qreal mObjectLineWidth; qreal mPainterScale; }; inline const Map *MapRenderer::map() const { return mMap; } inline QPointF MapRenderer::screenToTileCoords(const QPointF &point) const { return screenToTileCoords(point.x(), point.y()); } inline QPointF MapRenderer::tileToScreenCoords(const QPointF &point) const { return tileToScreenCoords(point.x(), point.y()); } inline QPointF MapRenderer::screenToPixelCoords(const QPointF &point) const { return screenToPixelCoords(point.x(), point.y()); } inline QPointF MapRenderer::pixelToScreenCoords(const QPointF &point) const { return pixelToScreenCoords(point.x(), point.y()); } /** * A utility class for rendering cells. */ class CellRenderer { public: enum Origin { BottomLeft, BottomCenter }; explicit CellRenderer(QPainter *painter); ~CellRenderer() { flush(); } void render(const Cell &cell, const QPointF &pos, const QSizeF &size, Origin origin); void flush(); private: QPainter * const mPainter; Tile *mTile; QVector mFragments; const bool mIsOpenGL; }; } // namespace Tiled Q_DECLARE_OPERATORS_FOR_FLAGS(Tiled::RenderFlags) #endif // MAPRENDERER_H tiled-0.14.2/src/libtiled/maptovariantconverter.cpp000066400000000000000000000333721260670167100224350ustar00rootroot00000000000000/* * maptovariantconverter.cpp * Copyright 2011, Porfírio José Pereira Ribeiro * Copyright 2011-2015, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "maptovariantconverter.h" #include "imagelayer.h" #include "map.h" #include "mapobject.h" #include "objectgroup.h" #include "properties.h" #include "tile.h" #include "tilelayer.h" #include "tileset.h" #include "terrain.h" using namespace Tiled; QVariant MapToVariantConverter::toVariant(const Map *map, const QDir &mapDir) { mMapDir = mapDir; mGidMapper.clear(); QVariantMap mapVariant; mapVariant[QLatin1String("version")] = 1.0; mapVariant[QLatin1String("orientation")] = orientationToString(map->orientation()); mapVariant[QLatin1String("renderorder")] = renderOrderToString(map->renderOrder()); mapVariant[QLatin1String("width")] = map->width(); mapVariant[QLatin1String("height")] = map->height(); mapVariant[QLatin1String("tilewidth")] = map->tileWidth(); mapVariant[QLatin1String("tileheight")] = map->tileHeight(); mapVariant[QLatin1String("properties")] = toVariant(map->properties()); mapVariant[QLatin1String("nextobjectid")] = map->nextObjectId(); if (map->orientation() == Map::Hexagonal) { mapVariant[QLatin1String("hexsidelength")] = map->hexSideLength(); } if (map->orientation() == Map::Hexagonal || map->orientation() == Map::Staggered) { mapVariant[QLatin1String("staggeraxis")] = staggerAxisToString(map->staggerAxis()); mapVariant[QLatin1String("staggerindex")] = staggerIndexToString(map->staggerIndex()); } const QColor bgColor = map->backgroundColor(); if (bgColor.isValid()) mapVariant[QLatin1String("backgroundcolor")] = bgColor.name(); QVariantList tilesetVariants; unsigned firstGid = 1; foreach (const SharedTileset &tileset, map->tilesets()) { tilesetVariants << toVariant(tileset.data(), firstGid); mGidMapper.insert(firstGid, tileset.data()); firstGid += tileset->tileCount(); } mapVariant[QLatin1String("tilesets")] = tilesetVariants; QVariantList layerVariants; foreach (const Layer *layer, map->layers()) { switch (layer->layerType()) { case Layer::TileLayerType: layerVariants << toVariant(static_cast(layer), map->layerDataFormat()); break; case Layer::ObjectGroupType: layerVariants << toVariant(static_cast(layer)); break; case Layer::ImageLayerType: layerVariants << toVariant(static_cast(layer)); break; } } mapVariant[QLatin1String("layers")] = layerVariants; return mapVariant; } QVariant MapToVariantConverter::toVariant(const Tileset &tileset, const QDir &directory) { mMapDir = directory; return toVariant(&tileset, 0); } QVariant MapToVariantConverter::toVariant(const Tileset *tileset, int firstGid) const { QVariantMap tilesetVariant; if (firstGid > 0) tilesetVariant[QLatin1String("firstgid")] = firstGid; const QString &fileName = tileset->fileName(); if (!fileName.isEmpty()) { QString source = mMapDir.relativeFilePath(fileName); tilesetVariant[QLatin1String("source")] = source; // Tileset is external, so no need to write any of the stuff below return tilesetVariant; } tilesetVariant[QLatin1String("name")] = tileset->name(); tilesetVariant[QLatin1String("tilewidth")] = tileset->tileWidth(); tilesetVariant[QLatin1String("tileheight")] = tileset->tileHeight(); tilesetVariant[QLatin1String("spacing")] = tileset->tileSpacing(); tilesetVariant[QLatin1String("margin")] = tileset->margin(); tilesetVariant[QLatin1String("tilecount")] = tileset->tileCount(); tilesetVariant[QLatin1String("properties")] = toVariant(tileset->properties()); const QPoint offset = tileset->tileOffset(); if (!offset.isNull()) { QVariantMap tileOffset; tileOffset[QLatin1String("x")] = offset.x(); tileOffset[QLatin1String("y")] = offset.y(); tilesetVariant[QLatin1String("tileoffset")] = tileOffset; } // Write the image element const QString &imageSource = tileset->imageSource(); if (!imageSource.isEmpty()) { const QString rel = mMapDir.relativeFilePath(tileset->imageSource()); tilesetVariant[QLatin1String("image")] = rel; const QColor transColor = tileset->transparentColor(); if (transColor.isValid()) tilesetVariant[QLatin1String("transparentcolor")] = transColor.name(); tilesetVariant[QLatin1String("imagewidth")] = tileset->imageWidth(); tilesetVariant[QLatin1String("imageheight")] = tileset->imageHeight(); } // Write the properties, terrain, external image, object group and // animation for those tiles that have them. QVariantMap tilePropertiesVariant; QVariantMap tilesVariant; for (int i = 0; i < tileset->tileCount(); ++i) { const Tile *tile = tileset->tileAt(i); const Properties properties = tile->properties(); if (!properties.isEmpty()) tilePropertiesVariant[QString::number(i)] = toVariant(properties); QVariantMap tileVariant; if (tile->terrain() != 0xFFFFFFFF) { QVariantList terrainIds; for (int j = 0; j < 4; ++j) terrainIds << QVariant(tile->cornerTerrainId(j)); tileVariant[QLatin1String("terrain")] = terrainIds; } if (tile->probability() != 1.f) tileVariant[QLatin1String("probability")] = tile->probability(); if (!tile->imageSource().isEmpty()) { const QString rel = mMapDir.relativeFilePath(tile->imageSource()); tileVariant[QLatin1String("image")] = rel; } if (tile->objectGroup()) tileVariant[QLatin1String("objectgroup")] = toVariant(tile->objectGroup()); if (tile->isAnimated()) { QVariantList frameVariants; foreach (const Frame &frame, tile->frames()) { QVariantMap frameVariant; frameVariant[QLatin1String("tileid")] = frame.tileId; frameVariant[QLatin1String("duration")] = frame.duration; frameVariants.append(frameVariant); } tileVariant[QLatin1String("animation")] = frameVariants; } if (!tileVariant.empty()) tilesVariant[QString::number(i)] = tileVariant; } if (!tilePropertiesVariant.empty()) tilesetVariant[QLatin1String("tileproperties")] = tilePropertiesVariant; if (!tilesVariant.empty()) tilesetVariant[QLatin1String("tiles")] = tilesVariant; // Write terrains if (tileset->terrainCount() > 0) { QVariantList terrainsVariant; for (int i = 0; i < tileset->terrainCount(); ++i) { Terrain *terrain = tileset->terrain(i); const Properties &properties = terrain->properties(); QVariantMap terrainVariant; terrainVariant[QLatin1String("name")] = terrain->name(); if (!properties.isEmpty()) terrainVariant[QLatin1String("properties")] = toVariant(properties); terrainVariant[QLatin1String("tile")] = terrain->imageTileId(); terrainsVariant << terrainVariant; } tilesetVariant[QLatin1String("terrains")] = terrainsVariant; } return tilesetVariant; } QVariant MapToVariantConverter::toVariant(const Properties &properties) const { QVariantMap variantMap; Properties::const_iterator it = properties.constBegin(); Properties::const_iterator it_end = properties.constEnd(); for (; it != it_end; ++it) variantMap[it.key()] = it.value(); return variantMap; } QVariant MapToVariantConverter::toVariant(const TileLayer *tileLayer, Map::LayerDataFormat format) const { QVariantMap tileLayerVariant; tileLayerVariant[QLatin1String("type")] = QLatin1String("tilelayer"); addLayerAttributes(tileLayerVariant, tileLayer); switch (format) { case Map::XML: case Map::CSV: { QVariantList tileVariants; for (int y = 0; y < tileLayer->height(); ++y) for (int x = 0; x < tileLayer->width(); ++x) tileVariants << mGidMapper.cellToGid(tileLayer->cellAt(x, y)); tileLayerVariant[QLatin1String("data")] = tileVariants; break; } case Map::Base64: case Map::Base64Zlib: case Map::Base64Gzip: { tileLayerVariant[QLatin1String("encoding")] = QLatin1String("base64"); if (format == Map::Base64Zlib) tileLayerVariant[QLatin1String("compression")] = QLatin1String("zlib"); else if (format == Map::Base64Gzip) tileLayerVariant[QLatin1String("compression")] = QLatin1String("gzip"); QByteArray layerData = mGidMapper.encodeLayerData(*tileLayer, format); tileLayerVariant[QLatin1String("data")] = layerData; break; } } return tileLayerVariant; } QVariant MapToVariantConverter::toVariant(const ObjectGroup *objectGroup) const { QVariantMap objectGroupVariant; objectGroupVariant[QLatin1String("type")] = QLatin1String("objectgroup"); if (objectGroup->color().isValid()) objectGroupVariant[QLatin1String("color")] = objectGroup->color().name(); objectGroupVariant[QLatin1String("draworder")] = drawOrderToString(objectGroup->drawOrder()); addLayerAttributes(objectGroupVariant, objectGroup); QVariantList objectVariants; foreach (const MapObject *object, objectGroup->objects()) { QVariantMap objectVariant; const QString &name = object->name(); const QString &type = object->type(); objectVariant[QLatin1String("properties")] = toVariant(object->properties()); objectVariant[QLatin1String("id")] = object->id(); objectVariant[QLatin1String("name")] = name; objectVariant[QLatin1String("type")] = type; if (!object->cell().isEmpty()) objectVariant[QLatin1String("gid")] = mGidMapper.cellToGid(object->cell()); objectVariant[QLatin1String("x")] = object->x(); objectVariant[QLatin1String("y")] = object->y(); objectVariant[QLatin1String("width")] = object->width(); objectVariant[QLatin1String("height")] = object->height(); objectVariant[QLatin1String("rotation")] = object->rotation(); objectVariant[QLatin1String("visible")] = object->isVisible(); /* Polygons are stored in this format: * * "polygon/polyline": [ * { "x": 0, "y": 0 }, * { "x": 1, "y": 1 }, * ... * ] */ const QPolygonF &polygon = object->polygon(); if (!polygon.isEmpty()) { QVariantList pointVariants; foreach (const QPointF &point, polygon) { QVariantMap pointVariant; pointVariant[QLatin1String("x")] = point.x(); pointVariant[QLatin1String("y")] = point.y(); pointVariants.append(pointVariant); } if (object->shape() == MapObject::Polygon) objectVariant[QLatin1String("polygon")] = pointVariants; else objectVariant[QLatin1String("polyline")] = pointVariants; } if (object->shape() == MapObject::Ellipse) objectVariant[QLatin1String("ellipse")] = true; objectVariants << objectVariant; } objectGroupVariant[QLatin1String("objects")] = objectVariants; return objectGroupVariant; } QVariant MapToVariantConverter::toVariant(const ImageLayer *imageLayer) const { QVariantMap imageLayerVariant; imageLayerVariant[QLatin1String("type")] = QLatin1String("imagelayer"); addLayerAttributes(imageLayerVariant, imageLayer); const QString rel = mMapDir.relativeFilePath(imageLayer->imageSource()); imageLayerVariant[QLatin1String("image")] = rel; const QColor transColor = imageLayer->transparentColor(); if (transColor.isValid()) imageLayerVariant[QLatin1String("transparentcolor")] = transColor.name(); return imageLayerVariant; } void MapToVariantConverter::addLayerAttributes(QVariantMap &layerVariant, const Layer *layer) const { layerVariant[QLatin1String("name")] = layer->name(); layerVariant[QLatin1String("width")] = layer->width(); layerVariant[QLatin1String("height")] = layer->height(); layerVariant[QLatin1String("x")] = layer->x(); layerVariant[QLatin1String("y")] = layer->y(); layerVariant[QLatin1String("visible")] = layer->isVisible(); layerVariant[QLatin1String("opacity")] = layer->opacity(); const QPointF offset = layer->offset(); if (!offset.isNull()) { layerVariant[QLatin1String("offsetx")] = offset.x(); layerVariant[QLatin1String("offsety")] = offset.y(); } const Properties &properties = layer->properties(); if (!properties.isEmpty()) layerVariant[QLatin1String("properties")] = toVariant(properties); } tiled-0.14.2/src/libtiled/maptovariantconverter.h000066400000000000000000000042361260670167100220770ustar00rootroot00000000000000/* * maptovariantconverter.h * Copyright 2011, Porfírio José Pereira Ribeiro * Copyright 2011-2015, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef MAPTOVARIANTCONVERTER_H #define MAPTOVARIANTCONVERTER_H #include #include #include "gidmapper.h" namespace Tiled { /** * Converts Map instances to QVariant. Meant to be used together with * JsonWriter. */ class TILEDSHARED_EXPORT MapToVariantConverter { public: MapToVariantConverter() {} /** * Converts the given \s map to a QVariant. The \a mapDir is used to * construct relative paths to external resources. */ QVariant toVariant(const Map *map, const QDir &mapDir); /** * Converts the given \s tileset to a QVariant. The \a directory is used to * construct relative paths to external resources. */ QVariant toVariant(const Tileset &tileset, const QDir &directory); private: QVariant toVariant(const Tileset *tileset, int firstGid) const; QVariant toVariant(const Properties &properties) const; QVariant toVariant(const TileLayer *tileLayer, Map::LayerDataFormat format) const; QVariant toVariant(const ObjectGroup *objectGroup) const; QVariant toVariant(const ImageLayer *imageLayer) const; void addLayerAttributes(QVariantMap &layerVariant, const Layer *layer) const; QDir mMapDir; GidMapper mGidMapper; }; } // namespace Tiled #endif // MAPTOVARIANTCONVERTER_H tiled-0.14.2/src/libtiled/mapwriter.cpp000066400000000000000000000567761260670167100200270ustar00rootroot00000000000000/* * mapwriter.cpp * Copyright 2008-2014, Thorbjørn Lindeijer * Copyright 2010, Jeff Bland * Copyright 2010, Dennis Honeyman * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mapwriter.h" #include "compression.h" #include "gidmapper.h" #include "map.h" #include "mapobject.h" #include "imagelayer.h" #include "objectgroup.h" #include "tile.h" #include "tilelayer.h" #include "tileset.h" #include "terrain.h" #include #include #include #include #include using namespace Tiled; using namespace Tiled::Internal; namespace Tiled { namespace Internal { class MapWriterPrivate { Q_DECLARE_TR_FUNCTIONS(MapReader) public: MapWriterPrivate(); void writeMap(const Map *map, QIODevice *device, const QString &path); void writeTileset(const Tileset &tileset, QIODevice *device, const QString &path); bool openFile(QIODevice *file); QString mError; Map::LayerDataFormat mLayerDataFormat; bool mDtdEnabled; private: void writeMap(QXmlStreamWriter &w, const Map &map); void writeTileset(QXmlStreamWriter &w, const Tileset &tileset, unsigned firstGid); void writeTileLayer(QXmlStreamWriter &w, const TileLayer &tileLayer); void writeLayerAttributes(QXmlStreamWriter &w, const Layer &layer); void writeObjectGroup(QXmlStreamWriter &w, const ObjectGroup &objectGroup); void writeObject(QXmlStreamWriter &w, const MapObject &mapObject); void writeImageLayer(QXmlStreamWriter &w, const ImageLayer &imageLayer); void writeProperties(QXmlStreamWriter &w, const Properties &properties); QDir mMapDir; // The directory in which the map is being saved GidMapper mGidMapper; bool mUseAbsolutePaths; }; } // namespace Internal } // namespace Tiled MapWriterPrivate::MapWriterPrivate() : mLayerDataFormat(Map::Base64Zlib) , mDtdEnabled(false) , mUseAbsolutePaths(false) { } bool MapWriterPrivate::openFile(QIODevice *file) { if (!file->open(QIODevice::WriteOnly | QIODevice::Text)) { mError = tr("Could not open file for writing."); return false; } return true; } static QXmlStreamWriter *createWriter(QIODevice *device) { QXmlStreamWriter *writer = new QXmlStreamWriter(device); writer->setAutoFormatting(true); writer->setAutoFormattingIndent(1); return writer; } void MapWriterPrivate::writeMap(const Map *map, QIODevice *device, const QString &path) { mMapDir = QDir(path); mUseAbsolutePaths = path.isEmpty(); mLayerDataFormat = map->layerDataFormat(); QXmlStreamWriter *writer = createWriter(device); writer->writeStartDocument(); if (mDtdEnabled) { writer->writeDTD(QLatin1String("")); } writeMap(*writer, *map); writer->writeEndDocument(); delete writer; } void MapWriterPrivate::writeTileset(const Tileset &tileset, QIODevice *device, const QString &path) { mMapDir = QDir(path); mUseAbsolutePaths = path.isEmpty(); QXmlStreamWriter *writer = createWriter(device); writer->writeStartDocument(); if (mDtdEnabled) { writer->writeDTD(QLatin1String("")); } writeTileset(*writer, tileset, 0); writer->writeEndDocument(); delete writer; } void MapWriterPrivate::writeMap(QXmlStreamWriter &w, const Map &map) { w.writeStartElement(QLatin1String("map")); const QString orientation = orientationToString(map.orientation()); const QString renderOrder = renderOrderToString(map.renderOrder()); w.writeAttribute(QLatin1String("version"), QLatin1String("1.0")); w.writeAttribute(QLatin1String("orientation"), orientation); w.writeAttribute(QLatin1String("renderorder"), renderOrder); w.writeAttribute(QLatin1String("width"), QString::number(map.width())); w.writeAttribute(QLatin1String("height"), QString::number(map.height())); w.writeAttribute(QLatin1String("tilewidth"), QString::number(map.tileWidth())); w.writeAttribute(QLatin1String("tileheight"), QString::number(map.tileHeight())); if (map.orientation() == Map::Hexagonal) { w.writeAttribute(QLatin1String("hexsidelength"), QString::number(map.hexSideLength())); } if (map.orientation() == Map::Staggered || map.orientation() == Map::Hexagonal) { w.writeAttribute(QLatin1String("staggeraxis"), staggerAxisToString(map.staggerAxis())); w.writeAttribute(QLatin1String("staggerindex"), staggerIndexToString(map.staggerIndex())); } if (map.backgroundColor().isValid()) { w.writeAttribute(QLatin1String("backgroundcolor"), map.backgroundColor().name()); } w.writeAttribute(QLatin1String("nextobjectid"), QString::number(map.nextObjectId())); writeProperties(w, map.properties()); mGidMapper.clear(); unsigned firstGid = 1; for (const SharedTileset &tileset : map.tilesets()) { writeTileset(w, *tileset, firstGid); mGidMapper.insert(firstGid, tileset.data()); firstGid += tileset->tileCount(); } for (const Layer *layer : map.layers()) { const Layer::TypeFlag type = layer->layerType(); if (type == Layer::TileLayerType) writeTileLayer(w, *static_cast(layer)); else if (type == Layer::ObjectGroupType) writeObjectGroup(w, *static_cast(layer)); else if (type == Layer::ImageLayerType) writeImageLayer(w, *static_cast(layer)); } w.writeEndElement(); } static QString makeTerrainAttribute(const Tile *tile) { QString terrain; for (int i = 0; i < 4; ++i ) { if (i > 0) terrain += QLatin1String(","); int t = tile->cornerTerrainId(i); if (t > -1) terrain += QString::number(t); } return terrain; } void MapWriterPrivate::writeTileset(QXmlStreamWriter &w, const Tileset &tileset, unsigned firstGid) { w.writeStartElement(QLatin1String("tileset")); if (firstGid > 0) w.writeAttribute(QLatin1String("firstgid"), QString::number(firstGid)); const QString &fileName = tileset.fileName(); if (!fileName.isEmpty()) { QString source = fileName; if (!mUseAbsolutePaths) source = mMapDir.relativeFilePath(source); w.writeAttribute(QLatin1String("source"), source); // Tileset is external, so no need to write any of the stuff below w.writeEndElement(); return; } w.writeAttribute(QLatin1String("name"), tileset.name()); w.writeAttribute(QLatin1String("tilewidth"), QString::number(tileset.tileWidth())); w.writeAttribute(QLatin1String("tileheight"), QString::number(tileset.tileHeight())); const int tileSpacing = tileset.tileSpacing(); const int margin = tileset.margin(); if (tileSpacing != 0) w.writeAttribute(QLatin1String("spacing"), QString::number(tileSpacing)); if (margin != 0) w.writeAttribute(QLatin1String("margin"), QString::number(margin)); w.writeAttribute(QLatin1String("tilecount"), QString::number(tileset.tileCount())); const QPoint offset = tileset.tileOffset(); if (!offset.isNull()) { w.writeStartElement(QLatin1String("tileoffset")); w.writeAttribute(QLatin1String("x"), QString::number(offset.x())); w.writeAttribute(QLatin1String("y"), QString::number(offset.y())); w.writeEndElement(); } // Write the tileset properties writeProperties(w, tileset.properties()); // Write the image element const QString &imageSource = tileset.imageSource(); if (!imageSource.isEmpty()) { w.writeStartElement(QLatin1String("image")); QString source = imageSource; if (!mUseAbsolutePaths) source = mMapDir.relativeFilePath(source); w.writeAttribute(QLatin1String("source"), source); const QColor transColor = tileset.transparentColor(); if (transColor.isValid()) w.writeAttribute(QLatin1String("trans"), transColor.name().mid(1)); if (tileset.imageWidth() > 0) w.writeAttribute(QLatin1String("width"), QString::number(tileset.imageWidth())); if (tileset.imageHeight() > 0) w.writeAttribute(QLatin1String("height"), QString::number(tileset.imageHeight())); w.writeEndElement(); } // Write the terrain types if (tileset.terrainCount() > 0) { w.writeStartElement(QLatin1String("terraintypes")); for (int i = 0; i < tileset.terrainCount(); ++i) { const Terrain *t = tileset.terrain(i); w.writeStartElement(QLatin1String("terrain")); w.writeAttribute(QLatin1String("name"), t->name()); w.writeAttribute(QLatin1String("tile"), QString::number(t->imageTileId())); writeProperties(w, t->properties()); w.writeEndElement(); } w.writeEndElement(); } // Write the properties for those tiles that have them for (int i = 0; i < tileset.tileCount(); ++i) { const Tile *tile = tileset.tileAt(i); const Properties properties = tile->properties(); unsigned terrain = tile->terrain(); float probability = tile->probability(); ObjectGroup *objectGroup = tile->objectGroup(); if (!properties.isEmpty() || terrain != 0xFFFFFFFF || probability != 1.f || imageSource.isEmpty() || objectGroup || tile->isAnimated()) { w.writeStartElement(QLatin1String("tile")); w.writeAttribute(QLatin1String("id"), QString::number(i)); if (terrain != 0xFFFFFFFF) w.writeAttribute(QLatin1String("terrain"), makeTerrainAttribute(tile)); if (probability != 1.f) w.writeAttribute(QLatin1String("probability"), QString::number(probability)); if (!properties.isEmpty()) writeProperties(w, properties); if (imageSource.isEmpty()) { w.writeStartElement(QLatin1String("image")); const QSize tileSize = tile->size(); if (!tileSize.isNull()) { w.writeAttribute(QLatin1String("width"), QString::number(tileSize.width())); w.writeAttribute(QLatin1String("height"), QString::number(tileSize.height())); } if (tile->imageSource().isEmpty()) { w.writeAttribute(QLatin1String("format"), QLatin1String("png")); w.writeStartElement(QLatin1String("data")); w.writeAttribute(QLatin1String("encoding"), QLatin1String("base64")); QBuffer buffer; tile->image().save(&buffer, "png"); w.writeCharacters(QString::fromLatin1(buffer.data().toBase64())); w.writeEndElement(); // } else { QString source = tile->imageSource(); if (!mUseAbsolutePaths) source = mMapDir.relativeFilePath(source); w.writeAttribute(QLatin1String("source"), source); } w.writeEndElement(); // } if (objectGroup) writeObjectGroup(w, *objectGroup); if (tile->isAnimated()) { const QVector &frames = tile->frames(); w.writeStartElement(QLatin1String("animation")); for (const Frame &frame : frames) { w.writeStartElement(QLatin1String("frame")); w.writeAttribute(QLatin1String("tileid"), QString::number(frame.tileId)); w.writeAttribute(QLatin1String("duration"), QString::number(frame.duration)); w.writeEndElement(); // } w.writeEndElement(); // } w.writeEndElement(); // } } w.writeEndElement(); } void MapWriterPrivate::writeTileLayer(QXmlStreamWriter &w, const TileLayer &tileLayer) { w.writeStartElement(QLatin1String("layer")); writeLayerAttributes(w, tileLayer); writeProperties(w, tileLayer.properties()); QString encoding; QString compression; if (mLayerDataFormat == Map::Base64 || mLayerDataFormat == Map::Base64Gzip || mLayerDataFormat == Map::Base64Zlib) { encoding = QLatin1String("base64"); if (mLayerDataFormat == Map::Base64Gzip) compression = QLatin1String("gzip"); else if (mLayerDataFormat == Map::Base64Zlib) compression = QLatin1String("zlib"); } else if (mLayerDataFormat == Map::CSV) encoding = QLatin1String("csv"); w.writeStartElement(QLatin1String("data")); if (!encoding.isEmpty()) w.writeAttribute(QLatin1String("encoding"), encoding); if (!compression.isEmpty()) w.writeAttribute(QLatin1String("compression"), compression); if (mLayerDataFormat == Map::XML) { for (int y = 0; y < tileLayer.height(); ++y) { for (int x = 0; x < tileLayer.width(); ++x) { const unsigned gid = mGidMapper.cellToGid(tileLayer.cellAt(x, y)); w.writeStartElement(QLatin1String("tile")); w.writeAttribute(QLatin1String("gid"), QString::number(gid)); w.writeEndElement(); } } } else if (mLayerDataFormat == Map::CSV) { QString tileData; for (int y = 0; y < tileLayer.height(); ++y) { for (int x = 0; x < tileLayer.width(); ++x) { const unsigned gid = mGidMapper.cellToGid(tileLayer.cellAt(x, y)); tileData.append(QString::number(gid)); if (x != tileLayer.width() - 1 || y != tileLayer.height() - 1) tileData.append(QLatin1String(",")); } tileData.append(QLatin1String("\n")); } w.writeCharacters(QLatin1String("\n")); w.writeCharacters(tileData); } else { QByteArray tileData = mGidMapper.encodeLayerData(tileLayer, mLayerDataFormat); w.writeCharacters(QLatin1String("\n ")); w.writeCharacters(QString::fromLatin1(tileData)); w.writeCharacters(QLatin1String("\n ")); } w.writeEndElement(); // w.writeEndElement(); // } void MapWriterPrivate::writeLayerAttributes(QXmlStreamWriter &w, const Layer &layer) { if (!layer.name().isEmpty()) w.writeAttribute(QLatin1String("name"), layer.name()); const int x = layer.x(); const int y = layer.y(); const qreal opacity = layer.opacity(); if (x != 0) w.writeAttribute(QLatin1String("x"), QString::number(x)); if (y != 0) w.writeAttribute(QLatin1String("y"), QString::number(y)); if (layer.layerType() == Layer::TileLayerType) { w.writeAttribute(QLatin1String("width"), QString::number(layer.width())); w.writeAttribute(QLatin1String("height"), QString::number(layer.height())); } if (!layer.isVisible()) w.writeAttribute(QLatin1String("visible"), QLatin1String("0")); if (opacity != qreal(1)) w.writeAttribute(QLatin1String("opacity"), QString::number(opacity)); const QPointF offset = layer.offset(); if (!offset.isNull()) { w.writeAttribute(QLatin1String("offsetx"), QString::number(offset.x())); w.writeAttribute(QLatin1String("offsety"), QString::number(offset.y())); } } void MapWriterPrivate::writeObjectGroup(QXmlStreamWriter &w, const ObjectGroup &objectGroup) { w.writeStartElement(QLatin1String("objectgroup")); if (objectGroup.color().isValid()) w.writeAttribute(QLatin1String("color"), objectGroup.color().name()); if (objectGroup.drawOrder() != ObjectGroup::TopDownOrder) { w.writeAttribute(QLatin1String("draworder"), drawOrderToString(objectGroup.drawOrder())); } writeLayerAttributes(w, objectGroup); writeProperties(w, objectGroup.properties()); for (const MapObject *mapObject : objectGroup.objects()) writeObject(w, *mapObject); w.writeEndElement(); } void MapWriterPrivate::writeObject(QXmlStreamWriter &w, const MapObject &mapObject) { w.writeStartElement(QLatin1String("object")); w.writeAttribute(QLatin1String("id"), QString::number(mapObject.id())); const QString &name = mapObject.name(); const QString &type = mapObject.type(); if (!name.isEmpty()) w.writeAttribute(QLatin1String("name"), name); if (!type.isEmpty()) w.writeAttribute(QLatin1String("type"), type); if (!mapObject.cell().isEmpty()) { const unsigned gid = mGidMapper.cellToGid(mapObject.cell()); w.writeAttribute(QLatin1String("gid"), QString::number(gid)); } const QPointF pos = mapObject.position(); const QSizeF size = mapObject.size(); w.writeAttribute(QLatin1String("x"), QString::number(pos.x())); w.writeAttribute(QLatin1String("y"), QString::number(pos.y())); if (size.width() != 0) w.writeAttribute(QLatin1String("width"), QString::number(size.width())); if (size.height() != 0) w.writeAttribute(QLatin1String("height"), QString::number(size.height())); const qreal rotation = mapObject.rotation(); if (rotation != 0.0) w.writeAttribute(QLatin1String("rotation"), QString::number(rotation)); if (!mapObject.isVisible()) w.writeAttribute(QLatin1String("visible"), QLatin1String("0")); writeProperties(w, mapObject.properties()); const QPolygonF &polygon = mapObject.polygon(); if (!polygon.isEmpty()) { if (mapObject.shape() == MapObject::Polygon) w.writeStartElement(QLatin1String("polygon")); else w.writeStartElement(QLatin1String("polyline")); QString points; for (const QPointF &point : polygon) { points.append(QString::number(point.x())); points.append(QLatin1Char(',')); points.append(QString::number(point.y())); points.append(QLatin1Char(' ')); } points.chop(1); w.writeAttribute(QLatin1String("points"), points); w.writeEndElement(); } if (mapObject.shape() == MapObject::Ellipse) w.writeEmptyElement(QLatin1String("ellipse")); w.writeEndElement(); } void MapWriterPrivate::writeImageLayer(QXmlStreamWriter &w, const ImageLayer &imageLayer) { w.writeStartElement(QLatin1String("imagelayer")); writeLayerAttributes(w, imageLayer); // Write the image element const QString &imageSource = imageLayer.imageSource(); if (!imageSource.isEmpty()) { w.writeStartElement(QLatin1String("image")); QString source = imageSource; if (!mUseAbsolutePaths) source = mMapDir.relativeFilePath(source); w.writeAttribute(QLatin1String("source"), source); const QColor transColor = imageLayer.transparentColor(); if (transColor.isValid()) w.writeAttribute(QLatin1String("trans"), transColor.name().mid(1)); w.writeEndElement(); } writeProperties(w, imageLayer.properties()); w.writeEndElement(); } void MapWriterPrivate::writeProperties(QXmlStreamWriter &w, const Properties &properties) { if (properties.isEmpty()) return; w.writeStartElement(QLatin1String("properties")); Properties::const_iterator it = properties.constBegin(); Properties::const_iterator it_end = properties.constEnd(); for (; it != it_end; ++it) { w.writeStartElement(QLatin1String("property")); w.writeAttribute(QLatin1String("name"), it.key()); const QString &value = it.value(); if (value.contains(QLatin1Char('\n'))) { w.writeCharacters(value); } else { w.writeAttribute(QLatin1String("value"), it.value()); } w.writeEndElement(); } w.writeEndElement(); } MapWriter::MapWriter() : d(new MapWriterPrivate) { } MapWriter::~MapWriter() { delete d; } void MapWriter::writeMap(const Map *map, QIODevice *device, const QString &path) { d->writeMap(map, device, path); } bool MapWriter::writeMap(const Map *map, const QString &fileName) { QSaveFile file(fileName); if (!d->openFile(&file)) return false; writeMap(map, &file, QFileInfo(fileName).absolutePath()); if (file.error() != QFile::NoError) { d->mError = file.errorString(); return false; } if (!file.commit()) { d->mError = file.errorString(); return false; } return true; } void MapWriter::writeTileset(const Tileset &tileset, QIODevice *device, const QString &path) { d->writeTileset(tileset, device, path); } bool MapWriter::writeTileset(const Tileset &tileset, const QString &fileName) { QFile file(fileName); if (!d->openFile(&file)) return false; writeTileset(tileset, &file, QFileInfo(fileName).absolutePath()); if (file.error() != QFile::NoError) { d->mError = file.errorString(); return false; } return true; } QString MapWriter::errorString() const { return d->mError; } void MapWriter::setDtdEnabled(bool enabled) { d->mDtdEnabled = enabled; } bool MapWriter::isDtdEnabled() const { return d->mDtdEnabled; } tiled-0.14.2/src/libtiled/mapwriter.h000066400000000000000000000066041260670167100174550ustar00rootroot00000000000000/* * mapwriter.h * Copyright 2008-2010, Thorbjørn Lindeijer * Copyright 2010, Dennis Honeyman * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef MAPWRITER_H #define MAPWRITER_H #include "map.h" #include "tiled_global.h" #include class QIODevice; namespace Tiled { class Map; class Tileset; namespace Internal { class MapWriterPrivate; } /** * A QXmlStreamWriter based writer for the TMX and TSX formats. */ class TILEDSHARED_EXPORT MapWriter { public: MapWriter(); ~MapWriter(); /** * Writes a TMX map to the given \a device. Optionally a \a path can * be given, which will be used to create relative references to external * images and tilesets. * * Error checking will need to be done on the \a device after calling this * function. */ void writeMap(const Map *map, QIODevice *device, const QString &path = QString()); /** * Writes a TMX map to the given \a fileName. * * Returns false and sets errorString() when reading failed. * \overload */ bool writeMap(const Map *map, const QString &fileName); /** * Writes a TSX tileset to the given \a device. Optionally a \a path can * be given, which will be used to create relative references to external * images. * * Error checking will need to be done on the \a device after calling this * function. */ void writeTileset(const Tileset &tileset, QIODevice *device, const QString &path = QString()); /** * Writes a TSX tileset to the given \a fileName. * * Returns false and sets errorString() when reading failed. * \overload */ bool writeTileset(const Tileset &tileset, const QString &fileName); /** * Returns the error message for the last occurred error. */ QString errorString() const; /** * Sets whether the DTD reference is written when saving the map. */ void setDtdEnabled(bool enabled); bool isDtdEnabled() const; private: Internal::MapWriterPrivate *d; }; } // namespace Tiled #endif // MAPWRITER_H tiled-0.14.2/src/libtiled/object.h000066400000000000000000000065321260670167100167110ustar00rootroot00000000000000/* * object.h * Copyright 2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef OBJECT_H #define OBJECT_H #include "properties.h" namespace Tiled { /** * The base class for anything that can hold properties. */ class TILEDSHARED_EXPORT Object { public: enum TypeId { LayerType, MapObjectType, MapType, TerrainType, TilesetType, TileType }; Object(TypeId typeId) : mTypeId(typeId) {} Object(const Object &object) : mTypeId(object.mTypeId), mProperties(object.mProperties) {} /** * Virtual destructor. */ virtual ~Object() {} /** * Returns the type of this object. */ TypeId typeId() const { return mTypeId; } /** * Returns the properties of this object. */ const Properties &properties() const { return mProperties; } /** * Replaces all existing properties with a new set of properties. */ void setProperties(const Properties &properties) { mProperties = properties; } /** * Merges \a properties with the existing properties. Properties with the * same name will be overridden. * * \sa Properties::merge */ void mergeProperties(const Properties &properties) { mProperties.merge(properties); } /** * Returns the value of the object's \a name property. */ QString property(const QString &name) const { return mProperties.value(name); } /** * Returns whether this object has a property with the given \a name. */ bool hasProperty(const QString &name) const { return mProperties.contains(name); } /** * Sets the value of the object's \a name property to \a value. */ void setProperty(const QString &name, const QString &value) { mProperties.insert(name, value); } /** * Removes the property with the given \a name. */ void removeProperty(const QString &name) { mProperties.remove(name); } private: TypeId mTypeId; Properties mProperties; }; } // namespace Tiled #endif // OBJECT_H tiled-0.14.2/src/libtiled/objectgroup.cpp000066400000000000000000000162441260670167100203220ustar00rootroot00000000000000/* * objectgroup.cpp * Copyright 2008, Roderic Morris * Copyright 2008-2014, Thorbjørn Lindeijer * Copyright 2009-2010, Jeff Bland * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "objectgroup.h" #include "layer.h" #include "map.h" #include "mapobject.h" #include "tile.h" #include using namespace Tiled; ObjectGroup::ObjectGroup() : Layer(ObjectGroupType, QString(), 0, 0, 0, 0) , mDrawOrder(TopDownOrder) { } ObjectGroup::ObjectGroup(const QString &name, int x, int y, int width, int height) : Layer(ObjectGroupType, name, x, y, width, height) , mDrawOrder(TopDownOrder) { } ObjectGroup::~ObjectGroup() { qDeleteAll(mObjects); } void ObjectGroup::addObject(MapObject *object) { mObjects.append(object); object->setObjectGroup(this); if (mMap && object->id() == 0) object->setId(mMap->takeNextObjectId()); } void ObjectGroup::insertObject(int index, MapObject *object) { mObjects.insert(index, object); object->setObjectGroup(this); if (mMap && object->id() == 0) object->setId(mMap->takeNextObjectId()); } int ObjectGroup::removeObject(MapObject *object) { const int index = mObjects.indexOf(object); Q_ASSERT(index != -1); mObjects.removeAt(index); object->setObjectGroup(nullptr); return index; } void ObjectGroup::removeObjectAt(int index) { MapObject *object = mObjects.takeAt(index); object->setObjectGroup(nullptr); } void ObjectGroup::moveObjects(int from, int to, int count) { // It's an error when 'to' lies within the moving range of objects Q_ASSERT(count >= 0); Q_ASSERT(to <= from || to >= from + count); // Nothing to be done when 'to' is the start or the end of the range, or // when the number of objects to be moved is 0. if (to == from || to == from + count || count == 0) return; const QList movingObjects = mObjects.mid(from, count); mObjects.erase(mObjects.begin() + from, mObjects.begin() + from + count); if (to > from) to -= count; for (int i = 0; i < count; ++i) mObjects.insert(to + i, movingObjects.at(i)); } QRectF ObjectGroup::objectsBoundingRect() const { QRectF boundingRect; foreach (const MapObject *object, mObjects) boundingRect = boundingRect.united(object->bounds()); return boundingRect; } bool ObjectGroup::isEmpty() const { return mObjects.isEmpty(); } QSet ObjectGroup::usedTilesets() const { QSet tilesets; foreach (const MapObject *object, mObjects) if (const Tile *tile = object->cell().tile) tilesets.insert(tile->sharedTileset()); return tilesets; } bool ObjectGroup::referencesTileset(const Tileset *tileset) const { foreach (const MapObject *object, mObjects) { const Tile *tile = object->cell().tile; if (tile && tile->tileset() == tileset) return true; } return false; } void ObjectGroup::replaceReferencesToTileset(Tileset *oldTileset, Tileset *newTileset) { foreach (MapObject *object, mObjects) { const Tile *tile = object->cell().tile; if (tile && tile->tileset() == oldTileset) { Cell cell = object->cell(); cell.tile = newTileset->tileAt(tile->id()); object->setCell(cell); } } } void ObjectGroup::offsetObjects(const QPointF &offset, const QRectF &bounds, bool wrapX, bool wrapY) { foreach (MapObject *object, mObjects) { const QPointF objectCenter = object->bounds().center(); if (!bounds.contains(objectCenter)) continue; QPointF newCenter(objectCenter + offset); if (wrapX && bounds.width() > 0) { qreal nx = std::fmod(newCenter.x() - bounds.left(), bounds.width()); newCenter.setX(bounds.left() + (nx < 0 ? bounds.width() + nx : nx)); } if (wrapY && bounds.height() > 0) { qreal ny = std::fmod(newCenter.y() - bounds.top(), bounds.height()); newCenter.setY(bounds.top() + (ny < 0 ? bounds.height() + ny : ny)); } object->setPosition(object->position() + (newCenter - objectCenter)); } } bool ObjectGroup::canMergeWith(Layer *other) const { return other->isObjectGroup(); } Layer *ObjectGroup::mergedWith(Layer *other) const { Q_ASSERT(canMergeWith(other)); const ObjectGroup *og = static_cast(other); ObjectGroup *merged = static_cast(clone()); foreach (const MapObject *mapObject, og->objects()) merged->addObject(mapObject->clone()); return merged; } /** * Returns a duplicate of this ObjectGroup. * * \sa Layer::clone() */ Layer *ObjectGroup::clone() const { return initializeClone(new ObjectGroup(mName, mX, mY, mWidth, mHeight)); } ObjectGroup *ObjectGroup::initializeClone(ObjectGroup *clone) const { Layer::initializeClone(clone); foreach (const MapObject *object, mObjects) clone->addObject(object->clone()); clone->setColor(mColor); clone->setDrawOrder(mDrawOrder); return clone; } QString Tiled::drawOrderToString(ObjectGroup::DrawOrder drawOrder) { switch (drawOrder) { default: case ObjectGroup::UnknownOrder: return QLatin1String("unknown"); break; case ObjectGroup::TopDownOrder: return QLatin1String("topdown"); break; case ObjectGroup::IndexOrder: return QLatin1String("index"); break; } } ObjectGroup::DrawOrder Tiled::drawOrderFromString(const QString &string) { ObjectGroup::DrawOrder drawOrder = ObjectGroup::UnknownOrder; if (string == QLatin1String("topdown")) drawOrder = ObjectGroup::TopDownOrder; else if (string == QLatin1String("index")) drawOrder = ObjectGroup::IndexOrder; return drawOrder; } tiled-0.14.2/src/libtiled/objectgroup.h000066400000000000000000000154251260670167100177670ustar00rootroot00000000000000/* * objectgroup.h * Copyright 2008, Roderic Morris * Copyright 2008-2014, Thorbjørn Lindeijer * Copyright 2009-2010, Jeff Bland * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef OBJECTGROUP_H #define OBJECTGROUP_H #include "tiled_global.h" #include "layer.h" #include #include #include namespace Tiled { class MapObject; /** * A group of objects on a map. */ class TILEDSHARED_EXPORT ObjectGroup : public Layer { public: /** * Objects within an object group can either be drawn top down (sorted * by their y-coordinate) or by index (manual stacking order). * * The default is top down. */ enum DrawOrder { UnknownOrder = -1, TopDownOrder, IndexOrder }; /** * Default constructor. */ ObjectGroup(); /** * Constructor with some parameters. */ ObjectGroup(const QString &name, int x, int y, int width, int height); /** * Destructor. */ ~ObjectGroup(); /** * Returns a pointer to the list of objects in this object group. */ const QList &objects() const { return mObjects; } /** * Returns the number of objects in this object group. */ int objectCount() const { return mObjects.size(); } /** * Returns the object at the specified index. */ MapObject *objectAt(int index) const { return mObjects.at(index); } /** * Adds an object to this object group. */ void addObject(MapObject *object); /** * Inserts an object at the specified index. This is only used for undoing * the removal of an object at the moment, to make sure not to change the * saved order of the objects. */ void insertObject(int index, MapObject *object); /** * Removes an object from this object group. Ownership of the object is * transferred to the caller. * * @return the index at which the specified object was removed */ int removeObject(MapObject *object); /** * Removes the object at the given index. Ownership of the object is * transferred to the caller. * * This is faster than removeObject when you've already got the index. * * @param index the index at which to remove an object */ void removeObjectAt(int index); /** * Moves \a count objects starting at \a from to the index given by \a to. * * The \a to index may not lie within the range of objects that is * being moved. */ void moveObjects(int from, int to, int count); /** * Returns the bounding rect around all objects in this object group. */ QRectF objectsBoundingRect() const; /** * Returns whether this object group contains any objects. */ bool isEmpty() const override; /** * Computes and returns the set of tilesets used by this object group. */ QSet usedTilesets() const override; /** * Returns whether any tile objects in this object group reference tiles * in the given tileset. */ bool referencesTileset(const Tileset *tileset) const override; /** * Replaces all references to tiles from \a oldTileset with tiles from * \a newTileset. */ void replaceReferencesToTileset(Tileset *oldTileset, Tileset *newTileset) override; /** * Offsets all objects within the group by the \a offset given in pixel * coordinates, and optionally wraps them. The object's center must be * within \a bounds, and wrapping occurs if the displaced center is out of * the bounds. * * \sa TileLayer::offsetTiles() */ void offsetObjects(const QPointF &offset, const QRectF &bounds, bool wrapX, bool wrapY); bool canMergeWith(Layer *other) const override; Layer *mergedWith(Layer *other) const override; const QColor &color() const; void setColor(const QColor &color); DrawOrder drawOrder() const; void setDrawOrder(DrawOrder drawOrder); Layer *clone() const override; protected: ObjectGroup *initializeClone(ObjectGroup *clone) const; private: QList mObjects; QColor mColor; DrawOrder mDrawOrder; }; /** * Returns the color of the object group, or an invalid color if no color * is set. */ inline const QColor &ObjectGroup::color() const { return mColor; } /** * Sets the display color of the object group. */ inline void ObjectGroup::setColor(const QColor &color) { mColor = color; } /** * Returns the draw order for the objects in this group. * * \sa ObjectGroup::DrawOrder */ inline ObjectGroup::DrawOrder ObjectGroup::drawOrder() const { return mDrawOrder; } /** * Sets the draw order for the objects in this group. * * \sa ObjectGroup::DrawOrder */ inline void ObjectGroup::setDrawOrder(DrawOrder drawOrder) { mDrawOrder = drawOrder; } /** * Helper function that converts a drawing order to its string value. Useful * for map writers. * * @return The draw order as a lowercase string. */ TILEDSHARED_EXPORT QString drawOrderToString(ObjectGroup::DrawOrder); /** * Helper function that converts a string to a drawing order enumerator. * Useful for map readers. * * @return The draw order matching the given string, or * ObjectGroup::UnknownOrder if the string is unrecognized. */ TILEDSHARED_EXPORT ObjectGroup::DrawOrder drawOrderFromString(const QString &); } // namespace Tiled Q_DECLARE_METATYPE(Tiled::ObjectGroup*) #endif // OBJECTGROUP_H tiled-0.14.2/src/libtiled/orthogonalrenderer.cpp000066400000000000000000000371511260670167100217020ustar00rootroot00000000000000/* * orthogonalrenderer.cpp * Copyright 2009-2011, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "orthogonalrenderer.h" #include "map.h" #include "mapobject.h" #include "tile.h" #include "tilelayer.h" #include "tileset.h" #include using namespace Tiled; QSize OrthogonalRenderer::mapSize() const { return QSize(map()->width() * map()->tileWidth(), map()->height() * map()->tileHeight()); } QRect OrthogonalRenderer::boundingRect(const QRect &rect) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); return QRect(rect.x() * tileWidth, rect.y() * tileHeight, rect.width() * tileWidth, rect.height() * tileHeight); } QRectF OrthogonalRenderer::boundingRect(const MapObject *object) const { const QRectF bounds = object->bounds(); QRectF boundingRect; if (!object->cell().isEmpty()) { const QPointF bottomLeft = bounds.topLeft(); const Tile *tile = object->cell().tile; const QSize imgSize = tile->image().size(); const QPoint tileOffset = tile->offset(); const QSizeF objectSize = object->size(); const QSizeF scale(objectSize.width() / imgSize.width(), objectSize.height() / imgSize.height()); boundingRect = QRectF(bottomLeft.x() + (tileOffset.x() * scale.width()), bottomLeft.y() + (tileOffset.y() * scale.height()) - objectSize.height(), objectSize.width(), objectSize.height()).adjusted(-1, -1, 1, 1); } else { qreal extraSpace = qMax(objectLineWidth(), qreal(1)); switch (object->shape()) { case MapObject::Ellipse: case MapObject::Rectangle: if (bounds.isNull()) { boundingRect = bounds.adjusted(-10 - extraSpace, -10 - extraSpace, 10 + extraSpace + 1, 10 + extraSpace + 1); } else { boundingRect = bounds.adjusted(-extraSpace, -extraSpace, extraSpace + 1, extraSpace + 1); } break; case MapObject::Polygon: case MapObject::Polyline: { // Make some more room for the starting dot extraSpace += objectLineWidth() * 4; const QPointF &pos = object->position(); const QPolygonF polygon = object->polygon().translated(pos); QPolygonF screenPolygon = pixelToScreenCoords(polygon); boundingRect = screenPolygon.boundingRect().adjusted(-extraSpace, -extraSpace, extraSpace + 1, extraSpace + 1); break; } } } return boundingRect; } QPainterPath OrthogonalRenderer::shape(const MapObject *object) const { QPainterPath path; if (!object->cell().isEmpty()) { path.addRect(boundingRect(object)); } else { switch (object->shape()) { case MapObject::Rectangle: { const QRectF bounds = object->bounds(); if (bounds.isNull()) { path.addEllipse(bounds.topLeft(), 20, 20); } else { path.addRoundedRect(bounds, 10, 10); } break; } case MapObject::Polygon: case MapObject::Polyline: { const QPointF &pos = object->position(); const QPolygonF polygon = object->polygon().translated(pos); const QPolygonF screenPolygon = pixelToScreenCoords(polygon); if (object->shape() == MapObject::Polygon) { path.addPolygon(screenPolygon); } else { for (int i = 1; i < screenPolygon.size(); ++i) { path.addPolygon(lineToPolygon(screenPolygon[i - 1], screenPolygon[i])); } path.setFillRule(Qt::WindingFill); } break; } case MapObject::Ellipse: { const QRectF bounds = object->bounds(); if (bounds.isNull()) { path.addEllipse(bounds.topLeft(), 20, 20); } else { path.addEllipse(bounds); } break; } } } return path; } void OrthogonalRenderer::drawGrid(QPainter *painter, const QRectF &rect, QColor gridColor) const { const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); if (tileWidth <= 0 || tileHeight <= 0) return; const int startX = qMax(0, (int) (rect.x() / tileWidth) * tileWidth); const int startY = qMax(0, (int) (rect.y() / tileHeight) * tileHeight); const int endX = qMin(qCeil(rect.right()), map()->width() * tileWidth + 1); const int endY = qMin(qCeil(rect.bottom()), map()->height() * tileHeight + 1); gridColor.setAlpha(128); QPen gridPen(gridColor); gridPen.setCosmetic(true); gridPen.setDashPattern(QVector() << 2 << 2); if (startY < endY) { gridPen.setDashOffset(startY); painter->setPen(gridPen); for (int x = startX; x < endX; x += tileWidth) painter->drawLine(x, startY, x, endY - 1); } if (startX < endX) { gridPen.setDashOffset(startX); painter->setPen(gridPen); for (int y = startY; y < endY; y += tileHeight) painter->drawLine(startX, y, endX - 1, y); } } void OrthogonalRenderer::drawTileLayer(QPainter *painter, const TileLayer *layer, const QRectF &exposed) const { const QTransform savedTransform = painter->transform(); const int tileWidth = map()->tileWidth(); const int tileHeight = map()->tileHeight(); const QPointF layerPos(layer->x() * tileWidth, layer->y() * tileHeight); painter->translate(layerPos); int startX = 0; int startY = 0; int endX = layer->width() - 1; int endY = layer->height() - 1; if (!exposed.isNull()) { QMargins drawMargins = layer->drawMargins(); drawMargins.setTop(drawMargins.top() - tileHeight); drawMargins.setRight(drawMargins.right() - tileWidth); QRectF rect = exposed.adjusted(-drawMargins.right(), -drawMargins.bottom(), drawMargins.left(), drawMargins.top()); rect.translate(-layerPos); startX = qMax(qFloor(rect.x() / tileWidth), 0); startY = qMax(qFloor(rect.y() / tileHeight), 0); endX = qMin(qCeil(rect.right()) / tileWidth, endX); endY = qMin(qCeil(rect.bottom()) / tileHeight, endY); } // Return immediately when there is nothing to draw if (startX > endX || startY > endY) return; CellRenderer renderer(painter); Map::RenderOrder renderOrder = map()->renderOrder(); int incX = 1, incY = 1; switch (renderOrder) { case Map::RightUp: std::swap(startY, endY); incY = -1; break; case Map::LeftDown: std::swap(startX, endX); incX = -1; break; case Map::LeftUp: std::swap(startX, endX); std::swap(startY, endY); incX = -1; incY = -1; break; case Map::RightDown: default: break; } endX += incX; endY += incY; for (int y = startY; y != endY; y += incY) { for (int x = startX; x != endX; x += incX) { const Cell &cell = layer->cellAt(x, y); if (cell.isEmpty()) continue; renderer.render(cell, QPointF(x * tileWidth, (y + 1) * tileHeight), QSizeF(0, 0), CellRenderer::BottomLeft); } } renderer.flush(); painter->setTransform(savedTransform); } void OrthogonalRenderer::drawTileSelection(QPainter *painter, const QRegion ®ion, const QColor &color, const QRectF &exposed) const { foreach (const QRect &r, region.rects()) { const QRectF toFill = QRectF(boundingRect(r)).intersected(exposed); if (!toFill.isEmpty()) painter->fillRect(toFill, color); } } void OrthogonalRenderer::drawMapObject(QPainter *painter, const MapObject *object, const QColor &color) const { painter->save(); const QRectF bounds = object->bounds(); QRectF rect(bounds); painter->translate(rect.topLeft()); rect.moveTopLeft(QPointF(0, 0)); const Cell &cell = object->cell(); if (!cell.isEmpty()) { CellRenderer(painter).render(cell, QPointF(), object->size(), CellRenderer::BottomLeft); if (testFlag(ShowTileObjectOutlines)) { const Tile *tile = cell.tile; const QSize imgSize = tile->size(); const QPointF tileOffset = tile->offset(); QRectF rect(QPointF(tileOffset.x(), tileOffset.y() - imgSize.height()), imgSize); QPen pen(Qt::SolidLine); pen.setCosmetic(true); painter->setPen(pen); painter->drawRect(rect); pen.setStyle(Qt::DotLine); pen.setColor(color); painter->setPen(pen); painter->drawRect(rect); } } else { const qreal lineWidth = objectLineWidth(); const qreal scale = painterScale(); const qreal shadowDist = (lineWidth == 0 ? 1 : lineWidth) / scale; const QPointF shadowOffset = QPointF(shadowDist * 0.5, shadowDist * 0.5); QPen linePen(color, lineWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); linePen.setCosmetic(true); QPen shadowPen(linePen); shadowPen.setColor(Qt::black); QColor brushColor = color; brushColor.setAlpha(50); const QBrush fillBrush(brushColor); painter->setRenderHint(QPainter::Antialiasing); // Trying to draw an ellipse with 0-width is causing a hang in // CoreGraphics when drawing the path requested by the // QCoreGraphicsPaintEngine. Draw them as rectangle instead. MapObject::Shape shape = object->shape(); if (shape == MapObject::Ellipse && ((rect.width() == qreal(0)) ^ (rect.height() == qreal(0)))) { shape = MapObject::Rectangle; } switch (shape) { case MapObject::Rectangle: { if (rect.isNull()) rect = QRectF(QPointF(-10, -10), QSizeF(20, 20)); // Draw the shadow painter->setPen(shadowPen); painter->drawRect(rect.translated(shadowOffset)); painter->setPen(linePen); painter->setBrush(fillBrush); painter->drawRect(rect); break; } case MapObject::Polyline: { QPolygonF screenPolygon = pixelToScreenCoords(object->polygon()); QPen thickShadowPen(shadowPen); QPen thickLinePen(linePen); thickShadowPen.setWidthF(thickShadowPen.widthF() * 4); thickLinePen.setWidthF(thickLinePen.widthF() * 4); painter->setPen(shadowPen); painter->drawPolyline(screenPolygon.translated(shadowOffset)); painter->setPen(thickShadowPen); painter->drawPoint(screenPolygon.first() + shadowOffset); painter->setPen(linePen); painter->setBrush(fillBrush); painter->drawPolyline(screenPolygon); painter->setPen(thickLinePen); painter->drawPoint(screenPolygon.first()); break; } case MapObject::Polygon: { QPolygonF screenPolygon = pixelToScreenCoords(object->polygon()); QPen thickShadowPen(shadowPen); QPen thickLinePen(linePen); thickShadowPen.setWidthF(thickShadowPen.widthF() * 4); thickLinePen.setWidthF(thickLinePen.widthF() * 4); painter->setPen(shadowPen); painter->drawPolygon(screenPolygon.translated(shadowOffset)); painter->setPen(thickShadowPen); painter->drawPoint(screenPolygon.first() + shadowOffset); painter->setPen(linePen); painter->setBrush(fillBrush); painter->drawPolygon(screenPolygon); painter->setPen(thickLinePen); painter->drawPoint(screenPolygon.first()); break; } case MapObject::Ellipse: { if (rect.isNull()) rect = QRectF(QPointF(-10, -10), QSizeF(20, 20)); // Draw the shadow painter->setPen(shadowPen); painter->drawEllipse(rect.translated(shadowOffset)); painter->setPen(linePen); painter->setBrush(fillBrush); painter->drawEllipse(rect); break; } } } painter->restore(); } QPointF OrthogonalRenderer::pixelToTileCoords(qreal x, qreal y) const { return QPointF(x / map()->tileWidth(), y / map()->tileHeight()); } QPointF OrthogonalRenderer::tileToPixelCoords(qreal x, qreal y) const { return QPointF(x * map()->tileWidth(), y * map()->tileHeight()); } QPointF OrthogonalRenderer::screenToTileCoords(qreal x, qreal y) const { return QPointF(x / map()->tileWidth(), y / map()->tileHeight()); } QPointF OrthogonalRenderer::tileToScreenCoords(qreal x, qreal y) const { return QPointF(x * map()->tileWidth(), y * map()->tileHeight()); } QPointF OrthogonalRenderer::screenToPixelCoords(qreal x, qreal y) const { return QPointF(x, y); } QPointF OrthogonalRenderer::pixelToScreenCoords(qreal x, qreal y) const { return QPointF(x, y); } tiled-0.14.2/src/libtiled/orthogonalrenderer.h000066400000000000000000000064161260670167100213470ustar00rootroot00000000000000/* * orthogonalrenderer.h * Copyright 2009-2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ORTHOGONALRENDERER_H #define ORTHOGONALRENDERER_H #include "maprenderer.h" namespace Tiled { /** * The orthogonal map renderer. This is the most basic map renderer, * dealing with maps that use rectangular tiles. */ class TILEDSHARED_EXPORT OrthogonalRenderer : public MapRenderer { public: OrthogonalRenderer(const Map *map) : MapRenderer(map) {} QSize mapSize() const override; QRect boundingRect(const QRect &rect) const override; QRectF boundingRect(const MapObject *object) const override; QPainterPath shape(const MapObject *object) const override; void drawGrid(QPainter *painter, const QRectF &rect, QColor gridColor) const override; void drawTileLayer(QPainter *painter, const TileLayer *layer, const QRectF &exposed = QRectF()) const override; void drawTileSelection(QPainter *painter, const QRegion ®ion, const QColor &color, const QRectF &exposed) const override; void drawMapObject(QPainter *painter, const MapObject *object, const QColor &color) const override; using MapRenderer::pixelToTileCoords; QPointF pixelToTileCoords(qreal x, qreal y) const override; using MapRenderer::tileToPixelCoords; QPointF tileToPixelCoords(qreal x, qreal y) const override; using MapRenderer::screenToTileCoords; QPointF screenToTileCoords(qreal x, qreal y) const override; using MapRenderer::tileToScreenCoords; QPointF tileToScreenCoords(qreal x, qreal y) const override; using MapRenderer::screenToPixelCoords; QPointF screenToPixelCoords(qreal x, qreal y) const override; using MapRenderer::pixelToScreenCoords; QPointF pixelToScreenCoords(qreal x, qreal y) const override; }; } // namespace Tiled #endif // ORTHOGONALRENDERER_H tiled-0.14.2/src/libtiled/plugin.cpp000066400000000000000000000034121260670167100172660ustar00rootroot00000000000000/* * plugin.cpp * Copyright 2015, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "plugin.h" #include "pluginmanager.h" namespace Tiled { /** * Convenience function that calls PluginManager::addObject. */ void Plugin::addObject(QObject *object) { PluginManager::addObject(object); } /** * Convenience function that calls PluginManager::removeObject. */ void Plugin::removeObject(QObject *object) { PluginManager::removeObject(object); } } // namespace Tiled tiled-0.14.2/src/libtiled/plugin.h000066400000000000000000000036771260670167100167500ustar00rootroot00000000000000/* * plugin.h * Copyright 2015, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TILED_PLUGIN_H #define TILED_PLUGIN_H #include "tiled_global.h" #include namespace Tiled { /** * @brief The interface to be implemented by Tiled plugins. * * This interface provides access to the extensions implemented by the plugin. */ class TILEDSHARED_EXPORT Plugin : public QObject { Q_OBJECT public: virtual void initialize() = 0; protected: static void addObject(QObject *object); static void removeObject(QObject *object); }; } // namespace Tiled Q_DECLARE_INTERFACE(Tiled::Plugin, "org.mapeditor.Plugin") #endif // TILED_PLUGIN_H tiled-0.14.2/src/libtiled/pluginmanager.cpp000066400000000000000000000101521260670167100206200ustar00rootroot00000000000000/* * pluginmanager.cpp * Copyright 2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pluginmanager.h" #include "mapformat.h" #include "plugin.h" #include #include #include #include #include namespace Tiled { PluginManager *PluginManager::mInstance; PluginManager::PluginManager() { } PluginManager::~PluginManager() { } PluginManager *PluginManager::instance() { if (!mInstance) mInstance = new PluginManager; return mInstance; } void PluginManager::deleteInstance() { delete mInstance; mInstance = nullptr; } void PluginManager::addObject(QObject *object) { Q_ASSERT(object); Q_ASSERT(mInstance); Q_ASSERT(!mInstance->mObjects.contains(object)); mInstance->mObjects.append(object); emit mInstance->objectAdded(object); } void PluginManager::removeObject(QObject *object) { Q_ASSERT(object); Q_ASSERT(mInstance); Q_ASSERT(mInstance->mObjects.contains(object)); emit mInstance->objectAboutToBeRemoved(object); mInstance->mObjects.removeOne(object); } void PluginManager::loadPlugins() { // Load static plugins foreach (QObject *instance, QPluginLoader::staticInstances()) { mPlugins.append(LoadedPlugin(QLatin1String(""), instance)); if (Plugin *plugin = qobject_cast(instance)) plugin->initialize(); else addObject(instance); } // Determine the plugin path based on the application location #ifndef TILED_PLUGIN_DIR QString pluginPath = QCoreApplication::applicationDirPath(); #endif #ifdef Q_OS_WIN32 pluginPath += QLatin1String("/plugins/tiled"); #elif defined(Q_OS_MAC) pluginPath += QLatin1String("/../PlugIns"); #elif defined(TILED_PLUGIN_DIR) QString pluginPath = QLatin1String(TILED_PLUGIN_DIR); #else pluginPath += QLatin1String("/../lib/tiled/plugins"); #endif // Load dynamic plugins QDirIterator iterator(pluginPath, QDir::Files | QDir::Readable); while (iterator.hasNext()) { const QString &pluginFile = iterator.next(); if (!QLibrary::isLibrary(pluginFile)) continue; QPluginLoader loader(pluginFile); QObject *instance = loader.instance(); if (!instance) { qWarning() << "Error:" << qPrintable(loader.errorString()); continue; } mPlugins.append(LoadedPlugin(pluginFile, instance)); if (Plugin *plugin = qobject_cast(instance)) plugin->initialize(); else addObject(instance); } } const LoadedPlugin *PluginManager::pluginByFileName(const QString &pluginFileName) const { foreach (const LoadedPlugin &plugin, mPlugins) if (pluginFileName == plugin.fileName) return &plugin; return nullptr; } } // namespace Tiled tiled-0.14.2/src/libtiled/pluginmanager.h000066400000000000000000000072061260670167100202730ustar00rootroot00000000000000/* * pluginmanager.h * Copyright 2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef PLUGINMANAGER_H #define PLUGINMANAGER_H #include "tiled_global.h" #include #include #include #include namespace Tiled { struct LoadedPlugin { LoadedPlugin(const QString &fileName, QObject *instance) : fileName(fileName) , instance(instance) {} QString fileName; QObject *instance; }; /** * The plugin manager loads the plugins and provides ways to access them. */ class TILEDSHARED_EXPORT PluginManager : public QObject { Q_OBJECT public: /** * Returns the plugin manager instance. */ static PluginManager *instance(); static void deleteInstance(); /** * Scans the plugin directory for plugins and attempts to load them. */ void loadPlugins(); /** * Returns the list of plugins found by the plugin manager. */ const QList &plugins() const { return mPlugins; } /** * Adds the given \a object. This allows the object to be found later based * on the interfaces it implements. */ static void addObject(QObject *object); /** * Removes the given \a object. */ static void removeObject(QObject *object); /** * Returns the list of objects that implement a given interface. */ template static QList objects() { QList results; for (QObject *object : mInstance->mObjects) if (T *result = qobject_cast(object)) results.append(result); return results; } /** * Calls the given function for each object implementing a given interface. */ template static void each(std::function function) { for (QObject *object : mInstance->mObjects) if (T *result = qobject_cast(object)) function(result); } const LoadedPlugin *pluginByFileName(const QString &pluginFileName) const; signals: void objectAdded(QObject *object); void objectAboutToBeRemoved(QObject *object); private: Q_DISABLE_COPY(PluginManager) PluginManager(); ~PluginManager(); static PluginManager *mInstance; QList mPlugins; QObjectList mObjects; }; } // namespace Tiled #endif // PLUGINMANAGER_H tiled-0.14.2/src/libtiled/properties.cpp000066400000000000000000000033251260670167100201670ustar00rootroot00000000000000/* * properties.cpp * Copyright 2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "properties.h" using namespace Tiled; void Properties::merge(const Properties &other) { // Based on QMap::unite, but using insert instead of insertMulti const_iterator it = other.constEnd(); const const_iterator b = other.constBegin(); while (it != b) { --it; insert(it.key(), it.value()); } } tiled-0.14.2/src/libtiled/properties.h000066400000000000000000000032421260670167100176320ustar00rootroot00000000000000/* * properties.h * Copyright 2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef PROPERTIES_H #define PROPERTIES_H #include "tiled_global.h" #include #include namespace Tiled { class TILEDSHARED_EXPORT Properties : public QMap { public: void merge(const Properties &other); }; } // namespace Tiled #endif // PROPERTIES_H tiled-0.14.2/src/libtiled/staggeredrenderer.cpp000066400000000000000000000062221260670167100214660ustar00rootroot00000000000000/* * staggeredrenderer.cpp * Copyright 2011-2014, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "staggeredrenderer.h" #include using namespace Tiled; /** * Converts screen to tile coordinates. Sub-tile return values are not * supported by this renderer. * * This override exists because the method used by the HexagonalRenderer * does not produce nice results for isometric shapes in the tile corners. */ QPointF StaggeredRenderer::screenToTileCoords(qreal x, qreal y) const { const RenderParams p(map()); if (p.staggerX) x -= p.staggerEven ? p.sideOffsetX : 0; else y -= p.staggerEven ? p.sideOffsetY : 0; // Start with the coordinates of a grid-aligned tile QPoint referencePoint = QPoint(qFloor(x / p.tileWidth), qFloor(y / p.tileHeight)); // Relative x and y position on the base square of the grid-aligned tile const QPointF rel(x - referencePoint.x() * p.tileWidth, y - referencePoint.y() * p.tileHeight); // Adjust the reference point to the correct tile coordinates int &staggerAxisIndex = p.staggerX ? referencePoint.rx() : referencePoint.ry(); staggerAxisIndex *= 2; if (p.staggerEven) ++staggerAxisIndex; const qreal y_pos = rel.x() * ((qreal) p.tileHeight / p.tileWidth); // Check whether the cursor is in any of the corners (neighboring tiles) if (p.sideOffsetY - y_pos > rel.y()) return topLeft(referencePoint.x(), referencePoint.y()); if (-p.sideOffsetY + y_pos > rel.y()) return topRight(referencePoint.x(), referencePoint.y()); if (p.sideOffsetY + y_pos < rel.y()) return bottomLeft(referencePoint.x(), referencePoint.y()); if (p.sideOffsetY * 3 - y_pos < rel.y()) return bottomRight(referencePoint.x(), referencePoint.y()); return referencePoint; } tiled-0.14.2/src/libtiled/staggeredrenderer.h000066400000000000000000000062471260670167100211420ustar00rootroot00000000000000/* * staggeredrenderer.h * Copyright 2011-2014, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef STAGGEREDRENDERER_H #define STAGGEREDRENDERER_H #include "hexagonalrenderer.h" namespace Tiled { /** * A staggered isometric renderer. * * This renderer is meant to be used with isometric tiles, but rather than * doing a true isometric projection the tiles are shifted in order to fit * together. This has the advantage that the map has a rectangular shape. * * Only one variation of staggered map rendering is supported at the moment, * namely shifting the uneven rows to the right. * * Objects are handled the same way as the OrthogonalRenderer, though they * snap at half the tile width and height. * * At the moment, several Tiled features will not work correctly with this * renderer. This is due to the way the shifting messes with the coordinate * system. List of known issues: * * Fill tool: * * Doesn't work properly cause its assumptions about neighboring are * broken by this renderer. * * Stamp tool: * * A stamp only makes sense if it's placed at an even y offset from * where it was created. When moved by an uneven y offset, the rows * that are shifted swap, messing up the stamp. * * The circle and line drawing modes of the stamp tool won't work * properly due to the irregular coordinate system. * * Rectangular select tool: * * This one will appear to behave somewhat erratic. * * Map resize and offset actions: * * Similar problem as with stamps when offsetting at an uneven y offset. * */ class TILEDSHARED_EXPORT StaggeredRenderer : public HexagonalRenderer { public: StaggeredRenderer(const Map *map) : HexagonalRenderer(map) {} using HexagonalRenderer::screenToTileCoords; QPointF screenToTileCoords(qreal x, qreal y) const override; }; } // namespace Tiled #endif // STAGGEREDRENDERER_H tiled-0.14.2/src/libtiled/terrain.h000066400000000000000000000105721260670167100171060ustar00rootroot00000000000000/* * terrain.h * Copyright 2012, Manu Evans * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TERRAIN_H #define TERRAIN_H #include "object.h" #include "tileset.h" #include #include #include namespace Tiled { /** * Represents a terrain type. */ class TILEDSHARED_EXPORT Terrain : public Object { public: Terrain(int id, Tileset *tileset, QString name, int imageTileId): Object(TerrainType), mId(id), mTileset(tileset), mName(name), mImageTileId(imageTileId) { } int id() const; Tileset *tileset() const; QSharedPointer sharedTileset() const; QString name() const; void setName(const QString &name); int imageTileId() const; void setImageTileId(int imageTileId); Tile *imageTile() const; int transitionDistance(int targetTerrainType) const; void setTransitionDistance(int targetTerrainType, int distance); void setTransitionDistances(const QVector &transitionDistances); private: int mId; Tileset *mTileset; QString mName; int mImageTileId; QVector mTransitionDistance; friend class Tileset; // To allow changing the terrain id }; /** * Returns ID of this terrain type. */ inline int Terrain::id() const { return mId; } /** * Returns the tileset this terrain type belongs to. */ inline Tileset *Terrain::tileset() const { return mTileset; } /** * Returns the tileset this terrain type belongs to as a shared pointer. */ inline QSharedPointer Terrain::sharedTileset() const { return mTileset->sharedPointer(); } /** * Returns the name of this terrain type. */ inline QString Terrain::name() const { return mName; } /** * Sets the name of this terrain type. */ inline void Terrain::setName(const QString &name) { mName = name; } /** * Returns the index of the tile that visually represents this terrain type. */ inline int Terrain::imageTileId() const { return mImageTileId; } /** * Sets the index of the tile that visually represents this terrain type. */ inline void Terrain::setImageTileId(int imageTileId) { mImageTileId = imageTileId; } /** * Returns a Tile that represents this terrain type in the terrain palette. */ inline Tile *Terrain::imageTile() const { return mImageTileId >= 0 ? mTileset->tileAt(mImageTileId) : nullptr; } /** * Returns the transition penalty(/distance) from this terrain type to another terrain type. */ inline int Terrain::transitionDistance(int targetTerrainType) const { return mTransitionDistance[targetTerrainType + 1]; } /** * Sets the transition penalty(/distance) from this terrain type to another terrain type. */ inline void Terrain::setTransitionDistance(int targetTerrainType, int distance) { mTransitionDistance[targetTerrainType + 1] = distance; } /** * Returns the array of terrain penalties(/distances). */ inline void Terrain::setTransitionDistances(const QVector &transitionDistances) { mTransitionDistance = transitionDistances; } } // namespace Tiled Q_DECLARE_METATYPE(Tiled::Terrain*) #endif // TERRAIN_H tiled-0.14.2/src/libtiled/tile.cpp000066400000000000000000000113421260670167100167260ustar00rootroot00000000000000/* * tile.cpp * Copyright 2012-2014, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tile.h" #include "objectgroup.h" #include "tileset.h" using namespace Tiled; Tile::Tile(const QPixmap &image, int id, Tileset *tileset): Object(TileType), mId(id), mTileset(tileset), mImage(image), mTerrain(-1), mProbability(1.f), mObjectGroup(nullptr), mCurrentFrameIndex(0), mUnusedTime(0) {} Tile::Tile(const QPixmap &image, const QString &imageSource, int id, Tileset *tileset): Object(TileType), mId(id), mTileset(tileset), mImage(image), mImageSource(imageSource), mTerrain(-1), mProbability(1.f), mObjectGroup(nullptr), mCurrentFrameIndex(0), mUnusedTime(0) {} Tile::~Tile() { delete mObjectGroup; } /** * Returns the tileset that this tile is part of as a shared pointer. */ QSharedPointer Tile::sharedTileset() const { return mTileset->sharedPointer(); } /** * Returns the image for rendering this tile, taking into account tile * animations. */ const QPixmap &Tile::currentFrameImage() const { if (isAnimated()) { const Frame &frame = mFrames.at(mCurrentFrameIndex); return mTileset->tileAt(frame.tileId)->image(); } else { return mImage; } } /** * Returns the drawing offset of the tile (in pixels). */ QPoint Tile::offset() const { return mTileset->tileOffset(); } /** * Returns the Terrain of a given corner. */ Terrain *Tile::terrainAtCorner(int corner) const { return mTileset->terrain(cornerTerrainId(corner)); } /** * Set the terrain for each corner of the tile. */ void Tile::setTerrain(unsigned terrain) { if (mTerrain == terrain) return; mTerrain = terrain; mTileset->markTerrainDistancesDirty(); } /** * Sets \a objectGroup to be the group of objects associated with this tile. * The Tile takes ownership over the ObjectGroup and it can't also be part of * a map. */ void Tile::setObjectGroup(ObjectGroup *objectGroup) { Q_ASSERT(!objectGroup || !objectGroup->map()); if (mObjectGroup == objectGroup) return; delete mObjectGroup; mObjectGroup = objectGroup; } /** * Swaps the object group of this tile with \a objectGroup. The tile releases * ownership over its existing object group and takes ownership over the new * one. * * @return The previous object group referenced by this tile. */ ObjectGroup *Tile::swapObjectGroup(ObjectGroup *objectGroup) { ObjectGroup *previousObjectGroup = mObjectGroup; mObjectGroup = objectGroup; return previousObjectGroup; } /** * Sets the animation frames to be used by this tile. Resets any currently * running animation. */ void Tile::setFrames(const QVector &frames) { mFrames = frames; mCurrentFrameIndex = 0; mUnusedTime = 0; } /** * Advances this tile animation by the given amount of milliseconds. Returns * whether this caused the current tileId to change. */ bool Tile::advanceAnimation(int ms) { if (!isAnimated()) return false; mUnusedTime += ms; Frame frame = mFrames.at(mCurrentFrameIndex); const int previousTileId = frame.tileId; while (frame.duration > 0 && mUnusedTime > frame.duration) { mUnusedTime -= frame.duration; mCurrentFrameIndex = (mCurrentFrameIndex + 1) % mFrames.size(); frame = mFrames.at(mCurrentFrameIndex); } return previousTileId != frame.tileId; } tiled-0.14.2/src/libtiled/tile.h000066400000000000000000000137241260670167100164010ustar00rootroot00000000000000/* * tile.h * Copyright 2008-2014, Thorbjørn Lindeijer * Copyright 2009, Edward Hutchins * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TILE_H #define TILE_H #include "object.h" #include #include namespace Tiled { class ObjectGroup; class Terrain; class Tileset; /** * Returns the given \a terrain with the \a corner modified to \a terrainId. */ inline unsigned setTerrainCorner(unsigned terrain, int corner, int terrainId) { unsigned mask = 0xFF << (3 - corner) * 8; unsigned insert = terrainId << (3 - corner) * 8; return (terrain & ~mask) | (insert & mask); } /** * A single frame of an animated tile. */ struct Frame { int tileId; int duration; }; class TILEDSHARED_EXPORT Tile : public Object { public: Tile(const QPixmap &image, int id, Tileset *tileset); Tile(const QPixmap &image, const QString &imageSource, int id, Tileset *tileset); ~Tile(); int id() const; Tileset *tileset() const; QSharedPointer sharedTileset() const; const QPixmap &image() const; void setImage(const QPixmap &image); const QPixmap ¤tFrameImage() const; const QString &imageSource() const; void setImageSource(const QString &imageSource); int width() const; int height() const; QSize size() const; QPoint offset() const; Terrain *terrainAtCorner(int corner) const; int cornerTerrainId(int corner) const; void setCornerTerrainId(int corner, int terrainId); inline unsigned terrain() const; void setTerrain(unsigned terrain); float probability() const; void setProbability(float probability); ObjectGroup *objectGroup() const; void setObjectGroup(ObjectGroup *objectGroup); ObjectGroup *swapObjectGroup(ObjectGroup *objectGroup); const QVector &frames() const; void setFrames(const QVector &frames); bool isAnimated() const; int currentFrameIndex() const; bool advanceAnimation(int ms); private: int mId; Tileset *mTileset; QPixmap mImage; QString mImageSource; unsigned mTerrain; float mProbability; ObjectGroup *mObjectGroup; QVector mFrames; int mCurrentFrameIndex; int mUnusedTime; friend class Tileset; // To allow changing the tile id }; /** * Returns ID of this tile within its tileset. */ inline int Tile::id() const { return mId; } /** * Returns the tileset that this tile is part of. */ inline Tileset *Tile::tileset() const { return mTileset; } /** * Returns the image of this tile. */ inline const QPixmap &Tile::image() const { return mImage; } /** * Sets the image of this tile. */ inline void Tile::setImage(const QPixmap &image) { mImage = image; } /** * Returns the file name of the external image that represents this tile. * When this tile doesn't refer to an external image, an empty string is * returned. */ inline const QString &Tile::imageSource() const { return mImageSource; } inline void Tile::setImageSource(const QString &imageSource) { mImageSource = imageSource; } /** * Returns the width of this tile. */ inline int Tile::width() const { return mImage.width(); } /** * Returns the height of this tile. */ inline int Tile::height() const { return mImage.height(); } /** * Returns the size of this tile. */ inline QSize Tile::size() const { return mImage.size(); } /** * Returns the terrain id at a given corner. */ inline int Tile::cornerTerrainId(int corner) const { unsigned t = (terrain() >> (3 - corner)*8) & 0xFF; return t == 0xFF ? -1 : (int)t; } /** * Set the terrain type of a given corner. */ inline void Tile::setCornerTerrainId(int corner, int terrainId) { setTerrain(setTerrainCorner(mTerrain, corner, terrainId)); } /** * Returns the terrain for each corner of this tile. */ inline unsigned Tile::terrain() const { return mTerrain; } /** * Returns the relative probability of this tile appearing while painting. */ inline float Tile::probability() const { return mProbability; } /** * Set the relative probability of this tile appearing while painting. */ inline void Tile::setProbability(float probability) { mProbability = probability; } /** * @return The group of objects associated with this tile. This is generally * expected to be used for editing collision shapes. */ inline ObjectGroup *Tile::objectGroup() const { return mObjectGroup; } inline const QVector &Tile::frames() const { return mFrames; } inline bool Tile::isAnimated() const { return !mFrames.isEmpty(); } inline int Tile::currentFrameIndex() const { return mCurrentFrameIndex; } } // namespace Tiled #endif // TILE_H tiled-0.14.2/src/libtiled/tiled.h000066400000000000000000000035371260670167100165460ustar00rootroot00000000000000/* * tiled.h * Copyright 2013, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TILED_H #define TILED_H namespace Tiled { enum FlipDirection { FlipHorizontally, FlipVertically }; enum RotateDirection { RotateLeft, RotateRight }; enum Alignment { TopLeft, Top, TopRight, Left, Center, Right, BottomLeft, Bottom, BottomRight }; static const char TILES_MIMETYPE[] = "application/vnd.tile.list"; static const char FRAMES_MIMETYPE[] = "application/vnd.frame.list"; } // namespace Tiled #endif // TILED_H tiled-0.14.2/src/libtiled/tiled_global.h000066400000000000000000000031441260670167100200600ustar00rootroot00000000000000/* * tiled_global.h * Copyright 2010, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TILED_GLOBAL_H #define TILED_GLOBAL_H #include #if defined(TILED_LIBRARY) # define TILEDSHARED_EXPORT Q_DECL_EXPORT #else # define TILEDSHARED_EXPORT Q_DECL_IMPORT #endif #endif // TILED_GLOBAL_H tiled-0.14.2/src/libtiled/tilelayer.cpp000066400000000000000000000325721260670167100177730ustar00rootroot00000000000000/* * tilelayer.cpp * Copyright 2008-2011, Thorbjørn Lindeijer * Copyright 2009, Jeff Bland * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tilelayer.h" #include "map.h" #include "tile.h" using namespace Tiled; TileLayer::TileLayer(const QString &name, int x, int y, int width, int height): Layer(TileLayerType, name, x, y, width, height), mMaxTileSize(0, 0), mGrid(width * height) { Q_ASSERT(width >= 0); Q_ASSERT(height >= 0); } static QSize maxSize(const QSize &a, const QSize &b) { return QSize(qMax(a.width(), b.width()), qMax(a.height(), b.height())); } static QMargins maxMargins(const QMargins &a, const QMargins &b) { return QMargins(qMax(a.left(), b.left()), qMax(a.top(), b.top()), qMax(a.right(), b.right()), qMax(a.bottom(), b.bottom())); } /** * Recomputes the draw margins. Needed after the tile offset of a tileset * has changed for example. * * Generally you want to call Map::recomputeDrawMargins instead. */ void TileLayer::recomputeDrawMargins() { QSize maxTileSize(0, 0); QMargins offsetMargins; for (int i = 0, i_end = mGrid.size(); i < i_end; ++i) { const Cell &cell = mGrid.at(i); if (const Tile *tile = cell.tile) { QSize size = tile->size(); if (cell.flippedAntiDiagonally) size.transpose(); const QPoint offset = tile->offset(); maxTileSize = maxSize(size, maxTileSize); offsetMargins = maxMargins(QMargins(-offset.x(), -offset.y(), offset.x(), offset.y()), offsetMargins); } } mMaxTileSize = maxTileSize; mOffsetMargins = offsetMargins; if (mMap) mMap->adjustDrawMargins(drawMargins()); } void TileLayer::setCell(int x, int y, const Cell &cell) { Q_ASSERT(contains(x, y)); if (cell.tile) { QSize size = cell.tile->size(); if (cell.flippedAntiDiagonally) size.transpose(); const QPoint offset = cell.tile->offset(); mMaxTileSize = maxSize(size, mMaxTileSize); mOffsetMargins = maxMargins(QMargins(-offset.x(), -offset.y(), offset.x(), offset.y()), mOffsetMargins); if (mMap) mMap->adjustDrawMargins(drawMargins()); } mGrid[x + y * mWidth] = cell; } TileLayer *TileLayer::copy(const QRegion ®ion) const { const QRegion area = region.intersected(QRect(0, 0, width(), height())); const QRect bounds = region.boundingRect(); const QRect areaBounds = area.boundingRect(); const int offsetX = qMax(0, areaBounds.x() - bounds.x()); const int offsetY = qMax(0, areaBounds.y() - bounds.y()); TileLayer *copied = new TileLayer(QString(), 0, 0, bounds.width(), bounds.height()); for (const QRect &rect : area.rects()) for (int x = rect.left(); x <= rect.right(); ++x) for (int y = rect.top(); y <= rect.bottom(); ++y) copied->setCell(x - areaBounds.x() + offsetX, y - areaBounds.y() + offsetY, cellAt(x, y)); return copied; } void TileLayer::merge(const QPoint &pos, const TileLayer *layer) { // Determine the overlapping area QRect area = QRect(pos, QSize(layer->width(), layer->height())); area &= QRect(0, 0, width(), height()); for (int y = area.top(); y <= area.bottom(); ++y) { for (int x = area.left(); x <= area.right(); ++x) { const Cell &cell = layer->cellAt(x - pos.x(), y - pos.y()); if (!cell.isEmpty()) setCell(x, y, cell); } } } void TileLayer::setCells(int x, int y, TileLayer *layer, const QRegion &mask) { // Determine the overlapping area QRegion area = QRect(x, y, layer->width(), layer->height()); area &= QRect(0, 0, width(), height()); if (!mask.isEmpty()) area &= mask; for (const QRect &rect : area.rects()) for (int _x = rect.left(); _x <= rect.right(); ++_x) for (int _y = rect.top(); _y <= rect.bottom(); ++_y) setCell(_x, _y, layer->cellAt(_x - x, _y - y)); } void TileLayer::erase(const QRegion &area) { const Cell emptyCell; for (const QRect &rect : area.rects()) for (int x = rect.left(); x <= rect.right(); ++x) for (int y = rect.top(); y <= rect.bottom(); ++y) setCell(x, y, emptyCell); } void TileLayer::flip(FlipDirection direction) { QVector newGrid(mWidth * mHeight); Q_ASSERT(direction == FlipHorizontally || direction == FlipVertically); for (int y = 0; y < mHeight; ++y) { for (int x = 0; x < mWidth; ++x) { Cell &dest = newGrid[x + y * mWidth]; if (direction == FlipHorizontally) { const Cell &source = cellAt(mWidth - x - 1, y); dest = source; dest.flippedHorizontally = !source.flippedHorizontally; } else if (direction == FlipVertically) { const Cell &source = cellAt(x, mHeight - y - 1); dest = source; dest.flippedVertically = !source.flippedVertically; } } } mGrid = newGrid; } void TileLayer::rotate(RotateDirection direction) { static const char rotateRightMask[8] = { 5, 4, 1, 0, 7, 6, 3, 2 }; static const char rotateLeftMask[8] = { 3, 2, 7, 6, 1, 0, 5, 4 }; const char (&rotateMask)[8] = (direction == RotateRight) ? rotateRightMask : rotateLeftMask; int newWidth = mHeight; int newHeight = mWidth; QVector newGrid(newWidth * newHeight); for (int y = 0; y < mHeight; ++y) { for (int x = 0; x < mWidth; ++x) { const Cell &source = cellAt(x, y); Cell dest = source; unsigned char mask = (dest.flippedHorizontally << 2) | (dest.flippedVertically << 1) | (dest.flippedAntiDiagonally << 0); mask = rotateMask[mask]; dest.flippedHorizontally = (mask & 4) != 0; dest.flippedVertically = (mask & 2) != 0; dest.flippedAntiDiagonally = (mask & 1) != 0; if (direction == RotateRight) newGrid[x * newWidth + (mHeight - y - 1)] = dest; else newGrid[(mWidth - x - 1) * newWidth + y] = dest; } } std::swap(mMaxTileSize.rwidth(), mMaxTileSize.rheight()); mWidth = newWidth; mHeight = newHeight; mGrid = newGrid; } QSet TileLayer::usedTilesets() const { QSet tilesets; for (int i = 0, i_end = mGrid.size(); i < i_end; ++i) if (const Tile *tile = mGrid.at(i).tile) tilesets.insert(tile->sharedTileset()); return tilesets; } bool TileLayer::referencesTileset(const Tileset *tileset) const { for (int i = 0, i_end = mGrid.size(); i < i_end; ++i) { const Tile *tile = mGrid.at(i).tile; if (tile && tile->tileset() == tileset) return true; } return false; } void TileLayer::removeReferencesToTileset(Tileset *tileset) { for (int i = 0, i_end = mGrid.size(); i < i_end; ++i) { const Tile *tile = mGrid.at(i).tile; if (tile && tile->tileset() == tileset) mGrid.replace(i, Cell()); } } void TileLayer::replaceReferencesToTileset(Tileset *oldTileset, Tileset *newTileset) { for (int i = 0, i_end = mGrid.size(); i < i_end; ++i) { const Tile *tile = mGrid.at(i).tile; if (tile && tile->tileset() == oldTileset) mGrid[i].tile = newTileset->tileAt(tile->id()); } } void TileLayer::resize(const QSize &size, const QPoint &offset) { if (this->size() == size && offset.isNull()) return; QVector newGrid(size.width() * size.height()); // Copy over the preserved part const int startX = qMax(0, -offset.x()); const int startY = qMax(0, -offset.y()); const int endX = qMin(mWidth, size.width() - offset.x()); const int endY = qMin(mHeight, size.height() - offset.y()); for (int y = startY; y < endY; ++y) { for (int x = startX; x < endX; ++x) { const int index = x + offset.x() + (y + offset.y()) * size.width(); newGrid[index] = cellAt(x, y); } } mGrid = newGrid; setSize(size); } void TileLayer::offsetTiles(const QPoint &offset, const QRect &bounds, bool wrapX, bool wrapY) { QVector newGrid(mWidth * mHeight); for (int y = 0; y < mHeight; ++y) { for (int x = 0; x < mWidth; ++x) { // Skip out of bounds tiles if (!bounds.contains(x, y)) { newGrid[x + y * mWidth] = cellAt(x, y); continue; } // Get position to pull tile value from int oldX = x - offset.x(); int oldY = y - offset.y(); // Wrap x value that will be pulled from if (wrapX && bounds.width() > 0) { while (oldX < bounds.left()) oldX += bounds.width(); while (oldX > bounds.right()) oldX -= bounds.width(); } // Wrap y value that will be pulled from if (wrapY && bounds.height() > 0) { while (oldY < bounds.top()) oldY += bounds.height(); while (oldY > bounds.bottom()) oldY -= bounds.height(); } // Set the new tile if (contains(oldX, oldY) && bounds.contains(oldX, oldY)) newGrid[x + y * mWidth] = cellAt(oldX, oldY); else newGrid[x + y * mWidth] = Cell(); } } mGrid = newGrid; } bool TileLayer::canMergeWith(Layer *other) const { return other->isTileLayer(); } Layer *TileLayer::mergedWith(Layer *other) const { Q_ASSERT(canMergeWith(other)); const TileLayer *o = static_cast(other); const QRect unitedBounds = bounds().united(o->bounds()); const QPoint offset = position() - unitedBounds.topLeft(); TileLayer *merged = static_cast(clone()); merged->resize(unitedBounds.size(), offset); merged->merge(o->position() - unitedBounds.topLeft(), o); return merged; } QRegion TileLayer::computeDiffRegion(const TileLayer *other) const { QRegion ret; const int dx = other->x() - mX; const int dy = other->y() - mY; QRect r = QRect(0, 0, width(), height()); r &= QRect(dx, dy, other->width(), other->height()); for (int y = r.top(); y <= r.bottom(); ++y) { for (int x = r.left(); x <= r.right(); ++x) { if (cellAt(x, y) != other->cellAt(x - dx, y - dy)) { const int rangeStart = x; while (x <= r.right() && cellAt(x, y) != other->cellAt(x - dx, y - dy)) { ++x; } const int rangeEnd = x; ret += QRect(rangeStart, y, rangeEnd - rangeStart, 1); } } } return ret; } bool TileLayer::isEmpty() const { for (int i = 0, i_end = mGrid.size(); i < i_end; ++i) if (!mGrid.at(i).isEmpty()) return false; return true; } /** * Returns a duplicate of this TileLayer. * * \sa Layer::clone() */ Layer *TileLayer::clone() const { return initializeClone(new TileLayer(mName, mX, mY, mWidth, mHeight)); } TileLayer *TileLayer::initializeClone(TileLayer *clone) const { Layer::initializeClone(clone); clone->mGrid = mGrid; clone->mMaxTileSize = mMaxTileSize; clone->mOffsetMargins = mOffsetMargins; return clone; } tiled-0.14.2/src/libtiled/tilelayer.h000066400000000000000000000240351260670167100174330ustar00rootroot00000000000000/* * tilelayer.h * Copyright 2008-2011, Thorbjørn Lindeijer * Copyright 2009, Jeff Bland * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TILELAYER_H #define TILELAYER_H #include "tiled_global.h" #include "layer.h" #include "tiled.h" #include #include #include #include namespace Tiled { class Tile; /** * A cell on a tile layer grid. */ class Cell { public: Cell() : tile(nullptr), flippedHorizontally(false), flippedVertically(false), flippedAntiDiagonally(false) {} explicit Cell(Tile *tile) : tile(tile), flippedHorizontally(false), flippedVertically(false), flippedAntiDiagonally(false) {} bool isEmpty() const { return tile == nullptr; } bool operator == (const Cell &other) const { return tile == other.tile && flippedHorizontally == other.flippedHorizontally && flippedVertically == other.flippedVertically && flippedAntiDiagonally == other.flippedAntiDiagonally; } bool operator != (const Cell &other) const { return tile != other.tile || flippedHorizontally != other.flippedHorizontally || flippedVertically != other.flippedVertically || flippedAntiDiagonally != other.flippedAntiDiagonally; } Tile *tile; bool flippedHorizontally; bool flippedVertically; bool flippedAntiDiagonally; }; /** * A tile layer is a grid of cells. Each cell refers to a specific tile, and * stores how the tile is flipped. * * Coordinates and regions passed to function parameters are in local * coordinates and do not take into account the position of the layer. */ class TILEDSHARED_EXPORT TileLayer : public Layer { public: /** * Constructor. */ TileLayer(const QString &name, int x, int y, int width, int height); /** * Returns the maximum tile size of this layer. */ QSize maxTileSize() const { return mMaxTileSize; } /** * Returns the margins that have to be taken into account while drawing * this tile layer. The margins depend on the maximum tile size and the * offset applied to the tiles. */ QMargins drawMargins() const { return QMargins(mOffsetMargins.left(), mOffsetMargins.top() + mMaxTileSize.height(), mOffsetMargins.right() + mMaxTileSize.width(), mOffsetMargins.bottom()); } void recomputeDrawMargins(); /** * Returns whether (x, y) is inside this map layer. */ bool contains(int x, int y) const { return x >= 0 && y >= 0 && x < mWidth && y < mHeight; } bool contains(const QPoint &point) const { return contains(point.x(), point.y()); } /** * Calculates the region of cells in this tile layer for which the given * \a condition returns true. */ template QRegion region(Condition condition) const; /** * Calculates the region occupied by the tiles of this layer. Similar to * Layer::bounds(), but leaves out the regions without tiles. */ QRegion region() const; /** * Returns a read-only reference to the cell at the given coordinates. The * coordinates have to be within this layer. */ const Cell &cellAt(int x, int y) const; const Cell &cellAt(const QPoint &point) const; /** * Sets the cell at the given coordinates. */ void setCell(int x, int y, const Cell &cell); /** * Returns a copy of the area specified by the given \a region. The * caller is responsible for the returned tile layer. */ TileLayer *copy(const QRegion ®ion) const; TileLayer *copy(int x, int y, int width, int height) const { return copy(QRegion(x, y, width, height)); } /** * Merges the given \a layer onto this layer at position \a pos. Parts that * fall outside of this layer will be lost and empty tiles in the given * layer will have no effect. */ void merge(const QPoint &pos, const TileLayer *layer); /** * Removes all cells in the specified region. */ void erase(const QRegion ®ion); /** * Sets the cells starting at the given position to the cells in the given * \a tileLayer. Parts that fall outside of this layer will be ignored. * * When a \a mask is given, only cells that fall within this mask are set. * The mask is applied in local coordinates. */ void setCells(int x, int y, TileLayer *tileLayer, const QRegion &mask = QRegion()); /** * Flip this tile layer in the given \a direction. Direction must be * horizontal or vertical. This doesn't change the dimensions of the * tile layer. */ void flip(FlipDirection direction); /** * Rotate this tile layer by 90 degrees left or right. The tile positions * are rotated within the layer, and the tiles themselves are rotated. The * dimensions of the tile layer are swapped. */ void rotate(RotateDirection direction); /** * Computes and returns the set of tilesets used by this tile layer. */ QSet usedTilesets() const override; /** * Returns whether this tile layer has any cell for which the given * \a condition returns true. */ template bool hasCell(Condition condition) const; /** * Returns whether this tile layer is referencing the given tileset. */ bool referencesTileset(const Tileset *tileset) const override; /** * Removes all references to the given tileset. This sets all tiles on this * layer that are from the given tileset to null. */ void removeReferencesToTileset(Tileset *tileset); /** * Replaces all tiles from \a oldTileset with tiles from \a newTileset. */ void replaceReferencesToTileset(Tileset *oldTileset, Tileset *newTileset) override; /** * Resizes this tile layer to \a size, while shifting all tiles by * \a offset. */ void resize(const QSize &size, const QPoint &offset); /** * Offsets the tiles in this layer within \a bounds by \a offset, * and optionally wraps them. * * \sa ObjectGroup::offsetObjects() */ void offsetTiles(const QPoint &offset, const QRect &bounds, bool wrapX, bool wrapY); bool canMergeWith(Layer *other) const override; Layer *mergedWith(Layer *other) const override; /** * Returns the region where this tile layer and the given tile layer * are different. The relative positions of the layers are taken into * account. The returned region is relative to this tile layer. */ QRegion computeDiffRegion(const TileLayer *other) const; /** * Returns true if all tiles in the layer are empty. */ bool isEmpty() const override; virtual Layer *clone() const override; // Enable easy iteration over cells with range-based for QVector::iterator begin() { return mGrid.begin(); } QVector::iterator end() { return mGrid.end(); } QVector::const_iterator begin() const { return mGrid.begin(); } QVector::const_iterator end() const { return mGrid.end(); } protected: TileLayer *initializeClone(TileLayer *clone) const; private: QSize mMaxTileSize; QMargins mOffsetMargins; QVector mGrid; }; template QRegion TileLayer::region(Condition condition) const { QRegion region; for (int y = 0; y < mHeight; ++y) { for (int x = 0; x < mWidth; ++x) { if (condition(cellAt(x, y))) { const int rangeStart = x; for (++x; x <= mWidth; ++x) { if (x == mWidth || !condition(cellAt(x, y))) { const int rangeEnd = x; region += QRect(rangeStart + mX, y + mY, rangeEnd - rangeStart, 1); break; } } } } } return region; } template bool TileLayer::hasCell(Condition condition) const { for (const Cell &cell : mGrid) if (condition(cell)) return true; return false; } inline QRegion TileLayer::region() const { return region([] (const Cell &cell) { return !cell.isEmpty(); }); } inline const Cell &TileLayer::cellAt(int x, int y) const { Q_ASSERT(contains(x, y)); return mGrid.at(x + y * mWidth); } inline const Cell &TileLayer::cellAt(const QPoint &point) const { return cellAt(point.x(), point.y()); } typedef QSharedPointer SharedTileLayer; } // namespace Tiled #endif // TILELAYER_H tiled-0.14.2/src/libtiled/tileset.cpp000066400000000000000000000327211260670167100174460ustar00rootroot00000000000000/* * tileset.cpp * Copyright 2008-2015, Thorbjørn Lindeijer * Copyright 2009, Edward Hutchins * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tileset.h" #include "tile.h" #include "terrain.h" #include using namespace Tiled; Tileset::~Tileset() { qDeleteAll(mTiles); qDeleteAll(mTerrainTypes); } Tile *Tileset::tileAt(int id) const { return (id < mTiles.size()) ? mTiles.at(id) : nullptr; } /** * Load this tileset from the given tileset \a image. This will replace * existing tile images in this tileset with new ones. If the new image * contains more tiles than exist in the tileset new tiles will be * appended, if there are fewer tiles the excess images will be blanked. * * The tile width and height of this tileset must be higher than 0. * * @param image the image to load the tiles from * @param fileName the file name of the image, which will be remembered * as the image source of this tileset. * @return true if loading was successful, otherwise * returns false */ bool Tileset::loadFromImage(const QImage &image, const QString &fileName) { const QSize tileSize = this->tileSize(); const int margin = this->margin(); const int spacing = this->tileSpacing(); Q_ASSERT(tileSize.width() > 0 && tileSize.height() > 0); if (image.isNull()) return false; const int stopWidth = image.width() - tileSize.width(); const int stopHeight = image.height() - tileSize.height(); int oldTilesetSize = tileCount(); int tileNum = 0; for (int y = margin; y <= stopHeight; y += tileSize.height() + spacing) { for (int x = margin; x <= stopWidth; x += tileSize.width() + spacing) { const QImage tileImage = image.copy(x, y, tileSize.width(), tileSize.height()); QPixmap tilePixmap = QPixmap::fromImage(tileImage); if (mTransparentColor.isValid()) { const QImage mask = tileImage.createMaskFromColor(mTransparentColor.rgb()); tilePixmap.setMask(QBitmap::fromImage(mask)); } if (tileNum < oldTilesetSize) { mTiles.at(tileNum)->setImage(tilePixmap); } else { mTiles.append(new Tile(tilePixmap, tileNum, this)); } ++tileNum; } } // Blank out any remaining tiles to avoid confusion while (tileNum < oldTilesetSize) { QPixmap tilePixmap = QPixmap(tileSize); tilePixmap.fill(); mTiles.at(tileNum)->setImage(tilePixmap); ++tileNum; } mImageWidth = image.width(); mImageHeight = image.height(); mColumnCount = columnCountForWidth(mImageWidth); mImageSource = fileName; return true; } static bool sameTileImages(const Tileset &a, const Tileset &b) { Q_ASSERT(a.tileCount() == b.tileCount()); for (int i = 0; i < a.tileCount(); ++i) { const Tile *tileA = a.tileAt(i); const Tile *tileB = b.tileAt(i); if (tileA->imageSource() != tileB->imageSource()) return false; } return true; } SharedTileset Tileset::findSimilarTileset(const QVector &tilesets) const { foreach (const SharedTileset &candidate, tilesets) { Q_ASSERT(candidate != this); if (candidate->tileCount() != tileCount()) continue; if (candidate->imageSource() != imageSource()) continue; if (candidate->tileSize() != tileSize()) continue; if (candidate->tileSpacing() != tileSpacing()) continue; if (candidate->margin() != margin()) continue; if (candidate->tileOffset() != tileOffset()) continue; // For an image collection tileset, check the image sources if (imageSource().isEmpty()) if (!sameTileImages(*this, *candidate)) continue; return candidate; } return SharedTileset(); } int Tileset::columnCountForWidth(int width) const { Q_ASSERT(mTileWidth > 0); return (width - mMargin + mTileSpacing) / (mTileWidth + mTileSpacing); } /** * Adds a new terrain type. * * @param name the name of the terrain * @param imageTile the id of the tile that represents the terrain visually * @return the created Terrain instance */ Terrain *Tileset::addTerrain(const QString &name, int imageTileId) { Terrain *terrain = new Terrain(terrainCount(), this, name, imageTileId); insertTerrain(terrainCount(), terrain); return terrain; } void Tileset::insertTerrain(int index, Terrain *terrain) { Q_ASSERT(terrain->tileset() == this); mTerrainTypes.insert(index, terrain); // Reassign terrain IDs for (int terrainId = index; terrainId < mTerrainTypes.size(); ++terrainId) mTerrainTypes.at(terrainId)->mId = terrainId; // Adjust tile terrain references foreach (Tile *tile, mTiles) { for (int corner = 0; corner < 4; ++corner) { const int terrainId = tile->cornerTerrainId(corner); if (terrainId >= index) tile->setCornerTerrainId(corner, terrainId + 1); } } mTerrainDistancesDirty = true; } Terrain *Tileset::takeTerrainAt(int index) { Terrain *terrain = mTerrainTypes.takeAt(index); // Reassign terrain IDs for (int terrainId = index; terrainId < mTerrainTypes.size(); ++terrainId) mTerrainTypes.at(terrainId)->mId = terrainId; // Clear and adjust tile terrain references foreach (Tile *tile, mTiles) { for (int corner = 0; corner < 4; ++corner) { const int terrainId = tile->cornerTerrainId(corner); if (terrainId == index) tile->setCornerTerrainId(corner, 0xFF); else if (terrainId > index) tile->setCornerTerrainId(corner, terrainId - 1); } } mTerrainDistancesDirty = true; return terrain; } int Tileset::terrainTransitionPenalty(int terrainType0, int terrainType1) const { if (mTerrainDistancesDirty) { const_cast(this)->recalculateTerrainDistances(); const_cast(this)->mTerrainDistancesDirty = false; } terrainType0 = terrainType0 == 255 ? -1 : terrainType0; terrainType1 = terrainType1 == 255 ? -1 : terrainType1; // Do some magic, since we don't have a transition array for no-terrain if (terrainType0 == -1 && terrainType1 == -1) return 0; if (terrainType0 == -1) return mTerrainTypes.at(terrainType1)->transitionDistance(terrainType0); return mTerrainTypes.at(terrainType0)->transitionDistance(terrainType1); } void Tileset::recalculateTerrainDistances() { // some fancy macros which can search for a value in each byte of a word simultaneously #define hasZeroByte(dword) (((dword) - 0x01010101UL) & ~(dword) & 0x80808080UL) #define hasByteEqualTo(dword, value) (hasZeroByte((dword) ^ (~0UL/255 * (value)))) // Terrain distances are the number of transitions required before one terrain may meet another // Terrains that have no transition path have a distance of -1 for (int i = 0; i < terrainCount(); ++i) { Terrain *type = terrain(i); QVector distance(terrainCount() + 1, -1); // Check all tiles for transitions to other terrain types for (int j = 0; j < tileCount(); ++j) { Tile *t = tileAt(j); if (!hasByteEqualTo(t->terrain(), i)) continue; // This tile has transitions, add the transitions as neightbours (distance 1) int tl = t->cornerTerrainId(0); int tr = t->cornerTerrainId(1); int bl = t->cornerTerrainId(2); int br = t->cornerTerrainId(3); // Terrain on diagonally opposite corners are not actually a neighbour if (tl == i || br == i) { distance[tr + 1] = 1; distance[bl + 1] = 1; } if (tr == i || bl == i) { distance[tl + 1] = 1; distance[br + 1] = 1; } // terrain has at least one tile of its own type distance[i + 1] = 0; } type->setTransitionDistances(distance); } // Calculate indirect transition distances bool bNewConnections; do { bNewConnections = false; // For each combination of terrain types for (int i = 0; i < terrainCount(); ++i) { Terrain *t0 = terrain(i); for (int j = 0; j < terrainCount(); ++j) { if (i == j) continue; Terrain *t1 = terrain(j); // Scan through each terrain type, and see if we have any in common for (int t = -1; t < terrainCount(); ++t) { int d0 = t0->transitionDistance(t); int d1 = t1->transitionDistance(t); if (d0 == -1 || d1 == -1) continue; // We have cound a common connection int d = t0->transitionDistance(j); Q_ASSERT(t1->transitionDistance(i) == d); // If the new path is shorter, record the new distance if (d == -1 || d0 + d1 < d) { d = d0 + d1; t0->setTransitionDistance(j, d); t1->setTransitionDistance(i, d); // We're making progress, flag for another iteration... bNewConnections = true; } } } } // Repeat while we are still making new connections (could take a // number of iterations for distant terrain types to connect) } while (bNewConnections); } /** * Adds a new tile to the end of the tileset. */ Tile *Tileset::addTile(const QPixmap &image, const QString &source) { Tile *newTile = new Tile(image, source, tileCount(), this); mTiles.append(newTile); if (mTileHeight < image.height()) mTileHeight = image.height(); if (mTileWidth < image.width()) mTileWidth = image.width(); return newTile; } void Tileset::insertTiles(int index, const QList &tiles) { const int count = tiles.count(); for (int i = 0; i < count; ++i) mTiles.insert(index + i, tiles.at(i)); // Adjust the tile IDs of the remaining tiles for (int i = index + count; i < mTiles.size(); ++i) mTiles.at(i)->mId += count; updateTileSize(); } void Tileset::removeTiles(int index, int count) { const QList::iterator first = mTiles.begin() + index; QList::iterator last = first + count; last = mTiles.erase(first, last); // Adjust the tile IDs of the remaining tiles for (; last != mTiles.end(); ++last) (*last)->mId -= count; updateTileSize(); } void Tileset::setTileImage(int id, const QPixmap &image, const QString &source) { // This operation is not supposed to be used on tilesets that are based // on a single image Q_ASSERT(mImageSource.isEmpty()); Tile *tile = tileAt(id); if (!tile) return; const QSize previousImageSize = tile->image().size(); const QSize newImageSize = image.size(); tile->setImage(image); tile->setImageSource(source); if (previousImageSize != newImageSize) { // Update our max. tile size if (previousImageSize.height() == mTileHeight || previousImageSize.width() == mTileWidth) { // This used to be the max image; we have to recompute updateTileSize(); } else { // Check if we have a new maximum if (mTileHeight < newImageSize.height()) mTileHeight = newImageSize.height(); if (mTileWidth < newImageSize.width()) mTileWidth = newImageSize.width(); } } } void Tileset::updateTileSize() { int maxWidth = 0; int maxHeight = 0; foreach (Tile *tile, mTiles) { const QSize size = tile->size(); if (maxWidth < size.width()) maxWidth = size.width(); if (maxHeight < size.height()) maxHeight = size.height(); } mTileWidth = maxWidth; mTileHeight = maxHeight; } tiled-0.14.2/src/libtiled/tileset.h000066400000000000000000000241361260670167100171140ustar00rootroot00000000000000/* * tileset.h * Copyright 2008-2015, Thorbjørn Lindeijer * Copyright 2009, Edward Hutchins * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TILESET_H #define TILESET_H #include "object.h" #include #include #include #include #include #include #include class QImage; namespace Tiled { class Tile; class Tileset; class Terrain; typedef QSharedPointer SharedTileset; /** * A tileset, representing a set of tiles. * * This class is meant to be used by either loading tiles from a tileset image * (using loadFromImage) or by adding/removing individual tiles (using * addTile, insertTiles and removeTiles). These two use-cases are not meant to * be mixed. */ class TILEDSHARED_EXPORT Tileset : public Object { public: /** * Creates a new tileset with the given parameters. Using this function * makes sure the internal weak pointer is initialized, which enables the * sharedPointer() function. * * @param name the name of the tileset * @param tileWidth the width of the tiles in the tileset * @param tileHeight the height of the tiles in the tileset * @param tileSpacing the spacing between the tiles in the tileset image * @param margin the margin around the tiles in the tileset image */ static SharedTileset create(const QString &name, int tileWidth, int tileHeight, int tileSpacing = 0, int margin = 0) { SharedTileset tileset(new Tileset(name, tileWidth, tileHeight, tileSpacing, margin)); tileset->mWeakPointer = tileset; return tileset; } private: /** * Private constructor. Use create() instead. */ Tileset(const QString &name, int tileWidth, int tileHeight, int tileSpacing = 0, int margin = 0): Object(TilesetType), mName(name), mTileWidth(tileWidth), mTileHeight(tileHeight), mTileSpacing(tileSpacing), mMargin(margin), mImageWidth(0), mImageHeight(0), mColumnCount(0), mTerrainDistancesDirty(false) { Q_ASSERT(tileSpacing >= 0); Q_ASSERT(margin >= 0); } public: /** * Destructor. */ ~Tileset(); /** * Returns the name of this tileset. */ const QString &name() const { return mName; } /** * Sets the name of this tileset. */ void setName(const QString &name) { mName = name; } /** * Returns the file name of this tileset. When the tileset isn't an * external tileset, the file name is empty. */ const QString &fileName() const { return mFileName; } /** * Sets the filename of this tileset. */ void setFileName(const QString &fileName) { mFileName = fileName; } /** * Returns whether this tileset is external. */ bool isExternal() const { return !mFileName.isEmpty(); } /** * Returns the maximum width of the tiles in this tileset. */ int tileWidth() const { return mTileWidth; } /** * Returns the maximum height of the tiles in this tileset. */ int tileHeight() const { return mTileHeight; } /** * Returns the maximum size of the tiles in this tileset. */ QSize tileSize() const { return QSize(mTileWidth, mTileHeight); } /** * Returns the spacing between the tiles in the tileset image. */ int tileSpacing() const { return mTileSpacing; } /** * Returns the margin around the tiles in the tileset image. */ int margin() const { return mMargin; } /** * Returns the offset that is applied when drawing the tiles in this * tileset. */ QPoint tileOffset() const { return mTileOffset; } /** * @see tileOffset */ void setTileOffset(QPoint offset) { mTileOffset = offset; } /** * Returns a const reference to the list of tiles in this tileset. */ const QList &tiles() const { return mTiles; } /** * Returns the tile for the given tile ID. * The tile ID is local to this tileset, which means the IDs are in range * [0, tileCount() - 1]. */ Tile *tileAt(int id) const; /** * Returns the number of tiles in this tileset. */ int tileCount() const { return mTiles.size(); } /** * Returns the number of tile columns in the tileset image. */ int columnCount() const { return mColumnCount; } /** * Returns the width of the tileset image. */ int imageWidth() const { return mImageWidth; } /** * Returns the height of the tileset image. */ int imageHeight() const { return mImageHeight; } /** * Returns the transparent color, or an invalid color if no transparent * color is used. */ QColor transparentColor() const { return mTransparentColor; } /** * Sets the transparent color. Pixels with this color will be masked out * when loadFromImage() is called. */ void setTransparentColor(const QColor &c) { mTransparentColor = c; } bool loadFromImage(const QImage &image, const QString &fileName); bool loadFromImage(const QString &fileName); /** * This checks if there is a similar tileset in the given list. * It is needed for replacing this tileset by its similar copy. */ SharedTileset findSimilarTileset(const QVector &tilesets) const; /** * Returns the file name of the external image that contains the tiles in * this tileset. Is an empty string when this tileset doesn't have a * tileset image. */ const QString &imageSource() const { return mImageSource; } /** * Returns the column count that this tileset would have if the tileset * image would have the given \a width. This takes into account the tile * size, margin and spacing. */ int columnCountForWidth(int width) const; /** * Returns a const reference to the list of terrains in this tileset. */ const QList &terrains() const { return mTerrainTypes; } /** * Returns the number of terrain types in this tileset. */ int terrainCount() const { return mTerrainTypes.size(); } /** * Returns the terrain type at the given \a index. */ Terrain *terrain(int index) const { return index >= 0 ? mTerrainTypes[index] : nullptr; } Terrain *addTerrain(const QString &name, int imageTileId); /** * Adds the \a terrain type at the given \a index. * * The terrain should already have this tileset associated with it. */ void insertTerrain(int index, Terrain *terrain); /** * Removes the terrain type at the given \a index and returns it. The * caller becomes responsible for the lifetime of the terrain type. * * This will cause the terrain ids of subsequent terrains to shift up to * fill the space and the terrain information of all tiles in this tileset * will be updated accordingly. */ Terrain *takeTerrainAt(int index); /** * Returns the transition penalty(/distance) between 2 terrains. -1 if no * transition is possible. */ int terrainTransitionPenalty(int terrainType0, int terrainType1) const; Tile *addTile(const QPixmap &image, const QString &source = QString()); void insertTiles(int index, const QList &tiles); void removeTiles(int index, int count); /** * Sets the \a image to be used for the tile with the given \a id. */ void setTileImage(int id, const QPixmap &image, const QString &source = QString()); /** * Used by the Tile class when its terrain information changes. */ void markTerrainDistancesDirty() { mTerrainDistancesDirty = true; } SharedTileset sharedPointer() const; private: /** * Sets tile size to the maximum size. */ void updateTileSize(); /** * Calculates the transition distance matrix for all terrain types. */ void recalculateTerrainDistances(); QString mName; QString mFileName; QString mImageSource; QColor mTransparentColor; int mTileWidth; int mTileHeight; int mTileSpacing; int mMargin; QPoint mTileOffset; int mImageWidth; int mImageHeight; int mColumnCount; QList mTiles; QList mTerrainTypes; bool mTerrainDistancesDirty; QWeakPointer mWeakPointer; }; /** * Convenience override that loads the image using the QImage constructor. */ inline bool Tileset::loadFromImage(const QString &fileName) { return loadFromImage(QImage(fileName), fileName); } inline SharedTileset Tileset::sharedPointer() const { return SharedTileset(mWeakPointer); } } // namespace Tiled #endif // TILESET_H tiled-0.14.2/src/libtiled/tilesetformat.cpp000066400000000000000000000044511260670167100206560ustar00rootroot00000000000000/* * tilesetformat.cpp * Copyright 2015, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tilesetformat.h" #include "mapreader.h" namespace Tiled { SharedTileset readTileset(const QString &fileName, QString *error) { // Try the first registered tileset format that claims to support the file for (TilesetFormat *format : PluginManager::objects()) { if (format->supportsFile(fileName)) { SharedTileset tileset = format->read(fileName); if (error) { if (!tileset) *error = format->errorString(); else *error = QString(); } return tileset; } } // Fall back to default reader (TSX format) MapReader reader; SharedTileset tileset = reader.readTileset(fileName); if (error) { if (!tileset) *error = reader.errorString(); else *error = QString(); } return tileset; } } // namespace Tiled tiled-0.14.2/src/libtiled/tilesetformat.h000066400000000000000000000056731260670167100203320ustar00rootroot00000000000000/* * tilesetformat.h * Copyright 2015, Thorbjørn Lindeijer * * This file is part of libtiled. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TILESETFORMAT_H #define TILESETFORMAT_H #include "mapformat.h" #include "tileset.h" namespace Tiled { /** * An interface to be implemented for adding support for a tileset format to * Tiled. It can implement support for either loading or saving to a certain * tileset format, or both. */ class TILEDSHARED_EXPORT TilesetFormat : public FileFormat { public: explicit TilesetFormat(QObject *parent = nullptr) : FileFormat(parent) {} /** * Reads the tileset and returns a new Tileset instance, or a null shared * pointer if reading failed. */ virtual SharedTileset read(const QString &fileName) = 0; /** * Writes the given \a tileset based on the suggested \a fileName. * * This function may write to a different file name or may even write to * multiple files. The actual files that will be written to can be * determined by calling outputFiles(). * * @return true on success, false when an error * occurred. The error can be retrieved by errorString(). */ virtual bool write(const Tileset &tileset, const QString &fileName) = 0; }; /** * Attempt to read the given tileset using any of the tileset formats added * to the plugin manager, falling back to the TSX format if none are capable. */ TILEDSHARED_EXPORT SharedTileset readTileset(const QString &fileName, QString *error = nullptr); } // namespace Tiled Q_DECLARE_INTERFACE(Tiled::TilesetFormat, "org.mapeditor.TilesetFormat") #endif // MAPFORMAT_H tiled-0.14.2/src/libtiled/varianttomapconverter.cpp000066400000000000000000000511461260670167100224340ustar00rootroot00000000000000/* * varianttomapconverter.cpp * Copyright 2011, Porfírio José Pereira Ribeiro * Copyright 2011-2015, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "varianttomapconverter.h" #include "imagelayer.h" #include "map.h" #include "mapobject.h" #include "objectgroup.h" #include "properties.h" #include "tile.h" #include "tilelayer.h" #include "tileset.h" #include "tilesetformat.h" #include using namespace Tiled; static QString resolvePath(const QDir &dir, const QVariant &variant) { QString fileName = variant.toString(); if (QDir::isRelativePath(fileName)) fileName = QDir::cleanPath(dir.absoluteFilePath(fileName)); return fileName; } Map *VariantToMapConverter::toMap(const QVariant &variant, const QDir &mapDir) { mGidMapper.clear(); mMapDir = mapDir; const QVariantMap variantMap = variant.toMap(); const QString orientationString = variantMap[QLatin1String("orientation")].toString(); Map::Orientation orientation = orientationFromString(orientationString); if (orientation == Map::Unknown) { mError = tr("Unsupported map orientation: \"%1\"") .arg(orientationString); return nullptr; } const QString staggerAxisString = variantMap[QLatin1String("staggeraxis")].toString(); Map::StaggerAxis staggerAxis = staggerAxisFromString(staggerAxisString); const QString staggerIndexString = variantMap[QLatin1String("staggerindex")].toString(); Map::StaggerIndex staggerIndex = staggerIndexFromString(staggerIndexString); const QString renderOrderString = variantMap[QLatin1String("renderorder")].toString(); Map::RenderOrder renderOrder = renderOrderFromString(renderOrderString); const int nextObjectId = variantMap[QLatin1String("nextobjectid")].toInt(); QScopedPointer map(new Map(orientation, variantMap[QLatin1String("width")].toInt(), variantMap[QLatin1String("height")].toInt(), variantMap[QLatin1String("tilewidth")].toInt(), variantMap[QLatin1String("tileheight")].toInt())); map->setHexSideLength(variantMap[QLatin1String("hexsidelength")].toInt()); map->setStaggerAxis(staggerAxis); map->setStaggerIndex(staggerIndex); map->setRenderOrder(renderOrder); if (nextObjectId) map->setNextObjectId(nextObjectId); mMap = map.data(); map->setProperties(toProperties(variantMap[QLatin1String("properties")])); const QString bgColor = variantMap[QLatin1String("backgroundcolor")].toString(); if (!bgColor.isEmpty() && QColor::isValidColor(bgColor)) map->setBackgroundColor(QColor(bgColor)); foreach (const QVariant &tilesetVariant, variantMap[QLatin1String("tilesets")].toList()) { SharedTileset tileset = toTileset(tilesetVariant); if (!tileset) return nullptr; map->addTileset(tileset); } foreach (const QVariant &layerVariant, variantMap[QLatin1String("layers")].toList()) { Layer *layer = toLayer(layerVariant); if (!layer) return nullptr; map->addLayer(layer); } return map.take(); } SharedTileset VariantToMapConverter::toTileset(const QVariant &variant, const QDir &directory) { mMapDir = directory; mReadingExternalTileset = true; SharedTileset tileset = toTileset(variant); mReadingExternalTileset = false; return tileset; } Properties VariantToMapConverter::toProperties(const QVariant &variant) { const QVariantMap variantMap = variant.toMap(); Properties properties; QVariantMap::const_iterator it = variantMap.constBegin(); QVariantMap::const_iterator it_end = variantMap.constEnd(); for (; it != it_end; ++it) properties[it.key()] = it.value().toString(); return properties; } SharedTileset VariantToMapConverter::toTileset(const QVariant &variant) { const QVariantMap variantMap = variant.toMap(); const int firstGid = variantMap[QLatin1String("firstgid")].toInt(); // Handle external tilesets const QVariant sourceVariant = variantMap[QLatin1String("source")]; if (!sourceVariant.isNull()) { QString source = resolvePath(mMapDir, sourceVariant); QString error; SharedTileset tileset = Tiled::readTileset(source, &error); if (!tileset) { mError = tr("Error while loading tileset '%1': %2") .arg(source, error); } else { mGidMapper.insert(firstGid, tileset.data()); } return tileset; } const QString name = variantMap[QLatin1String("name")].toString(); const int tileWidth = variantMap[QLatin1String("tilewidth")].toInt(); const int tileHeight = variantMap[QLatin1String("tileheight")].toInt(); const int spacing = variantMap[QLatin1String("spacing")].toInt(); const int margin = variantMap[QLatin1String("margin")].toInt(); const QVariantMap tileOffset = variantMap[QLatin1String("tileoffset")].toMap(); const int tileOffsetX = tileOffset[QLatin1String("x")].toInt(); const int tileOffsetY = tileOffset[QLatin1String("y")].toInt(); if (tileWidth <= 0 || tileHeight <= 0 || (firstGid == 0 && !mReadingExternalTileset)) { mError = tr("Invalid tileset parameters for tileset '%1'").arg(name); return SharedTileset(); } SharedTileset tileset(Tileset::create(name, tileWidth, tileHeight, spacing, margin)); tileset->setTileOffset(QPoint(tileOffsetX, tileOffsetY)); const QString trans = variantMap[QLatin1String("transparentcolor")].toString(); if (!trans.isEmpty() && QColor::isValidColor(trans)) tileset->setTransparentColor(QColor(trans)); QVariant imageVariant = variantMap[QLatin1String("image")]; if (!imageVariant.isNull()) { QString imagePath = resolvePath(mMapDir, imageVariant); if (!tileset->loadFromImage(imagePath)) { mError = tr("Error loading tileset image:\n'%1'").arg(imagePath); return SharedTileset(); } } tileset->setProperties(toProperties(variantMap[QLatin1String("properties")])); // Read terrains QVariantList terrainsVariantList = variantMap[QLatin1String("terrains")].toList(); for (int i = 0; i < terrainsVariantList.count(); ++i) { QVariantMap terrainMap = terrainsVariantList[i].toMap(); tileset->addTerrain(terrainMap[QLatin1String("name")].toString(), terrainMap[QLatin1String("tile")].toInt()); } // Read tile terrain and external image information const QVariantMap tilesVariantMap = variantMap[QLatin1String("tiles")].toMap(); QVariantMap::const_iterator it = tilesVariantMap.constBegin(); for (; it != tilesVariantMap.end(); ++it) { bool ok; const int tileIndex = it.key().toInt(); if (tileIndex < 0) { mError = tr("Tileset tile index negative:\n'%1'").arg(tileIndex); } if (tileIndex >= tileset->tileCount()) { // Extend the tileset to fit the tile if (tileIndex >= tilesVariantMap.count()) { // If tiles are defined this way, there should be an entry // for each tile. // Limit the index to number of entries to prevent running out // of memory on malicious input. mError = tr("Tileset tile index too high:\n'%1'").arg(tileIndex); return SharedTileset(); } for (int i = tileset->tileCount(); i <= tileIndex; i++) tileset->addTile(QPixmap()); } Tile *tile = tileset->tileAt(tileIndex); if (tile) { const QVariantMap tileVar = it.value().toMap(); QList terrains = tileVar[QLatin1String("terrain")].toList(); if (terrains.count() == 4) { for (int i = 0; i < 4; ++i) { int terrainId = terrains.at(i).toInt(&ok); if (ok && terrainId >= 0 && terrainId < tileset->terrainCount()) tile->setCornerTerrainId(i, terrainId); } } float probability = tileVar[QLatin1String("probability")].toFloat(&ok); if (ok) tile->setProbability(probability); imageVariant = tileVar[QLatin1String("image")]; if (!imageVariant.isNull()) { QString imagePath = resolvePath(mMapDir, imageVariant); tileset->setTileImage(tileIndex, QPixmap(imagePath), imagePath); } QVariantMap objectGroupVariant = tileVar[QLatin1String("objectgroup")].toMap(); if (!objectGroupVariant.isEmpty()) tile->setObjectGroup(toObjectGroup(objectGroupVariant)); QVariantList frameList = tileVar[QLatin1String("animation")].toList(); if (!frameList.isEmpty()) { QVector frames(frameList.size()); for (int i = frameList.size() - 1; i >= 0; --i) { const QVariantMap frameVariantMap = frameList[i].toMap(); Frame &frame = frames[i]; frame.tileId = frameVariantMap[QLatin1String("tileid")].toInt(); frame.duration = frameVariantMap[QLatin1String("duration")].toInt(); } tile->setFrames(frames); } } } // Read tile properties QVariantMap propertiesVariantMap = variantMap[QLatin1String("tileproperties")].toMap(); for (it = propertiesVariantMap.constBegin(); it != propertiesVariantMap.constEnd(); ++it) { const int tileIndex = it.key().toInt(); const QVariant propertiesVar = it.value(); if (tileIndex >= 0 && tileIndex < tileset->tileCount()) { const Properties properties = toProperties(propertiesVar); tileset->tileAt(tileIndex)->setProperties(properties); } } if (!mReadingExternalTileset) mGidMapper.insert(firstGid, tileset.data()); return tileset; } Layer *VariantToMapConverter::toLayer(const QVariant &variant) { const QVariantMap variantMap = variant.toMap(); Layer *layer = nullptr; if (variantMap[QLatin1String("type")] == QLatin1String("tilelayer")) layer = toTileLayer(variantMap); else if (variantMap[QLatin1String("type")] == QLatin1String("objectgroup")) layer = toObjectGroup(variantMap); else if (variantMap[QLatin1String("type")] == QLatin1String("imagelayer")) layer = toImageLayer(variantMap); if (layer) { layer->setProperties(toProperties(variantMap[QLatin1String("properties")])); const QPointF offset(variantMap[QLatin1String("offsetx")].toDouble(), variantMap[QLatin1String("offsety")].toDouble()); layer->setOffset(offset); } return layer; } TileLayer *VariantToMapConverter::toTileLayer(const QVariantMap &variantMap) { const QString name = variantMap[QLatin1String("name")].toString(); const int width = variantMap[QLatin1String("width")].toInt(); const int height = variantMap[QLatin1String("height")].toInt(); const QVariant dataVariant = variantMap[QLatin1String("data")]; typedef QScopedPointer TileLayerPtr; TileLayerPtr tileLayer(new TileLayer(name, variantMap[QLatin1String("x")].toInt(), variantMap[QLatin1String("y")].toInt(), width, height)); const qreal opacity = variantMap[QLatin1String("opacity")].toReal(); const bool visible = variantMap[QLatin1String("visible")].toBool(); tileLayer->setOpacity(opacity); tileLayer->setVisible(visible); const QString encoding = variantMap[QLatin1String("encoding")].toString(); const QString compression = variantMap[QLatin1String("compression")].toString(); Map::LayerDataFormat layerDataFormat; if (encoding.isEmpty() || encoding == QLatin1String("csv")) { layerDataFormat = Map::CSV; } else if (encoding == QLatin1String("base64")) { if (compression.isEmpty()) { layerDataFormat = Map::Base64; } else if (compression == QLatin1String("gzip")) { layerDataFormat = Map::Base64Gzip; } else if (compression == QLatin1String("zlib")) { layerDataFormat = Map::Base64Zlib; } else { mError = tr("Compression method '%1' not supported").arg(compression); return nullptr; } } else { mError = tr("Unknown encoding: %1").arg(encoding); return nullptr; } mMap->setLayerDataFormat(layerDataFormat); switch (layerDataFormat) { case Map::XML: case Map::CSV: { const QVariantList dataVariantList = dataVariant.toList(); if (dataVariantList.size() != width * height) { mError = tr("Corrupt layer data for layer '%1'").arg(name); return nullptr; } int x = 0; int y = 0; bool ok; foreach (const QVariant &gidVariant, dataVariantList) { const unsigned gid = gidVariant.toUInt(&ok); if (!ok) { mError = tr("Unable to parse tile at (%1,%2) on layer '%3'") .arg(x).arg(y).arg(tileLayer->name()); return nullptr; } const Cell cell = mGidMapper.gidToCell(gid, ok); tileLayer->setCell(x, y, cell); x++; if (x >= tileLayer->width()) { x = 0; y++; } } break; } case Map::Base64: case Map::Base64Zlib: case Map::Base64Gzip: { const QByteArray data = dataVariant.toByteArray(); GidMapper::DecodeError error = mGidMapper.decodeLayerData(*tileLayer, data, layerDataFormat); switch (error) { case GidMapper::CorruptLayerData: mError = tr("Corrupt layer data for layer '%1'").arg(name); return nullptr; case GidMapper::TileButNoTilesets: mError = tr("Tile used but no tilesets specified"); return nullptr; case GidMapper::InvalidTile: mError = tr("Invalid tile: %1").arg(mGidMapper.invalidTile()); return nullptr; case GidMapper::NoError: break; } break; } } return tileLayer.take(); } ObjectGroup *VariantToMapConverter::toObjectGroup(const QVariantMap &variantMap) { typedef QScopedPointer ObjectGroupPtr; ObjectGroupPtr objectGroup(new ObjectGroup(variantMap[QLatin1String("name")].toString(), variantMap[QLatin1String("x")].toInt(), variantMap[QLatin1String("y")].toInt(), variantMap[QLatin1String("width")].toInt(), variantMap[QLatin1String("height")].toInt())); const qreal opacity = variantMap[QLatin1String("opacity")].toReal(); const bool visible = variantMap[QLatin1String("visible")].toBool(); objectGroup->setOpacity(opacity); objectGroup->setVisible(visible); objectGroup->setColor(variantMap.value(QLatin1String("color")).value()); const QString drawOrderString = variantMap.value(QLatin1String("draworder")).toString(); if (!drawOrderString.isEmpty()) { objectGroup->setDrawOrder(drawOrderFromString(drawOrderString)); if (objectGroup->drawOrder() == ObjectGroup::UnknownOrder) { mError = tr("Invalid draw order: %1").arg(drawOrderString); return nullptr; } } foreach (const QVariant &objectVariant, variantMap[QLatin1String("objects")].toList()) { const QVariantMap objectVariantMap = objectVariant.toMap(); const QString name = objectVariantMap[QLatin1String("name")].toString(); const QString type = objectVariantMap[QLatin1String("type")].toString(); const int id = objectVariantMap[QLatin1String("id")].toInt(); const int gid = objectVariantMap[QLatin1String("gid")].toInt(); const qreal x = objectVariantMap[QLatin1String("x")].toReal(); const qreal y = objectVariantMap[QLatin1String("y")].toReal(); const qreal width = objectVariantMap[QLatin1String("width")].toReal(); const qreal height = objectVariantMap[QLatin1String("height")].toReal(); const qreal rotation = objectVariantMap[QLatin1String("rotation")].toReal(); const QPointF pos(x, y); const QSizeF size(width, height); MapObject *object = new MapObject(name, type, pos, size); object->setId(id); object->setRotation(rotation); if (gid) { bool ok; object->setCell(mGidMapper.gidToCell(gid, ok)); if (!object->cell().isEmpty()) { const QSizeF &tileSize = object->cell().tile->size(); if (width == 0) object->setWidth(tileSize.width()); if (height == 0) object->setHeight(tileSize.height()); } } if (objectVariantMap.contains(QLatin1String("visible"))) object->setVisible(objectVariantMap[QLatin1String("visible")].toBool()); object->setProperties(toProperties(objectVariantMap[QLatin1String("properties")])); objectGroup->addObject(object); const QVariant polylineVariant = objectVariantMap[QLatin1String("polyline")]; const QVariant polygonVariant = objectVariantMap[QLatin1String("polygon")]; if (polygonVariant.isValid()) { object->setShape(MapObject::Polygon); object->setPolygon(toPolygon(polygonVariant)); } if (polylineVariant.isValid()) { object->setShape(MapObject::Polyline); object->setPolygon(toPolygon(polylineVariant)); } if (objectVariantMap.contains(QLatin1String("ellipse"))) object->setShape(MapObject::Ellipse); } return objectGroup.take(); } ImageLayer *VariantToMapConverter::toImageLayer(const QVariantMap &variantMap) { typedef QScopedPointer ImageLayerPtr; ImageLayerPtr imageLayer(new ImageLayer(variantMap[QLatin1String("name")].toString(), variantMap[QLatin1String("x")].toInt(), variantMap[QLatin1String("y")].toInt(), variantMap[QLatin1String("width")].toInt(), variantMap[QLatin1String("height")].toInt())); const qreal opacity = variantMap[QLatin1String("opacity")].toReal(); const bool visible = variantMap[QLatin1String("visible")].toBool(); imageLayer->setOpacity(opacity); imageLayer->setVisible(visible); const QString trans = variantMap[QLatin1String("transparentcolor")].toString(); if (!trans.isEmpty() && QColor::isValidColor(trans)) imageLayer->setTransparentColor(QColor(trans)); QVariant imageVariant = variantMap[QLatin1String("image")].toString(); if (!imageVariant.isNull()) { QString imagePath = resolvePath(mMapDir, imageVariant); if (!imageLayer->loadFromImage(QImage(imagePath), imagePath)) { mError = tr("Error loading image:\n'%1'").arg(imagePath); return nullptr; } } return imageLayer.take(); } QPolygonF VariantToMapConverter::toPolygon(const QVariant &variant) const { QPolygonF polygon; foreach (const QVariant &pointVariant, variant.toList()) { const QVariantMap pointVariantMap = pointVariant.toMap(); const qreal pointX = pointVariantMap[QLatin1String("x")].toReal(); const qreal pointY = pointVariantMap[QLatin1String("y")].toReal(); polygon.append(QPointF(pointX, pointY)); } return polygon; } tiled-0.14.2/src/libtiled/varianttomapconverter.h000066400000000000000000000054431260670167100221000ustar00rootroot00000000000000/* * varianttomapconverter.h * Copyright 2011, Porfírio José Pereira Ribeiro * Copyright 2011-2015, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef VARIANTTOMAPCONVERTER_H #define VARIANTTOMAPCONVERTER_H #include "gidmapper.h" #include #include #include namespace Tiled { class Layer; class Map; class ObjectGroup; class Properties; class Tileset; /** * Converts a QVariant to a Map instance. Meant to be used together with * JsonReader. */ class TILEDSHARED_EXPORT VariantToMapConverter { // Using the MapReader context since the messages are the same Q_DECLARE_TR_FUNCTIONS(MapReader) public: VariantToMapConverter() : mMap(nullptr) , mReadingExternalTileset(false) {} /** * Tries to convert the given \a variant to a Map instance. The \a mapDir * is necessary to resolve any relative references to external images. * * Returns 0 in case of an error. The error can be obstained using * errorString(). */ Map *toMap(const QVariant &variant, const QDir &mapDir); /** * Tries to convert the given \a variant to a Tileset instance. The * \a directory is necessary to resolve any relative references to external * images. * * Returns 0 in case of an error. The error can be obstained using * errorString(). */ SharedTileset toTileset(const QVariant &variant, const QDir &directory); /** * Returns the last error, if any. */ QString errorString() const { return mError; } private: Properties toProperties(const QVariant &variant); SharedTileset toTileset(const QVariant &variant); Layer *toLayer(const QVariant &variant); TileLayer *toTileLayer(const QVariantMap &variantMap); ObjectGroup *toObjectGroup(const QVariantMap &variantMap); ImageLayer *toImageLayer(const QVariantMap &variantMap); QPolygonF toPolygon(const QVariant &variant) const; Map *mMap; QDir mMapDir; bool mReadingExternalTileset; GidMapper mGidMapper; QString mError; }; } // namespace Tiled #endif // VARIANTTOMAPCONVERTER_H tiled-0.14.2/src/plugins/000077500000000000000000000000001260670167100151555ustar00rootroot00000000000000tiled-0.14.2/src/plugins/csv/000077500000000000000000000000001260670167100157505ustar00rootroot00000000000000tiled-0.14.2/src/plugins/csv/csv.pro000066400000000000000000000001631260670167100172650ustar00rootroot00000000000000include(../plugin.pri) DEFINES += CSV_LIBRARY SOURCES += csvplugin.cpp HEADERS += csvplugin.h \ csv_global.h tiled-0.14.2/src/plugins/csv/csv.qbs000066400000000000000000000002351260670167100172520ustar00rootroot00000000000000import qbs 1.0 TiledPlugin { cpp.defines: ["CSV_LIBRARY"] files: [ "csv_global.h", "csvplugin.cpp", "csvplugin.h", ] } tiled-0.14.2/src/plugins/csv/csv_global.h000066400000000000000000000017371260670167100202440ustar00rootroot00000000000000/* * CSV Tiled Plugin * Copyright 2014, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CSV_GLOBAL_H #define CSV_GLOBAL_H #include #if defined(CSV_LIBRARY) # define CSVSHARED_EXPORT Q_DECL_EXPORT #else # define CSVSHARED_EXPORT Q_DECL_IMPORT #endif #endif // CSV_GLOBAL_H tiled-0.14.2/src/plugins/csv/csvplugin.cpp000066400000000000000000000074151260670167100204750ustar00rootroot00000000000000/* * CSV Tiled Plugin * Copyright 2014, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "csvplugin.h" #include "map.h" #include "tile.h" #include "tilelayer.h" #include #include #include #include using namespace Tiled; using namespace Csv; CsvPlugin::CsvPlugin() { } bool CsvPlugin::write(const Map *map, const QString &fileName) { // Get file paths for each layer QStringList layerPaths = outputFiles(map, fileName); // Traverse all tile layers uint currentLayer = 0u; foreach (const Layer *layer, map->layers()) { if (layer->layerType() != Layer::TileLayerType) continue; const TileLayer *tileLayer = static_cast(layer); QSaveFile file(layerPaths.at(currentLayer)); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { mError = tr("Could not open file for writing."); return false; } // Write out tiles either by ID or their name, if given. -1 is "empty" for (int y = 0; y < tileLayer->height(); ++y) { for (int x = 0; x < tileLayer->width(); ++x) { if (x > 0) file.write(",", 1); const Cell &cell = tileLayer->cellAt(x, y); const Tile *tile = cell.tile; if (tile && tile->hasProperty(QLatin1String("name"))) { file.write(tile->property(QLatin1String("name")).toUtf8()); } else { const int id = tile ? tile->id() : -1; file.write(QByteArray::number(id)); } } file.write("\n", 1); } if (file.error() != QFile::NoError) { mError = file.errorString(); return false; } if (!file.commit()) { mError = file.errorString(); return false; } ++currentLayer; } return true; } QString CsvPlugin::errorString() const { return mError; } QStringList CsvPlugin::outputFiles(const Tiled::Map *map, const QString &fileName) const { QStringList result; // Extract file name without extension and path QFileInfo fileInfo(fileName); const QString base = fileInfo.completeBaseName() + QLatin1String("_"); const QString path = fileInfo.path(); // Loop layers to calculate the path for the exported file foreach (const Layer *layer, map->layers()) { if (layer->layerType() != Layer::TileLayerType) continue; // Get the output file name for this layer const QString layerName = layer->name(); const QString layerFileName = base + layerName + QLatin1String(".csv"); const QString layerFilePath = QDir(path).filePath(layerFileName); result.append(layerFilePath); } // If there was only one tile layer, there's no need to change the name // (also keeps behavior backwards compatible) if (result.size() == 1) result[0] = fileName; return result; } QString CsvPlugin::nameFilter() const { return tr("CSV files (*.csv)"); } tiled-0.14.2/src/plugins/csv/csvplugin.h000066400000000000000000000025671260670167100201450ustar00rootroot00000000000000/* * CSV Tiled Plugin * Copyright 2014, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CSVPLUGIN_H #define CSVPLUGIN_H #include "mapformat.h" #include "csv_global.h" namespace Csv { class CSVSHARED_EXPORT CsvPlugin : public Tiled::WritableMapFormat { Q_OBJECT Q_PLUGIN_METADATA(IID "org.mapeditor.MapFormat" FILE "plugin.json") public: CsvPlugin(); bool write(const Tiled::Map *map, const QString &fileName) override; QString errorString() const override; QStringList outputFiles(const Tiled::Map *map, const QString &fileName) const override; protected: QString nameFilter() const override; private: QString mError; }; } // namespace Csv #endif // CSVPLUGIN_H tiled-0.14.2/src/plugins/csv/plugin.json000066400000000000000000000000321260670167100201340ustar00rootroot00000000000000{ "Keys": [ "notused" ] } tiled-0.14.2/src/plugins/droidcraft/000077500000000000000000000000001260670167100172765ustar00rootroot00000000000000tiled-0.14.2/src/plugins/droidcraft/droidcraft.pro000066400000000000000000000003201260670167100221340ustar00rootroot00000000000000include(../plugin.pri) DEFINES += DROIDCRAFT_LIBRARY SOURCES += droidcraftplugin.cpp HEADERS += droidcraftplugin.h\ droidcraft_global.h RESOURCES += \ droidcraft.qrc OTHER_FILES = plugin.json tiled-0.14.2/src/plugins/droidcraft/droidcraft.qbs000066400000000000000000000003231260670167100221240ustar00rootroot00000000000000import qbs 1.0 TiledPlugin { cpp.defines: ["DROIDCRAFT_LIBRARY"] files: [ "droidcraft_global.h", "droidcraftplugin.cpp", "droidcraftplugin.h", "droidcraft.qrc", ] } tiled-0.14.2/src/plugins/droidcraft/droidcraft.qrc000066400000000000000000000001321260670167100221220ustar00rootroot00000000000000 tileset.png tiled-0.14.2/src/plugins/droidcraft/droidcraft_global.h000066400000000000000000000020071260670167100231070ustar00rootroot00000000000000/* * Droidcraft Tiled Plugin * Copyright 2011, seeseekey * * This file is part of Tiled. * * 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, see . */ #ifndef DROIDCRAFT_GLOBAL_H #define DROIDCRAFT_GLOBAL_H #include #if defined(DROIDCRAFT_LIBRARY) # define DROIDCRAFTSHARED_EXPORT Q_DECL_EXPORT #else # define DROIDCRAFTSHARED_EXPORT Q_DECL_IMPORT #endif #endif // DROIDCRAFT_GLOBAL_H tiled-0.14.2/src/plugins/droidcraft/droidcraftplugin.cpp000066400000000000000000000076101260670167100233460ustar00rootroot00000000000000/* * Droidcraft Tiled Plugin * Copyright 2011, seeseekey * * This file is part of Tiled. * * 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, see . */ #include "droidcraftplugin.h" #include "map.h" #include "tile.h" #include "tileset.h" #include "tilelayer.h" #include "compression.h" #include #include #include using namespace Droidcraft; DroidcraftPlugin::DroidcraftPlugin() { } // Reader Tiled::Map *DroidcraftPlugin::read(const QString &fileName) { using namespace Tiled; QByteArray uncompressed; // Read data QFile f(fileName); if (f.open(QIODevice::ReadOnly)) { QByteArray compressed = f.readAll(); f.close(); uncompressed = decompress(compressed, 48 * 48); } // Check the data if (uncompressed.count() != 48 * 48) { mError = tr("This is not a valid Droidcraft map file!"); return nullptr; } // Build 48 x 48 map // Create a Map -> Create a Tileset -> Add Tileset to map // -> Create a TileLayer -> Fill layer -> Add TileLayer to Map Map *map = new Map(Map::Orthogonal, 48, 48, 32, 32); SharedTileset mapTileset(Tileset::create("tileset", 32, 32)); mapTileset->loadFromImage(QImage(":/tileset.png"), "tileset.png"); map->addTileset(mapTileset); // Fill layer TileLayer *mapLayer = new TileLayer("map", 0, 0, 48, 48); // Load for (int i = 0; i < 48 * 48; i++) { unsigned char tileFile = uncompressed.at(i); int y = i / 48; int x = i - (48 * y); Tile *tile = mapTileset->tileAt(tileFile); mapLayer->setCell(x, y, Cell(tile)); } map->addLayer(mapLayer); return map; } bool DroidcraftPlugin::supportsFile(const QString &fileName) const { return QFileInfo(fileName).suffix() == QLatin1String("dat"); } // Writer bool DroidcraftPlugin::write(const Tiled::Map *map, const QString &fileName) { using namespace Tiled; // Check layer count and type if (map->layerCount() != 1 || !map->layerAt(0)->isTileLayer()) { mError = tr("The map needs to have exactly one tile layer!"); return false; } TileLayer *mapLayer = map->layerAt(0)->asTileLayer(); // Check layer size if (mapLayer->width() != 48 || mapLayer->height() != 48) { mError = tr("The layer must have a size of 48 x 48 tiles!"); return false; } // Create QByteArray and compress it QByteArray uncompressed = QByteArray(48 * 48, 0); const int width = mapLayer->width(); const int height = mapLayer->height(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { if (Tile *tile = mapLayer->cellAt(x, y).tile) uncompressed[y * width + x] = (unsigned char) tile->id(); } } QByteArray compressed = compress(uncompressed, Gzip); // Write QByteArray QSaveFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { mError = tr("Could not open file for writing."); return false; } file.write(compressed); if (!file.commit()) { mError = file.errorString(); return false; } return true; } QString DroidcraftPlugin::nameFilter() const { return tr("Droidcraft map files (*.dat)"); } QString DroidcraftPlugin::errorString() const { return mError; } tiled-0.14.2/src/plugins/droidcraft/droidcraftplugin.h000066400000000000000000000030041260670167100230040ustar00rootroot00000000000000/* * Droidcraft Tiled Plugin * Copyright 2011, seeseekey * * This file is part of Tiled. * * 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, see . */ #ifndef DROIDCRAFTPLUGIN_H #define DROIDCRAFTPLUGIN_H #include "droidcraft_global.h" #include "map.h" #include "mapformat.h" #include namespace Droidcraft { class DROIDCRAFTSHARED_EXPORT DroidcraftPlugin : public Tiled::MapFormat { Q_OBJECT Q_INTERFACES(Tiled::MapFormat) Q_PLUGIN_METADATA(IID "org.mapeditor.MapFormat" FILE "plugin.json") public: DroidcraftPlugin(); Tiled::Map *read(const QString &fileName) override; bool supportsFile(const QString &fileName) const override; bool write(const Tiled::Map *map, const QString &fileName) override; QString nameFilter() const override; QString errorString() const override; private: QString mError; }; } // namespace Droidcraft #endif // DROIDCRAFTPLUGIN_H tiled-0.14.2/src/plugins/droidcraft/plugin.json000066400000000000000000000000321260670167100214620ustar00rootroot00000000000000{ "Keys": [ "notused" ] } tiled-0.14.2/src/plugins/droidcraft/tileset.png000066400000000000000000001566141260670167100214720ustar00rootroot00000000000000PNG  IHDRxsRGBbKGD pHYsltIME IDATxyeיٗ$}!BTm=x=*^Q^Wz縜Aq ( ,a˾gLYתGuUwϒ_^C/UOꩧ]?_oPw*Oƴ#͘$ 6~O?LO|!utt BrhiiA4;F<SUF|>LǏ0m4^/B:;;CUUN8A8F"']`FBw kyy@F@BrxJO~)y=K i*ǿ}Jkt/hJW)y CBB0 a HYȪ, $yQ=,8NPUs:(B__TXEQ4D"A__d]z8ND"!$ 04 Il |.{!@,7׆~SF|j)__^=  _JmUʔp122z322.! FH )8tT0L@YQb1 `*dY&LbFbNp000@"@Q멨@4E!Ni=F4dK0;4FBYQAJT{l"I`+cj.\HKK 7?l+3xFN>C*,/R[ Z8~p@GG|ǻmO5ٯ  2~9p`?ipe`_HF52I  1&@RS@R$iT^V!sb14p*N'$L&Bֿin ànjkkq8Ȳa8l4 ˅&JRV{,~]zi$M ݟB =&q* s}sHB5X(JMu5dkYǕW^ ٳ}CON'zxI!Cl$'еj2j HFY`G{Lǻ-NR\8M`xy=O8U.! a9|'O檫Q7d􄌒<._ٗ@BJH) >.$$Pz{BQYY,6h;xH&\.xl3@uEAQn7J@4%ɘ1쵑$H?5V@2~*j)0ٕhUZŠ`0yDx1} NK.eʕ8{[ccp γn#(/O#3!kܳ1dW̯Hx"jAH꘽$;VD!Q ~k*i']3 >L+\/sq8]nV_~EY4 !%s [j ٜE9*VQ3I!Pͼl8Y+rrH&j+tv WUmƊB*L&c$ Yq\!l>$u62ĎFd G> #iHv&XGq+HH=l@?KĚ5Wq \xᅣOIXt)K._raȣ,cɈ㉾mEd-4 KmV!jYΙ3ɤ3h/x '^}o|8NN?AUu >}ie`t7}n9 @aQ) #!M MU T CT*Ȋ^aСC$ 9qT ECC$9~KD(ؾg>EQ%p)!HӤ<+|IvqWk}&"~*jR]IR}I٥4"cVK_ ;/k׭vV\9u8yG?5v$>DBC0}QK @P|bnux<,]zfv߲0@P! RL}(v8@( eߧ[An32j-Ivٟ$Ii$3~:Fu[)!"~!ǃ,LV`X Icd d p:smւyՂ9yyİ7o\lYQ?O|;8% ߒ8tAW|xId=NjGBR WlQK U 3[ G t: Elf@ ̧md`0\~ڍ,d]vt%`޽,\3fW 9̙TWt:f͢m֬WVF$UUfHr܀~9bQ 2/YZux匿ˮ$ Emm]&h$?Ͻ5QO"(DZGq($hNK%0p$w?[gi0Ĉ( bBUW+9njjSN8=ig#Ѫ0/n|=3໔g4q4W!鞍'琍UWestvv& ~;z]%ƶ*:8qɉc̝7T2E}}}(h׏gk7o++#ZՕHqIf_2 ;j)|=X$-VEQXX^uӉ]uT*E? 8!!;Jz%0F@q(Uz=?//W&"1ဦ9طoߤ)o{Oz^7b)ek ѪW+xOSٻ%"]BI ՏT\}芏%r[Rό .(mpپ#?;%l_Μ>Mu$z<9300ۏL&i5t*ԔX@f0 ""TJ037 3sa$I;:\."]l!===ؠr6mLx _*KKkk61:iSijm>==Dzv(?'|}z9edY$]׉D"tww6 0|>L~S1H 4XXEtOũ87CY a[VgV"t2$IB4֭[7s=ׄ0U¶ HgӯTjqDM2[A}!2=bU#>yRd}iKc~#/`0X6G)ffϭ#PP :}:m3HK446Dy\r* sNJED%DJFrGa{ jV.+ȲMca&!JeJ[Qd2d2D8Z UUuI$&:H8jgV"2[?mC,Q9/ _ nb{O.Y?\0wey2Zg}2Dr 7\3 տ?F`0XN6Ģ1z7wP(@-huPVb$Fd@mDb1 ]p€W fl Vf@Y|L&B!Ml6?l~+9t:M<r D"ߟdL86@q+zNN胡I{9B07y-Mވ7\9ﯢšeduxCOy5ÀoiGB8_3gi .ȇ#x^;i$io?J*by;KWG7({¹ Xf^+2:Iexqi.AeIkk+i$IBbFn~.zzzz^5558M{Yᰝ/a;dGONtIٟ V PHʽ|R -]H,{H+W؋:ˀ% | k?0};[o,Kp}:UVs%Nٷo/;^~zeG0 CPxdQ1iى(+Css3466ڍ#dl@0s2^0,\޹>%.jm(rm}$H~*V8D~썺e˖xUhUH"Me#xCMZauF:WyvYt ?s4<4Utwu *˘%LeXl$$>g˅#ڙH^u*E!HPYYiTWWDMMMA2먪G#9dU _ } Rq   ^[2/+ Е K鯽VGez3~Izs/6mMe?~pF/_ҋ.-}D6ں:dIw_cTe\sנ''ɐH$p\ %Gav )`QaJP%Kˏg! 'ؗ of sPV0Iw+ɼg5Jf@+q'T׫`7|Fz{8|aE4LqY83f]d9bp8p8$2o``NLRL&C$$ T*Euu5v}<[76JV aya "`pJaիW2_–XJho&휆Faf~FXS#[; 457hbdYc#z\nnd"1J&ts ȲCeRN:h4J:8PU^*++ Xd  x|\.bDQSٰ z5;nVp $̕Je`!8pşgnV;D gb.C Q{v U {td۶gȞ=y'H| /_#GUŐc5#}Ã],D"!hmmEu:;;qve@*ɓ(BUUg%Iv]455c'l?;/|?O y¼H$B2`ٲeCnbʩry0-td=d RqBRU߫qj xP\ٹsմN?E[,|>Vf…=sfX`#`90:jU 3 Pq< |(bg[؄ Bhnl$hb ˲b1$uuu2mڴKVTy^Q@geb08gSSO=5i`~x3d9pLt:m”$*>}:ӧOftXUU6!%g$-r|_`R^_Hx&W !-/<1h2m5^U2ræ<ͯK/X x^r`2)8+PPϮv(tuu|w{#Ցv4cla6yKٌB&_oA$G6P.[=fpI2"z9%]GB~nfUxD"HDss`U d2B]]]b1[p:D"Μ9C<'NE__`v#;/K+(@iD̙ݻ۷m.j i0}M$" g{%Af>_^jf}Mn7PcKxf~\[ tU IBR9 pI&vBӷۍG(*3EQz~?Lۋtg3 644U&ȱ2L3A!o SHg0` <ȣn:jk=?˼緗@1d'IF2#/f !)eW_K03߷~#zy}FΝSO># pi~sKkg9r0/hfSNΌ3 @1De2*ညDcWz{{1 f2L>x8{,d.4ndln ðY>ٳg%"ou߿/B0d`o@w^Ξ=/"z+\pv]s]F!݉bUIx`Nb(ZY/杦 ̌[oUBx<\{<㶗S\j5s.K80nlm3t[3²P/j*nN`.ij___v& !d2h4J4uºAY9}KWBe!`z#ʃ  2s̡H>}Ξ=S^\H?,R-dZi5Ye]}7rf.fȡʘ/x=zjjsz%I&H"2ӦD<>?}((x9(P= e^0d28EV`?X kY@8tIzTWWۍᠫ0.D׷bU?C\h+L&C{QkOJvE"$N-S T@ɄI;m7t ]񛚚_)J@_)VZZ[tL8rR[[颮%˨^q(+hj~ IDAT$9$>g+p~]2$(9rp\JD;J 0bob1k/18Jo-o4RƋY=5M#g'\@2 ! 3}%;/KV$ JAY__Z Pׄ8Q?)twa p5 `2e%?W}L]F㹷s"CZ` N?BYS]x5cddE (UE@&v59 4lwJw)wqG9`:`" ٘|e%uLI" q$,_ Y6CY1RLPTPU:@˾ye)KY(KY^jxgY9 'q~5k$kg@SA)b|ԁ@@Q H=۷nzccv{衇qMܓS%ߺM[Nܱfa2Kd5 `6Tj*V_~<2n羚/;OrequOf۶mL6kגNٶmۘOd@IpѶLWF%'k8 :qihj b*ep-|pw߱O@5h`0 M42k pic!C&ì*mĬ-@.졕 )T v3}T;f_A~+r[V zՑUg.d=q#lhhm\M>H7?Ot Fj;(.5}4^l0,!fMR͛޽Us;-܂(\|\q$-{yγ::{ۚ3˩ӫ Yu /g>J*SK'X@ WɌlyQvEWgiIϚōo,bޙ7 rNAtX}ۺp8 V&wz+kmitXϏϫU`0go`VvӒG}u/{waݻxOc뮙UUT2: $FPs-xJ;I; a`F~f:9Nfؼ8 1&=ʦ_7q2(V[yI}g_X`_JM  .ytuuq]wIg$y}f42l'9p Pc6Su/fwH)N>,`p9#m Xt)x(M_r ?߼eI^7s o@~`0^q-ZݻohήNEO'$v0Z%۩P"' \ X\q0vbDfo>KgW{>.ihŮn7'|Tmyv_V +yn1?To^kyIgjƢ(5?ZO@)v-So8Rd YWe_  [6ρ=`p[ XI.H0y_x<֮]K[[}}}'dooK~,xnYT$=3=g:x2 SRw>5PT X V1|x<^nam۞-Vl)# @6oW6m3~#/op. qYs4 ]B`Y?[L{SFL@.L| * z2,[ EDEA_s۴ؿ "/Ap95?ZO]-9Y }W|KQUXoztӾ%U$~5vdy_?|.vO/QsEo~3ӦMӧO\s5vCr5p饗>#2lgpɩcYli΋.yO ^ fO:dUOκ1唙ؤ.Ro>Yc'|W`f>|cQ~qc1.nN*~yh?#b2;'>4߮e^ɫwhiYJ9 [Y`P;g';LyI]}E^w8uj)ծX+gvNJW,~Ѭp 8  J#>juY3f=bk׎tRfϞ=̜{2Zc{bDl^}dR.>*l,I̼9u3 Q̶Y%׾'s|!*-s:p Ѕ* 9+)&ĉ5n8+ZܚԤ ;svׄƷXdR*sT\F_،־J^iRD`|SWoORTJy&}رϼ\$*5З~l;<"B, xM-wOSlK?]) 9fU |GaJn}o~I|<%qn_ K+n^1G۪z'j'-gR8[Ny?fXV_~2 @WWO?4<2gr=|˗Q׿9%ȩx77̔Z=YgD_ /`-YvES<([3o>~{I5ês0yl<^,澊 MP &~gaf|qFyS+ΰ1)!c2o 2PIe~u^Me7W35|w= {8n & ƯvrҥsZrW) "KMˏ{>SG@Us 7ceu=?U{x<~,cR_7Jig-ioWXK;XaxǀGZOf2΂%~3qq$I8N4^p{|c{mq%7v\9 LibOu<~1YĿA(p_OaAc?w|կVB1H, mkF]P3qPU̿d(`yo_&s*G.T&t籰+]4tV69Mt9Tv'4QϼOJo\ɟ#Gc+VͿ'@Us;NWudn"Hx<ӵ9|ωPgtuX=3qoI`F r=/LarqGVo/ĉG?flRpM8B4ޘ+/w/.~߱&*2/̂SbuOa2\T~_u.~A ЇXJXwifvxFaHGC#{-nz?gU|om K<%*I%iNܠ?} {8~I>.:ݬo;ė>';d?)v藍pߡTVU 7RPUUڵk'99 ՘6LbֿW~9gA{ jug3kߪuց@Zg?/9teYf#tPU /IF$F,\жG+Zwu'?hS-/u(A|gѬoKrځbm{+/+/cD$NM׳d:{T}2/6K 1ߧ2>y'{]:M4ӧ0PYV9@KLR#w1$vuƉ?>e:gb7V f%э*$~ηמ(E1yzjL\a\٠ oM*_)H$zc\.8ǁ۲k7v_tXO_vro灯~ (U%OqWH׾5Λ7*Μ9ÓO>9>ndž{B9}euϻL@)Х#dCZO/ZgK Wc%o&ӄϽŋ?DDcxer.i,mpd 8QeiMVjC-[nfڏ2Rc#´L ,µoIڡܚA8)wtxLJFj|:v2d~z2|i)fpjk~/LGAZȈ cJVX G8{ 'dcà8J@=c͙e˖3f㓶.\xTYc<9ٵXMe*Z gZ`Q\/4d@qߗOrOD<~Pi$$FU,ïd2ϜTxdqU1x/w\rZ|{{s; 'slVJ_c; %+y]CYO6ϟ:H4o?)4Rcd.Y-_oLmm-'Ojdڴic$+q'^Y"0ܴ/lqi]PO=/j]nk[5̜ 3Kfrdw{j"qQygbKc <,R?|CAq߀ W&m]2޽I8UKy9(6p5&?[C.jXP%/0˟₪+Ҭ%cHC\N$gc>>6<ַ{H}4\?-?@lCr,WifY(J]y啎۷sL9֭[(Ì3waD]C6p9&׫#qMIѤ+Vs=pd2: ۥ&>7w8!d=  ӥ:Ϝ]-'tW?&LQD y!bS%!DWf ߔ?@l~XW EʽW%)G$Kf93[+6ЄbeHc;UQ^aUR0l91v??fבTg,6/K <9gŊ6ssu{W;^O}hkpz&"fFJBgd@Y!̤oG-Z\R뿘L\ +=40\cf aE*)1: x&79XfНߙ6_̵\74i,E`8b|u_џ~ePŸWrD?fo YH2Kn{/ IDATx<-zN]Q5d{[9%ܺЄW]=ToBsȩgOM kvWc|@CNLv0@ZU~?3f`Νʕ+Fú::t;we/=FS\l,:'%𞆣D\*.h(Ο=eu)>yhN(fko#Д&cMĭǶ*C'rw=SV͕ NMx}-]|C0*>+V0|f̘͛K.gլZG7|GN{9'POBIK3rǺ3t7E$ s|./gs|dKfs3QBS s܀վK'_C#!^mBk^ZXI^ZΫr|5/f;J6-8_!(|>kjkkl;TWW~Y?ZcR['K!MxJܜw.CnhԬhllu+++G?륯Yy{B!VZECCTjDK9#NH n1D6 2OD? D1&` Ɍi'RKо-7T)o!`0SUͰA_s9gEÂh~Z]]]… q .,X _Bf de f%;g6?It{&o?fqrR?O}|Sb#b10 .䗿%Nt{oGu^xsv/E{h<߯=ʁ%'QZy`^ey4\~# >~#-չf"%b3Sg+b?-/"2-``L%UUU!"o}[vjСCttt`#H TRμQ\C~~{`F sa²S9vIǗQWﶷ8YNc% ;GNn,O|;)M ~Xv}NdZ#6Fl<wބan)/")Hjsse rN浥ox.BഘPbD@?o)/&r&R{~N&=tڥwӦM.:˅HWVV*eYq %ou+#靝tvvN?꒎\‚ss.,n\x; aX^(I@f3;*{9k! "jjV[Vz{jֺW[mojp+ *JY9 $$$`:33Ϝgw6VqG/@/$82(~V ~:#8hp$dߑrn͉_zi&zu IiDeQuAqG,W>{[S?won] & xG]?B\!7rb'+`s  xQd(֜B LUq`eާߕm{@_N01qH SPj:!;W`A\ Qktn y^}t!+D0q|$= MM529&+Gw#аM̉!^ liS"88T8e,{F(((YO\:uã 'Z{[G~qk W\uSϜJ4G h6Z6o;By9H`6hԸo8ԡoa2)#?JG 2w.ơqTtpDOҿoǐBD t/]edn!Xn%MepawlH>/ߥ{σu~i.ZC A+H7$O BMhH)17vХ5m;v%͓#l,iyzPPP0tv*1:H 'ځ(,,${wmuũ5U iQ0􂥁.!ل#:iR}YA!-S_r`Ff_J rCAAi mZ \;-poJ^AtdU 3Fy],b[W<{-_47NB *#s2^(Hh!--(53<Ƴi pK+.4XBk[Z8 ԕ&n͈e?Jc?vۆ[_(((S6= ܵmZ[Q ;{ `2o)1BžuEYGFDt-1y<i$qՋ ??A ..;۲d{6 7dxr4Ԩz_!up^4>̆pIyzԂ!7e>:d0hd|/CpIr$\0iͶ4>^o}J;lXXM^Y6C~y6ˇUEܕ1Ԛsw=w 2F3;NKF6x:j_ .p]9Dp,Y𦁑uhl@d7ۇ~]`-aƐ*8Аv\PiH<2ժp`KA zК!7vRmaa!uuu̝;7}~-`&?я4hPӶ̙31cƴ=-L6zL |zDH#OXu~xk, B~ 5`T5I:^ ~?cH}Q:dŠBU IIW@j5>yO|x|0dÐ7jz 4M;-_QuPblޖѬ5xV?#q/n?CspAmV>ګ /v<.FUqu;9U,ʿLVNWRI\ YNl&䧿+0!m"4Ep@RZ1QKH&zuOCkfٙ6m;vUB֭[yyǎwڴiTVVslB:j-v] j1 w9':އ~)Ay6%wG ] EsVx6OO]1dO_Jՠma s]iNۻȃpArp鳦siJz3lXoLl'.r v~Ar\BctrLTաέ\ mJU J  dH%UkI$HLQ`^If_IA`noIQq^Y2 o,j=uK3}nMD ({Ude.]pҍ?:[1h~ | *b~?մ `BhC`vR.AFkU+;b\ ]hʗ@e)a'HOpcwш PC8-/ V|9,Hj@n\31 MgΜ9檾ZoпƏOVV1ЅLzaejSmTs':Gv10 jVH@p1 vO?J߭;-:(s7,|w 6~Y&OW)KgvڎY HPBJep9PU/Ahs~>c`h,ثR6I1jӏ vn8}&LIJ )lKr%>5c $9f/Tvx68U71 |r4:Oh=3R)pf RDCx1[,Xo_W˘ @8x3F À@ iWUEdC"q!Z.~md,kNC WRjfWOH Jb.¤-) x@IiH1 C: G vX>C&} ~/*3_~5k`Cꫯ>{g B# a̙g믿O>p++`Y7_t4S(#O),,4?$TӎoPŹ;wp$޿ͽK3O;.jЊK/y/rB-߿\7#9X67aWj^z%VScZlJQWza>Jؗغ/e8`\범aLLPTAZ(2J6^Rmv+M&8, I7T2qCrdNAA鐛/9÷56 d,O`]=e D[xգR79kkHkU 1)_Ѐ wI 5g2Ds,v_]x\g\ZT/cSMsQDP7;a4#ju~[m`ɘdOzq*ÈRfLseF3d>ޭ*FX*->^J]^e8gp7eRRߎD( ^t܄/m*Q)J%ZߵWRb) E`!gyok#]!\"'E3 ٢8_̅^i\G rW^y%eee!HLL䪫bĈMA(;>]& 0ґWPChwlYY7hŵꂂ->l"9q ߾[d1y~ڜ[_)3'LKkuɓ>ϛODxǎ;M\ 2oh[Ųט.X as2>pnH;SMl~INg>0>GPC0bL9ۡdg9ᄂSSN0@;lHV($|a=.#pܒK[غK&qDžIUc ;TA'>;SԔY!6;i\;  i/K2DpϮ ZU?ZC+۾M=kaO:gK¶U}SdxnZ !nF5V\a;i76hB2ӱ)A#۸7#ί ( c8x_Gr?ӉbK 8s\#K<%% O@CW 6jA-5wxѿuRK*;=?( |GC.:}J=V4OXUܕB@ x?jkkٹs'̺tCg;+xW ; (ߍe[F_WV*B s*P [h U2m-ط]÷l/A7 ?|ΡnV !~0#G UsTo d콱wN#f$f+IzNOcwjҤHݩ+?wr0KwIHs[d0 !6!r}VlC̛bױ0'TDي|H5«y[v`'Ү{{0BIzamN> Ēh}n.((X]GjMlYݰ 3V"Kjnp!O]B),,駞gz.q`w lOUfԾc@_ݥ R x4؞uc.m r4̵4>zGF/NymgoϒfE.rIoTڟE;/UXI"A:.i!|) 2[4bkCH $L@ qmGsL\ZBq\ >vdu `͗$ʮqǙw{0kj .0x~/pTUkϾWkBkg03D!DyV}om<=o믳jx~.D^xr$]ʼŵ KTC|%>8^kiX1CZ#2ʡIm̓ڸ1A*?{_`n7yHIƄ;$}Wg2/:-h@8~Ϧ)1سoɢѱؾ^wj" j ZoX7k ɘr)wQT]S[xυ"ә Ί[{Pn2T@)ĒuMD]6;M~$- mJII<{cRᑶߝz wXof7ķǤXOcZ&}Ѻ>* uuu\wuvi:^4%z5Faw}R$wj| )((x<LWPP:L \ԜI_GrS;Ӈqi2+3Bq3Cܓ~a'PJ<'nJT:#T ]Ӡ֭j4RBMWtl[[u֙8a(Mku6ڣ)@ q6~1%05b:B'e^V )3h`fE8_r!HljF]iɆ^(R8i/GV`;kegL.׸Ts IDATpC VAF0(0`?|w[mo{.jADAZOڱM+MBÅHL ub *c.ƺc,.i1Laz-NK*))$54oMUUW\TVVMVV6mc|M e!4oA羧ߵ&ȷ0XPPT!q"+`bF\DZ:{uh$rUMXpxo,cݰWCZˮ@eU{;!dMv'܃#%mm('Xƺ PCJ Z Ӿ yC$"=5Ѭyk H WZ]LiSo*{rwy}CR]6ggSu5Mw)\J1yQc?"<:A|OU'kN)^Aݰ9w;zkΒccX@ HR`Gm.B | k:Ŧ\1Cr 9N6*R~~>?0m=3fikl߾D͛GVV'NdĉG>q`/922d]KQ" 4cgo),, a0* ,uv͆ 0aRZZޒtNҎyBZ3xp {θ_|lW:]uio15H҇+0~/K>Er Uǣ+xUHȊ[gbJsp-{TBOfsc N,`胸 ސۏӏӁp;&Im)[-xc!AT򿵎FcJ o^c00xh exv*((U ɲɷM;oD < ߌ_iGo74S ,1X0kSPg}Fծ ^*'+V h9\pYJʮ]l 9jY_ 9Sai,VVW+3d|9:]pEnsMYqdcO 68b;IECO[@3/`._p[I,YG8{X8QYhv~rBWRmklz^W%mN:QB1)-!&>#z"@ ].['!OAb^f/q9ޣ-gJ$c\TsG|sM_0u+o7#߂ER*4UdDAAB8Ɵ?7bEzw*N p%#진!0e1n8:|ehwuqPmip~Uƣ.UOWe*L5pU@+*aD1`jg8e5KrH _|Pm XJNz)Y|"bSM"( ̀dPP썸0 87G= @FU W"v 4 ,.@t4> 0d$tK?F#:M73d_O v'uc?dɒ%m6^z%}~_i&V\ʕ+[~a}Qz){96n}󎃭y^ UKUzp~#/gs򽲣[XX>n:ppgƟ:WO0 yxH`?ɔ!B=n߿5i`q6FB>썸6O)^qT6!ވ1aE/_oMY.; ;RӗB[iM7;L7&QZ&h* ?bC_ 'wuIٿ"W|\wuM͞=eLn"9Nzz:m"=,|bEt,Ksȝ/.WIbk)a!׌n& Z˔o\Om?\sGpx<.[tW]{XCR0FSyH=L.x%~jo쀩eIqc`8n 96WuJJ&I\n0\0hô k iYWO4LN~%~sMlMou!c4&T GbrhRez=85LS'$a\hT/v?݌;+$, 6G_4_#MֺP߿rqff&E/ąkbVYnWApw]MK3#.|$u*{X < khcQE Uo`C0.v(`g Ɇ-iJPVv3`*,l([k(Xj?]rhçTQy9xK<(9GÌ*+quU* l(-}v:h[Ͷ9+QOK!2=,$O`jMuc6&xċ'ƕjKH\ |H0G|2`Kp"'VΉ~&NmHl0ҎGd׌+J'lS  J[֩u|B2SO?X#`sxe /4XM- WmaSs4kTd1>vT}jf X,YѶq}4n6O[oo:xÆU:_vHݰ ңʜ)]vI"5My|4<1J E^[ 9ɦj*{ 3b má{f+ /Ҳ$;$J>xKdF$ o x-4ʎtlR'cK)j=jکaܕ:AG{9 aUJS,fo$nux}gz{-:<գ Uȟ\K"D# I2{h{Q=Oį54&*&:d"^_L'=iʟX2Z V+;vn>xYqGe{#L<2N$D'$*,"]D⮁^t1mee%唕a]GGF;d|g,83p}O/*X>nI鶛4x*௼⸎Ky}lnyn{4 7ZɆgp&~JK[VR?BY$MJb•U6Qkro^h3i;PRƎ"A,:WPm)XdѤJ\dTvbɷؾ 3/UsT^Q 瀀W&ͮAU}Z-Sףu'%_dp!#n]8jLc<@5xMxS(sWzKv#|i L7c=Q\ʮ]7i$fP^{x%GuF7_/Y{q^ >J,f&}!ɿ/pYgrofmKSL_:$wgƣ M+v(`o" lscVǶnoi̹f~MI한66ذJ# i0,!$4ԈNErWThBz@#3/QQcfڸ+[.h(PChIpxnb6ӣL1]V ݳr~=XVtcHX=eyDG5D݂co-]# \pj֯_tv65Oۻ8\m](XqĔQD[42-qI{z7_\}֯_Ϲ>`Zt]oQ)pҤI 2)%Bk,Z{cc3pb&{@GI'wTUvMo]n&N-߿xCGKE ?RY=&G la@ix-x5., 9 {5yQp96#$)54*[㨞ٵY}oX\:Eyk.z@-t9/&SrFd/ߨuQ}{&p~$au7#+TSSb"0%=PwP7h8X?hTXz &0Аh8%&+B/fǦX[uЅNLŁ+ -ݏnw ֨m~iw>r8~k^*!, v&߸(ʀV~(?m݂DI9 dO뱯C.8wNN' ~1EPO佃CH&nvq@5jLLvr]=u`4*CUE{߮Kڸ㚿%tFQC<$c"ETZ4rK`#-́BSTitt=57n̓KaL'GռJh44B9Lđ6tp$艘.C^OMu =Ps!ǟj0G0-ۅ[Yw6!۶X,>UJjҗeR OIwޚߞ6<X Etpa\MMG3,Mav!቟iS_s3CIiSq"Z-mF$&ŕBĎ/{{O {~ֳˇ}{ŸPA=Z|)M뽑^,U߿y@[ i8A lȗ;vN(K_D͂˾JWJݗer㮻:ߓR_^ _fE/zqVMF<^μXkW=ovVu[C@} (TT9pCUt-P1HIE/8FsNOee%`)%>}ljӋ^]G Ym= oUߚR'R9Wk!tp{WS_o_=O>$~#GqyU^GÑ#`AZ'#μ\ ׏XUqh'lneڿ]ɩi9O\μ|Uwֹ~oJ5; (ugnC`/ƧqTq>0զ7[WZ@FMJ;Œ~ 6nߘ?&!mu#amLI1ߘu,oޝ55tIzaaa9_J[oŭފ_o?~-`wٴr b 3dhYX _~$⏩i-Z믿NCCCm+FU>b_Fɛ ~o]|{~<Wk]y E5Δ#})}v*Ϳj`+' zfk$.qM NہP\ښo67_8ZOZmkJm+X~~~qdߑ{Iߞ]ѷdׄc%?8HJJv75,L$##X,+tMZ|iSK_{o9g֓> E7ŕqy@k5ܯݾlbmѣYzQ@s,7>:kW=._=8j8ߛnxs!Ny@n[StT| dk[@z)BϏ9'Q}'4l+`W.gsNoE[߸1gOOP.'O^X7qoHn4SRSSCii)@E5Ϥ$|>q6~KKEjj*K.eСjB y'5k}W FfӦ"OV+ʛ4QFw&~i?jR#6Dp$xt"pig:Ae>/풒yWk{{Rn^Ep* '[9v :4ILL׿5֭cӦM̟?g}<L0֮]˴iӈD"]>ŋ1b6D>nhi0M!@^{ 3f`ƌ /HKKs% |e:=1JWF Q@f4T~;qmYI7@^T cRցV" \ʝ=*h]Rv`G"\pk׮e!x<8pI&nݺc[|޷Oԙb -ͬkGX*2'ut{xȧu4Ld}a˖-3UV5iuuu׏H$Bjj*a0uTYv-}ŶmnW@FH 0my3vX^WD"MϞ={[f <|k_N`wY&ͷڣ?_EqRrPćK1 owb׻bV$IGHM(>&DmoKAmLeKH Ed3ga0c H))**?䢋.jW,s$] ƶ౸U硸}_Qӿ!n1I|? < ,F_OdtF%cqqގ-gYElx@@bJRL´SaJ3PRzs?t 4e#[r޲ۀ߼\l>|P~b"~Dɟ/VV.WO lmދX hooG?QtttoK//zTUoUCz+P^O%zW#V*\k:y} b ~}^ @;Y2XmSSSd2 Ya&A@Xmۈbؽ{7vڅg}iPK^T^BS oqg?//EA{{;|A|޽x;.<Ýwމ7MxЇՅ\}{=߭OlSQ?=s[:ox$dew,'VV_[֜Y~ތ nsOـ宼ЮU@5:r;---|2.^FH{A"__s#p |Yԓ,kX8(Wwx;t_hđ$ ssslqe$  tk\g!IZOÖaŋO~8{lwM7wwߏ߁$I򗿌/| 0Mԧ> cTq||<TUeTCVN|6`˟|3FH_rH2c\_/ GY2pfP4TZ9[nAKK b1D"WBQtvvP(Օ~ˊ xaUVXq}gJի.|Gi XF( RvYvui$IBT,ˈD"me= )* mۈ4|Ÿ@e9s&,_3(x $ À(Go6>O~7q|ӟ~xN]W&gE^f~WƊ1B'M~]ՈIة-||jǫZh =яz(H^TZP4AfeOs]4F)Կv?${mPU5\vߵk:;;199V8dW芰E;/Z=zԧpe(Ox} tw(xbk =^|EtwwСCx1;; 0p*sW_,be% Y >z<bB=V6+-$*U ء~o>[~+JBaNP^D뎫G?xnB4Cێ?yg%X g Oï~[u?Qy}킷v?lpDQ(owvvbffiqXՔ%jt+aہ;[oى'D"$,'?I!.]OS;v gqw㮻Bkk+^~ec=K>{q|իWw^LOO?GFonox$&,o2O,{c6- $h,;}yfhe=~o௑z=hdFK_GvI:::0>>o,̙3سg4MÏc>}X y{f?Z>@CCwuWM ._2N]‡>!9sT ?OQ.nV8tv؁;v`xxo|x[Ѿɓ?-M<|,H/*S0Y.]]޿P &@]~Dp->ebXk~V G"o$xCc?_((?z5 hdFv \sG?~Յ9ض__ٳgO"gr >ܹs/D"> G?8X }/&''m Y  ۷/Ν;08ܹsFhmm]w݅~ݛ/w^}r+hkX8 ow@BgWJ% ˱ߟ>{}9KU?447GyaxߖN3u.e| |G/^%x_e@oϕJePN\fďogd;B_qxgyO>$.\> YiR$Ii(4 "… {ow ҄ އ3VTò8%WPW?>%*Ž]=;}94oߎ*]KAwAxse,$^:p$?[WZC?>__EWW^y<䓰mO<>a޽a݀|]w݅__N:;Ǐi_E؍^g]& J#P4"hSG[ (r};ξSKe;?)lM67lwnݻT e~7,W}cH&O~}s={ .] ⡇BP~=zgp}W_ťK|;nÿKD./ W|P=p@`羏8#Vq?ǞM߿[ewG;oz~AqGO>?/7ϣv>*=Ve{l*Mtb8(l?xBGgkS_ߺ7? /l&[yzkx۶m|Ư_*ẃ x]qJW\m|3A&.$/2\9 ͘/ v;:V,>r"o?\>mmmv /l}w-FN>/ש T  GPu 8enߝq#Gu&DT~vmpw;\:;wv?@E {X8gތA%I|s_OulO>urv{ޕJ] wVX~Kz?%MkO%P*/Ӊ_1Kߪ\V/q`5uhFgogbEoo5z2Xxehz|{V@{,~9[_''{z3˿$VU^#@AժwT.~:}kw= & SX>ovbzzN>]H+ٓ=~C}*^=\~]-dd'Ch']V6紕k=w|nߺ~ b[7|3 ".^۶q-|˗Æ\,G1??AŽr{Akk+'oiY2= 2dT>MmS5݁k_ym}7qBֳo> O~@\+JpP~VmD"C4HyJ%#LBxQa6< [k;=`{^NB EBA2ʎ†4,<(e("KyLOn]ׅiaWyXX,H$qpʕI8PmB۶iZ/ ߙQR[t@UDT <ի, xՋa @B5=˲ ].(fPWd:;BPgމD$aff/n6q(VLOOT*#C4p?χ?Hq8 $I D"Y=  y(m* X~@0,6r\˅nMBt#™~fBJ@:a@$nL/ᄒfz+˯mm§VAcIT\_fQ$E+hjP6dMEH,cn~w($f?qʲ~@+Ű]\EQ¥yu,[.]yp]b1| T6= ope̟3!T]C nɅ=c4QD⍭Rpy.2`Oj`BkA$K%bD5]^1$); yvIFiN yp"Қq" J$ɅH߼# ;=f,E?Tn(0._t>z0y%s#``Ϟ=PUb1,u r5 (b*сd2.(( E{@ii0^@[a])*AI#Rհ.-g mo @~d@u˳<3/ʄ?Oۇ?vv6n" pBM6w$XX~ VTD3Br"%bWY)EȪE-l(ͫ%Hua ']_4'׽%0U\%{,߻d`Wmmm,+F, ?$ ǩqɲbRRQ( 4Mib(JAgggm_X.JW 2\ۅ<<ǟ+IPwPvh5xP*› XFHxb9 p+~ h[ IDATu?S9S[e̙Q|?zw!RUSg"g!gE%Ē1V3۲¿[ gxB]Dk/ 1< AbuQɃ$ """% &DeWv(\,˂q2TEA2X4(aꕙN؟yP---0MxmmmP$sssr(a`sNp_X|>RT2ri-U- T][گ}o!OTQ/ /Dc;;;GF%`,eUB:.DE|B -i$6MwwIry:L\(wV( 8p`0c 5xQEa\a[?o@Ԥp@G|O<&JCY(\l#  ]S8C(Ku(iPWv k%)KbV~JU:UK"rK ,X));J.Yg`jzzռ۶6 jmm)d@4\?;; 0zHR $[?H.emC+3:<(@گ{ },/\߭/J՞Z x:HFH&iV/J"dYڒCu`Uiq_ %!+WLs]wI7%%"˗qq| UUEW*.W Ah4ZrȲH$bX,V8DQ AF>sW@T~ꙺWy0 A~1@`qU|J`Qb[g@X)׏'JlU87k./{U++u t<~}UZzW.1]XDu]VS%<ǟH$"D,LNN\.iTJX mmm󘝝EXD{{;8l}5jp=1l[3_6@ __`Ȼ@3 d<<ؿ>_mUME.#A%%Dc-?o1>c@\ u' ౫rM+ PE"$]%W*tE#?Smj$IB<|> d ^$IDPOݻwqLOO#χP(®A,C$A.åKz EGBA0ٯ:FWW}¹lA씁)[ W&&ĵsggCIT2vx<vDTfggw^XASY(Jy133&+Aa؃r=+O(O21*֌VE 5~V+5JE OU~&}aC4<<\1&! v_5$(2✶@] @E/YD\hu &]__nT(s͈b̼2( mzjPblGG4M(H$hooHRBGGGTTD"عs'ى6BءY. e 1!s(](ra@uaUT^TBR Wlf?W o6-ȫ e krh[FT:073\!Aʰ <!R\w-u"( HWE@] S}nf$ՁU9 `6^x1< "(Ҵaffb1lD%|>d2 `F 8- 28N JdXX,bΝ6<w! P uo,B#ROJ6` @uu)ɻ .V ޼ K3V {%fo! ¶lί9hMMN# ٞD-H,)sŕz%cLVVg!"XC]p bi"dHo$@\% |8y_&@8Dam`/>@:dr|>BA0;;`~~33ttt,J%#[ O%]μKy@[Pn|g$@=ʗEWE;oʅ8nZJ}7&y3C!_DhAEUЦbRnC]DE#**K?$\JĆ)/<=hWM^87] v&m%W6C\p ]Uݔ𖤃y3MA4+}Uꕂy?Xi$i<0j}A_Kv킦ism;l$2; "fggT*a׮]#B^ey_IX(gR\.'gC!U|D@qi<xRZ$^gB6bRZTEиZV*5gtK %b/" 7*zHH Uic" CZq.w?o]4O’E(0Vw$ xY xk,*JXwqaDvb1EJ@Cze@9P3P(077D"D"UU+˗tBLByg e׫ 2  B/81`@i硘/5jԆ8~@Ձ(:f!H lps %2hrZe *@$҂x<_ BEyAP(`YvY4"@)IJ!*.m d@쒪N,*5\;Ƿw#9? !E]huC1p333Z"bL^@uuD"bUUkN9^+9 ᩄ`lPӾ'cbQ=/t /.jGh}oBZ+q- G,BP@"EXmѿ oq o@Ӵ0X* UAO^߫YLֿ᷄%m%!wpԿ|/!du _~~KzO&ﯹJ0<< 0066%TO?_>s۶tt:]냪d2fFooo~F駟~t7gy>%#3`7g7@B1 u{Bnv-|^?!48yy=& }{B_ `g7ֿۆa@XZ2H$iZxlV5O?׆Ss2uŷ=ߏL&S"J|=Ju5Ġ~駿Mon̗\.#G@U՚BMQPX:֜g~iM2VBDXڲSccc8uԒ(`VO?׈ ?yhhzןL&166X07Z6E:;RUGKUo<4qiO?7] \,W ز,L&l6nYO?O? CCC!rCJBB!0 Be+.9a n$ h[U\O?Os5>zhxn#L&l6nYO?O? CCC!rCJBB!0 Be+.9a n$ h[U\O?Os5>zhxn#L&l6nYO?O? CCC!rCJBB!0 Be+.9a n$ h[U\O?Os5>zhxn#>>>>>{8yS$ʲL :zW&@""""""b ""dns^Ղ]BpW!tx}{{ۿp$*BUURrRWWWZ#ޫ:]__3ZDT^]ι gExݎ6mǽ?۶G Q,Ktss3z:JM+v웰֪,K5Mo 7}uޱ~]?g4ڶۭٙ=SD dxb4MtO:y;u-c...$Bޫi sϻ%*EQ4MUZ~al$""b """"""b """"""b """"""b """"""b """""":i_ukcXAl1ZZczss*\Y:UUKhj6key?M4M#km񮺮DZPAu]AJY{^tzg1rΩѭB?DQ,2giZvg \zon3즐b!T2|8a(RQrW۶l6{SL>>>>>>{8yS$ʲL :zW&@""""""b ""dns^Ղ]BpW!tx}{{ۿp$*BUURrRWWWZ#ޫ:]__3ZDT^]ι gExݎ6mǽ?۶G Q,Ktss3z:JM+v웰֪,K5Mo 7}uޱ~]?g4ڶۭٙ=SD dxb4MtO:y;u-c...$Bޫi sϻ%*EQ4MUZ~al$""b """"""b """"""b """"""b """"""b """""":i_ukcXAl1ZZczss*\Y:UUKhj6key?M4M#km񮺮DZPAu]AJY{^tzg1rΩѭB?DQ,2giZvg \zon3즐b!T2|8a(RQrW۶l6{SL>>>>>>{8yS$ʲL :zW&@""""""b ""dns^Ղ]BpW!tx}{{ۿp$*BUURrRWWWZ#ޫ:]__3ZDT^]ι gExݎ6mǽ?۶G Q,Ktss3z:JM+v웰֪,K5Mo 7}uޱ~]?g4ڶۭٙ=SD dxb4MtO:y;u-c...$Bޫi sϻ%*EQ4MUZ~al$""b """"""b """"""b """"""b """"""b """""":i_ukcXAl1ZZczss*\Y:UUKhj6key?M4M#km񮺮DZPAu]AJY{^tzg1rΩѭB?DQ,2giZvg \zon3즐b!T2|8a(RQrW۶l6{SL>>>>>>{8yS$ʲL :zW&@""""""b ""dns^Ղ]BpW!tx}{{ۿp$*BUURrRWWWZ#ޫ:]__3ZDT^]ι gExݎ6mǽ?۶G Q,Ktss3z:JM+v웰֪,K5Mo 7}uޱ~]?g4ڶۭٙ=SD dxb4MtO:y;u-c...$Bޫi sϻ%*EQ4MUZ~al$""b """"""b """"""?>]GQIENDB`tiled-0.14.2/src/plugins/flare/000077500000000000000000000000001260670167100162465ustar00rootroot00000000000000tiled-0.14.2/src/plugins/flare/flare.pro000066400000000000000000000002431260670167100200600ustar00rootroot00000000000000include(../plugin.pri) DEFINES += FLARE_LIBRARY HEADERS += \ flare_global.h \ flareplugin.h SOURCES += \ flareplugin.cpp OTHER_FILES = plugin.json tiled-0.14.2/src/plugins/flare/flare.qbs000066400000000000000000000002451260670167100200470ustar00rootroot00000000000000import qbs 1.0 TiledPlugin { cpp.defines: ["FLARE_LIBRARY"] files: [ "flare_global.h", "flareplugin.cpp", "flareplugin.h", ] } tiled-0.14.2/src/plugins/flare/flare_global.h000066400000000000000000000020401260670167100210240ustar00rootroot00000000000000/* * Flare Tiled Plugin * Copyright 2010, Jaderamiso * Copyright 2011, Stefan Beller * * This file is part of Tiled. * * 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, see . */ #ifndef FLARE_GLOBAL_H #define FLARE_GLOBAL_H #include #if defined(FLARE_LIBRARY) # define FLARESHARED_EXPORT Q_DECL_EXPORT #else # define FLARESHARED_EXPORT Q_DECL_IMPORT #endif #endif // FLARE_GLOBAL_H tiled-0.14.2/src/plugins/flare/flareplugin.cpp000066400000000000000000000335771260670167100213010ustar00rootroot00000000000000/* * Flare Tiled Plugin * Copyright 2010, Jaderamiso * Copyright 2011, Stefan Beller * Copyright 2011, Clint Bellanger * * This file is part of Tiled. * * 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, see . */ #include "flareplugin.h" #include "gidmapper.h" #include "map.h" #include "mapobject.h" #include "tile.h" #include "tilelayer.h" #include "tileset.h" #include "objectgroup.h" #include #include #include #include #include #include using namespace Flare; using namespace Tiled; FlarePlugin::FlarePlugin() { } Tiled::Map *FlarePlugin::read(const QString &fileName) { QFile file(fileName); if (!file.open (QIODevice::ReadOnly)) { mError = tr("Could not open file for reading."); return nullptr; } // default to values of the original flare alpha game. QScopedPointer map(new Map(Map::Isometric, 256, 256, 64, 32)); QTextStream stream (&file); QString line; QString sectionName; bool newsection = false; QString path = QFileInfo(file).absolutePath(); int base = 10; GidMapper gidMapper; int gid = 1; TileLayer *tilelayer = nullptr; ObjectGroup *objectgroup = nullptr; MapObject *mapobject = nullptr; bool tilesetsSectionFound = false; bool headerSectionFound = false; bool tilelayerSectionFound = false; // tile layer or objects while (!stream.atEnd()) { line = stream.readLine(); if (!line.length()) continue; QChar startsWith = line.at(0); if (startsWith == QChar('[')) { sectionName = line.mid(1, line.indexOf(QChar(']')) - 1); newsection = true; continue; } if (sectionName == QLatin1String("header")) { headerSectionFound = true; //get map properties int epos = line.indexOf(QChar('=')); if (epos != -1) { QString key = line.left(epos).trimmed(); QString value = line.mid(epos + 1, -1).trimmed(); if (key == QLatin1String("width")) map->setWidth(value.toInt()); else if (key == QLatin1String("height")) map->setHeight(value.toInt()); else if (key == QLatin1String("tilewidth")) map->setTileWidth(value.toInt()); else if (key == QLatin1String("tileheight")) map->setTileHeight(value.toInt()); else if (key == QLatin1String("orientation")) map->setOrientation(orientationFromString(value)); else map->setProperty(key, value); } } else if (sectionName == QLatin1String("tilesets")) { tilesetsSectionFound = true; int epos = line.indexOf(QChar('=')); QString key = line.left(epos).trimmed(); QString value = line.mid(epos + 1, -1).trimmed(); if (key == QLatin1String("tileset")) { QStringList list = value.split(QChar(',')); QString absoluteSource(list.first()); if (QDir::isRelativePath(absoluteSource)) absoluteSource = path + QLatin1Char('/') + absoluteSource; int tilesetwidth = 0; int tilesetheight = 0; if (list.size() > 2) { tilesetwidth = list[1].toInt(); tilesetheight = list[2].toInt(); } SharedTileset tileset(Tileset::create(QFileInfo(absoluteSource).fileName(), tilesetwidth, tilesetheight)); bool ok = tileset->loadFromImage(absoluteSource); if (!ok) { mError = tr("Error loading tileset %1, which expands to %2. Path not found!") .arg(list[0], absoluteSource); return nullptr; } else { if (list.size() > 4) tileset->setTileOffset(QPoint(list[3].toInt(),list[4].toInt())); gidMapper.insert(gid, tileset.data()); if (list.size() > 5) { gid += list[5].toInt(); } else { gid += tileset->tileCount(); } map->addTileset(tileset); } } } else if (sectionName == QLatin1String("layer")) { if (!tilesetsSectionFound) { mError = tr("No tilesets section found before layer section."); return nullptr; } tilelayerSectionFound = true; int epos = line.indexOf(QChar('=')); if (epos != -1) { QString key = line.left(epos).trimmed(); QString value = line.mid(epos + 1, -1).trimmed(); if (key == QLatin1String("type")) { tilelayer = new TileLayer(value, 0, 0, map->width(),map->height()); map->addLayer(tilelayer); } else if (key == QLatin1String("format")) { if (value == QLatin1String("dec")) { base = 10; } else if (value == QLatin1String("hex")) { base = 16; } } else if (key == QLatin1String("data")) { for (int y=0; y < map->height(); y++) { line = stream.readLine(); QStringList l = line.split(QChar(',')); for (int x=0; x < qMin(map->width(), l.size()); x++) { bool ok; int tileid = l[x].toInt(nullptr, base); Cell c = gidMapper.gidToCell(tileid, ok); if (!ok) { mError += tr("Error mapping tile id %1.").arg(tileid); return nullptr; } tilelayer->setCell(x, y, c); } } } else { tilelayer->setProperty(key, value); } } } else { if (newsection) { if (map->indexOfLayer(sectionName) == -1) { objectgroup = new ObjectGroup(sectionName, 0,0,map->width(), map->height()); map->addLayer(objectgroup); } else { objectgroup = dynamic_cast(map->layerAt(map->indexOfLayer(sectionName))); } mapobject = new MapObject(); objectgroup->addObject(mapobject); newsection = false; } if (!mapobject) continue; if (startsWith == QChar('#')) { QString name = line.mid(1).trimmed(); mapobject->setName(name); } int epos = line.indexOf(QChar('=')); if (epos != -1) { QString key = line.left(epos).trimmed(); QString value = line.mid(epos + 1, -1).trimmed(); if (key == QLatin1String("type")) { mapobject->setType(value); } else if (key == QLatin1String("location")) { QStringList loc = value.split(QChar(',')); float x,y; int w,h; if (map->orientation() == Map::Orthogonal) { x = loc[0].toFloat()*map->tileWidth(); y = loc[1].toFloat()*map->tileHeight(); if (loc.size() > 3) { w = loc[2].toInt()*map->tileWidth(); h = loc[3].toInt()*map->tileHeight(); } else { w = map->tileWidth(); h = map->tileHeight(); } } else { x = loc[0].toFloat()*map->tileHeight(); y = loc[1].toFloat()*map->tileHeight(); if (loc.size() > 3) { w = loc[2].toInt()*map->tileHeight(); h = loc[3].toInt()*map->tileHeight(); } else { w = h = map->tileHeight(); } } mapobject->setPosition(QPointF(x, y)); mapobject->setSize(w, h); } else { mapobject->setProperty(key, value); } } } } if (!headerSectionFound || !tilesetsSectionFound || !tilelayerSectionFound) { mError = tr("This seems to be no valid flare map. " "A Flare map consists of at least a header " "section, a tileset section and one tile layer."); return nullptr; } return map.take(); } bool FlarePlugin::supportsFile(const QString &fileName) const { return QFileInfo(fileName).suffix() == QLatin1String("txt"); } QString FlarePlugin::nameFilter() const { return tr("Flare map files (*.txt)"); } QString FlarePlugin::errorString() const { return mError; } bool FlarePlugin::write(const Tiled::Map *map, const QString &fileName) { QSaveFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) { mError = tr("Could not open file for writing."); return false; } QTextStream out(&file); out.setCodec("UTF-8"); const int mapWidth = map->width(); const int mapHeight = map->height(); // write [header] out << "[header]\n"; out << "width=" << mapWidth << "\n"; out << "height=" << mapHeight << "\n"; out << "tilewidth=" << map->tileWidth() << "\n"; out << "tileheight=" << map->tileHeight() << "\n"; out << "orientation=" << orientationToString(map->orientation()) << "\n"; // write all properties for this map Properties::const_iterator it = map->properties().constBegin(); Properties::const_iterator it_end = map->properties().constEnd(); for (; it != it_end; ++it) { out << it.key() << "=" << it.value() << "\n"; } out << "\n"; QDir mapDir = QFileInfo(fileName).absoluteDir(); out << "[tilesets]\n"; for (const SharedTileset &tileset : map->tilesets()) { const QString &imageSource = tileset->imageSource(); QString source = mapDir.relativeFilePath(imageSource); out << "tileset=" << source << "," << tileset->tileWidth() << "," << tileset->tileHeight() << "," << tileset->tileOffset().x() << "," << tileset->tileOffset().y() << "\n"; } out << "\n"; GidMapper gidMapper(map->tilesets()); // write layers for (Layer *layer : map->layers()) { if (TileLayer *tileLayer = layer->asTileLayer()) { out << "[layer]\n"; out << "type=" << layer->name() << "\n"; out << "data=\n"; for (int y = 0; y < mapHeight; ++y) { for (int x = 0; x < mapWidth; ++x) { Cell t = tileLayer->cellAt(x, y); int id = 0; if (t.tile) id = gidMapper.cellToGid(t); out << id; if (x < mapWidth - 1) out << ","; } if (y < mapHeight - 1) out << ","; out << "\n"; } out << "\n"; } if (ObjectGroup *group = layer->asObjectGroup()) { for (const MapObject *o : group->objects()) { if (!o->type().isEmpty()) { out << "[" << group->name() << "]\n"; // display object name as comment if (!o->name().isEmpty()) out << "# " << o->name() << "\n"; out << "type=" << o->type() << "\n"; int x,y,w,h; if (map->orientation() == Map::Orthogonal) { x = o->x()/map->tileWidth(); y = o->y()/map->tileHeight(); w = o->width()/map->tileWidth(); h = o->height()/map->tileHeight(); } else { x = o->x()/map->tileHeight(); y = o->y()/map->tileHeight(); w = o->width()/map->tileHeight(); h = o->height()/map->tileHeight(); } out << "location=" << x << "," << y; out << "," << w << "," << h << "\n"; // write all properties for this object Properties::const_iterator it = o->properties().constBegin(); Properties::const_iterator it_end = o->properties().constEnd(); for (; it != it_end; ++it) { out << it.key() << "=" << it.value() << "\n"; } out << "\n"; } } } } if (!file.commit()) { mError = file.errorString(); return false; } return true; } tiled-0.14.2/src/plugins/flare/flareplugin.h000066400000000000000000000030151260670167100207260ustar00rootroot00000000000000/* * Flare Tiled Plugin * Copyright 2010, Jaderamiso * Copyright 2011, Stefan Beller * * This file is part of Tiled. * * 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, see . */ #ifndef FLAREPLUGIN_H #define FLAREPLUGIN_H #include "flare_global.h" #include "mapformat.h" #include #include namespace Flare { class FLARESHARED_EXPORT FlarePlugin : public Tiled::MapFormat { Q_OBJECT Q_INTERFACES(Tiled::MapFormat) Q_PLUGIN_METADATA(IID "org.mapeditor.MapFormat" FILE "plugin.json") public: FlarePlugin(); Tiled::Map *read(const QString &fileName) override; bool supportsFile(const QString &fileName) const override; bool write(const Tiled::Map *map, const QString &fileName) override; QString nameFilter() const override; QString errorString() const override; private: QString mError; }; } // namespace Flare #endif // FLAREPLUGIN_H tiled-0.14.2/src/plugins/flare/plugin.json000066400000000000000000000000301260670167100204300ustar00rootroot00000000000000{ "Keys": [ "flare" ] } tiled-0.14.2/src/plugins/json/000077500000000000000000000000001260670167100161265ustar00rootroot00000000000000tiled-0.14.2/src/plugins/json/json.pro000066400000000000000000000002541260670167100176220ustar00rootroot00000000000000include(../plugin.pri) DEFINES += JSON_LIBRARY SOURCES += jsonplugin.cpp \ qjsonparser/json.cpp HEADERS += jsonplugin.h \ json_global.h \ qjsonparser/json.h tiled-0.14.2/src/plugins/json/json.qbs000066400000000000000000000003371260670167100176110ustar00rootroot00000000000000import qbs 1.0 TiledPlugin { cpp.defines: ["JSON_LIBRARY"] files: [ "json_global.h", "jsonplugin.cpp", "jsonplugin.h", "qjsonparser/json.cpp", "qjsonparser/json.h", ] } tiled-0.14.2/src/plugins/json/json_global.h000066400000000000000000000020651260670167100205730ustar00rootroot00000000000000/* * JSON Tiled Plugin * Copyright 2011, Porfírio José Pereira Ribeiro * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef JSON_GLOBAL_H #define JSON_GLOBAL_H #include #if defined(JSON_LIBRARY) # define JSONSHARED_EXPORT Q_DECL_EXPORT #else # define JSONSHARED_EXPORT Q_DECL_IMPORT #endif #endif // JSON_GLOBAL_H tiled-0.14.2/src/plugins/json/jsonplugin.cpp000066400000000000000000000153451260670167100210320ustar00rootroot00000000000000/* * JSON Tiled Plugin * Copyright 2011, Porfírio José Pereira Ribeiro * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "jsonplugin.h" #include "maptovariantconverter.h" #include "varianttomapconverter.h" #include "qjsonparser/json.h" #include #include #include #include namespace Json { void JsonPlugin::initialize() { addObject(new JsonMapFormat(JsonMapFormat::Json, this)); addObject(new JsonMapFormat(JsonMapFormat::JavaScript, this)); addObject(new JsonTilesetFormat(this)); } JsonMapFormat::JsonMapFormat(SubFormat subFormat, QObject *parent) : Tiled::MapFormat(parent) , mSubFormat(subFormat) {} Tiled::Map *JsonMapFormat::read(const QString &fileName) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { mError = tr("Could not open file for reading."); return nullptr; } JsonReader reader; QByteArray contents = file.readAll(); if (mSubFormat == JavaScript && contents.size() > 0 && contents[0] != '{') { // Scan past JSONP prefix; look for an open curly at the start of the line int i = contents.indexOf(QLatin1String("\n{")); if (i > 0) { contents.remove(0, i); contents = contents.trimmed(); // potential trailing whitespace if (contents.endsWith(';')) contents.chop(1); if (contents.endsWith(')')) contents.chop(1); } } reader.parse(contents); const QVariant variant = reader.result(); if (!variant.isValid()) { mError = tr("Error parsing file."); return nullptr; } Tiled::VariantToMapConverter converter; Tiled::Map *map = converter.toMap(variant, QFileInfo(fileName).dir()); if (!map) mError = converter.errorString(); return map; } bool JsonMapFormat::write(const Tiled::Map *map, const QString &fileName) { QSaveFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { mError = tr("Could not open file for writing."); return false; } Tiled::MapToVariantConverter converter; QVariant variant = converter.toVariant(map, QFileInfo(fileName).dir()); JsonWriter writer; writer.setAutoFormatting(true); if (!writer.stringify(variant)) { // This can only happen due to coding error mError = writer.errorString(); return false; } QTextStream out(&file); if (mSubFormat == JavaScript) { // Trim and escape name JsonWriter nameWriter; QString baseName = QFileInfo(fileName).baseName(); nameWriter.stringify(baseName); out << "(function(name,data){\n if(typeof onTileMapLoaded === 'undefined') {\n"; out << " if(typeof TileMaps === 'undefined') TileMaps = {};\n"; out << " TileMaps[name] = data;\n"; out << " } else {\n"; out << " onTileMapLoaded(name,data);\n"; out << " }})(" << nameWriter.result() << ",\n"; } out << writer.result(); if (mSubFormat == JavaScript) { out << ");"; } out.flush(); if (file.error() != QFile::NoError) { mError = tr("Error while writing file:\n%1").arg(file.errorString()); return false; } if (!file.commit()) { mError = file.errorString(); return false; } return true; } QString JsonMapFormat::nameFilter() const { if (mSubFormat == Json) return tr("Json map files (*.json)"); else return tr("JavaScript map files (*.js)"); } bool JsonMapFormat::supportsFile(const QString &fileName) const { if (mSubFormat == Json) return fileName.endsWith(QLatin1String(".json"), Qt::CaseInsensitive); else return fileName.endsWith(QLatin1String(".js"), Qt::CaseInsensitive); } QString JsonMapFormat::errorString() const { return mError; } JsonTilesetFormat::JsonTilesetFormat(QObject *parent) : Tiled::TilesetFormat(parent) { } Tiled::SharedTileset JsonTilesetFormat::read(const QString &fileName) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { mError = tr("Could not open file for reading."); return Tiled::SharedTileset(); } JsonReader reader; QByteArray contents = file.readAll(); reader.parse(contents); const QVariant variant = reader.result(); if (!variant.isValid()) { mError = tr("Error parsing file."); return Tiled::SharedTileset(); } Tiled::VariantToMapConverter converter; Tiled::SharedTileset tileset = converter.toTileset(variant, QFileInfo(fileName).dir()); if (!tileset) mError = converter.errorString(); else tileset->setFileName(fileName); return tileset; } bool JsonTilesetFormat::supportsFile(const QString &fileName) const { return fileName.endsWith(QLatin1String(".json"), Qt::CaseInsensitive); } bool JsonTilesetFormat::write(const Tiled::Tileset &tileset, const QString &fileName) { QSaveFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { mError = tr("Could not open file for writing."); return false; } Tiled::MapToVariantConverter converter; QVariant variant = converter.toVariant(tileset, QFileInfo(fileName).dir()); JsonWriter writer; writer.setAutoFormatting(true); if (!writer.stringify(variant)) { // This can only happen due to coding error mError = writer.errorString(); return false; } QTextStream out(&file); out << writer.result(); out.flush(); if (file.error() != QFile::NoError) { mError = tr("Error while writing file:\n%1").arg(file.errorString()); return false; } if (!file.commit()) { mError = file.errorString(); return false; } return true; } QString JsonTilesetFormat::nameFilter() const { return tr("Json tileset files (*.json)"); } QString JsonTilesetFormat::errorString() const { return mError; } } // namespace Json tiled-0.14.2/src/plugins/json/jsonplugin.h000066400000000000000000000046071260670167100204760ustar00rootroot00000000000000/* * JSON Tiled Plugin * Copyright 2011, Porfírio José Pereira Ribeiro * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef JSONPLUGIN_H #define JSONPLUGIN_H #include "json_global.h" #include "mapformat.h" #include "plugin.h" #include "tilesetformat.h" #include namespace Tiled { class Map; } namespace Json { class JSONSHARED_EXPORT JsonPlugin : public Tiled::Plugin { Q_OBJECT Q_INTERFACES(Tiled::Plugin) Q_PLUGIN_METADATA(IID "org.mapeditor.Plugin" FILE "plugin.json") public: void initialize() override; }; class JSONSHARED_EXPORT JsonMapFormat : public Tiled::MapFormat { Q_OBJECT Q_INTERFACES(Tiled::MapFormat) public: enum SubFormat { Json, JavaScript, }; JsonMapFormat(SubFormat subFormat, QObject *parent = nullptr); Tiled::Map *read(const QString &fileName) override; bool supportsFile(const QString &fileName) const override; bool write(const Tiled::Map *map, const QString &fileName) override; QString nameFilter() const override; QString errorString() const override; protected: QString mError; SubFormat mSubFormat; }; class JSONSHARED_EXPORT JsonTilesetFormat : public Tiled::TilesetFormat { Q_OBJECT Q_INTERFACES(Tiled::TilesetFormat) public: JsonTilesetFormat(QObject *parent = nullptr); Tiled::SharedTileset read(const QString &fileName) override; bool supportsFile(const QString &fileName) const override; bool write(const Tiled::Tileset &tileset, const QString &fileName) override; QString nameFilter() const override; QString errorString() const override; protected: QString mError; }; } // namespace Json #endif // JSONPLUGIN_H tiled-0.14.2/src/plugins/json/plugin.json000066400000000000000000000000321260670167100203120ustar00rootroot00000000000000{ "Keys": [ "notused" ] } tiled-0.14.2/src/plugins/json/qjsonparser/000077500000000000000000000000001260670167100204755ustar00rootroot00000000000000tiled-0.14.2/src/plugins/json/qjsonparser/json.cpp000066400000000000000000000327141260670167100221610ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (c) 2010 Girish Ramakrishnan ** ** Use, modification and distribution is allowed without limitation, ** warranty, liability or support of any kind. ** ****************************************************************************/ #include "json.h" #include "jsonparser.cpp" #include #include /*! \class JsonReader \reentrant \brief The JsonReader class provides a fast parser for reading well-formed JSON into a QVariant. The parser converts JSON types into QVariant types. For example, JSON arrays are translated into QVariantList and JSON objects are translated into QVariantMap. For example, \code JsonReader reader; if (reader.parse(QString("{ \"id\": 123, \"class\": \"JsonReader\", \"authors\": [\"Denis\",\"Ettrich\",\"Girish\"] }"))) { QVariant result = reader.result(); QVariantMap map = result.toMap(); // the JSON object qDebug() << map.count(); // 3 qDebug() << map["id"].toInt(); // 123 qDebug() << map["class"].toString(); // "JsonReader" QVariantList list = map["authors"].toList(); qDebug() << list[2].toString(); // "Girish" } else { qDebug() << reader.errorString(); } \endcode As seen above, the reader converts the JSON into a QVariant with arbitrary nesting. A complete listing of JSON to QVariant conversion is documented at parse(). JsonWriter can be used to convert a QVariant into JSON string. */ /*! Constructs a JSON reader. */ JsonReader::JsonReader() { } /*! Destructor */ JsonReader::~JsonReader() { } /*! Parses the JSON \a ba as a QVariant. If the parse succeeds, this function returns true and the QVariant can be accessed using result(). If the parse fails, this function returns false and the error message can be accessed using errorMessage(). The encoding of \ba is auto-detected based on the pattern of nulls in the initial 4 octets as described in "Section 3. Encoding" of RFC 2647. If an encoding could not be auto-detected, this function assumes UTF-8. The conversion from JSON type into QVariant type is as listed below: \table \row \o false \o QVariant::Bool with the value false. \row \o true \o QVariant::Bool with the value true. \row \o null \o QVariant::Invalid i.e QVariant() \row \o object \o QVariant::Map i.e QVariantMap \row \o array \o QVariant::List i.e QVariantList \row \o string \o QVariant::String i.e QString \row \o number \o QVariant::Double or QVariant::LongLong. If the JSON number contains a '.' or 'e' or 'E', QVariant::Double is used. \endtable The byte array \ba may or may not contain a BOM. */ bool JsonReader::parse(const QByteArray &ba) { QTextCodec *codec = QTextCodec::codecForUtfText(ba, 0); // try BOM detection if (!codec) { int mib = 106; // utf-8 if (ba.length() > 3) { // auto-detect const char *data = ba.constData(); if (data[0] != 0) { if (data[1] != 0) mib = 106; // utf-8 else if (data[2] != 0) mib = 1014; // utf16 le else mib = 1019; // utf32 le } else if (data[1] != 0) mib = 1013; // utf16 be else mib = 1018; // utf32 be } codec = QTextCodec::codecForMib(mib); } QString str = codec->toUnicode(ba); return parse(str); } /*! Parses the JSON string \a str as a QVariant. If the parse succeeds, this function returns true and the QVariant can be accessed using result(). If the parse fails, this function returns false and the error message can be accessed using errorMessage(). */ bool JsonReader::parse(const QString &str) { JsonLexer lexer(str); JsonParser parser; if (!parser.parse(&lexer)) { m_errorString = parser.errorMessage(); m_result = QVariant(); return false; } m_errorString.clear(); m_result = parser.result(); return true; } /*! Returns the result of the last parse() call. If parse() failed, this function returns an invalid QVariant. */ QVariant JsonReader::result() const { return m_result; } /*! Returns the error message for the last parse() call. If parse() succeeded, this functions return an empty string. The error message should be used for debugging purposes only. */ QString JsonReader::errorString() const { return m_errorString; } /*! \class JsonWriter \reentrant \brief The JsonWriter class converts a QVariant into a JSON string. The writer converts specific supported types stored in a QVariant into JSON. For example, \code QVariantMap map; map["id"] = 123; map["class"] = "JsonWriter"; QVariantList list; list << "Denis" << "Ettrich" << "Girish"; map["authors"] = list; JsonWriter writer; if (writer.stringify(map)) { QString json = writer.result(); qDebug() << json; // {"authors": ["Denis", "Ettrich", "Girish"], "class": "JsonWriter", "id": 123 } } else { qDebug() << "Failed to stringify " << writer.errorString(); } \endcode The list of QVariant types that the writer supports is listed in stringify(). Note that custom C++ types registered using Q_DECLARE_METATYPE are not supported. */ /*! Creates a JsonWriter. */ JsonWriter::JsonWriter() : m_autoFormatting(false), m_autoFormattingIndent(4, QLatin1Char(' ')) { } /*! Destructor. */ JsonWriter::~JsonWriter() { } /*! Enables auto formatting if \a enable is \c true, otherwise disables it. When auto formatting is enabled, the writer automatically inserts spaces and new lines to make the output more human readable. The default value is \c false. */ void JsonWriter::setAutoFormatting(bool enable) { m_autoFormatting = enable; } /*! Returns \c true if auto formattting is enabled, otherwise \c false. */ bool JsonWriter::autoFormatting() const { return m_autoFormatting; } /*! Sets the number of spaces or tabs used for indentation when auto-formatting is enabled. Positive numbers indicate spaces, negative numbers tabs. The default indentation is 4. \sa setAutoFormatting() */ void JsonWriter::setAutoFormattingIndent(int spacesOrTabs) { m_autoFormattingIndent = QString(qAbs(spacesOrTabs), QLatin1Char(spacesOrTabs >= 0 ? ' ' : '\t')); } /*! Retuns the numbers of spaces or tabs used for indentation when auto-formatting is enabled. Positive numbers indicate spaces, negative numbers tabs. The default indentation is 4. \sa setAutoFormatting() */ int JsonWriter::autoFormattingIndent() const { return m_autoFormattingIndent.count(QLatin1Char(' ')) - m_autoFormattingIndent.count(QLatin1Char('\t')); } /*! \internal Inserts escape character \ for characters in string as described in JSON specification. */ static QString escape(const QVariant &variant) { QString str = variant.toString(); QString res; res.reserve(str.length()); for (int i = 0; i < str.length(); i++) { if (str[i] == QLatin1Char('\b')) { res += QLatin1String("\\b"); } else if (str[i] == QLatin1Char('\f')) { res += QLatin1String("\\f"); } else if (str[i] == QLatin1Char('\n')) { res += QLatin1String("\\n"); } else if (str[i] == QLatin1Char('\r')) { res += QLatin1String("\\r"); } else if (str[i] == QLatin1Char('\t')) { res += QLatin1String("\\t"); } else if (str[i] == QLatin1Char('\"')) { res += QLatin1String("\\\""); } else if (str[i] == QLatin1Char('\\')) { res += QLatin1String("\\\\"); } else if (str[i] == QLatin1Char('/')) { res += QLatin1String("\\/"); } else if (str[i].unicode() > 127) { res += QLatin1String("\\u") + QString::number(str[i].unicode(), 16).rightJustified(4, QLatin1Char('0')); } else { res += str[i]; } } return res; } /*! \internal Stringifies \a variant. */ void JsonWriter::stringify(const QVariant &variant, int depth) { if (variant.type() == QVariant::List || variant.type() == QVariant::StringList) { m_result += QLatin1Char('['); QVariantList list = variant.toList(); for (int i = 0; i < list.count(); i++) { if (i != 0) { m_result += QLatin1Char(','); if (m_autoFormatting) m_result += QLatin1Char(' '); } stringify(list[i], depth+1); } m_result += QLatin1Char(']'); } else if (variant.type() == QVariant::Map) { QString indent = m_autoFormattingIndent.repeated(depth); QVariantMap map = variant.toMap(); if (m_autoFormatting && depth != 0) { m_result += QLatin1Char('\n'); m_result += indent; m_result += QLatin1String("{\n"); } else { m_result += QLatin1Char('{'); } for (QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) { if (it != map.constBegin()) { m_result += QLatin1Char(','); if (m_autoFormatting) m_result += QLatin1Char('\n'); } if (m_autoFormatting) m_result += indent + QLatin1Char(' '); m_result += QLatin1Char('\"') + escape(it.key()) + QLatin1String("\":"); stringify(it.value(), depth+1); } if (m_autoFormatting) { m_result += QLatin1Char('\n'); m_result += indent; } m_result += QLatin1Char('}'); } else if (variant.type() == QVariant::String || variant.type() == QVariant::ByteArray) { m_result += QLatin1Char('\"') + escape(variant) + QLatin1Char('\"'); } else if (variant.type() == QVariant::Double || (int)variant.type() == (int)QMetaType::Float) { double d = variant.toDouble(); if (qIsFinite(d)) m_result += QString::number(variant.toDouble(), 'g', 15); else m_result += QLatin1String("null"); } else if (variant.type() == QVariant::Bool) { m_result += variant.toBool() ? QLatin1String("true") : QLatin1String("false"); } else if (variant.type() == QVariant::Invalid) { m_result += QLatin1String("null"); } else if (variant.type() == QVariant::ULongLong) { m_result += QString::number(variant.toULongLong()); } else if (variant.type() == QVariant::LongLong) { m_result += QString::number(variant.toLongLong()); } else if (variant.type() == QVariant::Int) { m_result += QString::number(variant.toInt()); } else if (variant.type() == QVariant::UInt) { m_result += QString::number(variant.toUInt()); } else if (variant.type() == QVariant::Char) { QChar c = variant.toChar(); if (c.unicode() > 127) m_result += QLatin1String("\"\\u") + QString::number(c.unicode(), 16).rightJustified(4, QLatin1Char('0')) + QLatin1Char('\"'); else m_result += QLatin1Char('\"') + c + QLatin1Char('\"'); } else if (variant.canConvert()) { m_result += QString::number(variant.toLongLong()); } else if (variant.canConvert()) { m_result += QLatin1Char('\"') + escape(variant) + QLatin1Char('\"'); } else { if (!m_errorString.isEmpty()) m_errorString.append(QLatin1Char('\n')); QString msg = QString::fromLatin1("Unsupported type %1 (id: %2)").arg(QString::fromUtf8(variant.typeName())).arg(variant.userType()); m_errorString.append(msg); qWarning() << "JsonWriter::stringify - " << msg; m_result += QLatin1String("null"); } } /*! Converts the variant \a var into a JSON string. The stringizer converts \a var into JSON based on the type of it's contents. The supported types and their conversion into JSON is as listed below: \table \row \o QVariant::List, QVariant::StringList \o JSON array [] \row \o QVariant::Map \o JSON object {} \row \o QVariant::String, QVariant::ByteArray \o JSON string encapsulated in double quotes. String contents are escaped using '\' if necessary. \row \o QVariant::Double, QMetaType::Float \o JSON number with a precision 15. Infinity and NaN are converted into null. \row \o QVariant::Bool \o JSON boolean true and false \row \o QVariant::Invalid \o JSON null \row \o QVariant::ULongLong, QVariant::LongLong, QVariant::Int, QVariant::UInt, \o JSON number \row \o QVariant::Char \o JSON string. Non-ASCII characters are converted into the \uXXXX notation. \endtable As a fallback, the writer attempts to convert a type not listed above into a long long or a QString using QVariant::canConvert. See the QVariant documentation for possible conversions. JsonWriter does not support stringizing custom user types stored in the QVariant. Any such value would be converted into JSON null. */ bool JsonWriter::stringify(const QVariant &var) { m_errorString.clear(); m_result.clear(); stringify(var, 0 /* depth */); return m_errorString.isEmpty(); } /*! Returns the result of the last stringify() call. If stringify() failed, this function returns a null QString. */ QString JsonWriter::result() const { return m_result; } /*! Returns the error message for the last stringify() call. If stringify() succeeded, this functions return an empty string. The error message should be used for debugging purposes only. */ QString JsonWriter::errorString() const { return m_errorString; } tiled-0.14.2/src/plugins/json/qjsonparser/json.h000066400000000000000000000023201260670167100216140ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (c) 2010 Girish Ramakrishnan ** ** Use, modification and distribution is allowed without limitation, ** warranty, liability or support of any kind. ** ****************************************************************************/ #ifndef JSON_H #define JSON_H #include #include class JsonReader { public: JsonReader(); ~JsonReader(); bool parse(const QByteArray &ba); bool parse(const QString &str); QVariant result() const; QString errorString() const; private: QVariant m_result; QString m_errorString; }; class JsonWriter { public: JsonWriter(); ~JsonWriter(); bool stringify(const QVariant &variant); QString result() const; QString errorString() const; void setAutoFormatting(bool autoFormat); bool autoFormatting() const; void setAutoFormattingIndent(int spaceOrTabs); int autoFormattingIndent() const; private: void stringify(const QVariant &variant, int depth); QString m_result; QString m_errorString; bool m_autoFormatting; QString m_autoFormattingIndent; }; #endif // JSON_H tiled-0.14.2/src/plugins/json/qjsonparser/jsonparser.cpp000066400000000000000000000342341260670167100233750ustar00rootroot00000000000000// This file was generated by qlalr - DO NOT EDIT! #ifndef JSONPARSER_CPP #define JSONPARSER_CPP class JsonGrammar { public: enum VariousConstants { EOF_SYMBOL = 0, ERROR = 12, T_COLON = 7, T_COMMA = 8, T_FALSE = 9, T_LCURLYBRACKET = 3, T_LSQUAREBRACKET = 5, T_NULL = 11, T_NUMBER = 2, T_RCURLYBRACKET = 4, T_RSQUAREBRACKET = 6, T_STRING = 1, T_TRUE = 10, ACCEPT_STATE = 12, RULE_COUNT = 17, STATE_COUNT = 27, TERMINAL_COUNT = 13, NON_TERMINAL_COUNT = 7, GOTO_INDEX_OFFSET = 27, GOTO_INFO_OFFSET = 37, GOTO_CHECK_OFFSET = 37 }; static const char *const spell []; static const short lhs []; static const short rhs []; #ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO static const int rule_index []; static const int rule_info []; #endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO static const short goto_default []; static const short action_default []; static const short action_index []; static const short action_info []; static const short action_check []; static inline int nt_action (int state, int nt) { const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) return goto_default [nt]; return action_info [GOTO_INFO_OFFSET + yyn]; } static inline int t_action (int state, int token) { const int yyn = action_index [state] + token; if (yyn < 0 || action_check [yyn] != token) return - action_default [state]; return action_info [yyn]; } }; const char *const JsonGrammar::spell [] = { "end of file", "string", "number", "{", "}", "[", "]", ":", ",", "false", "true", "null", "error", #ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO "Root", "Value", "Object", "Members", "Array", "Values", "$accept" #endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO }; const short JsonGrammar::lhs [] = { 13, 15, 16, 16, 16, 14, 14, 14, 14, 14, 14, 14, 17, 18, 18, 18, 19}; const short JsonGrammar::rhs [] = { 1, 3, 3, 5, 0, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 0, 2}; #ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO const int JsonGrammar::rule_info [] = { 13, 14 , 15, 3, 16, 4 , 16, 1, 7, 14 , 16, 16, 8, 1, 7, 14 , 16 , 14, 9 , 14, 10 , 14, 11 , 14, 15 , 14, 17 , 14, 2 , 14, 1 , 17, 5, 18, 6 , 18, 14 , 18, 18, 8, 14 , 18 , 19, 13, 0}; const int JsonGrammar::rule_index [] = { 0, 2, 6, 10, 16, 17, 19, 21, 23, 25, 27, 29, 31, 35, 37, 41, 42}; #endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO const short JsonGrammar::action_default [] = { 0, 10, 9, 0, 6, 5, 16, 8, 11, 12, 7, 1, 17, 0, 0, 0, 2, 0, 0, 4, 0, 3, 14, 0, 0, 13, 15}; const short JsonGrammar::goto_default [] = { 3, 11, 2, 13, 1, 23, 0}; const short JsonGrammar::action_index [] = { 24, -13, -13, 12, -13, -1, 24, -13, -13, -13, -13, -13, -13, 1, -5, 2, -13, -6, 24, -13, 24, -13, -13, -2, 24, -13, -13, -7, -7, -7, -7, -7, -7, 1, -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, 0, -7, -1, -7, -7, -7, 5, -7, -7}; const short JsonGrammar::action_info [] = { 14, 18, 20, 17, 25, 16, 24, 0, 0, 15, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 5, 0, 6, 0, 0, 0, 4, 10, 7, 0, 21, 19, 22, 0, 0, 0, 26, 0, 0, 0, 0, 0}; const short JsonGrammar::action_check [] = { 1, 7, 7, 1, 6, 4, 8, -1, -1, 8, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 3, -1, 5, -1, -1, -1, 9, 10, 11, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1}; #line 29 "json.g" /**************************************************************************** ** ** Copyright (c) 2010 Girish Ramakrishnan ** Copyright (c) 2011 Denis Dzyubenko ** ** Use, modification and distribution is allowed without limitation, ** warranty, liability or support of any kind. ** ****************************************************************************/ #ifndef JSONPARSER_P_H #define JSONPARSER_P_H #include #include #include class JsonLexer { public: JsonLexer(const QString &string); ~JsonLexer(); int lex(); QVariant symbol() const { return m_symbol; } int lineNumber() const { return m_lineNumber; } int pos() const { return m_pos; } private: int parseNumber(); int parseString(); int parseKeyword(); QString m_strdata; int m_lineNumber; int m_pos; QVariant m_symbol; }; class JsonParser : protected JsonGrammar { public: JsonParser(); ~JsonParser(); bool parse(JsonLexer *lex); QVariant result() const { return m_result; } QString errorMessage() const { return QString::fromLatin1("%1 at line %2 pos %3").arg(m_errorMessage).arg(m_errorLineNumber).arg(m_errorPos); } private: void reallocateStack(); inline QVariant &sym(int index) { return m_symStack[m_tos + index - 1]; } inline QVariantMap &map(int index) { return m_mapStack[m_tos + index - 1]; } inline QVariantList &list(int index) { return m_listStack[m_tos + index - 1]; } int m_tos; QVector m_stateStack; QVector m_symStack; QVector m_mapStack; QVector m_listStack; QString m_errorMessage; int m_errorLineNumber; int m_errorPos; QVariant m_result; }; #endif // JSONPARSER_P_H #line 103 "json.g" /**************************************************************************** ** ** Copyright (c) 2010 Girish Ramakrishnan ** Copyright (c) 2011 Denis Dzyubenko ** ** Use, modification and distribution is allowed without limitation, ** warranty, liability or support of any kind. ** ****************************************************************************/ #include #define L1C(c) ushort(uchar(c)) JsonLexer::JsonLexer(const QString &str) : m_strdata(str), m_lineNumber(1), m_pos(0) { } JsonLexer::~JsonLexer() { } int JsonLexer::parseString() { bool esc = false; ++m_pos; // skip initial " int start = m_pos; const ushort *uc = m_strdata.utf16(); const int remaining = m_strdata.length() - m_pos; int i; for (i = 0; i < remaining; ++i) { const ushort c = uc[m_pos + i]; if (c == L1C('\"')) { m_symbol = QString((QChar *)uc + m_pos, i); m_pos += i; ++m_pos; // eat quote return JsonGrammar::T_STRING; } else if (c == L1C('\\')) { ++m_pos; // eat backslash esc = true; break; } } QString str; if (i) { str.resize(i); memcpy((char *)str.utf16(), uc + start, i * 2); m_pos += i; } for (; m_pos < m_strdata.length(); ++m_pos) { const ushort c = uc[m_pos]; if (esc) { if (c == L1C('b')) str += QLatin1Char('\b'); else if (c == L1C('f')) str += QLatin1Char('\f'); else if (c == L1C('n')) str += QLatin1Char('\n'); else if (c == L1C('r')) str += QLatin1Char('\r'); else if (c == L1C('t')) str += QLatin1Char('\t'); else if (c == L1C('\\')) str += QLatin1Char('\\'); else if (c == L1C('\"')) str += QLatin1Char('\"'); else if (c == L1C('u') && m_pos+4= L1C('0') && c <= L1C('9')) { if (!isDouble) { value *= 10; value += c - L1C('0'); } continue; } break; } if (!isDouble) { m_symbol = value * negative; } else { QString number = QString::fromRawData((QChar *)uc+start, m_pos-start); m_symbol = number.toDouble(); } return JsonGrammar::T_NUMBER; } int JsonLexer::parseKeyword() { int start = m_pos; for (; m_pos < m_strdata.length(); ++m_pos) { const ushort c = m_strdata.at(m_pos).unicode(); if (c >= L1C('a') && c <= L1C('z')) continue; break; } const ushort *k = (const ushort *)m_strdata.constData() + start; const int l = m_pos-start; if (l == 4) { static const ushort true_data[] = { 't', 'r', 'u', 'e' }; static const ushort null_data[] = { 'n', 'u', 'l', 'l' }; if (!memcmp(k, true_data, 4 * sizeof(ushort))) return JsonGrammar::T_TRUE; if (!memcmp(k, null_data, 4 * sizeof(ushort))) return JsonGrammar::T_NULL; } else if (l == 5) { static const ushort false_data[] = { 'f', 'a', 'l', 's', 'e' }; if (!memcmp(k, false_data, 5 * sizeof(ushort))) return JsonGrammar::T_FALSE; } return JsonGrammar::ERROR; } int JsonLexer::lex() { m_symbol.clear(); const ushort *uc = m_strdata.utf16(); const int len = m_strdata.length(); while (m_pos < len) { const ushort c = uc[m_pos]; switch (c) { case L1C('['): ++m_pos; return JsonGrammar::T_LSQUAREBRACKET; case L1C(']'): ++m_pos; return JsonGrammar::T_RSQUAREBRACKET; case L1C('{'): ++m_pos; return JsonGrammar::T_LCURLYBRACKET; case L1C('}'): ++m_pos; return JsonGrammar::T_RCURLYBRACKET; case L1C(':'): ++m_pos; return JsonGrammar::T_COLON; case L1C(','): ++m_pos; return JsonGrammar::T_COMMA; case L1C(' '): case L1C('\r'): case L1C('\t'): ++m_pos; break; case L1C('\n'): ++m_pos; ++m_lineNumber; break; case L1C('"'): return parseString(); default: if (c == L1C('+') || c == L1C('-') || (c >= L1C('0') && c <= L1C('9'))) { return parseNumber(); } if (c >= L1C('a') && c <= L1C('z')) { return parseKeyword(); } return JsonGrammar::ERROR; } } return JsonGrammar::EOF_SYMBOL; } #undef L1C JsonParser::JsonParser() : m_tos(0) , m_errorLineNumber(-1) , m_errorPos(-1) { } JsonParser::~JsonParser() { } void JsonParser::reallocateStack() { int size = m_stateStack.size(); if (size == 0) size = 128; else size <<= 1; m_symStack.resize(size); m_mapStack.resize(size); m_listStack.resize(size); m_stateStack.resize(size); } bool JsonParser::parse(JsonLexer *lexer) { const int INITIAL_STATE = 0; int yytoken = -1; reallocateStack(); m_tos = 0; m_stateStack[++m_tos] = INITIAL_STATE; while (true) { const int state = m_stateStack[m_tos]; if (yytoken == -1 && -TERMINAL_COUNT != action_index[state]) { yytoken = lexer->lex(); } int act = t_action(state, yytoken); if (act == ACCEPT_STATE) return true; else if (act > 0) { if (++m_tos == m_stateStack.size()) reallocateStack(); m_stateStack[m_tos] = act; m_symStack[m_tos] = lexer->symbol(); yytoken = -1; } else if (act < 0) { int r = -act-1; m_tos -= rhs[r]; act = m_stateStack.at(m_tos++); switch (r) { #line 334 "json.g" case 0: { m_result = sym(1); break; } #line 337 "json.g" case 1: { sym(1) = map(2); break; } #line 340 "json.g" case 2: { QVariantMap m; m.insert(sym(1).toString(), sym(3)); map(1) = m; break; } #line 343 "json.g" case 3: { map(1).insert(sym(3).toString(), sym(5)); break; } #line 346 "json.g" case 4: { map(1) = QVariantMap(); break; } #line 349 "json.g" case 5: { sym(1) = QVariant(false); break; } #line 352 "json.g" case 6: { sym(1) = QVariant(true); break; } #line 361 "json.g" case 12: { sym(1) = list(2); break; } #line 364 "json.g" case 13: { QVariantList l; l.append(sym(1)); list(1) = l; break; } #line 367 "json.g" case 14: { list(1).append(sym(3)); break; } #line 370 "json.g" case 15: { list(1) = QVariantList(); break; } #line 372 "json.g" } // switch m_stateStack[m_tos] = nt_action(act, lhs[r] - TERMINAL_COUNT); } else { int ers = state; int shifts = 0; int reduces = 0; int expected_tokens[3]; for (int tk = 0; tk < TERMINAL_COUNT; ++tk) { int k = t_action(ers, tk); if (! k) continue; else if (k < 0) ++reduces; else if (spell[tk]) { if (shifts < 3) expected_tokens[shifts] = tk; ++shifts; } } m_errorLineNumber = lexer->lineNumber(); m_errorPos = lexer->pos(); m_errorMessage.clear(); if (shifts && shifts < 3) { bool first = true; for (int s = 0; s < shifts; ++s) { if (first) m_errorMessage += QLatin1String("Expected "); else m_errorMessage += QLatin1String(", "); first = false; m_errorMessage += QLatin1String("'"); m_errorMessage += QLatin1String(spell[expected_tokens[s]]); m_errorMessage += QLatin1String("'"); } } return false; } } return false; } #endif // JSONPARSER_CPP tiled-0.14.2/src/plugins/json/qjsonparser/qjsonparser.pri000066400000000000000000000000751260670167100235620ustar00rootroot00000000000000INCLUDEPATH += $$PWD SOURCES += json.cpp HEADERS += json.h tiled-0.14.2/src/plugins/lua/000077500000000000000000000000001260670167100157365ustar00rootroot00000000000000tiled-0.14.2/src/plugins/lua/lua.pro000066400000000000000000000002421260670167100172370ustar00rootroot00000000000000include(../plugin.pri) DEFINES += LUA_LIBRARY SOURCES += luaplugin.cpp \ luatablewriter.cpp HEADERS += luaplugin.h\ lua_global.h \ luatablewriter.h tiled-0.14.2/src/plugins/lua/lua.qbs000066400000000000000000000003271260670167100172300ustar00rootroot00000000000000import qbs 1.0 TiledPlugin { cpp.defines: ["LUA_LIBRARY"] files: [ "lua_global.h", "luaplugin.cpp", "luaplugin.h", "luatablewriter.cpp", "luatablewriter.h", ] } tiled-0.14.2/src/plugins/lua/lua_global.h000066400000000000000000000017371260670167100202200ustar00rootroot00000000000000/* * Lua Tiled Plugin * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef LUA_GLOBAL_H #define LUA_GLOBAL_H #include #if defined(LUA_LIBRARY) # define LUASHARED_EXPORT Q_DECL_EXPORT #else # define LUASHARED_EXPORT Q_DECL_IMPORT #endif #endif // LUA_GLOBAL_H tiled-0.14.2/src/plugins/lua/luaplugin.cpp000066400000000000000000000417131260670167100204500ustar00rootroot00000000000000/* * Lua Tiled Plugin * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "luaplugin.h" #include "luatablewriter.h" #include "imagelayer.h" #include "mapobject.h" #include "objectgroup.h" #include "properties.h" #include "terrain.h" #include "tile.h" #include "tilelayer.h" #include "tileset.h" #include #include #include /** * See below for an explanation of the different formats. One of these needs * to be defined. */ #define POLYGON_FORMAT_FULL //#define POLYGON_FORMAT_PAIRS //#define POLYGON_FORMAT_OPTIMAL using namespace Lua; using namespace Tiled; LuaPlugin::LuaPlugin() { } bool LuaPlugin::write(const Map *map, const QString &fileName) { QSaveFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { mError = tr("Could not open file for writing."); return false; } mMapDir = QFileInfo(fileName).path(); LuaTableWriter writer(&file); writer.writeStartDocument(); writeMap(writer, map); writer.writeEndDocument(); if (file.error() != QFile::NoError) { mError = file.errorString(); return false; } if (!file.commit()) { mError = file.errorString(); return false; } return true; } QString LuaPlugin::nameFilter() const { return tr("Lua files (*.lua)"); } QString LuaPlugin::errorString() const { return mError; } void LuaPlugin::writeMap(LuaTableWriter &writer, const Map *map) { writer.writeStartReturnTable(); writer.writeKeyAndValue("version", "1.1"); writer.writeKeyAndValue("luaversion", "5.1"); writer.writeKeyAndValue("tiledversion", QCoreApplication::applicationVersion()); const QString orientation = orientationToString(map->orientation()); const QString renderOrder = renderOrderToString(map->renderOrder()); writer.writeKeyAndValue("orientation", orientation); writer.writeKeyAndValue("renderorder", renderOrder); writer.writeKeyAndValue("width", map->width()); writer.writeKeyAndValue("height", map->height()); writer.writeKeyAndValue("tilewidth", map->tileWidth()); writer.writeKeyAndValue("tileheight", map->tileHeight()); writer.writeKeyAndValue("nextobjectid", map->nextObjectId()); if (map->orientation() == Map::Hexagonal) writer.writeKeyAndValue("hexsidelength", map->hexSideLength()); if (map->orientation() == Map::Staggered || map->orientation() == Map::Hexagonal) { writer.writeKeyAndValue("staggeraxis", staggerAxisToString(map->staggerAxis())); writer.writeKeyAndValue("staggerindex", staggerIndexToString(map->staggerIndex())); } const QColor &backgroundColor = map->backgroundColor(); if (backgroundColor.isValid()) { // Example: backgroundcolor = { 255, 200, 100 } writer.writeStartTable("backgroundcolor"); writer.setSuppressNewlines(true); writer.writeValue(backgroundColor.red()); writer.writeValue(backgroundColor.green()); writer.writeValue(backgroundColor.blue()); if (backgroundColor.alpha() != 255) writer.writeValue(backgroundColor.alpha()); writer.writeEndTable(); writer.setSuppressNewlines(false); } writeProperties(writer, map->properties()); writer.writeStartTable("tilesets"); mGidMapper.clear(); unsigned firstGid = 1; foreach (const SharedTileset &tileset, map->tilesets()) { writeTileset(writer, tileset.data(), firstGid); mGidMapper.insert(firstGid, tileset.data()); firstGid += tileset->tileCount(); } writer.writeEndTable(); writer.writeStartTable("layers"); foreach (const Layer *layer, map->layers()) { switch (layer->layerType()) { case Layer::TileLayerType: writeTileLayer(writer, static_cast(layer), map->layerDataFormat()); break; case Layer::ObjectGroupType: writeObjectGroup(writer, static_cast(layer)); break; case Layer::ImageLayerType: writeImageLayer(writer, static_cast(layer)); break; } } writer.writeEndTable(); writer.writeEndTable(); } void LuaPlugin::writeProperties(LuaTableWriter &writer, const Properties &properties) { writer.writeStartTable("properties"); Properties::const_iterator it = properties.constBegin(); Properties::const_iterator it_end = properties.constEnd(); for (; it != it_end; ++it) writer.writeQuotedKeyAndValue(it.key(), it.value()); writer.writeEndTable(); } static bool includeTile(const Tile *tile) { if (!tile->properties().isEmpty()) return true; if (!tile->imageSource().isEmpty()) return true; if (tile->objectGroup()) return true; if (tile->isAnimated()) return true; if (tile->terrain() != 0xFFFFFFFF) return true; if (tile->probability() != 1.f) return true; return false; } void LuaPlugin::writeTileset(LuaTableWriter &writer, const Tileset *tileset, unsigned firstGid) { writer.writeStartTable(); writer.writeKeyAndValue("name", tileset->name()); writer.writeKeyAndValue("firstgid", firstGid); if (!tileset->fileName().isEmpty()) { const QString rel = mMapDir.relativeFilePath(tileset->fileName()); writer.writeKeyAndValue("filename", rel); } /* Include all tileset information even for external tilesets, since the * external reference is generally a .tsx file (in XML format). */ writer.writeKeyAndValue("tilewidth", tileset->tileWidth()); writer.writeKeyAndValue("tileheight", tileset->tileHeight()); writer.writeKeyAndValue("spacing", tileset->tileSpacing()); writer.writeKeyAndValue("margin", tileset->margin()); if (!tileset->imageSource().isEmpty()) { const QString rel = mMapDir.relativeFilePath(tileset->imageSource()); writer.writeKeyAndValue("image", rel); writer.writeKeyAndValue("imagewidth", tileset->imageWidth()); writer.writeKeyAndValue("imageheight", tileset->imageHeight()); } if (tileset->transparentColor().isValid()) { writer.writeKeyAndValue("transparentcolor", tileset->transparentColor().name()); } const QPoint offset = tileset->tileOffset(); writer.writeStartTable("tileoffset"); writer.writeKeyAndValue("x", offset.x()); writer.writeKeyAndValue("y", offset.y()); writer.writeEndTable(); writeProperties(writer, tileset->properties()); writer.writeStartTable("terrains"); for (int i = 0; i < tileset->terrainCount(); ++i) { const Terrain *t = tileset->terrain(i); writer.writeStartTable(); writer.writeKeyAndValue("name", t->name()); writer.writeKeyAndValue("tile", t->imageTileId()); writeProperties(writer, t->properties()); writer.writeEndTable(); } writer.writeEndTable(); writer.writeKeyAndValue("tilecount", tileset->tileCount()); writer.writeStartTable("tiles"); for (int i = 0; i < tileset->tileCount(); ++i) { const Tile *tile = tileset->tileAt(i); // For brevity only write tiles with interesting properties if (!includeTile(tile)) continue; writer.writeStartTable(); writer.writeKeyAndValue("id", i); if (!tile->properties().isEmpty()) writeProperties(writer, tile->properties()); if (!tile->imageSource().isEmpty()) { const QString src = mMapDir.relativeFilePath(tile->imageSource()); const QSize tileSize = tile->size(); writer.writeKeyAndValue("image", src); if (!tileSize.isNull()) { writer.writeKeyAndValue("width", tileSize.width()); writer.writeKeyAndValue("height", tileSize.height()); } } unsigned terrain = tile->terrain(); if (terrain != 0xFFFFFFFF) { writer.writeStartTable("terrain"); writer.setSuppressNewlines(true); for (int i = 0; i < 4; ++i ) writer.writeValue(tile->cornerTerrainId(i)); writer.writeEndTable(); writer.setSuppressNewlines(false); } if (tile->probability() != 1.f) writer.writeKeyAndValue("probability", tile->probability()); if (ObjectGroup *objectGroup = tile->objectGroup()) writeObjectGroup(writer, objectGroup, "objectGroup"); if (tile->isAnimated()) { const QVector &frames = tile->frames(); writer.writeStartTable("animation"); foreach (const Frame &frame, frames) { writer.writeStartTable(); writer.writeKeyAndValue("tileid", QString::number(frame.tileId)); writer.writeKeyAndValue("duration", QString::number(frame.duration)); writer.writeEndTable(); } writer.writeEndTable(); // animation } writer.writeEndTable(); // tile } writer.writeEndTable(); // tiles writer.writeEndTable(); // tileset } void LuaPlugin::writeTileLayer(LuaTableWriter &writer, const TileLayer *tileLayer, Map::LayerDataFormat format) { writer.writeStartTable(); writer.writeKeyAndValue("type", "tilelayer"); writer.writeKeyAndValue("name", tileLayer->name()); writer.writeKeyAndValue("x", tileLayer->x()); writer.writeKeyAndValue("y", tileLayer->y()); writer.writeKeyAndValue("width", tileLayer->width()); writer.writeKeyAndValue("height", tileLayer->height()); writer.writeKeyAndValue("visible", tileLayer->isVisible()); writer.writeKeyAndValue("opacity", tileLayer->opacity()); const QPointF offset = tileLayer->offset(); writer.writeKeyAndValue("offsetx", offset.x()); writer.writeKeyAndValue("offsety", offset.y()); writeProperties(writer, tileLayer->properties()); switch (format) { case Map::XML: case Map::CSV: writer.writeKeyAndValue("encoding", "lua"); writer.writeStartTable("data"); for (int y = 0; y < tileLayer->height(); ++y) { if (y > 0) writer.prepareNewLine(); for (int x = 0; x < tileLayer->width(); ++x) writer.writeValue(mGidMapper.cellToGid(tileLayer->cellAt(x, y))); } writer.writeEndTable(); break; case Map::Base64: case Map::Base64Zlib: case Map::Base64Gzip: { writer.writeKeyAndValue("encoding", "base64"); if (format == Map::Base64Zlib) writer.writeKeyAndValue("compression", "zlib"); else if (format == Map::Base64Gzip) writer.writeKeyAndValue("compression", "gzip"); QByteArray layerData = mGidMapper.encodeLayerData(*tileLayer, format); writer.writeKeyAndValue("data", layerData); break; } } writer.writeEndTable(); } void LuaPlugin::writeObjectGroup(LuaTableWriter &writer, const ObjectGroup *objectGroup, const QByteArray &key) { if (key.isEmpty()) writer.writeStartTable(); else writer.writeStartTable(key); writer.writeKeyAndValue("type", "objectgroup"); writer.writeKeyAndValue("name", objectGroup->name()); writer.writeKeyAndValue("visible", objectGroup->isVisible()); writer.writeKeyAndValue("opacity", objectGroup->opacity()); const QPointF offset = objectGroup->offset(); writer.writeKeyAndValue("offsetx", offset.x()); writer.writeKeyAndValue("offsety", offset.y()); writeProperties(writer, objectGroup->properties()); writer.writeStartTable("objects"); foreach (MapObject *mapObject, objectGroup->objects()) writeMapObject(writer, mapObject); writer.writeEndTable(); writer.writeEndTable(); } void LuaPlugin::writeImageLayer(LuaTableWriter &writer, const ImageLayer *imageLayer) { writer.writeStartTable(); writer.writeKeyAndValue("type", "imagelayer"); writer.writeKeyAndValue("name", imageLayer->name()); writer.writeKeyAndValue("x", imageLayer->x()); writer.writeKeyAndValue("y", imageLayer->y()); writer.writeKeyAndValue("visible", imageLayer->isVisible()); writer.writeKeyAndValue("opacity", imageLayer->opacity()); const QString rel = mMapDir.relativeFilePath(imageLayer->imageSource()); writer.writeKeyAndValue("image", rel); if (imageLayer->transparentColor().isValid()) { writer.writeKeyAndValue("transparentcolor", imageLayer->transparentColor().name()); } writeProperties(writer, imageLayer->properties()); writer.writeEndTable(); } static const char *toString(MapObject::Shape shape) { switch (shape) { case MapObject::Rectangle: return "rectangle"; case MapObject::Polygon: return "polygon"; case MapObject::Polyline: return "polyline"; case MapObject::Ellipse: return "ellipse"; } return "unknown"; } void LuaPlugin::writeMapObject(LuaTableWriter &writer, const Tiled::MapObject *mapObject) { writer.writeStartTable(); writer.writeKeyAndValue("id", mapObject->id()); writer.writeKeyAndValue("name", mapObject->name()); writer.writeKeyAndValue("type", mapObject->type()); writer.writeKeyAndValue("shape", toString(mapObject->shape())); writer.writeKeyAndValue("x", mapObject->x()); writer.writeKeyAndValue("y", mapObject->y()); writer.writeKeyAndValue("width", mapObject->width()); writer.writeKeyAndValue("height", mapObject->height()); writer.writeKeyAndValue("rotation", mapObject->rotation()); if (!mapObject->cell().isEmpty()) writer.writeKeyAndValue("gid", mGidMapper.cellToGid(mapObject->cell())); writer.writeKeyAndValue("visible", mapObject->isVisible()); const QPolygonF &polygon = mapObject->polygon(); if (!polygon.isEmpty()) { if (mapObject->shape() == MapObject::Polygon) writer.writeStartTable("polygon"); else writer.writeStartTable("polyline"); #if defined(POLYGON_FORMAT_FULL) /* This format is the easiest to read and understand: * * { * { x = 1, y = 1 }, * { x = 2, y = 2 }, * { x = 3, y = 3 }, * ... * } */ foreach (const QPointF &point, polygon) { writer.writeStartTable(); writer.setSuppressNewlines(true); writer.writeKeyAndValue("x", point.x()); writer.writeKeyAndValue("y", point.y()); writer.writeEndTable(); writer.setSuppressNewlines(false); } #elif defined(POLYGON_FORMAT_PAIRS) /* This is an alternative that takes about 25% less memory. * * { * { 1, 1 }, * { 2, 2 }, * { 3, 3 }, * ... * } */ foreach (const QPointF &point, polygon) { writer.writeStartTable(); writer.setSuppressNewlines(true); writer.writeValue(point.x()); writer.writeValue(point.y()); writer.writeEndTable(); writer.setSuppressNewlines(false); } #elif defined(POLYGON_FORMAT_OPTIMAL) /* Writing it out in two tables, one for the x coordinates and one for * the y coordinates. It is a compromise between code readability and * performance. This takes the least amount of memory (60% less than * the first approach). * * x = { 1, 2, 3, ... } * y = { 1, 2, 3, ... } */ writer.writeStartTable("x"); writer.setSuppressNewlines(true); foreach (const QPointF &point, polygon) writer.writeValue(point.x()); writer.writeEndTable(); writer.setSuppressNewlines(false); writer.writeStartTable("y"); writer.setSuppressNewlines(true); foreach (const QPointF &point, polygon) writer.writeValue(point.y()); writer.writeEndTable(); writer.setSuppressNewlines(false); #endif writer.writeEndTable(); } writeProperties(writer, mapObject->properties()); writer.writeEndTable(); } tiled-0.14.2/src/plugins/lua/luaplugin.h000066400000000000000000000043441260670167100201140ustar00rootroot00000000000000/* * Lua Tiled Plugin * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef LUAPLUGIN_H #define LUAPLUGIN_H #include "lua_global.h" #include "gidmapper.h" #include "map.h" #include "mapformat.h" #include #include namespace Tiled { class MapObject; class ObjectGroup; class Properties; class TileLayer; class Tileset; } namespace Lua { class LuaTableWriter; /** * This plugin allows exporting maps as Lua files. */ class LUASHARED_EXPORT LuaPlugin : public Tiled::WritableMapFormat { Q_OBJECT Q_PLUGIN_METADATA(IID "org.mapeditor.MapFormat" FILE "plugin.json") public: LuaPlugin(); bool write(const Tiled::Map *map, const QString &fileName) override; QString nameFilter() const override; QString errorString() const override; private: void writeMap(LuaTableWriter &, const Tiled::Map *); void writeProperties(LuaTableWriter &, const Tiled::Properties &); void writeTileset(LuaTableWriter &, const Tiled::Tileset *, unsigned firstGid); void writeTileLayer(LuaTableWriter &, const Tiled::TileLayer *, Tiled::Map::LayerDataFormat); void writeObjectGroup(LuaTableWriter &, const Tiled::ObjectGroup *, const QByteArray &key = QByteArray()); void writeImageLayer(LuaTableWriter &, const Tiled::ImageLayer *); void writeMapObject(LuaTableWriter &, const Tiled::MapObject *); QString mError; QDir mMapDir; // The directory in which the map is being saved Tiled::GidMapper mGidMapper; }; } // namespace Lua #endif // LUAPLUGIN_H tiled-0.14.2/src/plugins/lua/luatablewriter.cpp000066400000000000000000000112461260670167100214740ustar00rootroot00000000000000/* * Lua Tiled Plugin * Copyright 2011-2013, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "luatablewriter.h" #include namespace Lua { LuaTableWriter::LuaTableWriter(QIODevice *device) : m_device(device) , m_indent(0) , m_valueSeparator(',') , m_suppressNewlines(false) , m_newLine(true) , m_valueWritten(false) , m_error(false) { } void LuaTableWriter::writeStartDocument() { Q_ASSERT(m_indent == 0); } void LuaTableWriter::writeEndDocument() { Q_ASSERT(m_indent == 0); write('\n'); } void LuaTableWriter::writeStartTable() { prepareNewLine(); write('{'); ++m_indent; m_newLine = false; m_valueWritten = false; } void LuaTableWriter::writeStartReturnTable() { prepareNewLine(); write("return {"); ++m_indent; m_newLine = false; m_valueWritten = false; } void LuaTableWriter::writeStartTable(const QByteArray &name) { prepareNewLine(); write(name + " = {"); ++m_indent; m_newLine = false; m_valueWritten = false; } void LuaTableWriter::writeEndTable() { --m_indent; if (m_valueWritten) writeNewline(); write('}'); m_newLine = false; m_valueWritten = true; } void LuaTableWriter::writeValue(const QByteArray &value) { prepareNewValue(); write('"'); write(value); write('"'); m_newLine = false; m_valueWritten = true; } void LuaTableWriter::writeUnquotedValue(const QByteArray &value) { prepareNewValue(); write(value); m_newLine = false; m_valueWritten = true; } void LuaTableWriter::writeKeyAndValue(const QByteArray &key, const char *value) { prepareNewLine(); write(key); write(" = \""); write(value); write('"'); m_newLine = false; m_valueWritten = true; } void LuaTableWriter::writeKeyAndValue(const QByteArray &key, const QByteArray &value) { prepareNewLine(); write(key); write(" = \""); write(value); write('"'); m_newLine = false; m_valueWritten = true; } void LuaTableWriter::writeQuotedKeyAndValue(const QString &key, const QString &value) { prepareNewLine(); write('['); write(quote(key).toUtf8()); write("] = "); write(quote(value).toUtf8()); m_newLine = false; m_valueWritten = true; } void LuaTableWriter::writeKeyAndUnquotedValue(const QByteArray &key, const QByteArray &value) { prepareNewLine(); write(key); write(" = "); write(value); m_newLine = false; m_valueWritten = true; } /** * Quotes the given string, escaping special characters as necessary. */ QString LuaTableWriter::quote(const QString &str) { QString quoted("\""); for (int i = 0; i < str.length(); ++i) { const QChar c = str.at(i); switch (c.unicode()) { case '\\': quoted.append(QLatin1String("\\\\")); break; case '"': quoted.append(QLatin1String("\\\"")); break; case '\n': quoted.append(QLatin1String("\\n")); break; default: quoted.append(c); } } quoted.append(QLatin1Char('"')); return quoted; } void LuaTableWriter::prepareNewLine() { if (m_valueWritten) { write(m_valueSeparator); m_valueWritten = false; } writeNewline(); } void LuaTableWriter::prepareNewValue() { if (!m_valueWritten) { writeNewline(); } else { write(m_valueSeparator); write(' '); } } void LuaTableWriter::writeIndent() { for (int level = m_indent; level; --level) write(" "); } void LuaTableWriter::writeNewline() { if (!m_newLine) { if (m_suppressNewlines) { write(' '); } else { write('\n'); writeIndent(); } m_newLine = true; } } void LuaTableWriter::write(const char *bytes, unsigned length) { if (m_device->write(bytes, length) != length) m_error = true; } } // namespace Lua tiled-0.14.2/src/plugins/lua/luatablewriter.h000066400000000000000000000105111260670167100211330ustar00rootroot00000000000000/* * Lua Tiled Plugin * Copyright 2011-2013, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef LUATABLEWRITER_H #define LUATABLEWRITER_H #include #include class QIODevice; namespace Lua { /** * Makes it easy to produce a well formatted Lua table. */ class LuaTableWriter { public: LuaTableWriter(QIODevice *device); void writeStartDocument(); void writeEndDocument(); void writeStartTable(); void writeStartReturnTable(); void writeStartTable(const QByteArray &name); void writeEndTable(); void writeValue(int value); void writeValue(unsigned value); void writeValue(const QByteArray &value); void writeValue(const QString &value); void writeUnquotedValue(const QByteArray &value); void writeKeyAndValue(const QByteArray &key, int value); void writeKeyAndValue(const QByteArray &key, unsigned value); void writeKeyAndValue(const QByteArray &key, double value); void writeKeyAndValue(const QByteArray &key, bool value); void writeKeyAndValue(const QByteArray &key, const char *value); void writeKeyAndValue(const QByteArray &key, const QByteArray &value); void writeKeyAndValue(const QByteArray &key, const QString &value); void writeQuotedKeyAndValue(const QString &key, const QString &value); void writeKeyAndUnquotedValue(const QByteArray &key, const QByteArray &value); void setSuppressNewlines(bool suppressNewlines); bool suppressNewlines() const; void prepareNewLine(); bool hasError() const { return m_error; } static QString quote(const QString &str); private: void prepareNewValue(); void writeIndent(); void writeNewline(); void write(const char *bytes, unsigned length); void write(const char *bytes); void write(const QByteArray &bytes); void write(char c); QIODevice *m_device; int m_indent; char m_valueSeparator; bool m_suppressNewlines; bool m_newLine; bool m_valueWritten; bool m_error; }; inline void LuaTableWriter::writeValue(int value) { writeUnquotedValue(QByteArray::number(value)); } inline void LuaTableWriter::writeValue(unsigned value) { writeUnquotedValue(QByteArray::number(value)); } inline void LuaTableWriter::writeValue(const QString &value) { writeUnquotedValue(quote(value).toUtf8()); } inline void LuaTableWriter::writeKeyAndValue(const QByteArray &key, int value) { writeKeyAndUnquotedValue(key, QByteArray::number(value)); } inline void LuaTableWriter::writeKeyAndValue(const QByteArray &key, unsigned value) { writeKeyAndUnquotedValue(key, QByteArray::number(value)); } inline void LuaTableWriter::writeKeyAndValue(const QByteArray &key, double value) { writeKeyAndUnquotedValue(key, QByteArray::number(value)); } inline void LuaTableWriter::writeKeyAndValue(const QByteArray &key, bool value) { writeKeyAndUnquotedValue(key, value ? "true" : "false"); } inline void LuaTableWriter::writeKeyAndValue(const QByteArray &key, const QString &value) { writeKeyAndUnquotedValue(key, quote(value).toUtf8()); } inline void LuaTableWriter::write(const char *bytes) { write(bytes, qstrlen(bytes)); } inline void LuaTableWriter::write(const QByteArray &bytes) { write(bytes.constData(), bytes.length()); } inline void LuaTableWriter::write(char c) { write(&c, 1); } /** * Sets whether newlines should be suppressed. While newlines are suppressed, * the writer will write out spaces instead of newlines. */ inline void LuaTableWriter::setSuppressNewlines(bool suppressNewlines) { m_suppressNewlines = suppressNewlines; } inline bool LuaTableWriter::suppressNewlines() const { return m_suppressNewlines; } } // namespace Lua #endif // LUATABLEWRITER_H tiled-0.14.2/src/plugins/lua/plugin.json000066400000000000000000000000321260670167100201220ustar00rootroot00000000000000{ "Keys": [ "notused" ] } tiled-0.14.2/src/plugins/plugin.pri000066400000000000000000000017241260670167100171730ustar00rootroot00000000000000isEmpty(TARGET) { error("plugin.pri: You must provide a TARGET") } TEMPLATE = lib CONFIG += plugin contains(QT_CONFIG, reduce_exports): CONFIG += hide_symbols win32 { DESTDIR = $$OUT_PWD/../../../plugins/tiled } else:macx { DESTDIR = $$OUT_PWD/../../../bin/Tiled.app/Contents/PlugIns } else { DESTDIR = $$OUT_PWD/../../../lib/tiled/plugins } include(../../tiled.pri) target.path = $${LIBDIR}/tiled/plugins INSTALLS += target include(../libtiled/libtiled.pri) macx { QMAKE_LIBDIR += $$OUT_PWD/../../../bin/Tiled.app/Contents/Frameworks } else:win32 { LIBS += -L$$OUT_PWD/../../../lib } else { QMAKE_LIBDIR += $$OUT_PWD/../../../lib } # Set rpath so that the plugin will resolve libtiled correctly !win32:!macx:contains(RPATH, yes) { QMAKE_RPATHDIR += \$\$ORIGIN/../.. # It is not possible to use ORIGIN in QMAKE_RPATHDIR, so a bit manually QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$$join(QMAKE_RPATHDIR, ":")\' QMAKE_RPATHDIR = } tiled-0.14.2/src/plugins/plugins.pro000066400000000000000000000005401260670167100173570ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS = csv \ droidcraft \ flare \ json \ lua \ replicaisland \ tengine \ tmw include(python/find_python.pri) contains(HAVE_PYTHON, yes) { message("Have Python, will slither") SUBDIRS += python } else { !build_pass:message("No Python support") } tiled-0.14.2/src/plugins/plugins.qbs000066400000000000000000000003331260670167100173440ustar00rootroot00000000000000Project { name: "plugins" references: [ "csv", "droidcraft", "flare", "json", "lua", "python", "replicaisland", "tengine", "tmw", ] } tiled-0.14.2/src/plugins/python/000077500000000000000000000000001260670167100164765ustar00rootroot00000000000000tiled-0.14.2/src/plugins/python/find_python.pri000066400000000000000000000012431260670167100215330ustar00rootroot00000000000000!contains(DISABLE_PYTHON_PLUGIN, yes) { unix { system(pkg-config python-2.7) { HAVE_PYTHON = yes CONFIG += link_pkgconfig PKGCONFIG += python-2.7 } else:system(python-config --prefix) { # currently here for reference, only 2.7 is tested HAVE_PYTHON = yes QMAKE_CXXFLAGS = `python-config --cflags` QMAKE_LFLAGS = `python-config --ldflags` } } win32 { exists(C:/Python27/include/Python.h) { HAVE_PYTHON = yes QMAKE_CXXFLAGS += -IC:/Python27/include/ QMAKE_LIBS += -LC:/Python27/libs -lpython27 } } } tiled-0.14.2/src/plugins/python/plugin.json000066400000000000000000000000321260670167100206620ustar00rootroot00000000000000{ "Keys": [ "notused" ] } tiled-0.14.2/src/plugins/python/python.pro000066400000000000000000000002401260670167100205350ustar00rootroot00000000000000include(../plugin.pri) include(find_python.pri) QT += widgets DEFINES += PYTHON_LIBRARY SOURCES += pythonplugin.cpp pythonbind.cpp HEADERS += pythonplugin.h tiled-0.14.2/src/plugins/python/python.qbs000066400000000000000000000032111260670167100205230ustar00rootroot00000000000000import qbs 1.0 import qbs.Probes as Probes import qbs.File TiledPlugin { Depends { name: "Qt"; submodules: ["widgets"] } condition: { if (qbs.targetOS.contains("linux")) { return true; } else if (qbs.targetOS.contains("windows")) { // On Windows, currently only the default install location of // Python 2.7 is supported, and only when compiling with MinGW in // release mode. Also, it needs to be Python 2.7.9, since 2.7.10 // results in a linker error. // // https://www.python.org/ftp/python/2.7.9/python-2.7.9.msi // return File.exists("C:/Python27") && qbs.toolchain.contains("mingw") && !qbs.debugInformation; } // Not sure how to properly support Python on Mac OS X yet // (possibly requires using python-config) return false; } Probes.PkgConfigProbe { id: pkgConfig name: "python-2.7" } Properties { condition: qbs.targetOS.contains("linux") cpp.cxxFlags: pkgConfig.cflags // This should be it, but it doesn't work because the -lpython2.7 ends // up too early on the command line. //cpp.linkerFlags: pkgConfig.libs cpp.dynamicLibraries: ["python2.7"] } Properties { condition: qbs.targetOS.contains("windows") cpp.includePaths: ["C:/Python27/include"] cpp.libraryPaths: ["C:/Python27/libs"] cpp.dynamicLibraries: ["python27"] } files: [ "pythonplugin.cpp", "pythonplugin.h", "pythonbind.cpp", ] } tiled-0.14.2/src/plugins/python/pythonbind.cpp000066400000000000000000006447011260670167100213740ustar00rootroot00000000000000 #ifdef __MINGW32__ #include // included before Python.h to fix ::hypot not declared issue #endif /* This file was generated by PyBindGen 0.17.0 */ #define PY_SSIZE_T_CLEAN #include #include #if PY_VERSION_HEX < 0x020400F0 #define PyEval_ThreadsInitialized() 1 #define Py_CLEAR(op) \ do { \ if (op) { \ PyObject *tmp = (PyObject *)(op); \ (op) = NULL; \ Py_DECREF(tmp); \ } \ } while (0) #define Py_VISIT(op) \ do { \ if (op) { \ int vret = visit((PyObject *)(op), arg); \ if (vret) \ return vret; \ } \ } while (0) #endif #if PY_VERSION_HEX < 0x020500F0 typedef int Py_ssize_t; # define PY_SSIZE_T_MAX INT_MAX # define PY_SSIZE_T_MIN INT_MIN typedef inquiry lenfunc; typedef intargfunc ssizeargfunc; typedef intobjargproc ssizeobjargproc; #endif #ifndef PyVarObject_HEAD_INIT #define PyVarObject_HEAD_INIT(type, size) \ PyObject_HEAD_INIT(type) size, #endif #if PY_VERSION_HEX >= 0x03000000 typedef void* cmpfunc; #define PyCObject_FromVoidPtr(a, b) PyCapsule_New(a, NULL, b) #define PyCObject_AsVoidPtr(a) PyCapsule_GetPointer(a, NULL) #define PyString_FromString(a) PyBytes_FromString(a) #define Py_TPFLAGS_CHECKTYPES 0 /* this flag doesn't exist in python 3 */ #endif #if __GNUC__ > 2 # define PYBINDGEN_UNUSED(param) param __attribute__((__unused__)) #elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) # define PYBINDGEN_UNUSED(param) __attribute__((__unused__)) param #else # define PYBINDGEN_UNUSED(param) param #endif /* !__GNUC__ */ #ifndef _PyBindGenWrapperFlags_defined_ #define _PyBindGenWrapperFlags_defined_ typedef enum _PyBindGenWrapperFlags { PYBINDGEN_WRAPPER_FLAG_NONE = 0, PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED = (1<<0), } PyBindGenWrapperFlags; #endif #include "pythonplugin.h" #include "map.h" #include "layer.h" #include "tile.h" #include "mapobject.h" #include "imagelayer.h" #include "tilelayer.h" #include "objectgroup.h" #include "tileset.h" #include #include #include #include /* --- forward declarations --- */ typedef struct { PyObject_HEAD Python::PythonScript *obj; PyObject *inst_dict; PyBindGenWrapperFlags flags:8; } PyPythonPythonScript; extern PyTypeObject PyPythonPythonScript_Type; /* --- forward declarations --- */ typedef struct { PyObject_HEAD QPointF *obj; PyBindGenWrapperFlags flags:8; } PyQPointF; extern PyTypeObject PyQPointF_Type; typedef struct { PyObject_HEAD QSizeF *obj; PyBindGenWrapperFlags flags:8; } PyQSizeF; extern PyTypeObject PyQSizeF_Type; typedef struct { PyObject_HEAD QRgb *obj; PyBindGenWrapperFlags flags:8; } PyQRgb; extern PyTypeObject PyQRgb_Type; typedef struct { PyObject_HEAD QColor *obj; PyBindGenWrapperFlags flags:8; } PyQColor; extern PyTypeObject PyQColor_Type; typedef struct { PyObject_HEAD QImage *obj; PyBindGenWrapperFlags flags:8; } PyQImage; extern PyTypeObject PyQImage_Type; typedef struct { PyObject_HEAD QPixmap *obj; PyBindGenWrapperFlags flags:8; } PyQPixmap; extern PyTypeObject PyQPixmap_Type; typedef struct { PyObject_HEAD QWidget *obj; PyBindGenWrapperFlags flags:8; } PyQWidget; extern PyTypeObject PyQWidget_Type; typedef struct { PyObject_HEAD QFileDialog *obj; PyBindGenWrapperFlags flags:8; } PyQFileDialog; extern PyTypeObject PyQFileDialog_Type; typedef struct { PyObject_HEAD QVector *obj; } PyQVector__lt__QRgb__gt__; typedef struct { PyObject_HEAD PyQVector__lt__QRgb__gt__ *container; QVector::iterator *iterator; } PyQVector__lt__QRgb__gt__Iter; extern PyTypeObject PyQVector__lt__QRgb__gt___Type; extern PyTypeObject PyQVector__lt__QRgb__gt__Iter_Type; int _wrap_convert_py2c__QVector__lt___QRgb___gt__(PyObject *arg, QVector *container); typedef struct { PyObject_HEAD QList *obj; } PyQList__lt__QString__gt__; typedef struct { PyObject_HEAD PyQList__lt__QString__gt__ *container; QList::iterator *iterator; } PyQList__lt__QString__gt__Iter; extern PyTypeObject PyQList__lt__QString__gt___Type; extern PyTypeObject PyQList__lt__QString__gt__Iter_Type; int _wrap_convert_py2c__QList__lt___QString___gt__(PyObject *arg, QList *container); /* --- forward declarations --- */ typedef struct { PyObject_HEAD Tiled::Tile *obj; PyBindGenWrapperFlags flags:8; } PyTiledTile; extern PyTypeObject PyTiledTile_Type; typedef struct { PyObject_HEAD Tiled::SharedTileset *obj; PyBindGenWrapperFlags flags:8; } PyTiledSharedTileset; extern PyTypeObject PyTiledSharedTileset_Type; typedef struct { PyObject_HEAD Tiled::Tileset *obj; PyBindGenWrapperFlags flags:8; } PyTiledTileset; extern PyTypeObject PyTiledTileset_Type; typedef struct { PyObject_HEAD Tiled::Layer *obj; PyBindGenWrapperFlags flags:8; } PyTiledLayer; extern PyTypeObject PyTiledLayer_Type; typedef struct { PyObject_HEAD Tiled::Properties *obj; PyBindGenWrapperFlags flags:8; } PyTiledProperties; extern PyTypeObject PyTiledProperties_Type; typedef struct { PyObject_HEAD Tiled::Map *obj; PyBindGenWrapperFlags flags:8; } PyTiledMap; extern PyTypeObject PyTiledMap_Type; typedef struct { PyObject_HEAD Tiled::Cell *obj; PyBindGenWrapperFlags flags:8; } PyTiledCell; extern PyTypeObject PyTiledCell_Type; typedef struct { PyObject_HEAD Tiled::TileLayer *obj; PyBindGenWrapperFlags flags:8; } PyTiledTileLayer; extern PyTypeObject PyTiledTileLayer_Type; typedef struct { PyObject_HEAD Tiled::ImageLayer *obj; PyBindGenWrapperFlags flags:8; } PyTiledImageLayer; extern PyTypeObject PyTiledImageLayer_Type; typedef struct { PyObject_HEAD Tiled::Object *obj; PyBindGenWrapperFlags flags:8; } PyTiledObject; extern PyTypeObject PyTiledObject_Type; typedef struct { PyObject_HEAD Tiled::MapObject *obj; PyBindGenWrapperFlags flags:8; } PyTiledMapObject; extern PyTypeObject PyTiledMapObject_Type; typedef struct { PyObject_HEAD Tiled::ObjectGroup *obj; PyBindGenWrapperFlags flags:8; } PyTiledObjectGroup; extern PyTypeObject PyTiledObjectGroup_Type; typedef struct { PyObject_HEAD Tiled::LoggingInterface *obj; PyBindGenWrapperFlags flags:8; } PyTiledLoggingInterface; extern PyTypeObject PyTiledLoggingInterface_Type; #pragma GCC diagnostic ignored "-Wmissing-field-initializers" int _wrap_convert_py2c__QRgb(PyObject *value, QRgb *address); int _wrap_convert_py2c__QString(PyObject *value, QString *address); static PyMethodDef tiled_qt_functions[] = { {NULL, NULL, 0, NULL} }; /* --- classes --- */ static int _wrap_PyQPointF__tp_init(PyQPointF *self, PyObject *args, PyObject *kwargs) { float x; float y; const char *keywords[] = {"x", "y", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "ff", (char **) keywords, &x, &y)) { return -1; } self->obj = new QPointF(x, y); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } PyObject * _wrap_PyQPointF_y(PyQPointF *self) { PyObject *py_retval; int retval; retval = self->obj->y(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyQPointF_x(PyQPointF *self) { PyObject *py_retval; int retval; retval = self->obj->x(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyQPointF_setX(PyQPointF *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int x; const char *keywords[] = {"x", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &x)) { return NULL; } self->obj->setX(x); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQPointF_setY(PyQPointF *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int y; const char *keywords[] = {"y", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &y)) { return NULL; } self->obj->setY(y); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } static PyMethodDef PyQPointF_methods[] = { {(char *) "y", (PyCFunction) _wrap_PyQPointF_y, METH_NOARGS, NULL }, {(char *) "x", (PyCFunction) _wrap_PyQPointF_x, METH_NOARGS, NULL }, {(char *) "setX", (PyCFunction) _wrap_PyQPointF_setX, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setY", (PyCFunction) _wrap_PyQPointF_setY, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyQPointF__tp_dealloc(PyQPointF *self) { QPointF *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQPointF__tp_richcompare (PyQPointF *PYBINDGEN_UNUSED(self), PyQPointF *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyQPointF_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyQPointF_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QPointF", /* tp_name */ sizeof(PyQPointF), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQPointF__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyQPointF__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyQPointF_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQPointF__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyQSizeF__tp_init(PyQSizeF *self, PyObject *args, PyObject *kwargs) { float w; float h; const char *keywords[] = {"w", "h", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "ff", (char **) keywords, &w, &h)) { return -1; } self->obj = new QSizeF(w, h); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } PyObject * _wrap_PyQSizeF_setHeight(PyQSizeF *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int h; const char *keywords[] = {"h", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &h)) { return NULL; } self->obj->setHeight(h); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQSizeF_width(PyQSizeF *self) { PyObject *py_retval; int retval; retval = self->obj->width(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyQSizeF_setWidth(PyQSizeF *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int w; const char *keywords[] = {"w", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &w)) { return NULL; } self->obj->setWidth(w); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQSizeF_height(PyQSizeF *self) { PyObject *py_retval; int retval; retval = self->obj->height(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } static PyMethodDef PyQSizeF_methods[] = { {(char *) "setHeight", (PyCFunction) _wrap_PyQSizeF_setHeight, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "width", (PyCFunction) _wrap_PyQSizeF_width, METH_NOARGS, NULL }, {(char *) "setWidth", (PyCFunction) _wrap_PyQSizeF_setWidth, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "height", (PyCFunction) _wrap_PyQSizeF_height, METH_NOARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyQSizeF__tp_dealloc(PyQSizeF *self) { QSizeF *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQSizeF__tp_richcompare (PyQSizeF *PYBINDGEN_UNUSED(self), PyQSizeF *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyQSizeF_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyQSizeF_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QSizeF", /* tp_name */ sizeof(PyQSizeF), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQSizeF__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyQSizeF__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyQSizeF_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQSizeF__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyQRgb__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'QRgb' cannot be constructed ()"); return -1; } static PyMethodDef PyQRgb_methods[] = { {NULL, NULL, 0, NULL} }; static void _wrap_PyQRgb__tp_dealloc(PyQRgb *self) { QRgb *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQRgb__tp_richcompare (PyQRgb *PYBINDGEN_UNUSED(self), PyQRgb *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyQRgb_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyQRgb_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QRgb", /* tp_name */ sizeof(PyQRgb), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQRgb__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyQRgb__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyQRgb_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQRgb__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyQColor__tp_init__0(PyQColor *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { PyQRgb *col; const char *keywords[] = {"col", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyQRgb_Type, &col)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new QColor(*((PyQRgb *) col)->obj); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } static int _wrap_PyQColor__tp_init__1(PyQColor *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { int r; int g; int b; const char *keywords[] = {"r", "g", "b", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iii", (char **) keywords, &r, &g, &b)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new QColor(r, g, b); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } static int _wrap_PyQColor__tp_init__2(PyQColor *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { int r; int g; int b; int a; const char *keywords[] = {"r", "g", "b", "a", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iiii", (char **) keywords, &r, &g, &b, &a)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new QColor(r, g, b, a); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } int _wrap_PyQColor__tp_init(PyQColor *self, PyObject *args, PyObject *kwargs) { int retval; PyObject *error_list; PyObject *exceptions[3] = {0,}; retval = _wrap_PyQColor__tp_init__0(self, args, kwargs, &exceptions[0]); if (!exceptions[0]) { return retval; } retval = _wrap_PyQColor__tp_init__1(self, args, kwargs, &exceptions[1]); if (!exceptions[1]) { Py_DECREF(exceptions[0]); return retval; } retval = _wrap_PyQColor__tp_init__2(self, args, kwargs, &exceptions[2]); if (!exceptions[2]) { Py_DECREF(exceptions[0]); Py_DECREF(exceptions[1]); return retval; } error_list = PyList_New(3); PyList_SET_ITEM(error_list, 0, PyObject_Str(exceptions[0])); Py_DECREF(exceptions[0]); PyList_SET_ITEM(error_list, 1, PyObject_Str(exceptions[1])); Py_DECREF(exceptions[1]); PyList_SET_ITEM(error_list, 2, PyObject_Str(exceptions[2])); Py_DECREF(exceptions[2]); PyErr_SetObject(PyExc_TypeError, error_list); Py_DECREF(error_list); return -1; } PyObject * _wrap_PyQColor_rgb(PyQColor *self) { PyObject *py_retval; PyQRgb *py_QRgb; QRgb retval = self->obj->rgb(); py_QRgb = PyObject_New(PyQRgb, &PyQRgb_Type); py_QRgb->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QRgb->obj = new QRgb(retval); py_retval = Py_BuildValue((char *) "N", py_QRgb); return py_retval; } PyObject * _wrap_PyQColor_rgba(PyQColor *self) { PyObject *py_retval; PyQRgb *py_QRgb; QRgb retval = self->obj->rgba(); py_QRgb = PyObject_New(PyQRgb, &PyQRgb_Type); py_QRgb->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QRgb->obj = new QRgb(retval); py_retval = Py_BuildValue((char *) "N", py_QRgb); return py_retval; } static PyMethodDef PyQColor_methods[] = { {(char *) "rgb", (PyCFunction) _wrap_PyQColor_rgb, METH_NOARGS, NULL }, {(char *) "rgba", (PyCFunction) _wrap_PyQColor_rgba, METH_NOARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyQColor__tp_dealloc(PyQColor *self) { QColor *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQColor__tp_richcompare (PyQColor *PYBINDGEN_UNUSED(self), PyQColor *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyQColor_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyQColor_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QColor", /* tp_name */ sizeof(PyQColor), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQColor__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyQColor__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyQColor_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQColor__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyQImage__tp_init__0(PyQImage *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { const char *keywords[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "", (char **) keywords)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new QImage(); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } static int _wrap_PyQImage__tp_init__1(PyQImage *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { int w; int h; QImage::Format f; const char *keywords[] = {"w", "h", "f", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iii", (char **) keywords, &w, &h, &f)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new QImage(w, h, f); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } int _wrap_PyQImage__tp_init(PyQImage *self, PyObject *args, PyObject *kwargs) { int retval; PyObject *error_list; PyObject *exceptions[2] = {0,}; retval = _wrap_PyQImage__tp_init__0(self, args, kwargs, &exceptions[0]); if (!exceptions[0]) { return retval; } retval = _wrap_PyQImage__tp_init__1(self, args, kwargs, &exceptions[1]); if (!exceptions[1]) { Py_DECREF(exceptions[0]); return retval; } error_list = PyList_New(2); PyList_SET_ITEM(error_list, 0, PyObject_Str(exceptions[0])); Py_DECREF(exceptions[0]); PyList_SET_ITEM(error_list, 1, PyObject_Str(exceptions[1])); Py_DECREF(exceptions[1]); PyErr_SetObject(PyExc_TypeError, error_list); Py_DECREF(error_list); return -1; } PyObject * _wrap_PyQImage_load(PyQImage *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; const char *fileName; Py_ssize_t fileName_len; char *fmt; const char *keywords[] = {"fileName", "fmt", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#s", (char **) keywords, &fileName, &fileName_len, &fmt)) { return NULL; } retval = self->obj->load(QString::fromUtf8(fileName), fmt); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyQImage_setColor(PyQImage *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int i; PyQRgb *c; const char *keywords[] = {"i", "c", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iO!", (char **) keywords, &i, &PyQRgb_Type, &c)) { return NULL; } self->obj->setColor(i, *((PyQRgb *) c)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQImage_color(PyQImage *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int i; const char *keywords[] = {"i", NULL}; PyQRgb *py_QRgb; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &i)) { return NULL; } QRgb retval = self->obj->color(i); py_QRgb = PyObject_New(PyQRgb, &PyQRgb_Type); py_QRgb->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QRgb->obj = new QRgb(retval); py_retval = Py_BuildValue((char *) "N", py_QRgb); return py_retval; } PyObject * _wrap_PyQImage_mirrored(PyQImage *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool horiz; PyObject *py_horiz; bool vert; PyObject *py_vert; const char *keywords[] = {"horiz", "vert", NULL}; PyQImage *py_QImage; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "OO", (char **) keywords, &py_horiz, &py_vert)) { return NULL; } horiz = (bool) PyObject_IsTrue(py_horiz); vert = (bool) PyObject_IsTrue(py_vert); QImage const & retval = self->obj->mirrored(horiz, vert); py_QImage = PyObject_New(PyQImage, &PyQImage_Type); py_QImage->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QImage->obj = new QImage(retval); py_retval = Py_BuildValue((char *) "N", py_QImage); return py_retval; } PyObject * _wrap_PyQImage_height(PyQImage *self) { PyObject *py_retval; int retval; retval = self->obj->height(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyQImage_setPixel__0(PyQImage *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { PyObject *py_retval; int x; int y; unsigned int color; const char *keywords[] = {"x", "y", "color", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iiI", (char **) keywords, &x, &y, &color)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return NULL; } self->obj->setPixel(x, y, color); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQImage_setPixel__1(PyQImage *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { PyObject *py_retval; int x; int y; PyQRgb *color; const char *keywords[] = {"x", "y", "color", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iiO!", (char **) keywords, &x, &y, &PyQRgb_Type, &color)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return NULL; } self->obj->setPixel(x, y, *((PyQRgb *) color)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQImage_setPixel(PyQImage *self, PyObject *args, PyObject *kwargs) { PyObject * retval; PyObject *error_list; PyObject *exceptions[2] = {0,}; retval = _wrap_PyQImage_setPixel__0(self, args, kwargs, &exceptions[0]); if (!exceptions[0]) { return retval; } retval = _wrap_PyQImage_setPixel__1(self, args, kwargs, &exceptions[1]); if (!exceptions[1]) { Py_DECREF(exceptions[0]); return retval; } error_list = PyList_New(2); PyList_SET_ITEM(error_list, 0, PyObject_Str(exceptions[0])); Py_DECREF(exceptions[0]); PyList_SET_ITEM(error_list, 1, PyObject_Str(exceptions[1])); Py_DECREF(exceptions[1]); PyErr_SetObject(PyExc_TypeError, error_list); Py_DECREF(error_list); return NULL; } PyObject * _wrap_PyQImage_width(PyQImage *self) { PyObject *py_retval; int retval; retval = self->obj->width(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyQImage_colorTable(PyQImage *self) { PyObject *py_retval; QVector< QRgb > retval; PyQVector__lt__QRgb__gt__ *py_QVector__lt__QRgb__gt__; retval = self->obj->colorTable(); py_QVector__lt__QRgb__gt__ = PyObject_New(PyQVector__lt__QRgb__gt__, &PyQVector__lt__QRgb__gt___Type); py_QVector__lt__QRgb__gt__->obj = new QVector(retval); py_retval = Py_BuildValue((char *) "N", py_QVector__lt__QRgb__gt__); return py_retval; } PyObject * _wrap_PyQImage_setColorTable(PyQImage *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; QVector colors_value; const char *keywords[] = {"colors", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O&", (char **) keywords, _wrap_convert_py2c__QVector__lt___QRgb___gt__, &colors_value)) { return NULL; } self->obj->setColorTable(colors_value); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQImage_fill(PyQImage *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int color; const char *keywords[] = {"color", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &color)) { return NULL; } self->obj->fill(color); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } static PyMethodDef PyQImage_methods[] = { {(char *) "load", (PyCFunction) _wrap_PyQImage_load, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setColor", (PyCFunction) _wrap_PyQImage_setColor, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "color", (PyCFunction) _wrap_PyQImage_color, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "mirrored", (PyCFunction) _wrap_PyQImage_mirrored, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "height", (PyCFunction) _wrap_PyQImage_height, METH_NOARGS, NULL }, {(char *) "setPixel", (PyCFunction) _wrap_PyQImage_setPixel, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "width", (PyCFunction) _wrap_PyQImage_width, METH_NOARGS, NULL }, {(char *) "colorTable", (PyCFunction) _wrap_PyQImage_colorTable, METH_NOARGS, NULL }, {(char *) "setColorTable", (PyCFunction) _wrap_PyQImage_setColorTable, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "fill", (PyCFunction) _wrap_PyQImage_fill, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyQImage__tp_dealloc(PyQImage *self) { QImage *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQImage__tp_richcompare (PyQImage *PYBINDGEN_UNUSED(self), PyQImage *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyQImage_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyQImage_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QImage", /* tp_name */ sizeof(PyQImage), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQImage__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyQImage__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyQImage_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQImage__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyQPixmap__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'QPixmap' cannot be constructed ()"); return -1; } PyObject * _wrap_PyQPixmap_convertFromImage(PyQPixmap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyQImage *image; const char *keywords[] = {"image", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyQImage_Type, &image)) { return NULL; } self->obj->convertFromImage(*((PyQImage *) image)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQPixmap_width(PyQPixmap *self) { PyObject *py_retval; int retval; retval = self->obj->width(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyQPixmap_toImage(PyQPixmap *self) { PyObject *py_retval; PyQImage *py_QImage; QImage const & retval = self->obj->toImage(); py_QImage = PyObject_New(PyQImage, &PyQImage_Type); py_QImage->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QImage->obj = new QImage(retval); py_retval = Py_BuildValue((char *) "N", py_QImage); return py_retval; } PyObject * _wrap_PyQPixmap_fromImage(PyQPixmap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyQImage *image; const char *keywords[] = {"image", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyQImage_Type, &image)) { return NULL; } self->obj->fromImage(*((PyQImage *) image)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyQPixmap_height(PyQPixmap *self) { PyObject *py_retval; int retval; retval = self->obj->height(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } static PyMethodDef PyQPixmap_methods[] = { {(char *) "convertFromImage", (PyCFunction) _wrap_PyQPixmap_convertFromImage, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "width", (PyCFunction) _wrap_PyQPixmap_width, METH_NOARGS, NULL }, {(char *) "toImage", (PyCFunction) _wrap_PyQPixmap_toImage, METH_NOARGS, NULL }, {(char *) "fromImage", (PyCFunction) _wrap_PyQPixmap_fromImage, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "height", (PyCFunction) _wrap_PyQPixmap_height, METH_NOARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyQPixmap__tp_dealloc(PyQPixmap *self) { QPixmap *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQPixmap__tp_richcompare (PyQPixmap *PYBINDGEN_UNUSED(self), PyQPixmap *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyQPixmap_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyQPixmap_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QPixmap", /* tp_name */ sizeof(PyQPixmap), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQPixmap__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyQPixmap__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyQPixmap_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQPixmap__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyQWidget__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'QWidget' cannot be constructed ()"); return -1; } static PyMethodDef PyQWidget_methods[] = { {NULL, NULL, 0, NULL} }; static void _wrap_PyQWidget__tp_dealloc(PyQWidget *self) { QWidget *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQWidget__tp_richcompare (PyQWidget *PYBINDGEN_UNUSED(self), PyQWidget *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyQWidget_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyQWidget_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QWidget", /* tp_name */ sizeof(PyQWidget), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQWidget__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyQWidget__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyQWidget_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQWidget__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyQFileDialog__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'QFileDialog' cannot be constructed ()"); return -1; } PyObject * _wrap_PyQFileDialog_getOpenFileName(PyQFileDialog *PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs) { PyObject *py_retval; QString retval; PyQWidget *parent; QWidget *parent_ptr; const char *caption; Py_ssize_t caption_len; const char *dir; Py_ssize_t dir_len; const char *filter; Py_ssize_t filter_len; const char *selectedFilter; QFileDialog::Option options; const char *keywords[] = {"parent", "caption", "dir", "filter", "selectedFilter", "options", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "Os#s#s#|si", (char **) keywords, &parent, &caption, &caption_len, &dir, &dir_len, &filter, &filter_len, &selectedFilter, &options)) { return NULL; } if (parent && ((PyObject *) parent != Py_None) && !PyObject_IsInstance((PyObject *) parent, (PyObject *) &PyQWidget_Type)) { PyErr_SetString(PyExc_TypeError, "Parameter 1 must be of type QWidget"); return NULL; } if (parent) { if ((PyObject *) parent == Py_None) parent_ptr = NULL; else parent_ptr = parent->obj; } else { parent_ptr = NULL; } retval = QFileDialog::getOpenFileName(parent_ptr, QString::fromUtf8(caption), QString::fromUtf8(dir), QString::fromUtf8(filter), new QString(""), 0); py_retval = Py_BuildValue((char *) "s", retval.toUtf8().data()); return py_retval; } static PyMethodDef PyQFileDialog_methods[] = { {(char *) "getOpenFileName", (PyCFunction) _wrap_PyQFileDialog_getOpenFileName, METH_KEYWORDS|METH_VARARGS|METH_STATIC, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyQFileDialog__tp_dealloc(PyQFileDialog *self) { QFileDialog *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQFileDialog__tp_richcompare (PyQFileDialog *PYBINDGEN_UNUSED(self), PyQFileDialog *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyQFileDialog_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyQFileDialog_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QFileDialog", /* tp_name */ sizeof(PyQFileDialog), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQFileDialog__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyQFileDialog__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyQFileDialog_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQFileDialog__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; /* --- containers --- */ static void PyQVector__lt__QRgb__gt__Iter__tp_clear(PyQVector__lt__QRgb__gt__Iter *self) { Py_CLEAR(self->container); delete self->iterator; self->iterator = NULL; } static int PyQVector__lt__QRgb__gt__Iter__tp_traverse(PyQVector__lt__QRgb__gt__Iter *self, visitproc visit, void *arg) { Py_VISIT((PyObject *) self->container); return 0; } static void _wrap_PyQVector__lt__QRgb__gt____tp_dealloc(PyQVector__lt__QRgb__gt__ *self) { delete self->obj; self->obj = NULL; Py_TYPE(self)->tp_free((PyObject*)self); } static void _wrap_PyQVector__lt__QRgb__gt__Iter__tp_dealloc(PyQVector__lt__QRgb__gt__Iter *self) { Py_CLEAR(self->container); delete self->iterator; self->iterator = NULL; Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQVector__lt__QRgb__gt____tp_iter(PyQVector__lt__QRgb__gt__ *self) { PyQVector__lt__QRgb__gt__Iter *iter = PyObject_GC_New(PyQVector__lt__QRgb__gt__Iter, &PyQVector__lt__QRgb__gt__Iter_Type); Py_INCREF(self); iter->container = self; iter->iterator = new QVector::iterator(self->obj->begin()); return (PyObject*) iter; } static PyObject* _wrap_PyQVector__lt__QRgb__gt__Iter__tp_iter(PyQVector__lt__QRgb__gt__Iter *self) { Py_INCREF(self); return (PyObject*) self; } static PyObject* _wrap_PyQVector__lt__QRgb__gt__Iter__tp_iternext(PyQVector__lt__QRgb__gt__Iter *self) { PyObject *py_retval; QVector::iterator iter; PyQRgb *py_QRgb; iter = *self->iterator; if (iter == self->container->obj->end()) { PyErr_SetNone(PyExc_StopIteration); return NULL; } ++(*self->iterator); py_QRgb = PyObject_New(PyQRgb, &PyQRgb_Type); py_QRgb->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QRgb->obj = new QRgb((*iter)); py_retval = Py_BuildValue((char *) "N", py_QRgb); return py_retval; } int _wrap_convert_py2c__QRgb(PyObject *value, QRgb *address) { PyObject *py_retval; PyQRgb *tmp_QRgb; py_retval = Py_BuildValue((char *) "(O)", value); if (!PyArg_ParseTuple(py_retval, (char *) "O!", &PyQRgb_Type, &tmp_QRgb)) { Py_DECREF(py_retval); return 0; } *address = *tmp_QRgb->obj; Py_DECREF(py_retval); return 1; } int _wrap_convert_py2c__QVector__lt___QRgb___gt__(PyObject *arg, QVector *container) { if (PyObject_IsInstance(arg, (PyObject*) &PyQVector__lt__QRgb__gt___Type)) { *container = *((PyQVector__lt__QRgb__gt__*)arg)->obj; } else if (PyList_Check(arg)) { container->clear(); Py_ssize_t size = PyList_Size(arg); for (Py_ssize_t i = 0; i < size; i++) { QRgb item; if (!_wrap_convert_py2c__QRgb(PyList_GET_ITEM(arg, i), &item)) { return 0; } container->push_back(item); } } else { PyErr_SetString(PyExc_TypeError, "parameter must be None, a QVector__lt__QRgb__gt__ instance, or a list of QRgb"); return 0; } return 1; } static int _wrap_PyQVector__lt__QRgb__gt____tp_init(PyQVector__lt__QRgb__gt__ *self, PyObject *args, PyObject *kwargs) { const char *keywords[] = {"arg", NULL}; PyObject *arg = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "|O", (char **) keywords, &arg)) { return -1; } self->obj = new QVector; if (arg == NULL) return 0; if (!_wrap_convert_py2c__QVector__lt___QRgb___gt__(arg, self->obj)) { delete self->obj; self->obj = NULL; return -1; } return 0; } PyTypeObject PyQVector__lt__QRgb__gt___Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QVector__lt__QRgb__gt__", /* tp_name */ sizeof(PyQVector__lt__QRgb__gt__), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQVector__lt__QRgb__gt____tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)_wrap_PyQVector__lt__QRgb__gt____tp_iter, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)NULL, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQVector__lt__QRgb__gt____tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; PyTypeObject PyQVector__lt__QRgb__gt__Iter_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QVector__lt__QRgb__gt__Iter", /* tp_name */ sizeof(PyQVector__lt__QRgb__gt__Iter), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQVector__lt__QRgb__gt__Iter__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)PyQVector__lt__QRgb__gt__Iter__tp_traverse, /* tp_traverse */ (inquiry)PyQVector__lt__QRgb__gt__Iter__tp_clear, /* tp_clear */ (richcmpfunc)NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)_wrap_PyQVector__lt__QRgb__gt__Iter__tp_iter, /* tp_iter */ (iternextfunc)_wrap_PyQVector__lt__QRgb__gt__Iter__tp_iternext, /* tp_iternext */ (struct PyMethodDef*)NULL, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)NULL, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static void PyQList__lt__QString__gt__Iter__tp_clear(PyQList__lt__QString__gt__Iter *self) { Py_CLEAR(self->container); delete self->iterator; self->iterator = NULL; } static int PyQList__lt__QString__gt__Iter__tp_traverse(PyQList__lt__QString__gt__Iter *self, visitproc visit, void *arg) { Py_VISIT((PyObject *) self->container); return 0; } static void _wrap_PyQList__lt__QString__gt____tp_dealloc(PyQList__lt__QString__gt__ *self) { delete self->obj; self->obj = NULL; Py_TYPE(self)->tp_free((PyObject*)self); } static void _wrap_PyQList__lt__QString__gt__Iter__tp_dealloc(PyQList__lt__QString__gt__Iter *self) { Py_CLEAR(self->container); delete self->iterator; self->iterator = NULL; Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyQList__lt__QString__gt____tp_iter(PyQList__lt__QString__gt__ *self) { PyQList__lt__QString__gt__Iter *iter = PyObject_GC_New(PyQList__lt__QString__gt__Iter, &PyQList__lt__QString__gt__Iter_Type); Py_INCREF(self); iter->container = self; iter->iterator = new QList::iterator(self->obj->begin()); return (PyObject*) iter; } static PyObject* _wrap_PyQList__lt__QString__gt__Iter__tp_iter(PyQList__lt__QString__gt__Iter *self) { Py_INCREF(self); return (PyObject*) self; } static PyObject* _wrap_PyQList__lt__QString__gt__Iter__tp_iternext(PyQList__lt__QString__gt__Iter *self) { PyObject *py_retval; QList::iterator iter; iter = *self->iterator; if (iter == self->container->obj->end()) { PyErr_SetNone(PyExc_StopIteration); return NULL; } ++(*self->iterator); py_retval = Py_BuildValue((char *) "s", (*iter).toUtf8().data()); return py_retval; } int _wrap_convert_py2c__QString(PyObject *value, QString *address) { PyObject *py_retval; const char *retval_ptr; Py_ssize_t retval_len; py_retval = Py_BuildValue((char *) "(O)", value); if (!PyArg_ParseTuple(py_retval, (char *) "s#", &retval_ptr, &retval_len)) { Py_DECREF(py_retval); return 0; } *address = QString(retval_ptr); Py_DECREF(py_retval); return 1; } int _wrap_convert_py2c__QList__lt___QString___gt__(PyObject *arg, QList *container) { if (PyObject_IsInstance(arg, (PyObject*) &PyQList__lt__QString__gt___Type)) { *container = *((PyQList__lt__QString__gt__*)arg)->obj; } else if (PyList_Check(arg)) { container->clear(); Py_ssize_t size = PyList_Size(arg); for (Py_ssize_t i = 0; i < size; i++) { QString item; if (!_wrap_convert_py2c__QString(PyList_GET_ITEM(arg, i), &item)) { return 0; } container->push_back(item); } } else { PyErr_SetString(PyExc_TypeError, "parameter must be None, a QList__lt__QString__gt__ instance, or a list of QString"); return 0; } return 1; } static int _wrap_PyQList__lt__QString__gt____tp_init(PyQList__lt__QString__gt__ *self, PyObject *args, PyObject *kwargs) { const char *keywords[] = {"arg", NULL}; PyObject *arg = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "|O", (char **) keywords, &arg)) { return -1; } self->obj = new QList; if (arg == NULL) return 0; if (!_wrap_convert_py2c__QList__lt___QString___gt__(arg, self->obj)) { delete self->obj; self->obj = NULL; return -1; } return 0; } PyTypeObject PyQList__lt__QString__gt___Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QList__lt__QString__gt__", /* tp_name */ sizeof(PyQList__lt__QString__gt__), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQList__lt__QString__gt____tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)_wrap_PyQList__lt__QString__gt____tp_iter, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)NULL, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyQList__lt__QString__gt____tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; PyTypeObject PyQList__lt__QString__gt__Iter_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.qt.QList__lt__QString__gt__Iter", /* tp_name */ sizeof(PyQList__lt__QString__gt__Iter), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyQList__lt__QString__gt__Iter__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)PyQList__lt__QString__gt__Iter__tp_traverse, /* tp_traverse */ (inquiry)PyQList__lt__QString__gt__Iter__tp_clear, /* tp_clear */ (richcmpfunc)NULL, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)_wrap_PyQList__lt__QString__gt__Iter__tp_iter, /* tp_iter */ (iternextfunc)_wrap_PyQList__lt__QString__gt__Iter__tp_iternext, /* tp_iternext */ (struct PyMethodDef*)NULL, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ NULL, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)NULL, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; /* --- enumerations --- */ bool isImageLayerAt(Tiled::Map *map, int idx) { return (dynamic_cast(map->layerAt(idx)) != 0); } bool isTileLayerAt(Tiled::Map *map, int idx) { return (dynamic_cast(map->layerAt(idx)) != 0); } bool isObjectGroupAt(Tiled::Map *map, int idx) { return (dynamic_cast(map->layerAt(idx)) != 0); } Tiled::ImageLayer* imageLayerAt(Tiled::Map *map, int idx) { return static_cast(map->layerAt(idx)); } Tiled::TileLayer* tileLayerAt(Tiled::Map *map, int idx) { return static_cast(map->layerAt(idx)); } Tiled::ObjectGroup* objectGroupAt(Tiled::Map *map, int idx) { return static_cast(map->layerAt(idx)); } bool loadTilesetFromFile(Tiled::Tileset *ts, QString file) { QImage img(file); return ts->loadFromImage(img, file); } #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef qt_moduledef = { PyModuleDef_HEAD_INIT, "tiled.qt", NULL, -1, tiled_qt_functions, }; #endif static PyObject * inittiled_qt(void) { PyObject *m; #if PY_VERSION_HEX >= 0x03000000 m = PyModule_Create(&qt_moduledef); #else m = Py_InitModule3((char *) "tiled.qt", tiled_qt_functions, NULL); #endif if (m == NULL) { return NULL; } /* Register the 'QPointF' class */ if (PyType_Ready(&PyQPointF_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QPointF", (PyObject *) &PyQPointF_Type); /* Register the 'QSizeF' class */ if (PyType_Ready(&PyQSizeF_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QSizeF", (PyObject *) &PyQSizeF_Type); /* Register the 'QRgb' class */ if (PyType_Ready(&PyQRgb_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QRgb", (PyObject *) &PyQRgb_Type); /* Register the 'QColor' class */ if (PyType_Ready(&PyQColor_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QColor", (PyObject *) &PyQColor_Type); /* Register the 'QImage' class */ if (PyType_Ready(&PyQImage_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QImage", (PyObject *) &PyQImage_Type); /* Register the 'QPixmap' class */ if (PyType_Ready(&PyQPixmap_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QPixmap", (PyObject *) &PyQPixmap_Type); /* Register the 'QWidget' class */ if (PyType_Ready(&PyQWidget_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QWidget", (PyObject *) &PyQWidget_Type); /* Register the 'QFileDialog' class */ if (PyType_Ready(&PyQFileDialog_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QFileDialog", (PyObject *) &PyQFileDialog_Type); /* Register the 'QVector' class */ if (PyType_Ready(&PyQVector__lt__QRgb__gt___Type)) { return NULL; } if (PyType_Ready(&PyQVector__lt__QRgb__gt__Iter_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QVector__lt__QRgb__gt__", (PyObject *) &PyQVector__lt__QRgb__gt___Type); PyModule_AddObject(m, (char *) "QVector__lt__QRgb__gt__Iter", (PyObject *) &PyQVector__lt__QRgb__gt__Iter_Type); /* Register the 'QList' class */ if (PyType_Ready(&PyQList__lt__QString__gt___Type)) { return NULL; } if (PyType_Ready(&PyQList__lt__QString__gt__Iter_Type)) { return NULL; } PyModule_AddObject(m, (char *) "QList__lt__QString__gt__", (PyObject *) &PyQList__lt__QString__gt___Type); PyModule_AddObject(m, (char *) "QList__lt__QString__gt__Iter", (PyObject *) &PyQList__lt__QString__gt__Iter_Type); { PyObject *tmp_value; // QImage::Format_Invalid tmp_value = PyLong_FromLong(QImage::Format_Invalid); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_Invalid", tmp_value); Py_DECREF(tmp_value); // QImage::Format_Mono tmp_value = PyLong_FromLong(QImage::Format_Mono); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_Mono", tmp_value); Py_DECREF(tmp_value); // QImage::Format_MonoLSB tmp_value = PyLong_FromLong(QImage::Format_MonoLSB); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_MonoLSB", tmp_value); Py_DECREF(tmp_value); // QImage::Format_Indexed8 tmp_value = PyLong_FromLong(QImage::Format_Indexed8); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_Indexed8", tmp_value); Py_DECREF(tmp_value); // QImage::Format_RGB32 tmp_value = PyLong_FromLong(QImage::Format_RGB32); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_RGB32", tmp_value); Py_DECREF(tmp_value); // QImage::Format_ARGB32 tmp_value = PyLong_FromLong(QImage::Format_ARGB32); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_ARGB32", tmp_value); Py_DECREF(tmp_value); // QImage::Format_ARGB32_Premultiplied tmp_value = PyLong_FromLong(QImage::Format_ARGB32_Premultiplied); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_ARGB32_Premultiplied", tmp_value); Py_DECREF(tmp_value); // QImage::Format_RGB16 tmp_value = PyLong_FromLong(QImage::Format_RGB16); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_RGB16", tmp_value); Py_DECREF(tmp_value); // QImage::Format_ARGB8565_Premultiplied tmp_value = PyLong_FromLong(QImage::Format_ARGB8565_Premultiplied); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_ARGB8565_Premultiplied", tmp_value); Py_DECREF(tmp_value); // QImage::Format_RGB666 tmp_value = PyLong_FromLong(QImage::Format_RGB666); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_RGB666", tmp_value); Py_DECREF(tmp_value); // QImage::Format_ARGB6666_Premultiplied tmp_value = PyLong_FromLong(QImage::Format_ARGB6666_Premultiplied); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_ARGB6666_Premultiplied", tmp_value); Py_DECREF(tmp_value); // QImage::Format_RGB555 tmp_value = PyLong_FromLong(QImage::Format_RGB555); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_RGB555", tmp_value); Py_DECREF(tmp_value); // QImage::Format_ARGB8555_Premultiplied tmp_value = PyLong_FromLong(QImage::Format_ARGB8555_Premultiplied); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_ARGB8555_Premultiplied", tmp_value); Py_DECREF(tmp_value); // QImage::Format_RGB888 tmp_value = PyLong_FromLong(QImage::Format_RGB888); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_RGB888", tmp_value); Py_DECREF(tmp_value); // QImage::Format_RGB444 tmp_value = PyLong_FromLong(QImage::Format_RGB444); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_RGB444", tmp_value); Py_DECREF(tmp_value); // QImage::Format_ARGB4444_Premultiplied tmp_value = PyLong_FromLong(QImage::Format_ARGB4444_Premultiplied); PyDict_SetItemString((PyObject*) PyQImage_Type.tp_dict, "Format_ARGB4444_Premultiplied", tmp_value); Py_DECREF(tmp_value); } { PyObject *tmp_value; // QFileDialog::ShowDirsOnly tmp_value = PyLong_FromLong(QFileDialog::ShowDirsOnly); PyDict_SetItemString((PyObject*) PyQFileDialog_Type.tp_dict, "ShowDirsOnly", tmp_value); Py_DECREF(tmp_value); // QFileDialog::DontResolveSymlinks tmp_value = PyLong_FromLong(QFileDialog::DontResolveSymlinks); PyDict_SetItemString((PyObject*) PyQFileDialog_Type.tp_dict, "DontResolveSymlinks", tmp_value); Py_DECREF(tmp_value); // QFileDialog::DontConfirmOverwrite tmp_value = PyLong_FromLong(QFileDialog::DontConfirmOverwrite); PyDict_SetItemString((PyObject*) PyQFileDialog_Type.tp_dict, "DontConfirmOverwrite", tmp_value); Py_DECREF(tmp_value); // QFileDialog::DontUseNativeDialog tmp_value = PyLong_FromLong(QFileDialog::DontUseNativeDialog); PyDict_SetItemString((PyObject*) PyQFileDialog_Type.tp_dict, "DontUseNativeDialog", tmp_value); Py_DECREF(tmp_value); // QFileDialog::ReadOnly tmp_value = PyLong_FromLong(QFileDialog::ReadOnly); PyDict_SetItemString((PyObject*) PyQFileDialog_Type.tp_dict, "ReadOnly", tmp_value); Py_DECREF(tmp_value); // QFileDialog::HideNameFilterDetails tmp_value = PyLong_FromLong(QFileDialog::HideNameFilterDetails); PyDict_SetItemString((PyObject*) PyQFileDialog_Type.tp_dict, "HideNameFilterDetails", tmp_value); Py_DECREF(tmp_value); // QFileDialog::DontUseSheet tmp_value = PyLong_FromLong(QFileDialog::DontUseSheet); PyDict_SetItemString((PyObject*) PyQFileDialog_Type.tp_dict, "DontUseSheet", tmp_value); Py_DECREF(tmp_value); } return m; } static PyMethodDef tiled_Tiled_functions[] = { {NULL, NULL, 0, NULL} }; /* --- classes --- */ static int _wrap_PyTiledTile__tp_init(PyTiledTile *self, PyObject *args, PyObject *kwargs) { PyQPixmap *image; int id; PyTiledTileset *tileset; Tiled::Tileset *tileset_ptr; const char *keywords[] = {"image", "id", "tileset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!iO!", (char **) keywords, &PyQPixmap_Type, &image, &id, &PyTiledTileset_Type, &tileset)) { return -1; } tileset_ptr = (tileset ? tileset->obj : NULL); self->obj = new Tiled::Tile(*((PyQPixmap *) image)->obj, id, tileset_ptr); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } PyObject * _wrap_PyTiledTile_tileset(PyTiledTile *self) { PyObject *py_retval; Tiled::Tileset *retval; PyTiledTileset *py_Tileset; retval = self->obj->tileset(); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_Tileset = PyObject_New(PyTiledTileset, &PyTiledTileset_Type); py_Tileset->obj = retval; py_Tileset->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_Tileset); return py_retval; } PyObject * _wrap_PyTiledTile_setImage(PyTiledTile *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyQPixmap *image; const char *keywords[] = {"image", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyQPixmap_Type, &image)) { return NULL; } self->obj->setImage(*((PyQPixmap *) image)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledTile_image(PyTiledTile *self) { PyObject *py_retval; PyQPixmap *py_QPixmap; QPixmap const & retval = self->obj->image(); py_QPixmap = PyObject_New(PyQPixmap, &PyQPixmap_Type); py_QPixmap->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QPixmap->obj = new QPixmap(retval); py_retval = Py_BuildValue((char *) "N", py_QPixmap); return py_retval; } PyObject * _wrap_PyTiledTile_height(PyTiledTile *self) { PyObject *py_retval; int retval; retval = self->obj->height(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTile_width(PyTiledTile *self) { PyObject *py_retval; int retval; retval = self->obj->width(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTile_id(PyTiledTile *self) { PyObject *py_retval; int retval; retval = self->obj->id(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } static PyMethodDef PyTiledTile_methods[] = { {(char *) "tileset", (PyCFunction) _wrap_PyTiledTile_tileset, METH_NOARGS, NULL }, {(char *) "setImage", (PyCFunction) _wrap_PyTiledTile_setImage, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "image", (PyCFunction) _wrap_PyTiledTile_image, METH_NOARGS, NULL }, {(char *) "height", (PyCFunction) _wrap_PyTiledTile_height, METH_NOARGS, NULL }, {(char *) "width", (PyCFunction) _wrap_PyTiledTile_width, METH_NOARGS, NULL }, {(char *) "id", (PyCFunction) _wrap_PyTiledTile_id, METH_NOARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledTile__tp_dealloc(PyTiledTile *self) { Tiled::Tile *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledTile__tp_richcompare (PyTiledTile *PYBINDGEN_UNUSED(self), PyTiledTile *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledTile_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledTile_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.Tile", /* tp_name */ sizeof(PyTiledTile), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledTile__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledTile__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledTile_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledTile__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledSharedTileset__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'SharedTileset' cannot be constructed ()"); return -1; } static PyMethodDef PyTiledSharedTileset_methods[] = { {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledSharedTileset__tp_dealloc(PyTiledSharedTileset *self) { Tiled::SharedTileset *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledSharedTileset__tp_richcompare (PyTiledSharedTileset *PYBINDGEN_UNUSED(self), PyTiledSharedTileset *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledSharedTileset_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledSharedTileset_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.SharedTileset", /* tp_name */ sizeof(PyTiledSharedTileset), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledSharedTileset__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledSharedTileset__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledSharedTileset_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledSharedTileset__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledTileset__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'Tileset' cannot be constructed ()"); return -1; } PyObject * _wrap_PyTiledTileset_columnCount(PyTiledTileset *self) { PyObject *py_retval; int retval; retval = self->obj->columnCount(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTileset_loadFromImage(PyTiledTileset *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; PyQImage *img; const char *file; Py_ssize_t file_len; const char *keywords[] = {"img", "file", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!s#", (char **) keywords, &PyQImage_Type, &img, &file, &file_len)) { return NULL; } retval = self->obj->loadFromImage(*((PyQImage *) img)->obj, QString::fromUtf8(file)); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyTiledTileset_tileSpacing(PyTiledTileset *self) { PyObject *py_retval; int retval; retval = self->obj->tileSpacing(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTileset_name(PyTiledTileset *self) { PyObject *py_retval; QString retval; retval = self->obj->name(); py_retval = Py_BuildValue((char *) "s", retval.toUtf8().data()); return py_retval; } PyObject * _wrap_PyTiledTileset_setName(PyTiledTileset *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; const char *name; Py_ssize_t name_len; const char *keywords[] = {"name", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#", (char **) keywords, &name, &name_len)) { return NULL; } self->obj->setName(QString::fromUtf8(name)); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledTileset_tileHeight(PyTiledTileset *self) { PyObject *py_retval; int retval; retval = self->obj->tileHeight(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTileset_tileWidth(PyTiledTileset *self) { PyObject *py_retval; int retval; retval = self->obj->tileWidth(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTileset_create(PyTiledTileset *PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs) { PyObject *py_retval; const char *name; Py_ssize_t name_len; int tileWidth; int tileHeight; int tileSpacing; int margin; const char *keywords[] = {"name", "tileWidth", "tileHeight", "tileSpacing", "margin", NULL}; PyTiledSharedTileset *py_SharedTileset; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#iiii", (char **) keywords, &name, &name_len, &tileWidth, &tileHeight, &tileSpacing, &margin)) { return NULL; } Tiled::SharedTileset retval = Tiled::Tileset::create(QString::fromUtf8(name), tileWidth, tileHeight, tileSpacing, margin); py_SharedTileset = PyObject_New(PyTiledSharedTileset, &PyTiledSharedTileset_Type); py_SharedTileset->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_SharedTileset->obj = new Tiled::SharedTileset(retval); py_retval = Py_BuildValue((char *) "N", py_SharedTileset); return py_retval; } PyObject * _wrap_PyTiledTileset_transparentColor(PyTiledTileset *self) { PyObject *py_retval; PyQColor *py_QColor; QColor retval = self->obj->transparentColor(); py_QColor = PyObject_New(PyQColor, &PyQColor_Type); py_QColor->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QColor->obj = new QColor(retval); py_retval = Py_BuildValue((char *) "N", py_QColor); return py_retval; } PyObject * _wrap_PyTiledTileset_setFileName(PyTiledTileset *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; const char *name; Py_ssize_t name_len; const char *keywords[] = {"name", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#", (char **) keywords, &name, &name_len)) { return NULL; } self->obj->setFileName(QString::fromUtf8(name)); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledTileset_tileAt(PyTiledTileset *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; Tiled::Tile *retval; int id; const char *keywords[] = {"id", NULL}; PyTiledTile *py_Tile; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &id)) { return NULL; } retval = self->obj->tileAt(id); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_Tile = PyObject_New(PyTiledTile, &PyTiledTile_Type); py_Tile->obj = retval; py_Tile->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_Tile); return py_retval; } PyObject * _wrap_PyTiledTileset_fileName(PyTiledTileset *self) { PyObject *py_retval; QString retval; retval = self->obj->fileName(); py_retval = Py_BuildValue((char *) "s", retval.toUtf8().data()); return py_retval; } PyObject * _wrap_PyTiledTileset_tileCount(PyTiledTileset *self) { PyObject *py_retval; int retval; retval = self->obj->tileCount(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTileset_imageHeight(PyTiledTileset *self) { PyObject *py_retval; int retval; retval = self->obj->imageHeight(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTileset_imageWidth(PyTiledTileset *self) { PyObject *py_retval; int retval; retval = self->obj->imageWidth(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTileset_setTransparentColor(PyTiledTileset *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyQColor *col; const char *keywords[] = {"col", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyQColor_Type, &col)) { return NULL; } self->obj->setTransparentColor(*((PyQColor *) col)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledTileset_margin(PyTiledTileset *self) { PyObject *py_retval; int retval; retval = self->obj->margin(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledTileset_isExternal(PyTiledTileset *self) { PyObject *py_retval; bool retval; retval = self->obj->isExternal(); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } static PyMethodDef PyTiledTileset_methods[] = { {(char *) "columnCount", (PyCFunction) _wrap_PyTiledTileset_columnCount, METH_NOARGS, NULL }, {(char *) "loadFromImage", (PyCFunction) _wrap_PyTiledTileset_loadFromImage, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "tileSpacing", (PyCFunction) _wrap_PyTiledTileset_tileSpacing, METH_NOARGS, NULL }, {(char *) "name", (PyCFunction) _wrap_PyTiledTileset_name, METH_NOARGS, NULL }, {(char *) "setName", (PyCFunction) _wrap_PyTiledTileset_setName, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "tileHeight", (PyCFunction) _wrap_PyTiledTileset_tileHeight, METH_NOARGS, NULL }, {(char *) "tileWidth", (PyCFunction) _wrap_PyTiledTileset_tileWidth, METH_NOARGS, NULL }, {(char *) "create", (PyCFunction) _wrap_PyTiledTileset_create, METH_KEYWORDS|METH_VARARGS|METH_STATIC, NULL }, {(char *) "transparentColor", (PyCFunction) _wrap_PyTiledTileset_transparentColor, METH_NOARGS, NULL }, {(char *) "setFileName", (PyCFunction) _wrap_PyTiledTileset_setFileName, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "tileAt", (PyCFunction) _wrap_PyTiledTileset_tileAt, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "fileName", (PyCFunction) _wrap_PyTiledTileset_fileName, METH_NOARGS, NULL }, {(char *) "tileCount", (PyCFunction) _wrap_PyTiledTileset_tileCount, METH_NOARGS, NULL }, {(char *) "imageHeight", (PyCFunction) _wrap_PyTiledTileset_imageHeight, METH_NOARGS, NULL }, {(char *) "imageWidth", (PyCFunction) _wrap_PyTiledTileset_imageWidth, METH_NOARGS, NULL }, {(char *) "setTransparentColor", (PyCFunction) _wrap_PyTiledTileset_setTransparentColor, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "margin", (PyCFunction) _wrap_PyTiledTileset_margin, METH_NOARGS, NULL }, {(char *) "isExternal", (PyCFunction) _wrap_PyTiledTileset_isExternal, METH_NOARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledTileset__tp_dealloc(PyTiledTileset *self) { Tiled::Tileset *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledTileset__tp_richcompare (PyTiledTileset *PYBINDGEN_UNUSED(self), PyTiledTileset *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledTileset_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledTileset_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.Tileset", /* tp_name */ sizeof(PyTiledTileset), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledTileset__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledTileset__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledTileset_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledTileset__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledLayer__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'Layer' cannot be constructed ()"); return -1; } PyObject * _wrap_PyTiledLayer_opacity(PyTiledLayer *self) { PyObject *py_retval; float retval; retval = self->obj->opacity(); py_retval = Py_BuildValue((char *) "f", retval); return py_retval; } PyObject * _wrap_PyTiledLayer_map(PyTiledLayer *self) { PyObject *py_retval; Tiled::Map *retval; PyTiledMap *py_Map; retval = self->obj->map(); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_Map = PyObject_New(PyTiledMap, &PyTiledMap_Type); py_Map->obj = retval; py_Map->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_Map); return py_retval; } PyObject * _wrap_PyTiledLayer_asTileLayer(PyTiledLayer *self) { PyObject *py_retval; Tiled::TileLayer *retval; PyTiledTileLayer *py_TileLayer; retval = self->obj->asTileLayer(); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_TileLayer = PyObject_New(PyTiledTileLayer, &PyTiledTileLayer_Type); py_TileLayer->obj = retval; py_TileLayer->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_TileLayer); return py_retval; } PyObject * _wrap_PyTiledLayer_setMap(PyTiledLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyTiledMap *map; Tiled::Map *map_ptr; const char *keywords[] = {"map", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledMap_Type, &map)) { return NULL; } map_ptr = (map ? map->obj : NULL); self->obj->setMap(map_ptr); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledLayer_name(PyTiledLayer *self) { PyObject *py_retval; QString retval; retval = self->obj->name(); py_retval = Py_BuildValue((char *) "s", retval.toUtf8().data()); return py_retval; } PyObject * _wrap_PyTiledLayer_setName(PyTiledLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; const char *name; Py_ssize_t name_len; const char *keywords[] = {"name", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#", (char **) keywords, &name, &name_len)) { return NULL; } self->obj->setName(QString::fromUtf8(name)); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledLayer_setX(PyTiledLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int x; const char *keywords[] = {"x", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &x)) { return NULL; } self->obj->setX(x); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledLayer_asObjectGroup(PyTiledLayer *self) { PyObject *py_retval; Tiled::ObjectGroup *retval; PyTiledObjectGroup *py_ObjectGroup; retval = self->obj->asObjectGroup(); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_ObjectGroup = PyObject_New(PyTiledObjectGroup, &PyTiledObjectGroup_Type); py_ObjectGroup->obj = retval; py_ObjectGroup->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_ObjectGroup); return py_retval; } PyObject * _wrap_PyTiledLayer_setOpacity(PyTiledLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; float opacity; const char *keywords[] = {"opacity", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "f", (char **) keywords, &opacity)) { return NULL; } self->obj->setOpacity(opacity); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledLayer_height(PyTiledLayer *self) { PyObject *py_retval; int retval; retval = self->obj->height(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledLayer_width(PyTiledLayer *self) { PyObject *py_retval; int retval; retval = self->obj->width(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledLayer_isVisible(PyTiledLayer *self) { PyObject *py_retval; bool retval; retval = self->obj->isVisible(); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyTiledLayer_y(PyTiledLayer *self) { PyObject *py_retval; int retval; retval = self->obj->y(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledLayer_x(PyTiledLayer *self) { PyObject *py_retval; int retval; retval = self->obj->x(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledLayer_setPosition(PyTiledLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int x; int y; const char *keywords[] = {"x", "y", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "ii", (char **) keywords, &x, &y)) { return NULL; } self->obj->setPosition(x, y); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledLayer_setVisible(PyTiledLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool visible; PyObject *py_visible; const char *keywords[] = {"visible", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O", (char **) keywords, &py_visible)) { return NULL; } visible = (bool) PyObject_IsTrue(py_visible); self->obj->setVisible(visible); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledLayer_setY(PyTiledLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int y; const char *keywords[] = {"y", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &y)) { return NULL; } self->obj->setY(y); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } static PyMethodDef PyTiledLayer_methods[] = { {(char *) "opacity", (PyCFunction) _wrap_PyTiledLayer_opacity, METH_NOARGS, NULL }, {(char *) "map", (PyCFunction) _wrap_PyTiledLayer_map, METH_NOARGS, NULL }, {(char *) "asTileLayer", (PyCFunction) _wrap_PyTiledLayer_asTileLayer, METH_NOARGS, NULL }, {(char *) "setMap", (PyCFunction) _wrap_PyTiledLayer_setMap, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "name", (PyCFunction) _wrap_PyTiledLayer_name, METH_NOARGS, NULL }, {(char *) "setName", (PyCFunction) _wrap_PyTiledLayer_setName, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setX", (PyCFunction) _wrap_PyTiledLayer_setX, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "asObjectGroup", (PyCFunction) _wrap_PyTiledLayer_asObjectGroup, METH_NOARGS, NULL }, {(char *) "setOpacity", (PyCFunction) _wrap_PyTiledLayer_setOpacity, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "height", (PyCFunction) _wrap_PyTiledLayer_height, METH_NOARGS, NULL }, {(char *) "width", (PyCFunction) _wrap_PyTiledLayer_width, METH_NOARGS, NULL }, {(char *) "isVisible", (PyCFunction) _wrap_PyTiledLayer_isVisible, METH_NOARGS, NULL }, {(char *) "y", (PyCFunction) _wrap_PyTiledLayer_y, METH_NOARGS, NULL }, {(char *) "x", (PyCFunction) _wrap_PyTiledLayer_x, METH_NOARGS, NULL }, {(char *) "setPosition", (PyCFunction) _wrap_PyTiledLayer_setPosition, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setVisible", (PyCFunction) _wrap_PyTiledLayer_setVisible, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setY", (PyCFunction) _wrap_PyTiledLayer_setY, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledLayer__tp_dealloc(PyTiledLayer *self) { Tiled::Layer *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledLayer__tp_richcompare (PyTiledLayer *PYBINDGEN_UNUSED(self), PyTiledLayer *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledLayer_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledLayer_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.Layer", /* tp_name */ sizeof(PyTiledLayer), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledLayer__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledLayer__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledLayer_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledLayer__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledProperties__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'Properties' cannot be constructed ()"); return -1; } PyObject * _wrap_PyTiledProperties_keys(PyTiledProperties *self) { PyObject *py_retval; QList< QString > retval; PyQList__lt__QString__gt__ *py_QList__lt__QString__gt__; retval = self->obj->keys(); py_QList__lt__QString__gt__ = PyObject_New(PyQList__lt__QString__gt__, &PyQList__lt__QString__gt___Type); py_QList__lt__QString__gt__->obj = new QList(retval); py_retval = Py_BuildValue((char *) "N", py_QList__lt__QString__gt__); return py_retval; } static PyMethodDef PyTiledProperties_methods[] = { {(char *) "keys", (PyCFunction) _wrap_PyTiledProperties_keys, METH_NOARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledProperties__tp_dealloc(PyTiledProperties *self) { Tiled::Properties *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledProperties__tp_richcompare (PyTiledProperties *PYBINDGEN_UNUSED(self), PyTiledProperties *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledProperties_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledProperties_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.Properties", /* tp_name */ sizeof(PyTiledProperties), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledProperties__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledProperties__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledProperties_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledProperties__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledMap__tp_init__0(PyTiledMap *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { PyTiledMap *ctor_arg; const char *keywords[] = {"ctor_arg", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledMap_Type, &ctor_arg)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new Tiled::Map(*((PyTiledMap *) ctor_arg)->obj); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } static int _wrap_PyTiledMap__tp_init__1(PyTiledMap *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { Tiled::Map::Orientation orient; int w; int h; int tileW; int tileH; const char *keywords[] = {"orient", "w", "h", "tileW", "tileH", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iiiii", (char **) keywords, &orient, &w, &h, &tileW, &tileH)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new Tiled::Map(orient, w, h, tileW, tileH); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } int _wrap_PyTiledMap__tp_init(PyTiledMap *self, PyObject *args, PyObject *kwargs) { int retval; PyObject *error_list; PyObject *exceptions[2] = {0,}; retval = _wrap_PyTiledMap__tp_init__0(self, args, kwargs, &exceptions[0]); if (!exceptions[0]) { return retval; } retval = _wrap_PyTiledMap__tp_init__1(self, args, kwargs, &exceptions[1]); if (!exceptions[1]) { Py_DECREF(exceptions[0]); return retval; } error_list = PyList_New(2); PyList_SET_ITEM(error_list, 0, PyObject_Str(exceptions[0])); Py_DECREF(exceptions[0]); PyList_SET_ITEM(error_list, 1, PyObject_Str(exceptions[1])); Py_DECREF(exceptions[1]); PyErr_SetObject(PyExc_TypeError, error_list); Py_DECREF(error_list); return -1; } PyObject * _wrap_PyTiledMap_removeTilesetAt(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int pos; const char *keywords[] = {"pos", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &pos)) { return NULL; } self->obj->removeTilesetAt(pos); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_orientation(PyTiledMap *self) { PyObject *py_retval; Tiled::Map::Orientation retval; retval = self->obj->orientation(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_height(PyTiledMap *self) { PyObject *py_retval; int retval; retval = self->obj->height(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_addTileset(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyTiledSharedTileset *tileset; const char *keywords[] = {"tileset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledSharedTileset_Type, &tileset)) { return NULL; } self->obj->addTileset(*((PyTiledSharedTileset *) tileset)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_isTilesetUsed(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; PyTiledTileset *tileset; Tiled::Tileset *tileset_ptr; const char *keywords[] = {"tileset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledTileset_Type, &tileset)) { return NULL; } tileset_ptr = (tileset ? tileset->obj : NULL); retval = self->obj->isTilesetUsed(tileset_ptr); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyTiledMap_setWidth(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int w; const char *keywords[] = {"w", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &w)) { return NULL; } self->obj->setWidth(w); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_tileLayerCount(PyTiledMap *self) { PyObject *py_retval; int retval; retval = self->obj->tileLayerCount(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_insertTileset(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int pos; PyTiledSharedTileset *tileset; const char *keywords[] = {"pos", "tileset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iO!", (char **) keywords, &pos, &PyTiledSharedTileset_Type, &tileset)) { return NULL; } self->obj->insertTileset(pos, *((PyTiledSharedTileset *) tileset)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_width(PyTiledMap *self) { PyObject *py_retval; int retval; retval = self->obj->width(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_layerCount(PyTiledMap *self) { PyObject *py_retval; int retval; retval = self->obj->layerCount(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_setHeight(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int h; const char *keywords[] = {"h", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &h)) { return NULL; } self->obj->setHeight(h); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_tileHeight(PyTiledMap *self) { PyObject *py_retval; int retval; retval = self->obj->tileHeight(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_tilesetAt(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int idx; const char *keywords[] = {"idx", NULL}; PyTiledSharedTileset *py_SharedTileset; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &idx)) { return NULL; } Tiled::SharedTileset retval = self->obj->tilesetAt(idx); py_SharedTileset = PyObject_New(PyTiledSharedTileset, &PyTiledSharedTileset_Type); py_SharedTileset->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_SharedTileset->obj = new Tiled::SharedTileset(retval); py_retval = Py_BuildValue((char *) "N", py_SharedTileset); return py_retval; } PyObject * _wrap_PyTiledMap_layerAt(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; Tiled::Layer *retval; int idx; const char *keywords[] = {"idx", NULL}; PyTiledLayer *py_Layer; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &idx)) { return NULL; } retval = self->obj->layerAt(idx); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_Layer = PyObject_New(PyTiledLayer, &PyTiledLayer_Type); py_Layer->obj = retval; py_Layer->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_Layer); return py_retval; } PyObject * _wrap_PyTiledMap_setProperty(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; const char *name; Py_ssize_t name_len; const char *value; Py_ssize_t value_len; const char *keywords[] = {"name", "value", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#s#", (char **) keywords, &name, &name_len, &value, &value_len)) { return NULL; } self->obj->setProperty(QString::fromUtf8(name), QString::fromUtf8(value)); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_objectGroupCount(PyTiledMap *self) { PyObject *py_retval; int retval; retval = self->obj->objectGroupCount(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_properties(PyTiledMap *self) { PyObject *py_retval; PyTiledProperties *py_Properties; Tiled::Properties const retval = self->obj->properties(); py_Properties = PyObject_New(PyTiledProperties, &PyTiledProperties_Type); py_Properties->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_Properties->obj = new Tiled::Properties(retval); py_retval = Py_BuildValue((char *) "N", py_Properties); return py_retval; } PyObject * _wrap_PyTiledMap_setOrientation(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; Tiled::Map::Orientation o; const char *keywords[] = {"o", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &o)) { return NULL; } self->obj->setOrientation(o); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_tileWidth(PyTiledMap *self) { PyObject *py_retval; int retval; retval = self->obj->tileWidth(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_replaceTileset(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyTiledSharedTileset *oldTileset; PyTiledSharedTileset *newTileset; const char *keywords[] = {"oldTileset", "newTileset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!O!", (char **) keywords, &PyTiledSharedTileset_Type, &oldTileset, &PyTiledSharedTileset_Type, &newTileset)) { return NULL; } self->obj->replaceTileset(*((PyTiledSharedTileset *) oldTileset)->obj, *((PyTiledSharedTileset *) newTileset)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_indexOfTileset(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int retval; PyTiledSharedTileset *tileset; const char *keywords[] = {"tileset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledSharedTileset_Type, &tileset)) { return NULL; } retval = self->obj->indexOfTileset(*((PyTiledSharedTileset *) tileset)->obj); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMap_property(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; QString retval; const char *name; Py_ssize_t name_len; const char *keywords[] = {"name", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#", (char **) keywords, &name, &name_len)) { return NULL; } retval = self->obj->property(QString::fromUtf8(name)); py_retval = Py_BuildValue((char *) "s", retval.toUtf8().data()); return py_retval; } PyObject * _wrap_PyTiledMap_addLayer__0(PyTiledMap *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { PyObject *py_retval; PyTiledImageLayer *l; Tiled::ImageLayer *l_ptr; const char *keywords[] = {"l", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledImageLayer_Type, &l)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return NULL; } l_ptr = (l ? l->obj : NULL); self->obj->addLayer(l_ptr); if (l) { l->obj = NULL; } Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_addLayer__1(PyTiledMap *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { PyObject *py_retval; PyTiledTileLayer *l; Tiled::TileLayer *l_ptr; const char *keywords[] = {"l", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledTileLayer_Type, &l)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return NULL; } l_ptr = (l ? l->obj : NULL); self->obj->addLayer(l_ptr); if (l) { l->obj = NULL; } Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_addLayer__2(PyTiledMap *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { PyObject *py_retval; PyTiledObjectGroup *l; Tiled::ObjectGroup *l_ptr; const char *keywords[] = {"l", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledObjectGroup_Type, &l)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return NULL; } l_ptr = (l ? l->obj : NULL); self->obj->addLayer(l_ptr); if (l) { l->obj = NULL; } Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMap_addLayer(PyTiledMap *self, PyObject *args, PyObject *kwargs) { PyObject * retval; PyObject *error_list; PyObject *exceptions[3] = {0,}; retval = _wrap_PyTiledMap_addLayer__0(self, args, kwargs, &exceptions[0]); if (!exceptions[0]) { return retval; } retval = _wrap_PyTiledMap_addLayer__1(self, args, kwargs, &exceptions[1]); if (!exceptions[1]) { Py_DECREF(exceptions[0]); return retval; } retval = _wrap_PyTiledMap_addLayer__2(self, args, kwargs, &exceptions[2]); if (!exceptions[2]) { Py_DECREF(exceptions[0]); Py_DECREF(exceptions[1]); return retval; } error_list = PyList_New(3); PyList_SET_ITEM(error_list, 0, PyObject_Str(exceptions[0])); Py_DECREF(exceptions[0]); PyList_SET_ITEM(error_list, 1, PyObject_Str(exceptions[1])); Py_DECREF(exceptions[1]); PyList_SET_ITEM(error_list, 2, PyObject_Str(exceptions[2])); Py_DECREF(exceptions[2]); PyErr_SetObject(PyExc_TypeError, error_list); Py_DECREF(error_list); return NULL; } PyObject * _wrap_PyTiledMap_tilesetCount(PyTiledMap *self) { PyObject *py_retval; int retval; retval = self->obj->tilesetCount(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } static PyObject* _wrap_PyTiledMap__copy__(PyTiledMap *self) { PyTiledMap *py_copy; py_copy = PyObject_New(PyTiledMap, &PyTiledMap_Type); py_copy->obj = new Tiled::Map(*self->obj); py_copy->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return (PyObject*) py_copy; } static PyMethodDef PyTiledMap_methods[] = { {(char *) "removeTilesetAt", (PyCFunction) _wrap_PyTiledMap_removeTilesetAt, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "orientation", (PyCFunction) _wrap_PyTiledMap_orientation, METH_NOARGS, NULL }, {(char *) "height", (PyCFunction) _wrap_PyTiledMap_height, METH_NOARGS, NULL }, {(char *) "addTileset", (PyCFunction) _wrap_PyTiledMap_addTileset, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "isTilesetUsed", (PyCFunction) _wrap_PyTiledMap_isTilesetUsed, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setWidth", (PyCFunction) _wrap_PyTiledMap_setWidth, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "tileLayerCount", (PyCFunction) _wrap_PyTiledMap_tileLayerCount, METH_NOARGS, NULL }, {(char *) "insertTileset", (PyCFunction) _wrap_PyTiledMap_insertTileset, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "width", (PyCFunction) _wrap_PyTiledMap_width, METH_NOARGS, NULL }, {(char *) "layerCount", (PyCFunction) _wrap_PyTiledMap_layerCount, METH_NOARGS, NULL }, {(char *) "setHeight", (PyCFunction) _wrap_PyTiledMap_setHeight, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "tileHeight", (PyCFunction) _wrap_PyTiledMap_tileHeight, METH_NOARGS, NULL }, {(char *) "tilesetAt", (PyCFunction) _wrap_PyTiledMap_tilesetAt, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "layerAt", (PyCFunction) _wrap_PyTiledMap_layerAt, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setProperty", (PyCFunction) _wrap_PyTiledMap_setProperty, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "objectGroupCount", (PyCFunction) _wrap_PyTiledMap_objectGroupCount, METH_NOARGS, NULL }, {(char *) "properties", (PyCFunction) _wrap_PyTiledMap_properties, METH_NOARGS, NULL }, {(char *) "setOrientation", (PyCFunction) _wrap_PyTiledMap_setOrientation, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "tileWidth", (PyCFunction) _wrap_PyTiledMap_tileWidth, METH_NOARGS, NULL }, {(char *) "replaceTileset", (PyCFunction) _wrap_PyTiledMap_replaceTileset, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "indexOfTileset", (PyCFunction) _wrap_PyTiledMap_indexOfTileset, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "property", (PyCFunction) _wrap_PyTiledMap_property, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "addLayer", (PyCFunction) _wrap_PyTiledMap_addLayer, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "tilesetCount", (PyCFunction) _wrap_PyTiledMap_tilesetCount, METH_NOARGS, NULL }, {(char *) "__copy__", (PyCFunction) _wrap_PyTiledMap__copy__, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledMap__tp_dealloc(PyTiledMap *self) { Tiled::Map *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledMap__tp_richcompare (PyTiledMap *PYBINDGEN_UNUSED(self), PyTiledMap *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledMap_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledMap_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.Map", /* tp_name */ sizeof(PyTiledMap), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledMap__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledMap__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledMap_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledMap__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static PyObject* _wrap_PyTiledCell__get_tile(PyTiledCell *self, void * PYBINDGEN_UNUSED(closure)) { PyObject *py_retval; PyTiledTile *py_Tile; if (!(self->obj->tile)) { Py_INCREF(Py_None); return Py_None; } py_Tile = PyObject_New(PyTiledTile, &PyTiledTile_Type); py_Tile->obj = new Tiled::Tile((*self->obj->tile)); py_Tile->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_retval = Py_BuildValue((char *) "N", py_Tile); return py_retval; } static PyGetSetDef PyTiledCell__getsets[] = { { (char*) "tile", /* attribute name */ (getter) _wrap_PyTiledCell__get_tile, /* C function to get the attribute */ (setter) NULL, /* C function to set the attribute */ NULL, /* optional doc string */ NULL /* optional additional data for getter and setter */ }, { NULL, NULL, NULL, NULL, NULL } }; static int _wrap_PyTiledCell__tp_init(PyTiledCell *self, PyObject *args, PyObject *kwargs) { PyTiledTile *tile; Tiled::Tile *tile_ptr; const char *keywords[] = {"tile", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledTile_Type, &tile)) { return -1; } tile_ptr = (tile ? tile->obj : NULL); self->obj = new Tiled::Cell(tile_ptr); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } PyObject * _wrap_PyTiledCell_isEmpty(PyTiledCell *self) { PyObject *py_retval; bool retval; retval = self->obj->isEmpty(); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } static PyMethodDef PyTiledCell_methods[] = { {(char *) "isEmpty", (PyCFunction) _wrap_PyTiledCell_isEmpty, METH_NOARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledCell__tp_dealloc(PyTiledCell *self) { Tiled::Cell *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledCell__tp_richcompare (PyTiledCell *PYBINDGEN_UNUSED(self), PyTiledCell *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledCell_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledCell_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.Cell", /* tp_name */ sizeof(PyTiledCell), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledCell__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledCell__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledCell_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ PyTiledCell__getsets, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledCell__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledTileLayer__tp_init(PyTiledTileLayer *self, PyObject *args, PyObject *kwargs) { const char *name; Py_ssize_t name_len; int x; int y; int w; int h; const char *keywords[] = {"name", "x", "y", "w", "h", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#iiii", (char **) keywords, &name, &name_len, &x, &y, &w, &h)) { return -1; } self->obj = new Tiled::TileLayer(QString::fromUtf8(name), x, y, w, h); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } PyObject * _wrap_PyTiledTileLayer_referencesTileset(PyTiledTileLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; PyTiledTileset *ts; Tiled::Tileset *ts_ptr; const char *keywords[] = {"ts", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledTileset_Type, &ts)) { return NULL; } ts_ptr = (ts ? ts->obj : NULL); retval = self->obj->referencesTileset(ts_ptr); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyTiledTileLayer_setCell(PyTiledTileLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int x; int y; PyTiledCell *c; const char *keywords[] = {"x", "y", "c", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iiO!", (char **) keywords, &x, &y, &PyTiledCell_Type, &c)) { return NULL; } self->obj->setCell(x, y, *((PyTiledCell *) c)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledTileLayer_isEmpty(PyTiledTileLayer *self) { PyObject *py_retval; bool retval; retval = self->obj->isEmpty(); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyTiledTileLayer_cellAt(PyTiledTileLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int x; int y; const char *keywords[] = {"x", "y", NULL}; PyTiledCell *py_Cell; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "ii", (char **) keywords, &x, &y)) { return NULL; } Tiled::Cell retval = self->obj->cellAt(x, y); py_Cell = PyObject_New(PyTiledCell, &PyTiledCell_Type); py_Cell->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_Cell->obj = new Tiled::Cell(retval); py_retval = Py_BuildValue((char *) "N", py_Cell); return py_retval; } static PyMethodDef PyTiledTileLayer_methods[] = { {(char *) "referencesTileset", (PyCFunction) _wrap_PyTiledTileLayer_referencesTileset, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setCell", (PyCFunction) _wrap_PyTiledTileLayer_setCell, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "isEmpty", (PyCFunction) _wrap_PyTiledTileLayer_isEmpty, METH_NOARGS, NULL }, {(char *) "cellAt", (PyCFunction) _wrap_PyTiledTileLayer_cellAt, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledTileLayer__tp_dealloc(PyTiledTileLayer *self) { Tiled::TileLayer *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledTileLayer__tp_richcompare (PyTiledTileLayer *PYBINDGEN_UNUSED(self), PyTiledTileLayer *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledTileLayer_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledTileLayer_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.TileLayer", /* tp_name */ sizeof(PyTiledTileLayer), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledTileLayer__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledTileLayer__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledTileLayer_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledTileLayer__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledImageLayer__tp_init(PyTiledImageLayer *self, PyObject *args, PyObject *kwargs) { const char *name; Py_ssize_t name_len; int x; int y; int w; int h; const char *keywords[] = {"name", "x", "y", "w", "h", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#iiii", (char **) keywords, &name, &name_len, &x, &y, &w, &h)) { return -1; } self->obj = new Tiled::ImageLayer(QString::fromUtf8(name), x, y, w, h); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } PyObject * _wrap_PyTiledImageLayer_image(PyTiledImageLayer *self) { PyObject *py_retval; PyQPixmap *py_QPixmap; QPixmap const & retval = self->obj->image(); py_QPixmap = PyObject_New(PyQPixmap, &PyQPixmap_Type); py_QPixmap->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_QPixmap->obj = new QPixmap(retval); py_retval = Py_BuildValue((char *) "N", py_QPixmap); return py_retval; } PyObject * _wrap_PyTiledImageLayer_loadFromImage(PyTiledImageLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; PyQImage *img; const char *file; Py_ssize_t file_len; const char *keywords[] = {"img", "file", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!s#", (char **) keywords, &PyQImage_Type, &img, &file, &file_len)) { return NULL; } retval = self->obj->loadFromImage(*((PyQImage *) img)->obj, QString::fromUtf8(file)); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyTiledImageLayer_setImage(PyTiledImageLayer *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyQPixmap *image; const char *keywords[] = {"image", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyQPixmap_Type, &image)) { return NULL; } self->obj->setImage(*((PyQPixmap *) image)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } static PyMethodDef PyTiledImageLayer_methods[] = { {(char *) "image", (PyCFunction) _wrap_PyTiledImageLayer_image, METH_NOARGS, NULL }, {(char *) "loadFromImage", (PyCFunction) _wrap_PyTiledImageLayer_loadFromImage, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setImage", (PyCFunction) _wrap_PyTiledImageLayer_setImage, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledImageLayer__tp_dealloc(PyTiledImageLayer *self) { Tiled::ImageLayer *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledImageLayer__tp_richcompare (PyTiledImageLayer *PYBINDGEN_UNUSED(self), PyTiledImageLayer *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledImageLayer_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledImageLayer_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.ImageLayer", /* tp_name */ sizeof(PyTiledImageLayer), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledImageLayer__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledImageLayer__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledImageLayer_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledImageLayer__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledObject__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'Object' cannot be constructed ()"); return -1; } PyObject * _wrap_PyTiledObject_setProperty(PyTiledObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; const char *prop; Py_ssize_t prop_len; const char *val; Py_ssize_t val_len; const char *keywords[] = {"prop", "val", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#s#", (char **) keywords, &prop, &prop_len, &val, &val_len)) { return NULL; } self->obj->setProperty(QString::fromUtf8(prop), QString::fromUtf8(val)); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledObject_property(PyTiledObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; QString retval; const char *prop; Py_ssize_t prop_len; const char *keywords[] = {"prop", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#", (char **) keywords, &prop, &prop_len)) { return NULL; } retval = self->obj->property(QString::fromUtf8(prop)); py_retval = Py_BuildValue((char *) "s", retval.toUtf8().data()); return py_retval; } static PyMethodDef PyTiledObject_methods[] = { {(char *) "setProperty", (PyCFunction) _wrap_PyTiledObject_setProperty, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "property", (PyCFunction) _wrap_PyTiledObject_property, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledObject__tp_dealloc(PyTiledObject *self) { Tiled::Object *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledObject__tp_richcompare (PyTiledObject *PYBINDGEN_UNUSED(self), PyTiledObject *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledObject_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledObject_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.Object", /* tp_name */ sizeof(PyTiledObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledObject__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledObject__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledObject_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledObject__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledMapObject__tp_init__0(PyTiledMapObject *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { const char *keywords[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "", (char **) keywords)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new Tiled::MapObject(); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } static int _wrap_PyTiledMapObject__tp_init__1(PyTiledMapObject *self, PyObject *args, PyObject *kwargs, PyObject **return_exception) { const char *name; Py_ssize_t name_len; const char *type; Py_ssize_t type_len; PyQPointF *pos; PyQSizeF *size; const char *keywords[] = {"name", "type", "pos", "size", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#s#O!O!", (char **) keywords, &name, &name_len, &type, &type_len, &PyQPointF_Type, &pos, &PyQSizeF_Type, &size)) { { PyObject *exc_type, *traceback; PyErr_Fetch(&exc_type, return_exception, &traceback); Py_XDECREF(exc_type); Py_XDECREF(traceback); } return -1; } self->obj = new Tiled::MapObject(QString::fromUtf8(name), QString::fromUtf8(type), *((PyQPointF *) pos)->obj, *((PyQSizeF *) size)->obj); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } int _wrap_PyTiledMapObject__tp_init(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { int retval; PyObject *error_list; PyObject *exceptions[2] = {0,}; retval = _wrap_PyTiledMapObject__tp_init__0(self, args, kwargs, &exceptions[0]); if (!exceptions[0]) { return retval; } retval = _wrap_PyTiledMapObject__tp_init__1(self, args, kwargs, &exceptions[1]); if (!exceptions[1]) { Py_DECREF(exceptions[0]); return retval; } error_list = PyList_New(2); PyList_SET_ITEM(error_list, 0, PyObject_Str(exceptions[0])); Py_DECREF(exceptions[0]); PyList_SET_ITEM(error_list, 1, PyObject_Str(exceptions[1])); Py_DECREF(exceptions[1]); PyErr_SetObject(PyExc_TypeError, error_list); Py_DECREF(error_list); return -1; } PyObject * _wrap_PyTiledMapObject_height(PyTiledMapObject *self) { PyObject *py_retval; float retval; retval = self->obj->height(); py_retval = Py_BuildValue((char *) "f", retval); return py_retval; } PyObject * _wrap_PyTiledMapObject_shape(PyTiledMapObject *self) { PyObject *py_retval; Tiled::MapObject::Shape retval; retval = self->obj->shape(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledMapObject_setCell(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyTiledCell *c; const char *keywords[] = {"c", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledCell_Type, &c)) { return NULL; } self->obj->setCell(*((PyTiledCell *) c)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_setWidth(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; float w; const char *keywords[] = {"w", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "f", (char **) keywords, &w)) { return NULL; } self->obj->setWidth(w); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_setPosition(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyQPointF *pos; const char *keywords[] = {"pos", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyQPointF_Type, &pos)) { return NULL; } self->obj->setPosition(*((PyQPointF *) pos)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_setType(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; const char *n; Py_ssize_t n_len; const char *keywords[] = {"n", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#", (char **) keywords, &n, &n_len)) { return NULL; } self->obj->setType(QString::fromUtf8(n)); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_cell(PyTiledMapObject *self) { PyObject *py_retval; PyTiledCell *py_Cell; Tiled::Cell const retval = self->obj->cell(); py_Cell = PyObject_New(PyTiledCell, &PyTiledCell_Type); py_Cell->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_Cell->obj = new Tiled::Cell(retval); py_retval = Py_BuildValue((char *) "N", py_Cell); return py_retval; } PyObject * _wrap_PyTiledMapObject_width(PyTiledMapObject *self) { PyObject *py_retval; float retval; retval = self->obj->width(); py_retval = Py_BuildValue((char *) "f", retval); return py_retval; } PyObject * _wrap_PyTiledMapObject_setRotation(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; float r; const char *keywords[] = {"r", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "f", (char **) keywords, &r)) { return NULL; } self->obj->setRotation(r); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_type(PyTiledMapObject *self) { PyObject *py_retval; QString retval; retval = self->obj->type(); py_retval = Py_BuildValue((char *) "s", retval.toUtf8().data()); return py_retval; } PyObject * _wrap_PyTiledMapObject_setName(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; const char *n; Py_ssize_t n_len; const char *keywords[] = {"n", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#", (char **) keywords, &n, &n_len)) { return NULL; } self->obj->setName(QString::fromUtf8(n)); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_rotation(PyTiledMapObject *self) { PyObject *py_retval; float retval; retval = self->obj->rotation(); py_retval = Py_BuildValue((char *) "f", retval); return py_retval; } PyObject * _wrap_PyTiledMapObject_setX(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; float x; const char *keywords[] = {"x", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "f", (char **) keywords, &x)) { return NULL; } self->obj->setX(x); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_setY(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; float y; const char *keywords[] = {"y", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "f", (char **) keywords, &y)) { return NULL; } self->obj->setY(y); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_setHeight(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; float h; const char *keywords[] = {"h", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "f", (char **) keywords, &h)) { return NULL; } self->obj->setHeight(h); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_name(PyTiledMapObject *self) { PyObject *py_retval; QString retval; retval = self->obj->name(); py_retval = Py_BuildValue((char *) "s", retval.toUtf8().data()); return py_retval; } PyObject * _wrap_PyTiledMapObject_setSize(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyQSizeF *size; const char *keywords[] = {"size", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyQSizeF_Type, &size)) { return NULL; } self->obj->setSize(*((PyQSizeF *) size)->obj); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_isVisible(PyTiledMapObject *self) { PyObject *py_retval; bool retval; retval = self->obj->isVisible(); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyTiledMapObject_y(PyTiledMapObject *self) { PyObject *py_retval; float retval; retval = self->obj->y(); py_retval = Py_BuildValue((char *) "f", retval); return py_retval; } PyObject * _wrap_PyTiledMapObject_x(PyTiledMapObject *self) { PyObject *py_retval; float retval; retval = self->obj->x(); py_retval = Py_BuildValue((char *) "f", retval); return py_retval; } PyObject * _wrap_PyTiledMapObject_setVisible(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool v; PyObject *py_v; const char *keywords[] = {"v", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O", (char **) keywords, &py_v)) { return NULL; } v = (bool) PyObject_IsTrue(py_v); self->obj->setVisible(v); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledMapObject_setShape(PyTiledMapObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; Tiled::MapObject::Shape s; const char *keywords[] = {"s", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &s)) { return NULL; } self->obj->setShape(s); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } static PyMethodDef PyTiledMapObject_methods[] = { {(char *) "height", (PyCFunction) _wrap_PyTiledMapObject_height, METH_NOARGS, NULL }, {(char *) "shape", (PyCFunction) _wrap_PyTiledMapObject_shape, METH_NOARGS, NULL }, {(char *) "setCell", (PyCFunction) _wrap_PyTiledMapObject_setCell, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setWidth", (PyCFunction) _wrap_PyTiledMapObject_setWidth, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setPosition", (PyCFunction) _wrap_PyTiledMapObject_setPosition, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setType", (PyCFunction) _wrap_PyTiledMapObject_setType, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "cell", (PyCFunction) _wrap_PyTiledMapObject_cell, METH_NOARGS, NULL }, {(char *) "width", (PyCFunction) _wrap_PyTiledMapObject_width, METH_NOARGS, NULL }, {(char *) "setRotation", (PyCFunction) _wrap_PyTiledMapObject_setRotation, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "type", (PyCFunction) _wrap_PyTiledMapObject_type, METH_NOARGS, NULL }, {(char *) "setName", (PyCFunction) _wrap_PyTiledMapObject_setName, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "rotation", (PyCFunction) _wrap_PyTiledMapObject_rotation, METH_NOARGS, NULL }, {(char *) "setX", (PyCFunction) _wrap_PyTiledMapObject_setX, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setY", (PyCFunction) _wrap_PyTiledMapObject_setY, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setHeight", (PyCFunction) _wrap_PyTiledMapObject_setHeight, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "name", (PyCFunction) _wrap_PyTiledMapObject_name, METH_NOARGS, NULL }, {(char *) "setSize", (PyCFunction) _wrap_PyTiledMapObject_setSize, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "isVisible", (PyCFunction) _wrap_PyTiledMapObject_isVisible, METH_NOARGS, NULL }, {(char *) "y", (PyCFunction) _wrap_PyTiledMapObject_y, METH_NOARGS, NULL }, {(char *) "x", (PyCFunction) _wrap_PyTiledMapObject_x, METH_NOARGS, NULL }, {(char *) "setVisible", (PyCFunction) _wrap_PyTiledMapObject_setVisible, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "setShape", (PyCFunction) _wrap_PyTiledMapObject_setShape, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledMapObject__tp_dealloc(PyTiledMapObject *self) { Tiled::MapObject *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledMapObject__tp_richcompare (PyTiledMapObject *PYBINDGEN_UNUSED(self), PyTiledMapObject *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledMapObject_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledMapObject_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.MapObject", /* tp_name */ sizeof(PyTiledMapObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledMapObject__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledMapObject__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledMapObject_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledMapObject__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledObjectGroup__tp_init(PyTiledObjectGroup *self, PyObject *args, PyObject *kwargs) { const char *name; Py_ssize_t name_len; int x; int y; int w; int h; const char *keywords[] = {"name", "x", "y", "w", "h", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "s#iiii", (char **) keywords, &name, &name_len, &x, &y, &w, &h)) { return -1; } self->obj = new Tiled::ObjectGroup(QString::fromUtf8(name), x, y, w, h); self->flags = PYBINDGEN_WRAPPER_FLAG_NONE; return 0; } PyObject * _wrap_PyTiledObjectGroup_addObject(PyTiledObjectGroup *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; PyTiledMapObject *object; Tiled::MapObject *object_ptr; const char *keywords[] = {"object", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledMapObject_Type, &object)) { return NULL; } object_ptr = (object ? object->obj : NULL); self->obj->addObject(object_ptr); if (object) { object->obj = NULL; } Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledObjectGroup_referencesTileset(PyTiledObjectGroup *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; PyTiledTileset *ts; Tiled::Tileset *ts_ptr; const char *keywords[] = {"ts", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledTileset_Type, &ts)) { return NULL; } ts_ptr = (ts ? ts->obj : NULL); retval = self->obj->referencesTileset(ts_ptr); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_PyTiledObjectGroup_objectAt(PyTiledObjectGroup *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; Tiled::MapObject *retval; int index; const char *keywords[] = {"index", NULL}; PyTiledMapObject *py_MapObject; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "i", (char **) keywords, &index)) { return NULL; } retval = self->obj->objectAt(index); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_MapObject = PyObject_New(PyTiledMapObject, &PyTiledMapObject_Type); py_MapObject->obj = retval; py_MapObject->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_MapObject); return py_retval; } PyObject * _wrap_PyTiledObjectGroup_objectCount(PyTiledObjectGroup *self) { PyObject *py_retval; int retval; retval = self->obj->objectCount(); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } PyObject * _wrap_PyTiledObjectGroup_insertObject(PyTiledObjectGroup *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int idx; PyTiledMapObject *object; Tiled::MapObject *object_ptr; const char *keywords[] = {"idx", "object", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "iO!", (char **) keywords, &idx, &PyTiledMapObject_Type, &object)) { return NULL; } object_ptr = (object ? object->obj : NULL); self->obj->insertObject(idx, object_ptr); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } PyObject * _wrap_PyTiledObjectGroup_removeObject(PyTiledObjectGroup *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; int retval; PyTiledMapObject *object; Tiled::MapObject *object_ptr; const char *keywords[] = {"object", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!", (char **) keywords, &PyTiledMapObject_Type, &object)) { return NULL; } object_ptr = (object ? object->obj : NULL); retval = self->obj->removeObject(object_ptr); py_retval = Py_BuildValue((char *) "i", retval); return py_retval; } static PyMethodDef PyTiledObjectGroup_methods[] = { {(char *) "addObject", (PyCFunction) _wrap_PyTiledObjectGroup_addObject, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "referencesTileset", (PyCFunction) _wrap_PyTiledObjectGroup_referencesTileset, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "objectAt", (PyCFunction) _wrap_PyTiledObjectGroup_objectAt, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "objectCount", (PyCFunction) _wrap_PyTiledObjectGroup_objectCount, METH_NOARGS, NULL }, {(char *) "insertObject", (PyCFunction) _wrap_PyTiledObjectGroup_insertObject, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "removeObject", (PyCFunction) _wrap_PyTiledObjectGroup_removeObject, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledObjectGroup__tp_dealloc(PyTiledObjectGroup *self) { Tiled::ObjectGroup *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledObjectGroup__tp_richcompare (PyTiledObjectGroup *PYBINDGEN_UNUSED(self), PyTiledObjectGroup *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledObjectGroup_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledObjectGroup_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.ObjectGroup", /* tp_name */ sizeof(PyTiledObjectGroup), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledObjectGroup__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledObjectGroup__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledObjectGroup_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledObjectGroup__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; static int _wrap_PyTiledLoggingInterface__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'LoggingInterface' cannot be constructed ()"); return -1; } PyObject * _wrap_PyTiledLoggingInterface_log(PyTiledLoggingInterface *self, PyObject *args, PyObject *kwargs) { PyObject *py_retval; Tiled::LoggingInterface::OutputType type; const char *msg; Py_ssize_t msg_len; const char *keywords[] = {"type", "msg", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "is#", (char **) keywords, &type, &msg, &msg_len)) { return NULL; } self->obj->log(type, QString::fromUtf8(msg)); Py_INCREF(Py_None); py_retval = Py_None; return py_retval; } static PyMethodDef PyTiledLoggingInterface_methods[] = { {(char *) "log", (PyCFunction) _wrap_PyTiledLoggingInterface_log, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; static void _wrap_PyTiledLoggingInterface__tp_dealloc(PyTiledLoggingInterface *self) { self->obj = NULL; Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyTiledLoggingInterface__tp_richcompare (PyTiledLoggingInterface *PYBINDGEN_UNUSED(self), PyTiledLoggingInterface *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyTiledLoggingInterface_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyTiledLoggingInterface_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.Tiled.LoggingInterface", /* tp_name */ sizeof(PyTiledLoggingInterface), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyTiledLoggingInterface__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)NULL, /* tp_traverse */ (inquiry)NULL, /* tp_clear */ (richcmpfunc)_wrap_PyTiledLoggingInterface__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyTiledLoggingInterface_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)_wrap_PyTiledLoggingInterface__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; /* --- enumerations --- */ #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef Tiled_moduledef = { PyModuleDef_HEAD_INIT, "tiled.Tiled", NULL, -1, tiled_Tiled_functions, }; #endif static PyObject * inittiled_Tiled(void) { PyObject *m; #if PY_VERSION_HEX >= 0x03000000 m = PyModule_Create(&Tiled_moduledef); #else m = Py_InitModule3((char *) "tiled.Tiled", tiled_Tiled_functions, NULL); #endif if (m == NULL) { return NULL; } /* Register the 'Tiled::Tile' class */ if (PyType_Ready(&PyTiledTile_Type)) { return NULL; } PyModule_AddObject(m, (char *) "Tile", (PyObject *) &PyTiledTile_Type); /* Register the 'Tiled::SharedTileset' class */ if (PyType_Ready(&PyTiledSharedTileset_Type)) { return NULL; } PyModule_AddObject(m, (char *) "SharedTileset", (PyObject *) &PyTiledSharedTileset_Type); /* Register the 'Tiled::Tileset' class */ if (PyType_Ready(&PyTiledTileset_Type)) { return NULL; } PyModule_AddObject(m, (char *) "Tileset", (PyObject *) &PyTiledTileset_Type); /* Register the 'Tiled::Layer' class */ if (PyType_Ready(&PyTiledLayer_Type)) { return NULL; } PyModule_AddObject(m, (char *) "Layer", (PyObject *) &PyTiledLayer_Type); /* Register the 'Tiled::Properties' class */ if (PyType_Ready(&PyTiledProperties_Type)) { return NULL; } PyModule_AddObject(m, (char *) "Properties", (PyObject *) &PyTiledProperties_Type); /* Register the 'Tiled::Map' class */ if (PyType_Ready(&PyTiledMap_Type)) { return NULL; } PyModule_AddObject(m, (char *) "Map", (PyObject *) &PyTiledMap_Type); /* Register the 'Tiled::Cell' class */ if (PyType_Ready(&PyTiledCell_Type)) { return NULL; } PyModule_AddObject(m, (char *) "Cell", (PyObject *) &PyTiledCell_Type); /* Register the 'Tiled::TileLayer' class */ PyTiledTileLayer_Type.tp_base = &PyTiledLayer_Type; if (PyType_Ready(&PyTiledTileLayer_Type)) { return NULL; } PyModule_AddObject(m, (char *) "TileLayer", (PyObject *) &PyTiledTileLayer_Type); /* Register the 'Tiled::ImageLayer' class */ if (PyType_Ready(&PyTiledImageLayer_Type)) { return NULL; } PyModule_AddObject(m, (char *) "ImageLayer", (PyObject *) &PyTiledImageLayer_Type); /* Register the 'Tiled::Object' class */ if (PyType_Ready(&PyTiledObject_Type)) { return NULL; } PyModule_AddObject(m, (char *) "Object", (PyObject *) &PyTiledObject_Type); /* Register the 'Tiled::MapObject' class */ PyTiledMapObject_Type.tp_base = &PyTiledObject_Type; if (PyType_Ready(&PyTiledMapObject_Type)) { return NULL; } PyModule_AddObject(m, (char *) "MapObject", (PyObject *) &PyTiledMapObject_Type); /* Register the 'Tiled::ObjectGroup' class */ PyTiledObjectGroup_Type.tp_base = &PyTiledLayer_Type; if (PyType_Ready(&PyTiledObjectGroup_Type)) { return NULL; } PyModule_AddObject(m, (char *) "ObjectGroup", (PyObject *) &PyTiledObjectGroup_Type); /* Register the 'Tiled::LoggingInterface' class */ if (PyType_Ready(&PyTiledLoggingInterface_Type)) { return NULL; } PyModule_AddObject(m, (char *) "LoggingInterface", (PyObject *) &PyTiledLoggingInterface_Type); { PyObject *tmp_value; // Tiled::Map::Unknown tmp_value = PyLong_FromLong(Tiled::Map::Unknown); PyDict_SetItemString((PyObject*) PyTiledMap_Type.tp_dict, "Unknown", tmp_value); Py_DECREF(tmp_value); // Tiled::Map::Orthogonal tmp_value = PyLong_FromLong(Tiled::Map::Orthogonal); PyDict_SetItemString((PyObject*) PyTiledMap_Type.tp_dict, "Orthogonal", tmp_value); Py_DECREF(tmp_value); // Tiled::Map::Isometric tmp_value = PyLong_FromLong(Tiled::Map::Isometric); PyDict_SetItemString((PyObject*) PyTiledMap_Type.tp_dict, "Isometric", tmp_value); Py_DECREF(tmp_value); } { PyObject *tmp_value; // Tiled::MapObject::Rectangle tmp_value = PyLong_FromLong(Tiled::MapObject::Rectangle); PyDict_SetItemString((PyObject*) PyTiledMapObject_Type.tp_dict, "Rectangle", tmp_value); Py_DECREF(tmp_value); // Tiled::MapObject::Polygon tmp_value = PyLong_FromLong(Tiled::MapObject::Polygon); PyDict_SetItemString((PyObject*) PyTiledMapObject_Type.tp_dict, "Polygon", tmp_value); Py_DECREF(tmp_value); // Tiled::MapObject::Polyline tmp_value = PyLong_FromLong(Tiled::MapObject::Polyline); PyDict_SetItemString((PyObject*) PyTiledMapObject_Type.tp_dict, "Polyline", tmp_value); Py_DECREF(tmp_value); } { PyObject *tmp_value; // Tiled::LoggingInterface::INFO tmp_value = PyLong_FromLong(Tiled::LoggingInterface::INFO); PyDict_SetItemString((PyObject*) PyTiledLoggingInterface_Type.tp_dict, "INFO", tmp_value); Py_DECREF(tmp_value); // Tiled::LoggingInterface::ERROR tmp_value = PyLong_FromLong(Tiled::LoggingInterface::ERROR); PyDict_SetItemString((PyObject*) PyTiledLoggingInterface_Type.tp_dict, "ERROR", tmp_value); Py_DECREF(tmp_value); } return m; } /* --- module functions --- */ PyObject * _wrap_tiled_isTileLayerAt(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; PyTiledMap *map; Tiled::Map *map_ptr; int idx; const char *keywords[] = {"map", "idx", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!i", (char **) keywords, &PyTiledMap_Type, &map, &idx)) { return NULL; } map_ptr = (map ? map->obj : NULL); retval = isTileLayerAt(map_ptr, idx); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_tiled_isTileLayerAt(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs); PyObject * _wrap_tiled_loadTilesetFromFile(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; PyTiledTileset *ts; Tiled::Tileset *ts_ptr; const char *file; Py_ssize_t file_len; const char *keywords[] = {"ts", "file", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!s#", (char **) keywords, &PyTiledTileset_Type, &ts, &file, &file_len)) { return NULL; } ts_ptr = (ts ? ts->obj : NULL); retval = loadTilesetFromFile(ts_ptr, QString::fromUtf8(file)); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_tiled_loadTilesetFromFile(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs); PyObject * _wrap_tiled_objectGroupAt(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs) { PyObject *py_retval; Tiled::ObjectGroup *retval; PyTiledMap *map; Tiled::Map *map_ptr; int idx; const char *keywords[] = {"map", "idx", NULL}; PyTiledObjectGroup *py_ObjectGroup; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!i", (char **) keywords, &PyTiledMap_Type, &map, &idx)) { return NULL; } map_ptr = (map ? map->obj : NULL); retval = objectGroupAt(map_ptr, idx); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_ObjectGroup = PyObject_New(PyTiledObjectGroup, &PyTiledObjectGroup_Type); py_ObjectGroup->obj = retval; py_ObjectGroup->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_ObjectGroup); return py_retval; } PyObject * _wrap_tiled_objectGroupAt(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs); PyObject * _wrap_tiled_isObjectGroupAt(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs) { PyObject *py_retval; bool retval; PyTiledMap *map; Tiled::Map *map_ptr; int idx; const char *keywords[] = {"map", "idx", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!i", (char **) keywords, &PyTiledMap_Type, &map, &idx)) { return NULL; } map_ptr = (map ? map->obj : NULL); retval = isObjectGroupAt(map_ptr, idx); py_retval = Py_BuildValue((char *) "N", PyBool_FromLong(retval)); return py_retval; } PyObject * _wrap_tiled_isObjectGroupAt(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs); PyObject * _wrap_tiled_tileLayerAt(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs) { PyObject *py_retval; Tiled::TileLayer *retval; PyTiledMap *map; Tiled::Map *map_ptr; int idx; const char *keywords[] = {"map", "idx", NULL}; PyTiledTileLayer *py_TileLayer; if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O!i", (char **) keywords, &PyTiledMap_Type, &map, &idx)) { return NULL; } map_ptr = (map ? map->obj : NULL); retval = tileLayerAt(map_ptr, idx); if (!(retval)) { Py_INCREF(Py_None); return Py_None; } py_TileLayer = PyObject_New(PyTiledTileLayer, &PyTiledTileLayer_Type); py_TileLayer->obj = retval; py_TileLayer->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED; py_retval = Py_BuildValue((char *) "N", py_TileLayer); return py_retval; } PyObject * _wrap_tiled_tileLayerAt(PyObject * PYBINDGEN_UNUSED(dummy), PyObject *args, PyObject *kwargs); static PyMethodDef tiled_functions[] = { {(char *) "isTileLayerAt", (PyCFunction) _wrap_tiled_isTileLayerAt, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "loadTilesetFromFile", (PyCFunction) _wrap_tiled_loadTilesetFromFile, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "objectGroupAt", (PyCFunction) _wrap_tiled_objectGroupAt, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "isObjectGroupAt", (PyCFunction) _wrap_tiled_isObjectGroupAt, METH_KEYWORDS|METH_VARARGS, NULL }, {(char *) "tileLayerAt", (PyCFunction) _wrap_tiled_tileLayerAt, METH_KEYWORDS|METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; /* --- classes --- */ static int _wrap_PyPythonPythonScript__tp_init(void) { PyErr_SetString(PyExc_TypeError, "class 'PythonScript' cannot be constructed ()"); return -1; } static PyMethodDef PyPythonPythonScript_methods[] = { {NULL, NULL, 0, NULL} }; static void PyPythonPythonScript__tp_clear(PyPythonPythonScript *self) { Py_CLEAR(self->inst_dict); Python::PythonScript *tmp = self->obj; self->obj = NULL; if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) { delete tmp; } } static int PyPythonPythonScript__tp_traverse(PyPythonPythonScript *self, visitproc visit, void *arg) { Py_VISIT(self->inst_dict); return 0; } static void _wrap_PyPythonPythonScript__tp_dealloc(PyPythonPythonScript *self) { PyPythonPythonScript__tp_clear(self); Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject* _wrap_PyPythonPythonScript__tp_richcompare (PyPythonPythonScript *PYBINDGEN_UNUSED(self), PyPythonPythonScript *other, int opid) { if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyPythonPythonScript_Type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (opid) { case Py_LT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_LE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_EQ: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_NE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; case Py_GT: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } /* closes switch (opid) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } PyTypeObject PyPythonPythonScript_Type = { PyVarObject_HEAD_INIT(NULL, 0) (char *) "tiled.PythonScript", /* tp_name */ sizeof(PyPythonPythonScript), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)_wrap_PyPythonPythonScript__tp_dealloc, /* tp_dealloc */ (printfunc)0, /* tp_print */ (getattrfunc)NULL, /* tp_getattr */ (setattrfunc)NULL, /* tp_setattr */ (cmpfunc)NULL, /* tp_compare */ (reprfunc)NULL, /* tp_repr */ (PyNumberMethods*)NULL, /* tp_as_number */ (PySequenceMethods*)NULL, /* tp_as_sequence */ (PyMappingMethods*)NULL, /* tp_as_mapping */ (hashfunc)NULL, /* tp_hash */ (ternaryfunc)NULL, /* tp_call */ (reprfunc)NULL, /* tp_str */ (getattrofunc)NULL, /* tp_getattro */ (setattrofunc)NULL, /* tp_setattro */ (PyBufferProcs*)NULL, /* tp_as_buffer */ Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC, /* tp_flags */ NULL, /* Documentation string */ (traverseproc)PyPythonPythonScript__tp_traverse, /* tp_traverse */ (inquiry)PyPythonPythonScript__tp_clear, /* tp_clear */ (richcmpfunc)_wrap_PyPythonPythonScript__tp_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)NULL, /* tp_iter */ (iternextfunc)NULL, /* tp_iternext */ (struct PyMethodDef*)PyPythonPythonScript_methods, /* tp_methods */ (struct PyMemberDef*)0, /* tp_members */ 0, /* tp_getset */ NULL, /* tp_base */ NULL, /* tp_dict */ (descrgetfunc)NULL, /* tp_descr_get */ (descrsetfunc)NULL, /* tp_descr_set */ offsetof(PyPythonPythonScript, inst_dict), /* tp_dictoffset */ (initproc)_wrap_PyPythonPythonScript__tp_init, /* tp_init */ (allocfunc)PyType_GenericAlloc, /* tp_alloc */ (newfunc)PyType_GenericNew, /* tp_new */ (freefunc)0, /* tp_free */ (inquiry)NULL, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ NULL, /* tp_subclasses */ NULL, /* tp_weaklist */ (destructor) NULL /* tp_del */ }; #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef tiled_moduledef = { PyModuleDef_HEAD_INIT, "tiled", NULL, -1, tiled_functions, }; #endif #if PY_VERSION_HEX >= 0x03000000 #define MOD_ERROR NULL #define MOD_INIT(name) PyObject* PyInit_##name(void) #define MOD_RETURN(val) val #else #define MOD_ERROR #define MOD_INIT(name) void init##name(void) #define MOD_RETURN(val) #endif #if defined(__cplusplus) extern "C" #endif #if defined(__GNUC__) && __GNUC__ >= 4 __attribute__ ((visibility("default"))) #endif MOD_INIT(tiled) { PyObject *m; PyObject *submodule; #if PY_VERSION_HEX >= 0x03000000 m = PyModule_Create(&tiled_moduledef); #else m = Py_InitModule3((char *) "tiled", tiled_functions, NULL); #endif if (m == NULL) { return MOD_ERROR; } /* Register the 'Python::PythonScript' class */ if (PyType_Ready(&PyPythonPythonScript_Type)) { return MOD_ERROR; } PyModule_AddObject(m, (char *) "Plugin", (PyObject *) &PyPythonPythonScript_Type); submodule = inittiled_qt(); if (submodule == NULL) { return MOD_ERROR; } Py_INCREF(submodule); PyModule_AddObject(m, (char *) "qt", submodule); submodule = inittiled_Tiled(); if (submodule == NULL) { return MOD_ERROR; } Py_INCREF(submodule); PyModule_AddObject(m, (char *) "Tiled", submodule); return MOD_RETURN(m); } PyObject* _wrap_convert_c2py__Tiled__LoggingInterface(Tiled::LoggingInterface *cvalue) { PyObject *py_retval; PyTiledLoggingInterface *py_LoggingInterface; py_LoggingInterface = PyObject_New(PyTiledLoggingInterface, &PyTiledLoggingInterface_Type); py_LoggingInterface->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_LoggingInterface->obj = cvalue; py_retval = Py_BuildValue((char *) "N", py_LoggingInterface); return py_retval; } int _wrap_convert_py2c__Tiled__Map___star__(PyObject *value, Tiled::Map * *address) { PyObject *py_retval; PyTiledMap *tmp_Map; py_retval = Py_BuildValue((char *) "(O)", value); if (!PyArg_ParseTuple(py_retval, (char *) "O!", &PyTiledMap_Type, &tmp_Map)) { Py_DECREF(py_retval); return 0; } *address = new Tiled::Map(*tmp_Map->obj); Py_DECREF(py_retval); return 1; } PyObject* _wrap_convert_c2py__Tiled__Map_const(Tiled::Map const *cvalue) { PyObject *py_retval; PyTiledMap *py_Map; py_Map = PyObject_New(PyTiledMap, &PyTiledMap_Type); py_Map->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_Map->obj = new Tiled::Map(*cvalue); py_retval = Py_BuildValue((char *) "N", py_Map); return py_retval; } tiled-0.14.2/src/plugins/python/pythonplugin.cpp000066400000000000000000000255211260670167100217470ustar00rootroot00000000000000/* * Python Tiled Plugin * Copyright 2012-2013, Samuli Tuomola * * This file is part of Tiled. * * 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, see . */ #include "pythonplugin.h" #include "map.h" #include #include #include namespace Python { /** * Call whenever there might be an error (if error state is not cleared it * leaks to next PyErr_Occurred check and reports error in wrong place causing * confusion) */ static void handleError() { if (PyErr_Occurred() != nullptr) PyErr_Print(); } PythonPlugin::PythonPlugin() : mScriptDir(QDir::homePath() + "/.tiled") , mPluginClass(nullptr) { mReloadTimer.setSingleShot(true); mReloadTimer.setInterval(1000); connect(&mReloadTimer, &QTimer::timeout, this, &PythonPlugin::reloadModules); } PythonPlugin::~PythonPlugin() { for (const ScriptEntry &script : mScripts) { Py_DECREF(script.module); Py_DECREF(script.mapFormat->pythonClass()); } Py_XDECREF(mPluginClass); Py_Finalize(); } void PythonPlugin::initialize() { addObject(&mLogger); if (!Py_IsInitialized()) { // PEP370 Py_NoSiteFlag = 1; Py_NoUserSiteDirectory = 1; Py_Initialize(); inittiled(); // Get reference to base class to find its extensions later on PyObject *pmod = PyImport_ImportModule("tiled"); if (pmod) { PyObject *tiledPlugin = PyObject_GetAttrString(pmod, "Plugin"); Py_DECREF(pmod); if (tiledPlugin) { if (PyCallable_Check(tiledPlugin)) { mPluginClass = tiledPlugin; } else { Py_DECREF(tiledPlugin); } } } if (!mPluginClass) { log(Tiled::LoggingInterface::ERROR, "Can't find tiled.Plugin baseclass\n"); handleError(); return; } // w/o differentiating error messages could just rename "log" // to "write" in the binding and assign plugin directly to stdout/stderr PySys_SetObject((char *)"_tiledplugin", _wrap_convert_c2py__Tiled__LoggingInterface(&mLogger)); PyRun_SimpleString("import sys\n" "#from tiled.Tiled.LoggingInterface import INFO,ERROR\n" "class _Catcher:\n" " def __init__(self, type):\n" " self.buffer = ''\n" " self.type = type\n" " def write(self, msg):\n" " self.buffer += msg\n" " if self.buffer.endswith('\\n'):\n" " sys._tiledplugin.log(self.type, self.buffer)\n" " self.buffer = ''\n" "sys.stdout = _Catcher(0)\n" "sys.stderr = _Catcher(1)\n"); PyRun_SimpleString(QString("import sys; sys.path.insert(0, \"%1\")") .arg(mScriptDir).toUtf8().constData()); log(QString("-- Added %1 to path\n").arg(mScriptDir)); } reloadModules(); if (QFile::exists(mScriptDir)) { mFileSystemWatcher.addPath(mScriptDir); connect(&mFileSystemWatcher, SIGNAL(directoryChanged(QString)), &mReloadTimer, SLOT(start())); } } void PythonPlugin::log(Tiled::LoggingInterface::OutputType type, const QString &msg) { mLogger.log(type, msg); } void PythonPlugin::log(const QString &msg) { log(Tiled::LoggingInterface::INFO, msg); } /** * (Re)load modules in the script directory */ void PythonPlugin::reloadModules() { log(tr("Reloading Python scripts")); const QStringList pyfilter("*.py"); QDirIterator iter(mScriptDir, pyfilter, QDir::Files | QDir::Readable); while (iter.hasNext()) { iter.next(); QString name = iter.fileInfo().baseName(); ScriptEntry script = mScripts.take(name); script.name = name; // Throw away any existing class reference if (script.mapFormat) { PyObject *pluginClass = script.mapFormat->pythonClass(); Py_DECREF(pluginClass); } if (loadOrReloadModule(script)) { mScripts.insert(name, script); } else { if (!script.module) { PySys_WriteStderr("** Parse exception **\n"); PyErr_Print(); PyErr_Clear(); } if (script.mapFormat) { removeObject(script.mapFormat); delete script.mapFormat; } } } } /** * Finds the first python class that extends tiled.Plugin */ PyObject *PythonPlugin::findPluginSubclass(PyObject *module) { PyObject *dir = PyObject_Dir(module); PyObject *result = nullptr; for (int i = 0; i < PyList_Size(dir); i++) { PyObject *value = PyObject_GetAttr(module, PyList_GetItem(dir, i)); if (!value) { handleError(); break; } if (value != mPluginClass && PyCallable_Check(value) && PyObject_IsSubclass(value, mPluginClass) == 1) { result = value; handleError(); break; } Py_DECREF(value); } Py_DECREF(dir); return result; } bool PythonPlugin::loadOrReloadModule(ScriptEntry &script) { const QByteArray name = script.name.toUtf8(); if (script.module) { PySys_WriteStdout("-- Reloading %s\n", name.constData()); PyObject *module = PyImport_ReloadModule(script.module); Py_DECREF(script.module); script.module = module; } else { PySys_WriteStdout("-- Loading %s\n", name.constData()); script.module = PyImport_ImportModule(name.constData()); } if (!script.module) return false; PyObject *pluginClass = findPluginSubclass(script.module); if (!pluginClass) { PySys_WriteStderr("Extension of tiled.Plugin not defined in " "script: %s\n", name.constData()); return false; } if (script.mapFormat) { script.mapFormat->setPythonClass(pluginClass); } else { script.mapFormat = new PythonMapFormat(name, pluginClass, *this); addObject(script.mapFormat); } return true; } PythonMapFormat::PythonMapFormat(const QString &scriptFile, PyObject *class_, PythonPlugin &plugin) : MapFormat(&plugin) , mClass(nullptr) , mPlugin(plugin) , mScriptFile(scriptFile) { setPythonClass(class_); } Tiled::Map *PythonMapFormat::read(const QString &fileName) { mError = QString(); mPlugin.log(tr("-- Using script %1 to read %2").arg(mScriptFile, fileName)); if (!PyObject_HasAttrString(mClass, "read")) { mError = "Please define class that extends tiled.Plugin and " "has @classmethod read(cls, filename)"; return nullptr; } PyObject *pinst = PyObject_CallMethod(mClass, (char *)"read", (char *)"(s)", fileName.toUtf8().constData()); Tiled::Map *ret = nullptr; if (!pinst) { PySys_WriteStderr("** Uncaught exception in script **\n"); } else { _wrap_convert_py2c__Tiled__Map___star__(pinst, &ret); Py_DECREF(pinst); } handleError(); if (ret) ret->setProperty("__script__", mScriptFile); return ret; } bool PythonMapFormat::write(const Tiled::Map *map, const QString &fileName) { mError = QString(); mPlugin.log(tr("-- Using script %1 to write %2").arg(mScriptFile, fileName)); PyObject *pmap = _wrap_convert_c2py__Tiled__Map_const(map); if (!pmap) return false; PyObject *pinst = PyObject_CallMethod(mClass, (char *)"write", (char *)"(Ns)", pmap, fileName.toUtf8().constData()); if (!pinst) { PySys_WriteStderr("** Uncaught exception in script **\n"); mError = tr("Uncaught exception in script. Please check console."); } else { bool ret = PyObject_IsTrue(pinst); Py_DECREF(pinst); if (!ret) mError = tr("Script returned false. Please check console."); return ret; } handleError(); return false; } bool PythonMapFormat::supportsFile(const QString &fileName) const { if (!PyObject_HasAttrString(mClass, "supportsFile")) return false; PyObject *pinst = PyObject_CallMethod(mClass, (char *)"supportsFile", (char *)"(s)", fileName.toUtf8().constData()); if (!pinst) { handleError(); return false; } bool ret = PyObject_IsTrue(pinst); Py_DECREF(pinst); return ret; } QString PythonMapFormat::nameFilter() const { QString ret; // find fun PyObject *pfun = PyObject_GetAttrString(mClass, "nameFilter"); if (!pfun || !PyCallable_Check(pfun)) { PySys_WriteStderr("Plugin extension doesn't define \"nameFilter\"\n"); return ret; } // have fun PyObject *pinst = PyEval_CallFunction(pfun, "()"); if (!pinst) { PySys_WriteStderr("** Uncaught exception in script **\n"); } else { ret = PyString_AsString(pinst); Py_DECREF(pinst); } handleError(); Py_DECREF(pfun); return ret; } QString PythonMapFormat::errorString() const { return mError; } void PythonMapFormat::setPythonClass(PyObject *class_) { mClass = class_; mCapabilities = NoCapability; // @classmethod nameFilter(cls) if (PyObject_HasAttrString(mClass, "nameFilter")) { // @classmethod write(cls, map, filename) if (PyObject_HasAttrString(mClass, "write")) { mCapabilities |= Tiled::MapFormat::Write; } // @classmethod read(cls, filename) // @classmethod supportsFile(cls, filename) if (PyObject_HasAttrString(mClass, "read") && PyObject_HasAttrString(mClass, "supportsFile")) { mCapabilities |= Tiled::MapFormat::Read; } } } } // namespace Python tiled-0.14.2/src/plugins/python/pythonplugin.h000066400000000000000000000070061260670167100214120ustar00rootroot00000000000000/* * Python Tiled Plugin * Copyright 2012, Samuli Tuomola * * This file is part of Tiled. * * 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, see . */ #ifndef PYTHONPLUGIN_H #define PYTHONPLUGIN_H #ifdef __MINGW32__ #include // included before Python.h to fix ::hypot not declared issue #endif #include #include "logginginterface.h" #include "mapformat.h" #include "plugin.h" #include #include #include #include namespace Tiled { class Map; } namespace Python { class PythonMapFormat; struct ScriptEntry { ScriptEntry() : module(nullptr) , mapFormat(nullptr) {} QString name; PyObject *module; PythonMapFormat *mapFormat; }; class Q_DECL_EXPORT PythonPlugin : public Tiled::Plugin { Q_OBJECT Q_INTERFACES(Tiled::Plugin) Q_PLUGIN_METADATA(IID "org.mapeditor.Plugin" FILE "plugin.json") public: PythonPlugin(); ~PythonPlugin(); void initialize() override; void log(Tiled::LoggingInterface::OutputType type, const QString &msg); void log(const QString &msg); private slots: void reloadModules(); private: bool loadOrReloadModule(ScriptEntry &script); PyObject *findPluginSubclass(PyObject *module); QString mScriptDir; QMap mScripts; PyObject *mPluginClass; QFileSystemWatcher mFileSystemWatcher; QTimer mReloadTimer; Tiled::LoggingInterface mLogger; }; // Class exposed for python scripts to extend class PythonScript { public: // perhaps provide default that throws NotImplementedError Tiled::Map *read(const QString &fileName); bool supportsFile(const QString &fileName) const; bool write(const Tiled::Map *map, const QString &fileName); QString nameFilter() const; }; class PythonMapFormat : public Tiled::MapFormat { Q_OBJECT Q_INTERFACES(Tiled::MapFormat) public: PythonMapFormat(const QString &scriptFile, PyObject *class_, PythonPlugin &plugin); Capabilities capabilities() const override { return mCapabilities; } Tiled::Map *read(const QString &fileName) override; bool supportsFile(const QString &fileName) const override; bool write(const Tiled::Map *map, const QString &fileName) override; QString nameFilter() const override; QString errorString() const override; PyObject *pythonClass() const { return mClass; } void setPythonClass(PyObject *class_); private: PyObject *mClass; PythonPlugin &mPlugin; QString mScriptFile; QString mError; Capabilities mCapabilities; }; } // namespace Python PyMODINIT_FUNC inittiled(void); extern int _wrap_convert_py2c__Tiled__Map___star__(PyObject *obj, Tiled::Map * *address); extern PyObject* _wrap_convert_c2py__Tiled__Map_const(Tiled::Map const *cvalue); extern PyObject* _wrap_convert_c2py__Tiled__LoggingInterface(Tiled::LoggingInterface *cvalue); #endif // PYTHONPLUGIN_H tiled-0.14.2/src/plugins/python/qtbinding.py000066400000000000000000000202351260670167100210310ustar00rootroot00000000000000""" Python Tiled Plugin Copyright 2012, Samuli Tuomola This file is part of Tiled. 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, see . """ import re from pybindgen import * import pybindgen.typehandlers.base as typehandlers from pybindgen.typehandlers.base import ForwardWrapperBase, PointerParameter """ class QFlagsTransformation(typehandlers.TypeTransformation): def __init__(self): self.rx = re.compile(r'(?:::)?QFlags<\s*(\w+)\s*>') def get_untransformed_name(self, name): m = self.rx.match(name) if m is None: return None else: return m.group(1)+' *' def create_type_handler(self, type_handler, *args, **kwargs): ctype = self.get_untransformed_name(args[0]) handler = type_handler(ctype, *args[1:], **kwargs) handler.has_been_transformed = True return handler typehandlers.param_type_matcher.register_transformation(QFlagsTransformation()) """ class QFlagsOptionParam(Parameter): DIRECTIONS = [Parameter.DIRECTION_IN] CTYPES = ['QFlags'] def get_c_error_return(self): return "return QFlags(0);" def convert_c_to_python(self, wrapper): raise NotImplementedError #wrapper.build_params.add_parameter("s", ['%s.toUtf8().data()' % self.value], prepend=True) def convert_python_to_c(self, wrapper): name = wrapper.declarations.declare_variable("QFileDialog::Option", self.name) wrapper.parse_params.add_parameter('i', ['&'+name], self.value, optional=bool(self.default_value)) if self.default_value is None: wrapper.call_params.append('(QFlags)%s' % name) else: wrapper.call_params.append(self.default_value) class QStringPtrParam(PointerParameter): DIRECTIONS = [Parameter.DIRECTION_IN] # could be out as well CTYPES = ['QString*'] def convert_c_to_python(self, wrapper): raise NotImplementedError def convert_python_to_c(self, wrapper): name = wrapper.declarations.declare_variable("const char *", self.name) if self.default_value is None: name_qst = wrapper.declarations.declare_variable("QString*", self.name + '_qst', 'new QString(%s)' % name) wrapper.call_params.append('%s' % name_qst) else: wrapper.call_params.append(self.default_value) wrapper.parse_params.add_parameter('s', ['&'+name], self.value, optional=bool(self.default_value)) class QStringParam(Parameter): DIRECTIONS = [Parameter.DIRECTION_IN] CTYPES = ['QString'] def get_c_error_return(self): return "return QString();" def convert_c_to_python(self, wrapper): wrapper.build_params.add_parameter("s", ['%s.toUtf8().data()' % self.value], prepend=True) def convert_python_to_c(self, wrapper): name = wrapper.declarations.declare_variable("const char *", self.name) len_ = wrapper.declarations.declare_variable("Py_ssize_t", self.name+"_len") wrapper.parse_params.add_parameter('s#', ['&'+name, '&'+len_], self.value) wrapper.call_params.append('QString::fromUtf8(%s)' % name) class QStringReturnValue(ReturnValue): CTYPES = ['QString'] def get_c_error_return(self): return "return QString();" def convert_python_to_c(self, wrapper): #raise NotImplementedError # TODO (needed only for virtual methods where C calls Python code) ptr = wrapper.declarations.declare_variable("const char *", "retval_ptr") len_ = wrapper.declarations.declare_variable("Py_ssize_t", "retval_len") wrapper.parse_params.add_parameter("s#", ['&'+ptr, '&'+len_]) wrapper.after_call.write_code("%s = QString(%s);" % (self.value, ptr)) def convert_c_to_python(self, wrapper): wrapper.build_params.add_parameter("s", ['%s.toUtf8().data()' % self.value], prepend=True) def generate(parent_mod): mod = module.SubModule('qt', parent_mod) mod.add_include('') mod.add_include('') mod.add_include('') mod.add_include('') #mod.add_include('"qtbind.h"') cls_qpointf = mod.add_class('QPointF') cls_qpointf.add_constructor([('float','x'),('float','y')]) cls_qpointf.add_method('x', 'int', []) cls_qpointf.add_method('setX', None, [('int','x')]) cls_qpointf.add_method('y', 'int', []) cls_qpointf.add_method('setY', None, [('int','y')]) cls_sizef = mod.add_class('QSizeF') cls_sizef.add_constructor([('float','w'),('float','h')]) cls_sizef.add_method('width', 'int', []) cls_sizef.add_method('setWidth', None, [('int','w')]) cls_sizef.add_method('height', 'int', []) cls_sizef.add_method('setHeight', None, [('int','h')]) cls_qrgb = mod.add_class('QRgb') mod.add_container('QVector', retval('QRgb'), 'vector') cls_color = mod.add_class('QColor') cls_color.add_constructor([('QRgb','col')]) cls_color.add_constructor([('int','r'), ('int','g'), ('int','b')]) cls_color.add_constructor([('int','r'), ('int','g'), ('int','b'),('int','a')]) cls_color.add_method('rgb', 'QRgb', []) cls_color.add_method('rgba', 'QRgb', []) cls_qimage = mod.add_class('QImage') cls_qimage.add_enum('Format', ('Format_Invalid','Format_Mono','Format_MonoLSB', 'Format_Indexed8','Format_RGB32','Format_ARGB32', 'Format_ARGB32_Premultiplied','Format_RGB16', 'Format_ARGB8565_Premultiplied','Format_RGB666', 'Format_ARGB6666_Premultiplied','Format_RGB555', 'Format_ARGB8555_Premultiplied','Format_RGB888','Format_RGB444', 'Format_ARGB4444_Premultiplied')) cls_qimage.add_constructor([]) cls_qimage.add_constructor([('int','w'), ('int','h'), ('Format','f')]) cls_qimage.add_method('color', 'QRgb', [('int','i')]) cls_qimage.add_method('colorTable', 'QVector', []) cls_qimage.add_method('fill', None, [('int','color')]) cls_qimage.add_method('load', 'bool', [('const QString','fileName'),('char*','fmt')]) cls_qimage.add_method('mirrored', retval('const QImage&'), [('bool','horiz'),('bool','vert')]) cls_qimage.add_method('width', 'int', []) cls_qimage.add_method('height', 'int', []) cls_qimage.add_method('setColor', None, [('int','i'),('QRgb','c')]) cls_qimage.add_method('setPixel', None, [('int','x'),('int','y'), ('unsigned int','color')]) cls_qimage.add_method('setPixel', None, [('int','x'),('int','y'), ('QRgb','color')]) cls_qimage.add_method('setColorTable', None, [('QVector','colors')]) cls_qpixmap = mod.add_class('QPixmap') cls_qpixmap.add_method('toImage', retval('const QImage&'), []) cls_qpixmap.add_method('fromImage', None, [('const QImage&','image')]) cls_qpixmap.add_method('convertFromImage', None, [('const QImage&','image')]) cls_qpixmap.add_method('width', 'int', []) cls_qpixmap.add_method('height', 'int', []) cls_qwidget = mod.add_class('QWidget') cls_qfiledialog = mod.add_class('QFileDialog') cls_qfiledialog.add_enum('Option', ('ShowDirsOnly','DontResolveSymlinks','DontConfirmOverwrite','DontUseNativeDialog', 'ReadOnly','HideNameFilterDetails','DontUseSheet')) cls_qfiledialog.add_method('getOpenFileName', 'QString', [ param('QWidget*','parent',transfer_ownership=False,null_ok=True), ('const QString','caption'),('const QString','dir'),('const QString','filter'), param('QString*','selectedFilter',default_value='new QString("")'), param('QFlags','options', direction=Parameter.DIRECTION_IN, default_value='0') ], is_static=True) mod.add_container('QList', retval('QString'), 'list') """ with open('qtbind.h','w') as fh: import pybindgen.typehandlers.codesink as cs sink = cs.MemoryCodeSink() mod.generate_forward_declarations(sink) includes = ['QImage','QFileDialog','QWidget','Qflags'] print >>fh, '\n'.join(['#include <%s>' % f for f in includes]) print >>fh, sink.flush() with open('qtbind.cpp','w') as fh: mod.generate(fh) """ tiled-0.14.2/src/plugins/python/scripts/000077500000000000000000000000001260670167100201655ustar00rootroot00000000000000tiled-0.14.2/src/plugins/python/scripts/fotf.py000066400000000000000000000070271260670167100215030ustar00rootroot00000000000000""" Fury of the Furries level loader for Tiled 2012, """ import sys, re from tiled import * from tiled.qt import * from os.path import dirname from lib import cpystruct, lbm from struct import pack,unpack from collections import namedtuple maps = {} tilesets = {} MetaData = namedtuple( 'MetaData', 'startX, startY, lType,'+ 'fin1X, fin1Y, u1, fin2X, fin2Y, lvl' ) class Fury(Plugin): @classmethod def nameFilter(cls): return "Fury of the Furries (*.bin)" @classmethod def supportsFile(cls, f): return open(f).read(4) == 'byt4' @classmethod def read(cls, f): print 'Loading map at',f fr = Fury(f) m = Tiled.Map(Tiled.Map.Orthogonal, fr.w, fr.h, 16, 16) maps[f] = m # probably defined explicitly somewhere in the data decs = [1,3,4,2,8,6,7,9,10,5] decnum = (int(re.findall('[0-9]+', f).pop())-1)/10 if decnum >= len(decs): decnum %= len(decs) gfxf = dirname(f)+'/../DEC/DECOR%02i.LBM' % decs[decnum] t = Tiled.Tileset('DECOR', 16,16, 0, 0) t.loadFromImage(fr.readtilegfx(gfxf), '') l = Tiled.TileLayer('Tiles',0,0, fr.w, fr.h) l.setMap(m) fr.populatetiles(l, t) # have to pass ownership so can't add tileset before populating layer m.addTileset(t) m.addLayer(l) #if not f.endswith('DATA19.BIN'): # del fr.lvl[:21*2] # skip some zeros, todo: more deterministic print len(fr.lvl), unpack('<40h', str(fr.lvl[:80])) print MetaData(*unpack('<9h', str(fr.lvl[:18]))) return m @classmethod def write(cls, m, fn): print "-- script doesn't support writing yet" fn += '.testing' print ".. map(%i,%i) to" % (m.width(),m.height()), fn lvl = [] with open(fn, 'w') as fh: for i in range(m.layerCount()): tiles = [] l = 0 if isTileLayerAt(m, i): l = tileLayerAt(m, i) print l elif isObjectGroupAt(m, i): #l = objectGroupAt(m, i) continue for x in range(l.width()): for y in range(l.height()): tiles.append( l.cellAt(x, y).tile.id() ) print >>fh, tiles return False def __init__(self, f): dat = bytearray() with open(f, 'rb') as fh: fh.read(4) #skip sig ldata = LevelData() rdata = RleData() while ldata.unpack(fh) and ldata.len != 0 : if len(ldata.d)==1 and ldata.d[0] == 0: break rdata.unpack(fh) dat.extend(ldata.d) dat.extend([rdata.val for i in range(rdata.rep)]) print 'le',len(dat) self.w, self.h = unpack("<2H", str(dat[:4])) del dat[:4] self.lvl = dat def readtilegfx(self, fn): lc = dict(lbm.parselbm(fn)) #print lc['BMHD'] bd = list(lbm.readbody(lc['BODY'], lc['BMHD'])) img = QImage(lc['BMHD'].sz.w, lc['BMHD'].sz.h, QImage.Format_Indexed8) img.setColorTable(lc['CMAP']) # there should be a faster alternative for y in range(img.height()): for x in range(img.width()): img.setPixel(x, y, bd[y*img.width()+x]) return img def populatetiles(self, l, t): i = 0 for y in range(self.h): for x in range(self.w): tpos = self.lvl[i+1]*t.columnCount() + self.lvl[i] if tpos < t.tileCount(): ti = t.tileAt(tpos) if ti != None: l.setCell(x, y, Tiled.Cell(ti)) i += 2 if self.w < 78: # padded to width of 78 tiles i += (78-self.w)*2 del self.lvl[:self.w*self.h*2] class LevelData(cpystruct.CpyStruct('ushort len; BYTE d[len];')): pass class RleData(cpystruct.CpyStruct('BYTE rep, sig, val')): pass tiled-0.14.2/src/plugins/python/scripts/lib/000077500000000000000000000000001260670167100207335ustar00rootroot00000000000000tiled-0.14.2/src/plugins/python/scripts/lib/__init__.py000066400000000000000000000000001260670167100230320ustar00rootroot00000000000000tiled-0.14.2/src/plugins/python/scripts/lib/cpystruct.py000066400000000000000000000213031260670167100233440ustar00rootroot00000000000000""" CreepyStruct - Convenience class for (un)packing structured binaries (c)2011-2012, 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 . """ import re, sys, struct # struct.pack format characters prefixed by : REFMT = r':[@!<>=]?[0-9xcbBhHiIlLqQfdspP]+' # possible array definition or value assignment REARR = r'(?:\[(\w+)\])?(?:\s*=\s*([0-9a-fx]+))?' # skip C or python style comments to the end of line RECMT = r'\s*(?:#.*|//.*)?' # whole line with at least format/struct ref and attribute name REPCK = r'(%s|[\s\w]+|,)\s+(\w+)%s%s[;]?%s' % (REFMT, RECMT, REARR, RECMT) FORMATS = { 'c':'char', 'b':'signed char|SBYTE', 'B':'unsigned char|uchar|BYTE', '?':'_Bool|bool', 'h':'short|SWORD', 'H':'unsigned short|ushort|UWORD', 'i':'int', 'I':'unsigned int|uint|WORD', 'l':'long', 'L':'unsigned long|ulong|DWORD', 'q':'long long', 'Q':'unsigned long long', 'f':'float', 'd':'double' } fdict = {} for f in FORMATS: fdict.update( [(p,f) for p in FORMATS[f].split('|')] ) class CpySkeleton(struct.Struct): """ Not to be used directly, use CpyStruct() to build a class """ def __init__(self, dat=None, **kws): """ Takes keyword arguments to initialize attributes """ struct.Struct.__init__(self, getattr(self, '__fstr')) self.validate() if len(kws) > 0: for k in kws: setattr(self, k, kws[k]) if dat != None: self.unpack(dat) def validate(self): "check that the extending classes specify valid struct" for i,(f,n,a,v) in enumerate(self.formats): if a != '' and not a.isdigit() and i < len(self.formats): for b in self.formats[i:]: if a=='' or b[2].isdigit(): raise Exception('Varlength arrays only '+ 'supported at end of struct: %s[%s]' % (n,a)) def pack(self): "convert member values to binary" ret = '' for i,(f,n,a,v) in enumerate(self.formats): v = getattr(self, n) if issubclass(v.__class__, CpySkeleton): ret += v.pack() continue if type(f) != type(struct.Struct) and f in fdict: f = fdict[f] if a != '': # array (possibly varlength) a = int(a) if a.isdigit() else getattr(self, a) if f=='c': # chararray as string f = str(a)+'s' a = 0 if type(f) == type(struct.Struct): fstr = getattr(f, '__fstr') # temp hack because of qmap limitations in tiled map props sz = struct.calcsize(fstr) m = re.match('<[0-9]*[sc]',fstr) if a != '' and a > 0 and (m is None or m.group(0) != fstr): for j in range(len(v)): #a): v2 = f(v[j].ljust(sz,'\0')) ret += v2.pack() elif type(v) == list: print 'pack list' # todo else: #v = f(v.ljust(sz,'\0')) ret += struct.pack(getattr(f, '__fstr'), v) else: f = getattr(self, '__endianflag') + f if type(v) is list: for x in v: ret += struct.pack(f, x) else: # just an ordinary var ret += struct.pack(f, v) return ret def unpack(self, dat): """ Takes a string, file, mmap or StringIO instance """ rawpos = 0 # position in binary for custom types pos = 0 # in case substruct handles multiple values if dat.__class__.__name__ in ('file','mmap', 'StringIO'): # this doesn't cover varlen members, for that dat is read directly buf = dat.read(len(self)) else: buf = dat unpacked = None if hasattr(self, 'fromraw'): sz = struct.calcsize(getattr(self, '__fstr')) unpacked = self.fromraw(buf[:sz]) if unpacked is None: unpacked = list(struct.Struct.unpack(self, buf)) if hasattr(self, 'fromval'): unpacked = self.fromval(unpacked) if not hasattr(unpacked, '__iter__'): unpacked = [unpacked] #if len(self.formats) != len(unpacked): # print unpacked # raise LookupError('Unmatched number of unpacked variables: %i != %i' # % (len(self.formats),len(unpacked))) for i,(f,n,a,v) in enumerate(self.formats): if a != '' and not a.isdigit(): break arlen = 0 if a.isdigit() and (type(f) is type or fdict[f] != 'c'): arlen = int(a) v = unpacked[pos] if type(f) == type(struct.Struct): sz = struct.calcsize(getattr(f, '__fstr')) if arlen > 0: arr = [] for i in range(arlen): arr.append( f(buf[rawpos:rawpos+sz]) ) rawpos += sz pos += len(f.formats) setattr(self, n, arr) else: setattr(self, n, f(buf[rawpos:rawpos+sz])) rawpos += sz pos += len(f.formats) else: if arlen > 0: setattr(self, n, unpacked[pos:pos+arlen]) pos += arlen else: setattr(self, n, v) pos += 1 rawpos += getattr(self, "__fsz")[i] # variable-length members for f,n,a,v in self.formats: if a != '' and not a.isdigit(): c = getattr(self, a) # one level of custom varlen types should be enough for everyone if isinstance(c, struct.Struct): # would it be better to delegate this to the custom class? c = getattr(c, c.__slots__[0]) #dat.seek(rawpos) if type(f) == type(struct.Struct): # custom types sz = struct.calcsize(getattr(f, '__fstr')) arr = [] for i in range(c): arr.append( f(dat.read(sz)) ) rawpos += sz setattr(self, n, arr) else: # primitives f = str(c)+'s' if fdict[f]=='c' else str(c)+fdict[f] sz = struct.calcsize(f) val = struct.unpack(f, dat.read(sz)) #if len(val) == 1: val = val[0] rawpos += sz setattr(self, n, val) return buf def __len__(self): return struct.calcsize(getattr(self, '__fstr')) def __str__(self): ret = self.__class__.__name__+'[' for f,n,a,v in self.formats: ret += '%s=%s,' % (n,getattr(self, n, '')) return ret[:-1]+']' def peek(s, n): p = s.tell() r = s.read(n) s.seek(p) return r def parseformat(fmt, callscope=None): fstr = '' sz = [] for i,(f,n,a,v) in enumerate(fmt): if f == ',' and i > 0: fmt[i] = (fmt[i-1][0],n,a,v) f = fmt[i-1][0] elif f == ',': raise Exception('Unexpected comma at '+str(fmt[i])) fs = '' if fdict.has_key(f): if a.isdigit(): fs = 's' if fdict[f] == 'c' else fdict[f] elif a != '' and not a.isdigit(): # varlength array, read separately pass else: # C type fs = fdict[f] elif type(f) is type(CpySkeleton): # might have an alignment issue when mixing endians.. fs = re.sub('[<>]?','',f.__fstr) elif callscope.f_globals.has_key(f): # resolve references to other CpyStructs fmt[i] = (callscope.f_globals[f],n,a,v) fs = re.sub('[<>]?','',fmt[i][0].__fstr) elif f[0] == ':': # struct format uses colon as prefix for explicitness fs = f[1:] fmt[i] = (f[1:],n,a,v) else: raise Exception('Unknown format at '+str(fmt[i])) if a.isdigit(): # in case it's e.g. custom type of a string if fs[0].isdigit(): fs *= int(a) else: fs = a + fs #elif a != '': # fstr += '{'+a+'}' sz.append(struct.calcsize(fs)) fstr += fs return (fmt, fstr, sz) def CpyStruct(s, endianflg='<'): """ Call with a string specifying C-like struct to get a Struct class """ # f=format, n=name, a=arraydef, v=default value fmt = [(f.strip(),n,a,v) for f,n,a,v in re.findall(REPCK, s)] # peek into caller's namespace in case they refer to custom classes callscope = sys._getframe(1) try: fmt, fstr, fsz = parseformat(fmt, callscope) finally: del callscope # for backwards compatibility if endianflg == True: endianflg = '>' elif endianflg == False: endianflg = '<' d = {} d['__endianflag'] = endianflg d['__fstr'] = endianflg + fstr d['__fsz'] = fsz d['__slots__'] = [n for f,n,a,v in fmt] d['formats'] = fmt for f,n,a,v in fmt: if v != '': d[n] = int(v,0) return type('', (CpySkeleton,), d) tiled-0.14.2/src/plugins/python/scripts/lib/lbm.py000066400000000000000000000062201260670167100220570ustar00rootroot00000000000000""" ILBM pure python decoder 2012, 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 . """ from tiled.qt import * from cpystruct import * #from PyQt4.Qt import QColor # to test outside tiled import struct class IFFhead(CpyStruct(":4s id; :I len; :4s type;", True)): pass class IFFchunk(CpyStruct(":4s id; :I len;", True)): @classmethod def parsefile(cls, f): """ Reads whole file consisting of IFF chunks Returns tuple generator of chunk name and body """ with open(f, 'rb') as fh: # header ih = IFFhead(fh) yield ih.type, ih # chunks ic = IFFchunk() filelen = ih.len - len(ih) while fh.tell() < filelen and ic.unpack(fh) != None: yield ic.id, fh.read(ic.len) class BMHDsize(CpyStruct("short w, h", True)): @classmethod def fromraw(cls, v): return struct.unpack(getattr(cls,'__fstr'), v) class BMHD(CpyStruct(""" BMHDsize sz; short x, y; BYTE planes, mask; short comp, trans; BYTE xaspect, yaspect; short pgw, pgh; """)): pass class CRNG(CpyStruct("short pad, cycrate, cycle, lowhireg;", True)): pass class CMAP(CpyStruct("BYTE color[3];", True)): @classmethod def parse(cls, dat): c = CMAP() sz = struct.calcsize(getattr(cls, '__fstr')) for i in range(len(dat)/sz): c.unpack(dat[i*sz:i*sz+sz]) yield QColor(c.color[0],c.color[1],c.color[2]).rgb() def uncomp(dat): i = 0 ret = bytearray() while i < len(dat): v = struct.unpack('b', dat[i])[0] i += 1 if v >= 0: for n in range(v+1): ret += dat[i] i += 1 elif v != -128: for n in range(v-1,0,1): ret += dat[i] i += 1 return ret def readbody(bd, ch): bj = [0,(ch.sz.w+15) / 16 * 2] for p in range(2,ch.planes): bj.append(bj[1] * p) sj = bj[1] * ch.planes for sl in range(0, sj*ch.sz.h, sj): for x in range(ch.sz.w): b = x & 7 bm = 128 >> b ib = sl + (x >> 3) px = (bd[ib] & bm) # only 4 planes tested for p in range(1,ch.planes,1): px |= (bd[ib+bj[p]] & bm) << p yield px >> (7 - b) def parselbm(f): for id,dat in list(IFFchunk.parsefile(f)): if id == 'BMHD': ch = BMHD(dat) yield id, ch elif id == 'CMAP': yield id, list(CMAP.parse(dat)) elif id == 'CRNG': yield id, CRNG(dat) elif id == 'CAMG': raise Exception('HAM/HALFBRITE not supported at the moment') elif id == 'BODY': if ch.comp == 1: bd = uncomp(dat) else: bd = dat yield id, bd if __name__ == "__main__": import sys print list(parselbm(sys.argv[1])) tiled-0.14.2/src/plugins/python/scripts/lib/mappy_types.py000066400000000000000000000077421260670167100236710ustar00rootroot00000000000000 from cpystruct import * """ #define AN_END -1 /* Animation types, AN_END = end of anims */ #define AN_NONE 0 /* No anim defined */ #define AN_LOOPF 1 /* Loops from start to end, then jumps to start etc */ #define AN_LOOPR 2 /* As above, but from end to start */ #define AN_ONCE 3 /* Only plays once */ #define AN_ONCEH 4 /* Only plays once, but holds end frame */ #define AN_PPFF 5 /* Ping Pong start-end-start-end-start etc */ #define AN_PPRR 6 /* Ping Pong end-start-end-start-end etc */ #define AN_PPRF 7 /* Used internally by playback */ #define AN_PPFR 8 /* Used internally by playback */ #define AN_ONCES 9 /* Used internally by playback */ """ class BLKSTR(CpyStruct(""" int olay[4]; unsigned int user1; unsigned int user2; // user long data */ unsigned short user3; unsigned short user4; // user short data */ unsigned char user5; unsigned char user6; unsigned char user7; // user byte data */ unsigned char tl; // bits for collision detection */ """)): pass """for newer fmp version? unsigned char tr; unsigned char bl; unsigned char br; unsigned char trigger; // bit to trigger an event */ unsigned char unused1; unsigned char unused2; unsigned char unused3; """ class ANISTR(CpyStruct(""" signed char antype; // Type of anim, AN_? */ signed char andelay; // Frames to go before next frame */ signed char ancount; // Counter, decs each frame, till 0, then resets to andelay */ signed char anuser; // User info */ long ancuroff; // Points to current offset in list */ long anstartoff; // Points to start of blkstr offsets list, AFTER ref. blkstr offset */ long anendoff; """)): pass class OBJSTR(CpyStruct(""" int xpos; int ypos; // pixel position in map to handle */ int gfxid; int tileid; int gxoff; int gyoff; // offset into graphic */ int gwidth; int gheight; int ghandlexoff; int ghandleyoff; // handle pos, from gxoff, gyoff */ int show; // display mode */ int user1; int user2; int user3; int user4; int user5; int user6; int user7; int flags; """)): pass class GENHEAD(CpyStruct(""" char id1; char id2; char id3; char id4; // 4 byte header id. */ long headsize; // size of header chunk. */ """)): pass #// char M,P,H,D; 4 byte chunk identification. */ #// long int mphdsize; size of map header. */ class MPHD(CpyStruct(""" BYTE mapverhigh; // map version number to left of . (ie X.0). */ BYTE mapverlow; // map version number to right of . (ie 0.X). */ BYTE lsb; // if 1, data stored LSB first, otherwise MSB first. */ BYTE type; // 0=old, 1=new, 2=iso short mapwidth; // width in blocks. */ short mapheight; // height in blocks. */ short reserved1; short reserved2; short blockwidth; // width of a block (tile) in pixels. */ short blockheight; // height of a block (tile) in pixels. */ short blockdepth; // depth of a block (tile) in planes (ie. 256 colours is 8) */ short blockstrsize; // size of a block data structure */ short numblockstr; // Number of block structures in BKDT */ short numblockgfx; // Number of 'blocks' in graphics (BODY) */ BYTE skip; SBYTE trans8bit; short transhi; """)): pass #// char E,D,H,D; 4 byte chunk identification. */ #// long int edhdsize; size of editor header. */ class EDHD(CpyStruct(""" short xmapoffset; // editor offset, in blocks, from left. */ short ymapoffset; // editor offset, in blocks, from right. */ long fgcolour; // fg colour for text, buttons etc. */ long bgcolour; // bg colour for text, buttons etc. */ short swidth; // width of current screen res */ short sheight; // height of current screen res */ short strtstr; // first structure in view */ short strtblk; // first block graphic in view */ short curstr; // current block structure */ short curanim; // current anim structure */ short animspd; // gap in frames between anims */ short span; // control panel height */ short numbrushes; // number of brushes to follow. */ """)): pass class MAPFILL(CpyStruct("short leftedge, width, yoff;")): pass class fmpchunk(CpyStruct(":4s id; :I len;",True)): pass class BODY(CpyStruct(":H dat[len]", True)): pass tiled-0.14.2/src/plugins/python/scripts/mappy.py000066400000000000000000000141111260670167100216630ustar00rootroot00000000000000""" Mappy support for Tiled 2012-2013, """ from tiled import * from tiled.qt import * import os, sys, struct from lib.mappy_types import BLKSTR, MPHD, fmpchunk import pickle from StringIO import StringIO from collections import OrderedDict from base64 import b64encode, b64decode class FMPPicklerMixin: @classmethod def unpackchunks(cls, f): chunks = OrderedDict() with open(f, 'rb') as fh: frm = fmpchunk() frm.unpack(fh) frm.data = fh.read(4) filelen = frm.len - 16 chunks[frm.id] = frm print frm while fh.tell() < filelen: fc = fmpchunk() if not fc.unpack(fh): break print fh.tell(), fc fc.data = fh.read(fc.len) chunks[fc.id] = fc return chunks @classmethod def packchunks(cls, fn, chunks): with open(fn, 'wb') as fh: for k,v in chunks.items(): print k, len(v) + v.len # chunk header + data fh.write(v.pack()) fh.write(v.data) @classmethod def picklechunks(cls, chunks): src = StringIO() pi = pickle.Pickler(src, 2) pi.dump(chunks) print "packlen", src.len return b64encode(src.getvalue()) @classmethod def unpicklechunks(cls, data): src = StringIO(b64decode(data)) print "unpacklen",src.len return pickle.Unpickler(src).load() class Mappy(Plugin, FMPPicklerMixin): @classmethod def nameFilter(cls): return "Mappy (*.fmp)" @classmethod def supportsFile(cls, f): return open(f).read(4) == 'FORM' @classmethod def read(cls, f): print 'Loading map at',f chunks = cls.unpackchunks(f) hd = MPHD() # perhaps cpystruct should only read as many bytes as it can handle? hd.unpack(chunks['MPHD'].data[:len(hd)]) m = Tiled.Map(Tiled.Map.Orthogonal, hd.mapwidth, hd.mapheight, hd.blockwidth, hd.blockheight) if hd.type == 2: print 'Isometric maps not supported at the moment' return m m.setProperty('chunks', cls.picklechunks(chunks)) tset = Tiled.Tileset('Tiles', hd.blockwidth, hd.blockheight, 0, 0) cmap = list(FMPColormap.unpack(chunks['CMAP'].data)) tset.loadFromImage(FMPTileGfx.unpack(hd, chunks['BGFX'].data, cmap), "") blks = FMPBlocks(chunks['BKDT'].data, hd).blocks for c in ['LYR'+str(i) for i in range(7,0,-1)]+['BODY']: if not chunks.has_key(c): continue print 'populating',c lay = Tiled.TileLayer(c,0,0,hd.mapwidth, hd.mapheight) lvl = list(FMPLayer.unpack(hd, chunks[c].data)) FMPLayer.populate(lay, blks, tset, hd, lvl) m.addLayer(lay) m.addTileset(tset) return m @classmethod def write(cls, m, fn): if m.orientation() != Tiled.Map.Orthogonal: print 'Isometric maps not supported at the moment' return False if not m.property('chunks'): raise Exception("Export depends on unparsed binary blobs from original " +"fmp to be stored in the map property 'chunks'") print 'Writing map at',fn chunks = cls.unpicklechunks(m.property('chunks')) hd = MPHD() hd.unpack(chunks['MPHD'].data[:len(hd)]) blks = FMPBlocks(chunks['BKDT'].data, hd).blocks for i in range(m.layerCount()): if not isTileLayerAt(m, i): continue l = tileLayerAt(m, i) chunks[l.name()].data = FMPLayer.pack(hd, blks, l, i) cls.packchunks(fn, chunks) return True class FMPBlocks: @classmethod def unpack(cls, chunk, hd): mod = hd.blockwidth * hd.blockheight * ((hd.blockdepth+1)/8) for pos in range(0, hd.numblockstr*hd.blockstrsize, hd.blockstrsize): b = BLKSTR() b.unpack(chunk[pos:pos+hd.blockstrsize]) if hd.type == 0: for i in range(4): b.olay[i] /= mod yield b def __init__(self, chunk, hd): self.blocks = list(FMPBlocks.unpack(chunk, hd)) class FMPTileGfx: @classmethod def unpack(cls, hd, dat, cmap): n = 0 w,h = hd.blockwidth*10, hd.blockheight*hd.numblockgfx/10+hd.blockheight fmt = QImage.Format_Indexed8 if hd.blockdepth==8 else QImage.Format_ARGB32 img = QImage(w, h, fmt) img.setColorTable(cmap) for i in range(hd.numblockgfx): col,row = i%10, i/10 tx,ty = col*hd.blockwidth, row*hd.blockheight for y in range(hd.blockheight): for x in range(hd.blockwidth): c = struct.unpack('B', dat[n])[0] if hd.blockdepth==8: img.setPixel(tx+x, ty+y, c) else: img.setPixel(tx+x, ty+y, cmap[c]) n+=1 return img class FMPLayer: @classmethod def unpack(cls, hd, dat): for i in range(0,hd.mapheight*hd.mapwidth*2,2): d = struct.unpack('= len(blocks): pass#print 'unknown block at',i else: n = blocks[ldata[i]].olay[fg] if n != 0: ti = tileset.tileAt(n) if ti is None: print 'invalid tile',n,'at',x,y else: layer.setCell(x, y, Tiled.Cell(ti)) i += 1 class FMPColormap: @classmethod def unpack(self, cmap): """cmap -- rgb bytearray""" print 'got',len(cmap) for i in range(0,len(cmap),3): r,g,b = struct.unpack('3B', cmap[i:i+3]) yield QColor(r,g,b).rgb() @classmethod def pack(self, cmap): """cmap -- QImage.colorTable""" yield fmpchunk(id='CMAP', len=len(list(cmap))).pack() for c in cmap: yield struct.pack('3B', (c.qRed,c.qGreen,c.qBlue)) tiled-0.14.2/src/plugins/python/scripts/pk2.py000066400000000000000000000214541260670167100212410ustar00rootroot00000000000000""" Pekka Kana 2 map support for Tiled 2012, Notes: - should make PK2 classes mixins with Tiled ones """ import os, sys, re, string from tiled import * from tiled.qt import * from lib import cpystruct from os.path import dirname, exists from struct import pack,unpack,Struct from base64 import b64encode, b64decode maps = [] class PK2(Plugin): @classmethod def nameFilter(cls): return "Pekka Kana 2 (*.map)" @classmethod def supportsFile(cls, f): return open(f, 'rb').read(4) == '1.3\0' @classmethod def read(cls, f): lvl = PK2MAP() with open(f, 'rb') as fh: lvl.unpack(fh) # spriteCount is +1 fh.seek(-len(lvl.spriteFiles[0]), 1) lay1 = PK2MAPLAYER(fh) lay2 = PK2MAPLAYER(fh) lay3 = PK2MAPLAYER(fh) print lvl # -- tileset img = QImage() imgfile = dirname(f)+'/../../gfx/tiles/'+str(lvl.tileFile) img.load(imgfile, 'BMP') t = Tiled.Tileset('Tiles', 32,32, 0, 0) t.setTransparentColor(QColor(img.color(255))) t.loadFromImage(img, imgfile) # find common bounding box for the layers bb = ['','',10,10] for l in [lay1,lay2,lay3]: print l bb[0] = min([bb[0], l.lx.num]) bb[1] = min([bb[1], l.ly.num]) bb[2] = max([bb[2], l.width()]) bb[3] = max([bb[3], l.height()]) print 'bounds', bb m = Tiled.Map(Tiled.Map.Orthogonal, bb[2], bb[3], 32,32) maps.append(m) # -- background image lai = Tiled.ImageLayer('Scenery', 0,0, bb[2], bb[3]) img = QImage() imgfile = dirname(f)+'/../../gfx/scenery/'+str(lvl.fieldFile) img.load(imgfile, 'BMP') lai.loadFromImage(img, imgfile) # -- layers la1 = Tiled.TileLayer('Back', 0,0, bb[2], bb[3]) la1.setMap(m) lay1.doTiles(t, la1, bb) la2 = Tiled.TileLayer('Front', 0,0, bb[2], bb[3]) la2.setMap(m) lay2.doTiles(t, la2, bb) sprdir = dirname(f)+'/../../sprites/' lay3.sprites = [0] lay3.spriteGfx = {} for s in lvl.spriteFiles: # spriteCount is +1 if not exists(sprdir+str(s)): break spr = PK2SPR(sprdir+str(s), m) if not lay3.spriteGfx.has_key(str(spr.kuvatiedosto)): sprfile = find_case_insensitive_filename(sprdir, str(spr.kuvatiedosto)) img = QImage() img.load(sprdir+sprfile, 'BMP') print 'loading', sprdir+sprfile sprts = Tiled.Tileset(sprfile, 32,32, 0, 0) sprts.setTransparentColor(QColor(img.color(255))) sprts.loadFromImage(img, sprdir+sprfile) lay3.spriteGfx[str(spr.kuvatiedosto)] = sprts #sprgfx[(str(spr.kuvatiedosto] lay3.sprites.append(spr) #print spr la3 = Tiled.ObjectGroup('Sprites', 0,0, bb[2], bb[3]) la3.setMap(m) lay3.doSprites(la3, bb) m.addLayer(lai) m.addTileset(t) for sprts in lay3.spriteGfx.values(): m.addTileset(sprts) m.addLayer(la1) m.addLayer(la2) m.addLayer(la3) for f in lvl.__slots__: val = repr(getattr(lvl, f)) m.setProperty(f, b64encode(val)) return m @classmethod def write(cls, m, fn): out = PK2MAP() for f in m.properties().keys(): if not f.startswith('__'): setattr(out, f, b64decode(m.property(f))) #setattr(out, "sprites", ['pla']) with open(fn, 'wb') as fh: print >>fh, out.pack() for i in range(m.layerCount()): tiles = [] l = 0 if isTileLayerAt(m, i): l = tileLayerAt(m, i) print l elif isObjectGroupAt(m, i): #l = objectGroupAt(m, i) continue for y in range(l.height()): for x in range(l.width()): if l.cellAt(x, y).tile != None: tiles.append( l.cellAt(x, y).tile.id() ) print >>fh, 0,0, l.width(), l.height() print >>fh, bytearray(tiles) return True def find_case_insensitive_filename(path, fn): for f in os.listdir(path): if f.lower() == fn.lower(): return f class asciilongfile(cpystruct.CpyStruct("char filename[100]")): @classmethod def fromraw(cls, v): return re.search('[\w\.]*', v, re.U).group(0) def __repr__(self): return str(self) def __str__(self): return self.filename class asciifile(cpystruct.CpyStruct("char filename[13]")): @classmethod def fromraw(cls, v): return re.search('[\w\.]*', v, re.U).group(0) def __repr__(self): return str(self) def __str__(self): return self.filename class asciitxt(cpystruct.CpyStruct("char txt[40]")): @classmethod def fromraw(cls, v): return re.search('[\w\. ]', v, re.U).group(0) class asciinum(cpystruct.CpyStruct("char num[8]")): @classmethod def fromraw(cls, v): #v = ''.join(re.findall('[0-9]', v)) v = re.sub('[^0-9]','',v) return 0 if not v.strip().isdigit() else int(v) class PK2MAPLAYER(cpystruct.CpyStruct("asciinum lx, ly, w, h;")): MAXW = 256 MAXH = 224 MAXSZ = MAXW*MAXH def width(self): return self.w.num + 1 def height(self): return self.h.num + 1 def __init__(self, dat): # should make cpystruct support this usecase better super(self.__class__, self).__init__(dat) #print str(cpystruct.peek(dat, 128)) self.layer = bytearray(self.MAXSZ) for i in range(len(self.layer)): self.layer[i] = 0xff for y in range(self.ly.num, self.ly.num+self.height()): for x in range(self.lx.num, self.lx.num+self.width()): self.layer[x+y*self.MAXW] = dat.read(1) def findBounds(self): "find bounding box for coords that have tiles" mx,my,mw,mh = None,None,10,10 for y in range(self.ly, self.ly+self.height()): for x in range(self.lx, self.lx+self.width()): if self.layer[x + y * self.MAXW] != 255: if not my: my = y if not mx or x < mx: mx = x if x > mw: mw = x if y > mh: mh = y if not mx: mx = 0 if not my: my = 0 return mx, my, mw, mh def doSprites(self, la, bb): for y in range(self.height()): for x in range(self.width()): sprite = self.layer[self.lx.num + x + (self.ly.num + y) * self.MAXW] if sprite != 255: #if sprite > len(self.sprites): # print 'invalid spr',sprite # continue rx = self.lx.num + x - bb[0] ry = self.ly.num + y - bb[1] + 1 spr = self.sprites[sprite] obj = Tiled.MapObject(str(spr.kuvatiedosto), '', QPointF(rx, ry), QSizeF(1, 1)) #spr.width, spr.height)) # 0 should point to the actual sprite but how? obj.setCell(Tiled.Cell(self.spriteGfx[str(spr.kuvatiedosto)].tileAt(0))) la.addObject(obj) def doTiles(self, ts, la, bb): for y in range(self.height()): for x in range(self.width()): tile = self.layer[self.lx.num + x + (self.ly.num + y) * self.MAXW] if tile != 255: rx = self.lx.num + x - bb[0] ry = self.ly.num + y - bb[1] if tile == 149: print 'start @',rx,ry if tile == 150: print 'end @',rx,ry ti = ts.tileAt(tile) if ti != None and rx < bb[2] and ry < bb[3]: # app should check that coords are within layer #print rx,ry,self.ly,y la.setCell(rx, ry, Tiled.Cell(ti)) else: print 'invalid',rx,ry class PK2SPR_ANIM(cpystruct.CpyStruct(""" uchar seq[10]; uchar frames; bool loop; """)): def __repr__(self): return str(self) class PK2SPR(cpystruct.CpyStruct(""" asciinum tyyppi; asciilongfile kuvatiedosto; asciilongfile aanitiedostot[7]; int aanet[7]; uchar frameja; PK2SPR_ANIM animaatiot[20]; uchar animaatioita; uchar frame_rate; int kuva_x; int kuva_y; int kuva_frame_leveys; int kuva_frame_korkeus; int kuva_frame_vali; char nimi[30]; int width, height; double paino; bool vihollinen; int energia; int vahinko; uchar vahinko_tyyppi; uchar suojaus; int pisteet; int AI[10]; uchar max_hyppy; double max_nopeus; int latausaika; uchar vari; bool este; int tuhoutuminen; bool avain; bool tarisee; uchar bonusten_lkm; int hyokkays1_aika; int hyokkays2_aika; int pallarx_kerroin; char muutos_sprite[100]; char bonus_sprite[100]; char ammus1_sprite[100]; char ammus2_sprite[100]; bool tiletarkistus; DWORD aani_frq; bool random_frq; bool este_ylos; bool este_alas; bool este_oikealle; bool este_vasemmalle; uchar lapinakyvyys; bool hehkuu; int tulitauko; bool liitokyky; bool boss; bool bonus_aina; bool osaa_uida; """)): def __init__(self, f, m): with open(f, 'rb') as fh: super(self.__class__, self).__init__(fh) class PK2MAP(cpystruct.CpyStruct(""" char ver[4]; BYTE nan; asciifile tileFile, fieldFile, musicFile; asciitxt mapName, author; asciinum lvl, air, trig1, trig2, trig3; asciinum playTime, v1, background, plrSpr; asciinum lvlX, lvlY, icon; asciinum spriteCount; asciifile spriteFiles[spriteCount]; """)): pass tiled-0.14.2/src/plugins/python/scripts/zst.py000066400000000000000000000111441260670167100213600ustar00rootroot00000000000000""" Initial support for SNES emulator save states in Tiled 2012, Note: - assumes 8x8px tiles in 64x32 map of 4bpp gfx of max 7 palgroups - only supports bg1 of bgmode 1 http://snesemu.black-ship.net/misc/techdocs/snesdoc.html#GraphicsFormat """ import sys, re, string from tiled import * from tiled.qt import * from os.path import dirname from struct import pack,unpack,Struct from collections import namedtuple class ZST(Plugin): @classmethod def nameFilter(cls): return "zSNES Save State (*.zs?)" @classmethod def supportsFile(cls, f): return open(f).read(26) == 'ZSNES Save State File V0.6' @classmethod def read(cls, f): m = Tiled.Map(Tiled.Map.Orthogonal, 64,32, 8,8) # bg1-4 layer bpp counts bgmodes = ( (2, 4, 4, 8, 8, 4, 4, 0), (2, 4, 4, 4, 2, 2, 0, 0), (2, 2, 0, 0, 0, 0, 0, 0), (2, 0, 0, 0, 0, 0, 0, 0)) img = QImage(32*8, 32*8, QImage.Format_Indexed8) #img.fill(255) cmap = [] with open(f, 'rb') as fh: #fh.seek(0x66) #bgmode = unpack('B', fh.read(1))[0] #if bgmode != 7: raise Exception('only mode7 supported atm: '+str(bgmode)) # supporting new uncompressed save state formats should be just # a matter of adding correct addresses for these cgrambase = 0x618 tilemapbase = 0x20C13 # vram:0 tilebase = 0x2000 # vram offset fh.seek(cgrambase) cmap = list(parseColors(fh.read(0x200))) #img.setColorTable(cmap) colors = 16 tsets = [] for pal in range(7): img.setColorTable(cmap[pal*colors:pal*colors+colors]) fh.seek(tilemapbase+tilebase) readTileset(fh, img) tsets.append(Tiled.Tileset('Pal%i'%pal, 8,8, 0, 0)) tsets[pal].setTransparentColor(QColor(img.color(0))) tsets[pal].loadFromImage(img, 'script') la = Tiled.TileLayer('Back', 0,0, 64,32) la.setMap(m) fh.seek(tilemapbase) for y in range(la.height()): for x in range(32): t = parseTile(unpack('H', fh.read(2))[0]) try: tile = tsets[t.pal].tileAt(t.idx) pix = tile.image() tile.setImage(pix) """ overriding tile gfx could be an alternative to palgroup layers img = pix.toImage() img.setColorTable(cmap[t.pal*16:t.pal*16+16]) pix.convertFromImage(img) """ la.setCell(x, y, Tiled.Cell(tile)) except: print 'out of range %i,%i: %i' % (x,y,t.idx) if la.width() > 32: for y in range(la.height()): for x in range(32, la.width()): t = parseTile(unpack('H', fh.read(2))[0]) try: tile = tsets[t.pal].tileAt(t.idx) la.setCell(x, y, Tiled.Cell(tile)) except: print 'out of range %i,%i: %i' % (x,y,t.idx) for pal in range(7): m.addTileset(tsets[pal]) m.addLayer(la) return m def readTileset(dat, img, tvert=32, thoriz=32): tw, th = 8, 8 # iterate tiles for i in range(tvert*thoriz): tx,ty = i%tvert*tw, i/thoriz*th l1 = unpack('>16B', dat.read(16)) l2 = unpack('>16B', dat.read(16)) colordat = deplane4bpp([l1,l2]) # iterate lines in a tile for l in range(th): # ..pixels in a line for p in range(tw): c = colordat[l][p] img.setPixel(tx+p, ty+l, c) def deplane2bpp(src, dst): "takes 16 bytes, simplify" for i in range(8): b0 = src[i*2] b1 = src[i*2+1] if i <= len(dst): dst.append(bytearray(8)) dst[i][0] += (b0 >> 7) | b1 >> 6 & 2 dst[i][1] += (b0 >> 6 & 1) | b1 >> 5 & 2 dst[i][2] += (b0 >> 5 & 1) | b1 >> 4 & 2 dst[i][3] += (b0 >> 4 & 1) | b1 >> 3 & 2 dst[i][4] += (b0 >> 3 & 1) | b1 >> 2 & 2 dst[i][5] += (b0 >> 2 & 1) | b1 >> 1 & 2 dst[i][6] += (b0 >> 1 & 1) | b1 & 2 dst[i][7] += (b0 & 1) | b1 & 1 << 1 return dst #deplane2bpp( bytearray('3C3C4266 99 66 99 66 99 66 99 3C 42 00 3C 3C'.replace(' ','').decode('hex')) ) def deplane4bpp(src): "decode planar 4bpp line of 8px into packed color indexes" dst = deplane2bpp(src[1], list()) for i in range(len(dst)): for j in range(len(dst[i])): dst[i][j] <<= 2 return deplane2bpp(src[0], dst) def parseColors(cgram): for i in range(0, len(cgram), 2): col = unpack('H', cgram[i:i+2])[0] r = (col << 3) & 0xf8 g = ((col >> 5) << 3) & 0xf8 b = ((col >> 10) << 3) & 0xf8 #print (r,g,b), yield QColor(r,g,b).rgb() def parseTile(t): ret = namedtuple('Tile', 'idx pal prio flipx flipy') return ret(idx = t & 1023, pal = t >> 10 & 7, prio = t >> 13, flipx = t >> 14 != 0, flipy = t >> 15 != 0) tiled-0.14.2/src/plugins/python/tiledbinding.py000066400000000000000000000340651260670167100215140ustar00rootroot00000000000000""" Python Tiled Plugin Copyright 2012-2013, Samuli Tuomola This file is part of Tiled. 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, see . """ from pybindgen import * mod = Module('tiled') mod.add_include('"pythonplugin.h"') mod.add_include('"map.h"') mod.add_include('"layer.h"') mod.add_include('"tile.h"') mod.add_include('"mapobject.h"') mod.add_include('"imagelayer.h"') mod.add_include('"tilelayer.h"') mod.add_include('"objectgroup.h"') mod.add_include('"tileset.h"') mod.header.writeln('#pragma GCC diagnostic ignored "-Wmissing-field-initializers"') # one day PyQt/PySide could be considered import qtbinding qtbinding.generate(mod) #mod.add_include('"qtbind.h"') tiled = mod.add_cpp_namespace('Tiled') cls_tile = tiled.add_class('Tile') cls_tile.add_method('id', 'int', []) cls_tile.add_method('image', retval('const QPixmap&'), []) cls_tile.add_method('setImage', None, [('const QPixmap&','image')]) cls_tile.add_method('width', 'int', []) cls_tile.add_method('height', 'int', []) #cls_tile.add_method('size', 'QSize', []) cls_sharedtileset = tiled.add_class('SharedTileset') cls_tileset = tiled.add_class('Tileset') cls_tileset.add_method('create', 'Tiled::SharedTileset', [('QString','name'), ('int','tileWidth'), ('int','tileHeight'), ('int','tileSpacing'), ('int','margin')], is_static=True) cls_tileset.add_method('name', 'QString', []) cls_tileset.add_method('setName', None, [('QString','name')]) cls_tileset.add_method('fileName', 'QString', []) cls_tileset.add_method('setFileName', None, [('QString','name')]) cls_tileset.add_method('isExternal', 'bool', []) cls_tileset.add_method('tileWidth', 'int', []) cls_tileset.add_method('tileHeight', 'int', []) cls_tileset.add_method('tileSpacing', 'int', []) cls_tileset.add_method('margin', 'int', []) #cls_tileset.add_method('tileOffset', 'QPoint', []) cls_tileset.add_method('loadFromImage', 'bool', [('const QImage&','img'),('QString','file')]) cls_tileset.add_method('tileAt', retval('Tiled::Tile*',reference_existing_object=True), [('int','id')]) cls_tileset.add_method('tileCount', 'int', []) cls_tileset.add_method('columnCount', 'int', []) cls_tileset.add_method('imageWidth', 'int', []) cls_tileset.add_method('imageHeight', 'int', []) cls_tileset.add_method('setTransparentColor', None, [('QColor','col')]) cls_tileset.add_method('transparentColor', 'QColor', []) cls_tile.add_constructor([param('const QPixmap&','image'), param('int','id'), param('Tileset*','tileset',transfer_ownership=False)]) cls_tile.add_method('tileset', retval('Tiled::Tileset*',reference_existing_object=True), []) cls_layer = tiled.add_class('Layer') #mod.add_container('QList', # retval('Tiled::Tileset*',caller_owns_return=False), 'list') cls_props = tiled.add_class('Properties') cls_props.add_method('keys', 'QList', []) #cls_propsc = tiled.add_container('QMap', ('QString','QString'), 'map', cls_props) cls_map = tiled.add_class('Map') cls_map.add_enum('Orientation', ('Unknown','Orthogonal','Isometric')) cls_map.add_copy_constructor() cls_map.add_constructor([('Orientation','orient'), ('int','w'), ('int','h'), ('int','tileW'), ('int','tileH')]) cls_map.add_method('orientation', 'Orientation', []) cls_map.add_method('setOrientation', None, [('Orientation','o')]) cls_map.add_method('width', 'int', []) cls_map.add_method('setWidth', None, [('int','w')]) cls_map.add_method('height', 'int', []) cls_map.add_method('setHeight', None, [('int','h')]) cls_map.add_method('tileWidth', 'int', []) cls_map.add_method('tileHeight', 'int', []) cls_map.add_method('layerCount', 'int', []) cls_map.add_method('tileLayerCount', 'int', []) cls_map.add_method('objectGroupCount', 'int', []) cls_map.add_method('addTileset', None, [param('SharedTileset','tileset')]) cls_map.add_method('insertTileset', None, [('int','pos'),param('SharedTileset','tileset')]) cls_map.add_method('indexOfTileset', 'int', [param('const SharedTileset &','tileset')]) cls_map.add_method('removeTilesetAt', None, [('int','pos')]) cls_map.add_method('replaceTileset', None, [param('SharedTileset','oldTileset'), param('SharedTileset','newTileset')]) cls_map.add_method('tilesetAt', retval('Tiled::SharedTileset'), [('int','idx')]) cls_map.add_method('tilesetCount', 'int', []) cls_map.add_method('isTilesetUsed', 'bool', [param('const Tileset*','tileset')]) cls_map.add_method('properties', retval('Tiled::Properties','p'), []) cls_map.add_method('property', 'QString', [('QString','name')]) cls_map.add_method('setProperty', None, [('QString','name'), ('QString','value')]) cls_cell = tiled.add_class('Cell') cls_cell.add_constructor([param('Tiled::Tile*','tile', transfer_ownership=False)]) cls_cell.add_method('isEmpty', 'bool', []) cls_cell.add_instance_attribute('tile', retval('Tiled::Tile*', is_const=True), is_const=True) cls_tilelayer = tiled.add_class('TileLayer', cls_layer) cls_tilelayer.add_constructor([('QString','name'), ('int','x'), ('int','y'), ('int','w'), ('int','h')]) cls_tilelayer.add_method('cellAt', retval('Tiled::Cell'), [('int','x'),('int','y')]) cls_tilelayer.add_method('setCell', None, [('int','x'),('int','y'), ('Cell','c')]) cls_tilelayer.add_method('referencesTileset', 'bool', [param('Tileset*','ts',transfer_ownership=False)]) cls_tilelayer.add_method('isEmpty', 'bool', []) cls_imagelayer = tiled.add_class('ImageLayer') cls_imagelayer.add_constructor([('QString','name'), ('int','x'), ('int','y'), ('int','w'), ('int','h')]) cls_imagelayer.add_method('loadFromImage', 'bool', [('const QImage&','img'),('QString','file')]) cls_imagelayer.add_method('image', retval('const QPixmap&'), []) cls_imagelayer.add_method('setImage', None, [('const QPixmap&','image')]) cls_object = tiled.add_class('Object') cls_object.add_method('property', 'QString', [('QString','prop')]) cls_object.add_method('setProperty', None, [('QString','prop'),('QString','val')]) cls_mapobject = tiled.add_class('MapObject', cls_object) cls_mapobject.add_constructor([]) cls_mapobject.add_constructor([('QString','name'), ('QString','type'), ('QPointF','pos'), ('QSizeF','size') ]) cls_mapobject.add_enum('Shape', ('Rectangle','Polygon','Polyline')) cls_mapobject.add_method('setPosition', None, [('QPointF','pos')]) cls_mapobject.add_method('x', 'float', []) cls_mapobject.add_method('setX', None, [('float','x')]) cls_mapobject.add_method('y', 'float', []) cls_mapobject.add_method('setY', None, [('float','y')]) cls_mapobject.add_method('setSize', None, [param('QSizeF','size')]) cls_mapobject.add_method('width', 'float', []) cls_mapobject.add_method('setWidth', None, [('float','w')]) cls_mapobject.add_method('height', 'float', []) cls_mapobject.add_method('setHeight', None, [('float','h')]) #cls_mapobject.add_method('setPolygon', None, [param('QPolygonF','pol')]) #cls_mapobject.add_method('polygon', 'QPolygonF', []) cls_mapobject.add_method('setShape', None, [param('Shape','s')]) cls_mapobject.add_method('shape', 'Shape', []) #cls_mapobject.add_method('bounds', 'QRectF', []) cls_mapobject.add_method('setCell', None, [param('const Tiled::Cell','c',)]) cls_mapobject.add_method('cell', retval('const Tiled::Cell'), []) #cls_mapobject.add_method('setObjectGroup', 'ObjectGroup*', []) #cls_mapobject.add_method('objectGroup', 'ObjectGroup*', []) cls_mapobject.add_method('rotation', 'float', []) cls_mapobject.add_method('setRotation', None, [('float','r')]) cls_mapobject.add_method('isVisible', 'bool', []) cls_mapobject.add_method('setVisible', None, [('bool','v')]) cls_mapobject.add_method('name', 'QString', []) cls_mapobject.add_method('setName', None, [('QString','n')]) cls_mapobject.add_method('type', 'QString', []) cls_mapobject.add_method('setType', None, [('QString','n')]) cls_objectgroup = tiled.add_class('ObjectGroup', cls_layer) cls_objectgroup.add_constructor([('QString','name'), ('int','x'), ('int','y'), ('int','w'), ('int','h')]) cls_objectgroup.add_method('addObject', None, [param('MapObject*','object',transfer_ownership=True)]) cls_objectgroup.add_method('insertObject', None, [('int','idx'),param('MapObject*','object',transfer_ownership=False)]) cls_objectgroup.add_method('removeObject', 'int', [param('MapObject*','object',transfer_ownership=False)]) #cls_tilelayer.add_method('cellAt', retval('Tiled::Cell'), # [('int','x'),('int','y')]) cls_objectgroup.add_method('objectAt', retval('Tiled::MapObject*',reference_existing_object=True),[('int','index')]) cls_objectgroup.add_method('objectCount', 'int',[]) #cls_objectgroup.add_method('objectsBoundingRect', 'QRectF', []) #cls_objectgroup.add_method('usedTilesets', 'QSet', []) cls_objectgroup.add_method('referencesTileset', 'bool', [param('Tileset*','ts',transfer_ownership=False)]) #MapObject *objectAt(int index) cls_map.add_method('addLayer', None, [param('ImageLayer*','l',transfer_ownership=True)]) cls_map.add_method('addLayer', None, [param('TileLayer*','l',transfer_ownership=True)]) cls_map.add_method('addLayer', None, [param('ObjectGroup*','l',transfer_ownership=True)]) cls_map.add_method('layerAt', retval('Tiled::Layer*',reference_existing_object=True), [('int','idx')]) cls_layer.add_method('name', 'QString', []) cls_layer.add_method('setName', None, [('QString','name')]) cls_layer.add_method('opacity', 'float', []) cls_layer.add_method('setOpacity', None, [('float','opacity')]) cls_layer.add_method('isVisible', 'bool', []) cls_layer.add_method('setVisible', None, [('bool','visible')]) cls_layer.add_method('map', retval('Tiled::Map*',reference_existing_object=True), []) cls_layer.add_method('setMap', None, [param('Tiled::Map*','map',transfer_ownership=False)]) cls_layer.add_method('x', 'int', []) cls_layer.add_method('setX', None, [('int','x')]) cls_layer.add_method('y', 'int', []) cls_layer.add_method('setY', None, [('int','y')]) cls_layer.add_method('setPosition', None, [('int','x'),('int','y')]) cls_layer.add_method('width', 'int', []) cls_layer.add_method('height', 'int', []) cls_layer.add_method('asTileLayer', retval('Tiled::TileLayer*',reference_existing_object=True), [], is_virtual=True) cls_layer.add_method('asObjectGroup', retval('Tiled::ObjectGroup*',reference_existing_object=True), [], is_virtual=True) mod.body.writeln(""" bool isImageLayerAt(Tiled::Map *map, int idx) { return (dynamic_cast(map->layerAt(idx)) != 0); } bool isTileLayerAt(Tiled::Map *map, int idx) { return (dynamic_cast(map->layerAt(idx)) != 0); } bool isObjectGroupAt(Tiled::Map *map, int idx) { return (dynamic_cast(map->layerAt(idx)) != 0); } Tiled::ImageLayer* imageLayerAt(Tiled::Map *map, int idx) { return static_cast(map->layerAt(idx)); } Tiled::TileLayer* tileLayerAt(Tiled::Map *map, int idx) { return static_cast(map->layerAt(idx)); } Tiled::ObjectGroup* objectGroupAt(Tiled::Map *map, int idx) { return static_cast(map->layerAt(idx)); } """) mod.add_function('isTileLayerAt', 'bool', [param('Tiled::Map*','map',transfer_ownership=False),('int','idx')]) mod.add_function('isObjectGroupAt', 'bool', [param('Tiled::Map*','map',transfer_ownership=False),('int','idx')]) mod.add_function('tileLayerAt', retval('Tiled::TileLayer*',reference_existing_object=True), [param('Tiled::Map*','map',transfer_ownership=False),('int','idx')]) mod.add_function('objectGroupAt', retval('Tiled::ObjectGroup*',reference_existing_object=True), [param('Tiled::Map*','map',transfer_ownership=False),('int','idx')]) mod.add_function('loadTilesetFromFile', 'bool', [param('Tileset*','ts',transfer_ownership=False),('QString','file')]) mod.body.writeln(""" bool loadTilesetFromFile(Tiled::Tileset *ts, QString file) { QImage img(file); return ts->loadFromImage(img, file); } """) """ C++ class PythonScript is seen as Tiled.Plugin from Python script (naming describes the opposite side from either perspective) """ cls_pp = mod.add_class('PythonScript', allow_subclassing=True, foreign_cpp_namespace='Python', custom_name='Plugin') """ PythonPlugin implements LoggingInterface for messaging to Tiled """ cls_logi = tiled.add_class('LoggingInterface', destructor_visibility='private') cls_logi.add_enum('OutputType', ('INFO','ERROR')) cls_logi.add_method('log', 'void', [('OutputType','type'),('const QString','msg')], is_virtual=True) with open('pythonbind.cpp','w') as fh: import pybindgen.typehandlers.codesink as cs sink = cs.MemoryCodeSink() print >>fh, """ #ifdef __MINGW32__ #include // included before Python.h to fix ::hypot not declared issue #endif """ mod.generate(fh) print >>fh, """ PyObject* _wrap_convert_c2py__Tiled__LoggingInterface(Tiled::LoggingInterface *cvalue) { PyObject *py_retval; PyTiledLoggingInterface *py_LoggingInterface; py_LoggingInterface = PyObject_New(PyTiledLoggingInterface, &PyTiledLoggingInterface_Type); py_LoggingInterface->flags = PYBINDGEN_WRAPPER_FLAG_NONE; py_LoggingInterface->obj = cvalue; py_retval = Py_BuildValue((char *) "N", py_LoggingInterface); return py_retval; } """ #mod.generate_c_to_python_type_converter( # utils.eval_retval(retval("Tiled::LoggingInterface")), # sink) mod.generate_python_to_c_type_converter( utils.eval_retval(retval('Tiled::Map*',caller_owns_return=True)), sink) mod.generate_c_to_python_type_converter( utils.eval_retval("const Tiled::Map"), sink) print >>fh, sink.flush() # vim: ai ts=4 sts=4 et sw=4 ft=python tiled-0.14.2/src/plugins/replicaisland/000077500000000000000000000000001260670167100177675ustar00rootroot00000000000000tiled-0.14.2/src/plugins/replicaisland/MAKING_TILESETS_FOR_OBJECTS.txt000066400000000000000000000024071260670167100246740ustar00rootroot00000000000000Replica Island has variably-sized objects, stored as individual images (and sequences of images for frames). But we need to represent our objects as a single tiled image. If you have a bunch of object images of various sizes, and you want to make a tiled image, you place one image of each object in a directory, numbering them sequentially and putting in transparent placeholders for unused object IDs: 00_player.png 01_coin.png 02_ruby.png 03_diary.png 04_trans.png You can then convert these images into a tile image using the 'convert' and 'montage' commands from ImageMagick: # Trim transparent borders off of images. This is necessary to make # nice tiles out of characters who are 1.5 tiles high with a 2-tile high # image. mkdir trimmed for F in *.png; do convert $F -bordercolor none -border 1x1 -trim +repage trimmed/$F done cd trimmed # Shrink images larger than 32x32. mkdir shrunk for F in *.png; do convert $F -resize '32x32>' shrunk/$F done cd shrunk # Center images on 32x32 tiles. mkdir fitted for F in *.png; do convert $F -background none -gravity center -extent 32x32 fitted/$F done cd fitted # Assemble tiles into a single image. montage *.png -tile 7x -geometry +0+0 -background none objects.png tiled-0.14.2/src/plugins/replicaisland/cave.png000066400000000000000000002522741260670167100214270ustar00rootroot00000000000000PNG  IHDRŐgtEXtSoftwareAdobe ImageReadyqe<T^IDATxk\Օ[qܙ3j=Cݶ~*CK EƖx/A!! =) $^ѸʒR!Y,ƌ=37b?̇?tܘ1qs'W:''OVReĎs{}ز/lq>ڿ>w ?Goh?{}]?tM[7wO]/yy[yb{{}g"]׳~g|XskY:~C#Eߜ\s+؏_o]:zYсۿǓ/7X{jLߞKĺK}_^џ^/m8;v]ۇWzkߗn_1Í_\fڦtۃO}{ }=#|~mS<_CM_Nǁo?k-|.lu':{~x>gn9:|im sW֯$_|@?yi`yzڴ_mgs W7~={w_^k׬u}Nq KU8o֘h& %"zaʳ򽘇bPܓ!x{0X ڑ6|aQx \d(ڿNyF +ߘk|پχ 쳩mt /L7/ |<,FBXu_!}-=tO>Z<; `,ƫS4xn'=T_DƭbA s-o^3nVA5x\YmEg{A0~H/{Ksh BidQr(wYz/L;b޳Cc&x?מQ7|'&o\MJ `gnyi~|CgI9͎]7>[ 8e3-X Zge€>1wg@_r^O:P&}'ƒ3`! }~XBijk~!?e?olAg?ǿ7@/ǿel5vr >7Qw ᦝ>硸7 }$٥Y=M:d8P/F9G?l43?}&a-oΘU8KL"`nhZ~'.YeCgEBQX:_97SEǞF@e_b?طxAK>Ul:d(c߸u>Ot֨] _Rk6 +o?=n9g<{SǮ?#鍧EnY=y[ϭyRkƼK &:0(96>H<1أkݚ&s64Q:\.KvqGoA?Vk& sKnzE4ebpYl8q';#t|(hA Sv鳘@.N}dD?:b3)젘G=Q6i8K>C+ᵢKRh-)D=!U[urs&ޝ^観Cyv^NX]Ӷ F (04:!p d{rz(Qȇcހ>!a.EZ\dn"dgvB-$ j`,V".z=4Af< L,ILa~g @֪NEg<$>sp83>;-'Yxf,1ǥcOu\ϵB6_ P]UcN58ew(~Prk%Eқ?]3Q*Y4tgc_]/n>ŻR|`XKv~jw ߔy!8Q\W$X"^&sNg($M n0` >>4Q @AQ"R;ev\ (kѦW/0n0XB|_ro20(qhJ{M@mw\مeGo6caK τ0T O e`s)`zvEZoriՏA?>?Px_a>gr$„YL"Сh ;p9$s0 T c,Zh~7 \߇;.}e d^-3(!DI-~[E `,a@X[#/F?YП]pvvzX`x=F/,:ќg@тg xlV+$;.wcIk"_gl|ڟgG׬+CtU.t]t_FW /-o]l5jK ҈ϊ+p#e@FY= D5 J}XG} nGgH z5.@IU b:_hkg+JPd6$əFl^7Da^fT 0v|:wMiNH @A ;~#7_xv4|GcTI02W( ~?>}gsxѳmM.[0Ӣe?]q_G߹/o\97>?@/?0c3IC;@);KImPp|3*u;Ifv]}b%KjBt/$ *I@^6ߚh}04[Q a̰W\2/U~)+}uO\Ed;s$B>N@$}_͗}ѓk myaZEqi^lԈ `lxֿi5_nfgDw,n*gDn\hՖEё+<|I)tl:!nPkiw7Mf w~ls!- 1Owq/ȥ?gb4:ᙵmsqYVؚ5x6?/|C(@^-@*}ns:G/'8daw?;2ߟ90VYXhho> Z9mxeM 0;^ DoGmD[6}%:[ODGw.Na`ΓWz}amw`vYNT8mW!Ztɲ;HяC*sgCºUrafUaB w%siN|2 !P)L*+&v4wse3q{5.ዂCneX(f@5qѭ)ߧ&P< R^D)BXʾils`744}& Mww}1iύ&v^=#[.zmsg&:}wDO^m#PPܬIW lf6i-m|+YN?qfg1n0ɾtFq%{gL xmX_p3!&jI{5{ ѺUf-'U L@'NRr/A&OS. VR#> kDu6rh|עWSܳu_^|{і~;:g-^o.^Peq5ڙ2 B< ' P;Tf7q鬭Ƶ/^ $ptsM2Qe? ǟ=uI0@NݿY,ⅳ,cU h~f?7bvj;^nzw5aW|lP `(;*^oRl[K 1LY"q4P ѾD~jtrkB?']ߦBx=ҋt-Lυo&y3uW]*jݻRe7Y<{cMr 媟w[`O"kΈrϊ.?}νOs\{'Dmw,\- 2C21S(wzt;e4S&VjS6H$g)[EB}k3P32{  W3NE_o`ܓq܈}hhet!}5qJkA͈3_p^n7%2P*:(8e<4#3Ղ|yŠ֒I- ÿG^|=,1'̵_)6"_Z,H Diҷ _N8hz/|1܎uo;&a?ڿaA'u81xgeE4xŧo\s3o?qE85M?c8q9W!1PɦKf<M= rj|}4YH0G=SޱyFX~{|$gKGzWrͪ2 U66=?jYbr?gLZ4` @`J#WJ]*†Eil@YdqÖ1Ϳ̒ ̶R%ۘQT#_5qƳ?s×Ʊ8Tl$gd|6N"m]ɫ٩%&0L+uk}DA- ߁5kb,32" M7?(pSA˦A:GUpN{.}&';cREhr;aSݖ? 1ťw`QoYѝ,hƓew'E>=6f|2z'27I{$ʗX.\$0/7f+eo%b'KUHF׀ &}܍01xLgl8F' ߆y>GNV*kR Β55fWy.2Y[pͫBc/s%[(z <@9WM 2 {сۿ:d1_a@ HmlÄI򻑜P d:KnX<PT0hE~ztMno[ןX.ыe!s9OV8a^u`<Qޜs6!^t&0 MH_#B \84p9Ϳ=\+fkQ~]!Yv;.?yp^w+TߚAC0לT*|(o\~bP]yo_X鲓bVdNI;`{{89hͧ}/zqE73sL9qFe~*^W P_@P>O*S}F ]yZf9&" e"S' J_1*&_BQgP3s̒a\Yg-8CSRN΄~gȅa\f,FY_H Fm?a]4@@qv/;9r&~O~~פȎon}@7r|hG:kweAnxlNϮψ~o{;)zphFOlFt`ѳP9[*ic8dž{qiL /9,7vZ=7FfΎy`E\b%_} vy߈>m4mDM}Es#I!?i6ӔlHN>("Khh3sӜ2!м.T^k[%޵Sg Q x4?'+M8!w2/JLctSpf??'`@jV/Щvewn<<=q>s99Il%ZqW9׏$i]U:P6ys睳5R֡Iǃ|EߗBLXvǨyENxnyچP!U@pmKv$"sU1b k@8lZ˴Hݭ+eU uv݋|(B; 9!YB9Q@=\$ܺ'͕_ea箕n7!z~W[ASe?~)Yv[8#Ta JelhMf}ŕ ˵L!s0ЧMʼn_C[ބ_>QB\O^9ې>; l3V?d21?:(yuܻזF4?>ݬ.aP!޴QZ(a9%'uT` W~7s_ (Pr%mP S$Ӓ&#d@^TEVLJd9R){O-鐡zgp0$Mf%շ-9'p?N„{àoΟ(ͷ"3 {n'?.޽~uS9a37!)+o CKOEs5lk$0DʇaL  csl_؏\%jBʈ@%s(-sJfHSIUKKm`VX}-4uF`lB1gwv0ͣYal܋ K/? 9ؗSn짳_+©0f@` K nҍ|v +Py/ XF"?.ׇN):Hȓ\UX90swsaP` (iS H+u@TK.PA D1D+ul팢e36;@mik a/ZBQd"}d~AWmB\>k6}"UY-[Bl%2 \7a)%@77柴-Oͷ4j b}UL낆aUY56ywX]3Đ?UmSB8t^F|7 jح-_-kZ9c9Ӫ6 kRYP2BIx $a{z: :f¤DlKfT<&QKH%liJB*?+rKr ͢u TQJz**Yk\gg꯫jd*I32gfcYC'x{/N'a@e-9q;>ccs@9Po`\d(`fڊ+{Pe˃$*L qZ"*2^&cߋ~wmڵ@?TjwѿܯL*kije^Xvv\Cs8)|n:dd$Vm>pOɕF0ĀNeFD&<֐ [Zx 3Ϥ`O-' ,"3+ %+G{h'!}@+(Kjuov)':FZK`?ӣߏc9lK)mYf_}gVqiq%eϙx>Mѳj_ @! _ێp;WgK~Kٸ4ZO}z LAasX 5%sIe.O88ZH2nYICx)tbSVf;&C/=?E t~mqx2i}(=c4p8@vr.a3i4*v15MU_&'!M)OϠRzެxrd3[ 7!~Ed]oLE9fǎEw=h^7=Jkk_FR?)?ẑje'yP4۟0Xa_⹧l;o >- NfٌƍQJ0 TN$lX)΂EPΏsU0LB"bK_ls4㡁Y惝 MCX6Uq|-T3؇>ó$XE؅ȣ[4REh #le}s}[rf}z& @AΏ G76LHπIXVDHq"b;{eՖѕEt¿i`tCuYv/WoV\tOE(JbÕNߗ8$]GۢNT$9 sV<3GRE^7|>_c@_ίf@x3PH1]!W٭dJ Ȍ#8=Jx0 ECxc€0ҀZAnB&Tx;'-Bݗ<˕ 0+3)W}V)) ]e=ctW ʑ%ȡ'IK]d,kf':V*rO!bwrk`Ḿw ,e<AǸ0a(dx΁0xSzXAnN.}Y8_hckO/Wcxhq]6c2zb]QDHDI?p|Ӯٺ/Z=-h F+wQC7!8(4Zc %[. Ozki]E*R?+=O\d޴| kF""A+ɪWl3d*|K*K Qf#5YY% dKuR-qi(*G9 TKrSL&zRjI[8؊}R@F@ $E~PB;xz݄BA51 bt8cM\/LR8FsTͪ/Y4%WnQ\CѵɊܑe kvq IՈ(k,rtˢϼw[߭)vVW "oDk?r,vh#K p-tZMywsȲWO*djĖZ"eBɆB8q%Za(F#P贫Q(^=2G`u 8vE~Ug4[ dԲ*x;*lR6!v ܸMM7^#KCo|9v(8ݰ}Y@5 9*dsk#qm #f_yUq U P29zzB%?I2 GG8uO,Lót @lK EVBG+I ~(r0|Ћ:?9wr@XL(!}~$ qjYе,<1<0Q̦B |&,%6hx$dD ŸNfm=Odd{1?o>?_aK)9`Bȸ'G2(ʬF1@g ^J2z[Tg4ub|q* sYdYn,^E ίEK؁zpŽ?Y ⎧_+#9BA_wiM,ˁ+K:Y[U~F4adj)+0?Hbk1z|sBI#>VB\q|]̖v'߫!aTЧ@*їCއ&2;ϩ]\C_1 .:gPSGP"RRaS xz$Qd??:Bi# `I Fٚc@Qy"y~='I?-Qm.j-aljǻ0kj:8~L/SG.ky^&Tůn~Jf0遭5Á ,1vΕ2u7?)JP[;&pf)AaѮE;B~eN@Hx"=xg)~>((@xOs%_e`]),5\J?2)Zҫ^أa95$R`=R3['Uw0/qsT/M̳Z؛;-SKA@ V [Rb!Y7~y B{X+@߅o5{m 㭘1ЊgW\?OTP«ʌP/좼hEʶ__@Yl[5 /GK+ZMW脾Smt߳k:*tޣ-(#QYeO)zEٱTj6K d=y$klxxW\gYϬr,V)EB´j,?Y-OyfpoC$<1gѷiYÝ ( NvA|i@ Hw:wbje W!gPh{ -usIY?D33?/7E;o4cBŃcplH&@bhWHZ\LP_aǽ{1 LPA<evV_NaOGtq'zYg1ep.`׮]՛njժl)}K3f(5Zvce7Q>qn'r_ڄY\{)X@z_ׇݜkPt֚O%\uיE" -_RQ1~i}¤Tؚsb3vE_׈։-/; ng{g3['p \ g,Y#d.OR|oe?c 2ॷK4wzqX Bd@ZP̰$i3S x[ߦz[peZNHldT) ޽;իWG&JycU$O/#+kŽN l^``QWqR*67ݷȜtJ\l/+3j0 d@%n;[U LVXrYeΧY&J1@xƭE-4<VD(2MaRNIŠuOD63~Tv c}R4MʮDS3W՝f87eIWK?gl4w0 :hL8VhLlYˠd±zvvOp@Y ׅ`xC ( $}bzaI(BK o.F4T5Qg'}(sp;WdMYA%]JH1*{ !+ |E٫-ub)8 ZEʌ,tHkkT[24(f^eڊM82e5x݆SESovjcS/oaR񟄶M;xsiv3q] =_2hærV&6-c,!GxWTahn: /~ORD}R$5UDV}?ifiZS7B]鼭Q8ɧl_WA٣M'4^dm< ZK(I# Tζݙ2yh/Nu6e `-5բy[/-Ad7&(g_R@4?hbeϫ=Я]͵/'"&X77#5$USOI݅U/c^aXs; D(%U'J$T,3/9/'F#fG !d||k{j~?a`Re#Qb@/sH`.r1x{T>? p.,0nR k.ƒBV\̜YQ5g0[>f ZfB23oAj&}[ŸJ)؇JXi ѹCmfM !s Lhl>s~XUCA P:T|49zQ wϳ5JM*E>@Yv^0S8a0OU> ϵ2C2/\'5,d2SWM2$z?Q?xFjJz. 970&Pcܐk4R.p.s pU0GMȿǜZ ߫O; WPPyNUdwJx{zIQ5 @YJD2볖%m2J3CLj64[y D RKSS<UBbTS5%\Q<[ = ȶ_B2rv*EM*)el:򬊻_MXGBIa(,b y3gi_%3A LŠ4R8"RlIa/GQ!{$ױMwi!Zl>˫G:aJR$>j80^+p!"7ʠ/ſG{ߨS輷~|}~ Phv P( P9<yC3ZSھt=WRP`mMjZРvLx7?LxX㷱-?pSq :k(:oCZء` 4> mxj۳vs ! @ga6='toϛQsg[[K_G F)K'9 9H_hi38ly)*`"`Q&vJl@Tu^P)\?a52KeÔ~ЏvE"1_2~_5ekƚ9]sW$1E6tF?⶞{Syɉ5M5ܣLN;( d^Y@Zvm _m4\WF:LO+u-(]ݼJsKbx <" h(;z֑c^6<(o?,:')oX* mݿ] N8 l}"`j ۳p ];FvwX XQErkgWزP -K,p@۰ +,f%u:gTɢ@6M'7r 0x-˺4Iu'gm<`>p1W7قfET?)jy8-OVf)A=F=6ņ K( E3w)9ي٤Vz o]'X/lR@n=ALU#cYRT~@IMzhDc p^V mY&[v^Vd%a/N[~μɭO~YYud b4a<=&dX+:12/<6 ib7 a0YeQP2˖@f p ֍se*ܥ20}{]؝e@U@:Mj'^f $ :Z!ܩB?b+E P $݋9՚1PN@<,бB䤗@4B::cX*`₻M(9(dS)}@xv`%_wDE2:({EYC`xF~+,e7_4b[1r+wu"'z1jِkn$|ITF{ig'|J"qn 'Rgqrڲ^u4@%h̫2eY̫s^<Yٴ!EF"F?Xy=di <bkK` 僕B^:>,3 jg\;}^󿼰B+0Ro@ׄj(\]@_d(kP~?JD8 Bt rkhJ0?J\hY5qVɒDFRcuA#G+7K(1: 1GùY X7n0DN a*+upWQKy8O1p %d/kH(DL̨M/Lxn͸a2axGя00͢3Ph ݗ۹VJ^]0ԏކ/y{ iuGU'1˂\Y_MUT^Eˤ>J<_H cGYpkay' ZMa ~-1@( 웅 (}*^^8KhNut{dQ?v7- "QKV7-@~g,ɮ|]P<胀t6o&U\26"qЧLR@`6'TH:drO"ې.< P@ !k>&ܷ`[roweqs1X%['@*O;5xV 㨥0L@6QE@(U{8QR$!8u?ڐ"[ɯ\ M?Ddᑤ&:8n^y}R FKIy-/܀ 'a $$j2ۅg"x`@$' P#—NUbZr# >5sj ?#DKNyJbCeJϸMoW5R<'@&S3g܋gPԆvv% B<*l3=t oE5qbS"`)iЂL {' ]jY` HXT&})2>}ާ^yاK e+pX+BgEav́_gci͖R? "! ⷵ_&r^J3[/v_QMYQ}}Qʟҷɬveoϙ0rw KPn~'@rql-QFVH("NZ 3bHQ(h" 6V-B hW$.@I)Y]yt<`#ؕqOnN#(dɩFsY&Fz+>2I!nWa0“ 9b|`Vhl8#-xLt}ǵ3V %*Wd4e: NK;-Z|ar~ 8Y-@H[߀9ka~L+yl"^D)ZP̱$BE[3YkwEP&}f}1xv(ζxOumiwYpK%n-]4d< Kd%, L@z ;;- vYpSyus(%-  ǻxG>fb1a|J[;vec9!m^D  }d$mjgbGܱũr5ߛߓzۓBIN?,|q{% >%`}Cci2i pR|j~`|`*b gmAݲ|P@iVw_sz jn]QyQת;_EeҗkWu $~AN>kX@ohʺH;n+l6tux\d#* 3IЄo%ӧ2 P:{tb=uVP a[Rٖ>H83b,63ҵYR zN ˣޗW!PB"*g͜#Z}iRߔ(:^xS|N&ST]_KG/sb@?{ݨ7WNL*iL$7FMaYŜƵg~>x\[T07Lie=$:HS.qaff$ 0혅mrr+;/z6 ,[6?س9vRܟqRJáocɯV1?9:DȷG:LJ}Z֚o t N]+@&k_u4S{p;֒vlS: {~1?_{坥NR]eot;.I~s? 8 }8zwLj6#HX*jk۝̙|.-Լ8i=MVQO1rHVR7>Vm9`ק٠oh2MjU<`7VfO;?k5 !MT ?ㄈ?ϽspȄ…9ȵDUAkKQtBfv"sRcgw/ᆟ@wAκ}X/\GA~tq2mKꈇ 88d[#:]j;urJv=]p,Hx z@}- 4^ypCy ğ#]R兛Uf"*vi'˵)k&V=$ұoYe_Ef/Kwtm Gt'Y/Sb퀕G!w$"c{@ch `–;@& 2#PbCĔd-$t!0SiY/d7UC^%$;H%,q%fwB Ї&BSCzU2#5XVQY95Ϣ=hvI_C{]~+/s);*ׄNIowd(9vrzY{osp&DHɠtdW1#DOƕVN@}Odgl&ů46?:`pFE7=Q(yBſ}ƵWN?4zzWo{G}4ڶmxif7U<ƴgzB 3e$ >0*?~ Y,p+arg)@ /_S#QP+gIEZI\339cvJ`@C<6BOXy +2%gƾ?Rі ,}xCzl_hUff;ogM1H8LuAVA{)DR"%)EgeοB0cP*u:JEϨ#@[Ӊ{ MQtU3+ xx&Y%eٽ+uEٝ[`w:-,ꬳK/ʙv: m`*XX-zWf-_J\ω7mNKG\W*d&? aZ<,4qzm)2e0釣˂T7˔VH&`IO_=p}tX+.JZT&9 e,Ч<;'E-@gj񣼱pZ(~oI/;]G< x^{HvwO_tE :8([)vYy<媰gj炕LrQVKKUBy@Ty*0RU9^a>9&J=P^| UswlAزAYu:_>s,P O[>jJ_ ]s P<uRp`r|bKW[`C;8ߵ p7:_s(,"lYNukj=zt8wuWtWwt/k@_ ,DU^v;P yCL2sO v\68~Ӹ?Z!L6%ma`>дgEƿ#$GXw2(U@a6&N* I{@AgR蚧:SSWAYG׺EdG(OP}tP Vtz@peϚଢ଼+?.lէ6n8]!P[9xfM2*:d@NŬve3 &۬8eGgRǬ8w{{WQcvYgRri. Iltg,;[Ӻ6Y+ #<@,6^`!wa >GQ6ҷbۿZX\J_(fyEQ9?ϵd5| w[6M{>qɓ`;.,٩D@,>д#Lfl̔={ЩUȘkðixQ~i"fuɗDMAYBB?pE?K[[W"_P 8>dƿٌ'G;?ܾ:?cyߔ6́ryd90IHŦ._ϯͿ"|E? uQ mG)@:8qS/{+@;pɭOD_kn LZJQ;`hh̛,[Ȏ @!Y{QF3ںJ۩ 6?*$Ⅱ -ү+>ğ3%صS}v+<*\ggpB7vs߈; ǿ%>MNXLc<-%Jοe eUsԁ?MMf bJjʁ5 01تG(_Q/ܻHƐUe[O{u'?<ӗw?oP+e)e7΅߾|}|?Hƕ]c4ߓ.ϿXδ DLB 'T'ߴp ̏b|a;U&Wi ,X6 hɵʱW'Vm$qV1ċҷ){9Z3vƿSW-L`# B I_m=E?b;grX`sv}hP!ԊiO,p'?iz7>R P?5 򾛍(7#\f~jwY?O;/ǭ,3 *zRS8v=,9(xl{,}iFL ]-5^TBg@ UY4q@b0{Z 2bQXYʨp%sb`kY'k O,ei$2c1KG;*4\ }@Yl$h (H!}g;j(W{GfH4y ѲOYffy9ۢ|(齔rvE:ʒL89PbD,%* ADI!ͣoc#܃khtOgV ?ΌX?K(p< LJQGoOPXTY-3(nQЎ?`?!rl=YzC>ʏ39eaSxG5%T^W~ 6lgc-,"w߷ BRz}6t`уc|d!$yL8 1ol __-Z|e[p7y0@0"dP";,?*G(5'Rvk#~rĜTIfjc|Q2Ya|{*w,~VX|C8%y=op}LsW1Z`3ʼn߰S{P e%'z΁YYGEY@s[.3XG}.,<"',@gXʑ2RE(Ƒ? mkBR$G_kN;|>` =k"X9>:KbuAϧMUក$Lj R `Cz$g/EnKt[ _/kTl%n;Jd[g!}Q_ѧON;~;Rmʌ\%ϵO`w n?αeJJ^wRcƯ`"_}"|h49 r톔)̆;Pڐ*y,%ʑ^(4~kݛ3°4Bπ*}lH7 <( y _K$7TE?wiO^RW{JJ?[g+ݰGVaYA e}ھ+PS+4|*re*L3Ϡ@}6ؑpA>χKH_:~6_~UHU P=1-c[g! ߁`ս'8uU%Q4ˡ*au^C8M~{,V"6 F}e @s[G}Hm|Xo^UQRVa=m ,v"L}8}.l~CU#&*@YˤyޑF p<*;vbijC;^tHYO?7L@(qLϦߓOFZ94^9(K :T'_ѷU}#?xlwP{o~}ѩ"@/>"@>m([6v@BA?@0SN֮'tR CO;y>vo/$7\ҙR g`'keʳ;V^$)2_E/';E7hGH“s Y{ar^dO^Z,<#k*<Gt}#(և8dB ڀ3f(O? ?L$k$+ ;|+@΃n Z\/PןE)7&w9)vvCfR"U^5o|pq\PJ#y`JH*W#oCswh64Gh7L$Losa,:;"hv΄U⢘m"k7y^QKPQ\Æw-dkkHBҗZ艿s Q?I2+ߘF_z+~v4>à4h׀\6+r ߽F9 S]c߉VUg? DZ>z{e cz[$e+k@ J3ܨ2Ya7b[[m~dBi,/Ūʞ\{-J*uNp6iT-<4%MIߔv_eЗI=kg.-ҟvmP%dP+TK} ،r8V w? 嫤<:NP]=rQʞ X?}u pus G~Ay.rrٻ]+sW?EPnK??>&pİCZ=0 ^nW27C~o_,+otC['( H 4yg,\&ZY[;E{4"_ 503LʢC_d@DdNױ߱sUZ!Q"E@*y@ ǼZצYܲ|c7{+5 @:$m@sC`9()+) 6͒ BcBI;rordzUa֟ZqşߍzmXo=۾/?<8波xndQ5”Ⱦm +Fvʷ.mrc6ן3mB`݆~)|%Zy'6?7[4=om]-~}hӽ_nhwգ?xftߚ{@|ޫǓwqt>,GA+iNaj'xW><8-6³U%&Py"hm6 gEHaJ rb7ɸXY [@P zǼo'gǠ/Oy Cu /&m׃5᪏a>EpFNs{\@x`>(o5{aapj's@~ʟ  \]E"G_߼uk}tӽg{8/{wշooK4ޮUUvW}bzSkO^?xxyvע.|+l!S׽;3oFjta^xhX~hSVs- :o~_ W@/(6Ρ`$)z;t?vIUǰdm9"e݂~}ULKasbk}.A+j,tL>ݣ_/$CNG&-4w 9 _E=?J(g[_ c[gRfN\]T-ٽ*z}tӢuWk76sp_dEoQtqS(q9Y7MOwtٱGlbqۧD.`.v|F{燝kju^8p`{]p.YbI,_Iq0~*E8y.HM_`3Q' j)Mr;mS,Sq'Ξ9Y)J7:f#J}DVm? 5秎3Zv9QSO3"Jn~@,Ȫ&@8(3dLW ʿ>yeI!TM@X#l~Kt-E|0; s.8t`', w{+.nL>v/lńd=`QlRyr/sqa-̆ɞFY0*aJ1JI^mpMXDh0&Y̑g;ohru(7?)׆_Vopcݸ`SI?<GKm`Do7sx:O?\$fzk]Zl[-_YpF9j#B1nz3'ɣxq+0&Գ\}izlq̣*vyǼKfL)ϰg~yQ9\!V8ú)ǚl *=N}7/v`̈́ b|?;Z@{@8I+DJw)< PY8DM$,oc1*`4g`M#(\$l,|eS:_`w$P:_ԾԜ-ITej[S ڹrƧ˚e0!X4Tf? 5ϱe9w_> -Y -rBV h \ 0쇣Lk8aceUQ=:zK ˤnļE&{ZROvsOe@?+#<^381_I;v8@I"ʤ0C[aLOr*LS\gk*yP܍K㇣҃%! ˋ >4O[L ^8z2z֩*z*Eh1P=p8?D<"9}p|W;VSaBeoJPPgFlsjQ&~p )pRźsnp fSUNkNMt's ^~|gcX&32;U {Tඔ-gp<@\]\gkD$Vm]$'ڶm*JȂW%61-Zcc_ #8p2B*8@<_-9y*^ 0^Ir$R%㯊*1)!XvT-Ρ{6~NN_ng7b}CG $Ϡ]83e}T4y-ıG0u84툍aflWQո _^8$J Iy'E”B8!)2]yoޛЋxo\d AJy#םyEE1K<'m)*⋹?n~#Sd,?Ʌí,V5\ϟ\?C+ 5#=7ρ\t=]|+)VNDT,"Bu@OH?M. /i&b6TPn'X74EJWzh (yN)Ik!et%[^7BHd^c&>!Gwą@];ג6,ʁR]>o_~ I7K5#=q}0xfuKzyc.`7 o"y٪*/_Me IC})8iE sJ9 QKI=Vo#IdfX ןXDq]ݴ/qj>a'l1 zz"|p[g?d0rxbMCkݕOպFx`gGtgjPLC$9HR1$HN_I d.?>yqT懜$tE,R,./3pty>H]#W9nwr!zY*>]D$˻!n&B:!JqCǿ)/)P}?x6ڈDZZ"##0W/z)]8Hn7<4` @* A Iy>T?).ǝ޾4/f@4R/>2)u\-< Q qt-+iƯ;/E\3ϟTsg 1J'&&8yct[=b|./<}E| duumimZz=Rۺ'" oDZ^n+ ғ׿ǧْ+U6'h)"2>!_ins폎s787 _ϟN>,gG8` Vi1^ Ǜ^GRxy ujy RCzoykr9$}}ZX:9_Vsq0޼4Q_p$m6R!lۗKsw-]nS7f'?A@EZ,G|-quvqIl|Z5a#-7>~2>Pᕬ)8QB .`-~{jbt?NxO`_$eQˉMzsw翷oo+]@_ߝʑ*,?tچi٭Bse3`Pi[R%`<4Dr%ܞcxz/?bQrë a,~ l3%Gwl3I1Hc #{%#Բ1<}0P2/8ٝyļfN%åG Kr݀qxwvL4= kbuu=/<тĬAe4翷oOV/cr5X@e]YHG:U`cf%f9fs.54翷;/fNTd|lP(bv F q:>c^vi2ݬ ` l]L_ʲ'_ȕGj{&."S/'Y"?mQM51D7YIF'a(/nѵc|_Ԃ$hij!)$|X'̗i hj'>q !&w| ^3zPD=bJ\ߧk_#qFZ'w?|F.j ') h.$)z:lC6A_'O3Y$b^v5>sҚ^1KyG?0H:ӬoG_:pCxuh`?\'1y+b_qz7ݦ~39KӣI#r9ncNXtq2ߩP1|}cCBqK)c. D–h>O{{˩7￞LvlV~h@⌀6Зy̌#˟f|8'&t-,ϟ] A|ľ!OO^(ߔ;':{. 4y2ҁz\Le+l @v)T\ر6,?͕._I~s@<" '<7P/RG9yJc LS<>_%H]cˋ7iVUQ\<_O!0GT˻e3s1?j REn?4H/=L~2=֜Y<66=z q[@kwR߅T(@4iyf`i*p $o=MlQ̪W͗)s[w#$7;t@ΛW@g\w \$qx gח5<.x/5—i6lAL\믎Ө(i_/1E` ԆVoG+=c u6 3g%=ȴ?Ϝ>ЅG0ɤ X7jT`)8wy,x/!mmmx/p ~!W\=8taׅVp̞=Æ x" 7aeJOf0pT##x `b"O~z 0# P@?-KNSE=`3j@ r'!7vҭ_o%,Au,1hb޿/z|]`Y'S.1c"h>K yLӟv= :GEG_( !ODb,ڭDrJqBA`H_j&t`522\|7T5Y޾0>5\`t@O(s'l5}j<ҟA9 _{DS:QA&ei1+sCdD^,T ,C_N~c2),/?l/SGOx%u/Fs^i 5g=M`("fUw"fZd/N6<7LqDmjOzG4j:qے `~(fjErd/j|y?O IWâ=EO@@M0&Y8 o38y$T78p@֭[bŊneٲe <=|E~w 묩0}һk2?'}6}7K{`7u2w c0>yc!] Ucc¸ѿQ^w?f<_ǘ<6yh!EiouR]ߏ'/}swm{{&䙞P.'O^G̢Al?gm~MsYQ}#8M% H= }X.c,Que-[~c)O "]G#Lu| йO[Ctܗ9_Ȋ̛1]PI_H I}ǧ/2<X0}Է !p/H ݪ\ot.z=EoK}Ϸ$ǀA<@^{<Ӌ!~r_<o,!PR7 @"z : WA@}F-c q܎l>VO?^o" [0XCd?W#G}߿!j%yφ?+,i&F=:ab3!pf%64< +ENx\$~P[ru_7sFH (0߽^}pS*BL4&*kN>ә}cU%"f}0[_3pu / 2lV .#^eyN)9Y=eo//fT[ں#I6 V!H >v${xŰ8(7Ŀ+?0}z"V%z&L?IZNtZTq 8UQ Qj`}A8B$!rBdx/KwҏǨ8 /'v t˲z`3W"ֈz|m?M>I'| $@`,QvʾnObHI~#fg|>P($9P⥤D :*Fkߜg&XsJ)e2}W@]^'2{9^݊`[$ǫk\ee{#Jܤ(a- .? L>E.;E3*jQVWy;~?5@;j"KD;1I$5 p,ͩSjEjƏ}X|=r$~HOf|(p! ,!)_}Ib< '^!:$ :JpT I 3e0V@I7./å4*}]P3&U`'@ :#4Le}|o)Sc:`A_ G+r8 /EUA?>X%8L/¿vV4}\?mCV4oF"{ 9hLKuo;kW 4Gt/O! I0'Vom}|˳~:_w(px 2<`J/OS:A]<iޙX =!S;ד|qvWq :_e_Pe/Cؑ,Wﳋ{,pPc"/,y1-د$>C6CەhS@r> dLGƈ4ւ}_5\^xIvB %@/,Y̙9%8ߏ1;X]P`_$֞u3J"6/EVԼ)x$@ǡZ?E xEq },ccrؗ @Xe5+.SۂE{RL\G6Lf' 3){㡒[aˮ͜[hsvE8ۆ}M7<~trʢoÚeCEjn͌ S:LB$SD/d ,dm)6m_+_<_$i~7>>%?(I6@!sg w5~/zB"4dC,ձ:pbĺT%aj Jq:):#spFEd׋7x]eںS3=i񼸐!y]/\BUn9vBuZ9waKF]|-lL `í+ͨgqD GQRkۮʖb\%"xaB@fm_O6I_A}{+EӦ="@RB0dp')gY# u@|FA5K'MRCG1ڴ3 ? >Wcp[xiE?AIW 8 n)tzOHj1J#?[- .$A sӰ@:Bl;,%oǀuk:wgzӛ􏙲ܚ\\V i}_bTD܂55q6TGՠ2LV\Y rmjLIžOW@ӃۧbG]! Jl D1w6c"B@ 9*z}[Ii! 3 ӱg[|:Zf4 bD6Yd0 eZtEz P8^G~<~`n Dfw|?Ob"1cen:V)W`e x6Bv!XX*<&wX/EY`1>9Ó2%+Σleo+CUt9l1VآkQ^;+l(Ph:݄3MvF9\ǩ/B|VP͎Ծ%Zc^32 ﻲp{f}3Ј@E, nCfAB~Ȑ wzi(m"4# /֠=',_/c\ fH\#ғ|$/@1~^_"{A?Ρ2(.^_Xy 7@e`ݡLlTÝ; NF O@gzO_sT/|O ݏBǖvX)*v܁-֊Z$5a_3rZaMQmQ`wζ߆+Q0 F~ahG ~oV# |H4 XdVt !tkd$rҤE  qǂ?] 2 dBz] @@݄]Tg]$L"u4x궍/~J_##±@t8nGG2tYe*LPd{ 3=iiTEeolB(+Cz-eHrTŔ.Zr G`׊oPDq[W V]đG1- !΂ Rϟ et t `}pNXL ` M޾#up|3l4~;*"]|KAH[ l~Lz7z+H|Ht@O1krftӁ49xsy/fazj|ئ>#fb,$Ƙmpݍ8O@gzm54; 8E7P ܉(E^+Zϵޅ6t@[z3*V'QώjTBj|V-e:~z.7 !Q>?rJV.`'o\]b7G?-.{Z\®?]h-ЏWh4SL."Fnߢ߬ %0hSߟf: #R?;(E8;~> _ N LlڃuM^[kĹGQCq73UT"h4@+Pa>,nG܄mO lGjP{ ! yxѢw6Pd>:+ ɟ?- LoW_CSھ;?4fLE #>i_':` :>c7sCORg[f %w Q@Tr:prBhi }\')& qu-m|OSץώڌ?~~JeݩڟU S`"+@RS6e#83օ `W2BZ0/62[YM_,-6G]D ʷrYbԟ.C]~5Oף\ηMڡAn)/8rqPu~#m渾loHZHOTA2YB.c`ÇSx^^OGFcO? žvS:6VM5awgδ1e`̝1]4(x  '"^G B}#$p1u3q1[D:bB"@tiFt @OSohJOi t9 _wn [11#Xo 9Iv3xYeMEfaR&oZ;]YLGW.k-;.(*^xu'o~|ѪPކըlCWB|ފŹşqW{.?ʧ}  @s6FRO D 0`Qr# zX?đ2دOS?|H{g@ {'Q|jShpMi^SIsVtp^8YiCM9XtKI_K06 EtI. K]J3OoNL Zi 0pV Mƨ$KO”dLoV gYPIPN*f[RUSi*6a4ղ@Lߎi[[=噞ŔzҰIͨcCy \OŰE'k\hGF4:6 KQ8ͧ`ͱ8sx{"Aȥ%lAl=UsW19ORt_D{GQ)4k+R43_E {,܁x<,;pPD%Bf?q}s쮼!@!5k?'=nEU=s\1Az$>tP+t q_'.'fzFH^s<%.%h:!f,P?| tAǀk0T} Ǥx'=)K-`{DmXHK8E&+0=#s21/#~*76]GUr5Jy@NL= {rϧɵÞ {V ocxO7MOS0<'A}r+'Sȳ()p n$fRqa)O1-- zÛ |+ =E\ zJ#_z q 0L0,ܼo d&`fc|6݊;#> @j+HL%>)' %0#6Ӣ1%" 6m%OOO]c' 3دz^5 JѲ u6Wzf}rCv_B;j4L ǛX|w>wWq/(bPm7qqey#s]6߄&-$ c~j@N l@>}أЪ@uϫ3a ɀ(@~Z(0f r nPt|i{R"WjU~@ܧ~CWjsub&z܃ C?Eh# 3)};f'nwNOJ4w%!Him؄wm '%cYInF`^")j_('&mہaW++1Gb†5xB<Wm MjįGRImw=zE'}{Q95+p>ߌ{|NɆ:ZXqg6wJH1>_VdYY2fv4oD:64lFoA~  `  ;8 *@76_ž@՜] b MXhOBt#bB'H꿟Sd}\יh2 a #cFOq?y-lѢ^[X@?39X/SeD8hK&+@ӿwf2fOZ:$+1FbT !aAxC`<発# z+JtP35 {?e Wp&8y_b%c7\؈mnѵhXaG͌}T `K<e;o|B/{r52,;XAӧvdl vwo9I R }x!.=fxCJ ̓&nOX3oŢq]`]B&{<&|…Q-H/pb3`&#z!;`vp\e0WRa&f3 u#Uhw0,wQ8+7 Pz wP\dE06աj_5OJd%_ 3\ߜ&RrNO!hfС `O 5i?] ?Ν1F 1@P >ݮA'I3 ŪuK͕ * u_Z>в>B>z:~uezVE"ᗢ@z X' ksSfOJ'۩>~9JW7bC #YDM  qLKd1d2@v8@F*&[0j[Qgzd8ߵԒ+h-nCۥh)l-ɎGQw7;ڲvm(^9'g܆C+F]M\;h/h-jT Z[и &ܜueaWY+l5PcAɇVnzѰɎ5EhYqgs)l;`Q5(TaT,qvW>ϋwu YGb_ro ٱM$iL*pۿ >E W!`}'KڟY\5}]1@ @$XO{=iΣ@:"{fחJ9N9n3AI#>O}PĊ!޼Xf}3d~n5FGl‚h,N@ȞdS dw2hUo": e!jQ@If2q ̊ىuxrLXCWcE('()O>1!e%_GQMGźT&TeT|gZ3jq? 9,yЃ KQ[PUӎeH\-h׊E6bM+ [RûW[==zY^7Ϩ}o޹bSA.tdP<+y`6 `0ߓb_gX'.7#Vhif+-: hR+~\u>~]HPՀ]b]ZS߉_ \#nmX)X KbtE|ȱ`i Wy)JHظς4J!lU'߂O`zf&%a8O:gzd8~c{/PnlԠr }֝RƳF_K 6fd 9,C/\Z.rhk?Ռ\Eд\/3gWtu-D#]nٽ ;`ÝWbCV}qڌFCM;ڀr ) PSt?9f|Ic?s4 Ic>  y<P 29 u&G7#%fЅoVyw&Dup6K`7wY  p )A-sʩ w^/˃+1dcѩoZ\@Sczb,|0~$ R0GErX PD(Iz"$ 4'Iu3Ʈ U n-[ItLLJ6 }ނV(QtY]h' .{q } tgH9*=&9ψSS1C yF,8G.num2mW0rՌP+J\G7! e.v Q[CJc?Y뚃 h;Ҋo|_W}_;."uQ{e1e8>[f+<x}3+qsԟKh8X FTO%W܆"x\%@ P_|9,|:s_ db70sze ́^zw"Vj#t 85r@?fZvR RKvӈVzA^5{:НY_Oct,ݺg7|u1xGyJzYWW,Ǡk0=d!(;A*,]VǠ-_ٝ2fXOE) VCq`I1$0#Ba֭H`DSmn1laVAYYBY;.! eQ:*rPt-u_[o9Ó2q5ߎV崡}W;QAx͑ZF`id}} mPv)Pj󯣭-_CyT #ja2ą|0=k>$HErm VCnCS@@aa RP@ r?oKm ?IXXM69z-, N|X=^oQ|~gsg"K! p19#z"@;X- 2օ`͞DߗeX9ɘIB04631;;?K24O:{Ef2Epl]A|~hZ0'# ,LΦ~p' 7\DÙh7qa94iBYϐ?wcM 6Uϕ"ZQ&7ǗA}}?}_j!K)D}., g <b̜i1}|iPקSR29#01< QXE ed`lx&ST@Y} (Mh4p-Zζ* %l;9+FVTQ0=sPTۨ>XJW$T%ZB7@f&%BwiJQE-Z(K],H)Z^vPwPEvYz59p q>Q=1B_Hc?MtHN8YsFj>I|V@:20`0g_سm0Mu|bz jP"L~G!ue,`*Y*#`D<8'h j`C=O 1= ?¡el ޸DMhX}p S`;$`A@+"! 7uutb @!J߄Q!9~;4)ߕYيD'{gr:^GchseGڊZev5.}.ym#WUxy&B%lobo *ra-Cݱr |іׂ{{jQ@V[kPu-Za;d yU.83PXh:gj-n-ц +n?2c&9PWo_T(@V1 >]H|3 z#>|GW$ej f~[W* Q1/e`N^Z" Ǜ[086 ;-ެ+  XEҰڿ\~eE6dZ6owfxmق1XNNxnyѺ#.Y#eh9{~3"`Q;nʻa[]&=ƧByv1n\ByF1l7P.kv[q/ vGKB+AJi;]oSiW`;7pf4'HR' @'_HW2.u< .zBfzj$zZtK\E@jB(t 2Y@ͩ& 4 4w\C_2wW.흁9-DBs ˔)?Lq-،9Q 5R阑-LּpgKN-Eu54^B6OC~34֜2K¾ΎKsOBqg_`IQTih m' ihVh[gFUfNՠ]F}A9wӎUz <_;QG@4.2!V Kr8hEaʔv i ht zE̦} MPgT㧘)5+59>|:\ t .)rfZ&k'|z9__~'j+@ Gٯ/ݦxgm[a Xl:f76n/"b08!lNA,ߝ5{S1`A"7~'c;Jtʹ/ͿZ:*El`/GК{d#8%Ѱh G`X  3$P&v)CwgYۗ Ds ''I@: w4)[ctd8"c 8x'DuƦmxk{,Ƨ` 4d#p9(_' y$a? @`J4%b^r<90; ^ilz Eje}m krkQwԎoW'AsYPư¥gqb^XE6XoNU*F24VY]P@~77]f4*׸_H@}4|a7@q;Zv7-+|Pu8MkחƭCE!VGKU? @q%hHW Г v`ĈBL4)Jc` ƍnHTNYBt- @S.H@rmO@3 %5V-#CI~(d tB\ <.N|z U_-̅{g$"K l13xq3!2ˠ@!+0` U`pLwNO[laaXӒ,ς5ҙ@/NFHVaߒj|ElQ ;aqr4ъCI)4Ljct4l}( %Ͽ<;}%WMZP_.3 wr `U]49P[z\F|{k|[-> ڏ|FT@ܻ~6|k[[%9x[Shhƭy7\؂ѷpf4,9 84vQ pқF)C) (@|'W@^xc֬<끿?DRa`ܞ2+{() @3;' e<0hJz5לnvv@ˀ b's)z5>y0v䛆3XOjCM>-p|}3Fbg ۄW6joǠ '"X:"g)U?:ki ȱ`]zCHEGn쭝`aN)0/%3-ɊH@gn*I,a~ 8|u,K7h8֩+Eh Rpr'R jUmTT9*V%7'AۡVXa/T  ͗[`+E"woD%Z6lG+Uh܆+<'Owר;t-_l=_ @BpG I4Ztb@RXi 3fBi tVOX^"`?j'|َ c .25~HUn"Vǁ)5q=%S3. >ߺ+@V$S P )jLd)l"@öl[sR 3Wv` ?{$ՙk2㻇Zx!Fx'lwEy}Uw>b 'ZBV!0%nػ1wvbc"vޙwds,y"HwD xc\u#f۝Xl–vr{(E/yQ 'y(9Q׃,~*ö*ĹaeS#Vy\XnwanYcDXGԯ < \z +˸{'#iguf>5~U _9}_uJDK| | 8q \]ߞ~vۈz6zǙ'qe?r_;O[>CqWE_yO>šWOQw._ęXpw]™g`4b#0Ɨ?^`g`Tp@Ss]2~0̯ыi1L!$Xd0-p;.DT=E[ -gG1:3#za [-QyȣCyc`y-g:!Q9H->RH? Ll*ǢlFGxLRZ`@1&Lit`vc#VljN7JP*{HkiB݆<&2j 5T!Qo@݊^5 | |p32 ى>Bׁ8c\x+\ۍkWcUGНtX t}ǫ>O^Y}$ .t빅~Q67۸M\+=V?_ *73m}ëqrG1+g@5|nk=c»9oೃ\POT7ݥؙFo57߸K.$w?E\E7Np'] tǻ_^k>GQu_H@(Fv  g8mZ`kF,X@(S*hmRJ[Uq[`s9 G]PQPU@u%?<A}P@g&miPt$.EdKUjcgbՉ"KNlhmB ;p Մ쨮Ca`X]TSMHlw#R[w7۝ɨ~1+'|b>EU |\k_>oW}Tc?s ?k|s~u7޸W= o/n~_$N:nM\5\H|nz8j t5|WAW9}%Ϊŏ?Ӹ X:&R=3oE{9WBƎqzjl<^=sb!sp3YᵕIh=&vo~wpv ]9ЕswN!{ \R9z/k~nQл_< 8 7>>3F/!ku:ԅWS>xLԇ8qgg=}6w\ow;41ON;P7Aj~8Xtߞ{4ujC2υ?˗z|U/u3i?^ 9ZzC`@*a|-`+ M>FAe!^OP}@_B (OyzA$ _)>(Ūz 6GjӀ(10xBip Åe"}ne8ى GRV$lah<ue$4ۑˍ}-XDV:zҾ4]&q\x4ng8]\ʼ3YqQ$a/|y._EϢ|ߞxn} 72?Qе .ƍ7qK _16|t:'^ŜrG)ݘw6қW v?S޿**wD81y (0M^L ݫm}E? gM@δAS{` ;"C ҇_pn(+^y t uJi ϛ"@?#6Tq pSh[Ȇrl#׈b22r 1 l+ۍ->׃"<(93j,Cxg8mH,Cؙe AZmo83FE𻋷"?Gw|uX m#{ܸt O_q=8%uߜc7N<'œ?8ы|%_`l n|U\*'8I{ ;tNΠ7P@Fg؞r~z{*4GTޏ1 92Т cߚ5ض"։.ǯ?MrkXCEbf0fQŇz*B6G j,0\~W12`$P@_,_:@}gx*رo ,`@-o"Î1IF "P^&,OBvGߋ>BR=:!ވ-ey'&$afF >l> omei y??={n{? aB|w Gs?™NↀB#^ŕ.ǻuᷧN⷟_wokrkۅ_y^-\Q;g󛫸Mygw~*>BkK\n\}?;v?;E\?g{g.?ʧ7GV+^X .5K~?s'0PFZz<0Xw覶>-@=qZ,D\ 9+)ne ū>|eJ uzs*VDc@6@n_F-ӱUHOi!Yh?(5 J0_raωV7:]AUbՇ}h<ЂN5!aö `Jj&6Td@' cN9Qxs*kF.?ӱ¹p1Q31N_G<ǯqN_}҃[?[oĵ]qsΨ=~\?f9\]_֟˴q8q8_#}Dg'ϊ~GQ)K [BW)V?;m,s<D0v&b`=ٞ8L=gA`j` cXWX9v%L}.?'GP`"G M0>_~L @o#I06:II9x[Hm_?g"qZL-Ĥr̬"˘ַŃmnd2׿_@@fTlFX^J]ؐae^oH,DVU N/R K_,Npi{?_x_GW⯌@ /pi|8Nz.Q p7>lf*x?o>oBwk7Nu?s N]NEp"N?S罳9tW]͊)ܪ/?0GY?4"d@W{T\hX˷}2_uP3.Y9H#.af\_K/=t?,G(|_(l! -?:p|sogSBn 0hD2wٱYə٘W kl2k=&|8FC T T²ۍ;MFLdAD1"eo3yoߐl~pq&n|r)PsׁP})S VAx~`zA F 09gƮo"\6~k5C>U:`_oH)PA&}Üadި߂ } (qy$x`[f.`Rr"2vz_o ?H3*b0[FbBf6bvM ؛ZMD{}rq%D!V$55 ш\ q)b97) _cOpqQ"3~r/q^utzO;Ӌ \5;+埞ƕw7Fϫb+|nʯ'A_=vXO5<|??ٙgqM !PO/Q/QPs t6r@SO_竊T s@ն`ci]*jǔÂJ7 j Pm{ h"n6~E:O0|c;K,ŶV*z{Gon4FoqT->LKe_[Nִxŋv)g[^Nd;4)1-i|^r@,&ŧ`Zz6Vbu] >?t~ھƉ=s:kwx7>Ɨ+A/ |=k@9/\c7NؕΠ5?@ҋnozN7u=g~^2: !~qӀ`ߥy]KY?!6@*6cc@{ѳxLf*`iM 9jD'lŔ,LlK96#z>lw#C݅N10kn6yd→ MH6sS0n[@*e`vAGU|rfza TS 0>C_e,ԧ7vA}Na!? ˂L"m?v5{Imzb7!`n\c9DGYWl9Cz* `s ^G`HtFh3@'ti?}O4@{3͠ğQ`T`ɂ1 w-$#5}AkfaviVYo ϧcZA!"ڈ6hEBǘߟ!⟹Dž  f\$QSϟ)t@a1VT"+v |lXoş-@H?T!Z8+GBf820@D=T%h(TޏPKg} mAPP[)ԬW z2 w4?Wˇx@_% +řyz?@=@X/SX8gzmE9u;2*_$a\V:b]c~`21󫪑ۃuM/ϜHDZmMڍ-v)M6#nԝ񘔠@e%z@x,el䱝Sy9f ^9o1][stm5rS5@bAv⯆PݗUg2pSN/YrWٶC~S\c?}#] !;<̑CSPsuz_[Xd?|Qذ!  @mo >j}^lN' ):z"؍O,_Yþ~ -n/&cm\}3rEQ rv lxr 5#s_3j1cC8Hmm!i{G@NJ1~{<&'azf.Ta&p!`ьUuaO _2eIc)A0(dz P<{jYl4{4xo~: Pڟ7+^{L?<}7?3ga͚>,_ J~}X(ǎX?幺G{ !!a1) Г' kz=.x}0cʀ3@)ld$@ L=_lŗbq:]}g{sb36T`ju"6lA^ѿ %U*Zx"%kف-p % m^$巈K]vd7ۑ)|z?-р4y)`01*H @Q UUa1>D |<?_ْ1!@قQǾˈJi|n8m^ng. v {.oz'$blx%XPח,./8/!arn`fbr^TEI iMHiYT4jPf$s^ D^Hs c?ׄkQ8%^#)31 /W`y~:rWD< ?zs? (c`C7eb j07;6ag狨g_{؇EU%}[-RDȳ" Z'gcqeQ(߄]N<EX^WYuXr"nv7:H46[(Ǽ* =d j6D6{+X~؁fune|࣎i]jpşϰ~ =}2TF4-c}=eJSwĂEAFN,_}\͟@ByqP3OOW BŗBm d ؠ  0”>yVKF{ (]UN]_c6;)`hL0I[)(0rlMxE>_ߢԻ0(wcc4Xlf>ٍ^K1-S 0 Q s LHN7O,*Ŝz ۚ]m vyh9vd`5s}v$k(=)| kZvcfQc>?q_?<;gsR=@E(}Qϕ=  OOc!X+k?&N3ρC4UOR#V`z?搾< 1 40 TﭾI뭎#֟t{k1Nc K_ϟ?@Ą;3.뛛0)7lʋvDY0X< X`fm#@p"S~K;@@A*K0)6e~p4aσEu+|<mmQG.@y,"Asj [ y=* l۴"#҇`$CcܢEqc1mQ <P5AۥD@>DX/Ӎ)`P9~%\D&\Y>͈l31zM`V (@){K޼G r0B P<¨@v ow)S1K=Mm2al٣WRPjcvi$bݎ S|@a.@nuaqi1f`NU5^_'`g(Lc@?YحH7V`}I!f&&cbL2far,cWrGnt$Ny@[5]O W||+`={yS@O`6 ,>j1cAy[ŋ;oPn];KV[8oyA 9'A@|Fueϋ\6.1SՆAog3K` 5`QO!"|/Xj'@f03:  Pj^붑❯<W`;c}:l1{tKH E))+P.zz`F ԰!,+b4rz*Jy>g`0⯢ 3 6`$ 1=k-waLn;X)o6C,2/~թѮxj1-'K*003bA6X ,*jC~5x/7aa?cwQ}H5V:-?-bmuE<dymX-iƂ0}J#R!j! 1lyNGϏ}C/|u/!}GcLq|*PU[P"h)PK}"fyF_z`@Ӱ,J1(_i@bk# I cM]%V#z7;]D?ÿ/ui8xi'v"Z+@Ѐ m/% )ecV~X*J*mw> hlOKL}@ؗǏ3iȪ+m]„k6 0 =*iNg\䣄j0郁tзe@_`{QtF\H#HP`GZykT9|zz=qU#`65.*M# 𞃉L{RUMF*\@}]>v8T_O5#E T Ҋc[*=k˱{= {ۜHpY1') JKaÜJ[`R~MBe%]iTy"VE9ro " u5X%Fn=>1~c!`ύ 'oojZlkT, = ʦt U_~gd$NxHˮ@l)FEV z_0PiB^D=.0O~6OCp sHnOB@(oߞ{e;8mZ{ "A@?G:w>5؇ПP3u rzBj+dECPPy9hZe"[ ᛽uy0`_UPC8x(Ԑ'mQՍzPÁc`a?A :9#}!1h{}R]5* ږY5j5qP^0]LH.,B@cX@x]43Wb2a `[ mH޸^-~GBAY/v1_UΟb ~j?Gh|su`h}{r40'  08]ۇ38fƌ#PhC0C*4 ljsmaO(&@ 2{mڀPl (j`:_u ;]r@"`-[f!** %00@Ŀ+|#,cт;0=k T^ޣ20? Ra > ׿"}Z}V oC.ᒞ`8mnZz"f?%(ЏO07 kK-201ޱJ+9ŘnĆ&}ԖcsQN;6>+f=H#[N*zlzk TaIc"Xu`GI{F #Y'No?C 'Og~a_Ž?PA.eUn:KFX<g\V:MzzCcH]_W{ 6s`OmDCVGc^D8E ש"t%]8Cɂ (@0" G_J7O 'zgHar}MLlF `4$w 0!]wB%g [;)ri<_!@]<߼E5˧ %+ "-"5} ;ωR)վ@ 3 IJ{e5X"͎t/ksaCI!UbˆŕEWו__=="#mFG=V/c*NĴ{˿(ˀ 作H4!ha"q6&Yv`Žt*n,9>8,؄~0 YBF`BA֭^:"_ |SY(?={ s[4sJ λ`4Ut(Y <eBM_kWVu JQ]3zBlX 1G *į<} @ gyR U` ':~{q;LVG ff2DG TWM`*@ ECP(ށjb5Xa[`E5bwSQ  :T ˛7 ** "P.` ş-'ilDL\Zg30!"߄}"o/ČDYkjeU ZwW}lo& "Xaʼn61(gO3J: <(h,W`#ZF`0rfdc.WW`yK><4䄟m~y89pS*ZC!8sk9,z !80W@P??2X @Q*]`^K`$a 𫰿('HΖB|vnU P#MTZ#0 a4IIo9+k-Qb:Wax{\$xlQUQX^R(H— DԔ`Y6T:RfbE9c@((EA\lGӆxNd$ Q+b+|t"^Lθ5 xq3|G9%4W8SWE~k 871B`F6{0|g%PFl#|,79N@Dk Ptcz%ZB.yPF Krs0).΂EF Q]vTOi|1^։[/@L˰vR=(a`ϟhqۍ?DWk0fDL!c^V̢ƈG}+iiiFg(៺ꇘ懘1]O+Fg<s7`{XjzQ 峟lPaBs:5Wu;j oKv(Ҭ׋t0u2ohsAd`!Ezl|J``7qp(hPy30*"_ѰQ*I_"b!>YpbgoFcϊR#kVו!U=T)zT0}E7m??A}>fwxQۋb?H@0fN$cYьcm5MXa,sgHdUNÂ? #!r؟Oaޏfa k/cC-L߃S#,"u"VQ>2yP߃n$¾PD7[/Pa?Tkvpxڱi?5#9] p02R HO6"EMT^c0=) 321;cW֎yaC?UC)PBo"?A#W }U"AyL (ЫUa8HU0/a}v@s Q@BjO0T*S}!BEB݇ߕb;V/߫G~-%6FQx'8osjJr@RK#0_TH4F⥔T`V{rwYx %Ċx5D\'@т3X`㷉ېkm"lbFB f?/'󋊱Kcš0vMYZly~]&+@E x>t_3A 0OV=kg螏f`ELpa!"G1 F zżQu ˥>\Ч,"^΀`^w^>DT  O_t)/ִ9p0@HN 8plF*vk/`ˉ vUzl)["Ho`h,`Φ{bGrKϿ`+,r%,ZP%{}ׂ\"yb6cQ@F+ r0/%󳲱 /`qe%˒F7o6- obOA7)||.#x`vZ|嫔>305V+3a Af3߷m1`tT#r)% * ;kS4z!"h0Q`0}/^yUŀf[͂*z!@>a= sY9y9FN(r@OÆjĸjD҈]M(G2[HHY.<Q_kG(K` ܨO!͎"~|GXPv;5"zW5 | MƦ$߸ X OsG`|?} 3__ G vdjǔ ş2L2D`}Syx8b ZG#RЃ0oԧEB:8Mn)~50]eeX\Y ^]/݁VGzk#vQu UXDv2;};؆"~5" I F;7b\HԾ&0I9M_T}hu#^E}8'a"%T c5/>4 *_o *׮"^* ;Զ?XG@*T1* 38`У" CJo:އu^ \ NqZ2X b.vGϞ/Ҁ|aDXGlLwd@zh"CA~zQw~`]i@)Trza%"²&0'q̜? :'X>C."mҒxfAp11ET4Q`\s,gD3F%SP)*@Gu> 1.e/~ uP+bx 5_#퀺@PQc=CF'N+E[+&b}6`K[ԖFq[D^k1Blj@ IkAV3ZZQ' `@(vhA>j=* # EVCdqV ‚ՕXXv+" pbviOK(}>YC9?Cg9~=v탶zGS\*5@D6*@DX0Q)"JSYֵl\GV}PQP~! b؊`;u{gNSBLSU l븸M坛*jF@@n `jK X^:+˃ 4 QfT#5*bV, "a:vذZ`- ?i-sC):P?OO^ymXCJy _#0f鈾Q F iȣ@`N @G0`k](!UKvRys}7< z)\x3_MntqoZ <} |mjQu 0 6I) ]ٝ;!ֿ*Vg҂n$ tޛ0_{uzc@#[H @@@:}(E^QZFwE+7 ,,++ h&+VX̒ΰ!@خȪv~VpxZ=z (?h7KL_9A|ĝqF Q@D M< E?PjtR( 5G6@s*`Q&\ÈMN!wPu/Az[Kliu_Vo8m01Ϩ5`1F$Sv{8PX_iC@ (TL)M xsQxi3m+81}H:Ei<2ecǖlK^xˊd-ZSeɦd{^]Ҳ3E8E_^^0 kJ;:)WRSn̷hÝ`TPvi¯eTO0?"Q-y8/za/ x foz?ХDe*u6F7 ݹܖOB4K˦S׿yzǩ*`DJ] AoM BQ,sDd`H\6*o4( D=3V:pH"iH@`1dPhMd.^\RW:+TVFFQ<+kGxЖY,Yp=P \"q* ='1 2. J*@³x#N >R%[B?NX @Ta3}ι͙a'q*OR7S++ﻤw_= ័E1 !@cOgMU6E@}!hh- T By=7lj P:F6vP@ut͐0/D{X@xx ۜ~ yPP';(\/Et-i9K/ X ,@aLΥ܊K.ل\}*}`55pz_&HO|[XJ(وЯwﶩˇ?7t,g !]-yH4=[X9oW 0J7BFܲ]x/ 2#q5O춡/ߞU]wG$@5jnjk؟'h#c- z3m@j#e@{% ~v~?1vPϼ7-C(ٴ g^|t zQ'@NdMQ8M0 ?دA~' {ǩOq9Op}':VӒ uu ߋ '}}{ NKK_GI{zn2\?%Àj|*(}H-wF1a'9nd-&t!S̆s0Q덣_FD 95EgzN s>jV=6Dctqbt}<=! (@}F: Q|t > c>CV8AA8ϧ#NJP0s`N @4 xPVf8w;v? &YYKUx,T9u#= ޱUCP!x#(٫ " j\`t6@|3^'' DEw5ފT >NvSEeCt Niم;?O*An9S +" 0Mcg`daJQx'@H? )' ,^ 9iiMHIyfF&KڵYS?xwN~MB,m\@g@D |K IO/Y)oh $ ˳ k_qw#Ϭ,`hq+|) x»>㦮FGMnB}20UC"#Ľy~Z=4 -LӰQ@?Р0yxA O|W- QqPKCs-TR.dQAyč]-RI@dw0C,Qn. n.b~#poz"or=j5omZ] 6@" ߇~ Px&P"[ዩ9 ) 1͖;M:8Z P(nйI=T҉gR8בi|@Kp- *1[o<]'lL@; `ҦmR賳G/&+\%%2g>ȬDH_-.\PSvҢ r~(/]y%*dP[\{\{"CT"x_u1w$gB}#j*_£OB»tjɤcQ W^Qf*we]q3{^ z /b{T\l˗7yy/:W[TxsTd͛@ߺ^$!J!?Uyl=gn3y^F׫i5" G*F @ξuiguЕ)u)[x :;u %@X\tQkp{:H3Aj)K@7@@<O<`>HOr;xp@묗Zk4б~jZRS,О-3N9׶sN>FGMV薹ڼZ$ /< >mhh0mٌF.>#b^=zD=/DCV~߱cЉ+Px ,zl9WHUd$K5PZT72wDleHD;w!΍3ܛ3/Q*LiP R #KX=?u{K=u6Xt4vI,B>RZRS?߱ʺH?U? z'Dy=[C!j~ોTP j Pk<3@ouOPg7O= ZF9n_K*[Y<Μ*(1h:vi>j4 aPS`X@cq u="@oRhY*n|:o a/i& ;sk)~ɂk2ߠ7%D&x]`T7}_W׮ӄ-~˜ڵH`к?t?O?, 8KcЦ{Ԙt>pi::LQHQQaZmm5ѿYޫ_ CaGt%` i"\\W57/[K>yaq~DA#B<ؐ otm~g#Ux#6 %w]Rkj q-1pi38?LRimw4IENDB`tiled-0.14.2/src/plugins/replicaisland/collision_map.png000066400000000000000000000024261260670167100233310ustar00rootroot00000000000000PNG  IHDR99tEXtSoftwareAdobe ImageReadyqe< PLTE~OtRNS AIDATxM -}aއ#N9 n`"݌O3M@ ""=N 3Ƥ8&9zxmSZ 'X131R^Ia&o7~oHdL༗D3:eW'7"&8, @X3q4 ?%u g&pu7&pߦO7 p3/!n&&%B % ,@hA8xWړ/#`y++Lw$p?`# L l8/o C@'21 `.A(soNVP'21 lue4yMN{ .`]!EPwB&R.b6r>~ FVK:YڋZYzY 9K99E Y[<-6dZlh+`7`_N&CSmg [nz+̤m͎4lw5ދHIENDB`tiled-0.14.2/src/plugins/replicaisland/grass.png000066400000000000000000002267751260670167100216370ustar00rootroot00000000000000PNG  IHDRŐg-IDATx Uչ?x CH!P㽷QQP͋>"P2CAPLTU , RCPc RF3*{__կ{~~gϝorګ{gO@@y2060%azy^笶@3;ft,]w=VcZ9- dqCbCX]^"^4Lyl?w6}EsU_uV?8D|#7du/G{k __vR}:*wxwss ר6?,.cwy}:Ow`Q|)AyFxoKH|'e d[x~ Ʀgΐ\C|ښ1;$8bWV=ȋo/pܶl9ϧykLg܎s¾eU^B{\YjK 3}N1:,әUKnj{Z0^5DغJLFio cxoo KG=sϳ6zaegF9@q1Cby_yG$b# $Ԫ|IXwmC?=r޷7{O+.ϯX$*'Uu8w[f,p{ڠ꣌Q?={[]߽y3ώƺ@|ߪ'05z9ϯo`)al??ޞ@U'M-v% |?Eۋ;tr~8bINs:+L; k[Bs1XJ'lbqВs"}d.>B@@:M GT*.4zӀ4 } d Kp~{(nWN(dAk&+Az4}7b oo,>sݿCCMar9~{bcbpn; Erz8o붸"CU׾Zko;rv040%Dt$ԏ*jHd &U]maz@?(Ϥ +RVQf35A_V=)LU wTb =@NbT Yݳ3\onº~NG g/-ph맅pf+bb9="̷"Ph_HtZIaU>},0 Ip DăKhNpS%(>7\&lF\D  /T$7| ,$T-1Lv|Sڠ#r5 3ĠnVu6X^WJUu;w@8R@"{n&{TX\?[gD@g2~{7;݋(r |o xgJ{ϥiKSM6kN@s`F@'g̷뺮uzsu\Q'w^ ꃅXùD+kL9O Uhv]xxl;C@Q)rh}?ﴲ:MA-3  0d{G`H|=5 ~*pb7r$W@HBvAU%Bxw6qG@]F睮02@8'O !kˤbXi5Do46b /T6m_ 'GGL dMߌM gc_]S$5'gH l S-2ng ̶~6_jUy>98ܣEE:D@T̿1g7 Uы 1᬴[C\bv|\6@K̖ `E@~C*7(hH~ڰ$ru96 gBuaQD^ZUkAֆs֯3 "G~op?I|lp"]6ܛs[$HUP2 Ӟ'3~=>~0lGAZpRwH z33n"|w7ځnįGr71S%h`3@#U32  @d³l|Yd|ˢ̷Dm|̉~6Odߪ~GeEsiXnK:qpr;Mwio"RJX]1 0jb ^`} c<$m j'MY]ƵMF=tc|& p?OE߯ &!d*1NutM_?|0az~?ޞI,dGojdh{;L* ~07~fɁ'DIĊe7Ȇ?'^ḌO)b:Y`v x{tP@ e\q¬'ʣψfs8/ð9(eJ<${x>ƌ')Uωfxa"'c(qpgGKG0n(NUp H U?!dLlP'T3HHv'?WVҧMMZu4tW$n2|p03L6oXtU`;vetf2$98WX Oo3,dDӋiĨy1Z0d㦱_1ET%qGxau?{޾o;;.p){&VSkQgGz {>cŻ  ׍Mk5?ܖY%#`[T}ۿ!Gd0D,cL?=oa > 愘&@nx[V_/|LҪ~q([q1B*|}D=VWmO(ECץLmkĦE3?g늤4F1ogOj3~GybB-4v{dɻD{cş^ω+1"hπyu?iKH:jRub@Kek2֙Z}} ,j$Z B@3U BU=:~:u94>!=qMŏ}J,ʹ~?7K Hxf2q牌T`X3KZՠ9JՌ&sZJd.K2WN.rBo LnBwi1>8MSQl y7Y7wX;OYV(sYt$$-I-sR#+L ߢ!ԂPs[ D~pU9ޖyo|T?JO鰖oYbTyfX20~n:?E2%JA05T+ceC_X/'gD~s駁J_+BHZ3 nc?.l^~kp-l8AS&*/i=;8=&cbM٭U?319ϠD ߏ ӎآ^{8c}xZ1U=cm`6$]rot>L9Ω)W9F|)/;ܪGG_U?@63? ˴I PvJď@%Op!IP!Z |ڣU|~ӓo'*&/_uCOzR/xoket/ɪJIaR9οEx-ur.-ʔPSD2P|W"tH{l 0/7 tpM6*]<+80$#dzS?]7~HWIio~ĕK>j!>~rS՟#/d#sZOdd`~#u% y@ׁ 0٫}EYX=詜r :Ն3:FZ-+'U]wwUmϝmJUw"mxZ0T矴I~))/gE¶vzM]̟]p do/_⥪N=rUZnD5$Oo:&?@'٬XK|9PǯJP|^uX~$JJ_MCwtz%uX(# \ UⅵH{2Gw^8P_Q\2z AG_s_.YN>?9Ɔl>֟AtaJq>'kWk"3_sRgtczmFp\ |"2Q*(ƀwDP\/ml&SoOr\R*遼{U&)\Ih#@j]xL7-(%Wxw+å*0>jb߬-0 <ߣ_"1:yKU1y#U}?˫V$But Eh, j&B3HHnp^IyOj:tg;;4aGhBjo6-sHL_ mBucTo ȼk:$}Á'^t I l\_NM `,rOTz\eHLiE1$>;2$wFϿ |WhԉNTL0-rXQg19_C!Au^)\h{uM'WiM6WFL7m;;`Y,'Ey9}KtM4dUxY` jbQq<ů.ߗ,$AO*7D1@RP[N[C<yw@ypLJ> p)v~D kJfϋ}z~z?4nh_N_/>՘T?9zl cf{eHM*}<( 5Y%ڙc>3^W>LւCL?nLK=WO[ sZp6&7z7-k|q=ʓKd槵kjkt)U-sS7qjXjI@пI@Cs4\_| HXR"*ǩC|U{ak;Q!q:?t?F!&{$$']*ca+\ptyIrB Kd1LP>=ȸd֟'KR?~bn/! sÃu[ %JO0v9Te~UA~~\4)R3{ehoE3qqaTR5 [dU;?MV $!|E7:?$}"ZH{|!ts_Uc)+_B\@=y>:V6P1IM ]h i-qPI@i9b\˫ !P\@E~jMg>]5jmCt)tO fj+@@* `bCC@ &4fr -P(({H?~iɡBPi&i|+iGHXr6~  _Z0xL[w F4Ag>0*K[3VMʗ@P`?8- !9h\u6+tu!x=4U Հplt”BM B&Q0wʁ_\YdHeFr %NY$knw 6j!fiwsZF$nv ܮ)_o='LCkGJ颹0|DeY.4E{9- Қ3U Gv_h t/(_4̃tE9/COZP@ R~^L?&X>lWk~}m |ɮ?ϣ+>`̷K[ pƽ^IuFXԚ +wcT-HEn0ũy%?$rMxż3c[P#@yiFt_VJ; %z}V6>L0wûXhiK5kJiT oW @{R Sw L}?%&;AR 9i?󶇺XL sa R?ld2n辰U7a?֎|*ӵ\=V.~5B `7_QNVVv:?QɎ'!Ze& ,.%^P@:HE4?  @*J7!/QvB 3ґ{^e[f'~{eߡ;3]ƺF:> rQmN-Zysuw d?4dSK xmլW>?nTpE{JC`ɷ@_d{<`5k#<- g{Z- @ӳw_O~޽{ѣGe۵k qFHе;w:,_\<쳲-\0bI;[ᅻTf5RL)u4Вb퓅[cyzrg 6äUd]wun8qC2JŅF1@UmmBu4:$~`NXVEA$vgz7d% f<2A:q]-iR?S qȥ̒C1~1k.6O}} D ^r;1tqgKt?Zw qfe1g98x{ǎb˖-)~ȑ#.F(}/sqI&tMHMuL@s:F*bH?\9 _$fRp*0Kӂ(I,`\\ѿ7ٷ&dǦ(skzM*!MEbTyP=vQLpuwAy ΀UN}م!F j/ӳjwuS~Wľ;vҘ,-KcS}[龖TGR8(" 4M~;^<'/`զL3wWIiᦇm߂;%3k~R=h$;\ 3Ado6en@ 4~0H&$ްad* $Pǽ:-A/JRʝ|5P:J'+ dúQ q&<]w$"~"=#ZVKYqKHD-Xo6m H/Ԋ{T&UR}YxM$BdX;DM@E@"?beUS@,Űn< M.#n@'FO-K~v|gz LHϕ3)z^$m-XO?BTdFBvl?^JAR?gpRx&p(G'*CZ$rM(<:c]U!i'ұ@5U+,YD &8`̙͙_zL\ `JMNo97 ߢfьfO Uhv]x8+'oJ92+CxDLtW't8E]c4\O  K. dCk Pď\Dn{q򇤯:-X@  ~>pfbh}P=XG)=:t.L $ʸ],@0|qjUiCĹYyZ PPm+;gRp>ّq*VykC̞Hވ~P ܼ_\2Sj Pkht<AKIJX8<hUm4l]QF?WÃ9Qڲ+.s'HpFg 7*~۶2wź~禕aCՓ?BTU?]f,܋OQ̀?/9}Q?i97c>73\ٿNa~d ^}5|ha&"0#  'Q=W zV0j{p"$oW6lbz@P&]!p3?;:ԥN59Wp/`}5k~6mkJ)0鮿m6[To,?ZC׉ww Gv$!NĢ*"0N 9 _x:*뛈iCb.]*nau>֭'~B0~|jm5䛃T})͉oKq}pIO S5 (K.?#GgZG P\{P5ś%+!$S sEM=]CD_][+=T;KK*o׆*Hu?g2rƩTv *#+~z|TM sru7~c}aVZGDxء[?&tgf ȸ=@ N7ޗ苺h߯qS0@0u,#zj<>,0H`F-R"oxc]mKr>3g?󶾇& Diք<~g~gNpx DSta*8ujq<2= A흴g eI{G إPEX~3ʮ럭x?97o QiC`"H=gD(gPիL@O0?͛@OdWK/ZLR`+; \03!gHsCd@̚8ڞ 8)tx=v%%KjJ? > r{ޅw߳lW!$q. 1 ^&s1".5K9 >ڝ߿q3r҃l] 2 #)oi0S*vz ~]Yԅ}?7MC};#?!G/,ep?|XNDT__J6}U@Ҽ5q-$~5u0}ʕL2%co,8Jh'>]22\/Q?i9,Y^P ʌC tMRvG#I A U +3%H|J $=97$[0xP-:DP'W:NvFAgZ33~%[?GpDF:?oZU\tMAm68dOe#i@mcܩ5|Cptyt2b/^zik_@|޿Lp~{@@Bi2C=I ¾aFtn$izOlJjelp K`9hN6V||`X\ɡę6 Tr/$q5ΩKK':EjyS 8wxk?{>GRhlދD~\s8$sߧOU~l/~`\O"tŮh~ښn1 r|Δ_o OС·WyCh`ۧ @6@ la"S..tF)46^z;Ҿ]PjJ$D|3 + 61)z`uPܭ7I`*tASRM9]0~PҥxL8_DJ`hʭ Fz ht PoA*Y%m[gK*+hAѠ}HĉVR 󟪁IO0熤tr 6O7X(H>]B 0y40}R  0c=92HMF&]LS$#sERId켲lI$}0}7aw92 ?tE )2@{?%`@ RB/sࠖt& +r%QY`Sj$|!FU,kk =*`tș`^,.P^.W V4yVqFH;x?A{1  P݀@Xm3Oȁ^S$k;wHZA> !tu}UkFK{mwt2O|nn`ccc)923ɡ`JTVVJ`ٲelfGm<j ALS2 JR>^К8XZ^8] \q"ۓɗh[ɨ)dDuR@R?1 s ׹IQ!T54?U L:B^Y0eN*%GߛKK(w]b`k@ PQ0uɯk#s=R1hqM_2r( A 2{ dGq`_&6ڹ<ڏ9@'o.JIBK:5'Q"PSy"~NhFgPDVmV":˝BEiyLVezB kK;ꠣU'JUU-jHL|U/? Y5ZtE@[cR:H LZXר`3ӆL[x$ BC!|(04uჅ1g;=M;|a?։ŪEY)~uYLg4% joG#6uU7^ig$8ڜ`~:*yUDR('舟z@u6xWUj UW d#&ʝtφ>+yT|Ip HX_HdV\RYÙ?RE ԁ'V:_25HMy>yC2('___? ~I)|Hh's=(/Z2(S _W Zf@ONpJjJ- $*`38/?n ?BăH%#*'*_uysI]ƨ# /e+7Y\b&Z?<״hk s [ ?`ȃxU?^LHeP1@7|f QH]]Ό}H6Z[nR\J=U,:g~?yҁEt $t" G$}2<ŀ滫^ *ӧPm3yh(䏴< 9(Hyc?a/Ü0bR,{j׿K^m|&N>Y*nsI%Nߴ0T \st_|$+1+$}m 8j65>dS~~%)AOILa|nIkG}bsߴ#ciر֦=t@/j_(J62r0uu,  gV=?1FՂ?H@yAJhO?@#ŞU^bY6d濾󜖩oH:nbYӭ)1n D}N 4t&.'6P8;ȩJ\@.)l,K 1CLƁ%%o8$ė! *V.DEjFcA `aH8yo>9b6ٰ;!;" x@"v")xPPk(ãyX9!?lݐr52UzcwT?WgrsAQڦay~!T>*v $R?zV&_Ki_UV {u6A10- h?1l~Hju_tA@矴O|qOK;$pe0$dj4`lvi3νh |9ZɁEv,0.F}pMD HsNphIةTĥX?* ix'iWU@A$T"*w:Zi#t!8lF~8\ꡊcW%v0=φ,4 lqT )!x0Tjn>=4z\_]{Vn=:c(LA0]?󗪟 3Nk:iCѶO?QH0sb "-0@ ( :裏f]F-LOj? 5WmWl'y~0|Zh 1mݽ*!~Zg>0Nvl GcCR" nꑧe:yTl`/ lʪ"n yy#^uNN/=W`R3xrhNė&Ԑh/BykK~SŞrvJ/G>Ǿ_7~n+FH_=ő  c\?^3@%r" ݑ:bΧdKlWQ. nKJT(&/qG9(?HM aY/ MF!|5-/i[)ԬӚmz粡"4E~̹oDj(8ꍙakO@XN*oZry:F͔1C<3^y ڄor1BWV]4i /?i vKj}0;!<Hǹ<NptR?w${-5 8~Whho}] ufTxm.Ngznsj3GC+$@ 6M綅\>7G?y0@;S#0SL9sFcrY kZNKPZŇD*g&Ҙyp1WmFqӱ w\(j {;)@CK U}Sכ2q)T&%MEM/w\C{ ۍ޺i1|Ï5xsSmCy>6?"䔰 h-[ݑO^Z;ēEo5$A$ZSGHCR?qWJ_*f1UӮ߯7Ƙm?Au{{ JrȯR_3~: k~0|@7M^|R:gc}6%3io`j w!O4+dM(NOHQ /m,aq%0 ը%:~ /D5l0R^j\zOlYa"0@z?<6~_=$*/=:`v-Nu ?TN} Zdl0P\Z%r &yU/;* 2H>|ڠ"T-ZRQW_5@F+W۹q-h~_ѷrr9ˤ7{?>O/Mx*. }?6XcMOOz=\W:$VmϜݳng_/~bˆb[yb5b>u/Zu=W(Z{ff[s:/oIh+_ :_gdS?6֙XWܲG'Dt|: rGn/V>(c">@AAj ^=tLId` ῡv~_@ $ATH.v#ڮL׽ja5 \~eVڦW(:L }CClo#ڇsȣ⦇rjoC,:|v9$LT< b z(P}XC/5VLIp*uϙ4=NozLd)@:ʙEv|U\ (5kL]KKBZ?&CSzU{^čvW?u \_$Î:Q!iPͩϜ%ҿz}#j_sd`,Z;,eߙ6];?ig/X6b/ pI@*wC<0HkPqQ;%g>'yS>Ӧ7 IR?aT08s}p Hf](`-}uIpïKH8@vxd >7 J\:-R(.vJO+(t$wKZ3$Vyp0q:B~|`0 <1[d@hj=ӄZ`}ԽxA>y'ጻê뺮W]/V@T,$L*ЌhGRPٓ-=P&I XOmg튶hٻL>LO-ɾNHdTP04RҿOU3jj:D:e]w$;\c6E90Pgжj}*X: $8`1ShHCPAD I]H*$n̛3qfK]$Ͳ}WUw߮U!~-VQ5 ػj[ !PCcP@>{9&b<`Kfng춴 |>b^s@{:P/uXʍ(/ᄎr_߿"HoElMX㚛[!9 rjԡgD\YVvkPKWJbה*6.̲u8a:M _l'.奠a@f s 4)7%)1x7Κ;23uCGfLBT Pdos… SO=%&M$:~~\Gς`Μ9 J;̽N\mo4:;BKzf} ]ӣwj ՊgtYLI?_I ?pįώ<0(R`ﳽUnmjb,b@?/A?;Q_;a'Til֒ˊ:ќQ-5"F4 e78R8T'XcnzFnϜR%'SI7IrWӫHwpuyy:| ص'@TLYl/4 1mSȪC淤 8CF3<#l`i߁O8SݏIM?XI'NZWi ;֖3ws4'͏'.yNĖT}T;]4\7<')̯yDNt`L(Jm3Y\-7Vha7٥+z&,8bN8ۀ"l>5na#A&U#2JAIu=l]㫀 (&`StJg(U]sAjAX}o aT$}RCZ'_Rf?o<=9vfɓ'jjj`„ =Gd5XRr8sSeWo䄭&T9 J`O ?S"%S7s/LцnT^izSǞ/ [44^5A, &# : Y|u@jyBHK*=V~牣3=1q8qB޷~$@} j r`vuK-lZk RX~vmFRH<yx5NJFtxnڿn Iy ZR'n:dL ~kַZ1:[DHp% c`'5_G0˻RQ#|vw2. \ ?ꡮ?K)5lʠY P KZm}ɓ'&i&uVǫ_ 4}?Q|;{-1G|}Rw@"0M+\kiSH| {}m0)HϦkTW$sտI'?|)v"1`{$یwЊ%A3g~uV/ Jb<(={$?@ a" L:_)7fu}!Λ):{??W T|X8cw7?[['?JdT?%?(8Ŀx|>%I1!$S뾬{ƴ* ~Zc-UOtSIF cA#`<`kOtT؁w](U^][,xlV6x뭷477;L}0qI;w^yv-C3 "@YSXW|n\gn]2Y=$H8 rJhIOz~Ƚሗl}.;F]n pʉE@b5?ēI@eߖ<{:$"6U^xh$ 3zTdQ?a2%e7L!\6dzPLCNx{"Hf;ULh_G+c"4a)>~xxccğyK/9̞KpW@- :@-yHˣ(>9]nh+ Jl[-G=.оX@Ïk_6G_?Ye_ @Ċ B78!:̸Q;”@."@i 9sof@:Iު6=g=gөN[A!pD2:Cef#2莪͢2QgS 9?JY_|km[CR0iݮ^3ѡRyW|̱k ϟky_<0ܨZE;2ˤPwzoTmB'n;< j+) $i>R5s8wd%v|~N4ڼ^S0W7[i;ZB<׵a_w05Y Q0Ȍ 0>e%G@ / PoH`0 @& df@4L(P'x"*|\ʀW1vQw_%3 W~͵,d&E.5Yg!60phXWCRQ"NOe5"X .$MEGX4&-b靄@8w!U ˩7K-$LdQ 碎:%DʎI93P̞f'⌟h8pD8e}eH Ɵ0x20"mpO'QmAC94HI&M-oinwۤ!Ph)'xty'fc?#Hf RRLs N{_nMD-u? rQ__TC@H0s\ %"zis,=1qdGpCDz 5TkN |Sakn Ό+'iؐ/4@BGHB( OlӉ+zN ye$G8rVaーtOX*D=.U4} b78IrdE^$r dTȹ#? f|44aռjP@=+O9ɛy `: A䔲:$8>Gӧ;)gϞ)pV@TG,g]t̿>k:oI0oo/^Kgvg[ i:Y&H`֡ Xj p`6_ 3n6"s3ϻXh[xNSHyKA;©R*7k!^s?يm_j?G;U@ $~3& A^zwzmxEəd%Mm0''4?u@U?dސwK PR'HfO}]2JG۞/%5lj2Sz fn գ![<O<~l 0iµp]aFO?t( 1w^%. sdA U\4#\ Uf5J1T8ks܁,Hh|gA*&K=-F=BCE2@{{٥̜x <~b'y.JMuR0uB{3'N Hs?-799?1>GvܟJOcyqĔFfل^|XQDr$-ceRa|ARhj:Br?+A*]^~=׏.z h В%3~~F_7- N}Ԡ  <&s̴ro׆<@C '@d %#9?NU_PfTI\'.{NO5 ::?ٟՓ<o+E P#z?S08MUΕ3_HL ;Tڸʪ|k>|'TUk-h\E0c-ZR HCkِuVI+Q%@zGgcG$ТE=H9fN p_{Znqxd7-0?=JgqL x\ʺ ̆D ̙9~!k %BBI< ?(P+=w{c/PA 4Kp8$-p!0>8=ρ*Oe蟊lQ]Ο }W,^m-Xu=*:z1jvKxF`x!~`<ܘg|Mtؑ4GvP@@O]9,J6kH@ OmgC~wKaXKc~j(KsM`B Vww㟹I`-AWLhҐ\ Zdɕ}Z+|hpC6?S`'AD BgbȔ1LIp &# o\%/Y͍ sÕvtEO"`␪; T8.0V6g-&m1-0%RB(>ZfQ3@xq];0zYEE"#z&Ei!8#@՘IҸI!dtHKM ){,k'0VN$ 3J2oNH\S%0n3 B)0va߸ף8dA~Rɸ~8bҝt%پ?>A'̎),I8vaGq֖Qa1UHeb6̱!0a(Gւe 0}tKm=Q$6>,ȱP%EuL89H0rip!_?Z_dPGY6SglF{Ӓ,TAyt8~A  'ވp?M0o*I0-R_@6jçΙۂFHLÝ%d"A?"pF' T#o ?֩ic4({;:%I06zTD5ih0  N $&NtuH YX3Ёq%8 @5E-v&d*.Wt6fCS{?.C[a^N~:B@ 5?@mV dH.Q͆m5s"uϜs&UQ.J܆NsH>Al`Dv|F߷e&Im?'gּ p?ӍMӽ}8s&&~V][@ -K{Pp\ 6~Ny58#_b30YhPǿgnjM@hftl9Yy[$}?4r;s``$e r4C@~"U|JQmݹwy jy 9LjI b@Ec![ shq9BHGtKuW@ ?:A@fu9;Rhmivo,dc`eFgAWDn/tMiպF )X>`&ف `9BT)6X@E:vy|N/EnzRh, dyBl- a-@12x[St[MUfΫŵFJ٪R7!@"RO5I |WH+b\:@:!t@g>,m\S6? a|yNk˰=D̟,ph".)\ߗ9dL˼U )4UpxikƛOg R sL?o.S_j (u9)鏯?&? ?oo͍ ljۗ>6Cn周, s흁kBC@ 4x @@䚡&B , q::{>öYڻ 60 8Nӽ0{BGDPG- )zD6OZ] A=nNXO'@I'=TS=Fd}|I;!E?z=b'^=/'\u_Np;ߒ'*+.c_J9PD`-s/OˆŇ '!Ϗ2.^( ceJlsN{pkׯ?e 6NB;~" =߮nPM>}|~;2?tN{;] B/^**la-6Q>@w>6OѴ(;o!P귥ɦ@f 0ojjd@v̀IB&u?|W9z\D6(ŒO?Aۀj?xṧ?wE  O yn['W-qhdE}<:bE@'*p6? pSCW/ٕު@88dαuUw5q!mz~YD ,T={9+ieVpi0m7{'=O}}gs{,XG_:s:>ֶXj :>U7<:_x/` VY&<7vLmh&d2wPޗ=˶2e@ͱ!a|mVZjL2@0(g?i~1:2h1xF?b@jXX$%W :=rpFtD <7 .0w=H/ Ke8@^c`ܮ٢[ B ILZDl~LTA=L@ph@Ă @U0JhXNK rC Lp[T` ??x1%%}itCts0?;~$-<"Udu-:;ݟ"0$"@G24XmWfw#[s6:+UE!W'b8Y'Z6P8ߜ~͹>Їt"+w_ju:DfI<&/~F)Ш_!yC}Nb"FOOW%g둫3[gm-Zwh Dv-\ _n&`(>>uϭAUZ_~R%T͘@g WX9P@j(Kb1+E?ӈc=G'x!EH~+m"֯i@!$qx<"4~G0?b(C])6E*Nf .gՑ7*/҇_ka vr|v>`r.)@ܖ,^`; )) ə?(IŸ6ߋF_o;897@AUե|qSMM_xMȵV[qg -!휠V]kyؔna}ӷa9gngf:N=5?bN R`i#lď~C `9?b~=eAݨq,؍zi6zFd48&~D>8'#Fw9lDmݽ}ӴNƝ !!&T>i|\Z g4iQ-P#byn<Zi=r+08=?r?~]'%@m0}W9Prq @eX :zsAHQZL=RV!'!,Џ}Q5ȹaD$ qvb[A.泄sy㩤Hk8, P9F5wk?:9uzPWf-]1 (_*ɷ{6#m٩zj c} l1l΃ OG0u=fiĀq)@֍z(;G9`|ЌUYȃ',0NF6 qDL>ڙ?0`d'3y8@$=thnA;I^P]ƘGg @@Kdl֥|YBT[N35-st#sy.˱`?Xq܁Vmoõ}6h O7 @ߟq˽g 9lnÈ:A GIMG纙`ylu-L6A'/{z8TҒ"C-C YaGtP-o4DѻW$hu4>yv۾tv#z/>[̾ſP[{g"W*7\V@{VH1?y)8qwWyST4B2[e q2uY#zdkLU.V^)r%ظ9U IjP,N/L_{Imk\{<ֳ?tx]tQ9K`JPb HNBȿ*=b B^wOsu.D?9[`[}~!/ōĀqCv׸ mߚ5 d(1TÛ&20Q~Q*P< := )NNwXW :jM<Aď 9d-=x+ygJl:*$jQ.8w"on&D`!P0oxxE @v !Ou7 ;W L1R\O<`_d@ٓA6|zﱹ}|V$38X%Y3?![=ikl#Ml6[A#,s@ `W#~!iVwDۮJRnUΠ=qdcx^l?-(x[s,Ph*i.0l8d^(.W 8=7P"!Sd,0c<&cu< d̠g4Ύ !$vo'nt|-'hCپ`ol;$IsmwYC!Xֿs?uBh~ӧƪ<4~T2?.X\Rv :'`%obR@8<8s߮r,`A|\RF_X`8p‘FL/s<H>Q PBqz֫)@9~0mzpPqYz\߿]'dirͪ_6 *G24^6.`)񹵹O^N4*ZDjz1bQ;޿2wvx+G6+#e_/ZT蜠; 9hjti w@IM& T=#t8ǿ?Y] d}'w / ɿGUsU㟇M:^^6J/kO/_, yl xNǑl}A/2~S `( Xqc s w|C^}:AL:UZJ/ϰw^ ˃X޷Ofj+r<@/K(p~*{,Q pr; {D9М +NԿA q ^R?+GJuMف-afo//߾Ppɭ> ]1?hؑ'l(O*aեڽRTI4h,P _xg}7}gvF?B՟]7_q Z{;G"@# 1Z^&:A1%` v [" +;(j2?|G!>"ne"P੯@KDȨ+-eE9Jާ[ WYCbsn< y 3N`x"s ||AV.;sCOzuƙГu9CArC@yּ0^Rv#{G 1TqT5K_VEYug %+?.5S#ǁu^x_,#ug$55ˏ;1T{MPP)# Q3 $s?~\ׄ#BT(̢\ :@L=@$pEJqТvgr>~}$WK][srVMJc0B-'-i Xx&VUm7jp&k7Al u1%Ksy$hKP ?|^O~Ÿ6? ! ٶٿipSE,_.Y/yaGI5U\(OPm>5ɓ7 %@]7qd@ 0g3N 1#fcXG 9C٦Op@ߋ</|DD0TdW mv" l$}${Xٿ* ՛{M}n$m ':UZ[gB(, x~f#"G;d"c:1wrtq̺9L 'OC~D_>:9,EI{mB+;AP/Dk$$CBd3cϝ&83!~fKcTx=I<#Fr}!Ь91RX`G%āY&@xlQv#|FG-'|F.?? `]w ?5{ΌCS**K;.l,eBƏ`8JsA9 2L>jX+N~lx<?zdG5|M,@t},/W\Ix:z>3C<~78J1 Ź/_B^'l59^ړlmX@9@} S F9JD;`c{MǍn' *׏籱́t 0ʮ ƮNV ZQ)s' ŸKIy83E=8'x;g0c@EZ/_;nF^_vر_~{7}(}a37`,:t#uƨzi`s d{vҿV8|vA nS>hE0`.g^?ܞHH- _y,Mm˦,4[4OsOu˚tf@7F |J B4r ei8=l}KW}X ITva׍םӁmHf-1?PI殺l>m7x˒>"1 H"`qP8 (K}8am7zWm?"`{@DX_`Af -)F/{Of;Ȃ#"Nb#!8#?mݎEF}Q xdVzH_zw}7#xvo#Ǐ_U.\C4776b/:iJe'Ł^/2[H=F@Ŋ I6Odf)w{~v⁓rDZ'!8qYC)ont |94CuniO>Tm@+ m52U|g@L0AXN7 noWm*X P'@rm^Զmwo`,?{#!LrQ%DzhsO,@Zhִ ,T̃0lhZkJVp1hчvxL/%]`lxtLW \bAcT  EϬ2}hqغ}[,)̙3!"ϟ@0ЖOe#f&l$I_:t?6_(#ܷ0 \D/i?p2KKw"^$ \_͹D'X#}.'FG@p\[2+iLd fϠ\3:fR@s B7?˼@a-?7\ >k̷Y. {T>E Vt Pt}zwB_%tJT7~PA,3 B:]4Fy ZlP`[UCfy}1#?||G ݨ2zAJ0:)ɥSdK ^'U0pᦧwӉR?2sd TWu!N" 6}&/_Z5blZ> ',z_[!=\(;<jgC} ?뇳YgSr,9^+ nsb

m! D~*d-hP9@X= Ac @$ Zt|*ˡs{&`U`d$27d/p#?O{@&2C pYmJ'@̰r?͙mO'T|{Y1$ǣ$)<0Pl&;Q?n\1FI\QkXBU-&*^8Qf [9^ ~ɻ5 3G|f'5/FPP?_/籯ՀR֊/dn D>TSf5'Kg"k_8.z"at 37n&;jOWl霊+cvuja-yySBXy<{evtYOC 1`!SwtO}8G`}H42%7ŀ4@}HI.J?׵}prEAΘGjog'MK@Vb$h8?zz ;;;K/"9Bd ~c.}rRɟ?䌐w/w$4RO@(PЎNcA~`:z \=ʀJ[Nt(%={"+^gK1/Me>Zb)8_~8#]ctO#0zDX#4"W`U l9dG`k;dF bMZ̽>JQ9G_ BEĨȓy|(98AdGxwuu rKĸ"6A \heV)l'p?W>'1*"[L|^;dϯ[uJVb 'K]k"kOf?eks#s:F\h+y )͸0)+ٟ^o@vfNG6_YPi[Cop={bɾ{4 k{<%J:B`~^Wőm?{_Պ~{8R'F4_Y>{>=CbəB@. 6 =^rOJQX,(*j}߂Fp ICƆ+nO,8w'OԎD@n 8|}wNAء6ٵ,tFϐf2~Α m:;N<5~/@ݏt!@n~;]dE%{pI0^8P^eo?>~MاO8g~vI@tB7RurFEt=?f;eZSךnrxߝlKlc=rwx"`kh `lQ +{㓹'ݭvHo @7:/?.~9`ZM f$'O/*>i Xmp'`*}&#Gu=իWE%@G@1ǰο.>e pp<fi^>: S8Ou'|Ha_uNcGc"Ci;q:]#+DZ%w/|Lym[|}|b*|[}rhG ُNg_0|D|ϊ~rkfț~ >υo^6/((Ma-uf]v$-&K&{'=+^}wT-}g}X R`_?FAg\'{ %-~ w'[+89HbM)l*wlתɬeLq[?.9pĽIl౲$G*۲$q0A9Ss;`6]:ÇwiqΔs 1dQr ~/r n {,4|`^nۻf N濛vڷf  k*  Ã2quwDYvl.4:&^O)#ej@-3m W"W|wGUkS9HaR2ki쭁ݜ([¶VOc[8V;kX$JRYSU :cTXŜ1l]82kېs ے;RDs(ĮQ}Q-h)gz$t8/gUЧc%6Gt !q0N '`D)$' oa["2u3Yۦf`U(ïۺm 6'ä#o1${dh>VVnE[~p@ͼ{_AZ|Ѣ:z#=S2OÂ3 @[F; @\ONAK yEI' l҉ؓqPOgOd^ڇpGuh ^;oIQ(kʒ_$D Zl'7s#5F/}ndwWzp%s#&_͵*쭝Ep2@` ` 5 025U&̿mlOtYVMS$@k4Aۓ`''jê)h 0!' v`V;G>!oӀh%c^<@?NsEG %P7Op+8)HE59`?I'{qֺ!8ݑ p'0QT7{1L0|F^BQ4o,mTWoTߞ;ųn-G߿:V85AĖdV~'[;-5F2oTz+Y<ڦ hJF}e6fٜ3/4pP ₱>7bE"~b~{Fq8 @1gS J%, <Ni1ϳ{V @߻v>`65,HD@D +3x6id#G!2rB% c YA<.. (_05WdO4e-%;KWE_4[ʌǿp)4z \hsekq@=Iz~ [x2k^7!;-A v^??Y ~ꄎ>Wn*?nӟ*@'b:D+ 4byOe5NbOc{W:8함$)05,Mc-kj}>;kSEeaڴL=6c T)ZM~cEh@9~2v@,-Zc 0z " 7-TG"mSTGp JeϬUXƧOzځ+-7ӌ[0p۷nZȟ.0ش>X}Y2VMf۫'9]uSL~xX(<+f[M1" ($7VbA[rraf!^pܵz dEO|JRZ0m\S\ ]ܿW~(;"J~gMO`Ubٕ>'♕'XoIX$U銾pUgj/:>OT&zYSq0 Ϩ&I175LL #$"onKexUO6mf6/0Q'UIH*m*P /v Pp {̂&ms/΋ ޓ4T@S՝LJA:կ?8S|*:\-ljY}8_Q~X+bGŽ~7RACy8*΀â 㕂>=} Rc<'Pթty[rS(<.L~`oC2guT2&1oˬ=?Bp2a&IDϻ"/ ea~^uVz7G~+DDnG :cB['UTW^o/ Gg*Ґi#A6/بx%Ht7Z Eq?/a <__);__ΫӕzE~<,l߲g߿hRE?vh`Юim,/@5Ds-@̳(ҭ@E EG nUYcƼqǿݥ~n.b|z4ەm37:㏀@}(msBAKs}q`K!7mTcҨ`IԿw3oËu[G[y@>Tt ^6ëmqz-FP`ɿK .J?'+y oN{ޚik~6@}Y*QeY3ߜn $k_='G@ϱ"#$`U HA$IO fg%&p [ ~.>U;;_rS$,ͥ??neZpg md琟mMwF:ŧO9@Rآx:}ݧ@@VB$/3^k/΍(Y& :[Y([/z(Kl'ggo?xgON>LbNV$W;Ķ``$-Bh k`f&/ Sϴ~"tdLS#'4T41{P-u7'@ų(/aaHֿx 'ْ+ڑwg\p NnU<_=/ .P^ >)\j&8o[lfr$Վ8,8wH hHY>x"+;_Ej_:Y!o胳=7p_SVq.C?)8h20SVODSU#_eKN.~$Sp1)ȌjU a`W1@ԿyYo̽ʺ26;|ySՃ ^qg1?Yʁ~>Hs{MQ ( tK=RQԚ "|  |/m4-D~r>߽0/ q_fErw*ߣT$F剁 +IeME_2ݦ"(/'sE>2Ib57cXKkdXȑm ꏤԎ!2|T*@,/gϏ_O6b 0jK٢ߵk'W/5Ji!()B 5v?Q(mY>5LK~@vզu*%M =Z JtSz[Ԛ@挫725qv<%v@@&g*D3GrZN8@ˁ0jlϲ{γH@>Sr{j^(b/+`.ܛ5A gn}7\Hg -`;2IٶTF"Abl o\oV lU *Ill&@ր#f'8*ӢQfH~%Z L9f[<-2pTfܨ p_qjǺJOP+,~X" jɆ@pfIՏj@@~=j8=JD cA.5籋& @@7|=hn''?P7 퇖t[(S[3~  Tĺ}**OeK! Lem* qX6,Kcmf   zV6M%~`GOv@ctnVI$:3$K og{ ,7@ElKxksdz#̻߇=ic;)kvnO'? pF/_4x!ɏd  Vt7 ѐ[D Zrߨ1 ~~+T5P?ed%y_]~)Xb-^k]%l@WO`$Q)+M̓f*C@/Q?}D|rQеf 2ch~@caR~4/{AYwuarX"Dq-h9U^& p{u@"}%p: p{|] RA`, ?:=靹:}qm<u]%J4<f)*4[NySܜZdG ԙ#' M#hJ]$gCw~A>+%BG .[DzM @cm~oF3 ^6{aփ? O9N`́E"vӉ@}ǗE|zw|KE6G<7_]&:  \ o\leMZHvT% eI۷ `G5X9A Ll dQQe@~F҇=}2Xf` @}}{z/0zZㆰU/eau'0/;MF]/܇ dv;윲s7uT>^^r}Ќ8O1[@%q/`$AVMw5'L㟝s`:[fI ipCm]$&,z(3L8ȫK nɏM0(2AN-ec[;K~F[|;Xܱ=%tȕkGogҔ p2zlAȇu,?#s??JɃOgD/ٺ[|ѝܧwB0^x ?wdU{}~:q`Dgɀ7Ni]B[־+MaqmVLYTAv: C~c(H=HYOs}b3>Hӗ.>_6nϏ& ?5@{( }ϧ"ˁR]==ˊ`XNk?^wH{r`[~P{ qg̋~FO!F&-A&,6=͖UwțL d.O# ؠpS 8DL|3`On!~Ȣc6Y~X}1gTA(c[ܚVq3h.3zNJ?*jI_ @`H{j(#-hKney/RwDI@Ҹ (㵩Sx@q}-fs,0F%wͮ2XA#d}ߟk1@y }f`pL`2Sطn*k۔n7L X;^3ULd@lE Co-Yr,xiooh%; NsC_䵾T7;)+sTHv*4N)ٹCAh.ٵx~hks/D+C%!Bɯ?oKOea`XמS_EIУ !^Xm+R`˺B8]ު$ִ"Q6bkXmQ[[l9NdyPĞ̾=7,8Y@PG,2,-ǃ3}(l0 CL{|>n&3vvl: 7(@|H=|0 {|M9U 1RU@}?.-%eC0SGm?Jb1ⷻ6uyXr3A2v kX25:?}8Hb &$v-HdE)?Z P0n F`!\c<ƖWW%-$9 P- F1|\YX`tNAXPt8׭+6PmQ)kMߋ0/ Y f, US F-щt_W)P} AAŁ航~''aoO$S<`y?x)ߤ}T'k?e akUOf%ms0I-$`uD,427&&B<_*roaOR*ZbIbEcD|Nkw@ߡ%Ba7`b+G~xXu~/wB[AJXTԥ@}$-|ؖїkz?PþwLdjSnG*\XJUQGח: CGe{t-2'Q&JD*WŽ3 ^ ) 9`\ zi쾍֌ũ0W7]l۷v x ? D렱<3XYcG=WAۨ8'I ?YHVkn4v$ Z`hڔ3{b4pM-~X-"4VfvÍ # P'? RˁTKt&tI5"~' /bBPN $?y,8`DOv6Zd+`̻Ypw5-) ɪluႬ~q!߾uSDߴd`΁[VLeAALC(D?x>6ǀo*3cPgn 0j%ҶH2"?yP7 /"(sGҠ#g2UpĬDDO_?B{d}\*nۋ ydwX8m@#$GwX(u]GVoV/HbKR53m5:%r uG@Č@81Ih s;q_ 0YhVPD"2؎SX4 ް$5' ٪lG LA6A2O?>b~A8ظ4yh Sq֒?ӊyJUpE "9T'tĂxi nX,#j' X/,-CGzvύ)Ép[յOlO;2j@ %D7W /x5@n!\JN#[ f-|pDgh :@I5ؼ]FzSr˶~տc[zDdz t|Q0F@<.6[Ko:#)t"bjpPwMsC[ fhAdTaB uHx]]L*9q"Ƚ{u$$幖:㟁 K ܕ.6=h *@ĝ0}WAտӕnQM Mo"AMIamhZaח& kMf;WMek&l𬿲 Y[~O_RYIV.>_RQH Rt?@c}9rB= 8(/4Cvސ0HW_@i?uA^ _בw-!`[fD̫z #d es jS4)g$bp~k8z _n)3zP( k{#n3S D5ᵤ1?8]?= Ylj`Ll[;ILԗ&j @db~ wG3~׬TGLX21E *S5Xd4 ]a܏Vow+۷ht`O DnSOSlFvJn>n#?Anvu U8~z16 hN~27\i,_P{@ފJn Sv/:b96Zjuی>m``0f5d-7<`X nQ0 X0U@V$D2x<.d_$ed T?`N$R VIyS՛ZqBP:c|o;B9w Ub.w{v":w]4l 6¿_!2Ε$@gN ;5Kd=NHپ| "'&G*G' $okl V@Xp:Xk! dU[^ m[v;WՂɃG(t3?Պ%/J A/I!KS@ 0UD2͙Pxژ{ X0+-*ÒxNħߩ\geEw̯V2p&h/_<]+VFe @U1Lvea`Dr)"|DZDE@Baۺa'@+梅hpXj'Qh(OF ߗ 30 ǟW 'πgEb&9L D00 ]it: ΔuP^>~8 _7@}*S5AX" V,3hY ֻW+//5F0~TX (:|=Ѽl(wԤ}k< եɖ)P\@w~e֓,28*3II*'S{IG!(W"NeyG tB׿R@3QEz;kŹu<'d_0=zC:^ *oX]MԮXV^QVv/ht1E.GNrAD$h c+L@XSvVWjU$x'nۚnJ%R(# &BC $w@(hb?Fd! J nwٿ'ढ़>Q@6%@\;GJ}77۩e},:2wl\ݽcS=hڸmY*lPV.`˗-[HtPWXW[97,ʋ"6/(wT%]?7Ƕ- > ܫRD?/I$x`zY\/4 a_$=3:oc[bm@{ݑ7mj"7@n[Š!9Fe }OV‰@[H5 TPCEG͹\" O ) |2.ۏ4mZ]cc}[ct{Ql,_%*+VWɷX_6%oQF hXUӄd-0"![G_e=&Wxl'* j({n wͲV=t)SOOs,odECP؉`1'coUmtXE+yp\7ѿ"3 -OwHvۉsCX!/R/{s zB`h P5 !X T]Pă8:.DCUnZ[6];Uy@0d߼n ֯\C}cbU}4j/v,F+j6:""t3C`Or ]15%?Ocya\_J'&_x/go 1 ^Efe b0=!FD<yii$,upXhp8dF@;_D Vwmpm5l?R -C}nE}>ɕ]pٍ ; n,K〪]q${*VbyDf3Q[[S)u+z+PoP|5r\;D4lC 0X~Cyr ll)  uV@͆DA6-1@A71c]'Kx1q9ӕ o`EHT+5 @{ Vdi"``lb / #Gi /gKu쾧ne@V0VT?7ÝӚ1˪}qOsw Z-X] Eo)׭҂,ۄ#1&Hף%@3~^ Xp1[\ZZ~]h^^3Sl{U q;lCֿh@7yĐaT B;P6QO 2?* P֯dzy2s5&Yd6xtAoύ;6jD-͚G3z#h10{|:2!J*H t= u"@{=P -(\ bqIYuMh X(I}3Ih E,Y?V_4[,2QWd'9b9P LoP/QUv ;g<:u$Ce}G k^P;zn}t/INz|u `+Íȡƒ hxWxiPkU,dɀ`zD97^)Kf5Mw]Z`7m\050և,L!A?Zo 3-P'uN3^{wΚ3']?H*d!:U{%_rS( /rk)::{clm6[%mY4־[%[-زCHLB@ 84i8 U l !CH9٫@NMiwoEsfe{\)\h(v\$U2s@վ 2m7%{&H}yߍ\U }U#\ 0  l΃ˠB@?lcE0`7#t\nh!HP%ғIav:?\Á\|f܂%dnY$P׆ol@@]k{djg :Aˣ$p[wVړ&֯ Y #H)w@{pۅ,,T"7X?U |{Zl(dF8jkۍ{ Н?l޶7"΃ "+#$cW9V|vbvj wt^{m^CK"')c!Eqi yO^xx²? 9 '¸b }Jz̀er|u=p5Lۜ:&DSedl[Cw @[M\u̡Ў@\8`PTu<1T̖".T#WeV#V}χ/@[CCԏ2Nh*H*#!P>ǏC @\য়.i\Nz١08HÑ铻~7;+2P~dS? g@Յ +ib X}FT2>9gPrQ`0iUcD@ @f\jwTl&є,rIN pC#?x}ٿ`[F^V+ x, \`Ui PྫtG~.~2 0AC[B ~3N 0Bؕ+g(bqNdZA؊ 33C*xݺ*jS Y+֬eh`0 k ;dIW~]|.+?ݗH}+fm{= GZ ?'1|Le w^!@''/f TV#p&f#-T}Oƪ;=v ik6uُTG1޸;@n!Ŭ_|$&@O_$Cd#x*uA ion<0AA;p彃7^c*@,?(THU(u=u+ ݸɞ`/n]n<ا߷iܬmIO={ﲐ~[R^ܴxrv1a ;sۗõ߃ki!;g#]}9d_Z`Gw #  `Gwu&;!@IFwg Ç/ rڔKkJzr f$yʮ` ޝ}ֽjWk9S ,=&u+z8ߍ~l. /z#Hc (EZ98o^)I*S\~Ou#p#X4Dr9) 1o{H@ j?JςM?Fz@T{L~_K6;1JF$ dC;@b37-+?dFdG6h)h }3FȭZyF!~`}n~Rn FVL}_ n \ `,;J ۆ_Gd` _+po#qPmOQ=DCH_ }x@/χ U;`H l* ~9z @J}ۂ"CU   I i}P_Å{5?֛Nek *d0X,vw-@_q"fynL{jQ{1_aO29sRv*6vP웊6lwe*;ZxJ}sܹ@ r=Y*}[#`.%E_;->,$c॑ @OG Ҭ\B\#l5Rh͛-IyI`b=` @ ?Jx_%S T 3Y/o@0D Б+C xUM$:YY3EEaIe3 -~>o=8UK:*AP1U||+Rk߻0D(G[‘%SAqJ~v] s\v;/Y}+`SqIQ召9sUfO?յҠXH39?pѪbw\c\цU?߮ B2(" ; j  1Pk_ރvVesuhN `{ֱS{|x7 0JEBhhk#͋vE/' bh׊P@$BiFaT0i7*EZfo&7&[_+AZCPn}E_S˟*=u| k(h@X̭}qE"0f`eGCBQ@fO49cSlZ)yO$_ԀRs<bAXh=_  Q{{c߮NǀU@@Ɔ0!;OiZvj ?L7󏒾=o{;˚ :6_}H+ 0,EmdivwMfKĬGNh) 2ui@P~tߢwo3㽹ltw;ٻG p믃/峁u<6jqpgun\ei.6 {B <33Wf(1Jޕlo@K@q^U6aT B\j{ ,ћI"`z#Ui `XxQi5F͜q@q?ស癀]4\VU}T.Dwm\9A? Y~.~ 6CŰL̲x9ɤ;-83@2V2w܇ OC=8ґ?ҙ=^v¢|>ήo Q{GUu'U(9pC C[Pli'<)˫̆@._ _ŭܫ1NE.#}58aʀS ͏ 1O=}d5=[~魞C[1%"7Ƴgׇ LT^ #VUwJ[`I?_q"(,̞* C58&86& @ӃwwB' n=7f,%۩ǜ`IO#*,( ƍX{Y ]lAU[ $ޫ0qp!b=hm,|pP|OuU@pt V%{ 2*Z ZO$A6=ؚ.Vt L} MNc-@?v_7Q9#f8(Dz9R%Z(ӯ~yފIXpt?Z&@d: amm{kOپ\nq$,d,͎&@U^"Nx_ɞ9^<}:1C eHi'ca: 8Hd@ ē@jчw*Sm sVXh$h p[*qF <Ԛ vץqk_?*WN/,1#VJKq<`ГaFh\Ѐ&=z׳`?_;:o# \ ̀Nߝ;`^LB8( 0샃("`O^vg#?-R }o j2cVKOg;k7x;SO3"$"p"xiON!h0I 6\w`j ؑtK"0jg}{0)7 O*XhJKb|K\KJ릑 {ejyv͵:pۦ*@5v8[ է`C`}᪰|.}06"+p/`TOY! JC*蟼*Xk u2y]VoIW Pc!#Npj҃sB#"NE N|(0 04(I{lNTv#ͼߓJ{@3Xf [Q d]|U0,+(V1YEK~jgJF@3^o8(* ,OUDئj@mҕ˿7vWP AB«]m㭋ۆ\[}p\cf{TUqO,0A;PS־ %@"Zs9zY%X 4c* z|F '5+zy6Pcjwզr7@ߟ7HO')hnI *àFyeF{@ `=2^paF,ېpA,h F!SHy.wUߍ qEA oãa "t؟cp$7̩/n_H;!ob-g9QaIbྞ];fJ-o{,m$H)5۞NC[i  .lw;ҕzj2 @,wg`{Ÿ%d0[  #Y;=UY$cU+NOlqMD|A{1/9~twk_XO, @gKE /٣ ?@UH_ `ڏk{ު`/H{Z~쏖>it ֽ-Wd+ aJ=k_xLABes2BD/X,#>N\.x ~j} @ʅEZ7#_y|5ȣf@=^Xsv-bȇQyzqn x~8BE"P@ GN"&{޷32jObᡷPuj p ` %|z?dl@̘Gsa@};2٩6 +a~!/ ۞N x}ސMxbm< !_io*VR( xV_.m.Ⱥ$ 6> *ߜU=dTj[2 "Vs8 f"@+W@Z $ʐ @mCg?U*"i`4 @x="Ba: Hp=Ӎ~*_{[79ڵ.߾լ&]ghe3{Ad|W@{o tUesع!op. ~qc.Pۘ <Q?b@s\oKLZsB~r6;LwfN8o5}`E[[`=l$t9=*VA@ ='yuǐb9YEz.fC捠4G?9VdPH&Cͺ OX_qړϏ?0ԥq ~o45sAz Wv"ӛi`):JhpaayȡPy.wܿY ^'b@'oV} }B%5x`wv0pw˘,5!B@3_|}\ B>NjϞb7%B +X/ " };r/zkRԎ\jxN v\MhQN&kmOg3pW^7zW ֩.rӞbg a~ [) 9}/؛w0*v R0s w3#+uHR?BUw7#/, -jeU}eS`fP\i72i={^4v"3bq@7@)yZ>z"8e},lzi_U=q\U 6D>₠$H\gg'z7g-Κtv;ݸTLAˠZlNOb8Vތ/"HGQ.V?e@EU Yˆ>N1x:H-}hK] *D|ȈK;@46RH-<șL| T8!fpe w s x  ̕DJ P 1f@[Ru?<_:;ԙ+#8֙ڞj0x}FJ%*4/h P5 IտVS*0o4?T^|fdłؖ@ "Z } /q Nb *`2@@ l*#wk}KM$| -X@~kmtvEwMYomkJgru_#3@c]A]``2MÅc%  ` 1@@Q$᏷Z.MKwhV{%f>JX> ^ ,Zg>p,͖ z\F2ojȠ Chփ{Z*>#H& s67{/j쨩 Hq Mp!?0E$/ N}vP':vόx_t;I9bf>'`k/@?/ tf>w..AX- $_Td" E2$I}N&|#@Չ1B@$sRUGZG`5oU!<!o2wdP5jLH{x_9!/FU>JC/i_jj\}F 9hF*G*Yyȋ HZl>D}#t|ka`4[+T3%PWUGIp>^Ed o8Gҹewa uvaPHN,,{88 pCpZc^`6@~~/#O ЊD}Zw"x߷.nU,Fw'?q&d=Wmm@5fS4':k(ŃkD"!~LzD@hg$ 狴Xj-"[T-RX^3DY2zWٿ2yuS@#{%A ZŁ o+Z,o爵pM\OѡU"xLqhr#x!{,z -V<w@ yP'=J u3tmC*@?I4@_E=ZѢ_&-* 2"py<@ģ&?7Vʦ!`iyw,Pe@2-1Pa,*>`*{#Dk$d G\2l9Pҕsl~Pf e[ lHf6FP80z.2x+D@!B@q>3Y]_x?/w?/'~on6@%"۳:Up 99<"i %ee5Q4@pa3qRM{Lg]uM" $"4{ˁq9 -ǃc*R:"Ȣ (jT0IZ8ZQ{@-BCew|?K!?|ny>7y-h5Y?VrWT U/ ĉL tJF<ӻ6,V]vdGA4E*wWC'1`,sMPs %3V#;=_nUJ߶f6G]WއkDK}@6@/7቟o!$Hz!{/vNOOQ0XzI\Uwu'W]XX)m/b`CկIUf?f %P[RV2gi+ /o|rR_JD4H 2qQ4@طs, T=$B}LIMCO"}s?#2@_7pZ/ځi ڙ$NxG]LG2hJ X 8sA82XJ5׏48'Wo6#sw%ĖZG+k2RmB 8\$ i_n-q$0IB@?i|}]p ߪ8(%;naWԜe0̾甖óߞ!OM~Fo޽x:-ҍɧ_g73T T ,߱) 1^Dxd=%K.fP; T8UM `2`^Hv] УDzk!`"Wx }w }ܬ57jr!<'[o /Oly,%sT#.1`+O={J> ]@X}W;w KCeAP94U0 @$`ݮuS܌H#(.; (( mI1`~ 0VOB>d+. %>ϹE* S߳+ -e&0o'U7gd7@BD$_t{DػOrE lOP Q?_۞eM=gpM#fMa _*# 0# 8T7iQd}d9wi{{0_ %'gvM`1n'S ~I1+ppm&2y_|ĒP}H͢F[@/& H@u_9=/ERTA&"XHK KD#z$pLt#x~sAGyҷ9]۬*׵ńh"ǤO(90+gI1 \OK&JC4@/.B+z"+@֤EJˇ*'e ~`٢&G_xDMrN|("Fe} Tw PQM7`6I0 Cހ$p ( &tNyoBps?=;J{>ZE?Zcwm394'3}e`7#'/?Yf@@UyepIX4@6"%+) b@+֭0\UQA"0BHu@4Dt lMs8Ufk0!`߀q$ @P)#b_{w}iRDt >yq.SK}d>>0^%tVX8 !y B\[+'#%wzb@q: 17Ry > |yATo}ʲZ+wn%ѬN?=I0 *={k}h5.`BCϼ=_xzylLd!!Rou@@lvLU7D@sXwu#y`wK3ۿ{wZ:$NN:[cx=IOMO{KO~'}k A ȟ}>߹o~ 3O}ah8 zZ稤͗$^1k6L@$r-_??z"MvF޾"p# y+a&;]3[EC"HD ܭZD$ahEM^W$'ƹ3 @`?w?5DB`cP)>B%[0Q;|!|*` P$I)`ՕV2pvO|rֶ.9w/b8&V !@m&6X=on-~gK>N- %PDV ;%"$ ċL8< (u}_D'~:Q ^;|#y@ĀK0<$ϵجRУj|PT&$e(S3#˂|5~[ 9E;0<Čλ\'58h,&;;K&&?x"t/|$՛>??@@AABBCCDDEEGGHHIIJJKKMMNNOOPPQQRRSSTTUUVVWWXXYYZZ[[]]^^__``aaccffgghhiijjkkllmmnnooqqrrssuuvvwwxxyyzz{{||}}~~=_ IDATx흉_}j,G 9 hjնikb466"m6QzV 5xpjl@E^P3{컻yy4` 2@RW]g>ѹ\}ge\Wmf@M|C㫞@0v?gO;%|%w,RɎz'|tsԍ|*58ҁY8hOvziTmQ&e D(<Ȑ.n'B}+,0b+,͎ Ahȑ  D(юwBlaj} s&f $c }RMoE~ a,9MO>Ѡ4Q_F`M~dLIp7XAާi,t缭Dy˳_9 ػ 5HUkz..DwLOMqM9`t";n~>J6r~_߅cnPܯfsەSlLEUۂH_#kcɚ~U ^9X%{ n4tymh 8Ni;5mq <A[wd$'4q>qn)J++ߠ?)pp}pq弇:Gc9y~|~lQ9'sQ d pAh>}TL@֠V~^rYyG @M{˨} ;kVC:[T]s@^;@rS  `ijTS"f5J9@G~Dp!HC(`qx@lBQ>j3T_cSc7kU&2Xz 6k> 9۸*?'\qO U1M]<7V,}ר-'Xpr^xyhO&[(pƯf"*ΠN>bk崧'oa\JMkPN"3('1qs 'YFn Am7FҒLN\`>͋P-{ym a?1:^E۷$J/}B0ظ#m1ψlr"hB5($II;OX3'taL P$b Lj4Ij3 T,>A Bm xPnx&(O3NCmȍk^⚡{DQyB̖΃HBT^'PA$d 2@ dbMڋ7Or?PT;9ǥUޓ$Q4 壾})|gw/=T;9ߔVuC_N @S{xqDuz]qai+3<3Qa  9 װg >?vr!U-+ Sy6{5=,_>tߥN j )Xo{lVKT;9  @SMbf5E8 n\ӳ,>r (4u',Ms6ѭ?ZGUEu$,M+{)mrg\FvQ=r]ۻb#gGK;l]349ZCd-΄F'OʃÞ=R#v;MLަ?Jko"3}2Z|Q` ZtX 4}G쇇X d 2@ 0^`%{_8 Z}/pvb{{C&z  (Fꄉ]jl\CфRޘ_kU;h)IbD@) 73 aV2@ d 0hX.\OO{SI]~C]3]z5Hv.G<7NWR] pxW|ه $%Tt?gF͛f ٽTtٯ  =ɮx 'M3]|OBf2R8{~=f3(H}ΠP2 𾞓IN[(ž+Wilj;Ik ?<MDn 6 w4eQM& ; kx&ymGh[jNG$}M;!ymݕr&*KUc ٝmPyHď ȕo0V땓W.ч=ix\@Ay<~hc̟>ⵧU ]dix>('UW}DσCgWY, d _|T^sw߬4M';moVTYtRS}жf:*ߩ>h[}uVS}P}XlNwZlMg `$*'dY>sYdY粝jOoWoqk] j'rZ3(_`Otyވ+z`b'rR@@o_eONd7"u2om+NJOo"{&cڹvu>T;AQ5->h/@lWz; M 2@ daCЩt&F0" 0:#kw*;Sj 2@=R d n6`ʺM0-0-0-̓ 2@#?zIENDB`tiled-0.14.2/src/plugins/replicaisland/island.png000066400000000000000000002227121260670167100217550ustar00rootroot00000000000000PNG  IHDRŐgtEXtSoftwareAdobe ImageReadyqe<%lIDATx] |S(ΡSdžB;mI-(K[Pp(oPQ(ABmrQ`HDюJ(jE8闓sNN^B={X/髒85|5RzQ϶gpCy՚|IOW }.I!I=gI'̯ٗ)9_kݙ#S/ʜRQzic{k^,K ' ?mSZ993+3{ig8c1wr|g[ϝs&{peF}n揊v.p_o|Ǭ;ICm(I/yEvYsc[zI?9dScifgĵzQ׸,^cۦZbaqu]wU-Zj5C+V䷻vlNN]}7޽=;e.Y=ݻMKKKZc3ڵk3*::z%*==}_nV>&ܹ鳸ܫ/:v "cAvzV$XO軲tْt̓;ʍ~y&6u/m(%eZ"c K79/[< ѵij" ŪGl!,wo>]4]Dk,&j 0|qU^X*un>۾T)1Ң1/MfOO0<>[0*Q|C_4F!];$x}m~?X'l^wBu׺|qLyi?+Aiэ} |{f@>+=1"@JtkW^iђHyQ˖-"#prͶ@vv޽{ׯj߾}~ue뻤tʸGQݲbZov\LL{]t9ؽ{uDJLL| ))i!YYYyyyB v-R B#256TonR"}9/}GNn:dk@=.pp= Oz(.@(&$H+I@6'vȟaܗIZpڋ)$''"]v@Hm!4nݐ4ƴW4/4hPzh \W mӦͭ {H?ҳgϭԳ Y]6KIN(HMI~(+3kV戴qVk^'Z 1D簕oGvע&,&Jm}B~.\C74#/*:)=sthmogHqlBD||ϿտRts\g歧3e;K+3f}WHxc"@YP-Ҟe!4"nB_͚wܗ{ ,vb Ӷm[P,LA* ]':1N{)]2'065sA:cmVΝ;-۱^zU"Sh>!!>019;=-u~fSS;wq J޽{ٳG9k6"%{Ai6 {zDBTxwMҙgD(?~tòƨi:vsdu13 eX8 btO)a"gS9ZP0O J\/([oQZUezѮ85EqM0`BG/?\S 7F0o{i篥r|OSb}H#c[=#}<3"  +ߑ'ػwk kF_|lrҀ"DZĐt\GZvӡC^?q,jt:/]QQ[SNK@8D`-SRJJJ{ΤpKRSSvHyh\f"D>#W*:մge]vH2-, 43,U+fq/?# U '޼оH0F,Y:Q+*OF:_jX-FCxoY$ozܮ9kȞPT,j0@\wW\T-s0v\xP 6>[+TZh/0|H /;>7{SI~`?[0.k hvys|>Ogo=q_}<^,g " vkVxohW&''_Dx'r4 5N'{k*wD,jB`}Yv~ӪeKZұS'QW^Dbd1g' go`Y_@dNNݻw,!J?D+C& $^$8_ G?tiii7$ӕCC!$&/dn?!/Dӽ| Ń*f%%)ĄۏH`B8%JLEnLY7퇣W §6>/,"K^=V hΟ@Ga`> 26կ)Hq($S P#?9o1J 83II4i^|W6K-]vI&89B i@r1}I Ii1~.%oHbQijq]|TT;.755v:)ؽ,$Y^111Ӷ2N:<zbRbMVV7=zCxkqY&Oڼ?S"o7㻌xs ( èiv?7e98,cLҵW (0?3co4ޅ)wqο'lL۰cǎrN2#- H\M҉$4絴Hj&%%M6kZ:t4ηDvf`ȠOnOXJFFԔ{ND1: +m[n&2pl_ww1:hWS\VDnyˇ7TFRьi ؀p H?Lʉ j%x-Ltt*b͔"3*2סYī>XIXa/<ˠ|^?b+D`Qg2VL_+;>k!:/ѯ?Au9Na,}C&We|_tqi0809@' ]w݅$E] iQ$lwY,w?$dffZINۛI^OnwVެu[hqmj˖-Fov_|ݫWw @c%cn"-qݾ!-5ekf2v";N7Co'McHKK[Ax?[kWEzot^@0q;ZD&k ,,-XV'~橢*Sbwt|OA]^@"Ũb,F 9U kst#`>cۦt\|ě8'+ UkwXA$'^1qm/aкpC9@#6?e69 %z?QF=L?3d<3?G䪨#FhD }OXF,$&H o&v{+\4Rdxum֭[lq]&{۵k/t\Kh_wgy]allSY]i۶;v|#!!wDD8Hǵٟ}>+h"pNjvN f($@Aa"f8 \ @eZ2c[rexS_gjZ<)d ]\m9{pUO܁6+j(K7.%iV:hl¥*,T {9V-b Biz#jQL"~WPƟ8*=xS?.fuN-(bwAsX7P;u?js ҂hw}7 d(I. KT ei-l~9ݻw%  $$%'_Oݱe9-[VA)C:Dgii;2'f3Co|I_@@t<9DN썬5WE:HQrx f&qf"`V?/LX~uP34J ٩]j`!( Zr&Az/-+8)Nv揢%jZK8S /NI;}KT]+P0(oXT`tNH<`_H  ,:U {WV39,`_ V(?,Z& {+ $,K}ILLIR{i7p>~Kb" ծ=r4#e#0wXF*꣉<6}j{~=Hp dgg{CtU$0(2@#  2JDB1ÄXCX 9,jௗ\$\DWWPY(h-H#J`RhfiӌT6oD٣9ծUՊlUήTY@GK\W#/OC}X*埗_d|1o:0ᦘ`C>Z3]n|"RH^<3 /MKns_@ oFz `JG[_~7кv %y_K҅I.$M%{& PRZT @N|ٷo7'}O'ާ珶ifm-igWD4Jr:D-ovPEj~? `/d4e"p H Pv(h^<֢ ZHADf G6vcD~5GoroCӇ Zzɕ˜L8M @ie}|ܔ:.ρtN_$J0:>+xz>~o9 esgFfrM+d3X'0Ҹ'@#Џ6O mAҍn"'$].2};vL}jvma=Dv=Iclt:e욕}&}>}m"!/"!uϱtncfPax8k-@ n~ՊW)}3'S%Z9pLl7iۊ}@B9V,)2JmD+ ; N{yjt{/~>Vg_1wZX}zA @CX E8n![Q<|?8vqf'_ҡ61͘\޲k jhZT٠A܌2. D$&NW6\ qƖ wC" -Iz8!0>{>Z7ꪫb(&$ sZtttwއnzUa"Rպ"@- 3;t谜ĻDJ#?"A>}m#3p9y!&LK:h@}/HDAu9a' 9CJyW| 2hPI,ΩUJK)XqRZ!E iiZZ_$^KU:6fpN׫|w`YrǴ^=k2By;1Tp,!NQ^ ;KO12X6W鬘0} jd{YO(a55^8K|z/"2~[j$i֍@$ 0޽ L0˭k1'++ߩg;@@:?gV}##@D25Q<` 3Pjv # Ij׀v5og< br#  XVW9~*͋솴?,Q >=g \h]ŅDfY冒G^!0daŴI)qr"eADk/nrdc]e`G,Ag/\3 @;#ʞti͋#L˻~o}/gv56lX#]jժ }v=p?Gi |op4߿EM p56fjtbߊ>!k}l% C:ޯ֭.IIIeVt s9KODq&PN-x3& +!U s$ױ=HXd"_wդ$饩i>MJʉXؼFDS~e~\|ݞ1L' Vlh|aG o_mY;MCbFd욤r.Ee8PP{q\ke(?3_e%N]ap?݃:ujFٙ@>w  X/44iRo!6F _:"w&`Gp:5]~ h~?ONJ>MJ r&>9ྯ]Ocf{ D@ܳgO D$:7q_ӯ_Q-m>8__x}C8$;`DEQ[@I]0F$( ֺ"mnW thj"( e\ i}XkSDcpUPKJWPl֋`mOė BY#@GlR@1C*@-7|\sA_ʗ]W̲e]ٴX s-nSxg֭[7#LҔH>O 0w} o֋@/%}vYvve"КL#}I'Gcp 2d ^Աcdž#hժɉNe6k&" ,is`rr:o/++ocNB;~:C}ID~}|OO>h3%"dƗhXd@ۜsCm-tLBXZ&@6.x"9xк ? "O\#Ň.K_1 ҈0v1R;!,x<%Cm@ H>V%xq!`zA49IE,; WP.Z<[p̞ϖ:wC `C>_ f(cZ>OZyH%lJ7Cx^EssT K`}o{"7f&-%BvkP7tSc" b!-~YrRGkqwď>K#1RIO>C=zt?ۻ9={|NllL5q""G_{ȃ,pocef\`a!e~~} f$^HY#_-rrx.*IΉ󉺇GC a aGCBy}vg*1{YG3` R 5 AU.&D֮sboAp\k ็/?LŜ!a]{k׮]JLLXiii3ޯD &2h$ Zdw"77))i].]%𾟶A!Ё% Z_zw64ik׬Pw{||DBNBwJJO?8ۻwOOO;.g{!>O޽z~~lLa:Xc OI+VdQ[`/f8/$u;JKƏT W2o$l %e>̋j> y<ɚt.,$hˑz@\``0P߽Nx!gX%|AD*$VWc׽Qh)\j0ծ??=ph1 YVd5 4ow[N!K4x֗Cߙ/ru>}ZFF߷%SNxnXE<ϣmI$Ѵ󦅅!"%zfO-.oDq%3@;w4%?]d%S]7cD`>k׶_:od@)weg#t,6hDAqJK@8Fr\':OޡWb}84R.@X9PkzJَ|jetxek"}z!@PِȫF_15ի}tŔŽŮj+ nxAͿ&yVbi`,8Aޟ2v,N 8_Ҿ}qD^"0ޚ"83I~ҋ{%%$GPGEGڶmw+k HHI"W 4ȑ#7n".mWC:'گDÄs>?g&svv7 ?d}y@ , ݉ҹ|O}PPP4EE_l:챠+%r H:>jR^ӢHW"]/4Q@l|5p> (!QE,+;[%"|pJ  ?%7L**@rѕ@'Ws^D.hժUmێ%_m"P͞$h6߿%y}^ݷw"}"@OHKKkKm[tttm>{$݉L ͠ǀPoF}=99 ࿰hrrzԵkOD~ꞝS}!"]FFڷؘo۵k.LX~&W^ @YN>D/ƂB4OmhnE ޥ~ ~C.zXߊ}Xy7? q7 +LZ;M:na"Rd0ӺhܣV:<w%7Xn. >\}p柚OSȴfDՀcV&-[LnݺN:!ٹs-A@5?V '77i׽" m#g۶mMH : w%0OI  ѝ4^Mbb?HzUʔy"RA~ԷO%#6lN;JDh  +/ѵVM\jH$ uOd9;8WRPl9PA{4wAukJ?wDs-hg6]#AD>rq!G-xm~\|,jtb/u#R%0:u=hvXx`{kZhtױcI#t. mO@ڄߜ@?w^Y~=[ccc 'PN >N^z@$aPFFF4gkw*a#~="iZ=ÿ"(У{w|]KqqvԱ6::Aqm8@A!8UR'*e哢XlX&XID" /)w.F $a<`_$>78@,[Vim\ cts[s*!ͨN|f8e@ 84 ]r\qrt""!kUV#I~4=III @!mVW幹9#n9=H}Opڮ]{|W>ߡv?KPRSSo&RCEi7[w|L~C|G%%%PK>)"Dc8E;:~y:Z" ;}4V8=ߟm!?0|{JTm0?W>;۪"3۔m+a;]6Ҕ.KrGXZ&iQ1cnkcݒ9o%SvKEm0rheZطCypWZAEGN-rqmϲ ?\Htp"(#i zd M)'X~lYFX4ЧFXb ^Jgʨe%`%XBl@#@?rC':sˆ[j C,|J$i"W\2ܒȿ=`bX>Q̪`Oմ8T{wqU\v? yg,Mz߅ks=4+\:%->23RB!vudlȭxs߀x܃wFz7K7[pcl+gS]>s!5J|ϙ$(>;U~$j[Vfc>~w_u֋j̀_pHAC,5ן0(qhDFroi D%2Wa|Dž؛ .%;ˁ5yE̕7g`42H3S@xe@_щͮK _8jءǔV({a]5Sɋ1ZPOщ&L3 |Gt `(@ӰD3ؗ<˒7>$v*h~;;, \Jus- XOLA!좁XVe1d%焹Θ4xD"M % ~r?0IRF8#cXE80 s2u'p>@xA bxCk \<6!QUկلNm|ύĂp]'HtBqfh&AXj~w$ 4Kf+ A<UH)glZ9Sihz2d}A&~ۼ۽N-&zLD=W'CV% `y$zyt;oE6SAXPO$ 4K_@h h9fqlmO͌  `O4df} !_ӗZW f-+8EQM(@Ƅ#.\G*rjh4*O$ óHX; u0a5|N$ċySN(Vܬ@2 z_y$V±Y"VF$K6KG7ɦ2!aWt1* cV;r蚍3l{sE@kQaKK)Fs0J.ݯUA婲,ScQ o\5W*++/DϪq? J:l0d o!O$ No ߃P2E &|/bٙb7=x1^}<^vߝC:Ɯ'-!F U+LvAST @$ hԼvlwpb|2X|@c !+{$*֩pMQhin}Y8_Vcs0V1+o`!&}yRu2Q&s̑Ǝ7hD*C%%nlG4R^%{а:blö(#je@ؾ?x;X7 ML~3 $o^00"IX|^Z1~9=e5pə>A64MH&IDu8 D(OkCYfKVͳ?z -s2T}o }6G7 ؾU+| S+y`$Ke:`4_plXM.< !Lt< 07Dp?@ F6 /[ṔF旖[]!MC*2WDsU9UN(Jk-4G#R'47uL+ rI`J71A#z |u,rJS+Vմџ{i#IoDTo"xK!Z @XpA.ǁB7tO\G cW tS@HI(L (?@O~@S3ns"6b?4b=2_ƫ0bf/,vfbFTrp$";mM7Ȁ$MPjf0WN,fN1l[PĨn9roifxT3 B$ kw"[؊C1)+;c"{haA>Rѧ@76NuT-S&fN#G\qWjif b+э9sfY| Ug0oS(%AދAvn/UK x.F XS8Y>{TOgc\ ͗>z%?@+w V\ l+@ָHTKl#% |gipEG5)+)5nشq %UD LJ7QPcL@_.nK\>vT1յEw͠['Fx\ j!,'ܭ B,PGp]~\X&Oq=+ -UgܗXptҘp)8s@SXGHb&/>h;ԊE+@,pao:'`7ly.Yuy5Ő/`ј0j/U&2!?Pd;+@i`9sAլH," e#Zjl8h_R{ @WML @C )w({T䀣#Ȓ1] Ч yQ7v)\%tЯ`!_IyO'. r6枚OYX f\,Z31ҔBw[l5a4WJ;/̀` Ff[Pn_M̨)M,T@ #*(F? Sj f["eh-˛X8^*3AD\]2B*>RڹntrHSH#>7Y[ Ĺۊ}< 8WV 7a? ld#FA u#GN+(wUe̗,M'WkPeImviyޫڌVf<PW^P[=N{^.7X."sMJŃȁb W*2Oc<A{VO.-^XZ6wt3,BX9̀sw_=s.F\[4"$ wvi~ c]\o~[|8W^z%Hٹ'+D7׻ )7 X7\tuB"eΦ˜J? rE:XPPT} ?p3~M"įb̝;S܇Ikк#BAf)DvU<όO`P59%+`:PE?'rQ {Db jBLAj>~%DlY?= |ona!RgyLXCHF=ր"~B FX@5%Z2uѐ8yp=Yorh/ynBB%- 5ޖ,K_>w9bYtj>;Wko\kz$4WI i8P(N1XZ(m&`01P`@[iV[I?*yCv/Dp3IW*[rC/bW%+@Mj + 0JF* ɓ>{щj)FܢݦW=!\~bC1>J#$b:* @KSӼHZ'3 3>fDv@#bi`/\Vg8AxhuD,+`P@ZL 4@1Bo߾W }76Y!Z%i4{e !Q&rgS TD ??,4?Z~ fE!uYD72u2RV1Dm~Fg?|byh3Ejp"Wqϰ@~ +O*)$>'R  _M&KH#wIR% P=& ^?l„bP# x4^uɇRy@&\%DQ2̞"fs7B)LqM%@$~8X!{ GiaIC]91hQ 5L7D( W}1Ab(]qo4Xk.}%}6`k@$仪AMQ!.  2wjlA#I@T!YN 댰m{ӊO+u P|9jfꈔK!T0bıQ2cwπ9$"@Ɲ20`,K,2EP PyB^'LQZ?Aka&)@ۄԻx"a Y Wy UfPR m!(z@i1pi4Vl} >;C)1}S5k [oxLFkiYm[[!BaRTC}D@7 @Po_KA޾3$@ֹcq )6"\J[G ű A³I廒#/-V(Y[912Jp3X7m.(~>KG 7)[[dSI9(5"DЯ h}tJ5K ji‘Z@"6 \a-&&rլZI"0)Y4> GQF>@f@EP>.yH:a&{qx^p3[IYs&^- -~oaZ&=4*\n%=2'ZJXʞp~p^Cv\7?z )clfDO T _qr,DTK'FI)| UQꬄ<3.rWVp Nw6,w[$ _iT3I2eDp`&É%kŎu8Go܅m/Ir;B@ZRϼl 7oSZ着\ G+(:Jҏrx1UPSw8TF$$ 9^C eMpek]<v N9c}M!A;xRK +/yHRb JI[@vNr;ac !cK,r+x`;oR /@qw|,wV߮rU])C±+?~ {G;#IN,OH#Zʡsv'9\Y}uJOK$K=:WN*o#!'Ot23# u6$!aKJ WCI,(ͻ Rُ77H&>,n%'JJ>KVBQ:'* b;`_A*(g`DYz2@-$Юr')>uF14nUNA@&hO$p]瞠SdFLȖo@ֹK.~d޹::IK_HJ1QDkf+Ifn(-|&=.?OҤ(LHM3]XEDz{aQrEOC@оu=[y鞫cD&nwg$ѣM-Y"}> |Ujn 9z@LWIbwj|Y&ՁKgt. ]1+AjK Ł0ξg3%.de`+3 / e mj~? + p>׎='eܽ`3g+]Hb`d㲭yrzR7X<=^8(fI[ܓ?&HVNmw]}:ɱ`7"ۊm c½GGu^y*A&:<_L+] pLz/O[䱒tKO#ђL(໲RMVVHu O' kֿ<'aQ C _=~ A`FPJ4~Pk% YH``oje:kT1)8g0gzZ:M ,~ǽYt bb/s|3>V YXG]ہ o|aAЦRWoKGz4r~lI:pzNv$H_p ː gl]B?)ɫZkujAE^ HG󤈖g敊Y<6Nip3%)ܧZP:"mQx-hLqX$ynZN0ɱ 鱉AfNq|~d?iiw_*ܚK?EYv?@Qҩc\_o`?@E  Ɂ2GXGr%4i$M"! @7NޘU"A1xm\T{6揊j*PA36%IP#  ،s|(J:0V{5`RWyFz`nz[)z-?I-\2>QPo~yqjTfѥ҉r,ÇU.8L#-;T)՞x[&OXΜ9#=!#"=Z"99 +H!n)$Djퟁp1F?&,yH:` B̥ja{s|he(\ A 8Xb)j%_Ϋ>)nT\\PIn| f6n Q1+Iׯ S&?tւ,wq|M8F87UUUJUUUҩ:uɪ2Ǫ~tmU'XfTb  OV/I?糼}@HnխKsYʍd wpvG@0 ؟WHYX @'B'OS}Zju`& p?o+:軺6FL<)A-YC( 0{h^myc#%HFj|-tCk{m%{LUePxVuAv7KU3&RMME B!( }Իjq /M3xz)\GY|w,-}$N$ 9$^+> j9YjsdϲlMg.mMneBX;[D` 1=)pr~!Y,|s?^g  Wg'H'okօ_ͯ%y/@2GRM;Lyrƚ$!RUe?΁4 к#4"Ϲ܇t(qJ8[ 2VVοWgřF7wHc>iYF\!"Ъ_/@}9%W?ցE2  Ke芠w"-s9 ҇z뚿y? rq~6Gw#Hwv[|b d(0݉', a!_ͯÝ!Gu(}H̓~?4D@!I K.9oOqKV( bd`U~!k xICa] !P"࠿ѩ(I糼Vo,^Vy5Qf] (j|qATjB7IdMb;&Ug;p?P_?[b%g!/lgG%Nʖ[,mxH{o霌Q#*G&\UHI 3QwCoQZf(Po "M(LD_QB@N6RK@~҄fb)BךIilz٩QU˻X_e3 ~F!n갸e'c#eyX|EjOwnlj<^K$ͪͩ^UZ ৌ3I$bF`_4A/W3+k `zzH(p\!gKW%qH'[yW VsֿzB[)Fb):"#jo4 <Rgc낚6}`yn]$guq. C4F'6)8Z7Xt 4 0i&}%׺򦥬e5 h%pJ$^{RuS\vun*"OP nK\__@%'z^\*geIw-LU&V9* `_m1udUZԑ>J^&mD2X]~c~)sANo@;Z.k+l/Gv (9C`E}#O.цd A[ V"*F`"NZP/ +%u@|;K1&쀣t2KT(}DiD;TZ|,R#CDTASySV0B޹8Y4hF|Wv3ۅ򥱅F#<,Ы"ǦIa6ظ%K\=ћh1V`lU:0E56: bvg'$cG_&Y&b`(hwYZ-MEtE @#I> "F" v3@i((.>w"oJ-DB"D̴¼_.~>a)>Nm ijx}8* ^!@1*'9.-@nw_B BR~MrAC#=\*_ :`ϟ+c-HFp@̽!f|aMV5 b{!.6 7p28R|OLQ@q`=B\@~g;-Q"pK~YrsRK%lKwk %w:g4ij=?ze0Fӱ;Aފ,9")`.IQgp%CORj}j~à }hj`߯rk4zI@CbɺҤ RU@c/@ s9T+seU9ه[2a[[bBC<~$$Eehoo+,Ybkcw  Wو m" l?KHh,v68Em.PZD qP/e|9>qGo@XLw񎑎?1& GLֺQܨVfƮ%۝HC_U'@s0I(4fV'ګ?i>"ã&\2]JHĨ ;X  ZBhV"QEJy,|h}M*A y"[-hF*P tR:Ǭߖ~{H#bP"%7]@Rӻ,yjpƼY(5\%IUO&$7RR0>7;Y0*[<Arf6F ?|M_*}`K ?ȔMs[}4{{[G0½73#YMxy<\-Y&7W 3 ,i(Q,SkB%l7B&4 N|81Fi-gY7[ZXaq~=p&R8R@5|o--~ bHA{>J-q}HlIYK[dɾ%e_~ϹZvKpBY"3q0 Z3sd49;땍kYDd"qb>=YJWOm|4Rs _:.ͻח@P$ PoI*!<1p4,xzLax{7tYs9S0.f! \/NyF߳$CzaYgnWr)ho0(FZ<&V.d[v@$zڿyh$@ܡo}J9T˘XQ((zi¤AJ q2,co1ĠlՂ&_K^#^O(T1LؒQ0EY`mI@r#K-~ XȔ/wώص@A~rpcKOS% -ԅj ld|2>Apͼ3>Z._ cLI dqQ. 5*(_"}&mgڰCK=L20mC[:!!^%gw,n;$!jđ8*ǎv6@Bf@(-!jYZZjJh30}=Gh,':\-l3"=3(ӧ @ݷj I 2Tk<}d,O0EЈD#j۔}'#/@=t|h i?9?BtD(S-kj,kaE5<&Pw[r6_:(Hm| v9ew=5]j@!:L)"  !?襙Y\ }y v!zrh=p1Ns(ge c]vn}Cuh}xqNx@QGlaH\ $@G޿f$%Y#@2s߯#UŴNw<|^+ IMw@7"d&fӵnW^#w__ D!'j fy({":A@kgx!@,DF}EB汷̯]OP* qJp( /`HG"h:}ݓ-*, 8O5ym~_o]!Py2z:xG.2zE8l["K@zťlF[ywjq 8=փp ɉ_@bQb1!pmHԏd?NΌcfsEa}GJ(D1><MsQ8Ժ"IŊz IG7 )(_"눱/*N,x5d5T7y(P* O4HVHP 6̲*DzkPD "Xlku dz.b?l~ߧ"}@o x֥I!ܟGǑ!8o$1N.c ([|h捰"}~[\+{]o1#@-{^x^ KCgq&9M Gȋf[TbLډ* !?7ixwK|%`0 CohT/'c$IJZ~}17ZzzC**ON֗S"o `*8GF4(R kKSao 0; o`$ir` `oN$^pqSZՇ];RCvj!P|sM% ݗwkndwqHLEC D@ީkDR*FϐɜQ~`D&}$PiKߢ7\kq~I/@MШxPSxLhw)[AtqdAxyebPm>/%_,\ygDR ȣ%}  v6fFp%&ԺBuI.-JpTxJl}Fc?}h}`ky  -&ոDDR=ժuFd'?x` kf (Po +u6,KBM7!De9п-?snʻ1Y}Ok ȥ#4@*U?G Jd~G^~t \+/ AbEAz"kr~_B@}MDf#ea_PHJK`r$S*CܛG`臧<@ İ<B:JXA5zu?33 /J6-(`ŎT0='VbjB&`$tSvXPullR"^H_3o wݭHOc:ܶ-*|idEywi䁍H 5:ZRN;߿_dmKV;t|̵xVm#-"Uv(j~k DA}~1`FxBYRkP~3;`]dVDk]u,k 0?m{gۊ|D@ܙZ}=GrZG=~Pjd;@4/ qOQ3O4 y8H?aR6&o Va[+_s'}^vW-Ρ)DR ^i?H}{-@RAZ|18_rXt2EdN F~ @*fрtF U(E~A<@(3{:@C`t $ Q1K _4(VY;ٺ$~m 򱵦$giO2֚B.!HSDD`#3 #8~m@c&F9?<+ h$e U~p=d`z䰼ԑhvq"tPa+ 䯙1~40 sB5hnh5(Lg")X7>@ľ)+T媁<@2 HdM *}Z@.\8ctA?frG^dw]+ੑ=~Kmo߽gOu q=sC|b;4 8o7 8ϽKJzx{'G$a8Ey)005o``*MiMHk(axd OeN6]EŎ0yJMSʷIDgӖ)@*y \ &5}o #b J[ uF?${Q[d`(*f~ C{o/Ok`Nfc\U.Ba0j{~khmK?>6p⟙@@dĀb1sSRdF5ƌIG(HԘI'o.SKGMKD%µ+j.Ra*Rɦ4ObRIf|\);VR$ˁpm'1<\G}*j["w#V joiصEWm7#( <;=6Wg[템%J =t|H  fш=! JGa HM?DP/'H`^x7{y@>icIЛkwĘ`PY@$4;ZD"'1h$RR*K_Q( H<"8cH>8}pfݯt]ї8= ֮߿`&7΋~ќWsf$  =ls@ʇp[Ofmc(-!2JDF ! Js 4RԡB#oʴR:Tvޢ$Qݹ_ 88x"u;Ţ}Hf3k" zg.9//L 2zߞ;rY*PoŐsa82GfC lAT<SAf Hx`1=$ъF&מЋljTsFX (O銼؇[]q{AS "U̘8?"|if?%덲ĨXH>UzV |ӣ_2j$+#I_Nu҃!5A#D#r@ H\0{Ư/,y+a\[? Ah8f:rA?pH?@ K"7 x{CO.Oa?93(pV{o@2>|qZ@=R$Jr4ŴY<4 U5Є@DP)g'=a$I&uT0sxXZsRir ٻǘތ$SH"wje džuM@2HO\Y^8K^Iȇ:}b5Xh I??0-%C`~fBL7b#oWb% s ӶcJ(r`s)&imzPvb$XWy@}ĚPU?!=F]RpC"">Z`n?f@_Ok  t% *f~ڼ yTL4tiCXSG%{VAuzdeV ژq>]5 /LݦDz?73,À40)(>$Ї_,L'pi Wg]W;pp Yhh!FX_l}LBh{{c Ykϖz"t'RX H$k-2_]pJ=>fA}Bι//L倯'Fu7(œպߝOub@@_,Sȃ7R7ao+7gG4A |HޝqUAa̳j# j~zo,4Qox?Fʝb%*(FWӍOlynDN$ 7?z"=@gO O |j QXe](%`TD#) vr$p?Z_o4~$ sضaC:*4y=ٮ|p©E4<?y+Z"@" hjs෭.|?C.6NLSf)7hqBzTS@}Q߃@% @H5HǏ[xO:̨kI)|/ $J'|u?g~ǽ{?LQt,UFޤ~gXf6I2q%dH j/o_!]ӟ4 Tw YF}_w!oI$[ix<-=P,8%_Qh myӂbMх(@|)Um'¡} zrpyKB Y1H@*xzf  .$2zDH@)Gz'u7 W `Iq(Mrx j @KP)@sFqG NU>Pu)|x}A_ .G!l6~{"? /<>h"lUqHP[{lIa!_$R[ؽ=ׯ1K޻G$x(nv~-+Glkڂ3 y.]sÅ"M~!z> a{ 㽖`BǞH-ldZ;=, -Ԩ\[I$>7t bD1 Z!n*. FBNJuo3>-k.:^}r?"4"A?& ż>O@}O^aCz>]ؒB4Q 5S"  @ B+҅hΩ|_ez?ȃxRg&g[ ɮ(sx{^v /NR'>,AQ(<~}? J&W~{eGcF^?/8̲#ޚk4Dc^{w:a~Nׂ 5pow ">0 PuV8iO`Buu=>?g?v{>ۯ7D,H[aW8 ޿0^T.% v<ό=%]?˗EoD%069  ~j-"@O4 YBf O=! i*yY E,6"\ q礻R*?>;#s^D}0߷(fMgQ@߿jv\GX:wjT :OE`J{/yA-E@P"JR2eA=!H4 `tN<>6_0j bjҢ# %DL>tgu'PvRGDeG@#{BPg&hh$;&uCb}SA@DII(?vm/m~&>fT' B(H3lSA*}$#~dׇı#{ xu 1v允:+ABžB: wbf@L .^>~-|#B ú,RaK//hрqΞB0+a}TO|Ė@3@Q}`*I_;RBNZBӃ@~@H-R+#mJk_,߿|`FAe0q *1* <ZSɮop wg|`|R'xIYڵ%~gk鰸R#p}ץ3 }}YV@^w__ rV{x幙)NJ.~R R&F_vl$WՊ$ /A- }>r' }^;R`UǏg3pt&Һe}FܛW bu(D)~Lu4N=lT Mgo/cOf}\Wr{pwJ@HGQUBdIޱM؛:,[>k-z&W197o0<*>=篶ss!?վj:@\2 :N P|OיA p|K&b-Ep^Zm}&BA-b-@J_ ݉\Pl:lfj}>B8ͮRBTHG]@"`Nz86t?ZXm$DzcU!1o?/xQ2 jn ۥcIǔKzK[,>x_lqK^F$참9wl($fHj3 ^x];g_n2KUp:q+#G^M)PZT|ɢړC8spd}xmH#Ba0/ uQ5}AޮFyC8$tWw}Ha:G7ێH7]!XӔJI ɑC6׏ ЃL[4@]9b ܽK:>̥7Ibp6 % >wJkn|%x k(x,mBm iB]o<s~B3_+:"1 Gn tPAū<Zl'գ?|i>[CKG58 Hwe9p>sPP8Qyҗ(-0+=Ñu!i"ԽooBd@7 ~ОOb~<^I}NTwr€@\1 U3L>#)t؏H( FcIǡ^@ Zjf_ɼ0Vh2џkĮ~5G u<+" xQ+}1@Uk{ `SBZd?_y=@Okd[DuHdt%Uvg !9 YjLlujv)Ua$=ŪݕmnCMϽk I<}СCv4E6mܖR)> "`Xw;6m=$69AKk ~qo}%Ǟ=\%({[ sX] Rǻy<K}… L1Gr[䬛~gʶ;C9t\@GɩU٤x @/ }Ag}oz@?b`r'ލa̙3O<;u["u ܖr >3@:^@wUj[h禷'ӯf|dχ1~zC|.n*`'+صm6vigJ<,?J_ZcҥM4͙3͘15;YKK ۷s۰͛7%BC@"Y$1*+e/ݞ/M6Kv-|Ѿu]!h >w(^|o8{T!ÓkH Pc5Z<R0e6~x6lذ`yyfVVV4hj*++]<:H 9r[nj &6EZ -ɗ=m?kM$C9V1+2Ǣ;v̎v8xm'k猿&v7C 7GVso8txL}lo Z y_d*'TzQn{?uW^a]n1ۘS*]z=渳=wrۍՔX` kjzp4w}gVuEƆquQs.sUݢnjlֆ2kZK6Tk%8 LKgR5,V9?=3]=X(3-TkcHS@رcĉҥK*k>HHF x4]y] i7V1ц֍cz}jSy/+rF$6٬_f_,Do怸}!l۸r`]r(|f- [4lFS%u=o!k'͚~f-o_`NŶ/dǭsɷewWDa>{i5Shf,{a.ؕElBVfD( `* ( nkJԩSy56jٳYmmV^SbMٖ-[K .* 4m-C;k;n]_hƤ8gZ Pŭy2dV[#۠ Hbܑϼ2|uޥگ齿*k`p[5u}hoͷsW{ݼ= ϗ* a'E kgyŷԼF@0j{ܧoӌXo-㑃_f/nLð6-yv#_xGc!TlHQ eee*3f 6mT# tj6nkjQܖRw6k;Ԏao]Xzy{؂}NV2 Z:Hj:r[[W-ay>xn!I] +Z Q[ɁEM\ ]oov/ٞELG]\RME|Xe<wI!{bu {8S@x>MoŠ6"\= At.n.^;"{EІI^UUe/))[ޭHCn: k: 4?9՟ݓs14I ph|@S&yh亪~UA.$gQQb{qT 3jWAړcO#|;Om7?o^V+qQe ,#i=pψ;l,wc=C"텡b& CıW?xvϢDVt)ߏ?liڢ㽨9l~/#kj#=],+YהeuQe1` sL!Ho(lVk5Z +@^?Rnki( `˜taJ0U$T ?Nd׎ )ZAzo=W,Xh (CC?@P?qt𵵵@"]`I{c/fc>ID 0& m92mag}5~w!?HB9 ?l2Dz. Hie|}o޷YY4SzO[ȘyCO-Mmv^b 69D0:joFAx GVX8|^?g46rH^7p@ QpCjL8Z_=|3Xw; <*6bwa3{~s` rP ϿAƇ )t ^?1 )tlr`Ƀkz WmYYG \O=#M[Ш/Rtͣ팦ݑ!O)j«{mШ@$TuZc"Z#>Z-Ol}Qw0|1OK<ɓ' swk;ttuN>w7g:آ3'.FȖ;{o{]):=PY>o'J/\luY Xcca#Kdݲ&g=@D@E`恋޿o;fb{oʣF늵OB"}<<pqLxyOѨ_Ӹ/; @De@\ʇmz{F %5A4l9ٸ[X孾\@ȣG?a9?yJT7#$wVf"8fTQ#vֹsAsͻ|ُ͜-ZT=xgcg߂XH~1yz\i˽KC"¼5{H rpeg Qލ{>4)߾Aq5A D%@REP_<𫯾ItU s{BAnT;6Dr& a(CϿQGYVݛ{q8o>P6ZP0m˂ j$2BjmkpbL `A 6[KߖuQm}bqѺtF;v:yd?:<$E`A:db{1gE ~C<|Yצ9gF>)q9 5sPL뿶'<믏2BbŵU? }wH\p@ZoGMl1]MlA`GwE?R/G`<_Pi8?}*lGF$N$CȫU Dpa4ےps/.<. G OU$fzM}}!|3<= /Ǣ~^' K\TA~ yKx@ uH@̹iG+ f*( {P:yU"!mPk:\_ "`_f.dvsb2BE/$q$Ax9ܛ"f-n$f00>Nз>a ?s>$zX "׋(Q==/V FP(OŐ*Hu@5t<\Oi ԩS{/Qu70ЧO&?ªWgvyz^Ky|0DD%샖\)oD(BN\x,6ۈ%p6t73D r - >=N '  `x+ "2D)u6^TIb'/`(FRZ(O?LiS8ȏظfk$G$!?:HM"kćC$@|KDsGFZm?_:O1mv Yte+}f6bo^ ]0a"HZ8@Ȇl#SO &A}Q<B=4 ާǐ #-"4QH'Uֺ^d?ǹKa}εr *`gک5 T|P8p'y2Kt `ZQ0: $üА:j?%laȊe\) `(EFpc@z[_%lb c׮B+'~vvfw@i 2J\[ *iH6=1 }7amJĪfL!w   %peBܖbn+5LsьGd"o5j! "azDvod~g}( ~zXzQH@K -^X %PiYVKWZ }ɳWPȶ6VddXc~55.?LQ?q f(-< Mn y1-1@ޢ/zoNyf=SHǣE@>}(|Cޯ5 ~$, q qeTx~}ci ŜElDUx}5bFXF(C?I ziAcz9`" ]zʶjܘGL-GӇb mC7'A *J>:I]D@Yi0ٸC:G׀8$UmToꉕ~ +kMZ68_>Ѐ(!R}>*@QJ%"_} 'JvH@I믙_ƶ5Tj$uE|gP ".b'- dXvnL@^ Y4GiCMżB] PO`mԮ@Ł~ nzgM . ם{]L ykrϴm jʹό m@ \X,8$7;K;J<`>uЌ"sk- :t֫k=>+0Ӄ-zut忸=h $~E?HHC:8 0@ޡ41CxEzHU:" )`l77BJlƇ)R@1HadWׂliDJ}JڊBzEߌP^/Ռvf$Օ)NɅhm4"أoa sd)m<5 O F3[-ATE=KhP}uO =xi=ȽS3F}Ncx`ʠ q?H`O4PCHd  9 *C]+|{&u!D~-0 ȅQFDG|P$"Hy"0HHo4gp;D; x}mҹh X6P0%qH75F (a *',Yei?W;d=}Θ z F ͘ >dn}1@v N_^|ηWZz@2!>N- Da:3A  0ZA\7jВ7M CaZ{K.U֭[O/_ޞ?~!:12@/W% 8Qd7B~|[Cb3X657hܧx帿|3(H QF|zr@1!`}50۪Ul*QϏUT:=7B(aeee^}V\X>W)mw畞{ݧx^T◴{dGN1D8) 8q1"@e;y}t?x}ֿY52[^Q_97i!^+M_^7gu:DG\ ABqY?Y71\|mҏťM;[ ʴ= .9"#Hm I$L+{BՒN`w : cz?SR*)?Vdih$`kE[+y2]JassELOJAc@@|7c,S-I\eP=Z,A eU!ğq хpyKIFիW@1oϜ9d&z TzމpFj`#`Ma׮`5+x__b`жzM+" JS{DWȏ^ųr=<94I=0п4Ty+-ucmXR3piEP?-0VP[ku_v}Ȑ&hDLB8]r[ҟYPj*}?EFwR) 1 7G6~'}"I!L&D< jMq i !lps: )8֯_% HϞ=;LEa!7 xR DRـU+Y!Hd`fVR& e79um#mFM Cta PgگA= e:FSWooJB@1 шD8Zk^c%2#jhZ h?ɼi-L5 _Q#$ 7SDxh},cr徙_|sܳgf@[@sEU ~1m)OR'ԩSK.u5551g{o&zjTGxF Q%U myV9F @3(%"j_okVTS_Z%OD( :VX b1u}xߛEH3L$5/#aOQn" iKFۇ a9<G6@Z rK/1`Ns @O_">65ԩS'x"(N D ":( "= >*@lC6bvc>MXfk~kEi#mQA* 0I-0uʁd$O2๱@d+؄#ԩ@3o:"2I$^d*(!`HZkUPfĚ1 qc|Lf<0@ DCiۭ*nٲ} yoy#܎tk؞[܎nelHc3Q044sFZhFOhzvP8cnʧ)U 8"NQrML\ D#K+DFH"0#> z`)$ WG>@ z=\mw̜U{ɫwC3%FQ|IUÙ~@^+ 1!PwG1W1Bh/D:K`x`c(`g4=~<.N-3Y&vȳl5lz'dYi[=뿦 k_v T04&(]ȻoiU<=7#F#g_A$yy@ӟ.4#ukx D`8pΜ"u-v lhE@5")MhSaT8~V$sy{")âUlx&i"D H%?&#ǔ0eŝ2c38YF>H`yR`_w.eaOxa Gi.ihΤcMꔴ;GkX'M6)rDQA _x_7-yhP($U@?/wDHVT`0H,y-NC{{yL9+.4o^q ? }Maɿ𲕢!zw+{SK^{93 *FVH>l:p$ @D"U:Jycp"y #"#]R-B@8Akg;Vso"% dg:0!ۛ§>={[Z~=1rE*D+ăwwt_P 0Nhfb<0ulkJ y^{{q>7"4#paA0YmdXP0C$(= W'[Z̘Y*'IձgRpxSFD@ 7R[sD("o(O:E  쓇}&Ο9$"|>"HW*vWB*H V*xˮ½&v\'}:q|ҵ lP4HFPAF"^P&8?@7m:hC_NP\RHB@)PSceӧgϾ#L@l3N;]D|A3ųOx&O=0p!@ =?nH6V~3*@޿Q_OoF DT0Tx( ?dG_YYZHY v&CoZsOy8 *hwlɐhmmT%U "fih?Н+&붽q@ˢ*i^*Q;vĘ7iohP1G"=TESy]qP&A2xG &ƒ c&z We G}hy@*71b%H}v)zt(LUt0?UUUǎ[Xn#Yr|s[À}>&?T+@[8)^>@ZZBD]H,vk[i:}d&>=$ttJy{^:M__gތZ(paq5ϙSS%y #} lpKOfGwq'ıJ^O1GA$uŅ]ŁpZPȇ=F^ >(K?C>)(-N/?WW4'+ؑ&c`I ܹs^<[9#o 쯙)\gvF;4T~`~YN4U RFs@ml(R( Dqb"zFN~lehcg U'"S'G+IvZ/-= JǎΚi7:^ϻY`m_do^>jq7oh-V69ټEA v5c A S"TA?-@R@$ZUCZvO)O*X@aL&0}޺ʧJ~3zFU<:njr\`]x9=_??SAO1/ `gQŀH~E#@nZ8ح7סoͼ_')]TGQ/P_D\]ڶ0s \ @s=\d# q.Ja7 'QQ"He9dDQ?աm $jP'{X%c$$1cnCߴi}{kKdOڇ?GDps\"/#Ր}V6hJ eZaHuA!Tإ_TPy(,% 4~ @ H T *a{T>FM]Fp?@VS_Q Dȥe0f_ oh`ۜVgZ'klpG<ZoNO^k0jgz>m ;+ cג$*+:~VBt3iה{(("FnZ7s&"/]ұf6I>!ȒSGfV-2#?jx91"Æ4 Iu#SB~|ʞV;3NC/?/LwND0rJ·6mUP6lXpС\ 7NUѣGg>%U{es^ZЧ H ?:h0(ʑof_lUSs.m`֭` pfN=\Nc! |)a ;Zz8@֍KOM ؾdLC,@A&=QޞO|7EP~(yj` id {K>v>7H%f?:uVvUwǛcG Ԉng){P"ɴJ$΋wApBE/lԾzM _|N>G s:h?gy݁Oc?4!(%R%|u|%ug{A T ?7} Hf@BG?vaS!'8 $Aq3-IĠM j f Y 4+`\7߁)%/m;TzpRC(#`-i 5ܜױ+Ս+Yilfk4P@f.L:ws i* Däc ޞLUFɀiUt &յYҟ ,p9w*Vǐ( 0Ol(DCq)bF?3_X?2/T%`,>/ *~G Hk-? @Ap{՘xZa~x=z`GTǂ=.?y1yLٳg/\%3,~pѕuC&M}2BQҾuJ~9d,U0Fgm;[Zj._J|>PNj 7;TBQ*b#u@Q Q28V!__H}RAF R!WQ삒^p{٤ID`%%BüHvABnAW,^^!PLZ@ǘZ, z"\m8'|=yH -Ǐ >ZN/%K^SW;{$osM ~J:r]ְo:}t@g_hSp?$"jd:B{sk]Mq~[\%9lZXp3ԍ0T+Wޮ)Xmj=33ά"%M`^n]w_NꫪѲ2ZٻDA*D^dC#|T?q7T 5E(u 3bkV:L@ޏ"R uk*j&$ 0!;(nWN8o:w}L!r 62Y#'O{ <-{p3j`T =w;T*RqH|þ~4o>ϙ=Ys\?yJLG?:%vH`d  =90ZGjBXA~2to gY엏n E5]L czP RF7Z}#T^1?隣:(`{VMVdab@2>*>Lhbf=„DY}ʐض*4 P>['6ii A"@W,]7lŊ;@͚lƌq*|,6A*Te'͞ 1w= ᑾk Ep*ڇݓY[E, A#;~^0־_J?rwW;nҺeP.ll6E~}wTǫfy_@ͯ|}Q|$Tֈ*"aãjN=:1c VY,uzvM@{!]p`Wf@r`,pŊes?*@΁99O '<JU@@[~z9Je#!׏xa޲`{8\e~46y#Ge@^~=tYԖ13l:?O!/oޖ7ZMsdG?J^"( m!, f̘i=j`#f0D;l_ {`vnVȪK#`Sum5 QH|]UŵꂟjC ~Ы&@T[0 \W_:Q-] T-!{Qp!0h_%'ܼUL $w_EFf/CGۇk|1nFV Ogcm폗1<}?+V@©}}TG&/Iзy ;u!?}t@_%ڙ 6O rRYǚK=QNUTj%vfA &S]lu) E\?l\r5Z^M7OmT.Jx,̚yu$0TIp^gIpeOIŘs$nInIﲫ%L9%\xVR–tPZetX$ܨV<E{^Ȅأ=[ځ*u-W̻z|j֯yVm[a*jK Xծjh''_BE5D|eY% qNd0Vi {Qc6L̈́?( l{~W ˆ8Zڽ4 4RgV=uuČKشcs YޡE\9scWVjǾp)s )p}%^" qy*^NT~bXgؔNl%Aty QugjFFW­5{௎} \@]MMMz^W<}Yd"!1c/*{A>iO9%@B< `|}${A0ڇg0[!B}` `Vxn D{>'x NʊrNʂpDUp-Zd?({яz% WWqFM _-so(nKx2|M," pMiͰTSFac%@z@Jwd 'Ϧ knJ +Y%lUwƩY52t$ "懰 Ӧ+!  &x"D FQ|_wspΙN!{p`FôQ;m9P \YYv~mCO@}?۷J<r|w|d q\R0p2܌3^d͙C<9DC_zQ"Ci'".~eong-?WɂW~M QzgE‹%bY?/! Z疳g[D wND!Y`jf~uDcb?qm`P%I\d:?<5g2co<h:&@Do.KJJ8h%j쇩%~F2zdʱ޶m`'Q̞=5T&=;"9"' ϹWgj@_%3mX}@,ߔc TA"V %w{bZ'zfJ՛I~?zaڻ%% @/4HY;)ߙ6dDe=ރ$^c6knpN"Ke0,#SDZ%Xğ/wY}  gr?Ap,2mDɽ e,rQ]b/|,h@mB@P[8 /T볥.Ug`&lgyuxZ.k*gw|@G%{gyDt}w~>΅ϧ@f*QjꛑDiT:7 2s5Q09 ɀ1Qzd y8^.9So~|ٯsRTFOh(vo(2i:l<] g"@A` `zB>s}ŞB|t_4m-tO-e6Y[V.Y_})>1 *8aF,c `Bi 2QIJFlեlL̤zv|>zEρ}5uV72 #{z Y{= pˣwF Y葀X>V˓Ɍ(P~UXY?e]sqdFsacM6[T1,aG*zE?>>T1(B@"t.]˗/̝HZPA7E曽RZ 8. &aoR+C̿$XvT}ժ<'aBM`՛qZF']~0%Cp&'cڊLA_3* /7أ["b:_<: `1?'aٲCe# &= 4T'0%m2vh2y~=WCq`-_my c?K{6,##@?'T.5BK%KwykƌS?'VO8g@> ȟ6CLL}hljaT'@AVjIFA5VH#!?M=.A܇l8B%ļ(Ua2x>~ PwQ;fr@< D!x ğ:"8:Ϟ,9i yLEocnD `J@ܱly){z-;fikr\s׏*2~/;#}(DR=UP!*nLw.TP CFǮ2O`j]:Q1T7?B V :YVPGӖ3g|v[o{~L p3OOz@^A,GmZ {"rr-CKل3{McZq߹=wn7Ί룄/_y~:y.<nUKD&j⤀BrYsf'Og pM&C77ADIAP% ƄuݳT =G?'ՇVqllL(6b4ŕ}G&Fg+ GCB 1(ٿ~H!:(3ضN4b660 3QaT]E= [<}|}jV`o*,yU:ˀ2#~&l &$ \Gf-ޮ9Y!C XoR:.l҂i>:u1k21pt>B\[5Thׅއ@ZA>81?A|ޜ? "}i@dfwN?ʏ`-҉p{!UDd,I"`|;Vb`ҥAd +Ȓ ^/-- Vmo][]?o.oٞ(ӫV!A`, :e,7 83'z C& [.˙hK)ݑqSwɒE{JJ#nz-=n_ j&9 ~)+ )@N?F-K͍Ǐ0mӽ8?"~8u䣵ײkr ֭^]r-vSxᮘx-eXWfN$$@Ѱ9>~r,Pb*hQֿrFw?`T qzXrb4y2 )h $93\Xxd@(&vD~'H,a{iwg.[>k:%lƉeuSED?aT2v?ed,WWWs7;vl8{,0qDH10 HX^յ?Twyd L-|hi+_E"_f`$@ހhwy?,|=%Q=V%>?4?ݿd =bc4% /3gx*C@A|"~ebsĀUNX~cu$KkrY-WJ/ae%Yc˘|~)[ (#_{ΠC O& $Kh7>ӞM1nh-i[dHPt? 0nL#~!^@C vk#=uI12MY e C*  _OHH5dd5`ٲIɮS3{tOkVot}  U5BCdǣ)U*]ĪVf9lUH?GP4CII%>2O] ik(d? .7i@%$8+rxA9FmT O TU[bXk,JO$pkW,DϵzI@wgPΖK8kThĖЈ-S2';~1 ~ve`sC_u@r|:'7=^6c#_?{ ll{MvD_.X8k#~r@uh@:`( ((V^/os~q-X,ĖL'i@}$[re9sobq.Vl۵nbϭ$Sd|h[,>@2VL>B S@ xe8ʆh$ ~ (H]# <\vf 6h}׎^{)]7ducnf@ܽ"Az{}0Ef "U[فڰx`M֔5@a! #UA>\E?hؐ\4UݸRe{.oH'Я? ͅP@=)@QyID$x .ON0Ľ=ٻ\{L`JpslME@c}K¿.NĬihabVdeծZ -t)A>\':FhI:81Fm+X`lgK-_'KQQ Ձ35bQ,nL}+Czn˔@&nԷۤ(U5\#=i,?r۲a V@]6{o]j6X*-o1&4' !… u`K,}ok?Ͼ?ܽ Ԩ5hqu*m<;O~Kз0g5A7% khh=vFX 6k\=lFGD@&E@'vض)YJ|k#kUeTG3VqDEV'"mSl%*\9ΐԪ%;eI)n(4G? \(O+P/}p TT&hԐ/ н=7O7m" ۧ|O]i ͫ}gu6Aׁw4͉(} ' C# v^,JL}ͫ) e>w+~[Vϻȍ,3}rQ{ ?O79} >]@R 7p 4(^c;YǙ5WVD  )Z qy>:v̰|݉/UД{=FQT|zE+UOV"@A pa$k0?J[U :AGQ=ǖ6MGivɮz 4 2!O`b;X [_@qg8$q`mm]X@>ZUE0 npWжic::(FD H,RM?0 vX5Id3 )=9@dQH|DKM#yeE.۲ϣ4Q!pǙeQ "wNd*^*@\Pafoht/ꊟe Fj|zd"a?m&Q x祬 P_dO"D+{8nu]zAv{ce21St$ "@kxA*H=$L(@A&ƑZi GU`Ūlb>lgGIĒR_7ސqzsܿYx4 _A@P ?< |;+`fH/m'@yg5?mVdj@ }!E2a*P·8H6.BD4 †DVNNS@rLƎzޤpF+ 6D<>vHL (4a[׎2m+}WFHsq(G/,-cU翁K?vUTc_7|;ȫW[X7 Dƭ0ќ,i-Dw mTq_"D *\$(ӿ\vA֬`VhfJ !{Z*"@Ǡ*`lqTRߝz`xZK(@RHC6@Ȩh-o+ζGS SOzEp2,>9YuUgDYU/7_D$/LsfB9OuZٹ/^^(È(W@m@ G&$o/w&\&xNb*bl8;T1L! ?`OzG|v j|Ym$6=fP&k"C&$@Ӿtݳ=:OaZصu].+ʵF[ZDxzz[ngF tcuT >?#w8( !ޓ/a5b9@tr@^<;?LЯkuڒ,?4]2@uPE.> ب-ڵqKh`Ӣ^t:0`k.(;l*So۰/ K.՚ /j_7Z,h3{UdzD G]l `jdӒ<>5E-hdDFDB=EU rDE4nޖn͔ٿ/1@A 4"n!ƴ6MO}g }9+6br%uH];Y"7i{#`{w%P!n5d# @ J@<`3#TMK޻]f@qA0@`jۮYp{8H'uO~/f؝ 1 @y=UfK]_7[fiSzB@,yH-8Iq@2xJz&CGu ĉz S|o  VWVqy&-#3N#NhFB9f=qyf$»- -:_sL.c[-Qл׀wwO! u:ԋ 'kjwVh)frP508!Hʊz~clk6;Ezz׾pQoPe'lD-/pQĖZ*ԱTjdp B9@rSb0+p?FbDdM>gׁA!pÉpf?g @5j^SS@L%v488"\*`ofƲ-9I8(oa]u:D_g۵mewzu1v 0e -6j8SP5> DGd׳ 2Om$"@^wPǿ״i.}˟ ty%#*LY\3"+7ml?qJ"@m $ԏ VF@-2U3"uPߘx2GrLF{=N&D0@!0hB= X?ZH=)!{% ?OLȒk>D"5bQL!@FxK p&8[*@xĈ誱݇[#Ci@*3%KQ&:O`F>^Y?H&ۏEXYsl5AB7n=v}f*RV {E @_/@7߄sUTpo6" T= jg uS"5[ӫR'4o@v*ΣR< ,kz׾SgB)! @HP^&bI]nxfc4:AV ]h0 /_v0jā 1zov P߽Tҹ@>ۿ[_?ܼ?W^'G|ةC _h8 1&:/<ïD|ͯ(NGBIZ pfeҿ[˖*i.}by\O'@+߯x4B.%5jTzf?۷ IAc纚,yfK;Ұ+#rnj_򗈨Ɵ^T8?}7P }7dɀLtv(`( DOe?xӻ1=婀w6ChSfB@1gor ?+(ÞSHTgF(8Siގy|\ùIl(b?G[Os󪶶VIWO,X^^nD%%%qe/ ְ661Tjo6 =byfB??`rfսjfg q~;~_W@_󊁪S0%捈@$F ,y6ͤ@L ,jt7n{#\ {.o4%.[6X$6 XХX[(9F`TA{ŊybȽRV/P̯?H{{j: .'0 ݻ#F@5N;_}UY_yUOw<=+׎ꑩ z$A"r,0cPEoog>=l .ҁ@uVzATA"׾@bDˁT04<D?*^W/6HDB>U-dJ'!D7۷m qg+** ݙ2DOP4)$nu5v>c ?do#<//D+dTI I^GW08Wpސ|^/$)x^t ϔww!p7:6'@ {0!HK@"Ck6FaB$"S@e{:@V^$/AhI T@d# {ZZ#թ}"`M>]=WS{lҤI<˗/gX(I#Sm|I'_xQ~3gD;~d?QW_#=~&U!sY@KA@|'}}ˀ,D|W}~1sD-Jb}?N[,SA# 0D{v+@o/ZW_*5+А'șz}P@9>UyyiHD޵Ō}Kz׆@0Jϭ5ltr'!Grj:`=`3~<&hwM@oDl [`#pQX<m=UU(@kjjb |<[/8TbW%_G>N1%8PTUU'ȚCP,c7BP_DR! JO>k/^~1@f8T/ɵQ%ЩuܺW\o+i]@ϵzk N?o ā@mq')\'"Nމ- 28 J^>7O. Wx맆#2]g$?5+FPyޞzݮy\'P @ZkHYii)s\ڨ U蕪^۷odq H<[JDYkZczٿwk8؏HP裏гcX-@^xc1 l_$wB{"yi(+5%F(Nff tr،O!#KeXPoA>|=uȋ=FW_ b@U*8Wle bsf! Uzَj}@vf_ ~]]!r#dP]Wd`OkrP_rl {cQ2{S>?q{En5 9qSG{,ǽV Uk >zٸS=P\ԶXVn(viwm/y J"PJ`z=*"Zqt/3 +`^DVabQu <A{X1, @R~@0pWe&;7B9^GGG(> h ?~uwwj?>^T,*Y~P-Q\C91r9c~C;ﰫWr_FT%M5{}I3@[zyp2;[Bv8%BpumZтJvB\Z$#+`׏?3@& NO|gFPzGر697L^mM6qNN Xd"Q (UB IQ2 6@n%VUG'kooA/ ՛WgeVnD_U~mFO?Q~ҥKϹq;y$G = "©ۚJ,l2b'Gɢi N\:{6-zˀ(CVh8'3#t,[[@ڝ;wV^[x3%'u}QiӦ1*hѢVϸ(𛛛gG d nc5%FORs~2y*~) fN5~I S|wdF?:=*Jb{y^zҸ_$Rvrs %=F`޽{+d'@*h!h#ԏJF\{p]5S*? nMdPB?\ [9v,0256.|u5w_臯FOmkc 4% 6qfߥe5"r@@#]``wG}dbiY;tׯ>m+tq;::By *茤IENDB`tiled-0.14.2/src/plugins/replicaisland/lab.png000066400000000000000000002004561260670167100212420ustar00rootroot00000000000000PNG  IHDRŐgtEXtSoftwareAdobe ImageReadyqe<IDATxiWy:u8?#u-u?.!50\B.8 @l6ƖlY-njukV[-vd!1Ii 8|w=Kl^}v-dU~ߚaE1K._\Mo:_Ncy[Rmo+|w^0ſ~۷o/nZ/+,G}ػwo?^___nݺzᇋ 6a<߳gIp CB3A?'ikΝfH]vGrܳXp⾻.-6Z_v~}ktp`1mG/It-,u=Ь7Q9ϝ;x|Aַ5 n}Graa`l Ł{,o|2cl޼9xM|˖-} 6` /B;lB7m׾ ꩧo(կ~5~>p7߁+_uۿPjZs1.\xxla5{hW808=z4g7o(?,3Am۶?e߽kwkz=Xmb}׺E}꧟CVWt_f϶0?箻ꪫ̗O~EMȼ?Os;any_^+?7M2/3d!$ŦO~RGD2`lFڤ~ eb?S؈ 7M6.AGf&Ά]_DUa,<3Yk:3ڷco#2AC|V@:1C/~?Fk?BVg"dC`$پ6XyW!}WgzJqhߡbuEK2;@q$ûe&im_fkL8ω_+o;r, -)@>F25=:f͝Gs{WqNiuӱPo @=3FzdD,X`Nl2id_ K~pwV`0o$PO~zI|?lx66p.`/KVfsHwhO][h5g?Hʧ N?pq 9e~ƥScc(yM2}oo}<ڤ )?q쉓 }?/53jiW_kfjq׶M5g|jl stuϝ/TZtB$>w 7NVi $Q*Ω!) L &SDg(#wsRWuYsz@\?L8U]"lM\\{i+ 5J!N|? #g!`8D<q{>s j=Z>kW>?7Ylݸ%O\ ܴ=#mpB^xE7]glhpYSsxvؑ;kv۶l϶67_K.Ilt6H~,4&M*q A:52jd¦JԍP5ac)yQ_~cC0 i?^#w5rBQi[CD0́gg!c}okdWwמbp`}Y>hĴe3ZtU y}&@{@v5cL—FI?cp g}8kc-u~ڒ>0ȓ5~MO31Ŗ/kwӯ"0:a<~w߿gD7c>et7SEO_3_lhCL6&9W|ʏ2ˮhYmOR<'B†a9x\5/1Zmلl|W+;|)~" +bUU; 6mjJn~0};g>/ @xZ;£LLO.{"2[C##uL8O}~ִ-e>#\lٱ2 ! ac`3BYўꞶ;/FGMxtsMu:o:98ȸ?kqЖ-  &ykܙB@rFR- -OQPO`%)é_8~箂 xh+t8[]FP"e*!>Q= )s\q߲➛.fjӥż 1Q9_f7n&"ub&?pN?vl:qIz D}cyM㜛sYcֲ }OgkhW^ 5}q#$))T5j^j`탃>;"$PRpKUdG i ,&-0=zVB0=h( 3]vjOe5u'Ue'?k-$k$\y@aZT0a~I¤s 0=Yw4 )}@Ӗw5_Bޡ.XuF8 }B@{UXU2֪;dPfiwqw3`l'2 qO}[rKaoQr26U*n`\ g؃y"0>Dl&굑mŞ۲o?S&cAK[pYr.WmE8O{U4()<|J7;ᴗ`x!N|g`+B7v;l\ {]*WTϜv-ljWo8IsYfLlO$"[-B&sCXq? p0LPm E, oų3t;\nUPNXLbܡXD?ר}`FS7jo 1:Ҧ4'ِ$bκ< I"l紮RՐ0Y.g3Xs὜>߬39]-w?[~x9tZٕ0Qiݦ`"=\qv77&y׿dHfe /mM ws@6[zb"7kxWf~E0:>ڧ~և2}4/3D-bl?g})>#:Ѻ,رPnۓӳzmnLַܿܟzh]■wN'[!\+_̻UO_J _-O`'ZM '8"lXx631ſ9P֨ē8L f~}' %|ׯg<ݫ*|g.m D[.E'n0nP:Ya g# ̨̦E)oǿJ=֭9i~?~_X\`_!֟S:s p_@C^ӰkW)._;`~xc7"0XeȾZ&bdfտDj_t?j?Wڿ̓{huG ?V{$_ѹV?8p6f&fS35ZC6t{5dn_Ŀ2)R͌;iv&6sIߠ T _ T W]*7CͣM7ʓrBac +3nM3>=3* ۰~CVႀ^ Zc-\($B 9+A27~0%pN`Hl`?(u_m GAeU_@γ_0_y+YaN }QGQ Ͽ{T#[#jpܹm$3x.##11n* 3O/?GheʶœOGsOP?k}Kځ̆¾aQ$zDx3#h&?M8Yy_FoµgN]bMoS_tŒEKN %>dg6әZ[ſ>"]*0ptT,iʧaaj`s*!ҕ;tuw}mw[$I%IqF.g֭JfHx@4SOBE6K}،Vm S?fDa#<>D?1(}>P_ꥫV,Z1Yxpu:gמw>v`}$b\4}{S}xk"8w;gkQ7% JǢU/S@oXԷ$rh3EdfDʗ]Т&E2ƙqp8LI4> ߏq!_;_r)nlE:X23'Huך3hP]tqmnzܲeJVͲ1 p}7@8?39AO4?S9bT~=c쾎kn)fcM/Icl$GOg1~p 8sY{?4Ki *,ܙ?N!6y>Ou $ʼn Ry<5R! \ާ^7sY`W;;:/:gkK?R㿕vVQ)CgWJ #;FNb(w~1_;0cpO UpX Zdg~&W+  mkTM톪{6wrTpWL^O16|yWfc£Dzޖu5#ghPNj#d_w9ᡲybcͽ$ ϩ`l44zYڔq |2&]pe*4 u?X_70ٵPq 8 :_`=}t7S̙ٱy8Pe,acaG88w^ X jg"P !}a`p U3+s DjS.۹v/4O @?25AheF &*Lb\ΧhH9< g3:Bϩ2۾ *}*X &|&#jpP~ؓ 1Mhu$2zUt=N؅.e_QȊg~oό'An}嫳`ƵC4?-b"l^|͊z?\mh†8p`FTxeRnw#;}{-~e*H|Q}85 c}ډ?p& p'O:]Rǭ'9pUIyկ~Ur>xҬ>cţ? wصxgx*ZHNk8xzbЮz`kz `,'k< /9v`V{3imƜQE?LTWB쑸o&AnҮUNqcE2y=P}7h3'5e+_qo:ןG:07CZ }i |?@[ (SgeU *|&~-_1H_$~~`r2x>ڗU# ?Pϊ\`ͅ yׯ߽jx؜=9~ޥR5) ɼnO?t>yA| XN0=d;3 ^ />O0l_6 ֠f\֖ʹVE?XWXE?g¸C׋:?,:Z<{-~/ }Og_i |Ŵ-@gV* Еڷ\aa~2 hh t6iU>urr>h ~y: Ø5,(ɡogONp| 3eGoM%}O>ǒ{DsA4q;&ơ]ֵ\jԏ n+GN!9Aȱ`^k{^#= _1N1ϧE8gu94Eod ˥qNln2=~WP` ԥpﺸt~p/ÈQzoXg>y8ƅ9\ %O Pf_ ˚lϿ v'Gm:]m VU{1-ͧnRh?)Fx']n /BDWPwec62m#MJ6 Dxn@E)u7TwiizxGa"}ޓW{«ڧ UÃ'ԇz-_.sNHk3JaXCa@:c?bnrȆ8kC9f:FepRoY(d{!+L1h?lEk\qo)cE26sf̡&6,~61oNa.ywLZ;?;e ?o΋/Xo<ت|Z["aU像 *|d1<;m `ó1~ 232H?0ڞFCޛ|N '.dKl$,]0C2 fQ%@X`N{648ү>p> Яl1 ~٦~^G#ys90[(L]E9A`ԯ93z @_{UV| ?7=b6T}rC4fZ|O{v^#PFEp/:YcY|<' 'O}9KIB _mn;C# &ѯO3MKFּ\!1V }*q6?;?M<c4nBĿ!ߜkUsHR7OUО.D r,'L3<=t{˗WwU"ZHWKtO0v. }cMy >0r~ûicQigO#{7zVz;py>m|` \izY1:~-1tɲs]mŢe5`zV'8ƵG?m1F;ɷLx o{ Mҿ~Szy:,*֮^[3Tj_n]eۛA%v 3~`hD}!v\7uζ@1@_70!D4?\q\uj@GL>_di+µRDAq JYP=OJb1@ |JsB${;m+ ĤKup6{s{K|?Rai?u[}k>Xz|17\rIqe[V>Z,|,|{۸MղPkܟ/}C_r饗NJko/޶pxSŻ/6g… |3ysG {a5ÔS7tO0K]zW^C拹z;!U/Q=t闏U~w꾖ƏWL Uзées8ڐc1Z:/ }?0=d<^}Q>qU:sT}y;*sE>M$PM+rqT99&igF ̥W0T>};ٞ 8nLl~&qO־)]/CD=F5=hdp$\^h Xٲ7`ϱ $y6&268o&??)>яV b>xl 0mp y7x n^󌼵= bzH6YCpx+߁е3\;k{7ϙRњ&g ܸ148ccSA 7rr/CAC'^8!R.S:1 [e`bZE-3H*GMrDeCH@oh |qKcJֿ=dUMTDk WVa>3L  1 F30E$|΀0Pј_|?և`O !h=<o≪]Vo}flp#[cpSW2Ac^nKYkPCD;0z7Znd= O}X?CǢe7tS3;}}Uk1?ٻ9 ؓyO롆#}Y{{2J24k|_+3c=|VG72sXCc7˚4<vyFޚ8 X?8=k2=@;D5bZ4<(~lRAk$_| FaڷL3WGr(Ew/,>wk6A#`C/׆1+9ND&jӖE#ϪDVW18s Z1qq-O_)ޣ{FKoL[mPWn7'sbi!8DLk=:|ߙ0d^7\f4{O@g6Y_7~i×;̧C_< &|O$=[ ȿOMTG,3|Ɯ#.s~h5\Ǎ8*Д]=9!FRjHRAbEhM V6tu/*F7* sf͚LXK8Wn5GWw~tSorLK`\-#c5jNXvq4]>c_OnFi$?LkX'mF7?⅐[&.L5Z c/ Gkx=ތ@ߘc \:^3'Eb 'į~g#=: ^&/znQo7T TAr|ͺlEVAN .P}̘_m` ,d{w.{7գz"@ /3ﴡ=gƧիWb192[SآvB沊+PTx4%zYЫ̞;0J"^=D'>qYא)"lt)EFSZà,YrJ@{bߪV^m~O"FL>2B<ӞnJ@`'\sQp|&JS#1?EY<*GVGZT|ľ(sz=OX`N(xĪ|j:拦惎pbGsZ.{$^߾>]%i.\7驆߀iǻj:ZN?+5 e :ឺGKy"lP0 Q 1@!Jn}ׯ9,cWj>bw~#o|n@[6_t'.Y&w+rhi!ܶeo綾 39yET333M}'̹!RX*ѿ|땜;U˺N -5s{́ _Z!k/ƠKslL .=bwW׭܌'?^coJ}!02oT] ̄@\?4b ȁ^ h[-9;lx;nUu('~0`O0FǘZ gxw0buD5J2174swJ>h%^Q9yw=AĘHڀЮ gxߘ\ga 0^t.ZYxV{\ g.`FB 7wVHu\3UbȮ~wPW+_x>R7m,w[|[پxEfz|tm+eoGK^ Αyd;cؽݰZۿ̏~O#R'L#t-gd L7%>tG`l\MO=\IgXWiw-Wxo}咕5O~;<50gj|1oрz<_ſ[Փ19LIkIΦ~#0Z#A8jo1BlrONZ{ 7ȣ}ZboZ}3.|}н.6s%uRRQ,e 4oʧ}>(Cf~> s{_ c1djfkhG:3Sſov[ :ׯ^W;8ֿ?k7{SrO 5dٟHN(Y_UkҌ:7^!y8,}Ec|J'##Fm}[Iؿo&{w'CtGK{0{>k0N#ۆAZ_wC"ٹU(b_믟2VNOHtt#+ /l)P?O'Ef* ׳n[zo4'2eZ! ښ?7t{S kP]oXpf ?F:`\jPJx́ s/]pY+ׯnsʼnC8 W[D&Q*?\Jcj~ܑSpqbν`bkч{EM׿nOQKp޻Fch63hhJ6Oj28ƸQ^U} ]/{/1gp#h&I{^+'31nHW~&"'bEW,]wA`h"s TZ`5 ` ڀqauE'p~p V=}= z@bj}>s}=P|F 靂"}7sg­F⵭BW^+)i4:6=x9khbA>_}Uu**QD9.@ZU4V M7jr>wopʧ 4tG[ǻo-55S?cJu?N?!]5z⫿x/_<狁֊I~ɴQ>VFr>|bܽ'3}Ojh8z5s`{D??,)|G8}DgL%njt{cmp1nj6[O]2m^ Y+##xP629 TWw|~^|_ȩ)N'}90>a:ۯX׽7M}an::}7-W_+Ŏ+xG+'2soU"9_GM~y}@Ɯy |+N%=)y)|7WeN7L:gg Ğa}g{gL]AC9 xx9T@. o_+h&l+UtKgggQ@"s$MAH*}'B5x^{E7|؊+'w YOJU%G2?ZGI7Ӹ 2?|`k?U<˿|x/[~zq'|7ު`U׮a߱e~@cCr4{ݹ8Wu;`*Ҷ0#p/]b^TQpڪ`9.'&VO2Of.?\3V/}gAl}m?F8'=m$$ ^Up G7cW3 ϘO2<|;I'i,?Q|bg+_):GsoUH} G9lsdgs=xxɧ;)Ga0|NPC}4XS8Os֯߼g}k%cΞNKF=eT7؟Up`?m /㟞9$5kPn`";>U}Έ2F:o$q@OxֿG?O2<[nymŊWD~wd뮻/~/αz.Wԥg B ƅa}{6X*p_Y/ј\eY88 ^k?pnRm} pC;ia I̗ͤI߿~F&]m‚[&߁3 Йo/hGk@* 9A N"ϩaxp2&S" ACt x$zW,_6Yߧι߉2Fp783Ʃ;_eӯ߄5qg M "~ٖxƺFc#3. F+)oߚ˫6_n.?u>d EX|yO<1?96_>}_Lxb?>HG3 Gcbce3p͠MyBO)`?^gR]P bz[-n ^/_妠U4-NB*Nպc clQL!џ~1Tї}:%}NGKcF>WoAտG'\q ~0*Lj1yG/؈lkǮLd`ǭG[FInHuU}_C'0Lu7Y|p`˸}^ = ^@d^U~w)xo !۰(o{Lb:f(X̜y "x(. }sbp`sѻYεuT?7^?vsr5苆_-Z4!>/%!8k8¨볟… c˸6Ǹ膫F.c\><*.@G,rh)oJA#ҰDj#QN4SbQp8*3Q{"ǜP9ֽ끀bضBr-B1Q>Si9 6$ҵ6pbpg>ߔz,ꁒ&qݛ?}=6Jlxda_ᮯ/.T5Ox6?m|gZ s^,o‚ >G?m^? ރa]gzw(:@Sbx_hhUp׫?z c||7!FRS I΁gbyFh:Fܙ`,c>w&p*豨G;Fa/9|y|UgZؾm{/=)~e'=]0^gR(sg E( CHYѯ ^+t7?"0VwڿM o~YM.+75[+:px_qd_-ho?Ld1)χ> .k|uQbcG>SKpb޼y2 YOax tNT]~T׍g)3 FnO$AA9 QĦX> }gx߼׬N8O%J9=0;gXX<=} Ϫ|]thr>xgocXC<8=P/_}~vYX IXj3g֕@6JL#h2}[ aq)jhw Y*!k*?cdN¿rmV}R!h 38 HJQ3`'jRߧ,/1w%8яLOͧmlqOo!"Om>m?Eur~r>x-Ͻ=,b>]7~&vp߰j]ϙ:3vIN-s֯_[eT;5շ߁eӯ$. 3? X ޑ^z-K2V&É"\!$. <0=EF/7ImS^A]ݤw?Y>m5 m/M޶57"dыB/ 2>ekd!~vG+,E-[r07a~l֡z5˺ǶtmL 쿲MU:g-2g~'+N ;iz~ zpD/ $Tv#mNX:2~MOYZ!ډ5%P1W!tNQCF6t]W}+vAQ7߈?1w]|;ڟO>;}Eb??yQݟ=B{  Xx~W3GjؾZ 13bO{^g0vԞ81Sl2T_|q1.̛% !s#{ƫ AB`}_;^gV|慙iR0.J1#WJ]ņl ^;"?#poL;(H\.02c`Xb}uoe'YsKzo&yKaHLRΧFZUkuVG&Sʞ'BbQKB͞]3/o ٗ9>#Qwsՙue,ɻgZ-oyK.| !3Ia17 tM%\Pg|zWc#\cS6b ohBe]/ho 7w}JTdKk?𾞾)at aښg _~wT.鿋!օN$?" 8C aR0`|q1( s$[g_2~ro|c>r)K|)[ЩR·Nn{?~&-3o>Lt3xL[a"gSL a\͘]zWq饗̙d1QHԳB֓= _”^ڃV%OxČ5fnvI!Seu!xǨ܌Va a|?zLRbOӾjiswTrֿf@/ZsZrg  In35F@P r !H Ȁ K & SŽbcs|.N%~o~S} t POaF^32ҳ{>Txmj&x}AACpܹsOb_~yqm EKPd~ +{&FFqgC`̽,QHdz-F(@5r2`CD4\|3)E]9Wn~ :kI_؛m`DQﶶ}ƀp4yв}s@;-g`:H=C"m3Wt;/4> Q׈Olp!ktyb3Ռ~%|O%5E?c:`?UFx-{744 mq9; ѦRmP&N3x:8| !+D3|0TBdЍ m!T {:L):O O57x0>pn喺Vt-D1(Q37xC+1HldGxl&s de M]lU\?O"FX}^"G[+F ٯ (\Qt3a_`ǀ$u rcj@;[=!mɧ~lp*l*hP>隞% ҡmtm3n( 4eHeYpo 722SD6`dSg-DRY}9PTnb y9 Pq_^;'8IB൭%L9}GDY ֑RhJ+4< Q#hK16t?6Z=@1|0cCR;~kFH] 5OUǫEߺς `«to_ձiwL8zgyyWZ\@7c@:崡64ُFtw+)"' Oѯ|liE/^:DkaP`,dԹ́S2;`ߍD5\.aQu\GejBe פ~a~Ι"ߌ)̟%Kd) P1LS1rj|X_`| 潗a4]bEHP@3/h'د{pUp7&C@0,`mժUτ@tOgap|‡3>0\&}?[?Z$e˖͟?FgNbPm 6O9.pA}DȘ^`{9„zWM?|<óQ|taMnG\ٴ Tj%0Y>y` !0lxwox"µؾ1!KХʹPq7#F{3hҳss~aM0) eB = ~1~n6<Z .&~ +C K Bhk!{MA?>hFߒ`̫4d]1~c˶I{O`ͲO^=w܎QFż]{/zT[ D~\{t+Ҵ.|_1p?Y>jى?, t}8V崏o>uAfZ?@#揻#8>;-0vDEUq/&`ƾG`2_X6X_OFk!= ͸[[| )7!ÔԼK09o mVH[h#+?yK3l] c/Rvý㿮ŝcO~ZsP=i9b`}oUח  y 2DF "(40DvSg /~6e0IȘi/~  'Nrp)Bk'7:]g HA٫282X( J9^QqQx2abXIcƔөNtIԹ[uk޵ֻnݻϼ4we"Ze_il(o@8/X *M6!1Ct8 8w}m47)"@;_1SO-Y9__/sgh Pl0ah2ESޫAsWhO; ̾N`+6-l_e;c[~cLpZ9'|޲ AP`"M>l{W̿7/l̔*`咧,("ZrpCm1[dܫίxxẃ;#G9wV b'ăg}!9³tvyWn-A=jl!yoy^ZgdA҈`奎D1F+YZ!`># CNy:;~`?m F* $Ժ**v#LTM${罳y`8(qOaj|j*\V5|3W@Nmvg5D)e "p #J?ǹM46p#\+wEʣGNIwP;n@/MF7 rȳD Z qu|iWi.۠ n]@"v.kXpne-%7OL&nhO S備s:ڙg"dk (,aR \J/$j=qos}>o'. xIs͗0\y˗{LtDp>R*u  (ԮmgzT\k Kqwkr+$㬦\+;Ld GN]ZKKzQ؟rGq ^Q>+1Y?5cs-W owg{˩AL^v]q{$aڴiu,<\ YT3@{$L6v1 O3⻙`Zۗ4 O[&0&\er Iq VR0Dz8?DDUܤGY m ] Y Jy.xz_yv|Q8~;n$-]Cpb)eD~(Je0>;C=7/v%B_v qڵ'߱Eogִl9Gvh,c66Fz3~;S Ў  <ϙ57m MO@Zڕkq`=yi.86<^}5p> Y/}֝_R備\|*緾9M[D\Y5t`l HÎ]i.?j%/-vE0q5z-u|iъWMʴ,DmN `_9i"J|OeIz<v;@[.q|[>-!,I !A6%i< ;wklMPt~p~_3iR~ X39+S f\D996TB .39092G REk(dN1gm'TJ]{;x&l( WC.W ~C)/P^ +6s_LZ&غvc󒃪y ;or|WEH0휟m1#qW_} `_9C칇aϔ7j};K`yw=U<<4ZEr5+^]\/srlAp!'V7OTG8$}nz/_w5s=gN ~<[zU;fNkn~eŕ;+soo/R[7UqѵIMww̹ݿw=~yCќG8cw_Ƚ{9&r>_dOpƻc{QϚb@L*ƄvXCWV E˞jW  vUTOyTMjv?"%*Vc NN lp|C]D% V-)蜀 U)c}2%5 d{,쯂?I)G\xe؟AUxFq?*v_Zyi޸nqd8W-~ rRN(Xi61rC!cw1<~e\4V @l Z+w(E[w39sfU xbh` Z5Y7x䞇<4G>\qMklK_ܺ +Z;|/x֗Rn$on %;_-۫$ھ˝vt勇;^ yiK_ǣ 1(oʇxϞ2myo}n+{-/}>tƄhSLvLS<_o֬YcniC^ 7 |HAy1b po ",*̙SsL.<*mAQ&\{yx"1,qw*BRA4k嚹v{ី7Q zP4i*J3X3fέP""J.&Pҗ92NGGɋҵڹM@; Y}>Z'@rz`BQU7Op6o Z^[kX^i3z ?M,~jvOS?}lsDcOZ)|gR/T5@e^öuEg _r0l=s(&E&'e.S=4bM**Mqu0DK(6yaG?Ǿ?d1CN: ޗ"+F}0✍Vxw\!'N4&'!`biӯ`A%\!&ZUT>w[q˰,IiiW~^z[e{]kCEh1̺9M'-6z߫Jh>z{3x`f={[K4Yʺ덳W>2c97D # @8)'KJJ;oU.mpgb! ë,^rq }AN Z"xWs0K*0mlo… J|?$@\҄ 2>m้=!A_}今AxobzӎojB)'>LG8 ~ T fRDZsH7Jo@ yX0a&&?R(QGUYPM@K7KL*'!rbR8yy ̋*܀ OR: @Cg0'2$AÐg>X[S78Ț%eR?GNEFEk-wفC3~{D:"퟈\Ɵq!Fb 5?IKU\R*&@iBh祍jD(;Cx7 YVy+m/~a/%1mW?}#@p!H6Ȗ~SN>Sژ4A1=y#ni' U?4!g<<3{qǟ13U<pVf k$J p@[kSQ%N򧈊-K/oz~_Zղ4 (VXYl";_FXe~i)^ a 3ίD$sA|I35&~Xp/6lIFH8?#',8W0!pyZ _6E6<.I>oׯYغ#eXp ~֪ [/[/]l )eIK#BϟWE@;ڄ&{4C>IMExXkrd@a-8?fbc?UT]CGm1:+(j^{ z,_~7)'j+Ja{{RAI{?SKQ*?bUTM'1Q2c B@]V cHIJ!O=TId@W>ŚS"`Ge"?Cy c q3hS8W@aT4t]W¯үQ)G+oϯ{/{vy k* m=ڮW׿)L?o9Ua1@,!pA_ІϤB9$28JJ@n—|duw3(C$^p'RL>$7%YΕG gqƟj,Axތ-WeT c˫8WP6S='v[7l1ϗ=}}%SW>fMe ȳ?JBP7 Içj3i(X⎙84TU&z %hh& $X Ev4J&_]>zGs!Xx؆c/q[%ٴo'هPɹh18sV#6m|Mg7p)i[f~Ҁ>m&@~$?Վ`W1yK[gR^&)B ]"?$&3LĴs^`b8OKNt" 3I&yV~>ـ i?"Kxw)]xd"g=ŀO[%qs6L_i DDZ͡1B%gp /@ ymYJ._-h .3ؙ R"M+ևF5H&vLRr 8yؗ J*,&Mr$ O 3㐦QdI ɻ$S3nijD .qjW4Dߐ9|ȌFjqc h}& sVq\|!\8^r%!]tQj@402+&18΀8114H\?r/Uk+dN'Y+\53"z>:k_kIImi18šD"8?I#, %3񣍬_,`WA>*=a_ec?ڴdv>hc(ρ<7mڔv䯼)%Y?iN9?DUc д)2}ݗ? IxCLghBeq ?@$r@ xC -ȑi5"LxUZ3i#hL~z0|y16e doڱBHCp4DΣe(H#R`VI@ME9s+V3s{Nm{_/̚6@'@c vGׇZ6σSchN5g1vx>ϸ" c2 y3xvj<@7 䢾%3_ѷoì;7$뗌GVkc̾ ɊYjDPTTTl>}zFg yS%9Bvoٴڼeu%WrP_t dL2/-39Ę7&& &p&l⽿T=rژtpJɅͧ2@*&e& H@Ƅ$GSU˜hH"I@. |qq5/__E!  ;x?L?L4"0fCI) hF{mj"Gv?cc1YP.H:Ono3b߿{wq]7[mZϞ>>wں7ݿsloyG ~;Ÿ=.^]Ϟu0;/`xl^` =Ly% S&9  2o?< 0>~ann:mTImwǘ~{1T}׾կ,Tj{wZ3 5%qԉW?Юׯ.lpEAU0"fϞdSlW' K)j ?HdLLך:L@ld@/?,Ni}αx1APqLO"g٣39vʁRP&ܿ4N'*O6ҟ=v=z frC߀Lz?hh:~pl$X<ɎhJ"W;~vym!Ø ;DS@ 9~j`bV/+i{.ogndNs17{@f/i`ZϟG&ဥOz+.Zleǖ{|}5^|_lE%{bOWg4c> V~(\)ʫ?JS'M xL".9~Iޏg )`rRX`dεZ$TL*%,'&m?ĒfK@&;}N}׭[r ԗMN|g$C(wZѸ>Υ9tQy<@doXONA9󛞱"kMcctَCHV9[bREz>L퐋{>^ wZ>?k /U3Ŋ+=xymhsh"6c#.] ɖ[عV*/\O\i {t_Jڣ0@y# Abҷ6Dod1= Rl jOڠbӃ}<"-)O@ـ?]>r}GZ>ВPO*~nQ%z?h~qN`y"gz ??CcgD?)Bcg-@GK3CQZbl.?# 4 L8fk @ŀd}f睙8qb @xt :8ۼxZU)f׃ozz-,Yp׮]UxZE & mxۡ h'q4cЪ _&gnc|k g⼴K;da⡝sBX&Zܣ@LfG$PWTO:g}WY?v\awm1w;b!-_YW|4Dd 6^d#3\8_D nſl_~=P)so/lνA)F.VxZ`gCRh SKT LN]϶+W$1ŋwSOBx 70v@Kx+P^1LiKK‹@"/ /01P-c =T8ONC"00HOD9^{f?KDAc}nL]:aT+hZ7vw ixLCd\hGm@zkLڞ۰l&.fZ8vai;6c6zyv_ѨW\g?]3hO`a V"'SEG KQ Z7@~T=彠 1 <dL}?{?)Jm!Y8S8Vxq߬_Q(JgǬEnu\h8aLvU?t+sE;0Y+L`\קv`ap(7<|G@LW P1yaI=H"M'򴔩J]d ?5!8իW2&;<_uOh4y d?~wHq؎vaS۩];Q@yǢyhTlóMOw, MF?^D q篸_|=yF@xW4?@ydѵًc)/I6z& \vJW ٛ=W[vpB9Vnѿ%kOv+8fSݯtz/Qń~Fln@^Z}JԆ&E‚`/Б"T__%}G̉x>kdۅD2yŸ!/ K]* ,6hv;oցlȎ+W5E '0-+ G, 6 Ѧzp!k~?L\;&\Bdoƚwx/Q 鑃`/@#]qNG df=#JBFyDJ&8`}Bq?"(GD 'k=F 篼Qh2sh15s7|h@pSO;ؽi[Io,!p,{J/;ԼGx[5&̠%(hN0w"R"/l~w=&,Ay17mHd ,W`( hވ#7//[ӊ`⨘3gN%ns`B c)(~ ?sF˥mlL.mlCcM9/J/T1b.X~:~ &a&u(ϟ_*^RЯ""7 /cO.G<]GNm-S *%qhcO>ކy<+7!k* @19u伇,z˻ޗ2;*y^۷o7:ϟh }Uqo9{sn*xϫ~oMޢED"䞃gP:S1K0ӳV'$SO8# yGǕOapŊd6/J\}Օ|\s'b Atĉ/#8i*!ǟgsU_&M<X@kO{-'%_y*d+@vnbnSq} xpIcX7ݯcr(wX:: @ ~גfG|>-HCRtI@@$:TH:b:pb4|QMqo'NS}__u{YU󮺭tmW[[8Ĭy+tǔq1G",9j z:ZVCF񍃼TP:[IU+6$cpcÉ'!kg5[T|{ ˶?. MC8[KGult0!-I@( H@ z:tj΃x_1yEn|8q$'_$ŕ~@~ϛ:q @̫:.]]-G[h&D`E  `] `T `7::t.wߖ0H2u;NI 8q$Ϫ)Uﳪ*@+&ڭ xk@yB] ~:D l Z p`V+@gC:vTp ۦ$ޫW/J3 Ɖ'N%[^zǏ!x֗DNѶM @pI~ yLs̉kԶ%KZrߡC/HTh't'vjC "aРAnē_|Ν;azꊺ]v>ur|M^ >=6&Px7-|& Yϗ/_Lnzݎ$"{-5`/dZ Ho|Pn" tp[?gϞ=a1q tV̀ㅇwX=jӣtb.ؾ9 cˊe7xL׼sTK-,qId"I嬢κ& T )zSD@ր8]tKu#2F&H_Мx}~Q_W#Xl [ N>XWBoq%.q:Rꏝ5/;Qvk;ܻAG"u|xi :VC1 }WU5FwIF?ak}) ~ @]w8PԜ0P6w޽$.05DoG~G,Z? טc߸hGu.ȻCf+Y]{O<~B OZY0L:t7rQd"ݺuYE zծ'z.oZlH5+n/j u>v5]+KĕO#Y#ŕV%_h -sw_o{=z{|ݐ O7km+@eZ8vr7;tlr D &ٞ %zǐdHP9_^|(׼j![=7:+V~׈W#%V~U>"8B @iWTk]juY-{ԧZNVV1^Ǫ}ݷkK';-[)KdT$Xp ʉUuhfH@.\I,)ۺǏ+k(}/t=ɵ[*&-pRNK˘'?ү3.vl~ȀxQ %CPQT #g#}iw ͛\AI@`Bkk-uHƥ%nNuM_S˼ҫK"o/KNW$uB YY4[I|JWAw~=e8:0@#r$:7E_@:P `[O:56A >;4 0U`" B\/9Ա~KIǔ8ml{.@S'<{:Z /SJ'eZM3K<`?H/n@YxA0}=\رFk "P /nɁvT@6", sqk,_LKuɕ)I&9 ?āz ǜ8zHp 26Eۯ0l%~B:a{h&ֿMp0bVWd@x0#"|82:ir[-o[ؚ-E޿-1o U̞ 9. Do,OP!TJ3fӦMGѦ\[iSi&0Mۯ8+6/o޷ 0YTR}wg䕊T$)껉^{hp'ٶx`#*`IhMgz*N<&3_^s:pFH IK"WWVwr @a`9 &%)7s [7Kg*/Gki.nj ƻm2xכhF UL'hQ,kop(yOqE ޏ_?I"~iy?vt@C(֤p"2^+@D"ŁD@i @r Twީ|q@DNG$F@؟`̘1vrVi_3kI 1QQ3\s: g@,)- 'soT.+{{'׽D*{3OAYeRsO*T C5%k,1Җ!%^z%\נAZu2\$@]60% _K" ʁN"d+ƐK_Q|zFW%W^:gekWwu &8ÓeJ9FqS (j@ @h?E8@/n(PWC xa޽{EH5ᆭˤmB8@NuvoI6.It9rT>]:OIc$7qT.@6ee.@Vr r@^V6Q-p6@۲N!m-((:c; &|"+EGK H=Ғ(D0*m=cv(n N*ws &Mp Od 5_]Oiy7g9OE:@\FokҶE6k,L*}pkKRAf9^D_~f8ii 87"OY3Μ7DFɟ4遌2k1$]gq`i@LV$ x@5 .5o4_#t5x9綗B h˕ae4koT#6`NXYۯLy8\G?!|/@k #NZ Yл?4O;?}O?>}[L~2yo)?`"YH耽D E:6B L+cyu=Ϣt>Q6Ȣq}ޗd4>e "OrrC8$>Z#8iY$?KL O}#idxK׼^|J ޖ!-Q?=q#CA2% k @5+jZ4w7-`Y}GgXBJj+3r5 G4- 9E$)^^xq$rќ垑w1A`ő?a‚@Ȩ^V#7_u. iz}zssCJ@TX`:K@ -]k=tGyLh翆-P-liAAAtlG}&ut@|lJGpVvrǜ8^#9czygǜ74pw$9r?hPaJO?"_ iE:u:kB@xdѫfyK'va!^n"JS,p]Qٶ&r'Ϳ0`g_2Q >2oٗU u/77aB_Tt+_u]'LA@8JF,CJ+θ) #-PP{IQd zjQ"VN:.p3t1vgkQ@V>Zu-GpbIsҗ>b}O\ķEOXԛL0-::]67+M KϾ<`½>`,;yK8SEJT䡾m|Ppp:%~cGƸ_}i$ Pª:+k݆w[K2 j8U]|Ä/2i_GE]rɍŋr}谩ǏZܸo/e0<}2>7 8(>޹6 ]ҐRW?y҃:4[U@۳LHuGp~5@AZҷ8Bwulg|o˸?<}Р S7kB&_YGץ}$Gg$;Yr@L?C&l?_o;kuP&NtY?s3]:}O|*rmabr'vůޮ(J~X+ Wƃ3ȑg@`nj)J 0la21`$֬ :Ek6~N-6K/ٴٚOw?bĴZPi:րLD Qg4gQFUcH;Xo"p]5WVG,W_)zגc_a$OA9Ҙ)t޽ -,q~Ẹ>-ML8eʜf?r<ʧ\|V~cJF`?` _pl}%xy:D/Z=z䑲/\쿗&4C'YRornc7++@Ks%i@62pdN_8|ha?;Os!;S@QR8 S"Y-m-NL8,~|␣zdd yBšGu[2ii7E޼Gӂ?&z? <016 ޟڗkZ̹߳Ȍÿ鑑|T;~~}N{>/@ X:߫1}NtRIeb֚{ݑ''p 'q=pn40XS0U0PT=,"vv%S]K &%^K9O@ude$Z2 LL8:ڮϟ8kgmə]y5Ͽχd pA?uK.)^ѡ?If{,W\qט{rrS//~e/?pljg_@[~C2"NusϠApYpI ~G&+&<;o[w7Jp;+b 7oG~Yݶqlg9A>}. $%vq$o?sG8[_*ao_%Xa:2eNF\OyQulX|&DLp9'Z@= oas!C^ðaSRI~XB  \w~Sj,4Q O:lF@߾}+jB~)GpR @uE,]Id<#KwVJVNfY O=@z棕ڞe0|f)C`)6ɒ5͐.~?hpA.66uptYf/F5%{+k<#8$_2z‚.L䞢sݓ{%c!w%+ 9 ?.L'瘬y ѓ%8{2&šqRֆBX/=#] 06X+V" ٳ?¿}W ϝc5`?oī CV`?8p#m$p \@7 5 #-<#],YhM@ 3JL‰W>x%\7+O5`, w@5R ,l0nHZ."@΀(>|96s1`TK'!^kpd~kGtݛKL<5oI"qy "C]lBOՀ)wVbڿ>o߽V0C>#F\d@`0*їB!@z[hC& 1m4ɕ󴧉z,9,#.}xA>+w֐]2?~_&RՇ< hm!@~@H( Baд1FߧϹu?hYvĈEh9mbjSϨ~{W,$>?tB_? 8`כ|Ď+vVZEI ^٤\?w4u6,`+P=q90g9á:tJ bQϲ}GZUX8qbZ\p-u,Ȃ#жśKn[ū?R/ 7ݴNnA7n@ Ot/ OIe !C.0ݺg9#m,3QF ٞ؟p:1%GC^@2SMI;@2lUzե^ =gvŰsfM%Ӂ?){߷n@;#5$AJɓ'ӧOO+!=OLPuw(l#hOoyߢ}m׾_KjfRzwﱵ5lv8&X\ W<U:hZاOBbFʭwoOcD}6 #4y:μ,q張W]9yeޕsV8sUfdҤMhFYlOT?~FxlW -?SD?`pQ@Z.Qr82uTqk6Zl_u'[_{rbpxv[g7),ݼ'YiOi{TL"37R"Iڡ{I q??`K~{_УL8 J-Ϛ=zZM}9F8#rV~@+?O"9j !gL>䑲@+g_ YjN\dxdC@$8q~Ta 7N>|쌴fA:P9P{)GrJR<'=/yk{߿)͚E.Zm'?ʻ6C7n_Ϫ~'붽_s:׀'oY߶] a&$a T瞧~o%q9ką!Yg W˂#%eeeM^ Bm71M{Y쓒ot?MgO/7(DG3Ϻ&mM*0jkSjTԶM8?W˂#/`s4E8VKsM34̹c#Y{$3>Mf"~DRk'ޛ MK3Qa$@ey%JV*+ 8X'_#QBŸ9=n-g)qve бN?f'7]q?eQM*矴?}b#@a&)ϼ JF ),@q$Cҁ?y1C@;b$Qd$/ pi7CL4g/7?p/47;@&ЧO& 9@k$qפ'K׼Q9!e߮Lf"^($Gd&"7c\27Vƌ۲??h8 8ެ7;v@y%H#6@|~Auo/x<j߾]4H껉:`ą)sϽ<)iU'9̩ v@>-pʔ90@Mp awh*_Xo?c({357-^P {N]-/D:`y#(++S>8^u]Ƒ~#%q3;4 70b B.`B҄\AB HY Bǀ@efلdV;xfk:֮+qǩˇv眾NzC}^#}$םkON&W5 6;b,JZ??Gno̪Jx> wcUݴik p(spDyO|Zڞ?Qu}}V R?L3fx07w`Ub&91AuEcStXo(O0_ :x*ź&PZPZP_~MR./<..Q۴V%#Ჲ'| 5* ;#yi> &@w88ÀBf8xڣE%T+7b0د*G ?"5$ I]Gs!AW/ -WjqNj B N%*<li>}Q t NHTm\1ʗJI)eq FŸVQ&C{J--Yf೮Bnor'BwBLh0Nʸ}b XP\wԩ/v4$@cY9t>mRrr!@ч:?zEzӬB`#c^ Q4LDzT$.k5dX{,1wW0>;=JЮ7]LqRW{z~!;6 81!|>>L `nen&V+ -PTk~we4kNj:>Ŀx焋?O(xmTD@Ci|j MO/k)DJ1R~}ReN|OeVSuMv7/`csNz L5kJP '?PG@ZV 0  Г}-%9O]q;0.\3֛D`[V$?oqyDH05 ""~[nn.@Pſ4/TîO} w;K48`@2j?~F 5pFÓ&DglmlA[ʪt| :#W (Ƀ|- ss\V,{ScJ1߼b_ښ55`)=˩>&@אX6n;DL"@ HG!/@zG@〭ǎ87F\ҥK~3;d GG?tT!-~ w.ENl,9\zBe9, T|?9g` ssWqfE}ZXn^vWAOJعS`MLqVX:!^hVOy7?ogתK-_-fy :Y>dO~а-=@6Uwx<w5f`\gm \+2Vn}<Њ?x t|p[}xPD?B7纬17񇻟 :'L $fϷ3@~ 3IyhًR@?w++ \O+H u0L?Q447fn-1Ԕm➛r.nVw[37kזJiiUƍ&Z\ڣիpcxZ na= zb<,Y@9 I3]l 5|9ځ}B -];wn=;3g\IU((E71OT xV3vs@|{P"m[c>wXYN$rǵ!55ODylH6,@`MXܴ4[EEEAA/_-722-orZL&m (C?^x@O;({z _^_"ʀO=? &Y\7u/Siro1_;zZxO =U[[7O8VzaC0#y̑!y ,UuuO\8kr"Я?U1`L]CFgQ9(gP{-z9 c-,@؅'|6w/;K4F]o,i6z)vH%-.QPrcPVxR5014=?hnc⏵YX<-+W Ya\|Jtek]jV]  >#apIݓ\f6Pd`[_'[WCYjk=Ĵ1{%/goqCP187/rMD aK{2|p7G'ؚ7GB wr*3^o$x/>c'fU---MMM6M*ŗ.$ZM@y2̙3*;uxyN]vr(t@t@KG}sTΟ L"c4߁8A<GS}#V0z-8=Yж%t/@(_D7a/ : ߸nS@-P?SJ5k Y _dJJ|)..&x& g?G&.InhMcH0 ZRL|v;ON ~!c r ҥ9 tځ9S8{I#Ώ:]vH liS/sæ ]|_Py?jYrbnUr)V+-~uҎ ׊?BӾRGW`l x6r载?Ajmm{R{R27 *wXiz|5@I1~> ;D3xRM*-+YKԇ?JֿU"@zO0om=Ȅ&=))E,_~d''BBL7 40S@nӿj;ݴik8+í*R^~Q/ 0dw$:)¶Isayt3 b1W}ߣH!y\ 5ztC' *"tKe{*9p!fM0F߿Wn-{+k$[dLẇcb)~b}8DAϙ[ 0l& %G`j<!jk;I _n$&&?vlƍN0 @ Dg$jimݺ l& 0v'N;Cvax}!wn, jq {x0?%^8)İ/1<bҒk=qR'@K:3xi# 0uV xolzppe}?YH&@Hi' yx9JU!ytTP(y-huUNǷt<Ma:q ̧jCse{(LJͅ[wt L\dD>QG~ XժpC%٭+*4 BOӊ?Q+[ & Hzp/mf/mߌѦg_.චphL!xF/RQCe1[!V4=f__/RjUvm}^)>> ʕVſx' HHc#"6HIIyҚ5?L65Z5b}a7a F +-IkN[/ SXt?NKdxGs0YsarKow?H#Ȩr?CI ZZ/O#WA4oK!ˢ6zKp` @}}TSc@ccMjNS 0Kvt2 BꔅU\hÑQbTJ1..I\( Lcb`eWaqbT*زQq l 12,""#Fm|%=).-`&la(lğ~Al~*ʢLi >}Źyv86g8 6kٺ~|Ǯ#_ϵ.|06X Hl;M]8'b{ XIdXy0~-?x%# 76O%eXiAIENDB`tiled-0.14.2/src/plugins/replicaisland/objects.png000066400000000000000000001665531260670167100221460ustar00rootroot00000000000000PNG  IHDR`u pHYsHHFk>bKGDC IDATxXR]P((E"6@%nXb)DML31 |F!yٙev~sBFҾ5&`E ˄+OD,3ۺآ,_>2=z.}T3M4UpƦVIrޝz[WHW:G|w3Oijc%rPQbY$rŧTk7OJ"V;[v6GBK"?n3˴m6j xǨQPh]ڨ[.Dt?N'+[CCJ{{{8|0۷CYY(((ܡ{Ҟ∱$0h)]2JC!-n1?SwwNQYp!8 -[Q莽ǵXX*;oK5 BvAXpmL4 !<`(?d3I$=iWPkد@f&@L 4yBHN7oB}>|~-/3E-22B{voK#.{L!nt\΍G@\zu ~%j<`%p#44͛Lꄸ))Tݎ Kय़wz|gȸgAq KO0lDwi0EGT m@K22eiθ(xtZz^t@r:uS>T 5+Z^-dKxCBZ|2+$Br [>10;w S:n)\VQ~g6E E!!8bm>~@ۂགྷMBc/~,'wa)?nf{)dS~tɓ'piرc̝;q[n1\Hwzݰ}'EM*qt8O]O uA~3'=ZiWr_Li.mp=0hyr^x|~Nh] ?t9\rr{SC6Џek8! _ )SGkh):PFFqI>--z!|MK&42sd% !fhofWgFJU:{-*Gi50ೇƛh}P#g@h8 U i B _- BI@~=^)Pˡ-<&R ''OUcܒ.۶ׅN^2?tޫsDnˢ[Ma|]T C}& qy9VR 9jJ376ӋϮO"[WCtW 4}s:}W<^+dh/!!qGHj'm4̤Ӫgtt4Sty _EQIk}o{VhSZW!iXIQP)"9Rb 6.z>* 䫀~o1̫#`~ l窂Z=X1{Bw'lFƚontax=w@˝D5h/lƥs0RRG jkkʕ+Ӷ`k^~R5z;_v?  }Ueڊ4|պZnO5X 5 7$uezTQoƒesZ!?K^& mn<;cN+t?4/5;R7X*79 }}M2//C'z/W8bQ%ގ & m* _N ,r\RP^vS6XSSw<1i([?r>!?'wZhQOG)&Tክ ޥQN->GiMyRJOPYY9LC}(Qх&r?+>>9`ua'nhh~^Q|Is{-P4w%oO$R^ڽ-k?)w.vK >-P 1Ȅi6pau{Vz'u# >@Fs=xۂ*t A  _߿mEm][5@y NkXH!VYY gφGE].GNj*"V>EaADHurJ̵kHGdHAi`۶#m F!K_逢!q4P1#Cq-:(,<Ɯ+_ H!>Sp@J@ 2S)))?i;- S)8C^>y_1~`Fk'2QHW(=㛇oh?"}ˡikGӝه0Le`!1tO0<^ZhB]yL Ę<-Gxp[: vaT.S- OSINH9߶869#:}zTˬ&3囎}-E"#-Юy @n|TmW“MLG)x2p.uJ? :} +!!0CzV~;PEO$ UUã=UP Md 8߆@ ^h֌eѥܥP`(; vG;/#"nܹcśs[a!ƒp <^Ng"|t65 T-*OY3QmD=qu~;B,{ EuAlPdG#)4R E:chF~LHt Q9slh2v4o> ר(큏>e@n&.VӎxuN:N8t_eK xah<4Kx8:6!x"@$: _!/[_0CѰ4/OQvBMAA۷;Ey_OKa_L `GuH:MvCP)QE7N:+թZ (x4!F}}FP/΢!.(x+;[tyԭ>ӻs-"Ln* w'RqOU5sE'nHA@I.O ݱ4vMvz:}(GPi L 2Bi9 ( էmpTAMa{6au0ϲBO !̥NS{1Lm ^0w|7y@RZ-aÄ4ϣj'-Nz -yHг _+޴kBGCR }=]WAHs;bQ񆮇:_άH&F>d9K,҄jh;UvԛJeggÝ{]үxMmU&\٦(Cm\RhXJj4~mA+30rWRU))4ԵD{[ӐX=`l:ꅂGm= !uE"IDGHFW4_ef3OF Ao!6BQu pbP7XE-//Ỏjl#)F-*0>N =V)F/wϊxt$V7:w=j@1Gl0~*)&DBLz1H<@ꌽ{(+;VrK.sH>J4pbF$e8b I'ADtx5Gz[oNghMɦJ 'HՑD梻,IiN}` z[Om5wpK=@ j$TixzzM0!jɒ%-[vlF9h me$J}辞8> ,F]rIЛeP1|oDޕoMn WEEE6l>{,3fUߖ xk=Yo>kɾk:N둄+yg \.n-dm>eK%pQqZFY{̺}.Uo7)sK644̣Q]p>oMc 2XND퉶#9@+791.;>f<>&$$bklBǨ@{ Q( :Dqݧ*T\8^ڴڻO>o[[֭cNQڳklYT ;*G{[7}e6˷a(.v8L8Hx/#$yfƠA˝R)=Wh)0Pixozg{<{(X(.j@G/EŠuiڦKljo]>Y Õ:Ö D*S= AP8v늆p?;%%4RX`%Yyְv|%32xRiiq+& \m燄hG .@GdD<*ww)@"#'v./GxLE:5huvԞp7PXy0sZXg8y-G }tdkp(IK`d Q|T6gtʿgxKl$QlxOܾ>zҎNM6wt1 C#YHO@ X>zs(]]@vvL&BYTDQa(7,/7M˶)S&e폖8|sDzp4ֻN>]m ?qɯUx:~nsVja= @B0Y9+'imY LcUږM[L9Pt}[O32qq;ٖ} 9e`fΎ} 3?Q* WMA8(WTPXXQz"!bj>uL4 -| <;>z바W@ gg QZÎ _KL'%>:gO{wAqyĠT/v& 0SWWSd+z6ޖYY:rڛ!hVЄx/p/a( T0,@zPdT"nTT읦;\h|G|R2^p@2QpvPГaD,ܰʂW| ׮߀K7Iaڜbclު_Hkii]= |gɑ#89X[ [4xpeڭ~*]@ *\yM[fr?P( mo0ƳՎ\. Lr+h"WV7/d~ǽl|)w' _ꋆî•WaH͛+<>EA 2Xh'tAS4o.耟b\z+ؓYOxc|rCL(*aظi,XpaPyGAccc@W^?hԷU4l(Nj*CHu?X`0/r|(wJ ) e9Jy3 !'/rwnn;f:NVjl[ccB΋!p`985ŗs@xv9S W$RF]ʿ`C>}#:eUL-"PTTT~TSSc@n%WIf5|g?b=}\^^ _5?( <|?ee(@;R{J_-u.9,' 1q\-Jikkj6m|"53?e(!9Pګ}@tICϱ p֎yWW^^a%₯S}}үPNa?a8R8=y$~gFT2QqV* dWw@ !|-g43lIB!=vvi‘y Ƽ> ˕7ygEXG|z:::󼼼dgfd H9>[# |{; j :"p%X%%e 7L4^o:B>AlxW-tNcbb!"#UuI8%*ACsd ͍V: N &uݽ̔ ޔ۱a˪U=M;[.k /BЕ@l{+ӕ!2; O.z`e~}q$5voIT~9_ NՃVXtfDL$#AuY[?vQhij5ɶ' 2d$HԴuLhO 'js:y]hp$\bB// Ri12f0VwyVE_쁌 uwylSRGKN:NN؅'ҤT >_GKtHZ |'5 $z@V*aB" 8Nu;NC3_]CYSCl[Nԑ醳.YOGHdIPpI y-L|*&P =Q2$e/gHR*ϙNFrrZ;_ҁٶxQ:moIݕF}*)Wnu'7$ts#,6L e0?f;A4 #?}).rY _)/+ {Z!uzD\F7XQ=->J^=şI9H@AF=W]"uW^YEWB#9g߾#3؇z!XKStaQF^}_P p@7wtwkN6B; bb.ns_:mcŜsJf 72&33!p۞VC IMݐgL>vgK!=qU22p۽yR+xúЁQ dGH u;jPZ؂9`zg(]YK%HUIr|&mѧj܎/E h:嵐`"7D#v]E#4#/{9i4%HA:r!:Bu9:eso(22\]_0#i^SS~۹^ rm6ba-KN/Åe|&D#$Fىa' mePk~w۟@UMCZIYe#,*cXO)ԟI2j 2TMNzhx:P:mw" b)|vQ#jj5a]2ϹD$ҥo*K_0g`-ʣ`Eoc}n?t8Ίm`(0ܯ @%p +&x$pf/ u"uL=F9|少ph\h1vuF$#vmgqpJgòtV 19}8,Hr~]Qؓ%ɼ}U67| Swp$A#Z0ȾvYkߠg"L``'066ln*7ƻMu׍Mh~+38Aj?p.\3X=Y_o,^xL0.l'5|F>!oz:੄Nx{>wTwG[~ðOo]~t fAsE n"m?e`m[C!Х)ġ>Sڞ肭*%^ 1';o5Uꀭ0_##O!ٯs0# \c5giAA5φijb?rth#xծlڂtn~ :fWUv6f9{S-amĊGwJJʠo𳌌E%%:圝[":wQTi`nLONRG׀3㙊ٱ"xh"g$!@#N,phg"6k"5w%rM c}iXەTDdt>~v{ ^ J͖?%%P))ǃG577wzKѾ6!(|<3Sȅ1n$n "0`_7C7k1NeJQMN6ډmbwpjs>l,5]QI8 ɕۗ91$lB[tI[0#| _#r; +bLc ? 9[llP8xt,]]&w3NN^wmtoąuVP*+jRIAm:q{F6! :@a\]]=TUTw(`4SPUyֹkldڿ&⚊ad; 7#@^Z\K KM_)@^& ՗&cX-SY0-@p5!p՞#dҒGQ4kA'j5Doc*ZJ?i)蚨*+*虫vTOHl`bz9^YkhIٱihʥ svrzΕᔖ$UdrUP84L'҉DO⵵ Sc nT8T\&A|+?Bs[s@1 9gϒӌGp)?Qg;MSI^R+jR(*Ȓ[X-˛H1Y+͝;7b4UUUUƍ=7olpK#:SBeFel{ӕUWٯ-URAt*T Ņ@D~^llʒ/JKKLMM=A<6e49k%[>< gAٳttKVc|0phbU(kr'LiĈ(449..~~~ _z?yl'Vň3ٙ\d|5{7.rټXk &u9ЅiVraWzgFhdu]>E5}?۷Om۶=\ٷn0E!8se0tH<~l!ҶC ,2#!S4>Łuֱ" \ɤI߳gOWaEpځ:rkpJ{Zl krvwq؎z C[CC|> H?`x+^`GXtUq׬p1C, u u4Qc(vgK7S|=,45TE (Xtċs^'fff)hѢb&PiD撗s}}=sGNxر% PsMŐ&,|j8u_ 7o|!uիW7zyyE7z&E&1Rۚ!w/ GOB:O^!tF9C C'eL-3ٞe0iҚTÃ52N(sBH;;"q\077(((r]vu"ކRna -m|.99Hw)iC-g26m> aذa@~9 7WWq o4vO--m{@S8Aw 9Y1,?!hJB~B k;D>}:s=||{ùsLꥪM9dY[|&!Q޳WSDȘ30tRX SAЪw~X6 K1 Z;I&](ָ>A\^qI3'uM>l-5qbN]]|OD!@NNN/H([[GTt愴83a„kXM?H|/9߅u7iobW -6MkkNr %}}}̛7?tDdL̚5qD́8GЄBwL4nw 4_U Ym}{a}`_\ a쁌K`փk.ט*A8%c"AH" #xZ`~[k07nRHQ.$]7ڍ3Pv@z\d ',ZO88N,3%tq9}jj74Cii)cxY`{$Ϫ|:FO RՁƶOV]b<[R ֹ@9tbJ[<%_^ e`]&s`cr,;\?ฤ7nZ{YčD |wH UK]gu4wjƠ9Q㤬s [Ž1'N#o`>x'K-v%5z:ػ-?:!>/N2ϟ, 555̴̘1c3/o;ʈ)@ kȽc% a'vOֆCە~6ӆkt!'ݕa \Ltt^br͛7޽{o7nٳgXJFrF#M3qΈ ׬13'}d$˙EAwTIAK(ľ!,\I@aHam +d i@K %WK{Qqq>RC2%L &k *ӗpµ|Oq P}̘1;(pRѪ(p~? 347rwwgÃYb(G<եϫ; ,E{#*ߧC^4V;̏]v|GYƇC; ;)-ogDYAm[iQv,7n((GpÒ$}2̏^mN )Ώ1!PnGҥKGmEQi؞J :C n|y F28Os=fdӥd?(3K6fi;+qY2.u׳#-;vI"2Ks kinq|N[~~~3-K,i?dȐbbbFFǀ6PuqL ,ݴrFeՌ`1u>M3A/whMRP<TŘ9R cqH ")?FKlHB a[Z':lPUZMLG\&UVO<(.̴npׂWuL2&y2cdE"G?>!!!w;Ex/88w4~0:;{k_lPu%p2K}4I2g&Tz^ GcޚnY:Yn_7 #Q)/Zx,"Q1/B(%X"cX`Ae!ɱ( 7Liz/C/N>͚;w #/uۈc.8 x3ZҐU4hIo]-}. -\AGz?QO|ԕ5-)'j= umRpՇֺ?_޲2,Kz7D(M %7IE676&]ZzXʍT QsϑHB6i&?j߾1}1OP2h VA,5 |]<i1cԆ^%4vo AH9~B& aN8pd$jRaX'Uc\5XO${Ca}"₍@& Wy=tODNC8s1+b֜9sO>رc?z?FDD\7-^8QZMnP>o6B[m_n-uΞ=4l)zҮS=ע=_6i`aB1PZ\%8wi-.N ȩ=piÈ= n֕MwT(i20I 7l6B҇B/(ip,n$weBIr#ɒpB*hj*MyKH Ƈ?8nn sx:Sp` 4+l@{#`/$әraq򼼼h =iVSSSG_r O?eDرc5k񪮮E$+W1󆑋]ۄ|T +37E z 1wd2{8 +Qia3h%9€?6^V;2:X47Z}d]an bSCK'>?Ei>kKKL]9.6/-2{*χt> v>͸^[Qk@_>LŁd`&Ϙ(pjRD&2d(oN.rܮC#`{5]A yD}MM^~i,O[n2%~3XY9 !d{L| ] #&AM`7xf7!9K9_*]v ֮ $4n`/ޟaߓ MgR=-LQ&S(myvOߛ[K}v!af:|h.HG 26[ Re4HCK^nқXA][ 5v|3a+l%Ѯ~Cd֏5xgl2uXCpY/,-%-IMImt56> 02d@s fG>Gfg݃]ǗՖѣf*4vbl3hǔ1%l WE`1f j@ \&O4J.qJ/8} ya(P a uXDY,: Ԧ`(ˉöRpe3h +GIc+S&5)3@>m<"{l~e9 b耂\/ֱ}[y2haEU"I洨[@ŋlZu4IՀ#s iD)oՃw[n|E%lȕcT<;Py07恖nK36`I <ȉ0!QQc>Jf5K@g8#)"M֤BؒYw I'OA̞]oQ=(>V4JD61b28d]b ٞ+r!h!&AG`bxӤ`h*TZT<~0z?Z E3w캩Ge n355mb:ԩг7Yի]>ٴ<</vJ/0e<0I`Lk6)pX~Y#rzA渽A]ynt%>΍&&&LH!AAAM'O>WWW7dƍ]&;Ê҆19:EhF.^1~AA` l&1\i_K ̊g1埢ui\(shF/ 9!P$Hz8/\7,gv(Wn)`O(É̱N?/Yj.jpNNe:ʅhi{;uB dRR=tɍPڱ$*!:%N=r3Vҹ:]L_x"WH-Oc50d`l/l*J_#S}19--h'"7YNbVl4dЖĤ'!>6ߍ7i`yŁjkk nF1EK.6?ǒ?|CSTիI\h‰'2d/O D۶gS⃋/^V]]=3D͛78qaj$ȸ9CeT'?[) F)`gz^~dL9OrX56;c?H~dkQdo#ԨwgRhyݙ8,r'ՀMB nsVG͛7oraaymt\h5u@zZS)г~}n\쪪*_ WB#,R@z%´0s0]%5FfTP"[E>DQzd]ݱ_WDZiDڙIJ $$耫1>N9K?,$R칠?CW4'bo~Ӑq)8]!U]=OAӱ4fo* "͎3aB˳\xՃ70e;8RaxbC˻5;>@,̨]F P$ 1 MNlKݙMo8[}T?e_/U=by-"s y'%؂nMDDD#u/NEoIE(++\'$ZˢQP)"kal쫘#:'K1iPN( BYvMRzA:B|HAӞvgE)wn}HCS:w`U\M*ػ1"Wi;(U@@DIU Ш-1W5 b}yryw=C 4{ށWÀHaY/=?sj)5ѽI}鈜W ^I~5< UW i3vZHM=[LʎIwin&^pEEEW`$ɈҐ)Y ғGϞGcl߷[h&ƚv'e8~T,|Y2^?BR4n/w1U]MOw^\1k--3m 'KUe+y2x3\2e/^l;̀o4ڭw _]:+|{/d6222js45uttUUnjޥsB:n#J:d޽eҲ%5Wuz&ޚa>J#sBĭ8#[ajBW ׍)vS-skfOjyjyZ| USךeim?QG|bRҲQ1/憫j]A$$t ]H'ҍt$]Igҝl [&(?XZZ={asZ_[E^'IN}DHovIZa`3)v P0l'-#kix;_hM$h4}յc+yEV<kfG!1% b-m؊wcg~صoFrJC7IOIH&&H҉t#IWҙt'l# UGO(Ϻ,)gVؿf%`Y%c 3yvA_Isj0pY{#t,*BX ߢE,,1 cWN@K a膙0:lzm MðpwG'xpŠO;ϳq]EZ*`jn7ab-eT~ t?q =}|Śiӷ=j綝d,II҅t"HGҕt&l"F?m_`(/FYi Ңjb^L&>6SMDT\VĪ+j*Pn@ZhX^^tzt[K:C󴖸!rsa?O;_2rںW1%0s*j~јy ӱ 1ͽ;?f 9ʈl_[,Jl]Lw1ߠƗ0OWP,YReX}*--E@@O2'+˝se>SVVE9] Å %`xH;z=/'ӥ[- Ko/1Fs n>s?`p\!ybP\U1/tvAvns++[s̄"$dLM:.F:3N6-dF6dsso HY>s<*"=hr(Vm|{0ޯm3AKJJ#)0`0n8s$OHA""΅PMA^p'/HB)3 y=:ܡL6do*:vXOuɭIR+~:1%xʌ." ۻGKiYf&LM٩XW +U %p&r c붝+Vm@ج|9II"$t ]H'ҍt$]Igҝl [&l$[f9#BWij*"mP]!.J!/"4x?&!dV4 >Hii; \'iih)<i9~XBL Ãs5F'@cmh[f l5'0@~RaZ.feM@1FGc::*;׃3c2%ѣF WASYWȪ N_W}U6:zEgcXIə`X7egG+II"$tS+p:3N6-dF6d3ތzfr,Jy;"Q[A Bt"fDr^CpqcZ 90(WDgKVgg5F#c<߯iK!c]0QIȑ#O11uTaucCuFvD .S0sdL0* 9 2P;7PS.Lutail ZÔy9@\/H^Mz8~pCr1t{=oܸp;vH`яmuqdbg>|DnG{_t kFKCQְwwQrV;νџ^W{\?ׇjpf dd .1=|`1iBOM2H$٤B:n#J:dB6md#J6 |OԵaGr^cᗨ<{.?նʯ5tZ?q`\B"2iSU:E<7 Y$d D+L 7g6md#J6 |ZZZo͛8|0֮] rׯ_Gvv:iiS@ODGG% PuEy8 d0TԅsDZ QsmšL kw#/u;ۓ'[,&Ɓhr/{@%Ή -ۮ3:蚂k3W ^ez==|̾3g{4cFlS55@e03DƊ: JdʹP@oi! @JH0H!(QQ8*"yEjk7^qoy׆ \bVeyl܊h2 eRܜ[q;~ρVD9WVr]p9On{c_c*.4MPn'.mw%Y.;k/, m=S _!Nck۷o|˞ڂ&M k,o]&#$$AHOMX9s1=p2Os¢xC$҇ sPcUY Zpds2e#l ,}MN@S!2r|z<)$} \# @y=;//KR6'LQp'nǥy L"m.%ܵȞ=SyM n3y8fTIY g0*! #a^aKX^|AANn xXZYgaQ֭[sss۷oMuuu'kSYz%ċxoAH&&H׺+L d Dd+g3 BϞ*WBOWO`UUC}}}6惀i0eTLƎ"}]yiFr3AxhsVPm8Йkyd:+)oyqCr|p- <"tH5uCpmѣGmFR{cSylr.y >k1 AKYH! iޙSXb0PV0>s3}H+YJ*߯!uPhBY8{g\8 pr{.;1o'MD:za$_UMj]t:5f+lfXXH1/xU:t C sCѓH'"X#-uqcXFIf -5.5:كπWe@TD.^P7v>ҁCrOy=  >>>ڏ ZmAd$>J,e{20`^l'ԱeƁz<`3?x0eswbC@D/$e53m^I(XbZׄDedJ.]\{g/a Mm`5M#;io8p`{S;0G!^Eg"ěd,II҅t"HGҕt&l"FlnFًk]r W\yFiYa^V0c2&O%v<9zZ%+XŜ a*#ZZ0g 'S{Zst][Ak|Mm&A㌋Ij5Qg(X7K `d>|- |v z#6{8|=n|?1Rp3d^֤+KL݇Wi+{k9F{8\ -v()^jK֬4I2uUeaT7QR59Ե'@UcMhvdmfUVVnfalZRYz%ċxoAH&&H҉t#IWҙt'l#4гg. iѵk8􂬬{@O IϴXHhmN9$'Gji.I lf5 u hf c3:gƪhk˜R-O[GwhMz_rԫW{+^K?@:Λ.j8kMqzG)_Wcsgiֆy5U~9m>+8(uGK_t,0e9@b) Kݽ? 䴊K*a< IeX&˼6׆f^ER eZ3JXC$響 !1T3, ^ēx E2I6@Ncr:3l"6H~^!Gz6͛aOAhy0Tf֮wlje%*Yy,a䢬 CM*Xu<&SZfg!մ`ie$: |j,S4\J&I; B֭[Ԣ.9WDmJfhDY{ k]'OAT  Uq`i{ ^Ɓ}8x*$C1A:˧Ś!uV-`|UZVymm)F׆Na8`9k>%hi?:! =CE<7 Y$d.Ӎt$]Igҝl [&9N=c!FAAGr!(GX>=>8MSr@4ug@L;&03r&#g2P91rxh9s5 ٱtL8pkw+y [G덮c}(Ć]nL<`]'$s6Žu) p4;#7GT.Ѧ\qO*ۃKޢMUXwa}FţrCzQ#%{XJ膤 9;%d4/KH+aXR^^b~#_5\bnddd%fZ!,=CE<7 Y$d.t$]Igҝl [&^3X_XXXUUm۶q3h Y,s,ֶjJ=Q1K52ײ]^ ree;(؂ɳk Z֯O]Y5s FHkVBmP}:+ Gܧ  %am Y_(Wir<{)~ [}N\z!h =k;U.ƺEUTm8%wbgE;V0pzT9/M^ ;#)HGH衭ކy+rs ]fZ4MLL`ggOOY(녑ZP*KгăxOM2^{$t ]H7*G fΝ;2k P}4KeaSҳRɼ!#ڳ߷:v׷*k`pJy2[+?`YLAo$=aazqg}iqc#4LvWCu1~)>_/i(>QJhvcO^'y8䶐yDܜv8Gr-o3vn;{Z} {.Үؽvm>a[~l+چOp~ֱɑE?Ga6'\ZZZ/h^ldd$mm.KII9vݣ2Tg"эy{QbҮ]nAÖ-[hVVQ6^1–N&͝1cnsF^HICP|V~5V~(Kqk6YS#; M]g1ڦZCZwamrӦ:wlx8::Oi6Qee%pR`h &~'O_(<~.f\YQ+q{1kq*${`OR)k: ' jTGA[QCMKsUf^3f3JjB!$E T2PE :T}BDtL =K<m,,w^zKMT+**Wzv$trN܋h :Й rǼ sG /M.ٌIX7-P3a=3W7eCI^ٙ_5ّ2Z f4@x{Gί'UeNyi'=>YDͱɱϯ,z`ldnxr? 6MOm&z|'I7+^ꌥ/G^a=e,ԉg{ N];Gr_^aD05Ge,=C/XvrrJ'G17nv7j1,ǩ]hV=$lJFc M_SQ1DÑ2lrIG<(9C )8BA R{AlG8kAB0 vRPIυO^*v ڥ'#< SJ'1UXa Pz|dd Yc#jABq5rc ~PUM'LAB\]6x7o͟#R{M 0ۛ 蘮'zgS}W1#[&Pd uo(+ \-Z8w)BsFnv8D%}(8t{?LBK.b]f|,xu lgStx5Zkx6e-NZfM[vj]3?\wVM1|F]]]1|J 忟rYh$gҷih\~{r,ͱW{FoRGlrBc-X[3 ܶ -n~4C?FffWx^,^}ZsOZ-8Uxś1#&&Ӛ$?Z{Ȏ.)\Qm+o94Hb''"""=133㖕ٳgC__( GƼX^=7EZZѵebʝ(.ߊel5Dd,]w|'eG{(?܆ W8kr81HNmp~zhߪeKק|s~\<}_iky/ūt!,Y{~Zwy)Dزu+hkeπ@,Z#Oˏ'_ +qlre,BZt]-]2n߶M`7Qh֭GwTuvaþRPr*L*?c* %Y q'?O_ Ash[x`X^Ms..].Z_SW(?am~ 1X:1ӱf6X _YcwNJ,  Z gPQg''Z#Qǎ_XPX[8RUE_d>xUH~韓_o#{Pudk6?#WprW=TJ$O[d~= Uذn ~$v܅EːlxɈH\mɟv~3#['b/"'_t]|׻=zujQaڈho!U?^ *t]ǎ:a_q;4!7/@ ?iۏ BFfi[y?& xmۡ[ j0bYKvz.ܾ刊NrowV bcQܫi""н; ÑS-0&+x1P6]b3 +m£>gӘ `!zA}_Aht5 "+ 5ZuDXci9ˌ^ w$/TD9#)*^k0="~`SSSȌ;pJt3j`~lFut`B6ih;|<l1Hҳ5666\i4!EV22Hgod& MI>iiIl` d$gd3:)ʐIWg/F/HشZkIK聣Fjȍb!,O- \Q'Fа_rrr'j>NJJgԻV:w\a&* :@-D/u/t"_ },L)'CNTij `G 8=JBIKS٦'oA\--^,_Q8& MCTb%.{صyL)8; XaLk]k[Rp=0+sזǟD2~4XBmmH 1ItSz D#LUѕP~ H^?)$C r9UqRHSWnbZ]:>j ^R$in2*eg  B4x?viu$O5MmPZ~YϔX*(++B,?I+**#Go~ D!4"!hnp(ίE͙ ؞ضm;nݺu~PBʍ9;3ӹg%cBf̘u8ׯŽOOݿ40]ݦxZ%UsbK_H> Hwh =د'vCH z(Cb@/|ק;:Es6MHHZQ;u@@3Z Ik|# y&>~>6Ԁy/@u(Szy9h ZN䑞ۛqu KqXYZ8Ir($s3$kdP Iu:clPcuDUot"ݿW_tዞ)0k="Hs sk1u1ѹꖡ<'(‘̜5|>e*&9'iy 2 ϏWT=ؾe#nZ7?sQ1wOH Dbس0qmǍ|=l7@G TC!@oXSsM?&ڪb]^#&8zK[to#waEDm*>\B}v{;5M6㢞=jPX&!.]ʵo>[~DZ2$ZY' z'̅" ^ P6Bh&U4gҤzQmOxbold3l"?+3M9L&?L~|\ 凓؄NuV xV"ڵC~e9۴_E~~kM-[btj^2l.:Rm 5a.o섡'Z*qݹN)A'DvV6/ǴmCLt k5]'BYbl (F67$D3xcy[mnH7 ؜}p?l+*$m6N1ܾ8-UHlkx-) ZB_~/_mHCHEǞ\ض~Ďvh&;YT N4:!9JIJ`x-z̛$l$/*oX8I`Y]5c<}pl hۦekVm;oͧ-[,FxCEzH}ӮFw ~}a8?whvћ^ 8 >VE^ykldYy ( &?7y?\=}'Bϫ, 5g5C;Áep9G~C`;tuPkk[V{*&7K~4:'=p+F-[h@׀<BBzu+÷ 5&=g^a)uf9H!\4&#О>I ]/7hj/?64kk 4SuY5Xio1~PwQ6-[~ëmRb`%3`!#K;Mmd#Upl廠IYʁ)xs8gA>"޺Z|f-W~MBBrX[Z:0 ϔX%bعkGq|R|.U u0V=Ut[ei*(˰k.n\ic6pM6l%y %hں^3!g5wnd|RCZZeCU:zn00/L|o4Z:PVams9CPY~z!2NOjyz'nF&5PVkc \9ovc:s l#V![acޜq 爏a)y>)y/ln8%{Z:.ox̅h<)қ8%gRR +q)SRgլ ;BxҺ%}.cFBqؿxLGNWҙN6-dF6-/9 Dtn(Yl2tN@$ I&G&~RP ={Q(JMke/tD.Cn&,-B)MǮy{WMW:z͜A R[Ž`Z*P}_I'N7ґJ:dB6mdȻZQ<'Ҟl$M{ˋ&φ6M^A\SNgR*,)ۉcCq|JL ʆc I}YPoʱ~m™sF9jŋdh kbV2R3c:pNL7ґt%Iwl!6>m < u@HW<TSfi}21aN~ 膨X%Q~h|>>dQV?]GhٝpђyE3΄#ߔ?D{ w$|F4`ۯ8N?d 2y 9b͆Y\O4~&#?zR:Xg~‚~îOpE]FY-6 )GDyd Ӊt#9]Τ;@MdW$Eۋ O&rƤ,{ |~ac'cO,mXU vU΋q:aWG͝M/A{;c@uc|~/~U΃tb ?lsυF§v~;bǪWp9χ >l|榳_Ie|x LyQx+ąK?skϏ/ق8/dPV7r䐏gqҥKe/^nbݻpy&!49;b#[a*RϮ}I"$ӁB:n#J:dB6mvyY1 /&{qg]P;IY87 OT4N,>3lBsl_xEaCfUxLAo=O@?6*+L-B>9k-'.ڍvč F_ njݻ12YU?{ݩ3},;}#c?BiGycO_Tu•AQ0%V7Vir1ěd,II҅t"HGҕә d TH^= 8PQh9%d[D&u*>u0ڻ PG#нذ/<0"N5QA;b]W1wGIwcc~6|㿿tnv T>b^hE k <!{4J~t_lǹ==1CLJ|]Na:ahWp(׉A\*%#nnr&y'#6ǹ 7p}p+CLrLJUװ)%%]cd|BUcɃG/[uat0uC7wc\~1Owf!8̷J~=J@OZ/II"$t ]H'ҍӑte:dB65#1ga!C-QhIu8{t.U% Ѱxy?bVt̼ @ګj[|QÑ{6//֬={=uj Y;pO{Q3.$JEŐK^Vg^$ŷFg#GnޙgXs}霮׶k= eOC4j`9@xRD\ 69xY u?<y8tÉkpnOtk/tOQh Cm0 '"1(6D_ Mj kgq=M֡(P"5Px d 5M-2ʍJz"p٨1nm zQy|5ԖA5X*|!ƀܕU~'i)B>(35Ѵ+:E{|xY 5T3, ^ēx E2I6@NnLGҕt&lj7|0\'``K  ͜fTtkם0Ew2Fml\+>SS^$xV0﷘00"8{hH-^_vѧ83+x]?"'!pCxb>D 1ɟ|].^Swtl6qx#,\XJ%٢PLr{^ -&,MDblveyI81O [n.(s7 ̃Z#+f }w^.ob<ObYX>;*,t DiwpciG,۽zD߶ƌ` kUZ=*CeYƃxO`H&&8]NHΤ;@M `*PA1ǫ `]x?-C7D0\? ""~W7ɀE9=12iρKwdndE]<`r7dCRqN ~r`3=wY-a|9sa!YaEqʄM23!n1ؿz^oU>|nrزڃ]j+G]αxm/FQc"a(d0d12:ed$5,x*BZ_pX玨( 3g#lV b#>Be?9VޡyCw.Jv)!>="CIfC$P*: Lb/vLϋn;5Ge,=CE<7 Y$d D+L d D54_H@bA9 @A/>z8-.Z}mZr $b&{ hG1c3k1(02J+\b^Ko׶񘧣pBR.\-߭rTbG!bsv@xr1r!bDX,eڍKE.1vv-QI!)GCTSisT `C * KT$}8FGuke5My,!aā89I7Lē'KpN&L2j C2 ɓC^+s8h{WֆgA.BBQD,TLr  @Dl؅yf/rQW>;{̉9g&$Fh]g4ϟYQ!xyh49 h>zӾ;,kC5Q^mC>b/u/sSV >4>y8/_r\es\us-&nms/'[V8nϴ-8(42/Sr 2aD@D?mKD&\|.jDSɧZ9?vR#2=|HM"%+ 0qftg^RtL.plfz wNOo~ m¡a[Ovk1MGB~P$zGb>5ݟ+HǟuEJ_;Po)ipmLӆ$mX%ӃH~J.N-tr8=n/I Uõuqލ7x30' Zx]Ͼm˯!k'BD vm=O3 1iUhA0h1@7g }D2 E.DI0s@yB|i|p^2,.S,ຸNm6q۸Vn3}>q2# U:tG1|)y8ڙB3% _ؗwFIBlD| B_4;E$ȷ%V| UTË``t'b'ERfc󒉶"ŸEwQA>NoA [}%iOy4Fpn.؇ u&k66/h.j ӓk}PwiWLگh(=7@ݿ|2jg/->|%l.E ul8sf->L۷,GʕSs7|zxD7t _xqrO%q# xIpYS.)OG9=hʼ_fdr6[Dh#(6!Lجdߎ,X+'Jw"Gcpr_(a\m !Sد~DIȚJѷ k:֊9}y;Nc3zAqO~mCIvmFC__֋bR$iYɾXXӱVO+5q"mӃkʡ0#a (O1ktlԬǛ6N(H3\[_w`Ϟc^l۱W/0Lx2)q5NzY%4jg&I1n'މ5axޝ.x "Z=-jS0wHkKLj]e{OmQwYy_ y8/_r\es\us-&nms/'[R=C 8z2)\j{ph||=r2%`LLLXʟd&cs}:ngd<$^2CNnX ZXd_ nau00@ES/H"dlNO'qY٘E(5| jۈ#עZESytN0h0v}ҭsgL"dlNOڭY٘E*q5NR ~k{m tXT m#lf a:(7Xh]햳8zKGwLt-0yy brD.®pX%<>& t !j4RHx.|| Gv]sƼx ^(T䲹亹 nm6s۹-mLSʚ ZqfkL+ J&o覍"g_~'S׿qQw(gןTk}ķy]^ /TBqK6s۹ Ld^ߙBEy ")OiBoi䷋? +ןT|3f kr}>q߸z5L nƫzu7 Q5L.:nnm6r[6#0',Er%hCvpl)s8 M&3OOnGl1sOj#A䄿WVw WD@p\Vf;~yrdӢ-dp5$[k!֗觋S8RQ+nMW=[ESlLO'S+PcNtE.䲹亹 nۘiWsFGHY?٧KK [X1)SV3dH@f͚5Cxg` hjժ7Z[W\Ex2bZ`* 7)&4$v1fn N=7p\VF?\^g19yಸL.ຸNm6ežpot3=3D39XMv&VS1ϚG鿰XY԰xǥuGݚZi)c8,/F;7ʍ6%ɡ6DXh[U6ediڈQCǽȟRpw-Ö;fW3| _epY\&up]\X7mJFv}>}>SSiߒiVnIn7bir.)*_\*Wѱch аqx61y4rt (^Ψ_ tM5;}1+i_Eb|>HqA~$ *CD5< WiVK`~u,wPC~Qrڍb[aYC? \1yoCjh`:Ƥ_-k .䲹UίkfF/JjʄkiwaB2)_TjLN&uAmo6A$S2:7oID$o"ڦBf,;rʴK# dZЕi~<)v BQDA 1r&WQiI(&&24 ddz(rJrEB t*#q*n?;#$S$?!͞1 z^UBVUV 8OI0liTfHe)."I}#E1vTLjٌQ[$5JA,kшPZ:W=[1&DZLD9SJ"$d,|0QJE(GhYm}v tn)RZK:ׄ'22-Z6Q PYz2d% dFU5$JˉcX1q,I(Jl^ZӲEVutծ!91!](#itme҆e$dbS3 jI[J+JsA&ȉ4kvsxjUS}뢟=4}t8]Th2 lO HD3P%|LQ\$_;2/}lCu0X :#HǜӈjU%i!lr`b x&2cd=A%J{ iڂ[69>VڒcfcM$#\0Z-1Z#Zӹb0 Y9>!f S2A-de&1$J[k?Plzr%qlvv'mƄzD7I5ǜFP!MkXz9YI ̰)Z[.(VHb9A=ii9LMAv^ʩk,6hUA՘|cۋd3 0Ӱf8,xn~ J>a얢9Z5,y|HuZD61(ɏ"1E&Ï}B&j9P|?ךkVclZ?6쁹9bA"q8MOynIXn4\D$3 {Q Q-[џlQF4CyUM2yB@63ӓr;(!&xXlE.8aCɟ k9ɷh4rZG "MO4GY r`keF"6 Ö<ӈDMZpawL6 2]4D7*@-y( t8sk cM$JUC dSpZ~FaXmLgnR5e&Q*#ey&he1VIev ]]\Kl>4b*pY2AAOA[13S30ljF~ _Jfۧ L_e5 oh1A tM; B!5 /N9SLCL>҄襜ui(fȻ#>&9s_5!_-~JW.CSL[ y2}r"'ٙ%NwNNc)&]D&lW1c%N'L?S7d}9~!%7 s|k5Tw6 KXc.E- >f5OAlĥh)]Two҆\I046|Lhlzhʏ` ZwYB8„cQ.c;cӓf]G(.Ρ\#=7B"$$ ?p4;q/`@*F1H؎$c c3Y܎TR 姨ijǩb%-ؚ( 嵛Wư9ؐ[[\^ؐPs|lv2q|ul%M{+P?Mt$]Acyć+& ?f7MVe<`kUaU e歞L3%J"ɿ [Da&+6"^ͤ] W0ljȁvr}>6;Y1xQ]PDu%S8pL#IwDd'yU kFG Rc֫_SLh%ʩ%a%^'ʏL&#/)U91Yy])Os|7TUi>WDMP;ʏ*d":bai%L<֠Z,W2Pu$J_~Lus҈ɜ8y2w4)_i|<) 7][BA/g(y XA#E$;FD Eѹ1!_O^nҲ==H#p)A\. B˵6 d8$r\k:7Zmu \o*b`ꍊ¬Y0{lغu+΅aNxڭ.M-6aܹbpL4 Q8Nާ} 6oNL4M'4s?_?S3dWmkznCb3]AxRЍ19 Fn<Ү@$!;[_ǻkKxw"j|c 1?/qq={=?hNB: x"_.8̿?Ԩ]tnO1o_Ӌ3n0_`Xp#mKvW'zXfcU[*pQM5! 'u^R >y(|=KaƉ*U_h5RB.zi ܃Owu/Dǣ&x$pQɉDҹD&ڵk? >"Cq,W.hq4n(]`b9sl:w5rM8&[_`J̿.`_Ez8r+&/\%nZƞX0WO4,ˏ[ v5ǵ+ۡw!# Q }ϊ0FNĺ;up^N!oUE~9q=%<q3CGD=bk/+$L{4IH~wgģeK2?G۩=DF 5BVF} q!!۵k'@qfΜӧcZ kk̠_Πs'*4@zO>NM0X130L3ggLGi`f??3gȗSF2Cc^c,{xu9i甦:/<:?mzN}MK\W'M"_x0iCY}$xBo 8|"O(^n||'/6óDGDyJ3Hz <MI4 '/bĉ"D:7oW0C?Q'??P4^ n&HSa&G\h0 :Y'ȧ=v06#^OpY1‹ф',="r2Aq[dE)~pX(x! &H$鐠AُskVI%\9Ҕ;#Y</ _l0Q/}Bgln.1;&MH=qo_{~߭z'0J4UEܴej;b-]& C IwF~SȲ_~(!TO59OgIBÓ5exM9*L,DD~{ W0ƹfCeW"\WTDAZq='oµ p:i*o=q0/75Ex֩xP! ߂!򿛆C!D:ˊZbB !eDD@;K) B`BrkDN[^ xD(\Uw"ǘ:TFr7sib˾2^6Ѹddn7ŃjH:ʏV 7| >^<|q,64 ' L &DD"m<$R^_ *\/[N|ݓxA&IG$nHxjx6p]+ݙ(P_oѮI9U W#3Gqۨ+&|T Rë}ձoQ<: I]pg&G@RI `w"`"`"`"`"`"`"`"YFΟDY#qz~˜׫|by(x뜫!`ni QBE!0Ś˔U'u~!Lsgmk/V pF ֐۰4u']%H|؝h"S?&!^l2xJ'#?_B@_"/ЗGoƾD@_"Y R}}F@nN)`b^ v[eݟ-Tp5VP0aiDܮ +@1907P j*ԓl+*8S,z ̆dxw4) H~;"@ʶg;\e rіjHQH wpZ)vc73݈D@KEdnJBJ=k$ &hz$dddvgsȤJ9OKcջ:YClv:[`V$!.f#n5& Cx|L0 %ݜ2\lG4^lEPN'}E1%!'tyC4y괣km&DvG,\mrml;" v)DvYk((#"|h!6iFx޵W Q@A" S/7yDgz9c4qCvS|^v K0&D>[&$?"pcn'Z{+JJx!|x1v &K\Xw^oչ5uh?~cǚ29RѣZfyСl{4JsNwvR /}6LZVSÚR-U%aDJT""`˯7䦘҄pC.9)ߚCht%q˨kMOFM "co"cgT^" \TLiX b,EG V_I`ay+2q %p1#?/Ǚ ~_I%.~ogϞ͵cǎʕ+͜9sŋDGGO_būe˖5k֥"4&^F 7ө3'# 9ZbDs")?+npruՑ/33J8Q9KH^ZT]1 =x-/2O5yD%X A',%!;hw ^o&+D zH hعx49jxiǡ֓kߴ͛ׯ_/aÆ3f 000X]vGDD|g >80wQ f(9.WCYZ/~bf@yA?s럗|.||\M3AF8nW,~R`HI3AC^# l*,9l*֛و gCdI[=PX.6xu" 9>r&~/P5[/Nt6lٲe˷/ ~є)S0bĈk֬AB2nj@yNxGDwrY:mKpʒO_=2GаyQ uKYWp ׹ p0&| dks v=r8Ԟ4H$w7G8%^uqgQî.p|Ly\Džy vIg |5" "`o0~,?p1U|LQ1;? E-]Td1 Ա[Z&wJm>GЎ:;%nrd3i 8O'O02 *# 5aE 0"]xKV=#Ȓ i+mڠhGR#;9 n'߶mH>}>!R^Z6*U|< ˇsrm:W|FZU7+7y 9>&"ND2"$O4x($TrziXu1Vo)W[wvqkwIfg{Mk;UNڕ3zɊzv.*m"Vٙ)/  =^)&\4Ez%L8{v ̮u""~7: Ph":`'P_?/gu*mX>)~=u~Zeҭo4@ }$D.~gSIu4 E: &J"ɷKk`9k]_ZdȲ@7!`IP}l$:΄ UQ" 64,o XaVKnƀ3: w%Cإ^%9_\/F3nL39%R &P6`s3B?T&D^L*)af_p" RytX=~OO9\tocR.nMYit#![F* kT!4w-NTiU UR\*v~D> Ӄ- 'Qn }"`=f>*#|NT"<XuCE_PFtΒZY`/PYNگG,$yCd S v~a1 v!=xDͦhUe%˼d%-gZe2O\G~/=WoleżvNaT +)r[,O$ w\WDMc4L+';mQN.R/;?Te?-=c^AԂ!_ :8,)EfS"4#-\zV+k~j4?B ]yUL:Q(׆%`\jg)=3}*)WW$K 5 Թs< yẮ"j. {+CA_`p~tri/D%!2.WOD"`Zy 0xfi㊕3-i#gPMJ"IF&TͰ(} S/-*r˼d/6KIHr~ _mzW_E%C#-/\I$Ɋx Sk-6NbR1 3^D<-aK%q/^(TI$:uIXvb~H9?mxD|a9>k_h:*tS%$f)8htQs`):PS_͕ʒ$䏐+<3O?Z]y VB~͑D)&s:Rmdb^ XeĜDӟJf(J"J`]3cv%v{=+~Ğ@a8ZՀB! %DeRѽnn{m>v G}0sچjݺ[}% >lAFtt B2%['ha& "IYtkv]kl=pYsPۡ6SѾ.[ ֛@s  8j/g m'"IY >lZI>q1t6kR ]l' ]Aym҈npsEꛬh@D 9s̑?~?y?n%Fm!ƢCcN'=< 4I;Ŧ80V̏^yYoJ@Wn,XЙUP! E?IC f-A]H E{P4Ocf"z {B`dLʫBf={I¤*U\/899Zj077G…r78ڈI-nE;~-jMG h<{:-!߼l <Τ%۬ۍWhwJ|s2,#Peo>[n>^~;w`„ y"A*UBѢEY#h~&E;W=d.BQ` F1QmLԘAN#Pwrcb|mBנ*򑂥wMR"pt*D(н|5j'?aaacccpncB(aO*w-B5g E|}a(]XQ(g4v3q߼l=(=y: z5qG5 %ٺcTumڴ Ƅ={Οhee%5! ,&x}F+USWWMZ]l6fS|a1}&,gBpT?銍g?:܇0<8Af){k((wנ=҃gA+Pe~_gKKtDÆ Eխ[%J*A"X3Ic̎/9ϫ"j2?ǐ&!Sa:) &MV~t(ʍ2&q(w wPk t?{ͮl| ZwB6w.2@6^/$}Tv,0icc˖-˾` .hMtpQsڝ{ԬeB}wװemQm(v+={LB3}Z )o;Z(ݡlkOIHiO}?kM~"^…Q\A@QӱcUsLsS()WP[g+mEqBZ G{]^G_X{AIOBr_Bvg`9:v(N=0ի'^R<_&xqw^*}"* ArR]V3"&sV%8%j%E!%3f D35?i=;;;T\8SL@e*} jl8̜k֊+d|Nt2j[r7 FκRR!sҥ?,l֪UKT&'L *x|b8E °STD kxX8&ǢXC;yߡZlU(񩉖^&4xLLLRȷ<2 Ļ*>TeSiDJn]sz3# C+a6p@ ~H>րNK7$:[N&J(/dI2&!tL8`gy&#WKҩ}BVJw#:EG+`6w:z Cg~$PM0,E~(/dI25kD&[jpkA?o3fm|o ]"F=1i8_iFlؑl=2MF} &BZ{ziTrV%Zt5"O-[75ڮh f}ðq_lkĩU#zwֲX/qנB֤_ ɒHI,:3B%JYP(߹P_veN03tuV|b>!m*W5es_Xh[ߥ7$K"'1,n5l7h;U짼ƳҀi OĜIڮPɠAe&W3%}ǡPdeP&`c\&oHDORCl@zu >Sv(Sj־ɯie:,=t@RKPc"hD0u7 C$TӰr~YKgTBQ\f=ٿ)VXFVg蹯s9 8 zXηA"$?^9p{ùpW\FгnW(($*|HfhZB5tS$gOvl?,^~mBEMD)V6~s4O*yn$H"$H"$A]$D/$RwK!wjղlcʇ?5+6lUA_?t$D -jgĴz[nnc~r]c;ŊIwNIx9&|9>Q'tي\~|eнy *fK7t#&#QbG:.II$*n/ ۴&nS##Eʘ@&Pro~`= }!=xI͖D~.t}j. ԑ$d" =ڍ0HMw1{*k*j`h(dbYQ}){:=c'Q9>!fLIjDdW9t{h7cpp~8x/6A{C 11ߘt8d4 K䏾a`Mj1P$d t,u;1nh8N^.%*q?n "/>ÊϰSDǚpZ4G'dSQnB1sC.K"I«Z屴ӨYobLj{qu\}c螫9ʦ*f8:S.O)#jRQ?7^z軯q{yO߉$lޥ{ZՀ~AchBvmqҞWh73n$dD{9?cvmLY^N CGך5" Y > B371\yhh^Qgul\,$ߠ{=.]w5mZ&ds}q!>,NM ^&i@I$ɢȄ)kY sΣ72܆䅨hSAAV?hO8|@PQ.K"IQМm๻FA~Fl8)N?0 aOȁ1$GK9 8![s/WP٤,$Iey /!{ ZOgnQ" _ܳ GGGtI0z#.U5: {yK7XI2l \zZB"߆"UP 2 l{9lxi,8ӁV̀2(v ހAeyt!; F@@41o940Kp[4 /x ӎ?/; /2e<`|:Ym4LG( zNMFGWWݷ5hvu#U1(83_>Ѡ\ #aSh he:ܹۧ=i˾4ЁN̷6=G(a״S-)㴌2N%fږB@}Q0 F(`Q0 F9L(Xx5 ?IENDB`tiled-0.14.2/src/plugins/replicaisland/plugin.json000066400000000000000000000000321260670167100221530ustar00rootroot00000000000000{ "Keys": [ "notused" ] } tiled-0.14.2/src/plugins/replicaisland/replicaisland.pro000066400000000000000000000003041260670167100233200ustar00rootroot00000000000000include(../plugin.pri) DEFINES += REPLICAISLAND_LIBRARY SOURCES += replicaislandplugin.cpp HEADERS += replicaislandplugin.h\ replicaisland_global.h RESOURCES += \ replicaisland.qrc tiled-0.14.2/src/plugins/replicaisland/replicaisland.qbs000066400000000000000000000003421260670167100233070ustar00rootroot00000000000000import qbs 1.0 TiledPlugin { cpp.defines: ["REPLICAISLAND_LIBRARY"] files: [ "replicaisland_global.h", "replicaislandplugin.cpp", "replicaislandplugin.h", "replicaisland.qrc", ] } tiled-0.14.2/src/plugins/replicaisland/replicaisland.qrc000066400000000000000000000006051260670167100233110ustar00rootroot00000000000000 grass.png island.png sewage.png cave.png lab.png titletileset.png tutorial.png collision_map.png objects.png hotspots.png tiled-0.14.2/src/plugins/replicaisland/replicaisland_global.h000066400000000000000000000021221260670167100242670ustar00rootroot00000000000000/* * Replica Island Tiled Plugin * Copyright 2011, Eric Kidd * Copyright 2011, seeseekey * * This file is part of Tiled. * * 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, see . */ #ifndef REPLICAISLAND_GLOBAL_H #define REPLICAISLAND_GLOBAL_H #include #if defined(REPLICAISLAND_LIBRARY) # define REPLICAISLANDSHARED_EXPORT Q_DECL_EXPORT #else # define REPLICAISLANDSHARED_EXPORT Q_DECL_IMPORT #endif #endif // REPLICAISLAND_GLOBAL_H tiled-0.14.2/src/plugins/replicaisland/replicaislandplugin.cpp000066400000000000000000000241371260670167100245330ustar00rootroot00000000000000/* * Replica Island Tiled Plugin * Copyright 2011, Eric Kidd * Copyright 2011, seeseekey * * This file is part of Tiled. * * 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, see . */ #include "replicaislandplugin.h" #include "map.h" #include "tile.h" #include "tileset.h" #include "tilelayer.h" #include "compression.h" #include #include #include #include using namespace ReplicaIsland; static Tiled::SharedTileset tilesetForLayer(int type, int tileIndex, const QVector &typeTilesets, const QVector &tileIndexTilesets) { if (type == 0) return tileIndexTilesets[tileIndex]; else return typeTilesets[type]; } ReplicaIslandPlugin::ReplicaIslandPlugin() { } Tiled::Map *ReplicaIslandPlugin::read(const QString &fileName) { using namespace Tiled; // Read data. QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { mError = tr("Cannot open Replica Island map file!"); return 0; } QDataStream in(&file); in.setByteOrder(QDataStream::LittleEndian); in.setFloatingPointPrecision(QDataStream::SinglePrecision); // Parse file header. quint8 mapSignature, layerCount, backgroundIndex; in >> mapSignature >> layerCount >> backgroundIndex; if (in.status() == QDataStream::ReadPastEnd || mapSignature != 96) { mError = tr("Can't parse file header!"); return 0; } // Create our map, setting width and height to 0 until we load a layer. Map *map = new Map(Map::Orthogonal, 0, 0, 32, 32); map->setProperty("background_index", QString::number(backgroundIndex)); // Load our Tilesets. QVector typeTilesets, tileIndexTilesets; loadTilesetsFromResources(map, typeTilesets, tileIndexTilesets); // Load each of our layers. for (quint8 i = 0; i < layerCount; i++) { // Parse layer header. quint8 type, tileIndex, levelSignature; float scrollSpeed; qint32 width, height; in >> type >> tileIndex >> scrollSpeed >> levelSignature >> width >> height; if (in.status() == QDataStream::ReadPastEnd || levelSignature != 42) { delete map; mError = tr("Can't parse layer header!"); return 0; } // Make sure our width and height are consistent. if (map->width() == 0) map->setWidth(width); if (map->height() == 0) map->setHeight(height); if (map->width() != width || map->height() != height) { delete map; mError = tr("Inconsistent layer sizes!"); return 0; } // Create a layer object. TileLayer *layer = new TileLayer(layerTypeToName(type), 0, 0, width, height); layer->setProperty("type", QString::number(type)); layer->setProperty("tile_index", QString::number(tileIndex)); layer->setProperty("scroll_speed", QString::number(scrollSpeed, 'f')); map->addLayer(layer); // Look up the tileset for this layer. SharedTileset tileset = tilesetForLayer(type, tileIndex, typeTilesets, tileIndexTilesets); // Read our tile data all at once. QByteArray tileData(width*height, '\0'); int bytesRead = in.readRawData(tileData.data(), tileData.size()); if (bytesRead != tileData.size()) { delete map; mError = tr("File ended in middle of layer!"); return 0; } quint8 *tp = reinterpret_cast(tileData.data()); // Add the tiles to our layer. for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { quint8 tile_id = *tp++; if (tile_id != 255) { Tile *tile = tileset->tileAt(tile_id); layer->setCell(x, y, Cell(tile)); } } } } // Make sure we read the entire *.bin file. if (in.status() != QDataStream::Ok || !in.atEnd()) { delete map; mError = tr("Unexpected data at end of file!"); return 0; } return map; } void ReplicaIslandPlugin::loadTilesetsFromResources( Tiled::Map *map, QVector &typeTilesets, QVector &tileIndexTilesets) { // Create tilesets for type 0 to 3, inclusive. typeTilesets.append(Tiled::SharedTileset()); // Use a tileIndexTileset. typeTilesets.append(loadTilesetFromResource("collision_map")); typeTilesets.append(loadTilesetFromResource("objects")); typeTilesets.append(loadTilesetFromResource("hotspots")); addTilesetsToMap(map, typeTilesets); // Create tilesets for tileIndex 0 to 7, inclusive. tileIndexTilesets.append(loadTilesetFromResource("grass")); tileIndexTilesets.append(loadTilesetFromResource("island")); tileIndexTilesets.append(loadTilesetFromResource("sewage")); tileIndexTilesets.append(loadTilesetFromResource("cave")); tileIndexTilesets.append(loadTilesetFromResource("lab")); // The titletileset is also known as "lighting". tileIndexTilesets.append(loadTilesetFromResource("titletileset")); tileIndexTilesets.append(loadTilesetFromResource("tutorial")); addTilesetsToMap(map, tileIndexTilesets); } Tiled::SharedTileset ReplicaIslandPlugin::loadTilesetFromResource(const QString &name) { using namespace Tiled; SharedTileset tileset(Tileset::create(name, 32, 32)); tileset->loadFromImage(QImage(":/" + name + ".png"), name + ".png"); return tileset; } void ReplicaIslandPlugin::addTilesetsToMap(Tiled::Map *map, const QVector &tilesets) { using namespace Tiled; for (const Tiled::SharedTileset &tileset : tilesets) if (tileset) map->addTileset(tileset); } QString ReplicaIslandPlugin::layerTypeToName(char type) { switch (type) { case 0: return "Background"; case 1: return "Collision"; case 2: return "Objects"; case 3: return "Hot spots"; default: return "Unknown layer type"; } } QString ReplicaIslandPlugin::nameFilter() const { return tr("Replica Island map files (*.bin)"); } bool ReplicaIslandPlugin::supportsFile(const QString &fileName) const { // Check the file extension first. if (QFileInfo(fileName).suffix() != QLatin1String("bin")) return false; // Since we may have lots of Android-related *.bin files that aren't // maps, check our signature byte, too. QFile f(fileName); if (!f.open(QIODevice::ReadOnly)) return false; char signature; qint64 read = f.read(&signature, 1); return (read == 1 || signature == 96); } QString ReplicaIslandPlugin::errorString() const { return mError; } // Writer bool ReplicaIslandPlugin::write(const Tiled::Map *map, const QString &fileName) { using namespace Tiled; // Open up a temporary file for saving the level. QSaveFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { mError = tr("Could not open file for writing."); return false; } // Create an output stream for serializing data. QDataStream out(&file); out.setByteOrder(QDataStream::LittleEndian); out.setFloatingPointPrecision(QDataStream::SinglePrecision); // Write out the signature and file header. out << static_cast(96); // Signature. out << static_cast(map->layerCount()); bool ok; out << static_cast(map->property("background_index").toInt(&ok)); if (!ok) { mError = tr("You must define a background_index property on the map!"); return false; } // Write out each layer. for (int i = 0; i < map->layerCount(); i++) { TileLayer *layer = map->layerAt(i)->asTileLayer(); if (!layer) { mError = tr("Can't save non-tile layer!"); return false; } if (!writeLayer(out, layer)) return false; } if (!file.commit()) { mError = file.errorString(); return false; } return true; } // Write out a map layer. bool ReplicaIslandPlugin::writeLayer(QDataStream &out, Tiled::TileLayer *layer) { using namespace Tiled; // Write out the layer header. bool ok; out << static_cast(layer->property("type").toInt(&ok)); if (!ok) { mError = tr("You must define a type property on each layer!"); return false; } out << static_cast(layer->property("tile_index").toInt(&ok)); if (!ok) { mError = tr("You must define a tile_index property on each layer!"); return false; } out << layer->property("scroll_speed").toFloat(&ok); if (!ok) { mError = tr("You must define a scroll_speed property on each layer!"); return false; } out << static_cast(42); // Layer signature. out << static_cast(layer->width()); out << static_cast(layer->height()); // Write out the raw tile data. We assume that the user has used the // correct tileset for this layer. for (int y = 0; y < layer->height(); y++) { for (int x = 0; x < layer->width(); x++) { Tile *tile = layer->cellAt(x, y).tile; if (tile) out << static_cast(tile->id()); else out << static_cast(255); } } return true; } tiled-0.14.2/src/plugins/replicaisland/replicaislandplugin.h000066400000000000000000000045041260670167100241740ustar00rootroot00000000000000/* * Replica Island Tiled Plugin * Copyright 2011, Eric Kidd * Copyright 2011, seeseekey * * This file is part of Tiled. * * 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, see . */ #ifndef REPLICAISLANDPLUGIN_H #define REPLICAISLANDPLUGIN_H #include "replicaisland_global.h" #include "map.h" #include "mapformat.h" #include namespace Tiled { class TileLayer; } namespace ReplicaIsland { /** * Read and write maps in Replica Island format. Replica Island is an * open source side-scrolling video game for Android. */ class REPLICAISLANDSHARED_EXPORT ReplicaIslandPlugin : public Tiled::MapFormat { Q_OBJECT Q_INTERFACES(Tiled::MapFormat) Q_PLUGIN_METADATA(IID "org.mapeditor.MapFormat" FILE "plugin.json") public: /** * Create an instance of the plugin. */ ReplicaIslandPlugin(); Tiled::Map *read(const QString &fileName) override; QString nameFilter() const override; bool supportsFile(const QString &fileName) const override; QString errorString() const override; bool write(const Tiled::Map *map, const QString &fileName) override; private: QString mError; void loadTilesetsFromResources(Tiled::Map *map, QVector &typeTilesets, QVector &tileIndexTilesets); Tiled::SharedTileset loadTilesetFromResource(const QString &name); void addTilesetsToMap(Tiled::Map *map, const QVector &tilesets); QString layerTypeToName(char type); bool writeLayer(QDataStream &out, Tiled::TileLayer *layer); }; } // namespace ReplicaIsland #endif // REPLICAISLANDPLUGIN_H tiled-0.14.2/src/plugins/replicaisland/sewage.png000066400000000000000000001657621260670167100217710ustar00rootroot00000000000000PNG  IHDRŐgIDATxYl[W.Fޤ WTepq<$q8r(۲A[ ' ++k{xi|zCU[<,r-oHII8^ͮ2L5;e,==4>5V;;Ç!u_^˕X>cTez=N-IV\gڎ8_cSSi^\+uBϞG33QVP*ϠĽ^;%x%;`iŻ0qhJL{"ZLH~=0YeߘOb_f/lcѥ8cy\749;7x({+g^Xa*Ӕ b`||6b V ߬vk${%D[}4m*F (+:Yh(kD31^7; _;*@\J=;Lw&T(^Q(W$t AT;6'X<!}h7w^So%`!0GJbgHFooVviX@ C41V4 @zh@umm8dxI>I =)J&x@8)(_Z>7}mGIR,VcqZ@gL8כn /dkP 3=۽q%}j6PMVs7ou`{*shtʭ׿e z.,w!&?!pbtG3 3Zvw~Ǐ l舠goi1 ;~ 5D;R W3}'̄fb|pUI{oo庆{~jf&bϪ\_&o-$!f'Q>P۽w Hӹls''Vuja$9Sa.5짬B71@ IA!&ZTd߳vG_###;>=6|ONϵV[vM9JL4:jdREumʿ׋'Xwjg*ߣUg+?߰zV\w2 & bTvE 9cޗtԖVYQ.oY\c'XS.2=pd2 o>˗ҥK\?NN(:M~@?~f?06ޘFͨ?kRbMW3=)Ι{\j'SзTSF:EyyJڳaK*L(0 t8Z~[=-ՍNYj)Z-c5T5Kc!?0+-Ӵw~+ E8Qg>>ޟ3KZvzD۠znoj/Ӵh!CDΌsRBo)"L7YMɊ`ъ W6`ނ?ޅj>8T=7MeeTPP@yyy\233upܹ5H;@q[V$B$[vob$|S"hs8Fnsfh`J3)QجGhdfFf [d+cɡ<*@no?Vjqm[,+}30zߘ]k|spN(SvGLYe`& (@|r<܎90z` YXpԜuV]?9U:%3xҗŋ;Zq6_ j mMۀSŸ]6a ăpmt?|zode"#.WzohzkjwyHTO6Rѥ>MqX 6L80YpS/*D&R NlEwWMc` -HjBL~ G ./Y`4iKʒ>чeSOg`^PS{8pBMx1LwJ'c XLB˟+7"@>\.y2 ߟfuM]4l/L7sŚTv44kZԿp<+yG6w73b_n?,xo>Ȱ}e4oXT@G$RE'G. 8(@,>N-X pePɈ0IT@ha;LՁW,bueuYlglJuMvc`~eQW@ʷn\Bgmӭ*:[ò&ˠ!mfs0CCjzP>uOՅlyK&C꿕\KMja^J/5uF+gΩe}E?*s`D\/ߧD 7%`1Yӟ,`$)da6  İ"+ی^S%|3Fƿ+W?==}ڵki;o5RGfy G6v|()`4o±@'[Z6Gcz4000N=Mʢ&W Cl`V(_h0qZGJ1({hsc{m\G#@&0)&qTUDxX:p lO3%8Z'2F{Qf,Q->r[ސ>Jr\e`&o*hdcQ:`7p9` )0/a>VR@]l@.fwӀ\t+AVff yI \ho}V!@#ZsS423NSCܑ`B_p3@(6Ip#"B]LbG& B(Ep3ke:I;1' #1bc9Mdn&W$0'O(#7V2A1qSY{"r:b/v ֶ|jfkF)(C& qlЂ<1xhl Dli4R~A.7o&ļÀت#50o>/('CnCHK)(u~ `by҃;&lYь&Uֺ7-GO6!p/ĵU?2w##덭5v)eoE4 5 >T7KwھSVTJ/r)I}\PyϡtPm!MTRZ{TޛAA^Fn -70>J>['}HQw?G+z( TڥđI鍇4  xF*9-Xp7Xh4(J์A2Ē>` l T*A,cA"X1Esn,̌aaWA҃{ `vTk"̏Hk߱z?Y=;~/RBQ>DXEf ~fݨ % tRNQaO)3T l]{ߡY!D/Ӌs4ᛠb˦vwyɵ!f᭤nn1VW6xᪧ\.Ȑtmkd\I: 4PT~_ҟA5T;\/I ?uwکeNA@$}VQEi0VLֈx,E[bc5߈pgcJ0:=A%WL=rq6d;=GlWKhrƧcSSHʲ7f`Q0υ?/Ѝ} Y>Xb)NsD(Xo"*$p"209t ˦QѝM壗vSʔ~1Mws^蠑N<|\%uWnlqS. Ph9SǸ?Pp+Ew:Өr ]Q08Nӥ_B7x*"&눅ݽFG:"X-|UVZ`TnC },'P ̊+2dT@s18ſ4?!.=m:-7v}_Ή=͝O1*;MƹMo83sp<v4P#mݻ~#'Vo!#a@g_9ROx!B?9 FiXH'48:Cv&0?1ixjn͝_Ἣ{i?AMPFT=| ~ g\iOmSea?,Cj3Y$L0cSQdز*v9QW T9N|? z<;Jl0 9,L+ڈ^âΎrEXdC\t>wS OJɹ (πr3$1r83 4ȻY@hj]uӌwf4: e]5uz49x+APpOǨo!8pLni @EK>_^y*f֣I&w|MW>)ao|}nw NV3- )g0wtɴVh*YLGaGSS2BPlY6O4V̏D={h yuc#ɸnf1HI}%45NvX8s/_&߭=:OBHwdzqf:pQ' lDo~Oi$@ӭVfƔiݷgKyufT@a)Fi3.aR`buUsqA ^ovơ sC P`41P@ bxE/{rf_ˉl`^ 4BvޒLe<:9 򃈜$+ 88wW)崟t%r/#AuoluSh^Xcxb i+.#lvObGjSdʿH!m2w58Ӆ+_2W4rKt%7ͭ Uq :"Qnԥэhn5}MOҝtݭ?MYu|N)8ƥ^bWݟSv'~{vl`l3XFʨem7\?M9^9] __'wr`\H#spn,fJΟDK: '@"2x rUx#QP?8ALU NI[zIXCINhk#l6,MD3ʚ&R-+,M^=SHkjYcAM[$A$Ś5t* eo`^yH(58uZ&Ji*רj0FnpuOP-:y4Av?_H @L'=O9St@>J~4 ɥ+o >[M,L:XO\lxxA-/ iLUFGkv/& Z>SCÑmQpu</E rHPF,yc},琓,VTPYe%'E\dhJ͛ ߟ[^~w"v$3h5}wܯ[w+5OgfZ H.ݽ'5]!"-v-qȩKhhz@/9ۮ?PO2 [<2bbOuBk-GΓ}+} ^[ z`lz4"YPrY0< -9t :BAdf1A&h(~[MLG"1,@X00@d/bH,򴽚BHn{_86(x4kfK e'CgpK߿s'ɘɟb{{,g@Ts<2akkb,Д5TVw':of+jd|+s! 08%P1Vn|;NT^|L~/@f/³ِO†i^lT'-.V[ҕ*5!9[v4rrsvV֚xV?f?~9I5ˍp>5#6bo\NO k&7 g/,H @R-Q(;`./z3IJ0>=`5ޔkZ& },d+ʍ?uv }s=:}M}AMqcޗ4oFM}7B0^W/k.2<3[ `W$`7U;n&,D  %H0<-!,(?\ W 4F7)G@40u8n`KB8"޿ ~ܹneeQ}}}vY7cAbcy4Z f]Yd#'ord?OVhz^";x&+ N+(hom:+m0@( < P` _u!'vrIZ|gҢNAx\XSGU߾V&m[Xʟuаg<Ћc=01ceM=&tfwcv⪝Ηk װ"iۖ *)H W}{{WUF;[Z~̵sQVPdg(U E7cܣ6.Ap٭H{vZU}!QCBm9vnV=q/Y&P]QhVT~,z^y)gBNJWNk4%&bLb ],1fc2b!b m/e7<%L:zo.\s׿yEb oREdeGzv+((j53ؤ0r4Lha?R{-J\jeY{|cm; #?^q~߿3s_¾K`m5?V;eINmyQ,Fplɴl@qw=` HR,@v9oL7o3ɵ8#Wfƈb͡)yf =%(FE&Gy7, YkEjb"01X|e񖷃4+ߢ {%j`Joi rOv[8&~ʾJػt-#F̦܋"9>Nu z3 ,Uo#Ȁk;3nW<} v& S *Nnh;EHHIy4U ϮHl@4Yl(PI >yKkn^[^0@qg %n~rDiО?J4 16m"k1ӟq s-!6ymJёd dLNC[te|9!*/'#zhl1fɗxg VA6?D\'i ` Z۱ݻwh$ׁnWJYeotAÅͶs>{>~_\6~&y% Pp}SuͿeBUTIKEe_SvcESAd|vފ4e9:jϾm [%-11ĸ8<!bd_*5)m`dPА2!"kl_=H0-oDaR͸i;e3A--J@~2<>QΕ 7gkl gU3%%0|_#VnÍ Oc1RG[+c'Z}M~1_I8I!8@O!ح;KW~SG?+{owԘkf!ǝ}ϏhqmSVö?a8Z ˕/3/@ ȿ` bA}T-ETNDEEE{T!; лt>]s^ w S(`ʒ>N/oW\xo.3,vƥefH/@pXy¹O7?>'QzZF|j/A}w(:o}|]tOݷ>\ :g.rw2zFMu2Idy=x}!EiǪYY<^r2:7LMA!3TRRrSrzc̽a_8 Gh牙qERY]M%unx Dw1dG @F0Kn,=~|0k]|gѧTzk/]=n|@@^:I/۔.e{Uq?^E;׼UwS'2` ԬAb!b,ͯ,@0`B<jl׮:Rd迤18ÔŰ)ەY-bXL,PPNKy3> Z[U Le`M65ʘ:\ } pS-E>3x5T]xxTT1mN]7?`  ޣsy}?FS|d}!|F$1?BM DKwt@@NA6X/[SU[4d-ʹwK$ 0j ϏD^^hB @w[b⚟mZ\\'!OE$˘5RqFUmb: V#1S{Dy`010H\% e'3=H/O9_4RqG):o^bg4;Tًy$Kz@-fڟ[CPk~999! >M$K F5I!h'Od-X ?QKa$p\!h(=0 Q H+Sl P_"1K6*x툶m25փk-Nuur_$ 7Ѧ|5cti ^pH˝`UD /k7~]gb!ٙg@3<]O:s}ʻm7;x '#ތ:>?O\߻kjga+tm_xU^Afe))++Wd?vd?AŒuGWzzBGJ\S!l'-/^ʌ_{Ʋg+oEJ1ynt)]AoRgzqi)p6>D#>ϰ#UsC6P?Nڿ[ߘXCVR| V<* w.m͛O*g*y>hO!*n @PjPB0G$Nivvc>Ācr՞ɺS4p k:ߦ;zO9Թߒ: ^[wD2><4/ ?hk={ `s8Ǯ߸A|!€&Iz4ݛ,"\@.vd<PKPwpk0x yVT 5;p(pAꃅFWTWsWQAt-]D^nZ?t\V&Q 0Q="2uvqNL@-f-NXĵhھt]7L*dj33h9/>@ݨ;v= "h:"1 ~/_cܰi̱z9IWܿfe=QЯhk/(@<8pUI*NP֑A`H78 "pjf)P@H7AW8h|ڥ<%Jc T$phSjRɈw$YO"c.;̱bA.. XEg&0aD,FyOuK0J@uo+,ȁ؂O $_dmLAJ(:.jdފEJn-X/ǧ6XL1Egߪ1W Ud4^vrޔ6@>@w-(=/1Ps@t_dlN7"x)np~:h+rk1<_4A⟼)h)F# ۙ,N1?WmȲ&L853ǿ(W\8oRh],;_-(#7ڟ`t{(W67Wr?a;|+q_zT-w% P\9[XcJtEXugX>svb&C%)Lpqfɿi@fV\BZl0:!% @Al&#}'oϕꗕUc70S`~/Np/MDfu7K ng?Gs"e)'.g@ xw\T' @aև\7&.}F>o),f"h|M@_BV؉a|07I˳xvܴ0 9,L])`ken,Ś'>Wި,?w I;crIQ,Pwba<7 f >?/ʇL Ôr{2ys_h[j9:%r0-'?^@4Qrw B`[J[h7NK^%`lq ~t|R؛g,'n5 EȕbgVo~/b13h(7L*0?B1*۷o>&a&uK b~'d6f2,|T+dV` V|MHS}jOegw|Wrտ~g߷_}5 Bwe硫OB2Yx1i biAНr\Y/N*059cvZf(0[xÞshN&r{Xf E5ARSU v2AӞ@Z;'4n!₍< r"=V,{;EX?8^^k?ay9y=?Z @3)}G9ޗ)17<פPVQDoӒ CEKAȂ11qS oIHgvoXci!vK"xz+/7cp!HN9C'OTʅ %/3o]"+mQa!*pc͓DͿxݰ VʗǺRqN> ~yor`ť(o(]!ꇔyw/-(<q l ?Adوojk p@DW%Khlk[$Kٷ)_7UY, 0AhEU6{Zhpr9#c9gNOY$JKcu;X辳S6gtwt__<t_4Щ(^ʻ]?6e}4? F^ۇ^G KDFAT^J@Ie ]VxkdpdFruIBbܗ-ovm YC&Tv[&c R<3$\_!_K~TUWs$$I8fD;Sy:_7@\fe$B{FD$>>3/̆{{Wa{1Xi#Rrs};Z2e0`V_ߧ܌}*ǥg~E9p @KQ_+ " |!8-TsPN>oc ogH)l%oKH'o,3bDβ(~V뛳B4#H@&F8A;06}&;Po߾CEM`%b @baBbiN9=EC<$9 3x.'gKs,Dj+nOegwQ79uxd0>6}?;*I{k{s(€ 92b+LY8AX`@23d4cMNq#t!Xb.emP%)2Sw^tЁ]q~wǝlq^ͭ#"J*@,PXYb!R=EGej%gExGh?~jKǝ LBIgſ=jw{ș{T;mj(<cvRTsac|F{upO6@+쀬Ř!hwp 7n0HCCNH{@4ԨQKUi<ȼ3.iLls;2sGP݅7T|UG_qБ. đu̡ )/+WFFFXv[$B=S &ci=IcJfao?@NfghO)> @bR~7tv ~ + (:Mn:"W2G_ ?필|wwU}F`2KKKS-feuQ%.2y~;} @xYɽ=Œ33R%pB+#)sNmDa~*/{&JЉzM7/tm4YrQchaחGWt*`}8~)0Fzs hl9R 0IX拏ѢR#kt PsdKw?p떪p4vb'uBp8\zd}t)Q=LM6e#QaMŝQ;_^|>y S˵)K/~(H~f(g_<vZkEs4n^C(!k!+Ilя??1d N$ՄZ.7Yȓeޫ!mܤ?__91[\_q.ddgoYT"K>,8@w;FG1#X ™'5Gl hū@#x@YV!խ "MjVq?+@ b}/@E333)'' gK$>w7oߦ;99QE'}i$9 L#8˿L4^ C/Хwcʚ~$^onJA ?q@k͗.mg!4c&H"2DޭȲ]ʯoiVɬf(YW5v2`?dQ{  uLh3!>f ƺXY:`mH"gS g3ZhȐ!leכl}_! oMWW/Z??x.)`ボQ&6''S8k~7%. *QJ?`f\321(1XmE7m:fSQKa,Ocl*3(dԂXL(;eo0K~Ҵ_Q= Bh&@Ya?Y\\nh|A(7!|pJ` 1?~AƃY?\$7^wrE?1/RԬE^ Ekˆ1[|{";+k4Vghս#=֊T|\r/灛=Ʌq}SJT:H_95^ٳx]%@79@6 ,w"+AlIn{ȿIJBuX+RɄٽ(RU43nG2,21H[PFP*6@v/[vvTK3_@g<c*j~T}4fgy~jjj[,䧇 Gqj /[ $j.*5zp @sq#,nߌ;0)#``Ϋ@b$rqQZG\בxwS JH$-.CG`?q?—96Uk\(3nyHK^ &ޡqwwwӟ(lWK3AX΀vA !¥#JJ8V20זg黎I.Ȫ9,9"/dn~@%ޣ`G4_}%g ߋ#w, CZ4Z&ٚ49Їҵ֑QӋOу}Fnⶅ}ww  Yk8sDf\M{QDJJÞ'xgAhmg٪d?,4:(H9?@e _qÍ#r}u/}:=?(8J'߼OZ;.@YGiTًq({>шL EZfiBe +TZZz0fpcLּCTrU*&<]|3||[2?Żr0|x'en,Wަh@82@G6ls NsOJyo3oي!ݲmcvzzdȽ׻NdG>Q=b)*f65q0e@x )r "Xr8bb׍)"=0$3K?gxQ|P.N#D6mK!J<ʊM=WDVI0}mlss㡉/;+VEw}|+7L!" P\J4@)//\}F6 Yetq3@7Z9\];r (;\_:>Xps=J3oC/\`,=N `~#J!eN_RuT$S%(![R v1kX(|"|0r9S@BH:>j,C{!_HS` $Ȼt-brF2H"QS vr#\6E GU6`7| &scCտQqRݤ[x$ <39A(%LXɓ$)`N5Рsp3pC,ؽCf5"%Q0Z9{(_e0Rr̮da-ZІ=?ZߐHoa/D}v|#"b-LB4}u8^q:9h 'hOL@D0 >k(UdOgvEgÙo1 8 Q7L?R?bڂ QF" `ͣ@,"Y 3ZɌ&X*i&"IAUn:-K<Ǽ"S ĕ@(\¼|tq8g̲3훧97--loeȞzYEMYꚚup{܉)?\{sq0}`ds:Ok  ʒei3)`T@= z<;!,,͹hfaZI3vE&h˟Q*adW)~9M\xqYU>EYx<xL㧲 ߸#V BvV<DXD % ŋ~⛟@P|6S3V,.>o~~:|c)8=ʏԪl4Eb¡6鶶X@Mpl^copG 9;D @_-c ol:[+,Q3QY72nGs d(czFB,Xb1I4 X!O x˟$Pĸ()| \PeڵU|{QG Dq!0<_SZ{vxӗUR5SsƟ8 QM #Cc *@?"40^u*ϽFgwɀ`@W5g`|\1u " 3C)GQ33 ܆V$Sj!dj.왝p Q?=] DCzzLPpTB1}+p 駼ř[ ݘ^6<|ńk^u3 EL|P^KK@HKˬg=կe 1pV(ӱ?7@._;fK((mp?LUIemm` =ӗ?U' 逵#S8h=Ҩ i/+aAP qJ7}szԏ PХٗr܎`lj*MĢ8SB)v݌pB^$D," /UqÛ]۷ueͥ ֊-3 NXaU t7/O]l"묎 8܉1((Hm.h "C3/W;ҁQH rGW,{iʙ {~*ƙ aM/LeL EԿ\j>5pm&ll? d~@PpTk?yor`ť_ӝP޷B@ݕy*:o ac;sO $\[㸐CH&)V_6>4Z%Y+LV#\D-]H&V)a;6RVkwEU2.s |i Jby/PAѣG$Z"X?RvӧOKr/AaLW{;J ?ʋ(^ʿ]?6e}4T)?b}Ef[-/¹F a0UKs-D`WL#/TrnSݧI wRͅ|߭tpa 9"b<)z{".Z1e]?^;^;)\&~'.j*qwd-D,ZV*Sa\)h%J3 ygb;փ Oe_ W] 0\p @Ks@"Gl:lT՟{`2?~n|uysk3H@qЇ 4]{7#pj7e}+x4ОG_ 1~$I';kffuljjU/iߝ_X8p8{ g{ߡt(a{;k>? l4 )pA' 6Go(pOd(gGNlq 1K4_=]zUrw~& B6h04PBً3@+NhTA?,im%_#hQ/U|?RPFr+.r8+*?x`ČVAC, .GS>xݥ_3%o oR5S7/qjϿMEPaj[KAw+z2 F\? 89Bx0VYvs"900dU&|@A3żέv饉W9 ` =)~L?s?[η҃ X %~'!Ѿ`F „6:ʼȍ7-z8 UVW떄22.7=6P!Z*]+9IvlW.!qd3bUb #EtOECj8 ƿ e~׆F6/%'Z%ݣyCs;o^^ ?&s?¯w@dC@4@ 0]b" p 䧽XHDîRFH $L]kÀtL)P3 6aW##0k  1_>x۹H@(r~\s\D83]4u2ecWE xgE%%%qqѣ ɟ)қ%@y+GS;o^B%mbߟ w;3~H #R`$ owUߦtg,%@)uf_ڟ5?USO4sP;9+ymמ 9~`Ho`15H7 v!ߡ]5j)ly9Yʙdق0 Q"albbvlᾷr =fNh ,?kmsUrݿN.k/L:Oeȯ/0&941Δ֚dBs UR?ʪu^X^ю;R-ֻe &v7/0~/W<?ZR)xVyA(m4xY}&P XxܿwpŪV3&>D(z]P_/Y,uqR W, =S/iֶ;%2"Dh,#4I{_QQQ $A񋾂Ґ3u:BGFVpG)A/Ç4`i=.ɘ|^x./ VjyxwA€L2q+|gElg+ˊE@@@r01Hu&)~&6 av,;]u^׸pDkrHX\DG`Į^ )rVJr P*bHK/';?gM棊uc2P<^gB"0FPZZjO & T8ȱW\1gs.0I1n JJ7͓i`@daY+dz)`~=Jy9X ~}8YI9ەwlȲ8t7gz pUiuf[#x+oX?a?NӦJ(}U}~_ԚvU_k OHĔ.y 1 !_ջJ/@J%c#RnH3!b#o,uq)n `Fo1q4vKge'ܴtC'_ᅕB`@w5 kxFG?PnX\m} y: {qh5̸ K3?<߿׀8 ֻΨXN 0Qd*`[FX% U]-T7F#ZoJU,W2vݻ{;rGȉ}sZ*jNY ~U Oc%DWEbuڡѫsߑ=Yq4^X:?<^ɗt={_/ZNZ,$V6}>VX%-ժ[7uϱc*Pa?:W>fHc?7؞Vx|t޵{4$ ;W>u .>|K/6/[`w\- JrDY;`QTJᾦ9c(4ė)?sƯNY,3 '_=BjE}?p<'}^=[ZΗԎ%wgbC37uuD'9x1y"\pn"dHEF(Og^ڷ?>zαБ#t+tiMG?Ҩ0nYèQD/s{xfbBnH~g&Q F~Cb70e%Cʕ+$PfW?~{NA(WG=!G"2ԾT;~ Jʑ?«O^|ѯ9(g*ǐ~|do8D1h*"Ws< cPΡadD BQo&, EԵ~=`;ܫ^8xwbȎX Za_ٷu+\r< &6T d߽ wo$`>0S3ZBW:¸(_S/B7/Fa%:{x^l}mk۟+jd^L><(M9%[(~>UAM{~ވ؏W=3lC ï ȌsF|7,-<6}Wd7&E.a au}Aoju%62㈜KzynH]je_'#W* 'l4*# 0 *k]%{EJ3>Ͷ׳2VSޣCpƌblFX&ٗaRi4"[8t{aᶝ8t1=Vn_32͵,4RLczV5W~ }1|1W3_6b9okξ(y"QJL AQ[- .6M޼ b?% *VG۽$Mx{jj +c7 >a&Rh `0 \>FWK:Rz`ޗmٶ7T0}hࣜw_v(K, p pʾ|/3g9bV]F}oMhma<Oًi\0*) {ax%_e_} ݺN_u~czMzT\<>7~Sz%&b+enӸ=t<6W1B}:UK>ˌnAޒ;3K^ub F}at&F)ukAr #)^;L'رc.V}dðό}Hm%:-s!J#> uiXnl1:|5Gy r7LJo.`e݅zpifFo~o|a R+̀WeO/^HGHFOcԖ@c.Ç[@{0gS_t)xo5>w q&_,=f_QG@u*_H&RF\e&b" PiZh)Өofk.Eb{ _ػ\g={7Dɽ|zL]C/$ pTtz5Jq|EVY;vL;_z {~8c>8|C d{ ZUA,K`Dz>|ϭ0{-xiy \ }:gTy :1pg?][E]whsQy `@9~$/`\Q..Hq]mc|4w0}׮]Np0/eyA{@׾6x mIU}%?.=p|uyMZhp<ɽ(*0qZsG+Kz{suO5*wh@x;pnb{Ʌr{>F|l PIC> 7 hIERbN__\f7}kpc/9FW`~X 9cui/1S9` }sL"[rYPVZe*`1zrIץW_<6Hԙ};=5"pb]9_yC3gH+k* 08_Zg&@H\$8@3|w13.VxW~S׮]AM̸=g ،|c/>J@"g,+xpb7v(ogbny}ꖼ 0.5"Eon|y ~c>_s G,+WT< d>&}@Z^kNd#zdc)_9Da@Ҵd(=iCeeyt|zEwQ)YʜS1)Ք _Eo~QV[w2JO?\#0HC R d x C/$xE_:ziTK2 *<RnsכaE_2e8kȥvU w)ֿ[ 4A0Ò?H2qp ]."D:ļL/ {Oo?~ 摥קH9p=j0q!iM@YOϙO# pܗ'Zw"r2߿,{W`*@OvZ|Yτw^)?~uӴ<;d`/N/\p3Fhʧ w(dIO9`K6YAo$p#v!4|@w۠g#t{&2< tzL}r1\kPEzXtb&2 F0T@%?rycQߏ*n^=ܩx%ˁ;VR[ƴszK {ds/\"KC|JaDa tWGW@Dn ӫy(U'V "}z?KO 5z!L/ gN˗\cW1'@9U_;ǤGbԏG1_>Wvcd+<Ѹ O,:@j_LȁhkrOF8GZ1`FBﱛ2<jLS9aPf4OOΛlr^|qqb{\}{`5I|y.ZamsqϤߟu \6Ԋg N.r_ZN`<"(?_| ^vޖ84ьfPԩĮob- 5Smc#XV] <$641 OK&$$Xkjj2SȜG1B-ٳg)<<Ҩ}^J9 ->%KXՎIIIIyG?ee?m^>Gk(˔I`4QUm-7m+V؟ogVJ T@Cc=e%9%. 11)c!ȣ0hF3]]BV9E\ a? Z@ 8Ԥ #R=$e12Xc>̦;&M1Y!zTQVI`4qaCfF`DofRJi Q '?(IQ͛")

-kl/3dqg}0=M3hF3'sm'ums5L۩CVuڶs@bmu/ysft u`4>`JWnUxV} hRjAA8̛YiҥPvvqM[ >OS 0ьfbїkD=¹ &N@ p0}1PPP@B f$*KShF{\i~&W4@{jWO` 2' ?LT\\LeeeUZZ:)xvQia6 m&+rG?^/ HOZzlq%Mۨ}Q i]rePYYI :D˗/:m57R˲fZ޲&ֿ 77PjaiijM̵'v_}Q[xA0F!8*1Bk[rljcL j4=~ *(#Ń*ʫN6 sȚ&4@^^ edPzvR(+++==2ӓ23'Bi122(#+)3(-3R'73#czt$/΋?+3~P&;s's[N'`-Dž1^ݔFO-Oޕ1i:T~.8ؖLV9RyC1E^ r{o9 ƥfGyrn}[Z_W<Bl/>|a@b\8%]@]Eɔ@dd$ E1))^Rl~Ȩh+ZIpR,g\LBQFfp'EF'21 M gO(!&;猔Ms#LX)iCG+a|"5jԒLy[ь\"=y@ ~j iƀ/ !:bB@]P_]I٩iv|BCC),4C5^vra!vaW(?&,bÃTηRUpX]1aA0^'xd_9{,#$@l.zo] PkU%F3ڣj+9HK4/ 6*CA  ` @zj2%6 ,hKhda}c@~ɚ `fÃI ()8`!1,^D/v+l@u. 9 'KTW@@KIB?RXwa/ov<:ÏQ?˵3ҕ{B+:iVZڦ5n ,_:%MQ $$B(v2Ph/p6͛;̙[^h|(XE fܹs]u8m+ {bsK評%tzLY?_ e-F3# x챫Vw.-Vhw^X١ZDH}̞@\,FӒQQ$͛K ysZltΝzjGuD9K4~m`'V S SHkm:w?pֶ*/-øhȟ 7hM`X4A9u@  LS 1 EEDX>-BCC]* i|Nxe-q]Nי/~럪Q?L_g㩮bV!"h3'^>ïN)_z:@@.; ?v'B-.Ɠzjz gVO_ hLh3|[H^GK>j¾`i~",zܮVcG{h s*kXVҷkSj: %h3{S(5TM@3DGG;{N@l0 %&&NJfyFwD =Ion 3^Dw?[H',=*l|ڽ:o >l4,[9FMWۡv*%4@VJGF R@,TUUEu߫\mHԴk5,TSK]i&jlw[яvO{ onEs_3;Tl޻6ʆ ܈[ь6cUHYHpAO ƹꪫ(+ @ȸâ JR~IW*(Jť˩#QQR|,+u[h?eO:o*~ЖS  ?< }gB@#3hF{@>[P0HD !R!%$3\FUh+ BO8\*@tD8xdivX0 @NN TB)iɺL))n:kȕΎJL9H)fdK[_=xr^yY1ݸnS-KuN0ק8/ 4nF3ڣջ\P]E)IQ!RZбSJjan,23 Zx͚;@bvlS 9.bc.H0+Ĕb6; 's%%P9AIѪJHӌ8Wljc/׆~S_<7i?)nʘ_ KbܢfG ?ePUIiIlml pMDdB-b)b@AQ\1\!eJ vx/>2LRW;F 0E0}|"Ùg k/Wo-=94OSt\|߮(=&op0BXIH 4nQ81pVQzfE&R\TY b"B] k9$$$QtT D8d .\@P [,`\}N f @%煿]tx"Ojt0kȞ$`ꪊ_?-y~.d`4?=$Vӳ-=0)*.CE 9)(N  (0 f͞M>3DV=_5n[yАﯸR` |fD 4J ӟgEs}i)E>"@B"8 K| $m5͖@VI;6# 1gP+(BC. 1Ă>cO/}$]4|xj׏?`0Úﷺ{7A@?O>1A|000-۩kFZaVZGm+ePWW !9 0 pyi)WPYϪX[s,ez+yaOŮIi$o 1YƹAʀ0{T ?J>V./:4F06$;DRި,f0rfhnP{ vEwk޽$|) O??x a;W4ZjXA- J S hX>T9T |(PkltPC#VMkԲfZ|Zw[{oeߛ\mj]ƎZ꩹jʘJU\[Mu=o+0o.Fȝ%VW;Y2Û 㿽#*l#h {L42Pu~;;fv.P5;B`4'Fee޹֮clXx2զrY99md -3yJǘjP~~>#73Ӯd}L,tlRR'MI)9JeOzcSnF夙'%o+HD.}m?d`s+B(.y!gưxs@jN0>4Vn30##ML[p9BAgqO{z?.o[Im]\U7O:z<ZVvmX>*+۪ʟ|@emmSl[_R7PWWk Ҽ XS:BX'9). df琠R(11}A T7q%@϶E_sR2%Sbl *3~X-/~'%eU44y-+SYe=aR`&;7̘o;u1ҹm_I@z.ΜdhZ9s|8_eqCCPH OAΊZpd \ZaJ}9k ZY!wF5k0ppcc5ZK 0=|YÌ2B @ISDZ+UZQGՍnh; p;7ëQ1PBL`@,3w\fђ48- Bfx|Gi!ӜBJZLs4oτfS|Y OM[5Gz.jLYk<y"nͥ%^WDo ^e-!ZFsSaIK{m Z-h-, |1,@lt,EsD%x\ga7o.?O ^9ٳgG_^wrߜ  O{_HV6iXA:W K1%})%3gR^A9W/-"o>> Ό| / )INmņR3lNH3DkDEDX-BCCdTUZFn&u#]O`{ݻjf4kUeC_0aJ*PWBEQ%/u-3vZ`jaaPmC55QeM bfEDϳHλR)1@!>"@\~ Qt~]|k(``))]M%F! \ 5?4O^׌)șFȱRN)QϗSlD1u@jf"fhB^<%'F.+r%A;:#Օ84 Y* i B5A yS." bf).> @;b%3  ![97HrJ|qLд8U&%nC4w令G 3[+XXJfjB\ +DZ-۪]~B@Ki `>5U=D{ x{ 1S qA鱲g'Ȍ]_#>ZMJrbVmEahKK迥d$F3@h0(bi E8o5hj```ހumiyELLL61mI7Ka{C~RľN5 Gd *=OoX40Кu\ms%*|VϮG?~?߶mٻ+=UEe@zF7z #7k1ڠSp@7Owd/-??@C繭94>׿|fݫ,C' S/;2!k Vh~dsjwΉ^g;R;WUx\>39lD2T-=ٶ*D~lf~5 =ţ|GˆB aPQ]61`ժUC)))(8P2 !X$Mը k!_raJk?Q 7xpT Xbsc.6_Z>0P\90_i{xc;l"E]eZuBU%=*NPWGu\@t' ˥>Wȼ}K \Xa=z-tiglb^2!M Gu;,'Ҕ@,5? /3^|L:\3g֙?{=6o;w|#>ۣc?rq_K7u4Pc{ښ 0m%j;W%Z1 nvSV-wud-?//k4!@0g>rBkg;Q?agp@d>#LwF "6ߕf{`Mͱw?b >Wy;0kl9 ){H< k5|W~Z}XX q!Bx̺ 3g4ݨP,0w:JPPVmƍC~[ wG#_۞ v w  SSrUl33X2)!)""($$ӂ)0 myK 2HMMXK,E|'44t4222?)+#kA@b~ \S]XHyMZ?4:vܬ' PvvVǺ4X#bWX@fTciYNUJ 2h@f4 :3l/:F=+@> @-PW_5[ 0ȗFp :ŋiܹHǰ:>l{kQQSVVs~QQ֥K֋c#((<%|g (xZm/rIFT\^OcsӶmۨ(A;G,S#/V4ь,!ooN*xu@6``=2lt㜜̍32VDDTVV>0(a%vb8Fhh~t;M]Hc]x‰yz_y酃 (9)GOL޽{: t?TQQZ2hF{ { lաff=n Vvoޚme`eFfeƜ?CRR08a#z'J>&"b|'|{c[G?q Li|gZ4.@"߸z^|0]8G-Il`Xe|:`&JRniz種?2hF߶~f\ڧec˖-S* 5ĬɹWbcc7ӤDCESyhh躔~ ת PhgǍ\ffy !… rc Xݒw9ļEqysgRoo/mܸmG:}{Ŋ+YpTS; yL#j6 L7` ҥKEO/^ P`ʃ je> ra_ >Ar]?t=T=Kc0@su ` `OcZ)1|q/p8:]fy3VB{O…3tj]p~oMgZy6;:#Rqzh0Mr)ڷo[ 0L7L-pc\Q)ø;^Kڰa_ 'q/vV@@@}ee寚BCHHH9|~$a HJJo'#GpaDDD?7]vAg#>;M]s.h]M/_C/Cm5 bgp@qq0=S-Ottma|$>.eepʈӕKtAh}<~ސi&^{iΝn?$lڴy6#6RG:2H[~5, }^Z!4aQGs".<*)BA =0 F pB?cRDcPm"/!&hMSA+s|,1y̌7_ǽ$G5k y555~z~on7 YSO=lݺ7@HW"+AqE :ѣ<[)<'@Att$C|N%1cB~E0\̞Zr~,3LgMislKj o_$@ u1i@Xh`+FO ]Pb,_(v"X5P9u_m-*qYcS0Ծ42H!2s޿qm?]{8q(wx2*8PzZlwRr%Q('0@CCK(((DZ!48@QP (.]Ot8z}lkqDZ'/5 <]cx5u@rbJ!'QFe;ַ.+)Y *3 Wq8֮]K[עPJGjN@Br%?w(_zZkk@䩓`4v wYJ;Zdb6+FHTLֽGJv0$1j C$0Z?aa] > 9- ;#@Od_Ov;nf\2mc*N~!@J^~uPHX]x|kT:@ b"ƵtqFp XZ).`FSiHSQM6Z>~+_\G++&iv^[` c׾2Oj. q6׬A|N 0֏+kȝ`؞[ ]ڍ~^C/)Ql6^S/:m@k8Q4ߟ/ 6% :lހV D7 R;p,#/@zeL9ΰؿ,F[`P3m.3`ѮaJ䨎'z_=@Ghs},_dx1Ǩ|k45sRK~Jd%&-S e`4+o`NW-m+#fg /q@o{6x.}m^#4+j+]v/HS_ܰ5`J94XB]ܵP X+@_%3@YA&UZhe\ٺ=5π)s s^9ƧJ`PBWv?W-@ZP'tGD*n0 6 y?T?1{x>Mʘn s.GL ( Oofv _;R `Z-n=̍3䧙= (SՅ<Ν4qiq/eUs76oNjr,S7^F„LZ.pb?G:dѴVF[8y?BfD {u؈#DXd:1u.׿\ B)@fv>+/g?K /`Y r5Fv7u׾4ǪH[=/ln}xf)\Exn[ @snbFs.Dҙz)6[x(%Й3giߜl(>y-#|/,7r[Mn^V g4s_| 6j^V )))?1IF He;[Gft^3{JO2(+5—io.p|p|ȏcQ7`apI r4]-,Ǹ+ Yl?[Va1V*Zj͞=݋Еi=< 7**Mҽn +{n@ڤ#wFMNOғ͕pF?A}m̠0C.T Ìq4y Q;}= ZFF"inݿCý{2 02bU10(GnX{&o)p1}A*QS ( :::?f|?::ڪa !xؑ}m.o ^J%VM<{4hz2MMOTr Cgtnz+ 5 7b>P ];^WXTߗJ؏cC>mpnl p>lAOk{ŅϷѵTV=*xxu\\IUiיu@\lXlEmmG9P>e'hooDzb؏x{O`p6CN) vp{cn2 .))-k5?V #F?AgZW^=A? r$GnHPS "<0wH^F el> %O@bF0*P3A(F+87w_/ޅ8 2sgmEYct 7C|%?**ʱOW?63h;'v랴Cޓ+rxώM_j6xi7N~@߿\g Z2)#/=(t(--()$#E;ȃ( 8i! ӶiA&n{O8-V6yc/&`4vpC(v5A"y?Uj`4 ^^wkLSݻF (9=mvM=_C )1=NE,y qatJcl?iuE9ETQ.x9_Lp+虭[xA:Yӂ祅. Ӯ]x@CCCFSkV/ylwkA< 1L"%oH3|7` @`l6O02Ri+`umѐV/YO{F =5;"Q!D{)IOi8,[kGі')%% oo1ѡ\G;w<`f/`Va~ 3g (ԴVU;pe\Sf ۼ/@PYY9YwY H$pڧԘ{7i1 ȧ篏1Y5;Lz-l;,jE<0(*o^ۻrzHj"ƒ+i.>/#jÇmq .`4l{ -%W9HU?̧ 'F픚)ڭlP@ku)8ӯ" <A@L ܻW( Q902(_[7T]{hD,4VיgЭ1nj1{ f SC +R#5f 1բb@7ᰰo`ǫP/p$~M#3, 0mmLcSB(q(ctxS_+bd8%?媮;Og'PlY 4rK# cJwv"t'Vٳ*//\W\81i~*ڣHSJ7W^OG ޴`iMٞY^= s%Ep~_n]yaq_Кs ?/KpKHD!X I*F]~.̈k@V?}+>a `E D"@^A|]m*shQ.Mx9{=}ʖ._ȧ:@~^ {c3+,,DZaFSjylwZYڊ$~.:fB@-YC[O|f#‚F{V**.kz& r* TSJ]c_;q-HOzGۊ=sh3Õ $#;fΝ-+돩]c'yZ(d9{7`ߊ= I[-|feee  0l2]M^^ Qy?hf+g@OEԼJǷӂ}-Ut2~&+;i5GD:! ݻg'Q?۳?޿et ` wdT7ۗV4`{A~j!P f 3o p!Q(8:ًh?#ezJҾt m?^SxfSMaS_%?k"r?`*Qto"j0] B8F? |uKO!]_A/ 1=j+4ӫK = ͔*׬Y?m`m##ht4^8.JvVM~ i*/\>JE {]t{r]H. -oh+F;997%x:!P 0m_^iE ;-O,D! |9tfg!YDʁjvA@kmȲ0(//OҖeSM9s~ßŌ|&O8v_OX&S\A~ l+[c`ۊeeez J"@H۽{7XTT'QW,FDZ_`ΜهD-3 %<< HĔ~"JK.GP&oۖ[lԄ회xi1@^:bJI]>' ~z7Һ|M`3-\$&ӯ  |hK*8dUz Ɲ;vp@aa?PxLZ{C x6!`gz` YSEʞO6~jKY4_ '+afwQyHo2{ +)pmڴ/#V:׈%\{e3)))^,^ @?ڵK5m+*+٩ mQ\СZ%<~>{58vz<Ooa}.=E.ƕ-\K鵋O%nxF0 L2ExJ cHO=dgm+TVVmauܹzꂯÛk 8 X,P~V-m>uVrJKK\_O}vqPY~f_u5_"~ڿȢkmsMUYNM vC'T7,k>{58pUVV\j+е_vڹg 0Osvq^wW/muH.^J7R;dGa اLG?u\/aԘWĊv( ƣA۷oOC \0F :x Qx<GvttX_cG^o\`<>##c  $ql0v0Ij6 ;vc0 lXݮжjnVyQBhMtUߞs3{I裠>gAd''$۾%H/~{9`ۖ322ZrЮӑtߢqEOjD, &o-|~]u/_?0pKpB@  MCxGaP+Ӊ%{̆aۋu@Y8{Ga},(!" VUUmE(//{]P X\\X%<@7 j;{pAd''$e&IUE{/]]],Uu }ffnUK37gml s7U* M[;iC=L.Rc_rp}|[ Yn,B-Mz [0na kTQQAGz~\r7f . Pqih lX+bE$N8;L|"ow@FaDg) Jr/͸/Htb&/~S > c6#A5Â9rYc|Q @ٜ2w=)cB;y^yΫWVwU5ԇtR6ou4ӱ lf\x#<7&_igUVV"}C_ʂ-OC`,++pC^]]gj>CUGhY'x(@,g``W𙓖WMox)r+iHK*V+1{ f8lƮ׵񠕟^<#SYɓ'V^^n KcLAgѡ@h֭>QSc#hHLL P|/0xS*[ HG?>-DPߴ5K1 y(_C{G`4  -jjj;vRRSS0S4uIr>Z4[5EANg \~= Px~ٷQڙjޟB8= |=H0A/~Pp @K0YP(ks1SF-Y:a1*x0ٯM+OcLHN3{o'$ ћMgN1f. ؝Vi1GLF.3liYin=E1 9uسFu_Ҽ T6&@m׫K鵵cVW X2# PP_)q$wi[qi; >PZ.f@ @;_3n\{8erj?y(}0n kQ؄퉯1Gh|r]Gi<^;l2bϏL[Ʃ)X f,'B@=>/ L:}1 t3Zǒ}w%>e_KM?';+7^ [-6579{tq[__f7?_BՁ@ߠZ7g 4JOOF O*WǏ'\WJP!9!cíhಲ*; 0R@m_o}(aZ7_eɺV8wo"z}àI7c4RÀ@WZXBϏ̹e%@\!)ؕM0mxy]%$=}DL L_ZÀ[0\_;~[Ҷ=,>x'(&/QA+! j;QgѵkD=^|􍇋e֭@ ?D;hE Vܿz~R@EL~DP5l`#zߞ!`־|fM,hcE$u i! E oGZ`נڪ -ʡPBҚ'* PׯhAzWD"$9=Owo5 2ss70 %zoՁhs.>PtPSS_b !c `!,؜O̽G/d#'B6m,+HZ> }*AWҡe< JRW{p*2}z ^~=}S)]Eq#C|߻R1[e9)*~Q9>uDҰ & K \JHīx%@_ )++J/ Jrfp:;eaMX%x@9w"=_U~ g5!'pq^zJ~k7@/?0b$'d#Y^!kh@pj}.J}tôy[RR螴{d >>n`>^_UP ŇG὿ph '|w&k+M||?89ŠeyoYA}yG;n7??*)XIENDB`tiled-0.14.2/src/plugins/replicaisland/titletileset.png000066400000000000000000002034441260670167100232170ustar00rootroot00000000000000PNG  IHDRŐgtEXtSoftwareAdobe ImageReadyqe<IDATx ty&Wwc_ @p_DRܴK,oHdG^cَ('ɱs̜LcOΜ{9y쌳8&fEj!ŝ A o]WU)O]{o_ADaJpC߅|Iчwqqo (Z`x]U` vL8/  'A+7|/[|y. ( (E~?&3r.B_Wƫ~T@ (Z4 ׵{/i!"Cd M {|?q7 P@P@ i>xu,5 囚lQ O ( h1-91{fpe0={i gQEat,P@-) ϥ_5G4[S-a5~bθ R 漟t* ( (En^moy-Aj _ߘZ.@4}1Eӏ)cjT;3wS (Zp @&?W|uY"# `p@s 0=~R~LjT8Y:t  (ٯ 3 򴿪 "u0@[._ }K2_{N [ ]@P@Ky ;gk _Wҷ-;^lYg\^#3 J~ן<ȵ*O̴x98^z ɔjDkE vvh~Q~G?OEKNh?iў%vPD;"1юvJ3:hmNvṵ9\ӧN8}>%gLO;c|9sΜ3G:sv3w:sݙΜHPOZ*dX,M,=8*Ef׏yg"}גM<)ߋ>w/'ߜ:~K&d2?: 78w6@0{YLd kE_39O6O?9Z]8oӭy5>cM<=3Ȯw;~!LyHo=PM,y ];A=Is;Ebz5N+HD 4]݇jX^A7C:ґMϦn vOp.lPmip~>IL伪n2u3uc=>[fm~XkzS662->S>'Ꚑad*7yV>P3d?9F9~\O]C{&lFE~?[ ?J9Vf8lz?PhB;5"\2tl}n&T`!y}=*3;ғpMg@@@ew|HgԤ>87o0;si~//s)-խ%e?-G]]:#|h ff? f7u?97ku5΅M >'x ar3]PIm/A7߼`&Ix䳇>G fCз-qiZF??T@+MWAjp]U_禹c/}/JPu %:c"T׺O{RO'̑$[QǪ&H' fK΃|>#:4&hxz?f?\ӭBL6)J~z:nZsѼ#S=hOVz brPS^fĒmЗ rh \d.Ⱦ\U&t&'9uۍ EsA$0q7sq9х\Vߪ86[ ~Vu~TVs zԽKVf?i-[ ׺.]in~" "\-BVԹs[ϛ ϯ>~4|.ƃAϝO"} w44c[_=\\cC|^{uuLRU7Y,k-#J9keC(M+ VE+QZ򷐒ȽtTk\|Md`Wژh# +euڈn'uPH$t-ͤ22H7j_x6dK&Ga)l/ٓʧfS t>>{ ޲!BR ?_ `g#콾 &4 !02P@4פ҅[~:Ӹ_:Lݲ4cw+=\< (Ԉtݿ%B@ ]?ZdO3G~svWu ( h,nˇ [lc pd  P@P@K.܄wT_je4c+XP@Вn{.BPmXfL0h ߠ!P@P@j _:__h p_q @P@"pkT_@=2 (3B?*eSP (tzb/ml@@@P@K鱙% 13׀ (Z@/\m0ߵ ! (y \ 5  (+>U (;yZ P@P@EXXׅἍSOڋ> A_y/ܖKC|3<auϢJBkiMt@@~o~3q7[u57_syjiiYtdY)O<Ē YL 0@T }׮]cǧ{7XA s1Z =4}/U!1RnVJP`h7>СC # M߃9R3G~TUm c6*S-7YZsy3Rg `^Ǻэ!?CK*#{ՄhZ0'ԊU:j1ó$ϝ*(-rU3ֿӒXTMU6:O<͔pL  Ч3d&}¸oyިsu_3]3sᚸ <-ՠlzcx%G_W_53YoL_+hhESD{XGEh"Dh/hvVѺEmH1&D-&Z\4Sioj_19cwΜ?9sߝ93;s|3[uŃo$F~{-ZXp __e1$knZ[[=)C[I'ONM0Ք|ig{C<ztOkJژɜ[Fgc[9=S? s.ӵ^{5#sk\ΙqA} J.Q T4j@Q@RkvjV:RWp>tVd`&y,Ɓy5UIυump""IZ>0f6f;~X*&3}͸ #3//>Ipzw93 @:X6CÂFj-kK䎿83Ow>Ciаy7-U U^Y;M׊0g^ߣzjԹ9{WᅴglL܍0}&ZBZfz ׾ uzqMC=|a.ƫ[TqAkzӕBV67pI=dbNOQ z΁ʼ$cxyW=okA+zژɜnhLCմ R;]8:y.\Y<^h >oM7'<&Hf5Kw-an?~dEj@+U9- SK PE9q g0Ow~kE`6JYB_EcAd|&56.~'_}w)ոV`LRźgKEsiXW\s*o@1JP&E~$.NvAˢ6((Eiz& 3X& :c3;s#gwnNdTF2J^E[WEMӣƞRݼI@i Eo럞]@.)n+oewd6f23_ZB@3g~vg e!Klƫggzsi3 ,e7AܬvTUKBw;/-]G~# ZXV~xi4X46ӢKA|Y7cMTKkZźgM~B#4hَ?>}LD+ix]*Zheh9@|:-0!X.7!fd}q6A!NJ04>XUMF1ȶjBU͋Km&Ml3e69_{v=W=`p q \TnƝ6광kP@tR,8WSZ*ԋ/ݸ,9Q-`P@T *!ܥ$>ǯ xe ( hIXtպ 9S;K7&sE@+ (m7]NC462 hiӦMtw>馛(778r4M2\W^y^xyz3YQq!)dkD}wW݅P@-"A_oB `Ecd o9!QNNnV瞻~.^Ld@פ "U'PHX>րd.o^AnuW@@-2544<@CMcBZ7 ``(77LyTTO<W?&5k@җK9z_^}) ve&Nj E,ÀZx{ھ}uuuQ0Dirbod :fT\) L*-+;VX9SSStMe_)ÊGs>>׋x>B~1Fw1D]*ǝ0I:<,ÀZXڷo};|zH& oזM]ib,JW8SAaY֭]G`ZR(*>O L!|CU!jSWOjiA@@- m߾,4>b׎7e;? `NFib|ˋW Z` hrEQ_4iz\Y}7=~]O(_wL9璛%}%X0T^^NFhlԴ &~[˷ #hX>T,$8{ UTPeeo&}>qa?innLkS /\ZoM:(<^ 鹴u>ܨǴߨsP@-0}K_Zf?|m-!>&>ڕMqX3d R$Z{>:punЎ;{ݻP]mm?422LP@OS^e0`aEAgPf5 w.s`~ke (BC|ՒGϟ9ϧ7r*7B *8]0 @Y/5\J |S)JuzοlaE\/0Umn $ڜ9@@@- }Wo{hGMRj>ӿIł2kO4}7?]H)E@ZSFh:+.'.~bѥξ/V7twЩS'B ѣY& h0/4e/ WWht/dA<``|n Ch  Ao&ʫQSSGYC¼'‚B*tx49Ar,SHEeb9~n*l !xm*,>M@Y.WE"XVIXTI|D0  @9__b}\vػT(* MvI%K~j˨Y(:Ile1\ʉ cY΢`K\ Ѱmk;if})ra/5 .݂Tvn?A~ KCWKʂ~ha\[Q9JJĄ̐m&p~SYU! tǏ??3<2wBTVV\ƞ+<TTTJУ>F >s"9P‘HʕS[@zuq9BHT+WZVկo>/Ћ/{&Y7Bo|sB:BM2٨5t^ |Z3xr"f)icZ -»1/P__/kSp~J }I"FF& hYE55#"L{PDOtПB9)," D\#94('7"T+qwy7@KzI/Ft*J7lgV Nɜ~)Ê@ {Y `R2@ .Piq̅FHMsO@0뮻wwuI<4B`:BjbfxG3MF"j0R|McqҨ$d_XCk]+alA_E laA_SǾp8WG444s RS]˱06Slb3:.(qB?*j%f 9]mӞ VH)ѧQ*-)MhGlmoE۞0H(Ktww̟ 3,L͌?ăx3X(XV+";hJeq}3(JBcbbL!+|DܗH.]|d^@:*8EҺ$;Ɓ07''O|/ѩSDz:---Bxʕ^Z:1GW7@xߏMPO_.ѿW}} 0ĺիPGGu 0 ] P)=U) +yXt7@@cn2㏻Uijr#eA|w6a?1ay63*KɴBs0gSwʹcBG rXwCO<}[ߢg}v\ +5jKXhQG#K.d#QO%>'6ɔ!$3sνeY@& S?zO|6Oճ>G XP,R,n}> mk0l[d‘g"o *4B0t̅@!M@o'ii!'Z QA~! |.rx,bcWd?X`-/52&c$` `$V,<~u3կl丌'%IƿXɎB}[PRA*bA^+ p&?0Vs6TPz <8RYطia-rhbm?8v2 Q݊F:|-7`z B?~?[><1N8A/2gXxV, % ҟٟ3(w[n𯨨 Tc}ĽWFvqbh30-_^N7! #Gd7!jÇߦ~ȯ֪ݖ+&\:pОƝk@rFh1 7,E]B˺L7֬]Kf̢\錄"?U|:[~GhvGHw}O2zۭۚD\,Irǹ3o ڨ؎_1Ď1`c YXP (&+ɲH#4\c/5s\GV sHe-B K_yy!:=⸑, `x1`UzdpapΌ~\'QU}}ļ3xI X5R9,CCtmQӪIq 8Lz5P1Kqྯ_`e@H֥_-#5?a1^>kӠM:`&yWS K`Z)N96l-\WKaf nle 'B[)NŝToʼn$;)+B3x &)sc4%22Y1A0@@f~ b| 0k+U!>E~jS8Hw/2=c~gI!DDZ_R}ܑU.aScZrΔZ*[/,*E,tL5H0UJh=U~@˝>J.uя7 ;` .; Qh"NTj1}8'L( \)9yBF94+19Q׊%<}BSg-eJRh0ΘG|Ǹ&05 +!%52…v?g!_aC}x {\T[Ś+1 x ̙~ /^Xg.1[SIXŕ:gH":u(r_PSs{/\ipX f 9!fIzqz[tɘf276'Dr7yTf`AC02%^~l~ߺX6P7kcaz{{p6^Ξm]+²[3O4-@@YiYSd{n  h>UF_ XM y (.BOB%-+fdDBOQ)r`CAҲe},SXC ա !kㆭS30tw W:vGАҊz6dDOؓV@M}NEʇ-.5aGGSR&> ,&/#3-lh9/_cǏ HMͮb?L& 7_͛QN@0NW'˿[o63ĵ$POX@{)}}T_h 8){|d}[L!`ndtVo]Kmm4XUҸ>Fcw@f6|ĹOAȰu:TtzoA@!`# hX.'Oie- ~v6_-:z/Bu*nA5A HKMe˪hݚ t5%5^cEUT 0hJABl0]JqMhzTS.4wyG! Lzٍ;v,5rUt{mMTN>A+WְyYK5JG&ΚZFͫia͒_PJ_WD/CbrJ$Dǡȍ͸8ǧ!P NYvU0 K(v 0qHD?W_}^ųF:&`.#a{~b󝙆kc_+96:A͍kh޽\yu xPu,{(柭8 xiE366R v H >\1^T;׭[[X=yXWOfe(TI1(Bwb-q5@'ni>Wǚp[unLhړSY%(E'(/'U Qa<\=<Gw%HnWJ``8bp) Š@(Y-0RQ~ܳ ]-@U*u៶/hooo__}{nc_K0kV+@ ~b<U'ϲ}}֯NTzgvC{/>(L[ QN֭4>q%>٤7/-fJohA$Ћbu>C\ 09gB6-MM-w;a'?R(5_d F yy [+SĈ։Ȱ' _u~ȱ+1ӹ4'o7qQڼq#UUf=Іm=nZ+`ҧedc~ξ͉І驧~B'icno?w=qa붌hJE"`P$@v?Fi|lW7ǰ?2TArάZnѡQ.H5u8?/,à zj/RkGfдAT#+zFo@*8B2G+d"CcZHMZ|qXq+$@T^5?UMdkd5ƵTQWV pg JfEʼn #Kʪ+aԞ.=|S佺Q=44FOHo<@;oJ3/P;'`IK>v|aFZ!1`P8 [~~D0Ut-q'z{ZP/]/Xi&%bNlH.@sۣ4:2AcWZNjj^4O )S>z6۩B xʾzDpeϢt8~ m42(WrWr̜^)@qp-&~Z7]jDԵ ;x6'&a$? 7O;[.=-J}o8&|Lso|K /]ꤧS6JnF-9fJF)x :"3ĵf5Z,H߭iys`z4}OCثn34S;<'ž=fTEI6lX?Mո1CT3L/ !l=U|´ך%@^K0:|8<8&R!$̙S7ixh$PN֭H}F@`fvGo!lvƬOFSahڲdZ/GV>ZfN%,t&u73h&$AVۅY+$Tar [^CNm˲<:7:uKS@+76Y6 y{Gk5* XEr/&4twfqHs@`^JϷj]L@ۅB׀%{ި[޻&:-ʕ+8}|`b&ta;1ʀtB8bdAeP(!Xdž._ooT+],5]0c덃?oiyA M4kƹs?ȯAd{{ԸʶYk;4=]$oq|`k^}eP˚::y&fHl0lw=syLƼg.ڶmKT4{W,c>(7ĺYq7P!>_?KK+}s$mh5[h"=\hDmj8~-Jd!Xz@GNP`a,q?d`W,?vjhS IweЯoCvjP-XӘe%GQۅVoby L_۸[(Pǜ[ML3;PE+{>(&=іMET9F`aC]nݺS$m޴7C pJ$2F*~Wļpmk:X,%INSt2uK5 ^)洛MO?N<,xE.F@aLM{4"?a ps]^i}nҖ.@`(8=[_mMS]( &$tC-p0K rg6lڸV;)ej6a{W;a5nHucr18~c40ˀY zîU pᒝ 8YݼNa;5{1!>/J=K?{'ѯ}䣼ZB&c4bi>ȑ9XOtiv)d8ljR6Ae>"t OwiD!k#fbM@w~=pC6kNF!΅pE(k`λcN{q gqq9mذ=U• mYL M1Ϗ;!BK =Z(rnR?Gܧ6]B^=QW%*8S̱9/',[Kjjazqs逺 p;.u "iZ.`@'wcLO];ob_ږv {jV&3~R'^CS)+)]do i2oJn=Q(RRo8$4p-vOt>GbAg70_7Дؚ;ǹ3ٻ-Zv!n^ZYWñ jS2l!R#L5L@??ySh]}Bsgrm6`MZ\햗)OCCtwGoDNu-QT"LʪrZ֮kNOw>OwN 7596\6,Q}cPAouuWEDjx[ [ 125h)6+PV;:p2hRRie>X6VS[[577,Iծ5k+@sΰnü@JOO}_>@Og Xo.u~B, @B&4ә3gxq}]D7mۼyo%w }=.啼yK"PF&)95ϖ$Ў!W00-MAҍ1l9'6ermܰqLyeĝC?h֭~NZ`\Cqϓ좠Qiy-XmGΞv HZ MȀЄ/9 ; ߰? :W[f_S+P(p&' k&'{۶m!=آCUwFuonuk`}\IʩtyYT,e`)t @& M_\Z^z]O26F7l;ZMJSaI &ת}]< nC) HצTZ *{ IbqV mk#fͺDfflNDtBȰ9w^7Ɇ=6F`hؗ={GXajqFQT(xĜzt^ѱa_(Q( Lx!Wg۱ckzoLcGneV;Kc \G>NO=MeBml]xhALtY؆k.խ79>&=Sڮ[jVΛK)E2<ܿ +|[R|TDg&u~i ,}=wǩKTC6ziSM},u2***f$VfNE%ܼN>uݧF4 <7P/DFmT߃kIu />'K;?ڴ\H#ݰw{,n2OȖD¼&ᶉg|p, ?8q~gKb=vϕQ^&@l^r6l ƭ@6z̓}-ݷ o-(oܱ5T &Afɲk8 ;yL-0g(=q ,39wЬΝ?G۶aӎ|OW^//Y0&j!D|VYQ |?-r)N{O#c#tw  Lhyŧbl u-k'`oǛ"x;xg+h ;ye"|g0~/\ΏͨL6 o1KB٪&j4zu#-4!""_ c,pC0Z296H`&lzxlI_xŇ5 5ilt|Y:A_rU G`LyW78V<ϡܐRKHn$AZBmE,[򦂸dz&ց0Vg5ӧN +ajoMqεM-B_޻[*[^E{nтtu[[kZǎ@ 0q0G[1Nz TE?F= _#SP{:Q`v6;Ik_J.dW|+--J3~"ϻƝ ;}jVԱ}{nZftBܟ>DUׯRFh\L`r(]7lTqG?R 1@D"i+}Ga6Q~a~bꌲLsi ^@5-mǓ H:_O" v U "nlgnnD  k^-*gy̌磽]0)^EEt݌WӖ7Є@㓜 3x8 V75` :fZ+N@:~(+/`! ~I%!B#Gip`^~Eڲi CH1 <7gBu%ieE%o nSs'xaV%wt|+57$R${L *v&4䶮!Yf@(3$GCwUWr;짋~hd_~o'YitHr\`swD *ItdS(TT"v.ӝ^!fN8vlƶ8VLf@ FGoc*~&N  aKu53ۥXSd&M8Pl-ZVj3}@먝27b>W7@$c@&Zy>ޕ54489jkD Mzt&&P(ЙṆJ0Sv1i%S6&vr=톓AV966; 1L}`tIQ ͆Mffz0^vƖqFÎ4lybFa :6u#X x튆S!(/D?}i9!,s.w}ڻ;1ETZ>ƄOxvcf^)v\װ$0Mq:|GAOdF:MMTTT$]邓Ӏ]j Jl w-t {G>R:;q4+j$5#Mg;h#MP !*\؉eNx>DkֶpQק8BƍXn W l- :/|ȫl&υtM9|ټ_88ogTU]q:te4OsihZw:2 0)*F:v^}oUЯ= Fsv~q<Xpy'ngO/s!%X}ⱘ'qX =!0jg7҆ [6uyȀd%\Ũp$P^_GRCο~-(Ҋf7RX@7"!X)CT fuBར=.,,rQիK0>W:c\G#9-fM0.\NWodndcj$2 @m|b>y6ljs9\if@-/LsԐ}|V}ۅt߇?D͍knY60wux` Mrbw4xưG'^vM !Ny8OJhki$X̾R_6nj2E˥BઉCoPSl sj p|`eD;kBʨ7rؤNĞ H!,<'3Gwg&E18ף B-ڰa==ohc#rJTB|`kQQα6z] 0 sP "kQ?+mv& `rM7ea5PPx'ڕ`Lcۗ| 67y] _پRXSV֮f8L/vPo_7ܹ/_wìٳma#5eXˇW $,1 Gt43/Wu`9P+e0rd@J+X{Cty.E>:Ex9kkBmIa5@NbdDمfW̫_@WWM:a))^&$ $l9өhXl IÍ;q-JIR& uUT>q)6P1'%|5Ʉq#t=k1'#k%ga+KB:Zv=%et`Hj@h mٲ˪(lDDPѣB3G~ӜJ'#kafWR_z)v ?ô]r`]+W h;nOf6u3 =<]ۡݴ%QkQ踐q-.ḻU;~N'|'K_?8,pRX~ 56b! "h`?bU&v|ravzX_@#-_s>D%S)zEyHZ{âV ֹVn +asSΞriP?c1g Po/4줭a [gz1wطk+If1\ 4$'UYj@O"؎1d*|j8 QC@fp%9`U&shYeX Ŝ3`_ɴ`@f讀Wk"D5>{,^彾.wёwwߛ\( *GYI) x_5TVVAB+KJl~x]*4m=;O@_%Bh*yD"N>錙(RmDԸF<@_+Q t^G 6PV[Wß1d0||Ѱ'0pꚇdZA^p!ỏGN!ϊcA?u]:'` saѐki* b|n A7IFZj赸ֈ/4#q1x"^96HOBK@SfdJֺƒ(ױv+iDU&21Bn_BX'X8[Q_/?3&ƣ Co`crrsik&¯ B @εe+- "**Ӛ\݆FXPBa;nXȅ A@Шo (t5+o7>J+Z?ΉWr] 흣8}{)S2l߾[IdV8p:3 U~֐Ue 7t>^ݺN~'hNDYv~'DŽ*,Ĭfg.ӥg( $ Ldʛɚ(ךHJI.ڻ}@M_|-^=d󂈁aa#ˋt+BN۷v6_'ehuwJ H\OH$Po*M r=a4!ZurWڶLj6K\5Ƨ:җ.{E`a*h<.O|s4$)`U,id8MŌwJ{gKhm2{C ?.Yp w1FqUQP"Ur3::YW))S_}1(BN~^,m,@X  '?LЮ]idxTU*~0PC R{ I~^h!%RdŋdE'Z;щ41qAYo؎]O};6˿ۊ{4;LI_+f@pXxLƆYkd)@f#tlgٹ< )g3.5xpHa\ndBvv)͜G [QƢQi0ჴmt;}䱏p4j (ID[ sߡjkq#x,&  xΛL]K/'کҔelW]&)$イ}RoԳv}'veR%UfDXh #tsʚ&T/KI_U"VRլQ:cB-u峯~/uJ\)`h ;55-wf7}8FN 5j8*% f#0,߻ nr{]駟t *;B<4;}28>O#<(N}&h뾠Erّ䄔Ξ;eAzǨ/5vuVWJz% H2 k@=:|#t@ ǹ4#q'm:*ͷj ~c獱Nk k\8Hd2oE8np&Kn䲔+v<ړԑD{%KP+F3 (ͨJRigt|LO%Eck}OPOw_Y5JKl-d:1IeJ91|Ki |W7ϵ`Z*]2GZ 5{ OP޼}HkboPָ^M"pGIϛ*U8\`c;r:9'%n鄐Ve5n'9@ҝ8j^ueJ_{4NOPCd/aϠ{%{c;=CAdΜ4pS: fff8 k$n# dXF,W"+&o-'V$)f o<RYDw顶;̞Zr4G \wEڳ{?q®?wɼVw?/qtD`"H8 IAD!s5IRH0ЈG4p1FU'{nK] 2JzKj!;9S{ޒyE YM 9B*> |k+F^LEƔ̋_+zu\sS^|tb@Oꡥ%җTha~hY{σWkt^Q3-9??+ֶrtuu4tΘ0<$m@^x B dhrac/lIeT6I##Ҁt0Iw]ptN >a _8Cc/m6{9ڠUMQPo_2 뺯iv$*@mΛh-"ݴҍU.v*^ïѿ/Jb9GYFMgmK)~riY iOhz6ڵk@$s[,ղ띌CAV %48< { #{!W9r]!+*ϋѲ]er-p! 28ɗb/mM_ʗE-Br`HibP ԖV'JZ lDAӕIff,IqHc?^M 5NBg'h0,LqɔBv:[31 i[dlo߀RJVhOOeG? ѥ Gjh*v/آxC?K㯑}s㑯,*?fjRwOV8P/=W*%ԟ=ZW/c#ҤSgGhnz[) pa& ֒yw9X#ʉ%49N8@8EdsIqlJL[0eʏPXjf`~qerwtp9M Z؄vFI+ CE"L#cq8DoyE=me%=|:1gdpk"Q4"[ hqB9K/|oA> ,ji'S63u/Rd4q&S=.Ts8H^y;YABN1q3F'OӉ'd-DsdА&uUkgvW&cZCPn:Fs Rs}e j1Wg b|fD\6 ]iduXZ롞(oauyqzk!&8y[-S_K^Qo4R-l٦u 511I6P~uIxq)JW&ŋ8O8Ps:=oGXCbhau! 隲D[)o6 y334=='HX[ur k"QXE ԾCґ^~Qfīa@ֈL&GǏ_A^FY9PKv=qMoiZQk#yJjuf8idj T:4z_0׊1$Gӓt)WtzE ԩSt1-8zzzѣbqq}lunnӥse@Qut xLKBq>t3׸n%8bN|L\cj(+YR:EH'X1+}ǎ%2VԨL^3ĨfP#2 { X!i;Yu0MfWסր)Ӓ_yYiˋ(F~~0Br#wuwVr,iDRJ@wL~Mg^ kE|c7!?' ?$ϥ%h8~5'#OJ[(* ^eL:U[K? `e0~\?}˨Nv@KJ0Wknm;}Ӟt.8v=^poߥ &_ʰ6&9 *i6I&v ٹS/3uo."A- ȼx"*z|#*]Ν@vF& xAe='g"q~p}нݭf9,'e:Q\4 lo .^ڻ'En,9D&ʡ~keY0O WX%2GxnT%UB(9F~SW F8 nLso[2(h繧Y\NQQ}--" h}ٸ^x>ω(<τ{1(0WD`.PaikM\p42[ʊȆ -? 5N諍m}rnj| _71;[lA Yy~@Mȶsf:˒οZ5@8Kܔ08#[wpQC?J>+%-q"c&XͺoRq/-勴4+N;dJ_#GODq>Y%*NuPK u!B,T1p:BН %ܲnLAj( ZZU|o֥Oχs/4<.yѡCV5 Kl_%쉔j φSўz+ dp[2zBS]_dL0F=k /oڴu%ڽ{80y{y˴8%܀ղu FV I6QoWz'%bt)8~JbQ2jRgR^&s\A9D3Jg8Ȥ;}F_(bޞU4ʒ U#ƚnX\IDhEj0Lc $u{3]wu.v.l dT&0 4SY7g4Xs t8EG*Ydg˗l4?;C'8ptXClP-z!2MG $+-H%unZ #Jv9q]Ǟ {#zLȞP99x+Meϐ{Ͼ"]Hm6 V}m80ICyt (^ދe_=t d >[]x/\.9 hܡQ\Iu_Anoݐ;Bx Cҥj%ptt8>{{0*rh+˭֫|K3mi;vyv2^6Cu#W4W8U"퍍72H)q0UW7z=㑢l/al&=LSc[ @:ZΟ?/dᨩņ;Hn0NẀtB?R͹5D r!L;Frgc0ʼ WX3#aT ZVR? q25 @7w 2#(_jʡ.mnd&.JJ9Oe!N>(Rfܣ*Jj>qX;9~s>51MoutC=Lv~#o48C{(kQSJ6ޖ62zT[xu ? U^*D"Pܬl \6ph æUjRWZa$yFI0(@-h%[8Z^^r*_ ( {eXP :l7qeZF&PUOHV69vkoZE#:80(Jh- `&pcQZye=-A-TrI*'i5@@AIpKW^V;yU`udo3CF7a!2la%Qo0V]&JD9=ۨ(]^e!}nվADQM4C$+N)aMZ֪E slV?fmUp`Rb?!m%R$AaR-hǜZӟQ%5Rȗa<ԏW_nxRG?| s(A}ne&'.+%(G:}Lvv霁ȐS)Z4emÐ_D{ή6׃;w}{(oޣ 3Pp`f*ΚcOp`JvvRש+#Q$P{,]4KM75C.9ѿ= mmr#M]Y1n ˒6 D"*-\Kv^A*`xr;i2 .~'R!X[wvΝ{e"`!I/Gٸ c2|ܤjÜT@)K^ _@+=7c:RFCx^4< b؇|XHlV٪9X~F]-BZ :iDˆIt"OFԹ1>tTZ9+TR + *͌괾 4sfؕv(I)NAJdyj`[myjM]G[>ƣoȵ Х52&ٮ2H3&&9ٺS6ɓIK徛oWN?_#1iCT{G.]%@zG9L:?dA [s<*$d!q Bc36ZPj*ϘQM."Bh d3de^/|Wssi:r~swt)p TPEt&A程 DBdꫯJ$Qe"4<ؼ7$yQ x9QU#% Y#$n.􌭾~5Pi(S !Ej|?>vpnHV^?ݴg;Ӊ|}mלs(xJH3veߣU VC_.t`{$>j ~Nf,Sl491/Z\ p~Ww*YQ33y6 )?+o0s1{ C %~a9<G i1عmOdoh\9{]ꎪX͏Pvx_3?7#S쐮3TE?+fqrMuu ؎cʆ8SB!#46~zӇ'`<,B+żA/J- 4G t ޯ$G7￙n1!*v۷ʱf"9OۨmPK& ĚGU] MG.9"pQ{gYb*ָ>\2Jt TZ<ٮPwÄ0R BDZ.Kf0z]f;)p9LG8zV:phF63^ in?vL1Ct]}e"5 GvU)![`HGf+gӿXS5㙍9&j(;13̔*ߨd*9"5gF̯х ctR,X 2]')eNiiND7j )_¯v.q 6P˒ԺeL/ > "%ZoV8ʌD`0#GFqAag?}+Mº'@Nbp`2-cy]{~λ鮻3{;L{?88@[mY0-kT>fAc2j wg5eSfxdg~8 /z+a<X`dJ( LF0Js-ʼ/!^eJSzp}}r Q*7&T{TM.ep= Xǚyz3sEw?o^cTWmU 5[[V #r&iD><_Uy*v-Vx}A R,@@"}@$*j^X81uIqrcQ6/ɜ]Z1}OKO%vWcx Z7!Rw{)~#[Jb{.X7K[6,mI8o֖)EJ7J ֑ 7$XEB `kfO#/ y8! utQG466uSY !Tfz)3Ϝ9`9DK9~sЋnLs$\UQ`B",R/)`o|ҋ/=%)pƶ[|GKCѢ`,򍘹?SO}^3әPíJOvg}%#p<7#Vm7ѹ}6UzD2aN/ՙ7c,-Vɸ >;4'f|Dv3G݌}u~(T5X]Z)I*-7jV@DKc(~cg }="Iݫ(\S+&usQZȒ@zU3YS.>Wv\ixkMckv4`ѮHXmϩBaԝIR@ȟK `o@TِQNר) P1]Z zg? DTg,L+Yg,K)T|4"=1i/"/.-mJnw t*KidxFFo$8zxN$K˜_ kTWQD֑lL+I8 Xuɹ)?oF` V3R0ZΌRZvMRچfiU^Or=S?Tŗ^Nf{-U:^%_jwbn6)Wc B!'2M_/_k'N8!5۷K#A}j?G5Q[ F&5j3l궰Kdc#V](P[VLRqjQppm;5Mu9~h̜ 57V-]a%^,ddzլH?1.B ^X>S|ND4ݜh4*+LåW]A.z`(`XE?_ S>^}ڧrLJרz^0Ge8mZMU>dq%2r8U&/hŏPv6.h-.K>y JFoإ. 9} a`90"]Fq뾖s104[mD^rWmd[rؖSP]uXXV@9~ Q/9ldZ\Ld zv&ծ}{i&xW.ڂOUb*z]X+Q2տF@pCq*'?.| Жd~VU̶?kI(PUD ѐ]ty!-(sD# CmGj}[쵊 *NZ2Nԓ$wT+/k$s΍Ԛ2 6YJbjbdWhyyKr&6ƠSTG)Rr צHk8&g;Gdps@Y":yeՏBVJ>RƋ޺ J'(^3B`I fb;cL}5 l]b['S2@R\0 PBO*?s4')5T$a2@Id@ټnM.]@VY9m~NjX]ƲBaAkG?}NDÌUaNk btnతBB0e 6QJPэn&\.1.JWlt B&[.YR3{Э [MŒ҂G< i^,,iA hjiL3s@XtS,LCM^y]|uuHsکNv].tmV'EfI֏[4w^d2H 00o|42==ʦtt>E+? BrȖL=V3-̎Alo86d3RRԭd ߋ%% l%zF(Ȭ 7>'GP]x~Q0[4 \M\oӚ%3)LFizvRع0JZ joK˜(G&^'!&%d}^_yBa9!F cwh@sskFi Y Դ.elUY ߛmg*rj?sȃTa)PIj" K +Ǣcg h -2̙4i0;iL$7&YD]vC?RE.;Ժ'DoM8KTj,`8^[G`G@n.P.*h}Ns3~Fޭ^6ɜN:4{>O#⦗*,ikL/{n:sQ:Vk̯ m1`O|LK+Gωhr:/##:bN+JY6I]"7*AM\M.YpzP! eҥbn^ڹs7rk~o4vh"h=ǥ?t-wѶm;UwB,j_0Dp8^ny׾fbU o! %4 d/CQdU=QQD3'|SR[ӡu">SP^GX}jahW4>3ߝ)op* չdlZ6R;vQV'yV/g.F#{\(K' Q|ۘ-Aj"tƋJ4^]! SoXV^[{̚2=v2ʪu*aB*^>arQL}æcF"D%*tugC.7;%/(v9cs5@sC wD(XGzoHNN^[*#|cՎ*l~_H]i}ߡ q!pͮ8 ЁA4FѣeMz.h`㯙s/JBEH:"jc\mv_Jց-T@ ,l}>;arH]gN#DuA5Ji\آ.||g p,OjC߻ 6J]JShuKN'EwoGL~O;%uk#k/ &%3Rd))Ѧ eP4[qłk_i J ~=PCG)|GZԉDh"FV X9ғiJLP!$6h{yPb8&D+-5TDtfTҺfTJѿ "`Pc~i:{&CdY&#nsZ`tF6Okd,"f,DO&5\Jħ:,fD8+4X !xf"d[K1oZ;ArhqHykn.p?y ;?fFȸ;D/'h tQ-Yz\`wPE^lz饗EH3;?,^ݎij%$zl} zkN N.M(^ޖ4OATgIYȞ-Qv%/%R-F}P;z͜ P-y!Bcʴ5@sm zḍ_/7*0Vˎn_I;.?L/LpUQj2 Ug=ۥõ^׊s쎰8S ,\ux;:OeviZM S3r)ņuf\7 ܣf`)($&J.W!:y銥.Hæ5tֱe5eF/ײg8ԮvX͹~;1~V  w%31{O=~wih7`'D[xR(YmTt5㡁_ .N?mLR\F Wzoӗ7N,\ ɍ)_Sε6M]BLs{LdȔ*#GNWUQW5 FIzQtK480Lo唨5DS WEJ?IhaqbCws X3 O')Ƞ\!/xRsά?c*cp)zN/y^v.ayJ *22tv:,w:u!^tALcGg'"y6pEFH*g@v@Z?(B@)JNȾܬI#9&+ch[= 6`\i}[ߢ?.^'07?)u|IyUuͥiiyA8G°Fo}"j>6Пe:Qw;6)LP!fPM{nS'<pٟ"&(QJ,X$oeg.: 6zfY 5є{K A29NXN9k fqpdwRNEL`D{>WQ r`6(^$&o=l~Q UfN2Nr4?@^N^ۉv~A?lqRF'_ʕSHzVK_tùMIǃ碹 :,Sh.'}.gNT};I h"oկ9|a;}ߖҭ R{}=NShFK{Jk(8]Nt:j0+3Л5(xSG̽5luRը!z! 0@K::/;Zչ}_QOP:g7vMAx: 2 ?̘ 38͍L.Q:a߼ZohTf'(|mSM.XΝc˒ӟ8/k#q08=?o=}+B/P[[7[8ϒ)f#?e:ur=V,U+ş@npp#*Da,̦h9M J]Svҗoǯ fr!_ [GSYt)RjvZ\pny8;l \NzNu4_YȦ`/PTh܊}ep!s)"V;:6^CxW-$sѨ:k ~P0lQ'-͔vR#43L9p"joN\Xz|zk{[t;tWrhd1ҫE$0s?r}4" 9FEP65eWʀ:mo 188||V Go F<-JSrVx]ǩ5H.8G/Q{un_[hPD@IHd~q>A.JkwI#eYFc7`]7j^s S'ia2TAcpC.:;|hw9ϳUce0ϫѳӜR:[*;y\㊢|c;'/ug :@?}jf1@BR9NOmAiP"ӷW)OQTGk{GKt6#W (ղzK~thٝ0vG$r ㅾEM:zN)Ixײ.-)uMD TOCb`Sg_+TtLv`^$wQJ't8o6CLQ29XSQ6)šV=d! ޢ4xAgP+ntYA ܜ}9f pu+?Eħfh ~2L|?(;6GQ"L xy*{a{SR\OVk/CNF/d-n5L9̔z M.(, y;8r gu$ʱSϲoA`t!sl lu cizjyŜPA\K<]D-.r1P%/ HTnC2gNR)yC]6;n\I"{c$#N\츿CO%O`'Q4 ؎S4mvRz:-(v0in$e W[Eګ꾁zi{n2љH3r?h7 lWFZ\y*HWYtxP6sڜ|_=DwxC4WhCf@Z(Ȩ: 2%>')EQ1QV]/Bjcs_/ "U2<S^ h+EҢ 9/ PYG?BɳrUq k rp^BSB/wI4ZlMc@c uBR:p{8(s 1+QX25$6dtȋDWe!0z۵t Q-aZzag6.iZZ4;H:&\ y8;DS(B e!oS\%7˥I'+{\檣뿢-ezWkUq. ۋgL/G)զ!;g{fJ9 |H2W i)VR[螽-r8zP lGRc\zPV@@eѮC!*`REV+%o̽cwۨޮUi G CJ76PHD*  =N=U( t`زS`wL)lT L2AN3o% ώLN)OFxz~2B_.;>;#+bt3ŤGӅtm1ar&NNYNJ_HR!y[!WDLG8?l'AqT$"sE:rtvݏPp,H?_%JKȬJYZjCP)wު,2Ŷ}.̗he֠x)N3S唄o/o3s-$)*e}c[=Rt'zmy咎BD+++XI>J PAtD 7RxTD֓?nwhɤ5LG_Aee]6*GLB=ƂIv9fGoեf7C w7~:4HOSTmnP3D}͵{b8fگg2I^]3eGBkf"lI8r.IgРI[.:'It6W"ڂ_** M4e7PX*Pn%GN9eBɰ0 ߈`&DŽ+׎-e^lbgop˧5âWs&i>o@BΟFꠃ8}[s1K:( K-7͑/N(;DSIZ8@օVVy9BWI yLK>"{GT[=Ѯ ,—w2|exx4Ő7-DCQ|{Ȍ7".g/h3)mНldmS8X1'\зLTq]U XŞ$ֶPp 0ΕjV٪9[ ?nkfd0y-OΡ FD8Yח3˲q=}dI_bP3'b4ߦ6ƆpnṈ( o|{j6\zt -\fͿMM9Z~}y7t!.N{Iy+WXVP~R6MM ".WiK<Zh6Jm6y\vQuM>gĎe*#t zi-,G9*,9hlWX~TrLf\}ߪ7K{{A?E: 꼿&9)r~8. K͕-tG0H ʌaX)P` qPc4Rjʙ"yv޹lm=4\)&S0s8]|Qq>-jMOBo[k4u>,@u'evQ/k鴧iK# Qzzi:rP4"ͿjArIO9#6z u+ӗeI#uGoQ;k~$uxW'MdsӦ` 2 J8\t%e-}Q[@2S!mBtBvzM EpAAڶr1qs{#A~IlwO k|@/tRLJ&esV3 5ʙ#nbPއ9`5jPQn~,U MǧUݿ?i5MqJg3bJe ޽ ۪BTFn%^X -ԣ;gؚa5Hjlƥh68Nrdժ}ǮitZ4 z!F=d\L 2!{J&(,q6A *&\*??C \N؁$ߍ_nkAIՎfe\_7}EKyIIGZXShzD}}ޙq:XAGzȭ\ Qן'n'EZ ""[Z_/~ vw]n<;0L4cyO^;*RE{RqqUhlj$U!Y5I%hq\]X &f|} kk@DZK"B"hui(N|olӾmmgE.>9D.fL|-Hwv[j)^ƏST:4@s5&.}^ǚ v#%Sr3GY /^X G8r6B" )V2Wi1At _ }m2Fs9B[FdCZ(Sj EY Gh,-Ng(8@$LB:%| F<^^'s h:*df?P@8LA)v>?xxNMww3~AT&Kv_É-dŝfgH,H_0vn>tw8 r' :)sY"Q΀+~0 {{֠-df;{7{=|)WPDR0Na!RpޖSq:<9ܳS٫Z|9@77ѿ՝t΍[e:QE+˚N~_ 8clmU8|Ҧ{";tA Z+?h0G.$i(|u6cD ?z],=oص:b$1~j _>vQN\a/Dy5F+I ҩtͤ'V;LۛvqʱLնʢij&B#0\qzLR37Z.&ߞf[d|?Dq勞o?ںAkvT&kƈz\ mPt,rV2=4}@ f:9f`<;":]p NoMqrA}MJ_QR_;:GtC^^RDqTO{5(=Hsh @b tYPHu 7&pweOKM3GZ۩E)D(nּ酲3H#RArN]JTRL|({vJiptڹC.k[-҂e"Z?Nc|F <|5ŹN Y*Qe[-U6s-D 4Cqr~V/t1ٵ52)]M\u2 9.2ri.ڟF 뇇"4;hD#MS$oH+bD|z3 F?H)x@zAAmK4=634Cl 䃦\ؙ@ù7꼷&9R}h(@kb>G/po-2ve5ZoTs 8`{),M Äv7u2 ZziNʉox+ݹ6'Hr>XuVfO=QR^jZ;6BO7; J* J]1"}Eimqqot}};v M\um:m9d<͑~Q=H ?bOV+LC[q.԰5S9"SyCvu-s}1C)vVy_-D K5"qXF>;z\\CmtK0T>xqL,VG (>檴6ʥ*N6. !Jw烍4N_P>AS~ZS(o;j>Cg>KJcrloeБ5X{d7WsmyM3p)YDNlաW߀s ,Ǥ 9,PuP'AҪh_WJ&LْTs /YD-v4>ry\\(YA轞1pSdB9ٳC1|v̀3J 备azw3HtSݫ>/RRD%F1R 6ZWPoF]?s$Ǐ\],(ӯmПT~ʊZ t.#xK4E>>r#1) ~&&e`35Xjv{a.7禰!%~i7+(P.d b`hS]Yzڀ-GYYBT>T8ޛ>mo/]OMP2Vjjk8GlMFQ!!UN$:9i"/8e'o0ɮUUչ{{rh" I 'y6Xְ6`a6cmc`&I! #8:ʹ9W{f4$JS]?/ÿ:y1SiNWˋsصLY%F֢>hZgtD ȮR&6ٰ}}Q]=-"rh5l573ْ [ppTs}\Me8yV=xX=Np_+_ Uo ǿ:эKa,u蟟*D/ݯj/7yzy w-,l ty\?ҳa 97%8| b[Bl.~La_$~<R<-n@CM/1K^7y{_p.mZ4J\LPooYj>Ğ]8Dyy Cj8$f@%ub*@~~7$+sqC?B#4~/$7y99 %EUr4 "ZQfm09}Z ^~itTL~u|??r([\39zcaȩ=}6nAmlМK˭h8Kwl:_Sn_|w 7uU`Xs,k?nh4M$꫒sO  ]DbHC|諈_ `Ix [ueC,G.p ?BQűql*oΨ;oVq~vvr,˦c6mǮ]C|`AZAvnUC(_ܹ9^_˭3-OD#Az!Tf! ~L'}n}z}NdV[bUݨ͇TTS2lwFxs_y(E\Yoy"{ze(r{"pL kfydQǝ/q2}R:w'o^tuC$˃  Jʊz[B>8Fk:T2qXR65nt1>[RXa|Ta7gZQmg[}JkoI]T?z"}8z ;6mŸ?y v` @F^)p6WVHqλp7^ޅ]c浇#T/'Nv)(UCΫ*5TM:OfEaX؋wނ|Gy|hvRŪxm]"&+֐V1 ;4FcկC%(нGț|xy(ѡ^GTSJ Z4TB =CQld_ǥ]q|ozŊ",!kAXsX)JZzYq/`]IFg7y5ݝ-:Ɵ|da٢:u}8rڼ8^dxIJa_22ZQPKK\eJ:L9& >ϏN| 1: XC\U!m՞+5(-tOo{pez_Dxy|STSxX#9uHV׷O⓿KE}̚ dx𩓓Hqp&Zvr%YA CDxk"±"@w=Ks @и }jmaW+H5uJ >!׹oz;&Bsj>h)j>_+D߫S4v&cDrۋ˪0GOͨ) lz4 ' ¹׏^Tt2z!IE疫0z o_l*S_;K.swԭ3]c*T{-b}LM^v-g*ϋ9S?#ֹѪLQdnZQ] ?-^~ӥ 2Lw[~F|:gg{Xe0n>^щ1jx́F~xMy6>8UkY|MB*+ 9 x{?.srw,-@њ׽ݍH_Dg3Ѡ9>HF su^gF/ܪ 21T­(VlnR(.ʽ7V}c_UA٪pFDBAVMfoRFBc4Q_/룅eAQ:ЏhK<c_J-p&G"Tzy@Wt!=KOd&tykn|xt=űT(#qq=6Uă71 `5=s.em##^f^9Z?:w&%c$T#mn,i18*ͅq|w[{Bit3TϹ .DTj{m A$!?2'U`Qg\'bs ٝ{6Gy7-Jڞ~2k]a`9ZW`ElЍnVJ΋4W9ȧTD^Sn ʰ,{tNA5@R}`ꨎR1g#1i?e=^yzni'NcVSQ>4Yz K'+#W`CTQɄZ>eG~إu{.7kz*~ LJ{IhvƊԂZC'Om,B%pW^D~gC|T +:7vu^h܏+k>.S}rDnu5VwV&nb)]qT(~e,ܒ N>Y߬si]9W}Cc-_lX*-a6?kD~dl>PF'~h j "1–PG#N*Oz䌍\VՑVH{9TWh~=Nv?'ӤWGl*QAwkpdGc(./׬fG6<8xX;l5EOBu]9źRLw< &*kmcqu~a5?]**g(m xD9@waก D8HMNԚe}Y s\WeRRhdVTꪵ"ym;3<y+k_}u7YUwfV Sj7ᅇ#&gpF>= Tu+[ۇNj%\#d\-s)p)ϥ4Uq|#\־9EXr=mS ̀7DTMW,12o   nx1gu-A;WEb{8"ų1:'R` zުU/L0n%pWnQ=wD8h eraנP3~;8t%s_|_5M^VJ|yw7~a_Ӗ 1L׫a5}=|}h,Y#VD*.G8 T$Ԟ7'](@.}Ë{89gB Ŕ60\@pN7;&:Çsr<)g|ky\\1/>'W7JQ2g2,@ﭮ"[WKI@k9YѮvWMVKwG}i5'2.-8R&2c*k~Nv0Q@iz9Lg*LZ+/M$B::LE-aaݸ%Ӆ k{hIjj vLɠ1Eb:]k/;L3Uuqk}z\I8,44Trvħ-6Τbi|[8CW"4n<Z^m BbE.LCUӜ `қh޻pDZ_g]BeWcێ!旰R^E+p 1 sX7̊ y]Uoq9is4#'O̮t^dsĶSDܭQf;86 @<$aY2uxϧÿ.w21_g-s-zQQj^%bC (aU6d5؏Ȕʨ +nXjgStSO/HTS4JЍsJ{hЂ 1j4U]QZ<~w5Ըqq?؃ 8z/SIմSyР5t؅{`ʳŚ)冃P}nqUbg1M}rrYwfj'.s / tL/'R9-xM0[ ~i^,VQ5q4'=-W4#&ֺm׿sEDmCj̴?7A|se/yt* !'r9JyVN]&k1K@Z]ZdƳbjG^y*g5\Smb`)]m&) <¥;W̬ ˬDÇ9<ᄪ.-uz2hU؜å{5_\6cO$+}1dzDjZQbz^EDk/t-/B7Z_eQ0QE3zL>Vt3Io(ν 1-eT9*ϐ\E/U沺u# G^w8ڕMWCxa<<'t4a6SeK2ie8kּm`'>??iܸ&l8 W7}*Iž8һcߢRr/Vs`zGDNgFzkVaг%xϭ[Ub"k<1nNBmE͌MeXTR@p`2[LX@EX3"WPc_^PO0J1Ӭ۬ OzUZ1i>] $5/&ɛ T)'΅L-:vSwӛ LQ mlWζ~y{+uY*yjEyyxr\rEk=V]{ QΦۼ^>*ٍo/,/jU cW(t)U=dzq,TF߶6wYǜ6=_R!emZâ/s2:ص)}X^.7u1?⡣.e5mưsznˋ#\+EW+X`[`0%(R  `dć#Π@]0HDkɭ1m+{#hpZ@wPώ0oKi'Sgd y@g֥#(BKi8)c;"m$`N%ԗI|V\R%|D4Mhj T_#oUKSm@4J^Vo]:aYlKlݚ|}65,tY@p>GfQ"ЋuW'p*z?׵w*tM9ë,Pk/ٸAG+ {s0b=yH31$bhySl$8qr2]V־y"DcfVƳځU_H@@CC e0s 98~cUPI˅q @_D۳huY^~jjynv}qχh"1\ӍzzT#G01e&pۭL43ѯA:۳7tuaaa^-!NLK$%"nU-o546矮5URq"fƋ8H0mᅻm$`<`(*iIҥf#7v#e,LԔm:|~5K&Fxver߼g nI>V߷U F7ThgcuB: 3G`WT+dl8^BpXəPLJC<[\Y/F˧ 9hk:JRsW,UCy=^3"@ x{{ Gl|'/e%G j݃UۈqԪ^ZUI'hJǠTgqG*cjܫO1]81B٩M[iQv+ %X+"?߲Lks(r!"Jlͺ%CFnUKz O6sh-B@TnUBګPwp,ZSVI9d;޹~}|E'<$0:6SO>rT3Kgwx2l[j3 P-(Rp5hݮs *wolGqb>>pnye+ϙ-}ܑ>{|vc|X r" 9]?qڭ\!P]@+ zMoJFD!h` (s.CLAD$[77Ap4X 2\VeLf(o/S5.4}=l ~-}=shWd2yR'ۏfT.U!@lˆy]P5εJ@%,:GeN̒1jy\sөY7*2_@j|lя}~]qF/ =O5S'2`-5z5%}rjL%/;{O;Bs1'bl`mul,NΝ~7wm+I`K` S%dz>BŝLE*}Z1 q=.e{Y2\Nj6/蝆DwGvINN㣟~rZ%#r3jQnguz]UMzZme%w %kwud.[u Y"歗[X r3 3}x??#U_g}pDŽ l8Vƕ#UkR kn`_6)n}>zᖸ2NdH Dwmۈ׏'@ /`4xZÃr-ؼc.COgՃ&!'7βg(}+w wv\4ћt5: 'qh5̖\'x< mw<~-c,X!Y85> TQйԮS mߛÍw5-gj?pNj?QOk΍kNu؜Oi܊VT5auD;T}Ew*4y۪3~bs%BRsGWLD6ggKaS euo|( DBt2Hos}0t##L 2 yI`G<fR(53aϟ5GT>k;sfrg!%bko΍1KVDtZWƵl;KǎU_v~뾧gS;G<D2Yԭz.mx"kIL%C넎*4^isțxb_\V3k-*xi* &TO`H?|w=\ZI$*z<891 MXj%%=$'>{Pp ֈL{hSW'4ȨFOE"2I%M}ĉIk$D DB>"L*ˤ1t2%xa~l'pQK5c(֪(qA1o%j@dM'O/hpJxQꇧ86ݒRz ߒg[Yy'tn_oMO4h+ lzEemcÑ,BdD(+!@ݍ Ru NhW4pwW_lv5lj<9o2_rIc6-$: b2F X"MvTm>ZW-t׫ a TAåCHwFJq:g_~t{,>r]qhIz^eZm~wƒTUN.p|lcsO5DUN>|s7zfk(T+~Fs_Um|$uWUw' P&n"~ pōiK4[,Ųqh<6΃x6C+@@ ntݮ{|x+p`dsQ\/K1O$)W0]_D8pm.קθ s׏[U?*Vp}"|5j]){ M zkuؾV%oo^?'VQ/<>[½4W @ {gS[* {9T9MbϦ𪊕lXP?Eqå]D(U*q-jUe$) L繬ȥV?3*9u27G@ w޻go'OW)92UzV͞!FBd=p=XI@ 奔EVt 'K?_Q!B@p\6}>$D~}uD}~\Gr2U,J . @ !@@ !@ @  @@ !@ @  @@ !@ @  @@ !@ @  @@ B@ @ @ @ B@ @G@  4 @  @@ !@ @  @@ !@ @ @ @ B@ @ @ @ B@ @ @ @ B@ @ @ @ B@ @ @ !@ @  @@ !@ gk$kIENDB`tiled-0.14.2/src/plugins/replicaisland/tutorial.png000066400000000000000000000300771260670167100223470ustar00rootroot00000000000000PNG  IHDR\rftEXtSoftwareAdobe ImageReadyqe</IDATxُer}z{+(H? A_HJ/ `-)I 6/i;=Uu͕U9a"{2+2~ yrbŊqӉ[8.88 8.<'~|>_zOa !kx>~ƏS_?_o =o>$;O'/Z\B\\NG..{BpG..{BpG..{BpG..{BpG..{Bz|[(G+}Bkx!O0 xwtNCDp{..{.{\\N({\\N({O!+.= 8El( upQ2Q;Eѐ bQ )bQ )jq?|^G~\y 6?Y ~;g υd{xpʽ]N( {]N( {?1m{OO۷[([=?s? ̞].t0Y>a 츿'xqN?sXެo_BxF'}'txpCc(4z&id%N@pҢOs3N' r##1/Fi~Zy)~){SO E= ó]s)'8Fv\swq\kmqXcq>'8nQ{8Eswg$! p8Huq<((S<)?&Ը92JC(Bӎ;n'L>(ӊ;n'T>(Binn'\& pF$Q{7|9ww38Q{7|9FTww>G|O3_g(23==&E sWqyr=wN\{7|n)Q{7| , yvgܛJ11w>W{{ߝ_?&FIyK.o< s*^t!pp\\\Džq!p!pp\\Ng<9Wǡ號?8ϣ!c?c%K8 8 8 8 8 8 8 qǏ;O:x_2:֯۟ qq\qpqq\qpqq\qpqN?Y%] Ƞ6hH%90a]FvG̔-M&<6* [d=h£"v\O:%,wΌR&]m;]i;[I 0] Cip`_w}Q̲@0fsw'yeg'ۻ!ɵ]GlTlQ6(1<*M_8.Oapn4[qwӼv~i>^^Y:rzo7dDV'I/ouvZWZyXبDyP\q@뗊qfgj']vznr+Uk aeu!v1|]Jٮ魯GNp\aUq0؀o:.G4\qiѴ8db.VupYT%j⯶.<<[@5Ux0M:!рp/[\wzyܦӉ]|ya(_:RcXM`ϣc>r ˣV_kvu jYk\%Qg٫Ӧ˓Ftє/_XY 8CP6׻5S3ZjYhݦ];~8' VS3Mƭ^셦^XvCH~ژȫ#UQAUԸ `䗐 +S;IWS0չ~|>l$}O _y\]*xEq0MΤ:^\/_>[o`)RExV6kg[Ykv2Οņr q?|RsK[9SA͛~)9R̰0ڥIwy:^[W_8W yc-Xν4<j\j] kKXkLP ፫6 F RTiPDy@sw V_@z\+맔m|x=}D4u4H ;p0 Prܶk:^2KrWNHG yʹyrmw B+!j9Y<.@v=֫izq{7_#vRu?ƺ[?~|. -U#"(ưg%  d M HOZ{~׿y;w㩾7ׄ;sư/Ns3[nFׯ^!gGX?ѿ}P LUc0V|`k?i1|SKeXJ@h ҥ _?;}4#UOKWp.<|ۃ!o'.Nخu^|8n_SGG!!@x{E"XA,"AE hEbYY!x?y[9n!ˁ\ET/2s$AU[a9)_z~xmy!@;1u2A?ҿF355rH@@1JP" e5՗%c64 *B.߻}O_!K0Z]Xq7t:a#8ϣ0uXMճk*v~z`(?_~'ꠡl/O&(b Ȓ'(ro9[-? C(a2I uE}}{sC@Juww/u%D]rgq(|)>^E2Vl+V35C#3}'o+u,,{^E! 1i!A ;E P=` - ŨTdK@h)^fc6 +`VEh@glRl`g;g㸊\&Y)%|0̷VsŔ8WQ?+;X 5-n#MYн%0 倏LKjػuKY_V +MKYprDύXֶ-׎ U8lNRmU̜,UXL˄[Y ʞi"T'65)-ƟjR:]{uU 1e0%c@.dh{O ٘f)F{alcRTD#]9d)@3q\.ܙ.E̜,BJyMy~8W*>,o[j B+)޲}N_oh@ ͳx91-_U!,Ҡ>oPr A`B+ M%ӥNbB0T0CY^L )@<{7lL˂fje=1%{{ +4RCY8L@VϔH |o5Bg4){8C;Iҩ0%[H;'RBaK&G / JG6zKPalF3̨rOBAkKD P@KwJLd̝1g2) LTFST(Cif03j?S$, P)'H|}4 Qt sa\bS,.*)\J:4XnCGskƏBӰ58ۚJū[ր~hY6Kfka94a 9s6hHbF&{dqJ},ErYP!پ^|Cr8kICt.e)08'MT۔0(*?晔Yf x5XF;PTYCٶ]m62d? +T/74D$"*%E,RYh_ 0dڴ-cq.fq a#!rB||)YYYɶUɽXI Py3R{x /j"Z}b17Ue#$g M^oH/xH2p2H`1 T1PvpN^0Yt AUtMo( , 3b0Ԩ l >&HhYNG쟯>-0#LABĦjBܳ3OL @Um2@ @V:6!#-$afkPX(]ek0{`%U[6֛Zr%o3֗[1r֢J5 en` ՑA͢f~9'I,gZcZZÒY7nqY,Z556ijBa:͎ݟۇ Ҡ ^pAP`ZD0K4hƒ' RECESCz}="V0P4r6#f]F4"0x):s+?[%V? T,{`_`WATn0i˫m< |̖"TR?))ƚmx+&ijV[fSGf)uUbI>Ilk3 jU0/oD, ?XR  `B)G)^lILלfEzH*]sH'S4kN ]6$C71dK0mFs:2iӄFB`}Qc4Gzc@0 (v&ީlzϯ7#S5)SEP "J`r4OJU. 1%rJ*| ,DJŤD͐l9e!lʒFg/:'HN:LCހD>YzRa6P"3LbDȄPMHYV3RHl%@#/7USͦ9C"Tr+E 0Br&9"pc==Y$`9 뵟y9~4$h$)B V| <$@N"\hETe)_j "%D` 0A,CAFJlbC d!F+s6h5 Ry`ξ&=RfAJ!AQXQ!!(!ƚ M[ސC#RdD@Bf@(ʥL#:͗= I}~9')jf.i[su [t=K,)P QŐ޸1VU/h(`` }rk K4 Z;˜ &dB AjPrvKh0X]QF.ih999a4`C"fe i"&H I1%Q(!PD1!U0g /*L(ve1sIj HL)?fJq/k$j0+"aII&~ 9I@IK]1"f[k3z ?~˟,@ !e_:0$}.pМ,МL $*2i6ja9h@S #!pvf(vڙ!HˀwNR:!U@bP'\*ۂgOBlR&x]<)S~g?/yc>04~ŐL6ެ% }8"% X $!O3w&`\ +I!A8X19IDBT9%dU\Na/f:=#dqO,) e "Fc*su}^ǒiAʼ DVPHy`EUꋲ} t,eLH!Ȅd痛sܐ'&@!pզmO蓿yl,( Q(cfgfYL U@4)Xr2ndVs98KF7ebV p{e!fiuBf  С`"&!ԌVxbM;C@0e~Z<2q(ߝ}p?XEƪ*dfĽ/P|w_ރJU A&1`7pNrʠ|k"Ŕ͙1~xh#QE2F{OF?)_H)B s}`K&2g o`Od*Bv`vV$ܜ%\;im><;_|E iʌ3J@ d mVoC=-aG3'Z?xdN{ft(4!,el|˼+!Q؉T:FDI%#wc ;qe2&kewCkgg|,ec[۔3Mr7MI[flx3{ˆBwf$/\xge6- ۻy X޳/rN45c&vV-D{Q{Y5)[߳ƟeRW"7R@toA4%}Eq^½9ݴ2tܨDȭXc/3$ `l !㭴ծYyB97i) "?x698F~ހi5#f8aaS@Fԑ1r3FnC9Ve!"owӤvoweq,/BP3Rb3ZSU "3Ojc6L 0!}DR 9C~[~[n%Q]~ّUzdi/1y9hQd>in!I.W'?^/{emmIaeS뇁Skfe4m1:ՐEf}~Bޯ|oաUX7J6 uFDr#ZxQ]F h3&^?oko{^7NU6qv䄤d`c+ K0nKȿ_]oI}e!_"|ntk鵇Iج+nTl6ܯ ՗. T9Q̀+bU145^P %k@|02L34' +,g*4 ius/f߻7x+pbޞo@/u`o֑ul`֨ӗoL#M^_}=|d$"@_Ϧفl )[x7^w |Yͮz8jy|0l½&ۃ7w݋6_pu.Msiac0a[A4?*9}9;qL$3ۓ4=XQyQ[mMA%냆5υ;p/!0xFt6;˗V_Zpr >rA75 5߄;soH{ L4ťtz&]Wn*>h*y4r~ovq>$2MNw-Ώ[;ӥ|q8痪Tm q <~F?c+ͤNrku-k(k:ޙH8.hj&0m6cu2N\S8\;}D * * * This file is part of Tiled. * * 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, see . */ #ifndef TENGINE_GLOBAL_H #define TENGINE_GLOBAL_H #include #if defined(TENGINE_LIBRARY) # define TENGINESHARED_EXPORT Q_DECL_EXPORT #else # define TENGINESHARED_EXPORT Q_DECL_IMPORT #endif #endif // TENGINE_GLOBAL_H tiled-0.14.2/src/plugins/tengine/tengineplugin.cpp000066400000000000000000000320321260670167100221620ustar00rootroot00000000000000/* * The T-Engine 4 Tiled Plugin * Copyright 2010, Mikolai Fajer * * This file is part of Tiled. * * 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, see . */ #include "tengineplugin.h" #include "map.h" #include "tile.h" #include "tilelayer.h" #include "objectgroup.h" #include "mapobject.h" #include "properties.h" #include #include #include #include #include using namespace Tengine; TenginePlugin::TenginePlugin() { } bool TenginePlugin::write(const Tiled::Map *map, const QString &fileName) { using namespace Tiled; QSaveFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { mError = tr("Could not open file for writing."); return false; } QTextStream out(&file); // Write the header QString header = map->property("header"); foreach (const QString &line, header.split("\\n")) { out << line << endl; } const int width = map->width(); const int height = map->height(); QList asciiMap; QHash cachedTiles; QList propertyOrder; propertyOrder.append("terrain"); propertyOrder.append("object"); propertyOrder.append("actor"); propertyOrder.append("trap"); propertyOrder.append("status"); propertyOrder.append("spot"); // Ability to handle overflow and strings for display bool outputLists = false; int asciiDisplay = ASCII_MIN; int overflowDisplay = 1; QHash::const_iterator i; // Add the empty tile int numEmptyTiles = 0; Properties emptyTile; emptyTile["display"] = "?"; cachedTiles["?"] = emptyTile; // Process the map, collecting used display strings as we go for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { Properties currentTile = cachedTiles["?"]; foreach (Layer *layer, map->layers()) { // If the layer name does not start with one of the tile properties, skip it QString layerKey; QListIterator propertyIterator = propertyOrder; while (propertyIterator.hasNext()) { QString currentProperty = propertyIterator.next(); if (layer->name().startsWith(currentProperty, Qt::CaseInsensitive)) { layerKey = currentProperty; break; } } if (layerKey.isEmpty()) { continue; } TileLayer *tileLayer = layer->asTileLayer(); ObjectGroup *objectLayer = layer->asObjectGroup(); // Process the Tile Layer if (tileLayer) { Tile *tile = tileLayer->cellAt(x, y).tile; if (tile) { currentTile["display"] = tile->property("display"); currentTile[layerKey] = tile->property("value"); } // Process the Object Layer } else if (objectLayer) { foreach (const MapObject *obj, objectLayer->objects()) { if (floor(obj->y()) <= y && y <= floor(obj->y() + obj->height())) { if (floor(obj->x()) <= x && x <= floor(obj->x() + obj->width())) { // Check the Object Layer properties if either display or value was missing if (!obj->property("display").isEmpty()) { currentTile["display"] = obj->property("display"); } else if (!objectLayer->property("display").isEmpty()) { currentTile["display"] = objectLayer->property("display"); } if (!obj->property("value").isEmpty()) { currentTile[layerKey] = obj->property("value"); } else if (!objectLayer->property("value").isEmpty()) { currentTile[layerKey] = objectLayer->property("value"); } } } } } } // If the currentTile does not exist in the cache, add it if (!cachedTiles.contains(currentTile["display"])) { cachedTiles[currentTile["display"]] = currentTile; // Otherwise check that it EXACTLY matches the cached one // and if not... } else if (currentTile != cachedTiles[currentTile["display"]]) { // Search the cached tiles for a match bool foundInCache = false; QString displayString; for (i = cachedTiles.constBegin(); i != cachedTiles.constEnd(); ++i) { displayString = i.key(); currentTile["display"] = displayString; if (currentTile == i.value()) { foundInCache = true; break; } } // If we haven't found a match then find a random display string // and cache it if (!foundInCache) { while (true) { // First try to use the ASCII characters if (asciiDisplay < ASCII_MAX) { displayString = QString(QChar::fromLatin1(asciiDisplay)); asciiDisplay++; // Then fall back onto integers } else { displayString = QString::number(overflowDisplay); overflowDisplay++; } currentTile["display"] = displayString; if (!cachedTiles.contains(displayString)) { cachedTiles[displayString] = currentTile; break; } else if (currentTile == cachedTiles[currentTile["display"]]) { break; } } } } // Check the output type if (currentTile["display"].length() > 1) { outputLists = true; } // Check if we are still the emptyTile if (currentTile == emptyTile) { numEmptyTiles++; } // Finally add the character to the asciiMap asciiMap.append(currentTile["display"]); } } // Write the definitions to the file out << "-- defineTile section" << endl; for (i = cachedTiles.constBegin(); i != cachedTiles.constEnd(); ++i) { QString displayString = i.key(); // Only print the emptyTile definition if there were empty tiles if (displayString == QLatin1String("?") && numEmptyTiles == 0) { continue; } // Need to escape " and \ characters displayString.replace(QLatin1Char('\\'), "\\\\"); displayString.replace(QLatin1Char('"'), "\\\""); QString args = constructArgs(i.value(), propertyOrder); if (!args.isEmpty()) { args = QString(", %1").arg(args); } out << QString("defineTile(\"%1\"%2)").arg(displayString, args) << endl; } // Check for an ObjectGroup named AddSpot out << endl << "-- addSpot section" << endl; foreach (Layer *layer, map->layers()) { ObjectGroup *objectLayer = layer->asObjectGroup(); if (objectLayer && objectLayer->name().startsWith("addspot", Qt::CaseInsensitive)) { foreach (const MapObject *obj, objectLayer->objects()) { QList propertyOrder; propertyOrder.append("type"); propertyOrder.append("subtype"); propertyOrder.append("additional"); QString args = constructArgs(obj->properties(), propertyOrder); if (!args.isEmpty()) { args = QString(", %1").arg(args); } for (int y = floor(obj->y()); y <= floor(obj->y() + obj->height()); ++y) { for (int x = floor(obj->x()); x <= floor(obj->x() + obj->width()); ++x) { out << QString("addSpot({%1, %2}%3)").arg(x).arg(y).arg(args) << endl; } } } } } // Check for an ObjectGroup named AddZone out << endl << "-- addZone section" << endl; foreach (Layer *layer, map->layers()) { ObjectGroup *objectLayer = layer->asObjectGroup(); if (objectLayer && objectLayer->name().startsWith("addzone", Qt::CaseInsensitive)) { foreach (MapObject *obj, objectLayer->objects()) { QList propertyOrder; propertyOrder.append("type"); propertyOrder.append("subtype"); propertyOrder.append("additional"); QString args = constructArgs(obj->properties(), propertyOrder); if (!args.isEmpty()) { args = QString(", %1").arg(args); } int top_left_x = floor(obj->x()); int top_left_y = floor(obj->y()); int bottom_right_x = floor(obj->x() + obj->width()); int bottom_right_y = floor(obj->y() + obj->height()); out << QString("addZone({%1, %2, %3, %4}%5)").arg(top_left_x).arg(top_left_y).arg(bottom_right_x).arg(bottom_right_y).arg(args) << endl; } } } // Write the map QString returnStart; QString returnStop; QString lineStart; QString lineStop; QString itemStart; QString itemStop; QString seperator; if (outputLists) { returnStart = "{"; returnStop = "}"; lineStart = "{"; lineStop = "},"; itemStart = "[["; itemStop = "]]"; seperator = ","; } else { returnStart = "[["; returnStop = "]]"; lineStart = ""; lineStop = ""; itemStart = ""; itemStop = ""; seperator = ""; } out << endl << "-- ASCII map section" << endl; out << "return " << returnStart << endl; for (int y = 0; y < height; ++y) { out << lineStart; for (int x = 0; x < width; ++x) { out << itemStart << asciiMap[x + (y * width)] << itemStop << seperator; } if (y == height - 1) { out << lineStop << returnStop; } else { out << lineStop << endl; } } if (!file.commit()) { mError = file.errorString(); return false; } return true; } QString TenginePlugin::nameFilter() const { return tr("T-Engine4 map files (*.lua)"); } QString TenginePlugin::errorString() const { return mError; } QString TenginePlugin::constructArgs(Tiled::Properties props, QList propOrder) const { QString argString; // We work backwards so we don't have to include a bunch of nils for (int i = propOrder.size() - 1; i >= 0; --i) { QString currentValue = props[propOrder[i]]; // Special handling of the "additional" property if ((propOrder[i] == "additional") && currentValue.isEmpty()) { currentValue = constructAdditionalTable(props, propOrder); } if (!argString.isEmpty()) { if (currentValue.isEmpty()) { currentValue = "nil"; } argString = QString("%1, %2").arg(currentValue, argString); } else if (!currentValue.isEmpty()) { argString = currentValue; } } return argString; } // Finds unhandled properties and bundles them into a Lua table QString TenginePlugin::constructAdditionalTable(Tiled::Properties props, QList propOrder) const { QString tableString; QMap unhandledProps = QMap(props); // Remove handled properties for (int i = 0; i < propOrder.size(); i++) { unhandledProps.remove(propOrder[i]); } // Construct the Lua string if (unhandledProps.size() > 0) { tableString = "{"; QMapIterator i(unhandledProps); while (i.hasNext()) { i.next(); tableString = QString("%1%2=%3,").arg(tableString, i.key(), i.value()); } tableString = QString("%1}").arg(tableString); } return tableString; } tiled-0.14.2/src/plugins/tengine/tengineplugin.h000066400000000000000000000032021260670167100216240ustar00rootroot00000000000000/* * The T-Engine 4 Tiled Plugin * Copyright 2010, Mikolai Fajer * * This file is part of Tiled. * * 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, see . */ #ifndef TENGINEPLUGIN_H #define TENGINEPLUGIN_H #include "tengine_global.h" #include "mapformat.h" #include "properties.h" #include namespace Tengine { // ASCII characters between decimals 32 and 126 should be ok const int ASCII_MIN = 32; const int ASCII_MAX = 126; class TENGINESHARED_EXPORT TenginePlugin : public Tiled::WritableMapFormat { Q_OBJECT Q_PLUGIN_METADATA(IID "org.mapeditor.MapFormat" FILE "plugin.json") public: TenginePlugin(); bool write(const Tiled::Map *map, const QString &fileName) override; QString nameFilter() const override; QString errorString() const override; private: QString mError; QString constructArgs(Tiled::Properties props, QList propOrder) const; QString constructAdditionalTable(Tiled::Properties props, QList propOrder) const; }; } // namespace Tengine #endif // TENGINEPLUGIN_H tiled-0.14.2/src/plugins/tmw/000077500000000000000000000000001260670167100157645ustar00rootroot00000000000000tiled-0.14.2/src/plugins/tmw/plugin.json000066400000000000000000000000321260670167100201500ustar00rootroot00000000000000{ "Keys": [ "notused" ] } tiled-0.14.2/src/plugins/tmw/tmw.pro000066400000000000000000000001661260670167100173200ustar00rootroot00000000000000include(../plugin.pri) DEFINES += TMW_LIBRARY SOURCES += tmwplugin.cpp HEADERS += tmwplugin.h\ tmw_global.h tiled-0.14.2/src/plugins/tmw/tmw.qbs000066400000000000000000000002351260670167100173020ustar00rootroot00000000000000import qbs 1.0 TiledPlugin { cpp.defines: ["TMW_LIBRARY"] files: [ "tmw_global.h", "tmwplugin.cpp", "tmwplugin.h", ] } tiled-0.14.2/src/plugins/tmw/tmw_global.h000066400000000000000000000017521260670167100202710ustar00rootroot00000000000000/* * The Mana World Tiled Plugin * Copyright 2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef TMW_GLOBAL_H #define TMW_GLOBAL_H #include #if defined(TMW_LIBRARY) # define TMWSHARED_EXPORT Q_DECL_EXPORT #else # define TMWSHARED_EXPORT Q_DECL_IMPORT #endif #endif // TMW_GLOBAL_H tiled-0.14.2/src/plugins/tmw/tmwplugin.cpp000066400000000000000000000050061260670167100205170ustar00rootroot00000000000000/* * The Mana World Tiled Plugin * Copyright 2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "tmwplugin.h" #include "map.h" #include "tile.h" #include "tilelayer.h" #include #include using namespace Tmw; TmwPlugin::TmwPlugin() { } bool TmwPlugin::write(const Tiled::Map *map, const QString &fileName) { using namespace Tiled; TileLayer *collisionLayer = nullptr; foreach (Layer *layer, map->layers()) { if (layer->name().compare(QLatin1String("collision"), Qt::CaseInsensitive) == 0) { if (TileLayer *tileLayer = layer->asTileLayer()) { if (collisionLayer) { mError = tr("Multiple collision layers found!"); return false; } collisionLayer = tileLayer; } } } if (!collisionLayer) { mError = tr("No collision layer found!"); return false; } QSaveFile file(fileName); if (!file.open(QIODevice::WriteOnly)) { mError = tr("Could not open file for writing."); return false; } const int width = collisionLayer->width(); const int height = collisionLayer->height(); QDataStream stream(&file); stream.setByteOrder(QDataStream::LittleEndian); stream << (qint16) width; stream << (qint16) height; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { Tile *tile = collisionLayer->cellAt(x, y).tile; stream << (qint8) (tile && tile->id() > 0); } } if (!file.commit()) { mError = file.errorString(); return false; } return true; } QString TmwPlugin::nameFilter() const { return tr("TMW-eAthena collision files (*.wlk)"); } QString TmwPlugin::errorString() const { return mError; } tiled-0.14.2/src/plugins/tmw/tmwplugin.h000066400000000000000000000024561260670167100201720ustar00rootroot00000000000000/* * The Mana World Tiled Plugin * Copyright 2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef TMWPLUGIN_H #define TMWPLUGIN_H #include "tmw_global.h" #include "mapformat.h" #include namespace Tmw { class TMWSHARED_EXPORT TmwPlugin : public Tiled::WritableMapFormat { Q_OBJECT Q_PLUGIN_METADATA(IID "org.mapeditor.MapFormat" FILE "plugin.json") public: TmwPlugin(); bool write(const Tiled::Map *map, const QString &fileName) override; QString nameFilter() const override; QString errorString() const override; private: QString mError; }; } // namespace Tmw #endif // TMWPLUGIN_H tiled-0.14.2/src/qtpropertybrowser/000077500000000000000000000000001260670167100173315ustar00rootroot00000000000000tiled-0.14.2/src/qtpropertybrowser/README.TXT000066400000000000000000000104561260670167100206750ustar00rootroot00000000000000Qt Solutions Component: Property Browser A property browser framework enabling the user to edit a set of properties. The framework provides a browser widget that displays the given properties with labels and corresponding editing widgets (e.g. line edits or comboboxes). The various types of editing widgets are provided by the framework's editor factories: For each property type, the framework provides a property manager (e.g. QtIntPropertyManager and QtStringPropertyManager) which can be associated with the preferred editor factory (e.g. QtSpinBoxFactory and QtLineEditFactory). The framework also provides a variant based property type with corresponding variant manager and factory. Finally, the framework provides three ready-made implementations of the browser widget: QtTreePropertyBrowser, QtButtonPropertyBrowser and QtGroupBoxPropertyBrowser. Version history: 2.1: - QtTreePropertyBrowser - tooltip of property applied to first column, while second column shows the value text of property in its tooltip - QtAbstractPropertyManager - initializeProperty() and uninitializeProperty() without const modifier now - QtTreePropertyBrowser and QtGroupBoxPropertyBrowser - internal margin set to 0 - QtProperty - setEnabled() and isEnabled() methods added - QtTreePropertyBrowser - "rootIsDecorated", "indentation" and "headerVisible" properties added - QtProperty - hasValue() method added, useful for group properties 2.2: - FocusOut event now filtered out in case of Qt::ActiveWindowFocusReason reason. In that case editor is not closed when its sub dialog is executed - Removed bug in color icon generation - Decimals attribute added to "double" property type - PointF, SizeF and RectF types supported - Proper translation calls for tree property browser - QtProperty - ensure inserted subproperty is different from "this" property - QtBrowserItem class introduced, useful for identifying browser's gui elements - Possibility to control expanded state of QtTreePropertyBrowser's items from code - QtTreePropertyBrowser - "resizeMode" and "splitterPosition" properties added - QtGroupBoxPropertyBrowser - fixed crash in case of deleting the editor factory and then deleting the manager - "Decoration" example added - it shows how to add new responsibilities to the existing managers and editor factories 2.3: - Various bugfixes and improvements - QtProperty - setModified() and isModified() methods added - QtTreePropertyBrowser - disabling an item closes its editor - KeySequence, Char, Locale and Cursor types supported - Support for icons in enum type added - Kerning subproperty exposed in Font type - New property browser class added - QtButtonPropertyBrowser with drop down button as a grouping element 2.4: - Fixed memory leak of QtProperty - QtTreePropertyBrowser - group items are rendered better - QtTreePropertyBrowser - propertiesWithoutValueMarked and alternatingRowColors features added - QtTreePropertyBrowser - possibility of coloring properties added - QtTreePropertyBrowser - keyboard navigation improved - New factories providing popup dialogs added: QtColorEditorFactory and QtFontEditorFactory - Single step attribute added to: QtIntPropertyManager and QtDoublePropertyManager 2.5: - "Object Controller" example added. It implements a similar widget to the property editor in QDesigner - Compile with QT_NO_CURSOR - Expand root item with single click on the '+' icon - QtRectPropertyManager and QtRectFPropertyManager - by default constraint is null rect meaning no constraint is applied 2.6: - QtGroupPropertyBrowser - don't force the layout to show the whole labels' contents for read only properties, show tooltips for them in addition. - QtTreePropertyBrowser - fixed painting of the editor for color property type when style sheet is used (QTSOLBUG-64). - Make it possible to change the style of the checkboxes with a stylesheet (QTSOLBUG-61). - Change the minimum size of a combobox so that it can show at least one character and an icon. - Make it possible to properly style custom embedded editors (e.g. the color editor provided with the solution). tiled-0.14.2/src/qtpropertybrowser/common.pri000066400000000000000000000004041260670167100213330ustar00rootroot00000000000000TEMPLATE += fakelib QTPROPERTYBROWSER_LIBNAME = $$qtLibraryTarget(QtSolutions_PropertyBrowser-head) TEMPLATE -= fakelib QTPROPERTYBROWSER_LIBDIR = $$PWD/lib unix:qtpropertybrowser-uselib:!qtpropertybrowser-buildlib:QMAKE_RPATHDIR += $$QTPROPERTYBROWSER_LIBDIR tiled-0.14.2/src/qtpropertybrowser/qtpropertybrowser.qbs000066400000000000000000000016501260670167100236770ustar00rootroot00000000000000import qbs 1.0 StaticLibrary { name: "qtpropertybrowser" Depends { name: "cpp" } Depends { name: "Qt"; submodules: ["widgets"] } cpp.includePaths: ["src"] cpp.cxxLanguageVersion: "c++11" files: [ "src/qtbuttonpropertybrowser.cpp", "src/qtbuttonpropertybrowser.h", "src/qteditorfactory.cpp", "src/qteditorfactory.h", "src/qtgroupboxpropertybrowser.cpp", "src/qtgroupboxpropertybrowser.h", "src/qtpropertybrowser.cpp", "src/qtpropertybrowser.h", "src/qtpropertybrowserutils.cpp", "src/qtpropertybrowserutils_p.h", "src/qtpropertymanager.cpp", "src/qtpropertymanager.h", "src/qttreepropertybrowser.cpp", "src/qttreepropertybrowser.h", "src/qtvariantproperty.cpp", "src/qtvariantproperty.h", ] Export { Depends { name: "cpp" } cpp.includePaths: "src" } } tiled-0.14.2/src/qtpropertybrowser/src/000077500000000000000000000000001260670167100201205ustar00rootroot00000000000000tiled-0.14.2/src/qtpropertybrowser/src/QtAbstractEditorFactoryBase000066400000000000000000000000371260670167100254050ustar00rootroot00000000000000#include "qtpropertybrowser.h" tiled-0.14.2/src/qtpropertybrowser/src/QtAbstractPropertyBrowser000066400000000000000000000000371260670167100252240ustar00rootroot00000000000000#include "qtpropertybrowser.h" tiled-0.14.2/src/qtpropertybrowser/src/QtAbstractPropertyManager000066400000000000000000000000371260670167100251530ustar00rootroot00000000000000#include "qtpropertybrowser.h" tiled-0.14.2/src/qtpropertybrowser/src/QtBoolPropertyManager000066400000000000000000000000371260670167100243030ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtBrowserItem000066400000000000000000000000371260670167100226120ustar00rootroot00000000000000#include "qtpropertybrowser.h" tiled-0.14.2/src/qtpropertybrowser/src/QtButtonPropertyBrowser000066400000000000000000000000451260670167100247330ustar00rootroot00000000000000#include "qtbuttonpropertybrowser.h" tiled-0.14.2/src/qtpropertybrowser/src/QtCharEditorFactory000066400000000000000000000000351260670167100237220ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtCharPropertyManager000066400000000000000000000000371260670167100242650ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtCheckBoxFactory000066400000000000000000000000351260670167100233640ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtColorEditorFactory000066400000000000000000000000351260670167100241230ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtColorPropertyManager000066400000000000000000000000371260670167100244660ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtCursorEditorFactory000066400000000000000000000000351260670167100243220ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtCursorPropertyManager000066400000000000000000000000371260670167100246650ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtDateEditFactory000066400000000000000000000000351260670167100233610ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtDatePropertyManager000066400000000000000000000000371260670167100242650ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtDateTimeEditFactory000066400000000000000000000000351260670167100242000ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtDateTimePropertyManager000066400000000000000000000000371260670167100251040ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtDoublePropertyManager000066400000000000000000000000371260670167100246220ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtDoubleSpinBoxFactory000066400000000000000000000000351260670167100244130ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtEnumEditorFactory000066400000000000000000000000351260670167100237510ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtEnumPropertyManager000066400000000000000000000000371260670167100243140ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtFlagPropertyManager000066400000000000000000000000371260670167100242610ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtFontEditorFactory000066400000000000000000000000351260670167100237530ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtFontPropertyManager000066400000000000000000000000371260670167100243160ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtGroupBoxPropertyBrowser000066400000000000000000000000471260670167100252270ustar00rootroot00000000000000#include "qtgroupboxpropertybrowser.h" tiled-0.14.2/src/qtpropertybrowser/src/QtGroupPropertyManager000066400000000000000000000000371260670167100245040ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtIntPropertyManager000066400000000000000000000000371260670167100241420ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtKeySequenceEditorFactory000066400000000000000000000000351260670167100252660ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtKeySequencePropertyManager000066400000000000000000000000371260670167100256310ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtLineEditFactory000066400000000000000000000000351260670167100233730ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtLocalePropertyManager000066400000000000000000000000371260670167100246070ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtPointFPropertyManager000066400000000000000000000000371260670167100246070ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtPointPropertyManager000066400000000000000000000000371260670167100245010ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtProperty000066400000000000000000000000371260670167100221740ustar00rootroot00000000000000#include "qtpropertybrowser.h" tiled-0.14.2/src/qtpropertybrowser/src/QtRectFPropertyManager000066400000000000000000000000371260670167100244130ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtRectPropertyManager000066400000000000000000000000371260670167100243050ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtScrollBarFactory000066400000000000000000000000351260670167100235610ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtSizeFPropertyManager000066400000000000000000000000371260670167100244300ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtSizePolicyPropertyManager000066400000000000000000000000371260670167100255020ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtSizePropertyManager000066400000000000000000000000371260670167100243220ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtSliderFactory000066400000000000000000000000351260670167100231200ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtSpinBoxFactory000066400000000000000000000000351260670167100232600ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtStringPropertyManager000066400000000000000000000000371260670167100246560ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtTimeEditFactory000066400000000000000000000000351260670167100234020ustar00rootroot00000000000000#include "qteditorfactory.h" tiled-0.14.2/src/qtpropertybrowser/src/QtTimePropertyManager000066400000000000000000000000371260670167100243060ustar00rootroot00000000000000#include "qtpropertymanager.h" tiled-0.14.2/src/qtpropertybrowser/src/QtTreePropertyBrowser000066400000000000000000000000431260670167100243550ustar00rootroot00000000000000#include "qttreepropertybrowser.h" tiled-0.14.2/src/qtpropertybrowser/src/QtVariantEditorFactory000066400000000000000000000000371260670167100244530ustar00rootroot00000000000000#include "qtvariantproperty.h" tiled-0.14.2/src/qtpropertybrowser/src/QtVariantProperty000066400000000000000000000000371260670167100235210ustar00rootroot00000000000000#include "qtvariantproperty.h" tiled-0.14.2/src/qtpropertybrowser/src/QtVariantPropertyManager000066400000000000000000000000371260670167100250140ustar00rootroot00000000000000#include "qtvariantproperty.h" tiled-0.14.2/src/qtpropertybrowser/src/images/000077500000000000000000000000001260670167100213655ustar00rootroot00000000000000tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-arrow.png000066400000000000000000000002531260670167100245400ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@fPIDATx^=α 0 ѤA"9Oh؁-k^cK?m :V-@Gêeΰqo_NpoYք^]IuZIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-busy.png000066400000000000000000000003111260670167100243630ustar00rootroot00000000000000PNG  IHDR g PLTE~OtRNS@fnIDATx^ͱ 0P ~)~6idJWO.l(@ X`@ tJ!9l&aqlQ] ~#-搫I 8{4u4IENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-closedhand.png000066400000000000000000000002231260670167100255070ustar00rootroot00000000000000PNG  IHDR7 pHYs 7˭EIDAT(ϭ D-$pzS逢B@@r(2`' ـM^ PIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-cross.png000066400000000000000000000002021260670167100245310ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@f'IDATc`  P Vpm=XK "IENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-forbidden.png000066400000000000000000000003071260670167100253420ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@flIDATx^uα C1P y \`4.L`"EB \RAc!OҾU+2ֵ_d\l+ Zz<'r:#7$/sIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-hand.png000066400000000000000000000002371260670167100243220ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@fDIDAT[c``aL(=XzjБ JcZd N Ѫf @&ЫV-J7U%IENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-hsplit.png000066400000000000000000000002331260670167100247070ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f@IDATc`..@ ͡TY;AӀtS`` e Cap0 w/PܪIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-ibeam.png000066400000000000000000000001741260670167100244650ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f!IDATc`"`*@340܇^TIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-openhand.png000066400000000000000000000002401260670167100251760ustar00rootroot00000000000000PNG  IHDR7 pHYs 7˭RIDAT(υ_tW&DNt^a'`O#9#V*~Wa`'-$2d_=J;Ҁ>x0tbIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-sizeall.png000066400000000000000000000002561260670167100250540ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@fSIDAT[c`\ f^5P00:H0:%BD&pÁ f/0watêNXIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-sizeb.png000066400000000000000000000002411260670167100245170ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@fFIDATc` VjSC!*ҌPJBN1 D`uN:5J@(ƀbv l= jIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-sizef.png000066400000000000000000000002411260670167100245230ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@fFIDATc` VjSCtD|j!z(00AtpBhQU 5JsBiPTa.$,= 'IENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-sizeh.png000066400000000000000000000002211260670167100245230ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f6IDAT[c`h00p% l LSXBtg(D h8LL# /97IENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-sizev.png000066400000000000000000000002151260670167100245440ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f2IDAT[c`L+ 4W kKC驡 Emf>>0܇4 SvIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-uparrow.png000066400000000000000000000002041260670167100251010ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@f)IDAT[c`L+ 4W kKC驡 0` B7~2IENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-vsplit.png000066400000000000000000000002411260670167100247240ustar00rootroot00000000000000PNG  IHDRm PLTE~OtRNS@fFIDAT[c`  9Cjh3UfZR p`G3f~{VOIENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-wait.png000066400000000000000000000002541260670167100243530ustar00rootroot00000000000000PNG  IHDRm PLTEtRNS@fQIDATc`@RVӡ|:r&KS.ьK& ʜ10bpfD~%󦢚37--{PY IENDB`tiled-0.14.2/src/qtpropertybrowser/src/images/cursor-whatsthis.png000066400000000000000000000002771260670167100254320ustar00rootroot00000000000000PNG  IHDR g PLTEtRNS@fdIDATWch` ! U+Ai lS R #1B[&-3VHMa̘e,1TD֫6@D8 SÀ$W/qIENDB`tiled-0.14.2/src/qtpropertybrowser/src/qtbuttonpropertybrowser.cpp000066400000000000000000000471261260670167100257270ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtbuttonpropertybrowser.h" #include #include #include #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtButtonPropertyBrowserPrivate { QtButtonPropertyBrowser *q_ptr; Q_DECLARE_PUBLIC(QtButtonPropertyBrowser) public: void init(QWidget *parent); void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); void propertyRemoved(QtBrowserItem *index); void propertyChanged(QtBrowserItem *index); QWidget *createEditor(QtProperty *property, QWidget *parent) const { return q_ptr->createEditor(property, parent); } void slotEditorDestroyed(); void slotUpdate(); void slotToggled(bool checked); struct WidgetItem { WidgetItem() : widget(0), label(0), widgetLabel(0), button(0), container(0), layout(0), /*line(0), */parent(0), expanded(false) { } QWidget *widget; // can be null QLabel *label; // main label with property name QLabel *widgetLabel; // label substitute showing the current value if there is no widget QToolButton *button; // expandable button for items with children QWidget *container; // container which is expanded when the button is clicked QGridLayout *layout; // layout in container WidgetItem *parent; QList children; bool expanded; }; private: void updateLater(); void updateItem(WidgetItem *item); void insertRow(QGridLayout *layout, int row) const; void removeRow(QGridLayout *layout, int row) const; int gridRow(WidgetItem *item) const; int gridSpan(WidgetItem *item) const; void setExpanded(WidgetItem *item, bool expanded); QToolButton *createButton(QWidget *panret = 0) const; QMap m_indexToItem; QMap m_itemToIndex; QMap m_widgetToItem; QMap m_buttonToItem; QGridLayout *m_mainLayout; QList m_children; QList m_recreateQueue; }; QToolButton *QtButtonPropertyBrowserPrivate::createButton(QWidget *parent) const { QToolButton *button = new QToolButton(parent); button->setCheckable(true); button->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); button->setArrowType(Qt::DownArrow); button->setIconSize(QSize(3, 16)); /* QIcon icon; icon.addPixmap(q_ptr->style()->standardPixmap(QStyle::SP_ArrowDown), QIcon::Normal, QIcon::Off); icon.addPixmap(q_ptr->style()->standardPixmap(QStyle::SP_ArrowUp), QIcon::Normal, QIcon::On); button->setIcon(icon); */ return button; } int QtButtonPropertyBrowserPrivate::gridRow(WidgetItem *item) const { QList siblings; if (item->parent) siblings = item->parent->children; else siblings = m_children; int row = 0; QListIterator it(siblings); while (it.hasNext()) { WidgetItem *sibling = it.next(); if (sibling == item) return row; row += gridSpan(sibling); } return -1; } int QtButtonPropertyBrowserPrivate::gridSpan(WidgetItem *item) const { if (item->container && item->expanded) return 2; return 1; } void QtButtonPropertyBrowserPrivate::init(QWidget *parent) { m_mainLayout = new QGridLayout(); parent->setLayout(m_mainLayout); QLayoutItem *item = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding); m_mainLayout->addItem(item, 0, 0); } void QtButtonPropertyBrowserPrivate::slotEditorDestroyed() { QWidget *editor = qobject_cast(q_ptr->sender()); if (!editor) return; if (!m_widgetToItem.contains(editor)) return; m_widgetToItem[editor]->widget = 0; m_widgetToItem.remove(editor); } void QtButtonPropertyBrowserPrivate::slotUpdate() { QListIterator itItem(m_recreateQueue); while (itItem.hasNext()) { WidgetItem *item = itItem.next(); WidgetItem *parent = item->parent; QWidget *w = 0; QGridLayout *l = 0; const int oldRow = gridRow(item); if (parent) { w = parent->container; l = parent->layout; } else { w = q_ptr; l = m_mainLayout; } int span = 1; if (!item->widget && !item->widgetLabel) span = 2; item->label = new QLabel(w); item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); l->addWidget(item->label, oldRow, 0, 1, span); updateItem(item); } m_recreateQueue.clear(); } void QtButtonPropertyBrowserPrivate::setExpanded(WidgetItem *item, bool expanded) { if (item->expanded == expanded) return; if (!item->container) return; item->expanded = expanded; const int row = gridRow(item); WidgetItem *parent = item->parent; QGridLayout *l = 0; if (parent) l = parent->layout; else l = m_mainLayout; if (expanded) { insertRow(l, row + 1); l->addWidget(item->container, row + 1, 0, 1, 2); item->container->show(); } else { l->removeWidget(item->container); item->container->hide(); removeRow(l, row + 1); } item->button->setChecked(expanded); item->button->setArrowType(expanded ? Qt::UpArrow : Qt::DownArrow); } void QtButtonPropertyBrowserPrivate::slotToggled(bool checked) { WidgetItem *item = m_buttonToItem.value(q_ptr->sender()); if (!item) return; setExpanded(item, checked); if (checked) emit q_ptr->expanded(m_itemToIndex.value(item)); else emit q_ptr->collapsed(m_itemToIndex.value(item)); } void QtButtonPropertyBrowserPrivate::updateLater() { QTimer::singleShot(0, q_ptr, SLOT(slotUpdate())); } void QtButtonPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) { WidgetItem *afterItem = m_indexToItem.value(afterIndex); WidgetItem *parentItem = m_indexToItem.value(index->parent()); WidgetItem *newItem = new WidgetItem(); newItem->parent = parentItem; QGridLayout *layout = 0; QWidget *parentWidget = 0; int row = -1; if (!afterItem) { row = 0; if (parentItem) parentItem->children.insert(0, newItem); else m_children.insert(0, newItem); } else { row = gridRow(afterItem) + gridSpan(afterItem); if (parentItem) parentItem->children.insert(parentItem->children.indexOf(afterItem) + 1, newItem); else m_children.insert(m_children.indexOf(afterItem) + 1, newItem); } if (!parentItem) { layout = m_mainLayout; parentWidget = q_ptr; } else { if (!parentItem->container) { m_recreateQueue.removeAll(parentItem); WidgetItem *grandParent = parentItem->parent; QGridLayout *l = 0; const int oldRow = gridRow(parentItem); if (grandParent) { l = grandParent->layout; } else { l = m_mainLayout; } QFrame *container = new QFrame(); container->setFrameShape(QFrame::Panel); container->setFrameShadow(QFrame::Raised); parentItem->container = container; parentItem->button = createButton(); m_buttonToItem[parentItem->button] = parentItem; q_ptr->connect(parentItem->button, SIGNAL(toggled(bool)), q_ptr, SLOT(slotToggled(bool))); parentItem->layout = new QGridLayout(); container->setLayout(parentItem->layout); if (parentItem->label) { l->removeWidget(parentItem->label); delete parentItem->label; parentItem->label = 0; } int span = 1; if (!parentItem->widget && !parentItem->widgetLabel) span = 2; l->addWidget(parentItem->button, oldRow, 0, 1, span); updateItem(parentItem); } layout = parentItem->layout; parentWidget = parentItem->container; } newItem->label = new QLabel(parentWidget); newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); newItem->widget = createEditor(index->property(), parentWidget); if (newItem->widget) { QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed())); m_widgetToItem[newItem->widget] = newItem; } else if (index->property()->hasValue()) { newItem->widgetLabel = new QLabel(parentWidget); newItem->widgetLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); } insertRow(layout, row); int span = 1; if (newItem->widget) layout->addWidget(newItem->widget, row, 1); else if (newItem->widgetLabel) layout->addWidget(newItem->widgetLabel, row, 1); else span = 2; layout->addWidget(newItem->label, row, 0, span, 1); m_itemToIndex[newItem] = index; m_indexToItem[index] = newItem; updateItem(newItem); } void QtButtonPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) { WidgetItem *item = m_indexToItem.value(index); m_indexToItem.remove(index); m_itemToIndex.remove(item); WidgetItem *parentItem = item->parent; const int row = gridRow(item); if (parentItem) parentItem->children.removeAt(parentItem->children.indexOf(item)); else m_children.removeAt(m_children.indexOf(item)); const int colSpan = gridSpan(item); m_buttonToItem.remove(item->button); if (item->widget) delete item->widget; if (item->label) delete item->label; if (item->widgetLabel) delete item->widgetLabel; if (item->button) delete item->button; if (item->container) delete item->container; if (!parentItem) { removeRow(m_mainLayout, row); if (colSpan > 1) removeRow(m_mainLayout, row); } else if (parentItem->children.count() != 0) { removeRow(parentItem->layout, row); if (colSpan > 1) removeRow(parentItem->layout, row); } else { const WidgetItem *grandParent = parentItem->parent; QGridLayout *l = 0; if (grandParent) { l = grandParent->layout; } else { l = m_mainLayout; } const int parentRow = gridRow(parentItem); const int parentSpan = gridSpan(parentItem); l->removeWidget(parentItem->button); l->removeWidget(parentItem->container); delete parentItem->button; delete parentItem->container; parentItem->button = 0; parentItem->container = 0; parentItem->layout = 0; if (!m_recreateQueue.contains(parentItem)) m_recreateQueue.append(parentItem); if (parentSpan > 1) removeRow(l, parentRow + 1); updateLater(); } m_recreateQueue.removeAll(item); delete item; } void QtButtonPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const { QMap itemToPos; int idx = 0; while (idx < layout->count()) { int r, c, rs, cs; layout->getItemPosition(idx, &r, &c, &rs, &cs); if (r >= row) { itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs); } else { idx++; } } const QMap::ConstIterator icend = itemToPos.constEnd(); for(QMap::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { const QRect r = it.value(); layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); } } void QtButtonPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const { QMap itemToPos; int idx = 0; while (idx < layout->count()) { int r, c, rs, cs; layout->getItemPosition(idx, &r, &c, &rs, &cs); if (r > row) { itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs); } else { idx++; } } const QMap::ConstIterator icend = itemToPos.constEnd(); for(QMap::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { const QRect r = it.value(); layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); } } void QtButtonPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) { WidgetItem *item = m_indexToItem.value(index); updateItem(item); } void QtButtonPropertyBrowserPrivate::updateItem(WidgetItem *item) { QtProperty *property = m_itemToIndex[item]->property(); if (item->button) { QFont font = item->button->font(); font.setUnderline(property->isModified()); item->button->setFont(font); item->button->setText(property->propertyName()); item->button->setToolTip(property->toolTip()); item->button->setStatusTip(property->statusTip()); item->button->setWhatsThis(property->whatsThis()); item->button->setEnabled(property->isEnabled()); } if (item->label) { QFont font = item->label->font(); font.setUnderline(property->isModified()); item->label->setFont(font); item->label->setText(property->propertyName()); item->label->setToolTip(property->toolTip()); item->label->setStatusTip(property->statusTip()); item->label->setWhatsThis(property->whatsThis()); item->label->setEnabled(property->isEnabled()); } if (item->widgetLabel) { QFont font = item->widgetLabel->font(); font.setUnderline(false); item->widgetLabel->setFont(font); item->widgetLabel->setText(property->valueText()); item->widgetLabel->setToolTip(property->valueText()); item->widgetLabel->setEnabled(property->isEnabled()); } if (item->widget) { QFont font = item->widget->font(); font.setUnderline(false); item->widget->setFont(font); item->widget->setEnabled(property->isEnabled()); item->widget->setToolTip(property->valueText()); } } /*! \class QtButtonPropertyBrowser \brief The QtButtonPropertyBrowser class provides a drop down QToolButton based property browser. A property browser is a widget that enables the user to edit a given set of properties. Each property is represented by a label specifying the property's name, and an editing widget (e.g. a line edit or a combobox) holding its value. A property can have zero or more subproperties. QtButtonPropertyBrowser provides drop down button for all nested properties, i.e. subproperties are enclosed by a container associated with the drop down button. The parent property's name is displayed as button text. For example: \image qtbuttonpropertybrowser.png Use the QtAbstractPropertyBrowser API to add, insert and remove properties from an instance of the QtButtonPropertyBrowser class. The properties themselves are created and managed by implementations of the QtAbstractPropertyManager class. \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser */ /*! \fn void QtButtonPropertyBrowser::collapsed(QtBrowserItem *item) This signal is emitted when the \a item is collapsed. \sa expanded(), setExpanded() */ /*! \fn void QtButtonPropertyBrowser::expanded(QtBrowserItem *item) This signal is emitted when the \a item is expanded. \sa collapsed(), setExpanded() */ /*! Creates a property browser with the given \a parent. */ QtButtonPropertyBrowser::QtButtonPropertyBrowser(QWidget *parent) : QtAbstractPropertyBrowser(parent) { d_ptr = new QtButtonPropertyBrowserPrivate; d_ptr->q_ptr = this; d_ptr->init(this); } /*! Destroys this property browser. Note that the properties that were inserted into this browser are \e not destroyed since they may still be used in other browsers. The properties are owned by the manager that created them. \sa QtProperty, QtAbstractPropertyManager */ QtButtonPropertyBrowser::~QtButtonPropertyBrowser() { const QMap::ConstIterator icend = d_ptr->m_itemToIndex.constEnd(); for (QMap::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it) delete it.key(); delete d_ptr; } /*! \reimp */ void QtButtonPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) { d_ptr->propertyInserted(item, afterItem); } /*! \reimp */ void QtButtonPropertyBrowser::itemRemoved(QtBrowserItem *item) { d_ptr->propertyRemoved(item); } /*! \reimp */ void QtButtonPropertyBrowser::itemChanged(QtBrowserItem *item) { d_ptr->propertyChanged(item); } /*! Sets the \a item to either collapse or expanded, depending on the value of \a expanded. \sa isExpanded(), expanded(), collapsed() */ void QtButtonPropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded) { QtButtonPropertyBrowserPrivate::WidgetItem *itm = d_ptr->m_indexToItem.value(item); if (itm) d_ptr->setExpanded(itm, expanded); } /*! Returns true if the \a item is expanded; otherwise returns false. \sa setExpanded() */ bool QtButtonPropertyBrowser::isExpanded(QtBrowserItem *item) const { QtButtonPropertyBrowserPrivate::WidgetItem *itm = d_ptr->m_indexToItem.value(item); if (itm) return itm->expanded; return false; } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtbuttonpropertybrowser.cpp" tiled-0.14.2/src/qtpropertybrowser/src/qtbuttonpropertybrowser.h000066400000000000000000000061111260670167100253610ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTBUTTONPROPERTYBROWSER_H #define QTBUTTONPROPERTYBROWSER_H #include "qtpropertybrowser.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtButtonPropertyBrowserPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtButtonPropertyBrowser : public QtAbstractPropertyBrowser { Q_OBJECT public: QtButtonPropertyBrowser(QWidget *parent = 0); ~QtButtonPropertyBrowser(); void setExpanded(QtBrowserItem *item, bool expanded); bool isExpanded(QtBrowserItem *item) const; Q_SIGNALS: void collapsed(QtBrowserItem *item); void expanded(QtBrowserItem *item); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); virtual void itemRemoved(QtBrowserItem *item); virtual void itemChanged(QtBrowserItem *item); private: QtButtonPropertyBrowserPrivate *d_ptr; Q_DECLARE_PRIVATE(QtButtonPropertyBrowser) Q_DISABLE_COPY(QtButtonPropertyBrowser) Q_PRIVATE_SLOT(d_func(), void slotUpdate()) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed()) Q_PRIVATE_SLOT(d_func(), void slotToggled(bool)) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif tiled-0.14.2/src/qtpropertybrowser/src/qteditorfactory.cpp000066400000000000000000002455031260670167100240600ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qteditorfactory.h" #include "qtpropertybrowserutils_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_CC_MSVC) # pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ #endif #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif // Set a hard coded left margin to account for the indentation // of the tree view icon when switching to an editor static inline void setupTreeViewEditorMargin(QLayout *lt) { enum { DecorationMargin = 4 }; if (QApplication::layoutDirection() == Qt::LeftToRight) lt->setContentsMargins(DecorationMargin, 0, 0, 0); else lt->setContentsMargins(0, 0, DecorationMargin, 0); } // ---------- EditorFactoryPrivate : // Base class for editor factory private classes. Manages mapping of properties to editors and vice versa. template class EditorFactoryPrivate { public: typedef QList EditorList; typedef QMap PropertyToEditorListMap; typedef QMap EditorToPropertyMap; Editor *createEditor(QtProperty *property, QWidget *parent); void initializeEditor(QtProperty *property, Editor *e); void slotEditorDestroyed(QObject *object); PropertyToEditorListMap m_createdEditors; EditorToPropertyMap m_editorToProperty; }; template Editor *EditorFactoryPrivate::createEditor(QtProperty *property, QWidget *parent) { Editor *editor = new Editor(parent); initializeEditor(property, editor); return editor; } template void EditorFactoryPrivate::initializeEditor(QtProperty *property, Editor *editor) { typename PropertyToEditorListMap::iterator it = m_createdEditors.find(property); if (it == m_createdEditors.end()) it = m_createdEditors.insert(property, EditorList()); it.value().append(editor); m_editorToProperty.insert(editor, property); } template void EditorFactoryPrivate::slotEditorDestroyed(QObject *object) { const typename EditorToPropertyMap::iterator ecend = m_editorToProperty.end(); for (typename EditorToPropertyMap::iterator itEditor = m_editorToProperty.begin(); itEditor != ecend; ++itEditor) { if (itEditor.key() == object) { Editor *editor = itEditor.key(); QtProperty *property = itEditor.value(); const typename PropertyToEditorListMap::iterator pit = m_createdEditors.find(property); if (pit != m_createdEditors.end()) { pit.value().removeAll(editor); if (pit.value().empty()) m_createdEditors.erase(pit); } m_editorToProperty.erase(itEditor); return; } } } // ------------ QtSpinBoxFactory class QtSpinBoxFactoryPrivate : public EditorFactoryPrivate { QtSpinBoxFactory *q_ptr; Q_DECLARE_PUBLIC(QtSpinBoxFactory) public: void slotPropertyChanged(QtProperty *property, int value); void slotRangeChanged(QtProperty *property, int min, int max); void slotSingleStepChanged(QtProperty *property, int step); void slotReadOnlyChanged(QtProperty *property, bool readOnly); void slotSetValue(int value); }; void QtSpinBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSpinBox *editor = itEditor.next(); if (editor->value() != value) { editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } } void QtSpinBoxFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) { if (!m_createdEditors.contains(property)) return; QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setRange(min, max); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtSpinBoxFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setSingleStep(step); editor->blockSignals(false); } } void QtSpinBoxFactoryPrivate::slotReadOnlyChanged( QtProperty *property, bool readOnly) { if (!m_createdEditors.contains(property)) return; QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setReadOnly(readOnly); editor->blockSignals(false); } } void QtSpinBoxFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) { if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } } /*! \class QtSpinBoxFactory \brief The QtSpinBoxFactory class provides QSpinBox widgets for properties created by QtIntPropertyManager objects. \sa QtAbstractEditorFactory, QtIntPropertyManager */ /*! Creates a factory with the given \a parent. */ QtSpinBoxFactory::QtSpinBoxFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtSpinBoxFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtSpinBoxFactory::~QtSpinBoxFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtSpinBoxFactory::connectPropertyManager(QtIntPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); connect(manager, SIGNAL(readOnlyChanged(QtProperty *, bool)), this, SLOT(slotReadOnlyChanged(QtProperty *, bool))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtSpinBoxFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent) { QSpinBox *editor = d_ptr->createEditor(property, parent); editor->setSingleStep(manager->singleStep(property)); editor->setRange(manager->minimum(property), manager->maximum(property)); editor->setValue(manager->value(property)); editor->setKeyboardTracking(false); editor->setReadOnly(manager->isReadOnly(property)); connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtSpinBoxFactory::disconnectPropertyManager(QtIntPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); disconnect(manager, SIGNAL(readOnlyChanged(QtProperty *, bool)), this, SLOT(slotReadOnlyChanged(QtProperty *, bool))); } // QtSliderFactory class QtSliderFactoryPrivate : public EditorFactoryPrivate { QtSliderFactory *q_ptr; Q_DECLARE_PUBLIC(QtSliderFactory) public: void slotPropertyChanged(QtProperty *property, int value); void slotRangeChanged(QtProperty *property, int min, int max); void slotSingleStepChanged(QtProperty *property, int step); void slotSetValue(int value); }; void QtSliderFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSlider *editor = itEditor.next(); editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } void QtSliderFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) { if (!m_createdEditors.contains(property)) return; QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSlider *editor = itEditor.next(); editor->blockSignals(true); editor->setRange(min, max); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtSliderFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QSlider *editor = itEditor.next(); editor->blockSignals(true); editor->setSingleStep(step); editor->blockSignals(false); } } void QtSliderFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor ) { if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } } /*! \class QtSliderFactory \brief The QtSliderFactory class provides QSlider widgets for properties created by QtIntPropertyManager objects. \sa QtAbstractEditorFactory, QtIntPropertyManager */ /*! Creates a factory with the given \a parent. */ QtSliderFactory::QtSliderFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtSliderFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtSliderFactory::~QtSliderFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtSliderFactory::connectPropertyManager(QtIntPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtSliderFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent) { QSlider *editor = new QSlider(Qt::Horizontal, parent); d_ptr->initializeEditor(property, editor); editor->setSingleStep(manager->singleStep(property)); editor->setRange(manager->minimum(property), manager->maximum(property)); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtSliderFactory::disconnectPropertyManager(QtIntPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } // QtSliderFactory class QtScrollBarFactoryPrivate : public EditorFactoryPrivate { QtScrollBarFactory *q_ptr; Q_DECLARE_PUBLIC(QtScrollBarFactory) public: void slotPropertyChanged(QtProperty *property, int value); void slotRangeChanged(QtProperty *property, int min, int max); void slotSingleStepChanged(QtProperty *property, int step); void slotSetValue(int value); }; void QtScrollBarFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor( m_createdEditors[property]); while (itEditor.hasNext()) { QScrollBar *editor = itEditor.next(); editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } void QtScrollBarFactoryPrivate::slotRangeChanged(QtProperty *property, int min, int max) { if (!m_createdEditors.contains(property)) return; QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor( m_createdEditors[property]); while (itEditor.hasNext()) { QScrollBar *editor = itEditor.next(); editor->blockSignals(true); editor->setRange(min, max); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtScrollBarFactoryPrivate::slotSingleStepChanged(QtProperty *property, int step) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QScrollBar *editor = itEditor.next(); editor->blockSignals(true); editor->setSingleStep(step); editor->blockSignals(false); } } void QtScrollBarFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtIntPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtScrollBarFactory \brief The QtScrollBarFactory class provides QScrollBar widgets for properties created by QtIntPropertyManager objects. \sa QtAbstractEditorFactory, QtIntPropertyManager */ /*! Creates a factory with the given \a parent. */ QtScrollBarFactory::QtScrollBarFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtScrollBarFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtScrollBarFactory::~QtScrollBarFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtScrollBarFactory::connectPropertyManager(QtIntPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); connect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtScrollBarFactory::createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent) { QScrollBar *editor = new QScrollBar(Qt::Horizontal, parent); d_ptr->initializeEditor(property, editor); editor->setSingleStep(manager->singleStep(property)); editor->setRange(manager->minimum(property), manager->maximum(property)); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtScrollBarFactory::disconnectPropertyManager(QtIntPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); } // QtCheckBoxFactory class QtCheckBoxFactoryPrivate : public EditorFactoryPrivate { QtCheckBoxFactory *q_ptr; Q_DECLARE_PUBLIC(QtCheckBoxFactory) public: void slotPropertyChanged(QtProperty *property, bool value); void slotTextVisibleChanged(QtProperty *property, bool textVisible); void slotSetValue(bool value); }; void QtCheckBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, bool value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QtBoolEdit *editor = itEditor.next(); editor->blockCheckBoxSignals(true); editor->setChecked(value); editor->blockCheckBoxSignals(false); } } void QtCheckBoxFactoryPrivate::slotTextVisibleChanged(QtProperty *property, bool textVisible) { if (!m_createdEditors.contains(property)) return; QtBoolPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QtBoolEdit *editor = itEditor.next(); editor->setTextVisible(textVisible); } } void QtCheckBoxFactoryPrivate::slotSetValue(bool value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtBoolPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtCheckBoxFactory \brief The QtCheckBoxFactory class provides QCheckBox widgets for properties created by QtBoolPropertyManager objects. \sa QtAbstractEditorFactory, QtBoolPropertyManager */ /*! Creates a factory with the given \a parent. */ QtCheckBoxFactory::QtCheckBoxFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtCheckBoxFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtCheckBoxFactory::~QtCheckBoxFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCheckBoxFactory::connectPropertyManager(QtBoolPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotPropertyChanged(QtProperty *, bool))); connect(manager, SIGNAL(textVisibleChanged(QtProperty *, bool)), this, SLOT(slotTextVisibleChanged(QtProperty *, bool))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtCheckBoxFactory::createEditor(QtBoolPropertyManager *manager, QtProperty *property, QWidget *parent) { QtBoolEdit *editor = d_ptr->createEditor(property, parent); editor->setChecked(manager->value(property)); editor->setTextVisible(manager->textVisible(property)); connect(editor, SIGNAL(toggled(bool)), this, SLOT(slotSetValue(bool))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCheckBoxFactory::disconnectPropertyManager(QtBoolPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotPropertyChanged(QtProperty *, bool))); disconnect(manager, SIGNAL(textVisibleChanged(QtProperty *, bool)), this, SLOT(slotTextVisibleChanged(QtProperty *, bool))); } // QtDoubleSpinBoxFactory class QtDoubleSpinBoxFactoryPrivate : public EditorFactoryPrivate { QtDoubleSpinBoxFactory *q_ptr; Q_DECLARE_PUBLIC(QtDoubleSpinBoxFactory) public: void slotPropertyChanged(QtProperty *property, double value); void slotRangeChanged(QtProperty *property, double min, double max); void slotSingleStepChanged(QtProperty *property, double step); void slotDecimalsChanged(QtProperty *property, int prec); void slotReadOnlyChanged(QtProperty *property, bool readOnly); void slotSetValue(double value); }; void QtDoubleSpinBoxFactoryPrivate::slotPropertyChanged(QtProperty *property, double value) { QList editors = m_createdEditors[property]; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); if (editor->value() != value) { editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } } void QtDoubleSpinBoxFactoryPrivate::slotRangeChanged(QtProperty *property, double min, double max) { if (!m_createdEditors.contains(property)) return; QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QList editors = m_createdEditors[property]; QListIterator itEditor(editors); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setRange(min, max); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtDoubleSpinBoxFactoryPrivate::slotSingleStepChanged(QtProperty *property, double step) { if (!m_createdEditors.contains(property)) return; QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QList editors = m_createdEditors[property]; QListIterator itEditor(editors); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setSingleStep(step); editor->blockSignals(false); } } void QtDoubleSpinBoxFactoryPrivate::slotReadOnlyChanged( QtProperty *property, bool readOnly) { if (!m_createdEditors.contains(property)) return; QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setReadOnly(readOnly); editor->blockSignals(false); } } void QtDoubleSpinBoxFactoryPrivate::slotDecimalsChanged(QtProperty *property, int prec) { if (!m_createdEditors.contains(property)) return; QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QList editors = m_createdEditors[property]; QListIterator itEditor(editors); while (itEditor.hasNext()) { QDoubleSpinBox *editor = itEditor.next(); editor->blockSignals(true); editor->setDecimals(prec); editor->setValue(manager->value(property)); editor->blockSignals(false); } } void QtDoubleSpinBoxFactoryPrivate::slotSetValue(double value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator itcend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != itcend; ++itEditor) { if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtDoublePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } } /*! \class QtDoubleSpinBoxFactory \brief The QtDoubleSpinBoxFactory class provides QDoubleSpinBox widgets for properties created by QtDoublePropertyManager objects. \sa QtAbstractEditorFactory, QtDoublePropertyManager */ /*! Creates a factory with the given \a parent. */ QtDoubleSpinBoxFactory::QtDoubleSpinBoxFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtDoubleSpinBoxFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtDoubleSpinBoxFactory::~QtDoubleSpinBoxFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDoubleSpinBoxFactory::connectPropertyManager(QtDoublePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotPropertyChanged(QtProperty *, double))); connect(manager, SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); connect(manager, SIGNAL(singleStepChanged(QtProperty *, double)), this, SLOT(slotSingleStepChanged(QtProperty *, double))); connect(manager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); connect(manager, SIGNAL(readOnlyChanged(QtProperty *, bool)), this, SLOT(slotReadOnlyChanged(QtProperty *, bool))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtDoubleSpinBoxFactory::createEditor(QtDoublePropertyManager *manager, QtProperty *property, QWidget *parent) { QDoubleSpinBox *editor = d_ptr->createEditor(property, parent); editor->setSingleStep(manager->singleStep(property)); editor->setDecimals(manager->decimals(property)); editor->setRange(manager->minimum(property), manager->maximum(property)); editor->setValue(manager->value(property)); editor->setKeyboardTracking(false); editor->setReadOnly(manager->isReadOnly(property)); connect(editor, SIGNAL(valueChanged(double)), this, SLOT(slotSetValue(double))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDoubleSpinBoxFactory::disconnectPropertyManager(QtDoublePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotPropertyChanged(QtProperty *, double))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); disconnect(manager, SIGNAL(singleStepChanged(QtProperty *, double)), this, SLOT(slotSingleStepChanged(QtProperty *, double))); disconnect(manager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); disconnect(manager, SIGNAL(readOnlyChanged(QtProperty *, bool)), this, SLOT(slotReadOnlyChanged(QtProperty *, bool))); } // QtLineEditFactory class QtLineEditFactoryPrivate : public EditorFactoryPrivate { QtLineEditFactory *q_ptr; Q_DECLARE_PUBLIC(QtLineEditFactory) public: void slotPropertyChanged(QtProperty *property, const QString &value); void slotRegExpChanged(QtProperty *property, const QRegExp ®Exp); void slotSetValue(const QString &value); void slotEchoModeChanged(QtProperty *, int); void slotReadOnlyChanged(QtProperty *, bool); }; void QtLineEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QString &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor( m_createdEditors[property]); while (itEditor.hasNext()) { QLineEdit *editor = itEditor.next(); if (editor->text() != value) { editor->blockSignals(true); editor->setText(value); editor->blockSignals(false); } } } void QtLineEditFactoryPrivate::slotRegExpChanged(QtProperty *property, const QRegExp ®Exp) { if (!m_createdEditors.contains(property)) return; QtStringPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QLineEdit *editor = itEditor.next(); editor->blockSignals(true); const QValidator *oldValidator = editor->validator(); QValidator *newValidator = 0; if (regExp.isValid()) { newValidator = new QRegExpValidator(regExp, editor); } editor->setValidator(newValidator); if (oldValidator) delete oldValidator; editor->blockSignals(false); } } void QtLineEditFactoryPrivate::slotEchoModeChanged(QtProperty *property, int echoMode) { if (!m_createdEditors.contains(property)) return; QtStringPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QLineEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setEchoMode((EchoMode)echoMode); editor->blockSignals(false); } } void QtLineEditFactoryPrivate::slotReadOnlyChanged( QtProperty *property, bool readOnly) { if (!m_createdEditors.contains(property)) return; QtStringPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QLineEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setReadOnly(readOnly); editor->blockSignals(false); } } void QtLineEditFactoryPrivate::slotSetValue(const QString &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtStringPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtLineEditFactory \brief The QtLineEditFactory class provides QLineEdit widgets for properties created by QtStringPropertyManager objects. \sa QtAbstractEditorFactory, QtStringPropertyManager */ /*! Creates a factory with the given \a parent. */ QtLineEditFactory::QtLineEditFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtLineEditFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtLineEditFactory::~QtLineEditFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtLineEditFactory::connectPropertyManager(QtStringPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QString &)), this, SLOT(slotPropertyChanged(QtProperty *, const QString &))); connect(manager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); connect(manager, SIGNAL(echoModeChanged(QtProperty*, int)), this, SLOT(slotEchoModeChanged(QtProperty *, int))); connect(manager, SIGNAL(readOnlyChanged(QtProperty*, bool)), this, SLOT(slotReadOnlyChanged(QtProperty *, bool))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtLineEditFactory::createEditor(QtStringPropertyManager *manager, QtProperty *property, QWidget *parent) { QLineEdit *editor = d_ptr->createEditor(property, parent); editor->setEchoMode((EchoMode)manager->echoMode(property)); editor->setReadOnly(manager->isReadOnly(property)); QRegExp regExp = manager->regExp(property); if (regExp.isValid()) { QValidator *validator = new QRegExpValidator(regExp, editor); editor->setValidator(validator); } editor->setText(manager->value(property)); connect(editor, SIGNAL(textChanged(const QString &)), this, SLOT(slotSetValue(const QString &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtLineEditFactory::disconnectPropertyManager(QtStringPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QString &)), this, SLOT(slotPropertyChanged(QtProperty *, const QString &))); disconnect(manager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); disconnect(manager, SIGNAL(echoModeChanged(QtProperty*,int)), this, SLOT(slotEchoModeChanged(QtProperty *, int))); disconnect(manager, SIGNAL(readOnlyChanged(QtProperty*, bool)), this, SLOT(slotReadOnlyChanged(QtProperty *, bool))); } // QtDateEditFactory class QtDateEditFactoryPrivate : public EditorFactoryPrivate { QtDateEditFactory *q_ptr; Q_DECLARE_PUBLIC(QtDateEditFactory) public: void slotPropertyChanged(QtProperty *property, const QDate &value); void slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max); void slotSetValue(const QDate &value); }; void QtDateEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QDate &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDateEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setDate(value); editor->blockSignals(false); } } void QtDateEditFactoryPrivate::slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max) { if (!m_createdEditors.contains(property)) return; QtDatePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDateEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setDateRange(min, max); editor->setDate(manager->value(property)); editor->blockSignals(false); } } void QtDateEditFactoryPrivate::slotSetValue(const QDate &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtDatePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtDateEditFactory \brief The QtDateEditFactory class provides QDateEdit widgets for properties created by QtDatePropertyManager objects. \sa QtAbstractEditorFactory, QtDatePropertyManager */ /*! Creates a factory with the given \a parent. */ QtDateEditFactory::QtDateEditFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtDateEditFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtDateEditFactory::~QtDateEditFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDateEditFactory::connectPropertyManager(QtDatePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QDate &)), this, SLOT(slotPropertyChanged(QtProperty *, const QDate &))); connect(manager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtDateEditFactory::createEditor(QtDatePropertyManager *manager, QtProperty *property, QWidget *parent) { QDateEdit *editor = d_ptr->createEditor(property, parent); editor->setCalendarPopup(true); editor->setDateRange(manager->minimum(property), manager->maximum(property)); editor->setDate(manager->value(property)); connect(editor, SIGNAL(dateChanged(const QDate &)), this, SLOT(slotSetValue(const QDate &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDateEditFactory::disconnectPropertyManager(QtDatePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QDate &)), this, SLOT(slotPropertyChanged(QtProperty *, const QDate &))); disconnect(manager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); } // QtTimeEditFactory class QtTimeEditFactoryPrivate : public EditorFactoryPrivate { QtTimeEditFactory *q_ptr; Q_DECLARE_PUBLIC(QtTimeEditFactory) public: void slotPropertyChanged(QtProperty *property, const QTime &value); void slotSetValue(const QTime &value); }; void QtTimeEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QTime &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QTimeEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setTime(value); editor->blockSignals(false); } } void QtTimeEditFactoryPrivate::slotSetValue(const QTime &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtTimePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtTimeEditFactory \brief The QtTimeEditFactory class provides QTimeEdit widgets for properties created by QtTimePropertyManager objects. \sa QtAbstractEditorFactory, QtTimePropertyManager */ /*! Creates a factory with the given \a parent. */ QtTimeEditFactory::QtTimeEditFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtTimeEditFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtTimeEditFactory::~QtTimeEditFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtTimeEditFactory::connectPropertyManager(QtTimePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QTime &)), this, SLOT(slotPropertyChanged(QtProperty *, const QTime &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtTimeEditFactory::createEditor(QtTimePropertyManager *manager, QtProperty *property, QWidget *parent) { QTimeEdit *editor = d_ptr->createEditor(property, parent); editor->setTime(manager->value(property)); connect(editor, SIGNAL(timeChanged(const QTime &)), this, SLOT(slotSetValue(const QTime &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtTimeEditFactory::disconnectPropertyManager(QtTimePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QTime &)), this, SLOT(slotPropertyChanged(QtProperty *, const QTime &))); } // QtDateTimeEditFactory class QtDateTimeEditFactoryPrivate : public EditorFactoryPrivate { QtDateTimeEditFactory *q_ptr; Q_DECLARE_PUBLIC(QtDateTimeEditFactory) public: void slotPropertyChanged(QtProperty *property, const QDateTime &value); void slotSetValue(const QDateTime &value); }; void QtDateTimeEditFactoryPrivate::slotPropertyChanged(QtProperty *property, const QDateTime &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QDateTimeEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setDateTime(value); editor->blockSignals(false); } } void QtDateTimeEditFactoryPrivate::slotSetValue(const QDateTime &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtDateTimePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtDateTimeEditFactory \brief The QtDateTimeEditFactory class provides QDateTimeEdit widgets for properties created by QtDateTimePropertyManager objects. \sa QtAbstractEditorFactory, QtDateTimePropertyManager */ /*! Creates a factory with the given \a parent. */ QtDateTimeEditFactory::QtDateTimeEditFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtDateTimeEditFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtDateTimeEditFactory::~QtDateTimeEditFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDateTimeEditFactory::connectPropertyManager(QtDateTimePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), this, SLOT(slotPropertyChanged(QtProperty *, const QDateTime &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtDateTimeEditFactory::createEditor(QtDateTimePropertyManager *manager, QtProperty *property, QWidget *parent) { QDateTimeEdit *editor = d_ptr->createEditor(property, parent); editor->setDateTime(manager->value(property)); connect(editor, SIGNAL(dateTimeChanged(const QDateTime &)), this, SLOT(slotSetValue(const QDateTime &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtDateTimeEditFactory::disconnectPropertyManager(QtDateTimePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), this, SLOT(slotPropertyChanged(QtProperty *, const QDateTime &))); } // QtKeySequenceEditorFactory class QtKeySequenceEditorFactoryPrivate : public EditorFactoryPrivate { QtKeySequenceEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtKeySequenceEditorFactory) public: void slotPropertyChanged(QtProperty *property, const QKeySequence &value); void slotSetValue(const QKeySequence &value); }; void QtKeySequenceEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QKeySequence &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QtKeySequenceEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setKeySequence(value); editor->blockSignals(false); } } void QtKeySequenceEditorFactoryPrivate::slotSetValue(const QKeySequence &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtKeySequencePropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtKeySequenceEditorFactory \brief The QtKeySequenceEditorFactory class provides editor widgets for properties created by QtKeySequencePropertyManager objects. \sa QtAbstractEditorFactory */ /*! Creates a factory with the given \a parent. */ QtKeySequenceEditorFactory::QtKeySequenceEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtKeySequenceEditorFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtKeySequenceEditorFactory::~QtKeySequenceEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtKeySequenceEditorFactory::connectPropertyManager(QtKeySequencePropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), this, SLOT(slotPropertyChanged(QtProperty *, const QKeySequence &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtKeySequenceEditorFactory::createEditor(QtKeySequencePropertyManager *manager, QtProperty *property, QWidget *parent) { QtKeySequenceEdit *editor = d_ptr->createEditor(property, parent); editor->setKeySequence(manager->value(property)); connect(editor, SIGNAL(keySequenceChanged(const QKeySequence &)), this, SLOT(slotSetValue(const QKeySequence &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtKeySequenceEditorFactory::disconnectPropertyManager(QtKeySequencePropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), this, SLOT(slotPropertyChanged(QtProperty *, const QKeySequence &))); } // QtCharEdit class QtCharEdit : public QWidget { Q_OBJECT public: QtCharEdit(QWidget *parent = 0); QChar value() const; bool eventFilter(QObject *o, QEvent *e); public Q_SLOTS: void setValue(const QChar &value); Q_SIGNALS: void valueChanged(const QChar &value); protected: void focusInEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e); void keyPressEvent(QKeyEvent *e); void keyReleaseEvent(QKeyEvent *e); void paintEvent(QPaintEvent *); bool event(QEvent *e); private slots: void slotClearChar(); private: void handleKeyEvent(QKeyEvent *e); QChar m_value; QLineEdit *m_lineEdit; }; QtCharEdit::QtCharEdit(QWidget *parent) : QWidget(parent), m_lineEdit(new QLineEdit(this)) { QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(m_lineEdit); layout->setMargin(0); m_lineEdit->installEventFilter(this); m_lineEdit->setReadOnly(true); m_lineEdit->setFocusProxy(this); setFocusPolicy(m_lineEdit->focusPolicy()); setAttribute(Qt::WA_InputMethodEnabled); } bool QtCharEdit::eventFilter(QObject *o, QEvent *e) { if (o == m_lineEdit && e->type() == QEvent::ContextMenu) { QContextMenuEvent *c = static_cast(e); QMenu *menu = m_lineEdit->createStandardContextMenu(); QList actions = menu->actions(); QListIterator itAction(actions); while (itAction.hasNext()) { QAction *action = itAction.next(); action->setShortcut(QKeySequence()); QString actionString = action->text(); const int pos = actionString.lastIndexOf(QLatin1Char('\t')); if (pos > 0) actionString = actionString.remove(pos, actionString.length() - pos); action->setText(actionString); } QAction *actionBefore = 0; if (actions.count() > 0) actionBefore = actions[0]; QAction *clearAction = new QAction(tr("Clear Char"), menu); menu->insertAction(actionBefore, clearAction); menu->insertSeparator(actionBefore); clearAction->setEnabled(!m_value.isNull()); connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearChar())); menu->exec(c->globalPos()); delete menu; e->accept(); return true; } return QWidget::eventFilter(o, e); } void QtCharEdit::slotClearChar() { if (m_value.isNull()) return; setValue(QChar()); emit valueChanged(m_value); } void QtCharEdit::handleKeyEvent(QKeyEvent *e) { const int key = e->key(); switch (key) { case Qt::Key_Control: case Qt::Key_Shift: case Qt::Key_Meta: case Qt::Key_Alt: case Qt::Key_Super_L: case Qt::Key_Return: return; default: break; } const QString text = e->text(); if (text.count() != 1) return; const QChar c = text.at(0); if (!c.isPrint()) return; if (m_value == c) return; m_value = c; const QString str = m_value.isNull() ? QString() : QString(m_value); m_lineEdit->setText(str); e->accept(); emit valueChanged(m_value); } void QtCharEdit::setValue(const QChar &value) { if (value == m_value) return; m_value = value; QString str = value.isNull() ? QString() : QString(value); m_lineEdit->setText(str); } QChar QtCharEdit::value() const { return m_value; } void QtCharEdit::focusInEvent(QFocusEvent *e) { m_lineEdit->event(e); m_lineEdit->selectAll(); QWidget::focusInEvent(e); } void QtCharEdit::focusOutEvent(QFocusEvent *e) { m_lineEdit->event(e); QWidget::focusOutEvent(e); } void QtCharEdit::keyPressEvent(QKeyEvent *e) { handleKeyEvent(e); e->accept(); } void QtCharEdit::keyReleaseEvent(QKeyEvent *e) { m_lineEdit->event(e); } void QtCharEdit::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } bool QtCharEdit::event(QEvent *e) { switch(e->type()) { case QEvent::Shortcut: case QEvent::ShortcutOverride: case QEvent::KeyRelease: e->accept(); return true; default: break; } return QWidget::event(e); } // QtCharEditorFactory class QtCharEditorFactoryPrivate : public EditorFactoryPrivate { QtCharEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtCharEditorFactory) public: void slotPropertyChanged(QtProperty *property, const QChar &value); void slotSetValue(const QChar &value); }; void QtCharEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QChar &value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QtCharEdit *editor = itEditor.next(); editor->blockSignals(true); editor->setValue(value); editor->blockSignals(false); } } void QtCharEditorFactoryPrivate::slotSetValue(const QChar &value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtCharPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtCharEditorFactory \brief The QtCharEditorFactory class provides editor widgets for properties created by QtCharPropertyManager objects. \sa QtAbstractEditorFactory */ /*! Creates a factory with the given \a parent. */ QtCharEditorFactory::QtCharEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtCharEditorFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtCharEditorFactory::~QtCharEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCharEditorFactory::connectPropertyManager(QtCharPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QChar &)), this, SLOT(slotPropertyChanged(QtProperty *, const QChar &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtCharEditorFactory::createEditor(QtCharPropertyManager *manager, QtProperty *property, QWidget *parent) { QtCharEdit *editor = d_ptr->createEditor(property, parent); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(const QChar &)), this, SLOT(slotSetValue(const QChar &))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCharEditorFactory::disconnectPropertyManager(QtCharPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QChar &)), this, SLOT(slotPropertyChanged(QtProperty *, const QChar &))); } // QtEnumEditorFactory class QtEnumEditorFactoryPrivate : public EditorFactoryPrivate { QtEnumEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtEnumEditorFactory) public: void slotPropertyChanged(QtProperty *property, int value); void slotEnumNamesChanged(QtProperty *property, const QStringList &); void slotEnumIconsChanged(QtProperty *property, const QMap &); void slotSetValue(int value); }; void QtEnumEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, int value) { if (!m_createdEditors.contains(property)) return; QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QComboBox *editor = itEditor.next(); editor->blockSignals(true); editor->setCurrentIndex(value); editor->blockSignals(false); } } void QtEnumEditorFactoryPrivate::slotEnumNamesChanged(QtProperty *property, const QStringList &enumNames) { if (!m_createdEditors.contains(property)) return; QtEnumPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; QMap enumIcons = manager->enumIcons(property); QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QComboBox *editor = itEditor.next(); editor->blockSignals(true); editor->clear(); editor->addItems(enumNames); const int nameCount = enumNames.count(); for (int i = 0; i < nameCount; i++) editor->setItemIcon(i, enumIcons.value(i)); editor->setCurrentIndex(manager->value(property)); editor->blockSignals(false); } } void QtEnumEditorFactoryPrivate::slotEnumIconsChanged(QtProperty *property, const QMap &enumIcons) { if (!m_createdEditors.contains(property)) return; QtEnumPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; const QStringList enumNames = manager->enumNames(property); QListIterator itEditor(m_createdEditors[property]); while (itEditor.hasNext()) { QComboBox *editor = itEditor.next(); editor->blockSignals(true); const int nameCount = enumNames.count(); for (int i = 0; i < nameCount; i++) editor->setItemIcon(i, enumIcons.value(i)); editor->setCurrentIndex(manager->value(property)); editor->blockSignals(false); } } void QtEnumEditorFactoryPrivate::slotSetValue(int value) { QObject *object = q_ptr->sender(); const QMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (QMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtEnumPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtEnumEditorFactory \brief The QtEnumEditorFactory class provides QComboBox widgets for properties created by QtEnumPropertyManager objects. \sa QtAbstractEditorFactory, QtEnumPropertyManager */ /*! Creates a factory with the given \a parent. */ QtEnumEditorFactory::QtEnumEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtEnumEditorFactoryPrivate(); d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtEnumEditorFactory::~QtEnumEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtEnumEditorFactory::connectPropertyManager(QtEnumPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); connect(manager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtEnumEditorFactory::createEditor(QtEnumPropertyManager *manager, QtProperty *property, QWidget *parent) { QComboBox *editor = d_ptr->createEditor(property, parent); editor->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); editor->setMinimumContentsLength(1); editor->view()->setTextElideMode(Qt::ElideRight); QStringList enumNames = manager->enumNames(property); editor->addItems(enumNames); QMap enumIcons = manager->enumIcons(property); const int enumNamesCount = enumNames.count(); for (int i = 0; i < enumNamesCount; i++) editor->setItemIcon(i, enumIcons.value(i)); editor->setCurrentIndex(manager->value(property)); connect(editor, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetValue(int))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtEnumEditorFactory::disconnectPropertyManager(QtEnumPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotPropertyChanged(QtProperty *, int))); disconnect(manager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); } // QtCursorEditorFactory Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase) class QtCursorEditorFactoryPrivate { QtCursorEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtCursorEditorFactory) public: QtCursorEditorFactoryPrivate(); void slotPropertyChanged(QtProperty *property, const QCursor &cursor); void slotEnumChanged(QtProperty *property, int value); void slotEditorDestroyed(QObject *object); QtEnumEditorFactory *m_enumEditorFactory; QtEnumPropertyManager *m_enumPropertyManager; QMap m_propertyToEnum; QMap m_enumToProperty; QMap > m_enumToEditors; QMap m_editorToEnum; bool m_updatingEnum; }; QtCursorEditorFactoryPrivate::QtCursorEditorFactoryPrivate() : m_updatingEnum(false) { } void QtCursorEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QCursor &cursor) { // update enum property QtProperty *enumProp = m_propertyToEnum.value(property); if (!enumProp) return; m_updatingEnum = true; m_enumPropertyManager->setValue(enumProp, cursorDatabase()->cursorToValue(cursor)); m_updatingEnum = false; } void QtCursorEditorFactoryPrivate::slotEnumChanged(QtProperty *property, int value) { if (m_updatingEnum) return; // update cursor property QtProperty *prop = m_enumToProperty.value(property); if (!prop) return; QtCursorPropertyManager *cursorManager = q_ptr->propertyManager(prop); if (!cursorManager) return; #ifndef QT_NO_CURSOR cursorManager->setValue(prop, QCursor(cursorDatabase()->valueToCursor(value))); #endif } void QtCursorEditorFactoryPrivate::slotEditorDestroyed(QObject *object) { // remove from m_editorToEnum map; // remove from m_enumToEditors map; // if m_enumToEditors doesn't contains more editors delete enum property; const QMap::ConstIterator ecend = m_editorToEnum.constEnd(); for (QMap::ConstIterator itEditor = m_editorToEnum.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QWidget *editor = itEditor.key(); QtProperty *enumProp = itEditor.value(); m_editorToEnum.remove(editor); m_enumToEditors[enumProp].removeAll(editor); if (m_enumToEditors[enumProp].isEmpty()) { m_enumToEditors.remove(enumProp); QtProperty *property = m_enumToProperty.value(enumProp); m_enumToProperty.remove(enumProp); m_propertyToEnum.remove(property); delete enumProp; } return; } } /*! \class QtCursorEditorFactory \brief The QtCursorEditorFactory class provides QComboBox widgets for properties created by QtCursorPropertyManager objects. \sa QtAbstractEditorFactory, QtCursorPropertyManager */ /*! Creates a factory with the given \a parent. */ QtCursorEditorFactory::QtCursorEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtCursorEditorFactoryPrivate(); d_ptr->q_ptr = this; d_ptr->m_enumEditorFactory = new QtEnumEditorFactory(this); d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotEnumChanged(QtProperty *, int))); d_ptr->m_enumEditorFactory->addPropertyManager(d_ptr->m_enumPropertyManager); } /*! Destroys this factory, and all the widgets it has created. */ QtCursorEditorFactory::~QtCursorEditorFactory() { delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCursorEditorFactory::connectPropertyManager(QtCursorPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), this, SLOT(slotPropertyChanged(QtProperty *, const QCursor &))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtCursorEditorFactory::createEditor(QtCursorPropertyManager *manager, QtProperty *property, QWidget *parent) { QtProperty *enumProp = 0; if (d_ptr->m_propertyToEnum.contains(property)) { enumProp = d_ptr->m_propertyToEnum[property]; } else { enumProp = d_ptr->m_enumPropertyManager->addProperty(property->propertyName()); d_ptr->m_enumPropertyManager->setEnumNames(enumProp, cursorDatabase()->cursorShapeNames()); d_ptr->m_enumPropertyManager->setEnumIcons(enumProp, cursorDatabase()->cursorShapeIcons()); #ifndef QT_NO_CURSOR d_ptr->m_enumPropertyManager->setValue(enumProp, cursorDatabase()->cursorToValue(manager->value(property))); #endif d_ptr->m_propertyToEnum[property] = enumProp; d_ptr->m_enumToProperty[enumProp] = property; } QtAbstractEditorFactoryBase *af = d_ptr->m_enumEditorFactory; QWidget *editor = af->createEditor(enumProp, parent); d_ptr->m_enumToEditors[enumProp].append(editor); d_ptr->m_editorToEnum[editor] = enumProp; connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtCursorEditorFactory::disconnectPropertyManager(QtCursorPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), this, SLOT(slotPropertyChanged(QtProperty *, const QCursor &))); } // QtColorEditWidget class QtColorEditWidget : public QWidget { Q_OBJECT public: QtColorEditWidget(QWidget *parent); bool eventFilter(QObject *obj, QEvent *ev); public Q_SLOTS: void setValue(const QColor &value); Q_SIGNALS: void valueChanged(const QColor &value); protected: void paintEvent(QPaintEvent *); private Q_SLOTS: void buttonClicked(); private: QColor m_color; QLabel *m_pixmapLabel; QLabel *m_label; QToolButton *m_button; }; QtColorEditWidget::QtColorEditWidget(QWidget *parent) : QWidget(parent), m_pixmapLabel(new QLabel), m_label(new QLabel), m_button(new QToolButton) { QHBoxLayout *lt = new QHBoxLayout(this); setupTreeViewEditorMargin(lt); lt->setSpacing(0); lt->addWidget(m_pixmapLabel); lt->addWidget(m_label); lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); m_button->setFixedWidth(20); setFocusProxy(m_button); setFocusPolicy(m_button->focusPolicy()); m_button->setText(tr("...")); m_button->installEventFilter(this); connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); lt->addWidget(m_button); m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::brushValuePixmap(QBrush(m_color))); m_label->setText(QtPropertyBrowserUtils::colorValueText(m_color)); } void QtColorEditWidget::setValue(const QColor &c) { if (m_color != c) { m_color = c; m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::brushValuePixmap(QBrush(c))); m_label->setText(QtPropertyBrowserUtils::colorValueText(c)); } } void QtColorEditWidget::buttonClicked() { bool ok = false; QRgb oldRgba = m_color.rgba(); QRgb newRgba = QColorDialog::getRgba(oldRgba, &ok, this); if (ok && newRgba != oldRgba) { setValue(QColor::fromRgba(newRgba)); emit valueChanged(m_color); } } bool QtColorEditWidget::eventFilter(QObject *obj, QEvent *ev) { if (obj == m_button) { switch (ev->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate switch (static_cast(ev)->key()) { case Qt::Key_Escape: case Qt::Key_Enter: case Qt::Key_Return: ev->ignore(); return true; default: break; } } break; default: break; } } return QWidget::eventFilter(obj, ev); } void QtColorEditWidget::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } // QtColorEditorFactoryPrivate class QtColorEditorFactoryPrivate : public EditorFactoryPrivate { QtColorEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtColorEditorFactory) public: void slotPropertyChanged(QtProperty *property, const QColor &value); void slotSetValue(const QColor &value); }; void QtColorEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QColor &value) { const PropertyToEditorListMap::iterator it = m_createdEditors.find(property); if (it == m_createdEditors.end()) return; QListIterator itEditor(it.value()); while (itEditor.hasNext()) itEditor.next()->setValue(value); } void QtColorEditorFactoryPrivate::slotSetValue(const QColor &value) { QObject *object = q_ptr->sender(); const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtColorPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtColorEditorFactory \brief The QtColorEditorFactory class provides color editing for properties created by QtColorPropertyManager objects. \sa QtAbstractEditorFactory, QtColorPropertyManager */ /*! Creates a factory with the given \a parent. */ QtColorEditorFactory::QtColorEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent), d_ptr(new QtColorEditorFactoryPrivate()) { d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtColorEditorFactory::~QtColorEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtColorEditorFactory::connectPropertyManager(QtColorPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty*,QColor)), this, SLOT(slotPropertyChanged(QtProperty*,QColor))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtColorEditorFactory::createEditor(QtColorPropertyManager *manager, QtProperty *property, QWidget *parent) { QtColorEditWidget *editor = d_ptr->createEditor(property, parent); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(QColor)), this, SLOT(slotSetValue(QColor))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtColorEditorFactory::disconnectPropertyManager(QtColorPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty*,QColor)), this, SLOT(slotPropertyChanged(QtProperty*,QColor))); } // QtFontEditWidget class QtFontEditWidget : public QWidget { Q_OBJECT public: QtFontEditWidget(QWidget *parent); bool eventFilter(QObject *obj, QEvent *ev); public Q_SLOTS: void setValue(const QFont &value); Q_SIGNALS: void valueChanged(const QFont &value); protected: void paintEvent(QPaintEvent *); private Q_SLOTS: void buttonClicked(); private: QFont m_font; QLabel *m_pixmapLabel; QLabel *m_label; QToolButton *m_button; }; QtFontEditWidget::QtFontEditWidget(QWidget *parent) : QWidget(parent), m_pixmapLabel(new QLabel), m_label(new QLabel), m_button(new QToolButton) { QHBoxLayout *lt = new QHBoxLayout(this); setupTreeViewEditorMargin(lt); lt->setSpacing(0); lt->addWidget(m_pixmapLabel); lt->addWidget(m_label); lt->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); m_button->setFixedWidth(20); setFocusProxy(m_button); setFocusPolicy(m_button->focusPolicy()); m_button->setText(tr("...")); m_button->installEventFilter(this); connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); lt->addWidget(m_button); m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::fontValuePixmap(m_font)); m_label->setText(QtPropertyBrowserUtils::fontValueText(m_font)); } void QtFontEditWidget::setValue(const QFont &f) { if (m_font != f) { m_font = f; m_pixmapLabel->setPixmap(QtPropertyBrowserUtils::fontValuePixmap(f)); m_label->setText(QtPropertyBrowserUtils::fontValueText(f)); } } void QtFontEditWidget::buttonClicked() { bool ok = false; QFont newFont = QFontDialog::getFont(&ok, m_font, this, tr("Select Font")); if (ok && newFont != m_font) { QFont f = m_font; // prevent mask for unchanged attributes, don't change other attributes (like kerning, etc...) if (m_font.family() != newFont.family()) f.setFamily(newFont.family()); if (m_font.pointSize() != newFont.pointSize()) f.setPointSize(newFont.pointSize()); if (m_font.bold() != newFont.bold()) f.setBold(newFont.bold()); if (m_font.italic() != newFont.italic()) f.setItalic(newFont.italic()); if (m_font.underline() != newFont.underline()) f.setUnderline(newFont.underline()); if (m_font.strikeOut() != newFont.strikeOut()) f.setStrikeOut(newFont.strikeOut()); setValue(f); emit valueChanged(m_font); } } bool QtFontEditWidget::eventFilter(QObject *obj, QEvent *ev) { if (obj == m_button) { switch (ev->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: { // Prevent the QToolButton from handling Enter/Escape meant control the delegate switch (static_cast(ev)->key()) { case Qt::Key_Escape: case Qt::Key_Enter: case Qt::Key_Return: ev->ignore(); return true; default: break; } } break; default: break; } } return QWidget::eventFilter(obj, ev); } void QtFontEditWidget::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } // QtFontEditorFactoryPrivate class QtFontEditorFactoryPrivate : public EditorFactoryPrivate { QtFontEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtFontEditorFactory) public: void slotPropertyChanged(QtProperty *property, const QFont &value); void slotSetValue(const QFont &value); }; void QtFontEditorFactoryPrivate::slotPropertyChanged(QtProperty *property, const QFont &value) { const PropertyToEditorListMap::iterator it = m_createdEditors.find(property); if (it == m_createdEditors.end()) return; QListIterator itEditor(it.value()); while (itEditor.hasNext()) itEditor.next()->setValue(value); } void QtFontEditorFactoryPrivate::slotSetValue(const QFont &value) { QObject *object = q_ptr->sender(); const EditorToPropertyMap::ConstIterator ecend = m_editorToProperty.constEnd(); for (EditorToPropertyMap::ConstIterator itEditor = m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor) if (itEditor.key() == object) { QtProperty *property = itEditor.value(); QtFontPropertyManager *manager = q_ptr->propertyManager(property); if (!manager) return; manager->setValue(property, value); return; } } /*! \class QtFontEditorFactory \brief The QtFontEditorFactory class provides font editing for properties created by QtFontPropertyManager objects. \sa QtAbstractEditorFactory, QtFontPropertyManager */ /*! Creates a factory with the given \a parent. */ QtFontEditorFactory::QtFontEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent), d_ptr(new QtFontEditorFactoryPrivate()) { d_ptr->q_ptr = this; } /*! Destroys this factory, and all the widgets it has created. */ QtFontEditorFactory::~QtFontEditorFactory() { qDeleteAll(d_ptr->m_editorToProperty.keys()); delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtFontEditorFactory::connectPropertyManager(QtFontPropertyManager *manager) { connect(manager, SIGNAL(valueChanged(QtProperty*,QFont)), this, SLOT(slotPropertyChanged(QtProperty*,QFont))); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtFontEditorFactory::createEditor(QtFontPropertyManager *manager, QtProperty *property, QWidget *parent) { QtFontEditWidget *editor = d_ptr->createEditor(property, parent); editor->setValue(manager->value(property)); connect(editor, SIGNAL(valueChanged(QFont)), this, SLOT(slotSetValue(QFont))); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); return editor; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtFontEditorFactory::disconnectPropertyManager(QtFontPropertyManager *manager) { disconnect(manager, SIGNAL(valueChanged(QtProperty*,QFont)), this, SLOT(slotPropertyChanged(QtProperty*,QFont))); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qteditorfactory.cpp" #include "qteditorfactory.moc" tiled-0.14.2/src/qtpropertybrowser/src/qteditorfactory.h000066400000000000000000000400131260670167100235120ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTEDITORFACTORY_H #define QTEDITORFACTORY_H #include "qtpropertymanager.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtSpinBoxFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSpinBoxFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtSpinBoxFactory(QObject *parent = 0); ~QtSpinBoxFactory(); protected: void connectPropertyManager(QtIntPropertyManager *manager); QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtIntPropertyManager *manager); private: QtSpinBoxFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSpinBoxFactory) Q_DISABLE_COPY(QtSpinBoxFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotReadOnlyChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtSliderFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSliderFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtSliderFactory(QObject *parent = 0); ~QtSliderFactory(); protected: void connectPropertyManager(QtIntPropertyManager *manager); QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtIntPropertyManager *manager); private: QtSliderFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSliderFactory) Q_DISABLE_COPY(QtSliderFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtScrollBarFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtScrollBarFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtScrollBarFactory(QObject *parent = 0); ~QtScrollBarFactory(); protected: void connectPropertyManager(QtIntPropertyManager *manager); QWidget *createEditor(QtIntPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtIntPropertyManager *manager); private: QtScrollBarFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtScrollBarFactory) Q_DISABLE_COPY(QtScrollBarFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtCheckBoxFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCheckBoxFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtCheckBoxFactory(QObject *parent = 0); ~QtCheckBoxFactory(); protected: void connectPropertyManager(QtBoolPropertyManager *manager); QWidget *createEditor(QtBoolPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtBoolPropertyManager *manager); private: QtCheckBoxFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCheckBoxFactory) Q_DISABLE_COPY(QtCheckBoxFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotTextVisibleChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(bool)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtDoubleSpinBoxFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDoubleSpinBoxFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtDoubleSpinBoxFactory(QObject *parent = 0); ~QtDoubleSpinBoxFactory(); protected: void connectPropertyManager(QtDoublePropertyManager *manager); QWidget *createEditor(QtDoublePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtDoublePropertyManager *manager); private: QtDoubleSpinBoxFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDoubleSpinBoxFactory) Q_DISABLE_COPY(QtDoubleSpinBoxFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, double, double)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotDecimalsChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotReadOnlyChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(double)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtLineEditFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtLineEditFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtLineEditFactory(QObject *parent = 0); ~QtLineEditFactory(); protected: void connectPropertyManager(QtStringPropertyManager *manager); QWidget *createEditor(QtStringPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtStringPropertyManager *manager); private: QtLineEditFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtLineEditFactory) Q_DISABLE_COPY(QtLineEditFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QString &)) Q_PRIVATE_SLOT(d_func(), void slotRegExpChanged(QtProperty *, const QRegExp &)) Q_PRIVATE_SLOT(d_func(), void slotEchoModeChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotReadOnlyChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QString &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtDateEditFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDateEditFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtDateEditFactory(QObject *parent = 0); ~QtDateEditFactory(); protected: void connectPropertyManager(QtDatePropertyManager *manager); QWidget *createEditor(QtDatePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtDatePropertyManager *manager); private: QtDateEditFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDateEditFactory) Q_DISABLE_COPY(QtDateEditFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QDate &, const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtTimeEditFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtTimeEditFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtTimeEditFactory(QObject *parent = 0); ~QtTimeEditFactory(); protected: void connectPropertyManager(QtTimePropertyManager *manager); QWidget *createEditor(QtTimePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtTimePropertyManager *manager); private: QtTimeEditFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtTimeEditFactory) Q_DISABLE_COPY(QtTimeEditFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QTime &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QTime &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtDateTimeEditFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDateTimeEditFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtDateTimeEditFactory(QObject *parent = 0); ~QtDateTimeEditFactory(); protected: void connectPropertyManager(QtDateTimePropertyManager *manager); QWidget *createEditor(QtDateTimePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtDateTimePropertyManager *manager); private: QtDateTimeEditFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDateTimeEditFactory) Q_DISABLE_COPY(QtDateTimeEditFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QDateTime &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QDateTime &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtKeySequenceEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtKeySequenceEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtKeySequenceEditorFactory(QObject *parent = 0); ~QtKeySequenceEditorFactory(); protected: void connectPropertyManager(QtKeySequencePropertyManager *manager); QWidget *createEditor(QtKeySequencePropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtKeySequencePropertyManager *manager); private: QtKeySequenceEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtKeySequenceEditorFactory) Q_DISABLE_COPY(QtKeySequenceEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QKeySequence &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QKeySequence &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtCharEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCharEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtCharEditorFactory(QObject *parent = 0); ~QtCharEditorFactory(); protected: void connectPropertyManager(QtCharPropertyManager *manager); QWidget *createEditor(QtCharPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtCharPropertyManager *manager); private: QtCharEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCharEditorFactory) Q_DISABLE_COPY(QtCharEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QChar &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QChar &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtEnumEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtEnumEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtEnumEditorFactory(QObject *parent = 0); ~QtEnumEditorFactory(); protected: void connectPropertyManager(QtEnumPropertyManager *manager); QWidget *createEditor(QtEnumPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtEnumPropertyManager *manager); private: QtEnumEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtEnumEditorFactory) Q_DISABLE_COPY(QtEnumEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotEnumNamesChanged(QtProperty *, const QStringList &)) Q_PRIVATE_SLOT(d_func(), void slotEnumIconsChanged(QtProperty *, const QMap &)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtCursorEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCursorEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtCursorEditorFactory(QObject *parent = 0); ~QtCursorEditorFactory(); protected: void connectPropertyManager(QtCursorPropertyManager *manager); QWidget *createEditor(QtCursorPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtCursorPropertyManager *manager); private: QtCursorEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCursorEditorFactory) Q_DISABLE_COPY(QtCursorEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QCursor &)) Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) }; class QtColorEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtColorEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtColorEditorFactory(QObject *parent = 0); ~QtColorEditorFactory(); protected: void connectPropertyManager(QtColorPropertyManager *manager); QWidget *createEditor(QtColorPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtColorPropertyManager *manager); private: QtColorEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtColorEditorFactory) Q_DISABLE_COPY(QtColorEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QColor &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QColor &)) }; class QtFontEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtFontEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtFontEditorFactory(QObject *parent = 0); ~QtFontEditorFactory(); protected: void connectPropertyManager(QtFontPropertyManager *manager); QWidget *createEditor(QtFontPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtFontPropertyManager *manager); private: QtFontEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtFontEditorFactory) Q_DISABLE_COPY(QtFontEditorFactory) Q_PRIVATE_SLOT(d_func(), void slotPropertyChanged(QtProperty *, const QFont &)) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed(QObject *)) Q_PRIVATE_SLOT(d_func(), void slotSetValue(const QFont &)) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif tiled-0.14.2/src/qtpropertybrowser/src/qtgroupboxpropertybrowser.cpp000066400000000000000000000423631260670167100262570ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtgroupboxpropertybrowser.h" #include #include #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtGroupBoxPropertyBrowserPrivate { QtGroupBoxPropertyBrowser *q_ptr; Q_DECLARE_PUBLIC(QtGroupBoxPropertyBrowser) public: void init(QWidget *parent); void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); void propertyRemoved(QtBrowserItem *index); void propertyChanged(QtBrowserItem *index); QWidget *createEditor(QtProperty *property, QWidget *parent) const { return q_ptr->createEditor(property, parent); } void slotEditorDestroyed(); void slotUpdate(); struct WidgetItem { WidgetItem() : widget(0), label(0), widgetLabel(0), groupBox(0), layout(0), line(0), parent(0) { } QWidget *widget; // can be null QLabel *label; QLabel *widgetLabel; QGroupBox *groupBox; QGridLayout *layout; QFrame *line; WidgetItem *parent; QList children; }; private: void updateLater(); void updateItem(WidgetItem *item); void insertRow(QGridLayout *layout, int row) const; void removeRow(QGridLayout *layout, int row) const; bool hasHeader(WidgetItem *item) const; QMap m_indexToItem; QMap m_itemToIndex; QMap m_widgetToItem; QGridLayout *m_mainLayout; QList m_children; QList m_recreateQueue; }; void QtGroupBoxPropertyBrowserPrivate::init(QWidget *parent) { m_mainLayout = new QGridLayout(); parent->setLayout(m_mainLayout); QLayoutItem *item = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding); m_mainLayout->addItem(item, 0, 0); } void QtGroupBoxPropertyBrowserPrivate::slotEditorDestroyed() { QWidget *editor = qobject_cast(q_ptr->sender()); if (!editor) return; if (!m_widgetToItem.contains(editor)) return; m_widgetToItem[editor]->widget = 0; m_widgetToItem.remove(editor); } void QtGroupBoxPropertyBrowserPrivate::slotUpdate() { QListIterator itItem(m_recreateQueue); while (itItem.hasNext()) { WidgetItem *item = itItem.next(); WidgetItem *par = item->parent; QWidget *w = 0; QGridLayout *l = 0; int oldRow = -1; if (!par) { w = q_ptr; l = m_mainLayout; oldRow = m_children.indexOf(item); } else { w = par->groupBox; l = par->layout; oldRow = par->children.indexOf(item); if (hasHeader(par)) oldRow += 2; } if (item->widget) { item->widget->setParent(w); } else if (item->widgetLabel) { item->widgetLabel->setParent(w); } else { item->widgetLabel = new QLabel(w); item->widgetLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); item->widgetLabel->setTextFormat(Qt::PlainText); } int span = 1; if (item->widget) l->addWidget(item->widget, oldRow, 1, 1, 1); else if (item->widgetLabel) l->addWidget(item->widgetLabel, oldRow, 1, 1, 1); else span = 2; item->label = new QLabel(w); item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); l->addWidget(item->label, oldRow, 0, 1, span); updateItem(item); } m_recreateQueue.clear(); } void QtGroupBoxPropertyBrowserPrivate::updateLater() { QTimer::singleShot(0, q_ptr, SLOT(slotUpdate())); } void QtGroupBoxPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) { WidgetItem *afterItem = m_indexToItem.value(afterIndex); WidgetItem *parentItem = m_indexToItem.value(index->parent()); WidgetItem *newItem = new WidgetItem(); newItem->parent = parentItem; QGridLayout *layout = 0; QWidget *parentWidget = 0; int row = -1; if (!afterItem) { row = 0; if (parentItem) parentItem->children.insert(0, newItem); else m_children.insert(0, newItem); } else { if (parentItem) { row = parentItem->children.indexOf(afterItem) + 1; parentItem->children.insert(row, newItem); } else { row = m_children.indexOf(afterItem) + 1; m_children.insert(row, newItem); } } if (parentItem && hasHeader(parentItem)) row += 2; if (!parentItem) { layout = m_mainLayout; parentWidget = q_ptr;; } else { if (!parentItem->groupBox) { m_recreateQueue.removeAll(parentItem); WidgetItem *par = parentItem->parent; QWidget *w = 0; QGridLayout *l = 0; int oldRow = -1; if (!par) { w = q_ptr; l = m_mainLayout; oldRow = m_children.indexOf(parentItem); } else { w = par->groupBox; l = par->layout; oldRow = par->children.indexOf(parentItem); if (hasHeader(par)) oldRow += 2; } parentItem->groupBox = new QGroupBox(w); parentItem->layout = new QGridLayout(); parentItem->groupBox->setLayout(parentItem->layout); if (parentItem->label) { l->removeWidget(parentItem->label); delete parentItem->label; parentItem->label = 0; } if (parentItem->widget) { l->removeWidget(parentItem->widget); parentItem->widget->setParent(parentItem->groupBox); parentItem->layout->addWidget(parentItem->widget, 0, 0, 1, 2); parentItem->line = new QFrame(parentItem->groupBox); } else if (parentItem->widgetLabel) { l->removeWidget(parentItem->widgetLabel); delete parentItem->widgetLabel; parentItem->widgetLabel = 0; } if (parentItem->line) { parentItem->line->setFrameShape(QFrame::HLine); parentItem->line->setFrameShadow(QFrame::Sunken); parentItem->layout->addWidget(parentItem->line, 1, 0, 1, 2); } l->addWidget(parentItem->groupBox, oldRow, 0, 1, 2); updateItem(parentItem); } layout = parentItem->layout; parentWidget = parentItem->groupBox; } newItem->label = new QLabel(parentWidget); newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); newItem->widget = createEditor(index->property(), parentWidget); if (!newItem->widget) { newItem->widgetLabel = new QLabel(parentWidget); newItem->widgetLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); newItem->widgetLabel->setTextFormat(Qt::PlainText); } else { QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed())); m_widgetToItem[newItem->widget] = newItem; } insertRow(layout, row); int span = 1; if (newItem->widget) layout->addWidget(newItem->widget, row, 1); else if (newItem->widgetLabel) layout->addWidget(newItem->widgetLabel, row, 1); else span = 2; layout->addWidget(newItem->label, row, 0, 1, span); m_itemToIndex[newItem] = index; m_indexToItem[index] = newItem; updateItem(newItem); } void QtGroupBoxPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) { WidgetItem *item = m_indexToItem.value(index); m_indexToItem.remove(index); m_itemToIndex.remove(item); WidgetItem *parentItem = item->parent; int row = -1; if (parentItem) { row = parentItem->children.indexOf(item); parentItem->children.removeAt(row); if (hasHeader(parentItem)) row += 2; } else { row = m_children.indexOf(item); m_children.removeAt(row); } if (item->widget) delete item->widget; if (item->label) delete item->label; if (item->widgetLabel) delete item->widgetLabel; if (item->groupBox) delete item->groupBox; if (!parentItem) { removeRow(m_mainLayout, row); } else if (parentItem->children.count() != 0) { removeRow(parentItem->layout, row); } else { WidgetItem *par = parentItem->parent; QGridLayout *l = 0; int oldRow = -1; if (!par) { l = m_mainLayout; oldRow = m_children.indexOf(parentItem); } else { l = par->layout; oldRow = par->children.indexOf(parentItem); if (hasHeader(par)) oldRow += 2; } if (parentItem->widget) { parentItem->widget->hide(); parentItem->widget->setParent(0); } else if (parentItem->widgetLabel) { parentItem->widgetLabel->hide(); parentItem->widgetLabel->setParent(0); } else { //parentItem->widgetLabel = new QLabel(w); } l->removeWidget(parentItem->groupBox); delete parentItem->groupBox; parentItem->groupBox = 0; parentItem->line = 0; parentItem->layout = 0; if (!m_recreateQueue.contains(parentItem)) m_recreateQueue.append(parentItem); updateLater(); } m_recreateQueue.removeAll(item); delete item; } void QtGroupBoxPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const { QMap itemToPos; int idx = 0; while (idx < layout->count()) { int r, c, rs, cs; layout->getItemPosition(idx, &r, &c, &rs, &cs); if (r >= row) { itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs); } else { idx++; } } const QMap::ConstIterator icend = itemToPos.constEnd(); for (QMap::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { const QRect r = it.value(); layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); } } void QtGroupBoxPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const { QMap itemToPos; int idx = 0; while (idx < layout->count()) { int r, c, rs, cs; layout->getItemPosition(idx, &r, &c, &rs, &cs); if (r > row) { itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs); } else { idx++; } } const QMap::ConstIterator icend = itemToPos.constEnd(); for (QMap::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) { const QRect r = it.value(); layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height()); } } bool QtGroupBoxPropertyBrowserPrivate::hasHeader(WidgetItem *item) const { if (item->widget) return true; return false; } void QtGroupBoxPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) { WidgetItem *item = m_indexToItem.value(index); updateItem(item); } void QtGroupBoxPropertyBrowserPrivate::updateItem(WidgetItem *item) { QtProperty *property = m_itemToIndex[item]->property(); if (item->groupBox) { QFont font = item->groupBox->font(); font.setUnderline(property->isModified()); item->groupBox->setFont(font); item->groupBox->setTitle(property->propertyName()); item->groupBox->setToolTip(property->toolTip()); item->groupBox->setStatusTip(property->statusTip()); item->groupBox->setWhatsThis(property->whatsThis()); item->groupBox->setEnabled(property->isEnabled()); } if (item->label) { QFont font = item->label->font(); font.setUnderline(property->isModified()); item->label->setFont(font); item->label->setText(property->propertyName()); item->label->setToolTip(property->toolTip()); item->label->setStatusTip(property->statusTip()); item->label->setWhatsThis(property->whatsThis()); item->label->setEnabled(property->isEnabled()); } if (item->widgetLabel) { QFont font = item->widgetLabel->font(); font.setUnderline(false); item->widgetLabel->setFont(font); item->widgetLabel->setText(property->valueText()); item->widgetLabel->setToolTip(property->valueText()); item->widgetLabel->setEnabled(property->isEnabled()); } if (item->widget) { QFont font = item->widget->font(); font.setUnderline(false); item->widget->setFont(font); item->widget->setEnabled(property->isEnabled()); item->widget->setToolTip(property->valueText()); } //item->setIcon(1, property->valueIcon()); } /*! \class QtGroupBoxPropertyBrowser \brief The QtGroupBoxPropertyBrowser class provides a QGroupBox based property browser. A property browser is a widget that enables the user to edit a given set of properties. Each property is represented by a label specifying the property's name, and an editing widget (e.g. a line edit or a combobox) holding its value. A property can have zero or more subproperties. QtGroupBoxPropertyBrowser provides group boxes for all nested properties, i.e. subproperties are enclosed by a group box with the parent property's name as its title. For example: \image qtgroupboxpropertybrowser.png Use the QtAbstractPropertyBrowser API to add, insert and remove properties from an instance of the QtGroupBoxPropertyBrowser class. The properties themselves are created and managed by implementations of the QtAbstractPropertyManager class. \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser */ /*! Creates a property browser with the given \a parent. */ QtGroupBoxPropertyBrowser::QtGroupBoxPropertyBrowser(QWidget *parent) : QtAbstractPropertyBrowser(parent) { d_ptr = new QtGroupBoxPropertyBrowserPrivate; d_ptr->q_ptr = this; d_ptr->init(this); } /*! Destroys this property browser. Note that the properties that were inserted into this browser are \e not destroyed since they may still be used in other browsers. The properties are owned by the manager that created them. \sa QtProperty, QtAbstractPropertyManager */ QtGroupBoxPropertyBrowser::~QtGroupBoxPropertyBrowser() { const QMap::ConstIterator icend = d_ptr->m_itemToIndex.constEnd(); for (QMap::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it) delete it.key(); delete d_ptr; } /*! \reimp */ void QtGroupBoxPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) { d_ptr->propertyInserted(item, afterItem); } /*! \reimp */ void QtGroupBoxPropertyBrowser::itemRemoved(QtBrowserItem *item) { d_ptr->propertyRemoved(item); } /*! \reimp */ void QtGroupBoxPropertyBrowser::itemChanged(QtBrowserItem *item) { d_ptr->propertyChanged(item); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtgroupboxpropertybrowser.cpp" tiled-0.14.2/src/qtpropertybrowser/src/qtgroupboxpropertybrowser.h000066400000000000000000000055351260670167100257240ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTGROUPBOXPROPERTYBROWSER_H #define QTGROUPBOXPROPERTYBROWSER_H #include "qtpropertybrowser.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtGroupBoxPropertyBrowserPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtGroupBoxPropertyBrowser : public QtAbstractPropertyBrowser { Q_OBJECT public: QtGroupBoxPropertyBrowser(QWidget *parent = 0); ~QtGroupBoxPropertyBrowser(); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); virtual void itemRemoved(QtBrowserItem *item); virtual void itemChanged(QtBrowserItem *item); private: QtGroupBoxPropertyBrowserPrivate *d_ptr; Q_DECLARE_PRIVATE(QtGroupBoxPropertyBrowser) Q_DISABLE_COPY(QtGroupBoxPropertyBrowser) Q_PRIVATE_SLOT(d_func(), void slotUpdate()) Q_PRIVATE_SLOT(d_func(), void slotEditorDestroyed()) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif tiled-0.14.2/src/qtpropertybrowser/src/qtpropertybrowser.cpp000066400000000000000000001776471260670167100245070ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtpropertybrowser.h" #include #include #include #include #if defined(Q_CC_MSVC) # pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ #endif #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtPropertyPrivate { public: QtPropertyPrivate(QtAbstractPropertyManager *manager) : m_enabled(true), m_modified(false), m_manager(manager) {} QtProperty *q_ptr; QSet m_parentItems; QList m_subItems; QString m_toolTip; QString m_statusTip; QString m_whatsThis; QString m_name; QColor m_nameColor; QColor m_valueColor; bool m_enabled; bool m_modified; QtAbstractPropertyManager * const m_manager; }; class QtAbstractPropertyManagerPrivate { QtAbstractPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtAbstractPropertyManager) public: void propertyDestroyed(QtProperty *property); void propertyChanged(QtProperty *property) const; void propertyRemoved(QtProperty *property, QtProperty *parentProperty) const; void propertyInserted(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) const; QSet m_properties; }; /*! \class QtProperty \brief The QtProperty class encapsulates an instance of a property. Properties are created by objects of QtAbstractPropertyManager subclasses; a manager can create properties of a given type, and is used in conjunction with the QtAbstractPropertyBrowser class. A property is always owned by the manager that created it, which can be retrieved using the propertyManager() function. QtProperty contains the most common property attributes, and provides functions for retrieving as well as setting their values: \table \header \o Getter \o Setter \row \o propertyName() \o setPropertyName() \row \o statusTip() \o setStatusTip() \row \o toolTip() \o setToolTip() \row \o whatsThis() \o setWhatsThis() \row \o isEnabled() \o setEnabled() \row \o isModified() \o setModified() \row \o valueText() \o Nop \row \o valueIcon() \o Nop \endtable It is also possible to nest properties: QtProperty provides the addSubProperty(), insertSubProperty() and removeSubProperty() functions to manipulate the set of subproperties. Use the subProperties() function to retrieve a property's current set of subproperties. Note that nested properties are not owned by the parent property, i.e. each subproperty is owned by the manager that created it. \sa QtAbstractPropertyManager, QtBrowserItem */ /*! Creates a property with the given \a manager. This constructor is only useful when creating a custom QtProperty subclass (e.g. QtVariantProperty). To create a regular QtProperty object, use the QtAbstractPropertyManager::addProperty() function instead. \sa QtAbstractPropertyManager::addProperty() */ QtProperty::QtProperty(QtAbstractPropertyManager *manager) { d_ptr = new QtPropertyPrivate(manager); d_ptr->q_ptr = this; } /*! Destroys this property. Note that subproperties are detached but not destroyed, i.e. they can still be used in another context. \sa QtAbstractPropertyManager::clear() */ QtProperty::~QtProperty() { QSetIterator itParent(d_ptr->m_parentItems); while (itParent.hasNext()) { QtProperty *property = itParent.next(); property->d_ptr->m_manager->d_ptr->propertyRemoved(this, property); } d_ptr->m_manager->d_ptr->propertyDestroyed(this); QListIterator itChild(d_ptr->m_subItems); while (itChild.hasNext()) { QtProperty *property = itChild.next(); property->d_ptr->m_parentItems.remove(this); } itParent.toFront(); while (itParent.hasNext()) { QtProperty *property = itParent.next(); property->d_ptr->m_subItems.removeAll(this); } delete d_ptr; } /*! Returns the set of subproperties. Note that subproperties are not owned by \e this property, but by the manager that created them. \sa insertSubProperty(), removeSubProperty() */ QList QtProperty::subProperties() const { return d_ptr->m_subItems; } /*! Returns a pointer to the manager that owns this property. */ QtAbstractPropertyManager *QtProperty::propertyManager() const { return d_ptr->m_manager; } /*! Returns the property's tool tip. \sa setToolTip() */ QString QtProperty::toolTip() const { return d_ptr->m_toolTip; } /*! Returns the property's status tip. \sa setStatusTip() */ QString QtProperty::statusTip() const { return d_ptr->m_statusTip; } /*! Returns the property's "What's This" help text. \sa setWhatsThis() */ QString QtProperty::whatsThis() const { return d_ptr->m_whatsThis; } /*! Returns the property's name. \sa setPropertyName() */ QString QtProperty::propertyName() const { return d_ptr->m_name; } /*! Returns the property's name color. \sa setNameColor() */ QColor QtProperty::nameColor() const { return d_ptr->m_nameColor; } /*! Returns the property's value color. \sa setValueColor() */ QColor QtProperty::valueColor() const { return d_ptr->m_valueColor; } /*! Returns whether the property is enabled. \sa setEnabled() */ bool QtProperty::isEnabled() const { return d_ptr->m_enabled; } /*! Returns whether the property is modified. \sa setModified() */ bool QtProperty::isModified() const { return d_ptr->m_modified; } /*! Returns whether the property has a value. \sa QtAbstractPropertyManager::hasValue() */ bool QtProperty::hasValue() const { return d_ptr->m_manager->hasValue(this); } /*! Returns an icon representing the current state of this property. If the given property type can not generate such an icon, this function returns an invalid icon. \sa QtAbstractPropertyManager::valueIcon() */ QIcon QtProperty::valueIcon() const { return d_ptr->m_manager->valueIcon(this); } /*! Returns a string representing the current state of this property. If the given property type can not generate such a string, this function returns an empty string. \sa QtAbstractPropertyManager::valueText() */ QString QtProperty::valueText() const { return d_ptr->m_manager->valueText(this); } /*! Returns the display text according to the echo-mode set on the editor. When the editor is a QLineEdit, this will return a string equal to what is displayed. \sa QtAbstractPropertyManager::valueText() */ QString QtProperty::displayText() const { return d_ptr->m_manager->displayText(this); } /*! Sets the property's tool tip to the given \a text. \sa toolTip() */ void QtProperty::setToolTip(const QString &text) { if (d_ptr->m_toolTip == text) return; d_ptr->m_toolTip = text; propertyChanged(); } /*! Sets the property's status tip to the given \a text. \sa statusTip() */ void QtProperty::setStatusTip(const QString &text) { if (d_ptr->m_statusTip == text) return; d_ptr->m_statusTip = text; propertyChanged(); } /*! Sets the property's "What's This" help text to the given \a text. \sa whatsThis() */ void QtProperty::setWhatsThis(const QString &text) { if (d_ptr->m_whatsThis == text) return; d_ptr->m_whatsThis = text; propertyChanged(); } /*! \fn void QtProperty::setPropertyName(const QString &name) Sets the property's name to the given \a name. \sa propertyName() */ void QtProperty::setPropertyName(const QString &text) { if (d_ptr->m_name == text) return; d_ptr->m_name = text; propertyChanged(); } /*! \fn void QtProperty::setNameColor(const QColor &color) Sets the property's name color to the given \a color. \sa nameColor() */ void QtProperty::setNameColor(const QColor &color) { if (d_ptr->m_nameColor == color) return; d_ptr->m_nameColor = color; propertyChanged(); } /*! \fn void QtProperty::setValueColor(const QColor &color) Sets the property's value color to the given \a color. \sa valueColor() */ void QtProperty::setValueColor(const QColor &color) { if (d_ptr->m_valueColor == color) return; d_ptr->m_valueColor = color; propertyChanged(); } /*! Enables or disables the property according to the passed \a enable value. \sa isEnabled() */ void QtProperty::setEnabled(bool enable) { if (d_ptr->m_enabled == enable) return; d_ptr->m_enabled = enable; propertyChanged(); } /*! Sets the property's modified state according to the passed \a modified value. \sa isModified() */ void QtProperty::setModified(bool modified) { if (d_ptr->m_modified == modified) return; d_ptr->m_modified = modified; propertyChanged(); } /*! Appends the given \a property to this property's subproperties. If the given \a property already is added, this function does nothing. \sa insertSubProperty(), removeSubProperty() */ void QtProperty::addSubProperty(QtProperty *property) { QtProperty *after = 0; if (d_ptr->m_subItems.count() > 0) after = d_ptr->m_subItems.last(); insertSubProperty(property, after); } /*! \fn void QtProperty::insertSubProperty(QtProperty *property, QtProperty *precedingProperty) Inserts the given \a property after the specified \a precedingProperty into this property's list of subproperties. If \a precedingProperty is 0, the specified \a property is inserted at the beginning of the list. If the given \a property already is inserted, this function does nothing. \sa addSubProperty(), removeSubProperty() */ void QtProperty::insertSubProperty(QtProperty *property, QtProperty *afterProperty) { if (!property) return; if (property == this) return; // traverse all children of item. if this item is a child of item then cannot add. QList pendingList = property->subProperties(); QMap visited; while (!pendingList.isEmpty()) { QtProperty *i = pendingList.first(); if (i == this) return; pendingList.removeFirst(); if (visited.contains(i)) continue; visited[i] = true; pendingList += i->subProperties(); } pendingList = subProperties(); int pos = 0; int newPos = 0; QtProperty *properAfterProperty = 0; while (pos < pendingList.count()) { QtProperty *i = pendingList.at(pos); if (i == property) return; // if item is already inserted in this item then cannot add. if (i == afterProperty) { newPos = pos + 1; properAfterProperty = afterProperty; } pos++; } d_ptr->m_subItems.insert(newPos, property); property->d_ptr->m_parentItems.insert(this); d_ptr->m_manager->d_ptr->propertyInserted(property, this, properAfterProperty); } /*! Removes the given \a property from the list of subproperties without deleting it. \sa addSubProperty(), insertSubProperty() */ void QtProperty::removeSubProperty(QtProperty *property) { if (!property) return; d_ptr->m_manager->d_ptr->propertyRemoved(property, this); QList pendingList = subProperties(); int pos = 0; while (pos < pendingList.count()) { if (pendingList.at(pos) == property) { d_ptr->m_subItems.removeAt(pos); property->d_ptr->m_parentItems.remove(this); return; } pos++; } } /*! \internal */ void QtProperty::propertyChanged() { d_ptr->m_manager->d_ptr->propertyChanged(this); } //////////////////////////////// void QtAbstractPropertyManagerPrivate::propertyDestroyed(QtProperty *property) { if (m_properties.contains(property)) { emit q_ptr->propertyDestroyed(property); q_ptr->uninitializeProperty(property); m_properties.remove(property); } } void QtAbstractPropertyManagerPrivate::propertyChanged(QtProperty *property) const { emit q_ptr->propertyChanged(property); } void QtAbstractPropertyManagerPrivate::propertyRemoved(QtProperty *property, QtProperty *parentProperty) const { emit q_ptr->propertyRemoved(property, parentProperty); } void QtAbstractPropertyManagerPrivate::propertyInserted(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) const { emit q_ptr->propertyInserted(property, parentProperty, afterProperty); } /*! \class QtAbstractPropertyManager \brief The QtAbstractPropertyManager provides an interface for property managers. A manager can create and manage properties of a given type, and is used in conjunction with the QtAbstractPropertyBrowser class. When using a property browser widget, the properties are created and managed by implementations of the QtAbstractPropertyManager class. To ensure that the properties' values will be displayed using suitable editing widgets, the managers are associated with objects of QtAbstractEditorFactory subclasses. The property browser will use these associations to determine which factories it should use to create the preferred editing widgets. The QtAbstractPropertyManager class provides common functionality like creating a property using the addProperty() function, and retrieving the properties created by the manager using the properties() function. The class also provides signals that are emitted when the manager's properties change: propertyInserted(), propertyRemoved(), propertyChanged() and propertyDestroyed(). QtAbstractPropertyManager subclasses are supposed to provide their own type specific API. Note that several ready-made implementations are available: \list \o QtBoolPropertyManager \o QtColorPropertyManager \o QtDatePropertyManager \o QtDateTimePropertyManager \o QtDoublePropertyManager \o QtEnumPropertyManager \o QtFlagPropertyManager \o QtFontPropertyManager \o QtGroupPropertyManager \o QtIntPropertyManager \o QtPointPropertyManager \o QtRectPropertyManager \o QtSizePropertyManager \o QtSizePolicyPropertyManager \o QtStringPropertyManager \o QtTimePropertyManager \o QtVariantPropertyManager \endlist \sa QtAbstractEditorFactoryBase, QtAbstractPropertyBrowser, QtProperty */ /*! \fn void QtAbstractPropertyManager::propertyInserted(QtProperty *newProperty, QtProperty *parentProperty, QtProperty *precedingProperty) This signal is emitted when a new subproperty is inserted into an existing property, passing pointers to the \a newProperty, \a parentProperty and \a precedingProperty as parameters. If \a precedingProperty is 0, the \a newProperty was inserted at the beginning of the \a parentProperty's subproperties list. Note that signal is emitted only if the \a parentProperty is created by this manager. \sa QtAbstractPropertyBrowser::itemInserted() */ /*! \fn void QtAbstractPropertyManager::propertyChanged(QtProperty *property) This signal is emitted whenever a property's data changes, passing a pointer to the \a property as parameter. Note that signal is only emitted for properties that are created by this manager. \sa QtAbstractPropertyBrowser::itemChanged() */ /*! \fn void QtAbstractPropertyManager::propertyRemoved(QtProperty *property, QtProperty *parent) This signal is emitted when a subproperty is removed, passing pointers to the removed \a property and the \a parent property as parameters. Note that signal is emitted only when the \a parent property is created by this manager. \sa QtAbstractPropertyBrowser::itemRemoved() */ /*! \fn void QtAbstractPropertyManager::propertyDestroyed(QtProperty *property) This signal is emitted when the specified \a property is about to be destroyed. Note that signal is only emitted for properties that are created by this manager. \sa clear(), uninitializeProperty() */ /*! \fn void QtAbstractPropertyBrowser::currentItemChanged(QtBrowserItem *current) This signal is emitted when the current item changes. The current item is specified by \a current. \sa QtAbstractPropertyBrowser::setCurrentItem() */ /*! Creates an abstract property manager with the given \a parent. */ QtAbstractPropertyManager::QtAbstractPropertyManager(QObject *parent) : QObject(parent) { d_ptr = new QtAbstractPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys the manager. All properties created by the manager are destroyed. */ QtAbstractPropertyManager::~QtAbstractPropertyManager() { clear(); delete d_ptr; } /*! Destroys all the properties that this manager has created. \sa propertyDestroyed(), uninitializeProperty() */ void QtAbstractPropertyManager::clear() const { while (!properties().isEmpty()) { QSetIterator itProperty(properties()); QtProperty *prop = itProperty.next(); delete prop; } } /*! Returns the set of properties created by this manager. \sa addProperty() */ QSet QtAbstractPropertyManager::properties() const { return d_ptr->m_properties; } /*! Returns whether the given \a property has a value. The default implementation of this function returns true. \sa QtProperty::hasValue() */ bool QtAbstractPropertyManager::hasValue(const QtProperty *property) const { Q_UNUSED(property) return true; } /*! Returns an icon representing the current state of the given \a property. The default implementation of this function returns an invalid icon. \sa QtProperty::valueIcon() */ QIcon QtAbstractPropertyManager::valueIcon(const QtProperty *property) const { Q_UNUSED(property) return QIcon(); } /*! Returns a string representing the current state of the given \a property. The default implementation of this function returns an empty string. \sa QtProperty::valueText() */ QString QtAbstractPropertyManager::valueText(const QtProperty *property) const { Q_UNUSED(property) return QString(); } /*! Returns a string representing the current state of the given \a property. The default implementation of this function returns an empty string. \sa QtProperty::valueText() */ QString QtAbstractPropertyManager::displayText(const QtProperty *property) const { Q_UNUSED(property) return QString(); } /*! Returns the echo mode representing the current state of the given \a property. The default implementation of this function returns QLineEdit::Normal. \sa QtProperty::valueText() */ EchoMode QtAbstractPropertyManager::echoMode(const QtProperty *property) const { Q_UNUSED(property) return QLineEdit::Normal; } /*! Creates a property with the given \a name which then is owned by this manager. Internally, this function calls the createProperty() and initializeProperty() functions. \sa initializeProperty(), properties() */ QtProperty *QtAbstractPropertyManager::addProperty(const QString &name) { QtProperty *property = createProperty(); if (property) { property->setPropertyName(name); d_ptr->m_properties.insert(property); initializeProperty(property); } return property; } /*! Creates a property. The base implementation produce QtProperty instances; Reimplement this function to make this manager produce objects of a QtProperty subclass. \sa addProperty(), initializeProperty() */ QtProperty *QtAbstractPropertyManager::createProperty() { return new QtProperty(this); } /*! \fn void QtAbstractPropertyManager::initializeProperty(QtProperty *property) = 0 This function is called whenever a new valid property pointer has been created, passing the pointer as parameter. The purpose is to let the manager know that the \a property has been created so that it can provide additional attributes for the new property, e.g. QtIntPropertyManager adds \l {QtIntPropertyManager::value()}{value}, \l {QtIntPropertyManager::minimum()}{minimum} and \l {QtIntPropertyManager::maximum()}{maximum} attributes. Since each manager subclass adds type specific attributes, this function is pure virtual and must be reimplemented when deriving from the QtAbstractPropertyManager class. \sa addProperty(), createProperty() */ /*! This function is called just before the specified \a property is destroyed. The purpose is to let the property manager know that the \a property is being destroyed so that it can remove the property's additional attributes. \sa clear(), propertyDestroyed() */ void QtAbstractPropertyManager::uninitializeProperty(QtProperty *property) { Q_UNUSED(property) } //////////////////////////////////// /*! \class QtAbstractEditorFactoryBase \brief The QtAbstractEditorFactoryBase provides an interface for editor factories. An editor factory is a class that is able to create an editing widget of a specified type (e.g. line edits or comboboxes) for a given QtProperty object, and it is used in conjunction with the QtAbstractPropertyManager and QtAbstractPropertyBrowser classes. When using a property browser widget, the properties are created and managed by implementations of the QtAbstractPropertyManager class. To ensure that the properties' values will be displayed using suitable editing widgets, the managers are associated with objects of QtAbstractEditorFactory subclasses. The property browser will use these associations to determine which factories it should use to create the preferred editing widgets. Typically, an editor factory is created by subclassing the QtAbstractEditorFactory template class which inherits QtAbstractEditorFactoryBase. But note that several ready-made implementations are available: \list \o QtCheckBoxFactory \o QtDateEditFactory \o QtDateTimeEditFactory \o QtDoubleSpinBoxFactory \o QtEnumEditorFactory \o QtLineEditFactory \o QtScrollBarFactory \o QtSliderFactory \o QtSpinBoxFactory \o QtTimeEditFactory \o QtVariantEditorFactory \endlist \sa QtAbstractPropertyManager, QtAbstractPropertyBrowser */ /*! \fn virtual QWidget *QtAbstractEditorFactoryBase::createEditor(QtProperty *property, QWidget *parent) = 0 Creates an editing widget (with the given \a parent) for the given \a property. This function is reimplemented in QtAbstractEditorFactory template class which also provides a pure virtual convenience overload of this function enabling access to the property's manager. \sa QtAbstractEditorFactory::createEditor() */ /*! \fn QtAbstractEditorFactoryBase::QtAbstractEditorFactoryBase(QObject *parent = 0) Creates an abstract editor factory with the given \a parent. */ /*! \fn virtual void QtAbstractEditorFactoryBase::breakConnection(QtAbstractPropertyManager *manager) = 0 \internal Detaches property manager from factory. This method is reimplemented in QtAbstractEditorFactory template subclass. You don't need to reimplement it in your subclasses. Instead implement more convenient QtAbstractEditorFactory::disconnectPropertyManager() which gives you access to particular manager subclass. */ /*! \fn virtual void QtAbstractEditorFactoryBase::managerDestroyed(QObject *manager) = 0 \internal This method is called when property manager is being destroyed. Basically it notifies factory not to produce editors for properties owned by \a manager. You don't need to reimplement it in your subclass. This method is implemented in QtAbstractEditorFactory template subclass. */ /*! \class QtAbstractEditorFactory \brief The QtAbstractEditorFactory is the base template class for editor factories. An editor factory is a class that is able to create an editing widget of a specified type (e.g. line edits or comboboxes) for a given QtProperty object, and it is used in conjunction with the QtAbstractPropertyManager and QtAbstractPropertyBrowser classes. Note that the QtAbstractEditorFactory functions are using the PropertyManager template argument class which can be any QtAbstractPropertyManager subclass. For example: \code QtSpinBoxFactory *factory; QSet managers = factory->propertyManagers(); \endcode Note that QtSpinBoxFactory by definition creates editing widgets \e only for properties created by QtIntPropertyManager. When using a property browser widget, the properties are created and managed by implementations of the QtAbstractPropertyManager class. To ensure that the properties' values will be displayed using suitable editing widgets, the managers are associated with objects of QtAbstractEditorFactory subclasses. The property browser will use these associations to determine which factories it should use to create the preferred editing widgets. A QtAbstractEditorFactory object is capable of producing editors for several property managers at the same time. To create an association between this factory and a given manager, use the addPropertyManager() function. Use the removePropertyManager() function to make this factory stop producing editors for a given property manager. Use the propertyManagers() function to retrieve the set of managers currently associated with this factory. Several ready-made implementations of the QtAbstractEditorFactory class are available: \list \o QtCheckBoxFactory \o QtDateEditFactory \o QtDateTimeEditFactory \o QtDoubleSpinBoxFactory \o QtEnumEditorFactory \o QtLineEditFactory \o QtScrollBarFactory \o QtSliderFactory \o QtSpinBoxFactory \o QtTimeEditFactory \o QtVariantEditorFactory \endlist When deriving from the QtAbstractEditorFactory class, several pure virtual functions must be implemented: the connectPropertyManager() function is used by the factory to connect to the given manager's signals, the createEditor() function is supposed to create an editor for the given property controlled by the given manager, and finally the disconnectPropertyManager() function is used by the factory to disconnect from the specified manager's signals. \sa QtAbstractEditorFactoryBase, QtAbstractPropertyManager */ /*! \fn QtAbstractEditorFactory::QtAbstractEditorFactory(QObject *parent = 0) Creates an editor factory with the given \a parent. \sa addPropertyManager() */ /*! \fn QWidget *QtAbstractEditorFactory::createEditor(QtProperty *property, QWidget *parent) Creates an editing widget (with the given \a parent) for the given \a property. */ /*! \fn void QtAbstractEditorFactory::addPropertyManager(PropertyManager *manager) Adds the given \a manager to this factory's set of managers, making this factory produce editing widgets for properties created by the given manager. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. \sa propertyManagers(), removePropertyManager() */ /*! \fn void QtAbstractEditorFactory::removePropertyManager(PropertyManager *manager) Removes the given \a manager from this factory's set of managers. The PropertyManager type is a template argument class, and may be any QtAbstractPropertyManager subclass. \sa propertyManagers(), addPropertyManager() */ /*! \fn virtual void QtAbstractEditorFactory::connectPropertyManager(PropertyManager *manager) = 0 Connects this factory to the given \a manager's signals. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. This function is used internally by the addPropertyManager() function, and makes it possible to update an editing widget when the associated property's data changes. This is typically done in custom slots responding to the signals emitted by the property's manager, e.g. QtIntPropertyManager::valueChanged() and QtIntPropertyManager::rangeChanged(). \sa propertyManagers(), disconnectPropertyManager() */ /*! \fn virtual QWidget *QtAbstractEditorFactory::createEditor(PropertyManager *manager, QtProperty *property, QWidget *parent) = 0 Creates an editing widget with the given \a parent for the specified \a property created by the given \a manager. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. This function must be implemented in derived classes: It is recommended to store a pointer to the widget and map it to the given \a property, since the widget must be updated whenever the associated property's data changes. This is typically done in custom slots responding to the signals emitted by the property's manager, e.g. QtIntPropertyManager::valueChanged() and QtIntPropertyManager::rangeChanged(). \sa connectPropertyManager() */ /*! \fn virtual void QtAbstractEditorFactory::disconnectPropertyManager(PropertyManager *manager) = 0 Disconnects this factory from the given \a manager's signals. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. This function is used internally by the removePropertyManager() function. \sa propertyManagers(), connectPropertyManager() */ /*! \fn QSet QtAbstractEditorFactory::propertyManagers() const Returns the factory's set of associated managers. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. \sa addPropertyManager(), removePropertyManager() */ /*! \fn PropertyManager *QtAbstractEditorFactory::propertyManager(QtProperty *property) const Returns the property manager for the given \a property, or 0 if the given \a property doesn't belong to any of this factory's registered managers. The PropertyManager type is a template argument class, and represents the chosen QtAbstractPropertyManager subclass. \sa propertyManagers() */ /*! \fn virtual void QtAbstractEditorFactory::managerDestroyed(QObject *manager) \internal \reimp */ //////////////////////////////////// class QtBrowserItemPrivate { public: QtBrowserItemPrivate(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent) : m_browser(browser), m_property(property), m_parent(parent), q_ptr(0) {} void addChild(QtBrowserItem *index, QtBrowserItem *after); void removeChild(QtBrowserItem *index); QtAbstractPropertyBrowser * const m_browser; QtProperty *m_property; QtBrowserItem *m_parent; QtBrowserItem *q_ptr; QList m_children; }; void QtBrowserItemPrivate::addChild(QtBrowserItem *index, QtBrowserItem *after) { if (m_children.contains(index)) return; int idx = m_children.indexOf(after) + 1; // we insert after returned idx, if it was -1 then we set idx to 0; m_children.insert(idx, index); } void QtBrowserItemPrivate::removeChild(QtBrowserItem *index) { m_children.removeAll(index); } /*! \class QtBrowserItem \brief The QtBrowserItem class represents a property in a property browser instance. Browser items are created whenever a QtProperty is inserted to the property browser. A QtBrowserItem uniquely identifies a browser's item. Thus, if the same QtProperty is inserted multiple times, each occurrence gets its own unique QtBrowserItem. The items are owned by QtAbstractPropertyBrowser and automatically deleted when they are removed from the browser. You can traverse a browser's properties by calling parent() and children(). The property and the browser associated with an item are available as property() and browser(). \sa QtAbstractPropertyBrowser, QtProperty */ /*! Returns the property which is accosiated with this item. Note that several items can be associated with the same property instance in the same property browser. \sa QtAbstractPropertyBrowser::items() */ QtProperty *QtBrowserItem::property() const { return d_ptr->m_property; } /*! Returns the parent item of \e this item. Returns 0 if \e this item is associated with top-level property in item's property browser. \sa children() */ QtBrowserItem *QtBrowserItem::parent() const { return d_ptr->m_parent; } /*! Returns the children items of \e this item. The properties reproduced from children items are always the same as reproduced from associated property' children, for example: \code QtBrowserItem *item; QList childrenItems = item->children(); QList childrenProperties = item->property()->subProperties(); \endcode The \e childrenItems list represents the same list as \e childrenProperties. */ QList QtBrowserItem::children() const { return d_ptr->m_children; } /*! Returns the property browser which owns \e this item. */ QtAbstractPropertyBrowser *QtBrowserItem::browser() const { return d_ptr->m_browser; } QtBrowserItem::QtBrowserItem(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent) { d_ptr = new QtBrowserItemPrivate(browser, property, parent); d_ptr->q_ptr = this; } QtBrowserItem::~QtBrowserItem() { delete d_ptr; } //////////////////////////////////// typedef QMap > Map1; typedef QMap > > Map2; Q_GLOBAL_STATIC(Map1, m_viewToManagerToFactory) Q_GLOBAL_STATIC(Map2, m_managerToFactoryToViews) class QtAbstractPropertyBrowserPrivate { QtAbstractPropertyBrowser *q_ptr; Q_DECLARE_PUBLIC(QtAbstractPropertyBrowser) public: QtAbstractPropertyBrowserPrivate(); void insertSubTree(QtProperty *property, QtProperty *parentProperty); void removeSubTree(QtProperty *property, QtProperty *parentProperty); void createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty); void removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty); QtBrowserItem *createBrowserIndex(QtProperty *property, QtBrowserItem *parentIndex, QtBrowserItem *afterIndex); void removeBrowserIndex(QtBrowserItem *index); void clearIndex(QtBrowserItem *index); void slotPropertyInserted(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty); void slotPropertyRemoved(QtProperty *property, QtProperty *parentProperty); void slotPropertyDestroyed(QtProperty *property); void slotPropertyDataChanged(QtProperty *property); QList m_subItems; QMap > m_managerToProperties; QMap > m_propertyToParents; QMap m_topLevelPropertyToIndex; QList m_topLevelIndexes; QMap > m_propertyToIndexes; QtBrowserItem *m_currentItem; }; QtAbstractPropertyBrowserPrivate::QtAbstractPropertyBrowserPrivate() : m_currentItem(0) { } void QtAbstractPropertyBrowserPrivate::insertSubTree(QtProperty *property, QtProperty *parentProperty) { if (m_propertyToParents.contains(property)) { // property was already inserted, so its manager is connected // and all its children are inserted and theirs managers are connected // we just register new parent (parent has to be new). m_propertyToParents[property].append(parentProperty); // don't need to update m_managerToProperties map since // m_managerToProperties[manager] already contains property. return; } QtAbstractPropertyManager *manager = property->propertyManager(); if (m_managerToProperties[manager].isEmpty()) { // connect manager's signals q_ptr->connect(manager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), q_ptr, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); q_ptr->connect(manager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), q_ptr, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); q_ptr->connect(manager, SIGNAL(propertyDestroyed(QtProperty *)), q_ptr, SLOT(slotPropertyDestroyed(QtProperty *))); q_ptr->connect(manager, SIGNAL(propertyChanged(QtProperty *)), q_ptr, SLOT(slotPropertyDataChanged(QtProperty *))); } m_managerToProperties[manager].append(property); m_propertyToParents[property].append(parentProperty); QList subList = property->subProperties(); QListIterator itSub(subList); while (itSub.hasNext()) { QtProperty *subProperty = itSub.next(); insertSubTree(subProperty, property); } } void QtAbstractPropertyBrowserPrivate::removeSubTree(QtProperty *property, QtProperty *parentProperty) { if (!m_propertyToParents.contains(property)) { // ASSERT return; } m_propertyToParents[property].removeAll(parentProperty); if (!m_propertyToParents[property].isEmpty()) return; m_propertyToParents.remove(property); QtAbstractPropertyManager *manager = property->propertyManager(); m_managerToProperties[manager].removeAll(property); if (m_managerToProperties[manager].isEmpty()) { // disconnect manager's signals q_ptr->disconnect(manager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), q_ptr, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); q_ptr->disconnect(manager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), q_ptr, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); q_ptr->disconnect(manager, SIGNAL(propertyDestroyed(QtProperty *)), q_ptr, SLOT(slotPropertyDestroyed(QtProperty *))); q_ptr->disconnect(manager, SIGNAL(propertyChanged(QtProperty *)), q_ptr, SLOT(slotPropertyDataChanged(QtProperty *))); m_managerToProperties.remove(manager); } QList subList = property->subProperties(); QListIterator itSub(subList); while (itSub.hasNext()) { QtProperty *subProperty = itSub.next(); removeSubTree(subProperty, property); } } void QtAbstractPropertyBrowserPrivate::createBrowserIndexes(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) { QMap parentToAfter; if (afterProperty) { QMap >::ConstIterator it = m_propertyToIndexes.find(afterProperty); if (it == m_propertyToIndexes.constEnd()) return; QList indexes = it.value(); QListIterator itIndex(indexes); while (itIndex.hasNext()) { QtBrowserItem *idx = itIndex.next(); QtBrowserItem *parentIdx = idx->parent(); if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx)) parentToAfter[idx->parent()] = idx; } } else if (parentProperty) { QMap >::ConstIterator it = m_propertyToIndexes.find(parentProperty); if (it == m_propertyToIndexes.constEnd()) return; QList indexes = it.value(); QListIterator itIndex(indexes); while (itIndex.hasNext()) { QtBrowserItem *idx = itIndex.next(); parentToAfter[idx] = 0; } } else { parentToAfter[0] = 0; } const QMap::ConstIterator pcend = parentToAfter.constEnd(); for (QMap::ConstIterator it = parentToAfter.constBegin(); it != pcend; ++it) createBrowserIndex(property, it.key(), it.value()); } QtBrowserItem *QtAbstractPropertyBrowserPrivate::createBrowserIndex(QtProperty *property, QtBrowserItem *parentIndex, QtBrowserItem *afterIndex) { QtBrowserItem *newIndex = new QtBrowserItem(q_ptr, property, parentIndex); if (parentIndex) { parentIndex->d_ptr->addChild(newIndex, afterIndex); } else { m_topLevelPropertyToIndex[property] = newIndex; m_topLevelIndexes.insert(m_topLevelIndexes.indexOf(afterIndex) + 1, newIndex); } m_propertyToIndexes[property].append(newIndex); q_ptr->itemInserted(newIndex, afterIndex); QList subItems = property->subProperties(); QListIterator itChild(subItems); QtBrowserItem *afterChild = 0; while (itChild.hasNext()) { QtProperty *child = itChild.next(); afterChild = createBrowserIndex(child, newIndex, afterChild); } return newIndex; } void QtAbstractPropertyBrowserPrivate::removeBrowserIndexes(QtProperty *property, QtProperty *parentProperty) { QList toRemove; QMap >::ConstIterator it = m_propertyToIndexes.find(property); if (it == m_propertyToIndexes.constEnd()) return; QList indexes = it.value(); QListIterator itIndex(indexes); while (itIndex.hasNext()) { QtBrowserItem *idx = itIndex.next(); QtBrowserItem *parentIdx = idx->parent(); if ((parentProperty && parentIdx && parentIdx->property() == parentProperty) || (!parentProperty && !parentIdx)) toRemove.append(idx); } QListIterator itRemove(toRemove); while (itRemove.hasNext()) { QtBrowserItem *index = itRemove.next(); removeBrowserIndex(index); } } void QtAbstractPropertyBrowserPrivate::removeBrowserIndex(QtBrowserItem *index) { QList children = index->children(); for (int i = children.count(); i > 0; i--) { removeBrowserIndex(children.at(i - 1)); } q_ptr->itemRemoved(index); if (index->parent()) { index->parent()->d_ptr->removeChild(index); } else { m_topLevelPropertyToIndex.remove(index->property()); m_topLevelIndexes.removeAll(index); } QtProperty *property = index->property(); m_propertyToIndexes[property].removeAll(index); if (m_propertyToIndexes[property].isEmpty()) m_propertyToIndexes.remove(property); delete index; } void QtAbstractPropertyBrowserPrivate::clearIndex(QtBrowserItem *index) { QList children = index->children(); QListIterator itChild(children); while (itChild.hasNext()) { clearIndex(itChild.next()); } delete index; } void QtAbstractPropertyBrowserPrivate::slotPropertyInserted(QtProperty *property, QtProperty *parentProperty, QtProperty *afterProperty) { if (!m_propertyToParents.contains(parentProperty)) return; createBrowserIndexes(property, parentProperty, afterProperty); insertSubTree(property, parentProperty); //q_ptr->propertyInserted(property, parentProperty, afterProperty); } void QtAbstractPropertyBrowserPrivate::slotPropertyRemoved(QtProperty *property, QtProperty *parentProperty) { if (!m_propertyToParents.contains(parentProperty)) return; removeSubTree(property, parentProperty); // this line should be probably moved down after propertyRemoved call //q_ptr->propertyRemoved(property, parentProperty); removeBrowserIndexes(property, parentProperty); } void QtAbstractPropertyBrowserPrivate::slotPropertyDestroyed(QtProperty *property) { if (!m_subItems.contains(property)) return; q_ptr->removeProperty(property); } void QtAbstractPropertyBrowserPrivate::slotPropertyDataChanged(QtProperty *property) { if (!m_propertyToParents.contains(property)) return; QMap >::ConstIterator it = m_propertyToIndexes.find(property); if (it == m_propertyToIndexes.constEnd()) return; QList indexes = it.value(); QListIterator itIndex(indexes); while (itIndex.hasNext()) { QtBrowserItem *idx = itIndex.next(); q_ptr->itemChanged(idx); } //q_ptr->propertyChanged(property); } /*! \class QtAbstractPropertyBrowser \brief QtAbstractPropertyBrowser provides a base class for implementing property browsers. A property browser is a widget that enables the user to edit a given set of properties. Each property is represented by a label specifying the property's name, and an editing widget (e.g. a line edit or a combobox) holding its value. A property can have zero or more subproperties. \image qtpropertybrowser.png The top level properties can be retrieved using the properties() function. To traverse each property's subproperties, use the QtProperty::subProperties() function. In addition, the set of top level properties can be manipulated using the addProperty(), insertProperty() and removeProperty() functions. Note that the QtProperty class provides a corresponding set of functions making it possible to manipulate the set of subproperties as well. To remove all the properties from the property browser widget, use the clear() function. This function will clear the editor, but it will not delete the properties since they can still be used in other editors. The properties themselves are created and managed by implementations of the QtAbstractPropertyManager class. A manager can handle (i.e. create and manage) properties of a given type. In the property browser the managers are associated with implementations of the QtAbstractEditorFactory: A factory is a class able to create an editing widget of a specified type. When using a property browser widget, managers must be created for each of the required property types before the properties themselves can be created. To ensure that the properties' values will be displayed using suitable editing widgets, the managers must be associated with objects of the preferred factory implementations using the setFactoryForManager() function. The property browser will use these associations to determine which factory it should use to create the preferred editing widget. Note that a factory can be associated with many managers, but a manager can only be associated with one single factory within the context of a single property browser. The associations between managers and factories can at any time be removed using the unsetFactoryForManager() function. Whenever the property data changes or a property is inserted or removed, the itemChanged(), itemInserted() or itemRemoved() functions are called, respectively. These functions must be reimplemented in derived classes in order to update the property browser widget. Be aware that some property instances can appear several times in an abstract tree structure. For example: \table 100% \row \o \code QtProperty *property1, *property2, *property3; property2->addSubProperty(property1); property3->addSubProperty(property2); QtAbstractPropertyBrowser *editor; editor->addProperty(property1); editor->addProperty(property2); editor->addProperty(property3); \endcode \o \image qtpropertybrowser-duplicate.png \endtable The addProperty() function returns a QtBrowserItem that uniquely identifies the created item. To make a property editable in the property browser, the createEditor() function must be called to provide the property with a suitable editing widget. Note that there are two ready-made property browser implementations: \list \o QtGroupBoxPropertyBrowser \o QtTreePropertyBrowser \endlist \sa QtAbstractPropertyManager, QtAbstractEditorFactoryBase */ /*! \fn void QtAbstractPropertyBrowser::setFactoryForManager(PropertyManager *manager, QtAbstractEditorFactory *factory) Connects the given \a manager to the given \a factory, ensuring that properties of the \a manager's type will be displayed with an editing widget suitable for their value. For example: \code QtIntPropertyManager *intManager; QtDoublePropertyManager *doubleManager; QtProperty *myInteger = intManager->addProperty(); QtProperty *myDouble = doubleManager->addProperty(); QtSpinBoxFactory *spinBoxFactory; QtDoubleSpinBoxFactory *doubleSpinBoxFactory; QtAbstractPropertyBrowser *editor; editor->setFactoryForManager(intManager, spinBoxFactory); editor->setFactoryForManager(doubleManager, doubleSpinBoxFactory); editor->addProperty(myInteger); editor->addProperty(myDouble); \endcode In this example the \c myInteger property's value is displayed with a QSpinBox widget, while the \c myDouble property's value is displayed with a QDoubleSpinBox widget. Note that a factory can be associated with many managers, but a manager can only be associated with one single factory. If the given \a manager already is associated with another factory, the old association is broken before the new one established. This function ensures that the given \a manager and the given \a factory are compatible, and it automatically calls the QtAbstractEditorFactory::addPropertyManager() function if necessary. \sa unsetFactoryForManager() */ /*! \fn virtual void QtAbstractPropertyBrowser::itemInserted(QtBrowserItem *insertedItem, QtBrowserItem *precedingItem) = 0 This function is called to update the widget whenever a property is inserted or added to the property browser, passing pointers to the \a insertedItem of property and the specified \a precedingItem as parameters. If \a precedingItem is 0, the \a insertedItem was put at the beginning of its parent item's list of subproperties. If the parent of \a insertedItem is 0, the \a insertedItem was added as a top level property of \e this property browser. This function must be reimplemented in derived classes. Note that if the \a insertedItem's property has subproperties, this method will be called for those properties as soon as the current call is finished. \sa insertProperty(), addProperty() */ /*! \fn virtual void QtAbstractPropertyBrowser::itemRemoved(QtBrowserItem *item) = 0 This function is called to update the widget whenever a property is removed from the property browser, passing the pointer to the \a item of the property as parameters. The passed \a item is deleted just after this call is finished. If the the parent of \a item is 0, the removed \a item was a top level property in this editor. This function must be reimplemented in derived classes. Note that if the removed \a item's property has subproperties, this method will be called for those properties just before the current call is started. \sa removeProperty() */ /*! \fn virtual void QtAbstractPropertyBrowser::itemChanged(QtBrowserItem *item) = 0 This function is called whenever a property's data changes, passing a pointer to the \a item of property as parameter. This function must be reimplemented in derived classes in order to update the property browser widget whenever a property's name, tool tip, status tip, "what's this" text, value text or value icon changes. Note that if the property browser contains several occurrences of the same property, this method will be called once for each occurrence (with a different item each time). \sa QtProperty, items() */ /*! Creates an abstract property browser with the given \a parent. */ QtAbstractPropertyBrowser::QtAbstractPropertyBrowser(QWidget *parent) : QWidget(parent) { d_ptr = new QtAbstractPropertyBrowserPrivate; d_ptr->q_ptr = this; } /*! Destroys the property browser, and destroys all the items that were created by this property browser. Note that the properties that were displayed in the editor are not deleted since they still can be used in other editors. Neither does the destructor delete the property managers and editor factories that were used by this property browser widget unless this widget was their parent. \sa QtAbstractPropertyManager::~QtAbstractPropertyManager() */ QtAbstractPropertyBrowser::~QtAbstractPropertyBrowser() { QList indexes = topLevelItems(); QListIterator itItem(indexes); while (itItem.hasNext()) d_ptr->clearIndex(itItem.next()); delete d_ptr; } /*! Returns the property browser's list of top level properties. To traverse the subproperties, use the QtProperty::subProperties() function. \sa addProperty(), insertProperty(), removeProperty() */ QList QtAbstractPropertyBrowser::properties() const { return d_ptr->m_subItems; } /*! Returns the property browser's list of all items associated with the given \a property. There is one item per instance of the property in the browser. \sa topLevelItem() */ QList QtAbstractPropertyBrowser::items(QtProperty *property) const { return d_ptr->m_propertyToIndexes.value(property); } /*! Returns the top-level items associated with the given \a property. Returns 0 if \a property wasn't inserted into this property browser or isn't a top-level one. \sa topLevelItems(), items() */ QtBrowserItem *QtAbstractPropertyBrowser::topLevelItem(QtProperty *property) const { return d_ptr->m_topLevelPropertyToIndex.value(property); } /*! Returns the list of top-level items. \sa topLevelItem() */ QList QtAbstractPropertyBrowser::topLevelItems() const { return d_ptr->m_topLevelIndexes; } /*! Removes all the properties from the editor, but does not delete them since they can still be used in other editors. \sa removeProperty(), QtAbstractPropertyManager::clear() */ void QtAbstractPropertyBrowser::clear() { QList subList = properties(); QListIterator itSub(subList); itSub.toBack(); while (itSub.hasPrevious()) { QtProperty *property = itSub.previous(); removeProperty(property); } } /*! Appends the given \a property (and its subproperties) to the property browser's list of top level properties. Returns the item created by property browser which is associated with the \a property. In order to get all children items created by the property browser in this call, the returned item should be traversed. If the specified \a property is already added, this function does nothing and returns 0. \sa insertProperty(), QtProperty::addSubProperty(), properties() */ QtBrowserItem *QtAbstractPropertyBrowser::addProperty(QtProperty *property) { QtProperty *afterProperty = 0; if (d_ptr->m_subItems.count() > 0) afterProperty = d_ptr->m_subItems.last(); return insertProperty(property, afterProperty); } /*! \fn QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property, QtProperty *afterProperty) Inserts the given \a property (and its subproperties) after the specified \a afterProperty in the browser's list of top level properties. Returns item created by property browser which is associated with the \a property. In order to get all children items created by the property browser in this call returned item should be traversed. If the specified \a afterProperty is 0, the given \a property is inserted at the beginning of the list. If \a property is already inserted, this function does nothing and returns 0. \sa addProperty(), QtProperty::insertSubProperty(), properties() */ QtBrowserItem *QtAbstractPropertyBrowser::insertProperty(QtProperty *property, QtProperty *afterProperty) { if (!property) return 0; // if item is already inserted in this item then cannot add. QList pendingList = properties(); int pos = 0; int newPos = 0; while (pos < pendingList.count()) { QtProperty *prop = pendingList.at(pos); if (prop == property) return 0; if (prop == afterProperty) { newPos = pos + 1; } pos++; } d_ptr->createBrowserIndexes(property, 0, afterProperty); // traverse inserted subtree and connect to manager's signals d_ptr->insertSubTree(property, 0); d_ptr->m_subItems.insert(newPos, property); //propertyInserted(property, 0, properAfterProperty); return topLevelItem(property); } /*! Removes the specified \a property (and its subproperties) from the property browser's list of top level properties. All items that were associated with the given \a property and its children are deleted. Note that the properties are \e not deleted since they can still be used in other editors. \sa clear(), QtProperty::removeSubProperty(), properties() */ void QtAbstractPropertyBrowser::removeProperty(QtProperty *property) { if (!property) return; QList pendingList = properties(); int pos = 0; while (pos < pendingList.count()) { if (pendingList.at(pos) == property) { d_ptr->m_subItems.removeAt(pos); //perhaps this two lines d_ptr->removeSubTree(property, 0); //should be moved down after propertyRemoved call. //propertyRemoved(property, 0); d_ptr->removeBrowserIndexes(property, 0); // when item is deleted, item will call removeItem for top level items, // and itemRemoved for nested items. return; } pos++; } } /*! Creates an editing widget (with the given \a parent) for the given \a property according to the previously established associations between property managers and editor factories. If the property is created by a property manager which was not associated with any of the existing factories in \e this property editor, the function returns 0. To make a property editable in the property browser, the createEditor() function must be called to provide the property with a suitable editing widget. Reimplement this function to provide additional decoration for the editing widgets created by the installed factories. \sa setFactoryForManager() */ QWidget *QtAbstractPropertyBrowser::createEditor(QtProperty *property, QWidget *parent) { QtAbstractEditorFactoryBase *factory = 0; QtAbstractPropertyManager *manager = property->propertyManager(); if (m_viewToManagerToFactory()->contains(this) && (*m_viewToManagerToFactory())[this].contains(manager)) { factory = (*m_viewToManagerToFactory())[this][manager]; } if (!factory) return 0; return factory->createEditor(property, parent); } bool QtAbstractPropertyBrowser::addFactory(QtAbstractPropertyManager *abstractManager, QtAbstractEditorFactoryBase *abstractFactory) { bool connectNeeded = false; if (!m_managerToFactoryToViews()->contains(abstractManager) || !(*m_managerToFactoryToViews())[abstractManager].contains(abstractFactory)) { connectNeeded = true; } else if ((*m_managerToFactoryToViews())[abstractManager][abstractFactory] .contains(this)) { return connectNeeded; } if (m_viewToManagerToFactory()->contains(this) && (*m_viewToManagerToFactory())[this].contains(abstractManager)) { unsetFactoryForManager(abstractManager); } (*m_managerToFactoryToViews())[abstractManager][abstractFactory].append(this); (*m_viewToManagerToFactory())[this][abstractManager] = abstractFactory; return connectNeeded; } /*! Removes the association between the given \a manager and the factory bound to it, automatically calling the QtAbstractEditorFactory::removePropertyManager() function if necessary. \sa setFactoryForManager() */ void QtAbstractPropertyBrowser::unsetFactoryForManager(QtAbstractPropertyManager *manager) { if (!m_viewToManagerToFactory()->contains(this) || !(*m_viewToManagerToFactory())[this].contains(manager)) { return; } QtAbstractEditorFactoryBase *abstractFactory = (*m_viewToManagerToFactory())[this][manager]; (*m_viewToManagerToFactory())[this].remove(manager); if ((*m_viewToManagerToFactory())[this].isEmpty()) { (*m_viewToManagerToFactory()).remove(this); } (*m_managerToFactoryToViews())[manager][abstractFactory].removeAll(this); if ((*m_managerToFactoryToViews())[manager][abstractFactory].isEmpty()) { (*m_managerToFactoryToViews())[manager].remove(abstractFactory); abstractFactory->breakConnection(manager); if ((*m_managerToFactoryToViews())[manager].isEmpty()) { (*m_managerToFactoryToViews()).remove(manager); } } } /*! Returns the current item in the property browser. \sa setCurrentItem() */ QtBrowserItem *QtAbstractPropertyBrowser::currentItem() const { return d_ptr->m_currentItem; } /*! Sets the current item in the property browser to \a item. \sa currentItem(), currentItemChanged() */ void QtAbstractPropertyBrowser::setCurrentItem(QtBrowserItem *item) { QtBrowserItem *oldItem = d_ptr->m_currentItem; d_ptr->m_currentItem = item; if (oldItem != item) emit currentItemChanged(item); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtpropertybrowser.cpp" tiled-0.14.2/src/qtpropertybrowser/src/qtpropertybrowser.h000066400000000000000000000263661260670167100241430ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTPROPERTYBROWSER_H #define QTPROPERTYBROWSER_H #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif #if defined(Q_OS_WIN) # if !defined(QT_QTPROPERTYBROWSER_EXPORT) && !defined(QT_QTPROPERTYBROWSER_IMPORT) # define QT_QTPROPERTYBROWSER_EXPORT # elif defined(QT_QTPROPERTYBROWSER_IMPORT) # if defined(QT_QTPROPERTYBROWSER_EXPORT) # undef QT_QTPROPERTYBROWSER_EXPORT # endif # define QT_QTPROPERTYBROWSER_EXPORT __declspec(dllimport) # elif defined(QT_QTPROPERTYBROWSER_EXPORT) # undef QT_QTPROPERTYBROWSER_EXPORT # define QT_QTPROPERTYBROWSER_EXPORT __declspec(dllexport) # endif #else # define QT_QTPROPERTYBROWSER_EXPORT #endif typedef QLineEdit::EchoMode EchoMode; class QtAbstractPropertyManager; class QtPropertyPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtProperty { public: virtual ~QtProperty(); QList subProperties() const; QtAbstractPropertyManager *propertyManager() const; QString toolTip() const; QString statusTip() const; QString whatsThis() const; QString propertyName() const; QColor nameColor() const; QColor valueColor() const; bool isEnabled() const; bool isModified() const; bool hasValue() const; QIcon valueIcon() const; QString valueText() const; QString displayText() const; void setToolTip(const QString &text); void setStatusTip(const QString &text); void setWhatsThis(const QString &text); void setPropertyName(const QString &text); void setNameColor(const QColor &color); void setValueColor(const QColor &color); void setEnabled(bool enable); void setModified(bool modified); void addSubProperty(QtProperty *property); void insertSubProperty(QtProperty *property, QtProperty *afterProperty); void removeSubProperty(QtProperty *property); protected: explicit QtProperty(QtAbstractPropertyManager *manager); void propertyChanged(); private: friend class QtAbstractPropertyManager; QtPropertyPrivate *d_ptr; }; class QtAbstractPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtAbstractPropertyManager : public QObject { Q_OBJECT public: explicit QtAbstractPropertyManager(QObject *parent = 0); ~QtAbstractPropertyManager(); QSet properties() const; void clear() const; QtProperty *addProperty(const QString &name = QString()); Q_SIGNALS: void propertyInserted(QtProperty *property, QtProperty *parent, QtProperty *after); void propertyChanged(QtProperty *property); void propertyRemoved(QtProperty *property, QtProperty *parent); void propertyDestroyed(QtProperty *property); protected: virtual bool hasValue(const QtProperty *property) const; virtual QIcon valueIcon(const QtProperty *property) const; virtual QString valueText(const QtProperty *property) const; virtual QString displayText(const QtProperty *property) const; virtual EchoMode echoMode(const QtProperty *) const; virtual void initializeProperty(QtProperty *property) = 0; virtual void uninitializeProperty(QtProperty *property); virtual QtProperty *createProperty(); private: friend class QtProperty; QtAbstractPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtAbstractPropertyManager) Q_DISABLE_COPY(QtAbstractPropertyManager) }; class QT_QTPROPERTYBROWSER_EXPORT QtAbstractEditorFactoryBase : public QObject { Q_OBJECT public: virtual QWidget *createEditor(QtProperty *property, QWidget *parent) = 0; protected: explicit QtAbstractEditorFactoryBase(QObject *parent = 0) : QObject(parent) {} virtual void breakConnection(QtAbstractPropertyManager *manager) = 0; protected Q_SLOTS: virtual void managerDestroyed(QObject *manager) = 0; friend class QtAbstractPropertyBrowser; }; template class QtAbstractEditorFactory : public QtAbstractEditorFactoryBase { public: explicit QtAbstractEditorFactory(QObject *parent) : QtAbstractEditorFactoryBase(parent) {} QWidget *createEditor(QtProperty *property, QWidget *parent) { QSetIterator it(m_managers); while (it.hasNext()) { PropertyManager *manager = it.next(); if (manager == property->propertyManager()) { return createEditor(manager, property, parent); } } return 0; } void addPropertyManager(PropertyManager *manager) { if (m_managers.contains(manager)) return; m_managers.insert(manager); connectPropertyManager(manager); connect(manager, SIGNAL(destroyed(QObject *)), this, SLOT(managerDestroyed(QObject *))); } void removePropertyManager(PropertyManager *manager) { if (!m_managers.contains(manager)) return; disconnect(manager, SIGNAL(destroyed(QObject *)), this, SLOT(managerDestroyed(QObject *))); disconnectPropertyManager(manager); m_managers.remove(manager); } QSet propertyManagers() const { return m_managers; } PropertyManager *propertyManager(QtProperty *property) const { QtAbstractPropertyManager *manager = property->propertyManager(); QSetIterator itManager(m_managers); while (itManager.hasNext()) { PropertyManager *m = itManager.next(); if (m == manager) { return m; } } return 0; } protected: virtual void connectPropertyManager(PropertyManager *manager) = 0; virtual QWidget *createEditor(PropertyManager *manager, QtProperty *property, QWidget *parent) = 0; virtual void disconnectPropertyManager(PropertyManager *manager) = 0; void managerDestroyed(QObject *manager) { QSetIterator it(m_managers); while (it.hasNext()) { PropertyManager *m = it.next(); if (m == manager) { m_managers.remove(m); return; } } } private: void breakConnection(QtAbstractPropertyManager *manager) { QSetIterator it(m_managers); while (it.hasNext()) { PropertyManager *m = it.next(); if (m == manager) { removePropertyManager(m); return; } } } private: QSet m_managers; friend class QtAbstractPropertyEditor; }; class QtAbstractPropertyBrowser; class QtBrowserItemPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtBrowserItem { public: QtProperty *property() const; QtBrowserItem *parent() const; QList children() const; QtAbstractPropertyBrowser *browser() const; private: explicit QtBrowserItem(QtAbstractPropertyBrowser *browser, QtProperty *property, QtBrowserItem *parent); ~QtBrowserItem(); QtBrowserItemPrivate *d_ptr; friend class QtAbstractPropertyBrowserPrivate; }; class QtAbstractPropertyBrowserPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtAbstractPropertyBrowser : public QWidget { Q_OBJECT public: explicit QtAbstractPropertyBrowser(QWidget *parent = 0); ~QtAbstractPropertyBrowser(); QList properties() const; QList items(QtProperty *property) const; QtBrowserItem *topLevelItem(QtProperty *property) const; QList topLevelItems() const; void clear(); template void setFactoryForManager(PropertyManager *manager, QtAbstractEditorFactory *factory) { QtAbstractPropertyManager *abstractManager = manager; QtAbstractEditorFactoryBase *abstractFactory = factory; if (addFactory(abstractManager, abstractFactory)) factory->addPropertyManager(manager); } void unsetFactoryForManager(QtAbstractPropertyManager *manager); QtBrowserItem *currentItem() const; void setCurrentItem(QtBrowserItem *); Q_SIGNALS: void currentItemChanged(QtBrowserItem *); public Q_SLOTS: QtBrowserItem *addProperty(QtProperty *property); QtBrowserItem *insertProperty(QtProperty *property, QtProperty *afterProperty); void removeProperty(QtProperty *property); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) = 0; virtual void itemRemoved(QtBrowserItem *item) = 0; // can be tooltip, statustip, whatsthis, name, icon, text. virtual void itemChanged(QtBrowserItem *item) = 0; virtual QWidget *createEditor(QtProperty *property, QWidget *parent); private: bool addFactory(QtAbstractPropertyManager *abstractManager, QtAbstractEditorFactoryBase *abstractFactory); QtAbstractPropertyBrowserPrivate *d_ptr; Q_DECLARE_PRIVATE(QtAbstractPropertyBrowser) Q_DISABLE_COPY(QtAbstractPropertyBrowser) Q_PRIVATE_SLOT(d_func(), void slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotPropertyRemoved(QtProperty *, QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDataChanged(QtProperty *)) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif // QTPROPERTYBROWSER_H tiled-0.14.2/src/qtpropertybrowser/src/qtpropertybrowser.pri000066400000000000000000000022251260670167100244720ustar00rootroot00000000000000include(../common.pri) greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets INCLUDEPATH += $$PWD DEPENDPATH += $$PWD qtpropertybrowser-uselib:!qtpropertybrowser-buildlib { LIBS += -L$$QTPROPERTYBROWSER_LIBDIR -l$$QTPROPERTYBROWSER_LIBNAME } else { SOURCES += $$PWD/qtpropertybrowser.cpp \ $$PWD/qtpropertymanager.cpp \ $$PWD/qteditorfactory.cpp \ $$PWD/qtvariantproperty.cpp \ $$PWD/qttreepropertybrowser.cpp \ $$PWD/qtbuttonpropertybrowser.cpp \ $$PWD/qtgroupboxpropertybrowser.cpp \ $$PWD/qtpropertybrowserutils.cpp HEADERS += $$PWD/qtpropertybrowser.h \ $$PWD/qtpropertymanager.h \ $$PWD/qteditorfactory.h \ $$PWD/qtvariantproperty.h \ $$PWD/qttreepropertybrowser.h \ $$PWD/qtbuttonpropertybrowser.h \ $$PWD/qtgroupboxpropertybrowser.h \ $$PWD/qtpropertybrowserutils_p.h RESOURCES += $$PWD/qtpropertybrowser.qrc } win32 { contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTPROPERTYBROWSER_EXPORT else:qtpropertybrowser-uselib:DEFINES += QT_QTPROPERTYBROWSER_IMPORT } tiled-0.14.2/src/qtpropertybrowser/src/qtpropertybrowser.qrc000066400000000000000000000016471260670167100244740ustar00rootroot00000000000000 images/cursor-arrow.png images/cursor-busy.png images/cursor-closedhand.png images/cursor-cross.png images/cursor-forbidden.png images/cursor-hand.png images/cursor-hsplit.png images/cursor-ibeam.png images/cursor-openhand.png images/cursor-sizeall.png images/cursor-sizeb.png images/cursor-sizef.png images/cursor-sizeh.png images/cursor-sizev.png images/cursor-uparrow.png images/cursor-vsplit.png images/cursor-wait.png images/cursor-whatsthis.png tiled-0.14.2/src/qtpropertybrowser/src/qtpropertybrowserutils.cpp000066400000000000000000000367161260670167100255570ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtpropertybrowserutils_p.h" #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif QtCursorDatabase::QtCursorDatabase() { appendCursor(Qt::ArrowCursor, QCoreApplication::translate("QtCursorDatabase", "Arrow"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-arrow.png"))); appendCursor(Qt::UpArrowCursor, QCoreApplication::translate("QtCursorDatabase", "Up Arrow"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-uparrow.png"))); appendCursor(Qt::CrossCursor, QCoreApplication::translate("QtCursorDatabase", "Cross"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-cross.png"))); appendCursor(Qt::WaitCursor, QCoreApplication::translate("QtCursorDatabase", "Wait"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-wait.png"))); appendCursor(Qt::IBeamCursor, QCoreApplication::translate("QtCursorDatabase", "IBeam"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-ibeam.png"))); appendCursor(Qt::SizeVerCursor, QCoreApplication::translate("QtCursorDatabase", "Size Vertical"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizev.png"))); appendCursor(Qt::SizeHorCursor, QCoreApplication::translate("QtCursorDatabase", "Size Horizontal"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeh.png"))); appendCursor(Qt::SizeFDiagCursor, QCoreApplication::translate("QtCursorDatabase", "Size Backslash"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizef.png"))); appendCursor(Qt::SizeBDiagCursor, QCoreApplication::translate("QtCursorDatabase", "Size Slash"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeb.png"))); appendCursor(Qt::SizeAllCursor, QCoreApplication::translate("QtCursorDatabase", "Size All"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-sizeall.png"))); appendCursor(Qt::BlankCursor, QCoreApplication::translate("QtCursorDatabase", "Blank"), QIcon()); appendCursor(Qt::SplitVCursor, QCoreApplication::translate("QtCursorDatabase", "Split Vertical"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-vsplit.png"))); appendCursor(Qt::SplitHCursor, QCoreApplication::translate("QtCursorDatabase", "Split Horizontal"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-hsplit.png"))); appendCursor(Qt::PointingHandCursor, QCoreApplication::translate("QtCursorDatabase", "Pointing Hand"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-hand.png"))); appendCursor(Qt::ForbiddenCursor, QCoreApplication::translate("QtCursorDatabase", "Forbidden"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-forbidden.png"))); appendCursor(Qt::OpenHandCursor, QCoreApplication::translate("QtCursorDatabase", "Open Hand"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-openhand.png"))); appendCursor(Qt::ClosedHandCursor, QCoreApplication::translate("QtCursorDatabase", "Closed Hand"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-closedhand.png"))); appendCursor(Qt::WhatsThisCursor, QCoreApplication::translate("QtCursorDatabase", "What's This"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-whatsthis.png"))); appendCursor(Qt::BusyCursor, QCoreApplication::translate("QtCursorDatabase", "Busy"), QIcon(QLatin1String(":/qt-project.org/qtpropertybrowser/images/cursor-busy.png"))); } void QtCursorDatabase::clear() { m_cursorNames.clear(); m_cursorIcons.clear(); m_valueToCursorShape.clear(); m_cursorShapeToValue.clear(); } void QtCursorDatabase::appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon) { if (m_cursorShapeToValue.contains(shape)) return; const int value = m_cursorNames.count(); m_cursorNames.append(name); m_cursorIcons.insert(value, icon); m_valueToCursorShape.insert(value, shape); m_cursorShapeToValue.insert(shape, value); } QStringList QtCursorDatabase::cursorShapeNames() const { return m_cursorNames; } QMap QtCursorDatabase::cursorShapeIcons() const { return m_cursorIcons; } QString QtCursorDatabase::cursorToShapeName(const QCursor &cursor) const { int val = cursorToValue(cursor); if (val >= 0) return m_cursorNames.at(val); return QString(); } QIcon QtCursorDatabase::cursorToShapeIcon(const QCursor &cursor) const { int val = cursorToValue(cursor); return m_cursorIcons.value(val); } int QtCursorDatabase::cursorToValue(const QCursor &cursor) const { #ifndef QT_NO_CURSOR Qt::CursorShape shape = cursor.shape(); if (m_cursorShapeToValue.contains(shape)) return m_cursorShapeToValue[shape]; #endif return -1; } #ifndef QT_NO_CURSOR QCursor QtCursorDatabase::valueToCursor(int value) const { if (m_valueToCursorShape.contains(value)) return QCursor(m_valueToCursorShape[value]); return QCursor(); } #endif QPixmap QtPropertyBrowserUtils::brushValuePixmap(const QBrush &b) { QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); img.fill(0); QPainter painter(&img); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.fillRect(0, 0, img.width(), img.height(), b); QColor color = b.color(); if (color.alpha() != 255) { // indicate alpha by an inset QBrush opaqueBrush = b; color.setAlpha(255); opaqueBrush.setColor(color); painter.fillRect(img.width() / 4, img.height() / 4, img.width() / 2, img.height() / 2, opaqueBrush); } painter.end(); return QPixmap::fromImage(img); } QIcon QtPropertyBrowserUtils::brushValueIcon(const QBrush &b) { return QIcon(brushValuePixmap(b)); } QString QtPropertyBrowserUtils::colorValueText(const QColor &c) { return QCoreApplication::translate("QtPropertyBrowserUtils", "[%1, %2, %3] (%4)") .arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha()); } QPixmap QtPropertyBrowserUtils::fontValuePixmap(const QFont &font) { QFont f = font; QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); img.fill(0); QPainter p(&img); p.setRenderHint(QPainter::TextAntialiasing, true); p.setRenderHint(QPainter::Antialiasing, true); f.setPointSize(13); p.setFont(f); QTextOption t; t.setAlignment(Qt::AlignCenter); p.drawText(QRect(0, 0, 16, 16), QString(QLatin1Char('A')), t); return QPixmap::fromImage(img); } QIcon QtPropertyBrowserUtils::fontValueIcon(const QFont &f) { return QIcon(fontValuePixmap(f)); } QString QtPropertyBrowserUtils::fontValueText(const QFont &f) { return QCoreApplication::translate("QtPropertyBrowserUtils", "[%1, %2]") .arg(f.family()).arg(f.pointSize()); } QtBoolEdit::QtBoolEdit(QWidget *parent) : QWidget(parent), m_checkBox(new QCheckBox(this)), m_textVisible(true) { QHBoxLayout *lt = new QHBoxLayout; if (QApplication::layoutDirection() == Qt::LeftToRight) lt->setContentsMargins(4, 0, 0, 0); else lt->setContentsMargins(0, 0, 4, 0); lt->addWidget(m_checkBox); setLayout(lt); connect(m_checkBox, SIGNAL(toggled(bool)), this, SIGNAL(toggled(bool))); setFocusProxy(m_checkBox); m_checkBox->setText(tr("True")); } void QtBoolEdit::setTextVisible(bool textVisible) { if (m_textVisible == textVisible) return; m_textVisible = textVisible; if (m_textVisible) m_checkBox->setText(isChecked() ? tr("True") : tr("False")); else m_checkBox->setText(QString()); } Qt::CheckState QtBoolEdit::checkState() const { return m_checkBox->checkState(); } void QtBoolEdit::setCheckState(Qt::CheckState state) { m_checkBox->setCheckState(state); } bool QtBoolEdit::isChecked() const { return m_checkBox->isChecked(); } void QtBoolEdit::setChecked(bool c) { m_checkBox->setChecked(c); if (!m_textVisible) return; m_checkBox->setText(isChecked() ? tr("True") : tr("False")); } bool QtBoolEdit::blockCheckBoxSignals(bool block) { return m_checkBox->blockSignals(block); } void QtBoolEdit::mousePressEvent(QMouseEvent *event) { if (event->buttons() == Qt::LeftButton) { m_checkBox->click(); event->accept(); } else { QWidget::mousePressEvent(event); } } void QtBoolEdit::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } QtKeySequenceEdit::QtKeySequenceEdit(QWidget *parent) : QWidget(parent), m_num(0), m_lineEdit(new QLineEdit(this)) { QHBoxLayout *layout = new QHBoxLayout(this); layout->addWidget(m_lineEdit); layout->setMargin(0); m_lineEdit->installEventFilter(this); m_lineEdit->setReadOnly(true); m_lineEdit->setFocusProxy(this); setFocusPolicy(m_lineEdit->focusPolicy()); setAttribute(Qt::WA_InputMethodEnabled); } bool QtKeySequenceEdit::eventFilter(QObject *o, QEvent *e) { if (o == m_lineEdit && e->type() == QEvent::ContextMenu) { QContextMenuEvent *c = static_cast(e); QMenu *menu = m_lineEdit->createStandardContextMenu(); const QList actions = menu->actions(); QListIterator itAction(actions); while (itAction.hasNext()) { QAction *action = itAction.next(); action->setShortcut(QKeySequence()); QString actionString = action->text(); const int pos = actionString.lastIndexOf(QLatin1Char('\t')); if (pos > 0) actionString.remove(pos, actionString.length() - pos); action->setText(actionString); } QAction *actionBefore = 0; if (actions.count() > 0) actionBefore = actions[0]; QAction *clearAction = new QAction(tr("Clear Shortcut"), menu); menu->insertAction(actionBefore, clearAction); menu->insertSeparator(actionBefore); clearAction->setEnabled(!m_keySequence.isEmpty()); connect(clearAction, SIGNAL(triggered()), this, SLOT(slotClearShortcut())); menu->exec(c->globalPos()); delete menu; e->accept(); return true; } return QWidget::eventFilter(o, e); } void QtKeySequenceEdit::slotClearShortcut() { if (m_keySequence.isEmpty()) return; setKeySequence(QKeySequence()); emit keySequenceChanged(m_keySequence); } void QtKeySequenceEdit::handleKeyEvent(QKeyEvent *e) { int nextKey = e->key(); if (nextKey == Qt::Key_Control || nextKey == Qt::Key_Shift || nextKey == Qt::Key_Meta || nextKey == Qt::Key_Alt || nextKey == Qt::Key_Super_L || nextKey == Qt::Key_AltGr) return; nextKey |= translateModifiers(e->modifiers(), e->text()); int k0 = m_keySequence[0]; int k1 = m_keySequence[1]; int k2 = m_keySequence[2]; int k3 = m_keySequence[3]; switch (m_num) { case 0: k0 = nextKey; k1 = 0; k2 = 0; k3 = 0; break; case 1: k1 = nextKey; k2 = 0; k3 = 0; break; case 2: k2 = nextKey; k3 = 0; break; case 3: k3 = nextKey; break; default: break; } ++m_num; if (m_num > 3) m_num = 0; m_keySequence = QKeySequence(k0, k1, k2, k3); m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText)); e->accept(); emit keySequenceChanged(m_keySequence); } void QtKeySequenceEdit::setKeySequence(const QKeySequence &sequence) { if (sequence == m_keySequence) return; m_num = 0; m_keySequence = sequence; m_lineEdit->setText(m_keySequence.toString(QKeySequence::NativeText)); } QKeySequence QtKeySequenceEdit::keySequence() const { return m_keySequence; } int QtKeySequenceEdit::translateModifiers(Qt::KeyboardModifiers state, const QString &text) const { int result = 0; if ((state & Qt::ShiftModifier) && (text.size() == 0 || !text.at(0).isPrint() || text.at(0).isLetter() || text.at(0).isSpace())) result |= Qt::SHIFT; if (state & Qt::ControlModifier) result |= Qt::CTRL; if (state & Qt::MetaModifier) result |= Qt::META; if (state & Qt::AltModifier) result |= Qt::ALT; return result; } void QtKeySequenceEdit::focusInEvent(QFocusEvent *e) { m_lineEdit->event(e); m_lineEdit->selectAll(); QWidget::focusInEvent(e); } void QtKeySequenceEdit::focusOutEvent(QFocusEvent *e) { m_num = 0; m_lineEdit->event(e); QWidget::focusOutEvent(e); } void QtKeySequenceEdit::keyPressEvent(QKeyEvent *e) { handleKeyEvent(e); e->accept(); } void QtKeySequenceEdit::keyReleaseEvent(QKeyEvent *e) { m_lineEdit->event(e); } void QtKeySequenceEdit::paintEvent(QPaintEvent *) { QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } bool QtKeySequenceEdit::event(QEvent *e) { if (e->type() == QEvent::Shortcut || e->type() == QEvent::ShortcutOverride || e->type() == QEvent::KeyRelease) { e->accept(); return true; } return QWidget::event(e); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif tiled-0.14.2/src/qtpropertybrowser/src/qtpropertybrowserutils_p.h000066400000000000000000000115551260670167100255350ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists for the convenience // of Qt Designer. This header // file may change from version to version without notice, or even be removed. // // We mean it. // #ifndef QTPROPERTYBROWSERUTILS_H #define QTPROPERTYBROWSERUTILS_H #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QMouseEvent; class QCheckBox; class QLineEdit; class QtCursorDatabase { public: QtCursorDatabase(); void clear(); QStringList cursorShapeNames() const; QMap cursorShapeIcons() const; QString cursorToShapeName(const QCursor &cursor) const; QIcon cursorToShapeIcon(const QCursor &cursor) const; int cursorToValue(const QCursor &cursor) const; #ifndef QT_NO_CURSOR QCursor valueToCursor(int value) const; #endif private: void appendCursor(Qt::CursorShape shape, const QString &name, const QIcon &icon); QStringList m_cursorNames; QMap m_cursorIcons; QMap m_valueToCursorShape; QMap m_cursorShapeToValue; }; class QtPropertyBrowserUtils { public: static QPixmap brushValuePixmap(const QBrush &b); static QIcon brushValueIcon(const QBrush &b); static QString colorValueText(const QColor &c); static QPixmap fontValuePixmap(const QFont &f); static QIcon fontValueIcon(const QFont &f); static QString fontValueText(const QFont &f); }; class QtBoolEdit : public QWidget { Q_OBJECT public: QtBoolEdit(QWidget *parent = 0); bool textVisible() const { return m_textVisible; } void setTextVisible(bool textVisible); Qt::CheckState checkState() const; void setCheckState(Qt::CheckState state); bool isChecked() const; void setChecked(bool c); bool blockCheckBoxSignals(bool block); Q_SIGNALS: void toggled(bool); protected: void mousePressEvent(QMouseEvent * event); void paintEvent(QPaintEvent *); private: QCheckBox *m_checkBox; bool m_textVisible; }; class QtKeySequenceEdit : public QWidget { Q_OBJECT public: QtKeySequenceEdit(QWidget *parent = 0); QKeySequence keySequence() const; bool eventFilter(QObject *o, QEvent *e); public Q_SLOTS: void setKeySequence(const QKeySequence &sequence); Q_SIGNALS: void keySequenceChanged(const QKeySequence &sequence); protected: void focusInEvent(QFocusEvent *e); void focusOutEvent(QFocusEvent *e); void keyPressEvent(QKeyEvent *e); void keyReleaseEvent(QKeyEvent *e); void paintEvent(QPaintEvent *); bool event(QEvent *e); private slots: void slotClearShortcut(); private: void handleKeyEvent(QKeyEvent *e); int translateModifiers(Qt::KeyboardModifiers state, const QString &text) const; int m_num; QKeySequence m_keySequence; QLineEdit *m_lineEdit; }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif tiled-0.14.2/src/qtpropertybrowser/src/qtpropertymanager.cpp000066400000000000000000006457551260670167100244360ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtpropertymanager.h" #include "qtpropertybrowserutils_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_CC_MSVC) # pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ #endif #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif template static void setSimpleMinimumData(PrivateData *data, const Value &minVal) { data->minVal = minVal; if (data->maxVal < data->minVal) data->maxVal = data->minVal; if (data->val < data->minVal) data->val = data->minVal; } template static void setSimpleMaximumData(PrivateData *data, const Value &maxVal) { data->maxVal = maxVal; if (data->minVal > data->maxVal) data->minVal = data->maxVal; if (data->val > data->maxVal) data->val = data->maxVal; } template static void setSizeMinimumData(PrivateData *data, const Value &newMinVal) { data->minVal = newMinVal; if (data->maxVal.width() < data->minVal.width()) data->maxVal.setWidth(data->minVal.width()); if (data->maxVal.height() < data->minVal.height()) data->maxVal.setHeight(data->minVal.height()); if (data->val.width() < data->minVal.width()) data->val.setWidth(data->minVal.width()); if (data->val.height() < data->minVal.height()) data->val.setHeight(data->minVal.height()); } template static void setSizeMaximumData(PrivateData *data, const Value &newMaxVal) { data->maxVal = newMaxVal; if (data->minVal.width() > data->maxVal.width()) data->minVal.setWidth(data->maxVal.width()); if (data->minVal.height() > data->maxVal.height()) data->minVal.setHeight(data->maxVal.height()); if (data->val.width() > data->maxVal.width()) data->val.setWidth(data->maxVal.width()); if (data->val.height() > data->maxVal.height()) data->val.setHeight(data->maxVal.height()); } template static SizeValue qBoundSize(const SizeValue &minVal, const SizeValue &val, const SizeValue &maxVal) { SizeValue croppedVal = val; if (minVal.width() > val.width()) croppedVal.setWidth(minVal.width()); else if (maxVal.width() < val.width()) croppedVal.setWidth(maxVal.width()); if (minVal.height() > val.height()) croppedVal.setHeight(minVal.height()); else if (maxVal.height() < val.height()) croppedVal.setHeight(maxVal.height()); return croppedVal; } // Match the exact signature of qBound for VS 6. QSize qBound(QSize minVal, QSize val, QSize maxVal) { return qBoundSize(minVal, val, maxVal); } QSizeF qBound(QSizeF minVal, QSizeF val, QSizeF maxVal) { return qBoundSize(minVal, val, maxVal); } namespace { namespace { template void orderBorders(Value &minVal, Value &maxVal) { if (minVal > maxVal) qSwap(minVal, maxVal); } template static void orderSizeBorders(Value &minVal, Value &maxVal) { Value fromSize = minVal; Value toSize = maxVal; if (fromSize.width() > toSize.width()) { fromSize.setWidth(maxVal.width()); toSize.setWidth(minVal.width()); } if (fromSize.height() > toSize.height()) { fromSize.setHeight(maxVal.height()); toSize.setHeight(minVal.height()); } minVal = fromSize; maxVal = toSize; } void orderBorders(QSize &minVal, QSize &maxVal) { orderSizeBorders(minVal, maxVal); } void orderBorders(QSizeF &minVal, QSizeF &maxVal) { orderSizeBorders(minVal, maxVal); } } } //////// template static Value getData(const QMap &propertyMap, Value PrivateData::*data, const QtProperty *property, const Value &defaultValue = Value()) { typedef QMap PropertyToData; typedef typename PropertyToData::const_iterator PropertyToDataConstIterator; const PropertyToDataConstIterator it = propertyMap.constFind(property); if (it == propertyMap.constEnd()) return defaultValue; return it.value().*data; } template static Value getValue(const QMap &propertyMap, const QtProperty *property, const Value &defaultValue = Value()) { return getData(propertyMap, &PrivateData::val, property, defaultValue); } template static Value getMinimum(const QMap &propertyMap, const QtProperty *property, const Value &defaultValue = Value()) { return getData(propertyMap, &PrivateData::minVal, property, defaultValue); } template static Value getMaximum(const QMap &propertyMap, const QtProperty *property, const Value &defaultValue = Value()) { return getData(propertyMap, &PrivateData::maxVal, property, defaultValue); } template static void setSimpleValue(QMap &propertyMap, PropertyManager *manager, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), QtProperty *property, const Value &val) { typedef QMap PropertyToData; typedef typename PropertyToData::iterator PropertyToDataIterator; const PropertyToDataIterator it = propertyMap.find(property); if (it == propertyMap.end()) return; if (it.value() == val) return; it.value() = val; emit (manager->*propertyChangedSignal)(property); emit (manager->*valueChangedSignal)(property, val); } template static void setValueInRange(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), QtProperty *property, const Value &val, void (PropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, ValueChangeParameter)) { typedef typename PropertyManagerPrivate::Data PrivateData; typedef QMap PropertyToData; typedef typename PropertyToData::iterator PropertyToDataIterator; const PropertyToDataIterator it = managerPrivate->m_values.find(property); if (it == managerPrivate->m_values.end()) return; PrivateData &data = it.value(); if (data.val == val) return; const Value oldVal = data.val; data.val = qBound(data.minVal, val, data.maxVal); if (data.val == oldVal) return; if (setSubPropertyValue) (managerPrivate->*setSubPropertyValue)(property, data.val); emit (manager->*propertyChangedSignal)(property); emit (manager->*valueChangedSignal)(property, data.val); } template static void setBorderValues(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), QtProperty *property, const Value &minVal, const Value &maxVal, void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, ValueChangeParameter, ValueChangeParameter, ValueChangeParameter)) { typedef typename PropertyManagerPrivate::Data PrivateData; typedef QMap PropertyToData; typedef typename PropertyToData::iterator PropertyToDataIterator; const PropertyToDataIterator it = managerPrivate->m_values.find(property); if (it == managerPrivate->m_values.end()) return; Value fromVal = minVal; Value toVal = maxVal; orderBorders(fromVal, toVal); PrivateData &data = it.value(); if (data.minVal == fromVal && data.maxVal == toVal) return; const Value oldVal = data.val; data.setMinimumValue(fromVal); data.setMaximumValue(toVal); emit (manager->*rangeChangedSignal)(property, data.minVal, data.maxVal); if (setSubPropertyRange) (managerPrivate->*setSubPropertyRange)(property, data.minVal, data.maxVal, data.val); if (data.val == oldVal) return; emit (manager->*propertyChangedSignal)(property); emit (manager->*valueChangedSignal)(property, data.val); } template static void setBorderValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), QtProperty *property, Value (PrivateData::*getRangeVal)() const, void (PrivateData::*setRangeVal)(ValueChangeParameter), const Value &borderVal, void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, ValueChangeParameter, ValueChangeParameter, ValueChangeParameter)) { typedef QMap PropertyToData; typedef typename PropertyToData::iterator PropertyToDataIterator; const PropertyToDataIterator it = managerPrivate->m_values.find(property); if (it == managerPrivate->m_values.end()) return; PrivateData &data = it.value(); if ((data.*getRangeVal)() == borderVal) return; const Value oldVal = data.val; (data.*setRangeVal)(borderVal); emit (manager->*rangeChangedSignal)(property, data.minVal, data.maxVal); if (setSubPropertyRange) (managerPrivate->*setSubPropertyRange)(property, data.minVal, data.maxVal, data.val); if (data.val == oldVal) return; emit (manager->*propertyChangedSignal)(property); emit (manager->*valueChangedSignal)(property, data.val); } template static void setMinimumValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), QtProperty *property, const Value &minVal) { void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, ValueChangeParameter, ValueChangeParameter, ValueChangeParameter) = 0; setBorderValue(manager, managerPrivate, propertyChangedSignal, valueChangedSignal, rangeChangedSignal, property, &PropertyManagerPrivate::Data::minimumValue, &PropertyManagerPrivate::Data::setMinimumValue, minVal, setSubPropertyRange); } template static void setMaximumValue(PropertyManager *manager, PropertyManagerPrivate *managerPrivate, void (PropertyManager::*propertyChangedSignal)(QtProperty *), void (PropertyManager::*valueChangedSignal)(QtProperty *, ValueChangeParameter), void (PropertyManager::*rangeChangedSignal)(QtProperty *, ValueChangeParameter, ValueChangeParameter), QtProperty *property, const Value &maxVal) { void (PropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, ValueChangeParameter, ValueChangeParameter, ValueChangeParameter) = 0; setBorderValue(manager, managerPrivate, propertyChangedSignal, valueChangedSignal, rangeChangedSignal, property, &PropertyManagerPrivate::Data::maximumValue, &PropertyManagerPrivate::Data::setMaximumValue, maxVal, setSubPropertyRange); } class QtMetaEnumWrapper : public QObject { Q_OBJECT Q_PROPERTY(QSizePolicy::Policy policy READ policy) public: QSizePolicy::Policy policy() const { return QSizePolicy::Ignored; } private: QtMetaEnumWrapper(QObject *parent) : QObject(parent) {} }; class QtMetaEnumProvider { public: QtMetaEnumProvider(); QStringList policyEnumNames() const { return m_policyEnumNames; } QStringList languageEnumNames() const { return m_languageEnumNames; } QStringList countryEnumNames(QLocale::Language language) const { return m_countryEnumNames.value(language); } QSizePolicy::Policy indexToSizePolicy(int index) const; int sizePolicyToIndex(QSizePolicy::Policy policy) const; void indexToLocale(int languageIndex, int countryIndex, QLocale::Language *language, QLocale::Country *country) const; void localeToIndex(QLocale::Language language, QLocale::Country country, int *languageIndex, int *countryIndex) const; private: void initLocale(); QStringList m_policyEnumNames; QStringList m_languageEnumNames; QMap m_countryEnumNames; QMap m_indexToLanguage; QMap m_languageToIndex; QMap > m_indexToCountry; QMap > m_countryToIndex; QMetaEnum m_policyEnum; }; #if QT_VERSION < 0x040300 static QList countriesForLanguage(QLocale::Language language) { QList countries; QLocale::Country country = QLocale::AnyCountry; while (country <= QLocale::LastCountry) { QLocale locale(language, country); if (locale.language() == language && !countries.contains(locale.country())) countries << locale.country(); country = (QLocale::Country)((uint)country + 1); // ++country } return countries; } #endif static QList sortCountries(const QList &countries) { QMultiMap nameToCountry; QListIterator itCountry(countries); while (itCountry.hasNext()) { QLocale::Country country = itCountry.next(); nameToCountry.insert(QLocale::countryToString(country), country); } return nameToCountry.values(); } void QtMetaEnumProvider::initLocale() { QMultiMap nameToLanguage; QLocale::Language language = QLocale::C; while (language <= QLocale::LastLanguage) { QLocale locale(language); if (locale.language() == language) nameToLanguage.insert(QLocale::languageToString(language), language); language = (QLocale::Language)((uint)language + 1); // ++language } const QLocale system = QLocale::system(); if (!nameToLanguage.contains(QLocale::languageToString(system.language()))) nameToLanguage.insert(QLocale::languageToString(system.language()), system.language()); QList languages = nameToLanguage.values(); QListIterator itLang(languages); while (itLang.hasNext()) { QLocale::Language language = itLang.next(); QList countries; #if QT_VERSION < 0x040300 countries = countriesForLanguage(language); #else countries = QLocale::countriesForLanguage(language); #endif if (countries.isEmpty() && language == system.language()) countries << system.country(); if (!countries.isEmpty() && !m_languageToIndex.contains(language)) { countries = sortCountries(countries); int langIdx = m_languageEnumNames.count(); m_indexToLanguage[langIdx] = language; m_languageToIndex[language] = langIdx; QStringList countryNames; QListIterator it(countries); int countryIdx = 0; while (it.hasNext()) { QLocale::Country country = it.next(); countryNames << QLocale::countryToString(country); m_indexToCountry[langIdx][countryIdx] = country; m_countryToIndex[language][country] = countryIdx; ++countryIdx; } m_languageEnumNames << QLocale::languageToString(language); m_countryEnumNames[language] = countryNames; } } } QtMetaEnumProvider::QtMetaEnumProvider() { QMetaProperty p; p = QtMetaEnumWrapper::staticMetaObject.property( QtMetaEnumWrapper::staticMetaObject.propertyOffset() + 0); m_policyEnum = p.enumerator(); const int keyCount = m_policyEnum.keyCount(); for (int i = 0; i < keyCount; i++) m_policyEnumNames << QLatin1String(m_policyEnum.key(i)); initLocale(); } QSizePolicy::Policy QtMetaEnumProvider::indexToSizePolicy(int index) const { return static_cast(m_policyEnum.value(index)); } int QtMetaEnumProvider::sizePolicyToIndex(QSizePolicy::Policy policy) const { const int keyCount = m_policyEnum.keyCount(); for (int i = 0; i < keyCount; i++) if (indexToSizePolicy(i) == policy) return i; return -1; } void QtMetaEnumProvider::indexToLocale(int languageIndex, int countryIndex, QLocale::Language *language, QLocale::Country *country) const { QLocale::Language l = QLocale::C; QLocale::Country c = QLocale::AnyCountry; if (m_indexToLanguage.contains(languageIndex)) { l = m_indexToLanguage[languageIndex]; if (m_indexToCountry.contains(languageIndex) && m_indexToCountry[languageIndex].contains(countryIndex)) c = m_indexToCountry[languageIndex][countryIndex]; } if (language) *language = l; if (country) *country = c; } void QtMetaEnumProvider::localeToIndex(QLocale::Language language, QLocale::Country country, int *languageIndex, int *countryIndex) const { int l = -1; int c = -1; if (m_languageToIndex.contains(language)) { l = m_languageToIndex[language]; if (m_countryToIndex.contains(language) && m_countryToIndex[language].contains(country)) c = m_countryToIndex[language][country]; } if (languageIndex) *languageIndex = l; if (countryIndex) *countryIndex = c; } Q_GLOBAL_STATIC(QtMetaEnumProvider, metaEnumProvider) // QtGroupPropertyManager /*! \class QtGroupPropertyManager \brief The QtGroupPropertyManager provides and manages group properties. This class is intended to provide a grouping element without any value. \sa QtAbstractPropertyManager */ /*! Creates a manager with the given \a parent. */ QtGroupPropertyManager::QtGroupPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { } /*! Destroys this manager, and all the properties it has created. */ QtGroupPropertyManager::~QtGroupPropertyManager() { } /*! \reimp */ bool QtGroupPropertyManager::hasValue(const QtProperty *property) const { Q_UNUSED(property) return false; } /*! \reimp */ void QtGroupPropertyManager::initializeProperty(QtProperty *property) { Q_UNUSED(property) } /*! \reimp */ void QtGroupPropertyManager::uninitializeProperty(QtProperty *property) { Q_UNUSED(property) } // QtIntPropertyManager class QtIntPropertyManagerPrivate { QtIntPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtIntPropertyManager) public: struct Data { Data() : val(0), minVal(-INT_MAX), maxVal(INT_MAX), singleStep(1), readOnly(false) {} int val; int minVal; int maxVal; int singleStep; bool readOnly; int minimumValue() const { return minVal; } int maximumValue() const { return maxVal; } void setMinimumValue(int newMinVal) { setSimpleMinimumData(this, newMinVal); } void setMaximumValue(int newMaxVal) { setSimpleMaximumData(this, newMaxVal); } }; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtIntPropertyManager \brief The QtIntPropertyManager provides and manages int properties. An int property has a current value, and a range specifying the valid values. The range is defined by a minimum and a maximum value. The property's value and range can be retrieved using the value(), minimum() and maximum() functions, and can be set using the setValue(), setMinimum() and setMaximum() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtIntPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid values. \sa QtAbstractPropertyManager, QtSpinBoxFactory, QtSliderFactory, QtScrollBarFactory */ /*! \fn void QtIntPropertyManager::valueChanged(QtProperty *property, int value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtIntPropertyManager::rangeChanged(QtProperty *property, int minimum, int maximum) This signal is emitted whenever a property created by this manager changes its range of valid values, passing a pointer to the \a property and the new \a minimum and \a maximum values. \sa setRange() */ /*! \fn void QtIntPropertyManager::singleStepChanged(QtProperty *property, int step) This signal is emitted whenever a property created by this manager changes its single step property, passing a pointer to the \a property and the new \a step value \sa setSingleStep() */ /*! Creates a manager with the given \a parent. */ QtIntPropertyManager::QtIntPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtIntPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtIntPropertyManager::~QtIntPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns 0. \sa setValue() */ int QtIntPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, 0); } /*! Returns the given \a property's minimum value. \sa setMinimum(), maximum(), setRange() */ int QtIntPropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property, 0); } /*! Returns the given \a property's maximum value. \sa setMaximum(), minimum(), setRange() */ int QtIntPropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property, 0); } /*! Returns the given \a property's step value. The step is typically used to increment or decrement a property value while pressing an arrow key. \sa setSingleStep() */ int QtIntPropertyManager::singleStep(const QtProperty *property) const { return getData(d_ptr->m_values, &QtIntPropertyManagerPrivate::Data::singleStep, property, 0); } /*! Returns read-only status of the property. When property is read-only it's value can be selected and copied from editor but not modified. \sa QtIntPropertyManager::setReadOnly */ bool QtIntPropertyManager::isReadOnly(const QtProperty *property) const { return getData(d_ptr->m_values, &QtIntPropertyManagerPrivate::Data::readOnly, property, false); } /*! \reimp */ QString QtIntPropertyManager::valueText(const QtProperty *property) const { const QtIntPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return QString::number(it.value().val); } /*! \fn void QtIntPropertyManager::setValue(QtProperty *property, int value) Sets the value of the given \a property to \a value. If the specified \a value is not valid according to the given \a property's range, the \a value is adjusted to the nearest valid value within the range. \sa value(), setRange(), valueChanged() */ void QtIntPropertyManager::setValue(QtProperty *property, int val) { void (QtIntPropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, int) = 0; setValueInRange(this, d_ptr, &QtIntPropertyManager::propertyChanged, &QtIntPropertyManager::valueChanged, property, val, setSubPropertyValue); } /*! Sets the minimum value for the given \a property to \a minVal. When setting the minimum value, the maximum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within the range). \sa minimum(), setRange(), rangeChanged() */ void QtIntPropertyManager::setMinimum(QtProperty *property, int minVal) { setMinimumValue(this, d_ptr, &QtIntPropertyManager::propertyChanged, &QtIntPropertyManager::valueChanged, &QtIntPropertyManager::rangeChanged, property, minVal); } /*! Sets the maximum value for the given \a property to \a maxVal. When setting maximum value, the minimum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within the range). \sa maximum(), setRange(), rangeChanged() */ void QtIntPropertyManager::setMaximum(QtProperty *property, int maxVal) { setMaximumValue(this, d_ptr, &QtIntPropertyManager::propertyChanged, &QtIntPropertyManager::valueChanged, &QtIntPropertyManager::rangeChanged, property, maxVal); } /*! \fn void QtIntPropertyManager::setRange(QtProperty *property, int minimum, int maximum) Sets the range of valid values. This is a convenience function defining the range of valid values in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new range, the current value is adjusted if necessary (ensuring that the value remains within range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtIntPropertyManager::setRange(QtProperty *property, int minVal, int maxVal) { void (QtIntPropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, int, int, int) = 0; setBorderValues(this, d_ptr, &QtIntPropertyManager::propertyChanged, &QtIntPropertyManager::valueChanged, &QtIntPropertyManager::rangeChanged, property, minVal, maxVal, setSubPropertyRange); } /*! Sets the step value for the given \a property to \a step. The step is typically used to increment or decrement a property value while pressing an arrow key. \sa singleStep() */ void QtIntPropertyManager::setSingleStep(QtProperty *property, int step) { const QtIntPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtIntPropertyManagerPrivate::Data data = it.value(); if (step < 0) step = 0; if (data.singleStep == step) return; data.singleStep = step; it.value() = data; emit singleStepChanged(property, data.singleStep); } /*! Sets read-only status of the property. \sa QtIntPropertyManager::setReadOnly */ void QtIntPropertyManager::setReadOnly(QtProperty *property, bool readOnly) { const QtIntPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtIntPropertyManagerPrivate::Data data = it.value(); if (data.readOnly == readOnly) return; data.readOnly = readOnly; it.value() = data; emit propertyChanged(property); emit readOnlyChanged(property, data.readOnly); } /*! \reimp */ void QtIntPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtIntPropertyManagerPrivate::Data(); } /*! \reimp */ void QtIntPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtDoublePropertyManager class QtDoublePropertyManagerPrivate { QtDoublePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtDoublePropertyManager) public: struct Data { Data() : val(0), minVal(-INT_MAX), maxVal(INT_MAX), singleStep(1), decimals(2), readOnly(false) {} double val; double minVal; double maxVal; double singleStep; int decimals; bool readOnly; double minimumValue() const { return minVal; } double maximumValue() const { return maxVal; } void setMinimumValue(double newMinVal) { setSimpleMinimumData(this, newMinVal); } void setMaximumValue(double newMaxVal) { setSimpleMaximumData(this, newMaxVal); } }; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtDoublePropertyManager \brief The QtDoublePropertyManager provides and manages double properties. A double property has a current value, and a range specifying the valid values. The range is defined by a minimum and a maximum value. The property's value and range can be retrieved using the value(), minimum() and maximum() functions, and can be set using the setValue(), setMinimum() and setMaximum() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtDoublePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid values. \sa QtAbstractPropertyManager, QtDoubleSpinBoxFactory */ /*! \fn void QtDoublePropertyManager::valueChanged(QtProperty *property, double value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtDoublePropertyManager::rangeChanged(QtProperty *property, double minimum, double maximum) This signal is emitted whenever a property created by this manager changes its range of valid values, passing a pointer to the \a property and the new \a minimum and \a maximum values \sa setRange() */ /*! \fn void QtDoublePropertyManager::decimalsChanged(QtProperty *property, int prec) This signal is emitted whenever a property created by this manager changes its precision of value, passing a pointer to the \a property and the new \a prec value \sa setDecimals() */ /*! \fn void QtDoublePropertyManager::singleStepChanged(QtProperty *property, double step) This signal is emitted whenever a property created by this manager changes its single step property, passing a pointer to the \a property and the new \a step value \sa setSingleStep() */ /*! Creates a manager with the given \a parent. */ QtDoublePropertyManager::QtDoublePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtDoublePropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtDoublePropertyManager::~QtDoublePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns 0. \sa setValue() */ double QtDoublePropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, 0.0); } /*! Returns the given \a property's minimum value. \sa maximum(), setRange() */ double QtDoublePropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property, 0.0); } /*! Returns the given \a property's maximum value. \sa minimum(), setRange() */ double QtDoublePropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property, 0.0); } /*! Returns the given \a property's step value. The step is typically used to increment or decrement a property value while pressing an arrow key. \sa setSingleStep() */ double QtDoublePropertyManager::singleStep(const QtProperty *property) const { return getData(d_ptr->m_values, &QtDoublePropertyManagerPrivate::Data::singleStep, property, 0); } /*! Returns the given \a property's precision, in decimals. \sa setDecimals() */ int QtDoublePropertyManager::decimals(const QtProperty *property) const { return getData(d_ptr->m_values, &QtDoublePropertyManagerPrivate::Data::decimals, property, 0); } /*! Returns read-only status of the property. When property is read-only it's value can be selected and copied from editor but not modified. \sa QtDoublePropertyManager::setReadOnly */ bool QtDoublePropertyManager::isReadOnly(const QtProperty *property) const { return getData(d_ptr->m_values, &QtDoublePropertyManagerPrivate::Data::readOnly, property, false); } /*! \reimp */ QString QtDoublePropertyManager::valueText(const QtProperty *property) const { const QtDoublePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return QLocale::system().toString(it.value().val, 'f', it.value().decimals); } /*! \fn void QtDoublePropertyManager::setValue(QtProperty *property, double value) Sets the value of the given \a property to \a value. If the specified \a value is not valid according to the given \a property's range, the \a value is adjusted to the nearest valid value within the range. \sa value(), setRange(), valueChanged() */ void QtDoublePropertyManager::setValue(QtProperty *property, double val) { void (QtDoublePropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, double) = 0; setValueInRange(this, d_ptr, &QtDoublePropertyManager::propertyChanged, &QtDoublePropertyManager::valueChanged, property, val, setSubPropertyValue); } /*! Sets the step value for the given \a property to \a step. The step is typically used to increment or decrement a property value while pressing an arrow key. \sa singleStep() */ void QtDoublePropertyManager::setSingleStep(QtProperty *property, double step) { const QtDoublePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtDoublePropertyManagerPrivate::Data data = it.value(); if (step < 0) step = 0; if (data.singleStep == step) return; data.singleStep = step; it.value() = data; emit singleStepChanged(property, data.singleStep); } /*! Sets read-only status of the property. \sa QtDoublePropertyManager::setReadOnly */ void QtDoublePropertyManager::setReadOnly(QtProperty *property, bool readOnly) { const QtDoublePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtDoublePropertyManagerPrivate::Data data = it.value(); if (data.readOnly == readOnly) return; data.readOnly = readOnly; it.value() = data; emit propertyChanged(property); emit readOnlyChanged(property, data.readOnly); } /*! \fn void QtDoublePropertyManager::setDecimals(QtProperty *property, int prec) Sets the precision of the given \a property to \a prec. The valid decimal range is 0-13. The default is 2. \sa decimals() */ void QtDoublePropertyManager::setDecimals(QtProperty *property, int prec) { const QtDoublePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtDoublePropertyManagerPrivate::Data data = it.value(); if (prec > 13) prec = 13; else if (prec < 0) prec = 0; if (data.decimals == prec) return; data.decimals = prec; it.value() = data; emit decimalsChanged(property, data.decimals); } /*! Sets the minimum value for the given \a property to \a minVal. When setting the minimum value, the maximum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within in the range). \sa minimum(), setRange(), rangeChanged() */ void QtDoublePropertyManager::setMinimum(QtProperty *property, double minVal) { setMinimumValue(this, d_ptr, &QtDoublePropertyManager::propertyChanged, &QtDoublePropertyManager::valueChanged, &QtDoublePropertyManager::rangeChanged, property, minVal); } /*! Sets the maximum value for the given \a property to \a maxVal. When setting the maximum value, the minimum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within in the range). \sa maximum(), setRange(), rangeChanged() */ void QtDoublePropertyManager::setMaximum(QtProperty *property, double maxVal) { setMaximumValue(this, d_ptr, &QtDoublePropertyManager::propertyChanged, &QtDoublePropertyManager::valueChanged, &QtDoublePropertyManager::rangeChanged, property, maxVal); } /*! \fn void QtDoublePropertyManager::setRange(QtProperty *property, double minimum, double maximum) Sets the range of valid values. This is a convenience function defining the range of valid values in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new range, the current value is adjusted if necessary (ensuring that the value remains within range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtDoublePropertyManager::setRange(QtProperty *property, double minVal, double maxVal) { void (QtDoublePropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, double, double, double) = 0; setBorderValues(this, d_ptr, &QtDoublePropertyManager::propertyChanged, &QtDoublePropertyManager::valueChanged, &QtDoublePropertyManager::rangeChanged, property, minVal, maxVal, setSubPropertyRange); } /*! \reimp */ void QtDoublePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtDoublePropertyManagerPrivate::Data(); } /*! \reimp */ void QtDoublePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtStringPropertyManager class QtStringPropertyManagerPrivate { QtStringPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtStringPropertyManager) public: struct Data { Data() : regExp(QString(QLatin1Char('*')), Qt::CaseSensitive, QRegExp::Wildcard), echoMode(QLineEdit::Normal), readOnly(false) { } QString val; QRegExp regExp; int echoMode; bool readOnly; }; typedef QMap PropertyValueMap; QMap m_values; }; /*! \class QtStringPropertyManager \brief The QtStringPropertyManager provides and manages QString properties. A string property's value can be retrieved using the value() function, and set using the setValue() slot. The current value can be checked against a regular expression. To set the regular expression use the setRegExp() slot, use the regExp() function to retrieve the currently set expression. In addition, QtStringPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the regExpChanged() signal which is emitted whenever such a property changes its currently set regular expression. \sa QtAbstractPropertyManager, QtLineEditFactory */ /*! \fn void QtStringPropertyManager::valueChanged(QtProperty *property, const QString &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtStringPropertyManager::regExpChanged(QtProperty *property, const QRegExp ®Exp) This signal is emitted whenever a property created by this manager changes its currenlty set regular expression, passing a pointer to the \a property and the new \a regExp as parameters. \sa setRegExp() */ /*! Creates a manager with the given \a parent. */ QtStringPropertyManager::QtStringPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtStringPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtStringPropertyManager::~QtStringPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns an empty string. \sa setValue() */ QString QtStringPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's currently set regular expression. If the given \a property is not managed by this manager, this function returns an empty expression. \sa setRegExp() */ QRegExp QtStringPropertyManager::regExp(const QtProperty *property) const { return getData(d_ptr->m_values, &QtStringPropertyManagerPrivate::Data::regExp, property, QRegExp()); } /*! \reimp */ EchoMode QtStringPropertyManager::echoMode(const QtProperty *property) const { return (EchoMode)getData(d_ptr->m_values, &QtStringPropertyManagerPrivate::Data::echoMode, property, 0); } /*! Returns read-only status of the property. When property is read-only it's value can be selected and copied from editor but not modified. \sa QtStringPropertyManager::setReadOnly */ bool QtStringPropertyManager::isReadOnly(const QtProperty *property) const { return getData(d_ptr->m_values, &QtStringPropertyManagerPrivate::Data::readOnly, property, false); } /*! \reimp */ QString QtStringPropertyManager::valueText(const QtProperty *property) const { const QtStringPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().val; } /*! \reimp */ QString QtStringPropertyManager::displayText(const QtProperty *property) const { const QtStringPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); QLineEdit edit; edit.setEchoMode((EchoMode)it.value().echoMode); edit.setText(it.value().val); return edit.displayText(); } /*! \fn void QtStringPropertyManager::setValue(QtProperty *property, const QString &value) Sets the value of the given \a property to \a value. If the specified \a value doesn't match the given \a property's regular expression, this function does nothing. \sa value(), setRegExp(), valueChanged() */ void QtStringPropertyManager::setValue(QtProperty *property, const QString &val) { const QtStringPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtStringPropertyManagerPrivate::Data data = it.value(); if (data.val == val) return; if (data.regExp.isValid() && !data.regExp.exactMatch(val)) return; data.val = val; it.value() = data; emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the regular expression of the given \a property to \a regExp. \sa regExp(), setValue(), regExpChanged() */ void QtStringPropertyManager::setRegExp(QtProperty *property, const QRegExp ®Exp) { const QtStringPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtStringPropertyManagerPrivate::Data data = it.value() ; if (data.regExp == regExp) return; data.regExp = regExp; it.value() = data; emit regExpChanged(property, data.regExp); } void QtStringPropertyManager::setEchoMode(QtProperty *property, EchoMode echoMode) { const QtStringPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtStringPropertyManagerPrivate::Data data = it.value(); if (data.echoMode == echoMode) return; data.echoMode = echoMode; it.value() = data; emit propertyChanged(property); emit echoModeChanged(property, data.echoMode); } /*! Sets read-only status of the property. \sa QtStringPropertyManager::setReadOnly */ void QtStringPropertyManager::setReadOnly(QtProperty *property, bool readOnly) { const QtStringPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtStringPropertyManagerPrivate::Data data = it.value(); if (data.readOnly == readOnly) return; data.readOnly = readOnly; it.value() = data; emit propertyChanged(property); emit echoModeChanged(property, data.echoMode); } /*! \reimp */ void QtStringPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtStringPropertyManagerPrivate::Data(); } /*! \reimp */ void QtStringPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtBoolPropertyManager // Return an icon containing a check box indicator static QIcon drawCheckBox(bool value) { QStyleOptionButton opt; opt.state |= value ? QStyle::State_On : QStyle::State_Off; opt.state |= QStyle::State_Enabled; const QStyle *style = QApplication::style(); // Figure out size of an indicator and make sure it is not scaled down in a list view item // by making the pixmap as big as a list view icon and centering the indicator in it. // (if it is smaller, it can't be helped) const int indicatorWidth = style->pixelMetric(QStyle::PM_IndicatorWidth, &opt); const int indicatorHeight = style->pixelMetric(QStyle::PM_IndicatorHeight, &opt); const int listViewIconSize = indicatorWidth; const int pixmapWidth = indicatorWidth; const int pixmapHeight = qMax(indicatorHeight, listViewIconSize); opt.rect = QRect(0, 0, indicatorWidth, indicatorHeight); QPixmap pixmap = QPixmap(pixmapWidth, pixmapHeight); pixmap.fill(Qt::transparent); { // Center? const int xoff = (pixmapWidth > indicatorWidth) ? (pixmapWidth - indicatorWidth) / 2 : 0; const int yoff = (pixmapHeight > indicatorHeight) ? (pixmapHeight - indicatorHeight) / 2 : 0; QPainter painter(&pixmap); painter.translate(xoff, yoff); style->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, &painter); } return QIcon(pixmap); } class QtBoolPropertyManagerPrivate { QtBoolPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtBoolPropertyManager) public: QtBoolPropertyManagerPrivate(); struct Data { Data() : val(false), textVisible(true) {} bool val; bool textVisible; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; const QIcon m_checkedIcon; const QIcon m_uncheckedIcon; }; QtBoolPropertyManagerPrivate::QtBoolPropertyManagerPrivate() : m_checkedIcon(drawCheckBox(true)), m_uncheckedIcon(drawCheckBox(false)) { } /*! \class QtBoolPropertyManager \brief The QtBoolPropertyManager class provides and manages boolean properties. The property's value can be retrieved using the value() function, and set using the setValue() slot. In addition, QtBoolPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtCheckBoxFactory */ /*! \fn void QtBoolPropertyManager::valueChanged(QtProperty *property, bool value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. */ /*! Creates a manager with the given \a parent. */ QtBoolPropertyManager::QtBoolPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtBoolPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtBoolPropertyManager::~QtBoolPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by \e this manager, this function returns false. \sa setValue() */ bool QtBoolPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, false); } bool QtBoolPropertyManager::textVisible(const QtProperty *property) const { return getData(d_ptr->m_values, &QtBoolPropertyManagerPrivate::Data::textVisible, property, false); } /*! \reimp */ QString QtBoolPropertyManager::valueText(const QtProperty *property) const { const QtBoolPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QtBoolPropertyManagerPrivate::Data &data = it.value(); if (!data.textVisible) return QString(); static const QString trueText = tr("True"); static const QString falseText = tr("False"); return data.val ? trueText : falseText; } /*! \reimp */ QIcon QtBoolPropertyManager::valueIcon(const QtProperty *property) const { const QtBoolPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); return it.value().val ? d_ptr->m_checkedIcon : d_ptr->m_uncheckedIcon; } /*! \fn void QtBoolPropertyManager::setValue(QtProperty *property, bool value) Sets the value of the given \a property to \a value. \sa value() */ void QtBoolPropertyManager::setValue(QtProperty *property, bool val) { const QtBoolPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtBoolPropertyManagerPrivate::Data data = it.value(); if (data.val == val) return; data.val = val; it.value() = data; emit propertyChanged(property); emit valueChanged(property, data.val); } void QtBoolPropertyManager::setTextVisible(QtProperty *property, bool textVisible) { const QtBoolPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtBoolPropertyManagerPrivate::Data data = it.value(); if (data.textVisible == textVisible) return; data.textVisible = textVisible; it.value() = data; emit propertyChanged(property); emit textVisibleChanged(property, data.textVisible); } /*! \reimp */ void QtBoolPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtBoolPropertyManagerPrivate::Data(); } /*! \reimp */ void QtBoolPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtDatePropertyManager class QtDatePropertyManagerPrivate { QtDatePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtDatePropertyManager) public: struct Data { Data() : val(QDate::currentDate()), minVal(QDate(1752, 9, 14)), maxVal(QDate(7999, 12, 31)) {} QDate val; QDate minVal; QDate maxVal; QDate minimumValue() const { return minVal; } QDate maximumValue() const { return maxVal; } void setMinimumValue(const QDate &newMinVal) { setSimpleMinimumData(this, newMinVal); } void setMaximumValue(const QDate &newMaxVal) { setSimpleMaximumData(this, newMaxVal); } }; QString m_format; typedef QMap PropertyValueMap; QMap m_values; }; /*! \class QtDatePropertyManager \brief The QtDatePropertyManager provides and manages QDate properties. A date property has a current value, and a range specifying the valid dates. The range is defined by a minimum and a maximum value. The property's values can be retrieved using the minimum(), maximum() and value() functions, and can be set using the setMinimum(), setMaximum() and setValue() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtDatePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid dates. \sa QtAbstractPropertyManager, QtDateEditFactory, QtDateTimePropertyManager */ /*! \fn void QtDatePropertyManager::valueChanged(QtProperty *property, const QDate &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtDatePropertyManager::rangeChanged(QtProperty *property, const QDate &minimum, const QDate &maximum) This signal is emitted whenever a property created by this manager changes its range of valid dates, passing a pointer to the \a property and the new \a minimum and \a maximum dates. \sa setRange() */ /*! Creates a manager with the given \a parent. */ QtDatePropertyManager::QtDatePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtDatePropertyManagerPrivate; d_ptr->q_ptr = this; QLocale loc; d_ptr->m_format = loc.dateFormat(QLocale::ShortFormat); } /*! Destroys this manager, and all the properties it has created. */ QtDatePropertyManager::~QtDatePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by \e this manager, this function returns an invalid date. \sa setValue() */ QDate QtDatePropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's minimum date. \sa maximum(), setRange() */ QDate QtDatePropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property); } /*! Returns the given \a property's maximum date. \sa minimum(), setRange() */ QDate QtDatePropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property); } /*! \reimp */ QString QtDatePropertyManager::valueText(const QtProperty *property) const { const QtDatePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().val.toString(d_ptr->m_format); } /*! \fn void QtDatePropertyManager::setValue(QtProperty *property, const QDate &value) Sets the value of the given \a property to \a value. If the specified \a value is not a valid date according to the given \a property's range, the value is adjusted to the nearest valid value within the range. \sa value(), setRange(), valueChanged() */ void QtDatePropertyManager::setValue(QtProperty *property, const QDate &val) { void (QtDatePropertyManagerPrivate::*setSubPropertyValue)(QtProperty *, const QDate &) = 0; setValueInRange(this, d_ptr, &QtDatePropertyManager::propertyChanged, &QtDatePropertyManager::valueChanged, property, val, setSubPropertyValue); } /*! Sets the minimum value for the given \a property to \a minVal. When setting the minimum value, the maximum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within in the range). \sa minimum(), setRange() */ void QtDatePropertyManager::setMinimum(QtProperty *property, const QDate &minVal) { setMinimumValue(this, d_ptr, &QtDatePropertyManager::propertyChanged, &QtDatePropertyManager::valueChanged, &QtDatePropertyManager::rangeChanged, property, minVal); } /*! Sets the maximum value for the given \a property to \a maxVal. When setting the maximum value, the minimum and current values are adjusted if necessary (ensuring that the range remains valid and that the current value is within in the range). \sa maximum(), setRange() */ void QtDatePropertyManager::setMaximum(QtProperty *property, const QDate &maxVal) { setMaximumValue(this, d_ptr, &QtDatePropertyManager::propertyChanged, &QtDatePropertyManager::valueChanged, &QtDatePropertyManager::rangeChanged, property, maxVal); } /*! \fn void QtDatePropertyManager::setRange(QtProperty *property, const QDate &minimum, const QDate &maximum) Sets the range of valid dates. This is a convenience function defining the range of valid dates in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new date range, the current value is adjusted if necessary (ensuring that the value remains in date range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtDatePropertyManager::setRange(QtProperty *property, const QDate &minVal, const QDate &maxVal) { void (QtDatePropertyManagerPrivate::*setSubPropertyRange)(QtProperty *, const QDate &, const QDate &, const QDate &) = 0; setBorderValues(this, d_ptr, &QtDatePropertyManager::propertyChanged, &QtDatePropertyManager::valueChanged, &QtDatePropertyManager::rangeChanged, property, minVal, maxVal, setSubPropertyRange); } /*! \reimp */ void QtDatePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtDatePropertyManagerPrivate::Data(); } /*! \reimp */ void QtDatePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtTimePropertyManager class QtTimePropertyManagerPrivate { QtTimePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtTimePropertyManager) public: QString m_format; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtTimePropertyManager \brief The QtTimePropertyManager provides and manages QTime properties. A time property's value can be retrieved using the value() function, and set using the setValue() slot. In addition, QtTimePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtTimeEditFactory */ /*! \fn void QtTimePropertyManager::valueChanged(QtProperty *property, const QTime &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtTimePropertyManager::QtTimePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtTimePropertyManagerPrivate; d_ptr->q_ptr = this; QLocale loc; d_ptr->m_format = loc.timeFormat(QLocale::ShortFormat); } /*! Destroys this manager, and all the properties it has created. */ QtTimePropertyManager::~QtTimePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns an invalid time object. \sa setValue() */ QTime QtTimePropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QTime()); } /*! \reimp */ QString QtTimePropertyManager::valueText(const QtProperty *property) const { const QtTimePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().toString(d_ptr->m_format); } /*! \fn void QtTimePropertyManager::setValue(QtProperty *property, const QTime &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtTimePropertyManager::setValue(QtProperty *property, const QTime &val) { setSimpleValue(d_ptr->m_values, this, &QtTimePropertyManager::propertyChanged, &QtTimePropertyManager::valueChanged, property, val); } /*! \reimp */ void QtTimePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QTime::currentTime(); } /*! \reimp */ void QtTimePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtDateTimePropertyManager class QtDateTimePropertyManagerPrivate { QtDateTimePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtDateTimePropertyManager) public: QString m_format; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtDateTimePropertyManager \brief The QtDateTimePropertyManager provides and manages QDateTime properties. A date and time property has a current value which can be retrieved using the value() function, and set using the setValue() slot. In addition, QtDateTimePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtDateTimeEditFactory, QtDatePropertyManager */ /*! \fn void QtDateTimePropertyManager::valueChanged(QtProperty *property, const QDateTime &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. */ /*! Creates a manager with the given \a parent. */ QtDateTimePropertyManager::QtDateTimePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtDateTimePropertyManagerPrivate; d_ptr->q_ptr = this; QLocale loc; d_ptr->m_format = loc.dateFormat(QLocale::ShortFormat); d_ptr->m_format += QLatin1Char(' '); d_ptr->m_format += loc.timeFormat(QLocale::ShortFormat); } /*! Destroys this manager, and all the properties it has created. */ QtDateTimePropertyManager::~QtDateTimePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid QDateTime object. \sa setValue() */ QDateTime QtDateTimePropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QDateTime()); } /*! \reimp */ QString QtDateTimePropertyManager::valueText(const QtProperty *property) const { const QtDateTimePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().toString(d_ptr->m_format); } /*! \fn void QtDateTimePropertyManager::setValue(QtProperty *property, const QDateTime &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtDateTimePropertyManager::setValue(QtProperty *property, const QDateTime &val) { setSimpleValue(d_ptr->m_values, this, &QtDateTimePropertyManager::propertyChanged, &QtDateTimePropertyManager::valueChanged, property, val); } /*! \reimp */ void QtDateTimePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QDateTime::currentDateTime(); } /*! \reimp */ void QtDateTimePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtKeySequencePropertyManager class QtKeySequencePropertyManagerPrivate { QtKeySequencePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtKeySequencePropertyManager) public: QString m_format; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtKeySequencePropertyManager \brief The QtKeySequencePropertyManager provides and manages QKeySequence properties. A key sequence's value can be retrieved using the value() function, and set using the setValue() slot. In addition, QtKeySequencePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager */ /*! \fn void QtKeySequencePropertyManager::valueChanged(QtProperty *property, const QKeySequence &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. */ /*! Creates a manager with the given \a parent. */ QtKeySequencePropertyManager::QtKeySequencePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtKeySequencePropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtKeySequencePropertyManager::~QtKeySequencePropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an empty QKeySequence object. \sa setValue() */ QKeySequence QtKeySequencePropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QKeySequence()); } /*! \reimp */ QString QtKeySequencePropertyManager::valueText(const QtProperty *property) const { const QtKeySequencePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return it.value().toString(QKeySequence::NativeText); } /*! \fn void QtKeySequencePropertyManager::setValue(QtProperty *property, const QKeySequence &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtKeySequencePropertyManager::setValue(QtProperty *property, const QKeySequence &val) { setSimpleValue(d_ptr->m_values, this, &QtKeySequencePropertyManager::propertyChanged, &QtKeySequencePropertyManager::valueChanged, property, val); } /*! \reimp */ void QtKeySequencePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QKeySequence(); } /*! \reimp */ void QtKeySequencePropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtCharPropertyManager class QtCharPropertyManagerPrivate { QtCharPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtCharPropertyManager) public: typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtCharPropertyManager \brief The QtCharPropertyManager provides and manages QChar properties. A char's value can be retrieved using the value() function, and set using the setValue() slot. In addition, QtCharPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager */ /*! \fn void QtCharPropertyManager::valueChanged(QtProperty *property, const QChar &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. */ /*! Creates a manager with the given \a parent. */ QtCharPropertyManager::QtCharPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtCharPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtCharPropertyManager::~QtCharPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an null QChar object. \sa setValue() */ QChar QtCharPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QChar()); } /*! \reimp */ QString QtCharPropertyManager::valueText(const QtProperty *property) const { const QtCharPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QChar c = it.value(); return c.isNull() ? QString() : QString(c); } /*! \fn void QtCharPropertyManager::setValue(QtProperty *property, const QChar &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtCharPropertyManager::setValue(QtProperty *property, const QChar &val) { setSimpleValue(d_ptr->m_values, this, &QtCharPropertyManager::propertyChanged, &QtCharPropertyManager::valueChanged, property, val); } /*! \reimp */ void QtCharPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QChar(); } /*! \reimp */ void QtCharPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtLocalePropertyManager class QtLocalePropertyManagerPrivate { QtLocalePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtLocalePropertyManager) public: QtLocalePropertyManagerPrivate(); void slotEnumChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtEnumPropertyManager *m_enumPropertyManager; QMap m_propertyToLanguage; QMap m_propertyToCountry; QMap m_languageToProperty; QMap m_countryToProperty; }; QtLocalePropertyManagerPrivate::QtLocalePropertyManagerPrivate() { } void QtLocalePropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) { if (QtProperty *prop = m_languageToProperty.value(property, 0)) { const QLocale loc = m_values[prop]; QLocale::Language newLanguage = loc.language(); QLocale::Country newCountry = loc.country(); metaEnumProvider()->indexToLocale(value, 0, &newLanguage, 0); QLocale newLoc(newLanguage, newCountry); q_ptr->setValue(prop, newLoc); } else if (QtProperty *prop = m_countryToProperty.value(property, 0)) { const QLocale loc = m_values[prop]; QLocale::Language newLanguage = loc.language(); QLocale::Country newCountry = loc.country(); metaEnumProvider()->indexToLocale(m_enumPropertyManager->value(m_propertyToLanguage.value(prop)), value, &newLanguage, &newCountry); QLocale newLoc(newLanguage, newCountry); q_ptr->setValue(prop, newLoc); } } void QtLocalePropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *subProp = m_languageToProperty.value(property, 0)) { m_propertyToLanguage[subProp] = 0; m_languageToProperty.remove(property); } else if (QtProperty *subProp = m_countryToProperty.value(property, 0)) { m_propertyToCountry[subProp] = 0; m_countryToProperty.remove(property); } } /*! \class QtLocalePropertyManager \brief The QtLocalePropertyManager provides and manages QLocale properties. A locale property has nested \e language and \e country subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by QtEnumPropertyManager object. These submanager can be retrieved using the subEnumPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with editor factory. In addition, QtLocalePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtEnumPropertyManager */ /*! \fn void QtLocalePropertyManager::valueChanged(QtProperty *property, const QLocale &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtLocalePropertyManager::QtLocalePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtLocalePropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotEnumChanged(QtProperty *, int))); connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtLocalePropertyManager::~QtLocalePropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e language and \e country subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtEnumPropertyManager *QtLocalePropertyManager::subEnumPropertyManager() const { return d_ptr->m_enumPropertyManager; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns the default locale. \sa setValue() */ QLocale QtLocalePropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QLocale()); } /*! \reimp */ QString QtLocalePropertyManager::valueText(const QtProperty *property) const { const QtLocalePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); QLocale loc = it.value(); int langIdx = 0; int countryIdx = 0; metaEnumProvider()->localeToIndex(loc.language(), loc.country(), &langIdx, &countryIdx); QString str = tr("%1, %2") .arg(metaEnumProvider()->languageEnumNames().at(langIdx)) .arg(metaEnumProvider()->countryEnumNames(loc.language()).at(countryIdx)); return str; } /*! \fn void QtLocalePropertyManager::setValue(QtProperty *property, const QLocale &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtLocalePropertyManager::setValue(QtProperty *property, const QLocale &val) { const QtLocalePropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; const QLocale loc = it.value(); if (loc == val) return; it.value() = val; int langIdx = 0; int countryIdx = 0; metaEnumProvider()->localeToIndex(val.language(), val.country(), &langIdx, &countryIdx); if (loc.language() != val.language()) { d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToLanguage.value(property), langIdx); d_ptr->m_enumPropertyManager->setEnumNames(d_ptr->m_propertyToCountry.value(property), metaEnumProvider()->countryEnumNames(val.language())); } d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToCountry.value(property), countryIdx); emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtLocalePropertyManager::initializeProperty(QtProperty *property) { QLocale val; d_ptr->m_values[property] = val; int langIdx = 0; int countryIdx = 0; metaEnumProvider()->localeToIndex(val.language(), val.country(), &langIdx, &countryIdx); QtProperty *languageProp = d_ptr->m_enumPropertyManager->addProperty(); languageProp->setPropertyName(tr("Language")); d_ptr->m_enumPropertyManager->setEnumNames(languageProp, metaEnumProvider()->languageEnumNames()); d_ptr->m_enumPropertyManager->setValue(languageProp, langIdx); d_ptr->m_propertyToLanguage[property] = languageProp; d_ptr->m_languageToProperty[languageProp] = property; property->addSubProperty(languageProp); QtProperty *countryProp = d_ptr->m_enumPropertyManager->addProperty(); countryProp->setPropertyName(tr("Country")); d_ptr->m_enumPropertyManager->setEnumNames(countryProp, metaEnumProvider()->countryEnumNames(val.language())); d_ptr->m_enumPropertyManager->setValue(countryProp, countryIdx); d_ptr->m_propertyToCountry[property] = countryProp; d_ptr->m_countryToProperty[countryProp] = property; property->addSubProperty(countryProp); } /*! \reimp */ void QtLocalePropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *languageProp = d_ptr->m_propertyToLanguage[property]; if (languageProp) { d_ptr->m_languageToProperty.remove(languageProp); delete languageProp; } d_ptr->m_propertyToLanguage.remove(property); QtProperty *countryProp = d_ptr->m_propertyToCountry[property]; if (countryProp) { d_ptr->m_countryToProperty.remove(countryProp); delete countryProp; } d_ptr->m_propertyToCountry.remove(property); d_ptr->m_values.remove(property); } // QtPointPropertyManager class QtPointPropertyManagerPrivate { QtPointPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtPointPropertyManager) public: void slotIntChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QMap m_propertyToX; QMap m_propertyToY; QMap m_xToProperty; QMap m_yToProperty; }; void QtPointPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *xprop = m_xToProperty.value(property, 0)) { QPoint p = m_values[xprop]; p.setX(value); q_ptr->setValue(xprop, p); } else if (QtProperty *yprop = m_yToProperty.value(property, 0)) { QPoint p = m_values[yprop]; p.setY(value); q_ptr->setValue(yprop, p); } } void QtPointPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { m_propertyToX[pointProp] = 0; m_xToProperty.remove(property); } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { m_propertyToY[pointProp] = 0; m_yToProperty.remove(property); } } /*! \class QtPointPropertyManager \brief The QtPointPropertyManager provides and manages QPoint properties. A point property has nested \e x and \e y subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtIntPropertyManager object. This manager can be retrieved using the subIntPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. In addition, QtPointPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtIntPropertyManager, QtPointFPropertyManager */ /*! \fn void QtPointPropertyManager::valueChanged(QtProperty *property, const QPoint &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtPointPropertyManager::QtPointPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtPointPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtPointPropertyManager::~QtPointPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e x and \e y subproperties. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtPointPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns a point with coordinates (0, 0). \sa setValue() */ QPoint QtPointPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QPoint()); } /*! \reimp */ QString QtPointPropertyManager::valueText(const QtProperty *property) const { const QtPointPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QPoint v = it.value(); return QString(tr("(%1, %2)").arg(QString::number(v.x())) .arg(QString::number(v.y()))); } /*! \fn void QtPointPropertyManager::setValue(QtProperty *property, const QPoint &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtPointPropertyManager::setValue(QtProperty *property, const QPoint &val) { const QtPointPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value() == val) return; it.value() = val; d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToX[property], val.x()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToY[property], val.y()); emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtPointPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QPoint(0, 0); QtProperty *xProp = d_ptr->m_intPropertyManager->addProperty(); xProp->setPropertyName(tr("X")); d_ptr->m_intPropertyManager->setValue(xProp, 0); d_ptr->m_propertyToX[property] = xProp; d_ptr->m_xToProperty[xProp] = property; property->addSubProperty(xProp); QtProperty *yProp = d_ptr->m_intPropertyManager->addProperty(); yProp->setPropertyName(tr("Y")); d_ptr->m_intPropertyManager->setValue(yProp, 0); d_ptr->m_propertyToY[property] = yProp; d_ptr->m_yToProperty[yProp] = property; property->addSubProperty(yProp); } /*! \reimp */ void QtPointPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *xProp = d_ptr->m_propertyToX[property]; if (xProp) { d_ptr->m_xToProperty.remove(xProp); delete xProp; } d_ptr->m_propertyToX.remove(property); QtProperty *yProp = d_ptr->m_propertyToY[property]; if (yProp) { d_ptr->m_yToProperty.remove(yProp); delete yProp; } d_ptr->m_propertyToY.remove(property); d_ptr->m_values.remove(property); } // QtPointFPropertyManager class QtPointFPropertyManagerPrivate { QtPointFPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtPointFPropertyManager) public: struct Data { Data() : decimals(2) {} QPointF val; int decimals; }; void slotDoubleChanged(QtProperty *property, double value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtDoublePropertyManager *m_doublePropertyManager; QMap m_propertyToX; QMap m_propertyToY; QMap m_xToProperty; QMap m_yToProperty; }; void QtPointFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) { if (QtProperty *prop = m_xToProperty.value(property, 0)) { QPointF p = m_values[prop].val; p.setX(value); q_ptr->setValue(prop, p); } else if (QtProperty *prop = m_yToProperty.value(property, 0)) { QPointF p = m_values[prop].val; p.setY(value); q_ptr->setValue(prop, p); } } void QtPointFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { m_propertyToX[pointProp] = 0; m_xToProperty.remove(property); } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { m_propertyToY[pointProp] = 0; m_yToProperty.remove(property); } } /*! \class QtPointFPropertyManager \brief The QtPointFPropertyManager provides and manages QPointF properties. A point property has nested \e x and \e y subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtDoublePropertyManager object. This manager can be retrieved using the subDoublePropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. In addition, QtPointFPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtPointPropertyManager */ /*! \fn void QtPointFPropertyManager::valueChanged(QtProperty *property, const QPointF &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtPointFPropertyManager::decimalsChanged(QtProperty *property, int prec) This signal is emitted whenever a property created by this manager changes its precision of value, passing a pointer to the \a property and the new \a prec value \sa setDecimals() */ /*! Creates a manager with the given \a parent. */ QtPointFPropertyManager::QtPointFPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtPointFPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotDoubleChanged(QtProperty *, double))); connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtPointFPropertyManager::~QtPointFPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e x and \e y subproperties. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtDoublePropertyManager *QtPointFPropertyManager::subDoublePropertyManager() const { return d_ptr->m_doublePropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns a point with coordinates (0, 0). \sa setValue() */ QPointF QtPointFPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's precision, in decimals. \sa setDecimals() */ int QtPointFPropertyManager::decimals(const QtProperty *property) const { return getData(d_ptr->m_values, &QtPointFPropertyManagerPrivate::Data::decimals, property, 0); } /*! \reimp */ QString QtPointFPropertyManager::valueText(const QtProperty *property) const { const QtPointFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QPointF v = it.value().val; const int dec = it.value().decimals; return QString(tr("(%1, %2)").arg(QString::number(v.x(), 'f', dec)) .arg(QString::number(v.y(), 'f', dec))); } /*! \fn void QtPointFPropertyManager::setValue(QtProperty *property, const QPointF &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtPointFPropertyManager::setValue(QtProperty *property, const QPointF &val) { const QtPointFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value().val == val) return; it.value().val = val; d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToX[property], val.x()); d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToY[property], val.y()); emit propertyChanged(property); emit valueChanged(property, val); } /*! \fn void QtPointFPropertyManager::setDecimals(QtProperty *property, int prec) Sets the precision of the given \a property to \a prec. The valid decimal range is 0-13. The default is 2. \sa decimals() */ void QtPointFPropertyManager::setDecimals(QtProperty *property, int prec) { const QtPointFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtPointFPropertyManagerPrivate::Data data = it.value(); if (prec > 13) prec = 13; else if (prec < 0) prec = 0; if (data.decimals == prec) return; data.decimals = prec; d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToX[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToY[property], prec); it.value() = data; emit decimalsChanged(property, data.decimals); } /*! \reimp */ void QtPointFPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtPointFPropertyManagerPrivate::Data(); QtProperty *xProp = d_ptr->m_doublePropertyManager->addProperty(); xProp->setPropertyName(tr("X")); d_ptr->m_doublePropertyManager->setDecimals(xProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(xProp, 0); d_ptr->m_propertyToX[property] = xProp; d_ptr->m_xToProperty[xProp] = property; property->addSubProperty(xProp); QtProperty *yProp = d_ptr->m_doublePropertyManager->addProperty(); yProp->setPropertyName(tr("Y")); d_ptr->m_doublePropertyManager->setDecimals(yProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(yProp, 0); d_ptr->m_propertyToY[property] = yProp; d_ptr->m_yToProperty[yProp] = property; property->addSubProperty(yProp); } /*! \reimp */ void QtPointFPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *xProp = d_ptr->m_propertyToX[property]; if (xProp) { d_ptr->m_xToProperty.remove(xProp); delete xProp; } d_ptr->m_propertyToX.remove(property); QtProperty *yProp = d_ptr->m_propertyToY[property]; if (yProp) { d_ptr->m_yToProperty.remove(yProp); delete yProp; } d_ptr->m_propertyToY.remove(property); d_ptr->m_values.remove(property); } // QtSizePropertyManager class QtSizePropertyManagerPrivate { QtSizePropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtSizePropertyManager) public: void slotIntChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); void setValue(QtProperty *property, const QSize &val); void setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal, const QSize &val); struct Data { Data() : val(QSize(0, 0)), minVal(QSize(0, 0)), maxVal(QSize(INT_MAX, INT_MAX)) {} QSize val; QSize minVal; QSize maxVal; QSize minimumValue() const { return minVal; } QSize maximumValue() const { return maxVal; } void setMinimumValue(const QSize &newMinVal) { setSizeMinimumData(this, newMinVal); } void setMaximumValue(const QSize &newMaxVal) { setSizeMaximumData(this, newMaxVal); } }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QMap m_propertyToW; QMap m_propertyToH; QMap m_wToProperty; QMap m_hToProperty; }; void QtSizePropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *prop = m_wToProperty.value(property, 0)) { QSize s = m_values[prop].val; s.setWidth(value); q_ptr->setValue(prop, s); } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { QSize s = m_values[prop].val; s.setHeight(value); q_ptr->setValue(prop, s); } } void QtSizePropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { m_propertyToW[pointProp] = 0; m_wToProperty.remove(property); } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { m_propertyToH[pointProp] = 0; m_hToProperty.remove(property); } } void QtSizePropertyManagerPrivate::setValue(QtProperty *property, const QSize &val) { m_intPropertyManager->setValue(m_propertyToW.value(property), val.width()); m_intPropertyManager->setValue(m_propertyToH.value(property), val.height()); } void QtSizePropertyManagerPrivate::setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal, const QSize &val) { QtProperty *wProperty = m_propertyToW.value(property); QtProperty *hProperty = m_propertyToH.value(property); m_intPropertyManager->setRange(wProperty, minVal.width(), maxVal.width()); m_intPropertyManager->setValue(wProperty, val.width()); m_intPropertyManager->setRange(hProperty, minVal.height(), maxVal.height()); m_intPropertyManager->setValue(hProperty, val.height()); } /*! \class QtSizePropertyManager \brief The QtSizePropertyManager provides and manages QSize properties. A size property has nested \e width and \e height subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtIntPropertyManager object. This manager can be retrieved using the subIntPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. A size property also has a range of valid values defined by a minimum size and a maximum size. These sizes can be retrieved using the minimum() and the maximum() functions, and set using the setMinimum() and setMaximum() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtSizePropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid sizes. \sa QtAbstractPropertyManager, QtIntPropertyManager, QtSizeFPropertyManager */ /*! \fn void QtSizePropertyManager::valueChanged(QtProperty *property, const QSize &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtSizePropertyManager::rangeChanged(QtProperty *property, const QSize &minimum, const QSize &maximum) This signal is emitted whenever a property created by this manager changes its range of valid sizes, passing a pointer to the \a property and the new \a minimum and \a maximum sizes. \sa setRange() */ /*! Creates a manager with the given \a parent. */ QtSizePropertyManager::QtSizePropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtSizePropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtSizePropertyManager::~QtSizePropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e width and \e height subproperties. In order to provide editing widgets for the \e width and \e height properties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtSizePropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid size \sa setValue() */ QSize QtSizePropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's minimum size value. \sa setMinimum(), maximum(), setRange() */ QSize QtSizePropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property); } /*! Returns the given \a property's maximum size value. \sa setMaximum(), minimum(), setRange() */ QSize QtSizePropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property); } /*! \reimp */ QString QtSizePropertyManager::valueText(const QtProperty *property) const { const QtSizePropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QSize v = it.value().val; return QString(tr("%1 x %2").arg(QString::number(v.width())) .arg(QString::number(v.height()))); } /*! \fn void QtSizePropertyManager::setValue(QtProperty *property, const QSize &value) Sets the value of the given \a property to \a value. If the specified \a value is not valid according to the given \a property's size range, the \a value is adjusted to the nearest valid value within the size range. \sa value(), setRange(), valueChanged() */ void QtSizePropertyManager::setValue(QtProperty *property, const QSize &val) { setValueInRange(this, d_ptr, &QtSizePropertyManager::propertyChanged, &QtSizePropertyManager::valueChanged, property, val, &QtSizePropertyManagerPrivate::setValue); } /*! Sets the minimum size value for the given \a property to \a minVal. When setting the minimum size value, the maximum and current values are adjusted if necessary (ensuring that the size range remains valid and that the current value is within the range). \sa minimum(), setRange(), rangeChanged() */ void QtSizePropertyManager::setMinimum(QtProperty *property, const QSize &minVal) { setBorderValue(this, d_ptr, &QtSizePropertyManager::propertyChanged, &QtSizePropertyManager::valueChanged, &QtSizePropertyManager::rangeChanged, property, &QtSizePropertyManagerPrivate::Data::minimumValue, &QtSizePropertyManagerPrivate::Data::setMinimumValue, minVal, &QtSizePropertyManagerPrivate::setRange); } /*! Sets the maximum size value for the given \a property to \a maxVal. When setting the maximum size value, the minimum and current values are adjusted if necessary (ensuring that the size range remains valid and that the current value is within the range). \sa maximum(), setRange(), rangeChanged() */ void QtSizePropertyManager::setMaximum(QtProperty *property, const QSize &maxVal) { setBorderValue(this, d_ptr, &QtSizePropertyManager::propertyChanged, &QtSizePropertyManager::valueChanged, &QtSizePropertyManager::rangeChanged, property, &QtSizePropertyManagerPrivate::Data::maximumValue, &QtSizePropertyManagerPrivate::Data::setMaximumValue, maxVal, &QtSizePropertyManagerPrivate::setRange); } /*! \fn void QtSizePropertyManager::setRange(QtProperty *property, const QSize &minimum, const QSize &maximum) Sets the range of valid values. This is a convenience function defining the range of valid values in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new range, the current value is adjusted if necessary (ensuring that the value remains within the range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtSizePropertyManager::setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal) { setBorderValues(this, d_ptr, &QtSizePropertyManager::propertyChanged, &QtSizePropertyManager::valueChanged, &QtSizePropertyManager::rangeChanged, property, minVal, maxVal, &QtSizePropertyManagerPrivate::setRange); } /*! \reimp */ void QtSizePropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtSizePropertyManagerPrivate::Data(); QtProperty *wProp = d_ptr->m_intPropertyManager->addProperty(); wProp->setPropertyName(tr("Width")); d_ptr->m_intPropertyManager->setValue(wProp, 0); d_ptr->m_intPropertyManager->setMinimum(wProp, 0); d_ptr->m_propertyToW[property] = wProp; d_ptr->m_wToProperty[wProp] = property; property->addSubProperty(wProp); QtProperty *hProp = d_ptr->m_intPropertyManager->addProperty(); hProp->setPropertyName(tr("Height")); d_ptr->m_intPropertyManager->setValue(hProp, 0); d_ptr->m_intPropertyManager->setMinimum(hProp, 0); d_ptr->m_propertyToH[property] = hProp; d_ptr->m_hToProperty[hProp] = property; property->addSubProperty(hProp); } /*! \reimp */ void QtSizePropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *wProp = d_ptr->m_propertyToW[property]; if (wProp) { d_ptr->m_wToProperty.remove(wProp); delete wProp; } d_ptr->m_propertyToW.remove(property); QtProperty *hProp = d_ptr->m_propertyToH[property]; if (hProp) { d_ptr->m_hToProperty.remove(hProp); delete hProp; } d_ptr->m_propertyToH.remove(property); d_ptr->m_values.remove(property); } // QtSizeFPropertyManager class QtSizeFPropertyManagerPrivate { QtSizeFPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtSizeFPropertyManager) public: void slotDoubleChanged(QtProperty *property, double value); void slotPropertyDestroyed(QtProperty *property); void setValue(QtProperty *property, const QSizeF &val); void setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal, const QSizeF &val); struct Data { Data() : val(QSizeF(0, 0)), minVal(QSizeF(0, 0)), maxVal(QSizeF(INT_MAX, INT_MAX)), decimals(2) {} QSizeF val; QSizeF minVal; QSizeF maxVal; int decimals; QSizeF minimumValue() const { return minVal; } QSizeF maximumValue() const { return maxVal; } void setMinimumValue(const QSizeF &newMinVal) { setSizeMinimumData(this, newMinVal); } void setMaximumValue(const QSizeF &newMaxVal) { setSizeMaximumData(this, newMaxVal); } }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtDoublePropertyManager *m_doublePropertyManager; QMap m_propertyToW; QMap m_propertyToH; QMap m_wToProperty; QMap m_hToProperty; }; void QtSizeFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) { if (QtProperty *prop = m_wToProperty.value(property, 0)) { QSizeF s = m_values[prop].val; s.setWidth(value); q_ptr->setValue(prop, s); } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { QSizeF s = m_values[prop].val; s.setHeight(value); q_ptr->setValue(prop, s); } } void QtSizeFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { m_propertyToW[pointProp] = 0; m_wToProperty.remove(property); } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { m_propertyToH[pointProp] = 0; m_hToProperty.remove(property); } } void QtSizeFPropertyManagerPrivate::setValue(QtProperty *property, const QSizeF &val) { m_doublePropertyManager->setValue(m_propertyToW.value(property), val.width()); m_doublePropertyManager->setValue(m_propertyToH.value(property), val.height()); } void QtSizeFPropertyManagerPrivate::setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal, const QSizeF &val) { m_doublePropertyManager->setRange(m_propertyToW[property], minVal.width(), maxVal.width()); m_doublePropertyManager->setValue(m_propertyToW[property], val.width()); m_doublePropertyManager->setRange(m_propertyToH[property], minVal.height(), maxVal.height()); m_doublePropertyManager->setValue(m_propertyToH[property], val.height()); } /*! \class QtSizeFPropertyManager \brief The QtSizeFPropertyManager provides and manages QSizeF properties. A size property has nested \e width and \e height subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtDoublePropertyManager object. This manager can be retrieved using the subDoublePropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. A size property also has a range of valid values defined by a minimum size and a maximum size. These sizes can be retrieved using the minimum() and the maximum() functions, and set using the setMinimum() and setMaximum() slots. Alternatively, the range can be defined in one go using the setRange() slot. In addition, QtSizeFPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the rangeChanged() signal which is emitted whenever such a property changes its range of valid sizes. \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtSizePropertyManager */ /*! \fn void QtSizeFPropertyManager::valueChanged(QtProperty *property, const QSizeF &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtSizeFPropertyManager::rangeChanged(QtProperty *property, const QSizeF &minimum, const QSizeF &maximum) This signal is emitted whenever a property created by this manager changes its range of valid sizes, passing a pointer to the \a property and the new \a minimum and \a maximum sizes. \sa setRange() */ /*! \fn void QtSizeFPropertyManager::decimalsChanged(QtProperty *property, int prec) This signal is emitted whenever a property created by this manager changes its precision of value, passing a pointer to the \a property and the new \a prec value \sa setDecimals() */ /*! Creates a manager with the given \a parent. */ QtSizeFPropertyManager::QtSizeFPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtSizeFPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotDoubleChanged(QtProperty *, double))); connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtSizeFPropertyManager::~QtSizeFPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e width and \e height subproperties. In order to provide editing widgets for the \e width and \e height properties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtDoublePropertyManager *QtSizeFPropertyManager::subDoublePropertyManager() const { return d_ptr->m_doublePropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid size \sa setValue() */ QSizeF QtSizeFPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's precision, in decimals. \sa setDecimals() */ int QtSizeFPropertyManager::decimals(const QtProperty *property) const { return getData(d_ptr->m_values, &QtSizeFPropertyManagerPrivate::Data::decimals, property, 0); } /*! Returns the given \a property's minimum size value. \sa setMinimum(), maximum(), setRange() */ QSizeF QtSizeFPropertyManager::minimum(const QtProperty *property) const { return getMinimum(d_ptr->m_values, property); } /*! Returns the given \a property's maximum size value. \sa setMaximum(), minimum(), setRange() */ QSizeF QtSizeFPropertyManager::maximum(const QtProperty *property) const { return getMaximum(d_ptr->m_values, property); } /*! \reimp */ QString QtSizeFPropertyManager::valueText(const QtProperty *property) const { const QtSizeFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QSizeF v = it.value().val; const int dec = it.value().decimals; return QString(tr("%1 x %2").arg(QString::number(v.width(), 'f', dec)) .arg(QString::number(v.height(), 'f', dec))); } /*! \fn void QtSizeFPropertyManager::setValue(QtProperty *property, const QSizeF &value) Sets the value of the given \a property to \a value. If the specified \a value is not valid according to the given \a property's size range, the \a value is adjusted to the nearest valid value within the size range. \sa value(), setRange(), valueChanged() */ void QtSizeFPropertyManager::setValue(QtProperty *property, const QSizeF &val) { setValueInRange(this, d_ptr, &QtSizeFPropertyManager::propertyChanged, &QtSizeFPropertyManager::valueChanged, property, val, &QtSizeFPropertyManagerPrivate::setValue); } /*! \fn void QtSizeFPropertyManager::setDecimals(QtProperty *property, int prec) Sets the precision of the given \a property to \a prec. The valid decimal range is 0-13. The default is 2. \sa decimals() */ void QtSizeFPropertyManager::setDecimals(QtProperty *property, int prec) { const QtSizeFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtSizeFPropertyManagerPrivate::Data data = it.value(); if (prec > 13) prec = 13; else if (prec < 0) prec = 0; if (data.decimals == prec) return; data.decimals = prec; d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToW[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToH[property], prec); it.value() = data; emit decimalsChanged(property, data.decimals); } /*! Sets the minimum size value for the given \a property to \a minVal. When setting the minimum size value, the maximum and current values are adjusted if necessary (ensuring that the size range remains valid and that the current value is within the range). \sa minimum(), setRange(), rangeChanged() */ void QtSizeFPropertyManager::setMinimum(QtProperty *property, const QSizeF &minVal) { setBorderValue(this, d_ptr, &QtSizeFPropertyManager::propertyChanged, &QtSizeFPropertyManager::valueChanged, &QtSizeFPropertyManager::rangeChanged, property, &QtSizeFPropertyManagerPrivate::Data::minimumValue, &QtSizeFPropertyManagerPrivate::Data::setMinimumValue, minVal, &QtSizeFPropertyManagerPrivate::setRange); } /*! Sets the maximum size value for the given \a property to \a maxVal. When setting the maximum size value, the minimum and current values are adjusted if necessary (ensuring that the size range remains valid and that the current value is within the range). \sa maximum(), setRange(), rangeChanged() */ void QtSizeFPropertyManager::setMaximum(QtProperty *property, const QSizeF &maxVal) { setBorderValue(this, d_ptr, &QtSizeFPropertyManager::propertyChanged, &QtSizeFPropertyManager::valueChanged, &QtSizeFPropertyManager::rangeChanged, property, &QtSizeFPropertyManagerPrivate::Data::maximumValue, &QtSizeFPropertyManagerPrivate::Data::setMaximumValue, maxVal, &QtSizeFPropertyManagerPrivate::setRange); } /*! \fn void QtSizeFPropertyManager::setRange(QtProperty *property, const QSizeF &minimum, const QSizeF &maximum) Sets the range of valid values. This is a convenience function defining the range of valid values in one go; setting the \a minimum and \a maximum values for the given \a property with a single function call. When setting a new range, the current value is adjusted if necessary (ensuring that the value remains within the range). \sa setMinimum(), setMaximum(), rangeChanged() */ void QtSizeFPropertyManager::setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal) { setBorderValues(this, d_ptr, &QtSizeFPropertyManager::propertyChanged, &QtSizeFPropertyManager::valueChanged, &QtSizeFPropertyManager::rangeChanged, property, minVal, maxVal, &QtSizeFPropertyManagerPrivate::setRange); } /*! \reimp */ void QtSizeFPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtSizeFPropertyManagerPrivate::Data(); QtProperty *wProp = d_ptr->m_doublePropertyManager->addProperty(); wProp->setPropertyName(tr("Width")); d_ptr->m_doublePropertyManager->setDecimals(wProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(wProp, 0); d_ptr->m_doublePropertyManager->setMinimum(wProp, 0); d_ptr->m_propertyToW[property] = wProp; d_ptr->m_wToProperty[wProp] = property; property->addSubProperty(wProp); QtProperty *hProp = d_ptr->m_doublePropertyManager->addProperty(); hProp->setPropertyName(tr("Height")); d_ptr->m_doublePropertyManager->setDecimals(hProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(hProp, 0); d_ptr->m_doublePropertyManager->setMinimum(hProp, 0); d_ptr->m_propertyToH[property] = hProp; d_ptr->m_hToProperty[hProp] = property; property->addSubProperty(hProp); } /*! \reimp */ void QtSizeFPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *wProp = d_ptr->m_propertyToW[property]; if (wProp) { d_ptr->m_wToProperty.remove(wProp); delete wProp; } d_ptr->m_propertyToW.remove(property); QtProperty *hProp = d_ptr->m_propertyToH[property]; if (hProp) { d_ptr->m_hToProperty.remove(hProp); delete hProp; } d_ptr->m_propertyToH.remove(property); d_ptr->m_values.remove(property); } // QtRectPropertyManager class QtRectPropertyManagerPrivate { QtRectPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtRectPropertyManager) public: void slotIntChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); void setConstraint(QtProperty *property, const QRect &constraint, const QRect &val); struct Data { Data() : val(0, 0, 0, 0) {} QRect val; QRect constraint; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QMap m_propertyToX; QMap m_propertyToY; QMap m_propertyToW; QMap m_propertyToH; QMap m_xToProperty; QMap m_yToProperty; QMap m_wToProperty; QMap m_hToProperty; }; void QtRectPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *prop = m_xToProperty.value(property, 0)) { QRect r = m_values[prop].val; r.moveLeft(value); q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_yToProperty.value(property)) { QRect r = m_values[prop].val; r.moveTop(value); q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_wToProperty.value(property, 0)) { Data data = m_values[prop]; QRect r = data.val; r.setWidth(value); if (!data.constraint.isNull() && data.constraint.x() + data.constraint.width() < r.x() + r.width()) { r.moveLeft(data.constraint.left() + data.constraint.width() - r.width()); } q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { Data data = m_values[prop]; QRect r = data.val; r.setHeight(value); if (!data.constraint.isNull() && data.constraint.y() + data.constraint.height() < r.y() + r.height()) { r.moveTop(data.constraint.top() + data.constraint.height() - r.height()); } q_ptr->setValue(prop, r); } } void QtRectPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { m_propertyToX[pointProp] = 0; m_xToProperty.remove(property); } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { m_propertyToY[pointProp] = 0; m_yToProperty.remove(property); } else if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { m_propertyToW[pointProp] = 0; m_wToProperty.remove(property); } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { m_propertyToH[pointProp] = 0; m_hToProperty.remove(property); } } void QtRectPropertyManagerPrivate::setConstraint(QtProperty *property, const QRect &constraint, const QRect &val) { const bool isNull = constraint.isNull(); const int left = isNull ? INT_MIN : constraint.left(); const int right = isNull ? INT_MAX : constraint.left() + constraint.width(); const int top = isNull ? INT_MIN : constraint.top(); const int bottom = isNull ? INT_MAX : constraint.top() + constraint.height(); const int width = isNull ? INT_MAX : constraint.width(); const int height = isNull ? INT_MAX : constraint.height(); m_intPropertyManager->setRange(m_propertyToX[property], left, right); m_intPropertyManager->setRange(m_propertyToY[property], top, bottom); m_intPropertyManager->setRange(m_propertyToW[property], 0, width); m_intPropertyManager->setRange(m_propertyToH[property], 0, height); m_intPropertyManager->setValue(m_propertyToX[property], val.x()); m_intPropertyManager->setValue(m_propertyToY[property], val.y()); m_intPropertyManager->setValue(m_propertyToW[property], val.width()); m_intPropertyManager->setValue(m_propertyToH[property], val.height()); } /*! \class QtRectPropertyManager \brief The QtRectPropertyManager provides and manages QRect properties. A rectangle property has nested \e x, \e y, \e width and \e height subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtIntPropertyManager object. This manager can be retrieved using the subIntPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. A rectangle property also has a constraint rectangle which can be retrieved using the constraint() function, and set using the setConstraint() slot. In addition, QtRectPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the constraintChanged() signal which is emitted whenever such a property changes its constraint rectangle. \sa QtAbstractPropertyManager, QtIntPropertyManager, QtRectFPropertyManager */ /*! \fn void QtRectPropertyManager::valueChanged(QtProperty *property, const QRect &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtRectPropertyManager::constraintChanged(QtProperty *property, const QRect &constraint) This signal is emitted whenever property changes its constraint rectangle, passing a pointer to the \a property and the new \a constraint rectangle as parameters. \sa setConstraint() */ /*! Creates a manager with the given \a parent. */ QtRectPropertyManager::QtRectPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtRectPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtRectPropertyManager::~QtRectPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e x, \e y, \e width and \e height subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtRectPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid rectangle. \sa setValue(), constraint() */ QRect QtRectPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's constraining rectangle. If returned value is null QRect it means there is no constraint applied. \sa value(), setConstraint() */ QRect QtRectPropertyManager::constraint(const QtProperty *property) const { return getData(d_ptr->m_values, &QtRectPropertyManagerPrivate::Data::constraint, property, QRect()); } /*! \reimp */ QString QtRectPropertyManager::valueText(const QtProperty *property) const { const QtRectPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QRect v = it.value().val; return QString(tr("[(%1, %2), %3 x %4]").arg(QString::number(v.x())) .arg(QString::number(v.y())) .arg(QString::number(v.width())) .arg(QString::number(v.height()))); } /*! \fn void QtRectPropertyManager::setValue(QtProperty *property, const QRect &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. If the specified \a value is not inside the given \a property's constraining rectangle, the value is adjusted accordingly to fit within the constraint. \sa value(), setConstraint(), valueChanged() */ void QtRectPropertyManager::setValue(QtProperty *property, const QRect &val) { const QtRectPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectPropertyManagerPrivate::Data data = it.value(); QRect newRect = val.normalized(); if (!data.constraint.isNull() && !data.constraint.contains(newRect)) { const QRect r1 = data.constraint; const QRect r2 = newRect; newRect.setLeft(qMax(r1.left(), r2.left())); newRect.setRight(qMin(r1.right(), r2.right())); newRect.setTop(qMax(r1.top(), r2.top())); newRect.setBottom(qMin(r1.bottom(), r2.bottom())); if (newRect.width() < 0 || newRect.height() < 0) return; } if (data.val == newRect) return; data.val = newRect; it.value() = data; d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToX[property], newRect.x()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToY[property], newRect.y()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToW[property], newRect.width()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToH[property], newRect.height()); emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's constraining rectangle to \a constraint. When setting the constraint, the current value is adjusted if necessary (ensuring that the current rectangle value is inside the constraint). In order to reset the constraint pass a null QRect value. \sa setValue(), constraint(), constraintChanged() */ void QtRectPropertyManager::setConstraint(QtProperty *property, const QRect &constraint) { const QtRectPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectPropertyManagerPrivate::Data data = it.value(); QRect newConstraint = constraint.normalized(); if (data.constraint == newConstraint) return; const QRect oldVal = data.val; data.constraint = newConstraint; if (!data.constraint.isNull() && !data.constraint.contains(oldVal)) { QRect r1 = data.constraint; QRect r2 = data.val; if (r2.width() > r1.width()) r2.setWidth(r1.width()); if (r2.height() > r1.height()) r2.setHeight(r1.height()); if (r2.left() < r1.left()) r2.moveLeft(r1.left()); else if (r2.right() > r1.right()) r2.moveRight(r1.right()); if (r2.top() < r1.top()) r2.moveTop(r1.top()); else if (r2.bottom() > r1.bottom()) r2.moveBottom(r1.bottom()); data.val = r2; } it.value() = data; emit constraintChanged(property, data.constraint); d_ptr->setConstraint(property, data.constraint, data.val); if (data.val == oldVal) return; emit propertyChanged(property); emit valueChanged(property, data.val); } /*! \reimp */ void QtRectPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtRectPropertyManagerPrivate::Data(); QtProperty *xProp = d_ptr->m_intPropertyManager->addProperty(); xProp->setPropertyName(tr("X")); d_ptr->m_intPropertyManager->setValue(xProp, 0); d_ptr->m_propertyToX[property] = xProp; d_ptr->m_xToProperty[xProp] = property; property->addSubProperty(xProp); QtProperty *yProp = d_ptr->m_intPropertyManager->addProperty(); yProp->setPropertyName(tr("Y")); d_ptr->m_intPropertyManager->setValue(yProp, 0); d_ptr->m_propertyToY[property] = yProp; d_ptr->m_yToProperty[yProp] = property; property->addSubProperty(yProp); QtProperty *wProp = d_ptr->m_intPropertyManager->addProperty(); wProp->setPropertyName(tr("Width")); d_ptr->m_intPropertyManager->setValue(wProp, 0); d_ptr->m_intPropertyManager->setMinimum(wProp, 0); d_ptr->m_propertyToW[property] = wProp; d_ptr->m_wToProperty[wProp] = property; property->addSubProperty(wProp); QtProperty *hProp = d_ptr->m_intPropertyManager->addProperty(); hProp->setPropertyName(tr("Height")); d_ptr->m_intPropertyManager->setValue(hProp, 0); d_ptr->m_intPropertyManager->setMinimum(hProp, 0); d_ptr->m_propertyToH[property] = hProp; d_ptr->m_hToProperty[hProp] = property; property->addSubProperty(hProp); } /*! \reimp */ void QtRectPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *xProp = d_ptr->m_propertyToX[property]; if (xProp) { d_ptr->m_xToProperty.remove(xProp); delete xProp; } d_ptr->m_propertyToX.remove(property); QtProperty *yProp = d_ptr->m_propertyToY[property]; if (yProp) { d_ptr->m_yToProperty.remove(yProp); delete yProp; } d_ptr->m_propertyToY.remove(property); QtProperty *wProp = d_ptr->m_propertyToW[property]; if (wProp) { d_ptr->m_wToProperty.remove(wProp); delete wProp; } d_ptr->m_propertyToW.remove(property); QtProperty *hProp = d_ptr->m_propertyToH[property]; if (hProp) { d_ptr->m_hToProperty.remove(hProp); delete hProp; } d_ptr->m_propertyToH.remove(property); d_ptr->m_values.remove(property); } // QtRectFPropertyManager class QtRectFPropertyManagerPrivate { QtRectFPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtRectFPropertyManager) public: void slotDoubleChanged(QtProperty *property, double value); void slotPropertyDestroyed(QtProperty *property); void setConstraint(QtProperty *property, const QRectF &constraint, const QRectF &val); struct Data { Data() : val(0, 0, 0, 0), decimals(2) {} QRectF val; QRectF constraint; int decimals; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtDoublePropertyManager *m_doublePropertyManager; QMap m_propertyToX; QMap m_propertyToY; QMap m_propertyToW; QMap m_propertyToH; QMap m_xToProperty; QMap m_yToProperty; QMap m_wToProperty; QMap m_hToProperty; }; void QtRectFPropertyManagerPrivate::slotDoubleChanged(QtProperty *property, double value) { if (QtProperty *prop = m_xToProperty.value(property, 0)) { QRectF r = m_values[prop].val; r.moveLeft(value); q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_yToProperty.value(property, 0)) { QRectF r = m_values[prop].val; r.moveTop(value); q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_wToProperty.value(property, 0)) { Data data = m_values[prop]; QRectF r = data.val; r.setWidth(value); if (!data.constraint.isNull() && data.constraint.x() + data.constraint.width() < r.x() + r.width()) { r.moveLeft(data.constraint.left() + data.constraint.width() - r.width()); } q_ptr->setValue(prop, r); } else if (QtProperty *prop = m_hToProperty.value(property, 0)) { Data data = m_values[prop]; QRectF r = data.val; r.setHeight(value); if (!data.constraint.isNull() && data.constraint.y() + data.constraint.height() < r.y() + r.height()) { r.moveTop(data.constraint.top() + data.constraint.height() - r.height()); } q_ptr->setValue(prop, r); } } void QtRectFPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_xToProperty.value(property, 0)) { m_propertyToX[pointProp] = 0; m_xToProperty.remove(property); } else if (QtProperty *pointProp = m_yToProperty.value(property, 0)) { m_propertyToY[pointProp] = 0; m_yToProperty.remove(property); } else if (QtProperty *pointProp = m_wToProperty.value(property, 0)) { m_propertyToW[pointProp] = 0; m_wToProperty.remove(property); } else if (QtProperty *pointProp = m_hToProperty.value(property, 0)) { m_propertyToH[pointProp] = 0; m_hToProperty.remove(property); } } void QtRectFPropertyManagerPrivate::setConstraint(QtProperty *property, const QRectF &constraint, const QRectF &val) { const bool isNull = constraint.isNull(); const float left = isNull ? FLT_MIN : constraint.left(); const float right = isNull ? FLT_MAX : constraint.left() + constraint.width(); const float top = isNull ? FLT_MIN : constraint.top(); const float bottom = isNull ? FLT_MAX : constraint.top() + constraint.height(); const float width = isNull ? FLT_MAX : constraint.width(); const float height = isNull ? FLT_MAX : constraint.height(); m_doublePropertyManager->setRange(m_propertyToX[property], left, right); m_doublePropertyManager->setRange(m_propertyToY[property], top, bottom); m_doublePropertyManager->setRange(m_propertyToW[property], 0, width); m_doublePropertyManager->setRange(m_propertyToH[property], 0, height); m_doublePropertyManager->setValue(m_propertyToX[property], val.x()); m_doublePropertyManager->setValue(m_propertyToY[property], val.y()); m_doublePropertyManager->setValue(m_propertyToW[property], val.width()); m_doublePropertyManager->setValue(m_propertyToH[property], val.height()); } /*! \class QtRectFPropertyManager \brief The QtRectFPropertyManager provides and manages QRectF properties. A rectangle property has nested \e x, \e y, \e width and \e height subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtDoublePropertyManager object. This manager can be retrieved using the subDoublePropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. A rectangle property also has a constraint rectangle which can be retrieved using the constraint() function, and set using the setConstraint() slot. In addition, QtRectFPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the constraintChanged() signal which is emitted whenever such a property changes its constraint rectangle. \sa QtAbstractPropertyManager, QtDoublePropertyManager, QtRectPropertyManager */ /*! \fn void QtRectFPropertyManager::valueChanged(QtProperty *property, const QRectF &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtRectFPropertyManager::constraintChanged(QtProperty *property, const QRectF &constraint) This signal is emitted whenever property changes its constraint rectangle, passing a pointer to the \a property and the new \a constraint rectangle as parameters. \sa setConstraint() */ /*! \fn void QtRectFPropertyManager::decimalsChanged(QtProperty *property, int prec) This signal is emitted whenever a property created by this manager changes its precision of value, passing a pointer to the \a property and the new \a prec value \sa setDecimals() */ /*! Creates a manager with the given \a parent. */ QtRectFPropertyManager::QtRectFPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtRectFPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_doublePropertyManager = new QtDoublePropertyManager(this); connect(d_ptr->m_doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotDoubleChanged(QtProperty *, double))); connect(d_ptr->m_doublePropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtRectFPropertyManager::~QtRectFPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e x, \e y, \e width and \e height subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtDoublePropertyManager *QtRectFPropertyManager::subDoublePropertyManager() const { return d_ptr->m_doublePropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid rectangle. \sa setValue(), constraint() */ QRectF QtRectFPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property); } /*! Returns the given \a property's precision, in decimals. \sa setDecimals() */ int QtRectFPropertyManager::decimals(const QtProperty *property) const { return getData(d_ptr->m_values, &QtRectFPropertyManagerPrivate::Data::decimals, property, 0); } /*! Returns the given \a property's constraining rectangle. If returned value is null QRectF it means there is no constraint applied. \sa value(), setConstraint() */ QRectF QtRectFPropertyManager::constraint(const QtProperty *property) const { return getData(d_ptr->m_values, &QtRectFPropertyManagerPrivate::Data::constraint, property, QRect()); } /*! \reimp */ QString QtRectFPropertyManager::valueText(const QtProperty *property) const { const QtRectFPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QRectF v = it.value().val; const int dec = it.value().decimals; return QString(tr("[(%1, %2), %3 x %4]").arg(QString::number(v.x(), 'f', dec)) .arg(QString::number(v.y(), 'f', dec)) .arg(QString::number(v.width(), 'f', dec)) .arg(QString::number(v.height(), 'f', dec))); } /*! \fn void QtRectFPropertyManager::setValue(QtProperty *property, const QRectF &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. If the specified \a value is not inside the given \a property's constraining rectangle, the value is adjusted accordingly to fit within the constraint. \sa value(), setConstraint(), valueChanged() */ void QtRectFPropertyManager::setValue(QtProperty *property, const QRectF &val) { const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectFPropertyManagerPrivate::Data data = it.value(); QRectF newRect = val.normalized(); if (!data.constraint.isNull() && !data.constraint.contains(newRect)) { const QRectF r1 = data.constraint; const QRectF r2 = newRect; newRect.setLeft(qMax(r1.left(), r2.left())); newRect.setRight(qMin(r1.right(), r2.right())); newRect.setTop(qMax(r1.top(), r2.top())); newRect.setBottom(qMin(r1.bottom(), r2.bottom())); if (newRect.width() < 0 || newRect.height() < 0) return; } if (data.val == newRect) return; data.val = newRect; it.value() = data; d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToX[property], newRect.x()); d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToY[property], newRect.y()); d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToW[property], newRect.width()); d_ptr->m_doublePropertyManager->setValue(d_ptr->m_propertyToH[property], newRect.height()); emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's constraining rectangle to \a constraint. When setting the constraint, the current value is adjusted if necessary (ensuring that the current rectangle value is inside the constraint). In order to reset the constraint pass a null QRectF value. \sa setValue(), constraint(), constraintChanged() */ void QtRectFPropertyManager::setConstraint(QtProperty *property, const QRectF &constraint) { const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectFPropertyManagerPrivate::Data data = it.value(); QRectF newConstraint = constraint.normalized(); if (data.constraint == newConstraint) return; const QRectF oldVal = data.val; data.constraint = newConstraint; if (!data.constraint.isNull() && !data.constraint.contains(oldVal)) { QRectF r1 = data.constraint; QRectF r2 = data.val; if (r2.width() > r1.width()) r2.setWidth(r1.width()); if (r2.height() > r1.height()) r2.setHeight(r1.height()); if (r2.left() < r1.left()) r2.moveLeft(r1.left()); else if (r2.right() > r1.right()) r2.moveRight(r1.right()); if (r2.top() < r1.top()) r2.moveTop(r1.top()); else if (r2.bottom() > r1.bottom()) r2.moveBottom(r1.bottom()); data.val = r2; } it.value() = data; emit constraintChanged(property, data.constraint); d_ptr->setConstraint(property, data.constraint, data.val); if (data.val == oldVal) return; emit propertyChanged(property); emit valueChanged(property, data.val); } /*! \fn void QtRectFPropertyManager::setDecimals(QtProperty *property, int prec) Sets the precision of the given \a property to \a prec. The valid decimal range is 0-13. The default is 2. \sa decimals() */ void QtRectFPropertyManager::setDecimals(QtProperty *property, int prec) { const QtRectFPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtRectFPropertyManagerPrivate::Data data = it.value(); if (prec > 13) prec = 13; else if (prec < 0) prec = 0; if (data.decimals == prec) return; data.decimals = prec; d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToX[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToY[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToW[property], prec); d_ptr->m_doublePropertyManager->setDecimals(d_ptr->m_propertyToH[property], prec); it.value() = data; emit decimalsChanged(property, data.decimals); } /*! \reimp */ void QtRectFPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtRectFPropertyManagerPrivate::Data(); QtProperty *xProp = d_ptr->m_doublePropertyManager->addProperty(); xProp->setPropertyName(tr("X")); d_ptr->m_doublePropertyManager->setDecimals(xProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(xProp, 0); d_ptr->m_propertyToX[property] = xProp; d_ptr->m_xToProperty[xProp] = property; property->addSubProperty(xProp); QtProperty *yProp = d_ptr->m_doublePropertyManager->addProperty(); yProp->setPropertyName(tr("Y")); d_ptr->m_doublePropertyManager->setDecimals(yProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(yProp, 0); d_ptr->m_propertyToY[property] = yProp; d_ptr->m_yToProperty[yProp] = property; property->addSubProperty(yProp); QtProperty *wProp = d_ptr->m_doublePropertyManager->addProperty(); wProp->setPropertyName(tr("Width")); d_ptr->m_doublePropertyManager->setDecimals(wProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(wProp, 0); d_ptr->m_doublePropertyManager->setMinimum(wProp, 0); d_ptr->m_propertyToW[property] = wProp; d_ptr->m_wToProperty[wProp] = property; property->addSubProperty(wProp); QtProperty *hProp = d_ptr->m_doublePropertyManager->addProperty(); hProp->setPropertyName(tr("Height")); d_ptr->m_doublePropertyManager->setDecimals(hProp, decimals(property)); d_ptr->m_doublePropertyManager->setValue(hProp, 0); d_ptr->m_doublePropertyManager->setMinimum(hProp, 0); d_ptr->m_propertyToH[property] = hProp; d_ptr->m_hToProperty[hProp] = property; property->addSubProperty(hProp); } /*! \reimp */ void QtRectFPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *xProp = d_ptr->m_propertyToX[property]; if (xProp) { d_ptr->m_xToProperty.remove(xProp); delete xProp; } d_ptr->m_propertyToX.remove(property); QtProperty *yProp = d_ptr->m_propertyToY[property]; if (yProp) { d_ptr->m_yToProperty.remove(yProp); delete yProp; } d_ptr->m_propertyToY.remove(property); QtProperty *wProp = d_ptr->m_propertyToW[property]; if (wProp) { d_ptr->m_wToProperty.remove(wProp); delete wProp; } d_ptr->m_propertyToW.remove(property); QtProperty *hProp = d_ptr->m_propertyToH[property]; if (hProp) { d_ptr->m_hToProperty.remove(hProp); delete hProp; } d_ptr->m_propertyToH.remove(property); d_ptr->m_values.remove(property); } // QtEnumPropertyManager class QtEnumPropertyManagerPrivate { QtEnumPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtEnumPropertyManager) public: struct Data { Data() : val(-1) {} int val; QStringList enumNames; QMap enumIcons; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtEnumPropertyManager \brief The QtEnumPropertyManager provides and manages enum properties. Each enum property has an associated list of enum names which can be retrieved using the enumNames() function, and set using the corresponding setEnumNames() function. An enum property's value is represented by an index in this list, and can be retrieved and set using the value() and setValue() slots respectively. Each enum value can also have an associated icon. The mapping from values to icons can be set using the setEnumIcons() function and queried with the enumIcons() function. In addition, QtEnumPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. The enumNamesChanged() or enumIconsChanged() signal is emitted whenever the list of enum names or icons is altered. \sa QtAbstractPropertyManager, QtEnumEditorFactory */ /*! \fn void QtEnumPropertyManager::valueChanged(QtProperty *property, int value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtEnumPropertyManager::enumNamesChanged(QtProperty *property, const QStringList &names) This signal is emitted whenever a property created by this manager changes its enum names, passing a pointer to the \a property and the new \a names as parameters. \sa setEnumNames() */ /*! \fn void QtEnumPropertyManager::enumIconsChanged(QtProperty *property, const QMap &icons) This signal is emitted whenever a property created by this manager changes its enum icons, passing a pointer to the \a property and the new mapping of values to \a icons as parameters. \sa setEnumIcons() */ /*! Creates a manager with the given \a parent. */ QtEnumPropertyManager::QtEnumPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtEnumPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtEnumPropertyManager::~QtEnumPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value which is an index in the list returned by enumNames() If the given property is not managed by this manager, this function returns -1. \sa enumNames(), setValue() */ int QtEnumPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, -1); } /*! Returns the given \a property's list of enum names. \sa value(), setEnumNames() */ QStringList QtEnumPropertyManager::enumNames(const QtProperty *property) const { return getData(d_ptr->m_values, &QtEnumPropertyManagerPrivate::Data::enumNames, property, QStringList()); } /*! Returns the given \a property's map of enum values to their icons. \sa value(), setEnumIcons() */ QMap QtEnumPropertyManager::enumIcons(const QtProperty *property) const { return getData >(d_ptr->m_values, &QtEnumPropertyManagerPrivate::Data::enumIcons, property, QMap()); } /*! \reimp */ QString QtEnumPropertyManager::valueText(const QtProperty *property) const { const QtEnumPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QtEnumPropertyManagerPrivate::Data &data = it.value(); const int v = data.val; if (v >= 0 && v < data.enumNames.count()) return data.enumNames.at(v); return QString(); } /*! \reimp */ QIcon QtEnumPropertyManager::valueIcon(const QtProperty *property) const { const QtEnumPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); const QtEnumPropertyManagerPrivate::Data &data = it.value(); const int v = data.val; return data.enumIcons.value(v); } /*! \fn void QtEnumPropertyManager::setValue(QtProperty *property, int value) Sets the value of the given \a property to \a value. The specified \a value must be less than the size of the given \a property's enumNames() list, and larger than (or equal to) 0. \sa value(), valueChanged() */ void QtEnumPropertyManager::setValue(QtProperty *property, int val) { const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtEnumPropertyManagerPrivate::Data data = it.value(); if (val >= data.enumNames.count()) return; if (val < 0 && data.enumNames.count() > 0) return; if (val < 0) val = -1; if (data.val == val) return; data.val = val; it.value() = data; emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's list of enum names to \a enumNames. The \a property's current value is reset to 0 indicating the first item of the list. If the specified \a enumNames list is empty, the \a property's current value is set to -1. \sa enumNames(), enumNamesChanged() */ void QtEnumPropertyManager::setEnumNames(QtProperty *property, const QStringList &enumNames) { const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtEnumPropertyManagerPrivate::Data data = it.value(); if (data.enumNames == enumNames) return; data.enumNames = enumNames; data.val = -1; if (enumNames.count() > 0) data.val = 0; it.value() = data; emit enumNamesChanged(property, data.enumNames); emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's map of enum values to their icons to \a enumIcons. Each enum value can have associated icon. This association is represented with passed \a enumIcons map. \sa enumNames(), enumNamesChanged() */ void QtEnumPropertyManager::setEnumIcons(QtProperty *property, const QMap &enumIcons) { const QtEnumPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; it.value().enumIcons = enumIcons; emit enumIconsChanged(property, it.value().enumIcons); emit propertyChanged(property); } /*! \reimp */ void QtEnumPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtEnumPropertyManagerPrivate::Data(); } /*! \reimp */ void QtEnumPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } // QtFlagPropertyManager class QtFlagPropertyManagerPrivate { QtFlagPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtFlagPropertyManager) public: void slotBoolChanged(QtProperty *property, bool value); void slotPropertyDestroyed(QtProperty *property); struct Data { Data() : val(-1) {} int val; QStringList flagNames; }; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtBoolPropertyManager *m_boolPropertyManager; QMap > m_propertyToFlags; QMap m_flagToProperty; }; void QtFlagPropertyManagerPrivate::slotBoolChanged(QtProperty *property, bool value) { QtProperty *prop = m_flagToProperty.value(property, 0); if (prop == 0) return; QListIterator itProp(m_propertyToFlags[prop]); int level = 0; while (itProp.hasNext()) { QtProperty *p = itProp.next(); if (p == property) { int v = m_values[prop].val; if (value) { v |= (1 << level); } else { v &= ~(1 << level); } q_ptr->setValue(prop, v); return; } level++; } } void QtFlagPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { QtProperty *flagProperty = m_flagToProperty.value(property, 0); if (flagProperty == 0) return; m_propertyToFlags[flagProperty].replace(m_propertyToFlags[flagProperty].indexOf(property), 0); m_flagToProperty.remove(property); } /*! \class QtFlagPropertyManager \brief The QtFlagPropertyManager provides and manages flag properties. Each flag property has an associated list of flag names which can be retrieved using the flagNames() function, and set using the corresponding setFlagNames() function. The flag manager provides properties with nested boolean subproperties representing each flag, i.e. a flag property's value is the binary combination of the subproperties' values. A property's value can be retrieved and set using the value() and setValue() slots respectively. The combination of flags is represented by single int value - that's why it's possible to store up to 32 independent flags in one flag property. The subproperties are created by a QtBoolPropertyManager object. This manager can be retrieved using the subBoolPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. In addition, QtFlagPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes, and the flagNamesChanged() signal which is emitted whenever the list of flag names is altered. \sa QtAbstractPropertyManager, QtBoolPropertyManager */ /*! \fn void QtFlagPropertyManager::valueChanged(QtProperty *property, int value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtFlagPropertyManager::flagNamesChanged(QtProperty *property, const QStringList &names) This signal is emitted whenever a property created by this manager changes its flag names, passing a pointer to the \a property and the new \a names as parameters. \sa setFlagNames() */ /*! Creates a manager with the given \a parent. */ QtFlagPropertyManager::QtFlagPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtFlagPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_boolPropertyManager = new QtBoolPropertyManager(this); connect(d_ptr->m_boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotBoolChanged(QtProperty *, bool))); connect(d_ptr->m_boolPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtFlagPropertyManager::~QtFlagPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that produces the nested boolean subproperties representing each flag. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtBoolPropertyManager *QtFlagPropertyManager::subBoolPropertyManager() const { return d_ptr->m_boolPropertyManager; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns 0. \sa flagNames(), setValue() */ int QtFlagPropertyManager::value(const QtProperty *property) const { return getValue(d_ptr->m_values, property, 0); } /*! Returns the given \a property's list of flag names. \sa value(), setFlagNames() */ QStringList QtFlagPropertyManager::flagNames(const QtProperty *property) const { return getData(d_ptr->m_values, &QtFlagPropertyManagerPrivate::Data::flagNames, property, QStringList()); } /*! \reimp */ QString QtFlagPropertyManager::valueText(const QtProperty *property) const { const QtFlagPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QtFlagPropertyManagerPrivate::Data &data = it.value(); QString str; int level = 0; const QChar bar = QLatin1Char('|'); const QStringList::const_iterator fncend = data.flagNames.constEnd(); for (QStringList::const_iterator it = data.flagNames.constBegin(); it != fncend; ++it) { if (data.val & (1 << level)) { if (!str.isEmpty()) str += bar; str += *it; } level++; } return str; } /*! \fn void QtFlagPropertyManager::setValue(QtProperty *property, int value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. The specified \a value must be less than the binary combination of the property's flagNames() list size (i.e. less than 2\sup n, where \c n is the size of the list) and larger than (or equal to) 0. \sa value(), valueChanged() */ void QtFlagPropertyManager::setValue(QtProperty *property, int val) { const QtFlagPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtFlagPropertyManagerPrivate::Data data = it.value(); if (data.val == val) return; if (val > (1 << data.flagNames.count()) - 1) return; if (val < 0) return; data.val = val; it.value() = data; QListIterator itProp(d_ptr->m_propertyToFlags[property]); int level = 0; while (itProp.hasNext()) { QtProperty *prop = itProp.next(); if (prop) d_ptr->m_boolPropertyManager->setValue(prop, val & (1 << level)); level++; } emit propertyChanged(property); emit valueChanged(property, data.val); } /*! Sets the given \a property's list of flag names to \a flagNames. The property's current value is reset to 0 indicating the first item of the list. \sa flagNames(), flagNamesChanged() */ void QtFlagPropertyManager::setFlagNames(QtProperty *property, const QStringList &flagNames) { const QtFlagPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; QtFlagPropertyManagerPrivate::Data data = it.value(); if (data.flagNames == flagNames) return; data.flagNames = flagNames; data.val = 0; it.value() = data; QListIterator itProp(d_ptr->m_propertyToFlags[property]); while (itProp.hasNext()) { QtProperty *prop = itProp.next(); if (prop) { delete prop; d_ptr->m_flagToProperty.remove(prop); } } d_ptr->m_propertyToFlags[property].clear(); QStringListIterator itFlag(flagNames); while (itFlag.hasNext()) { const QString flagName = itFlag.next(); QtProperty *prop = d_ptr->m_boolPropertyManager->addProperty(); prop->setPropertyName(flagName); property->addSubProperty(prop); d_ptr->m_propertyToFlags[property].append(prop); d_ptr->m_flagToProperty[prop] = property; } emit flagNamesChanged(property, data.flagNames); emit propertyChanged(property); emit valueChanged(property, data.val); } /*! \reimp */ void QtFlagPropertyManager::initializeProperty(QtProperty *property) { d_ptr->m_values[property] = QtFlagPropertyManagerPrivate::Data(); d_ptr->m_propertyToFlags[property] = QList(); } /*! \reimp */ void QtFlagPropertyManager::uninitializeProperty(QtProperty *property) { QListIterator itProp(d_ptr->m_propertyToFlags[property]); while (itProp.hasNext()) { QtProperty *prop = itProp.next(); if (prop) { delete prop; d_ptr->m_flagToProperty.remove(prop); } } d_ptr->m_propertyToFlags.remove(property); d_ptr->m_values.remove(property); } // QtSizePolicyPropertyManager class QtSizePolicyPropertyManagerPrivate { QtSizePolicyPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtSizePolicyPropertyManager) public: QtSizePolicyPropertyManagerPrivate(); void slotIntChanged(QtProperty *property, int value); void slotEnumChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QtEnumPropertyManager *m_enumPropertyManager; QMap m_propertyToHPolicy; QMap m_propertyToVPolicy; QMap m_propertyToHStretch; QMap m_propertyToVStretch; QMap m_hPolicyToProperty; QMap m_vPolicyToProperty; QMap m_hStretchToProperty; QMap m_vStretchToProperty; }; QtSizePolicyPropertyManagerPrivate::QtSizePolicyPropertyManagerPrivate() { } void QtSizePolicyPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *prop = m_hStretchToProperty.value(property, 0)) { QSizePolicy sp = m_values[prop]; sp.setHorizontalStretch(value); q_ptr->setValue(prop, sp); } else if (QtProperty *prop = m_vStretchToProperty.value(property, 0)) { QSizePolicy sp = m_values[prop]; sp.setVerticalStretch(value); q_ptr->setValue(prop, sp); } } void QtSizePolicyPropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) { if (QtProperty *prop = m_hPolicyToProperty.value(property, 0)) { QSizePolicy sp = m_values[prop]; sp.setHorizontalPolicy(metaEnumProvider()->indexToSizePolicy(value)); q_ptr->setValue(prop, sp); } else if (QtProperty *prop = m_vPolicyToProperty.value(property, 0)) { QSizePolicy sp = m_values[prop]; sp.setVerticalPolicy(metaEnumProvider()->indexToSizePolicy(value)); q_ptr->setValue(prop, sp); } } void QtSizePolicyPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_hStretchToProperty.value(property, 0)) { m_propertyToHStretch[pointProp] = 0; m_hStretchToProperty.remove(property); } else if (QtProperty *pointProp = m_vStretchToProperty.value(property, 0)) { m_propertyToVStretch[pointProp] = 0; m_vStretchToProperty.remove(property); } else if (QtProperty *pointProp = m_hPolicyToProperty.value(property, 0)) { m_propertyToHPolicy[pointProp] = 0; m_hPolicyToProperty.remove(property); } else if (QtProperty *pointProp = m_vPolicyToProperty.value(property, 0)) { m_propertyToVPolicy[pointProp] = 0; m_vPolicyToProperty.remove(property); } } /*! \class QtSizePolicyPropertyManager \brief The QtSizePolicyPropertyManager provides and manages QSizePolicy properties. A size policy property has nested \e horizontalPolicy, \e verticalPolicy, \e horizontalStretch and \e verticalStretch subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by QtIntPropertyManager and QtEnumPropertyManager objects. These managers can be retrieved using the subIntPropertyManager() and subEnumPropertyManager() functions respectively. In order to provide editing widgets for the subproperties in a property browser widget, these managers must be associated with editor factories. In addition, QtSizePolicyPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtIntPropertyManager, QtEnumPropertyManager */ /*! \fn void QtSizePolicyPropertyManager::valueChanged(QtProperty *property, const QSizePolicy &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtSizePolicyPropertyManager::QtSizePolicyPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtSizePolicyPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotEnumChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtSizePolicyPropertyManager::~QtSizePolicyPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the nested \e horizontalStretch and \e verticalStretch subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtSizePolicyPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the manager that creates the nested \e horizontalPolicy and \e verticalPolicy subproperties. In order to provide editing widgets for the mentioned subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtEnumPropertyManager *QtSizePolicyPropertyManager::subEnumPropertyManager() const { return d_ptr->m_enumPropertyManager; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns the default size policy. \sa setValue() */ QSizePolicy QtSizePolicyPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QSizePolicy()); } /*! \reimp */ QString QtSizePolicyPropertyManager::valueText(const QtProperty *property) const { const QtSizePolicyPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); const QSizePolicy sp = it.value(); const QtMetaEnumProvider *mep = metaEnumProvider(); const int hIndex = mep->sizePolicyToIndex(sp.horizontalPolicy()); const int vIndex = mep->sizePolicyToIndex(sp.verticalPolicy()); //! Unknown size policy on reading invalid uic3 files const QString hPolicy = hIndex != -1 ? mep->policyEnumNames().at(hIndex) : tr(""); const QString vPolicy = vIndex != -1 ? mep->policyEnumNames().at(vIndex) : tr(""); const QString str = tr("[%1, %2, %3, %4]").arg(hPolicy, vPolicy).arg(sp.horizontalStretch()).arg(sp.verticalStretch()); return str; } /*! \fn void QtSizePolicyPropertyManager::setValue(QtProperty *property, const QSizePolicy &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtSizePolicyPropertyManager::setValue(QtProperty *property, const QSizePolicy &val) { const QtSizePolicyPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value() == val) return; it.value() = val; d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToHPolicy[property], metaEnumProvider()->sizePolicyToIndex(val.horizontalPolicy())); d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToVPolicy[property], metaEnumProvider()->sizePolicyToIndex(val.verticalPolicy())); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToHStretch[property], val.horizontalStretch()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToVStretch[property], val.verticalStretch()); emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtSizePolicyPropertyManager::initializeProperty(QtProperty *property) { QSizePolicy val; d_ptr->m_values[property] = val; QtProperty *hPolicyProp = d_ptr->m_enumPropertyManager->addProperty(); hPolicyProp->setPropertyName(tr("Horizontal Policy")); d_ptr->m_enumPropertyManager->setEnumNames(hPolicyProp, metaEnumProvider()->policyEnumNames()); d_ptr->m_enumPropertyManager->setValue(hPolicyProp, metaEnumProvider()->sizePolicyToIndex(val.horizontalPolicy())); d_ptr->m_propertyToHPolicy[property] = hPolicyProp; d_ptr->m_hPolicyToProperty[hPolicyProp] = property; property->addSubProperty(hPolicyProp); QtProperty *vPolicyProp = d_ptr->m_enumPropertyManager->addProperty(); vPolicyProp->setPropertyName(tr("Vertical Policy")); d_ptr->m_enumPropertyManager->setEnumNames(vPolicyProp, metaEnumProvider()->policyEnumNames()); d_ptr->m_enumPropertyManager->setValue(vPolicyProp, metaEnumProvider()->sizePolicyToIndex(val.verticalPolicy())); d_ptr->m_propertyToVPolicy[property] = vPolicyProp; d_ptr->m_vPolicyToProperty[vPolicyProp] = property; property->addSubProperty(vPolicyProp); QtProperty *hStretchProp = d_ptr->m_intPropertyManager->addProperty(); hStretchProp->setPropertyName(tr("Horizontal Stretch")); d_ptr->m_intPropertyManager->setValue(hStretchProp, val.horizontalStretch()); d_ptr->m_intPropertyManager->setRange(hStretchProp, 0, 0xff); d_ptr->m_propertyToHStretch[property] = hStretchProp; d_ptr->m_hStretchToProperty[hStretchProp] = property; property->addSubProperty(hStretchProp); QtProperty *vStretchProp = d_ptr->m_intPropertyManager->addProperty(); vStretchProp->setPropertyName(tr("Vertical Stretch")); d_ptr->m_intPropertyManager->setValue(vStretchProp, val.verticalStretch()); d_ptr->m_intPropertyManager->setRange(vStretchProp, 0, 0xff); d_ptr->m_propertyToVStretch[property] = vStretchProp; d_ptr->m_vStretchToProperty[vStretchProp] = property; property->addSubProperty(vStretchProp); } /*! \reimp */ void QtSizePolicyPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *hPolicyProp = d_ptr->m_propertyToHPolicy[property]; if (hPolicyProp) { d_ptr->m_hPolicyToProperty.remove(hPolicyProp); delete hPolicyProp; } d_ptr->m_propertyToHPolicy.remove(property); QtProperty *vPolicyProp = d_ptr->m_propertyToVPolicy[property]; if (vPolicyProp) { d_ptr->m_vPolicyToProperty.remove(vPolicyProp); delete vPolicyProp; } d_ptr->m_propertyToVPolicy.remove(property); QtProperty *hStretchProp = d_ptr->m_propertyToHStretch[property]; if (hStretchProp) { d_ptr->m_hStretchToProperty.remove(hStretchProp); delete hStretchProp; } d_ptr->m_propertyToHStretch.remove(property); QtProperty *vStretchProp = d_ptr->m_propertyToVStretch[property]; if (vStretchProp) { d_ptr->m_vStretchToProperty.remove(vStretchProp); delete vStretchProp; } d_ptr->m_propertyToVStretch.remove(property); d_ptr->m_values.remove(property); } // QtFontPropertyManager: // QtFontPropertyManagerPrivate has a mechanism for reacting // to QApplication::fontDatabaseChanged() [4.5], which is emitted // when someone loads an application font. The signals are compressed // using a timer with interval 0, which then causes the family // enumeration manager to re-set its strings and index values // for each property. Q_GLOBAL_STATIC(QFontDatabase, fontDatabase) class QtFontPropertyManagerPrivate { QtFontPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtFontPropertyManager) public: QtFontPropertyManagerPrivate(); void slotIntChanged(QtProperty *property, int value); void slotEnumChanged(QtProperty *property, int value); void slotBoolChanged(QtProperty *property, bool value); void slotPropertyDestroyed(QtProperty *property); void slotFontDatabaseChanged(); void slotFontDatabaseDelayedChange(); QStringList m_familyNames; typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QtEnumPropertyManager *m_enumPropertyManager; QtBoolPropertyManager *m_boolPropertyManager; QMap m_propertyToFamily; QMap m_propertyToPointSize; QMap m_propertyToBold; QMap m_propertyToItalic; QMap m_propertyToUnderline; QMap m_propertyToStrikeOut; QMap m_propertyToKerning; QMap m_familyToProperty; QMap m_pointSizeToProperty; QMap m_boldToProperty; QMap m_italicToProperty; QMap m_underlineToProperty; QMap m_strikeOutToProperty; QMap m_kerningToProperty; bool m_settingValue; QTimer *m_fontDatabaseChangeTimer; }; QtFontPropertyManagerPrivate::QtFontPropertyManagerPrivate() : m_settingValue(false), m_fontDatabaseChangeTimer(0) { } void QtFontPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (m_settingValue) return; if (QtProperty *prop = m_pointSizeToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setPointSize(value); q_ptr->setValue(prop, f); } } void QtFontPropertyManagerPrivate::slotEnumChanged(QtProperty *property, int value) { if (m_settingValue) return; if (QtProperty *prop = m_familyToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setFamily(m_familyNames.at(value)); q_ptr->setValue(prop, f); } } void QtFontPropertyManagerPrivate::slotBoolChanged(QtProperty *property, bool value) { if (m_settingValue) return; if (QtProperty *prop = m_boldToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setBold(value); q_ptr->setValue(prop, f); } else if (QtProperty *prop = m_italicToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setItalic(value); q_ptr->setValue(prop, f); } else if (QtProperty *prop = m_underlineToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setUnderline(value); q_ptr->setValue(prop, f); } else if (QtProperty *prop = m_strikeOutToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setStrikeOut(value); q_ptr->setValue(prop, f); } else if (QtProperty *prop = m_kerningToProperty.value(property, 0)) { QFont f = m_values[prop]; f.setKerning(value); q_ptr->setValue(prop, f); } } void QtFontPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_pointSizeToProperty.value(property, 0)) { m_propertyToPointSize[pointProp] = 0; m_pointSizeToProperty.remove(property); } else if (QtProperty *pointProp = m_familyToProperty.value(property, 0)) { m_propertyToFamily[pointProp] = 0; m_familyToProperty.remove(property); } else if (QtProperty *pointProp = m_boldToProperty.value(property, 0)) { m_propertyToBold[pointProp] = 0; m_boldToProperty.remove(property); } else if (QtProperty *pointProp = m_italicToProperty.value(property, 0)) { m_propertyToItalic[pointProp] = 0; m_italicToProperty.remove(property); } else if (QtProperty *pointProp = m_underlineToProperty.value(property, 0)) { m_propertyToUnderline[pointProp] = 0; m_underlineToProperty.remove(property); } else if (QtProperty *pointProp = m_strikeOutToProperty.value(property, 0)) { m_propertyToStrikeOut[pointProp] = 0; m_strikeOutToProperty.remove(property); } else if (QtProperty *pointProp = m_kerningToProperty.value(property, 0)) { m_propertyToKerning[pointProp] = 0; m_kerningToProperty.remove(property); } } void QtFontPropertyManagerPrivate::slotFontDatabaseChanged() { if (!m_fontDatabaseChangeTimer) { m_fontDatabaseChangeTimer = new QTimer(q_ptr); m_fontDatabaseChangeTimer->setInterval(0); m_fontDatabaseChangeTimer->setSingleShot(true); QObject::connect(m_fontDatabaseChangeTimer, SIGNAL(timeout()), q_ptr, SLOT(slotFontDatabaseDelayedChange())); } if (!m_fontDatabaseChangeTimer->isActive()) m_fontDatabaseChangeTimer->start(); } void QtFontPropertyManagerPrivate::slotFontDatabaseDelayedChange() { typedef QMap PropertyPropertyMap; // rescan available font names const QStringList oldFamilies = m_familyNames; m_familyNames = fontDatabase()->families(); // Adapt all existing properties if (!m_propertyToFamily.empty()) { PropertyPropertyMap::const_iterator cend = m_propertyToFamily.constEnd(); for (PropertyPropertyMap::const_iterator it = m_propertyToFamily.constBegin(); it != cend; ++it) { QtProperty *familyProp = it.value(); const int oldIdx = m_enumPropertyManager->value(familyProp); int newIdx = m_familyNames.indexOf(oldFamilies.at(oldIdx)); if (newIdx < 0) newIdx = 0; m_enumPropertyManager->setEnumNames(familyProp, m_familyNames); m_enumPropertyManager->setValue(familyProp, newIdx); } } } /*! \class QtFontPropertyManager \brief The QtFontPropertyManager provides and manages QFont properties. A font property has nested \e family, \e pointSize, \e bold, \e italic, \e underline, \e strikeOut and \e kerning subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by QtIntPropertyManager, QtEnumPropertyManager and QtBoolPropertyManager objects. These managers can be retrieved using the corresponding subIntPropertyManager(), subEnumPropertyManager() and subBoolPropertyManager() functions. In order to provide editing widgets for the subproperties in a property browser widget, these managers must be associated with editor factories. In addition, QtFontPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtEnumPropertyManager, QtIntPropertyManager, QtBoolPropertyManager */ /*! \fn void QtFontPropertyManager::valueChanged(QtProperty *property, const QFont &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtFontPropertyManager::QtFontPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtFontPropertyManagerPrivate; d_ptr->q_ptr = this; #if QT_VERSION >= 0x040500 QObject::connect(qApp, SIGNAL(fontDatabaseChanged()), this, SLOT(slotFontDatabaseChanged())); #endif d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); d_ptr->m_enumPropertyManager = new QtEnumPropertyManager(this); connect(d_ptr->m_enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotEnumChanged(QtProperty *, int))); d_ptr->m_boolPropertyManager = new QtBoolPropertyManager(this); connect(d_ptr->m_boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotBoolChanged(QtProperty *, bool))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); connect(d_ptr->m_enumPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); connect(d_ptr->m_boolPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtFontPropertyManager::~QtFontPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that creates the \e pointSize subproperty. In order to provide editing widgets for the \e pointSize property in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtFontPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the manager that create the \e family subproperty. In order to provide editing widgets for the \e family property in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtEnumPropertyManager *QtFontPropertyManager::subEnumPropertyManager() const { return d_ptr->m_enumPropertyManager; } /*! Returns the manager that creates the \e bold, \e italic, \e underline, \e strikeOut and \e kerning subproperties. In order to provide editing widgets for the mentioned properties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtBoolPropertyManager *QtFontPropertyManager::subBoolPropertyManager() const { return d_ptr->m_boolPropertyManager; } /*! Returns the given \a property's value. If the given property is not managed by this manager, this function returns a font object that uses the application's default font. \sa setValue() */ QFont QtFontPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QFont()); } /*! \reimp */ QString QtFontPropertyManager::valueText(const QtProperty *property) const { const QtFontPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return QtPropertyBrowserUtils::fontValueText(it.value()); } /*! \reimp */ QIcon QtFontPropertyManager::valueIcon(const QtProperty *property) const { const QtFontPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); return QtPropertyBrowserUtils::fontValueIcon(it.value()); } /*! \fn void QtFontPropertyManager::setValue(QtProperty *property, const QFont &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtFontPropertyManager::setValue(QtProperty *property, const QFont &val) { const QtFontPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; const QFont oldVal = it.value(); if (oldVal == val && oldVal.resolve() == val.resolve()) return; it.value() = val; int idx = d_ptr->m_familyNames.indexOf(val.family()); if (idx == -1) idx = 0; bool settingValue = d_ptr->m_settingValue; d_ptr->m_settingValue = true; d_ptr->m_enumPropertyManager->setValue(d_ptr->m_propertyToFamily[property], idx); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToPointSize[property], val.pointSize()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToBold[property], val.bold()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToItalic[property], val.italic()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToUnderline[property], val.underline()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToStrikeOut[property], val.strikeOut()); d_ptr->m_boolPropertyManager->setValue(d_ptr->m_propertyToKerning[property], val.kerning()); d_ptr->m_settingValue = settingValue; emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtFontPropertyManager::initializeProperty(QtProperty *property) { QFont val; d_ptr->m_values[property] = val; QtProperty *familyProp = d_ptr->m_enumPropertyManager->addProperty(); familyProp->setPropertyName(tr("Family")); if (d_ptr->m_familyNames.empty()) d_ptr->m_familyNames = fontDatabase()->families(); d_ptr->m_enumPropertyManager->setEnumNames(familyProp, d_ptr->m_familyNames); int idx = d_ptr->m_familyNames.indexOf(val.family()); if (idx == -1) idx = 0; d_ptr->m_enumPropertyManager->setValue(familyProp, idx); d_ptr->m_propertyToFamily[property] = familyProp; d_ptr->m_familyToProperty[familyProp] = property; property->addSubProperty(familyProp); QtProperty *pointSizeProp = d_ptr->m_intPropertyManager->addProperty(); pointSizeProp->setPropertyName(tr("Point Size")); d_ptr->m_intPropertyManager->setValue(pointSizeProp, val.pointSize()); d_ptr->m_intPropertyManager->setMinimum(pointSizeProp, 1); d_ptr->m_propertyToPointSize[property] = pointSizeProp; d_ptr->m_pointSizeToProperty[pointSizeProp] = property; property->addSubProperty(pointSizeProp); QtProperty *boldProp = d_ptr->m_boolPropertyManager->addProperty(); boldProp->setPropertyName(tr("Bold")); d_ptr->m_boolPropertyManager->setValue(boldProp, val.bold()); d_ptr->m_propertyToBold[property] = boldProp; d_ptr->m_boldToProperty[boldProp] = property; property->addSubProperty(boldProp); QtProperty *italicProp = d_ptr->m_boolPropertyManager->addProperty(); italicProp->setPropertyName(tr("Italic")); d_ptr->m_boolPropertyManager->setValue(italicProp, val.italic()); d_ptr->m_propertyToItalic[property] = italicProp; d_ptr->m_italicToProperty[italicProp] = property; property->addSubProperty(italicProp); QtProperty *underlineProp = d_ptr->m_boolPropertyManager->addProperty(); underlineProp->setPropertyName(tr("Underline")); d_ptr->m_boolPropertyManager->setValue(underlineProp, val.underline()); d_ptr->m_propertyToUnderline[property] = underlineProp; d_ptr->m_underlineToProperty[underlineProp] = property; property->addSubProperty(underlineProp); QtProperty *strikeOutProp = d_ptr->m_boolPropertyManager->addProperty(); strikeOutProp->setPropertyName(tr("Strikeout")); d_ptr->m_boolPropertyManager->setValue(strikeOutProp, val.strikeOut()); d_ptr->m_propertyToStrikeOut[property] = strikeOutProp; d_ptr->m_strikeOutToProperty[strikeOutProp] = property; property->addSubProperty(strikeOutProp); QtProperty *kerningProp = d_ptr->m_boolPropertyManager->addProperty(); kerningProp->setPropertyName(tr("Kerning")); d_ptr->m_boolPropertyManager->setValue(kerningProp, val.kerning()); d_ptr->m_propertyToKerning[property] = kerningProp; d_ptr->m_kerningToProperty[kerningProp] = property; property->addSubProperty(kerningProp); } /*! \reimp */ void QtFontPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *familyProp = d_ptr->m_propertyToFamily[property]; if (familyProp) { d_ptr->m_familyToProperty.remove(familyProp); delete familyProp; } d_ptr->m_propertyToFamily.remove(property); QtProperty *pointSizeProp = d_ptr->m_propertyToPointSize[property]; if (pointSizeProp) { d_ptr->m_pointSizeToProperty.remove(pointSizeProp); delete pointSizeProp; } d_ptr->m_propertyToPointSize.remove(property); QtProperty *boldProp = d_ptr->m_propertyToBold[property]; if (boldProp) { d_ptr->m_boldToProperty.remove(boldProp); delete boldProp; } d_ptr->m_propertyToBold.remove(property); QtProperty *italicProp = d_ptr->m_propertyToItalic[property]; if (italicProp) { d_ptr->m_italicToProperty.remove(italicProp); delete italicProp; } d_ptr->m_propertyToItalic.remove(property); QtProperty *underlineProp = d_ptr->m_propertyToUnderline[property]; if (underlineProp) { d_ptr->m_underlineToProperty.remove(underlineProp); delete underlineProp; } d_ptr->m_propertyToUnderline.remove(property); QtProperty *strikeOutProp = d_ptr->m_propertyToStrikeOut[property]; if (strikeOutProp) { d_ptr->m_strikeOutToProperty.remove(strikeOutProp); delete strikeOutProp; } d_ptr->m_propertyToStrikeOut.remove(property); QtProperty *kerningProp = d_ptr->m_propertyToKerning[property]; if (kerningProp) { d_ptr->m_kerningToProperty.remove(kerningProp); delete kerningProp; } d_ptr->m_propertyToKerning.remove(property); d_ptr->m_values.remove(property); } // QtColorPropertyManager class QtColorPropertyManagerPrivate { QtColorPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtColorPropertyManager) public: void slotIntChanged(QtProperty *property, int value); void slotPropertyDestroyed(QtProperty *property); typedef QMap PropertyValueMap; PropertyValueMap m_values; QtIntPropertyManager *m_intPropertyManager; QMap m_propertyToR; QMap m_propertyToG; QMap m_propertyToB; QMap m_propertyToA; QMap m_rToProperty; QMap m_gToProperty; QMap m_bToProperty; QMap m_aToProperty; }; void QtColorPropertyManagerPrivate::slotIntChanged(QtProperty *property, int value) { if (QtProperty *prop = m_rToProperty.value(property, 0)) { QColor c = m_values[prop]; c.setRed(value); q_ptr->setValue(prop, c); } else if (QtProperty *prop = m_gToProperty.value(property, 0)) { QColor c = m_values[prop]; c.setGreen(value); q_ptr->setValue(prop, c); } else if (QtProperty *prop = m_bToProperty.value(property, 0)) { QColor c = m_values[prop]; c.setBlue(value); q_ptr->setValue(prop, c); } else if (QtProperty *prop = m_aToProperty.value(property, 0)) { QColor c = m_values[prop]; c.setAlpha(value); q_ptr->setValue(prop, c); } } void QtColorPropertyManagerPrivate::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *pointProp = m_rToProperty.value(property, 0)) { m_propertyToR[pointProp] = 0; m_rToProperty.remove(property); } else if (QtProperty *pointProp = m_gToProperty.value(property, 0)) { m_propertyToG[pointProp] = 0; m_gToProperty.remove(property); } else if (QtProperty *pointProp = m_bToProperty.value(property, 0)) { m_propertyToB[pointProp] = 0; m_bToProperty.remove(property); } else if (QtProperty *pointProp = m_aToProperty.value(property, 0)) { m_propertyToA[pointProp] = 0; m_aToProperty.remove(property); } } /*! \class QtColorPropertyManager \brief The QtColorPropertyManager provides and manages QColor properties. A color property has nested \e red, \e green and \e blue subproperties. The top-level property's value can be retrieved using the value() function, and set using the setValue() slot. The subproperties are created by a QtIntPropertyManager object. This manager can be retrieved using the subIntPropertyManager() function. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. In addition, QtColorPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager, QtAbstractPropertyBrowser, QtIntPropertyManager */ /*! \fn void QtColorPropertyManager::valueChanged(QtProperty *property, const QColor &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtColorPropertyManager::QtColorPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtColorPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_intPropertyManager = new QtIntPropertyManager(this); connect(d_ptr->m_intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotIntChanged(QtProperty *, int))); connect(d_ptr->m_intPropertyManager, SIGNAL(propertyDestroyed(QtProperty *)), this, SLOT(slotPropertyDestroyed(QtProperty *))); } /*! Destroys this manager, and all the properties it has created. */ QtColorPropertyManager::~QtColorPropertyManager() { clear(); delete d_ptr; } /*! Returns the manager that produces the nested \e red, \e green and \e blue subproperties. In order to provide editing widgets for the subproperties in a property browser widget, this manager must be associated with an editor factory. \sa QtAbstractPropertyBrowser::setFactoryForManager() */ QtIntPropertyManager *QtColorPropertyManager::subIntPropertyManager() const { return d_ptr->m_intPropertyManager; } /*! Returns the given \a property's value. If the given \a property is not managed by \e this manager, this function returns an invalid color. \sa setValue() */ QColor QtColorPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QColor()); } /*! \reimp */ QString QtColorPropertyManager::valueText(const QtProperty *property) const { const QtColorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return QtPropertyBrowserUtils::colorValueText(it.value()); } /*! \reimp */ QIcon QtColorPropertyManager::valueIcon(const QtProperty *property) const { const QtColorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); return QtPropertyBrowserUtils::brushValueIcon(QBrush(it.value())); } /*! \fn void QtColorPropertyManager::setValue(QtProperty *property, const QColor &value) Sets the value of the given \a property to \a value. Nested properties are updated automatically. \sa value(), valueChanged() */ void QtColorPropertyManager::setValue(QtProperty *property, const QColor &val) { const QtColorPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value() == val) return; it.value() = val; d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToR[property], val.red()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToG[property], val.green()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToB[property], val.blue()); d_ptr->m_intPropertyManager->setValue(d_ptr->m_propertyToA[property], val.alpha()); emit propertyChanged(property); emit valueChanged(property, val); } /*! \reimp */ void QtColorPropertyManager::initializeProperty(QtProperty *property) { QColor val; d_ptr->m_values[property] = val; QtProperty *rProp = d_ptr->m_intPropertyManager->addProperty(); rProp->setPropertyName(tr("Red")); d_ptr->m_intPropertyManager->setValue(rProp, val.red()); d_ptr->m_intPropertyManager->setRange(rProp, 0, 0xFF); d_ptr->m_propertyToR[property] = rProp; d_ptr->m_rToProperty[rProp] = property; property->addSubProperty(rProp); QtProperty *gProp = d_ptr->m_intPropertyManager->addProperty(); gProp->setPropertyName(tr("Green")); d_ptr->m_intPropertyManager->setValue(gProp, val.green()); d_ptr->m_intPropertyManager->setRange(gProp, 0, 0xFF); d_ptr->m_propertyToG[property] = gProp; d_ptr->m_gToProperty[gProp] = property; property->addSubProperty(gProp); QtProperty *bProp = d_ptr->m_intPropertyManager->addProperty(); bProp->setPropertyName(tr("Blue")); d_ptr->m_intPropertyManager->setValue(bProp, val.blue()); d_ptr->m_intPropertyManager->setRange(bProp, 0, 0xFF); d_ptr->m_propertyToB[property] = bProp; d_ptr->m_bToProperty[bProp] = property; property->addSubProperty(bProp); QtProperty *aProp = d_ptr->m_intPropertyManager->addProperty(); aProp->setPropertyName(tr("Alpha")); d_ptr->m_intPropertyManager->setValue(aProp, val.alpha()); d_ptr->m_intPropertyManager->setRange(aProp, 0, 0xFF); d_ptr->m_propertyToA[property] = aProp; d_ptr->m_aToProperty[aProp] = property; property->addSubProperty(aProp); } /*! \reimp */ void QtColorPropertyManager::uninitializeProperty(QtProperty *property) { QtProperty *rProp = d_ptr->m_propertyToR[property]; if (rProp) { d_ptr->m_rToProperty.remove(rProp); delete rProp; } d_ptr->m_propertyToR.remove(property); QtProperty *gProp = d_ptr->m_propertyToG[property]; if (gProp) { d_ptr->m_gToProperty.remove(gProp); delete gProp; } d_ptr->m_propertyToG.remove(property); QtProperty *bProp = d_ptr->m_propertyToB[property]; if (bProp) { d_ptr->m_bToProperty.remove(bProp); delete bProp; } d_ptr->m_propertyToB.remove(property); QtProperty *aProp = d_ptr->m_propertyToA[property]; if (aProp) { d_ptr->m_aToProperty.remove(aProp); delete aProp; } d_ptr->m_propertyToA.remove(property); d_ptr->m_values.remove(property); } // QtCursorPropertyManager // Make sure icons are removed as soon as QApplication is destroyed, otherwise, // handles are leaked on X11. static void clearCursorDatabase(); namespace { struct CursorDatabase : public QtCursorDatabase { CursorDatabase() { qAddPostRoutine(clearCursorDatabase); } }; } Q_GLOBAL_STATIC(QtCursorDatabase, cursorDatabase) static void clearCursorDatabase() { cursorDatabase()->clear(); } class QtCursorPropertyManagerPrivate { QtCursorPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtCursorPropertyManager) public: typedef QMap PropertyValueMap; PropertyValueMap m_values; }; /*! \class QtCursorPropertyManager \brief The QtCursorPropertyManager provides and manages QCursor properties. A cursor property has a current value which can be retrieved using the value() function, and set using the setValue() slot. In addition, QtCursorPropertyManager provides the valueChanged() signal which is emitted whenever a property created by this manager changes. \sa QtAbstractPropertyManager */ /*! \fn void QtCursorPropertyManager::valueChanged(QtProperty *property, const QCursor &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! Creates a manager with the given \a parent. */ QtCursorPropertyManager::QtCursorPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtCursorPropertyManagerPrivate; d_ptr->q_ptr = this; } /*! Destroys this manager, and all the properties it has created. */ QtCursorPropertyManager::~QtCursorPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns a default QCursor object. \sa setValue() */ #ifndef QT_NO_CURSOR QCursor QtCursorPropertyManager::value(const QtProperty *property) const { return d_ptr->m_values.value(property, QCursor()); } #endif /*! \reimp */ QString QtCursorPropertyManager::valueText(const QtProperty *property) const { const QtCursorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QString(); return cursorDatabase()->cursorToShapeName(it.value()); } /*! \reimp */ QIcon QtCursorPropertyManager::valueIcon(const QtProperty *property) const { const QtCursorPropertyManagerPrivate::PropertyValueMap::const_iterator it = d_ptr->m_values.constFind(property); if (it == d_ptr->m_values.constEnd()) return QIcon(); return cursorDatabase()->cursorToShapeIcon(it.value()); } /*! \fn void QtCursorPropertyManager::setValue(QtProperty *property, const QCursor &value) Sets the value of the given \a property to \a value. \sa value(), valueChanged() */ void QtCursorPropertyManager::setValue(QtProperty *property, const QCursor &value) { #ifndef QT_NO_CURSOR const QtCursorPropertyManagerPrivate::PropertyValueMap::iterator it = d_ptr->m_values.find(property); if (it == d_ptr->m_values.end()) return; if (it.value().shape() == value.shape() && value.shape() != Qt::BitmapCursor) return; it.value() = value; emit propertyChanged(property); emit valueChanged(property, value); #endif } /*! \reimp */ void QtCursorPropertyManager::initializeProperty(QtProperty *property) { #ifndef QT_NO_CURSOR d_ptr->m_values[property] = QCursor(); #endif } /*! \reimp */ void QtCursorPropertyManager::uninitializeProperty(QtProperty *property) { d_ptr->m_values.remove(property); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtpropertymanager.cpp" #include "qtpropertymanager.moc" tiled-0.14.2/src/qtpropertybrowser/src/qtpropertymanager.h000066400000000000000000000662011260670167100240620ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTPROPERTYMANAGER_H #define QTPROPERTYMANAGER_H #include "qtpropertybrowser.h" #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QDate; class QTime; class QDateTime; class QLocale; class QT_QTPROPERTYBROWSER_EXPORT QtGroupPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtGroupPropertyManager(QObject *parent = 0); ~QtGroupPropertyManager(); protected: virtual bool hasValue(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); }; class QtIntPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtIntPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtIntPropertyManager(QObject *parent = 0); ~QtIntPropertyManager(); int value(const QtProperty *property) const; int minimum(const QtProperty *property) const; int maximum(const QtProperty *property) const; int singleStep(const QtProperty *property) const; bool isReadOnly(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, int val); void setMinimum(QtProperty *property, int minVal); void setMaximum(QtProperty *property, int maxVal); void setRange(QtProperty *property, int minVal, int maxVal); void setSingleStep(QtProperty *property, int step); void setReadOnly(QtProperty *property, bool readOnly); Q_SIGNALS: void valueChanged(QtProperty *property, int val); void rangeChanged(QtProperty *property, int minVal, int maxVal); void singleStepChanged(QtProperty *property, int step); void readOnlyChanged(QtProperty *property, bool readOnly); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtIntPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtIntPropertyManager) Q_DISABLE_COPY(QtIntPropertyManager) }; class QtBoolPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtBoolPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtBoolPropertyManager(QObject *parent = 0); ~QtBoolPropertyManager(); bool value(const QtProperty *property) const; bool textVisible(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, bool val); void setTextVisible(QtProperty *property, bool textVisible); Q_SIGNALS: void valueChanged(QtProperty *property, bool val); void textVisibleChanged(QtProperty *property, bool); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtBoolPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtBoolPropertyManager) Q_DISABLE_COPY(QtBoolPropertyManager) }; class QtDoublePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDoublePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtDoublePropertyManager(QObject *parent = 0); ~QtDoublePropertyManager(); double value(const QtProperty *property) const; double minimum(const QtProperty *property) const; double maximum(const QtProperty *property) const; double singleStep(const QtProperty *property) const; int decimals(const QtProperty *property) const; bool isReadOnly(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, double val); void setMinimum(QtProperty *property, double minVal); void setMaximum(QtProperty *property, double maxVal); void setRange(QtProperty *property, double minVal, double maxVal); void setSingleStep(QtProperty *property, double step); void setDecimals(QtProperty *property, int prec); void setReadOnly(QtProperty *property, bool readOnly); Q_SIGNALS: void valueChanged(QtProperty *property, double val); void rangeChanged(QtProperty *property, double minVal, double maxVal); void singleStepChanged(QtProperty *property, double step); void decimalsChanged(QtProperty *property, int prec); void readOnlyChanged(QtProperty *property, bool readOnly); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtDoublePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDoublePropertyManager) Q_DISABLE_COPY(QtDoublePropertyManager) }; class QtStringPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtStringPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtStringPropertyManager(QObject *parent = 0); ~QtStringPropertyManager(); QString value(const QtProperty *property) const; QRegExp regExp(const QtProperty *property) const; EchoMode echoMode(const QtProperty *property) const; bool isReadOnly(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QString &val); void setRegExp(QtProperty *property, const QRegExp ®Exp); void setEchoMode(QtProperty *property, EchoMode echoMode); void setReadOnly(QtProperty *property, bool readOnly); Q_SIGNALS: void valueChanged(QtProperty *property, const QString &val); void regExpChanged(QtProperty *property, const QRegExp ®Exp); void echoModeChanged(QtProperty *property, const int); void readOnlyChanged(QtProperty *property, bool); protected: QString valueText(const QtProperty *property) const; QString displayText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtStringPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtStringPropertyManager) Q_DISABLE_COPY(QtStringPropertyManager) }; class QtDatePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDatePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtDatePropertyManager(QObject *parent = 0); ~QtDatePropertyManager(); QDate value(const QtProperty *property) const; QDate minimum(const QtProperty *property) const; QDate maximum(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QDate &val); void setMinimum(QtProperty *property, const QDate &minVal); void setMaximum(QtProperty *property, const QDate &maxVal); void setRange(QtProperty *property, const QDate &minVal, const QDate &maxVal); Q_SIGNALS: void valueChanged(QtProperty *property, const QDate &val); void rangeChanged(QtProperty *property, const QDate &minVal, const QDate &maxVal); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtDatePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDatePropertyManager) Q_DISABLE_COPY(QtDatePropertyManager) }; class QtTimePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtTimePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtTimePropertyManager(QObject *parent = 0); ~QtTimePropertyManager(); QTime value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QTime &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QTime &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtTimePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtTimePropertyManager) Q_DISABLE_COPY(QtTimePropertyManager) }; class QtDateTimePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtDateTimePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtDateTimePropertyManager(QObject *parent = 0); ~QtDateTimePropertyManager(); QDateTime value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QDateTime &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QDateTime &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtDateTimePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtDateTimePropertyManager) Q_DISABLE_COPY(QtDateTimePropertyManager) }; class QtKeySequencePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtKeySequencePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtKeySequencePropertyManager(QObject *parent = 0); ~QtKeySequencePropertyManager(); QKeySequence value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QKeySequence &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QKeySequence &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtKeySequencePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtKeySequencePropertyManager) Q_DISABLE_COPY(QtKeySequencePropertyManager) }; class QtCharPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCharPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtCharPropertyManager(QObject *parent = 0); ~QtCharPropertyManager(); QChar value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QChar &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QChar &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtCharPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCharPropertyManager) Q_DISABLE_COPY(QtCharPropertyManager) }; class QtEnumPropertyManager; class QtLocalePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtLocalePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtLocalePropertyManager(QObject *parent = 0); ~QtLocalePropertyManager(); QtEnumPropertyManager *subEnumPropertyManager() const; QLocale value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QLocale &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QLocale &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtLocalePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtLocalePropertyManager) Q_DISABLE_COPY(QtLocalePropertyManager) Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtPointPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtPointPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtPointPropertyManager(QObject *parent = 0); ~QtPointPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QPoint value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QPoint &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QPoint &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtPointPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtPointPropertyManager) Q_DISABLE_COPY(QtPointPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtPointFPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtPointFPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtPointFPropertyManager(QObject *parent = 0); ~QtPointFPropertyManager(); QtDoublePropertyManager *subDoublePropertyManager() const; QPointF value(const QtProperty *property) const; int decimals(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QPointF &val); void setDecimals(QtProperty *property, int prec); Q_SIGNALS: void valueChanged(QtProperty *property, const QPointF &val); void decimalsChanged(QtProperty *property, int prec); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtPointFPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtPointFPropertyManager) Q_DISABLE_COPY(QtPointFPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtSizePropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSizePropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtSizePropertyManager(QObject *parent = 0); ~QtSizePropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QSize value(const QtProperty *property) const; QSize minimum(const QtProperty *property) const; QSize maximum(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QSize &val); void setMinimum(QtProperty *property, const QSize &minVal); void setMaximum(QtProperty *property, const QSize &maxVal); void setRange(QtProperty *property, const QSize &minVal, const QSize &maxVal); Q_SIGNALS: void valueChanged(QtProperty *property, const QSize &val); void rangeChanged(QtProperty *property, const QSize &minVal, const QSize &maxVal); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtSizePropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSizePropertyManager) Q_DISABLE_COPY(QtSizePropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtSizeFPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSizeFPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtSizeFPropertyManager(QObject *parent = 0); ~QtSizeFPropertyManager(); QtDoublePropertyManager *subDoublePropertyManager() const; QSizeF value(const QtProperty *property) const; QSizeF minimum(const QtProperty *property) const; QSizeF maximum(const QtProperty *property) const; int decimals(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QSizeF &val); void setMinimum(QtProperty *property, const QSizeF &minVal); void setMaximum(QtProperty *property, const QSizeF &maxVal); void setRange(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal); void setDecimals(QtProperty *property, int prec); Q_SIGNALS: void valueChanged(QtProperty *property, const QSizeF &val); void rangeChanged(QtProperty *property, const QSizeF &minVal, const QSizeF &maxVal); void decimalsChanged(QtProperty *property, int prec); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtSizeFPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSizeFPropertyManager) Q_DISABLE_COPY(QtSizeFPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtRectPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtRectPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtRectPropertyManager(QObject *parent = 0); ~QtRectPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QRect value(const QtProperty *property) const; QRect constraint(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QRect &val); void setConstraint(QtProperty *property, const QRect &constraint); Q_SIGNALS: void valueChanged(QtProperty *property, const QRect &val); void constraintChanged(QtProperty *property, const QRect &constraint); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtRectPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtRectPropertyManager) Q_DISABLE_COPY(QtRectPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtRectFPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtRectFPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtRectFPropertyManager(QObject *parent = 0); ~QtRectFPropertyManager(); QtDoublePropertyManager *subDoublePropertyManager() const; QRectF value(const QtProperty *property) const; QRectF constraint(const QtProperty *property) const; int decimals(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QRectF &val); void setConstraint(QtProperty *property, const QRectF &constraint); void setDecimals(QtProperty *property, int prec); Q_SIGNALS: void valueChanged(QtProperty *property, const QRectF &val); void constraintChanged(QtProperty *property, const QRectF &constraint); void decimalsChanged(QtProperty *property, int prec); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtRectFPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtRectFPropertyManager) Q_DISABLE_COPY(QtRectFPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotDoubleChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtEnumPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtEnumPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtEnumPropertyManager(QObject *parent = 0); ~QtEnumPropertyManager(); int value(const QtProperty *property) const; QStringList enumNames(const QtProperty *property) const; QMap enumIcons(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, int val); void setEnumNames(QtProperty *property, const QStringList &names); void setEnumIcons(QtProperty *property, const QMap &icons); Q_SIGNALS: void valueChanged(QtProperty *property, int val); void enumNamesChanged(QtProperty *property, const QStringList &names); void enumIconsChanged(QtProperty *property, const QMap &icons); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtEnumPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtEnumPropertyManager) Q_DISABLE_COPY(QtEnumPropertyManager) }; class QtFlagPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtFlagPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtFlagPropertyManager(QObject *parent = 0); ~QtFlagPropertyManager(); QtBoolPropertyManager *subBoolPropertyManager() const; int value(const QtProperty *property) const; QStringList flagNames(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, int val); void setFlagNames(QtProperty *property, const QStringList &names); Q_SIGNALS: void valueChanged(QtProperty *property, int val); void flagNamesChanged(QtProperty *property, const QStringList &names); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtFlagPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtFlagPropertyManager) Q_DISABLE_COPY(QtFlagPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotBoolChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtSizePolicyPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtSizePolicyPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtSizePolicyPropertyManager(QObject *parent = 0); ~QtSizePolicyPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QtEnumPropertyManager *subEnumPropertyManager() const; QSizePolicy value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QSizePolicy &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QSizePolicy &val); protected: QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtSizePolicyPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtSizePolicyPropertyManager) Q_DISABLE_COPY(QtSizePolicyPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtFontPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtFontPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtFontPropertyManager(QObject *parent = 0); ~QtFontPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QtEnumPropertyManager *subEnumPropertyManager() const; QtBoolPropertyManager *subBoolPropertyManager() const; QFont value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QFont &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QFont &val); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtFontPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtFontPropertyManager) Q_DISABLE_COPY(QtFontPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotEnumChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotBoolChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotFontDatabaseChanged()) Q_PRIVATE_SLOT(d_func(), void slotFontDatabaseDelayedChange()) }; class QtColorPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtColorPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtColorPropertyManager(QObject *parent = 0); ~QtColorPropertyManager(); QtIntPropertyManager *subIntPropertyManager() const; QColor value(const QtProperty *property) const; public Q_SLOTS: void setValue(QtProperty *property, const QColor &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QColor &val); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtColorPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtColorPropertyManager) Q_DISABLE_COPY(QtColorPropertyManager) Q_PRIVATE_SLOT(d_func(), void slotIntChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotPropertyDestroyed(QtProperty *)) }; class QtCursorPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtCursorPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtCursorPropertyManager(QObject *parent = 0); ~QtCursorPropertyManager(); #ifndef QT_NO_CURSOR QCursor value(const QtProperty *property) const; #endif public Q_SLOTS: void setValue(QtProperty *property, const QCursor &val); Q_SIGNALS: void valueChanged(QtProperty *property, const QCursor &val); protected: QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); private: QtCursorPropertyManagerPrivate *d_ptr; Q_DECLARE_PRIVATE(QtCursorPropertyManager) Q_DISABLE_COPY(QtCursorPropertyManager) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif tiled-0.14.2/src/qtpropertybrowser/src/qttreepropertybrowser.cpp000066400000000000000000001064601260670167100253500ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qttreepropertybrowser.h" #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtPropertyEditorView; class QtTreePropertyBrowserPrivate { QtTreePropertyBrowser *q_ptr; Q_DECLARE_PUBLIC(QtTreePropertyBrowser) public: QtTreePropertyBrowserPrivate(); void init(QWidget *parent); void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex); void propertyRemoved(QtBrowserItem *index); void propertyChanged(QtBrowserItem *index); QWidget *createEditor(QtProperty *property, QWidget *parent) const { return q_ptr->createEditor(property, parent); } QtProperty *indexToProperty(const QModelIndex &index) const; QTreeWidgetItem *indexToItem(const QModelIndex &index) const; QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const; bool lastColumn(int column) const; void disableItem(QTreeWidgetItem *item) const; void enableItem(QTreeWidgetItem *item) const; bool hasValue(QTreeWidgetItem *item) const; void slotCollapsed(const QModelIndex &index); void slotExpanded(const QModelIndex &index); QColor calculatedBackgroundColor(QtBrowserItem *item) const; QtPropertyEditorView *treeWidget() const { return m_treeWidget; } bool markPropertiesWithoutValue() const { return m_markPropertiesWithoutValue; } QtBrowserItem *currentItem() const; void setCurrentItem(QtBrowserItem *browserItem, bool block); void editItem(QtBrowserItem *browserItem); void slotCurrentBrowserItemChanged(QtBrowserItem *item); void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *); QTreeWidgetItem *editedItem() const; private: void updateItem(QTreeWidgetItem *item); QMap m_indexToItem; QMap m_itemToIndex; QMap m_indexToBackgroundColor; QtPropertyEditorView *m_treeWidget; bool m_headerVisible; QtTreePropertyBrowser::ResizeMode m_resizeMode; class QtPropertyEditorDelegate *m_delegate; bool m_markPropertiesWithoutValue; bool m_browserChangedBlocked; QIcon m_expandIcon; }; // ------------ QtPropertyEditorView class QtPropertyEditorView : public QTreeWidget { Q_OBJECT public: QtPropertyEditorView(QWidget *parent = 0); void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate) { m_editorPrivate = editorPrivate; } QTreeWidgetItem *indexToItem(const QModelIndex &index) const { return itemFromIndex(index); } protected: void keyPressEvent(QKeyEvent *event); void mousePressEvent(QMouseEvent *event); void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; private: QtTreePropertyBrowserPrivate *m_editorPrivate; }; QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) : QTreeWidget(parent), m_editorPrivate(0) { connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int))); } void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItemV3 opt = option; bool hasValue = true; if (m_editorPrivate) { QtProperty *property = m_editorPrivate->indexToProperty(index); if (property) hasValue = property->hasValue(); } if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) { const QColor c = option.palette.color(QPalette::Dark); painter->fillRect(option.rect, c); opt.palette.setColor(QPalette::AlternateBase, c); } else { const QColor c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index)); if (c.isValid()) { painter->fillRect(option.rect, c); opt.palette.setColor(QPalette::AlternateBase, c.lighter(112)); } } QTreeWidget::drawRow(painter, opt, index); QColor color = static_cast(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt)); painter->save(); painter->setPen(QPen(color)); painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom()); painter->restore(); } void QtPropertyEditorView::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Return: case Qt::Key_Enter: case Qt::Key_Space: // Trigger Edit if (!m_editorPrivate->editedItem()) if (const QTreeWidgetItem *item = currentItem()) if (item->columnCount() >= 2 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) { event->accept(); // If the current position is at column 0, move to 1. QModelIndex index = currentIndex(); if (index.column() == 0) { index = index.sibling(index.row(), 1); setCurrentIndex(index); } edit(index); return; } break; default: break; } QTreeWidget::keyPressEvent(event); } void QtPropertyEditorView::mousePressEvent(QMouseEvent *event) { QTreeWidget::mousePressEvent(event); QTreeWidgetItem *item = itemAt(event->pos()); if (item) { if ((item != m_editorPrivate->editedItem()) && (event->button() == Qt::LeftButton) && (header()->logicalIndexAt(event->pos().x()) == 1) && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) { editItem(item, 1); } else if (!m_editorPrivate->hasValue(item) && m_editorPrivate->markPropertiesWithoutValue() && !rootIsDecorated()) { if (event->pos().x() + header()->offset() < 20) item->setExpanded(!item->isExpanded()); } } } // ------------ QtPropertyEditorDelegate class QtPropertyEditorDelegate : public QItemDelegate { Q_OBJECT public: QtPropertyEditorDelegate(QObject *parent = 0) : QItemDelegate(parent), m_editorPrivate(0), m_editedItem(0), m_editedWidget(0), m_disablePainting(false) {} void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate) { m_editorPrivate = editorPrivate; } QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; void setModelData(QWidget *, QAbstractItemModel *, const QModelIndex &) const {} void setEditorData(QWidget *, const QModelIndex &) const {} bool eventFilter(QObject *object, QEvent *event); void closeEditor(QtProperty *property); QTreeWidgetItem *editedItem() const { return m_editedItem; } protected: void drawDecoration(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QPixmap &pixmap) const; void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const; private slots: void slotEditorDestroyed(QObject *object); private: int indentation(const QModelIndex &index) const; typedef QMap EditorToPropertyMap; mutable EditorToPropertyMap m_editorToProperty; typedef QMap PropertyToEditorMap; mutable PropertyToEditorMap m_propertyToEditor; QtTreePropertyBrowserPrivate *m_editorPrivate; mutable QTreeWidgetItem *m_editedItem; mutable QWidget *m_editedWidget; mutable bool m_disablePainting; }; int QtPropertyEditorDelegate::indentation(const QModelIndex &index) const { if (!m_editorPrivate) return 0; QTreeWidgetItem *item = m_editorPrivate->indexToItem(index); int indent = 0; while (item->parent()) { item = item->parent(); ++indent; } if (m_editorPrivate->treeWidget()->rootIsDecorated()) ++indent; return indent * m_editorPrivate->treeWidget()->indentation(); } void QtPropertyEditorDelegate::slotEditorDestroyed(QObject *object) { if (QWidget *w = qobject_cast(object)) { const EditorToPropertyMap::iterator it = m_editorToProperty.find(w); if (it != m_editorToProperty.end()) { m_propertyToEditor.remove(it.value()); m_editorToProperty.erase(it); } if (m_editedWidget == w) { m_editedWidget = 0; m_editedItem = 0; } } } void QtPropertyEditorDelegate::closeEditor(QtProperty *property) { if (QWidget *w = m_propertyToEditor.value(property, 0)) w->deleteLater(); } QWidget *QtPropertyEditorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const { if (index.column() == 1 && m_editorPrivate) { QtProperty *property = m_editorPrivate->indexToProperty(index); QTreeWidgetItem *item = m_editorPrivate->indexToItem(index); if (property && item && (item->flags() & Qt::ItemIsEnabled)) { QWidget *editor = m_editorPrivate->createEditor(property, parent); if (editor) { editor->setAutoFillBackground(true); editor->installEventFilter(const_cast(this)); connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *))); m_propertyToEditor[property] = editor; m_editorToProperty[editor] = property; m_editedItem = item; m_editedWidget = editor; } return editor; } } return 0; } void QtPropertyEditorDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index) editor->setGeometry(option.rect.adjusted(0, 0, 0, -1)); } void QtPropertyEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { bool hasValue = true; if (m_editorPrivate) { QtProperty *property = m_editorPrivate->indexToProperty(index); if (property) hasValue = property->hasValue(); } QStyleOptionViewItemV3 opt = option; if ((m_editorPrivate && index.column() == 0) || !hasValue) { QtProperty *property = m_editorPrivate->indexToProperty(index); if (property && property->isModified()) { opt.font.setBold(true); opt.fontMetrics = QFontMetrics(opt.font); } } QColor c; if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) { c = opt.palette.color(QPalette::Dark); opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::BrightText)); } else { c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index)); if (c.isValid() && (opt.features & QStyleOptionViewItemV2::Alternate)) c = c.lighter(112); } if (c.isValid()) painter->fillRect(option.rect, c); opt.state &= ~QStyle::State_HasFocus; if (index.column() == 1) { QTreeWidgetItem *item = m_editorPrivate->indexToItem(index); if (m_editedItem && m_editedItem == item) m_disablePainting = true; } QItemDelegate::paint(painter, opt, index); if (option.type) m_disablePainting = false; opt.palette.setCurrentColorGroup(QPalette::Active); QColor color = static_cast(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt)); painter->save(); painter->setPen(QPen(color)); if (!m_editorPrivate || (!m_editorPrivate->lastColumn(index.column()) && hasValue)) { int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left(); painter->drawLine(right, option.rect.y(), right, option.rect.bottom()); } painter->restore(); } void QtPropertyEditorDelegate::drawDecoration(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QPixmap &pixmap) const { if (m_disablePainting) return; QItemDelegate::drawDecoration(painter, option, rect, pixmap); } void QtPropertyEditorDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const { if (m_disablePainting) return; QItemDelegate::drawDisplay(painter, option, rect, text); } QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { return QItemDelegate::sizeHint(option, index) + QSize(3, 4); } bool QtPropertyEditorDelegate::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::FocusOut) { QFocusEvent *fe = static_cast(event); if (fe->reason() == Qt::ActiveWindowFocusReason) return false; } return QItemDelegate::eventFilter(object, event); } // -------- QtTreePropertyBrowserPrivate implementation QtTreePropertyBrowserPrivate::QtTreePropertyBrowserPrivate() : m_treeWidget(0), m_headerVisible(true), m_resizeMode(QtTreePropertyBrowser::Stretch), m_delegate(0), m_markPropertiesWithoutValue(false), m_browserChangedBlocked(false) { } // Draw an icon indicating opened/closing branches static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style) { QPixmap pix(14, 14); pix.fill(Qt::transparent); QStyleOption branchOption; QRect r(QPoint(0, 0), pix.size()); branchOption.rect = QRect(2, 2, 9, 9); // ### hardcoded in qcommonstyle.cpp branchOption.palette = palette; branchOption.state = QStyle::State_Children; QPainter p; // Draw closed state p.begin(&pix); style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p); p.end(); QIcon rc = pix; rc.addPixmap(pix, QIcon::Selected, QIcon::Off); // Draw opened state branchOption.state |= QStyle::State_Open; pix.fill(Qt::transparent); p.begin(&pix); style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p); p.end(); rc.addPixmap(pix, QIcon::Normal, QIcon::On); rc.addPixmap(pix, QIcon::Selected, QIcon::On); return rc; } void QtTreePropertyBrowserPrivate::init(QWidget *parent) { QHBoxLayout *layout = new QHBoxLayout(parent); layout->setMargin(0); m_treeWidget = new QtPropertyEditorView(parent); m_treeWidget->setEditorPrivate(this); m_treeWidget->setIconSize(QSize(18, 18)); layout->addWidget(m_treeWidget); parent->setFocusProxy(m_treeWidget); m_treeWidget->setColumnCount(2); QStringList labels; labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Property")); labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Value")); m_treeWidget->setHeaderLabels(labels); m_treeWidget->setAlternatingRowColors(true); m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed); m_delegate = new QtPropertyEditorDelegate(parent); m_delegate->setEditorPrivate(this); m_treeWidget->setItemDelegate(m_delegate); #if QT_VERSION >= 0x050000 m_treeWidget->header()->setSectionsMovable(false); m_treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch); #else m_treeWidget->header()->setMovable(false); m_treeWidget->header()->setResizeMode(QHeaderView::Stretch); #endif m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style()); QObject::connect(m_treeWidget, SIGNAL(collapsed(const QModelIndex &)), q_ptr, SLOT(slotCollapsed(const QModelIndex &))); QObject::connect(m_treeWidget, SIGNAL(expanded(const QModelIndex &)), q_ptr, SLOT(slotExpanded(const QModelIndex &))); QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); } QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const { if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem()) return m_itemToIndex.value(treeItem); return 0; } void QtTreePropertyBrowserPrivate::setCurrentItem(QtBrowserItem *browserItem, bool block) { const bool blocked = block ? m_treeWidget->blockSignals(true) : false; if (browserItem == 0) m_treeWidget->setCurrentItem(0); else m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem)); if (block) m_treeWidget->blockSignals(blocked); } QtProperty *QtTreePropertyBrowserPrivate::indexToProperty(const QModelIndex &index) const { QTreeWidgetItem *item = m_treeWidget->indexToItem(index); QtBrowserItem *idx = m_itemToIndex.value(item); if (idx) return idx->property(); return 0; } QtBrowserItem *QtTreePropertyBrowserPrivate::indexToBrowserItem(const QModelIndex &index) const { QTreeWidgetItem *item = m_treeWidget->indexToItem(index); return m_itemToIndex.value(item); } QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const { return m_treeWidget->indexToItem(index); } bool QtTreePropertyBrowserPrivate::lastColumn(int column) const { return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1; } void QtTreePropertyBrowserPrivate::disableItem(QTreeWidgetItem *item) const { Qt::ItemFlags flags = item->flags(); if (flags & Qt::ItemIsEnabled) { flags &= ~Qt::ItemIsEnabled; item->setFlags(flags); m_delegate->closeEditor(m_itemToIndex[item]->property()); const int childCount = item->childCount(); for (int i = 0; i < childCount; i++) { QTreeWidgetItem *child = item->child(i); disableItem(child); } } } void QtTreePropertyBrowserPrivate::enableItem(QTreeWidgetItem *item) const { Qt::ItemFlags flags = item->flags(); flags |= Qt::ItemIsEnabled; item->setFlags(flags); const int childCount = item->childCount(); for (int i = 0; i < childCount; i++) { QTreeWidgetItem *child = item->child(i); QtProperty *property = m_itemToIndex[child]->property(); if (property->isEnabled()) { enableItem(child); } } } bool QtTreePropertyBrowserPrivate::hasValue(QTreeWidgetItem *item) const { QtBrowserItem *browserItem = m_itemToIndex.value(item); if (browserItem) return browserItem->property()->hasValue(); return false; } void QtTreePropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex) { QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex); QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent()); QTreeWidgetItem *newItem = 0; if (parentItem) { newItem = new QTreeWidgetItem(parentItem, afterItem); } else { newItem = new QTreeWidgetItem(m_treeWidget, afterItem); } m_itemToIndex[newItem] = index; m_indexToItem[index] = newItem; newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); m_treeWidget->setItemExpanded(newItem, true); updateItem(newItem); } void QtTreePropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index) { QTreeWidgetItem *item = m_indexToItem.value(index); if (m_treeWidget->currentItem() == item) { m_treeWidget->setCurrentItem(0); } delete item; m_indexToItem.remove(index); m_itemToIndex.remove(item); m_indexToBackgroundColor.remove(index); } void QtTreePropertyBrowserPrivate::propertyChanged(QtBrowserItem *index) { QTreeWidgetItem *item = m_indexToItem.value(index); updateItem(item); } void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item) { QtProperty *property = m_itemToIndex[item]->property(); if (property->nameColor().isValid()) item->setForeground(0, QBrush(property->nameColor())); if (property->valueColor().isValid()) item->setForeground(1, QBrush(property->valueColor())); QIcon expandIcon; if (property->hasValue()) { QString toolTip = property->toolTip(); if (toolTip.isEmpty()) toolTip = property->displayText(); item->setToolTip(1, toolTip); item->setIcon(1, property->valueIcon()); property->displayText().isEmpty() ? item->setText(1, property->valueText()) : item->setText(1, property->displayText()); } else if (markPropertiesWithoutValue() && !m_treeWidget->rootIsDecorated()) { expandIcon = m_expandIcon; } item->setIcon(0, expandIcon); item->setFirstColumnSpanned(!property->hasValue()); item->setToolTip(0, property->propertyName()); item->setStatusTip(0, property->statusTip()); item->setWhatsThis(0, property->whatsThis()); item->setText(0, property->propertyName()); bool wasEnabled = item->flags() & Qt::ItemIsEnabled; bool isEnabled = wasEnabled; if (property->isEnabled()) { QTreeWidgetItem *parent = item->parent(); if (!parent || (parent->flags() & Qt::ItemIsEnabled)) isEnabled = true; else isEnabled = false; } else { isEnabled = false; } if (wasEnabled != isEnabled) { if (isEnabled) enableItem(item); else disableItem(item); } m_treeWidget->viewport()->update(); } QColor QtTreePropertyBrowserPrivate::calculatedBackgroundColor(QtBrowserItem *item) const { QtBrowserItem *i = item; const QMap::const_iterator itEnd = m_indexToBackgroundColor.constEnd(); while (i) { QMap::const_iterator it = m_indexToBackgroundColor.constFind(i); if (it != itEnd) return it.value(); i = i->parent(); } return QColor(); } void QtTreePropertyBrowserPrivate::slotCollapsed(const QModelIndex &index) { QTreeWidgetItem *item = indexToItem(index); QtBrowserItem *idx = m_itemToIndex.value(item); if (item) emit q_ptr->collapsed(idx); } void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index) { QTreeWidgetItem *item = indexToItem(index); QtBrowserItem *idx = m_itemToIndex.value(item); if (item) emit q_ptr->expanded(idx); } void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item) { if (!m_browserChangedBlocked && item != currentItem()) setCurrentItem(item, true); } void QtTreePropertyBrowserPrivate::slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *) { QtBrowserItem *browserItem = newItem ? m_itemToIndex.value(newItem) : 0; m_browserChangedBlocked = true; q_ptr->setCurrentItem(browserItem); m_browserChangedBlocked = false; } QTreeWidgetItem *QtTreePropertyBrowserPrivate::editedItem() const { return m_delegate->editedItem(); } void QtTreePropertyBrowserPrivate::editItem(QtBrowserItem *browserItem) { if (QTreeWidgetItem *treeItem = m_indexToItem.value(browserItem, 0)) { m_treeWidget->setCurrentItem (treeItem, 1); m_treeWidget->editItem(treeItem, 1); } } /*! \class QtTreePropertyBrowser \brief The QtTreePropertyBrowser class provides QTreeWidget based property browser. A property browser is a widget that enables the user to edit a given set of properties. Each property is represented by a label specifying the property's name, and an editing widget (e.g. a line edit or a combobox) holding its value. A property can have zero or more subproperties. QtTreePropertyBrowser provides a tree based view for all nested properties, i.e. properties that have subproperties can be in an expanded (subproperties are visible) or collapsed (subproperties are hidden) state. For example: \image qttreepropertybrowser.png Use the QtAbstractPropertyBrowser API to add, insert and remove properties from an instance of the QtTreePropertyBrowser class. The properties themselves are created and managed by implementations of the QtAbstractPropertyManager class. \sa QtGroupBoxPropertyBrowser, QtAbstractPropertyBrowser */ /*! \fn void QtTreePropertyBrowser::collapsed(QtBrowserItem *item) This signal is emitted when the \a item is collapsed. \sa expanded(), setExpanded() */ /*! \fn void QtTreePropertyBrowser::expanded(QtBrowserItem *item) This signal is emitted when the \a item is expanded. \sa collapsed(), setExpanded() */ /*! Creates a property browser with the given \a parent. */ QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent) : QtAbstractPropertyBrowser(parent) { d_ptr = new QtTreePropertyBrowserPrivate; d_ptr->q_ptr = this; d_ptr->init(this); connect(this, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentBrowserItemChanged(QtBrowserItem*))); } /*! Destroys this property browser. Note that the properties that were inserted into this browser are \e not destroyed since they may still be used in other browsers. The properties are owned by the manager that created them. \sa QtProperty, QtAbstractPropertyManager */ QtTreePropertyBrowser::~QtTreePropertyBrowser() { delete d_ptr; } /*! \property QtTreePropertyBrowser::indentation \brief indentation of the items in the tree view. */ int QtTreePropertyBrowser::indentation() const { return d_ptr->m_treeWidget->indentation(); } void QtTreePropertyBrowser::setIndentation(int i) { d_ptr->m_treeWidget->setIndentation(i); } /*! \property QtTreePropertyBrowser::rootIsDecorated \brief whether to show controls for expanding and collapsing root items. */ bool QtTreePropertyBrowser::rootIsDecorated() const { return d_ptr->m_treeWidget->rootIsDecorated(); } void QtTreePropertyBrowser::setRootIsDecorated(bool show) { d_ptr->m_treeWidget->setRootIsDecorated(show); QMapIterator it(d_ptr->m_itemToIndex); while (it.hasNext()) { QtProperty *property = it.next().value()->property(); if (!property->hasValue()) d_ptr->updateItem(it.key()); } } /*! \property QtTreePropertyBrowser::alternatingRowColors \brief whether to draw the background using alternating colors. By default this property is set to true. */ bool QtTreePropertyBrowser::alternatingRowColors() const { return d_ptr->m_treeWidget->alternatingRowColors(); } void QtTreePropertyBrowser::setAlternatingRowColors(bool enable) { d_ptr->m_treeWidget->setAlternatingRowColors(enable); QMapIterator it(d_ptr->m_itemToIndex); } /*! \property QtTreePropertyBrowser::headerVisible \brief whether to show the header. */ bool QtTreePropertyBrowser::isHeaderVisible() const { return d_ptr->m_headerVisible; } void QtTreePropertyBrowser::setHeaderVisible(bool visible) { if (d_ptr->m_headerVisible == visible) return; d_ptr->m_headerVisible = visible; d_ptr->m_treeWidget->header()->setVisible(visible); } /*! \enum QtTreePropertyBrowser::ResizeMode The resize mode specifies the behavior of the header sections. \value Interactive The user can resize the sections. The sections can also be resized programmatically using setSplitterPosition(). \value Fixed The user cannot resize the section. The section can only be resized programmatically using setSplitterPosition(). \value Stretch QHeaderView will automatically resize the section to fill the available space. The size cannot be changed by the user or programmatically. \value ResizeToContents QHeaderView will automatically resize the section to its optimal size based on the contents of the entire column. The size cannot be changed by the user or programmatically. \sa setResizeMode() */ /*! \property QtTreePropertyBrowser::resizeMode \brief the resize mode of setions in the header. */ QtTreePropertyBrowser::ResizeMode QtTreePropertyBrowser::resizeMode() const { return d_ptr->m_resizeMode; } void QtTreePropertyBrowser::setResizeMode(QtTreePropertyBrowser::ResizeMode mode) { if (d_ptr->m_resizeMode == mode) return; d_ptr->m_resizeMode = mode; QHeaderView::ResizeMode m = QHeaderView::Stretch; switch (mode) { case QtTreePropertyBrowser::Interactive: m = QHeaderView::Interactive; break; case QtTreePropertyBrowser::Fixed: m = QHeaderView::Fixed; break; case QtTreePropertyBrowser::ResizeToContents: m = QHeaderView::ResizeToContents; break; case QtTreePropertyBrowser::Stretch: default: m = QHeaderView::Stretch; break; } #if QT_VERSION >= 0x050000 d_ptr->m_treeWidget->header()->setSectionResizeMode(m); #else d_ptr->m_treeWidget->header()->setResizeMode(m); #endif } /*! \property QtTreePropertyBrowser::splitterPosition \brief the position of the splitter between the colunms. */ int QtTreePropertyBrowser::splitterPosition() const { return d_ptr->m_treeWidget->header()->sectionSize(0); } void QtTreePropertyBrowser::setSplitterPosition(int position) { d_ptr->m_treeWidget->header()->resizeSection(0, position); } /*! Sets the \a item to either collapse or expanded, depending on the value of \a expanded. \sa isExpanded(), expanded(), collapsed() */ void QtTreePropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded) { QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item); if (treeItem) treeItem->setExpanded(expanded); } /*! Returns true if the \a item is expanded; otherwise returns false. \sa setExpanded() */ bool QtTreePropertyBrowser::isExpanded(QtBrowserItem *item) const { QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item); if (treeItem) return treeItem->isExpanded(); return false; } /*! Returns true if the \a item is visible; otherwise returns false. \sa setItemVisible() \since 4.5 */ bool QtTreePropertyBrowser::isItemVisible(QtBrowserItem *item) const { if (const QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item)) return !treeItem->isHidden(); return false; } /*! Sets the \a item to be visible, depending on the value of \a visible. \sa isItemVisible() \since 4.5 */ void QtTreePropertyBrowser::setItemVisible(QtBrowserItem *item, bool visible) { if (QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item)) treeItem->setHidden(!visible); } /*! Sets the \a item's background color to \a color. Note that while item's background is rendered every second row is being drawn with alternate color (which is a bit lighter than items \a color) \sa backgroundColor(), calculatedBackgroundColor() */ void QtTreePropertyBrowser::setBackgroundColor(QtBrowserItem *item, const QColor &color) { if (!d_ptr->m_indexToItem.contains(item)) return; if (color.isValid()) d_ptr->m_indexToBackgroundColor[item] = color; else d_ptr->m_indexToBackgroundColor.remove(item); d_ptr->m_treeWidget->viewport()->update(); } /*! Returns the \a item's color. If there is no color set for item it returns invalid color. \sa calculatedBackgroundColor(), setBackgroundColor() */ QColor QtTreePropertyBrowser::backgroundColor(QtBrowserItem *item) const { return d_ptr->m_indexToBackgroundColor.value(item); } /*! Returns the \a item's color. If there is no color set for item it returns parent \a item's color (if there is no color set for parent it returns grandparent's color and so on). In case the color is not set for \a item and it's top level item it returns invalid color. \sa backgroundColor(), setBackgroundColor() */ QColor QtTreePropertyBrowser::calculatedBackgroundColor(QtBrowserItem *item) const { return d_ptr->calculatedBackgroundColor(item); } /*! \property QtTreePropertyBrowser::propertiesWithoutValueMarked \brief whether to enable or disable marking properties without value. When marking is enabled the item's background is rendered in dark color and item's foreground is rendered with light color. \sa propertiesWithoutValueMarked() */ void QtTreePropertyBrowser::setPropertiesWithoutValueMarked(bool mark) { if (d_ptr->m_markPropertiesWithoutValue == mark) return; d_ptr->m_markPropertiesWithoutValue = mark; QMapIterator it(d_ptr->m_itemToIndex); while (it.hasNext()) { QtProperty *property = it.next().value()->property(); if (!property->hasValue()) d_ptr->updateItem(it.key()); } d_ptr->m_treeWidget->viewport()->update(); } bool QtTreePropertyBrowser::propertiesWithoutValueMarked() const { return d_ptr->m_markPropertiesWithoutValue; } /*! \reimp */ void QtTreePropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) { d_ptr->propertyInserted(item, afterItem); } /*! \reimp */ void QtTreePropertyBrowser::itemRemoved(QtBrowserItem *item) { d_ptr->propertyRemoved(item); } /*! \reimp */ void QtTreePropertyBrowser::itemChanged(QtBrowserItem *item) { d_ptr->propertyChanged(item); } /*! Sets the current item to \a item and opens the relevant editor for it. */ void QtTreePropertyBrowser::editItem(QtBrowserItem *item) { d_ptr->editItem(item); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qttreepropertybrowser.cpp" #include "qttreepropertybrowser.moc" tiled-0.14.2/src/qtpropertybrowser/src/qttreepropertybrowser.h000066400000000000000000000115431260670167100250120ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTTREEPROPERTYBROWSER_H #define QTTREEPROPERTYBROWSER_H #include "qtpropertybrowser.h" #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QTreeWidgetItem; class QtTreePropertyBrowserPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtTreePropertyBrowser : public QtAbstractPropertyBrowser { Q_OBJECT Q_ENUMS(ResizeMode) Q_PROPERTY(int indentation READ indentation WRITE setIndentation) Q_PROPERTY(bool rootIsDecorated READ rootIsDecorated WRITE setRootIsDecorated) Q_PROPERTY(bool alternatingRowColors READ alternatingRowColors WRITE setAlternatingRowColors) Q_PROPERTY(bool headerVisible READ isHeaderVisible WRITE setHeaderVisible) Q_PROPERTY(ResizeMode resizeMode READ resizeMode WRITE setResizeMode) Q_PROPERTY(int splitterPosition READ splitterPosition WRITE setSplitterPosition) Q_PROPERTY(bool propertiesWithoutValueMarked READ propertiesWithoutValueMarked WRITE setPropertiesWithoutValueMarked) public: enum ResizeMode { Interactive, Stretch, Fixed, ResizeToContents }; QtTreePropertyBrowser(QWidget *parent = 0); ~QtTreePropertyBrowser(); int indentation() const; void setIndentation(int i); bool rootIsDecorated() const; void setRootIsDecorated(bool show); bool alternatingRowColors() const; void setAlternatingRowColors(bool enable); bool isHeaderVisible() const; void setHeaderVisible(bool visible); ResizeMode resizeMode() const; void setResizeMode(ResizeMode mode); int splitterPosition() const; void setSplitterPosition(int position); void setExpanded(QtBrowserItem *item, bool expanded); bool isExpanded(QtBrowserItem *item) const; bool isItemVisible(QtBrowserItem *item) const; void setItemVisible(QtBrowserItem *item, bool visible); void setBackgroundColor(QtBrowserItem *item, const QColor &color); QColor backgroundColor(QtBrowserItem *item) const; QColor calculatedBackgroundColor(QtBrowserItem *item) const; void setPropertiesWithoutValueMarked(bool mark); bool propertiesWithoutValueMarked() const; void editItem(QtBrowserItem *item); Q_SIGNALS: void collapsed(QtBrowserItem *item); void expanded(QtBrowserItem *item); protected: virtual void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem); virtual void itemRemoved(QtBrowserItem *item); virtual void itemChanged(QtBrowserItem *item); private: QtTreePropertyBrowserPrivate *d_ptr; Q_DECLARE_PRIVATE(QtTreePropertyBrowser) Q_DISABLE_COPY(QtTreePropertyBrowser) Q_PRIVATE_SLOT(d_func(), void slotCollapsed(const QModelIndex &)) Q_PRIVATE_SLOT(d_func(), void slotExpanded(const QModelIndex &)) Q_PRIVATE_SLOT(d_func(), void slotCurrentBrowserItemChanged(QtBrowserItem *)) Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #endif tiled-0.14.2/src/qtpropertybrowser/src/qtvariantproperty.cpp000066400000000000000000003117431260670167100244530ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qtvariantproperty.h" #include "qtpropertymanager.h" #include "qteditorfactory.h" #include #include #include #include #if defined(Q_CC_MSVC) # pragma warning(disable: 4786) /* MS VS 6: truncating debug info after 255 characters */ #endif #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif class QtEnumPropertyType { }; class QtFlagPropertyType { }; class QtGroupPropertyType { }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif Q_DECLARE_METATYPE(QtEnumPropertyType) Q_DECLARE_METATYPE(QtFlagPropertyType) Q_DECLARE_METATYPE(QtGroupPropertyType) #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif /*! Returns the type id for an enum property. Note that the property's value type can be retrieved using the valueType() function (which is QVariant::Int for the enum property type). \sa propertyType(), valueType() */ int QtVariantPropertyManager::enumTypeId() { return qMetaTypeId(); } /*! Returns the type id for a flag property. Note that the property's value type can be retrieved using the valueType() function (which is QVariant::Int for the flag property type). \sa propertyType(), valueType() */ int QtVariantPropertyManager::flagTypeId() { return qMetaTypeId(); } /*! Returns the type id for a group property. Note that the property's value type can be retrieved using the valueType() function (which is QVariant::Invalid for the group property type, since it doesn't provide any value). \sa propertyType(), valueType() */ int QtVariantPropertyManager::groupTypeId() { return qMetaTypeId(); } /*! Returns the type id for a icon map attribute. Note that the property's attribute type can be retrieved using the attributeType() function. \sa attributeType(), QtEnumPropertyManager::enumIcons() */ int QtVariantPropertyManager::iconMapTypeId() { return qMetaTypeId(); } typedef QMap PropertyMap; Q_GLOBAL_STATIC(PropertyMap, propertyToWrappedProperty) static QtProperty *wrappedProperty(QtProperty *property) { return propertyToWrappedProperty()->value(property, 0); } class QtVariantPropertyPrivate { QtVariantProperty *q_ptr; public: QtVariantPropertyPrivate(QtVariantPropertyManager *m) : manager(m) {} QtVariantPropertyManager *manager; }; /*! \class QtVariantProperty \brief The QtVariantProperty class is a convenience class handling QVariant based properties. QtVariantProperty provides additional API: A property's type, value type, attribute values and current value can easily be retrieved using the propertyType(), valueType(), attributeValue() and value() functions respectively. In addition, the attribute values and the current value can be set using the corresponding setValue() and setAttribute() functions. For example, instead of writing: \code QtVariantPropertyManager *variantPropertyManager; QtProperty *property; variantPropertyManager->setValue(property, 10); \endcode you can write: \code QtVariantPropertyManager *variantPropertyManager; QtVariantProperty *property; property->setValue(10); \endcode QtVariantProperty instances can only be created by the QtVariantPropertyManager class. \sa QtProperty, QtVariantPropertyManager, QtVariantEditorFactory */ /*! Creates a variant property using the given \a manager. Do not use this constructor to create variant property instances; use the QtVariantPropertyManager::addProperty() function instead. This constructor is used internally by the QtVariantPropertyManager::createProperty() function. \sa QtVariantPropertyManager */ QtVariantProperty::QtVariantProperty(QtVariantPropertyManager *manager) : QtProperty(manager), d_ptr(new QtVariantPropertyPrivate(manager)) { } /*! Destroys this property. \sa QtProperty::~QtProperty() */ QtVariantProperty::~QtVariantProperty() { delete d_ptr; } /*! Returns the property's current value. \sa valueType(), setValue() */ QVariant QtVariantProperty::value() const { return d_ptr->manager->value(this); } /*! Returns this property's value for the specified \a attribute. QtVariantPropertyManager provides a couple of related functions: \l{QtVariantPropertyManager::attributes()}{attributes()} and \l{QtVariantPropertyManager::attributeType()}{attributeType()}. \sa setAttribute() */ QVariant QtVariantProperty::attributeValue(const QString &attribute) const { return d_ptr->manager->attributeValue(this, attribute); } /*! Returns the type of this property's value. \sa propertyType() */ int QtVariantProperty::valueType() const { return d_ptr->manager->valueType(this); } /*! Returns this property's type. QtVariantPropertyManager provides several related functions: \l{QtVariantPropertyManager::enumTypeId()}{enumTypeId()}, \l{QtVariantPropertyManager::flagTypeId()}{flagTypeId()} and \l{QtVariantPropertyManager::groupTypeId()}{groupTypeId()}. \sa valueType() */ int QtVariantProperty::propertyType() const { return d_ptr->manager->propertyType(this); } /*! Sets the value of this property to \a value. The specified \a value must be of the type returned by valueType(), or of a type that can be converted to valueType() using the QVariant::canConvert() function; otherwise this function does nothing. \sa value() */ void QtVariantProperty::setValue(const QVariant &value) { d_ptr->manager->setValue(this, value); } /*! Sets the \a attribute of property to \a value. QtVariantPropertyManager provides the related \l{QtVariantPropertyManager::setAttribute()}{setAttribute()} function. \sa attributeValue() */ void QtVariantProperty::setAttribute(const QString &attribute, const QVariant &value) { d_ptr->manager->setAttribute(this, attribute, value); } class QtVariantPropertyManagerPrivate { QtVariantPropertyManager *q_ptr; Q_DECLARE_PUBLIC(QtVariantPropertyManager) public: QtVariantPropertyManagerPrivate(); bool m_creatingProperty; bool m_creatingSubProperties; bool m_destroyingSubProperties; int m_propertyType; void slotValueChanged(QtProperty *property, int val); void slotRangeChanged(QtProperty *property, int min, int max); void slotSingleStepChanged(QtProperty *property, int step); void slotValueChanged(QtProperty *property, double val); void slotRangeChanged(QtProperty *property, double min, double max); void slotSingleStepChanged(QtProperty *property, double step); void slotDecimalsChanged(QtProperty *property, int prec); void slotValueChanged(QtProperty *property, bool val); void slotValueChanged(QtProperty *property, const QString &val); void slotRegExpChanged(QtProperty *property, const QRegExp ®Exp); void slotEchoModeChanged(QtProperty *property, int); void slotValueChanged(QtProperty *property, const QDate &val); void slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max); void slotValueChanged(QtProperty *property, const QTime &val); void slotValueChanged(QtProperty *property, const QDateTime &val); void slotValueChanged(QtProperty *property, const QKeySequence &val); void slotValueChanged(QtProperty *property, const QChar &val); void slotValueChanged(QtProperty *property, const QLocale &val); void slotValueChanged(QtProperty *property, const QPoint &val); void slotValueChanged(QtProperty *property, const QPointF &val); void slotValueChanged(QtProperty *property, const QSize &val); void slotRangeChanged(QtProperty *property, const QSize &min, const QSize &max); void slotValueChanged(QtProperty *property, const QSizeF &val); void slotRangeChanged(QtProperty *property, const QSizeF &min, const QSizeF &max); void slotValueChanged(QtProperty *property, const QRect &val); void slotConstraintChanged(QtProperty *property, const QRect &val); void slotValueChanged(QtProperty *property, const QRectF &val); void slotConstraintChanged(QtProperty *property, const QRectF &val); void slotValueChanged(QtProperty *property, const QColor &val); void slotEnumChanged(QtProperty *property, int val); void slotEnumNamesChanged(QtProperty *property, const QStringList &enumNames); void slotEnumIconsChanged(QtProperty *property, const QMap &enumIcons); void slotValueChanged(QtProperty *property, const QSizePolicy &val); void slotValueChanged(QtProperty *property, const QFont &val); void slotValueChanged(QtProperty *property, const QCursor &val); void slotFlagChanged(QtProperty *property, int val); void slotFlagNamesChanged(QtProperty *property, const QStringList &flagNames); void slotReadOnlyChanged(QtProperty *property, bool readOnly); void slotTextVisibleChanged(QtProperty *property, bool textVisible); void slotPropertyInserted(QtProperty *property, QtProperty *parent, QtProperty *after); void slotPropertyRemoved(QtProperty *property, QtProperty *parent); void valueChanged(QtProperty *property, const QVariant &val); int internalPropertyToType(QtProperty *property) const; QtVariantProperty *createSubProperty(QtVariantProperty *parent, QtVariantProperty *after, QtProperty *internal); void removeSubProperty(QtVariantProperty *property); QMap m_typeToPropertyManager; QMap > m_typeToAttributeToAttributeType; QMap > m_propertyToType; QMap m_typeToValueType; QMap m_internalToProperty; const QString m_constraintAttribute; const QString m_singleStepAttribute; const QString m_decimalsAttribute; const QString m_enumIconsAttribute; const QString m_enumNamesAttribute; const QString m_flagNamesAttribute; const QString m_maximumAttribute; const QString m_minimumAttribute; const QString m_regExpAttribute; const QString m_echoModeAttribute; const QString m_readOnlyAttribute; const QString m_textVisibleAttribute; }; QtVariantPropertyManagerPrivate::QtVariantPropertyManagerPrivate() : m_constraintAttribute(QLatin1String("constraint")), m_singleStepAttribute(QLatin1String("singleStep")), m_decimalsAttribute(QLatin1String("decimals")), m_enumIconsAttribute(QLatin1String("enumIcons")), m_enumNamesAttribute(QLatin1String("enumNames")), m_flagNamesAttribute(QLatin1String("flagNames")), m_maximumAttribute(QLatin1String("maximum")), m_minimumAttribute(QLatin1String("minimum")), m_regExpAttribute(QLatin1String("regExp")), m_echoModeAttribute(QLatin1String("echoMode")), m_readOnlyAttribute(QLatin1String("readOnly")), m_textVisibleAttribute(QLatin1String("textVisible")) { } int QtVariantPropertyManagerPrivate::internalPropertyToType(QtProperty *property) const { int type = 0; QtAbstractPropertyManager *internPropertyManager = property->propertyManager(); if (qobject_cast(internPropertyManager)) type = QVariant::Int; else if (qobject_cast(internPropertyManager)) type = QtVariantPropertyManager::enumTypeId(); else if (qobject_cast(internPropertyManager)) type = QVariant::Bool; else if (qobject_cast(internPropertyManager)) type = QVariant::Double; return type; } QtVariantProperty *QtVariantPropertyManagerPrivate::createSubProperty(QtVariantProperty *parent, QtVariantProperty *after, QtProperty *internal) { int type = internalPropertyToType(internal); if (!type) return 0; bool wasCreatingSubProperties = m_creatingSubProperties; m_creatingSubProperties = true; QtVariantProperty *varChild = q_ptr->addProperty(type, internal->propertyName()); m_creatingSubProperties = wasCreatingSubProperties; varChild->setPropertyName(internal->propertyName()); varChild->setToolTip(internal->toolTip()); varChild->setStatusTip(internal->statusTip()); varChild->setWhatsThis(internal->whatsThis()); parent->insertSubProperty(varChild, after); m_internalToProperty[internal] = varChild; propertyToWrappedProperty()->insert(varChild, internal); return varChild; } void QtVariantPropertyManagerPrivate::removeSubProperty(QtVariantProperty *property) { QtProperty *internChild = wrappedProperty(property); bool wasDestroyingSubProperties = m_destroyingSubProperties; m_destroyingSubProperties = true; delete property; m_destroyingSubProperties = wasDestroyingSubProperties; m_internalToProperty.remove(internChild); propertyToWrappedProperty()->remove(property); } void QtVariantPropertyManagerPrivate::slotPropertyInserted(QtProperty *property, QtProperty *parent, QtProperty *after) { if (m_creatingProperty) return; QtVariantProperty *varParent = m_internalToProperty.value(parent, 0); if (!varParent) return; QtVariantProperty *varAfter = 0; if (after) { varAfter = m_internalToProperty.value(after, 0); if (!varAfter) return; } createSubProperty(varParent, varAfter, property); } void QtVariantPropertyManagerPrivate::slotPropertyRemoved(QtProperty *property, QtProperty *parent) { Q_UNUSED(parent) QtVariantProperty *varProperty = m_internalToProperty.value(property, 0); if (!varProperty) return; removeSubProperty(varProperty); } void QtVariantPropertyManagerPrivate::valueChanged(QtProperty *property, const QVariant &val) { QtVariantProperty *varProp = m_internalToProperty.value(property, 0); if (!varProp) return; emit q_ptr->valueChanged(varProp, val); emit q_ptr->propertyChanged(varProp); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, int val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, int min, int max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotSingleStepChanged(QtProperty *property, int step) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_singleStepAttribute, QVariant(step)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, double val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, double min, double max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotSingleStepChanged(QtProperty *property, double step) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_singleStepAttribute, QVariant(step)); } void QtVariantPropertyManagerPrivate::slotDecimalsChanged(QtProperty *property, int prec) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_decimalsAttribute, QVariant(prec)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, bool val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QString &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRegExpChanged(QtProperty *property, const QRegExp ®Exp) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_regExpAttribute, QVariant(regExp)); } void QtVariantPropertyManagerPrivate::slotEchoModeChanged(QtProperty *property, int mode) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_echoModeAttribute, QVariant(mode)); } void QtVariantPropertyManagerPrivate::slotReadOnlyChanged(QtProperty *property, bool readOnly) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_readOnlyAttribute, QVariant(readOnly)); } void QtVariantPropertyManagerPrivate::slotTextVisibleChanged(QtProperty *property, bool textVisible) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_textVisibleAttribute, QVariant(textVisible)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QDate &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QDate &min, const QDate &max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QTime &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QDateTime &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QKeySequence &val) { QVariant v; qVariantSetValue(v, val); valueChanged(property, v); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QChar &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QLocale &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QPoint &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QPointF &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSize &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QSize &min, const QSize &max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSizeF &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotRangeChanged(QtProperty *property, const QSizeF &min, const QSizeF &max) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { emit q_ptr->attributeChanged(varProp, m_minimumAttribute, QVariant(min)); emit q_ptr->attributeChanged(varProp, m_maximumAttribute, QVariant(max)); } } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QRect &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotConstraintChanged(QtProperty *property, const QRect &constraint) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_constraintAttribute, QVariant(constraint)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QRectF &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotConstraintChanged(QtProperty *property, const QRectF &constraint) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_constraintAttribute, QVariant(constraint)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QColor &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotEnumNamesChanged(QtProperty *property, const QStringList &enumNames) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_enumNamesAttribute, QVariant(enumNames)); } void QtVariantPropertyManagerPrivate::slotEnumIconsChanged(QtProperty *property, const QMap &enumIcons) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) { QVariant v; qVariantSetValue(v, enumIcons); emit q_ptr->attributeChanged(varProp, m_enumIconsAttribute, v); } } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QSizePolicy &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QFont &val) { valueChanged(property, QVariant(val)); } void QtVariantPropertyManagerPrivate::slotValueChanged(QtProperty *property, const QCursor &val) { #ifndef QT_NO_CURSOR valueChanged(property, QVariant(val)); #endif } void QtVariantPropertyManagerPrivate::slotFlagNamesChanged(QtProperty *property, const QStringList &flagNames) { if (QtVariantProperty *varProp = m_internalToProperty.value(property, 0)) emit q_ptr->attributeChanged(varProp, m_flagNamesAttribute, QVariant(flagNames)); } /*! \class QtVariantPropertyManager \brief The QtVariantPropertyManager class provides and manages QVariant based properties. QtVariantPropertyManager provides the addProperty() function which creates QtVariantProperty objects. The QtVariantProperty class is a convenience class handling QVariant based properties inheriting QtProperty. A QtProperty object created by a QtVariantPropertyManager instance can be converted into a QtVariantProperty object using the variantProperty() function. The property's value can be retrieved using the value(), and set using the setValue() slot. In addition the property's type, and the type of its value, can be retrieved using the propertyType() and valueType() functions respectively. A property's type is a QVariant::Type enumerator value, and usually a property's type is the same as its value type. But for some properties the types differ, for example for enums, flags and group types in which case QtVariantPropertyManager provides the enumTypeId(), flagTypeId() and groupTypeId() functions, respectively, to identify their property type (the value types are QVariant::Int for the enum and flag types, and QVariant::Invalid for the group type). Use the isPropertyTypeSupported() function to check if a particular property type is supported. The currently supported property types are: \table \header \o Property Type \o Property Type Id \row \o int \o QVariant::Int \row \o double \o QVariant::Double \row \o bool \o QVariant::Bool \row \o QString \o QVariant::String \row \o QDate \o QVariant::Date \row \o QTime \o QVariant::Time \row \o QDateTime \o QVariant::DateTime \row \o QKeySequence \o QVariant::KeySequence \row \o QChar \o QVariant::Char \row \o QLocale \o QVariant::Locale \row \o QPoint \o QVariant::Point \row \o QPointF \o QVariant::PointF \row \o QSize \o QVariant::Size \row \o QSizeF \o QVariant::SizeF \row \o QRect \o QVariant::Rect \row \o QRectF \o QVariant::RectF \row \o QColor \o QVariant::Color \row \o QSizePolicy \o QVariant::SizePolicy \row \o QFont \o QVariant::Font \row \o QCursor \o QVariant::Cursor \row \o enum \o enumTypeId() \row \o flag \o flagTypeId() \row \o group \o groupTypeId() \endtable Each property type can provide additional attributes, e.g. QVariant::Int and QVariant::Double provides minimum and maximum values. The currently supported attributes are: \table \header \o Property Type \o Attribute Name \o Attribute Type \row \o \c int \o minimum \o QVariant::Int \row \o \o maximum \o QVariant::Int \row \o \o singleStep \o QVariant::Int \row \o \c double \o minimum \o QVariant::Double \row \o \o maximum \o QVariant::Double \row \o \o singleStep \o QVariant::Double \row \o bool \o textVisible \o QVariant::Bool \row \o \o decimals \o QVariant::Int \row \o QString \o regExp \o QVariant::RegExp \row \o \o echoMode \o QVariant::Int \row \o QDate \o minimum \o QVariant::Date \row \o \o maximum \o QVariant::Date \row \o QPointF \o decimals \o QVariant::Int \row \o QSize \o minimum \o QVariant::Size \row \o \o maximum \o QVariant::Size \row \o QSizeF \o minimum \o QVariant::SizeF \row \o \o maximum \o QVariant::SizeF \row \o \o decimals \o QVariant::Int \row \o QRect \o constraint \o QVariant::Rect \row \o QRectF \o constraint \o QVariant::RectF \row \o \o decimals \o QVariant::Int \row \o \c enum \o enumNames \o QVariant::StringList \row \o \o enumIcons \o iconMapTypeId() \row \o \c flag \o flagNames \o QVariant::StringList \endtable The attributes for a given property type can be retrieved using the attributes() function. Each attribute has a value type which can be retrieved using the attributeType() function, and a value accessible through the attributeValue() function. In addition, the value can be set using the setAttribute() slot. QtVariantManager also provides the valueChanged() signal which is emitted whenever a property created by this manager change, and the attributeChanged() signal which is emitted whenever an attribute of such a property changes. \sa QtVariantProperty, QtVariantEditorFactory */ /*! \fn void QtVariantPropertyManager::valueChanged(QtProperty *property, const QVariant &value) This signal is emitted whenever a property created by this manager changes its value, passing a pointer to the \a property and the new \a value as parameters. \sa setValue() */ /*! \fn void QtVariantPropertyManager::attributeChanged(QtProperty *property, const QString &attribute, const QVariant &value) This signal is emitted whenever an attribute of a property created by this manager changes its value, passing a pointer to the \a property, the \a attribute and the new \a value as parameters. \sa setAttribute() */ /*! Creates a manager with the given \a parent. */ QtVariantPropertyManager::QtVariantPropertyManager(QObject *parent) : QtAbstractPropertyManager(parent) { d_ptr = new QtVariantPropertyManagerPrivate; d_ptr->q_ptr = this; d_ptr->m_creatingProperty = false; d_ptr->m_creatingSubProperties = false; d_ptr->m_destroyingSubProperties = false; d_ptr->m_propertyType = 0; // IntPropertyManager QtIntPropertyManager *intPropertyManager = new QtIntPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Int] = intPropertyManager; d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_minimumAttribute] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_maximumAttribute] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_singleStepAttribute] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[QVariant::Int][d_ptr->m_readOnlyAttribute] = QVariant::Bool; d_ptr->m_typeToValueType[QVariant::Int] = QVariant::Int; connect(intPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(intPropertyManager, SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(intPropertyManager, SIGNAL(singleStepChanged(QtProperty *, int)), this, SLOT(slotSingleStepChanged(QtProperty *, int))); // DoublePropertyManager QtDoublePropertyManager *doublePropertyManager = new QtDoublePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Double] = doublePropertyManager; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_minimumAttribute] = QVariant::Double; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_maximumAttribute] = QVariant::Double; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_singleStepAttribute] = QVariant::Double; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_decimalsAttribute] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[QVariant::Double][d_ptr->m_readOnlyAttribute] = QVariant::Bool; d_ptr->m_typeToValueType[QVariant::Double] = QVariant::Double; connect(doublePropertyManager, SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotValueChanged(QtProperty *, double))); connect(doublePropertyManager, SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); connect(doublePropertyManager, SIGNAL(singleStepChanged(QtProperty *, double)), this, SLOT(slotSingleStepChanged(QtProperty *, double))); connect(doublePropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); // BoolPropertyManager QtBoolPropertyManager *boolPropertyManager = new QtBoolPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Bool] = boolPropertyManager; d_ptr->m_typeToAttributeToAttributeType[QVariant::Bool][d_ptr->m_textVisibleAttribute] = QVariant::Bool; d_ptr->m_typeToValueType[QVariant::Bool] = QVariant::Bool; connect(boolPropertyManager, SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotValueChanged(QtProperty *, bool))); connect(boolPropertyManager, SIGNAL(textVisibleChanged(QtProperty*, bool)), this, SLOT(slotTextVisibleChanged(QtProperty*, bool))); // StringPropertyManager QtStringPropertyManager *stringPropertyManager = new QtStringPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::String] = stringPropertyManager; d_ptr->m_typeToValueType[QVariant::String] = QVariant::String; d_ptr->m_typeToAttributeToAttributeType[QVariant::String][d_ptr->m_regExpAttribute] = QVariant::RegExp; d_ptr->m_typeToAttributeToAttributeType[QVariant::String][d_ptr->m_echoModeAttribute] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[QVariant::String][d_ptr->m_readOnlyAttribute] = QVariant::Bool; connect(stringPropertyManager, SIGNAL(valueChanged(QtProperty *, const QString &)), this, SLOT(slotValueChanged(QtProperty *, const QString &))); connect(stringPropertyManager, SIGNAL(regExpChanged(QtProperty *, const QRegExp &)), this, SLOT(slotRegExpChanged(QtProperty *, const QRegExp &))); connect(stringPropertyManager, SIGNAL(echoModeChanged(QtProperty*,int)), this, SLOT(slotEchoModeChanged(QtProperty*, int))); connect(stringPropertyManager, SIGNAL(readOnlyChanged(QtProperty*, bool)), this, SLOT(slotReadOnlyChanged(QtProperty*, bool))); // DatePropertyManager QtDatePropertyManager *datePropertyManager = new QtDatePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Date] = datePropertyManager; d_ptr->m_typeToValueType[QVariant::Date] = QVariant::Date; d_ptr->m_typeToAttributeToAttributeType[QVariant::Date][d_ptr->m_minimumAttribute] = QVariant::Date; d_ptr->m_typeToAttributeToAttributeType[QVariant::Date][d_ptr->m_maximumAttribute] = QVariant::Date; connect(datePropertyManager, SIGNAL(valueChanged(QtProperty *, const QDate &)), this, SLOT(slotValueChanged(QtProperty *, const QDate &))); connect(datePropertyManager, SIGNAL(rangeChanged(QtProperty *, const QDate &, const QDate &)), this, SLOT(slotRangeChanged(QtProperty *, const QDate &, const QDate &))); // TimePropertyManager QtTimePropertyManager *timePropertyManager = new QtTimePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Time] = timePropertyManager; d_ptr->m_typeToValueType[QVariant::Time] = QVariant::Time; connect(timePropertyManager, SIGNAL(valueChanged(QtProperty *, const QTime &)), this, SLOT(slotValueChanged(QtProperty *, const QTime &))); // DateTimePropertyManager QtDateTimePropertyManager *dateTimePropertyManager = new QtDateTimePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::DateTime] = dateTimePropertyManager; d_ptr->m_typeToValueType[QVariant::DateTime] = QVariant::DateTime; connect(dateTimePropertyManager, SIGNAL(valueChanged(QtProperty *, const QDateTime &)), this, SLOT(slotValueChanged(QtProperty *, const QDateTime &))); // KeySequencePropertyManager QtKeySequencePropertyManager *keySequencePropertyManager = new QtKeySequencePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::KeySequence] = keySequencePropertyManager; d_ptr->m_typeToValueType[QVariant::KeySequence] = QVariant::KeySequence; connect(keySequencePropertyManager, SIGNAL(valueChanged(QtProperty *, const QKeySequence &)), this, SLOT(slotValueChanged(QtProperty *, const QKeySequence &))); // CharPropertyManager QtCharPropertyManager *charPropertyManager = new QtCharPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Char] = charPropertyManager; d_ptr->m_typeToValueType[QVariant::Char] = QVariant::Char; connect(charPropertyManager, SIGNAL(valueChanged(QtProperty *, const QChar &)), this, SLOT(slotValueChanged(QtProperty *, const QChar &))); // LocalePropertyManager QtLocalePropertyManager *localePropertyManager = new QtLocalePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Locale] = localePropertyManager; d_ptr->m_typeToValueType[QVariant::Locale] = QVariant::Locale; connect(localePropertyManager, SIGNAL(valueChanged(QtProperty *, const QLocale &)), this, SLOT(slotValueChanged(QtProperty *, const QLocale &))); connect(localePropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(localePropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(localePropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // PointPropertyManager QtPointPropertyManager *pointPropertyManager = new QtPointPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Point] = pointPropertyManager; d_ptr->m_typeToValueType[QVariant::Point] = QVariant::Point; connect(pointPropertyManager, SIGNAL(valueChanged(QtProperty *, const QPoint &)), this, SLOT(slotValueChanged(QtProperty *, const QPoint &))); connect(pointPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(pointPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(pointPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // PointFPropertyManager QtPointFPropertyManager *pointFPropertyManager = new QtPointFPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::PointF] = pointFPropertyManager; d_ptr->m_typeToValueType[QVariant::PointF] = QVariant::PointF; d_ptr->m_typeToAttributeToAttributeType[QVariant::PointF][d_ptr->m_decimalsAttribute] = QVariant::Int; connect(pointFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QPointF &)), this, SLOT(slotValueChanged(QtProperty *, const QPointF &))); connect(pointFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); connect(pointFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotValueChanged(QtProperty *, double))); connect(pointFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(pointFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // SizePropertyManager QtSizePropertyManager *sizePropertyManager = new QtSizePropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Size] = sizePropertyManager; d_ptr->m_typeToValueType[QVariant::Size] = QVariant::Size; d_ptr->m_typeToAttributeToAttributeType[QVariant::Size][d_ptr->m_minimumAttribute] = QVariant::Size; d_ptr->m_typeToAttributeToAttributeType[QVariant::Size][d_ptr->m_maximumAttribute] = QVariant::Size; connect(sizePropertyManager, SIGNAL(valueChanged(QtProperty *, const QSize &)), this, SLOT(slotValueChanged(QtProperty *, const QSize &))); connect(sizePropertyManager, SIGNAL(rangeChanged(QtProperty *, const QSize &, const QSize &)), this, SLOT(slotRangeChanged(QtProperty *, const QSize &, const QSize &))); connect(sizePropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(sizePropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(sizePropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(sizePropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // SizeFPropertyManager QtSizeFPropertyManager *sizeFPropertyManager = new QtSizeFPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::SizeF] = sizeFPropertyManager; d_ptr->m_typeToValueType[QVariant::SizeF] = QVariant::SizeF; d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_minimumAttribute] = QVariant::SizeF; d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_maximumAttribute] = QVariant::SizeF; d_ptr->m_typeToAttributeToAttributeType[QVariant::SizeF][d_ptr->m_decimalsAttribute] = QVariant::Int; connect(sizeFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QSizeF &)), this, SLOT(slotValueChanged(QtProperty *, const QSizeF &))); connect(sizeFPropertyManager, SIGNAL(rangeChanged(QtProperty *, const QSizeF &, const QSizeF &)), this, SLOT(slotRangeChanged(QtProperty *, const QSizeF &, const QSizeF &))); connect(sizeFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); connect(sizeFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotValueChanged(QtProperty *, double))); connect(sizeFPropertyManager->subDoublePropertyManager(), SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); connect(sizeFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(sizeFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // RectPropertyManager QtRectPropertyManager *rectPropertyManager = new QtRectPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Rect] = rectPropertyManager; d_ptr->m_typeToValueType[QVariant::Rect] = QVariant::Rect; d_ptr->m_typeToAttributeToAttributeType[QVariant::Rect][d_ptr->m_constraintAttribute] = QVariant::Rect; connect(rectPropertyManager, SIGNAL(valueChanged(QtProperty *, const QRect &)), this, SLOT(slotValueChanged(QtProperty *, const QRect &))); connect(rectPropertyManager, SIGNAL(constraintChanged(QtProperty *, const QRect &)), this, SLOT(slotConstraintChanged(QtProperty *, const QRect &))); connect(rectPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(rectPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(rectPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(rectPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // RectFPropertyManager QtRectFPropertyManager *rectFPropertyManager = new QtRectFPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::RectF] = rectFPropertyManager; d_ptr->m_typeToValueType[QVariant::RectF] = QVariant::RectF; d_ptr->m_typeToAttributeToAttributeType[QVariant::RectF][d_ptr->m_constraintAttribute] = QVariant::RectF; d_ptr->m_typeToAttributeToAttributeType[QVariant::RectF][d_ptr->m_decimalsAttribute] = QVariant::Int; connect(rectFPropertyManager, SIGNAL(valueChanged(QtProperty *, const QRectF &)), this, SLOT(slotValueChanged(QtProperty *, const QRectF &))); connect(rectFPropertyManager, SIGNAL(constraintChanged(QtProperty *, const QRectF &)), this, SLOT(slotConstraintChanged(QtProperty *, const QRectF &))); connect(rectFPropertyManager, SIGNAL(decimalsChanged(QtProperty *, int)), this, SLOT(slotDecimalsChanged(QtProperty *, int))); connect(rectFPropertyManager->subDoublePropertyManager(), SIGNAL(valueChanged(QtProperty *, double)), this, SLOT(slotValueChanged(QtProperty *, double))); connect(rectFPropertyManager->subDoublePropertyManager(), SIGNAL(rangeChanged(QtProperty *, double, double)), this, SLOT(slotRangeChanged(QtProperty *, double, double))); connect(rectFPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(rectFPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // ColorPropertyManager QtColorPropertyManager *colorPropertyManager = new QtColorPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Color] = colorPropertyManager; d_ptr->m_typeToValueType[QVariant::Color] = QVariant::Color; connect(colorPropertyManager, SIGNAL(valueChanged(QtProperty *, const QColor &)), this, SLOT(slotValueChanged(QtProperty *, const QColor &))); connect(colorPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(colorPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(colorPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // EnumPropertyManager int enumId = enumTypeId(); QtEnumPropertyManager *enumPropertyManager = new QtEnumPropertyManager(this); d_ptr->m_typeToPropertyManager[enumId] = enumPropertyManager; d_ptr->m_typeToValueType[enumId] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[enumId][d_ptr->m_enumNamesAttribute] = QVariant::StringList; d_ptr->m_typeToAttributeToAttributeType[enumId][d_ptr->m_enumIconsAttribute] = iconMapTypeId(); connect(enumPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(enumPropertyManager, SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); connect(enumPropertyManager, SIGNAL(enumIconsChanged(QtProperty *, const QMap &)), this, SLOT(slotEnumIconsChanged(QtProperty *, const QMap &))); // SizePolicyPropertyManager QtSizePolicyPropertyManager *sizePolicyPropertyManager = new QtSizePolicyPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::SizePolicy] = sizePolicyPropertyManager; d_ptr->m_typeToValueType[QVariant::SizePolicy] = QVariant::SizePolicy; connect(sizePolicyPropertyManager, SIGNAL(valueChanged(QtProperty *, const QSizePolicy &)), this, SLOT(slotValueChanged(QtProperty *, const QSizePolicy &))); connect(sizePolicyPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(sizePolicyPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(sizePolicyPropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(sizePolicyPropertyManager->subEnumPropertyManager(), SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); connect(sizePolicyPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(sizePolicyPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // FontPropertyManager QtFontPropertyManager *fontPropertyManager = new QtFontPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Font] = fontPropertyManager; d_ptr->m_typeToValueType[QVariant::Font] = QVariant::Font; connect(fontPropertyManager, SIGNAL(valueChanged(QtProperty *, const QFont &)), this, SLOT(slotValueChanged(QtProperty *, const QFont &))); connect(fontPropertyManager->subIntPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(fontPropertyManager->subIntPropertyManager(), SIGNAL(rangeChanged(QtProperty *, int, int)), this, SLOT(slotRangeChanged(QtProperty *, int, int))); connect(fontPropertyManager->subEnumPropertyManager(), SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(fontPropertyManager->subEnumPropertyManager(), SIGNAL(enumNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotEnumNamesChanged(QtProperty *, const QStringList &))); connect(fontPropertyManager->subBoolPropertyManager(), SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotValueChanged(QtProperty *, bool))); connect(fontPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(fontPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // CursorPropertyManager QtCursorPropertyManager *cursorPropertyManager = new QtCursorPropertyManager(this); d_ptr->m_typeToPropertyManager[QVariant::Cursor] = cursorPropertyManager; d_ptr->m_typeToValueType[QVariant::Cursor] = QVariant::Cursor; connect(cursorPropertyManager, SIGNAL(valueChanged(QtProperty *, const QCursor &)), this, SLOT(slotValueChanged(QtProperty *, const QCursor &))); // FlagPropertyManager int flagId = flagTypeId(); QtFlagPropertyManager *flagPropertyManager = new QtFlagPropertyManager(this); d_ptr->m_typeToPropertyManager[flagId] = flagPropertyManager; d_ptr->m_typeToValueType[flagId] = QVariant::Int; d_ptr->m_typeToAttributeToAttributeType[flagId][d_ptr->m_flagNamesAttribute] = QVariant::StringList; connect(flagPropertyManager, SIGNAL(valueChanged(QtProperty *, int)), this, SLOT(slotValueChanged(QtProperty *, int))); connect(flagPropertyManager, SIGNAL(flagNamesChanged(QtProperty *, const QStringList &)), this, SLOT(slotFlagNamesChanged(QtProperty *, const QStringList &))); connect(flagPropertyManager->subBoolPropertyManager(), SIGNAL(valueChanged(QtProperty *, bool)), this, SLOT(slotValueChanged(QtProperty *, bool))); connect(flagPropertyManager, SIGNAL(propertyInserted(QtProperty *, QtProperty *, QtProperty *)), this, SLOT(slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *))); connect(flagPropertyManager, SIGNAL(propertyRemoved(QtProperty *, QtProperty *)), this, SLOT(slotPropertyRemoved(QtProperty *, QtProperty *))); // FlagPropertyManager int groupId = groupTypeId(); QtGroupPropertyManager *groupPropertyManager = new QtGroupPropertyManager(this); d_ptr->m_typeToPropertyManager[groupId] = groupPropertyManager; d_ptr->m_typeToValueType[groupId] = QVariant::Invalid; } /*! Destroys this manager, and all the properties it has created. */ QtVariantPropertyManager::~QtVariantPropertyManager() { clear(); delete d_ptr; } /*! Returns the given \a property converted into a QtVariantProperty. If the \a property was not created by this variant manager, the function returns 0. \sa createProperty() */ QtVariantProperty *QtVariantPropertyManager::variantProperty(const QtProperty *property) const { const QMap >::const_iterator it = d_ptr->m_propertyToType.constFind(property); if (it == d_ptr->m_propertyToType.constEnd()) return 0; return it.value().first; } /*! Returns true if the given \a propertyType is supported by this variant manager; otherwise false. \sa propertyType() */ bool QtVariantPropertyManager::isPropertyTypeSupported(int propertyType) const { if (d_ptr->m_typeToValueType.contains(propertyType)) return true; return false; } /*! Creates and returns a variant property of the given \a propertyType with the given \a name. If the specified \a propertyType is not supported by this variant manager, this function returns 0. Do not use the inherited QtAbstractPropertyManager::addProperty() function to create a variant property (that function will always return 0 since it will not be clear what type the property should have). \sa isPropertyTypeSupported() */ QtVariantProperty *QtVariantPropertyManager::addProperty(int propertyType, const QString &name) { if (!isPropertyTypeSupported(propertyType)) return 0; bool wasCreating = d_ptr->m_creatingProperty; d_ptr->m_creatingProperty = true; d_ptr->m_propertyType = propertyType; QtProperty *property = QtAbstractPropertyManager::addProperty(name); d_ptr->m_creatingProperty = wasCreating; d_ptr->m_propertyType = 0; if (!property) return 0; return variantProperty(property); } /*! Returns the given \a property's value. If the given \a property is not managed by this manager, this function returns an invalid variant. \sa setValue() */ QVariant QtVariantPropertyManager::value(const QtProperty *property) const { QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); if (internProp == 0) return QVariant(); QtAbstractPropertyManager *manager = internProp->propertyManager(); if (QtIntPropertyManager *intManager = qobject_cast(manager)) { return intManager->value(internProp); } else if (QtDoublePropertyManager *doubleManager = qobject_cast(manager)) { return doubleManager->value(internProp); } else if (QtBoolPropertyManager *boolManager = qobject_cast(manager)) { return boolManager->value(internProp); } else if (QtStringPropertyManager *stringManager = qobject_cast(manager)) { return stringManager->value(internProp); } else if (QtDatePropertyManager *dateManager = qobject_cast(manager)) { return dateManager->value(internProp); } else if (QtTimePropertyManager *timeManager = qobject_cast(manager)) { return timeManager->value(internProp); } else if (QtDateTimePropertyManager *dateTimeManager = qobject_cast(manager)) { return dateTimeManager->value(internProp); } else if (QtKeySequencePropertyManager *keySequenceManager = qobject_cast(manager)) { #if QT_VERSION < 0x050000 return keySequenceManager->value(internProp); #else return QVariant::fromValue(keySequenceManager->value(internProp)); #endif } else if (QtCharPropertyManager *charManager = qobject_cast(manager)) { return charManager->value(internProp); } else if (QtLocalePropertyManager *localeManager = qobject_cast(manager)) { return localeManager->value(internProp); } else if (QtPointPropertyManager *pointManager = qobject_cast(manager)) { return pointManager->value(internProp); } else if (QtPointFPropertyManager *pointFManager = qobject_cast(manager)) { return pointFManager->value(internProp); } else if (QtSizePropertyManager *sizeManager = qobject_cast(manager)) { return sizeManager->value(internProp); } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast(manager)) { return sizeFManager->value(internProp); } else if (QtRectPropertyManager *rectManager = qobject_cast(manager)) { return rectManager->value(internProp); } else if (QtRectFPropertyManager *rectFManager = qobject_cast(manager)) { return rectFManager->value(internProp); } else if (QtColorPropertyManager *colorManager = qobject_cast(manager)) { return colorManager->value(internProp); } else if (QtEnumPropertyManager *enumManager = qobject_cast(manager)) { return enumManager->value(internProp); } else if (QtSizePolicyPropertyManager *sizePolicyManager = qobject_cast(manager)) { return sizePolicyManager->value(internProp); } else if (QtFontPropertyManager *fontManager = qobject_cast(manager)) { return fontManager->value(internProp); #ifndef QT_NO_CURSOR } else if (QtCursorPropertyManager *cursorManager = qobject_cast(manager)) { return cursorManager->value(internProp); #endif } else if (QtFlagPropertyManager *flagManager = qobject_cast(manager)) { return flagManager->value(internProp); } return QVariant(); } /*! Returns the given \a property's value type. \sa propertyType() */ int QtVariantPropertyManager::valueType(const QtProperty *property) const { int propType = propertyType(property); return valueType(propType); } /*! \overload Returns the value type associated with the given \a propertyType. */ int QtVariantPropertyManager::valueType(int propertyType) const { if (d_ptr->m_typeToValueType.contains(propertyType)) return d_ptr->m_typeToValueType[propertyType]; return 0; } /*! Returns the given \a property's type. \sa valueType() */ int QtVariantPropertyManager::propertyType(const QtProperty *property) const { const QMap >::const_iterator it = d_ptr->m_propertyToType.constFind(property); if (it == d_ptr->m_propertyToType.constEnd()) return 0; return it.value().second; } /*! Returns the given \a property's value for the specified \a attribute If the given \a property was not created by \e this manager, or if the specified \a attribute does not exist, this function returns an invalid variant. \sa attributes(), attributeType(), setAttribute() */ QVariant QtVariantPropertyManager::attributeValue(const QtProperty *property, const QString &attribute) const { int propType = propertyType(property); if (!propType) return QVariant(); QMap >::ConstIterator it = d_ptr->m_typeToAttributeToAttributeType.find(propType); if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) return QVariant(); QMap attributes = it.value(); QMap::ConstIterator itAttr = attributes.find(attribute); if (itAttr == attributes.constEnd()) return QVariant(); QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); if (internProp == 0) return QVariant(); QtAbstractPropertyManager *manager = internProp->propertyManager(); if (QtIntPropertyManager *intManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return intManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return intManager->minimum(internProp); if (attribute == d_ptr->m_singleStepAttribute) return intManager->singleStep(internProp); if (attribute == d_ptr->m_readOnlyAttribute) return intManager->isReadOnly(internProp); return QVariant(); } else if (QtDoublePropertyManager *doubleManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return doubleManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return doubleManager->minimum(internProp); if (attribute == d_ptr->m_singleStepAttribute) return doubleManager->singleStep(internProp); if (attribute == d_ptr->m_decimalsAttribute) return doubleManager->decimals(internProp); if (attribute == d_ptr->m_readOnlyAttribute) return doubleManager->isReadOnly(internProp); return QVariant(); } else if (QtBoolPropertyManager *boolManager = qobject_cast(manager)) { if (attribute == d_ptr->m_textVisibleAttribute) return boolManager->textVisible(internProp); return QVariant(); } else if (QtStringPropertyManager *stringManager = qobject_cast(manager)) { if (attribute == d_ptr->m_regExpAttribute) return stringManager->regExp(internProp); if (attribute == d_ptr->m_echoModeAttribute) return stringManager->echoMode(internProp); if (attribute == d_ptr->m_readOnlyAttribute) return stringManager->isReadOnly(internProp); return QVariant(); } else if (QtDatePropertyManager *dateManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return dateManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return dateManager->minimum(internProp); return QVariant(); } else if (QtPointFPropertyManager *pointFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_decimalsAttribute) return pointFManager->decimals(internProp); return QVariant(); } else if (QtSizePropertyManager *sizeManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return sizeManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return sizeManager->minimum(internProp); return QVariant(); } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) return sizeFManager->maximum(internProp); if (attribute == d_ptr->m_minimumAttribute) return sizeFManager->minimum(internProp); if (attribute == d_ptr->m_decimalsAttribute) return sizeFManager->decimals(internProp); return QVariant(); } else if (QtRectPropertyManager *rectManager = qobject_cast(manager)) { if (attribute == d_ptr->m_constraintAttribute) return rectManager->constraint(internProp); return QVariant(); } else if (QtRectFPropertyManager *rectFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_constraintAttribute) return rectFManager->constraint(internProp); if (attribute == d_ptr->m_decimalsAttribute) return rectFManager->decimals(internProp); return QVariant(); } else if (QtEnumPropertyManager *enumManager = qobject_cast(manager)) { if (attribute == d_ptr->m_enumNamesAttribute) return enumManager->enumNames(internProp); if (attribute == d_ptr->m_enumIconsAttribute) { QVariant v; qVariantSetValue(v, enumManager->enumIcons(internProp)); return v; } return QVariant(); } else if (QtFlagPropertyManager *flagManager = qobject_cast(manager)) { if (attribute == d_ptr->m_flagNamesAttribute) return flagManager->flagNames(internProp); return QVariant(); } return QVariant(); } /*! Returns a list of the given \a propertyType 's attributes. \sa attributeValue(), attributeType() */ QStringList QtVariantPropertyManager::attributes(int propertyType) const { QMap >::ConstIterator it = d_ptr->m_typeToAttributeToAttributeType.find(propertyType); if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) return QStringList(); return it.value().keys(); } /*! Returns the type of the specified \a attribute of the given \a propertyType. If the given \a propertyType is not supported by \e this manager, or if the given \a propertyType does not possess the specified \a attribute, this function returns QVariant::Invalid. \sa attributes(), valueType() */ int QtVariantPropertyManager::attributeType(int propertyType, const QString &attribute) const { QMap >::ConstIterator it = d_ptr->m_typeToAttributeToAttributeType.find(propertyType); if (it == d_ptr->m_typeToAttributeToAttributeType.constEnd()) return 0; QMap attributes = it.value(); QMap::ConstIterator itAttr = attributes.find(attribute); if (itAttr == attributes.constEnd()) return 0; return itAttr.value(); } /*! \fn void QtVariantPropertyManager::setValue(QtProperty *property, const QVariant &value) Sets the value of the given \a property to \a value. The specified \a value must be of a type returned by valueType(), or of type that can be converted to valueType() using the QVariant::canConvert() function, otherwise this function does nothing. \sa value(), QtVariantProperty::setValue(), valueChanged() */ void QtVariantPropertyManager::setValue(QtProperty *property, const QVariant &val) { int propType = val.userType(); if (!propType) return; int valType = valueType(property); if (propType != valType && !val.canConvert(static_cast(valType))) return; QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); if (internProp == 0) return; QtAbstractPropertyManager *manager = internProp->propertyManager(); if (QtIntPropertyManager *intManager = qobject_cast(manager)) { intManager->setValue(internProp, val.value()); return; } else if (QtDoublePropertyManager *doubleManager = qobject_cast(manager)) { doubleManager->setValue(internProp, val.value()); return; } else if (QtBoolPropertyManager *boolManager = qobject_cast(manager)) { boolManager->setValue(internProp, val.value()); return; } else if (QtStringPropertyManager *stringManager = qobject_cast(manager)) { stringManager->setValue(internProp, val.value()); return; } else if (QtDatePropertyManager *dateManager = qobject_cast(manager)) { dateManager->setValue(internProp, val.value()); return; } else if (QtTimePropertyManager *timeManager = qobject_cast(manager)) { timeManager->setValue(internProp, val.value()); return; } else if (QtDateTimePropertyManager *dateTimeManager = qobject_cast(manager)) { dateTimeManager->setValue(internProp, val.value()); return; } else if (QtKeySequencePropertyManager *keySequenceManager = qobject_cast(manager)) { keySequenceManager->setValue(internProp, val.value()); return; } else if (QtCharPropertyManager *charManager = qobject_cast(manager)) { charManager->setValue(internProp, val.value()); return; } else if (QtLocalePropertyManager *localeManager = qobject_cast(manager)) { localeManager->setValue(internProp, val.value()); return; } else if (QtPointPropertyManager *pointManager = qobject_cast(manager)) { pointManager->setValue(internProp, val.value()); return; } else if (QtPointFPropertyManager *pointFManager = qobject_cast(manager)) { pointFManager->setValue(internProp, val.value()); return; } else if (QtSizePropertyManager *sizeManager = qobject_cast(manager)) { sizeManager->setValue(internProp, val.value()); return; } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast(manager)) { sizeFManager->setValue(internProp, val.value()); return; } else if (QtRectPropertyManager *rectManager = qobject_cast(manager)) { rectManager->setValue(internProp, val.value()); return; } else if (QtRectFPropertyManager *rectFManager = qobject_cast(manager)) { rectFManager->setValue(internProp, val.value()); return; } else if (QtColorPropertyManager *colorManager = qobject_cast(manager)) { colorManager->setValue(internProp, val.value()); return; } else if (QtEnumPropertyManager *enumManager = qobject_cast(manager)) { enumManager->setValue(internProp, val.value()); return; } else if (QtSizePolicyPropertyManager *sizePolicyManager = qobject_cast(manager)) { sizePolicyManager->setValue(internProp, val.value()); return; } else if (QtFontPropertyManager *fontManager = qobject_cast(manager)) { fontManager->setValue(internProp, val.value()); return; #ifndef QT_NO_CURSOR } else if (QtCursorPropertyManager *cursorManager = qobject_cast(manager)) { cursorManager->setValue(internProp, val.value()); return; #endif } else if (QtFlagPropertyManager *flagManager = qobject_cast(manager)) { flagManager->setValue(internProp, val.value()); return; } } /*! Sets the value of the specified \a attribute of the given \a property, to \a value. The new \a value's type must be of the type returned by attributeType(), or of a type that can be converted to attributeType() using the QVariant::canConvert() function, otherwise this function does nothing. \sa attributeValue(), QtVariantProperty::setAttribute(), attributeChanged() */ void QtVariantPropertyManager::setAttribute(QtProperty *property, const QString &attribute, const QVariant &value) { QVariant oldAttr = attributeValue(property, attribute); if (!oldAttr.isValid()) return; int attrType = value.userType(); if (!attrType) return; if (attrType != attributeType(propertyType(property), attribute) && !value.canConvert((QVariant::Type)attrType)) return; QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); if (internProp == 0) return; QtAbstractPropertyManager *manager = internProp->propertyManager(); if (QtIntPropertyManager *intManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) intManager->setMaximum(internProp, value.value()); else if (attribute == d_ptr->m_minimumAttribute) intManager->setMinimum(internProp, value.value()); else if (attribute == d_ptr->m_singleStepAttribute) intManager->setSingleStep(internProp, value.value()); else if (attribute == d_ptr->m_readOnlyAttribute) intManager->setReadOnly(internProp, value.value()); return; } else if (QtDoublePropertyManager *doubleManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) doubleManager->setMaximum(internProp, value.value()); if (attribute == d_ptr->m_minimumAttribute) doubleManager->setMinimum(internProp, value.value()); if (attribute == d_ptr->m_singleStepAttribute) doubleManager->setSingleStep(internProp, value.value()); if (attribute == d_ptr->m_decimalsAttribute) doubleManager->setDecimals(internProp, value.value()); if (attribute == d_ptr->m_readOnlyAttribute) doubleManager->setReadOnly(internProp, value.value()); return; } else if (QtBoolPropertyManager *boolManager = qobject_cast(manager)) { if (attribute == d_ptr->m_textVisibleAttribute) boolManager->setTextVisible(internProp, value.value()); return; } else if (QtStringPropertyManager *stringManager = qobject_cast(manager)) { if (attribute == d_ptr->m_regExpAttribute) stringManager->setRegExp(internProp, value.value()); if (attribute == d_ptr->m_echoModeAttribute) stringManager->setEchoMode(internProp, (EchoMode)value.value()); if (attribute == d_ptr->m_readOnlyAttribute) stringManager->setReadOnly(internProp, (EchoMode)value.value()); return; } else if (QtDatePropertyManager *dateManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) dateManager->setMaximum(internProp, value.value()); if (attribute == d_ptr->m_minimumAttribute) dateManager->setMinimum(internProp, value.value()); return; } else if (QtPointFPropertyManager *pointFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_decimalsAttribute) pointFManager->setDecimals(internProp, value.value()); return; } else if (QtSizePropertyManager *sizeManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) sizeManager->setMaximum(internProp, value.value()); if (attribute == d_ptr->m_minimumAttribute) sizeManager->setMinimum(internProp, value.value()); return; } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_maximumAttribute) sizeFManager->setMaximum(internProp, value.value()); if (attribute == d_ptr->m_minimumAttribute) sizeFManager->setMinimum(internProp, value.value()); if (attribute == d_ptr->m_decimalsAttribute) sizeFManager->setDecimals(internProp, value.value()); return; } else if (QtRectPropertyManager *rectManager = qobject_cast(manager)) { if (attribute == d_ptr->m_constraintAttribute) rectManager->setConstraint(internProp, value.value()); return; } else if (QtRectFPropertyManager *rectFManager = qobject_cast(manager)) { if (attribute == d_ptr->m_constraintAttribute) rectFManager->setConstraint(internProp, value.value()); if (attribute == d_ptr->m_decimalsAttribute) rectFManager->setDecimals(internProp, value.value()); return; } else if (QtEnumPropertyManager *enumManager = qobject_cast(manager)) { if (attribute == d_ptr->m_enumNamesAttribute) enumManager->setEnumNames(internProp, value.value()); if (attribute == d_ptr->m_enumIconsAttribute) enumManager->setEnumIcons(internProp, value.value()); return; } else if (QtFlagPropertyManager *flagManager = qobject_cast(manager)) { if (attribute == d_ptr->m_flagNamesAttribute) flagManager->setFlagNames(internProp, value.value()); return; } } /*! \reimp */ bool QtVariantPropertyManager::hasValue(const QtProperty *property) const { if (propertyType(property) == groupTypeId()) return false; return true; } /*! \reimp */ QString QtVariantPropertyManager::valueText(const QtProperty *property) const { const QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); return internProp ? !internProp->displayText().isEmpty() ? internProp->displayText() : internProp->valueText() : QString(); } /*! \reimp */ QIcon QtVariantPropertyManager::valueIcon(const QtProperty *property) const { const QtProperty *internProp = propertyToWrappedProperty()->value(property, 0); return internProp ? internProp->valueIcon() : QIcon(); } /*! \reimp */ void QtVariantPropertyManager::initializeProperty(QtProperty *property) { QtVariantProperty *varProp = variantProperty(property); if (!varProp) return; QMap::ConstIterator it = d_ptr->m_typeToPropertyManager.find(d_ptr->m_propertyType); if (it != d_ptr->m_typeToPropertyManager.constEnd()) { QtProperty *internProp = 0; if (!d_ptr->m_creatingSubProperties) { QtAbstractPropertyManager *manager = it.value(); internProp = manager->addProperty(); d_ptr->m_internalToProperty[internProp] = varProp; } propertyToWrappedProperty()->insert(varProp, internProp); if (internProp) { QList children = internProp->subProperties(); QListIterator itChild(children); QtVariantProperty *lastProperty = 0; while (itChild.hasNext()) { QtVariantProperty *prop = d_ptr->createSubProperty(varProp, lastProperty, itChild.next()); lastProperty = prop ? prop : lastProperty; } } } } /*! \reimp */ void QtVariantPropertyManager::uninitializeProperty(QtProperty *property) { const QMap >::iterator type_it = d_ptr->m_propertyToType.find(property); if (type_it == d_ptr->m_propertyToType.end()) return; PropertyMap::iterator it = propertyToWrappedProperty()->find(property); if (it != propertyToWrappedProperty()->end()) { QtProperty *internProp = it.value(); if (internProp) { d_ptr->m_internalToProperty.remove(internProp); if (!d_ptr->m_destroyingSubProperties) { delete internProp; } } propertyToWrappedProperty()->erase(it); } d_ptr->m_propertyToType.erase(type_it); } /*! \reimp */ QtProperty *QtVariantPropertyManager::createProperty() { if (!d_ptr->m_creatingProperty) return 0; QtVariantProperty *property = new QtVariantProperty(this); d_ptr->m_propertyToType.insert(property, qMakePair(property, d_ptr->m_propertyType)); return property; } ///////////////////////////// class QtVariantEditorFactoryPrivate { QtVariantEditorFactory *q_ptr; Q_DECLARE_PUBLIC(QtVariantEditorFactory) public: QtSpinBoxFactory *m_spinBoxFactory; QtDoubleSpinBoxFactory *m_doubleSpinBoxFactory; QtCheckBoxFactory *m_checkBoxFactory; QtLineEditFactory *m_lineEditFactory; QtDateEditFactory *m_dateEditFactory; QtTimeEditFactory *m_timeEditFactory; QtDateTimeEditFactory *m_dateTimeEditFactory; QtKeySequenceEditorFactory *m_keySequenceEditorFactory; QtCharEditorFactory *m_charEditorFactory; QtEnumEditorFactory *m_comboBoxFactory; QtCursorEditorFactory *m_cursorEditorFactory; QtColorEditorFactory *m_colorEditorFactory; QtFontEditorFactory *m_fontEditorFactory; QMap m_factoryToType; QMap m_typeToFactory; }; /*! \class QtVariantEditorFactory \brief The QtVariantEditorFactory class provides widgets for properties created by QtVariantPropertyManager objects. The variant factory provides the following widgets for the specified property types: \table \header \o Property Type \o Widget \row \o \c int \o QSpinBox \row \o \c double \o QDoubleSpinBox \row \o \c bool \o QCheckBox \row \o QString \o QLineEdit \row \o QDate \o QDateEdit \row \o QTime \o QTimeEdit \row \o QDateTime \o QDateTimeEdit \row \o QKeySequence \o customized editor \row \o QChar \o customized editor \row \o \c enum \o QComboBox \row \o QCursor \o QComboBox \endtable Note that QtVariantPropertyManager supports several additional property types for which the QtVariantEditorFactory class does not provide editing widgets, e.g. QPoint and QSize. To provide widgets for other types using the variant approach, derive from the QtVariantEditorFactory class. \sa QtAbstractEditorFactory, QtVariantPropertyManager */ /*! Creates a factory with the given \a parent. */ QtVariantEditorFactory::QtVariantEditorFactory(QObject *parent) : QtAbstractEditorFactory(parent) { d_ptr = new QtVariantEditorFactoryPrivate(); d_ptr->q_ptr = this; d_ptr->m_spinBoxFactory = new QtSpinBoxFactory(this); d_ptr->m_factoryToType[d_ptr->m_spinBoxFactory] = QVariant::Int; d_ptr->m_typeToFactory[QVariant::Int] = d_ptr->m_spinBoxFactory; d_ptr->m_doubleSpinBoxFactory = new QtDoubleSpinBoxFactory(this); d_ptr->m_factoryToType[d_ptr->m_doubleSpinBoxFactory] = QVariant::Double; d_ptr->m_typeToFactory[QVariant::Double] = d_ptr->m_doubleSpinBoxFactory; d_ptr->m_checkBoxFactory = new QtCheckBoxFactory(this); d_ptr->m_factoryToType[d_ptr->m_checkBoxFactory] = QVariant::Bool; d_ptr->m_typeToFactory[QVariant::Bool] = d_ptr->m_checkBoxFactory; d_ptr->m_lineEditFactory = new QtLineEditFactory(this); d_ptr->m_factoryToType[d_ptr->m_lineEditFactory] = QVariant::String; d_ptr->m_typeToFactory[QVariant::String] = d_ptr->m_lineEditFactory; d_ptr->m_dateEditFactory = new QtDateEditFactory(this); d_ptr->m_factoryToType[d_ptr->m_dateEditFactory] = QVariant::Date; d_ptr->m_typeToFactory[QVariant::Date] = d_ptr->m_dateEditFactory; d_ptr->m_timeEditFactory = new QtTimeEditFactory(this); d_ptr->m_factoryToType[d_ptr->m_timeEditFactory] = QVariant::Time; d_ptr->m_typeToFactory[QVariant::Time] = d_ptr->m_timeEditFactory; d_ptr->m_dateTimeEditFactory = new QtDateTimeEditFactory(this); d_ptr->m_factoryToType[d_ptr->m_dateTimeEditFactory] = QVariant::DateTime; d_ptr->m_typeToFactory[QVariant::DateTime] = d_ptr->m_dateTimeEditFactory; d_ptr->m_keySequenceEditorFactory = new QtKeySequenceEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_keySequenceEditorFactory] = QVariant::KeySequence; d_ptr->m_typeToFactory[QVariant::KeySequence] = d_ptr->m_keySequenceEditorFactory; d_ptr->m_charEditorFactory = new QtCharEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_charEditorFactory] = QVariant::Char; d_ptr->m_typeToFactory[QVariant::Char] = d_ptr->m_charEditorFactory; d_ptr->m_cursorEditorFactory = new QtCursorEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_cursorEditorFactory] = QVariant::Cursor; d_ptr->m_typeToFactory[QVariant::Cursor] = d_ptr->m_cursorEditorFactory; d_ptr->m_colorEditorFactory = new QtColorEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_colorEditorFactory] = QVariant::Color; d_ptr->m_typeToFactory[QVariant::Color] = d_ptr->m_colorEditorFactory; d_ptr->m_fontEditorFactory = new QtFontEditorFactory(this); d_ptr->m_factoryToType[d_ptr->m_fontEditorFactory] = QVariant::Font; d_ptr->m_typeToFactory[QVariant::Font] = d_ptr->m_fontEditorFactory; d_ptr->m_comboBoxFactory = new QtEnumEditorFactory(this); const int enumId = QtVariantPropertyManager::enumTypeId(); d_ptr->m_factoryToType[d_ptr->m_comboBoxFactory] = enumId; d_ptr->m_typeToFactory[enumId] = d_ptr->m_comboBoxFactory; } /*! Destroys this factory, and all the widgets it has created. */ QtVariantEditorFactory::~QtVariantEditorFactory() { delete d_ptr; } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtVariantEditorFactory::connectPropertyManager(QtVariantPropertyManager *manager) { QList intPropertyManagers = manager->findChildren(); QListIterator itInt(intPropertyManagers); while (itInt.hasNext()) d_ptr->m_spinBoxFactory->addPropertyManager(itInt.next()); QList doublePropertyManagers = manager->findChildren(); QListIterator itDouble(doublePropertyManagers); while (itDouble.hasNext()) d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itDouble.next()); QList boolPropertyManagers = manager->findChildren(); QListIterator itBool(boolPropertyManagers); while (itBool.hasNext()) d_ptr->m_checkBoxFactory->addPropertyManager(itBool.next()); QList stringPropertyManagers = manager->findChildren(); QListIterator itString(stringPropertyManagers); while (itString.hasNext()) d_ptr->m_lineEditFactory->addPropertyManager(itString.next()); QList datePropertyManagers = manager->findChildren(); QListIterator itDate(datePropertyManagers); while (itDate.hasNext()) d_ptr->m_dateEditFactory->addPropertyManager(itDate.next()); QList timePropertyManagers = manager->findChildren(); QListIterator itTime(timePropertyManagers); while (itTime.hasNext()) d_ptr->m_timeEditFactory->addPropertyManager(itTime.next()); QList dateTimePropertyManagers = manager->findChildren(); QListIterator itDateTime(dateTimePropertyManagers); while (itDateTime.hasNext()) d_ptr->m_dateTimeEditFactory->addPropertyManager(itDateTime.next()); QList keySequencePropertyManagers = manager->findChildren(); QListIterator itKeySequence(keySequencePropertyManagers); while (itKeySequence.hasNext()) d_ptr->m_keySequenceEditorFactory->addPropertyManager(itKeySequence.next()); QList charPropertyManagers = manager->findChildren(); QListIterator itChar(charPropertyManagers); while (itChar.hasNext()) d_ptr->m_charEditorFactory->addPropertyManager(itChar.next()); QList localePropertyManagers = manager->findChildren(); QListIterator itLocale(localePropertyManagers); while (itLocale.hasNext()) d_ptr->m_comboBoxFactory->addPropertyManager(itLocale.next()->subEnumPropertyManager()); QList pointPropertyManagers = manager->findChildren(); QListIterator itPoint(pointPropertyManagers); while (itPoint.hasNext()) d_ptr->m_spinBoxFactory->addPropertyManager(itPoint.next()->subIntPropertyManager()); QList pointFPropertyManagers = manager->findChildren(); QListIterator itPointF(pointFPropertyManagers); while (itPointF.hasNext()) d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itPointF.next()->subDoublePropertyManager()); QList sizePropertyManagers = manager->findChildren(); QListIterator itSize(sizePropertyManagers); while (itSize.hasNext()) d_ptr->m_spinBoxFactory->addPropertyManager(itSize.next()->subIntPropertyManager()); QList sizeFPropertyManagers = manager->findChildren(); QListIterator itSizeF(sizeFPropertyManagers); while (itSizeF.hasNext()) d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itSizeF.next()->subDoublePropertyManager()); QList rectPropertyManagers = manager->findChildren(); QListIterator itRect(rectPropertyManagers); while (itRect.hasNext()) d_ptr->m_spinBoxFactory->addPropertyManager(itRect.next()->subIntPropertyManager()); QList rectFPropertyManagers = manager->findChildren(); QListIterator itRectF(rectFPropertyManagers); while (itRectF.hasNext()) d_ptr->m_doubleSpinBoxFactory->addPropertyManager(itRectF.next()->subDoublePropertyManager()); QList colorPropertyManagers = manager->findChildren(); QListIterator itColor(colorPropertyManagers); while (itColor.hasNext()) { QtColorPropertyManager *manager = itColor.next(); d_ptr->m_colorEditorFactory->addPropertyManager(manager); d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); } QList enumPropertyManagers = manager->findChildren(); QListIterator itEnum(enumPropertyManagers); while (itEnum.hasNext()) d_ptr->m_comboBoxFactory->addPropertyManager(itEnum.next()); QList sizePolicyPropertyManagers = manager->findChildren(); QListIterator itSizePolicy(sizePolicyPropertyManagers); while (itSizePolicy.hasNext()) { QtSizePolicyPropertyManager *manager = itSizePolicy.next(); d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); d_ptr->m_comboBoxFactory->addPropertyManager(manager->subEnumPropertyManager()); } QList fontPropertyManagers = manager->findChildren(); QListIterator itFont(fontPropertyManagers); while (itFont.hasNext()) { QtFontPropertyManager *manager = itFont.next(); d_ptr->m_fontEditorFactory->addPropertyManager(manager); d_ptr->m_spinBoxFactory->addPropertyManager(manager->subIntPropertyManager()); d_ptr->m_comboBoxFactory->addPropertyManager(manager->subEnumPropertyManager()); d_ptr->m_checkBoxFactory->addPropertyManager(manager->subBoolPropertyManager()); } QList cursorPropertyManagers = manager->findChildren(); QListIterator itCursor(cursorPropertyManagers); while (itCursor.hasNext()) d_ptr->m_cursorEditorFactory->addPropertyManager(itCursor.next()); QList flagPropertyManagers = manager->findChildren(); QListIterator itFlag(flagPropertyManagers); while (itFlag.hasNext()) d_ptr->m_checkBoxFactory->addPropertyManager(itFlag.next()->subBoolPropertyManager()); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ QWidget *QtVariantEditorFactory::createEditor(QtVariantPropertyManager *manager, QtProperty *property, QWidget *parent) { const int propType = manager->propertyType(property); QtAbstractEditorFactoryBase *factory = d_ptr->m_typeToFactory.value(propType, 0); if (!factory) return 0; return factory->createEditor(wrappedProperty(property), parent); } /*! \internal Reimplemented from the QtAbstractEditorFactory class. */ void QtVariantEditorFactory::disconnectPropertyManager(QtVariantPropertyManager *manager) { QList intPropertyManagers = manager->findChildren(); QListIterator itInt(intPropertyManagers); while (itInt.hasNext()) d_ptr->m_spinBoxFactory->removePropertyManager(itInt.next()); QList doublePropertyManagers = manager->findChildren(); QListIterator itDouble(doublePropertyManagers); while (itDouble.hasNext()) d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itDouble.next()); QList boolPropertyManagers = manager->findChildren(); QListIterator itBool(boolPropertyManagers); while (itBool.hasNext()) d_ptr->m_checkBoxFactory->removePropertyManager(itBool.next()); QList stringPropertyManagers = manager->findChildren(); QListIterator itString(stringPropertyManagers); while (itString.hasNext()) d_ptr->m_lineEditFactory->removePropertyManager(itString.next()); QList datePropertyManagers = manager->findChildren(); QListIterator itDate(datePropertyManagers); while (itDate.hasNext()) d_ptr->m_dateEditFactory->removePropertyManager(itDate.next()); QList timePropertyManagers = manager->findChildren(); QListIterator itTime(timePropertyManagers); while (itTime.hasNext()) d_ptr->m_timeEditFactory->removePropertyManager(itTime.next()); QList dateTimePropertyManagers = manager->findChildren(); QListIterator itDateTime(dateTimePropertyManagers); while (itDateTime.hasNext()) d_ptr->m_dateTimeEditFactory->removePropertyManager(itDateTime.next()); QList keySequencePropertyManagers = manager->findChildren(); QListIterator itKeySequence(keySequencePropertyManagers); while (itKeySequence.hasNext()) d_ptr->m_keySequenceEditorFactory->removePropertyManager(itKeySequence.next()); QList charPropertyManagers = manager->findChildren(); QListIterator itChar(charPropertyManagers); while (itChar.hasNext()) d_ptr->m_charEditorFactory->removePropertyManager(itChar.next()); QList localePropertyManagers = manager->findChildren(); QListIterator itLocale(localePropertyManagers); while (itLocale.hasNext()) d_ptr->m_comboBoxFactory->removePropertyManager(itLocale.next()->subEnumPropertyManager()); QList pointPropertyManagers = manager->findChildren(); QListIterator itPoint(pointPropertyManagers); while (itPoint.hasNext()) d_ptr->m_spinBoxFactory->removePropertyManager(itPoint.next()->subIntPropertyManager()); QList pointFPropertyManagers = manager->findChildren(); QListIterator itPointF(pointFPropertyManagers); while (itPointF.hasNext()) d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itPointF.next()->subDoublePropertyManager()); QList sizePropertyManagers = manager->findChildren(); QListIterator itSize(sizePropertyManagers); while (itSize.hasNext()) d_ptr->m_spinBoxFactory->removePropertyManager(itSize.next()->subIntPropertyManager()); QList sizeFPropertyManagers = manager->findChildren(); QListIterator itSizeF(sizeFPropertyManagers); while (itSizeF.hasNext()) d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itSizeF.next()->subDoublePropertyManager()); QList rectPropertyManagers = manager->findChildren(); QListIterator itRect(rectPropertyManagers); while (itRect.hasNext()) d_ptr->m_spinBoxFactory->removePropertyManager(itRect.next()->subIntPropertyManager()); QList rectFPropertyManagers = manager->findChildren(); QListIterator itRectF(rectFPropertyManagers); while (itRectF.hasNext()) d_ptr->m_doubleSpinBoxFactory->removePropertyManager(itRectF.next()->subDoublePropertyManager()); QList colorPropertyManagers = manager->findChildren(); QListIterator itColor(colorPropertyManagers); while (itColor.hasNext()) { QtColorPropertyManager *manager = itColor.next(); d_ptr->m_colorEditorFactory->removePropertyManager(manager); d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); } QList enumPropertyManagers = manager->findChildren(); QListIterator itEnum(enumPropertyManagers); while (itEnum.hasNext()) d_ptr->m_comboBoxFactory->removePropertyManager(itEnum.next()); QList sizePolicyPropertyManagers = manager->findChildren(); QListIterator itSizePolicy(sizePolicyPropertyManagers); while (itSizePolicy.hasNext()) { QtSizePolicyPropertyManager *manager = itSizePolicy.next(); d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); d_ptr->m_comboBoxFactory->removePropertyManager(manager->subEnumPropertyManager()); } QList fontPropertyManagers = manager->findChildren(); QListIterator itFont(fontPropertyManagers); while (itFont.hasNext()) { QtFontPropertyManager *manager = itFont.next(); d_ptr->m_fontEditorFactory->removePropertyManager(manager); d_ptr->m_spinBoxFactory->removePropertyManager(manager->subIntPropertyManager()); d_ptr->m_comboBoxFactory->removePropertyManager(manager->subEnumPropertyManager()); d_ptr->m_checkBoxFactory->removePropertyManager(manager->subBoolPropertyManager()); } QList cursorPropertyManagers = manager->findChildren(); QListIterator itCursor(cursorPropertyManagers); while (itCursor.hasNext()) d_ptr->m_cursorEditorFactory->removePropertyManager(itCursor.next()); QList flagPropertyManagers = manager->findChildren(); QListIterator itFlag(flagPropertyManagers); while (itFlag.hasNext()) d_ptr->m_checkBoxFactory->removePropertyManager(itFlag.next()->subBoolPropertyManager()); } #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif #include "moc_qtvariantproperty.cpp" tiled-0.14.2/src/qtpropertybrowser/src/qtvariantproperty.h000066400000000000000000000211151260670167100241070ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTVARIANTPROPERTY_H #define QTVARIANTPROPERTY_H #include "qtpropertybrowser.h" #include #include #if QT_VERSION >= 0x040400 QT_BEGIN_NAMESPACE #endif typedef QMap QtIconMap; class QtVariantPropertyManager; class QtVariantPropertyPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtVariantProperty : public QtProperty { public: ~QtVariantProperty(); QVariant value() const; QVariant attributeValue(const QString &attribute) const; int valueType() const; int propertyType() const; void setValue(const QVariant &value); void setAttribute(const QString &attribute, const QVariant &value); protected: QtVariantProperty(QtVariantPropertyManager *manager); private: friend class QtVariantPropertyManager; QtVariantPropertyPrivate *d_ptr; }; class QtVariantPropertyManagerPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtVariantPropertyManager : public QtAbstractPropertyManager { Q_OBJECT public: QtVariantPropertyManager(QObject *parent = 0); ~QtVariantPropertyManager(); virtual QtVariantProperty *addProperty(int propertyType, const QString &name = QString()); int propertyType(const QtProperty *property) const; int valueType(const QtProperty *property) const; QtVariantProperty *variantProperty(const QtProperty *property) const; virtual bool isPropertyTypeSupported(int propertyType) const; virtual int valueType(int propertyType) const; virtual QStringList attributes(int propertyType) const; virtual int attributeType(int propertyType, const QString &attribute) const; virtual QVariant value(const QtProperty *property) const; virtual QVariant attributeValue(const QtProperty *property, const QString &attribute) const; static int enumTypeId(); static int flagTypeId(); static int groupTypeId(); static int iconMapTypeId(); public Q_SLOTS: virtual void setValue(QtProperty *property, const QVariant &val); virtual void setAttribute(QtProperty *property, const QString &attribute, const QVariant &value); Q_SIGNALS: void valueChanged(QtProperty *property, const QVariant &val); void attributeChanged(QtProperty *property, const QString &attribute, const QVariant &val); protected: virtual bool hasValue(const QtProperty *property) const; QString valueText(const QtProperty *property) const; QIcon valueIcon(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); virtual QtProperty *createProperty(); private: QtVariantPropertyManagerPrivate *d_ptr; Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, int, int)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, double, double)) Q_PRIVATE_SLOT(d_func(), void slotSingleStepChanged(QtProperty *, double)) Q_PRIVATE_SLOT(d_func(), void slotDecimalsChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QString &)) Q_PRIVATE_SLOT(d_func(), void slotRegExpChanged(QtProperty *, const QRegExp &)) Q_PRIVATE_SLOT(d_func(), void slotEchoModeChanged(QtProperty *, int)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QDate &, const QDate &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QTime &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QDateTime &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QKeySequence &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QChar &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QLocale &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QPoint &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QPointF &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSize &)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QSize &, const QSize &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSizeF &)) Q_PRIVATE_SLOT(d_func(), void slotRangeChanged(QtProperty *, const QSizeF &, const QSizeF &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QRect &)) Q_PRIVATE_SLOT(d_func(), void slotConstraintChanged(QtProperty *, const QRect &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QRectF &)) Q_PRIVATE_SLOT(d_func(), void slotConstraintChanged(QtProperty *, const QRectF &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QColor &)) Q_PRIVATE_SLOT(d_func(), void slotEnumNamesChanged(QtProperty *, const QStringList &)) Q_PRIVATE_SLOT(d_func(), void slotEnumIconsChanged(QtProperty *, const QMap &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QSizePolicy &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QFont &)) Q_PRIVATE_SLOT(d_func(), void slotValueChanged(QtProperty *, const QCursor &)) Q_PRIVATE_SLOT(d_func(), void slotFlagNamesChanged(QtProperty *, const QStringList &)) Q_PRIVATE_SLOT(d_func(), void slotReadOnlyChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotTextVisibleChanged(QtProperty *, bool)) Q_PRIVATE_SLOT(d_func(), void slotPropertyInserted(QtProperty *, QtProperty *, QtProperty *)) Q_PRIVATE_SLOT(d_func(), void slotPropertyRemoved(QtProperty *, QtProperty *)) Q_DECLARE_PRIVATE(QtVariantPropertyManager) Q_DISABLE_COPY(QtVariantPropertyManager) }; class QtVariantEditorFactoryPrivate; class QT_QTPROPERTYBROWSER_EXPORT QtVariantEditorFactory : public QtAbstractEditorFactory { Q_OBJECT public: QtVariantEditorFactory(QObject *parent = 0); ~QtVariantEditorFactory(); protected: void connectPropertyManager(QtVariantPropertyManager *manager); QWidget *createEditor(QtVariantPropertyManager *manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtVariantPropertyManager *manager); private: QtVariantEditorFactoryPrivate *d_ptr; Q_DECLARE_PRIVATE(QtVariantEditorFactory) Q_DISABLE_COPY(QtVariantEditorFactory) }; #if QT_VERSION >= 0x040400 QT_END_NAMESPACE #endif Q_DECLARE_METATYPE(QIcon) Q_DECLARE_METATYPE(QtIconMap) #endif tiled-0.14.2/src/src.pro000066400000000000000000000002111260670167100147770ustar00rootroot00000000000000TEMPLATE = subdirs CONFIG += ordered SUBDIRS = libtiled tiled plugins \ tmxviewer \ tmxrasterizer \ automappingconverter tiled-0.14.2/src/tiled/000077500000000000000000000000001260670167100145755ustar00rootroot00000000000000tiled-0.14.2/src/tiled/Info.plist000066400000000000000000000024711260670167100165510ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable Tiled CFBundleGetInfoString Tiled 0.14.2, Copyright 2008-2015 Thorbjørn Lindeijer, GNU General Public License CFBundleIconFile tiled-icon-mac CFBundleIdentifier org.mapeditor.Tiled CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleShortVersionString 0.14.2 CFBundleVersion 0.14.2 CSResourcesFileMapped NSHumanReadableCopyright Copyright 2008-2015 Thorbjørn Lindeijer NSHighResolutionCapable CFBundleDocumentTypes CFBundleTypeName Tiled Map CFBundleTypeIconFile tmx-icon-mac CFBundleTypeRole Editor CFBundleTypeExtensions tmx tiled-0.14.2/src/tiled/aboutdialog.cpp000066400000000000000000000040351260670167100175750ustar00rootroot00000000000000/* * aboutdialog.cpp * Copyright 2008-2009, Thorbjørn Lindeijer * Copyright 2009, Dennis Honeyman * * This file is part of Tiled. * * 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, see . */ #include "aboutdialog.h" #include #include using namespace Tiled::Internal; AboutDialog::AboutDialog(QWidget *parent): QDialog(parent) { setupUi(this); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setMaximumSize(432, 460); const QString html = QCoreApplication::translate( "AboutDialog", "

Tiled Map Editor
Version %1

\n" "

Copyright 2008-2015 Thorbjørn Lindeijer
(see the AUTHORS file for a full list of contributors)

\n" "

You may modify and redistribute this program under the terms of the GPL (version 2 or later). " "A copy of the GPL is contained in the 'COPYING' file distributed with Tiled.

\n" "

http://www.mapeditor.org/

\n") .arg(QApplication::applicationVersion()); textBrowser->setHtml(html); connect(donateButton, SIGNAL(clicked()), SLOT(donate())); } void AboutDialog::donate() { QDesktopServices::openUrl(QUrl(QLatin1String("http://www.mapeditor.org/donate"))); } tiled-0.14.2/src/tiled/aboutdialog.h000066400000000000000000000022641260670167100172440ustar00rootroot00000000000000/* * aboutdialog.h * Copyright 2008-2009, Thorbjørn Lindeijer * Copyright 2009, Dennis Honeyman * * This file is part of Tiled. * * 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, see . */ #ifndef ABOUTDIALOG_H #define ABOUTDIALOG_H #include #include "ui_aboutdialog.h" namespace Tiled { namespace Internal { class AboutDialog : public QDialog, private Ui::AboutDialog { Q_OBJECT public: AboutDialog(QWidget *parent = nullptr); private slots: void donate(); }; } // namespace Internal } // namespace Tiled #endif // ABOUTDIALOG_H tiled-0.14.2/src/tiled/aboutdialog.ui000066400000000000000000000063611260670167100174340ustar00rootroot00000000000000 AboutDialog 0 0 432 452 About Tiled QLayout::SetDefaultConstraint Qt::Horizontal 0 20 400 200 :/images/about-tiled-logo.png Qt::Horizontal 0 20 true QLayout::SetDefaultConstraint Qt::Horizontal QSizePolicy::Expanding 40 20 Donate OK true pushButton clicked() AboutDialog close() 460 347 255 185 tiled-0.14.2/src/tiled/abstractimagetool.cpp000066400000000000000000000041271260670167100210110ustar00rootroot00000000000000/* * abstractimagetool.h * Copyright 2014, Mattia Basaglia * * This file is part of Tiled. * * 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, see . */ #include "abstractimagetool.h" #include "mapdocument.h" #include "maprenderer.h" #include "imagelayer.h" #include using namespace Tiled; using namespace Tiled::Internal; AbstractImageTool::AbstractImageTool(const QString &name, const QIcon &icon, const QKeySequence &shortcut, QObject *parent) : AbstractTool(name, icon, shortcut, parent), mMapScene(nullptr) { } void AbstractImageTool::activate(MapScene *scene) { mMapScene = scene; } void AbstractImageTool::deactivate(MapScene *) { mMapScene = nullptr; } void AbstractImageTool::keyPressed(QKeyEvent *event) { event->ignore(); } void AbstractImageTool::mouseLeft() { setStatusInfo(QString()); } void AbstractImageTool::mouseMoved(const QPointF &pos, Qt::KeyboardModifiers ) { const QPointF tilePosF = mapDocument()->renderer()->screenToTileCoords(pos); setStatusInfo(QString(QLatin1String("%1, %2")).arg((int)tilePosF.x()) .arg((int)tilePosF.y())); } void AbstractImageTool::updateEnabledState() { setEnabled(currentImageLayer()); } ImageLayer *AbstractImageTool::currentImageLayer() const { if (!mapDocument()) return nullptr; return dynamic_cast(mapDocument()->currentLayer()); } tiled-0.14.2/src/tiled/abstractimagetool.h000066400000000000000000000034551260670167100204610ustar00rootroot00000000000000/* * abstractimagetool.h * Copyright 2014, Mattia Basaglia * * This file is part of Tiled. * * 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, see . */ #ifndef ABSTRACTIMAGETOOL_H #define ABSTRACTIMAGETOOL_H #include "abstracttool.h" namespace Tiled { class ImageLayer; namespace Internal { /** * A convenient base class for tools that work on image layers. */ class AbstractImageTool : public AbstractTool { Q_OBJECT public: /** * Constructs an abstract image tool with the given \a name and \a icon. */ AbstractImageTool(const QString &name, const QIcon &icon, const QKeySequence &shortcut, QObject *parent = nullptr); void activate(MapScene *scene) override; void deactivate(MapScene *scene) override; void keyPressed(QKeyEvent *event) override; void mouseLeft() override; void mouseMoved(const QPointF &pos, Qt::KeyboardModifiers modifiers) override; protected: void updateEnabledState() override; MapScene *mapScene() const { return mMapScene; } ImageLayer *currentImageLayer() const; private: MapScene *mMapScene; }; } // namespace Internal } // namespace Tiled #endif // ABSTRACTIMAGETOOL_H tiled-0.14.2/src/tiled/abstractobjecttool.cpp000066400000000000000000000170211260670167100211720ustar00rootroot00000000000000/* * abstractobjecttool.cpp * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "abstractobjecttool.h" #include "map.h" #include "mapdocument.h" #include "mapobject.h" #include "mapobjectitem.h" #include "maprenderer.h" #include "mapscene.h" #include "objectgroup.h" #include "raiselowerhelper.h" #include "utils.h" #include #include #include #include using namespace Tiled; using namespace Tiled::Internal; AbstractObjectTool::AbstractObjectTool(const QString &name, const QIcon &icon, const QKeySequence &shortcut, QObject *parent) : AbstractTool(name, icon, shortcut, parent) , mMapScene(nullptr) { } void AbstractObjectTool::activate(MapScene *scene) { mMapScene = scene; } void AbstractObjectTool::deactivate(MapScene *) { mMapScene = nullptr; } void AbstractObjectTool::keyPressed(QKeyEvent *event) { switch (event->key()) { case Qt::Key_PageUp: raise(); return; case Qt::Key_PageDown: lower(); return; case Qt::Key_Home: raiseToTop(); return; case Qt::Key_End: lowerToBottom(); return; } event->ignore(); } void AbstractObjectTool::mouseLeft() { setStatusInfo(QString()); } void AbstractObjectTool::mouseMoved(const QPointF &pos, Qt::KeyboardModifiers) { // Take into account the offset of the current layer QPointF offsetPos = pos; if (Layer *layer = currentObjectGroup()) offsetPos -= layer->offset(); const QPointF tilePosF = mapDocument()->renderer()->screenToTileCoords(offsetPos); const int x = (int) std::floor(tilePosF.x()); const int y = (int) std::floor(tilePosF.y()); setStatusInfo(QString(QLatin1String("%1, %2")).arg(x).arg(y)); } void AbstractObjectTool::mousePressed(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::RightButton) { showContextMenu(topMostObjectItemAt(event->scenePos()), event->screenPos()); } } void AbstractObjectTool::updateEnabledState() { setEnabled(currentObjectGroup() != nullptr); } ObjectGroup *AbstractObjectTool::currentObjectGroup() const { if (!mapDocument()) return nullptr; return dynamic_cast(mapDocument()->currentLayer()); } MapObjectItem *AbstractObjectTool::topMostObjectItemAt(QPointF pos) const { foreach (QGraphicsItem *item, mMapScene->items(pos)) { if (MapObjectItem *objectItem = qgraphicsitem_cast(item)) return objectItem; } return nullptr; } void AbstractObjectTool::duplicateObjects() { mapDocument()->duplicateObjects(mapDocument()->selectedObjects()); } void AbstractObjectTool::removeObjects() { mapDocument()->removeObjects(mapDocument()->selectedObjects()); } void AbstractObjectTool::flipHorizontally() { mapDocument()->flipSelectedObjects(FlipHorizontally); } void AbstractObjectTool::flipVertically() { mapDocument()->flipSelectedObjects(FlipVertically); } void AbstractObjectTool::raise() { RaiseLowerHelper(mMapScene).raise(); } void AbstractObjectTool::lower() { RaiseLowerHelper(mMapScene).lower(); } void AbstractObjectTool::raiseToTop() { RaiseLowerHelper(mMapScene).raiseToTop(); } void AbstractObjectTool::lowerToBottom() { RaiseLowerHelper(mMapScene).lowerToBottom(); } /** * Shows the context menu for map objects. The menu allows you to duplicate and * remove the map objects, or to edit their properties. */ void AbstractObjectTool::showContextMenu(MapObjectItem *clickedObjectItem, QPoint screenPos) { QSet selection = mMapScene->selectedObjectItems(); if (clickedObjectItem && !selection.contains(clickedObjectItem)) { selection.clear(); selection.insert(clickedObjectItem); mMapScene->setSelectedObjectItems(selection); } if (selection.isEmpty()) return; const QList &selectedObjects = mapDocument()->selectedObjects(); const QList objectGroups = mapDocument()->map()->objectGroups(); QMenu menu; QAction *duplicateAction = menu.addAction(tr("Duplicate %n Object(s)", "", selection.size()), this, SLOT(duplicateObjects())); QAction *removeAction = menu.addAction(tr("Remove %n Object(s)", "", selection.size()), this, SLOT(removeObjects())); duplicateAction->setIcon(QIcon(QLatin1String(":/images/16x16/stock-duplicate-16.png"))); removeAction->setIcon(QIcon(QLatin1String(":/images/16x16/edit-delete.png"))); menu.addSeparator(); menu.addAction(tr("Flip Horizontally"), this, SLOT(flipHorizontally()), QKeySequence(tr("X"))); menu.addAction(tr("Flip Vertically"), this, SLOT(flipVertically()), QKeySequence(tr("Y"))); ObjectGroup *objectGroup = RaiseLowerHelper::sameObjectGroup(selection); if (objectGroup && objectGroup->drawOrder() == ObjectGroup::IndexOrder) { menu.addSeparator(); menu.addAction(tr("Raise Object"), this, SLOT(raise()), QKeySequence(tr("PgUp"))); menu.addAction(tr("Lower Object"), this, SLOT(lower()), QKeySequence(tr("PgDown"))); menu.addAction(tr("Raise Object to Top"), this, SLOT(raiseToTop()), QKeySequence(tr("Home"))); menu.addAction(tr("Lower Object to Bottom"), this, SLOT(lowerToBottom()), QKeySequence(tr("End"))); } if (objectGroups.size() > 1) { menu.addSeparator(); QMenu *moveToLayerMenu = menu.addMenu(tr("Move %n Object(s) to Layer", "", selectedObjects.size())); foreach (ObjectGroup *objectGroup, objectGroups) { QAction *action = moveToLayerMenu->addAction(objectGroup->name()); action->setData(QVariant::fromValue(objectGroup)); } } menu.addSeparator(); QIcon propIcon(QLatin1String(":images/16x16/document-properties.png")); QAction *propertiesAction = menu.addAction(propIcon, tr("Object &Properties...")); // TODO: Implement editing of properties for multiple objects propertiesAction->setEnabled(selectedObjects.size() == 1); Utils::setThemeIcon(removeAction, "edit-delete"); Utils::setThemeIcon(propertiesAction, "document-properties"); QAction *action = menu.exec(screenPos); if (!action) return; if (action == propertiesAction) { MapObject *mapObject = selectedObjects.first(); mapDocument()->setCurrentObject(mapObject); mapDocument()->emitEditCurrentObject(); return; } if (ObjectGroup *objectGroup = action->data().value()) { mapDocument()->moveObjectsToGroup(mapDocument()->selectedObjects(), objectGroup); } } tiled-0.14.2/src/tiled/abstractobjecttool.h000066400000000000000000000047231260670167100206440ustar00rootroot00000000000000/* * abstractobjecttool.h * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef ABSTRACTOBJECTTOOL_H #define ABSTRACTOBJECTTOOL_H #include "abstracttool.h" namespace Tiled { class MapObject; class ObjectGroup; namespace Internal { class MapObjectItem; /** * A convenient base class for tools that work on object layers. Implements * the standard context menu. */ class AbstractObjectTool : public AbstractTool { Q_OBJECT public: /** * Constructs an abstract object tool with the given \a name and \a icon. */ AbstractObjectTool(const QString &name, const QIcon &icon, const QKeySequence &shortcut, QObject *parent = nullptr); void activate(MapScene *scene) override; void deactivate(MapScene *scene) override; void keyPressed(QKeyEvent *event) override; void mouseLeft() override; void mouseMoved(const QPointF &pos, Qt::KeyboardModifiers modifiers) override; void mousePressed(QGraphicsSceneMouseEvent *event) override; protected: /** * Overridden to only enable this tool when the currently selected layer is * an object group. */ void updateEnabledState() override; MapScene *mapScene() const { return mMapScene; } ObjectGroup *currentObjectGroup() const; MapObjectItem *topMostObjectItemAt(QPointF pos) const; private slots: void duplicateObjects(); void removeObjects(); void flipHorizontally(); void flipVertically(); void raise(); void lower(); void raiseToTop(); void lowerToBottom(); private: void showContextMenu(MapObjectItem *clickedObject, QPoint screenPos); MapScene *mMapScene; }; } // namespace Internal } // namespace Tiled #endif // ABSTRACTOBJECTTOOL_H tiled-0.14.2/src/tiled/abstracttiletool.cpp000066400000000000000000000104301260670167100206560ustar00rootroot00000000000000/* * abstracttiletool.cpp * Copyright 2009-2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "abstracttiletool.h" #include "brushitem.h" #include "map.h" #include "mapdocument.h" #include "maprenderer.h" #include "mapscene.h" #include "tile.h" #include "tilelayer.h" #include using namespace Tiled; using namespace Tiled::Internal; AbstractTileTool::AbstractTileTool(const QString &name, const QIcon &icon, const QKeySequence &shortcut, QObject *parent) : AbstractTool(name, icon, shortcut, parent) , mTilePositionMethod(OnTiles) , mBrushItem(new BrushItem) , mBrushVisible(false) { mBrushItem->setVisible(false); mBrushItem->setZValue(10000); } AbstractTileTool::~AbstractTileTool() { delete mBrushItem; } void AbstractTileTool::activate(MapScene *scene) { scene->addItem(mBrushItem); } void AbstractTileTool::deactivate(MapScene *scene) { scene->removeItem(mBrushItem); } void AbstractTileTool::mouseEntered() { setBrushVisible(true); } void AbstractTileTool::mouseLeft() { setBrushVisible(false); } void AbstractTileTool::mouseMoved(const QPointF &pos, Qt::KeyboardModifiers) { // Take into account the offset of the current layer QPointF offsetPos = pos; if (Layer *layer = currentTileLayer()) { offsetPos -= layer->offset(); mBrushItem->setLayerOffset(layer->offset()); } const MapRenderer *renderer = mapDocument()->renderer(); const QPointF tilePosF = renderer->screenToTileCoords(offsetPos); QPoint tilePos; if (mTilePositionMethod == BetweenTiles) tilePos = tilePosF.toPoint(); else tilePos = QPoint((int) std::floor(tilePosF.x()), (int) std::floor(tilePosF.y())); if (mTilePosition != tilePos) { mTilePosition = tilePos; tilePositionChanged(tilePos); updateStatusInfo(); } } void AbstractTileTool::mapDocumentChanged(MapDocument *oldDocument, MapDocument *newDocument) { Q_UNUSED(oldDocument) mBrushItem->setMapDocument(newDocument); } void AbstractTileTool::updateEnabledState() { setEnabled(currentTileLayer() != nullptr); } void AbstractTileTool::updateStatusInfo() { if (mBrushVisible) { Tile *tile = nullptr; if (const TileLayer *tileLayer = currentTileLayer()) { const QPoint pos = tilePosition() - tileLayer->position(); if (tileLayer->contains(pos)) tile = tileLayer->cellAt(pos).tile; } QString tileIdString = tile ? QString::number(tile->id()) : tr("empty"); setStatusInfo(QString(QLatin1String("%1, %2 [%3]")) .arg(mTilePosition.x()) .arg(mTilePosition.y()) .arg(tileIdString)); } else { setStatusInfo(QString()); } } void AbstractTileTool::setBrushVisible(bool visible) { if (mBrushVisible == visible) return; mBrushVisible = visible; updateStatusInfo(); updateBrushVisibility(); } void AbstractTileTool::updateBrushVisibility() { // Show the tile brush only when a visible tile layer is selected bool showBrush = false; if (mBrushVisible) { if (Layer *layer = currentTileLayer()) { if (layer->isVisible()) showBrush = true; } } mBrushItem->setVisible(showBrush); } TileLayer *AbstractTileTool::currentTileLayer() const { if (!mapDocument()) return nullptr; return dynamic_cast(mapDocument()->currentLayer()); } tiled-0.14.2/src/tiled/abstracttiletool.h000066400000000000000000000074301260670167100203310ustar00rootroot00000000000000/* * abstracttiletool.h * Copyright 2009-2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef ABSTRACTTILETOOL_H #define ABSTRACTTILETOOL_H #include "abstracttool.h" namespace Tiled { class TileLayer; namespace Internal { class BrushItem; class MapDocument; /** * A convenient base class for tile based tools. */ class AbstractTileTool : public AbstractTool { Q_OBJECT public: /** * Constructs an abstract tile tool with the given \a name and \a icon. */ AbstractTileTool(const QString &name, const QIcon &icon, const QKeySequence &shortcut, QObject *parent = nullptr); ~AbstractTileTool(); void activate(MapScene *scene) override; void deactivate(MapScene *scene) override; void mouseEntered() override; void mouseLeft() override; void mouseMoved(const QPointF &pos, Qt::KeyboardModifiers modifiers) override; protected: void mapDocumentChanged(MapDocument *oldDocument, MapDocument *newDocument) override; /** * Overridden to only enable this tool when the currently selected layer is * a tile layer. */ void updateEnabledState() override; /** * New virtual method to implement for tile tools. This method is called * on mouse move events, but only when the tile position changes. */ virtual void tilePositionChanged(const QPoint &tilePos) = 0; /** * Updates the status info with the current tile position. When the mouse * is not in the view, the status info is set to an empty string. * * This behaviour can be overridden in a subclass. This method is * automatically called after each call to tilePositionChanged() and when * the brush visibility changes. */ virtual void updateStatusInfo(); bool isBrushVisible() const { return mBrushVisible; } /** * Determines what the tile position means. */ enum TilePositionMethod { OnTiles, /**< Tile position is the tile the mouse is on. */ BetweenTiles /**< Tile position is between the tiles. */ }; void setTilePositionMethod(TilePositionMethod method) { mTilePositionMethod = method; } /** * Returns the last recorded tile position of the mouse. */ QPoint tilePosition() const { return mTilePosition; } /** * Returns the brush item. The brush item is used to give an indication of * what a tile tool is going to do when used. It is automatically shown or * hidden based on whether the mouse is in the scene and whether the * currently selected layer is a tile layer. */ BrushItem *brushItem() const { return mBrushItem; } /** * Returns the current tile layer, or null if no tile layer is currently * selected. */ TileLayer *currentTileLayer() const; private: void setBrushVisible(bool visible); void updateBrushVisibility(); TilePositionMethod mTilePositionMethod; BrushItem *mBrushItem; QPoint mTilePosition; bool mBrushVisible; }; } // namespace Internal } // namespace Tiled #endif // ABSTRACTTILETOOL_H tiled-0.14.2/src/tiled/abstracttool.cpp000066400000000000000000000055471260670167100200150ustar00rootroot00000000000000/* * abstracttool.cpp * Copyright 2009-2013, Thorbjørn Lindeijer * Copyright 2010, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #include "abstracttool.h" #include "mapdocument.h" #include using namespace Tiled::Internal; AbstractTool::AbstractTool(const QString &name, const QIcon &icon, const QKeySequence &shortcut, QObject *parent) : QObject(parent) , mName(name) , mIcon(icon) , mShortcut(shortcut) , mEnabled(false) , mMapDocument(nullptr) { } /** * Sets the current status information for this tool. This information will be * displayed in the status bar. */ void AbstractTool::setStatusInfo(const QString &statusInfo) { if (mStatusInfo != statusInfo) { mStatusInfo = statusInfo; emit statusInfoChanged(mStatusInfo); } } /** * Sets the cursor used by this tool. This will be the cursor set on the * viewport of the MapView while the tool is active. */ void AbstractTool::setCursor(const QCursor &cursor) { mCursor = cursor; emit cursorChanged(cursor); } void AbstractTool::setEnabled(bool enabled) { if (mEnabled == enabled) return; mEnabled = enabled; emit enabledChanged(enabled); } void AbstractTool::keyPressed(QKeyEvent *event) { event->ignore(); } void AbstractTool::setMapDocument(MapDocument *mapDocument) { if (mMapDocument == mapDocument) return; if (mMapDocument) { disconnect(mMapDocument, &MapDocument::layerChanged, this, &AbstractTool::updateEnabledState); disconnect(mMapDocument, &MapDocument::currentLayerIndexChanged, this, &AbstractTool::updateEnabledState); } MapDocument *oldDocument = mMapDocument; mMapDocument = mapDocument; mapDocumentChanged(oldDocument, mMapDocument); if (mMapDocument) { connect(mMapDocument, &MapDocument::layerChanged, this, &AbstractTool::updateEnabledState); connect(mMapDocument, &MapDocument::currentLayerIndexChanged, this, &AbstractTool::updateEnabledState); } updateEnabledState(); } void AbstractTool::updateEnabledState() { setEnabled(mMapDocument != nullptr); } tiled-0.14.2/src/tiled/abstracttool.h000066400000000000000000000137011260670167100174510ustar00rootroot00000000000000/* * abstracttool.h * Copyright 2009-2013, Thorbjørn Lindeijer * Copyright 2010, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #ifndef ABSTRACTTOOL_H #define ABSTRACTTOOL_H #include #include #include #include #include #include #include class QEvent; class QKeyEvent; namespace Tiled { namespace Internal { class MapDocument; class MapScene; /** * An abstraction of any kind of tool used to edit the map. * * Events that hit the MapScene are forwarded to the current tool, which can * handle them as appropriate for that tool. * * A tool will usually add one or more QGraphicsItems to the scene in order to * represent it to the user. */ class AbstractTool : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QIcon icon READ icon WRITE setIcon) Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) Q_PROPERTY(QString statusInfo READ statusInfo WRITE setStatusInfo NOTIFY statusInfoChanged) Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor NOTIFY cursorChanged) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) public: /** * Constructs an abstract tool with the given \a name and \a icon. */ AbstractTool(const QString &name, const QIcon &icon, const QKeySequence &shortcut, QObject *parent = nullptr); virtual ~AbstractTool() {} QString name() const; void setName(const QString &name); QIcon icon() const; void setIcon(const QIcon &icon); QKeySequence shortcut() const; void setShortcut(const QKeySequence &shortcut); QString statusInfo() const; void setStatusInfo(const QString &statusInfo); QCursor cursor() const; void setCursor(const QCursor &cursor); bool isEnabled() const; void setEnabled(bool enabled); /** * Activates this tool. If the tool plans to add any items to the scene, it * probably wants to do it here. */ virtual void activate(MapScene *scene) = 0; /** * Deactivates this tool. Should do any necessary cleanup to make sure the * tool is no longer active. */ virtual void deactivate(MapScene *scene) = 0; virtual void keyPressed(QKeyEvent *); /** * Called when the mouse entered the scene. This is usually an appropriate * time to make a hover item visible. */ virtual void mouseEntered() = 0; /** * Called when the mouse left the scene. */ virtual void mouseLeft() = 0; /** * Called when the mouse cursor moves in the scene. */ virtual void mouseMoved(const QPointF &pos, Qt::KeyboardModifiers modifiers) = 0; /** * Called when a mouse button is pressed on the scene. */ virtual void mousePressed(QGraphicsSceneMouseEvent *event) = 0; /** * Called when a mouse button is released on the scene. */ virtual void mouseReleased(QGraphicsSceneMouseEvent *event) = 0; /** * Called when the user presses or releases a modifier key resulting * in a change of modifier status, and when the tool is enabled with * a modifier key pressed. */ virtual void modifiersChanged(Qt::KeyboardModifiers) {} /** * Called when the application language changed. */ virtual void languageChanged() = 0; public slots: void setMapDocument(MapDocument *mapDocument); protected: /** * Can be used to respond to the map document changing. */ virtual void mapDocumentChanged(MapDocument *oldDocument, MapDocument *newDocument) { Q_UNUSED(oldDocument) Q_UNUSED(newDocument) } MapDocument *mapDocument() const { return mMapDocument; } protected slots: /** * By default, this function is called after the current map has changed * and when the current layer changes. It can be overridden to implement * custom logic for when the tool should be enabled. * * The default implementation enables tools when a map document is set. */ virtual void updateEnabledState(); signals: void statusInfoChanged(const QString &statusInfo); void cursorChanged(const QCursor &cursor); void enabledChanged(bool enabled); private: QString mName; QIcon mIcon; QKeySequence mShortcut; QString mStatusInfo; QCursor mCursor; bool mEnabled; MapDocument *mMapDocument; }; inline QString AbstractTool::name() const { return mName; } inline void AbstractTool::setName(const QString &name) { mName = name; } inline QIcon AbstractTool::icon() const { return mIcon; } inline void AbstractTool::setIcon(const QIcon &icon) { mIcon = icon; } inline QKeySequence AbstractTool::shortcut() const { return mShortcut; } inline void AbstractTool::setShortcut(const QKeySequence &shortcut) { mShortcut = shortcut; } inline QString AbstractTool::statusInfo() const { return mStatusInfo; } inline QCursor AbstractTool::cursor() const { return mCursor; } inline bool AbstractTool::isEnabled() const { return mEnabled; } } // namespace Internal } // namespace Tiled Q_DECLARE_METATYPE(Tiled::Internal::AbstractTool*) #endif // ABSTRACTTOOL_H tiled-0.14.2/src/tiled/addremovelayer.cpp000066400000000000000000000036121260670167100203060ustar00rootroot00000000000000/* * addremovelayer.cpp * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "addremovelayer.h" #include "layer.h" #include "layermodel.h" #include "mapdocument.h" namespace Tiled { namespace Internal { AddRemoveLayer::AddRemoveLayer(MapDocument *mapDocument, int index, Layer *layer) : mMapDocument(mapDocument) , mLayer(layer) , mIndex(index) { } AddRemoveLayer::~AddRemoveLayer() { delete mLayer; } void AddRemoveLayer::addLayer() { const int currentLayer = mMapDocument->currentLayerIndex(); mMapDocument->layerModel()->insertLayer(mIndex, mLayer); mLayer = nullptr; // Insertion below or at the current layer increases current layer index if (mIndex <= currentLayer) mMapDocument->setCurrentLayerIndex(currentLayer + 1); } void AddRemoveLayer::removeLayer() { const int currentLayer = mMapDocument->currentLayerIndex(); mLayer = mMapDocument->layerModel()->takeLayerAt(mIndex); // Removal below the current layer decreases the current layer index if (mIndex < currentLayer) mMapDocument->setCurrentLayerIndex(currentLayer - 1); } } // namespace Internal } // namespace Tiled tiled-0.14.2/src/tiled/addremovelayer.h000066400000000000000000000044551260670167100177610ustar00rootroot00000000000000/* * addremovelayer.h * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef ADDREMOVELAYER_H #define ADDREMOVELAYER_H #include #include namespace Tiled { class Layer; namespace Internal { class MapDocument; /** * Abstract base class for AddLayer and RemoveLayer. */ class AddRemoveLayer : public QUndoCommand { public: AddRemoveLayer(MapDocument *mapDocument, int index, Layer *layer); ~AddRemoveLayer(); protected: void addLayer(); void removeLayer(); private: MapDocument *mMapDocument; Layer *mLayer; int mIndex; }; /** * Undo command that adds a layer to a map. */ class AddLayer : public AddRemoveLayer { public: /** * Creates an undo command that adds the \a layer at \a index. */ AddLayer(MapDocument *mapDocument, int index, Layer *layer) : AddRemoveLayer(mapDocument, index, layer) { setText(QCoreApplication::translate("Undo Commands", "Add Layer")); } void undo() override { removeLayer(); } void redo() override { addLayer(); } }; /** * Undo command that removes a layer from a map. */ class RemoveLayer : public AddRemoveLayer { public: /** * Creates an undo command that removes the layer at \a index. */ RemoveLayer(MapDocument *mapDocument, int index) : AddRemoveLayer(mapDocument, index, nullptr) { setText(QCoreApplication::translate("Undo Commands", "Remove Layer")); } void undo() override { addLayer(); } void redo() override { removeLayer(); } }; } // namespace Internal } // namespace Tiled #endif // ADDREMOVELAYER_H tiled-0.14.2/src/tiled/addremovemapobject.cpp000066400000000000000000000054171260670167100211430ustar00rootroot00000000000000/* * addremovemapobject.cpp * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "addremovemapobject.h" #include "mapdocument.h" #include "mapobject.h" #include "objectgroup.h" #include "mapobjectmodel.h" #include using namespace Tiled; using namespace Tiled::Internal; AddRemoveMapObject::AddRemoveMapObject(MapDocument *mapDocument, ObjectGroup *objectGroup, MapObject *mapObject, bool ownObject, QUndoCommand *parent) : QUndoCommand(parent) , mMapDocument(mapDocument) , mMapObject(mapObject) , mObjectGroup(objectGroup) , mIndex(-1) , mOwnsObject(ownObject) { } AddRemoveMapObject::~AddRemoveMapObject() { if (mOwnsObject) delete mMapObject; } void AddRemoveMapObject::addObject() { mMapDocument->mapObjectModel()->insertObject(mObjectGroup, mIndex, mMapObject); mOwnsObject = false; } void AddRemoveMapObject::removeObject() { mIndex = mMapDocument->mapObjectModel()->removeObject(mObjectGroup, mMapObject); mOwnsObject = true; } AddMapObject::AddMapObject(MapDocument *mapDocument, ObjectGroup *objectGroup, MapObject *mapObject, QUndoCommand *parent) : AddRemoveMapObject(mapDocument, objectGroup, mapObject, true, parent) { setText(QCoreApplication::translate("Undo Commands", "Add Object")); } RemoveMapObject::RemoveMapObject(MapDocument *mapDocument, MapObject *mapObject, QUndoCommand *parent) : AddRemoveMapObject(mapDocument, mapObject->objectGroup(), mapObject, false, parent) { setText(QCoreApplication::translate("Undo Commands", "Remove Object")); } tiled-0.14.2/src/tiled/addremovemapobject.h000066400000000000000000000044231260670167100206040ustar00rootroot00000000000000/* * addremovemapobject.h * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef ADDREMOVEMAPOBJECT_H #define ADDREMOVEMAPOBJECT_H #include namespace Tiled { class MapObject; class ObjectGroup; namespace Internal { class MapDocument; /** * Abstract base class for AddMapObject and RemoveMapObject. */ class AddRemoveMapObject : public QUndoCommand { public: AddRemoveMapObject(MapDocument *mapDocument, ObjectGroup *objectGroup, MapObject *mapObject, bool ownObject, QUndoCommand *parent = nullptr); ~AddRemoveMapObject(); protected: void addObject(); void removeObject(); private: MapDocument *mMapDocument; MapObject *mMapObject; ObjectGroup *mObjectGroup; int mIndex; bool mOwnsObject; }; /** * Undo command that adds an object to a map. */ class AddMapObject : public AddRemoveMapObject { public: AddMapObject(MapDocument *mapDocument, ObjectGroup *objectGroup, MapObject *mapObject, QUndoCommand *parent = nullptr); void undo() override { removeObject(); } void redo() override { addObject(); } }; /** * Undo command that removes an object from a map. */ class RemoveMapObject : public AddRemoveMapObject { public: RemoveMapObject(MapDocument *mapDocument, MapObject *mapObject, QUndoCommand *parent = nullptr); void undo() override { addObject(); } void redo() override { removeObject(); } }; } // namespace Internal } // namespace Tiled #endif // ADDREMOVEMAPOBJECT_H tiled-0.14.2/src/tiled/addremoveterrain.cpp000066400000000000000000000044021260670167100206340ustar00rootroot00000000000000/* * addremoveterrain.cpp * Copyright 2012, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "addremoveterrain.h" #include "mapdocument.h" #include "terrain.h" #include "terrainmodel.h" #include "tileset.h" #include using namespace Tiled; using namespace Tiled::Internal; AddRemoveTerrain::AddRemoveTerrain(MapDocument *mapDocument, Tileset *tileset, int index, Terrain *terrain) : mMapDocument(mapDocument) , mTileset(tileset) , mIndex(index) , mTerrain(terrain) { } AddRemoveTerrain::~AddRemoveTerrain() { delete mTerrain; } void AddRemoveTerrain::removeTerrain() { Q_ASSERT(!mTerrain); mTerrain = mMapDocument->terrainModel()->takeTerrainAt(mTileset, mIndex); } void AddRemoveTerrain::addTerrain() { Q_ASSERT(mTerrain); mMapDocument->terrainModel()->insertTerrain(mTileset, mIndex, mTerrain); mTerrain = nullptr; } AddTerrain::AddTerrain(MapDocument *mapDocument, Terrain *terrain) : AddRemoveTerrain(mapDocument, terrain->tileset(), terrain->tileset()->terrainCount(), terrain) { setText(QCoreApplication::translate("Undo Commands", "Add Terrain")); } RemoveTerrain::RemoveTerrain(MapDocument *mapDocument, Terrain *terrain) : AddRemoveTerrain(mapDocument, terrain->tileset(), terrain->id(), nullptr) { setText(QCoreApplication::translate("Undo Commands", "Remove Terrain")); } tiled-0.14.2/src/tiled/addremoveterrain.h000066400000000000000000000037111260670167100203030ustar00rootroot00000000000000/* * addremoveterrain.h * Copyright 2012, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef ADDREMOVETERRAIN_H #define ADDREMOVETERRAIN_H #include namespace Tiled { class Terrain; class Tileset; namespace Internal { class MapDocument; /** * Abstract base class for AddTerrain and RemoveTerrain. */ class AddRemoveTerrain : public QUndoCommand { public: AddRemoveTerrain(MapDocument *mapDocument, Tileset *tileset, int index, Terrain *terrain); ~AddRemoveTerrain(); protected: void addTerrain(); void removeTerrain(); private: MapDocument *mMapDocument; Tileset *mTileset; int mIndex; Terrain *mTerrain; }; /** * Adds a terrain to a map. */ class AddTerrain : public AddRemoveTerrain { public: AddTerrain(MapDocument *mapDocument, Terrain *terrain); void undo() override { removeTerrain(); } void redo() override { addTerrain(); } }; /** * Removes a terrain from a map. */ class RemoveTerrain : public AddRemoveTerrain { public: RemoveTerrain(MapDocument *mapDocument, Terrain *terrain); void undo() override { addTerrain(); } void redo() override { removeTerrain(); } }; } // namespace Internal } // namespace Tiled #endif // ADDREMOVETERRAIN_H tiled-0.14.2/src/tiled/addremovetiles.cpp000066400000000000000000000045771260670167100203250ustar00rootroot00000000000000/* * addremovetiles.cpp * Copyright 2013, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "addremovetiles.h" #include "mapdocument.h" #include "tile.h" #include "tileset.h" #include namespace Tiled { namespace Internal { AddRemoveTiles::AddRemoveTiles(MapDocument *mapDocument, Tileset *tileset, int index, int count, const QList &tiles) : mMapDocument(mapDocument) , mTileset(tileset) , mIndex(index) , mCount(count) , mTiles(tiles) { } AddRemoveTiles::~AddRemoveTiles() { qDeleteAll(mTiles); } void AddRemoveTiles::addTiles() { mTileset->insertTiles(mIndex, mTiles); mTiles.clear(); mMapDocument->emitTilesetChanged(mTileset); } void AddRemoveTiles::removeTiles() { mTiles = mTileset->tiles().mid(mIndex, mCount); mTileset->removeTiles(mIndex, mCount); mMapDocument->emitTilesetChanged(mTileset); } AddTiles::AddTiles(MapDocument *mapDocument, Tileset *tileset, const QList &tiles) : AddRemoveTiles(mapDocument, tileset, tileset->tileCount(), tiles.count(), tiles) { setText(QCoreApplication::translate("Undo Commands", "Add Tiles")); } RemoveTiles::RemoveTiles(MapDocument *mapDocument, Tileset *tileset, int index, int count) : AddRemoveTiles(mapDocument, tileset, index, count) { setText(QCoreApplication::translate("Undo Commands", "Remove Tiles")); } } // namespace Internal } // namespace Tiled tiled-0.14.2/src/tiled/addremovetiles.h000066400000000000000000000042401260670167100177550ustar00rootroot00000000000000/* * addremovetiles.h * Copyright 2013, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef ADDREMOVETILES_H #define ADDREMOVETILES_H #include namespace Tiled { class Tile; class Tileset; namespace Internal { class MapDocument; /** * Abstract base class for AddTiles and RemoveTiles. */ class AddRemoveTiles : public QUndoCommand { public: AddRemoveTiles(MapDocument *mapDocument, Tileset *tileset, int index, int count, const QList &tiles = QList()); ~AddRemoveTiles(); protected: void addTiles(); void removeTiles(); private: MapDocument *mMapDocument; Tileset *mTileset; int mIndex; int mCount; QList mTiles; }; /** * Undo command that adds tiles to a tileset. */ class AddTiles : public AddRemoveTiles { public: AddTiles(MapDocument *mapDocument, Tileset *tileset, const QList &tiles); void undo() override { removeTiles(); } void redo() override { addTiles(); } }; /** * Undo command that removes tiles from a tileset. */ class RemoveTiles : public AddRemoveTiles { public: RemoveTiles(MapDocument *mapDocument, Tileset *tileset, int index, int count); void undo() override { addTiles(); } void redo() override { removeTiles(); } }; } // namespace Internal } // namespace Tiled #endif // TILED_INTERNAL_ADDREMOVETILES_H tiled-0.14.2/src/tiled/addremovetileset.cpp000066400000000000000000000044651260670167100206520ustar00rootroot00000000000000/* * addremovetileset.cpp * Copyright 2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "addremovetileset.h" #include "map.h" #include "mapdocument.h" #include "tilesetmanager.h" using namespace Tiled; using namespace Tiled::Internal; AddRemoveTileset::AddRemoveTileset(MapDocument *mapDocument, int index, const SharedTileset &tileset, QUndoCommand *parent) : QUndoCommand(parent) , mMapDocument(mapDocument) , mTileset(tileset) , mIndex(index) { // Make sure the tileset manager keeps watching this tileset TilesetManager::instance()->addReference(mTileset); } AddRemoveTileset::~AddRemoveTileset() { TilesetManager::instance()->removeReference(mTileset); } void AddRemoveTileset::removeTileset() { mMapDocument->removeTilesetAt(mIndex); } void AddRemoveTileset::addTileset() { mMapDocument->insertTileset(mIndex, mTileset); } AddTileset::AddTileset(MapDocument *mapDocument, const SharedTileset &tileset, QUndoCommand *parent) : AddRemoveTileset(mapDocument, mapDocument->map()->tilesets().size(), tileset, parent) { setText(QCoreApplication::translate("Undo Commands", "Add Tileset")); } RemoveTileset::RemoveTileset(MapDocument *mapDocument, int index) : AddRemoveTileset(mapDocument, index, mapDocument->map()->tilesetAt(index)) { setText(QCoreApplication::translate("Undo Commands", "Remove Tileset")); } tiled-0.14.2/src/tiled/addremovetileset.h000066400000000000000000000040511260670167100203060ustar00rootroot00000000000000/* * addremovetileset.h * Copyright 2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef ADDREMOVETILESET_H #define ADDREMOVETILESET_H #include "tileset.h" #include #include namespace Tiled { namespace Internal { class MapDocument; /** * Abstract base class for AddTileset and RemoveTileset. */ class AddRemoveTileset : public QUndoCommand { public: AddRemoveTileset(MapDocument *mapDocument, int index, const SharedTileset &tileset, QUndoCommand *parent = nullptr); ~AddRemoveTileset(); protected: void addTileset(); void removeTileset(); private: MapDocument *mMapDocument; SharedTileset mTileset; int mIndex; }; /** * Adds a tileset to a map. */ class AddTileset : public AddRemoveTileset { public: AddTileset(MapDocument *mapDocument, const SharedTileset &tileset, QUndoCommand *parent = nullptr); void undo() override { removeTileset(); } void redo() override { addTileset(); } }; /** * Removes a tileset from a map. */ class RemoveTileset : public AddRemoveTileset { public: RemoveTileset(MapDocument *mapDocument, int index); void undo() override { addTileset(); } void redo() override { removeTileset(); } }; } // namespace Internal } // namespace Tiled #endif // ADDREMOVETILESET_H tiled-0.14.2/src/tiled/automapper.cpp000066400000000000000000001023371260670167100174640ustar00rootroot00000000000000/* * automapper.cpp * Copyright 2010-2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of Tiled. * * 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, see . */ #include "automapper.h" #include "addremovelayer.h" #include "addremovemapobject.h" #include "addremovetileset.h" #include "automappingutils.h" #include "changeproperties.h" #include "geometry.h" #include "layermodel.h" #include "map.h" #include "mapdocument.h" #include "mapobject.h" #include "maprenderer.h" #include "object.h" #include "objectgroup.h" #include "tile.h" #include "tilelayer.h" #include "tilesetmanager.h" #include using namespace Tiled; using namespace Tiled::Internal; /* * About the order of the methods in this file. * The Automapper class has 3 bigger public functions, that is * prepareLoad(), prepareAutoMap() and autoMap(). * These three functions make use of lots of different private methods, which * are put directly below each of these functions. */ AutoMapper::AutoMapper(MapDocument *workingDocument, Map *rules, const QString &rulePath) : mMapDocument(workingDocument) , mMapWork(workingDocument ? workingDocument->map() : nullptr) , mMapRules(rules) , mLayerInputRegions(nullptr) , mLayerOutputRegions(nullptr) , mRulePath(rulePath) , mDeleteTiles(false) , mAutoMappingRadius(0) , mNoOverlappingRules(false) { Q_ASSERT(mMapRules); if (!setupRuleMapProperties()) return; if (!setupRuleMapTileLayers()) return; if (!setupRuleList()) return; } AutoMapper::~AutoMapper() { cleanUpRulesMap(); } QSet AutoMapper::getTouchedTileLayers() const { return mTouchedTileLayers; } bool AutoMapper::ruleLayerNameUsed(QString ruleLayerName) const { return mInputRules.names.contains(ruleLayerName); } bool AutoMapper::setupRuleMapProperties() { Properties properties = mMapRules->properties(); foreach (QString key, properties.keys()) { QVariant value = properties.value(key); bool raiseWarning = true; if (key.toLower() == QLatin1String("deletetiles")) { if (value.canConvert(QVariant::Bool)) { mDeleteTiles = value.toBool(); raiseWarning = false; } } else if (key.toLower() == QLatin1String("automappingradius")) { if (value.canConvert(QVariant::Int)) { mAutoMappingRadius = value.toInt(); raiseWarning = false; } } else if (key.toLower() == QLatin1String("nooverlappingrules")) { if (value.canConvert(QVariant::Bool)) { mNoOverlappingRules = value.toBool(); raiseWarning = false; } } if (raiseWarning) mWarning += tr("'%1': Property '%2' = '%3' does not make sense. " "Ignoring this property.") .arg(mRulePath, key, value.toString()) + QLatin1Char('\n'); } return true; } bool AutoMapper::setupRuleMapTileLayers() { Q_ASSERT(mLayerList.isEmpty()); Q_ASSERT(mAddedTilesets.isEmpty()); Q_ASSERT(!mLayerInputRegions); Q_ASSERT(!mLayerOutputRegions); Q_ASSERT(mInputRules.isEmpty()); Q_ASSERT(mInputRules.names.isEmpty()); Q_ASSERT(mInputRules.indexes.isEmpty()); QString error; foreach (Layer *layer, mMapRules->layers()) { const QString layerName = layer->name(); if (layerName.startsWith(QLatin1String("regions"), Qt::CaseInsensitive)) { bool treatAsBoth = layerName.toLower() == QLatin1String("regions"); if (layerName.endsWith(QLatin1String("input"), Qt::CaseInsensitive) || treatAsBoth) { if (mLayerInputRegions) { error += tr("'regions_input' layer must not occur more than once.") + QLatin1Char('\n'); } if (layer->isTileLayer()) { mLayerInputRegions = layer->asTileLayer(); } else { error += tr("'regions_*' layers must be tile layers.") + QLatin1Char('\n'); } } if (layerName.endsWith(QLatin1String("output"), Qt::CaseInsensitive) || treatAsBoth) { if (mLayerOutputRegions) { error += tr("'regions_output' layer must not occur more than once.") + QLatin1Char('\n'); } if (layer->isTileLayer()) { mLayerOutputRegions = layer->asTileLayer(); } else { error += tr("'regions_*' layers must be tile layers.") + QLatin1Char('\n'); } } continue; } int nameStartPosition = layerName.indexOf( QLatin1Char('_')) + 1; // name is all characters behind the underscore (excluded) QString name = layerName.right(layerName.size() - nameStartPosition); // group is all before the underscore (included) QString index = layerName.left(nameStartPosition); if (index.startsWith(QLatin1String("output"), Qt::CaseInsensitive)) index.remove(0, 6); else if (index.startsWith(QLatin1String("inputnot"), Qt::CaseInsensitive)) index.remove(0, 8); else if (index.startsWith(QLatin1String("input"), Qt::CaseInsensitive)) index.remove(0, 5); // both 'rule' and 'output' layers will require and underscore and // rely on the correct position detected of the underscore if (nameStartPosition == 0) { error += tr("Did you forget an underscore in layer '%1'?").arg( layerName) + QLatin1Char('\n'); continue; } if (layerName.startsWith(QLatin1String("input"), Qt::CaseInsensitive)) { bool isNotList = layerName.startsWith(QLatin1String("inputnot"), Qt::CaseInsensitive); if (!layer->isTileLayer()) { error += tr("'input_*' and 'inputnot_*' layers must be tile layers.") + QLatin1Char('\n'); continue; } mInputRules.names.insert(name); if (!mInputRules.indexes.contains(index)) { mInputRules.indexes.insert(index); mInputRules.insert(index, InputIndex()); } if (!mInputRules[index].names.contains(name)) { mInputRules[index].names.insert(name); mInputRules[index].insert(name, InputIndexName()); } if (isNotList) mInputRules[index][name].listNo.append(layer->asTileLayer()); else mInputRules[index][name].listYes.append(layer->asTileLayer()); continue; } if (layerName.startsWith(QLatin1String("output"), Qt::CaseInsensitive)) { if (layer->isTileLayer()) mTouchedTileLayers.insert(name); else mTouchedObjectGroups.insert(name); Layer::TypeFlag type = layer->layerType(); int layerIndex = mMapWork->indexOfLayer(name, type); bool found = false; foreach (RuleOutput *translationTable, mLayerList) { if (translationTable->index == index) { translationTable->insert(layer, layerIndex); found = true; break; } } if (!found) { mLayerList.append(new RuleOutput()); mLayerList.last()->insert(layer, layerIndex); mLayerList.last()->index = index; } continue; } error += tr("Layer '%1' is not recognized as a valid layer for Automapping.") .arg(layerName) + QLatin1Char('\n'); } if (!mLayerInputRegions) error += tr("No 'regions' or 'regions_input' layer found.") + QLatin1Char('\n'); if (!mLayerOutputRegions) error += tr("No 'regions' or 'regions_output' layer found.") + QLatin1Char('\n'); if (mInputRules.isEmpty()) error += tr("No input_ layer found!") + QLatin1Char('\n'); // no need to check for mInputNotRules.size() == 0 here. // these layers are not necessary. if (!error.isEmpty()) { error = mRulePath + QLatin1Char('\n') + error; mError += error; return false; } return true; } static bool compareRuleRegion(const QRegion &r1, const QRegion &r2) { const QPoint &p1 = r1.boundingRect().topLeft(); const QPoint &p2 = r2.boundingRect().topLeft(); return p1.y() < p2.y() || (p1.y() == p2.y() && p1.x() < p2.x()); } bool AutoMapper::setupRuleList() { Q_ASSERT(mRulesInput.isEmpty()); Q_ASSERT(mRulesOutput.isEmpty()); Q_ASSERT(mLayerInputRegions); Q_ASSERT(mLayerOutputRegions); QList combinedRegions = coherentRegions( mLayerInputRegions->region() + mLayerOutputRegions->region()); qSort(combinedRegions.begin(), combinedRegions.end(), compareRuleRegion); QList rulesInput = coherentRegions( mLayerInputRegions->region()); QList rulesOutput = coherentRegions( mLayerOutputRegions->region()); for (int i = 0; i < combinedRegions.size(); ++i) { mRulesInput.append(QRegion()); mRulesOutput.append(QRegion()); } foreach(QRegion reg, rulesInput) for (int i = 0; i < combinedRegions.size(); ++i) { if (reg.intersects(combinedRegions[i])) { mRulesInput[i] += reg; break; } } foreach(QRegion reg, rulesOutput) for (int i = 0; i < combinedRegions.size(); ++i) { if (reg.intersects(combinedRegions[i])) { mRulesOutput[i] += reg; break; } } Q_ASSERT(mRulesInput.size() == mRulesOutput.size()); for (int i = 0; i < mRulesInput.size(); ++i) { const QRegion checkCoherent = mRulesInput.at(i).united(mRulesOutput.at(i)); Q_ASSERT(coherentRegions(checkCoherent).length() == 1); } return true; } bool AutoMapper::prepareAutoMap() { mError.clear(); mWarning.clear(); if (!setupMissingLayers()) return false; if (!setupCorrectIndexes()) return false; if (!setupTilesets(mMapRules, mMapWork)) return false; return true; } bool AutoMapper::setupMissingLayers() { // make sure all needed layers are there: foreach (const QString &name, mTouchedTileLayers) { if (mMapWork->indexOfLayer(name, Layer::TileLayerType) != -1) continue; const int index = mMapWork->layerCount(); TileLayer *tilelayer = new TileLayer(name, 0, 0, mMapWork->width(), mMapWork->height()); mMapDocument->undoStack()->push( new AddLayer(mMapDocument, index, tilelayer)); mAddedTileLayers.append(name); } foreach (const QString &name, mTouchedObjectGroups) { if (mMapWork->indexOfLayer(name, Layer::ObjectGroupType) != -1) continue; const int index = mMapWork->layerCount(); ObjectGroup *objectGroup = new ObjectGroup(name, 0, 0, mMapWork->width(), mMapWork->height()); mMapDocument->undoStack()->push( new AddLayer(mMapDocument, index, objectGroup)); mAddedTileLayers.append(name); } return true; } bool AutoMapper::setupCorrectIndexes() { // make sure all indexes of the layer translationtables are correct. for (int i = 0; i < mLayerList.size(); ++i) { RuleOutput *translationTable = mLayerList.at(i); foreach (Layer *layerKey, translationTable->keys()) { QString name = layerKey->name(); const int pos = name.indexOf(QLatin1Char('_')) + 1; name = name.right(name.length() - pos); const int index = translationTable->value(layerKey, -1); if (index >= mMapWork->layerCount() || index == -1 || name != mMapWork->layerAt(index)->name()) { int newIndex = mMapWork->indexOfLayer(name, layerKey->layerType()); Q_ASSERT(newIndex != -1); translationTable->insert(layerKey, newIndex); } } } return true; } // This cannot just be replaced by MapDocument::unifyTileset(Map), // because here mAddedTileset is modified. bool AutoMapper::setupTilesets(Map *src, Map *dst) { const QVector &existingTilesets = dst->tilesets(); TilesetManager *tilesetManager = TilesetManager::instance(); // Add tilesets that are not yet part of dst map foreach (const SharedTileset &tileset, src->tilesets()) { if (existingTilesets.contains(tileset)) continue; QUndoStack *undoStack = mMapDocument->undoStack(); SharedTileset replacement = tileset->findSimilarTileset(existingTilesets); if (!replacement) { mAddedTilesets.append(tileset); undoStack->push(new AddTileset(mMapDocument, tileset)); continue; } // Merge the tile properties const int sharedTileCount = qMin(tileset->tileCount(), replacement->tileCount()); for (int i = 0; i < sharedTileCount; ++i) { Tile *replacementTile = replacement->tileAt(i); Properties properties = replacementTile->properties(); properties.merge(tileset->tileAt(i)->properties()); undoStack->push(new ChangeProperties(mMapDocument, tr("Tile"), replacementTile, properties)); } src->replaceTileset(tileset, replacement); tilesetManager->addReference(replacement); tilesetManager->removeReference(tileset); } return true; } void AutoMapper::autoMap(QRegion *where) { Q_ASSERT(mRulesInput.size() == mRulesOutput.size()); // first resize the active area if (mAutoMappingRadius) { QRegion region; foreach (const QRect &r, where->rects()) { region += r.adjusted(- mAutoMappingRadius, - mAutoMappingRadius, + mAutoMappingRadius, + mAutoMappingRadius); } *where += region; } // delete all the relevant area, if the property "DeleteTiles" is set if (mDeleteTiles) { const QRegion setLayersRegion = getSetLayersRegion(); for (int i = 0; i < mLayerList.size(); ++i) { RuleOutput *translationTable = mLayerList.at(i); foreach (Layer *layer, translationTable->keys()) { const int index = mLayerList.at(i)->value(layer); Layer *dstLayer = mMapWork->layerAt(index); const QRegion region = setLayersRegion.intersected(*where); TileLayer *dstTileLayer = dstLayer->asTileLayer(); if (dstTileLayer) dstTileLayer->erase(region); else eraseRegionObjectGroup(mMapDocument, dstLayer->asObjectGroup(), region); } } } // Increase the given region where the next automapper should work. // This needs to be done, so you can rely on the order of the rules at all // locations QRegion ret; foreach (const QRect &rect, where->rects()) for (int i = 0; i < mRulesInput.size(); ++i) { // at the moment the parallel execution does not work yet // TODO: make multithreading available! // either by dividing the rules or the region to multiple threads ret = ret.united(applyRule(i, rect)); } *where = where->united(ret); } const QRegion AutoMapper::getSetLayersRegion() { QRegion result; foreach (const QString &name, mInputRules.names) { const int index = mMapWork->indexOfLayer(name, Layer::TileLayerType); if (index == -1) continue; TileLayer *setLayer = mMapWork->layerAt(index)->asTileLayer(); result |= setLayer->region(); } return result; } static bool compareLayerTo(const TileLayer *setLayer, const QVector &listYes, const QVector &listNo, const QRegion &ruleRegion, const QPoint &offset); QRect AutoMapper::applyRule(const int ruleIndex, const QRect &where) { QRect ret; if (mLayerList.isEmpty()) return ret; const QRegion ruleInput = mRulesInput.at(ruleIndex); const QRegion ruleOutput = mRulesOutput.at(ruleIndex); QRect rbr = ruleInput.boundingRect(); // Since the rule itself is translated, we need to adjust the borders of the // loops. Decrease the size at all sides by one: There must be at least one // tile overlap to the rule. const int minX = where.left() - rbr.left() - rbr.width() + 1; const int minY = where.top() - rbr.top() - rbr.height() + 1; const int maxX = where.right() - rbr.left() + rbr.width() - 1; const int maxY = where.bottom() - rbr.top() + rbr.height() - 1; // In this list of regions it is stored which parts or the map have already // been altered by exactly this rule. We store all the altered parts to // make sure there are no overlaps of the same rule applied to // (neighbouring) places QVector appliedRegions; if (mNoOverlappingRules) appliedRegions.resize(mMapWork->layerCount()); for (int y = minY; y <= maxY; ++y) for (int x = minX; x <= maxX; ++x) { bool anymatch = false; foreach (const QString &index, mInputRules.indexes) { const InputIndex &ii = mInputRules[index]; bool allLayerNamesMatch = true; foreach (const QString &name, ii.names) { const int i = mMapWork->indexOfLayer(name, Layer::TileLayerType); if (i == -1) { allLayerNamesMatch = false; } else { const TileLayer *setLayer = mMapWork->layerAt(i)->asTileLayer(); allLayerNamesMatch &= compareLayerTo(setLayer, ii[name].listYes, ii[name].listNo, ruleInput, QPoint(x, y)); } } if (allLayerNamesMatch) { anymatch = true; break; } } if (anymatch) { int r = 0; // choose by chance which group of rule_layers should be used: if (mLayerList.size() > 1) r = qrand() % mLayerList.size(); if (!mNoOverlappingRules) { copyMapRegion(ruleOutput, QPoint(x, y), mLayerList.at(r)); ret = ret.united(rbr.translated(QPoint(x, y))); continue; } bool missmatch = false; RuleOutput *translationTable = mLayerList.at(r); QList layers = translationTable->keys(); // check if there are no overlaps within this rule. QVector ruleRegionInLayer; for (int i = 0; i < layers.size(); ++i) { Layer *layer = layers.at(i); QRegion appliedPlace; TileLayer *tileLayer = layer->asTileLayer(); if (tileLayer) appliedPlace = tileLayer->region(); else appliedPlace = tileRegionOfObjectGroup(layer->asObjectGroup()); ruleRegionInLayer.append(appliedPlace.intersected(ruleOutput)); if (appliedRegions.at(i).intersects( ruleRegionInLayer[i].translated(x, y))) { missmatch = true; break; } } if (missmatch) continue; copyMapRegion(ruleOutput, QPoint(x, y), mLayerList.at(r)); ret = ret.united(rbr.translated(QPoint(x, y))); for (int i = 0; i < translationTable->size(); ++i) { appliedRegions[i] += ruleRegionInLayer[i].translated(x, y); } } } return ret; } /** * Returns a list of all cells which can be found within all tile layers * within the given region. */ static QVector cellsInRegion(const QVector &list, const QRegion &r) { QVector cells; foreach (const TileLayer *tilelayer, list) { foreach (const QRect &rect, r.rects()) { for (int x = rect.left(); x <= rect.right(); ++x) { for (int y = rect.top(); y <= rect.bottom(); ++y) { const Cell &cell = tilelayer->cellAt(x, y); if (!cells.contains(cell)) cells.append(cell); } } } } return cells; } /** * This function is one of the core functions for understanding the * automapping. * In this function a certain region (of the set layer) is compared to * several other layers (ruleSet and ruleNotSet). * This comparison will determine if a rule of automapping matches, * so if this rule is applied at this region given * by a QRegion and Offset given by a QPoint. * * This compares the tile layer setLayer to several others given * in the QList listYes (ruleSet) and OList listNo (ruleNotSet). * The tile layer setLayer is examined at QRegion ruleRegion + offset * The tile layers within listYes and listNo are examined at QRegion ruleRegion. * * Basically all matches between setLayer and a layer of listYes are considered * good, while all matches between setLayer and listNo are considered bad and * lead to canceling the comparison, returning false. * * The comparison is done for each position within the QRegion ruleRegion. * If all positions of the region are considered "good" return true. * * Now there are several cases to distinguish: * - both listYes and listNo are empty: * This should not happen, because with that configuration, absolutely * no condition is given. * return false, assuming this is an errornous rule being applied * * - both listYes and listNo are not empty: * When comparing a tile at a certain position of tile layer setLayer * to all available tiles in listYes, there must be at least * one layer, in which there is a match of tiles of setLayer and * listYes to consider this position good. * In listNo there must not be a match to consider this position * good. * If there are no tiles within all available tiles within all layers * of one list, all tiles in setLayer are considered good, * while inspecting this list. * All available tiles are all tiles within the whole rule region in * all tile layers of the list. * * - either of both lists are not empty * When comparing a certain position of tile layer setLayer * to all Tiles at the corresponding position this can happen: * A tile of setLayer matches a tile of a layer in the list. Then this * is considered as good, if the layer is from the listYes. * Otherwise it is considered bad. * * Exception, when having only the listYes: * if at the examined position there are no tiles within all Layers * of the listYes, all tiles except all used tiles within * the layers of that list are considered good. * * This exception was added to have a better functionality * (need of less layers.) * It was not added to the case, when having only listNo layers to * avoid total symmetry between those lists. * * If all positions are considered good, return true. * return false otherwise. * * @return bool, if the tile layer matches the given list of layers. */ static bool compareLayerTo(const TileLayer *setLayer, const QVector &listYes, const QVector &listNo, const QRegion &ruleRegion, const QPoint &offset) { if (listYes.isEmpty() && listNo.isEmpty()) return false; QVector cells; if (listYes.isEmpty()) cells = cellsInRegion(listNo, ruleRegion); if (listNo.isEmpty()) cells = cellsInRegion(listYes, ruleRegion); foreach (const QRect &rect, ruleRegion.rects()) { for (int x = rect.left(); x <= rect.right(); ++x) { for (int y = rect.top(); y <= rect.bottom(); ++y) { // this is only used in the case where only one list has layers // it is needed for the exception mentioned above bool ruleDefinedListYes = false; bool matchListYes = false; bool matchListNo = false; if (!setLayer->contains(x + offset.x(), y + offset.y())) return false; const Cell &c1 = setLayer->cellAt(x + offset.x(), y + offset.y()); // ruleDefined will be set when there is a tile in at least // one layer. if there is a tile in at least one layer, only // the given tiles in the different listYes layers are valid. // if there is given no tile at all in the listYes layers, // consider all tiles valid. foreach (const TileLayer *comparedTileLayer, listYes) { if (!comparedTileLayer->contains(x, y)) return false; const Cell &c2 = comparedTileLayer->cellAt(x, y); if (!c2.isEmpty()) ruleDefinedListYes = true; if (!c2.isEmpty() && c1 == c2) matchListYes = true; } foreach (const TileLayer *comparedTileLayer, listNo) { if (!comparedTileLayer->contains(x, y)) return false; const Cell &c2 = comparedTileLayer->cellAt(x, y); if (!c2.isEmpty() && c1 == c2) matchListNo = true; } // when there are only layers in the listNo // check only if these layers are unmatched // no need to check explicitly the exception in this case. if (listYes.isEmpty()) { if (matchListNo) return false; else continue; } // when there are only layers in the listYes // check if these layers are matched, or if the exception works if (listNo.isEmpty()) { if (matchListYes) continue; if (!ruleDefinedListYes && !cells.contains(c1)) continue; return false; } // there are layers in both lists: // no need to consider ruleDefinedListXXX if ((matchListYes || !ruleDefinedListYes) && !matchListNo) continue; else return false; } } } return true; } void AutoMapper::copyMapRegion(const QRegion ®ion, QPoint offset, const RuleOutput *layerTranslation) { for (int i = 0; i < layerTranslation->keys().size(); ++i) { Layer *from = layerTranslation->keys().at(i); Layer *to = mMapWork->layerAt(layerTranslation->value(from)); foreach (const QRect &rect, region.rects()) { TileLayer *fromTileLayer = from->asTileLayer(); ObjectGroup *fromObjectGroup = from->asObjectGroup(); if (fromTileLayer) { TileLayer *toTileLayer = to->asTileLayer(); Q_ASSERT(toTileLayer); //TODO check this before in prepareAutomap or such! copyTileRegion(fromTileLayer, rect.x(), rect.y(), rect.width(), rect.height(), toTileLayer, rect.x() + offset.x(), rect.y() + offset.y()); } else if (fromObjectGroup) { ObjectGroup *toObjectGroup = to->asObjectGroup(); copyObjectRegion(fromObjectGroup, rect.x(), rect.y(), rect.width(), rect.height(), toObjectGroup, rect.x() + offset.x(), rect.y() + offset.y()); } else { Q_ASSERT(false); } } } } void AutoMapper::copyTileRegion(TileLayer *srcLayer, int srcX, int srcY, int width, int height, TileLayer *dstLayer, int dstX, int dstY) { const int startX = qMax(dstX, 0); const int startY = qMax(dstY, 0); const int endX = qMin(dstX + width, dstLayer->width()); const int endY = qMin(dstY + height, dstLayer->height()); const int offsetX = srcX - dstX; const int offsetY = srcY - dstY; for (int x = startX; x < endX; ++x) { for (int y = startY; y < endY; ++y) { const Cell &cell = srcLayer->cellAt(x + offsetX, y + offsetY); if (!cell.isEmpty()) { // this is without graphics update, it's done afterwards for all dstLayer->setCell(x, y, cell); } } } } void AutoMapper::copyObjectRegion(ObjectGroup *srcLayer, int srcX, int srcY, int width, int height, ObjectGroup *dstLayer, int dstX, int dstY) { QUndoStack *undo = mMapDocument->undoStack(); const QRectF rect = QRectF(srcX, srcY, width, height); const QRectF pixelRect = mMapDocument->renderer()->tileToPixelCoords(rect); QList objects = objectsInRegion(srcLayer, pixelRect.toAlignedRect()); QPointF pixelOffset = mMapDocument->renderer()->tileToPixelCoords(dstX, dstY); pixelOffset -= pixelRect.topLeft(); QList clones; foreach (MapObject *obj, objects) { MapObject *clone = obj->clone(); clones.append(clone); clone->setX(clone->x() + pixelOffset.x()); clone->setY(clone->y() + pixelOffset.y()); undo->push(new AddMapObject(mMapDocument, dstLayer, clone)); } } void AutoMapper::cleanAll() { cleanTilesets(); cleanTileLayers(); } void AutoMapper::cleanTilesets() { foreach (const SharedTileset &tileset, mAddedTilesets) { if (mMapWork->isTilesetUsed(tileset.data())) continue; const int index = mMapWork->indexOfTileset(tileset); if (index == -1) continue; QUndoStack *undo = mMapDocument->undoStack(); undo->push(new RemoveTileset(mMapDocument, index)); } mAddedTilesets.clear(); } void AutoMapper::cleanTileLayers() { foreach (const QString &tilelayerName, mAddedTileLayers) { const int layerIndex = mMapWork->indexOfLayer(tilelayerName, Layer::TileLayerType); if (layerIndex == -1) continue; const Layer *layer = mMapWork->layerAt(layerIndex); if (!layer->isEmpty()) continue; QUndoStack *undo = mMapDocument->undoStack(); undo->push(new RemoveLayer(mMapDocument, layerIndex)); } mAddedTileLayers.clear(); } void AutoMapper::cleanUpRulesMap() { cleanTilesets(); // mMapRules can be empty, when in prepareLoad the very first stages fail. if (!mMapRules) return; TilesetManager *tilesetManager = TilesetManager::instance(); tilesetManager->removeReferences(mMapRules->tilesets()); delete mMapRules; mMapRules = nullptr; cleanUpRuleMapLayers(); mRulesInput.clear(); mRulesOutput.clear(); } void AutoMapper::cleanUpRuleMapLayers() { cleanTileLayers(); QList::const_iterator it; for (it = mLayerList.constBegin(); it != mLayerList.constEnd(); ++it) delete (*it); mLayerList.clear(); // do not delete mLayerRuleRegions, it is owned by the rulesmap mLayerInputRegions = nullptr; mLayerOutputRegions = nullptr; mInputRules.clear(); } tiled-0.14.2/src/tiled/automapper.h000066400000000000000000000253301260670167100171260ustar00rootroot00000000000000/* * automapper.h * Copyright 2010-2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of Tiled. * * 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, see . */ #ifndef AUTOMAPPER_H #define AUTOMAPPER_H #include "tileset.h" #include #include #include #include #include #include namespace Tiled { class Layer; class Map; class MapObject; class ObjectGroup; class TileLayer; namespace Internal { class MapDocument; class InputIndexName { public: QVector listYes; QVector listNo; }; class InputIndex : public QMap { public: QSet names; }; class InputLayers : public QMap { public: QSet indexes; QSet names; // all names }; class RuleOutput : public QMap { public: QString index; }; /** * This class does all the work for the automapping feature. * basically it can do the following: * - check the rules map for rules and store them * - compare TileLayers (i. e. check if/where a certain rule must be applied) * - copy regions of Maps (multiple Layers, the layerlist is a * lookup-table for matching the Layers) */ class AutoMapper : public QObject { Q_OBJECT public: /** * Constructs an AutoMapper. * All data structures, which only rely on the rules map are setup * here. * * @param workingDocument: the map to work on. * @param rules: The rule map which should be used for automapping * @param rulePath: The filepath to the rule map. */ AutoMapper(MapDocument *workingDocument, Map *rules, const QString &rulePath); ~AutoMapper(); /** * Checks if the passed \a ruleLayerName is used in this instance * of Automapper. */ bool ruleLayerNameUsed(QString ruleLayerName) const; /** * Call prepareLoad first! Returns a set of strings describing the tile * layers, which could be touched considering the given layers of the * rule map. */ QSet getTouchedTileLayers() const; /** * This needs to be called directly before the autoMap call. * It sets up some data structures which change rapidly, so it is quite * painful to keep these data structures up to date all time. (indices of * layers of the working map) */ bool prepareAutoMap(); /** * Here is done all the automapping. */ void autoMap(QRegion *where); /** * This cleans all data structures, which are setup via prepareAutoMap, * so the auto mapper becomes ready for its next automatic mapping. */ void cleanAll(); /** * Contains all errors until operation was canceled. * The errorlist is cleared within prepareLoad and prepareAutoMap. */ QString errorString() const { return mError; } /** * Contains all warnings which occur at loading a rules map or while * automapping. * The errorlist is cleared within prepareLoad and prepareAutoMap. */ QString warningString() const { return mWarning; } private: /** * Reads the map properties of the rulesmap. * @return returns true when anything is ok, false when errors occurred. */ bool setupRuleMapProperties(); void cleanUpRulesMap(); /** * Searches the rules layer for regions and stores these in \a rules. * @return returns true when anything is ok, false when errors occurred. */ bool setupRuleList(); /** * Sets up the layers in the rules map, which are used for automapping. * The layers are detected and put in the internal data structures * @return returns true when anything is ok, false when errors occurred. */ bool setupRuleMapTileLayers(); /** * Checks if all needed layers in the working map are there. * If not, add them in the correct order. */ bool setupMissingLayers(); /** * Checks if the layers setup as in setupRuleMapLayers are still right. * If it's not right, correct them. * @return returns true if everything went fine. false is returned when * no set layer was found */ bool setupCorrectIndexes(); /** * sets up the tilesets which are used in automapping. * @return returns true when anything is ok, false when errors occurred. * (in that case will be a msg box anyway) */ bool setupTilesets(Map *src, Map *dst); /** * Returns the conjunction of of all regions of all setlayers */ const QRegion getSetLayersRegion(); /** * This copies all Tiles from TileLayer src to TileLayer dst * * In src the Tiles are taken from the rectangle given by * src_x, src_y, width and height. * In dst they get copied to a rectangle given by * dst_x, dst_y, width, height . * if there is no tile in src TileLayer, there will nothing be copied, * so the maybe existing tile in dst will not be overwritten. * */ void copyTileRegion(TileLayer *src_lr, int src_x, int src_y, int width, int height, TileLayer *dst_lr, int dst_x, int dst_y); /** * This copies all objects from the \a src_lr ObjectGroup to the \a dst_lr * in the given rectangle. * * The rectangle is described by the upper left corner \a src_x \a src_y * and its \a width and \a height. The parameter \a dst_x and \a dst_y * offset the copied objects in the destination object group. */ void copyObjectRegion(ObjectGroup *src_lr, int src_x, int src_y, int width, int height, ObjectGroup *dst_lr, int dst_x, int dst_y); /** * This copies multiple TileLayers from one map to another. * Only the region \a region is considered for copying. * In the destination it will come to the region translated by Offset. * The parameter \a LayerTranslation is a map of which layers of the rulesmap * should get copied into which layers of the working map. */ void copyMapRegion(const QRegion ®ion, QPoint Offset, const RuleOutput *LayerTranslation); /** * This goes through all the positions of the mMapWork and checks if * there fits the rule given by the region in mMapRuleSet. * if there is a match all Layers are copied to mMapWork. * @param ruleIndex: the region which should be compared to all positions * of mMapWork will be looked up in mRulesInput and mRulesOutput * @return where: an rectangle where the rule actually got applied */ QRect applyRule(const int ruleIndex, const QRect &where); /** * Cleans up the data structures filled by setupRuleMapLayers(), * so the next rule can be processed. */ void cleanUpRuleMapLayers(); /** * Cleans up the data structures filled by setupTilesets(), * so the next rule can be processed. */ void cleanTilesets(); /** * Cleans up the added tile layers setup by setupMissingLayers(), * so we have a minimal addition of tile layers by the automapping. */ void cleanTileLayers(); /** * where to work in */ MapDocument *mMapDocument; /** * the same as mMapDocument->map() */ Map *mMapWork; /** * map containing the rules, usually different than mMapWork */ Map *mMapRules; /** * This contains all added tilesets as pointers. * if rules use Tilesets which are not in the mMapWork they are added. * keep track of them, because we need to delete them afterwards, * when they still are unused * they will be added while setupTilesets(). */ QVector mAddedTilesets; /** * description see: mAddedTilesets, just described by Strings */ QList mAddedTileLayers; /** * Points to the tilelayer, which defines the input regions. */ TileLayer *mLayerInputRegions; /** * Points to the tilelayer, which defines the output regions. */ TileLayer *mLayerOutputRegions; /** * Contains all tilelayer pointers, which names begin with input* * It is sorted by index and name */ InputLayers mInputRules; /** * List of Regions in mMapRules to know where the input rules are */ QList mRulesInput; /** * List of regions in mMapRules to know where the output of a * rule is. * mRulesOutput[i] is the output of that rule, * which has the input at mRulesInput[i], meaning that mRulesInput * and mRulesOutput must match with the indexes. */ QList mRulesOutput; /** * The inner set with layers to indexes is needed for translating * tile layers from mMapRules to mMapWork. * * The key is the pointer to the layer in the rulemap. The * pointer to the layer within the working map is not hardwired, but the * position in the layerlist, where it was found the last time. * This loosely bound pointer ensures we will get the right layer, since we * need to check before anyway, and it is still fast. * * The list is used to hold different translation tables * => one of the tables is chosen by chance, so randomness is available */ QList mLayerList; /** * store the name of the processed rules file, to have detailed * error messages available */ QString mRulePath; /** * determines if all tiles in all touched layers should be deleted first. */ bool mDeleteTiles; /** * This variable determines, how many overlapping tiles should be used. * The bigger the more area is remapped at an automapping operation. * This can lead to higher latency, but provides a better behavior on * interactive automapping. * It defaults to zero. */ int mAutoMappingRadius; /** * Determines if a rule is allowed to overlap itself. */ bool mNoOverlappingRules; QSet mTouchedTileLayers; QSet mTouchedObjectGroups; QString mError; QString mWarning; }; } // namespace Internal } // namespace Tiled #endif // AUTOMAPPER_H tiled-0.14.2/src/tiled/automapperwrapper.cpp000066400000000000000000000101241260670167100210550ustar00rootroot00000000000000/* * automapperwrapper.cpp * Copyright 2010-2011, Stefan Beller, stefanbeller@googlemail.com * * This file is part of Tiled. * * 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, see . */ #include "automapperwrapper.h" #include "map.h" #include "mapdocument.h" #include "tile.h" #include "tilelayer.h" using namespace Tiled; using namespace Tiled::Internal; AutoMapperWrapper::AutoMapperWrapper(MapDocument *mapDocument, QVector autoMapper, QRegion *where) { mMapDocument = mapDocument; Map *map = mMapDocument->map(); QSet touchedLayers; int index = 0; while (index < autoMapper.size()) { AutoMapper *a = autoMapper.at(index); if (a->prepareAutoMap()) { touchedLayers|= a->getTouchedTileLayers(); index++; } else { autoMapper.remove(index); } } foreach (const QString &layerName, touchedLayers) { const int layerindex = map->indexOfLayer(layerName); Q_ASSERT(layerindex != -1); mLayersBefore << static_cast(map->layerAt(layerindex)->clone()); } for (AutoMapper *a : autoMapper) a->autoMap(where); foreach (const QString &layerName, touchedLayers) { const int layerindex = map->indexOfLayer(layerName); // layer index exists, because AutoMapper is still alive, don't check Q_ASSERT(layerindex != -1); mLayersAfter << static_cast(map->layerAt(layerindex)->clone()); } // reduce memory usage by saving only diffs Q_ASSERT(mLayersAfter.size() == mLayersBefore.size()); for (int i = 0; i < mLayersAfter.size(); ++i) { TileLayer *before = mLayersBefore.at(i); TileLayer *after = mLayersAfter.at(i); QRect diffRegion = before->computeDiffRegion(after).boundingRect(); TileLayer *before1 = before->copy(diffRegion); TileLayer *after1 = after->copy(diffRegion); before1->setPosition(diffRegion.topLeft()); after1->setPosition(diffRegion.topLeft()); before1->setName(before->name()); after1->setName(after->name()); mLayersBefore.replace(i, before1); mLayersAfter.replace(i, after1); delete before; delete after; } for (AutoMapper *a : autoMapper) a->cleanAll(); } AutoMapperWrapper::~AutoMapperWrapper() { QVector::iterator i; for (i = mLayersAfter.begin(); i != mLayersAfter.end(); ++i) delete *i; for (i = mLayersBefore.begin(); i != mLayersBefore.end(); ++i) delete *i; } void AutoMapperWrapper::undo() { Map *map = mMapDocument->map(); for (TileLayer *layer : mLayersBefore) { const int layerindex = map->indexOfLayer(layer->name()); if (layerindex != -1) patchLayer(layerindex, layer); } } void AutoMapperWrapper::redo() { Map *map = mMapDocument->map(); for (TileLayer *layer : mLayersAfter) { const int layerindex = map->indexOfLayer(layer->name()); if (layerindex != -1) patchLayer(layerindex, layer); } } void AutoMapperWrapper::patchLayer(int layerIndex, TileLayer *layer) { Map *map = mMapDocument->map(); QRect b = layer->bounds(); Q_ASSERT(map->layerAt(layerIndex)->asTileLayer()); TileLayer *t = static_cast(map->layerAt(layerIndex)); t->setCells(b.left() - t->x(), b.top() - t->y(), layer, b.translated(-t->position())); mMapDocument->emitRegionChanged(b, t); } tiled-0.14.2/src/tiled/automapperwrapper.h000066400000000000000000000033461260670167100205320ustar00rootroot00000000000000/* * automapperwrapper.h * Copyright 2010-2011, Stefan Beller, stefanbeller@googlemail.com * * This file is part of Tiled. * * 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, see . */ #ifndef AUTOMAPPERWRAPPER_H #define AUTOMAPPERWRAPPER_H #include "automapper.h" #include #include namespace Tiled { namespace Internal { class MapDocument; /** * This is a wrapper class for the AutoMapper class. * Here in this class only undo/redo functionality all rulemaps * is provided. * This class will take a snapshot of the layers before and after the * automapping is done. In between instances of AutoMapper are doing the work. */ class AutoMapperWrapper : public QUndoCommand { public: AutoMapperWrapper(MapDocument *mapDocument, QVector autoMapper, QRegion *where); ~AutoMapperWrapper(); void undo() override; void redo() override; private: void patchLayer(int layerIndex, TileLayer *layer); MapDocument *mMapDocument; QVector mLayersAfter; QVector mLayersBefore; }; } // namespace Internal } // namespace Tiled #endif // AUTOMAPPERWRAPPER_H tiled-0.14.2/src/tiled/automappingmanager.cpp000066400000000000000000000137361260670167100211720ustar00rootroot00000000000000/* * automappingmanager.cpp * Copyright 2010-2011, Stefan Beller, stefanbeller@googlemail.com * * This file is part of Tiled. * * 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, see . */ #include "automappingmanager.h" #include "automapperwrapper.h" #include "map.h" #include "mapdocument.h" #include "tilelayer.h" #include "tilesetmanager.h" #include "tmxmapformat.h" #include "preferences.h" #include #include using namespace Tiled; using namespace Tiled::Internal; AutomappingManager::AutomappingManager(QObject *parent) : QObject(parent) , mMapDocument(nullptr) , mLoaded(false) { } AutomappingManager::~AutomappingManager() { cleanUp(); } void AutomappingManager::autoMap() { if (!mMapDocument) return; Map *map = mMapDocument->map(); int w = map->width(); int h = map->height(); autoMapInternal(QRect(0, 0, w, h), nullptr); } void AutomappingManager::autoMap(const QRegion &where, Layer *touchedLayer) { if (Preferences::instance()->automappingDrawing()) autoMapInternal(where, touchedLayer); } void AutomappingManager::autoMapInternal(const QRegion &where, Layer *touchedLayer) { mError.clear(); mWarning.clear(); if (!mMapDocument) return; const bool automatic = touchedLayer != nullptr; if (!mLoaded) { const QString mapPath = QFileInfo(mMapDocument->fileName()).path(); const QString rulesFileName = mapPath + QLatin1String("/rules.txt"); if (loadFile(rulesFileName)) { mLoaded = true; } else { emit errorsOccurred(automatic); return; } } QVector passedAutoMappers; if (touchedLayer) { foreach (AutoMapper *a, mAutoMappers) { if (a->ruleLayerNameUsed(touchedLayer->name())) passedAutoMappers.append(a); } } else { passedAutoMappers = mAutoMappers; } if (!passedAutoMappers.isEmpty()) { // use a copy of the region, so each automapper can manipulate it and the // following automappers do see the impact QRegion region(where); QUndoStack *undoStack = mMapDocument->undoStack(); undoStack->beginMacro(tr("Apply AutoMap rules")); AutoMapperWrapper *aw = new AutoMapperWrapper(mMapDocument, passedAutoMappers, ®ion); undoStack->push(aw); undoStack->endMacro(); } foreach (AutoMapper *automapper, mAutoMappers) { mWarning += automapper->warningString(); mError += automapper->errorString(); } if (!mWarning.isEmpty()) emit warningsOccurred(automatic); if (!mError.isEmpty()) emit errorsOccurred(automatic); } bool AutomappingManager::loadFile(const QString &filePath) { bool ret = true; const QString absPath = QFileInfo(filePath).path(); QFile rulesFile(filePath); if (!rulesFile.exists()) { mError += tr("No rules file found at:\n%1").arg(filePath) + QLatin1Char('\n'); return false; } if (!rulesFile.open(QIODevice::ReadOnly | QIODevice::Text)) { mError += tr("Error opening rules file:\n%1").arg(filePath) + QLatin1Char('\n'); return false; } QTextStream in(&rulesFile); QString line = in.readLine(); for (; !line.isNull(); line = in.readLine()) { QString rulePath = line.trimmed(); if (rulePath.isEmpty() || rulePath.startsWith(QLatin1Char('#')) || rulePath.startsWith(QLatin1String("//"))) continue; if (QFileInfo(rulePath).isRelative()) rulePath = absPath + QLatin1Char('/') + rulePath; if (!QFileInfo(rulePath).exists()) { mError += tr("File not found:\n%1").arg(rulePath) + QLatin1Char('\n'); ret = false; continue; } if (rulePath.endsWith(QLatin1String(".tmx"), Qt::CaseInsensitive)) { TmxMapFormat tmxFormat; Map *rules = tmxFormat.read(rulePath); if (!rules) { mError += tr("Opening rules map failed:\n%1").arg( tmxFormat.errorString()) + QLatin1Char('\n'); ret = false; continue; } TilesetManager *tilesetManager = TilesetManager::instance(); tilesetManager->addReferences(rules->tilesets()); AutoMapper *autoMapper; autoMapper = new AutoMapper(mMapDocument, rules, rulePath); mWarning += autoMapper->warningString(); const QString error = autoMapper->errorString(); if (error.isEmpty()) { mAutoMappers.append(autoMapper); } else { mError += error; delete autoMapper; } } if (rulePath.endsWith(QLatin1String(".txt"), Qt::CaseInsensitive)) { if (!loadFile(rulePath)) ret = false; } } return ret; } void AutomappingManager::setMapDocument(MapDocument *mapDocument) { cleanUp(); if (mMapDocument) mMapDocument->disconnect(this); mMapDocument = mapDocument; if (mMapDocument) { connect(mMapDocument, SIGNAL(regionEdited(QRegion,Layer*)), this, SLOT(autoMap(QRegion,Layer*))); } mLoaded = false; } void AutomappingManager::cleanUp() { qDeleteAll(mAutoMappers); mAutoMappers.clear(); } tiled-0.14.2/src/tiled/automappingmanager.h000066400000000000000000000070451260670167100206330ustar00rootroot00000000000000/* * automappingmanager.h * Copyright 2010-2011, Stefan Beller, stefanbeller@googlemail.com * * This file is part of Tiled. * * 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, see . */ #ifndef AUTOMAPPINGMANAGER_H #define AUTOMAPPINGMANAGER_H #include #include #include #include namespace Tiled { class Layer; namespace Internal { class AutoMapper; class MapDocument; /** * This class is a superior class to the AutoMapper and AutoMapperWrapper class. * It uses these classes to do the whole automapping process. */ class AutomappingManager : public QObject { Q_OBJECT public: /** * Constructor. */ AutomappingManager(QObject *parent = nullptr); ~AutomappingManager(); void setMapDocument(MapDocument *mapDocument); QString errorString() const { return mError; } QString warningString() const { return mWarning; } signals: /** * This signal is emitted after automapping was done and an error occurred. */ void errorsOccurred(bool automatic); /** * This signal is emitted after automapping was done and a warning occurred. */ void warningsOccurred(bool automatic); public slots: /** * This triggers an automapping on the whole current map document. */ void autoMap(); private slots: void autoMap(const QRegion &where, Layer *touchedLayer); private: Q_DISABLE_COPY(AutomappingManager) /** * This function parses a rules file. * For each path which is a rule, (file extension is tmx) an AutoMapper * object is setup. * * If a file extension is txt, this file will be opened and searched for * rules again. * * @return if the loading was successful: return true if it succeeded. */ bool loadFile(const QString &filePath); /** * Applies automapping to the Region \a where, considering only layer * \a touchedLayer has changed. * There will only those Automappers be used which have a rule layer * touching the \a touchedLayer * If layer is 0, all Automappers are used. */ void autoMapInternal(const QRegion &where, Layer *touchedLayer); /** * deletes all its data structures */ void cleanUp(); /** * The current map document. */ MapDocument *mMapDocument; /** * For each new file of rules a new AutoMapper is setup. In this vector we * can store all of the AutoMappers in order. */ QVector mAutoMappers; /** * This tells you if the rules for the current map document were already * loaded. */ bool mLoaded; /** * Contains all errors which occurred until canceling. * If mError is not empty, no serious result can be expected. */ QString mError; /** * Contains all strings, which try to explain unusual and unexpected * behavior. */ QString mWarning; }; } // namespace Internal } // namespace Tiled #endif // AUTOMAPPINGMANAGER_H tiled-0.14.2/src/tiled/automappingutils.cpp000066400000000000000000000071431260670167100207130ustar00rootroot00000000000000/* * automappingutils.cpp * Copyright 2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of Tiled. * * 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, see . */ #include "automappingutils.h" #include "addremovemapobject.h" #include "mapdocument.h" #include "mapobject.h" #include "maprenderer.h" #include "objectgroup.h" #include namespace Tiled { namespace Internal { void eraseRegionObjectGroup(MapDocument *mapDocument, ObjectGroup *layer, const QRegion &where) { QUndoStack *undo = mapDocument->undoStack(); foreach (MapObject *obj, layer->objects()) { // TODO: we are checking bounds, which is only correct for rectangles and // tile objects. polygons and polylines are not covered correctly by this // erase method (we are in fact deleting too many objects) // TODO2: toAlignedRect may even break rects. // Convert the boundary of the object into tile space const QRectF objBounds = obj->boundsUseTile(); QPointF tl = mapDocument->renderer()->pixelToTileCoords(objBounds.topLeft()); QPointF tr = mapDocument->renderer()->pixelToTileCoords(objBounds.topRight()); QPointF br = mapDocument->renderer()->pixelToTileCoords(objBounds.bottomRight()); QPointF bl = mapDocument->renderer()->pixelToTileCoords(objBounds.bottomLeft()); QRectF objInTileSpace; objInTileSpace.setTopLeft(tl); objInTileSpace.setTopRight(tr); objInTileSpace.setBottomRight(br); objInTileSpace.setBottomLeft(bl); const QRect objAlignedRect = objInTileSpace.toAlignedRect(); if (where.intersects(objAlignedRect)) undo->push(new RemoveMapObject(mapDocument, obj)); } } QRegion tileRegionOfObjectGroup(ObjectGroup *layer) { QRegion ret; foreach (MapObject *obj, layer->objects()) { // TODO: we are using bounds, which is only correct for rectangles and // tile objects. polygons and polylines are not probably covering less // tiles. ret += obj->bounds().toAlignedRect(); } return ret; } const QList objectsInRegion(ObjectGroup *layer, const QRegion &where) { QList ret; foreach (MapObject *obj, layer->objects()) { // TODO: we are checking bounds, which is only correct for rectangles and // tile objects. polygons and polylines are not covered correctly by this // erase method (we are in fact deleting too many objects) // TODO2: toAlignedRect may even break rects. const QRect rect = obj->boundsUseTile().toAlignedRect(); // QRegion::intersects() returns false for empty regions even if they are // contained within the region, so we also check for containment of the // top left to include the case of zero size objects. if (where.intersects(rect) || where.contains(rect.topLeft())) ret += obj; } return ret; } } } tiled-0.14.2/src/tiled/automappingutils.h000066400000000000000000000025121260670167100203530ustar00rootroot00000000000000/* * automappingutils.h * Copyright 2012, Stefan Beller, stefanbeller@googlemail.com * * This file is part of Tiled. * * 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, see . */ #ifndef AUTOMAPPINGUTILS_H #define AUTOMAPPINGUTILS_H #include namespace Tiled { class MapObject; class ObjectGroup; namespace Internal { class MapDocument; const QList objectsInRegion(ObjectGroup *layer, const QRegion &where); void eraseRegionObjectGroup(MapDocument *mapDocument, ObjectGroup *layer, const QRegion &where); QRegion tileRegionOfObjectGroup(ObjectGroup *layer); } // namespace Internal } // namespace Tiled #endif // AUTOMAPPINGUTILS_H tiled-0.14.2/src/tiled/brushitem.cpp000066400000000000000000000113351260670167100173060ustar00rootroot00000000000000/* * brushitem.cpp * Copyright 2008-2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "brushitem.h" #include "map.h" #include "mapdocument.h" #include "maprenderer.h" #include "painttilelayer.h" #include "tile.h" #include "tilelayer.h" #include #include #include #include using namespace Tiled; using namespace Tiled::Internal; BrushItem::BrushItem(): mMapDocument(nullptr) { setFlag(QGraphicsItem::ItemUsesExtendedStyleOption); } /** * Sets the map document this brush is operating on. */ void BrushItem::setMapDocument(MapDocument *mapDocument) { if (mMapDocument == mapDocument) return; mMapDocument = mapDocument; // The tiles in the stamp may no longer be valid clear(); } /** * Sets a tile layer representing this brush. When no tile layer is set, * the brush only draws the selection color. */ void BrushItem::setTileLayer(const SharedTileLayer &tileLayer) { mTileLayer = tileLayer; mRegion = tileLayer ? tileLayer->region() : QRegion(); updateBoundingRect(); update(); } /** * Changes the position of the tile layer, if one is set. */ void BrushItem::setTileLayerPosition(const QPoint &pos) { if (!mTileLayer) return; const QPoint oldPosition(mTileLayer->x(), mTileLayer->y()); if (oldPosition == pos) return; mRegion.translate(pos - oldPosition); mTileLayer->setX(pos.x()); mTileLayer->setY(pos.y()); updateBoundingRect(); } /** * Sets the region of tiles that this brush item occupies. */ void BrushItem::setTileRegion(const QRegion ®ion) { if (mRegion == region) return; mRegion = region; updateBoundingRect(); } /** * Sets the layer offset used by the currently active layer. */ void BrushItem::setLayerOffset(const QPointF &offset) { setPos(offset); } QRectF BrushItem::boundingRect() const { return mBoundingRect; } void BrushItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) { QColor insideMapHighlight = QApplication::palette().highlight().color(); insideMapHighlight.setAlpha(64); QColor outsideMapHighlight = QColor(255, 0, 0, 64); int mapWidth = mMapDocument->map()->width(); int mapHeight = mMapDocument->map()->height(); QRegion mapRegion = QRegion(0, 0, mapWidth, mapHeight); QRegion insideMapRegion = mRegion.intersected(mapRegion); QRegion outsideMapRegion = mRegion.subtracted(mapRegion); const MapRenderer *renderer = mMapDocument->renderer(); if (mTileLayer) { const qreal opacity = painter->opacity(); painter->setOpacity(0.75); renderer->drawTileLayer(painter, mTileLayer.data(), option->exposedRect); painter->setOpacity(opacity); } renderer->drawTileSelection(painter, insideMapRegion, insideMapHighlight, option->exposedRect); renderer->drawTileSelection(painter, outsideMapRegion, outsideMapHighlight, option->exposedRect); } void BrushItem::updateBoundingRect() { prepareGeometryChange(); if (!mMapDocument) { mBoundingRect = QRectF(); return; } const QRect bounds = mRegion.boundingRect(); mBoundingRect = mMapDocument->renderer()->boundingRect(bounds); // Adjust for amount of pixels tiles extend at the top and to the right if (mTileLayer) { const Map *map = mMapDocument->map(); QMargins drawMargins = mTileLayer->drawMargins(); drawMargins.setTop(drawMargins.top() - map->tileHeight()); drawMargins.setRight(drawMargins.right() - map->tileWidth()); // Since we're also drawing a tile selection, we should not apply // negative margins mBoundingRect.adjust(qMin(0, -drawMargins.left()), qMin(0, -drawMargins.top()), qMax(0, drawMargins.right()), qMax(0, drawMargins.bottom())); } } tiled-0.14.2/src/tiled/brushitem.h000066400000000000000000000045051260670167100167540ustar00rootroot00000000000000/* * brushitem.h * Copyright 2008-2010, Thorbjørn Lindeijer * Copyright 2010 Stefan Beller * * This file is part of Tiled. * * 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, see . */ #ifndef BRUSHITEM_H #define BRUSHITEM_H #include "tilelayer.h" #include namespace Tiled { namespace Internal { class MapDocument; /** * This brush item is used to represent a brush in a map scene before it is * used. */ class BrushItem : public QGraphicsItem { public: BrushItem(); void setMapDocument(MapDocument *mapDocument); void clear(); void setTileLayer(const SharedTileLayer &tileLayer); const SharedTileLayer &tileLayer() const; void setTileLayerPosition(const QPoint &pos); void setTileRegion(const QRegion ®ion); QRegion tileRegion() const; void setLayerOffset(const QPointF &offset); // QGraphicsItem QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; private: void updateBoundingRect(); MapDocument *mMapDocument; SharedTileLayer mTileLayer; QRegion mRegion; QRectF mBoundingRect; }; /** * Clears the tile layer and region set on this item. */ inline void BrushItem::clear() { setTileLayer(SharedTileLayer()); } /** * Returns the current tile layer. */ inline const SharedTileLayer &BrushItem::tileLayer() const { return mTileLayer; } /** * Returns the region of the current tile layer or the region that was set * using setTileRegion. */ inline QRegion BrushItem::tileRegion() const { return mRegion; } } // namespace Internal } // namespace Tiled #endif // BRUSHITEM_H tiled-0.14.2/src/tiled/bucketfilltool.cpp000066400000000000000000000254231260670167100203310ustar00rootroot00000000000000/* * bucketfilltool.cpp * Copyright 2009-2010, Jeff Bland * Copyright 2010, Thorbjørn Lindeijer * Copyright 2010, Jared Adams * Copyright 2011, Stefan Beller * * This file is part of Tiled. * * 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, see . */ #include "bucketfilltool.h" #include "addremovetileset.h" #include "brushitem.h" #include "tilepainter.h" #include "tile.h" #include "mapscene.h" #include "mapdocument.h" #include "painttilelayer.h" #include using namespace Tiled; using namespace Tiled::Internal; BucketFillTool::BucketFillTool(QObject *parent) : AbstractTileTool(tr("Bucket Fill Tool"), QIcon(QLatin1String( ":images/22x22/stock-tool-bucket-fill.png")), QKeySequence(tr("F")), parent) , mIsActive(false) , mLastShiftStatus(false) , mIsRandom(false) , mLastRandomStatus(false) { } BucketFillTool::~BucketFillTool() { } void BucketFillTool::activate(MapScene *scene) { AbstractTileTool::activate(scene); mIsActive = true; tilePositionChanged(tilePosition()); } void BucketFillTool::deactivate(MapScene *scene) { AbstractTileTool::deactivate(scene); mFillRegion = QRegion(); mIsActive = false; } static void fillWithStamp(TileLayer &layer, const TileStamp &stamp, const QRegion &mask) { const QSize size = stamp.maxSize(); // Fill the entire layer with random variations of the stamp for (int y = 0; y < layer.height(); y += size.height()) { for (int x = 0; x < layer.width(); x += size.width()) { const TileStampVariation variation = stamp.randomVariation(); layer.setCells(x, y, variation.tileLayer()); } } // Erase tiles outside of the masked region. This can easily be faster than // avoiding to place tiles outside of the region in the first place. layer.erase(QRegion(0, 0, layer.width(), layer.height()) - mask); } void BucketFillTool::tilePositionChanged(const QPoint &tilePos) { // Skip filling if the stamp is empty if (mStamp.isEmpty()) return; // Make sure that a tile layer is selected TileLayer *tileLayer = currentTileLayer(); if (!tileLayer) return; bool shiftPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier; bool fillRegionChanged = false; TilePainter regionComputer(mapDocument(), tileLayer); // If the stamp is a single tile, ignore it when making the region if (!shiftPressed && mStamp.variations().size() == 1) { const TileStampVariation &variation = mStamp.variations().first(); TileLayer *stampLayer = variation.tileLayer(); if (stampLayer->size() == QSize(1, 1) && stampLayer->cellAt(0, 0) == regionComputer.cellAt(tilePos)) return; } // This clears the connections so we don't get callbacks clearConnections(mapDocument()); // Optimization: we don't need to recalculate the fill area // if the new mouse position is still over the filled region // and the shift modifier hasn't changed. if (!mFillRegion.contains(tilePos) || shiftPressed != mLastShiftStatus) { // Clear overlay to make way for a new one clearOverlay(); // Cache information about how the fill region was created mLastShiftStatus = shiftPressed; // Get the new fill region if (!shiftPressed) { // If not holding shift, a region is generated from the current pos mFillRegion = regionComputer.computePaintableFillRegion(tilePos); } else { // If holding shift, the region is the selection bounds mFillRegion = mapDocument()->selectedArea(); // Fill region is the whole map if there is no selection if (mFillRegion.isEmpty()) mFillRegion = tileLayer->bounds(); // The mouse needs to be in the region if (!mFillRegion.contains(tilePos)) mFillRegion = QRegion(); } fillRegionChanged = true; } // Ensure that a fill region was created before making an overlay layer if (mFillRegion.isEmpty()) return; if (mLastRandomStatus != mIsRandom) { mLastRandomStatus = mIsRandom; fillRegionChanged = true; } if (!mFillOverlay) { // Create a new overlay region const QRect fillBounds = mFillRegion.boundingRect(); mFillOverlay = SharedTileLayer(new TileLayer(QString(), fillBounds.x(), fillBounds.y(), fillBounds.width(), fillBounds.height())); } // Paint the new overlay if (!mIsRandom) { if (fillRegionChanged || mStamp.variations().size() > 1) { fillWithStamp(*mFillOverlay, mStamp, mFillRegion.translated(-mFillOverlay->position())); fillRegionChanged = true; } } else { randomFill(*mFillOverlay, mFillRegion); fillRegionChanged = true; } if (fillRegionChanged) { // Update the brush item to draw the overlay brushItem()->setTileLayer(mFillOverlay); } // Create connections to know when the overlay should be cleared makeConnections(); } void BucketFillTool::mousePressed(QGraphicsSceneMouseEvent *event) { if (event->button() != Qt::LeftButton || mFillRegion.isEmpty()) return; if (!brushItem()->isVisible()) return; const TileLayer *preview = mFillOverlay.data(); if (!preview) return; PaintTileLayer *paint = new PaintTileLayer(mapDocument(), currentTileLayer(), preview->x(), preview->y(), preview); paint->setText(QCoreApplication::translate("Undo Commands", "Fill Area")); if (!mMissingTilesets.isEmpty()) { for (const SharedTileset &tileset : mMissingTilesets) new AddTileset(mapDocument(), tileset, paint); mMissingTilesets.clear(); } QRegion fillRegion(mFillRegion); mapDocument()->undoStack()->push(paint); mapDocument()->emitRegionEdited(fillRegion, currentTileLayer()); } void BucketFillTool::mouseReleased(QGraphicsSceneMouseEvent *) { } void BucketFillTool::modifiersChanged(Qt::KeyboardModifiers) { // Don't need to recalculate fill region if there was no fill region if (!mFillOverlay) return; tilePositionChanged(tilePosition()); } void BucketFillTool::languageChanged() { setName(tr("Bucket Fill Tool")); setShortcut(QKeySequence(tr("F"))); } void BucketFillTool::mapDocumentChanged(MapDocument *oldDocument, MapDocument *newDocument) { AbstractTileTool::mapDocumentChanged(oldDocument, newDocument); clearConnections(oldDocument); if (newDocument) updateRandomListAndMissingTilesets(); clearOverlay(); } void BucketFillTool::setStamp(const TileStamp &stamp) { // Clear any overlay that we presently have with an old stamp clearOverlay(); mStamp = stamp; updateRandomListAndMissingTilesets(); if (mIsActive && brushItem()->isVisible()) tilePositionChanged(tilePosition()); } void BucketFillTool::clearOverlay() { // Clear connections before clearing overlay so there is no // risk of getting a callback and causing an infinite loop clearConnections(mapDocument()); brushItem()->clear(); mFillOverlay.clear(); mFillRegion = QRegion(); } void BucketFillTool::makeConnections() { if (!mapDocument()) return; // Overlay may need to be cleared if a region changed connect(mapDocument(), &MapDocument::regionChanged, this, &BucketFillTool::clearOverlay); // Overlay needs to be cleared if we switch to another layer connect(mapDocument(), &MapDocument::currentLayerIndexChanged, this, &BucketFillTool::clearOverlay); // Overlay needs be cleared if the selection changes, since // the overlay may be bound or may need to be bound to the selection connect(mapDocument(), &MapDocument::selectedAreaChanged, this, &BucketFillTool::clearOverlay); } void BucketFillTool::clearConnections(MapDocument *mapDocument) { if (!mapDocument) return; disconnect(mapDocument, &MapDocument::regionChanged, this, &BucketFillTool::clearOverlay); disconnect(mapDocument, &MapDocument::currentLayerIndexChanged, this, &BucketFillTool::clearOverlay); disconnect(mapDocument, &MapDocument::selectedAreaChanged, this, &BucketFillTool::clearOverlay); } void BucketFillTool::setRandom(bool value) { if (mIsRandom == value) return; mIsRandom = value; updateRandomListAndMissingTilesets(); // Don't need to recalculate fill region if there was no fill region if (!mFillOverlay) return; tilePositionChanged(tilePosition()); } void BucketFillTool::randomFill(TileLayer &tileLayer, const QRegion ®ion) const { if (region.isEmpty() || mRandomCellPicker.isEmpty()) return; for (const QRect &rect : region.translated(-tileLayer.position()).rects()) { for (int _x = rect.left(); _x <= rect.right(); ++_x) { for (int _y = rect.top(); _y <= rect.bottom(); ++_y) { tileLayer.setCell(_x, _y, mRandomCellPicker.pick()); } } } } void BucketFillTool::updateRandomListAndMissingTilesets() { mRandomCellPicker.clear(); mMissingTilesets.clear(); for (const TileStampVariation &variation : mStamp.variations()) { mapDocument()->unifyTilesets(variation.map, mMissingTilesets); if (mIsRandom) { for (const Cell &cell : *variation.tileLayer()) { if (!cell.isEmpty()) mRandomCellPicker.add(cell, cell.tile->probability()); } } } } tiled-0.14.2/src/tiled/bucketfilltool.h000066400000000000000000000063541260670167100200000ustar00rootroot00000000000000/* * bucketfilltool.h * Copyright 2009-2010, Jeff Bland * Copyright 2010, Thorbjørn Lindeijer * Copyright 2011, Stefan Beller * * This file is part of Tiled. * * 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, see . */ #ifndef BUCKETFILLTOOL_H #define BUCKETFILLTOOL_H #include "abstracttiletool.h" #include "randompicker.h" #include "tilelayer.h" #include "tilestamp.h" namespace Tiled { namespace Internal { class MapDocument; /** * Implements a tool that bucket fills (flood fills) a region with a repeatable * stamp. */ class BucketFillTool : public AbstractTileTool { Q_OBJECT public: BucketFillTool(QObject *parent = nullptr); ~BucketFillTool(); void activate(MapScene *scene) override; void deactivate(MapScene *scene) override; void mousePressed(QGraphicsSceneMouseEvent *event) override; void mouseReleased(QGraphicsSceneMouseEvent *event) override; void modifiersChanged(Qt::KeyboardModifiers) override; void languageChanged() override; /** * Sets the stamp that is drawn when filling. */ void setStamp(const TileStamp &stamp); /** * This returns the current stamp used for filling. */ const TileStamp &stamp() const { return mStamp; } public slots: void setRandom(bool value); protected: void tilePositionChanged(const QPoint &tilePos) override; void mapDocumentChanged(MapDocument *oldDocument, MapDocument *newDocument) override; private slots: void clearOverlay(); private: void makeConnections(); void clearConnections(MapDocument *mapDocument); TileStamp mStamp; SharedTileLayer mFillOverlay; QRegion mFillRegion; QVector mMissingTilesets; bool mIsActive; bool mLastShiftStatus; /** * Indicates if the tool is using the random mode. */ bool mIsRandom; /** * Contains the value of mIsRandom at that time, when the latest call of * tilePositionChanged() took place. * This variable is needed to detect if the random mode was changed during * mFillOverlay being brushed at an area. */ bool mLastRandomStatus; RandomPicker mRandomCellPicker; /** * Updates the list of random cells. * This is done by taking all non-null tiles from the original stamp mStamp. */ void updateRandomListAndMissingTilesets(); /** * Fills the given \a region in the given \a tileLayer with random tiles. */ void randomFill(TileLayer &tileLayer, const QRegion ®ion) const; }; } // namespace Internal } // namespace Tiled #endif // BUCKETFILLTOOL_H tiled-0.14.2/src/tiled/changeimagelayerposition.cpp000066400000000000000000000031411260670167100223520ustar00rootroot00000000000000/* * changeimagelayerposition.cpp * Copyright 2014, Michael Aquilina * * This file is part of Tiled. * * 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, see . */ #include "changeimagelayerposition.h" #include "mapdocument.h" #include "imagelayer.h" #include using namespace Tiled; using namespace Tiled::Internal; ChangeImageLayerPosition::ChangeImageLayerPosition( MapDocument *mapDocument, ImageLayer *imageLayer, const QPoint &newPos) : QUndoCommand( QCoreApplication::translate( "Undo Commands", "Change Image Layer Position")) , mMapDocument(mapDocument) , mImageLayer(imageLayer) , mUndoPos(imageLayer->position()) , mRedoPos(newPos) { } void ChangeImageLayerPosition::redo() { mImageLayer->setPosition(mRedoPos); mMapDocument->emitImageLayerChanged(mImageLayer); } void ChangeImageLayerPosition::undo() { mImageLayer->setPosition(mUndoPos); mMapDocument->emitImageLayerChanged(mImageLayer); } tiled-0.14.2/src/tiled/changeimagelayerposition.h000066400000000000000000000033071260670167100220230ustar00rootroot00000000000000/* * changeimagelayerproperties.h * Copyright 2014, Michael Aquilina * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGEIMAGELAYERPOSITION_H #define CHANGEIMAGELAYERPOSITION_H #include #include namespace Tiled { class ImageLayer; namespace Internal { class MapDocument; class ChangeImageLayerPosition : public QUndoCommand { public: /** * Constructs a new 'Change Image Layer Position' command. * * @param mapDocument the map document of the layer's map * @param imageLayer the image layer to modify * @param newPos the new position of the image layer */ ChangeImageLayerPosition(MapDocument *mapDocument, ImageLayer *imageLayer, const QPoint &newPos); void undo() override; void redo() override; private: MapDocument *mMapDocument; ImageLayer *mImageLayer; const QPoint mUndoPos; const QPoint mRedoPos; }; } // namespace Internal } // namespace Tiled #endif // CHANGEIMAGELAYERPOSITION_H tiled-0.14.2/src/tiled/changeimagelayerproperties.cpp000066400000000000000000000041651260670167100227110ustar00rootroot00000000000000/* * changeimagelayerproperties.cpp * Copyright 2010, Jeff Bland * Copyright 2010, Thorbjørn Lindeijer * Copyright 2011, Gregory Nickonov * * This file is part of Tiled. * * 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, see . */ #include "changeimagelayerproperties.h" #include "mapdocument.h" #include "imagelayer.h" #include using namespace Tiled; using namespace Tiled::Internal; ChangeImageLayerProperties::ChangeImageLayerProperties( MapDocument *mapDocument, ImageLayer *imageLayer, const QColor &color, const QString &path) : QUndoCommand( QCoreApplication::translate( "Undo Commands", "Change Image Layer Properties")) , mMapDocument(mapDocument) , mImageLayer(imageLayer) , mUndoColor(imageLayer->transparentColor()) , mRedoColor(color) , mUndoPath(imageLayer->imageSource()) , mRedoPath(path) { } void ChangeImageLayerProperties::redo() { mImageLayer->setTransparentColor(mRedoColor); if (mRedoPath.isEmpty()) mImageLayer->resetImage(); else mImageLayer->loadFromImage(QImage(mRedoPath), mRedoPath); mMapDocument->emitImageLayerChanged(mImageLayer); } void ChangeImageLayerProperties::undo() { mImageLayer->setTransparentColor(mUndoColor); if (mUndoPath.isEmpty()) mImageLayer->resetImage(); else mImageLayer->loadFromImage(QImage(mUndoPath), mUndoPath); mMapDocument->emitImageLayerChanged(mImageLayer); } tiled-0.14.2/src/tiled/changeimagelayerproperties.h000066400000000000000000000040111260670167100223440ustar00rootroot00000000000000/* * changeimagelayerproperties.h * Copyright 2010, Jeff Bland * Copyright 2010, Thorbjørn Lindeijer * Copyright 2011, Gregory Nickonov * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGEIMAGELAYERPROPERTIES_H #define CHANGEIMAGELAYERPROPERTIES_H #include #include #include namespace Tiled { class ImageLayer; namespace Internal { class MapDocument; class ChangeImageLayerProperties : public QUndoCommand { public: /** * Constructs a new 'Change Image Layer Properties' command. * * @param mapDocument the map document of the layer's map * @param imageLayer the image layer to modify * @param newColor the new transparent color to apply * @param newPath the new image source to apply */ ChangeImageLayerProperties(MapDocument *mapDocument, ImageLayer *imageLayer, const QColor &newColor, const QString &newPath); void undo() override; void redo() override; private: MapDocument *mMapDocument; ImageLayer *mImageLayer; const QColor mUndoColor; const QColor mRedoColor; const QString mUndoPath; const QString mRedoPath; }; } // namespace Internal } // namespace Tiled #endif // CHANGEIMAGELAYERPROPERTIES_H tiled-0.14.2/src/tiled/changelayer.cpp000066400000000000000000000062221260670167100175650ustar00rootroot00000000000000/* * changelayer.cpp * Copyright 2012-2013, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changelayer.h" #include "layer.h" #include "layermodel.h" #include "map.h" #include "mapdocument.h" #include namespace Tiled { namespace Internal { SetLayerVisible::SetLayerVisible(MapDocument *mapDocument, int layerIndex, bool visible) : mMapDocument(mapDocument) , mLayerIndex(layerIndex) , mVisible(visible) { if (visible) setText(QCoreApplication::translate("Undo Commands", "Show Layer")); else setText(QCoreApplication::translate("Undo Commands", "Hide Layer")); } void SetLayerVisible::swap() { const Layer *layer = mMapDocument->map()->layerAt(mLayerIndex); const bool previousVisible = layer->isVisible(); mMapDocument->layerModel()->setLayerVisible(mLayerIndex, mVisible); mVisible = previousVisible; } SetLayerOpacity::SetLayerOpacity(MapDocument *mapDocument, int layerIndex, float opacity) : mMapDocument(mapDocument) , mLayerIndex(layerIndex) , mOldOpacity(mMapDocument->map()->layerAt(layerIndex)->opacity()) , mNewOpacity(opacity) { setText(QCoreApplication::translate("Undo Commands", "Change Layer Opacity")); } bool SetLayerOpacity::mergeWith(const QUndoCommand *other) { const SetLayerOpacity *o = static_cast(other); if (!(mMapDocument == o->mMapDocument && mLayerIndex == o->mLayerIndex)) return false; mNewOpacity = o->mNewOpacity; return true; } void SetLayerOpacity::setOpacity(float opacity) { mMapDocument->layerModel()->setLayerOpacity(mLayerIndex, opacity); } SetLayerOffset::SetLayerOffset(MapDocument *mapDocument, int layerIndex, const QPointF &offset) : mMapDocument(mapDocument) , mLayerIndex(layerIndex) , mOldOffset(mMapDocument->map()->layerAt(layerIndex)->offset()) , mNewOffset(offset) { setText(QCoreApplication::translate("Undo Commands", "Change Layer Offset")); } void SetLayerOffset::setOffset(const QPointF &offset) { mMapDocument->layerModel()->setLayerOffset(mLayerIndex, offset); } } // namespace Internal } // namespace Tiled tiled-0.14.2/src/tiled/changelayer.h000066400000000000000000000050031260670167100172260ustar00rootroot00000000000000/* * changelayer.h * Copyright 2012-2013, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGELAYER_H #define CHANGELAYER_H #include "undocommands.h" #include #include namespace Tiled { namespace Internal { class MapDocument; /** * Used for changing layer visibility. */ class SetLayerVisible : public QUndoCommand { public: SetLayerVisible(MapDocument *mapDocument, int layerIndex, bool visible); void undo() override { swap(); } void redo() override { swap(); } private: void swap(); MapDocument *mMapDocument; int mLayerIndex; bool mVisible; }; /** * Used for changing layer opacity. */ class SetLayerOpacity : public QUndoCommand { public: SetLayerOpacity(MapDocument *mapDocument, int layerIndex, float opacity); void undo() override { setOpacity(mOldOpacity); } void redo() override { setOpacity(mNewOpacity); } int id() const override { return Cmd_ChangeLayerOpacity; } bool mergeWith(const QUndoCommand *other) override; private: void setOpacity(float opacity); MapDocument *mMapDocument; int mLayerIndex; float mOldOpacity; float mNewOpacity; }; /** * Used for changing the layer offset. */ class SetLayerOffset : public QUndoCommand { public: SetLayerOffset(MapDocument *mapDocument, int layerIndex, const QPointF &offset); void undo() override { setOffset(mOldOffset); } void redo() override { setOffset(mNewOffset); } int id() const override { return Cmd_ChangeLayerOffset; } private: void setOffset(const QPointF &offset); MapDocument *mMapDocument; int mLayerIndex; QPointF mOldOffset; QPointF mNewOffset; }; } // namespace Internal } // namespace Tiled #endif // CHANGELAYER_H tiled-0.14.2/src/tiled/changemapobject.cpp000066400000000000000000000047531260670167100204240ustar00rootroot00000000000000/* * changemapobject.cpp * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changemapobject.h" #include "mapdocument.h" #include "mapobject.h" #include "mapobjectmodel.h" #include using namespace Tiled; using namespace Tiled::Internal; ChangeMapObject::ChangeMapObject(MapDocument *mapDocument, MapObject *mapObject, const QString &name, const QString &type) : QUndoCommand(QCoreApplication::translate("Undo Commands", "Change Object")) , mMapDocument(mapDocument) , mMapObject(mapObject) , mName(name) , mType(type) { } void ChangeMapObject::swap() { const QString name = mMapObject->name(); const QString type = mMapObject->type(); mMapDocument->mapObjectModel()->setObjectName(mMapObject, mName); mMapDocument->mapObjectModel()->setObjectType(mMapObject, mType); mName = name; mType = type; } SetMapObjectVisible::SetMapObjectVisible(MapDocument *mapDocument, MapObject *mapObject, bool visible) : mMapObjectModel(mapDocument->mapObjectModel()) , mMapObject(mapObject) , mOldVisible(mapObject->isVisible()) , mNewVisible(visible) { if (visible) setText(QCoreApplication::translate("Undo Commands", "Show Object")); else setText(QCoreApplication::translate("Undo Commands", "Hide Object")); } void SetMapObjectVisible::undo() { mMapObjectModel->setObjectVisible(mMapObject, mOldVisible); } void SetMapObjectVisible::redo() { mMapObjectModel->setObjectVisible(mMapObject, mNewVisible); } tiled-0.14.2/src/tiled/changemapobject.h000066400000000000000000000036711260670167100200670ustar00rootroot00000000000000/* * changemapobject.h * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGEMAPOBJECT_H #define CHANGEMAPOBJECT_H #include namespace Tiled { class MapObject; namespace Internal { class MapDocument; class MapObjectModel; class ChangeMapObject : public QUndoCommand { public: /** * Creates an undo command that sets the given \a object's \a name and * \a type. */ ChangeMapObject(MapDocument *mapDocument, MapObject *object, const QString &name, const QString &type); void undo() override { swap(); } void redo() override { swap(); } private: void swap(); MapDocument *mMapDocument; MapObject *mMapObject; QString mName; QString mType; }; /** * Used for changing object visibility. */ class SetMapObjectVisible : public QUndoCommand { public: SetMapObjectVisible(MapDocument *mapDocument, MapObject *mapObject, bool visible); void undo() override; void redo() override; private: MapObjectModel *mMapObjectModel; MapObject *mMapObject; bool mOldVisible; bool mNewVisible; }; } // namespace Internal } // namespace Tiled #endif // CHANGEMAPOBJECT_H tiled-0.14.2/src/tiled/changemapobjectsorder.cpp000066400000000000000000000042411260670167100216330ustar00rootroot00000000000000/* * changemapobjectsorder.cpp * Copyright 2013, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changemapobjectsorder.h" #include "mapdocument.h" #include "mapobjectmodel.h" #include "objectgroup.h" #include using namespace Tiled; using namespace Tiled::Internal; ChangeMapObjectsOrder::ChangeMapObjectsOrder(MapDocument *mapDocument, ObjectGroup *objectGroup, int from, int to, int count) : mMapDocument(mapDocument) , mObjectGroup(objectGroup) , mFrom(from) , mTo(to) , mCount(count) { if (mTo > mFrom) setText(QCoreApplication::translate("Undo Commands", "Raise Object")); else setText(QCoreApplication::translate("Undo Commands", "Lower Object")); } void ChangeMapObjectsOrder::undo() { int to = mFrom; int from = mTo; // When reversing the operation, either the 'from' or the 'to' index will // need to be adapted to take into account the number of objects moved. if (from > to) from -= mCount; else to += mCount; mMapDocument->mapObjectModel()->moveObjects(mObjectGroup, from, to, mCount); } void ChangeMapObjectsOrder::redo() { mMapDocument->mapObjectModel()->moveObjects(mObjectGroup, mFrom, mTo, mCount); } tiled-0.14.2/src/tiled/changemapobjectsorder.h000066400000000000000000000027061260670167100213040ustar00rootroot00000000000000/* * changemapobjectsorder.h * Copyright 2013, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGEMAPOBJECTSORDER_H #define CHANGEMAPOBJECTSORDER_H #include namespace Tiled { class ObjectGroup; namespace Internal { class MapDocument; class ChangeMapObjectsOrder : public QUndoCommand { public: ChangeMapObjectsOrder(MapDocument *mapDocument, ObjectGroup *objectGroup, int from, int to, int count); void undo() override; void redo() override; private: MapDocument *mMapDocument; ObjectGroup *mObjectGroup; int mFrom; int mTo; int mCount; }; } // namespace Internal } // namespace Tiled #endif // CHANGEMAPOBJECTSORDER_H tiled-0.14.2/src/tiled/changemapproperty.cpp000066400000000000000000000135471260670167100210430ustar00rootroot00000000000000/* * changemapproperty.cpp * Copyright 2012, Emmanuel Barroga emmanuelbarroga@gmail.com * * This file is part of Tiled. * * 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, see . */ #include "changemapproperty.h" #include "map.h" #include "mapdocument.h" #include "objectgroup.h" #include using namespace Tiled; using namespace Tiled::Internal; ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument, ChangeMapProperty::Property property, int value) : mMapDocument(mapDocument) , mProperty(property) , mIntValue(value) { switch (property) { case TileWidth: setText(QCoreApplication::translate("Undo Commands", "Change Tile Width")); break; case TileHeight: setText(QCoreApplication::translate("Undo Commands", "Change Tile Height")); break; case HexSideLength: setText(QCoreApplication::translate("Undo Commands", "Change Hex Side Length")); break; default: break; } } ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument, const QColor &backgroundColor) : QUndoCommand(QCoreApplication::translate("Undo Commands", "Change Background Color")) , mMapDocument(mapDocument) , mProperty(BackgroundColor) , mBackgroundColor(backgroundColor) { } ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument, Map::StaggerAxis staggerAxis) : QUndoCommand(QCoreApplication::translate("Undo Commands", "Change Stagger Axis")) , mMapDocument(mapDocument) , mProperty(StaggerAxis) , mStaggerAxis(staggerAxis) { } ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument, Map::StaggerIndex staggerIndex) : QUndoCommand(QCoreApplication::translate("Undo Commands", "Change Stagger Index")) , mMapDocument(mapDocument) , mProperty(StaggerIndex) , mStaggerIndex(staggerIndex) { } ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument, Map::Orientation orientation) : QUndoCommand(QCoreApplication::translate("Undo Commands", "Change Orientation")) , mMapDocument(mapDocument) , mProperty(Orientation) , mOrientation(orientation) { } ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument, Map::RenderOrder renderOrder) : QUndoCommand(QCoreApplication::translate("Undo Commands", "Change Render Order")) , mMapDocument(mapDocument) , mProperty(RenderOrder) , mRenderOrder(renderOrder) { } ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument, Map::LayerDataFormat layerDataFormat) : QUndoCommand(QCoreApplication::translate("Undo Commands", "Change Layer Data Format")) , mMapDocument(mapDocument) , mProperty(LayerDataFormat) , mLayerDataFormat(layerDataFormat) { } void ChangeMapProperty::redo() { swap(); } void ChangeMapProperty::undo() { swap(); } void ChangeMapProperty::swap() { Map *map = mMapDocument->map(); switch (mProperty) { case TileWidth: { const int tileWidth = map->tileWidth(); map->setTileWidth(mIntValue); mIntValue = tileWidth; break; } case TileHeight: { const int tileHeight = map->tileHeight(); map->setTileHeight(mIntValue); mIntValue = tileHeight; break; } case Orientation: { const Map::Orientation orientation = map->orientation(); map->setOrientation(mOrientation); mOrientation = orientation; mMapDocument->createRenderer(); break; } case HexSideLength: { const int hexSideLength = map->hexSideLength(); map->setHexSideLength(mIntValue); mIntValue = hexSideLength; break; } case StaggerAxis: { const Map::StaggerAxis staggerAxis = map->staggerAxis(); map->setStaggerAxis(mStaggerAxis); mStaggerAxis = staggerAxis; break; } case StaggerIndex: { const Map::StaggerIndex staggerIndex = map->staggerIndex(); map->setStaggerIndex(mStaggerIndex); mStaggerIndex = staggerIndex; break; } case RenderOrder: { const Map::RenderOrder renderOrder = map->renderOrder(); map->setRenderOrder(mRenderOrder); mRenderOrder = renderOrder; break; } case BackgroundColor: { const QColor backgroundColor = map->backgroundColor(); map->setBackgroundColor(mBackgroundColor); mBackgroundColor = backgroundColor; break; } case LayerDataFormat: { const Map::LayerDataFormat layerDataFormat = map->layerDataFormat(); map->setLayerDataFormat(mLayerDataFormat); mLayerDataFormat = layerDataFormat; break; } } mMapDocument->emitMapChanged(); } tiled-0.14.2/src/tiled/changemapproperty.h000066400000000000000000000073621260670167100205060ustar00rootroot00000000000000/* * changemapproperty.h * Copyright 2012, Emmanuel Barroga emmanuelbarroga@gmail.com * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGEMAPPROPERTY_H #define CHANGEMAPPROPERTY_H #include "map.h" #include #include namespace Tiled { namespace Internal { class MapDocument; class ChangeMapProperty : public QUndoCommand { public: enum Property { TileWidth, TileHeight, HexSideLength, StaggerAxis, StaggerIndex, Orientation, RenderOrder, BackgroundColor, LayerDataFormat }; /** * Constructs a command that changes the value of the given property. * * Can only be used for the HexSideLength property. * * @param mapDocument the map document of the map * @param backgroundColor the new color to apply for the background */ ChangeMapProperty(MapDocument *mapDocument, Property property, int value); /** * Constructs a command that changes the map background color. * * @param mapDocument the map document of the map * @param backgroundColor the new color to apply for the background */ ChangeMapProperty(MapDocument *mapDocument, const QColor &backgroundColor); /** * Constructs a command that changes the map stagger axis. * * @param mapDocument the map document of the map * @param orientation the new map stagger axis */ ChangeMapProperty(MapDocument *mapDocument, Map::StaggerAxis staggerAxis); /** * Constructs a command that changes the map stagger index. * * @param mapDocument the map document of the map * @param orientation the new map stagger index */ ChangeMapProperty(MapDocument *mapDocument, Map::StaggerIndex staggerIndex); /** * Constructs a command that changes the map orientation. * * @param mapDocument the map document of the map * @param orientation the new map orientation */ ChangeMapProperty(MapDocument *mapDocument, Map::Orientation orientation); /** * Constructs a command that changes the render order. * * @param mapDocument the map document of the map * @param renderOrder the new map render order */ ChangeMapProperty(MapDocument *mapDocument, Map::RenderOrder renderOrder); /** * Constructs a command that changes the layer data format. * * @param mapDocument the map document of the map * @param layerDataFormat the new layer data format */ ChangeMapProperty(MapDocument *mapDocument, Map::LayerDataFormat layerDataFormat); void undo() override; void redo() override; private: void swap(); MapDocument *mMapDocument; Property mProperty; QColor mBackgroundColor; union { int mIntValue; Map::StaggerAxis mStaggerAxis; Map::StaggerIndex mStaggerIndex; Map::Orientation mOrientation; Map::RenderOrder mRenderOrder; Map::LayerDataFormat mLayerDataFormat; }; }; } // namespace Internal } // namespace Tiled #endif // CHANGEMAPPROPERTY_H tiled-0.14.2/src/tiled/changeobjectgroupproperties.cpp000066400000000000000000000036611260670167100231150ustar00rootroot00000000000000/* * changeobjectgroupproperties.cpp * Copyright 2010, Jeff Bland * Copyright 2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changeobjectgroupproperties.h" #include "mapdocument.h" #include "objectgroup.h" #include "mapobjectmodel.h" #include using namespace Tiled; using namespace Tiled::Internal; ChangeObjectGroupProperties::ChangeObjectGroupProperties( MapDocument *mapDocument, ObjectGroup *objectGroup, const QColor &newColor, ObjectGroup::DrawOrder newDrawOrder) : QUndoCommand( QCoreApplication::translate( "Undo Commands", "Change Object Layer Properties")) , mMapDocument(mapDocument) , mObjectGroup(objectGroup) , mUndoColor(objectGroup->color()) , mRedoColor(newColor) , mUndoDrawOrder(objectGroup->drawOrder()) , mRedoDrawOrder(newDrawOrder) { } void ChangeObjectGroupProperties::redo() { mObjectGroup->setColor(mRedoColor); mObjectGroup->setDrawOrder(mRedoDrawOrder); mMapDocument->emitObjectGroupChanged(mObjectGroup); } void ChangeObjectGroupProperties::undo() { mObjectGroup->setColor(mUndoColor); mObjectGroup->setDrawOrder(mUndoDrawOrder); mMapDocument->emitObjectGroupChanged(mObjectGroup); } tiled-0.14.2/src/tiled/changeobjectgroupproperties.h000066400000000000000000000037041260670167100225600ustar00rootroot00000000000000/* * changeobjectgroupproperties.h * Copyright 2010, Jeff Bland * Copyright 2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGEOBJECTGROUPPROPERTIES_H #define CHANGEOBJECTGROUPPROPERTIES_H #include "objectgroup.h" #include #include namespace Tiled { namespace Internal { class MapDocument; class ChangeObjectGroupProperties : public QUndoCommand { public: /** * Constructs a new 'Change Object Layer Properties' command. * * @param mapDocument the map document of the object group's map * @param objectGroup the object group in to modify * @param newColor the new color to apply */ ChangeObjectGroupProperties(MapDocument *mapDocument, ObjectGroup *objectGroup, const QColor &newColor, ObjectGroup::DrawOrder newDrawOrder); void undo() override; void redo() override; private: MapDocument *mMapDocument; ObjectGroup *mObjectGroup; const QColor mUndoColor; const QColor mRedoColor; ObjectGroup::DrawOrder mUndoDrawOrder; ObjectGroup::DrawOrder mRedoDrawOrder; }; } // namespace Internal } // namespace Tiled #endif // CHANGEOBJECTGROUPPROPERTIES_H tiled-0.14.2/src/tiled/changepolygon.cpp000066400000000000000000000037041260670167100201420ustar00rootroot00000000000000/* * changepolygon.cpp * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changepolygon.h" #include "mapdocument.h" #include "mapobject.h" #include "mapobjectmodel.h" #include using namespace Tiled; using namespace Tiled::Internal; ChangePolygon::ChangePolygon(MapDocument *mapDocument, MapObject *mapObject, const QPolygonF &oldPolygon) : mMapDocument(mapDocument) , mMapObject(mapObject) , mOldPolygon(oldPolygon) , mNewPolygon(mapObject->polygon()) { setText(QCoreApplication::translate("Undo Commands", "Change Polygon")); } ChangePolygon::ChangePolygon(MapDocument *mapDocument, MapObject *mapObject, const QPolygonF &newPolygon, const QPolygonF &oldPolygon) : mMapDocument(mapDocument) , mMapObject(mapObject) , mOldPolygon(oldPolygon) , mNewPolygon(newPolygon) { setText(QCoreApplication::translate("Undo Commands", "Change Polygon")); } void ChangePolygon::undo() { mMapDocument->mapObjectModel()->setObjectPolygon(mMapObject, mOldPolygon); } void ChangePolygon::redo() { mMapDocument->mapObjectModel()->setObjectPolygon(mMapObject, mNewPolygon); } tiled-0.14.2/src/tiled/changepolygon.h000066400000000000000000000032751260670167100176120ustar00rootroot00000000000000/* * changepolygon.h * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGEPOLYGON_H #define CHANGEPOLYGON_H #include #include namespace Tiled { class MapObject; namespace Internal { class MapDocument; /** * Changes the polygon of a MapObject. * * This class expects the polygon to be already changed, and takes the previous * polygon in the constructor. */ class ChangePolygon : public QUndoCommand { public: ChangePolygon(MapDocument *mapDocument, MapObject *mapObject, const QPolygonF &oldPolygon); ChangePolygon(MapDocument *mapDocument, MapObject *mapObject, const QPolygonF &newPolygon, const QPolygonF &oldPolygon); void undo() override; void redo() override; private: MapDocument *mMapDocument; MapObject *mMapObject; QPolygonF mOldPolygon; QPolygonF mNewPolygon; }; } // namespace Internal } // namespace Tiled #endif // CHANGEPOLYGON_H tiled-0.14.2/src/tiled/changeproperties.cpp000066400000000000000000000106611260670167100206470ustar00rootroot00000000000000/* * changeproperties.cpp * Copyright 2008-2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changeproperties.h" #include "mapdocument.h" #include using namespace Tiled; using namespace Tiled::Internal; ChangeProperties::ChangeProperties(MapDocument *mapDocument, const QString &kind, Object *object, const Properties &newProperties) : mMapDocument(mapDocument) , mObject(object) , mNewProperties(newProperties) { setText(QCoreApplication::translate("Undo Commands", "Change %1 Properties").arg(kind)); } void ChangeProperties::redo() { swapProperties(); } void ChangeProperties::undo() { swapProperties(); } void ChangeProperties::swapProperties() { const Properties oldProperties = mObject->properties(); mMapDocument->setProperties(mObject, mNewProperties); mNewProperties = oldProperties; } SetProperty::SetProperty(MapDocument *mapDocument, const QList &objects, const QString &name, const QString &value, QUndoCommand *parent) : QUndoCommand(parent) , mMapDocument(mapDocument) , mObjects(objects) , mName(name) , mValue(value) { foreach (Object *obj, mObjects) { ObjectProperty prop; prop.existed = obj->hasProperty(mName); prop.previousValue = obj->property(mName); mProperties.append(prop); } if (mObjects.size() > 1 || mObjects[0]->hasProperty(mName)) setText(QCoreApplication::translate("Undo Commands", "Set Property")); else setText(QCoreApplication::translate("Undo Commands", "Add Property")); } void SetProperty::undo() { for (int i = 0; i < mObjects.size(); ++i) { if (mProperties[i].existed) mMapDocument->setProperty(mObjects[i], mName, mProperties[i].previousValue); else mMapDocument->removeProperty(mObjects[i], mName); } } void SetProperty::redo() { foreach (Object *obj, mObjects) mMapDocument->setProperty(obj, mName, mValue); } RemoveProperty::RemoveProperty(MapDocument *mapDocument, const QList &objects, const QString &name, QUndoCommand *parent) : QUndoCommand(parent) , mMapDocument(mapDocument) , mObjects(objects) , mName(name) { foreach (Object *obj, mObjects) mPreviousValues.append(obj->property(mName)); setText(QCoreApplication::translate("Undo Commands", "Remove Property")); } void RemoveProperty::undo() { for (int i = 0; i < mObjects.size(); ++i) mMapDocument->setProperty(mObjects[i], mName, mPreviousValues[i]); } void RemoveProperty::redo() { foreach (Object *obj, mObjects) mMapDocument->removeProperty(obj, mName); } RenameProperty::RenameProperty(MapDocument *mapDocument, const QList &objects, const QString &oldName, const QString &newName) { setText(QCoreApplication::translate("Undo Commands", "Rename Property")); // Remove the old name from all objects new RemoveProperty(mapDocument, objects, oldName, this); // Different objects may have different values for the same property, // or may not have a value at all. foreach (Object *object, objects) { if (!object->hasProperty(oldName)) continue; QList objects; objects.append(object); const QString value = object->property(oldName); new SetProperty(mapDocument, objects, newName, value, this); } } tiled-0.14.2/src/tiled/changeproperties.h000066400000000000000000000076471260670167100203260ustar00rootroot00000000000000/* * changeproperties.h * Copyright 2008-2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGEPROPERTIES_H #define CHANGEPROPERTIES_H #include "object.h" #include #include #include namespace Tiled { namespace Internal { class MapDocument; class ChangeProperties : public QUndoCommand { public: /** * Constructs a new 'Change Properties' command. * * @param mapDocument the map document of the object's map * @param kind the kind of properties (Map, Layer, Object, etc.) * @param object the object of which the properties should be changed * @param newProperties the new properties that should be applied */ ChangeProperties(MapDocument *mapDocument, const QString &kind, Object *object, const Properties &newProperties); void undo() override; void redo() override; private: void swapProperties(); MapDocument *mMapDocument; Object *mObject; Properties mNewProperties; }; class SetProperty : public QUndoCommand { public: /** * Constructs a new 'Set Property' command. * * @param mapDocument the map document of the object's map * @param objects the objects of which the property should be changed * @param name the name of the property to be changed * @param value the new value of the property */ SetProperty(MapDocument *mapDocument, const QList &objects, const QString &name, const QString &value, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: struct ObjectProperty { QString previousValue; bool existed; }; QVector mProperties; MapDocument *mMapDocument; QList mObjects; QString mName; QString mValue; }; class RemoveProperty : public QUndoCommand { public: /** * Constructs a new 'Remove Property' command. * * @param mapDocument the map document of the object's map * @param objects the objects from which the property should be removed * @param name the name of the property to be removed */ RemoveProperty(MapDocument *mapDocument, const QList &objects, const QString &name, QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: MapDocument *mMapDocument; QList mObjects; QVector mPreviousValues; QString mName; }; class RenameProperty : public QUndoCommand { public: /** * Constructs a new 'Rename Property' command. * * @param mapDocument the map document of the object's map * @param object the object of which the property should be renamed * @param oldName the old name of the property * @param newName the new name of the property */ RenameProperty(MapDocument *mapDocument, const QList &objects, const QString &oldName, const QString &newName); }; } // namespace Internal } // namespace Tiled #endif // CHANGEPROPERTIES_H tiled-0.14.2/src/tiled/changeselectedarea.cpp000066400000000000000000000030111260670167100210630ustar00rootroot00000000000000/* * changeselectedarea.cpp * Copyright 2009-2010, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changeselectedarea.h" #include "mapdocument.h" #include using namespace Tiled::Internal; ChangeSelectedArea::ChangeSelectedArea(MapDocument *mapDocument, const QRegion &newSelection) : QUndoCommand(QCoreApplication::translate("Undo Commands", "Change Selection")) , mMapDocument(mapDocument) , mSelection(newSelection) { } void ChangeSelectedArea::undo() { swapSelection(); } void ChangeSelectedArea::redo() { swapSelection(); } void ChangeSelectedArea::swapSelection() { const QRegion oldSelection = mMapDocument->selectedArea(); mMapDocument->setSelectedArea(mSelection); mSelection = oldSelection; } tiled-0.14.2/src/tiled/changeselectedarea.h000066400000000000000000000026471260670167100205460ustar00rootroot00000000000000/* * changeselectedarea.h * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGESELECTEDAREA_H #define CHANGESELECTEDAREA_H #include #include namespace Tiled { namespace Internal { class MapDocument; class ChangeSelectedArea: public QUndoCommand { public: /** * Creates an undo command that sets the selection of \a mapDocument to * the given \a selection. */ ChangeSelectedArea(MapDocument *mapDocument, const QRegion &selection); void undo() override; void redo() override; private: void swapSelection(); MapDocument *mMapDocument; QRegion mSelection; }; } // namespace Internal } // namespace Tiled #endif // CHANGESELECTEDAREA_H tiled-0.14.2/src/tiled/changetileanimation.cpp000066400000000000000000000027741260670167100213160ustar00rootroot00000000000000/* * changetileanimation.cpp * Copyright 2014, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changetileanimation.h" #include "mapdocument.h" #include namespace Tiled { namespace Internal { ChangeTileAnimation::ChangeTileAnimation(MapDocument *mapDocument, Tile *tile, const QVector &frames) : QUndoCommand(QCoreApplication::translate( "Undo Commands", "Change Tile Animation")) , mMapDocument(mapDocument) , mTile(tile) , mFrames(frames) { } void ChangeTileAnimation::swap() { const QVector frames = mTile->frames(); mTile->setFrames(mFrames); mFrames = frames; mMapDocument->emitTileAnimationChanged(mTile); } } // namespace Internal } // namespace Tiled tiled-0.14.2/src/tiled/changetileanimation.h000066400000000000000000000026521260670167100207560ustar00rootroot00000000000000/* * changetileanimation.h * Copyright 2014, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef TILED_INTERNAL_CHANGETILEANIMATION_H #define TILED_INTERNAL_CHANGETILEANIMATION_H #include "tile.h" #include namespace Tiled { namespace Internal { class MapDocument; class ChangeTileAnimation : public QUndoCommand { public: ChangeTileAnimation(MapDocument *mapDocument, Tile *tile, const QVector &frames); void undo() override { swap(); } void redo() override { swap(); } private: void swap(); MapDocument *mMapDocument; Tile *mTile; QVector mFrames; }; } // namespace Internal } // namespace Tiled #endif // TILED_INTERNAL_CHANGETILEANIMATION_H tiled-0.14.2/src/tiled/changetileobjectgroup.cpp000066400000000000000000000015171260670167100216540ustar00rootroot00000000000000#include "changetileobjectgroup.h" #include "mapdocument.h" #include "objectgroup.h" #include "tile.h" #include namespace Tiled { namespace Internal { ChangeTileObjectGroup::ChangeTileObjectGroup(MapDocument *mapDocument, Tile *tile, ObjectGroup *objectGroup) : QUndoCommand(QCoreApplication::translate( "Undo Commands", "Change Tile Collision")) , mMapDocument(mapDocument) , mTile(tile) , mObjectGroup(objectGroup) { } ChangeTileObjectGroup::~ChangeTileObjectGroup() { delete mObjectGroup; } void ChangeTileObjectGroup::swap() { mObjectGroup = mTile->swapObjectGroup(mObjectGroup); mMapDocument->emitTileObjectGroupChanged(mTile); } } // namespace Internal } // namespace Tiled tiled-0.14.2/src/tiled/changetileobjectgroup.h000066400000000000000000000015011260670167100213120ustar00rootroot00000000000000#ifndef CHANGETILEOBJECTGROUP_H #define CHANGETILEOBJECTGROUP_H #include namespace Tiled { class ObjectGroup; class Tile; namespace Internal { class MapDocument; class ChangeTileObjectGroup : public QUndoCommand { public: /** * Creates a command that changes the ObjectGroup of the given \a tile. The * command takes ownership of the \a objectGroup. */ ChangeTileObjectGroup(MapDocument *mapDocument, Tile *tile, ObjectGroup *objectGroup); ~ChangeTileObjectGroup(); void undo() override { swap(); } void redo() override { swap(); } private: void swap(); MapDocument *mMapDocument; Tile *mTile; ObjectGroup *mObjectGroup; }; } // namespace Internal } // namespace Tiled #endif // CHANGETILEOBJECTGROUP_H tiled-0.14.2/src/tiled/changetileprobability.cpp000066400000000000000000000030741260670167100216510ustar00rootroot00000000000000/* * changetileprobability.cpp * Copyright 2015, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changetileprobability.h" #include "mapdocument.h" #include "tile.h" #include namespace Tiled { namespace Internal { ChangeTileProbability::ChangeTileProbability(MapDocument *mapDocument, Tile *tile, float probability) : mMapDocument(mapDocument) , mTile(tile) , mProbability(probability) { setText(QCoreApplication::translate("Undo Commands", "Change Tile Probability")); } void ChangeTileProbability::swap() { float probability = mTile->probability(); mTile->setProbability(mProbability); mProbability = probability; mMapDocument->emitTileProbabilityChanged(mTile); } } // namespace Internal } // namespace Tiled tiled-0.14.2/src/tiled/changetileprobability.h000066400000000000000000000025711260670167100213170ustar00rootroot00000000000000/* * changetileprobability.h * Copyright 2015, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGETILEPROBABILITY_H #define CHANGETILEPROBABILITY_H #include namespace Tiled { class Tile; namespace Internal { class MapDocument; class ChangeTileProbability : public QUndoCommand { public: ChangeTileProbability(MapDocument *mapDocument, Tile *tile, float probability); void undo() override { swap(); } void redo() override { swap(); } private: void swap(); MapDocument *mMapDocument; Tile *mTile; float mProbability; }; } // namespace Internal } // namespace Tiled #endif // CHANGETILEPROBABILITY_H tiled-0.14.2/src/tiled/changetileterrain.cpp000066400000000000000000000066741260670167100210060ustar00rootroot00000000000000/* * changetileterrain.cpp * Copyright 2012, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "changetileterrain.h" #include "mapdocument.h" #include "tile.h" #include namespace Tiled { namespace Internal { ChangeTileTerrain::ChangeTileTerrain() : mMapDocument(nullptr) , mTileset(nullptr) , mMergeable(false) { initText(); } ChangeTileTerrain::ChangeTileTerrain(MapDocument *mapDocument, Tile *tile, unsigned terrain) : mMapDocument(mapDocument) , mTileset(tile->tileset()) , mMergeable(true) { initText(); mChanges.insert(tile, Change(tile->terrain(), terrain)); } ChangeTileTerrain::ChangeTileTerrain(MapDocument *mapDocument, const Changes &changes) : mMapDocument(mapDocument) , mTileset(changes.begin().key()->tileset()) , mChanges(changes) , mMergeable(true) { initText(); } void ChangeTileTerrain::undo() { Changes::const_iterator i = mChanges.constBegin(); QList changedTiles; changedTiles.reserve(mChanges.size()); while (i != mChanges.constEnd()) { Tile *tile = i.key(); const Change &change = i.value(); tile->setTerrain(change.from); changedTiles.append(tile); ++i; } mMapDocument->emitTileTerrainChanged(changedTiles); } void ChangeTileTerrain::redo() { Changes::const_iterator i = mChanges.constBegin(); QList changedTiles; changedTiles.reserve(mChanges.size()); while (i != mChanges.constEnd()) { Tile *tile = i.key(); const Change &change = i.value(); tile->setTerrain(change.to); changedTiles.append(tile); ++i; } mMapDocument->emitTileTerrainChanged(changedTiles); } bool ChangeTileTerrain::mergeWith(const QUndoCommand *other) { if (!mMergeable) return false; const ChangeTileTerrain *o = static_cast(other); if (o->mMapDocument && !(mMapDocument == o->mMapDocument && mTileset == o->mTileset)) return false; Changes::const_iterator i = o->mChanges.constBegin(); Changes::const_iterator i_end = o->mChanges.constEnd(); while (i != i_end) { Tile *tile = i.key(); const Change &change = i.value(); Changes::iterator tileChange = mChanges.find(tile); if (tileChange != mChanges.end()) tileChange->to = change.to; else mChanges.insert(tile, change); ++i; } mMergeable = o->mMergeable; return true; } void ChangeTileTerrain::initText() { setText(QCoreApplication::translate("Undo Commands", "Change Tile Terrain")); } } // namespace Internal } // namespace Tiled tiled-0.14.2/src/tiled/changetileterrain.h000066400000000000000000000041211260670167100204340ustar00rootroot00000000000000/* * changetileterrain.h * Copyright 2012, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CHANGETILETERRAIN_H #define CHANGETILETERRAIN_H #include #include #include "undocommands.h" namespace Tiled { class Tile; class Tileset; namespace Internal { class MapDocument; class ChangeTileTerrain : public QUndoCommand { public: struct Change { Change(unsigned from, unsigned to) : from(from), to(to) {} unsigned from; unsigned to; }; typedef QMap Changes; /** * Constructs an empty command that changes no terrain. When merged into * a previous terrain change command, it prevents that command from merging * with future commands. */ ChangeTileTerrain(); /** * Changes the terrain of \a tile. */ ChangeTileTerrain(MapDocument *mapDocument, Tile *tile, unsigned terrain); /** * Applies the given terrain \a changes. */ ChangeTileTerrain(MapDocument *mapDocument, const Changes &changes); void undo() override; void redo() override; int id() const override { return Cmd_ChangeTileTerrain; } bool mergeWith(const QUndoCommand *other) override; private: void initText(); MapDocument *mMapDocument; Tileset *mTileset; Changes mChanges; bool mMergeable; }; } // namespace Internal } // namespace Tiled #endif // CHANGETILETERRAIN_H tiled-0.14.2/src/tiled/clipboardmanager.cpp000066400000000000000000000135701260670167100206010ustar00rootroot00000000000000/* * clipboardmanager.cpp * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "clipboardmanager.h" #include "addremovemapobject.h" #include "map.h" #include "mapdocument.h" #include "mapobject.h" #include "maprenderer.h" #include "mapview.h" #include "objectgroup.h" #include "snaphelper.h" #include "tmxmapformat.h" #include "tile.h" #include "tilelayer.h" #include #include #include #include #include static const char * const TMX_MIMETYPE = "text/tmx"; using namespace Tiled; using namespace Tiled::Internal; ClipboardManager *ClipboardManager::mInstance; ClipboardManager::ClipboardManager() : mHasMap(false) { mClipboard = QApplication::clipboard(); connect(mClipboard, SIGNAL(dataChanged()), SLOT(updateHasMap())); updateHasMap(); } ClipboardManager *ClipboardManager::instance() { if (!mInstance) mInstance = new ClipboardManager; return mInstance; } void ClipboardManager::deleteInstance() { delete mInstance; mInstance = nullptr; } Map *ClipboardManager::map() const { const QMimeData *mimeData = mClipboard->mimeData(); const QByteArray data = mimeData->data(QLatin1String(TMX_MIMETYPE)); if (data.isEmpty()) return nullptr; TmxMapFormat format; return format.fromByteArray(data); } void ClipboardManager::setMap(const Map *map) { TmxMapFormat format; QMimeData *mimeData = new QMimeData; mimeData->setData(QLatin1String(TMX_MIMETYPE), format.toByteArray(map)); mClipboard->setMimeData(mimeData); } void ClipboardManager::copySelection(const MapDocument *mapDocument) { const Layer *currentLayer = mapDocument->currentLayer(); if (!currentLayer) return; const Map *map = mapDocument->map(); const QRegion &selectedArea = mapDocument->selectedArea(); const QList &selectedObjects = mapDocument->selectedObjects(); const TileLayer *tileLayer = dynamic_cast(currentLayer); Layer *copyLayer = nullptr; if (!selectedArea.isEmpty() && tileLayer) { // Copy the selected part of the layer copyLayer = tileLayer->copy(selectedArea.translated(-tileLayer->x(), -tileLayer->y())); } else if (!selectedObjects.isEmpty()) { // Create a new object group with clones of the selected objects ObjectGroup *objectGroup = new ObjectGroup; foreach (const MapObject *mapObject, selectedObjects) objectGroup->addObject(mapObject->clone()); copyLayer = objectGroup; } else { return; } // Create a temporary map to write to the clipboard Map copyMap(map->orientation(), copyLayer->width(), copyLayer->height(), map->tileWidth(), map->tileHeight()); copyMap.setRenderOrder(map->renderOrder()); // Resolve the set of tilesets used by this layer foreach (const SharedTileset &tileset, copyLayer->usedTilesets()) copyMap.addTileset(tileset); copyMap.addLayer(copyLayer); setMap(©Map); } void ClipboardManager::pasteObjectGroup(const ObjectGroup *objectGroup, MapDocument *mapDocument, const MapView *view, PasteMode mode) { Layer *currentLayer = mapDocument->currentLayer(); if (!currentLayer) return; ObjectGroup *currentObjectGroup = currentLayer->asObjectGroup(); if (!currentObjectGroup) return; // Determine where to insert the objects const MapRenderer *renderer = mapDocument->renderer(); const QPointF center = objectGroup->objectsBoundingRect().center(); // Take the mouse position if the mouse is on the view, otherwise // take the center of the view. QPoint viewPos; if (view->underMouse()) viewPos = view->mapFromGlobal(QCursor::pos()); else viewPos = QPoint(view->width() / 2, view->height() / 2); const QPointF scenePos = view->mapToScene(viewPos); QPointF insertPos = renderer->screenToPixelCoords(scenePos) - center; SnapHelper(renderer).snap(insertPos); QUndoStack *undoStack = mapDocument->undoStack(); QList pastedObjects; pastedObjects.reserve(objectGroup->objectCount()); undoStack->beginMacro(tr("Paste Objects")); foreach (const MapObject *mapObject, objectGroup->objects()) { if (mode == NoTileObjects && !mapObject->cell().isEmpty()) continue; MapObject *objectClone = mapObject->clone(); objectClone->setPosition(objectClone->position() + insertPos); pastedObjects.append(objectClone); undoStack->push(new AddMapObject(mapDocument, currentObjectGroup, objectClone)); } undoStack->endMacro(); mapDocument->setSelectedObjects(pastedObjects); } void ClipboardManager::updateHasMap() { const QMimeData *data = mClipboard->mimeData(); const bool mapInClipboard = data && data->hasFormat(QLatin1String(TMX_MIMETYPE)); if (mapInClipboard != mHasMap) { mHasMap = mapInClipboard; emit hasMapChanged(); } } tiled-0.14.2/src/tiled/clipboardmanager.h000066400000000000000000000052551260670167100202470ustar00rootroot00000000000000/* * clipboardmanager.h * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef CLIPBOARDMANAGER_H #define CLIPBOARDMANAGER_H #include class QClipboard; namespace Tiled { class ObjectGroup; class Map; namespace Internal { class MapDocument; class MapView; /** * The clipboard manager deals with interaction with the clipboard. */ class ClipboardManager : public QObject { Q_OBJECT public: /** * Returns the clipboard manager instance. Creates the instance when it * doesn't exist yet. */ static ClipboardManager *instance(); /** * Deletes the clipboard manager instance if it exists. */ static void deleteInstance(); /** * Returns whether the clipboard has a map. */ bool hasMap() const { return mHasMap; } /** * Retrieves the map from the clipboard. Returns 0 when there was no map or * loading failed. */ Map *map() const; /** * Sets the given map on the clipboard. */ void setMap(const Map *map); /** * Convenience method to copy the current selection to the clipboard. * Deals with either tile selection or object selection. */ void copySelection(const MapDocument *mapDocument); enum PasteMode { Standard, NoTileObjects, }; /** * Convenience method that deals with some of the logic related to pasting * a group of objects. */ void pasteObjectGroup(const ObjectGroup *objectGroup, MapDocument *mapDocument, const MapView *view, PasteMode mode = Standard); signals: /** * Emitted when whether the clip has a map changed. */ void hasMapChanged(); private slots: void updateHasMap(); private: ClipboardManager(); Q_DISABLE_COPY(ClipboardManager) QClipboard *mClipboard; bool mHasMap; static ClipboardManager *mInstance; }; #endif // CLIPBOARDMANAGER_H } // namespace Internal } // namespace Tiled tiled-0.14.2/src/tiled/colorbutton.cpp000066400000000000000000000032741260670167100176610ustar00rootroot00000000000000/* * colorbutton.cpp * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "colorbutton.h" #include #include using namespace Tiled; using namespace Tiled::Internal; ColorButton::ColorButton(QWidget *parent) : QToolButton(parent) { setColor(Qt::white); connect(this, SIGNAL(clicked()), this, SLOT(pickColor())); } void ColorButton::setColor(const QColor &color) { if (mColor == color || !color.isValid()) return; mColor = color; QSize size(iconSize()); size.rwidth() -= 2; size.rheight() -= 2; QPixmap pixmap(size); pixmap.fill(mColor); QPainter painter(&pixmap); QColor border(Qt::black); border.setAlpha(128); painter.setPen(border); painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1); setIcon(QIcon(pixmap)); emit colorChanged(color); } void ColorButton::pickColor() { QColor newColor = QColorDialog::getColor(mColor, this); if (newColor.isValid()) setColor(newColor); } tiled-0.14.2/src/tiled/colorbutton.h000066400000000000000000000026461260670167100173300ustar00rootroot00000000000000/* * colorbutton.h * Copyright 2009, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef COLORBUTTON_H #define COLORBUTTON_H #include #include namespace Tiled { namespace Internal { /** * A tool button for letting the user pick a color. When clicked it shows a * color dialog and it has an icon to represent the currently chosen color. */ class ColorButton : public QToolButton { Q_OBJECT public: ColorButton(QWidget *parent = nullptr); QColor color() const { return mColor; } void setColor(const QColor &color); signals: void colorChanged(const QColor &color); private slots: void pickColor(); private: QColor mColor; }; } // namespace Internal } // namespace Tiled #endif // COLORBUTTON_H tiled-0.14.2/src/tiled/command.cpp000066400000000000000000000142511260670167100167220ustar00rootroot00000000000000/* * command.cpp * Copyright 2011, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #include "command.h" #include "documentmanager.h" #include "mapdocument.h" #include "mapobject.h" #include #include using namespace Tiled; using namespace Tiled::Internal; QString Command::finalCommand() const { QString finalCommand = command; // Perform variable replacement MapDocument *mapDocument = DocumentManager::instance()->currentDocument(); if (mapDocument) { const QString fileName = mapDocument->fileName(); finalCommand.replace(QLatin1String("%mapfile"), QString(QLatin1String("\"%1\"")).arg(fileName)); MapObject *currentObject = dynamic_cast(mapDocument->currentObject()); if (currentObject) { finalCommand.replace(QLatin1String("%objecttype"), QString(QLatin1String("\"%1\"")).arg(currentObject->type())); } } return finalCommand; } void Command::execute(bool inTerminal) const { // Save if save option is unset or true QSettings settings; QVariant variant = settings.value(QLatin1String("saveBeforeExecute"), true); if (variant.toBool()) { MapDocument *document = DocumentManager::instance()->currentDocument(); if (document) document->save(); } // Start the process new CommandProcess(*this, inTerminal); } QVariant Command::toQVariant() const { QHash hash; hash[QLatin1String("Enabled")] = isEnabled; hash[QLatin1String("Name")] = name; hash[QLatin1String("Command")] = command; return hash; } Command Command::fromQVariant(const QVariant &variant) { const QHash hash = variant.toHash(); const QString namePref = QLatin1String("Name"); const QString commandPref = QLatin1String("Command"); const QString enablePref = QLatin1String("Enabled"); Command command; if (hash.contains(enablePref)) command.isEnabled = hash[enablePref].toBool(); if (hash.contains(namePref)) command.name = hash[namePref].toString(); if (hash.contains(commandPref)) command.command = hash[commandPref].toString(); return command; } CommandProcess::CommandProcess(const Command &command, bool inTerminal) : QProcess(DocumentManager::instance()) , mName(command.name) , mFinalCommand(command.finalCommand()) #ifdef Q_OS_MAC , mFile(QLatin1String("tiledXXXXXX.command")) #endif { // Give an error if the command is empty or just whitespace if (mFinalCommand.trimmed().isEmpty()) { handleError(QProcess::FailedToStart); return; } // Modify the command to run in a terminal if (inTerminal) { #ifdef Q_OS_LINUX static bool hasGnomeTerminal = QProcess::execute( QLatin1String("which gnome-terminal")) == 0; if (hasGnomeTerminal) mFinalCommand = QLatin1String("gnome-terminal -x ") + mFinalCommand; else mFinalCommand = QLatin1String("xterm -e ") + mFinalCommand; #elif defined(Q_OS_MAC) // The only way I know to launch a Terminal with a command on mac is // to make a .command file and open it. The client command invoke the // executable directly (rather than using open) in order to get std // output in the terminal. Otherwise, you can use the Console // application to see the output. // Create and write the command to a .command file if (!mFile.open()) { handleError(tr("Unable to create/open %1").arg(mFile.fileName())); return; } mFile.write(mFinalCommand.toStdString().c_str()); mFile.close(); // Add execute permission to the file int chmodRet = QProcess::execute(QString(QLatin1String( "chmod +x \"%1\"")).arg(mFile.fileName())); if (chmodRet != 0) { handleError(tr("Unable to add executable permissions to %1") .arg(mFile.fileName())); return; } // Use open command to launch the command in the terminal // -W makes it not return immediately // -n makes it open a new instance of terminal if it is open already mFinalCommand = QString(QLatin1String("open -W -n \"%1\"")) .arg(mFile.fileName()); #endif } connect(this, SIGNAL(error(QProcess::ProcessError)), SLOT(handleError(QProcess::ProcessError))); connect(this, SIGNAL(finished(int)), SLOT(deleteLater())); start(mFinalCommand); } void CommandProcess::handleError(QProcess::ProcessError error) { QString errorStr; switch (error) { case QProcess::FailedToStart: errorStr = tr("The command failed to start."); break; case QProcess::Crashed: errorStr = tr("The command crashed."); break; case QProcess::Timedout: errorStr = tr("The command timed out."); break; default: errorStr = tr("An unknown error occurred."); } handleError(errorStr); } void CommandProcess::handleError(const QString &error) { QString title = tr("Error Executing %1").arg(mName); QString message = error + QLatin1String("\n\n") + mFinalCommand; QWidget *parent = DocumentManager::instance()->widget(); QMessageBox::warning(parent, title, message); // Make sure this object gets deleted if the process failed to start deleteLater(); } tiled-0.14.2/src/tiled/command.h000066400000000000000000000041041260670167100163630ustar00rootroot00000000000000/* * command.h * Copyright 2011, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #ifndef COMMAND_H #define COMMAND_H #include #include #include #ifdef Q_OS_MAC #include #endif namespace Tiled { namespace Internal { struct Command { Command(bool isEnabled = true, const QString &name = QString(), const QString &command = QString()) : isEnabled(isEnabled) , name(name) , command(command) {} bool isEnabled; QString name; QString command; /** * Returns the final command with replaced tokens. */ QString finalCommand() const; /** * Executes the command in the operating system shell or terminal * application. */ void execute(bool inTerminal = false) const; /** * Stores this command in a QVariant. */ QVariant toQVariant() const; /** * Generates a command from a QVariant. */ static Command fromQVariant(const QVariant &variant); }; class CommandProcess : public QProcess { Q_OBJECT public: CommandProcess(const Command &command, bool inTerminal = false); private slots: void handleError(QProcess::ProcessError); private: void handleError(const QString &); QString mName; QString mFinalCommand; #ifdef Q_OS_MAC QTemporaryFile mFile; #endif }; } // namespace Internal } // namespace Tiled #endif // COMMAND_H tiled-0.14.2/src/tiled/commandbutton.cpp000066400000000000000000000073031260670167100201560ustar00rootroot00000000000000/* * commandbutton.cpp * Copyright 2010, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #include "commandbutton.h" #include "commanddatamodel.h" #include "commanddialog.h" #include "utils.h" #include #include #include using namespace Tiled; using namespace Tiled::Utils; using namespace Tiled::Internal; CommandButton::CommandButton(QWidget *parent) : QToolButton(parent) , mMenu(new QMenu(this)) { setIcon(QIcon(QLatin1String(":images/24x24/system-run.png"))); setThemeIcon(this, "system-run"); retranslateUi(); setPopupMode(QToolButton::MenuButtonPopup); setMenu(mMenu); connect(mMenu, SIGNAL(aboutToShow()), SLOT(populateMenu())); connect(this, SIGNAL(clicked()), SLOT(runCommand())); } void CommandButton::runCommand() { Command command; QAction *action = dynamic_cast(sender()); if (action && action->data().isValid()) { //run the command passed by the action command = Command::fromQVariant(action->data()); } else { //run the default command command = CommandDataModel().firstEnabledCommand(); if (!command.isEnabled) { QMessageBox msgBox(window()); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowTitle(tr("Error Executing Command")); msgBox.setText(tr("You do not have any commands setup.")); msgBox.addButton(QMessageBox::Ok); msgBox.addButton(tr("Edit commands..."), QMessageBox::ActionRole); msgBox.setDefaultButton(QMessageBox::Ok); msgBox.setEscapeButton(QMessageBox::Ok); QAbstractButton *button = msgBox.buttons().last(); connect(button, SIGNAL(clicked()), SLOT(showDialog())); msgBox.exec(); return; } } command.execute(); } void CommandButton::showDialog() { CommandDialog dialog(window()); dialog.exec(); } void CommandButton::populateMenu() { mMenu->clear(); // Use a data model for getting the command list to avoid having to // manually parse the settings const CommandDataModel model; const QList &commands = model.allCommands(); foreach (const Command &command, commands) { if (!command.isEnabled) continue; QAction *action = mMenu->addAction(command.name); action->setStatusTip(command.command); action->setData(command.toQVariant()); connect(action, SIGNAL(triggered()), SLOT(runCommand())); } if (!mMenu->isEmpty()) mMenu->addSeparator(); // Add "Edit Commands..." action QAction *action = mMenu->addAction(tr("Edit Commands...")); connect(action, SIGNAL(triggered()), SLOT(showDialog())); } void CommandButton::changeEvent(QEvent *event) { QToolButton::changeEvent(event); switch (event->type()) { case QEvent::LanguageChange: retranslateUi(); break; default: break; } } void CommandButton::retranslateUi() { setToolTip(tr("Execute Command")); setShortcut(QKeySequence(tr("F5"))); } tiled-0.14.2/src/tiled/commandbutton.h000066400000000000000000000024361260670167100176250ustar00rootroot00000000000000/* * commandbutton.h * Copyright 2010, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #ifndef COMMANDBUTTON_H #define COMMANDBUTTON_H #include class QMenu; namespace Tiled { namespace Internal { class MainWindow; class DocumentManager; class CommandButton : public QToolButton { Q_OBJECT public: CommandButton(QWidget *parent); protected: void changeEvent(QEvent *event) override; private slots: void runCommand(); void showDialog(); void populateMenu(); private: void retranslateUi(); QMenu *mMenu; }; } // namespace Internal } // namespace Tiled #endif // PREFERENCESDIALOG_H tiled-0.14.2/src/tiled/commanddatamodel.cpp000066400000000000000000000360711260670167100206010ustar00rootroot00000000000000/* * commanddatamodel.cpp * Copyright 2010, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #include "commanddatamodel.h" #include #include #include using namespace Tiled; using namespace Tiled::Internal; const char *commandMimeType = "application/x-tiled-commandptr"; CommandDataModel::CommandDataModel() { // Load saveBeforeExecute option QVariant s = mSettings.value(QLatin1String("saveBeforeExecute"), true); mSaveBeforeExecute = s.toBool(); // Load command list const QVariant variant = mSettings.value(QLatin1String("commandList")); const QList commands = variant.toList(); foreach (const QVariant &commandVariant, commands) mCommands.append(Command::fromQVariant(commandVariant)); // Add default commands the first time the app has booted up. // This is useful on it's own and helps demonstrate how to use the commands. const QString addPrefStr = QLatin1String("addedDefaultCommands"); const bool addedCommands = mSettings.value(addPrefStr, false).toBool(); if (!addedCommands) { // Disable default commands by default so user gets an informative // warning when clicking the command button for the first time Command command(false); #ifdef Q_OS_LINUX command.command = QLatin1String("gedit %mapfile"); #elif defined(Q_OS_MAC) command.command = QLatin1String("open -t %mapfile"); #endif if (!command.command.isEmpty()) { command.name = tr("Open in text editor"); mCommands.push_back(command); } commit(); mSettings.setValue(addPrefStr, true); } } void CommandDataModel::commit() { // Save saveBeforeExecute option mSettings.setValue(QLatin1String("saveBeforeExecute"), mSaveBeforeExecute); // Save command list QList commands; foreach (const Command &command, mCommands) commands.append(command.toQVariant()); mSettings.setValue(QLatin1String("commandList"), commands); } Command CommandDataModel::firstEnabledCommand() const { foreach (const Command &command, mCommands) if (command.isEnabled) return command; return Command(false); } bool CommandDataModel::removeRows(int row, int count, const QModelIndex &parent) { if (row < 0 || row + count > mCommands.size()) return false; beginRemoveRows(parent, row, row + count); mCommands.erase(mCommands.begin() + row, mCommands.begin() + row + count); endRemoveRows(); return true; } void CommandDataModel::removeRows(QModelIndexList indices) { while (!indices.empty()) { const int row = indices.takeFirst().row(); if (row >= mCommands.size()) continue; beginRemoveRows(QModelIndex(), row, row); mCommands.removeAt(row); // Decrement later indices since we removed a row for (QModelIndexList::iterator i = indices.begin(); i != indices.end(); ++i) if (i->row() > row) *i = i->sibling(i->row() - 1, i->column()); endRemoveRows(); } } int CommandDataModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : mCommands.size() + 1; } int CommandDataModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : 3; } QVariant CommandDataModel::data(const QModelIndex &index, int role) const { const bool isNormalRow = index.row() < mCommands.size(); Command command; if (isNormalRow) command = mCommands[index.row()]; switch (role) { case Qt::DisplayRole: case Qt::EditRole: if (isNormalRow) { if (index.column() == NameColumn) return command.name; if (index.column() == CommandColumn) return command.command; } else { if (index.column() == NameColumn) { if (role == Qt::EditRole) return QString(); else return tr(""); } } break; case Qt::ToolTipRole: if (isNormalRow) { if (index.column() == NameColumn) return tr("Set a name for this command"); if (index.column() == CommandColumn) return tr("Set the shell command to execute"); if (index.column() == EnabledColumn) return tr("Show or hide this command in the command list"); } else if (index.column() == NameColumn) return tr("Add a new command"); break; case Qt::CheckStateRole: if (isNormalRow && index.column() == EnabledColumn) return command.isEnabled ? 2 : 0; break; } return QVariant(); } bool CommandDataModel::setData(const QModelIndex &index, const QVariant &value, int role) { const bool isNormalRow = index.row() < mCommands.size(); bool isModified = false; bool shouldAppend = false; Command command; if (isNormalRow) { // Get the command as it exists already command = mCommands[index.row()]; // Modify the command based on the passed date switch (role) { case Qt::EditRole: { const QString text = value.toString(); if (!text.isEmpty()) { if (index.column() == NameColumn) { command.name = value.toString(); isModified = true; } else if (index.column() == CommandColumn) { command.command = value.toString(); isModified = true; } } break; } case Qt::CheckStateRole: if (index.column() == EnabledColumn) { command.isEnabled = value.toInt() > 0; isModified = true; } break; } } else { // If final row was edited, insert the new command if (role == Qt::EditRole && index.column() == NameColumn) { command.name = value.toString(); if (!command.name.isEmpty() && command.name != tr("")) { isModified = true; shouldAppend = true; } } } if (isModified) { // Write the modified command to our cache if (shouldAppend) mCommands.push_back(command); else mCommands[index.row()] = command; // Reset if there could be new rows or reordering, else emit dataChanged if (shouldAppend || index.column() == NameColumn) { beginResetModel(); endResetModel(); } else { emit dataChanged(index, index); } } return isModified; } Qt::ItemFlags CommandDataModel::flags(const QModelIndex &index) const { const bool isNormalRow = index.row() < mCommands.size(); Qt::ItemFlags f = QAbstractTableModel::flags(index); if (isNormalRow) { f |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; if (index.column() == EnabledColumn) f |= Qt::ItemIsUserCheckable; else f |= Qt::ItemIsEditable; } else { f |= Qt::ItemIsDropEnabled; if (index.column() == NameColumn) f |= Qt::ItemIsEditable; } return f; } QVariant CommandDataModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole || orientation != Qt::Horizontal) return QVariant(); const char *sectionLabels[3] = { QT_TR_NOOP("Name"), QT_TR_NOOP("Command"), QT_TR_NOOP("Enable") }; return tr(sectionLabels[section]); } QMenu *CommandDataModel::contextMenu(QWidget *parent, const QModelIndex &index) { QMenu *menu = nullptr; const int row = index.row(); if (row >= 0 && row < mCommands.size()) { menu = new QMenu(parent); if (row > 0) { QAction *action = menu->addAction(tr("Move Up")); QSignalMapper *mapper = new QSignalMapper(action); mapper->setMapping(action, row); connect(action, SIGNAL(triggered()), mapper, SLOT(map())); connect(mapper, SIGNAL(mapped(int)), SLOT(moveUp(int))); } if (row+1 < mCommands.size()) { QAction *action = menu->addAction(tr("Move Down")); QSignalMapper *mapper = new QSignalMapper(action); mapper->setMapping(action, row + 1); connect(action, SIGNAL(triggered()), mapper, SLOT(map())); connect(mapper, SIGNAL(mapped(int)), SLOT(moveUp(int))); } menu->addSeparator(); { QAction *action = menu->addAction(tr("Execute")); QSignalMapper *mapper = new QSignalMapper(action); mapper->setMapping(action, row); connect(action, SIGNAL(triggered()), mapper, SLOT(map())); connect(mapper, SIGNAL(mapped(int)), SLOT(execute(int))); } #if defined(Q_OS_LINUX) || defined(Q_OS_MAC) { QAction *action = menu->addAction(tr("Execute in Terminal")); QSignalMapper *mapper = new QSignalMapper(action); mapper->setMapping(action, row); connect(action, SIGNAL(triggered()), mapper, SLOT(map())); connect(mapper, SIGNAL(mapped(int)), SLOT(executeInTerminal(int))); } #endif menu->addSeparator(); { QAction *action = menu->addAction(tr("Delete")); QSignalMapper *mapper = new QSignalMapper(action); mapper->setMapping(action, row); connect(action, SIGNAL(triggered()), mapper, SLOT(map())); connect(mapper, SIGNAL(mapped(int)), SLOT(remove(int))); } } return menu; } QMimeData *CommandDataModel::mimeData(const QModelIndexList &indices) const { int row = -1; foreach (const QModelIndex &index, indices) { // Only generate mime data on command rows if (index.row() < 0 || index.row() >= mCommands.size()) return nullptr; // Currently only one row at a time is supported for drags // Note: we can get multiple indexes in the same row (different columns) if (row != -1 && index.row() != row) return nullptr; row = index.row(); } const Command &command = mCommands[row]; QMimeData* mimeData = new QMimeData(); // Text data is used if command is dragged to a text editor or terminal mimeData->setText(command.finalCommand()); // Ptr is used if command is dragged onto another command // We could store the index instead, the only difference would be that if // the item is moved or deleted somehow during the drag, the ptr approach // will result in a no-op instead of moving the wrong thing. const Command *addr = &command; mimeData->setData(QLatin1String(commandMimeType), QByteArray((const char *)&addr, sizeof(addr))); return mimeData; } QStringList CommandDataModel::mimeTypes() const { QStringList result(QLatin1String("text/plain")); result.append(QLatin1String(commandMimeType)); return result; } Qt::DropActions CommandDataModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } bool CommandDataModel::dropMimeData(const QMimeData *data, Qt::DropAction, int, int, const QModelIndex &parent) { if (!parent.isValid()) return false; const int dstRow = parent.row(); if (data->hasFormat(QLatin1String(commandMimeType))) { // Get the ptr to the command that was being dragged const QByteArray byteData = data->data(QLatin1String(commandMimeType)); Q_ASSERT(byteData.length() == sizeof(Command*)); const Command *addr = *(Command**)byteData.data(); // Find the command in the command list so we can move/copy it for (int srcRow = 0; srcRow < mCommands.size(); ++srcRow) if (addr == &mCommands[srcRow]) { // If a command is dropped on another command, // move the src command into the position of the dst command. if (dstRow < mCommands.size()) return move(srcRow, dstRow); // If a command is dropped elsewhere, create a copy of it if (dstRow == mCommands.size()) { append(Command(addr->isEnabled, tr("%1 (copy)").arg(addr->name), addr->command)); return true; } } } if (data->hasText()) { // If text is dropped on a valid command, just replace the data if (dstRow < mCommands.size()) return setData(parent, data->text(), Qt::EditRole); // If text is dropped elsewhere, create a new command // Assume the dropped text is the command, not the name if (dstRow == mCommands.size()) { append(Command(true, tr("New command"), data->text())); return true; } } return false; } bool CommandDataModel::move(int commandIndex, int newIndex) { if (commandIndex < 0 || commandIndex >= mCommands.size() || newIndex < 0 || newIndex >= mCommands.size() || newIndex == commandIndex) return false; if (!beginMoveRows(QModelIndex(), commandIndex, commandIndex, QModelIndex(), newIndex > commandIndex ? newIndex + 1 : newIndex)) return false; if (commandIndex - newIndex == 1 || newIndex - commandIndex == 1) // Swapping is probably more efficient than removing/inserting mCommands.swap(commandIndex, newIndex); else { const Command command = mCommands.at(commandIndex); mCommands.removeAt(commandIndex); mCommands.insert(newIndex, command); } endMoveRows(); return true; } void CommandDataModel::append(const Command &command) { beginInsertRows(QModelIndex(), mCommands.size(), mCommands.size()); mCommands.append(command); endInsertRows(); } void CommandDataModel::moveUp(int commandIndex) { move(commandIndex, commandIndex - 1); } void CommandDataModel::execute(int commandIndex) const { mCommands.at(commandIndex).execute(); } void CommandDataModel::executeInTerminal(int commandIndex) const { mCommands.at(commandIndex).execute(true); } void CommandDataModel::remove(int commandIndex) { removeRow(commandIndex); } tiled-0.14.2/src/tiled/commanddatamodel.h000066400000000000000000000120061260670167100202360ustar00rootroot00000000000000/* * commanddatamodel.h * Copyright 2010, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #ifndef COMMANDDATAMODEL_H #define COMMANDDATAMODEL_H #include "command.h" #include #include class QMenu; namespace Tiled { namespace Internal { class CommandDataModel : public QAbstractTableModel { Q_OBJECT public: enum { NameColumn, CommandColumn, EnabledColumn }; /** * Constructs the object and parses the users settings to allow easy * programmatic access to the command list. */ CommandDataModel(); /** * Saves the data to the users preferences. */ void commit(); /** * Returns whether saving before executing commands is enabled. */ bool saveBeforeExecute() const { return mSaveBeforeExecute; } /** * Enables or disables saving before executing commands. */ void setSaveBeforeExecute(bool enabled) { mSaveBeforeExecute = enabled; } /** * Returns the first enabled command in the list, or an empty * disabled command if there are no enabled commands. */ Command firstEnabledCommand() const; /** * Returns a list of all the commands. */ const QList &allCommands() const { return mCommands; } /** * Remove the given row or rows from the model. */ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; /** * Deletes the commands associated with the given row indices. */ void removeRows(QModelIndexList indices); /** * Returns the number of rows (this includes the row). */ int rowCount(const QModelIndex &) const override; /** * Returns the number of columns. */ int columnCount(const QModelIndex &) const override; /** * Returns the data at index for the given role. */ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; /** * Sets the data at index to the given value. * for the given role */ bool setData(const QModelIndex &index, const QVariant &value, int role) override; /** * Returns flags for the item at index. */ Qt::ItemFlags flags(const QModelIndex &index) const override; /** * Returns the header data for the given section and role. * orientation should be Qt::Horizontal. */ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::EditRole) const override; /** * Returns a menu containing a list of appropriate actions for the item at * index, or 0 if there are no actions for the index. */ QMenu *contextMenu(QWidget *parent, const QModelIndex &index); /** * Returns mime data for the first index in indexes. */ QMimeData *mimeData(const QModelIndexList &indexes) const override; /** * Returns a list of mime types that can represent a command. */ QStringList mimeTypes() const override; /** * Returns the drop actions that can be performed. */ Qt::DropActions supportedDropActions() const override; /** * Handles dropping of mime data onto parent. */ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; public slots: /** * Moves the command at commandIndex to newIndex>. */ bool move(int commandIndex, int newIndex); /** * Appends command to the command list. */ void append(const Command &command); /** * Moves the command at commandIndex up one index, if possible. */ void moveUp(int commandIndex); /** * Executes the command at commandIndex. */ void execute(int commandIndex) const; /** * Executes the command at commandIndex within the systems native * terminal if available. */ void executeInTerminal(int commandIndex) const; /** * Deletes the command at commandIndex. */ void remove(int commandIndex); private: QSettings mSettings; QList mCommands; bool mSaveBeforeExecute; }; } // namespace Internal } // namespace Tiled #endif // COMMANDDATAMODEL_H tiled-0.14.2/src/tiled/commanddialog.cpp000066400000000000000000000067431260670167100201110ustar00rootroot00000000000000/* * commanddialog.cpp * Copyright 2010, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #include "commanddialog.h" #include "ui_commanddialog.h" #include "commanddatamodel.h" #include "utils.h" #include #include #include #include using namespace Tiled; using namespace Tiled::Internal; CommandDialog::CommandDialog(QWidget *parent) : QDialog(parent) , mUi(new Ui::CommandDialog) { mUi->setupUi(this); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); mUi->saveBox->setChecked(mUi->treeView->model()->saveBeforeExecute()); setWindowTitle(tr("Edit Commands")); Utils::restoreGeometry(this); } CommandDialog::~CommandDialog() { Utils::saveGeometry(this); delete mUi; } void CommandDialog::accept() { QDialog::accept(); mUi->treeView->model()->setSaveBeforeExecute(mUi->saveBox->isChecked()); mUi->treeView->model()->commit(); } CommandTreeView::CommandTreeView(QWidget *parent) : QTreeView(parent) , mModel(new CommandDataModel) { setModel(mModel); setRootIsDecorated(false); // Setup resizing so the command column stretches setColumnWidth(0, 200); QHeaderView *h = header(); h->setStretchLastSection(false); h->setSectionResizeMode(CommandDataModel::NameColumn, QHeaderView::Interactive); h->setSectionResizeMode(CommandDataModel::CommandColumn, QHeaderView::Stretch); h->setSectionResizeMode(CommandDataModel::EnabledColumn, QHeaderView::ResizeToContents); // Allow deletion via keyboard QShortcut *d = new QShortcut(QKeySequence::Delete, this); d->setContext(Qt::WidgetShortcut); connect(d, SIGNAL(activated()), SLOT(removeSelectedCommands())); connect(mModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), SLOT(handleRowsRemoved(QModelIndex, int, int))); } CommandTreeView::~CommandTreeView() { delete mModel; } void CommandTreeView::contextMenuEvent(QContextMenuEvent *event) { QModelIndex index = indexAt(event->pos()); // Generate a run a menu for the index QMenu *menu = mModel->contextMenu(this, index); if (menu) menu->exec(event->globalPos()); } void CommandTreeView::handleRowsRemoved(const QModelIndex &parent, int, int) { if (parent.isValid()) return; // Reselect the same row index of the removed row QItemSelectionModel *sModel = selectionModel(); QModelIndex index = sModel->currentIndex(); sModel->select(index.sibling(index.row() + 1,index.column()), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } void CommandTreeView::removeSelectedCommands() { QItemSelectionModel *selection = selectionModel(); const QModelIndexList indices = selection->selectedRows(); mModel->removeRows(indices); } tiled-0.14.2/src/tiled/commanddialog.h000066400000000000000000000041041260670167100175430ustar00rootroot00000000000000/* * commanddialog.h * Copyright 2010, Jeff Bland * * This file is part of Tiled. * * 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, see . */ #ifndef COMMANDDIALOG_H #define COMMANDDIALOG_H #include #include namespace Ui { class CommandDialog; } namespace Tiled { namespace Internal { class CommandDataModel; class CommandDialog : public QDialog { Q_OBJECT public: CommandDialog(QWidget *parent = nullptr); ~CommandDialog(); /** * Saves the changes to the users preferences. * Automatically called when the dialog is accepted. */ void accept() override; private: Ui::CommandDialog *mUi; }; class CommandTreeView : public QTreeView { Q_OBJECT public: CommandTreeView(QWidget *parent); ~CommandTreeView(); /** * Returns the model used by this view in CommandDataMode form. */ CommandDataModel *model() const { return mModel; } private slots: /** * Displays a context menu for the item at event's position. */ void contextMenuEvent(QContextMenuEvent *event) override; /** * Fixes the selection after rows have been removed. */ void handleRowsRemoved(const QModelIndex &parent, int start, int end); /** * Gets the currently selected rows and tells the model to delete them. */ void removeSelectedCommands(); private: CommandDataModel *mModel; }; } // namespace Internal } // namespace Tiled #endif // COMMANDDIALOG_H tiled-0.14.2/src/tiled/commanddialog.ui000066400000000000000000000046041260670167100177360ustar00rootroot00000000000000 CommandDialog 0 0 479 258 Properties QAbstractItemView::DragDrop true QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows &Save map before executing Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok Tiled::Internal::CommandTreeView QTreeView
commanddialog.h
buttonBox accepted() CommandDialog accept() 248 254 157 274 buttonBox rejected() CommandDialog reject() 316 260 286 274
tiled-0.14.2/src/tiled/commandlineparser.cpp000066400000000000000000000114021260670167100210020ustar00rootroot00000000000000/* * commandlineparser.cpp * Copyright 2011, Ben Longbons * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #include "commandlineparser.h" #include #include using namespace Tiled; using namespace Tiled::Internal; CommandLineParser::CommandLineParser() : mLongestArgument(0) , mShowHelp(false) { } void CommandLineParser::registerOption(Callback callback, void *data, QChar shortName, const QString &longName, const QString &help) { mOptions.append(Option(callback, data, shortName, longName, help)); const int length = longName.length(); if (mLongestArgument < length) mLongestArgument = length; } bool CommandLineParser::parse(const QStringList &arguments) { mFilesToOpen.clear(); mShowHelp = false; QStringList todo = arguments; mCurrentProgramName = QFileInfo(todo.takeFirst()).fileName(); int index = 0; bool noMoreArguments = false; while (!todo.isEmpty()) { index++; const QString arg = todo.takeFirst(); if (arg.isEmpty()) continue; if (noMoreArguments || arg.at(0) != QLatin1Char('-')) { mFilesToOpen.append(arg); continue; } if (arg.length() == 1) { // Traditionally a single hyphen means read file from stdin, // write file to stdout. This isn't supported right now. qWarning() << qPrintable(tr("Bad argument %1: lonely hyphen").arg(index)); showHelp(); return false; } // Long options if (arg.at(1) == QLatin1Char('-')) { // Double hypen "--" means no more options will follow if (arg.length() == 2) { noMoreArguments = true; continue; } if (!handleLongOption(arg)) { qWarning() << qPrintable(tr("Unknown long argument %1: %2").arg(index).arg(arg)); mShowHelp = true; break; } continue; } // Short options for (int i = 1; i < arg.length(); ++i) { const QChar c = arg.at(i); if (!handleShortOption(c)) { qWarning() << qPrintable(tr("Unknown short argument %1.%2: %3").arg(index).arg(i).arg(c)); mShowHelp = true; break; } } } if (mShowHelp) { showHelp(); return false; } return true; } void CommandLineParser::showHelp() { qWarning().nospace() << qPrintable(tr("Usage:\n %1 [options] [files...]").arg(mCurrentProgramName)) << "\n\n" << qPrintable(tr("Options:")); qWarning(" -h %-*s : %s", mLongestArgument, "--help", qPrintable(tr("Display this help"))); foreach (const Option &option, mOptions) { if (!option.shortName.isNull()) { qWarning(" -%c %-*s : %s", option.shortName.toLatin1(), mLongestArgument, qPrintable(option.longName), qPrintable(option.help)); } else { qWarning(" %-*s : %s", mLongestArgument, qPrintable(option.longName), qPrintable(option.help)); } } qWarning(); } bool CommandLineParser::handleLongOption(const QString &longName) { if (longName == QLatin1String("--help")) { mShowHelp = true; return true; } foreach (const Option &option, mOptions) { if (longName == option.longName) { option.callback(option.data); return true; } } return false; } bool CommandLineParser::handleShortOption(QChar c) { if (c == QLatin1Char('h')) { mShowHelp = true; return true; } foreach (const Option &option, mOptions) { if (c == option.shortName) { option.callback(option.data); return true; } } return false; } tiled-0.14.2/src/tiled/commandlineparser.h000066400000000000000000000102341260670167100204510ustar00rootroot00000000000000/* * commandlineparser.h * Copyright 2011, Ben Longbons * Copyright 2011, Thorbjørn Lindeijer * * This file is part of Tiled. * * 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, see . */ #ifndef COMMANDLINEPARSER_H #define COMMANDLINEPARSER_H #include #include #include namespace Tiled { namespace Internal { /** * C-style callback function taking an arbitrary data pointer. */ typedef void (*Callback)(void *data); /** * A template function that will static-cast the given \a object to a type T * and call the member function of T given in the second template argument. */ template void MemberFunctionCall(void *object) { T *t = static_cast(object); (t->*memberFunction)(); } /** * A simple command line parser. Options should be registered through * registerOption(). * * The help option (-h/--help) is provided by the parser based on the * registered options. */ class CommandLineParser { Q_DECLARE_TR_FUNCTIONS(CommandLineParser) public: CommandLineParser(); /** * Registers an option with the parser. When an option with the given * \a shortName or \a longName is encountered, \a callback is called with * \a data as its only parameter. */ void registerOption(Callback callback, void *data, QChar shortName, const QString &longName, const QString &help); /** * Convenience overload that allows registering an option with a callback * as a member function of a class. The class type and the member function * are given as template parameters, while the instance is passed in as * \a handler. * * \overload */ template void registerOption(T *handler, QChar shortName, const QString &longName, const QString &help) { registerOption(&MemberFunctionCall, handler, shortName, longName, help); } /** * Parses the given \a arguments. Returns false when the application is not * expected to run (either there was a parsing error, or the help was * requested). */ bool parse(const QStringList &arguments); /** * Returns the files to open that were found among the arguments. */ const QStringList &filesToOpen() const { return mFilesToOpen; } private: void showHelp(); bool handleLongOption(const QString &longName); bool handleShortOption(QChar c); /** * Internal definition of a command line option. */ struct Option { Option() : callback(nullptr) , data(nullptr) {} Option(Callback callback, void *data, QChar shortName, const QString &longName, const QString &help) : callback(callback) , data(data) , shortName(shortName) , longName(longName) , help(help) {} Callback callback; void *data; QChar shortName; QString longName; QString help; }; QVector