├── .gitignore ├── AUTHORS ├── CHANGES ├── LICENSE ├── README.md ├── assets └── resources │ ├── default_button.png │ ├── raw │ ├── check-off.png │ ├── check-on.png │ ├── cursor.9.png │ ├── default-pane-noborder.9.png │ ├── default-pane.9.png │ ├── default-rect-down.9.png │ ├── default-rect-pad.9.png │ ├── default-rect.9.png │ ├── default-round-down.9.png │ ├── default-round-large.9.png │ ├── default-round.9.png │ ├── default-scroll.9.png │ ├── default-select-selection.9.png │ ├── default-select.9.png │ ├── default-slider-knob.png │ ├── default-slider.9.png │ ├── default-splitpane-vertical.9.png │ ├── default-splitpane.9.png │ ├── default-window.9.png │ ├── default.fnt │ ├── default.png │ ├── pack.json │ ├── paint_brush.png │ ├── selection.png │ ├── textfield.9.png │ ├── tree-minus.png │ ├── tree-plus.png │ ├── white.png │ └── widgets │ │ ├── Button.png │ │ ├── CheckBox.png │ │ ├── ImageButton.png │ │ ├── Label.png │ │ ├── List.png │ │ ├── ProgressBar.png │ │ ├── ScrollPane.png │ │ ├── SelectBox.png │ │ ├── Slider.png │ │ ├── SplitPane.png │ │ ├── TextButton.png │ │ ├── TextField.png │ │ ├── Touchpad.png │ │ ├── Tree.png │ │ └── Window.png │ ├── uiskin.atlas │ ├── uiskin.json │ └── uiskin.png ├── build.gradle ├── core ├── build.gradle └── src │ ├── com │ ├── badlogic │ │ └── gdx │ │ │ ├── scenes │ │ │ └── scene2d │ │ │ │ └── ui │ │ │ │ └── Skin.java │ │ │ └── tools │ │ │ └── hiero │ │ │ ├── BMFontUtil.java │ │ │ └── unicodefont │ │ │ └── GlyphPage.java │ └── mobidevelop │ │ └── maps │ │ └── editor │ │ └── ui │ │ └── utils │ │ └── Tooltips.java │ └── org │ └── shadebob │ └── skineditor │ ├── ColorPickerDialog.java │ ├── DrawablePickerDialog.java │ ├── FontPickerDialog.java │ ├── NewFontDialog.java │ ├── NinePatchEditorDialog.java │ ├── OptionalChecker.java │ ├── SkinEditorGame.gwt.xml │ ├── SkinEditorGame.java │ ├── SystemFonts.java │ ├── actors │ ├── MenuBar.java │ ├── OptionsPane.java │ ├── PreviewPane.java │ ├── RangeSelector.java │ └── WidgetsBar.java │ └── screens │ ├── MainScreen.java │ └── WelcomeScreen.java ├── desktop ├── build.gradle └── src │ └── org │ └── shadebob │ └── skineditor │ └── desktop │ └── DesktopLauncher.java ├── dist └── skin_editor_v0.3.zip ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ### Java ### 3 | *.class 4 | 5 | # Mobile Tools for Java (J2ME) 6 | .mtj.tmp/ 7 | 8 | # Package Files # 9 | *.jar 10 | *.war 11 | *.ear 12 | 13 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 14 | hs_err_pid* 15 | 16 | 17 | ### Gradle ### 18 | .gradle 19 | build/ 20 | 21 | # Ignore Gradle GUI config 22 | gradle-app.setting 23 | 24 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 25 | !gradle-wrapper.jar 26 | 27 | # Cache of project 28 | .gradletasknamecache 29 | 30 | 31 | ### Eclipse ### 32 | *.pydevproject 33 | .metadata 34 | bin/ 35 | tmp/ 36 | *.tmp 37 | *.bak 38 | *.swp 39 | *~.nib 40 | local.properties 41 | .settings/ 42 | .loadpath 43 | 44 | # Eclipse Core 45 | .project 46 | 47 | # External tool builders 48 | .externalToolBuilders/ 49 | 50 | # Locally stored "Eclipse launch configurations" 51 | *.launch 52 | 53 | # CDT-specific 54 | .cproject 55 | 56 | # JDT-specific (Eclipse Java Development Tools) 57 | .classpath 58 | 59 | # Java annotation processor (APT) 60 | .factorypath 61 | 62 | # PDT-specific 63 | .buildpath 64 | 65 | # sbteclipse plugin 66 | .target 67 | 68 | # TeXlipse plugin 69 | .texlipse 70 | 71 | # STS (Spring Tool Suite) 72 | .springBeans 73 | 74 | ### gdx-skineditor 75 | assets/projects 76 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of the AUTHORS of skin editor 2 | # for copyright purposes. 3 | 4 | # Names should be added to this file as 5 | # Name or Organization 6 | # The email address is not required for organizations. 7 | Yanick Bourbeau 8 | 9 | 10 | ############################### 11 | 12 | This project also reuse components made by others: 13 | 14 | - A modified version of com.badlogic.gdx.scenes.scene2d.ui.Skin from libGDX. 15 | - A modified version of com.badlogic.gdx.tools.hiero.BMFontUtil from libGDX. 16 | - A modified version of com.badlogic.gdx.tools.hiero.unicodefont.GlyphPage from libGDX. 17 | - com.mobidevelop.maps.editor.ui.utils.Tooltips from Justin Shapcott 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | [0.2] 2 | 3 | - Fixed scrollpane in scrollpane issue. 4 | - Added grey color for optional fields. 5 | - Window can now be resized as you want. 6 | - A faulty style will not prevent other styles to be rendered anymore. 7 | - Added system LAF for Swing dialogs. (#3) 8 | - Tree was displayed three times instead of one. (#2) 9 | - Deleting a bitmap font now remove both png and fnt files. (#4) 10 | - Fixed random crash when dealing with color creation. (#5) 11 | - Export to specific folder. 12 | 13 | 14 | [0.1] 15 | 16 | - Initial release 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Project not maintained anymore, please use Skin Composer: 2 | https://ray3k.wordpress.com/software/skin-composer-for-libgdx/ 3 | 4 | gdx-skineditor 5 | ============== 6 | 7 | A skin editor for libgdx 0.3 8 | 9 | Easy way to make it run (from console): 10 | 11 | ```sh 12 | git clone https://github.com/cobolfoo/gdx-skineditor.git skineditor 13 | cd skineditor 14 | ./gradlew run 15 | ``` 16 | 17 | *** You could also use the distribution zip file from DIST folder. *** 18 | 19 | 20 | -------------------------------------------------------------------------------- /assets/resources/default_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/default_button.png -------------------------------------------------------------------------------- /assets/resources/raw/check-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/check-off.png -------------------------------------------------------------------------------- /assets/resources/raw/check-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/check-on.png -------------------------------------------------------------------------------- /assets/resources/raw/cursor.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/cursor.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-pane-noborder.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-pane-noborder.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-pane.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-pane.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-rect-down.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-rect-down.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-rect-pad.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-rect-pad.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-rect.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-rect.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-round-down.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-round-down.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-round-large.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-round-large.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-round.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-round.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-scroll.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-scroll.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-select-selection.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-select-selection.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-select.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-select.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-slider-knob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-slider-knob.png -------------------------------------------------------------------------------- /assets/resources/raw/default-slider.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-slider.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-splitpane-vertical.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-splitpane-vertical.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-splitpane.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-splitpane.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default-window.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default-window.9.png -------------------------------------------------------------------------------- /assets/resources/raw/default.fnt: -------------------------------------------------------------------------------- 1 | info face="Droid Sans" size=17 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 2 | common lineHeight=20 base=18 scaleW=256 scaleH=128 pages=1 packed=0 3 | page id=0 file="default.png" 4 | chars count=96 5 | char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=16 xadvance=4 page=0 chnl=0 6 | char id=124 x=0 y=0 width=6 height=20 xoffset=1 yoffset=3 xadvance=9 page=0 chnl=0 7 | char id=106 x=6 y=0 width=9 height=20 xoffset=-4 yoffset=3 xadvance=4 page=0 chnl=0 8 | char id=81 x=15 y=0 width=15 height=19 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0 9 | char id=74 x=30 y=0 width=11 height=19 xoffset=-5 yoffset=3 xadvance=4 page=0 chnl=0 10 | char id=125 x=41 y=0 width=10 height=18 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0 11 | char id=123 x=51 y=0 width=10 height=18 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0 12 | char id=93 x=61 y=0 width=8 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 13 | char id=91 x=69 y=0 width=8 height=18 xoffset=-2 yoffset=3 xadvance=5 page=0 chnl=0 14 | char id=41 x=77 y=0 width=9 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 15 | char id=40 x=86 y=0 width=9 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 16 | char id=64 x=95 y=0 width=18 height=17 xoffset=-3 yoffset=3 xadvance=14 page=0 chnl=0 17 | char id=121 x=113 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0 18 | char id=113 x=126 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 19 | char id=112 x=139 y=0 width=13 height=17 xoffset=-2 yoffset=6 xadvance=9 page=0 chnl=0 20 | char id=103 x=152 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0 21 | char id=38 x=165 y=0 width=16 height=16 xoffset=-3 yoffset=3 xadvance=11 page=0 chnl=0 22 | char id=37 x=181 y=0 width=18 height=16 xoffset=-3 yoffset=3 xadvance=14 page=0 chnl=0 23 | char id=36 x=199 y=0 width=12 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 24 | char id=63 x=211 y=0 width=11 height=16 xoffset=-3 yoffset=3 xadvance=7 page=0 chnl=0 25 | char id=33 x=222 y=0 width=7 height=16 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0 26 | char id=48 x=229 y=0 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 27 | char id=57 x=242 y=0 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 28 | char id=56 x=0 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 29 | char id=54 x=13 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 30 | char id=53 x=26 y=20 width=12 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 31 | char id=51 x=38 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 32 | char id=100 x=51 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 33 | char id=98 x=64 y=20 width=13 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 34 | char id=85 x=77 y=20 width=14 height=16 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0 35 | char id=83 x=91 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0 36 | char id=79 x=104 y=20 width=15 height=16 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0 37 | char id=71 x=119 y=20 width=14 height=16 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0 38 | char id=67 x=133 y=20 width=13 height=16 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 39 | char id=127 x=146 y=20 width=12 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 40 | char id=35 x=158 y=20 width=15 height=15 xoffset=-3 yoffset=3 xadvance=10 page=0 chnl=0 41 | char id=92 x=173 y=20 width=11 height=15 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0 42 | char id=47 x=184 y=20 width=11 height=15 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0 43 | char id=59 x=195 y=20 width=8 height=15 xoffset=-3 yoffset=6 xadvance=4 page=0 chnl=0 44 | char id=55 x=203 y=20 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 45 | char id=52 x=216 y=20 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 46 | char id=50 x=230 y=20 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 47 | char id=49 x=243 y=20 width=9 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 48 | char id=116 x=0 y=36 width=10 height=15 xoffset=-3 yoffset=4 xadvance=5 page=0 chnl=0 49 | char id=108 x=10 y=36 width=6 height=15 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0 50 | char id=107 x=16 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0 51 | char id=105 x=28 y=36 width=7 height=15 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0 52 | char id=104 x=35 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 53 | char id=102 x=47 y=36 width=11 height=15 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 54 | char id=90 x=58 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 55 | char id=89 x=71 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0 56 | char id=88 x=84 y=36 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 57 | char id=87 x=98 y=36 width=19 height=15 xoffset=-3 yoffset=3 xadvance=15 page=0 chnl=0 58 | char id=86 x=117 y=36 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 59 | char id=84 x=131 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0 60 | char id=82 x=144 y=36 width=13 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 61 | char id=80 x=157 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 62 | char id=78 x=169 y=36 width=14 height=15 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0 63 | char id=77 x=183 y=36 width=17 height=15 xoffset=-2 yoffset=3 xadvance=14 page=0 chnl=0 64 | char id=76 x=200 y=36 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0 65 | char id=75 x=211 y=36 width=13 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 66 | char id=73 x=224 y=36 width=10 height=15 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 67 | char id=72 x=234 y=36 width=14 height=15 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0 68 | char id=70 x=0 y=51 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0 69 | char id=69 x=11 y=51 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0 70 | char id=68 x=22 y=51 width=14 height=15 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0 71 | char id=66 x=36 y=51 width=13 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 72 | char id=65 x=49 y=51 width=15 height=15 xoffset=-3 yoffset=3 xadvance=10 page=0 chnl=0 73 | char id=58 x=64 y=51 width=7 height=13 xoffset=-2 yoffset=6 xadvance=4 page=0 chnl=0 74 | char id=117 x=71 y=51 width=12 height=13 xoffset=-2 yoffset=6 xadvance=10 page=0 chnl=0 75 | char id=115 x=83 y=51 width=11 height=13 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0 76 | char id=111 x=94 y=51 width=13 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 77 | char id=101 x=107 y=51 width=13 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 78 | char id=99 x=120 y=51 width=12 height=13 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0 79 | char id=97 x=132 y=51 width=12 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 80 | char id=60 x=144 y=51 width=13 height=12 xoffset=-3 yoffset=5 xadvance=9 page=0 chnl=0 81 | char id=122 x=157 y=51 width=11 height=12 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0 82 | char id=120 x=168 y=51 width=13 height=12 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0 83 | char id=119 x=181 y=51 width=17 height=12 xoffset=-3 yoffset=6 xadvance=12 page=0 chnl=0 84 | char id=118 x=198 y=51 width=13 height=12 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0 85 | char id=114 x=211 y=51 width=10 height=12 xoffset=-2 yoffset=6 xadvance=6 page=0 chnl=0 86 | char id=110 x=221 y=51 width=12 height=12 xoffset=-2 yoffset=6 xadvance=10 page=0 chnl=0 87 | char id=109 x=233 y=51 width=17 height=12 xoffset=-2 yoffset=6 xadvance=15 page=0 chnl=0 88 | char id=94 x=0 y=66 width=13 height=11 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 89 | char id=62 x=13 y=66 width=13 height=11 xoffset=-3 yoffset=5 xadvance=9 page=0 chnl=0 90 | char id=42 x=26 y=66 width=13 height=10 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 91 | char id=43 x=39 y=66 width=13 height=10 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 92 | char id=61 x=52 y=66 width=13 height=8 xoffset=-3 yoffset=7 xadvance=9 page=0 chnl=0 93 | char id=39 x=65 y=66 width=6 height=8 xoffset=-2 yoffset=3 xadvance=3 page=0 chnl=0 94 | char id=34 x=71 y=66 width=9 height=8 xoffset=-2 yoffset=3 xadvance=6 page=0 chnl=0 95 | char id=44 x=80 y=66 width=8 height=7 xoffset=-3 yoffset=14 xadvance=4 page=0 chnl=0 96 | char id=126 x=88 y=66 width=13 height=6 xoffset=-3 yoffset=8 xadvance=9 page=0 chnl=0 97 | char id=46 x=101 y=66 width=7 height=6 xoffset=-2 yoffset=13 xadvance=4 page=0 chnl=0 98 | char id=96 x=108 y=66 width=8 height=6 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=0 99 | char id=45 x=116 y=66 width=9 height=5 xoffset=-3 yoffset=10 xadvance=5 page=0 chnl=0 100 | char id=95 x=125 y=66 width=13 height=4 xoffset=-4 yoffset=17 xadvance=6 page=0 chnl=0 101 | kernings count=-1 102 | -------------------------------------------------------------------------------- /assets/resources/raw/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/default.png -------------------------------------------------------------------------------- /assets/resources/raw/pack.json: -------------------------------------------------------------------------------- 1 | { 2 | duplicatePadding: false, 3 | paddingX: 1, 4 | paddingY: 1 5 | } -------------------------------------------------------------------------------- /assets/resources/raw/paint_brush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/paint_brush.png -------------------------------------------------------------------------------- /assets/resources/raw/selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/selection.png -------------------------------------------------------------------------------- /assets/resources/raw/textfield.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/textfield.9.png -------------------------------------------------------------------------------- /assets/resources/raw/tree-minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/tree-minus.png -------------------------------------------------------------------------------- /assets/resources/raw/tree-plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/tree-plus.png -------------------------------------------------------------------------------- /assets/resources/raw/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/white.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/Button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/Button.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/CheckBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/CheckBox.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/ImageButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/ImageButton.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/Label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/Label.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/List.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/ProgressBar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/ProgressBar.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/ScrollPane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/ScrollPane.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/SelectBox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/SelectBox.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/Slider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/Slider.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/SplitPane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/SplitPane.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/TextButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/TextButton.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/TextField.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/TextField.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/Touchpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/Touchpad.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/Tree.png -------------------------------------------------------------------------------- /assets/resources/raw/widgets/Window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/raw/widgets/Window.png -------------------------------------------------------------------------------- /assets/resources/uiskin.atlas: -------------------------------------------------------------------------------- 1 | 2 | uiskin.png 3 | size: 904,127 4 | format: RGBA8888 5 | filter: Nearest,Nearest 6 | repeat: none 7 | check-off 8 | rotate: false 9 | xy: 321, 64 10 | size: 14, 14 11 | orig: 14, 14 12 | offset: 0, 0 13 | index: -1 14 | textfield 15 | rotate: false 16 | xy: 321, 64 17 | size: 14, 14 18 | split: 3, 3, 3, 3 19 | orig: 14, 14 20 | offset: 0, 0 21 | index: -1 22 | check-on 23 | rotate: false 24 | xy: 762, 83 25 | size: 14, 14 26 | orig: 14, 14 27 | offset: 0, 0 28 | index: -1 29 | cursor 30 | rotate: false 31 | xy: 886, 109 32 | size: 3, 3 33 | split: 1, 1, 1, 1 34 | orig: 3, 3 35 | offset: 0, 0 36 | index: -1 37 | default 38 | rotate: false 39 | xy: 1, 50 40 | size: 254, 77 41 | orig: 254, 77 42 | offset: 0, 0 43 | index: -1 44 | default-pane 45 | rotate: false 46 | xy: 256, 50 47 | size: 5, 3 48 | split: 1, 1, 1, 1 49 | orig: 5, 3 50 | offset: 0, 0 51 | index: -1 52 | default-rect-pad 53 | rotate: false 54 | xy: 256, 50 55 | size: 5, 3 56 | split: 1, 1, 1, 1 57 | orig: 5, 3 58 | offset: 0, 0 59 | index: -1 60 | default-pane-noborder 61 | rotate: false 62 | xy: 787, 96 63 | size: 1, 1 64 | split: 0, 0, 0, 0 65 | orig: 1, 1 66 | offset: 0, 0 67 | index: -1 68 | default-rect 69 | rotate: false 70 | xy: 351, 75 71 | size: 3, 3 72 | split: 1, 1, 1, 1 73 | orig: 3, 3 74 | offset: 0, 0 75 | index: -1 76 | default-rect-down 77 | rotate: false 78 | xy: 901, 124 79 | size: 3, 3 80 | split: 1, 1, 1, 1 81 | orig: 3, 3 82 | offset: 0, 0 83 | index: -1 84 | default-round 85 | rotate: false 86 | xy: 873, 107 87 | size: 12, 20 88 | split: 5, 5, 5, 4 89 | pad: 4, 4, 1, 1 90 | orig: 12, 20 91 | offset: 0, 0 92 | index: -1 93 | default-round-down 94 | rotate: false 95 | xy: 860, 107 96 | size: 12, 20 97 | split: 5, 5, 5, 4 98 | orig: 12, 20 99 | offset: 0, 0 100 | index: -1 101 | default-round-large 102 | rotate: false 103 | xy: 818, 107 104 | size: 20, 20 105 | split: 5, 5, 5, 4 106 | orig: 20, 20 107 | offset: 0, 0 108 | index: -1 109 | default-scroll 110 | rotate: false 111 | xy: 839, 107 112 | size: 20, 20 113 | split: 2, 2, 2, 2 114 | orig: 20, 20 115 | offset: 0, 0 116 | index: -1 117 | default-select 118 | rotate: false 119 | xy: 790, 107 120 | size: 27, 20 121 | split: 4, 14, 4, 4 122 | orig: 27, 20 123 | offset: 0, 0 124 | index: -1 125 | default-select-selection 126 | rotate: false 127 | xy: 762, 79 128 | size: 3, 3 129 | split: 1, 1, 1, 1 130 | orig: 3, 3 131 | offset: 0, 0 132 | index: -1 133 | default-slider 134 | rotate: false 135 | xy: 256, 54 136 | size: 8, 8 137 | split: 2, 2, 2, 2 138 | orig: 8, 8 139 | offset: 0, 0 140 | index: -1 141 | default-slider-knob 142 | rotate: false 143 | xy: 777, 79 144 | size: 9, 18 145 | orig: 9, 18 146 | offset: 0, 0 147 | index: -1 148 | default-splitpane 149 | rotate: false 150 | xy: 262, 50 151 | size: 5, 3 152 | split: 0, 5, 0, 0 153 | orig: 5, 3 154 | offset: 0, 0 155 | index: -1 156 | default-splitpane-vertical 157 | rotate: false 158 | xy: 790, 101 159 | size: 3, 5 160 | split: 0, 0, 0, 5 161 | orig: 3, 5 162 | offset: 0, 0 163 | index: -1 164 | default-window 165 | rotate: false 166 | xy: 762, 98 167 | size: 27, 29 168 | split: 4, 3, 20, 3 169 | orig: 27, 29 170 | offset: 0, 0 171 | index: -1 172 | paint_brush 173 | rotate: false 174 | xy: 256, 63 175 | size: 64, 64 176 | orig: 64, 64 177 | offset: 0, 0 178 | index: -1 179 | selection 180 | rotate: false 181 | xy: 265, 61 182 | size: 1, 1 183 | orig: 1, 1 184 | offset: 0, 0 185 | index: -1 186 | tree-minus 187 | rotate: false 188 | xy: 886, 113 189 | size: 14, 14 190 | orig: 14, 14 191 | offset: 0, 0 192 | index: -1 193 | tree-plus 194 | rotate: false 195 | xy: 336, 64 196 | size: 14, 14 197 | orig: 14, 14 198 | offset: 0, 0 199 | index: -1 200 | white 201 | rotate: false 202 | xy: 790, 99 203 | size: 1, 1 204 | orig: 1, 1 205 | offset: 0, 0 206 | index: -1 207 | widgets/Button 208 | rotate: false 209 | xy: 1, 1 210 | size: 48, 48 211 | orig: 48, 48 212 | offset: 0, 0 213 | index: -1 214 | widgets/CheckBox 215 | rotate: false 216 | xy: 50, 1 217 | size: 48, 48 218 | orig: 48, 48 219 | offset: 0, 0 220 | index: -1 221 | widgets/ImageButton 222 | rotate: false 223 | xy: 99, 1 224 | size: 48, 48 225 | orig: 48, 48 226 | offset: 0, 0 227 | index: -1 228 | widgets/Label 229 | rotate: false 230 | xy: 148, 1 231 | size: 48, 48 232 | orig: 48, 48 233 | offset: 0, 0 234 | index: -1 235 | widgets/List 236 | rotate: false 237 | xy: 197, 1 238 | size: 48, 48 239 | orig: 48, 48 240 | offset: 0, 0 241 | index: -1 242 | widgets/ProgressBar 243 | rotate: false 244 | xy: 246, 1 245 | size: 48, 48 246 | orig: 48, 48 247 | offset: 0, 0 248 | index: -1 249 | widgets/ScrollPane 250 | rotate: false 251 | xy: 321, 79 252 | size: 48, 48 253 | orig: 48, 48 254 | offset: 0, 0 255 | index: -1 256 | widgets/SelectBox 257 | rotate: false 258 | xy: 370, 79 259 | size: 48, 48 260 | orig: 48, 48 261 | offset: 0, 0 262 | index: -1 263 | widgets/Slider 264 | rotate: false 265 | xy: 419, 79 266 | size: 48, 48 267 | orig: 48, 48 268 | offset: 0, 0 269 | index: -1 270 | widgets/SplitPane 271 | rotate: false 272 | xy: 468, 79 273 | size: 48, 48 274 | orig: 48, 48 275 | offset: 0, 0 276 | index: -1 277 | widgets/TextButton 278 | rotate: false 279 | xy: 517, 79 280 | size: 48, 48 281 | orig: 48, 48 282 | offset: 0, 0 283 | index: -1 284 | widgets/TextField 285 | rotate: false 286 | xy: 566, 79 287 | size: 48, 48 288 | orig: 48, 48 289 | offset: 0, 0 290 | index: -1 291 | widgets/Touchpad 292 | rotate: false 293 | xy: 615, 79 294 | size: 48, 48 295 | orig: 48, 48 296 | offset: 0, 0 297 | index: -1 298 | widgets/Tree 299 | rotate: false 300 | xy: 664, 79 301 | size: 48, 48 302 | orig: 48, 48 303 | offset: 0, 0 304 | index: -1 305 | widgets/Window 306 | rotate: false 307 | xy: 713, 79 308 | size: 48, 48 309 | orig: 48, 48 310 | offset: 0, 0 311 | index: -1 312 | -------------------------------------------------------------------------------- /assets/resources/uiskin.json: -------------------------------------------------------------------------------- 1 | { 2 | com.badlogic.gdx.graphics.g2d.BitmapFont: { default-font: { file: default.fnt } }, 3 | com.badlogic.gdx.graphics.Color: { 4 | green: { a: 1, b: 0, g: 1, r: 0 }, 5 | white: { a: 1, b: 1, g: 1, r: 1 }, 6 | light_grey: { a: 1, b: 0.8, g: 0.8, r: 0.8 }, 7 | grey: { a: 1, b: 0.7, g: 0.7, r: 0.7 }, 8 | red: { a: 1, b: 0, g: 0, r: 1 }, 9 | black: { a: 1, b: 0, g: 0, r: 0 } 10 | }, 11 | com.badlogic.gdx.scenes.scene2d.ui.Skin$TintedDrawable: { 12 | dialogDim: { name: white, color: { r: 0.2, g: 0.2, b: 0.2, a: 1 } } 13 | }, 14 | com.badlogic.gdx.scenes.scene2d.ui.Button$ButtonStyle: { 15 | default: { down: default-round-down, up: default-round }, 16 | toggle: { down: default-round-down, checked: default-round-down, up: default-round } 17 | }, 18 | com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle: { 19 | default: { down: default-round-down, up: default-round, font: default-font, fontColor: white, disabledFontColor: light_grey }, 20 | toggle: { down: default-round-down, up: default-round, checked: default-round-down, font: default-font, fontColor: white, downFontColor: red } 21 | }, 22 | com.badlogic.gdx.scenes.scene2d.ui.ScrollPane$ScrollPaneStyle: { 23 | default: { vScroll: default-scroll, hScrollKnob: default-round-large, background: default-rect, hScroll: default-scroll, vScrollKnob: default-round-large } 24 | }, 25 | com.badlogic.gdx.scenes.scene2d.ui.SplitPane$SplitPaneStyle: { 26 | default-vertical: { handle: default-splitpane-vertical }, 27 | default-horizontal: { handle: default-splitpane } 28 | }, 29 | com.badlogic.gdx.scenes.scene2d.ui.Window$WindowStyle: { 30 | default: { titleFont: default-font, background: default-window, titleFontColor: white }, 31 | dialog: { titleFont: default-font, background: default-window, titleFontColor: white, stageBackground: dialogDim } 32 | }, 33 | com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle: { 34 | default-horizontal: { background: default-slider, knob: default-slider-knob }, 35 | default-vertical: { background: default-slider, knob: default-slider-knob } 36 | }, 37 | com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle: { 38 | default: { font: default-font, fontColor: white }, 39 | optional: { font: default-font, fontColor: grey }, 40 | title: { font: default-font, fontColor: light_grey }, 41 | error: { font: default-font, fontColor: red } 42 | }, 43 | com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle: { 44 | default: { selection: selection, background: textfield, font: default-font, fontColor: white, cursor: cursor } 45 | }, 46 | com.badlogic.gdx.scenes.scene2d.ui.CheckBox$CheckBoxStyle: { 47 | default: { checkboxOn: check-on, checkboxOff: check-off, font: default-font, fontColor: white } 48 | }, 49 | com.badlogic.gdx.scenes.scene2d.ui.List$ListStyle: { 50 | default: { fontColorUnselected: white, selection: selection, fontColorSelected: white, font: default-font }, 51 | dimmed: { background: dialogDim, fontColorUnselected: white, selection: selection, fontColorSelected: white, font: default-font } 52 | }, 53 | com.badlogic.gdx.scenes.scene2d.ui.Touchpad$TouchpadStyle: { 54 | default: { background: default-pane, knob: default-round-large } 55 | }, 56 | com.badlogic.gdx.scenes.scene2d.ui.Tree$TreeStyle: { 57 | default: { minus: tree-minus, plus: tree-plus, selection: default-select-selection } 58 | }, 59 | com.badlogic.gdx.scenes.scene2d.ui.ProgressBar$ProgressBarStyle: { 60 | default: { background: default-scroll, knobBefore: default-round-large } 61 | }, 62 | com.badlogic.gdx.scenes.scene2d.ui.ImageButton$ImageButtonStyle: { 63 | default: { down: default-round-down, up: default-round, imageUp: paint_brush } 64 | }, 65 | com.badlogic.gdx.scenes.scene2d.ui.SelectBox$SelectBoxStyle: { 66 | default: { 67 | font: default-font, fontColor: white, background: default-select, 68 | scrollStyle: default, 69 | listStyle: default, 70 | } 71 | }, 72 | 73 | } 74 | 75 | -------------------------------------------------------------------------------- /assets/resources/uiskin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/assets/resources/uiskin.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } 5 | } 6 | } 7 | 8 | allprojects { 9 | apply plugin: "eclipse" 10 | apply plugin: "idea" 11 | 12 | version = "1.0" 13 | ext { 14 | appName = "SkinEditor" 15 | gdxVersion = "1.0.2-SNAPSHOT" 16 | } 17 | 18 | repositories { 19 | mavenLocal(); 20 | mavenCentral() 21 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } 22 | } 23 | } 24 | 25 | project(":core") { 26 | apply plugin: "java" 27 | 28 | dependencies { 29 | compile "com.badlogicgames.gdx:gdx:$gdxVersion" 30 | compile "com.badlogicgames.gdx:gdx-tools:$gdxVersion" 31 | } 32 | } 33 | 34 | project(":desktop") { 35 | apply plugin: "java" 36 | 37 | dependencies { 38 | compile project(":core") 39 | compile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" 40 | compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" 41 | } 42 | } 43 | 44 | 45 | tasks.eclipse.doLast { 46 | delete ".project" 47 | } 48 | -------------------------------------------------------------------------------- /core/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | 3 | sourceCompatibility = 1.6 4 | 5 | dependencies { 6 | compile "com.badlogicgames.gdx:gdx:$gdxVersion" 7 | } 8 | 9 | sourceSets.main.java.srcDirs = [ "src/" ] 10 | 11 | eclipse.project { 12 | name = appName + "-core" 13 | } 14 | -------------------------------------------------------------------------------- /core/src/com/badlogic/gdx/tools/hiero/BMFontUtil.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.gdx.tools.hiero; 18 | 19 | import java.awt.Font; 20 | import java.awt.font.GlyphMetrics; 21 | import java.awt.font.GlyphVector; 22 | import java.awt.image.BufferedImage; 23 | import java.awt.image.WritableRaster; 24 | import java.io.File; 25 | import java.io.FileOutputStream; 26 | import java.io.IOException; 27 | import java.io.PrintStream; 28 | import java.nio.IntBuffer; 29 | import java.util.ArrayList; 30 | import java.util.HashMap; 31 | import java.util.Iterator; 32 | import java.util.List; 33 | import java.util.Map; 34 | 35 | import javax.imageio.ImageIO; 36 | 37 | import org.lwjgl.BufferUtils; 38 | import org.lwjgl.opengl.GL11; 39 | import org.lwjgl.opengl.GL12; 40 | 41 | import sun.security.action.GetLongAction; 42 | 43 | import com.badlogic.gdx.Gdx; 44 | import com.badlogic.gdx.tools.hiero.unicodefont.Glyph; 45 | import com.badlogic.gdx.tools.hiero.unicodefont.GlyphPage; 46 | import com.badlogic.gdx.tools.hiero.unicodefont.UnicodeFont; 47 | 48 | /** @author Nathan Sweet */ 49 | public class BMFontUtil { 50 | private final UnicodeFont unicodeFont; 51 | 52 | public BMFontUtil (UnicodeFont unicodeFont) { 53 | this.unicodeFont = unicodeFont; 54 | } 55 | 56 | public void save (File outputBMFontFile) throws IOException { 57 | File outputDir = outputBMFontFile.getParentFile(); 58 | String outputName = outputBMFontFile.getName(); 59 | if (outputName.endsWith(".fnt")) outputName = outputName.substring(0, outputName.length() - 4); 60 | 61 | unicodeFont.setGlyphPageHeight(1024); 62 | 63 | unicodeFont.loadGlyphs(); 64 | 65 | // This is a tweak to limit texture height to minimum 66 | GlyphPage p = (GlyphPage) unicodeFont.getGlyphPages().get(0); 67 | int realHeight = p.getPageY() + unicodeFont.getLineHeight()+5; // keep space for shadow 68 | 69 | Gdx.app.log("BMFontUtil", "Real texture height: " + realHeight); 70 | 71 | PrintStream out = new PrintStream(new FileOutputStream(new File(outputDir, outputName + ".fnt"))); 72 | Font font = unicodeFont.getFont(); 73 | int pageWidth = unicodeFont.getGlyphPageWidth(); 74 | int pageHeight = unicodeFont.getGlyphPageHeight(); 75 | out.println("info face=\"" + font.getFontName() + "\" size=" + font.getSize() + " bold=" + (font.isBold() ? 1 : 0) 76 | + " italic=" + (font.isItalic() ? 1 : 0) + " charset=\"\" unicode=0 stretchH=100 smooth=1 aa=1 padding=" 77 | + unicodeFont.getPaddingTop() + "," + unicodeFont.getPaddingLeft() + "," + unicodeFont.getPaddingBottom() + "," 78 | + unicodeFont.getPaddingRight() + " spacing=" + unicodeFont.getPaddingAdvanceX() + "," 79 | + unicodeFont.getPaddingAdvanceY()); 80 | out.println("common lineHeight=" + unicodeFont.getLineHeight() + " base=" + unicodeFont.getAscent() + " scaleW=" 81 | + pageWidth + " scaleH=" + pageHeight + " pages=" + unicodeFont.getGlyphPages().size() + " packed=0"); 82 | 83 | int pageIndex = 0, glyphCount = 0; 84 | for (Iterator pageIter = unicodeFont.getGlyphPages().iterator(); pageIter.hasNext();) { 85 | GlyphPage page = (GlyphPage)pageIter.next(); 86 | String fileName; 87 | if (pageIndex == 0 && !pageIter.hasNext()) 88 | fileName = outputName + ".png"; 89 | else 90 | fileName = outputName + (pageIndex + 1) + ".png"; 91 | out.println("page id=" + pageIndex + " file=\"" + fileName + "\""); 92 | glyphCount += page.getGlyphs().size(); 93 | pageIndex++; 94 | } 95 | 96 | out.println("chars count=" + glyphCount); 97 | 98 | // Always output space entry (codepoint 32). 99 | int[] glyphMetrics = getGlyphMetrics(font, 32); 100 | int xAdvance = glyphMetrics[1]; 101 | out.println("char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=" + unicodeFont.getAscent() 102 | + " xadvance=" + xAdvance + " page=0 chnl=0 "); 103 | 104 | pageIndex = 0; 105 | List allGlyphs = new ArrayList(512); 106 | for (Iterator pageIter = unicodeFont.getGlyphPages().iterator(); pageIter.hasNext();) { 107 | GlyphPage page = (GlyphPage)pageIter.next(); 108 | for (Iterator glyphIter = page.getGlyphs().iterator(); glyphIter.hasNext();) { 109 | Glyph glyph = (Glyph)glyphIter.next(); 110 | 111 | glyphMetrics = getGlyphMetrics(font, glyph.getCodePoint()); 112 | int xOffset = glyphMetrics[0]; 113 | xAdvance = glyphMetrics[1]; 114 | 115 | out.println("char id=" + glyph.getCodePoint() + " " + "x=" + (int)(glyph.getU() * pageWidth) + " y=" 116 | + (int)(glyph.getV() * pageHeight) + " width=" + glyph.getWidth() + " height=" + glyph.getHeight() 117 | + " xoffset=" + xOffset + " yoffset=" + glyph.getYOffset() + " xadvance=" + xAdvance + " page=" 118 | + pageIndex + " chnl=0 "); 119 | } 120 | allGlyphs.addAll(page.getGlyphs()); 121 | pageIndex++; 122 | } 123 | 124 | String ttfFileRef = unicodeFont.getFontFile(); 125 | if (ttfFileRef == null) 126 | System.out.println("Kerning information could not be output because a TTF font file was not specified."); 127 | else { 128 | Kerning kerning = new Kerning(); 129 | try { 130 | kerning.load(Gdx.files.internal(ttfFileRef).read(), font.getSize()); 131 | } catch (IOException ex) { 132 | System.out.println("Unable to read kerning information from font: " + ttfFileRef); 133 | } 134 | 135 | Map glyphCodeToCodePoint = new HashMap(); 136 | for (Iterator iter = allGlyphs.iterator(); iter.hasNext();) { 137 | Glyph glyph = (Glyph)iter.next(); 138 | glyphCodeToCodePoint.put(new Integer(getGlyphCode(font, glyph.getCodePoint())), new Integer(glyph.getCodePoint())); 139 | } 140 | 141 | List kernings = new ArrayList(256); 142 | class KerningPair { 143 | public int firstCodePoint, secondCodePoint, offset; 144 | } 145 | for (Iterator iter1 = allGlyphs.iterator(); iter1.hasNext();) { 146 | Glyph firstGlyph = (Glyph)iter1.next(); 147 | int firstGlyphCode = getGlyphCode(font, firstGlyph.getCodePoint()); 148 | int[] values = kerning.getValues(firstGlyphCode); 149 | if (values == null) continue; 150 | for (int i = 0; i < values.length; i++) { 151 | Integer secondCodePoint = (Integer)glyphCodeToCodePoint.get(new Integer(values[i] & 0xffff)); 152 | if (secondCodePoint == null) continue; // We may not be outputting the second character. 153 | int offset = values[i] >> 16; 154 | KerningPair pair = new KerningPair(); 155 | pair.firstCodePoint = firstGlyph.getCodePoint(); 156 | pair.secondCodePoint = secondCodePoint.intValue(); 157 | pair.offset = offset; 158 | kernings.add(pair); 159 | } 160 | } 161 | out.println("kernings count=" + kerning.getCount()); 162 | for (Iterator iter = kernings.iterator(); iter.hasNext();) { 163 | KerningPair pair = (KerningPair)iter.next(); 164 | out.println("kerning first=" + pair.firstCodePoint + " second=" + pair.secondCodePoint + " amount=" + pair.offset); 165 | } 166 | } 167 | out.close(); 168 | 169 | int width = unicodeFont.getGlyphPageWidth(); 170 | int height = unicodeFont.getGlyphPageHeight(); 171 | IntBuffer buffer = BufferUtils.createIntBuffer(width * height); 172 | BufferedImage pageImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 173 | int[] row = new int[width]; 174 | 175 | pageIndex = 0; 176 | for (Iterator pageIter = unicodeFont.getGlyphPages().iterator(); pageIter.hasNext();) { 177 | GlyphPage page = (GlyphPage)pageIter.next(); 178 | String fileName; 179 | if (pageIndex == 0 && !pageIter.hasNext()) 180 | fileName = outputName + ".png"; 181 | else 182 | fileName = outputName + (pageIndex + 1) + ".png"; 183 | 184 | page.getTexture().bind(); 185 | buffer.clear(); 186 | GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, buffer); 187 | WritableRaster raster = pageImage.getRaster(); 188 | for (int y = 0; y < height; y++) { 189 | buffer.get(row); 190 | raster.setDataElements(0, y, width, 1, row); 191 | } 192 | File imageOutputFile = new File(outputDir, fileName); 193 | 194 | if (realHeight < height) { 195 | ImageIO.write(pageImage.getSubimage(0, 0, width, realHeight), "png", imageOutputFile); 196 | } else { 197 | ImageIO.write(pageImage, "png", imageOutputFile); 198 | } 199 | pageIndex++; 200 | } 201 | } 202 | 203 | private int getGlyphCode (Font font, int codePoint) { 204 | char[] chars = Character.toChars(codePoint); 205 | GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); 206 | return vector.getGlyphCode(0); 207 | } 208 | 209 | private int[] getGlyphMetrics (Font font, int codePoint) { 210 | // xOffset and xAdvance will be incorrect for unicode characters such as combining marks or non-spacing characters 211 | // (eg Pnujabi's "\u0A1C\u0A47") that require the context of surrounding glyphs to determine spacing, but thisis the 212 | // best we can do with the BMFont format. 213 | char[] chars = Character.toChars(codePoint); 214 | GlyphVector vector = font.layoutGlyphVector(GlyphPage.renderContext, chars, 0, chars.length, Font.LAYOUT_LEFT_TO_RIGHT); 215 | GlyphMetrics metrics = vector.getGlyphMetrics(0); 216 | int xOffset = vector.getGlyphPixelBounds(0, GlyphPage.renderContext, 0.5f, 0).x - unicodeFont.getPaddingLeft(); 217 | int xAdvance = (int)(metrics.getAdvanceX() + unicodeFont.getPaddingAdvanceX() + unicodeFont.getPaddingLeft() + unicodeFont 218 | .getPaddingRight()); 219 | return new int[] {xOffset, xAdvance}; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /core/src/com/badlogic/gdx/tools/hiero/unicodefont/GlyphPage.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.gdx.tools.hiero.unicodefont; 18 | 19 | import java.awt.AlphaComposite; 20 | import java.awt.Graphics2D; 21 | import java.awt.RenderingHints; 22 | import java.awt.font.FontRenderContext; 23 | import java.awt.image.BufferedImage; 24 | import java.awt.image.WritableRaster; 25 | import java.nio.ByteBuffer; 26 | import java.nio.ByteOrder; 27 | import java.nio.IntBuffer; 28 | import java.util.ArrayList; 29 | import java.util.Iterator; 30 | import java.util.List; 31 | import java.util.ListIterator; 32 | 33 | import org.lwjgl.opengl.GL11; 34 | import org.lwjgl.opengl.GL12; 35 | 36 | import com.badlogic.gdx.graphics.Pixmap.Format; 37 | import com.badlogic.gdx.graphics.Texture; 38 | import com.badlogic.gdx.tools.hiero.unicodefont.effects.ColorEffect; 39 | import com.badlogic.gdx.tools.hiero.unicodefont.effects.Effect; 40 | 41 | /** Stores a number of glyphs on a single texture. 42 | * @author Nathan Sweet */ 43 | public class GlyphPage { 44 | private final UnicodeFont unicodeFont; 45 | private final int pageWidth, pageHeight; 46 | private final Texture texture; 47 | private int pageX, pageY, rowHeight; 48 | private boolean orderAscending; 49 | private final List pageGlyphs = new ArrayList(32); 50 | 51 | /** @param pageWidth The width of the backing texture. 52 | * @param pageHeight The height of the backing texture. */ 53 | GlyphPage (UnicodeFont unicodeFont, int pageWidth, int pageHeight) { 54 | this.unicodeFont = unicodeFont; 55 | this.pageWidth = pageWidth; 56 | this.pageHeight = pageHeight; 57 | 58 | texture = new Texture(pageWidth, pageHeight, Format.RGBA8888); 59 | } 60 | 61 | /** Loads glyphs to the backing texture and sets the image on each loaded glyph. Loaded glyphs are removed from the list. 62 | * 63 | * If this page already has glyphs and maxGlyphsToLoad is -1, then this method will return 0 if all the new glyphs don't fit. 64 | * This reduces texture binds when drawing since glyphs loaded at once are typically displayed together. 65 | * @param glyphs The glyphs to load. 66 | * @param maxGlyphsToLoad This is the maximum number of glyphs to load from the list. Set to -1 to attempt to load all the 67 | * glyphs. 68 | * @return The number of glyphs that were actually loaded. */ 69 | int loadGlyphs (List glyphs, int maxGlyphsToLoad) { 70 | if (rowHeight != 0 && maxGlyphsToLoad == -1) { 71 | // If this page has glyphs and we are not loading incrementally, return zero if any of the glyphs don't fit. 72 | int testX = pageX; 73 | int testY = pageY; 74 | int testRowHeight = rowHeight; 75 | for (Iterator iter = getIterator(glyphs); iter.hasNext();) { 76 | Glyph glyph = (Glyph)iter.next(); 77 | int width = glyph.getWidth(); 78 | int height = glyph.getHeight(); 79 | if (testX + width >= pageWidth) { 80 | testX = 0; 81 | testY += testRowHeight; 82 | testRowHeight = height; 83 | } else if (height > testRowHeight) { 84 | testRowHeight = height; 85 | } 86 | if (testY + testRowHeight >= pageWidth) return 0; 87 | testX += width; 88 | } 89 | } 90 | 91 | GL11.glColor4f(1, 1, 1, 1); 92 | texture.bind(); 93 | 94 | int i = 0; 95 | for (Iterator iter = getIterator(glyphs); iter.hasNext();) { 96 | Glyph glyph = (Glyph)iter.next(); 97 | int width = Math.min(MAX_GLYPH_SIZE, glyph.getWidth()); 98 | int height = Math.min(MAX_GLYPH_SIZE, glyph.getHeight()); 99 | 100 | if (rowHeight == 0) { 101 | // The first glyph always fits. 102 | rowHeight = height; 103 | } else { 104 | // Wrap to the next line if needed, or break if no more fit. 105 | if (pageX + width >= pageWidth) { 106 | if (pageY + rowHeight + height >= pageHeight) break; 107 | pageX = 0; 108 | pageY += rowHeight; 109 | rowHeight = height; 110 | } else if (height > rowHeight) { 111 | if (pageY + height >= pageHeight) break; 112 | rowHeight = height; 113 | } 114 | } 115 | 116 | renderGlyph(glyph, width, height); 117 | pageGlyphs.add(glyph); 118 | 119 | pageX += width; 120 | 121 | iter.remove(); 122 | i++; 123 | if (i == maxGlyphsToLoad) { 124 | // If loading incrementally, flip orderAscending so it won't change, since we'll probably load the rest next time. 125 | orderAscending = !orderAscending; 126 | break; 127 | } 128 | } 129 | 130 | // Every other batch of glyphs added to a page are sorted the opposite way to attempt to keep same size glyps together. 131 | orderAscending = !orderAscending; 132 | 133 | return i; 134 | } 135 | 136 | /** Loads a single glyph to the backing texture, if it fits. */ 137 | private void renderGlyph (Glyph glyph, int width, int height) { 138 | 139 | // Draw the glyph to the scratch image using Java2D. 140 | scratchGraphics.setComposite(AlphaComposite.Clear); 141 | scratchGraphics.fillRect(0, 0, MAX_GLYPH_SIZE, MAX_GLYPH_SIZE); 142 | scratchGraphics.setComposite(AlphaComposite.SrcOver); 143 | if (unicodeFont.getNativeRendering()) { 144 | for (Iterator iter = unicodeFont.getEffects().iterator(); iter.hasNext();) { 145 | Effect effect = (Effect)iter.next(); 146 | if (effect instanceof ColorEffect) scratchGraphics.setColor(((ColorEffect)effect).getColor()); 147 | } 148 | scratchGraphics.setColor(java.awt.Color.white); 149 | scratchGraphics.setFont(unicodeFont.getFont()); 150 | scratchGraphics.drawString("" + (char)glyph.getCodePoint(), 0, unicodeFont.getAscent()); 151 | } else { 152 | scratchGraphics.setColor(java.awt.Color.white); 153 | for (Iterator iter = unicodeFont.getEffects().iterator(); iter.hasNext();) 154 | ((Effect)iter.next()).draw(scratchImage, scratchGraphics, unicodeFont, glyph); 155 | glyph.setShape(null); // The shape will never be needed again. 156 | } 157 | 158 | width = Math.min(width, texture.getWidth()); 159 | height = Math.min(height, texture.getHeight()); 160 | 161 | WritableRaster raster = scratchImage.getRaster(); 162 | int[] row = new int[width]; 163 | for (int y = 0; y < height; y++) { 164 | raster.getDataElements(0, y, width, 1, row); 165 | scratchIntBuffer.put(row); 166 | } 167 | GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, pageX, pageY, width, height, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, 168 | scratchByteBuffer); 169 | scratchIntBuffer.clear(); 170 | 171 | float u = pageX / (float)texture.getWidth(); 172 | float v = pageY / (float)texture.getHeight(); 173 | float u2 = (pageX + width) / (float)texture.getWidth(); 174 | float v2 = (pageY + height) / (float)texture.getHeight(); 175 | glyph.setTexture(texture, u, v, u2, v2); 176 | } 177 | 178 | /** Returns an iterator for the specified glyphs, sorted either ascending or descending. */ 179 | private Iterator getIterator (List glyphs) { 180 | if (orderAscending) return glyphs.iterator(); 181 | final ListIterator iter = glyphs.listIterator(glyphs.size()); 182 | return new Iterator() { 183 | public boolean hasNext () { 184 | return iter.hasPrevious(); 185 | } 186 | 187 | public Object next () { 188 | return iter.previous(); 189 | } 190 | 191 | public void remove () { 192 | iter.remove(); 193 | } 194 | }; 195 | } 196 | 197 | /** Returns the glyphs stored on this page. */ 198 | public List getGlyphs () { 199 | return pageGlyphs; 200 | } 201 | 202 | /** Returns the backing texture for this page. */ 203 | public Texture getTexture () { 204 | return texture; 205 | } 206 | 207 | static public final int MAX_GLYPH_SIZE = 256; 208 | 209 | static private ByteBuffer scratchByteBuffer = ByteBuffer.allocateDirect(MAX_GLYPH_SIZE * MAX_GLYPH_SIZE * 4); 210 | static { 211 | scratchByteBuffer.order(ByteOrder.LITTLE_ENDIAN); 212 | } 213 | static private IntBuffer scratchIntBuffer = scratchByteBuffer.asIntBuffer(); 214 | 215 | static private BufferedImage scratchImage = new BufferedImage(MAX_GLYPH_SIZE, MAX_GLYPH_SIZE, BufferedImage.TYPE_INT_ARGB); 216 | static Graphics2D scratchGraphics = (Graphics2D)scratchImage.getGraphics(); 217 | static { 218 | scratchGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 219 | scratchGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 220 | } 221 | static public FontRenderContext renderContext = scratchGraphics.getFontRenderContext(); 222 | 223 | /** 224 | * Return page maximum height, used by skin editor. 225 | */ 226 | public int getPageY() { 227 | return pageY; 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /core/src/com/mobidevelop/maps/editor/ui/utils/Tooltips.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013 See AUTHORS File 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.mobidevelop.maps.editor.ui.utils; 18 | 19 | import static com.badlogic.gdx.scenes.scene2d.actions.Actions.fadeIn; 20 | import static com.badlogic.gdx.scenes.scene2d.actions.Actions.parallel; 21 | import static com.badlogic.gdx.scenes.scene2d.actions.Actions.scaleTo; 22 | 23 | import com.badlogic.gdx.graphics.Color; 24 | import com.badlogic.gdx.graphics.g2d.BitmapFont; 25 | import com.badlogic.gdx.math.Vector2; 26 | import com.badlogic.gdx.scenes.scene2d.Actor; 27 | import com.badlogic.gdx.scenes.scene2d.InputEvent; 28 | import com.badlogic.gdx.scenes.scene2d.InputListener; 29 | import com.badlogic.gdx.scenes.scene2d.Stage; 30 | import com.badlogic.gdx.scenes.scene2d.ui.Label; 31 | import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; 32 | import com.badlogic.gdx.scenes.scene2d.ui.Skin; 33 | import com.badlogic.gdx.scenes.scene2d.utils.Drawable; 34 | import com.badlogic.gdx.utils.ObjectMap; 35 | import com.badlogic.gdx.utils.Timer; 36 | import com.badlogic.gdx.utils.Timer.Task; 37 | 38 | /** 39 | * Manages showing and hiding tooltips registered for actors on a {@link Stage}. 40 | * 41 | * @author Justin Shapcott 42 | */ 43 | public class Tooltips { 44 | 45 | private ObjectMap tooltips; 46 | 47 | private InputListener listener; 48 | 49 | private Stage stage; 50 | 51 | private Task show; 52 | 53 | private Task hide; 54 | 55 | private Label tooltip; 56 | 57 | private TooltipStyle tooltipStyle; 58 | 59 | public Tooltips(Skin skin, Stage stage) { 60 | this(skin.get(TooltipStyle.class), stage); 61 | } 62 | 63 | public Tooltips(Skin skin, String styleName, Stage stage) { 64 | this(skin.get(styleName, TooltipStyle.class), stage); 65 | } 66 | 67 | public Tooltips(TooltipStyle style, Stage stage) { 68 | this.tooltips =new ObjectMap(); 69 | this.stage = stage; 70 | this.tooltipStyle = style; 71 | this.listener = new InputListener() { 72 | @Override 73 | public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) { 74 | Actor actor = event.getTarget(); 75 | while (actor.getParent() != null) { 76 | if (tooltips.containsKey(actor)) { 77 | if (hide != null && hide.isScheduled()) { 78 | hide.cancel(); 79 | } 80 | if (tooltip == null) { 81 | final Actor finalActor = actor; 82 | show = new Task() { 83 | @Override 84 | public void run() { 85 | showTooltip(finalActor); 86 | } 87 | }; 88 | Timer.schedule(show, 1); 89 | } else { 90 | showTooltip(actor); 91 | } 92 | break; 93 | } 94 | actor = actor.getParent(); 95 | } 96 | } 97 | 98 | @Override 99 | public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) { 100 | if (show != null && show.isScheduled()) { 101 | show.cancel(); 102 | } 103 | hideTooltip(); 104 | } 105 | 106 | @Override 107 | public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { 108 | if (show != null && show.isScheduled()) { 109 | show.cancel(); 110 | } 111 | hideTooltipImmediate(); 112 | return false; 113 | } 114 | }; 115 | stage.addListener(listener); 116 | } 117 | 118 | public void registerTooltip(Actor actor, String tip) { 119 | tooltips.put(actor, tip); 120 | } 121 | 122 | public void unregisterToolip(Actor actor) { 123 | tooltips.remove(actor); 124 | } 125 | 126 | public void showTooltip(Actor actor) { 127 | Vector2 v = new Vector2(); 128 | actor.localToStageCoordinates(v); 129 | if (tooltip == null) { 130 | LabelStyle style = new LabelStyle(); 131 | style.font = tooltipStyle.font; 132 | style.background = tooltipStyle.background; 133 | style.fontColor = tooltipStyle.fontColor; 134 | tooltip = new Label(tooltips.get(actor), style); 135 | tooltip.setStyle(style); 136 | tooltip.pack(); 137 | tooltip.setPosition(v.x+7.5f, v.y - tooltip.getPrefHeight() - 15); 138 | 139 | tooltip.setOriginY(tooltip.getPrefHeight()); 140 | tooltip.setColor(1, 1, 1, 0); 141 | tooltip.setScale(1,0); 142 | tooltip.addAction(parallel(fadeIn(0.15f), scaleTo(1, 1, 0.15f))); 143 | } else { 144 | tooltip.setText(tooltips.get(actor)); 145 | tooltip.pack(); 146 | tooltip.setPosition(v.x+7.5f, v.y - tooltip.getPrefHeight() - 15); 147 | } 148 | stage.addActor(tooltip); 149 | } 150 | 151 | public void hideTooltip() { 152 | if (tooltip != null) { 153 | tooltip.remove(); 154 | if (hide == null || !hide.isScheduled()) { 155 | hide = new Task() { 156 | @Override 157 | public void run() { 158 | if (tooltip != null) { 159 | tooltip = null; 160 | } 161 | } 162 | }; 163 | Timer.schedule(hide, 1); 164 | } 165 | } 166 | } 167 | 168 | private void hideTooltipImmediate() { 169 | if (tooltip != null) { 170 | tooltip.remove(); 171 | tooltip = null; 172 | } 173 | } 174 | 175 | static public class TooltipStyle { 176 | 177 | public BitmapFont font; 178 | public Drawable background; 179 | public Color fontColor; 180 | 181 | public TooltipStyle() { 182 | } 183 | 184 | public TooltipStyle(BitmapFont font, Drawable background, Color fontColor) { 185 | this.font = font; 186 | this.background = background; 187 | this.fontColor = fontColor; 188 | } 189 | 190 | public TooltipStyle (TooltipStyle style) { 191 | this.font = style.font; 192 | if (style.fontColor != null) fontColor = new Color(style.fontColor); 193 | background = style.background; 194 | } 195 | 196 | } 197 | 198 | } -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/ColorPickerDialog.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor; 17 | 18 | import java.awt.Frame; 19 | import java.util.Iterator; 20 | 21 | import javax.swing.JColorChooser; 22 | import javax.swing.JOptionPane; 23 | 24 | import com.badlogic.gdx.Gdx; 25 | import com.badlogic.gdx.graphics.Color; 26 | import com.badlogic.gdx.graphics.Pixmap; 27 | import com.badlogic.gdx.graphics.Texture; 28 | import com.badlogic.gdx.graphics.g2d.Sprite; 29 | import com.badlogic.gdx.scenes.scene2d.Actor; 30 | import com.badlogic.gdx.scenes.scene2d.Stage; 31 | import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 32 | import com.badlogic.gdx.scenes.scene2d.ui.Image; 33 | import com.badlogic.gdx.scenes.scene2d.ui.Label; 34 | import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 35 | import com.badlogic.gdx.scenes.scene2d.ui.Skin; 36 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 37 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton; 38 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; 39 | import com.badlogic.gdx.scenes.scene2d.utils.SpriteDrawable; 40 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent; 41 | import com.badlogic.gdx.utils.ObjectMap; 42 | import com.badlogic.gdx.utils.reflect.ClassReflection; 43 | import com.badlogic.gdx.utils.reflect.Field; 44 | 45 | /** 46 | * A color picker class that allow to create and re-use colors across 47 | * the skin. It uses Swing color picker. 48 | * 49 | * @author Yanick Bourbeau 50 | * 51 | */ 52 | public class ColorPickerDialog extends Dialog { 53 | 54 | private SkinEditorGame game; 55 | private Table tableColors; 56 | ObjectMap colors; 57 | private Field field; 58 | 59 | /** 60 | * 61 | */ 62 | public ColorPickerDialog(final SkinEditorGame game, final Field field) { 63 | 64 | super("Color Picker", game.skin); 65 | 66 | this.game = game; 67 | this.field = field; 68 | 69 | tableColors = new Table(game.skin); 70 | tableColors.left().top().pad(5); 71 | tableColors.defaults().pad(5); 72 | colors = game.skinProject.getAll(Color.class); 73 | 74 | updateTable(); 75 | 76 | 77 | TextButton buttonNewColor = new TextButton("New Color", game.skin); 78 | buttonNewColor.addListener(new ChangeListener() { 79 | 80 | @Override 81 | public void changed(ChangeEvent event, Actor actor) { 82 | 83 | // Need to steal focus first with this hack (Thanks to Z-Man) 84 | Frame frame = new Frame(); 85 | frame.setUndecorated(true); 86 | frame.setOpacity(0); 87 | frame.setLocationRelativeTo(null); 88 | frame.setVisible(true); 89 | frame.toFront(); 90 | frame.setVisible(false); 91 | frame.dispose(); 92 | 93 | // Call swing color picker 94 | java.awt.Color color = JColorChooser.showDialog(null, "Pick your color", java.awt.Color.WHITE); 95 | if (color != null) { 96 | 97 | String colorName = JOptionPane.showInputDialog("Name your color"); 98 | 99 | if ((colorName != null) && (colorName.isEmpty() == false)) { 100 | // Verify if the color name is already in use 101 | if (colors.containsKey(colorName) == true) { 102 | game.showNotice("Error", "Color name already in use!", game.screenMain.stage); 103 | } else { 104 | // Add the color (asuming RGBA) 105 | float[] components = color.getComponents(null); 106 | Color newColor = new Color(components[0], components[1], components[2], components[3]); 107 | if (isColorInUse(newColor)) { 108 | game.showNotice("Error","Same color value (" + newColor.toString() + ") is already defined with a different name!", game.screenMain.stage); 109 | return; 110 | } 111 | 112 | 113 | colors.put(colorName, newColor); 114 | game.screenMain.saveToSkin(); 115 | 116 | // update table 117 | updateTable(); 118 | } 119 | } 120 | } 121 | 122 | } 123 | 124 | }); 125 | 126 | TextButton buttonNoColor = new TextButton("Empty Color", game.skin); 127 | buttonNoColor.addListener(new ChangeListener() { 128 | 129 | @Override 130 | public void changed(ChangeEvent event, Actor actor) { 131 | 132 | try { 133 | field.set(game.screenMain.paneOptions.currentStyle, null); 134 | } catch (Exception e) { 135 | e.printStackTrace(); 136 | } 137 | 138 | game.screenMain.saveToSkin(); 139 | 140 | hide(); 141 | game.screenMain.panePreview.refresh(); 142 | game.screenMain.paneOptions.updateSelectedTableFields(); 143 | 144 | } 145 | 146 | }); 147 | 148 | ScrollPane scrollPane = new ScrollPane(tableColors, game.skin); 149 | scrollPane.setFlickScroll(false); 150 | scrollPane.setFadeScrollBars(false); 151 | scrollPane.setScrollbarsOnTop(true); 152 | 153 | getContentTable().add(scrollPane).width(540).height(320).pad(20); 154 | getButtonTable().add(buttonNewColor); 155 | if (field != null) { 156 | getButtonTable().add(buttonNoColor); 157 | } 158 | getButtonTable().padBottom(15); 159 | button("Cancel", false); 160 | key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 161 | 162 | 163 | } 164 | 165 | /** 166 | * Refresh table content with colors from the skin 167 | */ 168 | public void updateTable() { 169 | 170 | tableColors.clear(); 171 | tableColors.add(new Label("Color Name", game.skin, "title")).left().width(170); 172 | tableColors.add(new Label("Value", game.skin, "title")).colspan(2).left().width(60).padRight(50); 173 | 174 | tableColors.row(); 175 | 176 | Iterator it = colors.keys().iterator(); 177 | while (it.hasNext()) { 178 | final String key = it.next(); 179 | final Color color = colors.get(key); 180 | 181 | tableColors.add(key).left(); 182 | 183 | // Create drawable on the fly 184 | Pixmap pixmap = new Pixmap(18, 18, Pixmap.Format.RGBA8888); 185 | pixmap.setColor(color); 186 | pixmap.fill(); 187 | pixmap.setColor(Color.BLACK); 188 | pixmap.drawRectangle(0, 0, 18, 18); 189 | Texture texture = new Texture(pixmap); 190 | pixmap.dispose(); 191 | tableColors.add(new Image(texture)); 192 | tableColors.add(color.toString()).left(); 193 | 194 | TextButton buttonSelect = new TextButton("Select", game.skin); 195 | buttonSelect.addListener(new ChangeListener() { 196 | 197 | @Override 198 | public void changed(ChangeEvent event, Actor actor) { 199 | try { 200 | field.set(game.screenMain.paneOptions.currentStyle, color); 201 | } catch (Exception e) { 202 | e.printStackTrace(); 203 | } 204 | 205 | hide(); 206 | game.screenMain.panePreview.refresh(); 207 | game.screenMain.paneOptions.updateSelectedTableFields(); 208 | game.screenMain.saveToSkin(); 209 | 210 | 211 | } 212 | 213 | }); 214 | 215 | TextButton buttonRemove = new TextButton("Remove", game.skin); 216 | buttonRemove.addListener(new ChangeListener() { 217 | 218 | @Override 219 | public void changed(ChangeEvent event, Actor actor) { 220 | 221 | Dialog dlg = new Dialog("Delete Style", game.skin) { 222 | 223 | @Override 224 | protected void result(Object object) { 225 | if ((Boolean) object == false) { 226 | return; 227 | } 228 | 229 | if (isColorInUse(color) == true) { 230 | 231 | game.showNotice("Error", "Color already in use!", game.screenMain.stage); 232 | 233 | } else { 234 | 235 | colors.remove(key); 236 | // update table 237 | updateTable(); 238 | game.screenMain.saveToSkin(); 239 | 240 | } 241 | } 242 | 243 | }; 244 | 245 | dlg.pad(20); 246 | dlg.getContentTable().add("You are sure you want to delete this color?"); 247 | dlg.button("OK", true); 248 | dlg.button("Cancel", false); 249 | dlg.key(com.badlogic.gdx.Input.Keys.ENTER, true); 250 | dlg.key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 251 | dlg.show(game.screenMain.stage); 252 | 253 | 254 | } 255 | 256 | }); 257 | 258 | if (field != null) { 259 | tableColors.add(buttonSelect).padRight(5); 260 | } 261 | tableColors.add(buttonRemove); 262 | tableColors.row(); 263 | } 264 | 265 | } 266 | 267 | 268 | /** 269 | * Check if the color is already in use somewhere else in the skin 270 | */ 271 | public boolean isColorInUse(Color color) { 272 | 273 | try { 274 | // Check if it is already in use somewhere! 275 | for (String widget : SkinEditorGame.widgets) { 276 | String widgetStyle = "com.badlogic.gdx.scenes.scene2d.ui." + widget + "$" + widget + "Style"; 277 | Class style = Class.forName(widgetStyle); 278 | ObjectMap styles = game.skinProject.getAll(style); 279 | Iterator it = styles.keys().iterator(); 280 | while (it.hasNext()) { 281 | Object item = styles.get((String) it.next()); 282 | Field[] fields = ClassReflection.getFields(item.getClass()); 283 | for (Field field : fields) { 284 | 285 | if (field.getType() == Color.class) { 286 | 287 | Color c = (Color) field.get(item); 288 | if (color.equals(c)) { 289 | return true; 290 | } 291 | 292 | } 293 | 294 | } 295 | 296 | } 297 | 298 | } 299 | } catch (Exception e) { 300 | e.printStackTrace(); 301 | 302 | } 303 | 304 | return false; 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/DrawablePickerDialog.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor; 17 | 18 | import java.awt.Frame; 19 | import java.io.File; 20 | import java.util.Iterator; 21 | 22 | import javax.swing.JFileChooser; 23 | import javax.swing.JOptionPane; 24 | import javax.swing.filechooser.FileNameExtensionFilter; 25 | 26 | import com.badlogic.gdx.files.FileHandle; 27 | import com.badlogic.gdx.graphics.g2d.NinePatch; 28 | import com.badlogic.gdx.graphics.g2d.Sprite; 29 | import com.badlogic.gdx.graphics.g2d.TextureRegion; 30 | import com.badlogic.gdx.scenes.scene2d.Actor; 31 | import com.badlogic.gdx.scenes.scene2d.Stage; 32 | import com.badlogic.gdx.scenes.scene2d.ui.Button; 33 | import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 34 | import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup; 35 | import com.badlogic.gdx.scenes.scene2d.ui.Image; 36 | import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; 37 | import com.badlogic.gdx.scenes.scene2d.ui.Label; 38 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 39 | import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 40 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton; 41 | import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup; 42 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; 43 | import com.badlogic.gdx.scenes.scene2d.utils.Drawable; 44 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent; 45 | import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable; 46 | import com.badlogic.gdx.scenes.scene2d.utils.SpriteDrawable; 47 | import com.badlogic.gdx.utils.ObjectMap; 48 | import com.badlogic.gdx.utils.reflect.Field; 49 | 50 | /** 51 | * Display a dialog allowing to pick a drawable resource such as a ninepatch 52 | * or a texture region. You can also add resource from file (PNG only for now) 53 | * 54 | * @author Yanick Bourbeau 55 | * 56 | */ 57 | public class DrawablePickerDialog extends Dialog { 58 | 59 | private SkinEditorGame game; 60 | private Field field; 61 | private Table tableDrawables; 62 | private boolean zoom = false; 63 | private ObjectMap items = new ObjectMap(); 64 | private ScrollPane scrollPane; 65 | 66 | public DrawablePickerDialog(final SkinEditorGame game, final Field field) { 67 | 68 | super("Drawable Picker", game.skin); 69 | this.game = game; 70 | this.field = field; 71 | 72 | tableDrawables = new Table(game.skin); 73 | scrollPane = new ScrollPane(tableDrawables, game.skin); 74 | getContentTable().add(scrollPane); 75 | scrollPane.setFlickScroll(false); 76 | scrollPane.setFadeScrollBars(false); 77 | scrollPane.setScrollbarsOnTop(true); 78 | 79 | TextButton buttonNewNinePatch = new TextButton("Create NinePatch", game.skin); 80 | buttonNewNinePatch.addListener(new ChangeListener() { 81 | 82 | @Override 83 | public void changed(ChangeEvent event, Actor actor) { 84 | 85 | NinePatchEditorDialog dlg = new NinePatchEditorDialog(game) { 86 | @Override 87 | public void hide() { 88 | super.hide(); 89 | 90 | updateTable(); 91 | } 92 | }; 93 | 94 | dlg.show(game.screenMain.stage); 95 | } 96 | 97 | }); 98 | 99 | TextButton buttonNewDrawable = new TextButton("Import Image", game.skin); 100 | buttonNewDrawable.addListener(new ChangeListener() { 101 | 102 | @Override 103 | public void changed(ChangeEvent event, Actor actor) { 104 | 105 | // Need to steal focus first with this hack (Thanks to Z-Man) 106 | Frame frame = new Frame(); 107 | frame.setUndecorated(true); 108 | frame.setOpacity(0); 109 | frame.setLocationRelativeTo(null); 110 | frame.setVisible(true); 111 | frame.toFront(); 112 | frame.setVisible(false); 113 | frame.dispose(); 114 | 115 | 116 | JFileChooser chooser = new JFileChooser(); 117 | FileNameExtensionFilter filter = new FileNameExtensionFilter("Images", "png"); 118 | chooser.setFileFilter(filter); 119 | int returnVal = chooser.showOpenDialog(null); 120 | if (returnVal != JFileChooser.APPROVE_OPTION) { 121 | return; 122 | } 123 | File selectedFile = chooser.getSelectedFile(); 124 | if (selectedFile == null) { 125 | return; 126 | } 127 | // Loop until the file is not found 128 | while (true) { 129 | String resourceName = selectedFile.getName(); 130 | String ext = resourceName.substring(resourceName.lastIndexOf(".") + 1); 131 | resourceName = resourceName.substring(0, resourceName.lastIndexOf(".")); 132 | resourceName = JOptionPane.showInputDialog("Please choose the name of your resource", resourceName); 133 | if (resourceName == null) { 134 | return; 135 | } 136 | 137 | // Lower case everything ! I sound like someone on 138 | // libgdx channel ;] 139 | resourceName = resourceName.toLowerCase(); 140 | 141 | // Check for duplicate resources 142 | FileHandle[] assetsFolder = new FileHandle("projects/" + game.screenMain.getcurrentProject() + "/assets/").list(); 143 | boolean foundSomething = false; 144 | for (FileHandle file : assetsFolder) { 145 | 146 | if (file.nameWithoutExtension().toLowerCase().equals(resourceName)) { 147 | foundSomething = true; 148 | break; 149 | } 150 | } 151 | if (foundSomething == true) { 152 | JOptionPane.showMessageDialog(null, "Sorry but this resource name is already in use!"); 153 | } else { 154 | 155 | // Copy the file 156 | FileHandle orig = new FileHandle(selectedFile); 157 | FileHandle dest = new FileHandle("projects/" + game.screenMain.getcurrentProject() + "/assets/" + resourceName + "." + ext); 158 | orig.copyTo(dest); 159 | 160 | 161 | game.screenMain.refreshResources(); 162 | refresh(); 163 | JOptionPane.showMessageDialog(null, "File successfully added to your project."); 164 | return; 165 | } 166 | 167 | 168 | } 169 | 170 | } 171 | 172 | }); 173 | 174 | 175 | TextButton buttonZoom = new TextButton("Toggle Zoom", game.skin); 176 | buttonZoom.addListener(new ChangeListener() { 177 | 178 | @Override 179 | public void changed(ChangeEvent event, Actor actor) { 180 | zoom = !zoom; 181 | updateTable(); 182 | 183 | } 184 | 185 | }); 186 | 187 | TextButton buttonNoDrawable = new TextButton("Empty Drawable", game.skin); 188 | 189 | buttonNoDrawable.addListener(new ChangeListener() { 190 | 191 | @Override 192 | public void changed(ChangeEvent event, Actor actor) { 193 | 194 | try { 195 | field.set(game.screenMain.paneOptions.currentStyle, null); 196 | } catch (Exception e) { 197 | e.printStackTrace(); 198 | } 199 | 200 | game.screenMain.saveToSkin(); 201 | 202 | hide(); 203 | game.screenMain.panePreview.refresh(); 204 | game.screenMain.paneOptions.updateSelectedTableFields(); 205 | 206 | } 207 | 208 | }); 209 | 210 | getContentTable().add(scrollPane).width(960).height(640).pad(20); 211 | getButtonTable().add(buttonNewNinePatch); 212 | getButtonTable().add(buttonNewDrawable); 213 | getButtonTable().add(buttonZoom); 214 | if (field != null) { 215 | getButtonTable().add(buttonNoDrawable); 216 | } 217 | getButtonTable().padBottom(15); 218 | button("Cancel", false); 219 | key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 220 | 221 | } 222 | 223 | @Override 224 | public Dialog show(Stage stage) { 225 | 226 | refresh(); 227 | 228 | Dialog d = super.show(stage); 229 | getStage().setScrollFocus(scrollPane); 230 | return d; 231 | } 232 | 233 | private void refresh() { 234 | 235 | ObjectMap itemsDrawables = game.skinProject.getAll(Drawable.class); 236 | ObjectMap itemsRegions = game.skinProject.getAll(TextureRegion.class); 237 | 238 | items.clear(); 239 | 240 | Iterator it = itemsDrawables.keys().iterator(); 241 | while (it.hasNext()) { 242 | String key = it.next(); 243 | items.put(key, itemsDrawables.get(key)); 244 | } 245 | 246 | it = itemsRegions.keys().iterator(); 247 | while (it.hasNext()) { 248 | String key = it.next(); 249 | if (itemsDrawables.containsKey(key)) { 250 | continue; 251 | } 252 | items.put(key, itemsRegions.get(key)); 253 | } 254 | 255 | updateTable(); 256 | 257 | } 258 | 259 | /** 260 | * 261 | */ 262 | public void updateTable() { 263 | 264 | tableDrawables.clear(); 265 | 266 | Iterator keys = items.keys().iterator(); 267 | int count = 0; 268 | 269 | while (keys.hasNext()) { 270 | 271 | final String key = keys.next(); 272 | if (key.startsWith("widgets/")) { 273 | continue; 274 | } 275 | 276 | Button buttonItem = new Button(game.skin); 277 | 278 | Image img = null; 279 | if (items.get(key) instanceof Drawable) { 280 | img = new Image((Drawable) items.get(key)); 281 | } else { 282 | img = new Image((TextureRegion) items.get(key)); 283 | 284 | } 285 | 286 | if (zoom == true) { 287 | buttonItem.add(img).expand().fill().pad(5); 288 | } else { 289 | buttonItem.add(img).expand().pad(5); 290 | } 291 | 292 | buttonItem.addListener(new ChangeListener() { 293 | 294 | @Override 295 | public void changed(ChangeEvent event, Actor actor) { 296 | 297 | if (field == null) { 298 | return; 299 | } 300 | 301 | try { 302 | // Since we have reloaded everything we have to get 303 | // field back 304 | 305 | // game.screenMain.paneOptions.refreshSelection(); 306 | if (items.get(key) instanceof Drawable) { 307 | field.set(game.screenMain.paneOptions.currentStyle, items.get(key)); 308 | } else { 309 | 310 | boolean ninepatch = false; 311 | FileHandle test = new FileHandle("projects/" + game.screenMain.getcurrentProject() + "/assets/" + key + ".9.png"); 312 | if (test.exists() == true) { 313 | ninepatch = true; 314 | } 315 | 316 | if (ninepatch == true) { 317 | game.skinProject.add(key, new NinePatchDrawable(new NinePatch((TextureRegion) items.get(key)))); 318 | field.set(game.screenMain.paneOptions.currentStyle, game.skinProject.getDrawable(key)); 319 | 320 | } else { 321 | game.skinProject.add(key, new SpriteDrawable(new Sprite((TextureRegion) items.get(key)))); 322 | field.set(game.screenMain.paneOptions.currentStyle, game.skinProject.getDrawable(key)); 323 | 324 | } 325 | } 326 | 327 | game.screenMain.saveToSkin(); 328 | hide(); 329 | game.screenMain.panePreview.refresh(); 330 | game.screenMain.paneOptions.updateSelectedTableFields(); 331 | } catch (Exception e) { 332 | e.printStackTrace(); 333 | } 334 | 335 | } 336 | 337 | }); 338 | 339 | String objectType = items.get(key).getClass().getSimpleName(); 340 | objectType = objectType.replace("Drawable", ""); 341 | 342 | buttonItem.row(); 343 | buttonItem.add(new Label(key, game.skin)); 344 | buttonItem.row(); 345 | buttonItem.add(new Label(objectType, game.skin, "title")); 346 | buttonItem.row(); 347 | buttonItem.setClip(true); 348 | tableDrawables.add(buttonItem).width(160).height(184).pad(5); 349 | 350 | if (count == 4) { 351 | count = 0; 352 | tableDrawables.row(); 353 | continue; 354 | } 355 | 356 | count++; 357 | } 358 | 359 | } 360 | 361 | } 362 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/FontPickerDialog.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor; 17 | 18 | import java.util.Iterator; 19 | 20 | import com.badlogic.gdx.files.FileHandle; 21 | import com.badlogic.gdx.graphics.Color; 22 | import com.badlogic.gdx.scenes.scene2d.Actor; 23 | import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 24 | import com.badlogic.gdx.scenes.scene2d.ui.Label; 25 | import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 26 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 27 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton; 28 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; 29 | import com.badlogic.gdx.utils.ObjectMap; 30 | import com.badlogic.gdx.utils.reflect.ClassReflection; 31 | import com.badlogic.gdx.utils.reflect.Field; 32 | import com.badlogic.gdx.graphics.g2d.BitmapFont; 33 | 34 | /** 35 | * Display a dialog that let you pick up a font. 36 | * I re-use some of the Hiero code here to generate bitmap fonts 37 | * from TTF files. 38 | * 39 | * @author Yanick Bourbeau 40 | * 41 | */ 42 | public class FontPickerDialog extends Dialog { 43 | 44 | private SkinEditorGame game; 45 | private Table tableFonts; 46 | ObjectMap fonts; 47 | private Field field; 48 | 49 | /** 50 | * 51 | */ 52 | public FontPickerDialog(final SkinEditorGame game, Field field) { 53 | 54 | super("Bitmap Font Picker", game.skin); 55 | 56 | this.game = game; 57 | this.field = field; 58 | 59 | tableFonts = new Table(game.skin); 60 | tableFonts.left().top().pad(5); 61 | tableFonts.defaults().pad(5); 62 | 63 | fonts = game.skinProject.getAll(BitmapFont.class); 64 | 65 | updateTable(); 66 | 67 | TextButton buttonNewFont = new TextButton("New Font", game.skin); 68 | buttonNewFont.addListener(new ChangeListener() { 69 | 70 | @Override 71 | public void changed(ChangeEvent event, Actor actor) { 72 | 73 | showNewFontDialog(); 74 | 75 | } 76 | 77 | }); 78 | 79 | 80 | ScrollPane scrollPane = new ScrollPane(tableFonts, game.skin); 81 | scrollPane.setFlickScroll(false); 82 | scrollPane.setFadeScrollBars(false); 83 | scrollPane.setScrollbarsOnTop(true); 84 | 85 | getContentTable().add(scrollPane).width(720).height(420).pad(20); 86 | getButtonTable().add(buttonNewFont); 87 | getButtonTable().padBottom(15); 88 | button("Cancel", false); 89 | key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 90 | 91 | } 92 | 93 | /** 94 | * 95 | */ 96 | public void updateTable() { 97 | 98 | fonts = game.skinProject.getAll(BitmapFont.class); 99 | 100 | tableFonts.clear(); 101 | tableFonts.add(new Label("Font Name", game.skin, "title")).left().width(170); 102 | tableFonts.add(new Label("Value", game.skin, "title")).colspan(3).left().width(60).padRight(50).expandX().fillX(); 103 | 104 | tableFonts.row(); 105 | 106 | Iterator it = fonts.keys().iterator(); 107 | while (it.hasNext()) { 108 | final String key = it.next(); 109 | final BitmapFont font = fonts.get(key); 110 | 111 | tableFonts.add(key).left(); 112 | 113 | Label.LabelStyle labelStyle = new Label.LabelStyle(); 114 | labelStyle.font = font; 115 | labelStyle.fontColor = Color.WHITE; 116 | 117 | tableFonts.add(new Label("Sample Text", labelStyle)).left(); 118 | 119 | TextButton buttonSelect = new TextButton("Select", game.skin); 120 | buttonSelect.addListener(new ChangeListener() { 121 | 122 | @Override 123 | public void changed(ChangeEvent event, Actor actor) { 124 | try { 125 | // Since we have reloaded everything we have to get 126 | // field back 127 | 128 | game.screenMain.paneOptions.refreshSelection(); 129 | field.set(game.screenMain.paneOptions.currentStyle, font); 130 | 131 | } catch (Exception e) { 132 | e.printStackTrace(); 133 | } 134 | 135 | hide(); 136 | game.screenMain.panePreview.refresh(); 137 | game.screenMain.paneOptions.updateSelectedTableFields(); 138 | game.screenMain.saveToSkin(); 139 | 140 | } 141 | 142 | }); 143 | 144 | TextButton buttonRemove = new TextButton("Remove", game.skin); 145 | buttonRemove.addListener(new ChangeListener() { 146 | 147 | @Override 148 | public void changed(ChangeEvent event, Actor actor) { 149 | 150 | Dialog dlg = new Dialog("Delete Font", game.skin) { 151 | 152 | @Override 153 | protected void result(Object object) { 154 | if ((Boolean) object == false) { 155 | return; 156 | } 157 | 158 | if (isFontInUse(font) == true) { 159 | 160 | game.showNotice("Error", "Bitmap font already in use!", getStage()); 161 | 162 | } else { 163 | 164 | // Remove files from disk (fnt and png) 165 | FileHandle targetFont = new FileHandle("projects/" + game.screenMain.getcurrentProject() + "/" +key + ".fnt"); 166 | FileHandle targetImage = new FileHandle("projects/" + game.screenMain.getcurrentProject() + "/assets/" + key + ".png"); 167 | targetFont.delete(); 168 | targetImage.delete(); 169 | 170 | fonts.remove(key); 171 | // update table 172 | updateTable(); 173 | game.screenMain.saveToSkin(); 174 | 175 | } 176 | } 177 | 178 | }; 179 | 180 | dlg.pad(20); 181 | dlg.getContentTable().add("You are sure you want to delete this bitmap font?"); 182 | dlg.button("OK", true); 183 | dlg.button("Cancel", false); 184 | dlg.key(com.badlogic.gdx.Input.Keys.ENTER, true); 185 | dlg.key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 186 | dlg.show(getStage()); 187 | 188 | } 189 | 190 | }); 191 | 192 | if (field != null) { 193 | tableFonts.add(buttonSelect).left(); 194 | } 195 | tableFonts.add(buttonRemove).left().expandX(); 196 | tableFonts.row(); 197 | } 198 | 199 | } 200 | 201 | /** 202 | * Is font is already in use somewhere else? 203 | */ 204 | public boolean isFontInUse(BitmapFont font) { 205 | 206 | try { 207 | // Check if it is already in use somewhere! 208 | for (String widget : SkinEditorGame.widgets) { 209 | String widgetStyle = "com.badlogic.gdx.scenes.scene2d.ui." + widget + "$" + widget + "Style"; 210 | Class style = Class.forName(widgetStyle); 211 | ObjectMap styles = game.skinProject.getAll(style); 212 | Iterator it = styles.keys().iterator(); 213 | while (it.hasNext()) { 214 | Object item = styles.get((String) it.next()); 215 | Field[] fields = ClassReflection.getFields(item.getClass()); 216 | for (Field field : fields) { 217 | 218 | if (field.getType() == BitmapFont.class) { 219 | 220 | BitmapFont f = (BitmapFont) field.get(item); 221 | if (font.equals(f)) { 222 | return true; 223 | } 224 | 225 | } 226 | 227 | } 228 | 229 | } 230 | 231 | } 232 | } catch (Exception e) { 233 | e.printStackTrace(); 234 | 235 | } 236 | 237 | return false; 238 | } 239 | 240 | /** 241 | * 242 | */ 243 | public void showNewFontDialog() { 244 | 245 | NewFontDialog dlg = new NewFontDialog(game) { 246 | 247 | @Override 248 | public void hide() { 249 | super.hide(); 250 | 251 | updateTable(); 252 | } 253 | }; 254 | dlg.show(getStage()); 255 | 256 | } 257 | 258 | } 259 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/NewFontDialog.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor; 17 | 18 | import java.awt.Font; 19 | import java.io.File; 20 | import java.util.Iterator; 21 | import java.util.Map; 22 | import java.util.TreeMap; 23 | 24 | import com.badlogic.gdx.Gdx; 25 | import com.badlogic.gdx.files.FileHandle; 26 | import com.badlogic.gdx.graphics.Color; 27 | import com.badlogic.gdx.graphics.g2d.BitmapFont; 28 | import com.badlogic.gdx.scenes.scene2d.Actor; 29 | import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; 30 | import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 31 | import com.badlogic.gdx.scenes.scene2d.ui.SelectBox; 32 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 33 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton; 34 | import com.badlogic.gdx.scenes.scene2d.ui.TextField; 35 | import com.badlogic.gdx.scenes.scene2d.ui.TextField.TextFieldListener; 36 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; 37 | import com.badlogic.gdx.tools.hiero.BMFontUtil; 38 | import com.badlogic.gdx.tools.hiero.unicodefont.UnicodeFont; 39 | import com.badlogic.gdx.tools.hiero.unicodefont.effects.ColorEffect; 40 | import com.badlogic.gdx.tools.hiero.unicodefont.effects.ShadowEffect; 41 | import com.badlogic.gdx.utils.Array; 42 | 43 | 44 | /** 45 | * Create new font using Hiero classes 46 | * 47 | * @author Yanick Bourbeau 48 | */ 49 | public class NewFontDialog extends Dialog { 50 | 51 | private SkinEditorGame game; 52 | private TextField textFontName; 53 | private TextField textFontPreview; 54 | private SelectBox selectFonts; 55 | private SelectBox selectSize; 56 | private CheckBox checkBold; 57 | private CheckBox checkItalic; 58 | private CheckBox checkShadow; 59 | 60 | /** 61 | * 62 | */ 63 | public NewFontDialog(final SkinEditorGame game) { 64 | 65 | super("New Font", game.skin); 66 | this.game = game; 67 | 68 | Table table = new Table(game.skin); 69 | table.debug(); 70 | table.defaults().pad(10); 71 | 72 | table.add("Bitmap font name:"); 73 | 74 | textFontName = new TextField("", game.skin); 75 | table.add(textFontName).width(300).left().colspan(4); 76 | table.row(); 77 | 78 | 79 | table.add("Source font (TTF):").padRight(10); 80 | 81 | selectFonts = new SelectBox(game.skin); 82 | table.add(selectFonts).left().colspan(4); 83 | 84 | Map mapFonts = new TreeMap(game.fm.fonts); 85 | Array items = new Array(); 86 | Iterator it = mapFonts.keySet().iterator(); 87 | 88 | boolean arialFound = false; 89 | 90 | while(it.hasNext()) { 91 | String key = it.next(); 92 | if (key.equals("Arial") == true) { 93 | arialFound = true; 94 | } 95 | items.add(key); 96 | } 97 | selectFonts.setItems(items); 98 | 99 | // Select arial if found 100 | if (arialFound == true) { 101 | selectFonts.setSelected("Arial"); 102 | } 103 | 104 | 105 | table.row(); 106 | table.add("Font size:"); 107 | selectSize = new SelectBox(game.skin); 108 | selectSize.setItems("4", "6", "8", "10", "12", "14", "16", "18", "20", "22", "24", "26", "28", "30", "32", "34", "36", "38", "40", "42","44","46","48","50","52","54","56"); 109 | selectSize.setSelected("16"); 110 | table.add(selectSize).left().width(50); 111 | 112 | checkBold = new CheckBox("Bold", game.skin); 113 | table.add(checkBold).left(); 114 | 115 | checkItalic = new CheckBox("Italic", game.skin); 116 | table.add(checkItalic).left(); 117 | 118 | checkShadow = new CheckBox("Shadow", game.skin); 119 | table.add(checkShadow).left().expandX(); 120 | 121 | table.row(); 122 | 123 | 124 | 125 | 126 | TextField.TextFieldStyle textStyle = new TextField.TextFieldStyle(); 127 | textStyle.cursor = game.skin.getDrawable("cursor"); 128 | textStyle.selection = game.skin.getDrawable("selection"); 129 | textStyle.background = game.skin.getDrawable("textfield"); 130 | textStyle.fontColor = Color.YELLOW; 131 | textStyle.font = game.skin.getFont("default-font"); 132 | 133 | textFontPreview = new TextField("This is a preview text", textStyle); 134 | table.add(textFontPreview).pad(20).colspan(5).expand().fill().left(); 135 | 136 | selectFonts.addListener(new ChangeListener() { 137 | 138 | @Override 139 | public void changed(ChangeEvent event, Actor actor) { 140 | 141 | refreshFontPreview(); 142 | 143 | } 144 | 145 | }); 146 | 147 | selectSize.addListener(new ChangeListener() { 148 | 149 | @Override 150 | public void changed(ChangeEvent event, Actor actor) { 151 | 152 | refreshFontPreview(); 153 | 154 | } 155 | 156 | }); 157 | 158 | checkBold.addListener(new ChangeListener() { 159 | 160 | @Override 161 | public void changed(ChangeEvent event, Actor actor) { 162 | 163 | refreshFontPreview(); 164 | 165 | } 166 | 167 | }); 168 | 169 | checkItalic.addListener(new ChangeListener() { 170 | 171 | @Override 172 | public void changed(ChangeEvent event, Actor actor) { 173 | 174 | refreshFontPreview(); 175 | 176 | } 177 | 178 | }); 179 | 180 | checkShadow.addListener(new ChangeListener() { 181 | 182 | @Override 183 | public void changed(ChangeEvent event, Actor actor) { 184 | 185 | refreshFontPreview(); 186 | 187 | } 188 | 189 | }); 190 | 191 | refreshFontPreview(); 192 | 193 | getContentTable().add(table).width(520).height(320).pad(20); 194 | getButtonTable().padBottom(15); 195 | 196 | TextButton buttonCreate = new TextButton("Create Font", game.skin); 197 | buttonCreate.addListener(new ChangeListener() { 198 | 199 | @Override 200 | public void changed(ChangeEvent event, Actor actor) { 201 | 202 | // First check if the name is already in use 203 | if (game.skinProject.has(textFontName.getText(), BitmapFont.class)) { 204 | game.showNotice("Error", "A font with the same name already exists!", getStage()); 205 | return; 206 | } 207 | 208 | String properFontName = generateProperFontName(selectFonts.getSelected()); 209 | FileHandle handleFont = new FileHandle(System.getProperty("java.io.tmpdir")).child(properFontName + ".fnt"); 210 | FileHandle handleImage = new FileHandle(System.getProperty("java.io.tmpdir")).child(properFontName + ".png"); 211 | 212 | FileHandle targetFont = Gdx.files.local("projects/" + game.screenMain.getcurrentProject() + "/" + textFontName.getText() + ".fnt"); 213 | FileHandle targetImage = Gdx.files.local("projects/" + game.screenMain.getcurrentProject() + "/assets/" + textFontName.getText() + ".png"); 214 | 215 | if ((targetFont.exists() == true) || (targetImage.exists() == true)) { 216 | 217 | game.showNotice("Error", "A file with the same name already exists!", getStage()); 218 | return; 219 | } 220 | 221 | handleFont.copyTo(targetFont); 222 | handleImage.copyTo(targetImage); 223 | 224 | game.skinProject.add(textFontName.getText(), new BitmapFont(targetFont, targetImage, false)); 225 | game.screenMain.saveToSkin(); 226 | game.screenMain.refreshResources(); 227 | 228 | 229 | hide(); 230 | 231 | } 232 | 233 | }); 234 | 235 | getButtonTable().add(buttonCreate); 236 | button("Cancel", false); 237 | key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 238 | 239 | } 240 | 241 | 242 | /** 243 | * 244 | */ 245 | @Override 246 | protected void result(Object object) { 247 | if ((Boolean) object == false) { 248 | return; 249 | } 250 | 251 | } 252 | 253 | 254 | /** 255 | * 256 | */ 257 | public void refreshFontPreview() { 258 | 259 | try { 260 | String fontName = selectFonts.getSelected(); 261 | Gdx.app.log("FontPickerDialog", "Refreshing preview for font: " + fontName); 262 | 263 | File fontPath = game.fm.fonts.get(selectFonts.getSelected()); 264 | Gdx.app.log("FontPickerDialog","Loading font from file:" + fontPath); 265 | 266 | Font font = Font.createFont(Font.TRUETYPE_FONT, fontPath); 267 | UnicodeFont unicodeFont = new UnicodeFont(font, Integer.valueOf(selectSize.getSelected()), checkBold.isChecked(), checkItalic.isChecked()); 268 | 269 | if (checkShadow.isChecked() == true) { 270 | 271 | ColorEffect colorEffect = new ColorEffect(); 272 | colorEffect.setColor(java.awt.Color.BLACK); 273 | unicodeFont.getEffects().add(colorEffect); 274 | 275 | ShadowEffect shadow = new ShadowEffect(); 276 | shadow.setOpacity(1.0f); 277 | shadow.setXDistance(1); 278 | shadow.setYDistance(1); 279 | shadow.setColor(java.awt.Color.WHITE); 280 | unicodeFont.getEffects().add(shadow); 281 | 282 | } else { 283 | ColorEffect colorEffect = new ColorEffect(); 284 | colorEffect.setColor(java.awt.Color.WHITE); 285 | unicodeFont.getEffects().add(colorEffect); 286 | 287 | } 288 | 289 | unicodeFont.addAsciiGlyphs(); 290 | 291 | String newFontName = generateProperFontName(fontName); 292 | 293 | textFontName.setText(newFontName); 294 | 295 | // Create bitmap font 296 | BMFontUtil bfu = new BMFontUtil(unicodeFont); 297 | 298 | 299 | FileHandle handle = new FileHandle(System.getProperty("java.io.tmpdir")).child(newFontName); 300 | FileHandle handleFont = new FileHandle(handle.file().getAbsolutePath() + ".fnt"); 301 | bfu.save(handle.file()); 302 | 303 | FileHandle handleImage = new FileHandle(System.getProperty("java.io.tmpdir")).child(newFontName + ".png"); 304 | 305 | TextField.TextFieldStyle textStyle = new TextField.TextFieldStyle(); 306 | textStyle.cursor = game.skin.getDrawable("cursor"); 307 | textStyle.selection = game.skin.getDrawable("selection"); 308 | textStyle.background = game.skin.getDrawable("textfield"); 309 | textStyle.fontColor = Color.YELLOW; 310 | textStyle.font = new BitmapFont(handleFont, handleImage, false); 311 | 312 | textFontPreview.setStyle(textStyle); 313 | 314 | // Have to do this to force clipping of font 315 | textFontPreview.setText(textFontPreview.getText()); 316 | 317 | } catch (Exception e) { 318 | e.printStackTrace(); 319 | textFontPreview.getStyle().font = game.skin.getFont("default-font"); 320 | // Have to do this to force clipping of font 321 | textFontPreview.setText(textFontPreview.getText()); 322 | } 323 | } 324 | 325 | private String generateProperFontName(String originalFontName) { 326 | // Generate a temporary name for your font (Do not end with a number, it will be removed in the atlas) 327 | String newFontName = "font_"+originalFontName.toLowerCase().replace(" ", "_") +"_"+selectSize.getSelected()+"pt"; 328 | if (checkBold.isChecked() == true) { 329 | newFontName += "_bold"; 330 | } 331 | 332 | if (checkItalic.isChecked() == true) { 333 | newFontName += "_italic"; 334 | } 335 | 336 | return newFontName; 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/NinePatchEditorDialog.java: -------------------------------------------------------------------------------- 1 | package org.shadebob.skineditor; 2 | 3 | import java.awt.Frame; 4 | import java.io.File; 5 | 6 | import javax.swing.JFileChooser; 7 | import javax.swing.filechooser.FileNameExtensionFilter; 8 | 9 | import org.shadebob.skineditor.actors.RangeSelector; 10 | 11 | import com.badlogic.gdx.Gdx; 12 | import com.badlogic.gdx.files.FileHandle; 13 | import com.badlogic.gdx.graphics.Color; 14 | import com.badlogic.gdx.graphics.Pixmap; 15 | import com.badlogic.gdx.graphics.PixmapIO; 16 | import com.badlogic.gdx.graphics.Texture; 17 | import com.badlogic.gdx.graphics.g2d.BitmapFont; 18 | import com.badlogic.gdx.graphics.g2d.NinePatch; 19 | import com.badlogic.gdx.graphics.g2d.TextureAtlas; 20 | import com.badlogic.gdx.graphics.g2d.TextureRegion; 21 | import com.badlogic.gdx.scenes.scene2d.Actor; 22 | import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 23 | import com.badlogic.gdx.scenes.scene2d.ui.Image; 24 | import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 25 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 26 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton; 27 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; 28 | import com.badlogic.gdx.scenes.scene2d.ui.TextField; 29 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; 30 | import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; 31 | import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable; 32 | import com.badlogic.gdx.tools.texturepacker.TexturePacker; 33 | import com.esotericsoftware.tablelayout.Cell; 34 | 35 | public class NinePatchEditorDialog extends Dialog { 36 | 37 | private SkinEditorGame game; 38 | private TextField textName; 39 | private TextField textSourceImage; 40 | private float currentZoom = 1.0f; 41 | private Table table; 42 | private Table tableEditor; 43 | private Table tablePreview; 44 | private Image image; 45 | private float imgWidth; 46 | private float imgHeight; 47 | private Cell cellImage; 48 | private RangeSelector rangeTop; 49 | private RangeSelector rangeBottom; 50 | private RangeSelector rangeLeft; 51 | private RangeSelector rangeRight; 52 | 53 | private TextButton buttonPreview1; 54 | private TextButton buttonPreview2; 55 | private TextButton buttonPreview3; 56 | private Cell cellPreview1; 57 | private Cell cellPreview2; 58 | private Cell cellPreview3; 59 | 60 | private FileHandle tmpFile; 61 | 62 | /** 63 | * 64 | */ 65 | public NinePatchEditorDialog(final SkinEditorGame game) { 66 | 67 | super("Create NinePatch", game.skin); 68 | this.game = game; 69 | 70 | 71 | tmpFile = new FileHandle(System.getProperty("java.io.tmpdir")).child("skin_ninepatch"); 72 | if (tmpFile.exists() == false) { 73 | tmpFile.mkdirs(); 74 | } 75 | tmpFile = tmpFile.child("button.9.png"); 76 | 77 | 78 | table = new Table(game.skin); 79 | // table.debug(); 80 | table.defaults().pad(10); 81 | 82 | table.top(); 83 | table.left(); 84 | 85 | textName = new TextField("default_button", game.skin); 86 | Table tableTop = new Table(game.skin); 87 | tableTop.add("NinePatch Name:").padRight(10); 88 | tableTop.add(textName).padRight(10); 89 | tableTop.add("Source Image:").padRight(10); 90 | 91 | textSourceImage = new TextField("resources/default_button.png", game.skin); 92 | textSourceImage.setDisabled(true); 93 | tableTop.add(textSourceImage).expandX().fill().padRight(10); 94 | 95 | TextButton buttonChoose = new TextButton("...", game.skin); 96 | tableTop.add(buttonChoose).width(32); 97 | buttonChoose.addListener(new ChangeListener() { 98 | 99 | @Override 100 | public void changed(ChangeEvent event, Actor actor) { 101 | 102 | 103 | // Need to steal focus first with this hack (Thanks to Z-Man) 104 | Frame frame = new Frame(); 105 | frame.setUndecorated(true); 106 | frame.setOpacity(0); 107 | frame.setLocationRelativeTo(null); 108 | frame.setVisible(true); 109 | frame.toFront(); 110 | frame.setVisible(false); 111 | frame.dispose(); 112 | 113 | 114 | JFileChooser chooser = new JFileChooser(); 115 | FileNameExtensionFilter filter = new FileNameExtensionFilter("Images", "png"); 116 | chooser.setFileFilter(filter); 117 | int returnVal = chooser.showOpenDialog(null); 118 | if (returnVal != JFileChooser.APPROVE_OPTION) { 119 | return; 120 | } 121 | File selectedFile = chooser.getSelectedFile(); 122 | if (selectedFile == null) { 123 | return; 124 | } 125 | String name = new FileHandle(selectedFile).nameWithoutExtension(); 126 | name = name.replace(" ", "_"); 127 | name = name.replace("-", "_"); 128 | textName.setText(name); 129 | textSourceImage.setText(selectedFile.getAbsolutePath()); 130 | TextureRegionDrawable trd = new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal(textSourceImage.getText())))); 131 | image.setDrawable(trd); 132 | image.setWidth(trd.getMinWidth()); 133 | image.setHeight(trd.getMinHeight()); 134 | imgWidth = image.getWidth(); 135 | imgHeight = image.getHeight(); 136 | refreshPreview(); 137 | refreshImage(); 138 | } 139 | 140 | }); 141 | 142 | 143 | table.add(tableTop).colspan(2).expandX().fillX(); 144 | table.row(); 145 | 146 | 147 | rangeTop = new RangeSelector(false, game.skin); 148 | rangeRight = new RangeSelector(true, game.skin); 149 | rangeBottom = new RangeSelector(false, game.skin); 150 | rangeLeft = new RangeSelector(true, game.skin); 151 | 152 | ChangeListener listener = new ChangeListener() { 153 | 154 | @Override 155 | public void changed(ChangeEvent event, Actor actor) { 156 | refreshPreview(); 157 | 158 | } 159 | }; 160 | 161 | rangeTop.addListener(listener); 162 | rangeRight.addListener(listener); 163 | rangeBottom.addListener(listener); 164 | rangeLeft.addListener(listener); 165 | 166 | tableEditor = new Table(game.skin); 167 | //tableEditor.debug(); 168 | tableEditor.add(); 169 | tableEditor.add(rangeTop).fillX().height(10); 170 | tableEditor.row(); 171 | 172 | tableEditor.add(rangeLeft).width(10).fillY(); 173 | image = new Image(new Texture(Gdx.files.internal(textSourceImage.getText()))); 174 | imgWidth = image.getWidth(); 175 | imgHeight = image.getHeight(); 176 | cellImage = tableEditor.add(image); 177 | cellImage.width(imgWidth * currentZoom).height(imgHeight * currentZoom); 178 | 179 | tableEditor.add(rangeRight).width(10).fillY(); 180 | tableEditor.row(); 181 | tableEditor.add(); 182 | tableEditor.add(rangeBottom).fillX().height(10); 183 | tableEditor.row(); 184 | 185 | ScrollPane scrollPane = new ScrollPane(tableEditor,game.skin); 186 | scrollPane.setOverscroll(false, false); 187 | scrollPane.setFadeScrollBars(false); 188 | scrollPane.setFlingTime(0); 189 | table.add(scrollPane).width(500).expand().fill(); 190 | 191 | tablePreview = new Table(game.skin); 192 | reviewTablePreview(); 193 | 194 | table.add(new ScrollPane(tablePreview,game.skin)).width(360).expand().fill().row(); 195 | 196 | Table tableButtons = new Table(game.skin); 197 | tableButtons.center(); 198 | TextButton buttonSave = new TextButton("Save NinePatch", game.skin); 199 | tableButtons.add(buttonSave).padRight(10); 200 | 201 | TextButton buttonZoomIn = new TextButton("+", game.skin); 202 | tableButtons.add(buttonZoomIn).width(32).padRight(10); 203 | 204 | TextButton buttonZoomOut = new TextButton("-", game.skin); 205 | tableButtons.add(buttonZoomOut).width(32).padRight(10); 206 | 207 | 208 | TextButton buttonCancel = new TextButton("Cancel", game.skin); 209 | tableButtons.add(buttonCancel); 210 | 211 | table.add(tableButtons).colspan(2).row(); 212 | 213 | getContentTable().add(table).width(900).height(640).pad(20); 214 | getButtonTable().padBottom(15); 215 | 216 | 217 | buttonSave.addListener(new ChangeListener() { 218 | 219 | @Override 220 | public void changed(ChangeEvent event, Actor actor) { 221 | 222 | if (textName.getText().isEmpty() == true) { 223 | game.showNotice("Error", "Empty name!", getStage()); 224 | return; 225 | 226 | } 227 | // First check if the name is already in use 228 | if (game.skinProject.has(textName.getText(), NinePatch.class)) { 229 | game.showNotice("Error", "A ninepatch with the same name already exists!", getStage()); 230 | return; 231 | } 232 | 233 | 234 | FileHandle targetImage = new FileHandle("projects/" + game.screenMain.getcurrentProject() + "/assets/" + textName.getText() + ".9.png"); 235 | 236 | if (targetImage.exists() == true) { 237 | 238 | game.showNotice("Error", "A file with the same name already exists!", getStage()); 239 | return; 240 | } 241 | 242 | tmpFile.copyTo(targetImage); 243 | 244 | game.screenMain.saveToSkin(); 245 | game.screenMain.refreshResources(); 246 | 247 | 248 | hide(); 249 | 250 | 251 | } 252 | 253 | }); 254 | 255 | buttonZoomIn.addListener(new ChangeListener() { 256 | 257 | @Override 258 | public void changed(ChangeEvent event, Actor actor) { 259 | 260 | if (currentZoom < 16) { 261 | currentZoom *= 2; 262 | refreshImage(); 263 | } 264 | } 265 | 266 | }); 267 | 268 | buttonZoomOut.addListener(new ChangeListener() { 269 | 270 | @Override 271 | public void changed(ChangeEvent event, Actor actor) { 272 | 273 | if (currentZoom > 0.5f) { 274 | currentZoom /= 2; 275 | refreshImage(); 276 | } 277 | } 278 | 279 | }); 280 | 281 | buttonCancel.addListener(new ChangeListener() { 282 | 283 | @Override 284 | public void changed(ChangeEvent event, Actor actor) { 285 | 286 | cancel(); 287 | hide(); 288 | } 289 | 290 | }); 291 | 292 | key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 293 | refreshPreview(); 294 | } 295 | 296 | private void reviewTablePreview() { 297 | tablePreview.clear(); 298 | //tablePreview.debug(); 299 | tablePreview.center().left(); 300 | 301 | TextButtonStyle stylePreview = new TextButton.TextButtonStyle(); 302 | stylePreview.font = game.skin.getFont("default-font"); 303 | buttonPreview1 = new TextButton("1x Button", stylePreview); 304 | buttonPreview1.setSize(imgWidth, imgHeight); 305 | cellPreview1 = tablePreview.add(buttonPreview1).width(buttonPreview1.getWidth()).height(buttonPreview1.getHeight()).padBottom(15); 306 | tablePreview.row(); 307 | 308 | buttonPreview2 = new TextButton("2x Button", stylePreview); 309 | buttonPreview2.setSize(imgWidth * 2.0f, imgHeight * 2.0f); 310 | cellPreview2 = tablePreview.add(buttonPreview2).width(buttonPreview2.getWidth()).height(buttonPreview2.getHeight()).padBottom(15); 311 | tablePreview.row(); 312 | 313 | buttonPreview3 = new TextButton("3x Button", stylePreview); 314 | buttonPreview3.setSize(imgWidth * 3.0f, imgHeight * 3.0f); 315 | cellPreview3 = tablePreview.add(buttonPreview3).width(buttonPreview3.getWidth()).height(buttonPreview3.getHeight()).padBottom(15); 316 | tablePreview.row(); 317 | 318 | } 319 | 320 | /** 321 | * 322 | */ 323 | private void refreshImage() { 324 | 325 | float newX = imgWidth * currentZoom; 326 | float newY = imgHeight * currentZoom; 327 | 328 | image.setSize(newX, newY); 329 | cellImage.width(newX).height(newY); 330 | tableEditor.setWidth(newX); 331 | tableEditor.setHeight(newY); 332 | ScrollPane sp = (ScrollPane) tableEditor.getParent(); 333 | sp.layout(); 334 | 335 | } 336 | 337 | public void refreshPreview() { 338 | 339 | Gdx.app.log("NinePatchEditorDialog","refresh preview."); 340 | 341 | Pixmap pixmapImage = new Pixmap(Gdx.files.internal(textSourceImage.getText())); 342 | 343 | Pixmap pixmap = new Pixmap((int) (pixmapImage.getWidth()+2), (int) (pixmapImage.getHeight()+2), Pixmap.Format.RGBA8888); 344 | pixmap.drawPixmap(pixmapImage,1,1); 345 | 346 | pixmap.setColor(Color.BLACK); 347 | 348 | // Range left 349 | int h = pixmapImage.getHeight()+1; 350 | pixmap.drawLine(0, (int) (h * rangeLeft.rangeStart),0, (int) (h * rangeLeft.rangeStop)); 351 | 352 | 353 | // Range top 354 | int w = pixmapImage.getWidth()+1; 355 | pixmap.drawLine((int) (w * rangeTop.rangeStart), 0,(int) (w * rangeTop.rangeStop), 0); 356 | 357 | // Range right 358 | h = pixmapImage.getHeight()+1; 359 | pixmap.drawLine(pixmapImage.getWidth()+1, (int) (h * rangeRight.rangeStart),pixmapImage.getWidth()+1, (int) (h * rangeRight.rangeStop)); 360 | 361 | // Range bottom 362 | w = pixmapImage.getWidth()+1; 363 | pixmap.drawLine((int) (w * rangeBottom.rangeStart), pixmap.getHeight()-1,(int) (w * rangeBottom.rangeStop), pixmap.getHeight()-1); 364 | 365 | 366 | PixmapIO.writePNG(tmpFile, pixmap); 367 | 368 | pixmapImage.dispose(); 369 | pixmap.dispose(); 370 | 371 | FileHandle fh = new FileHandle(System.getProperty("java.io.tmpdir")).child("skin_ninepatch"); 372 | TexturePacker.Settings settings = new TexturePacker.Settings(); 373 | TexturePacker.process(settings, fh.path(), fh.path(), "pack"); 374 | 375 | TextureAtlas ta = new TextureAtlas(fh.child("pack.atlas")); 376 | NinePatch np = ta.createPatch("button"); 377 | NinePatchDrawable drawable = new NinePatchDrawable(np); 378 | reviewTablePreview(); 379 | buttonPreview1.getStyle().up = drawable; 380 | 381 | 382 | } 383 | } 384 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/OptionalChecker.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor; 17 | 18 | import com.badlogic.gdx.scenes.scene2d.ui.Button; 19 | import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; 20 | import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; 21 | import com.badlogic.gdx.scenes.scene2d.ui.Label; 22 | import com.badlogic.gdx.scenes.scene2d.ui.List; 23 | import com.badlogic.gdx.scenes.scene2d.ui.ProgressBar; 24 | import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 25 | import com.badlogic.gdx.scenes.scene2d.ui.SelectBox; 26 | import com.badlogic.gdx.scenes.scene2d.ui.Slider; 27 | import com.badlogic.gdx.scenes.scene2d.ui.SplitPane; 28 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton; 29 | import com.badlogic.gdx.scenes.scene2d.ui.TextField; 30 | import com.badlogic.gdx.scenes.scene2d.ui.Touchpad; 31 | import com.badlogic.gdx.scenes.scene2d.ui.Tree; 32 | import com.badlogic.gdx.scenes.scene2d.ui.Window; 33 | 34 | 35 | /** 36 | * A class that check if a scene2d-ui widget style field is optional or not. 37 | * I think I could store it in a JSON file instead. It will do for now. 38 | * 39 | * @author Yanick Bourbeau 40 | * 41 | */ 42 | public class OptionalChecker { 43 | 44 | public boolean isFieldOptional(Class objClass, String fieldName) { 45 | 46 | if (objClass == Label.LabelStyle.class) { 47 | 48 | if (fieldName.equals("font")) { 49 | return false; 50 | } else { 51 | return true; 52 | } 53 | 54 | } else if (objClass == Button.ButtonStyle.class) { 55 | // They are all optional 56 | return true; 57 | 58 | } else if (objClass == TextButton.TextButtonStyle.class) { 59 | 60 | if (fieldName.equals("font")) { 61 | return false; 62 | } else { 63 | return true; 64 | } 65 | 66 | } else if (objClass == ImageButton.ImageButtonStyle.class) { 67 | // They are all optional 68 | return true; 69 | 70 | } else if (objClass == CheckBox.CheckBoxStyle.class) { 71 | 72 | if (fieldName.equals("checkboxOff") || fieldName.equals("checkboxOn")) { 73 | return false; 74 | } else { 75 | return true; 76 | } 77 | 78 | } else if (objClass == TextField.TextFieldStyle.class) { 79 | 80 | if (fieldName.equals("font") || fieldName.equals("fontColor")) { 81 | return false; 82 | } else { 83 | return true; 84 | } 85 | 86 | } else if (objClass == List.ListStyle.class) { 87 | 88 | if (fieldName.equals("background")) { 89 | return true; 90 | } else { 91 | return false; 92 | } 93 | 94 | } else if (objClass == SelectBox.SelectBoxStyle.class) { 95 | 96 | if (fieldName.equals("background") || fieldName.equals("font") || fieldName.equals("fontColor") || 97 | fieldName.equals("listStyle") || fieldName.equals("scrollStyle")) { 98 | return false; 99 | } else { 100 | return true; 101 | } 102 | 103 | } else if (objClass == ProgressBar.ProgressBarStyle.class) { 104 | 105 | if (fieldName.equals("background")) { 106 | return false; 107 | } else { 108 | return true; 109 | } 110 | 111 | } else if (objClass == Slider.SliderStyle.class) { 112 | 113 | if (fieldName.equals("background")) { 114 | return false; 115 | } else { 116 | return true; 117 | } 118 | 119 | } else if (objClass == ScrollPane.ScrollPaneStyle.class) { 120 | 121 | // Everything is optional 122 | return true; 123 | 124 | } else if (objClass == SplitPane.SplitPaneStyle.class) { 125 | 126 | // Nothing is optional 127 | return false; 128 | 129 | } else if (objClass == Window.WindowStyle.class) { 130 | 131 | if (fieldName.equals("titleFont")) { 132 | return false; 133 | } else { 134 | return true; 135 | } 136 | 137 | } else if (objClass == Touchpad.TouchpadStyle.class) { 138 | 139 | if (fieldName.equals("background")) { 140 | return false; 141 | } else { 142 | return true; 143 | } 144 | 145 | } else if (objClass == Tree.TreeStyle.class) { 146 | if (fieldName.equals("plus") || fieldName.equals("minus")) { 147 | return false; 148 | } else { 149 | return true; 150 | } 151 | } 152 | 153 | 154 | return false; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/SkinEditorGame.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/SkinEditorGame.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor; 17 | 18 | import org.shadebob.skineditor.screens.MainScreen; 19 | import org.shadebob.skineditor.screens.WelcomeScreen; 20 | 21 | import com.badlogic.gdx.Game; 22 | import com.badlogic.gdx.Gdx; 23 | import com.badlogic.gdx.files.FileHandle; 24 | import com.badlogic.gdx.graphics.g2d.SpriteBatch; 25 | import com.badlogic.gdx.graphics.g2d.TextureAtlas; 26 | import com.badlogic.gdx.scenes.scene2d.Stage; 27 | import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 28 | import com.badlogic.gdx.scenes.scene2d.ui.Skin; 29 | import com.badlogic.gdx.tools.texturepacker.TexturePacker; 30 | 31 | 32 | /** 33 | * Main game class I re-use everywhere in this program. 34 | * 35 | * @author Yanick Bourbeau 36 | */ 37 | public class SkinEditorGame extends Game { 38 | 39 | 40 | public final static String[] widgets = { "Label","Button","TextButton", "ImageButton", "CheckBox", "TextField", "List", "SelectBox", "ProgressBar", "Slider", "ScrollPane", "SplitPane", "Window", "Touchpad", "Tree" }; 41 | 42 | public SpriteBatch batch; 43 | public Skin skin; 44 | public TextureAtlas atlas; 45 | 46 | public MainScreen screenMain; 47 | public WelcomeScreen screenWelcome; 48 | 49 | // Project related 50 | public Skin skinProject; 51 | 52 | // System fonts 53 | public SystemFonts fm; 54 | 55 | // Optional check 56 | public OptionalChecker opt; 57 | 58 | @Override 59 | public void create() { 60 | 61 | opt = new OptionalChecker(); 62 | 63 | fm = new SystemFonts(); 64 | fm.refreshFonts(); 65 | 66 | // Create projects folder if not already here 67 | FileHandle dirProjects = new FileHandle("projects"); 68 | 69 | if (dirProjects.isDirectory() == false) { 70 | dirProjects.mkdirs(); 71 | } 72 | 73 | // Rebuild from raw resources, kind of overkill, might disable it for production 74 | TexturePacker.Settings settings = new TexturePacker.Settings(); 75 | settings.combineSubdirectories = true; 76 | TexturePacker.process(settings, "resources/raw/", ".", "resources/uiskin"); 77 | 78 | batch = new SpriteBatch(); 79 | skin = new Skin(); 80 | atlas = new TextureAtlas(Gdx.files.internal("resources/uiskin.atlas")); 81 | 82 | 83 | skin.addRegions(new TextureAtlas(Gdx.files.local("resources/uiskin.atlas"))); 84 | skin.load(Gdx.files.local("resources/uiskin.json")); 85 | 86 | screenMain = new MainScreen(this); 87 | screenWelcome = new WelcomeScreen(this); 88 | setScreen(screenWelcome); 89 | 90 | } 91 | 92 | 93 | 94 | /** 95 | * Display a dialog with a notice 96 | */ 97 | public void showNotice(String title, String message, Stage stage) { 98 | Dialog dlg = new Dialog(title, skin); 99 | dlg.pad(20); 100 | dlg.getContentTable().add(message).pad(20); 101 | dlg.button("OK", true); 102 | dlg.key(com.badlogic.gdx.Input.Keys.ENTER, true); 103 | dlg.key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 104 | dlg.show(stage); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/SystemFonts.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor; 17 | 18 | import com.badlogic.gdx.Gdx; 19 | import com.badlogic.gdx.utils.Array; 20 | 21 | import java.io.File; 22 | import java.util.HashMap; 23 | 24 | /** 25 | * Ok here's the deal. 26 | * 27 | * Handling fonts from JAVA mostly sucks when you want to get proper file path. 28 | * I also only want to list TTF fonts. 29 | * 30 | * @author Yanick Bourbeau 31 | * 32 | */ 33 | public class SystemFonts { 34 | 35 | private Array fontPaths = new Array(); 36 | public HashMap fonts = new HashMap(); 37 | 38 | /** 39 | * 40 | */ 41 | public SystemFonts() { 42 | 43 | String osName = System.getProperty("os.name"); 44 | if (osName.equals("Linux")) { 45 | 46 | fontPaths.add("/usr/share/fonts/"); 47 | fontPaths.add("~/.fonts/"); 48 | 49 | } else if (osName.contains("Windows")) { 50 | 51 | fontPaths.add("c:\\Windows\\Fonts\\"); 52 | 53 | } else { // Mac OS X 54 | 55 | fontPaths.add("/Network/Library/Fonts/"); 56 | fontPaths.add("~/Library/Fonts/"); 57 | fontPaths.add("/Library/Fonts/"); 58 | } 59 | 60 | } 61 | 62 | /** 63 | * Perform a search for fonts in the OS folders 64 | */ 65 | private void searchForFonts(String fontPath) { 66 | 67 | File[] files = new File(fontPath).listFiles(); 68 | if (files == null) { 69 | return; 70 | } 71 | for(File file : files) { 72 | if (file.isDirectory() == true) { 73 | searchForFonts(file.getAbsolutePath()); 74 | } else { 75 | String filename = file.getName(); 76 | if (filename.toLowerCase().endsWith(".ttf")) { 77 | filename = filename.substring(0, filename.length() - 4); 78 | 79 | String newFilename = ""; 80 | boolean previousIsUpper = false; 81 | for (int i=0;i listStyles; 63 | private Array listItems = new Array(); 64 | private Table tableFields; 65 | public Object currentStyle; 66 | private ObjectMap styles; 67 | 68 | /** 69 | * 70 | */ 71 | public OptionsPane(final SkinEditorGame game) { 72 | super(); 73 | 74 | this.game = game; 75 | 76 | left(); 77 | top(); 78 | setBackground(game.skin.getDrawable("default-pane")); 79 | 80 | add(new Label("Styles", game.skin, "title")).pad(5).row(); 81 | listStyles = new List(game.skin, "dimmed"); 82 | listStyles.setItems(listItems); 83 | ScrollPane scroll = new ScrollPane(listStyles, game.skin); 84 | scroll.setFlickScroll(false); 85 | scroll.setFadeScrollBars(false); 86 | scroll.setScrollbarsOnTop(true); 87 | scroll.setScrollBarPositions(false, true); 88 | scroll.setScrollingDisabled(true, false); 89 | add(scroll).height(200).expandX().fillX().pad(5).row(); 90 | 91 | // Add buttons 92 | Table tableStylesButtons = new Table(); 93 | TextButton buttonNewStyle = new TextButton("New Style", game.skin); 94 | TextButton buttonDeleteStyle = new TextButton("Delete Style", game.skin); 95 | tableStylesButtons.add(buttonNewStyle).pad(5); 96 | tableStylesButtons.add(buttonDeleteStyle).pad(5); 97 | add(tableStylesButtons).row(); 98 | 99 | // Callbacks 100 | 101 | listStyles.addListener(new ChangeListener() { 102 | 103 | @Override 104 | public void changed(ChangeEvent event, Actor actor) { 105 | 106 | String key = (String) listStyles.getSelected(); 107 | if (key != null) { 108 | Gdx.app.log("OptionsPane", "Selected style: " + key); 109 | currentStyle = styles.get(key); 110 | updateTableFields(key); 111 | } 112 | } 113 | 114 | }); 115 | 116 | buttonNewStyle.addListener(new ChangeListener() { 117 | 118 | @Override 119 | public void changed(ChangeEvent event, Actor actor) { 120 | createNewStyle(); 121 | } 122 | 123 | }); 124 | 125 | buttonDeleteStyle.addListener(new ChangeListener() { 126 | 127 | @Override 128 | public void changed(ChangeEvent event, Actor actor) { 129 | showDeleteDialog(); 130 | } 131 | 132 | }); 133 | 134 | // Initialize table 135 | 136 | add(new Label("Fields", game.skin, "title")).pad(5).padTop(10).row(); 137 | 138 | tableFields = new Table(game.skin); 139 | tableFields.setBackground(game.skin.getDrawable("dialogDim")); 140 | tableFields.left().top(); 141 | 142 | ScrollPane scroll2 = new ScrollPane(tableFields, game.skin); 143 | scroll2.setFlickScroll(false); 144 | scroll2.setFadeScrollBars(false); 145 | scroll2.setScrollbarsOnTop(true); 146 | scroll2.setScrollBarPositions(false, true); 147 | scroll2.setScrollingDisabled(true, false); 148 | add(scroll2).pad(5).expand().fill(); 149 | 150 | } 151 | 152 | /** 153 | * 154 | */ 155 | protected void showDeleteDialog() { 156 | 157 | // Check if it used by other style prior to delete it 158 | // FIXME: TODO 159 | 160 | Dialog dlgStyle = new Dialog("Delete Style", game.skin) { 161 | 162 | @Override 163 | protected void result(Object object) { 164 | if ((Boolean) object == false) { 165 | return; 166 | } 167 | 168 | // Now we really add it! 169 | game.skinProject.remove((String) listStyles.getSelected(), currentStyle.getClass()); 170 | refresh(); 171 | game.screenMain.saveToSkin(); 172 | game.screenMain.panePreview.refresh(); 173 | 174 | } 175 | 176 | }; 177 | 178 | dlgStyle.pad(20); 179 | dlgStyle.getContentTable().add("You are sure you want to delete this style?"); 180 | dlgStyle.button("OK", true); 181 | dlgStyle.button("Cancel", false); 182 | dlgStyle.key(com.badlogic.gdx.Input.Keys.ENTER, true); 183 | dlgStyle.key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 184 | dlgStyle.show(getStage()); 185 | 186 | } 187 | 188 | /** 189 | * 190 | */ 191 | protected void createNewStyle() { 192 | 193 | final TextField textStyleName = new TextField("", game.skin); 194 | Dialog dlgStyle = new Dialog("New Style", game.skin) { 195 | 196 | @Override 197 | protected void result(Object object) { 198 | if ((Boolean) object == false) { 199 | return; 200 | } 201 | 202 | String styleName = textStyleName.getText(); 203 | if (styleName.length() == 0) { 204 | 205 | game.showNotice("Warning", "No style name entered!", game.screenMain.stage); 206 | return; 207 | } 208 | 209 | // Check if the style name is already in use 210 | if (listItems.contains(styleName, false)) { 211 | game.showNotice("Warning", "Style name already in use!", game.screenMain.stage); 212 | return; 213 | } 214 | 215 | 216 | try { 217 | game.skinProject.add(styleName, currentStyle.getClass().newInstance()); 218 | } catch(Exception e) { 219 | e.printStackTrace(); 220 | } 221 | //game.skinProject.add(text, game.skin.get("default", currentStyle.getClass()), currentStyle.getClass()); 222 | game.screenMain.saveToSkin(); 223 | refresh(); 224 | 225 | game.screenMain.panePreview.refresh(); 226 | 227 | } 228 | 229 | }; 230 | 231 | dlgStyle.pad(20); 232 | dlgStyle.getContentTable().add("Style Name:"); 233 | dlgStyle.getContentTable().add(textStyleName).pad(20); 234 | dlgStyle.button("OK", true); 235 | dlgStyle.button("Cancel", false); 236 | dlgStyle.key(com.badlogic.gdx.Input.Keys.ENTER, true); 237 | dlgStyle.key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 238 | dlgStyle.show(getStage()); 239 | getStage().setKeyboardFocus(textStyleName); 240 | 241 | } 242 | 243 | /** 244 | * 245 | */ 246 | public void refreshSelection() { 247 | 248 | String key = listStyles.getSelected(); 249 | 250 | ImageButton button = (ImageButton) game.screenMain.barWidgets.group.getChecked(); 251 | String widget = button.getUserObject().toString(); 252 | String widgetStyle = "com.badlogic.gdx.scenes.scene2d.ui." + widget + "$" + widget + "Style"; 253 | Gdx.app.log("OptionsPane", "Fetching style:" + widgetStyle); 254 | 255 | listItems.clear(); 256 | 257 | try { 258 | Class style = Class.forName(widgetStyle); 259 | 260 | styles = game.skinProject.getAll(style); 261 | if (styles == null) { 262 | Gdx.app.error("OptionsPane", "No styles defined for this widget type"); 263 | 264 | tableFields.clear(); 265 | } else { 266 | Keys keys = styles.keys(); 267 | 268 | for (String k : keys) { 269 | listItems.add(k); 270 | 271 | } 272 | 273 | } 274 | listItems.sort(); 275 | listStyles.setItems(listItems); 276 | 277 | } catch (Exception e) { 278 | e.printStackTrace(); 279 | } 280 | 281 | 282 | currentStyle = styles.get(key); 283 | updateTableFields(key); 284 | 285 | } 286 | 287 | /** 288 | * 289 | */ 290 | public void refresh() { 291 | 292 | Gdx.app.log("OptionsPane", "Refresh"); 293 | 294 | ImageButton button = (ImageButton) game.screenMain.barWidgets.group.getChecked(); 295 | String widget = button.getUserObject().toString(); 296 | String widgetStyle = "com.badlogic.gdx.scenes.scene2d.ui." + widget + "$" + widget + "Style"; 297 | Gdx.app.log("OptionsPane", "Fetching style:" + widgetStyle); 298 | 299 | listItems.clear(); 300 | int selection = -1; 301 | 302 | try { 303 | Class style = Class.forName(widgetStyle); 304 | 305 | styles = game.skinProject.getAll(style); 306 | if (styles == null) { 307 | Gdx.app.error("OptionsPane", "No styles defined for this widget type"); 308 | 309 | tableFields.clear(); 310 | } else { 311 | Keys keys = styles.keys(); 312 | boolean first = true; 313 | 314 | for (String key : keys) { 315 | listItems.add(key); 316 | 317 | if (first == true) { 318 | 319 | currentStyle = styles.get(key); 320 | updateTableFields(key); 321 | selection = listItems.size-1; 322 | first = false; 323 | } 324 | 325 | } 326 | 327 | } 328 | listItems.sort(); 329 | listStyles.setItems(listItems); 330 | 331 | if (selection != -1) { 332 | listStyles.setSelectedIndex(selection); 333 | } 334 | 335 | } catch (Exception e) { 336 | e.printStackTrace(); 337 | } 338 | 339 | } 340 | 341 | /** 342 | * 343 | */ 344 | public void updateSelectedTableFields() { 345 | 346 | String key = (String) listStyles.getSelected(); 347 | if (key != null) { 348 | Gdx.app.log("OptionsPane", "Selected style: " + key); 349 | currentStyle = styles.get(key); 350 | updateTableFields(key); 351 | } 352 | } 353 | 354 | /** 355 | * 356 | */ 357 | private void updateTableFields(final String style) { 358 | 359 | ImageButton button = (ImageButton) game.screenMain.barWidgets.group.getChecked(); 360 | String widget = button.getUserObject().toString(); 361 | 362 | Gdx.app.log("OptionsPane", "Update fields table for widget: " + widget + ", style: " + style); 363 | tableFields.clear(); 364 | tableFields.add(new Label("Name", game.skin, "title")).left().width(170); 365 | tableFields.add(new Label("Value", game.skin, "title")).left().width(60).padRight(50); 366 | tableFields.row(); 367 | 368 | Field[] fields = ClassReflection.getFields(currentStyle.getClass()); 369 | for (final Field field : fields) { 370 | try { 371 | 372 | // field name 373 | 374 | // White required 375 | // Grey optional 376 | if (game.opt.isFieldOptional(currentStyle.getClass(), field.getName())) { 377 | 378 | tableFields.add(new Label(field.getName(),game.skin,"optional")).left(); 379 | 380 | } else { 381 | tableFields.add(new Label(field.getName(), game.skin, "default")).left(); 382 | 383 | } 384 | 385 | Actor actor; 386 | 387 | // field type 388 | String name = field.getType().getSimpleName(); 389 | Object obj = field.get(currentStyle); 390 | 391 | if (name.equals("Drawable")) { 392 | 393 | /** 394 | * Handle Drawable object 395 | */ 396 | 397 | Drawable drawable = (Drawable) field.get(currentStyle); 398 | String resourceName = ""; 399 | ImageTextButton.ImageTextButtonStyle buttonStyle = new ImageTextButton.ImageTextButtonStyle(game.skin.getDrawable("default-round"), 400 | game.skin.getDrawable("default-round-down"), game.skin.getDrawable("default-round"), game.skin.getFont("default-font")); 401 | 402 | if (drawable != null) { 403 | resourceName = game.skinProject.resolveObjectName(Drawable.class, drawable); 404 | buttonStyle.imageUp = drawable; 405 | } else { 406 | buttonStyle.up = game.skinProject.getDrawable("default-rect"); 407 | buttonStyle.checked = game.skinProject.getDrawable("default-rect"); 408 | } 409 | 410 | actor = new ImageTextButton(resourceName, buttonStyle); 411 | ((ImageTextButton) actor).setClip(true); 412 | actor.addListener(new ChangeListener() { 413 | 414 | @Override 415 | public void changed(ChangeEvent event, Actor actor) { 416 | showDrawableDialog(field); 417 | 418 | } 419 | 420 | }); 421 | 422 | } else if (name.equals("Color")) { 423 | 424 | /** 425 | * Handle Color object 426 | */ 427 | Color color = (Color) field.get(currentStyle); 428 | ImageTextButton.ImageTextButtonStyle buttonStyle = new ImageTextButton.ImageTextButtonStyle(game.skin.getDrawable("default-round"), 429 | game.skin.getDrawable("default-round-down"), game.skin.getDrawable("default-round"), game.skin.getFont("default-font")); 430 | 431 | String resourceName = ""; 432 | if (color != null) { 433 | resourceName = game.skinProject.resolveObjectName(Color.class, color); 434 | resourceName += " (" + color.toString() + ")"; 435 | 436 | // Create drawable on the fly 437 | Pixmap pixmap = new Pixmap(18, 18, Pixmap.Format.RGBA8888); 438 | pixmap.setColor(color); 439 | pixmap.fill(); 440 | pixmap.setColor(Color.BLACK); 441 | pixmap.drawRectangle(0, 0, 18, 18); 442 | Texture texture = new Texture(pixmap); 443 | buttonStyle.imageUp = new SpriteDrawable(new Sprite(texture)); 444 | pixmap.dispose(); 445 | } else { 446 | buttonStyle.up = game.skinProject.getDrawable("default-rect"); 447 | buttonStyle.checked = game.skinProject.getDrawable("default-rect"); 448 | } 449 | 450 | actor = new ImageTextButton(resourceName, buttonStyle); 451 | ((ImageTextButton) actor).setClip(true); 452 | actor.addListener(new ChangeListener() { 453 | 454 | @Override 455 | public void changed(ChangeEvent event, Actor actor) { 456 | showColorPickerDialog(field); 457 | 458 | } 459 | 460 | }); 461 | 462 | } else if (name.equals("BitmapFont")) { 463 | 464 | /** 465 | * Handle BitmapFont object 466 | */ 467 | 468 | BitmapFont font = (BitmapFont) field.get(currentStyle); 469 | String resourceName = ""; 470 | ImageTextButton.ImageTextButtonStyle buttonStyle = new ImageTextButton.ImageTextButtonStyle(game.skin.getDrawable("default-round"), 471 | game.skin.getDrawable("default-round-down"), game.skin.getDrawable("default-round"), game.skin.getFont("default-font")); 472 | 473 | if (font != null) { 474 | resourceName = game.skinProject.resolveObjectName(BitmapFont.class, font); 475 | buttonStyle.font = font; 476 | } else { 477 | buttonStyle.up = game.skinProject.getDrawable("default-rect"); 478 | buttonStyle.checked = game.skinProject.getDrawable("default-rect"); 479 | } 480 | 481 | actor = new ImageTextButton(resourceName, buttonStyle); 482 | ((ImageTextButton) actor).setClip(true); 483 | 484 | actor.addListener(new ChangeListener() { 485 | 486 | @Override 487 | public void changed(ChangeEvent event, Actor actor) { 488 | showFontPickerDialog(field); 489 | 490 | } 491 | 492 | }); 493 | 494 | } else if (name.equals("float")) { 495 | 496 | /** 497 | * Handle Float object 498 | */ 499 | 500 | Float value = (Float) field.get(currentStyle); 501 | String resourceName = ""; 502 | 503 | ImageTextButton.ImageTextButtonStyle buttonStyle = new ImageTextButton.ImageTextButtonStyle(game.skin.getDrawable("default-round"), 504 | game.skin.getDrawable("default-round-down"), game.skin.getDrawable("default-round"), game.skin.getFont("default-font")); 505 | 506 | if ((value != null) && (value != 0)) { 507 | resourceName = String.valueOf(value); 508 | } else { 509 | buttonStyle.up = game.skinProject.getDrawable("default-rect"); 510 | buttonStyle.checked = game.skinProject.getDrawable("default-rect"); 511 | } 512 | 513 | actor = new ImageTextButton(resourceName, buttonStyle); 514 | ((ImageTextButton) actor).setClip(true); 515 | actor.addListener(new ChangeListener() { 516 | 517 | @Override 518 | public void changed(ChangeEvent event, Actor actor) { 519 | showFloatInputDialog(field); 520 | 521 | } 522 | 523 | }); 524 | 525 | } else if (name.equals("ListStyle")) { 526 | 527 | /** 528 | * Handle ListStyle object 529 | */ 530 | ListStyle listStyle = (ListStyle) field.get(currentStyle); 531 | 532 | actor = new SelectBox(game.skin, "default"); 533 | Array items = new Array(); 534 | 535 | final ObjectMap values = game.skinProject.getAll(ListStyle.class); 536 | Iterator it = values.keys().iterator(); 537 | String selection = null; 538 | 539 | while(it.hasNext()) { 540 | String key = it.next(); 541 | items.add(key); 542 | 543 | if (listStyle == values.get(key)) { 544 | selection = key; 545 | } 546 | } 547 | 548 | ((SelectBox) actor).setItems(items); 549 | 550 | if (selection != null) { 551 | ((SelectBox) actor).setSelected(selection); 552 | } 553 | 554 | actor.addListener(new ChangeListener() { 555 | 556 | @Override 557 | public void changed(ChangeEvent event, Actor actor) { 558 | 559 | String selection = (String) ((SelectBox) actor).getSelected(); 560 | try { 561 | field.set(currentStyle, values.get(selection)); 562 | } catch(Exception e) { 563 | e.printStackTrace(); 564 | } 565 | 566 | game.screenMain.saveToSkin(); 567 | refresh(); 568 | game.screenMain.paneOptions.updateSelectedTableFields(); 569 | game.screenMain.panePreview.refresh(); 570 | } 571 | 572 | }); 573 | 574 | 575 | } else if (name.equals("ScrollPaneStyle")) { 576 | 577 | /** 578 | * Handle ListStyle object 579 | */ 580 | ScrollPaneStyle scrollStyle = (ScrollPaneStyle) field.get(currentStyle); 581 | 582 | actor = new SelectBox(game.skin, "default"); 583 | Array items = new Array(); 584 | 585 | final ObjectMap values = game.skinProject.getAll(ScrollPaneStyle.class); 586 | Iterator it = values.keys().iterator(); 587 | String selection = null; 588 | 589 | while(it.hasNext()) { 590 | String key = it.next(); 591 | items.add(key); 592 | 593 | if (scrollStyle == values.get(key)) { 594 | selection = key; 595 | } 596 | } 597 | 598 | ((SelectBox) actor).setItems(items); 599 | 600 | if (selection != null) { 601 | ((SelectBox) actor).setSelected(selection); 602 | } 603 | 604 | actor.addListener(new ChangeListener() { 605 | 606 | @Override 607 | public void changed(ChangeEvent event, Actor actor) { 608 | 609 | String selection = (String) ((SelectBox) actor).getSelected(); 610 | try { 611 | field.set(currentStyle, values.get(selection)); 612 | } catch(Exception e) { 613 | e.printStackTrace(); 614 | } 615 | 616 | game.screenMain.saveToSkin(); 617 | refresh(); 618 | game.screenMain.paneOptions.updateSelectedTableFields(); 619 | game.screenMain.panePreview.refresh(); 620 | } 621 | 622 | }); 623 | 624 | } else { 625 | 626 | Gdx.app.log("OptionsPane", "Unknown type: " + name); 627 | actor = new Label("Unknown Type", game.skin); 628 | } 629 | 630 | tableFields.add(actor).left().height(32).padRight(24).expandX().fillX(); 631 | 632 | tableFields.row(); 633 | } catch (Exception e) { 634 | e.printStackTrace(); 635 | } 636 | } 637 | 638 | } 639 | 640 | /** 641 | * 642 | * Display a input dialog asking for a float value 643 | * 644 | */ 645 | public void showFloatInputDialog(final Field field) { 646 | 647 | try { 648 | final TextField textValue = new TextField(String.valueOf((Float) field.get(currentStyle)), game.skin); 649 | Dialog dlg = new Dialog("Change Value", game.skin) { 650 | 651 | @Override 652 | protected void result(Object object) { 653 | if ((Boolean) object == false) { 654 | return; 655 | } 656 | 657 | float value = 0; 658 | String text = textValue.getText(); 659 | if (text.isEmpty() == false) { 660 | value = Float.valueOf(text); 661 | } 662 | 663 | try { 664 | field.set(currentStyle, value); 665 | } catch (Exception e) { 666 | e.printStackTrace(); 667 | } 668 | 669 | game.screenMain.saveToSkin(); 670 | refresh(); 671 | game.screenMain.paneOptions.updateSelectedTableFields(); 672 | game.screenMain.panePreview.refresh(); 673 | 674 | } 675 | 676 | }; 677 | 678 | dlg.pad(20); 679 | dlg.getContentTable().add("Float Value:"); 680 | dlg.getContentTable().add(textValue).pad(20); 681 | dlg.button("OK", true); 682 | dlg.button("Cancel", false); 683 | dlg.key(com.badlogic.gdx.Input.Keys.ENTER, true); 684 | dlg.key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 685 | dlg.show(getStage()); 686 | getStage().setKeyboardFocus(textValue); 687 | 688 | } catch (Exception e) { 689 | e.printStackTrace(); 690 | } 691 | } 692 | 693 | /** 694 | * Show color picker dialog 695 | */ 696 | public void showColorPickerDialog(final Field field) { 697 | 698 | ColorPickerDialog dlg = new ColorPickerDialog(game, field); 699 | dlg.show(getStage()); 700 | } 701 | 702 | /** 703 | * Show font picker dialog 704 | */ 705 | public void showFontPickerDialog(final Field field) { 706 | 707 | FontPickerDialog dlg = new FontPickerDialog(game, field); 708 | dlg.show(getStage()); 709 | } 710 | 711 | 712 | /** 713 | * Show drawable picker dialog 714 | * @param field 715 | */ 716 | public void showDrawableDialog(final Field field) { 717 | 718 | DrawablePickerDialog dlg = new DrawablePickerDialog(game, field); 719 | dlg.show(getStage()); 720 | } 721 | 722 | } 723 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/actors/PreviewPane.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor.actors; 17 | 18 | import org.shadebob.skineditor.SkinEditorGame; 19 | 20 | import com.badlogic.gdx.Gdx; 21 | import com.badlogic.gdx.graphics.g3d.model.Node; 22 | import com.badlogic.gdx.scenes.scene2d.InputEvent; 23 | import com.badlogic.gdx.scenes.scene2d.InputListener; 24 | import com.badlogic.gdx.scenes.scene2d.Touchable; 25 | import com.badlogic.gdx.scenes.scene2d.ui.Button; 26 | import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; 27 | import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; 28 | import com.badlogic.gdx.scenes.scene2d.ui.Label; 29 | import com.badlogic.gdx.scenes.scene2d.ui.List; 30 | import com.badlogic.gdx.scenes.scene2d.ui.ProgressBar; 31 | import com.badlogic.gdx.scenes.scene2d.ui.ProgressBar.ProgressBarStyle; 32 | import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 33 | import com.badlogic.gdx.scenes.scene2d.ui.SelectBox; 34 | import com.badlogic.gdx.scenes.scene2d.ui.Slider; 35 | import com.badlogic.gdx.scenes.scene2d.ui.SplitPane; 36 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 37 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton; 38 | import com.badlogic.gdx.scenes.scene2d.ui.TextField; 39 | import com.badlogic.gdx.scenes.scene2d.ui.Touchpad; 40 | import com.badlogic.gdx.scenes.scene2d.ui.Tree; 41 | import com.badlogic.gdx.scenes.scene2d.ui.Window; 42 | import com.badlogic.gdx.utils.Array; 43 | import com.badlogic.gdx.utils.ObjectMap; 44 | import com.badlogic.gdx.utils.Sort; 45 | import com.badlogic.gdx.utils.ObjectMap.Keys; 46 | 47 | 48 | /** 49 | * A table representing the right part of the interface 50 | * 51 | * @author Yanick Bourbeau 52 | * 53 | */ 54 | public class PreviewPane extends Table { 55 | 56 | // private Table tab 57 | private SkinEditorGame game; 58 | // An input listener to use on items inside a scroll pane, thanks to Tomski for the hint. 59 | private InputListener stopTouchDown = new InputListener() { 60 | 61 | @Override 62 | public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { 63 | event.stop(); 64 | return false; 65 | } 66 | }; 67 | 68 | /** 69 | * 70 | */ 71 | public PreviewPane(SkinEditorGame game) { 72 | 73 | super(game.skin); 74 | this.game = game; 75 | top(); 76 | left(); 77 | 78 | } 79 | 80 | /** 81 | * 82 | */ 83 | public void refresh() { 84 | 85 | Gdx.app.log("PreviewPane", "Refresh pane!"); 86 | clear(); 87 | 88 | ImageButton button = (ImageButton) game.screenMain.barWidgets.group.getChecked(); 89 | String widget = button.getUserObject().toString(); 90 | String widgetStyle = "com.badlogic.gdx.scenes.scene2d.ui." + widget + "$" + widget + "Style"; 91 | 92 | 93 | 94 | try { 95 | Class style = Class.forName(widgetStyle); 96 | 97 | ObjectMap styles = game.skinProject.getAll(style); 98 | if (styles == null) { 99 | Label label = new Label("No styles defined for this widget type", game.skin, "error"); 100 | add(label).row().pad(10); 101 | 102 | } else { 103 | 104 | Keys keys = styles.keys(); 105 | Array sortedKeys = new Array(); 106 | for (String key : keys) { 107 | sortedKeys.add(key); 108 | } 109 | sortedKeys.sort(); 110 | 111 | for (String key : sortedKeys) { 112 | 113 | // We render one per key 114 | add(new Label(key, game.skin, "title")).left().pad(10).expandX().row(); 115 | 116 | try { 117 | if (widget.equals("Label")) { 118 | 119 | Label w = new Label("This is a Label widget", game.skinProject, key); 120 | add(w).pad(10).padBottom(20).row(); 121 | 122 | } else if (widget.equals("Button")) { // Button 123 | 124 | Button w = new Button(game.skinProject, key); 125 | add(w).width(120).height(32).pad(10).padBottom(20).row(); 126 | 127 | } else if (widget.equals("TextButton")) { // TextButton 128 | 129 | TextButton w = new TextButton("This is a TextButton widget", game.skinProject, key); 130 | 131 | add(w).pad(10).padBottom(20).row(); 132 | 133 | } else if (widget.equals("ImageButton")) { // ImageButton 134 | 135 | ImageButton w = new ImageButton(game.skinProject, key); 136 | add(w).pad(10).padBottom(20).row(); 137 | 138 | } else if (widget.equals("CheckBox")) { // CheckBox 139 | 140 | CheckBox w = new CheckBox("This is a CheckBox widget", game.skinProject, key); 141 | w.setChecked(true); 142 | add(w).pad(10).padBottom(20).row(); 143 | 144 | 145 | } else if (widget.equals("TextField")) { // TextField 146 | 147 | TextField w = new TextField("This is a TextField widget", game.skinProject, key); 148 | if (w.getStyle().fontColor == null) { 149 | throw new Exception("Textfield style requires a font color!"); 150 | } 151 | 152 | w.addListener(stopTouchDown); 153 | 154 | add(w).pad(10).width(220).padBottom(20).row(); 155 | 156 | } else if (widget.equals("List")) { // List 157 | 158 | List w = new List(game.skinProject, key); 159 | Array items = new Array(); 160 | items.add("This is"); 161 | items.add("a"); 162 | items.add("List widget!"); 163 | w.setItems(items); 164 | 165 | add(w).pad(10).width(220).height(120).padBottom(20).expandX().fillX().row(); 166 | 167 | } else if (widget.equals("SelectBox")) { // SelectBox 168 | SelectBox w = new SelectBox(game.skinProject, key); 169 | Array items = new Array(); 170 | items.add("This is"); 171 | items.add("a"); 172 | items.add("SelectBox widget!"); 173 | w.setItems(items); 174 | 175 | add(w).pad(10).width(220).padBottom(20).expandX().fillX().row(); 176 | 177 | } else if (widget.equals("ProgressBar")) { // ProgressBar 178 | 179 | ProgressBarStyle progressStyle = game.skinProject.get(key, ProgressBarStyle.class); 180 | 181 | // Check for edge-case: fields knob and knobBefore are optional but at least one should be specified 182 | if(progressStyle.knob == null && progressStyle.knobBefore == null) { 183 | throw new IllegalArgumentException("Fields 'knob' and 'knobBefore' in ProgressBarStyle are both optional but at least one should be specified"); 184 | } 185 | 186 | ProgressBar w = new ProgressBar(0, 100, 5, false, progressStyle); 187 | w.setValue(50); 188 | w.addListener(stopTouchDown); 189 | 190 | add(w).pad(10).width(220).padBottom(20).expandX().fillX().row(); 191 | 192 | } else if (widget.equals("Slider")) { // Slider 193 | 194 | Slider w = new Slider(0, 100, 5, false, game.skinProject, key); 195 | add(w).pad(10).width(220).padBottom(20).expandX().fillX().row(); 196 | w.addListener(stopTouchDown); 197 | 198 | Slider w2 = new Slider(0, 100, 5, true, game.skinProject, key); 199 | add(w2).pad(10).padBottom(20).expandX().fillX().row(); 200 | w2.addListener(stopTouchDown); 201 | 202 | 203 | } else if (widget.equals("ScrollPane")) { // ScrollPane 204 | 205 | Table t = new Table(game.skin); 206 | for (int i = 0; i < 20; i++) { 207 | t.add("This is a ScrollPane Widget").padRight(10); 208 | t.add("This is a ScrollPane Widget").padRight(10); 209 | t.add("This is a ScrollPane Widget").row(); 210 | } 211 | ScrollPane w = new ScrollPane(t, game.skinProject, key); 212 | w.addListener(stopTouchDown); 213 | w.setFlickScroll(true); 214 | w.setScrollbarsOnTop(true); 215 | w.setScrollBarPositions(true, true); 216 | w.setFadeScrollBars(false); 217 | add(w).pad(10).width(420).height(240).padBottom(20).expandX().fillX().row(); 218 | 219 | } else if (widget.equals("SplitPane")) { // SplitPane 220 | 221 | for (int j = 0; j < 2; j++) { 222 | Table t = new Table(game.skin); 223 | t.setBackground(game.skin.getDrawable("default-rect")); 224 | Table t2 = new Table(game.skin); 225 | t2.setBackground(game.skin.getDrawable("default-rect")); 226 | for (int i = 0; i < 20; i++) { 227 | t.add("This is a SplitPane Widget").pad(10).row(); 228 | t2.add("This is a SplitPane Widget").pad(10).row(); 229 | } 230 | 231 | SplitPane w = new SplitPane(t, t2, (j % 2 == 0), game.skinProject, key); 232 | w.addListener(stopTouchDown); 233 | add(w).pad(10).width(220).height(160).padBottom(20).expandX().fillX(); 234 | } 235 | row(); 236 | 237 | } else if (widget.equals("Window")) { // Window 238 | 239 | Table t = new Table(game.skin); 240 | for (int i = 0; i < 5; i++) { 241 | t.add("This is a Window Widget").row(); 242 | } 243 | Window w = new Window("This is a Window Widget", game.skinProject, key); 244 | w.addListener(stopTouchDown); 245 | w.add(t); 246 | add(w).pad(10).width(420).height(240).padBottom(20).expandX().fillX().row(); 247 | 248 | } else if (widget.equals("Touchpad")) { // Touchpad 249 | 250 | Touchpad w = new Touchpad(0, game.skinProject, key); 251 | w.addListener(stopTouchDown); 252 | 253 | add(w).pad(10).width(200).height(200).padBottom(20).expandX().fillX().row(); 254 | 255 | } else if (widget.equals("Tree")) { // Tree 256 | 257 | Tree w = new Tree(game.skinProject, key); 258 | Tree.Node node = new Tree.Node(new Label("This", game.skin)); 259 | Tree.Node node1 = new Tree.Node(new Label("is", game.skin)); 260 | Tree.Node node2 = new Tree.Node(new Label("a", game.skin)); 261 | Tree.Node node3 = new Tree.Node(new Label("Tree", game.skin)); 262 | Tree.Node node4 = new Tree.Node(new Label("Widget", game.skin)); 263 | node3.add(node4); 264 | node2.add(node3); 265 | node1.add(node2); 266 | node.add(node1); 267 | w.add(node); 268 | 269 | w.expandAll(); 270 | add(w).pad(10).width(200).height(200).padBottom(20).expandX().fillX().row(); 271 | } else { 272 | add(new Label("Unknown widget type!", game.skin, "error")).pad(10).padBottom(20).row(); 273 | } 274 | } catch(Exception e) { 275 | add(new Label("Please fill all required fields", game.skin, "error")).pad(10).padBottom(20).row(); 276 | } 277 | } 278 | 279 | } 280 | 281 | } catch (Exception e) { 282 | e.printStackTrace(); 283 | } 284 | 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/actors/RangeSelector.java: -------------------------------------------------------------------------------- 1 | package org.shadebob.skineditor.actors; 2 | 3 | import com.badlogic.gdx.graphics.Color; 4 | import com.badlogic.gdx.graphics.g2d.Batch; 5 | import com.badlogic.gdx.math.Vector2; 6 | import com.badlogic.gdx.scenes.scene2d.Actor; 7 | import com.badlogic.gdx.scenes.scene2d.Event; 8 | import com.badlogic.gdx.scenes.scene2d.InputEvent; 9 | import com.badlogic.gdx.scenes.scene2d.InputListener; 10 | import com.badlogic.gdx.scenes.scene2d.ui.Skin; 11 | import com.badlogic.gdx.scenes.scene2d.ui.Widget; 12 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; 13 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent; 14 | import com.badlogic.gdx.scenes.scene2d.utils.Drawable; 15 | 16 | public class RangeSelector extends Widget { 17 | 18 | private Drawable drawableWhite; 19 | private Drawable drawableBlack; 20 | private boolean vertical; 21 | public float rangeStart = 0.25f; 22 | public float rangeStop = 0.75f; 23 | 24 | public RangeSelector(final boolean vertical, Skin skin) { 25 | super(); 26 | 27 | this.vertical = vertical; 28 | drawableWhite = skin.getDrawable("white"); 29 | drawableBlack = skin.newDrawable("white", 0,0,0,1); 30 | 31 | addListener(new InputListener() { 32 | 33 | public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { 34 | 35 | if (vertical == true) { 36 | 37 | if (event.getButton() == 0) { 38 | rangeStart = (getHeight() - y) / getHeight(); 39 | } else { 40 | rangeStop = (getHeight() - y) / getHeight(); 41 | } 42 | 43 | } else { 44 | 45 | if (event.getButton() == 0) { 46 | rangeStart = x / getWidth(); 47 | 48 | } else { 49 | rangeStop = x / getWidth(); 50 | } 51 | } 52 | 53 | 54 | if (rangeStart > rangeStop) { 55 | float temp = rangeStop; 56 | rangeStop = rangeStart; 57 | rangeStart = temp; 58 | 59 | } 60 | 61 | if (rangeStop < rangeStart) { 62 | float temp = rangeStop; 63 | rangeStop = rangeStart; 64 | rangeStart = temp; 65 | 66 | } 67 | 68 | fire(new ChangeListener.ChangeEvent()); 69 | 70 | return false; 71 | } 72 | 73 | 74 | 75 | }); 76 | 77 | } 78 | 79 | @Override 80 | public void draw (Batch batch, float parentAlpha) { 81 | 82 | validate(); 83 | Color color = getColor(); 84 | batch.setColor(color.r, color.g, color.b, color.a * parentAlpha); 85 | 86 | 87 | drawableWhite.draw(batch, getX(), getY(),getWidth(),getHeight()); 88 | if (vertical == true) { 89 | 90 | float start = rangeStart * getHeight(); 91 | float stop = rangeStop * getHeight(); 92 | 93 | drawableBlack.draw(batch, getX(),getY() + getHeight() - start,getWidth(),-(stop-start)); 94 | } else { 95 | float start = rangeStart * getWidth(); 96 | float stop = rangeStop * getWidth(); 97 | 98 | drawableBlack.draw(batch, getX() + start, getY(),stop-start, getHeight()); 99 | } 100 | 101 | } 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/actors/WidgetsBar.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor.actors; 17 | 18 | import org.shadebob.skineditor.SkinEditorGame; 19 | import com.badlogic.gdx.scenes.scene2d.InputEvent; 20 | import com.badlogic.gdx.scenes.scene2d.ui.ButtonGroup; 21 | import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; 22 | import com.badlogic.gdx.scenes.scene2d.ui.ImageButton.ImageButtonStyle; 23 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 24 | import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; 25 | import com.mobidevelop.maps.editor.ui.utils.Tooltips; 26 | 27 | /** 28 | * 29 | * A table representing the buttons panel at the top 30 | * 31 | * @author Yanick Bourbeau 32 | * 33 | */ 34 | public class WidgetsBar extends Table { 35 | 36 | private SkinEditorGame game; 37 | public ButtonGroup group; 38 | 39 | /** 40 | * 41 | */ 42 | public WidgetsBar(final SkinEditorGame game) { 43 | super(); 44 | this.game = game; 45 | 46 | left(); 47 | setBackground(game.skin.getDrawable("default-pane")); 48 | 49 | } 50 | 51 | /** 52 | * 53 | */ 54 | public void initializeButtons() { 55 | 56 | group = new ButtonGroup(); 57 | 58 | Tooltips.TooltipStyle styleTooltip = new Tooltips.TooltipStyle(game.skin.getFont("default-font"), game.skin.getDrawable("default-round"), game.skin.getColor("white")); 59 | 60 | String[] widgets = SkinEditorGame.widgets; 61 | for (String widget : widgets) { 62 | 63 | ImageButtonStyle style = new ImageButtonStyle(); 64 | style.checked = game.skin.getDrawable("default-round-down"); 65 | style.down = game.skin.getDrawable("default-round-down"); 66 | style.up = game.skin.getDrawable("default-round"); 67 | style.imageUp = game.skin.getDrawable("widgets/" + widget); 68 | ImageButton button = new ImageButton(style); 69 | button.setUserObject(widget); 70 | 71 | Tooltips tooltip = new Tooltips(styleTooltip, getStage()); 72 | tooltip.registerTooltip(button, (String) button.getUserObject()); 73 | 74 | button.addListener(new ClickListener() { 75 | 76 | @Override 77 | public void clicked(InputEvent event, float x, float y) { 78 | game.screenMain.panePreview.refresh(); 79 | game.screenMain.paneOptions.refresh(); 80 | 81 | } 82 | 83 | }); 84 | 85 | group.add(button); 86 | add(button).pad(5); 87 | } 88 | 89 | 90 | } 91 | 92 | /** 93 | * 94 | */ 95 | public void resetButtonSelection() { 96 | group.getButtons().get(0).setChecked(true); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/screens/MainScreen.java: -------------------------------------------------------------------------------- 1 | package org.shadebob.skineditor.screens; 2 | 3 | import org.shadebob.skineditor.SkinEditorGame; 4 | import org.shadebob.skineditor.actors.MenuBar; 5 | import org.shadebob.skineditor.actors.OptionsPane; 6 | import org.shadebob.skineditor.actors.PreviewPane; 7 | import org.shadebob.skineditor.actors.WidgetsBar; 8 | 9 | import com.badlogic.gdx.Gdx; 10 | import com.badlogic.gdx.Screen; 11 | import com.badlogic.gdx.files.FileHandle; 12 | import com.badlogic.gdx.graphics.GL20; 13 | import com.badlogic.gdx.graphics.g2d.TextureAtlas; 14 | import com.badlogic.gdx.scenes.scene2d.InputEvent; 15 | import com.badlogic.gdx.scenes.scene2d.InputListener; 16 | import com.badlogic.gdx.scenes.scene2d.Stage; 17 | import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 18 | import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 19 | import com.badlogic.gdx.scenes.scene2d.ui.Skin; 20 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 21 | import com.badlogic.gdx.tools.texturepacker.TexturePacker; 22 | import com.badlogic.gdx.utils.Array; 23 | import com.badlogic.gdx.utils.TimeUtils; 24 | import com.badlogic.gdx.utils.viewport.ExtendViewport; 25 | import com.badlogic.gdx.utils.viewport.FitViewport; 26 | import com.badlogic.gdx.utils.viewport.ScreenViewport; 27 | 28 | public class MainScreen implements Screen { 29 | 30 | private SkinEditorGame game; 31 | public MenuBar barMenu; 32 | public WidgetsBar barWidgets; 33 | public PreviewPane panePreview; 34 | public OptionsPane paneOptions; 35 | public Stage stage; 36 | private String currentProject = ""; 37 | 38 | public MainScreen(SkinEditorGame game) { 39 | this.game = game; 40 | 41 | barMenu = new MenuBar(game); 42 | barWidgets = new WidgetsBar(game); 43 | panePreview = new PreviewPane(game); 44 | paneOptions = new OptionsPane(game); 45 | stage = new Stage(new ScreenViewport()); 46 | 47 | Table table = new Table(); 48 | table.setFillParent(true); 49 | 50 | table.top().left().add(barMenu).expandX().fillX().colspan(2).row(); 51 | table.top().left().add(barWidgets).expandX().fillX().colspan(2).row(); 52 | table.top().left().add(paneOptions).width(420).left().fill().expandY(); 53 | ScrollPane scrollPane = new ScrollPane(panePreview); 54 | table.add(scrollPane).fill().expand(); 55 | stage.addActor(table); 56 | barWidgets.initializeButtons(); 57 | 58 | 59 | 60 | } 61 | 62 | @Override 63 | public void render(float delta) { 64 | 65 | Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 66 | 67 | stage.act(delta); 68 | stage.draw(); 69 | 70 | } 71 | 72 | /** 73 | * 74 | * @param project 75 | */ 76 | public void setCurrentProject(String project) { 77 | currentProject = project; 78 | } 79 | 80 | public String getcurrentProject() { 81 | return currentProject; 82 | } 83 | 84 | /** 85 | * 86 | */ 87 | @Override 88 | public void resize(int width, int height) { 89 | stage.getViewport().update(width, height, true); 90 | 91 | } 92 | 93 | /** 94 | * 95 | */ 96 | @Override 97 | public void show() { 98 | 99 | if (currentProject == "") { 100 | Gdx.app.error("MainScreen", "Current project not set!"); 101 | Gdx.app.exit(); 102 | } 103 | refreshResources(); 104 | 105 | barMenu.update(currentProject); 106 | 107 | panePreview.refresh(); 108 | paneOptions.refresh(); 109 | 110 | barWidgets.resetButtonSelection(); 111 | 112 | Gdx.input.setInputProcessor(stage); 113 | 114 | } 115 | 116 | 117 | @Override 118 | public void hide() { 119 | } 120 | 121 | @Override 122 | public void pause() { 123 | // Do nothing 124 | 125 | } 126 | 127 | @Override 128 | public void resume() { 129 | // Do nothing 130 | 131 | } 132 | 133 | @Override 134 | public void dispose() { 135 | // Do nothing 136 | 137 | } 138 | 139 | /** 140 | * Save everything to skin 141 | */ 142 | public void saveToSkin() { 143 | 144 | FileHandle projectFolder = Gdx.files.local("projects").child(currentProject); 145 | 146 | FileHandle[] items = projectFolder.child("backups").list(); 147 | Array sortedItems = new Array(); 148 | for(FileHandle item: items) { 149 | sortedItems.add(item.name()); 150 | } 151 | sortedItems.sort(); 152 | 153 | // Keep only last ten files 154 | int count = 0; 155 | for (String item : sortedItems) { 156 | if (count++ > 8) { 157 | // Remove file 158 | projectFolder.child("backups").child(item).delete(); 159 | } 160 | } 161 | 162 | FileHandle projectFile = projectFolder.child("uiskin.json"); 163 | FileHandle backupFile = projectFolder.child("backups").child("uiskin_" +(TimeUtils.millis()/1000) +".json"); 164 | projectFile.copyTo(backupFile); 165 | game.skinProject.save(projectFile); 166 | 167 | } 168 | 169 | /** 170 | * 171 | */ 172 | public void refreshResources() { 173 | 174 | TexturePacker.Settings settings = new TexturePacker.Settings(); 175 | settings.combineSubdirectories = true; 176 | settings.maxWidth = 2048; 177 | settings.maxHeight = 2048; 178 | TexturePacker.process(settings, "projects/" + currentProject +"/assets/", "projects/" + currentProject, "uiskin"); 179 | 180 | 181 | // Load project skin 182 | if (game.skinProject != null) { 183 | game.skinProject.dispose(); 184 | } 185 | 186 | game.skinProject = new Skin(); 187 | game.skinProject.addRegions(new TextureAtlas(Gdx.files.local("projects/" + currentProject +"/uiskin.atlas"))); 188 | game.skinProject.load(Gdx.files.local("projects/" + currentProject +"/uiskin.json")); 189 | 190 | 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /core/src/org/shadebob/skineditor/screens/WelcomeScreen.java: -------------------------------------------------------------------------------- 1 | package org.shadebob.skineditor.screens; 2 | 3 | import org.shadebob.skineditor.NinePatchEditorDialog; 4 | import org.shadebob.skineditor.SkinEditorGame; 5 | 6 | import com.badlogic.gdx.Gdx; 7 | import com.badlogic.gdx.Screen; 8 | import com.badlogic.gdx.files.FileHandle; 9 | import com.badlogic.gdx.graphics.GL20; 10 | import com.badlogic.gdx.scenes.scene2d.Actor; 11 | import com.badlogic.gdx.scenes.scene2d.Stage; 12 | import com.badlogic.gdx.scenes.scene2d.ui.Dialog; 13 | import com.badlogic.gdx.scenes.scene2d.ui.Label; 14 | import com.badlogic.gdx.scenes.scene2d.ui.List; 15 | import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 16 | import com.badlogic.gdx.scenes.scene2d.ui.Table; 17 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton; 18 | import com.badlogic.gdx.scenes.scene2d.ui.TextField; 19 | import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; 20 | import com.badlogic.gdx.tools.texturepacker.TexturePacker; 21 | import com.badlogic.gdx.utils.Array; 22 | import com.badlogic.gdx.utils.Json; 23 | import com.badlogic.gdx.utils.viewport.FitViewport; 24 | import com.badlogic.gdx.utils.viewport.ScreenViewport; 25 | 26 | public class WelcomeScreen implements Screen { 27 | 28 | private SkinEditorGame game; 29 | public Stage stage; 30 | private List listProjects; 31 | 32 | public WelcomeScreen(SkinEditorGame game) { 33 | this.game = game; 34 | stage = new Stage(new ScreenViewport()); 35 | } 36 | 37 | @Override 38 | public void render(float delta) { 39 | 40 | Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 41 | 42 | stage.act(delta); 43 | stage.draw(); 44 | Table.drawDebug(stage); 45 | 46 | } 47 | 48 | @Override 49 | public void resize(int width, int height) { 50 | stage.getViewport().update(width, height, true); 51 | 52 | } 53 | 54 | @Override 55 | public void show() { 56 | 57 | Table table = new Table(game.skin); 58 | table.setFillParent(true); 59 | table.setBackground(game.skin.getDrawable("dialogDim")); 60 | stage.addActor(table); 61 | 62 | Table tableContent = new Table(game.skin); 63 | tableContent.left(); 64 | tableContent.add(new Label("Project List", game.skin, "title")).left().row(); 65 | listProjects = new List(game.skin); 66 | ScrollPane scrollPane = new ScrollPane(listProjects, game.skin); 67 | tableContent.add(scrollPane).width(320).height(200).row(); 68 | 69 | Table tableButtons = new Table(game.skin); 70 | 71 | TextButton buttonNewProject = new TextButton("New Project", game.skin); 72 | final TextButton buttonOpen = new TextButton("Open", game.skin); 73 | final TextButton buttonDelete = new TextButton("Delete", game.skin); 74 | buttonOpen.setDisabled(true); 75 | buttonDelete.setDisabled(true); 76 | 77 | tableButtons.add(buttonNewProject).pad(5).expandX().fillX(); 78 | tableButtons.add(buttonOpen).pad(5).width(92); 79 | tableButtons.add(buttonDelete).pad(5).width(92); 80 | 81 | tableContent.add(tableButtons).expandX().fillX(); 82 | 83 | table.add(tableContent); 84 | 85 | Gdx.input.setInputProcessor(stage); 86 | 87 | listProjects.addListener(new ChangeListener() { 88 | 89 | @Override 90 | public void changed(ChangeEvent event, Actor actor) { 91 | if (listProjects.getSelected() != null) { 92 | 93 | buttonOpen.setDisabled(false); 94 | buttonDelete.setDisabled(false); 95 | 96 | } else { 97 | buttonOpen.setDisabled(true); 98 | buttonDelete.setDisabled(true); 99 | 100 | } 101 | } 102 | 103 | }); 104 | 105 | 106 | buttonNewProject.addListener(new ChangeListener() { 107 | 108 | @Override 109 | public void changed(ChangeEvent event, Actor actor) { 110 | 111 | 112 | showNewProjectDialog(); 113 | 114 | } 115 | 116 | }); 117 | 118 | 119 | buttonOpen.addListener(new ChangeListener() { 120 | 121 | @Override 122 | public void changed(ChangeEvent event, Actor actor) { 123 | 124 | game.screenMain.setCurrentProject((String) listProjects.getSelected()); 125 | game.setScreen(game.screenMain); 126 | 127 | } 128 | }); 129 | 130 | buttonDelete.addListener(new ChangeListener() { 131 | 132 | @Override 133 | public void changed(ChangeEvent event, Actor actor) { 134 | 135 | showDeleteDialog(); 136 | 137 | } 138 | 139 | 140 | }); 141 | 142 | refreshProjects(); 143 | 144 | 145 | // NinePatchEditorDialog dlg = new NinePatchEditorDialog(game); 146 | // dlg.show(stage); 147 | 148 | } 149 | 150 | /** 151 | * 152 | */ 153 | private void showNewProjectDialog() { 154 | 155 | final TextField textProject = new TextField("", game.skin); 156 | Dialog dlg = new Dialog("New Project", game.skin) { 157 | 158 | @Override 159 | protected void result(Object object) { 160 | if ((Boolean) object == false) { 161 | return; 162 | } 163 | 164 | String projectName = textProject.getText(); 165 | projectName = projectName.replace(".", "_"); 166 | projectName = projectName.replace("/", "_"); 167 | projectName = projectName.replace("\\", "_"); 168 | projectName = projectName.replace("-", "_"); 169 | if (projectName.isEmpty() == true) 170 | return; 171 | 172 | createProject(projectName); 173 | 174 | } 175 | 176 | }; 177 | 178 | dlg.pad(20); 179 | dlg.getContentTable().add("Project Name:"); 180 | dlg.getContentTable().add(textProject).pad(20); 181 | dlg.button("OK", true); 182 | dlg.button("Cancel", false); 183 | dlg.key(com.badlogic.gdx.Input.Keys.ENTER, true); 184 | dlg.key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 185 | dlg.setWidth(480); 186 | dlg.show(stage); 187 | stage.setKeyboardFocus(textProject); 188 | } 189 | 190 | @Override 191 | public void hide() { 192 | // Do nothing 193 | } 194 | 195 | @Override 196 | public void pause() { 197 | // Do nothing 198 | 199 | } 200 | 201 | @Override 202 | public void resume() { 203 | // Do nothing 204 | 205 | } 206 | 207 | @Override 208 | public void dispose() { 209 | // Do nothing 210 | 211 | } 212 | 213 | /** 214 | * 215 | */ 216 | public void refreshProjects() { 217 | 218 | Array items = new Array(); 219 | 220 | FileHandle[] projects = Gdx.files.local("projects").list(); 221 | for (FileHandle project : projects) { 222 | if (project.child("uiskin.json").exists() == true) { 223 | items.add(project.name()); 224 | } 225 | } 226 | items.sort(); 227 | listProjects.setItems(items); 228 | } 229 | 230 | /** 231 | * 232 | * @param projectName 233 | */ 234 | public void createProject(String projectName) { 235 | 236 | FileHandle projectFolder = Gdx.files.local("projects").child(projectName); 237 | if (projectFolder.exists() == true) { 238 | game.showNotice("Error", "Project name already in use!", stage); 239 | return; 240 | } 241 | 242 | projectFolder.mkdirs(); 243 | projectFolder.child("assets").mkdirs(); 244 | projectFolder.child("backups").mkdirs(); 245 | game.skin.save(projectFolder.child("uiskin.json")); 246 | 247 | // Copy assets 248 | FileHandle assetsFolder = Gdx.files.local("resources/raw"); 249 | assetsFolder.copyTo(projectFolder.child("assets")); 250 | // Rebuild from raw resources 251 | TexturePacker.Settings settings = new TexturePacker.Settings(); 252 | settings.combineSubdirectories = true; 253 | TexturePacker.process(settings, "projects/" + projectName +"/assets/", "projects/" + projectName, "uiskin"); 254 | 255 | game.showNotice("Operation completed", "New project successfully created.", stage); 256 | 257 | refreshProjects(); 258 | } 259 | 260 | 261 | 262 | /** 263 | * 264 | */ 265 | private void showDeleteDialog() { 266 | 267 | Dialog dlgStyle = new Dialog("Delete Project", game.skin) { 268 | 269 | @Override 270 | protected void result(Object object) { 271 | if ((Boolean) object == false) { 272 | return; 273 | } 274 | 275 | // We delete it 276 | FileHandle projectFolder = Gdx.files.local("projects/" + (String) listProjects.getSelected()); 277 | projectFolder.deleteDirectory(); 278 | 279 | refreshProjects(); 280 | } 281 | 282 | }; 283 | 284 | dlgStyle.pad(20); 285 | dlgStyle.getContentTable().add( 286 | "You are sure you want to delete this project?"); 287 | dlgStyle.button("OK", true); 288 | dlgStyle.button("Cancel", false); 289 | dlgStyle.key(com.badlogic.gdx.Input.Keys.ENTER, true); 290 | dlgStyle.key(com.badlogic.gdx.Input.Keys.ESCAPE, false); 291 | dlgStyle.show(stage); 292 | 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /desktop/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "java" 2 | 3 | sourceCompatibility = 1.6 4 | sourceSets.main.java.srcDirs = [ "src/" ] 5 | 6 | project.ext.mainClassName = "org.shadebob.skineditor.desktop.DesktopLauncher" 7 | project.ext.assetsDir = new File("../assets"); 8 | 9 | task run(dependsOn: classes, type: JavaExec) { 10 | main = project.mainClassName 11 | classpath = sourceSets.main.runtimeClasspath 12 | standardInput = System.in 13 | workingDir = project.assetsDir 14 | ignoreExitValue = true 15 | } 16 | 17 | task dist(type: Jar) { 18 | from files(sourceSets.main.output.classesDir) 19 | from files(sourceSets.main.output.resourcesDir) 20 | from {configurations.compile.collect {zipTree(it)}} 21 | from files(project.assetsDir); 22 | 23 | manifest { 24 | attributes 'Main-Class': project.mainClassName 25 | } 26 | } 27 | 28 | dist.dependsOn classes 29 | 30 | 31 | eclipse.project { 32 | name = appName + "-desktop" 33 | } 34 | -------------------------------------------------------------------------------- /desktop/src/org/shadebob/skineditor/desktop/DesktopLauncher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | package org.shadebob.skineditor.desktop; 17 | 18 | import java.io.File; 19 | 20 | import javax.swing.LookAndFeel; 21 | import javax.swing.UIManager; 22 | 23 | import com.badlogic.gdx.Gdx; 24 | import com.badlogic.gdx.backends.lwjgl.LwjglApplication; 25 | import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; 26 | 27 | import org.shadebob.skineditor.SkinEditorGame; 28 | 29 | /** 30 | * Desktop launcher class 31 | * 32 | * @author Yanick Bourbeau 33 | * 34 | */ 35 | public class DesktopLauncher { 36 | 37 | /** 38 | * Entry point 39 | */ 40 | public static void main (String[] arg) { 41 | 42 | // Set look and feel for Swing dialogs 43 | try { 44 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 45 | } catch(Exception e) { 46 | e.printStackTrace(); 47 | } 48 | 49 | LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); 50 | config.width = 1024; 51 | config.height = 768; 52 | config.resizable = true; 53 | config.title = "Skin Editor for libGDX (v0.3)"; 54 | config.backgroundFPS = 1; 55 | config.vSyncEnabled = true; 56 | 57 | new LwjglApplication(new SkinEditorGame(), config); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /dist/skin_editor_v0.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/dist/skin_editor_v0.3.zip -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cobolfoo/gdx-skineditor/951504457edc5c9c4796ce72dd356d61a8e05e74/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Sep 21 13:08:26 CEST 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include "core", "desktop" 2 | --------------------------------------------------------------------------------