clang-format all files

This commit is contained in:
David Capello 2024-12-16 14:52:19 -03:00
parent 35c7f5bc4e
commit 09538f9a1a
1538 changed files with 57316 additions and 63036 deletions

View File

@ -1,22 +1,22 @@
# Contributor Code of Conduct # Contributor Code of Conduct
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include: Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery * The use of sexualized language or imagery
* Personal attacks * Personal attacks
* Trolling or insulting/derogatory comments * Trolling or insulting/derogatory comments
* Public or private harassment * Public or private harassment
* Publishing other's private information, such as physical or electronic addresses, without explicit permission * Publishing other's private information, such as physical or electronic addresses, without explicit permission
* Other unethical or unprofessional conduct. * Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)

224
README.md
View File

@ -1,112 +1,112 @@
# Aseprite # Aseprite
[![build](https://github.com/aseprite/aseprite/actions/workflows/build.yml/badge.svg)](https://github.com/aseprite/aseprite/actions/workflows/build.yml) [![build](https://github.com/aseprite/aseprite/actions/workflows/build.yml/badge.svg)](https://github.com/aseprite/aseprite/actions/workflows/build.yml)
[![Translation Status](https://hosted.weblate.org/widget/aseprite/aseprite/svg-badge.svg)](https://hosted.weblate.org/engage/aseprite/) [![Translation Status](https://hosted.weblate.org/widget/aseprite/aseprite/svg-badge.svg)](https://hosted.weblate.org/engage/aseprite/)
[![Discourse Community](https://img.shields.io/badge/discourse-community-brightgreen.svg?style=flat)](https://community.aseprite.org/) [![Discourse Community](https://img.shields.io/badge/discourse-community-brightgreen.svg?style=flat)](https://community.aseprite.org/)
[![Discord Server](https://discordapp.com/api/guilds/324979738533822464/embed.png)](https://discord.gg/Yb2CeX8) [![Discord Server](https://discordapp.com/api/guilds/324979738533822464/embed.png)](https://discord.gg/Yb2CeX8)
## Introduction ## Introduction
**Aseprite** is a program to create animated sprites. Its main features are: **Aseprite** is a program to create animated sprites. Its main features are:
* Sprites are composed of [layers & frames](https://www.aseprite.org/docs/timeline/) as separated concepts. * Sprites are composed of [layers & frames](https://www.aseprite.org/docs/timeline/) as separated concepts.
* Support for [color profiles](https://www.aseprite.org/docs/color-profile/) and different [color modes](https://www.aseprite.org/docs/color-mode/): RGBA, Indexed (palettes up to 256 colors), Grayscale. * Support for [color profiles](https://www.aseprite.org/docs/color-profile/) and different [color modes](https://www.aseprite.org/docs/color-mode/): RGBA, Indexed (palettes up to 256 colors), Grayscale.
* [Animation facilities](https://www.aseprite.org/docs/animation/), with real-time [preview](https://www.aseprite.org/docs/preview-window/) and [onion skinning](https://www.aseprite.org/docs/onion-skinning/). * [Animation facilities](https://www.aseprite.org/docs/animation/), with real-time [preview](https://www.aseprite.org/docs/preview-window/) and [onion skinning](https://www.aseprite.org/docs/onion-skinning/).
* [Export/import](https://www.aseprite.org/docs/exporting/) animations to/from [sprite sheets](https://www.aseprite.org/docs/sprite-sheet/), GIF files, or sequence of PNG files (and FLC, FLI, JPG, BMP, PCX, TGA). * [Export/import](https://www.aseprite.org/docs/exporting/) animations to/from [sprite sheets](https://www.aseprite.org/docs/sprite-sheet/), GIF files, or sequence of PNG files (and FLC, FLI, JPG, BMP, PCX, TGA).
* [Multiple editors](https://www.aseprite.org/docs/workspace/#drag-and-drop-tabs) support. * [Multiple editors](https://www.aseprite.org/docs/workspace/#drag-and-drop-tabs) support.
* [Layer groups](https://imgur.com/x3OKkGj) for organizing your work, and [reference layers](https://twitter.com/aseprite/status/806889204601016325) for rotoscoping. * [Layer groups](https://imgur.com/x3OKkGj) for organizing your work, and [reference layers](https://twitter.com/aseprite/status/806889204601016325) for rotoscoping.
* Pixel-art specific tools like [Pixel Perfect freehand mode](https://imgur.com/0fdlNau), [Shading ink](https://www.aseprite.org/docs/shading/), [Custom Brushes](https://twitter.com/aseprite/status/1196883990080344067), [Outlines](https://twitter.com/aseprite/status/1126548469865431041), [Wide Pixels](https://imgur.com/1yZKUcs), etc. * Pixel-art specific tools like [Pixel Perfect freehand mode](https://imgur.com/0fdlNau), [Shading ink](https://www.aseprite.org/docs/shading/), [Custom Brushes](https://twitter.com/aseprite/status/1196883990080344067), [Outlines](https://twitter.com/aseprite/status/1126548469865431041), [Wide Pixels](https://imgur.com/1yZKUcs), etc.
* Other special drawing tools like [Pressure sensitivity](https://twitter.com/aseprite/status/1253770784708886533), [Symmetry Tool](https://twitter.com/aseprite/status/659709226747625472), [Stroke and Fill](https://imgur.com/7JZQ81o) selection, [Gradients](https://twitter.com/aseprite/status/1126549217856622597). * Other special drawing tools like [Pressure sensitivity](https://twitter.com/aseprite/status/1253770784708886533), [Symmetry Tool](https://twitter.com/aseprite/status/659709226747625472), [Stroke and Fill](https://imgur.com/7JZQ81o) selection, [Gradients](https://twitter.com/aseprite/status/1126549217856622597).
* [Tiled mode](https://youtu.be/G_JeWBaxQIg) useful to draw patterns and textures. * [Tiled mode](https://youtu.be/G_JeWBaxQIg) useful to draw patterns and textures.
* [Transform multiple frames/layers](https://twitter.com/aseprite/status/1170007034651172866) at the same time. * [Transform multiple frames/layers](https://twitter.com/aseprite/status/1170007034651172866) at the same time.
* [Lua scripting capabilities](https://www.aseprite.org/docs/scripting/). * [Lua scripting capabilities](https://www.aseprite.org/docs/scripting/).
* [CLI - Command Line Interface](https://www.aseprite.org/docs/cli/) to automatize tasks. * [CLI - Command Line Interface](https://www.aseprite.org/docs/cli/) to automatize tasks.
* [Quick Reference / Cheat Sheet](https://www.aseprite.org/quickref/) keyboard shortcuts ([customizable keys](https://imgur.com/rvAUxyF) and [mouse wheel](https://imgur.com/oNqFqVb)). * [Quick Reference / Cheat Sheet](https://www.aseprite.org/quickref/) keyboard shortcuts ([customizable keys](https://imgur.com/rvAUxyF) and [mouse wheel](https://imgur.com/oNqFqVb)).
* [Reopen closed files](https://twitter.com/aseprite/status/1202641475256881153) and [recover data](https://www.aseprite.org/docs/data-recovery/) in case of crash. * [Reopen closed files](https://twitter.com/aseprite/status/1202641475256881153) and [recover data](https://www.aseprite.org/docs/data-recovery/) in case of crash.
* Undo/Redo for every operation and support for [non-linear undo](https://imgur.com/9I42fZK). * Undo/Redo for every operation and support for [non-linear undo](https://imgur.com/9I42fZK).
* [More features & tips](https://twitter.com/aseprite/status/1124442198651678720) * [More features & tips](https://twitter.com/aseprite/status/1124442198651678720)
## Issues ## Issues
There is a list of There is a list of
[Known Issues](https://github.com/aseprite/aseprite/issues) (things [Known Issues](https://github.com/aseprite/aseprite/issues) (things
to be fixed or that aren't yet implemented). to be fixed or that aren't yet implemented).
If you found a bug or have a new idea/feature for the program, If you found a bug or have a new idea/feature for the program,
[you can report them](https://github.com/aseprite/aseprite/issues/new). [you can report them](https://github.com/aseprite/aseprite/issues/new).
## Support ## Support
You can ask for help in: You can ask for help in:
* [Aseprite Community](https://community.aseprite.org/) * [Aseprite Community](https://community.aseprite.org/)
* [Aseprite Discord Server](https://discord.gg/Yb2CeX8) * [Aseprite Discord Server](https://discord.gg/Yb2CeX8)
* Official support: [support@aseprite.org](mailto:support@aseprite.org) * Official support: [support@aseprite.org](mailto:support@aseprite.org)
* Social networks and community-driven places: * Social networks and community-driven places:
[Twitter](https://twitter.com/aseprite/), [Twitter](https://twitter.com/aseprite/),
[Facebook](https://facebook.com/aseprite/), [Facebook](https://facebook.com/aseprite/),
[YouTube](https://www.youtube.com/user/aseprite), [YouTube](https://www.youtube.com/user/aseprite),
[Instagram](https://www.instagram.com/aseprite/). [Instagram](https://www.instagram.com/aseprite/).
## Authors ## Authors
Aseprite is being developed by [Igara Studio](https://igara.com/): Aseprite is being developed by [Igara Studio](https://igara.com/):
* [David Capello](https://davidcapello.com/) * [David Capello](https://davidcapello.com/)
* [Gaspar Capello](https://github.com/Gasparoken) * [Gaspar Capello](https://github.com/Gasparoken)
* [Martín Capello](https://github.com/martincapello) * [Martín Capello](https://github.com/martincapello)
## Credits ## Credits
The default Aseprite theme was introduced in v0.8, created by: The default Aseprite theme was introduced in v0.8, created by:
* [Ilija Melentijevic](https://ilkke.net/) * [Ilija Melentijevic](https://ilkke.net/)
A modified dark version of this theme introduced in v1.3-beta1 was created by: A modified dark version of this theme introduced in v1.3-beta1 was created by:
* [Nicolas Desilets](https://twitter.com/MapleGecko) * [Nicolas Desilets](https://twitter.com/MapleGecko)
* [David Capello](https://twitter.com/davidcapello) * [David Capello](https://twitter.com/davidcapello)
Aseprite includes color palettes created by: Aseprite includes color palettes created by:
* [Richard "DawnBringer" Fhager](http://pixeljoint.com/p/23821.htm), [16 colors](http://pixeljoint.com/forum/forum_posts.asp?TID=12795), [32 colors](http://pixeljoint.com/forum/forum_posts.asp?TID=16247). * [Richard "DawnBringer" Fhager](http://pixeljoint.com/p/23821.htm), [16 colors](http://pixeljoint.com/forum/forum_posts.asp?TID=12795), [32 colors](http://pixeljoint.com/forum/forum_posts.asp?TID=16247).
* [Arne Niklas Jansson](http://androidarts.com/), [16 colors](http://androidarts.com/palette/16pal.htm), [32 colors](http://wayofthepixel.net/index.php?topic=15824.msg144494). * [Arne Niklas Jansson](http://androidarts.com/), [16 colors](http://androidarts.com/palette/16pal.htm), [32 colors](http://wayofthepixel.net/index.php?topic=15824.msg144494).
* [ENDESGA Studios](https://twitter.com/ENDESGA), [EDG16 and EDG32](https://forums.tigsource.com/index.php?topic=46126.msg1279124#msg1279124), and [other palettes](https://twitter.com/ENDESGA/status/865812366931353600). * [ENDESGA Studios](https://twitter.com/ENDESGA), [EDG16 and EDG32](https://forums.tigsource.com/index.php?topic=46126.msg1279124#msg1279124), and [other palettes](https://twitter.com/ENDESGA/status/865812366931353600).
* [Hyohnoo Games](https://twitter.com/Hyohnoo), [mail24](https://twitter.com/Hyohnoo/status/797472587974639616) palette. * [Hyohnoo Games](https://twitter.com/Hyohnoo), [mail24](https://twitter.com/Hyohnoo/status/797472587974639616) palette.
* [Davit Masia](https://twitter.com/DavitMasia), [matriax8c](https://twitter.com/DavitMasia/status/834862452164612096) palette. * [Davit Masia](https://twitter.com/DavitMasia), [matriax8c](https://twitter.com/DavitMasia/status/834862452164612096) palette.
* [Javier Guerrero](https://twitter.com/Xavier_Gd), [nyx8](https://twitter.com/Xavier_Gd/status/868519467864686594) palette. * [Javier Guerrero](https://twitter.com/Xavier_Gd), [nyx8](https://twitter.com/Xavier_Gd/status/868519467864686594) palette.
* [Adigun A. Polack](https://twitter.com/adigunpolack), [AAP-64](http://pixeljoint.com/pixelart/119466.htm), [AAP-Splendor128](http://pixeljoint.com/pixelart/120714.htm), [SimpleJPC-16](http://pixeljoint.com/pixelart/119844.htm), and [AAP-Micro12](http://pixeljoint.com/pixelart/121151.htm) palette. * [Adigun A. Polack](https://twitter.com/adigunpolack), [AAP-64](http://pixeljoint.com/pixelart/119466.htm), [AAP-Splendor128](http://pixeljoint.com/pixelart/120714.htm), [SimpleJPC-16](http://pixeljoint.com/pixelart/119844.htm), and [AAP-Micro12](http://pixeljoint.com/pixelart/121151.htm) palette.
* [PineTreePizza](https://twitter.com/PineTreePizza), [Rosy-42](https://twitter.com/PineTreePizza/status/1006536191955623938) palette. * [PineTreePizza](https://twitter.com/PineTreePizza), [Rosy-42](https://twitter.com/PineTreePizza/status/1006536191955623938) palette.
It tries to replicate some pixel-art algorithms: It tries to replicate some pixel-art algorithms:
* [RotSprite](http://forums.sonicretro.org/index.php?showtopic=8848&st=15&p=159754&#entry159754) by Xenowhirl. * [RotSprite](http://forums.sonicretro.org/index.php?showtopic=8848&st=15&p=159754&#entry159754) by Xenowhirl.
* [Pixel perfect drawing algorithm](https://deepnight.net/blog/tools/pixel-perfect-drawing/) by [Sébastien Bénard](https://twitter.com/deepnightfr) and [Carduus](https://twitter.com/CarduusHimself/status/420554200737935361). * [Pixel perfect drawing algorithm](https://deepnight.net/blog/tools/pixel-perfect-drawing/) by [Sébastien Bénard](https://twitter.com/deepnightfr) and [Carduus](https://twitter.com/CarduusHimself/status/420554200737935361).
Thanks to [third-party open source projects](docs/LICENSES.md), to Thanks to [third-party open source projects](docs/LICENSES.md), to
[contributors](https://www.aseprite.org/contributors/), and all the [contributors](https://www.aseprite.org/contributors/), and all the
people who have contributed ideas, patches, bugs report, feature people who have contributed ideas, patches, bugs report, feature
requests, donations, and help us to develop Aseprite. requests, donations, and help us to develop Aseprite.
## License ## License
This program is distributed under three different licenses: This program is distributed under three different licenses:
1. Source code and official releases/binaries are distributed under 1. Source code and official releases/binaries are distributed under
our [End-User License Agreement for Aseprite (EULA)](EULA.txt). Please check our [End-User License Agreement for Aseprite (EULA)](EULA.txt). Please check
that there are [modules/libraries in the source code](src/README.md) that that there are [modules/libraries in the source code](src/README.md) that
are distributed under the MIT license are distributed under the MIT license
(e.g. [laf](https://github.com/aseprite/laf), (e.g. [laf](https://github.com/aseprite/laf),
[clip](https://github.com/aseprite/clip), [clip](https://github.com/aseprite/clip),
[undo](https://github.com/aseprite/undo), [undo](https://github.com/aseprite/undo),
[observable](https://github.com/aseprite/observable), [observable](https://github.com/aseprite/observable),
[ui](src/ui), etc.). [ui](src/ui), etc.).
2. You can request a special 2. You can request a special
[educational license](https://www.aseprite.org/faq/#is-there-an-educational-license) [educational license](https://www.aseprite.org/faq/#is-there-an-educational-license)
in case you are a teacher in an educational institution and want to in case you are a teacher in an educational institution and want to
use Aseprite in your classroom (in-situ). use Aseprite in your classroom (in-situ).
3. Steam releases are distributed under the terms of the 3. Steam releases are distributed under the terms of the
[Steam Subscriber Agreement](http://store.steampowered.com/subscriber_agreement/). [Steam Subscriber Agreement](http://store.steampowered.com/subscriber_agreement/).
You can get more information about Aseprite license in the You can get more information about Aseprite license in the
[FAQ](https://www.aseprite.org/faq/#licensing-&-commercial). [FAQ](https://www.aseprite.org/faq/#licensing-&-commercial).

View File

@ -1,70 +1,70 @@
GIMP Palette GIMP Palette
#Palette Name: AAP-64 #Palette Name: AAP-64
#Description: Created by Adigun Polack #Description: Created by Adigun Polack
#Colors: 64 #Colors: 64
#https://twitter.com/AdigunPolack #https://twitter.com/AdigunPolack
#http://pixeljoint.com/pixelart/119466.htm #http://pixeljoint.com/pixelart/119466.htm
6 6 8 #060608 6 6 8 #060608
20 16 19 #141013 20 16 19 #141013
59 23 37 #3b1725 59 23 37 #3b1725
115 23 45 #73172d 115 23 45 #73172d
180 32 42 #b4202a 180 32 42 #b4202a
223 62 35 #df3e23 223 62 35 #df3e23
250 106 10 #fa6a0a 250 106 10 #fa6a0a
249 163 27 #f9a31b 249 163 27 #f9a31b
255 213 65 #ffd541 255 213 65 #ffd541
255 252 64 #fffc40 255 252 64 #fffc40
214 242 100 #d6f264 214 242 100 #d6f264
156 219 67 #9cdb43 156 219 67 #9cdb43
89 193 53 #59c135 89 193 53 #59c135
20 160 46 #14a02e 20 160 46 #14a02e
26 122 62 #1a7a3e 26 122 62 #1a7a3e
36 82 59 #24523b 36 82 59 #24523b
18 32 32 #122020 18 32 32 #122020
20 52 100 #143464 20 52 100 #143464
40 92 196 #285cc4 40 92 196 #285cc4
36 159 222 #249fde 36 159 222 #249fde
32 214 199 #20d6c7 32 214 199 #20d6c7
166 252 219 #a6fcdb 166 252 219 #a6fcdb
255 255 255 #ffffff 255 255 255 #ffffff
254 243 192 #fef3c0 254 243 192 #fef3c0
250 214 184 #fad6b8 250 214 184 #fad6b8
245 160 151 #f5a097 245 160 151 #f5a097
232 106 115 #e86a73 232 106 115 #e86a73
188 74 155 #bc4a9b 188 74 155 #bc4a9b
121 58 128 #793a80 121 58 128 #793a80
64 51 83 #403353 64 51 83 #403353
36 34 52 #242234 36 34 52 #242234
34 28 26 #221c1a 34 28 26 #221c1a
50 43 40 #322b28 50 43 40 #322b28
113 65 59 #71413b 113 65 59 #71413b
187 117 71 #bb7547 187 117 71 #bb7547
219 164 99 #dba463 219 164 99 #dba463
244 210 156 #f4d29c 244 210 156 #f4d29c
218 224 234 #dae0ea 218 224 234 #dae0ea
179 185 209 #b3b9d1 179 185 209 #b3b9d1
139 147 175 #8b93af 139 147 175 #8b93af
109 117 141 #6d758d 109 117 141 #6d758d
74 84 98 #4a5462 74 84 98 #4a5462
51 57 65 #333941 51 57 65 #333941
66 36 51 #422433 66 36 51 #422433
91 49 56 #5b3138 91 49 56 #5b3138
142 82 82 #8e5252 142 82 82 #8e5252
186 117 106 #ba756a 186 117 106 #ba756a
233 181 163 #e9b5a3 233 181 163 #e9b5a3
227 230 255 #e3e6ff 227 230 255 #e3e6ff
185 191 251 #b9bffb 185 191 251 #b9bffb
132 155 228 #849be4 132 155 228 #849be4
88 141 190 #588dbe 88 141 190 #588dbe
71 125 133 #477d85 71 125 133 #477d85
35 103 78 #23674e 35 103 78 #23674e
50 132 100 #328464 50 132 100 #328464
93 175 141 #5daf8d 93 175 141 #5daf8d
146 220 186 #92dcba 146 220 186 #92dcba
205 247 226 #cdf7e2 205 247 226 #cdf7e2
228 210 170 #e4d2aa 228 210 170 #e4d2aa
199 176 139 #c7b08b 199 176 139 #c7b08b
160 134 98 #a08662 160 134 98 #a08662
121 103 85 #796755 121 103 85 #796755
90 78 68 #5a4e44 90 78 68 #5a4e44
66 57 52 #423934 66 57 52 #423934

View File

@ -1,23 +1,23 @@
GIMP Palette GIMP Palette
# ------------------------------------------------------ # ------------------------------------------------------
# T h e A A P - M i c r o 1 2 P a l e t t e # T h e A A P - M i c r o 1 2 P a l e t t e
# ------------------------------------------------------ # ------------------------------------------------------
# Created by Adigun Azikiwe Polack. # Created by Adigun Azikiwe Polack.
# (c)2018 Adigun Azikiwe Polack. All Rights Reserved. # (c)2018 Adigun Azikiwe Polack. All Rights Reserved.
# ------------------------------------------------------ # ------------------------------------------------------
# #
# https://twitter.com/AdigunPolack # https://twitter.com/AdigunPolack
# http://pixeljoint.com/pixelart/121151.htm # http://pixeljoint.com/pixelart/121151.htm
# #
4 3 3 Rich Black (FOGRA39) 4 3 3 Rich Black (FOGRA39)
28 22 24 Eerie Black 28 22 24 Eerie Black
71 65 107 Independence 71 65 107 Independence
108 140 80 Palm Leaf 108 140 80 Palm Leaf
227 210 69 Sandstorm 227 210 69 Sandstorm
216 128 56 Bronze 216 128 56 Bronze
161 61 59 Smoky Topaz 161 61 59 Smoky Topaz
78 40 46 Acajou 78 40 46 Acajou
154 64 126 Magenta Haze 154 64 126 Magenta Haze
240 212 114 Hansa Yellow 240 212 114 Hansa Yellow
249 245 239 Seashell 249 245 239 Seashell
138 143 196 Ube 138 143 196 Ube

View File

@ -1,139 +1,139 @@
GIMP Palette GIMP Palette
# -------------------------------------------------------- # --------------------------------------------------------
# T h e A A P - S p l e n d o r 1 2 8 P a l e t t e # T h e A A P - S p l e n d o r 1 2 8 P a l e t t e
# -------------------------------------------------------- # --------------------------------------------------------
# Created by Adigun Azikiwe Polack. # Created by Adigun Azikiwe Polack.
# (c)2018 Adigun Azikiwe Polack. All Rights Reserved. # (c)2018 Adigun Azikiwe Polack. All Rights Reserved.
# -------------------------------------------------------- # --------------------------------------------------------
# #
# https://twitter.com/AdigunPolack # https://twitter.com/AdigunPolack
# http://pixeljoint.com/pixelart/120714.htm # http://pixeljoint.com/pixelart/120714.htm
# #
5 4 3 Rich Black (FOGRA39) 5 4 3 Rich Black (FOGRA39)
14 12 12 Smoky Black 14 12 12 Smoky Black
45 27 30 Grape Black 45 27 30 Grape Black
97 39 33 Caput Mortuum 97 39 33 Caput Mortuum
185 69 29 Rust 185 69 29 Rust
241 100 31 Vivid Vermilion 241 100 31 Vivid Vermilion
252 165 112 Light Salmon 252 165 112 Light Salmon
255 224 183 Peach Puff 255 224 183 Peach Puff
255 255 255 White 255 255 255 White
255 240 137 Yellow (Crayola) 255 240 137 Yellow (Crayola)
248 197 58 Saffron 248 197 58 Saffron
232 138 54 Cadmium Orange 232 138 54 Cadmium Orange
176 91 44 Ruddy Brown 176 91 44 Ruddy Brown
103 57 49 Van Dyke Brown 103 57 49 Van Dyke Brown
39 31 27 Dark Bistre 39 31 27 Dark Bistre
76 61 46 Muddy Taupe 76 61 46 Muddy Taupe
133 95 57 Coyote Brown 133 95 57 Coyote Brown
211 151 65 Peru 211 151 65 Peru
248 246 68 Maximum Yellow 248 246 68 Maximum Yellow
213 220 29 Yellowish Pear 213 220 29 Yellowish Pear
173 184 52 Android Green 173 184 52 Android Green
127 142 68 Withering Palm Leaf 127 142 68 Withering Palm Leaf
88 99 53 Deep Yellowish Spring Bud 88 99 53 Deep Yellowish Spring Bud
51 60 36 Kombu Green 51 60 36 Kombu Green
24 28 25 Eerie Dark Green 24 28 25 Eerie Dark Green
41 63 33 Spring Leather Night Jacket 41 63 33 Spring Leather Night Jacket
71 114 56 Spring Fern 71 114 56 Spring Fern
97 165 63 Spring Palm Leaf 97 165 63 Spring Palm Leaf
143 208 50 Yellow-Green 143 208 50 Yellow-Green
196 241 41 Pear 196 241 41 Pear
208 255 234 Aero Blue 208 255 234 Aero Blue
151 237 202 Pale Robin Egg Blue 151 237 202 Pale Robin Egg Blue
89 207 147 Ocean Green 89 207 147 Ocean Green
66 164 89 Middle Green 66 164 89 Middle Green
61 111 67 Fern Green 61 111 67 Fern Green
39 65 45 Withered Leather Jacket 39 65 45 Withered Leather Jacket
20 18 29 Eerie Dark Blue 20 18 29 Eerie Dark Blue
27 36 71 Yankees Blue 27 36 71 Yankees Blue
43 78 149 B'dazzled Blue 43 78 149 B'dazzled Blue
39 137 205 Cyan Cornflower Blue 39 137 205 Cyan Cornflower Blue
66 191 232 Picton Blue 66 191 232 Picton Blue
115 239 232 Medium Sky Blue 115 239 232 Medium Sky Blue
241 242 255 Alice Blue 241 242 255 Alice Blue
201 212 253 Periwinkle 201 212 253 Periwinkle
138 161 246 Jordy Blue 138 161 246 Jordy Blue
69 114 227 Royal Blue 69 114 227 Royal Blue
73 65 130 Dark Slate Blue 73 65 130 Dark Slate Blue
120 100 198 Toolbox 120 100 198 Toolbox
156 139 219 Medium Purple 156 139 219 Medium Purple
206 170 237 Bright Ube 206 170 237 Bright Ube
250 214 255 Pink Lace 250 214 255 Pink Lace
238 181 156 Pale Pink 238 181 156 Pale Pink
212 128 187 Middle Purple 212 128 187 Middle Purple
144 82 188 Deep Lilac 144 82 188 Deep Lilac
23 21 22 Licorice 23 21 22 Licorice
55 51 52 Jet Taupe 55 51 52 Jet Taupe
105 91 89 Wenge 105 91 89 Wenge
178 139 120 Light Taupe 178 139 120 Light Taupe
226 178 126 Middle Yellow Red 226 178 126 Middle Yellow Red
246 216 150 Tuscan 246 216 150 Tuscan
252 247 190 Blond 252 247 190 Blond
236 235 231 Alabaster 236 235 231 Alabaster
203 198 193 Pale Silver 203 198 193 Pale Silver
166 158 154 Quick Silver 166 158 154 Quick Silver
128 123 122 Trolley Grey 128 123 122 Trolley Grey
89 87 87 Davy's Grey 89 87 87 Davy's Grey
50 50 50 Jet Grey 50 50 50 Jet Grey
79 52 47 Acajou 79 52 47 Acajou
140 91 62 Coconut 140 91 62 Coconut
198 133 86 Deer 198 133 86 Deer
214 168 81 Indian Yellow 214 168 81 Indian Yellow
180 117 56 Copper 180 117 56 Copper
114 75 44 Tuscan Brown 114 75 44 Tuscan Brown
69 42 27 Brown Bistre 69 42 27 Brown Bistre
97 104 58 Deep Tan Spring Bud 97 104 58 Deep Tan Spring Bud
147 148 70 Dark Tan 147 148 70 Dark Tan
198 184 88 Vegas Gold 198 184 88 Vegas Gold
239 221 145 Light Khaki 239 221 145 Light Khaki
181 231 203 Magic Mint 181 231 203 Magic Mint
134 198 154 Eton Blue 134 198 154 Eton Blue
93 155 121 Shiny Shamrock 93 155 121 Shiny Shamrock
72 104 89 Feldgrau 72 104 89 Feldgrau
44 59 57 Gunmetal Teal 44 59 57 Gunmetal Teal
23 24 25 Eerie Black 23 24 25 Eerie Black
44 52 56 Gunmetal Turquoise 44 52 56 Gunmetal Turquoise
70 84 86 Davy's Teal 70 84 86 Davy's Teal
100 135 140 Steel Teal 100 135 140 Steel Teal
138 196 195 Pearl Aqua 138 196 195 Pearl Aqua
175 233 223 Powder Blue 175 233 223 Powder Blue
220 234 238 Azureish White 220 234 238 Azureish White
184 204 216 Light Steel Blue 184 204 216 Light Steel Blue
136 163 188 Pewter Blue 136 163 188 Pewter Blue
94 113 142 UCLA Blue 94 113 142 UCLA Blue
72 82 98 Independence Blue 72 82 98 Independence Blue
40 44 60 Gunmetal Blue 40 44 60 Gunmetal Blue
70 71 98 Independence Blue-Gray 70 71 98 Independence Blue-Gray
105 102 130 Dark Blue-Gray 105 102 130 Dark Blue-Gray
154 151 185 Manatee 154 151 185 Manatee
197 199 221 Lavender Gray 197 199 221 Lavender Gray
230 231 240 Glitter 230 231 240 Glitter
238 230 234 Isabelline 238 230 234 Isabelline
227 205 223 Queen Pink 227 205 223 Queen Pink
191 165 201 Lilac 191 165 201 Lilac
135 115 143 Pomp And Power 135 115 143 Pomp And Power
86 79 91 Davy's Lavender 86 79 91 Davy's Lavender
50 47 53 Jet Lavender 50 47 53 Jet Lavender
54 40 43 Burgundy Bistre 54 40 43 Burgundy Bistre
101 73 86 Deep Fuchsia Wenge 101 73 86 Deep Fuchsia Wenge
150 104 136 Antique Fuchsia 150 104 136 Antique Fuchsia
192 144 169 Opera Mauve 192 144 169 Opera Mauve
212 184 184 Pale Magenta 212 184 184 Pale Magenta
234 224 221 Platinum Pink 234 224 221 Platinum Pink
241 235 219 Eggshell 241 235 219 Eggshell
221 206 191 Dust Storm 221 206 191 Dust Storm
189 164 153 Tuscany 189 164 153 Tuscany
136 110 106 Shadow 136 110 106 Shadow
89 77 77 Dark Liver 89 77 77 Dark Liver
51 39 42 Dark Mahogany-Violet 51 39 42 Dark Mahogany-Violet
178 148 118 Light Tanned Taupe 178 148 118 Light Tanned Taupe
225 191 137 Pale Gold 225 191 137 Pale Gold
248 227 152 Flavescent 248 227 152 Flavescent
255 233 227 Misty Rose 255 233 227 Misty Rose
253 201 201 Bubble Gum 253 201 201 Bubble Gum
246 162 168 Mauvelous 246 162 168 Mauvelous
226 114 133 Tango Pink 226 114 133 Tango Pink
178 82 102 China Rose 178 82 102 China Rose
100 54 75 Wine Dregs 100 54 75 Wine Dregs
42 30 35 Raisin Black 42 30 35 Raisin Black

View File

@ -1,27 +1,27 @@
GIMP Palette GIMP Palette
# ------------------------------------------------------ # ------------------------------------------------------
# S i m p l e J P C - 1 6 P a l e t t e # S i m p l e J P C - 1 6 P a l e t t e
# ------------------------------------------------------ # ------------------------------------------------------
# Created by Adigun Azikiwe Polack. # Created by Adigun Azikiwe Polack.
# (c)2018 Adigun Azikiwe Polack. All Rights Reserved. # (c)2018 Adigun Azikiwe Polack. All Rights Reserved.
# ------------------------------------------------------ # ------------------------------------------------------
# #
# https://twitter.com/AdigunPolack # https://twitter.com/AdigunPolack
# http://pixeljoint.com/pixelart/119844.htm # http://pixeljoint.com/pixelart/119844.htm
# #
5 4 3 Rich Black (FOGRA39) 5 4 3 Rich Black (FOGRA39)
34 31 49 Raisin Black 34 31 49 Raisin Black
84 53 22 Cafe Noir 84 53 22 Cafe Noir
155 110 45 Metallic Sunburst 155 110 45 Metallic Sunburst
225 176 71 Sunray 225 176 71 Sunray
245 238 155 Flavescent 245 238 155 Flavescent
254 254 254 White 254 254 254 White
139 225 224 Pale Robin Egg Blue 139 225 224 Pale Robin Egg Blue
124 194 100 Mantis 124 194 100 Mantis
103 143 203 Livid 103 143 203 Livid
49 111 35 Mughal Green 49 111 35 Mughal Green
64 74 104 Independence 64 74 104 Independence
161 77 63 Reddish Coconut 161 77 63 Reddish Coconut
165 104 212 Rich Lavender 165 104 212 Rich Lavender
154 147 183 Glossy Grape 154 147 183 Glossy Grape
234 145 130 Dark Salmon 234 145 130 Dark Salmon

View File

@ -1,58 +1,58 @@
GIMP Palette GIMP Palette
# #
0 0 0 Untitled 0 0 0 Untitled
0 0 0 Untitled 0 0 0 Untitled
121 121 121 Untitled 121 121 121 Untitled
162 162 162 Untitled 162 162 162 Untitled
48 81 130 Untitled 48 81 130 Untitled
65 146 195 Untitled 65 146 195 Untitled
97 211 227 Untitled 97 211 227 Untitled
162 255 243 Untitled 162 255 243 Untitled
48 97 65 Untitled 48 97 65 Untitled
73 162 105 Untitled 73 162 105 Untitled
113 227 146 Untitled 113 227 146 Untitled
162 255 203 Untitled 162 255 203 Untitled
56 109 0 Untitled 56 109 0 Untitled
73 170 16 Untitled 73 170 16 Untitled
113 243 65 Untitled 113 243 65 Untitled
162 243 162 Untitled 162 243 162 Untitled
56 105 0 Untitled 56 105 0 Untitled
81 162 0 Untitled 81 162 0 Untitled
154 235 0 Untitled 154 235 0 Untitled
203 243 130 Untitled 203 243 130 Untitled
73 89 0 Untitled 73 89 0 Untitled
138 138 0 Untitled 138 138 0 Untitled
235 211 32 Untitled 235 211 32 Untitled
255 243 146 Untitled 255 243 146 Untitled
121 65 0 Untitled 121 65 0 Untitled
195 113 0 Untitled 195 113 0 Untitled
255 162 0 Untitled 255 162 0 Untitled
255 219 162 Untitled 255 219 162 Untitled
162 48 0 Untitled 162 48 0 Untitled
227 81 0 Untitled 227 81 0 Untitled
255 121 48 Untitled 255 121 48 Untitled
255 203 186 Untitled 255 203 186 Untitled
178 16 48 Untitled 178 16 48 Untitled
219 65 97 Untitled 219 65 97 Untitled
255 97 178 Untitled 255 97 178 Untitled
255 186 235 Untitled 255 186 235 Untitled
154 32 121 Untitled 154 32 121 Untitled
219 65 195 Untitled 219 65 195 Untitled
243 97 255 Untitled 243 97 255 Untitled
227 178 255 Untitled 227 178 255 Untitled
97 16 162 Untitled 97 16 162 Untitled
146 65 243 Untitled 146 65 243 Untitled
162 113 255 Untitled 162 113 255 Untitled
195 178 255 Untitled 195 178 255 Untitled
40 0 186 Untitled 40 0 186 Untitled
65 65 255 Untitled 65 65 255 Untitled
81 130 255 Untitled 81 130 255 Untitled
162 186 255 Untitled 162 186 255 Untitled
32 0 178 Untitled 32 0 178 Untitled
65 97 251 Untitled 65 97 251 Untitled
97 162 255 Untitled 97 162 255 Untitled
146 211 255 Untitled 146 211 255 Untitled
121 121 121 Untitled 121 121 121 Untitled
178 178 178 Untitled 178 178 178 Untitled
235 235 235 Untitled 235 235 235 Untitled
255 255 255 Untitled 255 255 255 Untitled

View File

@ -12,4 +12,4 @@ Name: Monokai
230 219 116 Yellow 230 219 116 Yellow
102 217 239 Blue 102 217 239 Blue
166 226 46 Green 166 226 46 Green
174 129 255 Purple 174 129 255 Purple

View File

@ -1,222 +1,222 @@
GIMP Palette GIMP Palette
Name: Web Safe Colors Name: Web Safe Colors
Columns: 6 Columns: 6
# #
# ColorZilla Web Safe Colors palette # ColorZilla Web Safe Colors palette
# #
255 255 255 Untitled 255 255 255 Untitled
255 255 204 Untitled 255 255 204 Untitled
255 255 153 Untitled 255 255 153 Untitled
255 255 102 Untitled 255 255 102 Untitled
255 255 51 Untitled 255 255 51 Untitled
255 255 0 Untitled 255 255 0 Untitled
255 204 255 Untitled 255 204 255 Untitled
255 204 204 Untitled 255 204 204 Untitled
255 204 153 Untitled 255 204 153 Untitled
255 204 102 Untitled 255 204 102 Untitled
255 204 51 Untitled 255 204 51 Untitled
255 204 0 Untitled 255 204 0 Untitled
255 153 255 Untitled 255 153 255 Untitled
255 153 204 Untitled 255 153 204 Untitled
255 153 153 Untitled 255 153 153 Untitled
255 153 102 Untitled 255 153 102 Untitled
255 153 51 Untitled 255 153 51 Untitled
255 153 0 Untitled 255 153 0 Untitled
255 102 255 Untitled 255 102 255 Untitled
255 102 204 Untitled 255 102 204 Untitled
255 102 153 Untitled 255 102 153 Untitled
255 102 102 Untitled 255 102 102 Untitled
255 102 51 Untitled 255 102 51 Untitled
255 102 0 Untitled 255 102 0 Untitled
255 51 255 Untitled 255 51 255 Untitled
255 51 204 Untitled 255 51 204 Untitled
255 51 153 Untitled 255 51 153 Untitled
255 51 102 Untitled 255 51 102 Untitled
255 51 51 Untitled 255 51 51 Untitled
255 51 0 Untitled 255 51 0 Untitled
255 0 255 Untitled 255 0 255 Untitled
255 0 204 Untitled 255 0 204 Untitled
255 0 153 Untitled 255 0 153 Untitled
255 0 102 Untitled 255 0 102 Untitled
255 0 51 Untitled 255 0 51 Untitled
255 0 0 Untitled 255 0 0 Untitled
204 255 255 Untitled 204 255 255 Untitled
204 255 204 Untitled 204 255 204 Untitled
204 255 153 Untitled 204 255 153 Untitled
204 255 102 Untitled 204 255 102 Untitled
204 255 51 Untitled 204 255 51 Untitled
204 255 0 Untitled 204 255 0 Untitled
204 204 255 Untitled 204 204 255 Untitled
204 204 204 Untitled 204 204 204 Untitled
204 204 153 Untitled 204 204 153 Untitled
204 204 102 Untitled 204 204 102 Untitled
204 204 51 Untitled 204 204 51 Untitled
204 204 0 Untitled 204 204 0 Untitled
204 153 255 Untitled 204 153 255 Untitled
204 153 204 Untitled 204 153 204 Untitled
204 153 153 Untitled 204 153 153 Untitled
204 153 102 Untitled 204 153 102 Untitled
204 153 51 Untitled 204 153 51 Untitled
204 153 0 Untitled 204 153 0 Untitled
204 102 255 Untitled 204 102 255 Untitled
204 102 204 Untitled 204 102 204 Untitled
204 102 153 Untitled 204 102 153 Untitled
204 102 102 Untitled 204 102 102 Untitled
204 102 51 Untitled 204 102 51 Untitled
204 102 0 Untitled 204 102 0 Untitled
204 51 255 Untitled 204 51 255 Untitled
204 51 204 Untitled 204 51 204 Untitled
204 51 153 Untitled 204 51 153 Untitled
204 51 102 Untitled 204 51 102 Untitled
204 51 51 Untitled 204 51 51 Untitled
204 51 0 Untitled 204 51 0 Untitled
204 0 255 Untitled 204 0 255 Untitled
204 0 204 Untitled 204 0 204 Untitled
204 0 153 Untitled 204 0 153 Untitled
204 0 102 Untitled 204 0 102 Untitled
204 0 51 Untitled 204 0 51 Untitled
204 0 0 Untitled 204 0 0 Untitled
153 255 255 Untitled 153 255 255 Untitled
153 255 204 Untitled 153 255 204 Untitled
153 255 153 Untitled 153 255 153 Untitled
153 255 102 Untitled 153 255 102 Untitled
153 255 51 Untitled 153 255 51 Untitled
153 255 0 Untitled 153 255 0 Untitled
153 204 255 Untitled 153 204 255 Untitled
153 204 204 Untitled 153 204 204 Untitled
153 204 153 Untitled 153 204 153 Untitled
153 204 102 Untitled 153 204 102 Untitled
153 204 51 Untitled 153 204 51 Untitled
153 204 0 Untitled 153 204 0 Untitled
153 153 255 Untitled 153 153 255 Untitled
153 153 204 Untitled 153 153 204 Untitled
153 153 153 Untitled 153 153 153 Untitled
153 153 102 Untitled 153 153 102 Untitled
153 153 51 Untitled 153 153 51 Untitled
153 153 0 Untitled 153 153 0 Untitled
153 102 255 Untitled 153 102 255 Untitled
153 102 204 Untitled 153 102 204 Untitled
153 102 153 Untitled 153 102 153 Untitled
153 102 102 Untitled 153 102 102 Untitled
153 102 51 Untitled 153 102 51 Untitled
153 102 0 Untitled 153 102 0 Untitled
153 51 255 Untitled 153 51 255 Untitled
153 51 204 Untitled 153 51 204 Untitled
153 51 153 Untitled 153 51 153 Untitled
153 51 102 Untitled 153 51 102 Untitled
153 51 51 Untitled 153 51 51 Untitled
153 51 0 Untitled 153 51 0 Untitled
153 0 255 Untitled 153 0 255 Untitled
153 0 204 Untitled 153 0 204 Untitled
153 0 153 Untitled 153 0 153 Untitled
153 0 102 Untitled 153 0 102 Untitled
153 0 51 Untitled 153 0 51 Untitled
153 0 0 Untitled 153 0 0 Untitled
102 255 255 Untitled 102 255 255 Untitled
102 255 204 Untitled 102 255 204 Untitled
102 255 153 Untitled 102 255 153 Untitled
102 255 102 Untitled 102 255 102 Untitled
102 255 51 Untitled 102 255 51 Untitled
102 255 0 Untitled 102 255 0 Untitled
102 204 255 Untitled 102 204 255 Untitled
102 204 204 Untitled 102 204 204 Untitled
102 204 153 Untitled 102 204 153 Untitled
102 204 102 Untitled 102 204 102 Untitled
102 204 51 Untitled 102 204 51 Untitled
102 204 0 Untitled 102 204 0 Untitled
102 153 255 Untitled 102 153 255 Untitled
102 153 204 Untitled 102 153 204 Untitled
102 153 153 Untitled 102 153 153 Untitled
102 153 102 Untitled 102 153 102 Untitled
102 153 51 Untitled 102 153 51 Untitled
102 153 0 Untitled 102 153 0 Untitled
102 102 255 Untitled 102 102 255 Untitled
102 102 204 Untitled 102 102 204 Untitled
102 102 153 Untitled 102 102 153 Untitled
102 102 102 Untitled 102 102 102 Untitled
102 102 51 Untitled 102 102 51 Untitled
102 102 0 Untitled 102 102 0 Untitled
102 51 255 Untitled 102 51 255 Untitled
102 51 204 Untitled 102 51 204 Untitled
102 51 153 Untitled 102 51 153 Untitled
102 51 102 Untitled 102 51 102 Untitled
102 51 51 Untitled 102 51 51 Untitled
102 51 0 Untitled 102 51 0 Untitled
102 0 255 Untitled 102 0 255 Untitled
102 0 204 Untitled 102 0 204 Untitled
102 0 153 Untitled 102 0 153 Untitled
102 0 102 Untitled 102 0 102 Untitled
102 0 51 Untitled 102 0 51 Untitled
102 0 0 Untitled 102 0 0 Untitled
51 255 255 Untitled 51 255 255 Untitled
51 255 204 Untitled 51 255 204 Untitled
51 255 153 Untitled 51 255 153 Untitled
51 255 102 Untitled 51 255 102 Untitled
51 255 51 Untitled 51 255 51 Untitled
51 255 0 Untitled 51 255 0 Untitled
51 204 255 Untitled 51 204 255 Untitled
51 204 204 Untitled 51 204 204 Untitled
51 204 153 Untitled 51 204 153 Untitled
51 204 102 Untitled 51 204 102 Untitled
51 204 51 Untitled 51 204 51 Untitled
51 204 0 Untitled 51 204 0 Untitled
51 153 255 Untitled 51 153 255 Untitled
51 153 204 Untitled 51 153 204 Untitled
51 153 153 Untitled 51 153 153 Untitled
51 153 102 Untitled 51 153 102 Untitled
51 153 51 Untitled 51 153 51 Untitled
51 153 0 Untitled 51 153 0 Untitled
51 102 255 Untitled 51 102 255 Untitled
51 102 204 Untitled 51 102 204 Untitled
51 102 153 Untitled 51 102 153 Untitled
51 102 102 Untitled 51 102 102 Untitled
51 102 51 Untitled 51 102 51 Untitled
51 102 0 Untitled 51 102 0 Untitled
51 51 255 Untitled 51 51 255 Untitled
51 51 204 Untitled 51 51 204 Untitled
51 51 153 Untitled 51 51 153 Untitled
51 51 102 Untitled 51 51 102 Untitled
51 51 51 Untitled 51 51 51 Untitled
51 51 0 Untitled 51 51 0 Untitled
51 0 255 Untitled 51 0 255 Untitled
51 0 204 Untitled 51 0 204 Untitled
51 0 153 Untitled 51 0 153 Untitled
51 0 102 Untitled 51 0 102 Untitled
51 0 51 Untitled 51 0 51 Untitled
51 0 0 Untitled 51 0 0 Untitled
0 255 255 Untitled 0 255 255 Untitled
0 255 204 Untitled 0 255 204 Untitled
0 255 153 Untitled 0 255 153 Untitled
0 255 102 Untitled 0 255 102 Untitled
0 255 51 Untitled 0 255 51 Untitled
0 255 0 Untitled 0 255 0 Untitled
0 204 255 Untitled 0 204 255 Untitled
0 204 204 Untitled 0 204 204 Untitled
0 204 153 Untitled 0 204 153 Untitled
0 204 102 Untitled 0 204 102 Untitled
0 204 51 Untitled 0 204 51 Untitled
0 204 0 Untitled 0 204 0 Untitled
0 153 255 Untitled 0 153 255 Untitled
0 153 204 Untitled 0 153 204 Untitled
0 153 153 Untitled 0 153 153 Untitled
0 153 102 Untitled 0 153 102 Untitled
0 153 51 Untitled 0 153 51 Untitled
0 153 0 Untitled 0 153 0 Untitled
0 102 255 Untitled 0 102 255 Untitled
0 102 204 Untitled 0 102 204 Untitled
0 102 153 Untitled 0 102 153 Untitled
0 102 102 Untitled 0 102 102 Untitled
0 102 51 Untitled 0 102 51 Untitled
0 102 0 Untitled 0 102 0 Untitled
0 51 255 Untitled 0 51 255 Untitled
0 51 204 Untitled 0 51 204 Untitled
0 51 153 Untitled 0 51 153 Untitled
0 51 102 Untitled 0 51 102 Untitled
0 51 51 Untitled 0 51 51 Untitled
0 51 0 Untitled 0 51 0 Untitled
0 0 255 Untitled 0 0 255 Untitled
0 0 204 Untitled 0 0 204 Untitled
0 0 153 Untitled 0 0 153 Untitled
0 0 102 Untitled 0 0 102 Untitled
0 0 51 Untitled 0 0 51 Untitled
0 0 0 Untitled 0 0 0 Untitled

View File

@ -692,11 +692,11 @@
<item command="NewFile" text="@.file_new" group="file_new" /> <item command="NewFile" text="@.file_new" group="file_new" />
<item command="OpenFile" text="@.file_open" group="file_open" /> <item command="OpenFile" text="@.file_open" group="file_open" />
<menu text="@.file_open_recent" group="file_recent"> <menu text="@.file_open_recent" group="file_recent">
<item command="ReopenClosedFile" text="@.file_reopen_closed" group="file_recent_reopen" /> <item command="ReopenClosedFile" text="@.file_reopen_closed" group="file_recent_reopen" />
<separator id="recent_files_placeholder" group="file_recent_list" /> <separator id="recent_files_placeholder" group="file_recent_list" />
<separator /> <separator />
<item command="ClearRecentFiles" text="@.file_clear_recent_files" group="file_recent_clear" /> <item command="ClearRecentFiles" text="@.file_clear_recent_files" group="file_recent_clear" />
</menu> </menu>
<separator /> <separator />
<item command="SaveFile" text="@.file_save" /> <item command="SaveFile" text="@.file_save" />
<item command="SaveFileAs" text="@.file_save_as" group="file_save" /> <item command="SaveFileAs" text="@.file_save_as" group="file_save" />

View File

@ -1,12 +1,12 @@
# Aseprite Translations # Aseprite Translations
Aseprite is translated using the following Weblate project: Aseprite is translated using the following Weblate project:
https://hosted.weblate.org/projects/aseprite/aseprite/ https://hosted.weblate.org/projects/aseprite/aseprite/
You can find all the translations in this other repository: You can find all the translations in this other repository:
https://github.com/aseprite/strings https://github.com/aseprite/strings
The official English strings are from the [`en.ini` file here](https://github.com/aseprite/aseprite/blob/main/data/strings/en.ini), The official English strings are from the [`en.ini` file here](https://github.com/aseprite/aseprite/blob/main/data/strings/en.ini),
and this file will be copied to the [strings repository](https://github.com/aseprite/strings/blob/main/en.ini) regularly. and this file will be copied to the [strings repository](https://github.com/aseprite/strings/blob/main/en.ini) regularly.

View File

@ -8,14 +8,14 @@
<label text="Animated sprite editor &amp;&amp; pixel art tool" /> <label text="Animated sprite editor &amp;&amp; pixel art tool" />
<hbox homogeneous="true"> <hbox homogeneous="true">
<hbox> <hbox>
<vbox expansive="true"> <vbox expansive="true">
<separator text="Developer Team" horizontal="true" /> <separator text="Developer Team" horizontal="true" />
<link text="David Capello" url="https://twitter.com/davidcapello" /> <link text="David Capello" url="https://twitter.com/davidcapello" />
<link text="Gaspar Capello" url="https://twitter.com/Gasparoken" /> <link text="Gaspar Capello" url="https://twitter.com/Gasparoken" />
<link text="Martín Capello" url="https://twitter.com/martincapell0" /> <link text="Martín Capello" url="https://twitter.com/martincapell0" />
<vbox minheight="8" /> <vbox minheight="8" />
</vbox> </vbox>
<separator vertical="true" /> <separator vertical="true" />
</hbox> </hbox>
<vbox> <vbox>
<separator text="Credits" horizontal="true" cell_hspan="2" /> <separator text="Credits" horizontal="true" cell_hspan="2" />

View File

@ -1,58 +1,58 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2019-2024 Igara Studio S.A. --> <!-- Copyright (C) 2019-2024 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2018 David Capello --> <!-- Copyright (C) 2001-2018 David Capello -->
<gui> <gui>
<window id="canvas_size" text="@.title" help="canvas"> <window id="canvas_size" text="@.title" help="canvas">
<vbox> <vbox>
<separator text="@.size" left="true" horizontal="true" /> <separator text="@.size" left="true" horizontal="true" />
<hbox> <hbox>
<grid columns="2"> <grid columns="2">
<label text="@.width" /> <label text="@.width" />
<expr text="0" id="width" suffix="px" magnet="true" /> <expr text="0" id="width" suffix="px" magnet="true" />
<label text="@.height" /> <label text="@.height" />
<expr text="0" id="height" suffix="px" /> <expr text="0" id="height" suffix="px" />
<hbox filler="true" cell_hspan="2" /> <hbox filler="true" cell_hspan="2" />
</grid> </grid>
<buttonset columns="3" id="dir"> <buttonset columns="3" id="dir">
<item icon="canvas_nw" style="dir_item" /> <item icon="canvas_nw" style="dir_item" />
<item icon="canvas_n" style="dir_item" /> <item icon="canvas_n" style="dir_item" />
<item icon="canvas_ne" style="dir_item" /> <item icon="canvas_ne" style="dir_item" />
<item icon="canvas_w" style="dir_item" /> <item icon="canvas_w" style="dir_item" />
<item icon="canvas_c" style="dir_item" /> <item icon="canvas_c" style="dir_item" />
<item icon="canvas_e" style="dir_item" /> <item icon="canvas_e" style="dir_item" />
<item icon="canvas_sw" style="dir_item" /> <item icon="canvas_sw" style="dir_item" />
<item icon="canvas_s" style="dir_item" /> <item icon="canvas_s" style="dir_item" />
<item icon="canvas_se" style="dir_item" /> <item icon="canvas_se" style="dir_item" />
</buttonset> </buttonset>
</hbox> </hbox>
<separator text="@.borders" left="true" horizontal="true" /> <separator text="@.borders" left="true" horizontal="true" />
<grid columns="4"> <grid columns="4">
<label text="@.left" /> <label text="@.left" />
<expr text="0" id="left" suffix="px" tooltip="@.left_tooltip" /> <expr text="0" id="left" suffix="px" tooltip="@.left_tooltip" />
<label text="@.top" /> <label text="@.top" />
<expr text="0" id="top" suffix="px" tooltip="@.top_tooltip" /> <expr text="0" id="top" suffix="px" tooltip="@.top_tooltip" />
<label text="@.right" /> <label text="@.right" />
<expr text="0" id="right" suffix="px" tooltip="@.right_tooltip" /> <expr text="0" id="right" suffix="px" tooltip="@.right_tooltip" />
<label text="@.bottom" /> <label text="@.bottom" />
<expr text="0" id="bottom" suffix="px" tooltip="@.bottom_tooltip" /> <expr text="0" id="bottom" suffix="px" tooltip="@.bottom_tooltip" />
</grid> </grid>
<separator horizontal="true" /> <separator horizontal="true" />
<check id="trim" text="@.trim" tooltip="@.trim_tooltip" /> <check id="trim" text="@.trim" tooltip="@.trim_tooltip" />
<separator horizontal="true" /> <separator horizontal="true" />
<hbox> <hbox>
<boxfiller /> <boxfiller />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</hbox> </hbox>
</hbox> </hbox>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,20 +1,20 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2020-2024 by Igara Studio S.A. --> <!-- Copyright (C) 2020-2024 by Igara Studio S.A. -->
<!-- Copyright (C) 2001-2016 by David Capello --> <!-- Copyright (C) 2001-2016 by David Capello -->
<gui> <gui>
<window id="cel_properties" text="@.title"> <window id="cel_properties" text="@.title">
<grid id="properties_grid" columns="4"> <grid id="properties_grid" columns="4">
<label text="@.opacity" /> <label text="@.opacity" />
<opacityslider id="opacity" cell_align="horizontal" width="128" cell_hspan="2" /> <opacityslider id="opacity" cell_align="horizontal" width="128" cell_hspan="2" />
<button id="user_data" icon="icon_user_data" tooltip="@.user_data_tooltip" /> <button id="user_data" icon="icon_user_data" tooltip="@.user_data_tooltip" />
<label text="@.zindex" /> <label text="@.zindex" />
<expr id="zindex" cell_align="horizontal" width="128" /> <expr id="zindex" cell_align="horizontal" width="128" />
<buttonset id="zindex_spin" columns="1"> <buttonset id="zindex_spin" columns="1">
<item icon="spin_up" /> <item icon="spin_up" />
<item icon="spin_down" /> <item icon="spin_down" />
</buttonset> </buttonset>
<boxfiller /> <boxfiller />
</grid> </grid>
</window> </window>
</gui> </gui>

View File

@ -1,45 +1,45 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2019-2024 Igara Studio S.A. --> <!-- Copyright (C) 2019-2024 Igara Studio S.A. -->
<!-- Copyright (C) 2017 David Capello --> <!-- Copyright (C) 2017 David Capello -->
<gui> <gui>
<window id="color_mode" text="@.title"> <window id="color_mode" text="@.title">
<vbox> <vbox>
<view id="color_mode_view" expansive="true"> <view id="color_mode_view" expansive="true">
<listbox id="color_mode" /> <listbox id="color_mode" />
</view> </view>
<hbox id="dithering_placeholder" /> <hbox id="dithering_placeholder" />
<hbox id="amount"> <hbox id="amount">
<label text="@.amount" /> <label text="@.amount" />
<slider min="0" max="100" id="factor" minwidth="100" /> <slider min="0" max="100" id="factor" minwidth="100" />
<label text="%" /> <label text="%" />
</hbox> </hbox>
<combobox id="to_gray_combobox"> <combobox id="to_gray_combobox">
<listitem text="!Luminance" /> <listitem text="!Luminance" />
<listitem text="!HSV" /> <listitem text="!HSV" />
<listitem text="!HSL" /> <listitem text="!HSL" />
</combobox> </combobox>
<check text="@.flatten" id="flatten" /> <check text="@.flatten" id="flatten" />
<check id="advanced_check" text="@general.advanced_options" /> <check id="advanced_check" text="@general.advanced_options" />
<grid id="advanced" columns="2"> <grid id="advanced" columns="2">
<label text="@rgbmap_algorithm_selector.label" /> <label text="@rgbmap_algorithm_selector.label" />
<hbox id="rgbmap_algorithm_placeholder" cell_align="horizontal" /> <hbox id="rgbmap_algorithm_placeholder" cell_align="horizontal" />
<label text="@best_fit_criteria_selector.label" /> <label text="@best_fit_criteria_selector.label" />
<hbox id="best_fit_criteria_placeholder" cell_align="horizontal" /> <hbox id="best_fit_criteria_placeholder" cell_align="horizontal" />
</grid> </grid>
<separator horizontal="true" /> <separator horizontal="true" />
<hbox> <hbox>
<slider min="0" max="100" id="progress" minwidth="100" /> <slider min="0" max="100" id="progress" minwidth="100" />
<boxfiller /> <boxfiller />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</hbox> </hbox>
</hbox> </hbox>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,12 +1,12 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2016 by David Capello --> <!-- Copyright (C) 2001-2016 by David Capello -->
<gui> <gui>
<box vertical="true" id="controls" expansive="true"> <box vertical="true" id="controls" expansive="true">
<view expansive="true" id="view" minwidth="128" minheight="64"> <view expansive="true" id="view" minwidth="128" minheight="64">
<listbox id="stock" /> <listbox id="stock" />
</view> </view>
<box horizontal="true"> <box horizontal="true">
<button text="@convolution_matrix.reload_stock" id="reload" /> <button text="@convolution_matrix.reload_stock" id="reload" />
</box> </box>
</box> </box>
</gui> </gui>

View File

@ -1,12 +1,12 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2018 by David Capello --> <!-- Copyright (C) 2001-2018 by David Capello -->
<gui> <gui>
<hbox id="despeckle"> <hbox id="despeckle">
<grid columns="2"> <grid columns="2">
<label text="@.width" /> <label text="@.width" />
<expr id="width" cell_align="horizontal" /> <expr id="width" cell_align="horizontal" />
<label text="@.height" /> <label text="@.height" />
<expr id="height" cell_align="horizontal" /> <expr id="height" cell_align="horizontal" />
</grid> </grid>
</hbox> </hbox>
</gui> </gui>

View File

@ -1,23 +1,23 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2016 by David Capello --> <!-- Copyright (C) 2001-2016 by David Capello -->
<gui> <gui>
<window id="duplicate_sprite" text="@.title"> <window id="duplicate_sprite" text="@.title">
<box vertical="true"> <box vertical="true">
<box horizontal="true" expansive="true"> <box horizontal="true" expansive="true">
<box vertical="true" homogeneous="true"> <box vertical="true" homogeneous="true">
<label text="@.duplicate" /> <label text="@.duplicate" />
<label text="@.as" /> <label text="@.as" />
</box> </box>
<box vertical="true" homogeneous="true" expansive="true"> <box vertical="true" homogeneous="true" expansive="true">
<label text="" id="src_name" /> <label text="" id="src_name" />
<entry maxsize="256" id="dst_name" magnet="true" /> <entry maxsize="256" id="dst_name" magnet="true" />
</box> </box>
</box> </box>
<check text="@.merged_layers" id="flatten" /> <check text="@.merged_layers" id="flatten" />
<box horizontal="true" homogeneous="true"> <box horizontal="true" homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</box> </box>
</box> </box>
</window> </window>
</gui> </gui>

View File

@ -1,58 +1,58 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2022-2024 by Igara Studio S.A. --> <!-- Copyright (C) 2022-2024 by Igara Studio S.A. -->
<!-- Copyright (C) 2016-2018 by David Capello --> <!-- Copyright (C) 2016-2018 by David Capello -->
<gui> <gui>
<window id="export_file" text="@.title" help="exporting"> <window id="export_file" text="@.title" help="exporting">
<grid columns="3"> <grid columns="3">
<label text="@.output_file" /> <label text="@.output_file" />
<entry id="output_filename" cell_align="horizontal" maxsize="1024" maxwidth="256" /> <entry id="output_filename" cell_align="horizontal" maxsize="1024" maxwidth="256" />
<button id="output_filename_browse" text="..." style="mini_button" /> <button id="output_filename_browse" text="..." style="mini_button" />
<label id="resize_label" text="@.resize" /> <label id="resize_label" text="@.resize" />
<hbox cell_hspan="2" cell_align="horizontal"> <hbox cell_hspan="2" cell_align="horizontal">
<combobox id="resize" editable="true" suffix="%" expansive="true"> <combobox id="resize" editable="true" suffix="%" expansive="true">
<listitem text="25" /> <listitem text="25" />
<listitem text="50" /> <listitem text="50" />
<listitem text="100" /> <listitem text="100" />
<listitem text="200" /> <listitem text="200" />
<listitem text="300" /> <listitem text="300" />
<listitem text="400" /> <listitem text="400" />
<listitem text="500" /> <listitem text="500" />
<listitem text="600" /> <listitem text="600" />
<listitem text="700" /> <listitem text="700" />
<listitem text="800" /> <listitem text="800" />
<listitem text="900" /> <listitem text="900" />
<listitem text="1000" /> <listitem text="1000" />
</combobox> </combobox>
<label id="area_label" text="@.area" /> <label id="area_label" text="@.area" />
<combobox id="area" text="" cell_align="horizontal" cell_hspan="2" expansive="true" /> <combobox id="area" text="" cell_align="horizontal" cell_hspan="2" expansive="true" />
</hbox> </hbox>
<label id="layers_label" text="@.layers" /> <label id="layers_label" text="@.layers" />
<combobox id="layers" text="" cell_align="horizontal" cell_hspan="2" /> <combobox id="layers" text="" cell_align="horizontal" cell_hspan="2" />
<label id="frames_label" text="@.frames" /> <label id="frames_label" text="@.frames" />
<combobox id="frames" text="" cell_align="horizontal" cell_hspan="2" /> <combobox id="frames" text="" cell_align="horizontal" cell_hspan="2" />
<label id="anidir_label" text="@.anidir" /> <label id="anidir_label" text="@.anidir" />
<combobox id="anidir" text="" cell_align="horizontal" cell_hspan="2" /> <combobox id="anidir" text="" cell_align="horizontal" cell_hspan="2" />
<check id="play_subtags" text="@.play_subtags" cell_hspan="3" /> <check id="play_subtags" text="@.play_subtags" cell_hspan="3" />
<check id="pixel_ratio" text="@.pixel_ratio" cell_hspan="3" /> <check id="pixel_ratio" text="@.pixel_ratio" cell_hspan="3" />
<hbox cell_hspan="3"> <hbox cell_hspan="3">
<check id="for_twitter" text="@.for_twitter" tooltip="@.for_twitter_tooltip" /> <check id="for_twitter" text="@.for_twitter" tooltip="@.for_twitter_tooltip" />
<button id="adjust_resize" text="@.adjust_resize" style="mini_button" /> <button id="adjust_resize" text="@.adjust_resize" style="mini_button" />
</hbox> </hbox>
<hbox cell_hspan="3"> <hbox cell_hspan="3">
<boxfiller /> <boxfiller />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button text="@.export" minwidth="60" id="ok" magnet="true" /> <button text="@.export" minwidth="60" id="ok" magnet="true" />
<button text="@.cancel" minwidth="60" closewindow="true" /> <button text="@.cancel" minwidth="60" closewindow="true" />
</hbox> </hbox>
</hbox> </hbox>
</grid> </grid>
</window> </window>
</gui> </gui>

View File

@ -1,44 +1,44 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2019-2022 Igara Studio S.A. --> <!-- Copyright (C) 2019-2022 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2018 David Capello --> <!-- Copyright (C) 2001-2018 David Capello -->
<gui> <gui>
<window id="file_selector" text=""> <window id="file_selector" text="">
<vbox id="main"> <vbox id="main">
<box horizontal="true"> <box horizontal="true">
<hbox noborders="true"> <hbox noborders="true">
<button text="" id="go_back_button" style="go_back_button" <button text="" id="go_back_button" style="go_back_button"
tooltip="@.go_back_button_tooltip" tooltip_dir="bottom" /> tooltip="@.go_back_button_tooltip" tooltip_dir="bottom" />
<button text="" id="go_forward_button" style="go_forward_button" <button text="" id="go_forward_button" style="go_forward_button"
tooltip="@.go_forward_button_tooltip" tooltip_dir="bottom" /> tooltip="@.go_forward_button_tooltip" tooltip_dir="bottom" />
</hbox> </hbox>
<button text="" id="go_up_button" style="go_up_button" <button text="" id="go_up_button" style="go_up_button"
tooltip="@.go_up_button_tooltip" tooltip_dir="bottom" /> tooltip="@.go_up_button_tooltip" tooltip_dir="bottom" />
<button text="" id="new_folder_button" style="new_folder_button" <button text="" id="new_folder_button" style="new_folder_button"
tooltip="@.new_folder_button_tooltip" tooltip_dir="bottom" /> tooltip="@.new_folder_button_tooltip" tooltip_dir="bottom" />
<buttonset id="view_type" columns="3"> <buttonset id="view_type" columns="3">
<item icon="list_view" tooltip="@.list_view_button_tooltip" tooltip_dir="bottom" /> <item icon="list_view" tooltip="@.list_view_button_tooltip" tooltip_dir="bottom" />
<item icon="small_icon_view" tooltip="@.small_icon_view_button_tooltip" tooltip_dir="bottom" /> <item icon="small_icon_view" tooltip="@.small_icon_view_button_tooltip" tooltip_dir="bottom" />
<item icon="big_icon_view" tooltip="@.big_icon_view_button_tooltip" tooltip_dir="bottom" /> <item icon="big_icon_view" tooltip="@.big_icon_view_button_tooltip" tooltip_dir="bottom" />
</buttonset> </buttonset>
<combobox id="location" expansive="true" /> <combobox id="location" expansive="true" />
<button text="" id="refresh_button" style="refresh_button" <button text="" id="refresh_button" style="refresh_button"
tooltip="@.refresh_button_tooltip" tooltip_dir="bottom" /> tooltip="@.refresh_button_tooltip" tooltip_dir="bottom" />
</box> </box>
<vbox id="file_view_placeholder" expansive="true" /> <vbox id="file_view_placeholder" expansive="true" />
<grid columns="2"> <grid columns="2">
<label text="@.file_name" /> <label text="@.file_name" />
<box id="file_name_placeholder" cell_align="horizontal" /> <box id="file_name_placeholder" cell_align="horizontal" />
<label text="@.file_type" /> <label text="@.file_type" />
<hbox cell_align="horizontal"> <hbox cell_align="horizontal">
<combobox id="file_type" minwidth="70" /> <combobox id="file_type" minwidth="70" />
<boxfiller /> <boxfiller />
<box horizontal="true" homogeneous="true"> <box horizontal="true" homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" id="cancel" /> <button text="@general.cancel" closewindow="true" id="cancel" />
</box> </box>
</hbox> </hbox>
</grid> </grid>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,24 +1,24 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2020 Igara Studio S.A. --> <!-- Copyright (C) 2020 Igara Studio S.A. -->
<!-- Copyright (C) 2014-2018 David Capello --> <!-- Copyright (C) 2014-2018 David Capello -->
<gui> <gui>
<window id="gif_options" text="@.title"> <window id="gif_options" text="@.title">
<vbox> <vbox>
<separator text="@.general_options" left="true" horizontal="true" /> <separator text="@.general_options" left="true" horizontal="true" />
<check text="@.interlaced" id="interlaced" /> <check text="@.interlaced" id="interlaced" />
<check text="@.animation_loop" id="loop" /> <check text="@.animation_loop" id="loop" />
<check text="@.preserve_palette_order" id="preserve_palette_order" /> <check text="@.preserve_palette_order" id="preserve_palette_order" />
<separator horizontal="true" /> <separator horizontal="true" />
<hbox> <hbox>
<check text="@general.dont_show" id="dont_show" tooltip="@general.dont_show_tooltip" /> <check text="@general.dont_show" id="dont_show" tooltip="@general.dont_show_tooltip" />
<boxfiller /> <boxfiller />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</hbox> </hbox>
</hbox> </hbox>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,17 +1,17 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2017 by David Capello --> <!-- Copyright (C) 2001-2017 by David Capello -->
<gui> <gui>
<window id="goto_frame" text="@.title"> <window id="goto_frame" text="@.title">
<vbox> <vbox>
<label text="@.frame_or_tags" /> <label text="@.frame_or_tags" />
<vbox id="frame_placeholder" /> <vbox id="frame_placeholder" />
<separator horizontal="true" /> <separator horizontal="true" />
<hbox homogeneous="true" cell_align="right"> <hbox homogeneous="true" cell_align="right">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</hbox> </hbox>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,27 +1,27 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2018 by David Capello --> <!-- Copyright (C) 2001-2018 by David Capello -->
<gui> <gui>
<window id="grid_settings" text="@.title"> <window id="grid_settings" text="@.title">
<grid columns="4"> <grid columns="4">
<label text="@.x" /> <label text="@.x" />
<expr id="grid_x" text="" magnet="true" /> <expr id="grid_x" text="" magnet="true" />
<label text="@.y" /> <label text="@.y" />
<expr id="grid_y" text="" /> <expr id="grid_y" text="" />
<label text="@.width" /> <label text="@.width" />
<expr id="grid_w" text="" /> <expr id="grid_w" text="" />
<label text="@.height" /> <label text="@.height" />
<expr id="grid_h" text="" /> <expr id="grid_h" text="" />
<separator horizontal="true" cell_hspan="4" /> <separator horizontal="true" cell_hspan="4" />
<box horizontal="true" homogeneous="true" cell_hspan="4" cell_align="right"> <box horizontal="true" homogeneous="true" cell_hspan="4" cell_align="right">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</box> </box>
</grid> </grid>
</window> </window>
</gui> </gui>

View File

@ -1,42 +1,42 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2019-2021 Igara Studio S.A. --> <!-- Copyright (C) 2019-2021 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2017 David Capello --> <!-- Copyright (C) 2001-2017 David Capello -->
<gui> <gui>
<vbox noborders="true" id="home_view" border="4" childspacing="2" expansive="true"> <vbox noborders="true" id="home_view" border="4" childspacing="2" expansive="true">
<hbox noborders="true" id="header_placeholder"> <hbox noborders="true" id="header_placeholder">
<link id="aseprite_face" style="aseprite_face" /> <link id="aseprite_face" style="aseprite_face" />
<vbox border="4" childspacing="4"> <vbox border="4" childspacing="4">
<link id="new_file" text="@.new_file" style="workspace_link" /> <link id="new_file" text="@.new_file" style="workspace_link" />
<link id="open_file" text="@.open_file" style="workspace_link" /> <link id="open_file" text="@.open_file" style="workspace_link" />
<link id="recover_sprites" text="@.recover_files" style="workspace_link" <link id="recover_sprites" text="@.recover_files" style="workspace_link"
tooltip="@.recover_files_tooltip" /> tooltip="@.recover_files_tooltip" />
</vbox> </vbox>
<boxfiller /> <boxfiller />
<vbox border="4"> <vbox border="4">
<check id="share_crashdb" text="@.share_crashdb" <check id="share_crashdb" text="@.share_crashdb"
tooltip="@.share_crashdb_tooltip" style="workspace_check_box" /> tooltip="@.share_crashdb_tooltip" style="workspace_check_box" />
<link id="check_update" text="" style="workspace_link" /> <link id="check_update" text="" style="workspace_link" />
</vbox> </vbox>
</hbox> </hbox>
<splitter horizontal="true" noborders="true" childspacing="2" <splitter horizontal="true" noborders="true" childspacing="2"
expansive="true" by="percetage" position="50" expansive="true" by="percetage" position="50"
style="workspace_splitter"> style="workspace_splitter">
<splitter vertical="true" noborders="true" childspacing="2" <splitter vertical="true" noborders="true" childspacing="2"
style="workspace_splitter"> style="workspace_splitter">
<vbox id="files_placeholder"> <vbox id="files_placeholder">
<label text="@home_view.recent_files" style="workspace_label" /> <label text="@home_view.recent_files" style="workspace_label" />
<view id="files_view" expansive="true" style="workspace_view" /> <view id="files_view" expansive="true" style="workspace_view" />
</vbox> </vbox>
<vbox id="folders_placeholder"> <vbox id="folders_placeholder">
<label text="@home_view.recent_folders" style="workspace_label" /> <label text="@home_view.recent_folders" style="workspace_label" />
<view id="folders_view" expansive="true" style="workspace_view" /> <view id="folders_view" expansive="true" style="workspace_view" />
</vbox> </vbox>
</splitter> </splitter>
<vbox id="news_placeholder" noborders="true" childspacing="2"> <vbox id="news_placeholder" noborders="true" childspacing="2">
<label text="@home_view.news" style="workspace_label" /> <label text="@home_view.news" style="workspace_label" />
<view id="news_view" expansive="true" style="workspace_view" /> <view id="news_view" expansive="true" style="workspace_view" />
</vbox> </vbox>
</splitter> </splitter>
</vbox> </vbox>
</gui> </gui>

View File

@ -1,54 +1,54 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2019-2024 by Igara Studio S.A. --> <!-- Copyright (C) 2019-2024 by Igara Studio S.A. -->
<!-- Copyright (C) 2001-2018 by David Capello --> <!-- Copyright (C) 2001-2018 by David Capello -->
<gui> <gui>
<window id="import_sprite_sheet" text="@.title" help="sprite-sheet#import"> <window id="import_sprite_sheet" text="@.title" help="sprite-sheet#import">
<vbox> <vbox>
<grid columns="4"> <grid columns="4">
<button id="select_file" text="@select_file.text" cell_hspan="4" /> <button id="select_file" text="@select_file.text" cell_hspan="4" />
<label text="@.type" /> <label text="@.type" />
<combobox id="sheet_type" cell_hspan="3" /> <combobox id="sheet_type" cell_hspan="3" />
<separator text="@.tiles" horizontal="true" cell_hspan="4" /> <separator text="@.tiles" horizontal="true" cell_hspan="4" />
<label text="@.x" /> <label text="@.x" />
<expr id="x" text="0" /> <expr id="x" text="0" />
<label text="@.y" /> <label text="@.y" />
<expr id="y" text="0" /> <expr id="y" text="0" />
<label text="@.width" /> <label text="@.width" />
<expr id="width" text="16" /> <expr id="width" text="16" />
<label text="@.height" /> <label text="@.height" />
<expr id="height" text="16" /> <expr id="height" text="16" />
<separator horizontal="true" cell_hspan="4" /> <separator horizontal="true" cell_hspan="4" />
<label text="@.columns" /> <label text="@.columns" />
<expr id="columns" /> <expr id="columns" />
<label text="@.rows" /> <label text="@.rows" />
<expr id="rows" /> <expr id="rows" />
<check id="padding_enabled" text="@.padding" cell_hspan="4" /> <check id="padding_enabled" text="@.padding" cell_hspan="4" />
<label text="@.horizontal_padding" id="horizontal_padding_label" /> <label text="@.horizontal_padding" id="horizontal_padding_label" />
<expr id="horizontal_padding" text="0" /> <expr id="horizontal_padding" text="0" />
<label text="@.vertical_padding" id="vertical_padding_label" /> <label text="@.vertical_padding" id="vertical_padding_label" />
<expr id="vertical_padding" text="0" /> <expr id="vertical_padding" text="0" />
<check id="partial_tiles" text="@.partial_tiles" cell_hspan="4" /> <check id="partial_tiles" text="@.partial_tiles" cell_hspan="4" />
<hbox cell_hspan="4"> <hbox cell_hspan="4">
<boxfiller /> <boxfiller />
<hbox> <hbox>
</hbox> </hbox>
<button id="import" text="@.import" minwidth="60" magnet="true" cell_align="center" closewindow="true" /> <button id="import" text="@.import" minwidth="60" magnet="true" cell_align="center" closewindow="true" />
<button id="cancel" text="@.cancel" minwidth="60" cell_align="center" closewindow="true" /> <button id="cancel" text="@.cancel" minwidth="60" cell_align="center" closewindow="true" />
</hbox> </hbox>
</grid> </grid>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,21 +1,21 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2018 by David Capello --> <!-- Copyright (C) 2001-2018 by David Capello -->
<gui> <gui>
<window id="jpeg_options" text="@.title"> <window id="jpeg_options" text="@.title">
<grid columns="2"> <grid columns="2">
<label text="@.quality" /> <label text="@.quality" />
<slider min="0" max="10" id="quality" cell_align="horizontal" width="128" /> <slider min="0" max="10" id="quality" cell_align="horizontal" width="128" />
<separator horizontal="true" cell_hspan="2" /> <separator horizontal="true" cell_hspan="2" />
<hbox cell_hspan="2"> <hbox cell_hspan="2">
<check text="@general.dont_show" id="dont_show" tooltip="@general.dont_show_tooltip" /> <check text="@general.dont_show" id="dont_show" tooltip="@general.dont_show_tooltip" />
<boxfiller /> <boxfiller />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</hbox> </hbox>
</hbox> </hbox>
</grid> </grid>
</window> </window>
</gui> </gui>

View File

@ -1,124 +1,124 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2018-2024 Igara Studio S.A. --> <!-- Copyright (C) 2018-2024 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2016 David Capello --> <!-- Copyright (C) 2001-2016 David Capello -->
<gui> <gui>
<window id="keyboard_shortcuts" text="@keyboard_shortcuts.title" help="keyboard-shortcuts"> <window id="keyboard_shortcuts" text="@keyboard_shortcuts.title" help="keyboard-shortcuts">
<vbox> <vbox>
<splitter horizontal="true" expansive="true" noborders="true" childspacing="2" <splitter horizontal="true" expansive="true" noborders="true" childspacing="2"
by="pixel" position="80" id="section_splitter"> by="pixel" position="80" id="section_splitter">
<vbox expansive="true"> <vbox expansive="true">
<search id="search" magnet="true" /> <search id="search" magnet="true" />
<view expansive="true"> <view expansive="true">
<listbox id="section" expansive="true"> <listbox id="section" expansive="true">
<listitem text="@.section_menus" /> <listitem text="@.section_menus" />
<listitem text="@.section_commands" /> <listitem text="@.section_commands" />
<listitem text="@.section_tools" /> <listitem text="@.section_tools" />
<listitem text="@.section_action_modifiers" /> <listitem text="@.section_action_modifiers" />
<listitem text="@.section_mouse_wheel" /> <listitem text="@.section_mouse_wheel" />
<listitem text="@.section_drag_value" /> <listitem text="@.section_drag_value" />
</listbox> </listbox>
</view> </view>
<separator horizontal="true" /> <separator horizontal="true" />
<button text="@keyboard_shortcuts.import" id="import_button" /> <button text="@keyboard_shortcuts.import" id="import_button" />
<button text="@keyboard_shortcuts.export" id="export_button" /> <button text="@keyboard_shortcuts.export" id="export_button" />
<button text="@keyboard_shortcuts.reset" id="reset_button" /> <button text="@keyboard_shortcuts.reset" id="reset_button" />
</vbox> </vbox>
<vbox id="lists_placeholder" expansive="true"> <vbox id="lists_placeholder" expansive="true">
<view id="search_view" expansive="true"> <view id="search_view" expansive="true">
<listbox id="search_list" /> <listbox id="search_list" />
</view> </view>
<view id="menus_view" expansive="true"> <view id="menus_view" expansive="true">
<listbox id="menus" /> <listbox id="menus" />
</view> </view>
<view id="commands_view" expansive="true"> <view id="commands_view" expansive="true">
<listbox id="commands" /> <listbox id="commands" />
</view> </view>
<view id="tools_view" expansive="true"> <view id="tools_view" expansive="true">
<listbox id="tools" /> <listbox id="tools" />
</view> </view>
<view id="actions_view" expansive="true"> <view id="actions_view" expansive="true">
<listbox id="actions" /> <listbox id="actions" />
</view> </view>
<vbox id="wheel_section" expansive="true"> <vbox id="wheel_section" expansive="true">
<hbox> <hbox>
<buttonset columns="2" id="wheel_behavior"> <buttonset columns="2" id="wheel_behavior">
<item text="@.default_wheel_behavior" /> <item text="@.default_wheel_behavior" />
<item text="@.custom_wheel_behavior" /> <item text="@.custom_wheel_behavior" />
</buttonset> </buttonset>
</hbox> </hbox>
<check text="@options.wheel_zoom" id="wheel_zoom" <check text="@options.wheel_zoom" id="wheel_zoom"
pref="editor.zoom_with_wheel" /> pref="editor.zoom_with_wheel" />
<check text="@options.slide_zoom" id="slide_zoom" <check text="@options.slide_zoom" id="slide_zoom"
pref="editor.zoom_with_slide" /> pref="editor.zoom_with_slide" />
<check text="@.invert_brush_size_wheel" id="invert_brush_size_scroll" <check text="@.invert_brush_size_wheel" id="invert_brush_size_scroll"
pref="editor.invert_brush_size_wheel" /> pref="editor.invert_brush_size_wheel" />
<view expansive="true"> <view expansive="true">
<listbox id="wheel_actions" /> <listbox id="wheel_actions" />
</view> </view>
</vbox> </vbox>
<vbox id="drag_section" expansive="true"> <vbox id="drag_section" expansive="true">
<view expansive="true"> <view expansive="true">
<listbox id="drag_actions" /> <listbox id="drag_actions" />
</view> </view>
<separator horizontal="true" /> <separator horizontal="true" />
<hbox> <hbox>
<vbox> <vbox>
<label text="@.drag_angle" /> <label text="@.drag_angle" />
</vbox> </vbox>
<buttonset columns="3" id="drag_angle"> <buttonset columns="3" id="drag_angle">
<item icon="canvas_nw" <item icon="canvas_nw"
style="dir_item" style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="bottom" /> tooltip_dir="bottom" />
<item icon="canvas_n" <item icon="canvas_n"
style="dir_item" style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="bottom" /> tooltip_dir="bottom" />
<item icon="canvas_ne" <item icon="canvas_ne"
style="dir_item" style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="bottom" /> tooltip_dir="bottom" />
<item icon="canvas_w" <item icon="canvas_w"
style="dir_item" style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="right" /> tooltip_dir="right" />
<item /> <item />
<item icon="canvas_e" <item icon="canvas_e"
style="dir_item" style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="left" /> tooltip_dir="left" />
<item icon="canvas_sw" <item icon="canvas_sw"
style="dir_item" style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="top" /> tooltip_dir="top" />
<item icon="canvas_s" <item icon="canvas_s"
style="dir_item" style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="top" /> tooltip_dir="top" />
<item icon="canvas_se" <item icon="canvas_se"
style="dir_item" style="dir_item"
tooltip="@.drag_angle_tooltip" tooltip="@.drag_angle_tooltip"
tooltip_dir="top" /> tooltip_dir="top" />
</buttonset> </buttonset>
<vbox> <vbox>
<label text="@.drag_distance" /> <label text="@.drag_distance" />
</vbox> </vbox>
<vbox> <vbox>
<slider min="1" max="100" id="drag_distance" cell_align="horizontal" width="128" <slider min="1" max="100" id="drag_distance" cell_align="horizontal" width="128"
tooltip="@.drag_distance_tooltip" tooltip="@.drag_distance_tooltip"
tooltip_dir="bottom" /> tooltip_dir="bottom" />
</vbox> </vbox>
</hbox> </hbox>
</vbox> </vbox>
</vbox> </vbox>
</splitter> </splitter>
<hbox> <hbox>
<boxfiller /> <boxfiller />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button text="@keyboard_shortcuts.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@keyboard_shortcuts.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@keyboard_shortcuts.cancel" closewindow="true" /> <button text="@keyboard_shortcuts.cancel" closewindow="true" />
</hbox> </hbox>
</hbox> </hbox>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,21 +1,21 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2020 by Igara Studio S.A. --> <!-- Copyright (C) 2020 by Igara Studio S.A. -->
<!-- Copyright (C) 2001-2016 by David Capello --> <!-- Copyright (C) 2001-2016 by David Capello -->
<gui> <gui>
<window id="layer_properties" text="@.title"> <window id="layer_properties" text="@.title">
<vbox> <vbox>
<grid id="properties_grid" columns="3"> <grid id="properties_grid" columns="3">
<label text="@.name" /> <label text="@.name" />
<entry text="" id="name" magnet="true" maxsize="256" minwidth="64" cell_align="horizontal" /> <entry text="" id="name" magnet="true" maxsize="256" minwidth="64" cell_align="horizontal" />
<button id="user_data" icon="icon_user_data" tooltip="@general.user_data" /> <button id="user_data" icon="icon_user_data" tooltip="@general.user_data" />
<label text="@.mode" /> <label text="@.mode" />
<combobox id="mode" /> <combobox id="mode" />
<button id="tileset" icon="tiles" tooltip="@.tileset_tooltip" /> <button id="tileset" icon="tiles" tooltip="@.tileset_tooltip" />
<label text="@.opacity" /> <label text="@.opacity" />
<opacityslider id="opacity" width="128" cell_align="horizontal" cell_hspan="2" /> <opacityslider id="opacity" width="128" cell_align="horizontal" cell_hspan="2" />
</grid> </grid>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,30 +1,30 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2017 by David Capello --> <!-- Copyright (C) 2001-2017 by David Capello -->
<gui> <gui>
<window id="main_window" noborders="true" desktop="true"> <window id="main_window" noborders="true" desktop="true">
<vbox noborders="true" expansive="true"> <vbox noborders="true" expansive="true">
<hbox noborders="true" id="menu_bar_placeholder" /> <hbox noborders="true" id="menu_bar_placeholder" />
<hbox noborders="true" id="tabs_placeholder" /> <hbox noborders="true" id="tabs_placeholder" />
<splitter id="color_bar_splitter" <splitter id="color_bar_splitter"
horizontal="true" expansive="true" horizontal="true" expansive="true"
by="pixel" by="pixel"
style="workspace_splitter"> style="workspace_splitter">
<vbox noborders="true" id="color_bar_placeholder" /> <vbox noborders="true" id="color_bar_placeholder" />
<vbox noborders="true" expansive="true"> <vbox noborders="true" expansive="true">
<vbox noborders="true" id="context_bar_placeholder" /> <vbox noborders="true" id="context_bar_placeholder" />
<hbox noborders="true" expansive="true"> <hbox noborders="true" expansive="true">
<splitter id="timeline_splitter" <splitter id="timeline_splitter"
vertical="true" expansive="true" vertical="true" expansive="true"
by="percetage" position="100" by="percetage" position="100"
style="workspace_splitter"> style="workspace_splitter">
<hbox noborders="true" id="workspace_placeholder" expansive="true" /> <hbox noborders="true" id="workspace_placeholder" expansive="true" />
<vbox noborders="true" id="timeline_placeholder" expansive="true" /> <vbox noborders="true" id="timeline_placeholder" expansive="true" />
</splitter> </splitter>
<vbox noborders="true" id="tool_bar_placeholder" /> <vbox noborders="true" id="tool_bar_placeholder" />
</hbox> </hbox>
</vbox> </vbox>
</splitter> </splitter>
<hbox noborders="true" id="status_bar_placeholder" /> <hbox noborders="true" id="status_bar_placeholder" />
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,19 +1,19 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2016 by David Capello --> <!-- Copyright (C) 2001-2016 by David Capello -->
<gui> <gui>
<window id="new_folder_window" text="@new_folder.title"> <window id="new_folder_window" text="@new_folder.title">
<vbox> <vbox>
<hbox> <hbox>
<label text="@new_folder.folder_name" /> <label text="@new_folder.folder_name" />
<entry text="@new_folder.default_new_folder_name" id="name" maxsize="256" magnet="true" expansive="true" minwidth="128" /> <entry text="@new_folder.default_new_folder_name" id="name" maxsize="256" magnet="true" expansive="true" minwidth="128" />
</hbox> </hbox>
<hbox> <hbox>
<boxfiller /> <boxfiller />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" id="cancel" /> <button text="@general.cancel" closewindow="true" id="cancel" />
</hbox> </hbox>
</hbox> </hbox>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,50 +1,50 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (c) 2020-2024 Igara Studio S.A. --> <!-- Copyright (c) 2020-2024 Igara Studio S.A. -->
<!-- Copyright (c) 2001-2018 David Capello --> <!-- Copyright (c) 2001-2018 David Capello -->
<gui> <gui>
<window id="new_sprite" text="@.title" help="new-sprite"> <window id="new_sprite" text="@.title" help="new-sprite">
<box vertical="true"> <box vertical="true">
<separator text="@.size" left="true" horizontal="true" /> <separator text="@.size" left="true" horizontal="true" />
<grid columns="2"> <grid columns="2">
<label text="@.width" /> <label text="@.width" />
<expr id="width" magnet="true" cell_align="horizontal" suffix="px" /> <expr id="width" magnet="true" cell_align="horizontal" suffix="px" />
<label text="@.height" /> <label text="@.height" />
<expr id="height" cell_align="horizontal" suffix="px" /> <expr id="height" cell_align="horizontal" suffix="px" />
</grid> </grid>
<separator text="@.color_mode" left="true" horizontal="true" /> <separator text="@.color_mode" left="true" horizontal="true" />
<buttonset columns="3" id="color_mode"> <buttonset columns="3" id="color_mode">
<item text="@.rgba" icon="icon_rgb" style="new_sprite_rgb" tooltip="@.rgba_tooltip" tooltip_dir="bottom" /> <item text="@.rgba" icon="icon_rgb" style="new_sprite_rgb" tooltip="@.rgba_tooltip" tooltip_dir="bottom" />
<item text="@.grayscale" icon="icon_grayscale" style="new_sprite_grayscale" tooltip="@.grayscale_tooltip" tooltip_dir="bottom" /> <item text="@.grayscale" icon="icon_grayscale" style="new_sprite_grayscale" tooltip="@.grayscale_tooltip" tooltip_dir="bottom" />
<item text="@.indexed" icon="icon_indexed" style="new_sprite_indexed" tooltip="@.indexed_tooltip" tooltip_dir="bottom" /> <item text="@.indexed" icon="icon_indexed" style="new_sprite_indexed" tooltip="@.indexed_tooltip" tooltip_dir="bottom" />
</buttonset> </buttonset>
<separator text="@.background" left="true" horizontal="true" /> <separator text="@.background" left="true" horizontal="true" />
<buttonset columns="3" id="bg_color"> <buttonset columns="3" id="bg_color">
<item text="@.transparent" icon="icon_transparent" style="bg_transparent" /> <item text="@.transparent" icon="icon_transparent" style="bg_transparent" />
<item text="@.white" icon="icon_white" style="bg_white" /> <item text="@.white" icon="icon_white" style="bg_white" />
<item text="@.black" icon="icon_black" style="bg_black" /> <item text="@.black" icon="icon_black" style="bg_black" />
</buttonset> </buttonset>
<check id="advanced_check" text="@general.advanced_options" /> <check id="advanced_check" text="@general.advanced_options" />
<vbox id="advanced"> <vbox id="advanced">
<label text="@.pixel_ratio" /> <label text="@.pixel_ratio" />
<combobox id="pixel_ratio" cell_align="horizontal"> <combobox id="pixel_ratio" cell_align="horizontal">
<listitem text="@.square_pixels" value="1:1" /> <listitem text="@.square_pixels" value="1:1" />
<listitem text="@.double_wide" value="2:1" /> <listitem text="@.double_wide" value="2:1" />
<listitem text="@.double_high" value="1:2" /> <listitem text="@.double_high" value="1:2" />
</combobox> </combobox>
</vbox> </vbox>
<box horizontal="true"> <box horizontal="true">
<box horizontal="true" expansive="true" /> <box horizontal="true" expansive="true" />
<box horizontal="true" homogeneous="true"> <box horizontal="true" homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok_button" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok_button" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</box> </box>
</box> </box>
</box> </box>
</window> </window>
</gui> </gui>

File diff suppressed because it is too large Load Diff

View File

@ -10,16 +10,16 @@
</grid> </grid>
<hbox> <hbox>
<vbox> <vbox>
<hbox> <hbox>
<buttonset id="outline_type" columns="2"> <buttonset id="outline_type" columns="2">
<item icon="outline_circle" tooltip="@.circle" tooltip_dir="right" /> <item icon="outline_circle" tooltip="@.circle" tooltip_dir="right" />
<item icon="outline_square" tooltip="@.square" tooltip_dir="left" /> <item icon="outline_square" tooltip="@.square" tooltip_dir="left" />
<item icon="outline_horizontal" tooltip="@.horizontal" tooltip_dir="right" /> <item icon="outline_horizontal" tooltip="@.horizontal" tooltip_dir="right" />
<item icon="outline_vertical" tooltip="@.vertical" tooltip_dir="left" /> <item icon="outline_vertical" tooltip="@.vertical" tooltip_dir="left" />
</buttonset> </buttonset>
</hbox> </hbox>
<hbox> <hbox>
<buttonset id="outline_matrix" columns="3"> <buttonset id="outline_matrix" columns="3">
<item icon="outline_empty_pixel" style="outline_cell" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" style="outline_cell" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" style="outline_cell" /> <item icon="outline_empty_pixel" style="outline_cell" />
@ -29,14 +29,14 @@
<item icon="outline_empty_pixel" style="outline_cell" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" style="outline_cell" /> <item icon="outline_empty_pixel" style="outline_cell" />
<item icon="outline_empty_pixel" style="outline_cell" /> <item icon="outline_empty_pixel" style="outline_cell" />
</buttonset> </buttonset>
</hbox> </hbox>
</vbox> </vbox>
<vbox> <vbox>
<buttonset id="place" columns="1"> <buttonset id="place" columns="1">
<item text="@.outside" /> <item text="@.outside" />
<item text="@.inside" /> <item text="@.inside" />
</buttonset> </buttonset>
</vbox> </vbox>
</hbox> </hbox>
</vbox> </vbox>

View File

@ -1,29 +1,29 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (c) 2020 Igara Studio S.A. --> <!-- Copyright (c) 2020 Igara Studio S.A. -->
<!-- Copyright (c) 2015-2018 David Capello --> <!-- Copyright (c) 2015-2018 David Capello -->
<gui> <gui>
<window id="palette_from_sprite" text="@.title"> <window id="palette_from_sprite" text="@.title">
<grid columns="2"> <grid columns="2">
<radio id="new_palette" text="@.new_palette" group="1" /> <radio id="new_palette" text="@.new_palette" group="1" />
<expr expansive="true" id="ncolors" magnet="true" /> <expr expansive="true" id="ncolors" magnet="true" />
<radio id="current_palette" text="@.replace_palette" group="1" cell_hspan="2" /> <radio id="current_palette" text="@.replace_palette" group="1" cell_hspan="2" />
<radio id="current_range" text="@.replace_range" group="1" cell_hspan="2" /> <radio id="current_range" text="@.replace_range" group="1" cell_hspan="2" />
<separator horizontal="true" cell_hspan="2" /> <separator horizontal="true" cell_hspan="2" />
<check id="alpha_channel" text="@.alpha_channel" cell_hspan="2" /> <check id="alpha_channel" text="@.alpha_channel" cell_hspan="2" />
<check id="advanced_check" text="@general.advanced_options" cell_hspan="2" /> <check id="advanced_check" text="@general.advanced_options" cell_hspan="2" />
<hbox id="advanced" cell_hspan="2"> <hbox id="advanced" cell_hspan="2">
<label text="@rgbmap_algorithm_selector.label" /> <label text="@rgbmap_algorithm_selector.label" />
<hbox id="rgbmap_algorithm_placeholder" /> <hbox id="rgbmap_algorithm_placeholder" />
</hbox> </hbox>
<separator horizontal="true" cell_hspan="2" /> <separator horizontal="true" cell_hspan="2" />
<box horizontal="true" homogeneous="true" cell_hspan="2" cell_align="right"> <box horizontal="true" homogeneous="true" cell_hspan="2" cell_align="right">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</box> </box>
</grid> </grid>
</window> </window>
</gui> </gui>

View File

@ -1,17 +1,17 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2024 by Igara Studio S.A. --> <!-- Copyright (C) 2024 by Igara Studio S.A. -->
<!-- Copyright (C) 2014-2017 by David Capello --> <!-- Copyright (C) 2014-2017 by David Capello -->
<gui> <gui>
<vbox id="palette_popup"> <vbox id="palette_popup">
<hbox> <hbox>
<search id="search" magnet="true" expansive="true" /> <search id="search" magnet="true" expansive="true" />
<button text="" id="refresh" style="refresh_button" /> <button text="" id="refresh" style="refresh_button" />
</hbox> </hbox>
<view id="view" expansive="true" /> <view id="view" expansive="true" />
<hbox> <hbox>
<button id="load_pal" text="@.load" minwidth="80" magnet="true" /> <button id="load_pal" text="@.load" minwidth="80" magnet="true" />
<hbox expansive="true" /> <hbox expansive="true" />
<button id="open_folder" text="@.open_folder" minwidth="60" /> <button id="open_folder" text="@.open_folder" minwidth="60" />
</hbox> </hbox>
</vbox> </vbox>
</gui> </gui>

View File

@ -1,18 +1,18 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2015-2018 by David Capello --> <!-- Copyright (C) 2015-2018 by David Capello -->
<gui> <gui>
<window id="palette_size" text="@.title"> <window id="palette_size" text="@.title">
<grid columns="3"> <grid columns="3">
<label text="@.number_of_colors" /> <label text="@.number_of_colors" />
<expr expansive="true" id="colors" magnet="true" /> <expr expansive="true" id="colors" magnet="true" />
<box cell_align="horizontal" /> <box cell_align="horizontal" />
<separator horizontal="true" cell_hspan="3" /> <separator horizontal="true" cell_hspan="3" />
<box horizontal="true" homogeneous="true" cell_hspan="3" cell_align="right"> <box horizontal="true" homogeneous="true" cell_hspan="3" cell_align="right">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" /> <button text="@general.cancel" closewindow="true" />
</box> </box>
</grid> </grid>
</window> </window>
</gui> </gui>

View File

@ -1,17 +1,17 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2019 by Igara Studio S.A. --> <!-- Copyright (C) 2019 by Igara Studio S.A. -->
<!-- Copyright (C) 2001-2016 by David Capello --> <!-- Copyright (C) 2001-2016 by David Capello -->
<gui> <gui>
<vbox expansive="true" id="controls"> <vbox expansive="true" id="controls">
<hbox expansive="true"> <hbox expansive="true">
<grid columns="2" id="controls"> <grid columns="2" id="controls">
<label text="@replace_color.from" /> <label text="@replace_color.from" />
<colorpicker id="from" cell_align="horizontal" /> <colorpicker id="from" cell_align="horizontal" />
<label text="@replace_color.to" /> <label text="@replace_color.to" />
<colorpicker id="to" cell_align="horizontal" /> <colorpicker id="to" cell_align="horizontal" />
</grid> </grid>
</hbox> </hbox>
<label text="@replace_color.tolerance" /> <label text="@replace_color.tolerance" />
<slider min="0" max="255" id="tolerance" /> <slider min="0" max="255" id="tolerance" />
</vbox> </vbox>
</gui> </gui>

View File

@ -1,38 +1,38 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2001-2016 by David Capello --> <!-- Copyright (C) 2001-2016 by David Capello -->
<gui> <gui>
<window id="select_accelerator" text="@.title"> <window id="select_accelerator" text="@.title">
<vbox expansive="true"> <vbox expansive="true">
<grid columns="3"> <grid columns="3">
<label text="@.key" /> <label text="@.key" />
<hbox id="key_placeholder" cell_align="horizontal" /> <hbox id="key_placeholder" cell_align="horizontal" />
<button text="@.clear" id="clear_button" minwidth="60" /> <button text="@.clear" id="clear_button" minwidth="60" />
<label text="@.modifiers" /> <label text="@.modifiers" />
<hbox cell_hspan="2" cell_align="horizontal"> <hbox cell_hspan="2" cell_align="horizontal">
<check text="@.ctrl" id="ctrl" /> <check text="@.ctrl" id="ctrl" />
<check text="@.cmd" id="cmd" /> <check text="@.cmd" id="cmd" />
<check text="@.alt" id="alt" /> <check text="@.alt" id="alt" />
<check text="@.shift" id="shift" /> <check text="@.shift" id="shift" />
<check text="@.space" id="space" /> <check text="@.space" id="space" />
<check text="@.win" id="win" /> <check text="@.win" id="win" />
</hbox> </hbox>
<label text="@.assigned_to" /> <label text="@.assigned_to" />
<label text="" id="assigned_to" cell_hspan="2" /> <label text="" id="assigned_to" cell_hspan="2" />
</grid> </grid>
<boxfiller /> <boxfiller />
<separator horizontal="true" /> <separator horizontal="true" />
<box horizontal="true"> <box horizontal="true">
<boxfiller /> <boxfiller />
<box horizontal="true" homogeneous="true"> <box horizontal="true" homogeneous="true">
<button text="@.ok" id="ok_button" magnet="true" minwidth="60" /> <button text="@.ok" id="ok_button" magnet="true" minwidth="60" />
<button text="@.cancel" id="cancel_button" /> <button text="@.cancel" id="cancel_button" />
</box> </box>
</box> </box>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,27 +1,27 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2014-2016 by David Capello --> <!-- Copyright (C) 2014-2016 by David Capello -->
<gui> <gui>
<window id="send_crash" text="@.title"> <window id="send_crash" text="@.title">
<vbox> <vbox>
<vbox id="official"> <vbox id="official">
<label text="@.send_file" /> <label text="@.send_file" />
<link id="filename" text="" url="" /> <link id="filename" text="" url="" />
<label text="@.to_email" /> <label text="@.to_email" />
<entry readonly="true" text="support@aseprite.org" maxsize="256" /> <entry readonly="true" text="support@aseprite.org" maxsize="256" />
<label text="@.explaining" /> <label text="@.explaining" />
</vbox> </vbox>
<vbox id="dev"> <vbox id="dev">
<label text="@.using_dev_ver" /> <label text="@.using_dev_ver" />
<label text="@.open_dmp_file" /> <label text="@.open_dmp_file" />
<link id="dev_filename" text="" url="" /> <link id="dev_filename" text="" url="" />
</vbox> </vbox>
<separator horizontal="true" /> <separator horizontal="true" />
<button text="@.do_it_later" closewindow="true" /> <button text="@.do_it_later" closewindow="true" />
<button text="@.delete_file" closewindow="true" id="delete_file" /> <button text="@.delete_file" closewindow="true" id="delete_file" />
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -1,64 +1,64 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2018-2024 Igara Studio S.A. --> <!-- Copyright (C) 2018-2024 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2016 David Capello --> <!-- Copyright (C) 2001-2016 David Capello -->
<gui> <gui>
<window id="sprite_properties" text="@.title" help="sprite-properties"> <window id="sprite_properties" text="@.title" help="sprite-properties">
<vbox> <vbox>
<grid id="properties_grid" columns="3"> <grid id="properties_grid" columns="3">
<label text="@.filename" /> <label text="@.filename" />
<entry text="" id="name" maxsize="256" minwidth="64" readonly="true" cell_align="horizontal" /> <entry text="" id="name" maxsize="256" minwidth="64" readonly="true" cell_align="horizontal" />
<button id="user_data" icon="icon_user_data" maxsize="32" tooltip="@general.user_data" /> <button id="user_data" icon="icon_user_data" maxsize="32" tooltip="@general.user_data" />
<label text="@.type" /> <label text="@.type" />
<label text="" id="type" cell_hspan="2" /> <label text="" id="type" cell_hspan="2" />
<label text="@.size" /> <label text="@.size" />
<label text="" id="size" cell_hspan="2" /> <label text="" id="size" cell_hspan="2" />
<label text="@.frames" /> <label text="@.frames" />
<label text="" id="frames" cell_hspan="2" /> <label text="" id="frames" cell_hspan="2" />
</grid> </grid>
<grid columns="2"> <grid columns="2">
<separator text="@.advanced" horizontal="true" cell_hspan="2" /> <separator text="@.advanced" horizontal="true" cell_hspan="2" />
<label text="@.transparent_color" /> <label text="@.transparent_color" />
<hbox> <hbox>
<hbox id="transparent_color_placeholder" /> <hbox id="transparent_color_placeholder" />
</hbox> </hbox>
<label text="@.pixel_ratio" /> <label text="@.pixel_ratio" />
<combobox id="pixel_ratio" cell_align="horizontal"> <combobox id="pixel_ratio" cell_align="horizontal">
<listitem text="@.square_pixels" value="1:1" /> <listitem text="@.square_pixels" value="1:1" />
<listitem text="@.double_wide" value="2:1" /> <listitem text="@.double_wide" value="2:1" />
<listitem text="@.double_high" value="1:2" /> <listitem text="@.double_high" value="1:2" />
</combobox> </combobox>
<label text="@.color_profile" /> <label text="@.color_profile" />
<hbox> <hbox>
<combobox id="color_profile" cell_align="horizontal" expansive="true" /> <combobox id="color_profile" cell_align="horizontal" expansive="true" />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button id="assign_color_profile" text="@.assign" /> <button id="assign_color_profile" text="@.assign" />
<button id="convert_color_profile" text="@.convert" /> <button id="convert_color_profile" text="@.convert" />
</hbox> </hbox>
</hbox> </hbox>
</grid> </grid>
<vbox expansive="true" id="tilesets_placeholder"> <vbox expansive="true" id="tilesets_placeholder">
<separator text="@.tilesets" horizontal="true" /> <separator text="@.tilesets" horizontal="true" />
<view id="tilesets_view" expansive="true"> <view id="tilesets_view" expansive="true">
<listbox id="tilesets"></listbox> <listbox id="tilesets"></listbox>
</view> </view>
</vbox> </vbox>
<separator horizontal="true" /> <separator horizontal="true" />
<hbox> <hbox>
<boxfiller /> <boxfiller />
<hbox homogeneous="true"> <hbox homogeneous="true">
<button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" /> <button text="@general.ok" closewindow="true" id="ok" magnet="true" minwidth="60" />
<button text="@general.cancel" closewindow="true" id="cancel" /> <button text="@general.cancel" closewindow="true" id="cancel" />
</hbox> </hbox>
</hbox> </hbox>
</vbox> </vbox>
</window> </window>
</gui> </gui>

View File

@ -28,9 +28,9 @@
</box> </box>
<box vertical="true" homogeneous="true" expansive="true"> <box vertical="true" homogeneous="true" expansive="true">
<expr expansive="true" text="100" suffix="%" id="width_perc" magnet="true" tooltip="@.width_perc_tooltip" <expr expansive="true" text="100" suffix="%" id="width_perc" magnet="true" tooltip="@.width_perc_tooltip"
decimals="4" /> decimals="4" />
<expr expansive="true" text="100" suffix="%" id="height_perc" tooltip="@.height_perc_tooltip" <expr expansive="true" text="100" suffix="%" id="height_perc" tooltip="@.height_perc_tooltip"
decimals="4" /> decimals="4" />
</box> </box>
<box horizontal="true" width="64" /> <box horizontal="true" width="64" />
</box> </box>

View File

@ -1,59 +1,59 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2014-2018 by David Capello --> <!-- Copyright (C) 2014-2018 by David Capello -->
<gui> <gui>
<vbox id="timeline_conf"> <vbox id="timeline_conf">
<hbox> <hbox>
<vbox> <vbox>
<separator cell_hspan="2" text="@.position" left="true" horizontal="true" /> <separator cell_hspan="2" text="@.position" left="true" horizontal="true" />
<hbox> <hbox>
<buttonset columns="2" id="position"> <buttonset columns="2" id="position">
<item text="@.left" /> <item text="@.left" />
<item text="@.right" /> <item text="@.right" />
<item text="@.bottom" hspan="2" /> <item text="@.bottom" hspan="2" />
</buttonset> </buttonset>
</hbox> </hbox>
</vbox> </vbox>
<vbox> <vbox>
<separator text="@.frame_header" left="true" horizontal="true" /> <separator text="@.frame_header" left="true" horizontal="true" />
<hbox> <hbox>
<label text="@.first_frame" /> <label text="@.first_frame" />
<expr id="first_frame" /> <expr id="first_frame" />
</hbox> </hbox>
<hbox> <hbox>
<check id="thumb_enabled" text="@.thumbnails" horizontal="true" /> <check id="thumb_enabled" text="@.thumbnails" horizontal="true" />
<separator id="thumb_h_separator" horizontal="true" expansive="true" /> <separator id="thumb_h_separator" horizontal="true" expansive="true" />
</hbox> </hbox>
<grid columns="2" id="thumb_box"> <grid columns="2" id="thumb_box">
<label text="@.thumbnail_size" /> <label text="@.thumbnail_size" />
<slider min="1" max="10" id="zoom" cell_align="horizontal" width="128" /> <slider min="1" max="10" id="zoom" cell_align="horizontal" width="128" />
<check id="thumb_overlay_enabled" text="@.overlay_size"/> <check id="thumb_overlay_enabled" text="@.overlay_size"/>
<slider min="2" max="10" id="thumb_overlay_size" cell_align="horizontal" width="128" /> <slider min="2" max="10" id="thumb_overlay_size" cell_align="horizontal" width="128" />
</grid> </grid>
</vbox> </vbox>
</hbox> </hbox>
<separator text="@.onion_skin" left="true" horizontal="true" /> <separator text="@.onion_skin" left="true" horizontal="true" />
<grid columns="2"> <grid columns="2">
<hbox cell_hspan="2"> <hbox cell_hspan="2">
<radio group="1" text="@.merge_frames" id="merge" /> <radio group="1" text="@.merge_frames" id="merge" />
<radio group="1" text="@.red_blue_tint" id="tint" /> <radio group="1" text="@.red_blue_tint" id="tint" />
<button id="reset_onionskin" text="@.reset" minwidth="60" /> <button id="reset_onionskin" text="@.reset" minwidth="60" />
</hbox> </hbox>
<label text="@.opacity" /> <label text="@.opacity" />
<opacityslider id="opacity" cell_align="horizontal" width="128" /> <opacityslider id="opacity" cell_align="horizontal" width="128" />
<label text="@.opacity_step" /> <label text="@.opacity_step" />
<opacityslider id="opacity_step" cell_align="horizontal" width="128" /> <opacityslider id="opacity_step" cell_align="horizontal" width="128" />
<check id="loop_tag" text="@.loop_tags" cell_hspan="2" /> <check id="loop_tag" text="@.loop_tags" cell_hspan="2" />
<check id="current_layer" text="@.current_layer" cell_hspan="2" /> <check id="current_layer" text="@.current_layer" cell_hspan="2" />
<hbox cell_hspan="2"> <hbox cell_hspan="2">
<radio group="2" text="@.behind_sprite" id="behind" tooltip="@.behind_sprite_toolip" tooltip_dir="top" /> <radio group="2" text="@.behind_sprite" id="behind" tooltip="@.behind_sprite_toolip" tooltip_dir="top" />
<radio group="2" text="@.in_front" id="infront" tooltip="@.in_front_toolip" /> <radio group="2" text="@.in_front" id="infront" tooltip="@.in_front_toolip" />
</hbox> </hbox>
</grid> </grid>
</vbox> </vbox>
</gui> </gui>

2
laf

@ -1 +1 @@
Subproject commit 226a22bee53e888aff8d5df524edc31c19d9c29e Subproject commit 20d13cf0c762189650c7860bd3302a0a66cfa346

View File

@ -1,99 +1,99 @@
# Aseprite Source Code # Aseprite Source Code
If you are here is because you want to learn about Aseprite source If you are here is because you want to learn about Aseprite source
code. We'll try to write in these `README.md` files a summary of each code. We'll try to write in these `README.md` files a summary of each
module/library. module/library.
# Modules & Libraries # Modules & Libraries
Aseprite is separated in the following layers/modules: Aseprite is separated in the following layers/modules:
## Level 0: Completely independent modules ## Level 0: Completely independent modules
These libraries are easy to be used and embedded in other software These libraries are easy to be used and embedded in other software
because they don't depend on any other component. because they don't depend on any other component.
* [clip](https://github.com/aseprite/clip): Clipboard library. * [clip](https://github.com/aseprite/clip): Clipboard library.
* [fixmath](fixmath/): Fixed point operations (original code from Allegro code by Shawn Hargreaves). * [fixmath](fixmath/): Fixed point operations (original code from Allegro code by Shawn Hargreaves).
* [flic](https://github.com/aseprite/flic): Library to load/save FLI/FLC files. * [flic](https://github.com/aseprite/flic): Library to load/save FLI/FLC files.
* laf/[base](https://github.com/aseprite/laf/tree/main/base): Core/basic stuff, multithreading, utf8, sha1, file system, memory, etc. * laf/[base](https://github.com/aseprite/laf/tree/main/base): Core/basic stuff, multithreading, utf8, sha1, file system, memory, etc.
* laf/[gfx](https://github.com/aseprite/laf/tree/main/gfx): Abstract graphics structures like point, size, rectangle, region, color, etc. * laf/[gfx](https://github.com/aseprite/laf/tree/main/gfx): Abstract graphics structures like point, size, rectangle, region, color, etc.
* [observable](https://github.com/aseprite/observable): Signal/slot functions. * [observable](https://github.com/aseprite/observable): Signal/slot functions.
* [scripting](scripting/): JavaScript engine. * [scripting](scripting/): JavaScript engine.
* [steam](steam/): Steam API wrapper to avoid static linking to the .lib file. * [steam](steam/): Steam API wrapper to avoid static linking to the .lib file.
* [undo](https://github.com/aseprite/undo): Generic library to manage a history of undoable commands. * [undo](https://github.com/aseprite/undo): Generic library to manage a history of undoable commands.
## Level 1 ## Level 1
* [cfg](cfg/) (base): Library to load/save .ini files. * [cfg](cfg/) (base): Library to load/save .ini files.
* [gen](gen/) (base): Helper utility to generate C++ files from different XMLs. * [gen](gen/) (base): Helper utility to generate C++ files from different XMLs.
* [net](net/) (base): Networking library to send HTTP requests. * [net](net/) (base): Networking library to send HTTP requests.
* laf/[os](https://github.com/aseprite/laf/tree/main/os) (base, gfx, wacom): OS input/output. * laf/[os](https://github.com/aseprite/laf/tree/main/os) (base, gfx, wacom): OS input/output.
## Level 2 ## Level 2
* [doc](doc/) (base, fixmath, gfx): Document model library. * [doc](doc/) (base, fixmath, gfx): Document model library.
* [ui](ui/) (base, gfx, os): Portable UI library (buttons, windows, text fields, etc.) * [ui](ui/) (base, gfx, os): Portable UI library (buttons, windows, text fields, etc.)
* [updater](updater/) (base, cfg, net): Component to check for updates. * [updater](updater/) (base, cfg, net): Component to check for updates.
## Level 3 ## Level 3
* [dio](dio/) (base, doc, fixmath, flic): Load/save sprites/documents. * [dio](dio/) (base, doc, fixmath, flic): Load/save sprites/documents.
* [filters](filters/) (base, doc, gfx): Effects for images. * [filters](filters/) (base, doc, gfx): Effects for images.
* [render](render/) (base, doc, gfx): Library to render documents. * [render](render/) (base, doc, gfx): Library to render documents.
* [view](view/) (base, doc): Abstract timeline/range view/helpers. * [view](view/) (base, doc): Abstract timeline/range view/helpers.
## Level 4 ## Level 4
* [app](app/) (base, doc, dio, filters, fixmath, flic, gfx, pen, render, scripting, os, ui, undo, updater, view) * [app](app/) (base, doc, dio, filters, fixmath, flic, gfx, pen, render, scripting, os, ui, undo, updater, view)
* [desktop](desktop/) (base, doc, dio, render): Integration with the desktop (Windows Explorer, Finder, GNOME, KDE, etc.) * [desktop](desktop/) (base, doc, dio, render): Integration with the desktop (Windows Explorer, Finder, GNOME, KDE, etc.)
## Level 5 ## Level 5
* [main](main/) (app, base, os, ui) * [main](main/) (app, base, os, ui)
# Debugging Tricks # Debugging Tricks
When Aseprite is compiled with `ENABLE_DEVMODE`, you have the When Aseprite is compiled with `ENABLE_DEVMODE`, you have the
following extra commands/features available: following extra commands/features available:
* `F5`: On Windows shows the amount of used memory. * `F5`: On Windows shows the amount of used memory.
* `F1`: Switch between new/old/shader renderers. * `F1`: Switch between new/old/shader renderers.
* `Ctrl+F1`: Switch/test Screen/UI Scaling values. * `Ctrl+F1`: Switch/test Screen/UI Scaling values.
* `Ctrl+Alt+Shift+Q`: crashes the application in case that you want to * `Ctrl+Alt+Shift+Q`: crashes the application in case that you want to
test the anticrash feature or your need a memory dump file. test the anticrash feature or your need a memory dump file.
* `Ctrl+Alt+Shift+R`: recover the active document from the data * `Ctrl+Alt+Shift+R`: recover the active document from the data
recovery store. recovery store.
* `aseprite.ini`: `[perf] show_render_time=true` shows a performance * `aseprite.ini`: `[perf] show_render_time=true` shows a performance
clock in the Editor. clock in the Editor.
In Debug mode (`_DEBUG`): In Debug mode (`_DEBUG`):
* [`TRACEARGS`](https://github.com/aseprite/laf/blob/f3222bdee2d21556e9da55343e73803c730ecd97/base/debug.h#L40): * [`TRACEARGS`](https://github.com/aseprite/laf/blob/f3222bdee2d21556e9da55343e73803c730ecd97/base/debug.h#L40):
in debug mode, it prints in the terminal/console each given argument in debug mode, it prints in the terminal/console each given argument
# Detect Platform # Detect Platform
You can check the platform using some `laf` macros: You can check the platform using some `laf` macros:
#if LAF_WINDOWS #if LAF_WINDOWS
// ... // ...
#elif LAF_MACOS #elif LAF_MACOS
// ... // ...
#elif LAF_LINUX #elif LAF_LINUX
// ... // ...
#endif #endif
Or using platform-specific macros: Or using platform-specific macros:
#ifdef _WIN32 #ifdef _WIN32
#ifdef _WIN64 #ifdef _WIN64
// Windows x64 // Windows x64
#else #else
// Windows x86 // Windows x86
#endif #endif
#elif defined(__APPLE__) #elif defined(__APPLE__)
// macOS // macOS
#else #else
// Linux // Linux
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/active_site_handler.h" #include "app/active_site_handler.h"
@ -29,7 +29,7 @@ void ActiveSiteHandler::addDoc(Doc* doc)
{ {
Data data; Data data;
data.layer = doc::NullId; data.layer = doc::NullId;
if (doc->sprite()) { // The sprite can be nullptr in some tests if (doc->sprite()) { // The sprite can be nullptr in some tests
if (doc::Layer* layer = doc->sprite()->root()->firstLayer()) if (doc::Layer* layer = doc->sprite()->root()->firstLayer())
data.layer = layer->id(); data.layer = layer->id();
} }
@ -74,7 +74,7 @@ void ActiveSiteHandler::getActiveSiteForDoc(Doc* doc, Site* site)
void ActiveSiteHandler::setActiveLayerInDoc(Doc* doc, doc::Layer* layer) void ActiveSiteHandler::setActiveLayerInDoc(Doc* doc, doc::Layer* layer)
{ {
Data& data = getData(doc); Data& data = getData(doc);
data.layer = (layer ? layer->id(): 0); data.layer = (layer ? layer->id() : 0);
} }
void ActiveSiteHandler::setActiveFrameInDoc(Doc* doc, doc::frame_t frame) void ActiveSiteHandler::setActiveFrameInDoc(Doc* doc, doc::frame_t frame)
@ -133,9 +133,8 @@ void ActiveSiteHandler::onAddFrame(DocEvent& ev)
void ActiveSiteHandler::onBeforeRemoveLayer(DocEvent& ev) void ActiveSiteHandler::onBeforeRemoveLayer(DocEvent& ev)
{ {
Data& data = getData(ev.document()); Data& data = getData(ev.document());
doc::Layer* selectedLayer = (data.layer != doc::NullId ? doc::Layer* selectedLayer = (data.layer != doc::NullId ? doc::get<doc::Layer>(data.layer) :
doc::get<doc::Layer>(data.layer): nullptr);
nullptr);
if (!selectedLayer) if (!selectedLayer)
return; return;
@ -143,11 +142,9 @@ void ActiveSiteHandler::onBeforeRemoveLayer(DocEvent& ev)
data.range.eraseAndAdjust(ev.layer()); data.range.eraseAndAdjust(ev.layer());
// Select other layer as active // Select other layer as active
doc::Layer* layerToSelect = doc::Layer* layerToSelect = view::candidate_if_layer_is_deleted(selectedLayer, ev.layer());
view::candidate_if_layer_is_deleted(selectedLayer, ev.layer());
if (selectedLayer != layerToSelect) { if (selectedLayer != layerToSelect) {
data.layer = (layerToSelect ? layerToSelect->id(): data.layer = (layerToSelect ? layerToSelect->id() : doc::NullId);
doc::NullId);
} }
} }

View File

@ -17,53 +17,53 @@
#include <map> #include <map>
namespace doc { namespace doc {
class Layer; class Layer;
} }
namespace app { namespace app {
class Doc; class Doc;
class Site; class Site;
// Pseudo-DocViews to handle active layer/frame in a non-UI context // Pseudo-DocViews to handle active layer/frame in a non-UI context
// per Doc. // per Doc.
// //
// TODO we could move code to handle active frame/layer from // TODO we could move code to handle active frame/layer from
// Timeline to this class. // Timeline to this class.
class ActiveSiteHandler : public DocObserver { class ActiveSiteHandler : public DocObserver {
public: public:
ActiveSiteHandler(); ActiveSiteHandler();
virtual ~ActiveSiteHandler(); virtual ~ActiveSiteHandler();
void addDoc(Doc* doc); void addDoc(Doc* doc);
void removeDoc(Doc* doc); void removeDoc(Doc* doc);
void getActiveSiteForDoc(Doc* doc, Site* site); void getActiveSiteForDoc(Doc* doc, Site* site);
void setActiveLayerInDoc(Doc* doc, doc::Layer* layer); void setActiveLayerInDoc(Doc* doc, doc::Layer* layer);
void setActiveFrameInDoc(Doc* doc, doc::frame_t frame); void setActiveFrameInDoc(Doc* doc, doc::frame_t frame);
void setRangeInDoc(Doc* doc, const DocRange& range); void setRangeInDoc(Doc* doc, const DocRange& range);
void setSelectedColorsInDoc(Doc* doc, const doc::PalettePicks& picks); void setSelectedColorsInDoc(Doc* doc, const doc::PalettePicks& picks);
void setSelectedTilesInDoc(Doc* doc, const doc::PalettePicks& picks); void setSelectedTilesInDoc(Doc* doc, const doc::PalettePicks& picks);
private: private:
// DocObserver impl // DocObserver impl
void onAddLayer(DocEvent& ev) override; void onAddLayer(DocEvent& ev) override;
void onAddFrame(DocEvent& ev) override; void onAddFrame(DocEvent& ev) override;
void onBeforeRemoveLayer(DocEvent& ev) override; void onBeforeRemoveLayer(DocEvent& ev) override;
void onRemoveFrame(DocEvent& ev) override; void onRemoveFrame(DocEvent& ev) override;
// Active data for a document // Active data for a document
struct Data { struct Data {
doc::ObjectId layer; doc::ObjectId layer;
doc::frame_t frame; doc::frame_t frame;
DocRange range; DocRange range;
doc::PalettePicks selectedColors; doc::PalettePicks selectedColors;
doc::PalettePicks selectedTiles; doc::PalettePicks selectedTiles;
};
Data& getData(Doc* doc);
std::map<Doc*, Data> m_data;
}; };
Data& getData(Doc* doc);
std::map<Doc*, Data> m_data;
};
} // namespace app } // namespace app
#endif #endif

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/app.h" #include "app/app.h"
@ -109,13 +109,10 @@ namespace {
class ConsoleEngineDelegate : public script::EngineDelegate { class ConsoleEngineDelegate : public script::EngineDelegate {
public: public:
ConsoleEngineDelegate(Console& console) : m_console(console) { } ConsoleEngineDelegate(Console& console) : m_console(console) {}
void onConsoleError(const char* text) override { void onConsoleError(const char* text) override { onConsolePrint(text); }
onConsolePrint(text); void onConsolePrint(const char* text) override { m_console.printf("%s\n", text); }
}
void onConsolePrint(const char* text) override {
m_console.printf("%s\n", text);
}
private: private:
Console& m_console; Console& m_console;
}; };
@ -149,8 +146,7 @@ public:
std::unique_ptr<app::crash::DataRecovery> m_recovery; std::unique_ptr<app::crash::DataRecovery> m_recovery;
#endif #endif
Modules(const bool createLogInDesktop, Modules(const bool createLogInDesktop, Preferences& pref)
Preferences& pref)
: m_loggerModule(createLogInDesktop) : m_loggerModule(createLogInDesktop)
, m_strings(pref, m_extensions) , m_strings(pref, m_extensions)
, m_activeToolManager(&m_toolbox) , m_activeToolManager(&m_toolbox)
@ -161,14 +157,15 @@ public:
{ {
} }
~Modules() { ~Modules()
{
#ifdef ENABLE_DATA_RECOVERY #ifdef ENABLE_DATA_RECOVERY
ASSERT(m_recovery == nullptr || ASSERT(m_recovery == nullptr || ui::get_app_state() == ui::AppState::kClosingWithException);
ui::get_app_state() == ui::AppState::kClosingWithException);
#endif #endif
} }
app::crash::DataRecovery* recovery() { app::crash::DataRecovery* recovery()
{
#ifdef ENABLE_DATA_RECOVERY #ifdef ENABLE_DATA_RECOVERY
return m_recovery.get(); return m_recovery.get();
#else #else
@ -176,36 +173,39 @@ public:
#endif #endif
} }
void createDataRecovery(Context* ctx) { void createDataRecovery(Context* ctx)
{
#ifdef ENABLE_DATA_RECOVERY #ifdef ENABLE_DATA_RECOVERY
#ifdef ENABLE_TRIAL_MODE #ifdef ENABLE_TRIAL_MODE
DRM_INVALID{ DRM_INVALID
{
return; return;
} }
#endif #endif
m_recovery = std::make_unique<app::crash::DataRecovery>(ctx); m_recovery = std::make_unique<app::crash::DataRecovery>(ctx);
m_recovery->SessionsListIsReady.connect( m_recovery->SessionsListIsReady.connect([] {
[] { ui::assert_ui_thread();
ui::assert_ui_thread(); auto app = App::instance();
auto app = App::instance(); if (app && app->mainWindow()) {
if (app && app->mainWindow()) { // Notify that the list of sessions is ready.
// Notify that the list of sessions is ready. app->mainWindow()->dataRecoverySessionsAreReady();
app->mainWindow()->dataRecoverySessionsAreReady(); }
} });
});
#endif #endif
} }
void searchDataRecoverySessions() { void searchDataRecoverySessions()
{
#ifdef ENABLE_DATA_RECOVERY #ifdef ENABLE_DATA_RECOVERY
#ifdef ENABLE_TRIAL_MODE #ifdef ENABLE_TRIAL_MODE
DRM_INVALID{ DRM_INVALID
{
return; return;
} }
#endif #endif
ASSERT(m_recovery); ASSERT(m_recovery);
if (m_recovery) if (m_recovery)
@ -213,19 +213,20 @@ public:
#endif #endif
} }
void deleteDataRecovery() { void deleteDataRecovery()
{
#ifdef ENABLE_DATA_RECOVERY #ifdef ENABLE_DATA_RECOVERY
#ifdef ENABLE_TRIAL_MODE #ifdef ENABLE_TRIAL_MODE
DRM_INVALID{ DRM_INVALID
{
return; return;
} }
#endif #endif
m_recovery.reset(); m_recovery.reset();
#endif #endif
} }
}; };
App* App::m_instance = nullptr; App* App::m_instance = nullptr;
@ -258,9 +259,8 @@ int App::initialize(const AppOptions& options)
// True if we should show a warning when running the main Aseprite // True if we should show a warning when running the main Aseprite
// executable (no test/benchmark) without args and the GUI is not // executable (no test/benchmark) without args and the GUI is not
// available. // available.
m_showCliOnlyWarning = m_showCliOnlyWarning = (startGui && base::utf8_icmp(base::get_file_title(options.exeName()),
(startGui && base::utf8_icmp(base::get_file_title(options.exeName()), get_app_name()) == 0);
get_app_name()) == 0);
#endif #endif
// Notify the scripting engine that we're going to enter to GUI // Notify the scripting engine that we're going to enter to GUI
@ -281,8 +281,7 @@ int App::initialize(const AppOptions& options)
#if LAF_WINDOWS #if LAF_WINDOWS
if (options.disableWintab() || if (options.disableWintab() || !pref.experimental.loadWintabDriver() ||
!pref.experimental.loadWintabDriver() ||
pref.tablet.api() == "pointer") { pref.tablet.api() == "pointer") {
tabletOptions.api = os::TabletAPI::WindowsPointerInput; tabletOptions.api = os::TabletAPI::WindowsPointerInput;
} }
@ -307,20 +306,15 @@ int App::initialize(const AppOptions& options)
system->setTabletOptions(tabletOptions); system->setTabletOptions(tabletOptions);
system->setAppName(get_app_name()); system->setAppName(get_app_name());
system->setAppMode(m_isGui ? os::AppMode::GUI: system->setAppMode(m_isGui ? os::AppMode::GUI : os::AppMode::CLI);
os::AppMode::CLI);
if (m_isGui) if (m_isGui)
m_uiSystem.reset(new ui::UISystem); m_uiSystem.reset(new ui::UISystem);
bool createLogInDesktop = false; bool createLogInDesktop = false;
switch (options.verboseLevel()) { switch (options.verboseLevel()) {
case AppOptions::kNoVerbose: case AppOptions::kNoVerbose: base::set_log_level(ERROR); break;
base::set_log_level(ERROR); case AppOptions::kVerbose: base::set_log_level(INFO); break;
break;
case AppOptions::kVerbose:
base::set_log_level(INFO);
break;
case AppOptions::kHighlyVerbose: case AppOptions::kHighlyVerbose:
base::set_log_level(VERBOSE); base::set_log_level(VERBOSE);
createLogInDesktop = true; createLogInDesktop = true;
@ -341,7 +335,7 @@ int App::initialize(const AppOptions& options)
// Load modules // Load modules
m_modules = std::make_unique<Modules>(createLogInDesktop, pref); m_modules = std::make_unique<Modules>(createLogInDesktop, pref);
m_legacy = std::make_unique<LegacyModules>(isGui() ? REQUIRE_INTERFACE: 0); m_legacy = std::make_unique<LegacyModules>(isGui() ? REQUIRE_INTERFACE : 0);
m_appMenus = std::make_unique<AppMenus>(recentFiles()); m_appMenus = std::make_unique<AppMenus>(recentFiles());
m_brushes = std::make_unique<AppBrushes>(); m_brushes = std::make_unique<AppBrushes>();
@ -434,47 +428,48 @@ int App::initialize(const AppOptions& options)
namespace { namespace {
struct CloseMainWindow { struct CloseMainWindow {
std::unique_ptr<MainWindow>& m_win; std::unique_ptr<MainWindow>& m_win;
CloseMainWindow(std::unique_ptr<MainWindow>& win) : m_win(win) { } CloseMainWindow(std::unique_ptr<MainWindow>& win) : m_win(win) {}
~CloseMainWindow() { m_win.reset(nullptr); } ~CloseMainWindow() { m_win.reset(nullptr); }
}; };
// Deletes all docs. // Deletes all docs.
struct DeleteAllDocs { struct DeleteAllDocs {
Context* m_ctx; Context* m_ctx;
DeleteAllDocs(Context* ctx) : m_ctx(ctx) { } DeleteAllDocs(Context* ctx) : m_ctx(ctx) {}
~DeleteAllDocs() { ~DeleteAllDocs()
std::vector<Doc*> docs; {
std::vector<Doc*> docs;
// Add all documents that were closed in the past, these docs // Add all documents that were closed in the past, these docs
// are not part of any context and they are just temporarily in // are not part of any context and they are just temporarily in
// memory just in case the user wants to recover them. // memory just in case the user wants to recover them.
for (Doc* doc : static_cast<UIContext*>(m_ctx)->getAndRemoveAllClosedDocs()) for (Doc* doc : static_cast<UIContext*>(m_ctx)->getAndRemoveAllClosedDocs())
docs.push_back(doc); docs.push_back(doc);
// Add documents that are currently opened/in tabs/in the // Add documents that are currently opened/in tabs/in the
// context. // context.
for (Doc* doc : m_ctx->documents()) for (Doc* doc : m_ctx->documents())
docs.push_back(doc); docs.push_back(doc);
for (Doc* doc : docs) { for (Doc* doc : docs) {
// First we close the document. In this way we receive recent // First we close the document. In this way we receive recent
// notifications related to the document as a app::Doc. If // notifications related to the document as a app::Doc. If
// we delete the document directly, we destroy the app::Doc // we delete the document directly, we destroy the app::Doc
// too early, and then doc::~Document() call // too early, and then doc::~Document() call
// DocsObserver::onRemoveDocument(). In this way, observers // DocsObserver::onRemoveDocument(). In this way, observers
// could think that they have a fully created app::Doc when // could think that they have a fully created app::Doc when
// in reality it's a doc::Document (in the middle of a // in reality it's a doc::Document (in the middle of a
// destruction process). // destruction process).
// //
// TODO: This problem is because we're extending doc::Document, // TODO: This problem is because we're extending doc::Document,
// in the future, we should remove app::Doc. // in the future, we should remove app::Doc.
doc->close(); doc->close();
delete doc; delete doc;
}
} }
}; }
};
} // anonymous namespace } // anonymous namespace
@ -488,9 +483,8 @@ void App::run()
auto manager = ui::Manager::getDefault(); auto manager = ui::Manager::getDefault();
#if LAF_WINDOWS #if LAF_WINDOWS
// How to interpret one finger on Windows tablets. // How to interpret one finger on Windows tablets.
manager->display()->nativeWindow() manager->display()->nativeWindow()->setInterpretOneFingerGestureAsMouseMovement(
->setInterpretOneFingerGestureAsMouseMovement( preferences().experimental.oneFingerAsMouseMovement());
preferences().experimental.oneFingerAsMouseMovement());
#if ENABLE_WEBP #if ENABLE_WEBP
// In Windows we use a custom webp decoder for drag & drop operations. // In Windows we use a custom webp decoder for drag & drop operations.
os::set_decode_webp(util::decode_webp); os::set_decode_webp(util::decode_webp);
@ -507,8 +501,7 @@ void App::run()
ResourceFinder rf; ResourceFinder rf;
rf.includeDataDir(fmt::format("icons/ase{0}.png", size).c_str()); rf.includeDataDir(fmt::format("icons/ase{0}.png", size).c_str());
if (rf.findFirst()) { if (rf.findFirst()) {
os::SurfaceRef surf = os::System::instance() os::SurfaceRef surf = os::System::instance()->loadRgbaSurface(rf.filename().c_str());
->loadRgbaSurface(rf.filename().c_str());
if (surf) { if (surf) {
surf->setImmutable(); surf->setImmutable();
icons.push_back(surf); icons.push_back(surf);
@ -549,8 +542,7 @@ void App::run()
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
// Launch the thread to check for updates. // Launch the thread to check for updates.
app::CheckUpdateThreadLauncher checkUpdate( app::CheckUpdateThreadLauncher checkUpdate(m_mainWindow->getCheckUpdateDelegate());
m_mainWindow->getCheckUpdateDelegate());
checkUpdate.launch(); checkUpdate.launch();
#endif #endif
@ -586,7 +578,7 @@ void App::run()
Shell shell; Shell shell;
shell.run(*m_engine); shell.run(*m_engine);
} }
#endif // ENABLE_SCRIPTING #endif // ENABLE_SCRIPTING
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -698,10 +690,8 @@ bool App::isPortable()
{ {
static std::optional<bool> is_portable; static std::optional<bool> is_portable;
if (!is_portable) { if (!is_portable) {
is_portable = is_portable = base::is_file(
base::is_file(base::join_path( base::join_path(base::get_file_path(base::get_app_path()), "aseprite.ini"));
base::get_file_path(base::get_app_path()),
"aseprite.ini"));
} }
return *is_portable; return *is_portable;
} }
@ -896,14 +886,20 @@ int app_get_color_to_clear_layer(Layer* layer)
} }
#ifdef ENABLE_DRM #ifdef ENABLE_DRM
void app_configure_drm() { void app_configure_drm()
{
ResourceFinder userDirRf, dataDirRf; ResourceFinder userDirRf, dataDirRf;
userDirRf.includeUserDir(""); userDirRf.includeUserDir("");
dataDirRf.includeDataDir(""); dataDirRf.includeDataDir("");
std::map<std::string, std::string> config = { std::map<std::string, std::string> config = {
{"data", dataDirRf.getFirstOrCreateDefault()} { "data", dataDirRf.getFirstOrCreateDefault() }
}; };
DRM_CONFIGURE(get_app_url(), get_app_name(), get_app_version(), userDirRf.getFirstOrCreateDefault(), updater::getUserAgent(), config); DRM_CONFIGURE(get_app_url(),
get_app_name(),
get_app_version(),
userDirRf.getFirstOrCreateDefault(),
updater::getUserAgent(),
config);
} }
#endif #endif

View File

@ -19,150 +19,151 @@
#include <vector> #include <vector>
namespace doc { namespace doc {
class Layer; class Layer;
} }
namespace ui { namespace ui {
class UISystem; class UISystem;
} }
namespace app { namespace app {
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
namespace script { namespace script {
class Engine; class Engine;
} }
#endif #endif
class AppMenus; class AppMenus;
class AppMod; class AppMod;
class AppOptions; class AppOptions;
class BackupIndicator; class BackupIndicator;
class Context; class Context;
class ContextBar; class ContextBar;
class Doc; class Doc;
class Extensions; class Extensions;
class INotificationDelegate; class INotificationDelegate;
class InputChain; class InputChain;
class LegacyModules; class LegacyModules;
class LoggerModule; class LoggerModule;
class MainWindow; class MainWindow;
class Preferences; class Preferences;
class RecentFiles; class RecentFiles;
class Timeline; class Timeline;
class Workspace; class Workspace;
namespace crash { namespace crash {
class DataRecovery; class DataRecovery;
}
namespace tools {
class ActiveToolManager;
class Tool;
class ToolBox;
} // namespace tools
using namespace doc;
class App {
public:
App(AppMod* mod = nullptr);
~App();
static App* instance() { return m_instance; }
Context* context();
// Returns true if Aseprite is running with GUI available.
bool isGui() const { return m_isGui; }
// Returns true if the application is running in portable mode.
bool isPortable();
// Runs the Aseprite application. In GUI mode it's the top-level
// window, in console/scripting it just runs the specified
// scripts.
int initialize(const AppOptions& options);
void run();
void close();
AppMod* mod() const { return m_mod; }
tools::ToolBox* toolBox() const;
tools::Tool* activeTool() const;
tools::ActiveToolManager* activeToolManager() const;
RecentFiles* recentFiles() const;
MainWindow* mainWindow() const { return m_mainWindow.get(); }
Workspace* workspace() const;
ContextBar* contextBar() const;
Timeline* timeline() const;
Preferences& preferences() const;
Extensions& extensions() const;
crash::DataRecovery* dataRecovery() const;
AppBrushes& brushes()
{
ASSERT(m_brushes.get());
return *m_brushes;
} }
namespace tools { void showNotification(INotificationDelegate* del);
class ActiveToolManager; void showBackupNotification(bool state);
class Tool; void updateDisplayTitleBar();
class ToolBox;
}
using namespace doc; InputChain& inputChain();
class App {
public:
App(AppMod* mod = nullptr);
~App();
static App* instance() { return m_instance; }
Context* context();
// Returns true if Aseprite is running with GUI available.
bool isGui() const { return m_isGui; }
// Returns true if the application is running in portable mode.
bool isPortable();
// Runs the Aseprite application. In GUI mode it's the top-level
// window, in console/scripting it just runs the specified
// scripts.
int initialize(const AppOptions& options);
void run();
void close();
AppMod* mod() const { return m_mod; }
tools::ToolBox* toolBox() const;
tools::Tool* activeTool() const;
tools::ActiveToolManager* activeToolManager() const;
RecentFiles* recentFiles() const;
MainWindow* mainWindow() const { return m_mainWindow.get(); }
Workspace* workspace() const;
ContextBar* contextBar() const;
Timeline* timeline() const;
Preferences& preferences() const;
Extensions& extensions() const;
crash::DataRecovery* dataRecovery() const;
AppBrushes& brushes() {
ASSERT(m_brushes.get());
return *m_brushes;
}
void showNotification(INotificationDelegate* del);
void showBackupNotification(bool state);
void updateDisplayTitleBar();
InputChain& inputChain();
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
script::Engine* scriptEngine() { return m_engine.get(); } script::Engine* scriptEngine() { return m_engine.get(); }
#endif #endif
const std::string& memoryDumpFilename() const { return m_memoryDumpFilename; } const std::string& memoryDumpFilename() const { return m_memoryDumpFilename; }
void memoryDumpFilename(const std::string& fn) { m_memoryDumpFilename = fn; } void memoryDumpFilename(const std::string& fn) { m_memoryDumpFilename = fn; }
// App Signals // App Signals
obs::signal<void()> Exit; obs::signal<void()> Exit;
obs::signal<void()> ExitGui; obs::signal<void()> ExitGui;
obs::signal<void()> PaletteChange; obs::signal<void()> PaletteChange;
obs::signal<void()> ColorSpaceChange; obs::signal<void()> ColorSpaceChange;
obs::signal<void()> PalettePresetsChange; obs::signal<void()> PalettePresetsChange;
private: private:
class CoreModules; class CoreModules;
class LoadLanguage; class LoadLanguage;
class Modules; class Modules;
static App* m_instance; static App* m_instance;
AppMod* m_mod; AppMod* m_mod;
std::unique_ptr<ui::UISystem> m_uiSystem; std::unique_ptr<ui::UISystem> m_uiSystem;
std::unique_ptr<CoreModules> m_coreModules; std::unique_ptr<CoreModules> m_coreModules;
std::unique_ptr<Modules> m_modules; std::unique_ptr<Modules> m_modules;
std::unique_ptr<LegacyModules> m_legacy; std::unique_ptr<LegacyModules> m_legacy;
std::unique_ptr<AppMenus> m_appMenus; std::unique_ptr<AppMenus> m_appMenus;
bool m_isGui; bool m_isGui;
bool m_isShell; bool m_isShell;
#if !LAF_SKIA #if !LAF_SKIA
bool m_showCliOnlyWarning = false; bool m_showCliOnlyWarning = false;
#endif #endif
#ifdef ENABLE_STEAM #ifdef ENABLE_STEAM
bool m_inAppSteam = true; bool m_inAppSteam = true;
#endif #endif
std::unique_ptr<MainWindow> m_mainWindow; std::unique_ptr<MainWindow> m_mainWindow;
base::paths m_files; base::paths m_files;
std::unique_ptr<AppBrushes> m_brushes; std::unique_ptr<AppBrushes> m_brushes;
std::unique_ptr<BackupIndicator> m_backupIndicator; std::unique_ptr<BackupIndicator> m_backupIndicator;
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
std::unique_ptr<script::Engine> m_engine; std::unique_ptr<script::Engine> m_engine;
#endif #endif
// Set the memory dump filename to show in the Preferences dialog // Set the memory dump filename to show in the Preferences dialog
// or the "send crash" dialog. It's set by the SendCrash class. // or the "send crash" dialog. It's set by the SendCrash class.
std::string m_memoryDumpFilename; std::string m_memoryDumpFilename;
}; };
void app_refresh_screen(); void app_refresh_screen();
void app_rebuild_documents_tabs(); void app_rebuild_documents_tabs();
PixelFormat app_get_current_pixel_format(); PixelFormat app_get_current_pixel_format();
int app_get_color_to_clear_layer(doc::Layer* layer); int app_get_color_to_clear_layer(doc::Layer* layer);
void app_configure_drm(); void app_configure_drm();
} // namespace app } // namespace app

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/app_brushes.h" #include "app/app_brushes.h"
@ -41,9 +41,8 @@ ImageRef load_xml_image(const XMLElement* imageElem)
ImageRef image; ImageRef image;
int w, h; int w, h;
if (imageElem->QueryIntAttribute("width", &w) != XML_SUCCESS || if (imageElem->QueryIntAttribute("width", &w) != XML_SUCCESS ||
imageElem->QueryIntAttribute("height", &h) != XML_SUCCESS || imageElem->QueryIntAttribute("height", &h) != XML_SUCCESS || w < 0 || w > 9999 || h < 0 ||
w < 0 || w > 9999 || h > 9999)
h < 0 || h > 9999)
return image; return image;
auto formatValue = imageElem->Attribute("format"); auto formatValue = imageElem->Attribute("format");
@ -66,10 +65,14 @@ ImageRef load_xml_image(const XMLElement* imageElem)
if ((end - it) < 4) if ((end - it) < 4)
break; break;
int r = *it; ++it; int r = *it;
int g = *it; ++it; ++it;
int b = *it; ++it; int g = *it;
int a = *it; ++it; ++it;
int b = *it;
++it;
int a = *it;
++it;
pixel = doc::rgba(r, g, b, a); pixel = doc::rgba(r, g, b, a);
} }
@ -81,8 +84,10 @@ ImageRef load_xml_image(const XMLElement* imageElem)
if ((end - it) < 2) if ((end - it) < 2)
break; break;
int v = *it; ++it; int v = *it;
int a = *it; ++it; ++it;
int a = *it;
++it;
pixel = doc::graya(v, a); pixel = doc::graya(v, a);
} }
@ -121,10 +126,10 @@ void save_xml_image(XMLElement* imageElem, const Image* image)
std::string format; std::string format;
switch (image->pixelFormat()) { switch (image->pixelFormat()) {
case IMAGE_RGB: format = "rgba"; break; case IMAGE_RGB: format = "rgba"; break;
case IMAGE_GRAYSCALE: format = "grayscale"; break; case IMAGE_GRAYSCALE: format = "grayscale"; break;
case IMAGE_INDEXED: format = "indexed"; break; case IMAGE_INDEXED: format = "indexed"; break;
case IMAGE_BITMAP: format = "bitmap"; break; // TODO add "bitmap" format case IMAGE_BITMAP: format = "bitmap"; break; // TODO add "bitmap" format
} }
ASSERT(!format.empty()); ASSERT(!format.empty());
if (!format.empty()) if (!format.empty())
@ -133,7 +138,7 @@ void save_xml_image(XMLElement* imageElem, const Image* image)
base::buffer data; base::buffer data;
data.reserve(h * image->widthBytes()); data.reserve(h * image->widthBytes());
switch (image->pixelFormat()) { switch (image->pixelFormat()) {
case IMAGE_RGB:{ case IMAGE_RGB: {
const LockImageBits<RgbTraits> pixels(image); const LockImageBits<RgbTraits> pixels(image);
for (const auto& pixel : pixels) { for (const auto& pixel : pixels) {
data.push_back(doc::rgba_getr(pixel)); data.push_back(doc::rgba_getr(pixel));
@ -143,7 +148,7 @@ void save_xml_image(XMLElement* imageElem, const Image* image)
} }
break; break;
} }
case IMAGE_GRAYSCALE:{ case IMAGE_GRAYSCALE: {
const LockImageBits<GrayscaleTraits> pixels(image); const LockImageBits<GrayscaleTraits> pixels(image);
for (const auto& pixel : pixels) { for (const auto& pixel : pixels) {
data.push_back(doc::graya_getv(pixel)); data.push_back(doc::graya_getv(pixel));
@ -173,7 +178,7 @@ void save_xml_image(XMLElement* imageElem, const Image* image)
imageElem->InsertNewText(data_base64.c_str()); imageElem->InsertNewText(data_base64.c_str());
} }
} // anonymous namespace } // anonymous namespace
AppBrushes::AppBrushes() AppBrushes::AppBrushes()
{ {
@ -187,8 +192,7 @@ AppBrushes::AppBrushes()
load(fn); load(fn);
} }
catch (const std::exception& ex) { catch (const std::exception& ex) {
LOG(ERROR, "BRSH: Error loading user brushes from '%s': %s\n", LOG(ERROR, "BRSH: Error loading user brushes from '%s': %s\n", fn.c_str(), ex.what());
fn.c_str(), ex.what());
} }
} }
m_userBrushesFilename = fn; m_userBrushesFilename = fn;
@ -202,8 +206,10 @@ AppBrushes::~AppBrushes()
} }
// We cannot throw exceptions from a destructor // We cannot throw exceptions from a destructor
catch (const std::exception& ex) { catch (const std::exception& ex) {
LOG(ERROR, "BRSH: Error saving user brushes to '%s': %s\n", LOG(ERROR,
m_userBrushesFilename.c_str(), ex.what()); "BRSH: Error saving user brushes to '%s': %s\n",
m_userBrushesFilename.c_str(),
ex.what());
} }
} }
} }
@ -211,10 +217,10 @@ AppBrushes::~AppBrushes()
AppBrushes::slot_id AppBrushes::addBrushSlot(const BrushSlot& brush) AppBrushes::slot_id AppBrushes::addBrushSlot(const BrushSlot& brush)
{ {
// Use an empty slot // Use an empty slot
for (size_t i=0; i<m_slots.size(); ++i) { for (size_t i = 0; i < m_slots.size(); ++i) {
if (!m_slots[i].locked() || m_slots[i].isEmpty()) { if (!m_slots[i].locked() || m_slots[i].isEmpty()) {
m_slots[i] = brush; m_slots[i] = brush;
return i+1; return i + 1;
} }
} }
@ -230,8 +236,7 @@ void AppBrushes::removeBrushSlot(slot_id slot)
m_slots[slot] = BrushSlot(); m_slots[slot] = BrushSlot();
// Erase empty trailing slots // Erase empty trailing slots
while (!m_slots.empty() && while (!m_slots.empty() && m_slots[m_slots.size() - 1].isEmpty())
m_slots[m_slots.size()-1].isEmpty())
m_slots.erase(--m_slots.end()); m_slots.erase(--m_slots.end());
ItemsChange(); ItemsChange();
@ -249,8 +254,7 @@ void AppBrushes::removeAllBrushSlots()
bool AppBrushes::hasBrushSlot(slot_id slot) const bool AppBrushes::hasBrushSlot(slot_id slot) const
{ {
--slot; --slot;
return (slot >= 0 && slot < (int)m_slots.size() && return (slot >= 0 && slot < (int)m_slots.size() && !m_slots[slot].isEmpty());
!m_slots[slot].isEmpty());
} }
BrushSlot AppBrushes::getBrushSlot(slot_id slot) const BrushSlot AppBrushes::getBrushSlot(slot_id slot) const
@ -274,8 +278,7 @@ void AppBrushes::setBrushSlot(slot_id slot, const BrushSlot& brush)
void AppBrushes::lockBrushSlot(slot_id slot) void AppBrushes::lockBrushSlot(slot_id slot)
{ {
--slot; --slot;
if (slot >= 0 && slot < (int)m_slots.size() && if (slot >= 0 && slot < (int)m_slots.size() && !m_slots[slot].isEmpty()) {
!m_slots[slot].isEmpty()) {
m_slots[slot].setLocked(true); m_slots[slot].setLocked(true);
} }
} }
@ -283,8 +286,7 @@ void AppBrushes::lockBrushSlot(slot_id slot)
void AppBrushes::unlockBrushSlot(slot_id slot) void AppBrushes::unlockBrushSlot(slot_id slot)
{ {
--slot; --slot;
if (slot >= 0 && slot < (int)m_slots.size() && if (slot >= 0 && slot < (int)m_slots.size() && !m_slots[slot].isEmpty()) {
!m_slots[slot].isEmpty()) {
m_slots[slot].setLocked(false); m_slots[slot].setLocked(false);
} }
} }
@ -292,26 +294,22 @@ void AppBrushes::unlockBrushSlot(slot_id slot)
bool AppBrushes::isBrushSlotLocked(slot_id slot) const bool AppBrushes::isBrushSlotLocked(slot_id slot) const
{ {
--slot; --slot;
if (slot >= 0 && slot < (int)m_slots.size() && if (slot >= 0 && slot < (int)m_slots.size() && !m_slots[slot].isEmpty()) {
!m_slots[slot].isEmpty()) {
return m_slots[slot].locked(); return m_slots[slot].locked();
} }
else else
return false; return false;
} }
static const int kBrushFlags = static const int kBrushFlags = int(BrushSlot::Flags::BrushType) | int(BrushSlot::Flags::BrushSize) |
int(BrushSlot::Flags::BrushType) | int(BrushSlot::Flags::BrushAngle);
int(BrushSlot::Flags::BrushSize) |
int(BrushSlot::Flags::BrushAngle);
void AppBrushes::load(const std::string& filename) void AppBrushes::load(const std::string& filename)
{ {
XMLDocumentRef doc = app::open_xml(filename); XMLDocumentRef doc = app::open_xml(filename);
XMLHandle handle(doc.get()); XMLHandle handle(doc.get());
XMLElement* brushElem = handle XMLElement* brushElem =
.FirstChildElement("brushes") handle.FirstChildElement("brushes").FirstChildElement("brush").ToElement();
.FirstChildElement("brush").ToElement();
while (brushElem) { while (brushElem) {
// flags // flags
@ -329,14 +327,15 @@ void AppBrushes::load(const std::string& filename)
const char* size = brushElem->Attribute("size"); const char* size = brushElem->Attribute("size");
const char* angle = brushElem->Attribute("angle"); const char* angle = brushElem->Attribute("angle");
if (type || size || angle) { if (type || size || angle) {
if (type) flags |= int(BrushSlot::Flags::BrushType); if (type)
if (size) flags |= int(BrushSlot::Flags::BrushSize); flags |= int(BrushSlot::Flags::BrushType);
if (angle) flags |= int(BrushSlot::Flags::BrushAngle); if (size)
brush.reset( flags |= int(BrushSlot::Flags::BrushSize);
new Brush( if (angle)
(type ? string_id_to_brush_type(type): kFirstBrushType), flags |= int(BrushSlot::Flags::BrushAngle);
(size ? base::convert_to<int>(std::string(size)): 1), brush.reset(new Brush((type ? string_id_to_brush_type(type) : kFirstBrushType),
(angle ? base::convert_to<int>(std::string(angle)): 0))); (size ? base::convert_to<int>(std::string(size)) : 1),
(angle ? base::convert_to<int>(std::string(angle)) : 0)));
} }
// Brush image // Brush image
@ -397,16 +396,19 @@ void AppBrushes::load(const std::string& filename)
} }
// Image color (enabled by default for backward compatibility) // Image color (enabled by default for backward compatibility)
if (!brushElem->Attribute("imagecolor") || if (!brushElem->Attribute("imagecolor") || bool_attr(brushElem, "imagecolor", false))
bool_attr(brushElem, "imagecolor", false))
flags |= int(BrushSlot::Flags::ImageColor); flags |= int(BrushSlot::Flags::ImageColor);
if (flags != 0) if (flags != 0)
flags |= int(BrushSlot::Flags::Locked); flags |= int(BrushSlot::Flags::Locked);
BrushSlot brushSlot(BrushSlot::Flags(flags), BrushSlot brushSlot(BrushSlot::Flags(flags),
brush, fgColor, bgColor, brush,
inkType, inkOpacity, shade, fgColor,
bgColor,
inkType,
inkOpacity,
shade,
pixelPerfect); pixelPerfect);
m_slots.push_back(brushSlot); m_slots.push_back(brushSlot);
@ -437,8 +439,7 @@ void AppBrushes::save(const std::string& filename) const
ASSERT(slot.brush()); ASSERT(slot.brush());
if (flags & int(BrushSlot::Flags::BrushType)) { if (flags & int(BrushSlot::Flags::BrushType)) {
brushElem->SetAttribute( brushElem->SetAttribute("type", brush_type_to_string_id(slot.brush()->type()).c_str());
"type", brush_type_to_string_id(slot.brush()->type()).c_str());
} }
if (flags & int(BrushSlot::Flags::BrushSize)) { if (flags & int(BrushSlot::Flags::BrushSize)) {
@ -449,8 +450,7 @@ void AppBrushes::save(const std::string& filename) const
brushElem->SetAttribute("angle", slot.brush()->angle()); brushElem->SetAttribute("angle", slot.brush()->angle());
} }
if (slot.brush()->type() == kImageBrushType && if (slot.brush()->type() == kImageBrushType && slot.brush()->originalImage()) {
slot.brush()->originalImage()) {
XMLElement* elem = brushElem->InsertNewChildElement("image"); XMLElement* elem = brushElem->InsertNewChildElement("image");
save_xml_image(elem, slot.brush()->originalImage()); save_xml_image(elem, slot.brush()->originalImage());
@ -460,9 +460,8 @@ void AppBrushes::save(const std::string& filename) const
} }
// Image color // Image color
brushElem->SetAttribute( brushElem->SetAttribute("imagecolor",
"imagecolor", (flags & int(BrushSlot::Flags::ImageColor)) ? "true" : "false");
(flags & int(BrushSlot::Flags::ImageColor)) ? "true": "false");
} }
} }
@ -480,8 +479,7 @@ void AppBrushes::save(const std::string& filename) const
// Ink // Ink
if (flags & int(BrushSlot::Flags::InkType)) { if (flags & int(BrushSlot::Flags::InkType)) {
XMLElement* elem = brushElem->InsertNewChildElement("inktype"); XMLElement* elem = brushElem->InsertNewChildElement("inktype");
elem->SetAttribute( elem->SetAttribute("value", app::tools::ink_type_to_string_id(slot.inkType()).c_str());
"value", app::tools::ink_type_to_string_id(slot.inkType()).c_str());
} }
if (flags & int(BrushSlot::Flags::InkOpacity)) { if (flags & int(BrushSlot::Flags::InkOpacity)) {
@ -498,7 +496,7 @@ void AppBrushes::save(const std::string& filename) const
// Pixel-perfect // Pixel-perfect
if (flags & int(BrushSlot::Flags::PixelPerfect)) { if (flags & int(BrushSlot::Flags::PixelPerfect)) {
XMLElement* elem = brushElem->InsertNewChildElement("pixelperfect"); XMLElement* elem = brushElem->InsertNewChildElement("pixelperfect");
elem->SetAttribute("value", slot.pixelPerfect() ? "true": "false"); elem->SetAttribute("value", slot.pixelPerfect() ? "true" : "false");
} }
} }
} }

View File

@ -18,41 +18,41 @@
namespace app { namespace app {
class AppBrushes { class AppBrushes {
public: public:
// Number of slot (a range from 1 to AppBrushes::size() inclusive) // Number of slot (a range from 1 to AppBrushes::size() inclusive)
typedef int slot_id; typedef int slot_id;
typedef std::vector<BrushSlot> BrushSlots; typedef std::vector<BrushSlot> BrushSlots;
AppBrushes(); AppBrushes();
~AppBrushes(); ~AppBrushes();
// Adds a new brush and returns the slot number where the brush // Adds a new brush and returns the slot number where the brush
// is now available. // is now available.
slot_id addBrushSlot(const BrushSlot& brush); slot_id addBrushSlot(const BrushSlot& brush);
void removeBrushSlot(slot_id slot); void removeBrushSlot(slot_id slot);
void removeAllBrushSlots(); void removeAllBrushSlots();
bool hasBrushSlot(slot_id slot) const; bool hasBrushSlot(slot_id slot) const;
const doc::Brushes& getStandardBrushes() { return m_standard; } const doc::Brushes& getStandardBrushes() { return m_standard; }
BrushSlot getBrushSlot(slot_id slot) const; BrushSlot getBrushSlot(slot_id slot) const;
void setBrushSlot(slot_id slot, const BrushSlot& brush); void setBrushSlot(slot_id slot, const BrushSlot& brush);
const BrushSlots& getBrushSlots() const { return m_slots; } const BrushSlots& getBrushSlots() const { return m_slots; }
void lockBrushSlot(slot_id slot); void lockBrushSlot(slot_id slot);
void unlockBrushSlot(slot_id slot); void unlockBrushSlot(slot_id slot);
bool isBrushSlotLocked(slot_id slot) const; bool isBrushSlotLocked(slot_id slot) const;
obs::signal<void()> ItemsChange; obs::signal<void()> ItemsChange;
private: private:
void load(const std::string& filename); void load(const std::string& filename);
void save(const std::string& filename) const; void save(const std::string& filename) const;
static std::string userBrushesFilename(); static std::string userBrushesFilename();
doc::Brushes m_standard; doc::Brushes m_standard;
BrushSlots m_slots; BrushSlots m_slots;
std::string m_userBrushesFilename; std::string m_userBrushesFilename;
}; };
} // namespace app } // namespace app

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/app_menus.h" #include "app/app_menus.h"
@ -37,11 +37,11 @@
#include "tinyxml2.h" #include "tinyxml2.h"
#include <algorithm>
#include <cctype> #include <cctype>
#include <cstdlib>
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <algorithm>
#include <cstdlib>
#define MENUS_TRACE(...) // TRACEARGS #define MENUS_TRACE(...) // TRACEARGS
@ -53,18 +53,18 @@ using namespace ui;
namespace { namespace {
// TODO Move this to "os" layer // TODO Move this to "os" layer
const int kUnicodeEsc = 27; const int kUnicodeEsc = 27;
const int kUnicodeEnter = '\r'; // 10 const int kUnicodeEnter = '\r'; // 10
const int kUnicodeInsert = 0xF727; // NSInsertFunctionKey const int kUnicodeInsert = 0xF727; // NSInsertFunctionKey
const int kUnicodeDel = 0xF728; // NSDeleteFunctionKey const int kUnicodeDel = 0xF728; // NSDeleteFunctionKey
const int kUnicodeHome = 0xF729; // NSHomeFunctionKey const int kUnicodeHome = 0xF729; // NSHomeFunctionKey
const int kUnicodeEnd = 0xF72B; // NSEndFunctionKey const int kUnicodeEnd = 0xF72B; // NSEndFunctionKey
const int kUnicodePageUp = 0xF72C; // NSPageUpFunctionKey const int kUnicodePageUp = 0xF72C; // NSPageUpFunctionKey
const int kUnicodePageDown = 0xF72D; // NSPageDownFunctionKey const int kUnicodePageDown = 0xF72D; // NSPageDownFunctionKey
const int kUnicodeLeft = 0xF702; // NSLeftArrowFunctionKey const int kUnicodeLeft = 0xF702; // NSLeftArrowFunctionKey
const int kUnicodeRight = 0xF703; // NSRightArrowFunctionKey const int kUnicodeRight = 0xF703; // NSRightArrowFunctionKey
const int kUnicodeUp = 0xF700; // NSUpArrowFunctionKey const int kUnicodeUp = 0xF700; // NSUpArrowFunctionKey
const int kUnicodeDown = 0xF701; // NSDownArrowFunctionKey const int kUnicodeDown = 0xF701; // NSDownArrowFunctionKey
const char* kFileRecentListGroup = "file_recent_list"; const char* kFileRecentListGroup = "file_recent_list";
@ -75,22 +75,12 @@ bool is_text_entry_shortcut(const os::Shortcut& shortcut)
const int lchr = std::tolower(chr); const int lchr = std::tolower(chr);
bool result = bool result =
((mod == os::KeyModifiers::kKeyNoneModifier || ((mod == os::KeyModifiers::kKeyNoneModifier || mod == os::KeyModifiers::kKeyShiftModifier) &&
mod == os::KeyModifiers::kKeyShiftModifier) && chr >= 32 && chr < 0xF000) ||
chr >= 32 && chr < 0xF000) ((mod == os::KeyModifiers::kKeyCmdModifier || mod == os::KeyModifiers::kKeyCtrlModifier) &&
|| (lchr == 'a' || lchr == 'c' || lchr == 'v' || lchr == 'x')) ||
((mod == os::KeyModifiers::kKeyCmdModifier || (chr == kUnicodeInsert || chr == kUnicodeDel || chr == kUnicodeHome || chr == kUnicodeEnd ||
mod == os::KeyModifiers::kKeyCtrlModifier) && chr == kUnicodeLeft || chr == kUnicodeRight || chr == kUnicodeEsc || chr == kUnicodeEnter);
(lchr == 'a' || lchr == 'c' || lchr == 'v' || lchr == 'x'))
||
(chr == kUnicodeInsert ||
chr == kUnicodeDel ||
chr == kUnicodeHome ||
chr == kUnicodeEnd ||
chr == kUnicodeLeft ||
chr == kUnicodeRight ||
chr == kUnicodeEsc ||
chr == kUnicodeEnter);
return result; return result;
} }
@ -120,8 +110,7 @@ bool can_call_global_shortcut(const AppMenuItem::Native* native)
// prefer text input, so we cannot call shortcuts without // prefer text input, so we cannot call shortcuts without
// modifiers (e.g. F or T keystrokes) to trigger a global command // modifiers (e.g. F or T keystrokes) to trigger a global command
// in a text field. // in a text field.
(focus == nullptr || (focus == nullptr || focus->type() != ui::kEntryWidget ||
focus->type() != ui::kEntryWidget ||
!is_text_entry_shortcut(native->shortcut)) && !is_text_entry_shortcut(native->shortcut)) &&
(native->keyContext == KeyContext::Any || (native->keyContext == KeyContext::Any ||
native->keyContext == KeyboardShortcuts::instance()->getCurrentKeyContext()); native->keyContext == KeyboardShortcuts::instance()->getCurrentKeyContext());
@ -132,133 +121,133 @@ bool can_call_global_shortcut(const AppMenuItem::Native* native)
int from_scancode_to_unicode(KeyScancode scancode) int from_scancode_to_unicode(KeyScancode scancode)
{ {
static int map[] = { static int map[] = {
0, // kKeyNil 0, // kKeyNil
'a', // kKeyA 'a', // kKeyA
'b', // kKeyB 'b', // kKeyB
'c', // kKeyC 'c', // kKeyC
'd', // kKeyD 'd', // kKeyD
'e', // kKeyE 'e', // kKeyE
'f', // kKeyF 'f', // kKeyF
'g', // kKeyG 'g', // kKeyG
'h', // kKeyH 'h', // kKeyH
'i', // kKeyI 'i', // kKeyI
'j', // kKeyJ 'j', // kKeyJ
'k', // kKeyK 'k', // kKeyK
'l', // kKeyL 'l', // kKeyL
'm', // kKeyM 'm', // kKeyM
'n', // kKeyN 'n', // kKeyN
'o', // kKeyO 'o', // kKeyO
'p', // kKeyP 'p', // kKeyP
'q', // kKeyQ 'q', // kKeyQ
'r', // kKeyR 'r', // kKeyR
's', // kKeyS 's', // kKeyS
't', // kKeyT 't', // kKeyT
'u', // kKeyU 'u', // kKeyU
'v', // kKeyV 'v', // kKeyV
'w', // kKeyW 'w', // kKeyW
'x', // kKeyX 'x', // kKeyX
'y', // kKeyY 'y', // kKeyY
'z', // kKeyZ 'z', // kKeyZ
'0', // kKey0 '0', // kKey0
'1', // kKey1 '1', // kKey1
'2', // kKey2 '2', // kKey2
'3', // kKey3 '3', // kKey3
'4', // kKey4 '4', // kKey4
'5', // kKey5 '5', // kKey5
'6', // kKey6 '6', // kKey6
'7', // kKey7 '7', // kKey7
'8', // kKey8 '8', // kKey8
'9', // kKey9 '9', // kKey9
0, // kKey0Pad 0, // kKey0Pad
0, // kKey1Pad 0, // kKey1Pad
0, // kKey2Pad 0, // kKey2Pad
0, // kKey3Pad 0, // kKey3Pad
0, // kKey4Pad 0, // kKey4Pad
0, // kKey5Pad 0, // kKey5Pad
0, // kKey6Pad 0, // kKey6Pad
0, // kKey7Pad 0, // kKey7Pad
0, // kKey8Pad 0, // kKey8Pad
0, // kKey9Pad 0, // kKey9Pad
0xF704, // kKeyF1 (NSF1FunctionKey) 0xF704, // kKeyF1 (NSF1FunctionKey)
0xF705, // kKeyF2 0xF705, // kKeyF2
0xF706, // kKeyF3 0xF706, // kKeyF3
0xF707, // kKeyF4 0xF707, // kKeyF4
0xF708, // kKeyF5 0xF708, // kKeyF5
0xF709, // kKeyF6 0xF709, // kKeyF6
0xF70A, // kKeyF7 0xF70A, // kKeyF7
0xF70B, // kKeyF8 0xF70B, // kKeyF8
0xF70C, // kKeyF9 0xF70C, // kKeyF9
0xF70D, // kKeyF10 0xF70D, // kKeyF10
0xF70E, // kKeyF11 0xF70E, // kKeyF11
0xF70F, // kKeyF12 0xF70F, // kKeyF12
kUnicodeEsc, // kKeyEsc kUnicodeEsc, // kKeyEsc
'~', // kKeyTilde '~', // kKeyTilde
'-', // kKeyMinus '-', // kKeyMinus
'=', // kKeyEquals '=', // kKeyEquals
8, // kKeyBackspace 8, // kKeyBackspace
9, // kKeyTab 9, // kKeyTab
'[', // kKeyOpenbrace '[', // kKeyOpenbrace
']', // kKeyClosebrace ']', // kKeyClosebrace
kUnicodeEnter, // kKeyEnter kUnicodeEnter, // kKeyEnter
':', // kKeyColon ':', // kKeyColon
'\'', // kKeyQuote '\'', // kKeyQuote
'\\', // kKeyBackslash '\\', // kKeyBackslash
0, // kKeyBackslash2 0, // kKeyBackslash2
',', // kKeyComma ',', // kKeyComma
'.', // kKeyStop '.', // kKeyStop
'/', // kKeySlash '/', // kKeySlash
' ', // kKeySpace ' ', // kKeySpace
kUnicodeInsert, // kKeyInsert (NSInsertFunctionKey) kUnicodeInsert, // kKeyInsert (NSInsertFunctionKey)
kUnicodeDel, // kKeyDel (NSDeleteFunctionKey) kUnicodeDel, // kKeyDel (NSDeleteFunctionKey)
kUnicodeHome, // kKeyHome (NSHomeFunctionKey) kUnicodeHome, // kKeyHome (NSHomeFunctionKey)
kUnicodeEnd, // kKeyEnd (NSEndFunctionKey) kUnicodeEnd, // kKeyEnd (NSEndFunctionKey)
kUnicodePageUp, // kKeyPageUp (NSPageUpFunctionKey) kUnicodePageUp, // kKeyPageUp (NSPageUpFunctionKey)
kUnicodePageDown, // kKeyPageDown (NSPageDownFunctionKey) kUnicodePageDown, // kKeyPageDown (NSPageDownFunctionKey)
kUnicodeLeft, // kKeyLeft (NSLeftArrowFunctionKey) kUnicodeLeft, // kKeyLeft (NSLeftArrowFunctionKey)
kUnicodeRight, // kKeyRight (NSRightArrowFunctionKey) kUnicodeRight, // kKeyRight (NSRightArrowFunctionKey)
kUnicodeUp, // kKeyUp (NSUpArrowFunctionKey) kUnicodeUp, // kKeyUp (NSUpArrowFunctionKey)
kUnicodeDown, // kKeyDown (NSDownArrowFunctionKey) kUnicodeDown, // kKeyDown (NSDownArrowFunctionKey)
'/', // kKeySlashPad '/', // kKeySlashPad
'*', // kKeyAsterisk '*', // kKeyAsterisk
0, // kKeyMinusPad 0, // kKeyMinusPad
0, // kKeyPlusPad 0, // kKeyPlusPad
0, // kKeyDelPad 0, // kKeyDelPad
0, // kKeyEnterPad 0, // kKeyEnterPad
0, // kKeyPrtscr 0, // kKeyPrtscr
0, // kKeyPause 0, // kKeyPause
0, // kKeyAbntC1 0, // kKeyAbntC1
0, // kKeyYen 0, // kKeyYen
0, // kKeyKana 0, // kKeyKana
0, // kKeyConvert 0, // kKeyConvert
0, // kKeyNoconvert 0, // kKeyNoconvert
0, // kKeyAt 0, // kKeyAt
0, // kKeyCircumflex 0, // kKeyCircumflex
0, // kKeyColon2 0, // kKeyColon2
0, // kKeyKanji 0, // kKeyKanji
0, // kKeyEqualsPad 0, // kKeyEqualsPad
'`', // kKeyBackquote '`', // kKeyBackquote
0, // kKeySemicolon 0, // kKeySemicolon
0, // kKeyUnknown1 0, // kKeyUnknown1
0, // kKeyUnknown2 0, // kKeyUnknown2
0, // kKeyUnknown3 0, // kKeyUnknown3
0, // kKeyUnknown4 0, // kKeyUnknown4
0, // kKeyUnknown5 0, // kKeyUnknown5
0, // kKeyUnknown6 0, // kKeyUnknown6
0, // kKeyUnknown7 0, // kKeyUnknown7
0, // kKeyUnknown8 0, // kKeyUnknown8
0, // kKeyLShift 0, // kKeyLShift
0, // kKeyRShift 0, // kKeyRShift
0, // kKeyLControl 0, // kKeyLControl
0, // kKeyRControl 0, // kKeyRControl
0, // kKeyAlt 0, // kKeyAlt
0, // kKeyAltGr 0, // kKeyAltGr
0, // kKeyLWin 0, // kKeyLWin
0, // kKeyRWin 0, // kKeyRWin
0, // kKeyMenu 0, // kKeyMenu
0, // kKeyCommand 0, // kKeyCommand
0, // kKeyScrLock 0, // kKeyScrLock
0, // kKeyNumLock 0, // kKeyNumLock
0, // kKeyCapsLock 0, // kKeyCapsLock
}; };
if (scancode >= 0 && scancode < sizeof(map) / sizeof(map[0])) if (scancode >= 0 && scancode < sizeof(map) / sizeof(map[0]))
return map[scancode]; return map[scancode];
@ -266,9 +255,8 @@ int from_scancode_to_unicode(KeyScancode scancode)
return 0; return 0;
} }
AppMenuItem::Native get_native_shortcut_for_command( AppMenuItem::Native get_native_shortcut_for_command(const char* commandId,
const char* commandId, const Params& params = Params())
const Params& params = Params())
{ {
AppMenuItem::Native native; AppMenuItem::Native native;
KeyPtr key = KeyboardShortcuts::instance()->command(commandId, params); KeyPtr key = KeyboardShortcuts::instance()->command(commandId, params);
@ -307,8 +295,7 @@ os::Shortcut get_os_shortcut_from_key(const Key* key)
#endif #endif
return os::Shortcut( return os::Shortcut(
(accel.unicodeChar() ? accel.unicodeChar(): (accel.unicodeChar() ? accel.unicodeChar() : from_scancode_to_unicode(accel.scancode())),
from_scancode_to_unicode(accel.scancode())),
accel.modifiers()); accel.modifiers());
} }
else else
@ -323,15 +310,11 @@ AppMenus* AppMenus::instance()
return s_instance; return s_instance;
} }
AppMenus::AppMenus(RecentFiles* recentFiles) AppMenus::AppMenus(RecentFiles* recentFiles) : m_recentFilesPlaceholder(nullptr), m_osMenu(nullptr)
: m_recentFilesPlaceholder(nullptr)
, m_osMenu(nullptr)
{ {
ASSERT(s_instance == nullptr); ASSERT(s_instance == nullptr);
s_instance = this; s_instance = this;
m_recentFilesConn = m_recentFilesConn = recentFiles->Changed.connect([this] { rebuildRecentList(); });
recentFiles->Changed.connect(
[this]{ rebuildRecentList(); });
} }
AppMenus::~AppMenus() AppMenus::~AppMenus()
@ -386,8 +369,7 @@ void AppMenus::reload()
// Add one menu item to run each script from the user scripts/ folder // Add one menu item to run each script from the user scripts/ folder
{ {
MenuItem* scriptsMenu = dynamic_cast<MenuItem*>( MenuItem* scriptsMenu = dynamic_cast<MenuItem*>(m_rootMenu->findItemById("scripts_menu"));
m_rootMenu->findItemById("scripts_menu"));
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
// Load scripts // Load scripts
ResourceFinder rf; ResourceFinder rf;
@ -455,9 +437,7 @@ void AppMenus::reload()
LOG("MENU: Loading commands keyboard shortcuts from %s\n", path); LOG("MENU: Loading commands keyboard shortcuts from %s\n", path);
XMLElement* xmlKey = handle XMLElement* xmlKey = handle.FirstChildElement("gui").FirstChildElement("keyboard").ToElement();
.FirstChildElement("gui")
.FirstChildElement("keyboard").ToElement();
// From a fresh start, load the default keys // From a fresh start, load the default keys
KeyboardShortcuts::instance()->clear(); KeyboardShortcuts::instance()->clear();
@ -465,11 +445,9 @@ void AppMenus::reload()
// Load extension-defined keys // Load extension-defined keys
for (const Extension* ext : App::instance()->extensions()) { for (const Extension* ext : App::instance()->extensions()) {
if (ext->isEnabled() && if (ext->isEnabled() && ext->hasKeys()) {
ext->hasKeys()) {
for (const auto& kv : ext->keys()) { for (const auto& kv : ext->keys()) {
KeyboardShortcuts::instance()->importFile( KeyboardShortcuts::instance()->importFile(kv.second, KeySource::ExtensionDefined);
kv.second, KeySource::ExtensionDefined);
} }
} }
} }
@ -489,15 +467,12 @@ void AppMenus::reload()
} }
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
void AppMenus::loadScriptsSubmenu(ui::Menu* menu, void AppMenus::loadScriptsSubmenu(ui::Menu* menu, const std::string& dir, const bool rootLevel)
const std::string& dir,
const bool rootLevel)
{ {
auto files = base::list_files(dir); auto files = base::list_files(dir);
std::sort(files.begin(), files.end(), std::sort(files.begin(), files.end(), [](const std::string& a, const std::string& b) {
[](const std::string& a, const std::string& b) { return base::compare_filenames(a, b) < 0;
return base::compare_filenames(a, b) < 0; });
});
int insertPos = 0; int insertPos = 0;
for (auto fn : files) { for (auto fn : files) {
std::string fullFn = base::join_path(dir, fn); std::string fullFn = base::join_path(dir, fn);
@ -510,18 +485,15 @@ void AppMenus::loadScriptsSubmenu(ui::Menu* menu,
if (base::string_to_lower(base::get_file_extension(fn)) == "lua") { if (base::string_to_lower(base::get_file_extension(fn)) == "lua") {
Params params; Params params;
params.set("filename", fullFn.c_str()); params.set("filename", fullFn.c_str());
menuitem = new AppMenuItem( menuitem =
base::get_file_title(fn).c_str(), new AppMenuItem(base::get_file_title(fn).c_str(), CommandId::RunScript(), params);
CommandId::RunScript(),
params);
} }
} }
else if (base::is_directory(fullFn)) { else if (base::is_directory(fullFn)) {
Menu* submenu = new Menu(); Menu* submenu = new Menu();
loadScriptsSubmenu(submenu, fullFn, false); loadScriptsSubmenu(submenu, fullFn, false);
menuitem = new AppMenuItem( menuitem = new AppMenuItem(base::get_file_title(fn).c_str());
base::get_file_title(fn).c_str());
menuitem->setSubmenu(submenu); menuitem->setSubmenu(submenu);
} }
if (menuitem) { if (menuitem) {
@ -543,7 +515,8 @@ void AppMenus::initTheme()
bool AppMenus::rebuildRecentList() bool AppMenus::rebuildRecentList()
{ {
MENUS_TRACE("MENUS: AppMenus::rebuildRecentList m_recentFilesPlaceholder=", m_recentFilesPlaceholder); MENUS_TRACE("MENUS: AppMenus::rebuildRecentList m_recentFilesPlaceholder=",
m_recentFilesPlaceholder);
if (!m_recentFilesPlaceholder) if (!m_recentFilesPlaceholder)
return true; return true;
@ -563,21 +536,15 @@ bool AppMenus::rebuildRecentList()
auto recent = App::instance()->recentFiles(); auto recent = App::instance()->recentFiles();
base::paths files; base::paths files;
files.insert(files.end(), files.insert(files.end(), recent->pinnedFiles().begin(), recent->pinnedFiles().end());
recent->pinnedFiles().begin(), files.insert(files.end(), recent->recentFiles().begin(), recent->recentFiles().end());
recent->pinnedFiles().end());
files.insert(files.end(),
recent->recentFiles().begin(),
recent->recentFiles().end());
if (!files.empty()) { if (!files.empty()) {
Params params; Params params;
for (const auto& fn : files) { for (const auto& fn : files) {
params.set("filename", fn.c_str()); params.set("filename", fn.c_str());
std::unique_ptr<AppMenuItem> menuitem( std::unique_ptr<AppMenuItem> menuitem(
new AppMenuItem(base::get_file_name(fn).c_str(), new AppMenuItem(base::get_file_name(fn).c_str(), CommandId::OpenFile(), params));
CommandId::OpenFile(),
params));
menuitem->setIsRecentFileItem(true); menuitem->setIsRecentFileItem(true);
m_recentMenuItems.push_back(menuitem.get()); m_recentMenuItems.push_back(menuitem.get());
@ -585,9 +552,8 @@ bool AppMenus::rebuildRecentList()
} }
} }
else { else {
std::unique_ptr<AppMenuItem> menuitem( std::unique_ptr<AppMenuItem> menuitem(
new AppMenuItem( new AppMenuItem(Strings::main_menu_file_no_recent_file()));
Strings::main_menu_file_no_recent_file()));
menuitem->setIsRecentFileItem(true); menuitem->setIsRecentFileItem(true);
menuitem->setEnabled(false); menuitem->setEnabled(false);
@ -596,10 +562,9 @@ bool AppMenus::rebuildRecentList()
} }
// Sync native menus // Sync native menus
if (owner->native() && if (owner->native() && owner->native()->menuItem) {
owner->native()->menuItem) {
auto menus = os::System::instance()->menus(); auto menus = os::System::instance()->menus();
os::MenuRef osMenu = (menus ? menus->makeMenu(): nullptr); os::MenuRef osMenu = (menus ? menus->makeMenu() : nullptr);
if (osMenu) { if (osMenu) {
createNativeSubmenus(osMenu.get(), menu); createNativeSubmenus(osMenu.get(), menu);
owner->native()->menuItem->setSubmenu(osMenu); owner->native()->menuItem->setSubmenu(osMenu);
@ -611,16 +576,14 @@ bool AppMenus::rebuildRecentList()
Menu* AppMenus::getAnimationMenu() Menu* AppMenus::getAnimationMenu()
{ {
auto menuItem = auto menuItem = dynamic_cast<MenuItem*>(m_rootMenu->findItemById("animation_menu"));
dynamic_cast<MenuItem*>(m_rootMenu->findItemById("animation_menu"));
if (menuItem) if (menuItem)
return menuItem->getSubmenu(); return menuItem->getSubmenu();
else else
return nullptr; return nullptr;
} }
void AppMenus::addMenuGroup(const std::string& groupId, void AppMenus::addMenuGroup(const std::string& groupId, MenuItem* menuItem)
MenuItem* menuItem)
{ {
GroupInfo& group = m_groups[groupId]; GroupInfo& group = m_groups[groupId];
ASSERT(group.menu == nullptr); ASSERT(group.menu == nullptr);
@ -639,22 +602,20 @@ void AppMenus::removeMenuGroup(const std::string& groupId)
if (group.menu->getOwnerMenuItem()) { if (group.menu->getOwnerMenuItem()) {
ui::MenuItem* item = group.menu->getOwnerMenuItem(); ui::MenuItem* item = group.menu->getOwnerMenuItem();
removeMenuItemFromGroup( removeMenuItemFromGroup([item](Widget* i) { return item == i; });
[item](Widget* i){
return item == i;
});
} }
m_groups.erase(it); m_groups.erase(it);
} }
} }
void AppMenus::addMenuItemIntoGroup(const std::string& groupId, void AppMenus::addMenuItemIntoGroup(const std::string& groupId, std::unique_ptr<Widget>&& menuItem)
std::unique_ptr<Widget>&& menuItem)
{ {
auto it = m_groups.find(groupId); auto it = m_groups.find(groupId);
if (it == m_groups.end()) { if (it == m_groups.end()) {
LOG(ERROR, "MENU: An extension tried to add a command (%s) in a non-existent group (%s)\n", LOG(ERROR,
menuItem->text().c_str(), groupId.c_str()); "MENU: An extension tried to add a command (%s) in a non-existent group (%s)\n",
menuItem->text().c_str(),
groupId.c_str());
menuItem.release(); menuItem.release();
return; return;
} }
@ -666,7 +627,7 @@ void AppMenus::addMenuItemIntoGroup(const std::string& groupId,
if (group.end) { if (group.end) {
int insertIndex = menu->getChildIndex(group.end); int insertIndex = menu->getChildIndex(group.end);
ASSERT(insertIndex >= 0); ASSERT(insertIndex >= 0);
menu->insertChild(insertIndex+1, menuItem.get()); menu->insertChild(insertIndex + 1, menuItem.get());
} }
else { else {
menu->addChild(menuItem.get()); menu->addChild(menuItem.get());
@ -683,7 +644,7 @@ void AppMenus::removeMenuItemFromGroup(Pred pred)
{ {
for (auto& it : m_groups) { for (auto& it : m_groups) {
GroupInfo& group = it.second; GroupInfo& group = it.second;
for (auto it=group.items.begin(); it != group.items.end(); ) { for (auto it = group.items.begin(); it != group.items.end();) {
auto& item = *it; auto& item = *it;
if (pred(item)) { if (pred(item)) {
if (item == group.end) if (item == group.end)
@ -702,19 +663,15 @@ void AppMenus::removeMenuItemFromGroup(Pred pred)
void AppMenus::removeMenuItemFromGroup(Command* cmd) void AppMenus::removeMenuItemFromGroup(Command* cmd)
{ {
removeMenuItemFromGroup( removeMenuItemFromGroup([cmd](Widget* item) {
[cmd](Widget* item){ auto appMenuItem = dynamic_cast<AppMenuItem*>(item);
auto appMenuItem = dynamic_cast<AppMenuItem*>(item); return (appMenuItem && appMenuItem->getCommand() == cmd);
return (appMenuItem && appMenuItem->getCommand() == cmd); });
});
} }
void AppMenus::removeMenuItemFromGroup(Widget* menuItem) void AppMenus::removeMenuItemFromGroup(Widget* menuItem)
{ {
removeMenuItemFromGroup( removeMenuItemFromGroup([menuItem](Widget* item) { return (item == menuItem); });
[menuItem](Widget* item){
return (item == menuItem);
});
} }
Menu* AppMenus::loadMenuById(XMLHandle& handle, const char* id) Menu* AppMenus::loadMenuById(XMLHandle& handle, const char* id)
@ -722,10 +679,8 @@ Menu* AppMenus::loadMenuById(XMLHandle& handle, const char* id)
ASSERT(id != NULL); ASSERT(id != NULL);
// <gui><menus><menu> // <gui><menus><menu>
XMLElement* xmlMenu = handle XMLElement* xmlMenu =
.FirstChildElement("gui") handle.FirstChildElement("gui").FirstChildElement("menus").FirstChildElement("menu").ToElement();
.FirstChildElement("menus")
.FirstChildElement("menu").ToElement();
while (xmlMenu) { while (xmlMenu) {
const char* menuId = xmlMenu->Attribute("id"); const char* menuId = xmlMenu->Attribute("id");
@ -785,9 +740,7 @@ Widget* AppMenus::convertXmlelemToMenuitem(XMLElement* elem, Menu* menu)
} }
const char* commandId = elem->Attribute("command"); const char* commandId = elem->Attribute("command");
Command* command = Command* command = (commandId ? Commands::instance()->byId(commandId) : nullptr);
(commandId ? Commands::instance()->byId(commandId):
nullptr);
// load params // load params
Params params; Params params;
@ -805,9 +758,8 @@ Widget* AppMenus::convertXmlelemToMenuitem(XMLElement* elem, Menu* menu)
} }
// Create the item // Create the item
AppMenuItem* menuitem = new AppMenuItem(m_xmlTranslator(elem, "text"), AppMenuItem* menuitem =
(command ? command->id(): ""), new AppMenuItem(m_xmlTranslator(elem, "text"), (command ? command->id() : ""), params);
params);
if (!menuitem) if (!menuitem)
return nullptr; return nullptr;
@ -821,7 +773,8 @@ Widget* AppMenus::convertXmlelemToMenuitem(XMLElement* elem, Menu* menu)
menuitem->processMnemonicFromText(); menuitem->processMnemonicFromText();
} }
if (id) menuitem->setId(id); if (id)
menuitem->setId(id);
if (group) { if (group) {
m_groups[group].menu = menu; m_groups[group].menu = menu;
m_groups[group].end = menuitem; m_groups[group].end = menuitem;
@ -876,8 +829,7 @@ void AppMenus::applyShortcutToMenuitemsWithCommand(Menu* menu,
const std::string& mi_commandId = menuitem->getCommandId(); const std::string& mi_commandId = menuitem->getCommandId();
const Params& mi_params = menuitem->getParams(); const Params& mi_params = menuitem->getParams();
if ((base::utf8_icmp(mi_commandId, command->id()) == 0) && if ((base::utf8_icmp(mi_commandId, command->id()) == 0) && (mi_params == params)) {
(mi_params == params)) {
// Set the keyboard shortcut to be shown in this menu-item // Set the keyboard shortcut to be shown in this menu-item
menuitem->setKey(key); menuitem->setKey(key);
} }
@ -928,38 +880,38 @@ void AppMenus::updateMenusList()
void AppMenus::createNativeMenus() void AppMenus::createNativeMenus()
{ {
os::Menus* menus = os::System::instance()->menus(); os::Menus* menus = os::System::instance()->menus();
if (!menus) // This platform doesn't support native menu items if (!menus) // This platform doesn't support native menu items
return; return;
// Save a reference to the old menu to avoid destroying it. // Save a reference to the old menu to avoid destroying it.
os::MenuRef oldOSMenu = m_osMenu; os::MenuRef oldOSMenu = m_osMenu;
m_osMenu = menus->makeMenu(); m_osMenu = menus->makeMenu();
#if LAF_MACOS // Create default macOS app menus (App ... Window) #if LAF_MACOS // Create default macOS app menus (App ... Window)
{ {
os::MenuItemInfo about(fmt::format("About {}", get_app_name())); os::MenuItemInfo about(fmt::format("About {}", get_app_name()));
auto native = get_native_shortcut_for_command(CommandId::About()); auto native = get_native_shortcut_for_command(CommandId::About());
about.shortcut = native.shortcut; about.shortcut = native.shortcut;
about.execute = [native]{ about.execute = [native] {
if (can_call_global_shortcut(&native)) { if (can_call_global_shortcut(&native)) {
Command* cmd = Commands::instance()->byId(CommandId::About()); Command* cmd = Commands::instance()->byId(CommandId::About());
UIContext::instance()->executeCommandFromMenuOrShortcut(cmd); UIContext::instance()->executeCommandFromMenuOrShortcut(cmd);
} }
}; };
about.validate = [native](os::MenuItem* item){ about.validate = [native](os::MenuItem* item) {
item->setEnabled(can_call_global_shortcut(&native)); item->setEnabled(can_call_global_shortcut(&native));
}; };
os::MenuItemInfo preferences("Preferences..."); os::MenuItemInfo preferences("Preferences...");
native = get_native_shortcut_for_command(CommandId::Options()); native = get_native_shortcut_for_command(CommandId::Options());
preferences.shortcut = native.shortcut; preferences.shortcut = native.shortcut;
preferences.execute = [native]{ preferences.execute = [native] {
if (can_call_global_shortcut(&native)) { if (can_call_global_shortcut(&native)) {
Command* cmd = Commands::instance()->byId(CommandId::Options()); Command* cmd = Commands::instance()->byId(CommandId::Options());
UIContext::instance()->executeCommandFromMenuOrShortcut(cmd); UIContext::instance()->executeCommandFromMenuOrShortcut(cmd);
} }
}; };
preferences.validate = [native](os::MenuItem* item){ preferences.validate = [native](os::MenuItem* item) {
item->setEnabled(can_call_global_shortcut(&native)); item->setEnabled(can_call_global_shortcut(&native));
}; };
@ -975,7 +927,8 @@ void AppMenus::createNativeMenus()
appMenu->addItem(menus->makeMenuItem(preferences)); appMenu->addItem(menus->makeMenuItem(preferences));
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator))); appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator)));
appMenu->addItem(menus->makeMenuItem(hide)); appMenu->addItem(menus->makeMenuItem(hide));
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo("Hide Others", os::MenuItemInfo::HideOthers))); appMenu->addItem(
menus->makeMenuItem(os::MenuItemInfo("Hide Others", os::MenuItemInfo::HideOthers)));
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo("Show All", os::MenuItemInfo::ShowAll))); appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo("Show All", os::MenuItemInfo::ShowAll)));
appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator))); appMenu->addItem(menus->makeMenuItem(os::MenuItemInfo(os::MenuItemInfo::Separator)));
appMenu->addItem(menus->makeMenuItem(quit)); appMenu->addItem(menus->makeMenuItem(quit));
@ -1013,7 +966,7 @@ void AppMenus::createNativeMenus()
// We use helpIndex+1 because the first index in m_osMenu is the // We use helpIndex+1 because the first index in m_osMenu is the
// App menu. // App menu.
m_osMenu->insertItem(helpIndex+1, windowItem); m_osMenu->insertItem(helpIndex + 1, windowItem);
} }
#endif #endif
@ -1022,8 +975,7 @@ void AppMenus::createNativeMenus()
oldOSMenu.reset(); oldOSMenu.reset();
} }
void AppMenus::createNativeSubmenus(os::Menu* osMenu, void AppMenus::createNativeSubmenus(os::Menu* osMenu, const ui::Menu* uiMenu)
const ui::Menu* uiMenu)
{ {
os::Menus* menus = os::System::instance()->menus(); os::Menus* menus = os::System::instance()->menus();
@ -1036,17 +988,15 @@ void AppMenus::createNativeSubmenus(os::Menu* osMenu,
info.type = os::MenuItemInfo::Separator; info.type = os::MenuItemInfo::Separator;
} }
else if (child->type() == kMenuItemWidget) { else if (child->type() == kMenuItemWidget) {
if (appMenuItem && if (appMenuItem && appMenuItem->getCommand()) {
appMenuItem->getCommand()) { native = get_native_shortcut_for_command(appMenuItem->getCommandId().c_str(),
native = get_native_shortcut_for_command( appMenuItem->getParams());
appMenuItem->getCommandId().c_str(),
appMenuItem->getParams());
} }
info.type = os::MenuItemInfo::Normal; info.type = os::MenuItemInfo::Normal;
info.text = child->text(); info.text = child->text();
info.shortcut = native.shortcut; info.shortcut = native.shortcut;
info.execute = [appMenuItem]{ info.execute = [appMenuItem] {
if (can_call_global_shortcut(appMenuItem->native())) if (can_call_global_shortcut(appMenuItem->native()))
appMenuItem->executeClick(); appMenuItem->executeClick();
}; };
@ -1063,7 +1013,7 @@ void AppMenus::createNativeSubmenus(os::Menu* osMenu,
}; };
} }
else { else {
ASSERT(false); // Unsupported menu item type ASSERT(false); // Unsupported menu item type
continue; continue;
} }
@ -1075,8 +1025,7 @@ void AppMenus::createNativeSubmenus(os::Menu* osMenu,
appMenuItem->setNative(native); appMenuItem->setNative(native);
} }
if (child->type() == ui::kMenuItemWidget && if (child->type() == ui::kMenuItemWidget && ((ui::MenuItem*)child)->hasSubmenu()) {
((ui::MenuItem*)child)->hasSubmenu()) {
os::MenuRef osSubmenu = menus->makeMenu(); os::MenuRef osSubmenu = menus->makeMenu();
createNativeSubmenus(osSubmenu.get(), ((ui::MenuItem*)child)->getSubmenu()); createNativeSubmenus(osSubmenu.get(), ((ui::MenuItem*)child)->getSubmenu());
osItem->setSubmenu(osSubmenu); osItem->setSubmenu(osSubmenu);

View File

@ -21,117 +21,115 @@
#include <memory> #include <memory>
namespace tinyxml2 { namespace tinyxml2 {
class XMLElement; class XMLElement;
class XMLHandle; class XMLHandle;
} } // namespace tinyxml2
namespace app { namespace app {
class Command; class Command;
class Params; class Params;
class RecentFiles; class RecentFiles;
using namespace ui; using namespace ui;
// Class to handle/get/reload available menus in gui.xml file. // Class to handle/get/reload available menus in gui.xml file.
class AppMenus { class AppMenus {
DISABLE_COPYING(AppMenus); DISABLE_COPYING(AppMenus);
public: public:
static AppMenus* instance(); static AppMenus* instance();
AppMenus(RecentFiles* recentFiles); AppMenus(RecentFiles* recentFiles);
~AppMenus(); ~AppMenus();
void reload(); void reload();
void initTheme(); void initTheme();
// Updates the menu of recent files. // Updates the menu of recent files.
bool rebuildRecentList(); bool rebuildRecentList();
Menu* getRootMenu() { return m_rootMenu.get(); } Menu* getRootMenu() { return m_rootMenu.get(); }
Menu* getTabPopupMenu() { return m_tabPopupMenu.get(); } Menu* getTabPopupMenu() { return m_tabPopupMenu.get(); }
Menu* getDocumentTabPopupMenu() { return m_documentTabPopupMenu.get(); } Menu* getDocumentTabPopupMenu() { return m_documentTabPopupMenu.get(); }
Menu* getLayerPopupMenu() { return m_layerPopupMenu.get(); } Menu* getLayerPopupMenu() { return m_layerPopupMenu.get(); }
Menu* getFramePopupMenu() { return m_framePopupMenu.get(); } Menu* getFramePopupMenu() { return m_framePopupMenu.get(); }
Menu* getCelPopupMenu() { return m_celPopupMenu.get(); } Menu* getCelPopupMenu() { return m_celPopupMenu.get(); }
Menu* getCelMovementPopupMenu() { return m_celMovementPopupMenu.get(); } Menu* getCelMovementPopupMenu() { return m_celMovementPopupMenu.get(); }
Menu* getTagPopupMenu() { return m_tagPopupMenu.get(); } Menu* getTagPopupMenu() { return m_tagPopupMenu.get(); }
Menu* getSlicePopupMenu() { return m_slicePopupMenu.get(); } Menu* getSlicePopupMenu() { return m_slicePopupMenu.get(); }
Menu* getPalettePopupMenu() { return m_palettePopupMenu.get(); } Menu* getPalettePopupMenu() { return m_palettePopupMenu.get(); }
Menu* getInkPopupMenu() { return m_inkPopupMenu.get(); } Menu* getInkPopupMenu() { return m_inkPopupMenu.get(); }
Menu* getAnimationMenu(); Menu* getAnimationMenu();
Menu* getNewFrameMenu() { return m_newFramePopupMenu.get(); } Menu* getNewFrameMenu() { return m_newFramePopupMenu.get(); }
void applyShortcutToMenuitemsWithCommand(Command* command, const Params& params, void applyShortcutToMenuitemsWithCommand(Command* command,
const KeyPtr& key); const Params& params,
void syncNativeMenuItemKeyShortcuts(); const KeyPtr& key);
void syncNativeMenuItemKeyShortcuts();
// Menu item handling in groups // Menu item handling in groups
void addMenuGroup(const std::string& groupId, void addMenuGroup(const std::string& groupId, MenuItem* menuItem);
MenuItem* menuItem); void removeMenuGroup(const std::string& groupId);
void removeMenuGroup(const std::string& groupId); void addMenuItemIntoGroup(const std::string& groupId, std::unique_ptr<Widget>&& menuItem);
void addMenuItemIntoGroup(const std::string& groupId, void removeMenuItemFromGroup(Command* cmd);
std::unique_ptr<Widget>&& menuItem); void removeMenuItemFromGroup(Widget* menuItem);
void removeMenuItemFromGroup(Command* cmd);
void removeMenuItemFromGroup(Widget* menuItem);
private: private:
template<typename Pred> template<typename Pred>
void removeMenuItemFromGroup(Pred pred); void removeMenuItemFromGroup(Pred pred);
Menu* loadMenuById(tinyxml2::XMLHandle& handle, const char *id); Menu* loadMenuById(tinyxml2::XMLHandle& handle, const char* id);
Menu* convertXmlelemToMenu(tinyxml2::XMLElement* elem); Menu* convertXmlelemToMenu(tinyxml2::XMLElement* elem);
Widget* convertXmlelemToMenuitem(tinyxml2::XMLElement* elem, Menu* menu); Widget* convertXmlelemToMenuitem(tinyxml2::XMLElement* elem, Menu* menu);
void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, const Params& params, void applyShortcutToMenuitemsWithCommand(Menu* menu,
const KeyPtr& key); Command* command,
void syncNativeMenuItemKeyShortcuts(Menu* menu); const Params& params,
void updateMenusList(); const KeyPtr& key);
void createNativeMenus(); void syncNativeMenuItemKeyShortcuts(Menu* menu);
void createNativeSubmenus(os::Menu* osMenu, void updateMenusList();
const ui::Menu* uiMenu); void createNativeMenus();
void createNativeSubmenus(os::Menu* osMenu, const ui::Menu* uiMenu);
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
void loadScriptsSubmenu(ui::Menu* menu, void loadScriptsSubmenu(ui::Menu* menu, const std::string& dir, const bool rootLevel);
const std::string& dir,
const bool rootLevel);
#endif #endif
struct GroupInfo { struct GroupInfo {
Menu* menu = nullptr; Menu* menu = nullptr;
Widget* end = nullptr; Widget* end = nullptr;
WidgetsList items; WidgetsList items;
};
std::unique_ptr<Menu> m_rootMenu;
Widget* m_recentFilesPlaceholder;
MenuItem* m_helpMenuitem;
std::unique_ptr<Menu> m_tabPopupMenu;
std::unique_ptr<Menu> m_documentTabPopupMenu;
std::unique_ptr<Menu> m_layerPopupMenu;
std::unique_ptr<Menu> m_framePopupMenu;
std::unique_ptr<Menu> m_celPopupMenu;
std::unique_ptr<Menu> m_celMovementPopupMenu;
std::unique_ptr<Menu> m_tagPopupMenu;
std::unique_ptr<Menu> m_slicePopupMenu;
std::unique_ptr<Menu> m_palettePopupMenu;
std::unique_ptr<Menu> m_inkPopupMenu;
std::unique_ptr<Menu> m_newFramePopupMenu;
obs::scoped_connection m_recentFilesConn;
std::vector<Menu*> m_menus;
// List of recent menu items pointing to recent files.
WidgetsList m_recentMenuItems;
// Extension points for plugins (each group is a place where new
// menu items can be added).
std::map<std::string, GroupInfo> m_groups;
// Native main menu bar (== nullptr if the platform doesn't
// support native menus)
os::MenuRef m_osMenu;
XmlTranslator m_xmlTranslator;
static AppMenus* s_instance;
}; };
os::Shortcut get_os_shortcut_from_key(const Key* key); std::unique_ptr<Menu> m_rootMenu;
Widget* m_recentFilesPlaceholder;
MenuItem* m_helpMenuitem;
std::unique_ptr<Menu> m_tabPopupMenu;
std::unique_ptr<Menu> m_documentTabPopupMenu;
std::unique_ptr<Menu> m_layerPopupMenu;
std::unique_ptr<Menu> m_framePopupMenu;
std::unique_ptr<Menu> m_celPopupMenu;
std::unique_ptr<Menu> m_celMovementPopupMenu;
std::unique_ptr<Menu> m_tagPopupMenu;
std::unique_ptr<Menu> m_slicePopupMenu;
std::unique_ptr<Menu> m_palettePopupMenu;
std::unique_ptr<Menu> m_inkPopupMenu;
std::unique_ptr<Menu> m_newFramePopupMenu;
obs::scoped_connection m_recentFilesConn;
std::vector<Menu*> m_menus;
// List of recent menu items pointing to recent files.
WidgetsList m_recentMenuItems;
// Extension points for plugins (each group is a place where new
// menu items can be added).
std::map<std::string, GroupInfo> m_groups;
// Native main menu bar (== nullptr if the platform doesn't
// support native menus)
os::MenuRef m_osMenu;
XmlTranslator m_xmlTranslator;
static AppMenus* s_instance;
};
os::Shortcut get_os_shortcut_from_key(const Key* key);
} // namespace app } // namespace app

View File

@ -9,13 +9,13 @@
#pragma once #pragma once
namespace app { namespace app {
class MainWindow; class MainWindow;
class AppMod { class AppMod {
public: public:
virtual ~AppMod() { } virtual ~AppMod() {}
virtual void modMainWindow(MainWindow* mainWindow) = 0; virtual void modMainWindow(MainWindow* mainWindow) = 0;
}; };
} // namespace app } // namespace app

View File

@ -4,9 +4,8 @@
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include <gtest/gtest.h> #include <gtest/gtest.h>
@ -45,10 +44,8 @@ TEST(App, ExitCommand)
app::App app; app::App app;
app.initialize(options); app.initialize(options);
ui::execute_from_ui_thread([&app] { ui::execute_from_ui_thread(
app.context()->executeCommand( [&app] { app.context()->executeCommand(Commands::instance()->byId(CommandId::Exit())); });
Commands::instance()->byId(CommandId::Exit()));
});
app.run(); app.run();
} }
@ -64,10 +61,8 @@ TEST(App, ExitWithOneDoc)
ui::execute_from_ui_thread([&app] { ui::execute_from_ui_thread([&app] {
Params params; Params params;
params.set("ui", "false"); params.set("ui", "false");
app.context()->executeCommand( app.context()->executeCommand(Commands::instance()->byId(CommandId::NewFile()), params);
Commands::instance()->byId(CommandId::NewFile()), params); app.context()->executeCommand(Commands::instance()->byId(CommandId::Exit()));
app.context()->executeCommand(
Commands::instance()->byId(CommandId::Exit()));
}); });
app.run(); app.run();

View File

@ -19,17 +19,17 @@ namespace app {
class BrushSlot { class BrushSlot {
public: public:
enum class Flags { enum class Flags {
Locked = 0x0001, Locked = 0x0001,
BrushType = 0x0002, BrushType = 0x0002,
BrushSize = 0x0004, BrushSize = 0x0004,
BrushAngle = 0x0008, BrushAngle = 0x0008,
FgColor = 0x0010, FgColor = 0x0010,
BgColor = 0x0020, BgColor = 0x0020,
InkType = 0x0040, InkType = 0x0040,
InkOpacity = 0x0080, InkOpacity = 0x0080,
Shade = 0x0100, Shade = 0x0100,
PixelPerfect = 0x0200, PixelPerfect = 0x0200,
ImageColor = 0x0400, ImageColor = 0x0400,
}; };
BrushSlot(Flags flags = Flags(0), BrushSlot(Flags flags = Flags(0),
@ -47,26 +47,21 @@ public:
, m_inkType(inkType) , m_inkType(inkType)
, m_inkOpacity(inkOpacity) , m_inkOpacity(inkOpacity)
, m_shade(shade) , m_shade(shade)
, m_pixelPerfect(pixelPerfect) { , m_pixelPerfect(pixelPerfect)
{
} }
Flags flags() const { return m_flags; } Flags flags() const { return m_flags; }
void setFlags(Flags flags) { m_flags = flags; } void setFlags(Flags flags) { m_flags = flags; }
bool isEmpty() const { bool isEmpty() const { return int(m_flags) == 0; }
return int(m_flags) == 0;
}
bool hasFlag(Flags flag) const { bool hasFlag(Flags flag) const { return ((int(m_flags) & int(flag)) == int(flag)); }
return ((int(m_flags) & int(flag)) == int(flag));
}
bool hasBrush() const { bool hasBrush() const
return {
(brush() && return (brush() &&
(hasFlag(Flags::BrushType) || (hasFlag(Flags::BrushType) || hasFlag(Flags::BrushSize) || hasFlag(Flags::BrushAngle)));
hasFlag(Flags::BrushSize) ||
hasFlag(Flags::BrushAngle)));
} }
// Can be null if the user deletes the brush. // Can be null if the user deletes the brush.
@ -80,11 +75,10 @@ public:
// True if the user locked the brush using the shortcut key to // True if the user locked the brush using the shortcut key to
// access it. // access it.
bool locked() const { bool locked() const { return hasFlag(Flags::Locked); }
return hasFlag(Flags::Locked);
}
void setLocked(bool locked) { void setLocked(bool locked)
{
if (locked) if (locked)
m_flags = static_cast<Flags>(int(m_flags) | int(Flags::Locked)); m_flags = static_cast<Flags>(int(m_flags) | int(Flags::Locked));
else else

View File

@ -6,28 +6,28 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
#include "app/check_update.h" #include "app/check_update.h"
#include "app/check_update_delegate.h" #include "app/check_update_delegate.h"
#include "app/pref/preferences.h" #include "app/pref/preferences.h"
#include "base/convert_to.h" #include "base/convert_to.h"
#include "base/launcher.h" #include "base/launcher.h"
#include "base/replace_string.h" #include "base/replace_string.h"
#include "base/thread.h" #include "base/thread.h"
#include "base/version.h" #include "base/version.h"
#include "ver/info.h" #include "ver/info.h"
#if ENABLE_SENTRY #if ENABLE_SENTRY
#include "app/sentry_wrapper.h" #include "app/sentry_wrapper.h"
#endif #endif
#include <ctime> #include <ctime>
#include <sstream> #include <sstream>
static const int kMonitoringPeriod = 100; static const int kMonitoringPeriod = 100;
@ -35,27 +35,22 @@ namespace app {
class CheckUpdateBackgroundJob : public updater::CheckUpdateDelegate { class CheckUpdateBackgroundJob : public updater::CheckUpdateDelegate {
public: public:
CheckUpdateBackgroundJob() CheckUpdateBackgroundJob() : m_received(false) {}
: m_received(false) { }
void abort() { void abort() { m_checker.abort(); }
m_checker.abort();
}
bool isReceived() const { bool isReceived() const { return m_received; }
return m_received;
}
void sendRequest(const updater::Uuid& uuid, const std::string& extraParams) { void sendRequest(const updater::Uuid& uuid, const std::string& extraParams)
{
m_checker.checkNewVersion(uuid, extraParams, this); m_checker.checkNewVersion(uuid, extraParams, this);
} }
const updater::CheckUpdateResponse& getResponse() const { const updater::CheckUpdateResponse& getResponse() const { return m_response; }
return m_response;
}
private: private:
void onResponse(updater::CheckUpdateResponse& data) override { void onResponse(updater::CheckUpdateResponse& data) override
{
m_response = data; m_response = data;
m_received = true; m_received = true;
} }
@ -72,11 +67,11 @@ CheckUpdateThreadLauncher::CheckUpdateThreadLauncher(CheckUpdateDelegate* delega
, m_received(false) , m_received(false)
, m_inits(m_preferences.updater.inits()) , m_inits(m_preferences.updater.inits())
, m_exits(m_preferences.updater.exits()) , m_exits(m_preferences.updater.exits())
#ifdef _DEBUG #ifdef _DEBUG
, m_isDeveloper(true) , m_isDeveloper(true)
#else #else
, m_isDeveloper(m_preferences.updater.isDeveloper()) , m_isDeveloper(m_preferences.updater.isDeveloper())
#endif #endif
, m_timer(kMonitoringPeriod, NULL) , m_timer(kMonitoringPeriod, NULL)
{ {
// Get how many days we have to wait for the next "check for update" // Get how many days we have to wait for the next "check for update"
@ -87,15 +82,16 @@ CheckUpdateThreadLauncher::CheckUpdateThreadLauncher(CheckUpdateDelegate* delega
time_t now = std::time(NULL); time_t now = std::time(NULL);
// Verify if we are in the "WaitDays" period... // Verify if we are in the "WaitDays" period...
if (now < lastCheck+int(double(60*60*24*waitDays)) && if (now < lastCheck + int(double(60 * 60 * 24 * waitDays)) && now > lastCheck) { // <- Avoid
now > lastCheck) { // <- Avoid broken clocks // broken
// clocks
// So we do not check for updates. // So we do not check for updates.
m_doCheck = false; m_doCheck = false;
} }
} }
// Minimal stats: number of initializations // Minimal stats: number of initializations
m_preferences.updater.inits(m_inits+1); m_preferences.updater.inits(m_inits + 1);
m_preferences.save(); m_preferences.save();
} }
@ -112,7 +108,7 @@ CheckUpdateThreadLauncher::~CheckUpdateThreadLauncher()
} }
// Minimal stats: number of exits // Minimal stats: number of exits
m_preferences.updater.exits(m_exits+1); m_preferences.updater.exits(m_exits + 1);
m_preferences.save(); m_preferences.save();
} }
@ -122,9 +118,9 @@ void CheckUpdateThreadLauncher::launch()
m_uuid = m_preferences.updater.uuid(); m_uuid = m_preferences.updater.uuid();
if (!m_uuid.empty()) { if (!m_uuid.empty()) {
#if ENABLE_SENTRY #if ENABLE_SENTRY
Sentry::setUserID(m_uuid); Sentry::setUserID(m_uuid);
#endif #endif
LOG(VERBOSE, "APP: Saved UUID %s\n", m_uuid.c_str()); LOG(VERBOSE, "APP: Saved UUID %s\n", m_uuid.c_str());
} }
@ -138,7 +134,7 @@ void CheckUpdateThreadLauncher::launch()
m_delegate->onCheckingUpdates(); m_delegate->onCheckingUpdates();
m_bgJob.reset(new CheckUpdateBackgroundJob); m_bgJob.reset(new CheckUpdateBackgroundJob);
m_thread.reset(new std::thread([this]{ checkForUpdates(); })); m_thread.reset(new std::thread([this] { checkForUpdates(); }));
// Start a timer to monitoring the progress of the background job // Start a timer to monitoring the progress of the background job
// executed in "m_thread". The "onMonitoringTick" method will be // executed in "m_thread". The "onMonitoringTick" method will be
@ -156,11 +152,10 @@ void CheckUpdateThreadLauncher::onMonitoringTick()
{ {
// If we do not receive a response yet... // If we do not receive a response yet...
if (!m_received) if (!m_received)
return; // Skip and wait the next call. return; // Skip and wait the next call.
// Depending on the type of update received // Depending on the type of update received
switch (m_response.getUpdateType()) { switch (m_response.getUpdateType()) {
case updater::CheckUpdateResponse::NoUpdate: case updater::CheckUpdateResponse::NoUpdate:
// Clear // Clear
m_preferences.updater.newVersion(""); m_preferences.updater.newVersion("");
@ -182,9 +177,9 @@ void CheckUpdateThreadLauncher::onMonitoringTick()
m_preferences.updater.uuid(m_uuid); m_preferences.updater.uuid(m_uuid);
if (!m_uuid.empty()) { if (!m_uuid.empty()) {
#if ENABLE_SENTRY #if ENABLE_SENTRY
Sentry::setUserID(m_uuid); Sentry::setUserID(m_uuid);
#endif #endif
LOG(VERBOSE, "APP: New UUID %s\n", m_uuid.c_str()); LOG(VERBOSE, "APP: New UUID %s\n", m_uuid.c_str());
} }
} }
@ -207,8 +202,7 @@ void CheckUpdateThreadLauncher::checkForUpdates()
// Add mini-stats in the request // Add mini-stats in the request
std::stringstream extraParams; std::stringstream extraParams;
extraParams << "inits=" << m_inits extraParams << "inits=" << m_inits << "&exits=" << m_exits;
<< "&exits=" << m_exits;
if (m_isDeveloper) if (m_isDeveloper)
extraParams << "&dev=1"; extraParams << "&dev=1";
@ -235,8 +229,7 @@ void CheckUpdateThreadLauncher::showUI()
} }
if (newVer) { if (newVer) {
m_delegate->onNewUpdate(m_preferences.updater.newUrl(), m_delegate->onNewUpdate(m_preferences.updater.newUrl(), m_preferences.updater.newVersion());
m_preferences.updater.newVersion());
} }
else { else {
// If the program was updated, reset the "exits" counter // If the program was updated, reset the "exits" counter
@ -249,6 +242,6 @@ void CheckUpdateThreadLauncher::showUI()
} }
} }
} } // namespace app
#endif // ENABLE_UPDATER #endif // ENABLE_UPDATER

View File

@ -11,56 +11,53 @@
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
#include "ui/timer.h" #include "ui/timer.h"
#include "updater/check_update.h" #include "updater/check_update.h"
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <thread> #include <thread>
namespace app { namespace app {
class CheckUpdateDelegate; class CheckUpdateDelegate;
class CheckUpdateBackgroundJob; class CheckUpdateBackgroundJob;
class Preferences; class Preferences;
class CheckUpdateThreadLauncher { class CheckUpdateThreadLauncher {
public: public:
CheckUpdateThreadLauncher(CheckUpdateDelegate* delegate); CheckUpdateThreadLauncher(CheckUpdateDelegate* delegate);
~CheckUpdateThreadLauncher(); ~CheckUpdateThreadLauncher();
void launch(); void launch();
bool isReceived() const; bool isReceived() const;
const updater::CheckUpdateResponse& getResponse() const const updater::CheckUpdateResponse& getResponse() const { return m_response; }
{
return m_response;
}
private: private:
void onMonitoringTick(); void onMonitoringTick();
void checkForUpdates(); void checkForUpdates();
void showUI(); void showUI();
CheckUpdateDelegate* m_delegate; CheckUpdateDelegate* m_delegate;
Preferences& m_preferences; Preferences& m_preferences;
updater::Uuid m_uuid; updater::Uuid m_uuid;
std::unique_ptr<std::thread> m_thread; std::unique_ptr<std::thread> m_thread;
std::unique_ptr<CheckUpdateBackgroundJob> m_bgJob; std::unique_ptr<CheckUpdateBackgroundJob> m_bgJob;
bool m_doCheck; bool m_doCheck;
std::atomic<bool> m_received; std::atomic<bool> m_received;
// Mini-stats // Mini-stats
int m_inits; int m_inits;
int m_exits; int m_exits;
// True if this is a developer // True if this is a developer
bool m_isDeveloper; bool m_isDeveloper;
updater::CheckUpdateResponse m_response; updater::CheckUpdateResponse m_response;
ui::Timer m_timer; ui::Timer m_timer;
}; };
} // namespace app } // namespace app

View File

@ -10,17 +10,17 @@
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
#include <string> #include <string>
namespace app { namespace app {
class CheckUpdateDelegate { class CheckUpdateDelegate {
public: public:
virtual ~CheckUpdateDelegate() { } virtual ~CheckUpdateDelegate() {}
virtual void onCheckingUpdates() = 0; virtual void onCheckingUpdates() = 0;
virtual void onUpToDate() = 0; virtual void onUpToDate() = 0;
virtual void onNewUpdate(const std::string& url, const std::string& version) = 0; virtual void onNewUpdate(const std::string& url, const std::string& version) = 0;
}; };
} // namespace app } // namespace app

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cli/app_options.h" #include "app/cli/app_options.h"
@ -29,60 +29,145 @@ AppOptions::AppOptions(int argc, const char* argv[])
, m_shell(m_po.add("shell").description("Start an interactive console to execute scripts")) , m_shell(m_po.add("shell").description("Start an interactive console to execute scripts"))
#endif #endif
, m_batch(m_po.add("batch").mnemonic('b').description("Do not start the UI")) , m_batch(m_po.add("batch").mnemonic('b').description("Do not start the UI"))
, m_preview(m_po.add("preview").mnemonic('p').description("Do not execute actions, just print what will be\ndone")) , m_preview(m_po.add("preview").mnemonic('p').description(
, m_saveAs(m_po.add("save-as").requiresValue("<filename>").description("Save the last given sprite with other format")) "Do not execute actions, just print what will be\ndone"))
, m_palette(m_po.add("palette").requiresValue("<filename>").description("Change the palette of the last given sprite")) , m_saveAs(m_po.add("save-as")
, m_scale(m_po.add("scale").requiresValue("<factor>").description("Resize all previously opened sprites")) .requiresValue("<filename>")
, m_ditheringAlgorithm(m_po.add("dithering-algorithm").requiresValue("<algorithm>").description("Dithering algorithm used in --color-mode\nto convert images from RGB to Indexed\n none\n ordered\n old")) .description("Save the last given sprite with other format"))
, m_ditheringMatrix(m_po.add("dithering-matrix").requiresValue("<id>").description("Matrix used in ordered dithering algorithm\n bayer2x2\n bayer4x4\n bayer8x8\n filename.png")) , m_palette(m_po.add("palette")
, m_colorMode(m_po.add("color-mode").requiresValue("<mode>").description("Change color mode of all previously\nopened sprites:\n rgb\n grayscale\n indexed")) .requiresValue("<filename>")
, m_shrinkTo(m_po.add("shrink-to").requiresValue("width,height").description("Shrink each sprite if it is\nlarger than width or height")) .description("Change the palette of the last given sprite"))
, m_data(m_po.add("data").requiresValue("<filename.json>").description("File to store the sprite sheet metadata")) , m_scale(m_po.add("scale")
, m_format(m_po.add("format").requiresValue("<format>").description("Format to export the data file\n(json-hash, json-array)")) .requiresValue("<factor>")
, m_sheet(m_po.add("sheet").requiresValue("<filename.png>").description("Image file to save the texture")) .description("Resize all previously opened sprites"))
, m_sheetType(m_po.add("sheet-type").requiresValue("<type>").description("Algorithm to create the sprite sheet:\n horizontal\n vertical\n rows\n columns\n packed")) , m_ditheringAlgorithm(
m_po.add("dithering-algorithm")
.requiresValue("<algorithm>")
.description(
"Dithering algorithm used in --color-mode\nto convert images from RGB to Indexed\n none\n ordered\n old"))
, m_ditheringMatrix(
m_po.add("dithering-matrix")
.requiresValue("<id>")
.description(
"Matrix used in ordered dithering algorithm\n bayer2x2\n bayer4x4\n bayer8x8\n filename.png"))
, m_colorMode(
m_po.add("color-mode")
.requiresValue("<mode>")
.description(
"Change color mode of all previously\nopened sprites:\n rgb\n grayscale\n indexed"))
, m_shrinkTo(m_po.add("shrink-to")
.requiresValue("width,height")
.description("Shrink each sprite if it is\nlarger than width or height"))
, m_data(m_po.add("data")
.requiresValue("<filename.json>")
.description("File to store the sprite sheet metadata"))
, m_format(m_po.add("format")
.requiresValue("<format>")
.description("Format to export the data file\n(json-hash, json-array)"))
, m_sheet(m_po.add("sheet")
.requiresValue("<filename.png>")
.description("Image file to save the texture"))
, m_sheetType(
m_po.add("sheet-type")
.requiresValue("<type>")
.description(
"Algorithm to create the sprite sheet:\n horizontal\n vertical\n rows\n columns\n packed"))
, m_sheetPack(m_po.add("sheet-pack").description("Same as -sheet-type packed")) , m_sheetPack(m_po.add("sheet-pack").description("Same as -sheet-type packed"))
, m_sheetWidth(m_po.add("sheet-width").requiresValue("<pixels>").description("Sprite sheet width")) , m_sheetWidth(
, m_sheetHeight(m_po.add("sheet-height").requiresValue("<pixels>").description("Sprite sheet height")) m_po.add("sheet-width").requiresValue("<pixels>").description("Sprite sheet width"))
, m_sheetColumns(m_po.add("sheet-columns").requiresValue("<columns>").description("Fixed # of columns for -sheet-type rows")) , m_sheetHeight(
, m_sheetRows(m_po.add("sheet-rows").requiresValue("<rows>").description("Fixed # of rows for -sheet-type columns")) m_po.add("sheet-height").requiresValue("<pixels>").description("Sprite sheet height"))
, m_splitLayers(m_po.add("split-layers").description("Save each visible layer of sprites\nas separated images in the sheet\n")) , m_sheetColumns(m_po.add("sheet-columns")
.requiresValue("<columns>")
.description("Fixed # of columns for -sheet-type rows"))
, m_sheetRows(m_po.add("sheet-rows")
.requiresValue("<rows>")
.description("Fixed # of rows for -sheet-type columns"))
, m_splitLayers(
m_po.add("split-layers")
.description("Save each visible layer of sprites\nas separated images in the sheet\n"))
, m_splitTags(m_po.add("split-tags").description("Save each tag as a separated file")) , m_splitTags(m_po.add("split-tags").description("Save each tag as a separated file"))
, m_splitSlices(m_po.add("split-slices").description("Save each slice as a separated file")) , m_splitSlices(m_po.add("split-slices").description("Save each slice as a separated file"))
, m_splitGrid(m_po.add("split-grid").description("Save each grid tile as a separated file")) , m_splitGrid(m_po.add("split-grid").description("Save each grid tile as a separated file"))
, m_layer(m_po.add("layer").alias("import-layer").requiresValue("<name>").description("Include just the given layer in the sheet\nor save as operation")) , m_layer(m_po.add("layer")
, m_allLayers(m_po.add("all-layers").description("Make all layers visible\nBy default hidden layers will be ignored")) .alias("import-layer")
, m_ignoreLayer(m_po.add("ignore-layer").requiresValue("<name>").description("Exclude the given layer in the sheet\nor save as operation")) .requiresValue("<name>")
, m_tag(m_po.add("tag").alias("frame-tag").requiresValue("<name>").description("Include tagged frames in the sheet")) .description("Include just the given layer in the sheet\nor save as operation"))
, m_playSubtags(m_po.add("play-subtags").description("Play subtags and repeats when saving the frames of an animated sprite")) , m_allLayers(m_po.add("all-layers")
, m_frameRange(m_po.add("frame-range").requiresValue("from,to").description("Only export frames in the [from,to] range")) .description("Make all layers visible\nBy default hidden layers will be ignored"))
, m_ignoreLayer(m_po.add("ignore-layer")
.requiresValue("<name>")
.description("Exclude the given layer in the sheet\nor save as operation"))
, m_tag(m_po.add("tag")
.alias("frame-tag")
.requiresValue("<name>")
.description("Include tagged frames in the sheet"))
, m_playSubtags(
m_po.add("play-subtags")
.description("Play subtags and repeats when saving the frames of an animated sprite"))
, m_frameRange(m_po.add("frame-range")
.requiresValue("from,to")
.description("Only export frames in the [from,to] range"))
, m_ignoreEmpty(m_po.add("ignore-empty").description("Do not export empty frames/cels")) , m_ignoreEmpty(m_po.add("ignore-empty").description("Do not export empty frames/cels"))
, m_mergeDuplicates(m_po.add("merge-duplicates").description("Merge all duplicate frames into one in the sprite sheet")) , m_mergeDuplicates(m_po.add("merge-duplicates")
, m_borderPadding(m_po.add("border-padding").requiresValue("<value>").description("Add padding on the texture borders")) .description("Merge all duplicate frames into one in the sprite sheet"))
, m_shapePadding(m_po.add("shape-padding").requiresValue("<value>").description("Add padding between frames")) , m_borderPadding(m_po.add("border-padding")
, m_innerPadding(m_po.add("inner-padding").requiresValue("<value>").description("Add padding inside each frame")) .requiresValue("<value>")
, m_trim(m_po.add("trim").description("Trim whole sprite for --save-as\nor individual frames for --sheet")) .description("Add padding on the texture borders"))
, m_trimSprite(m_po.add("trim-sprite").description("Trim the whole sprite (for --save-as and --sheet)")) , m_shapePadding(
, m_trimByGrid(m_po.add("trim-by-grid").description("Trim all images by its correspondent grid boundaries before exporting")) m_po.add("shape-padding").requiresValue("<value>").description("Add padding between frames"))
, m_innerPadding(m_po.add("inner-padding")
.requiresValue("<value>")
.description("Add padding inside each frame"))
, m_trim(m_po.add("trim").description(
"Trim whole sprite for --save-as\nor individual frames for --sheet"))
, m_trimSprite(
m_po.add("trim-sprite").description("Trim the whole sprite (for --save-as and --sheet)"))
, m_trimByGrid(
m_po.add("trim-by-grid")
.description("Trim all images by its correspondent grid boundaries before exporting"))
, m_extrude(m_po.add("extrude").description("Extrude all images duplicating all edges one pixel")) , m_extrude(m_po.add("extrude").description("Extrude all images duplicating all edges one pixel"))
, m_crop(m_po.add("crop").requiresValue("x,y,width,height").description("Crop all the images to the given rectangle")) , m_crop(m_po.add("crop")
, m_slice(m_po.add("slice").requiresValue("<name>").description("Crop the sprite to the given slice area")) .requiresValue("x,y,width,height")
, m_filenameFormat(m_po.add("filename-format").requiresValue("<fmt>").description("Special format to generate filenames")) .description("Crop all the images to the given rectangle"))
, m_tagnameFormat(m_po.add("tagname-format").requiresValue("<fmt>").description("Special format to generate tagnames in JSON data")) , m_slice(m_po.add("slice").requiresValue("<name>").description(
"Crop the sprite to the given slice area"))
, m_filenameFormat(m_po.add("filename-format")
.requiresValue("<fmt>")
.description("Special format to generate filenames"))
, m_tagnameFormat(m_po.add("tagname-format")
.requiresValue("<fmt>")
.description("Special format to generate tagnames in JSON data"))
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
, m_script(m_po.add("script").requiresValue("<filename>").description("Execute a specific script")) , m_script(
, m_scriptParam(m_po.add("script-param").requiresValue("name=value").description("Parameter for a script executed from the\nCLI that you can access with app.params")) m_po.add("script").requiresValue("<filename>").description("Execute a specific script"))
, m_scriptParam(
m_po.add("script-param")
.requiresValue("name=value")
.description(
"Parameter for a script executed from the\nCLI that you can access with app.params"))
#endif #endif
, m_listLayers(m_po.add("list-layers").description("List layers of the next given sprite\nor include layers in JSON data")) , m_listLayers(
, m_listLayerHierarchy(m_po.add("list-layer-hierarchy").description("List layers with groups of the next given sprite\nor include layers hierarchy in JSON data")) m_po.add("list-layers")
, m_listTags(m_po.add("list-tags").description("List tags of the next given sprite\nor include frame tags in JSON data")) .description("List layers of the next given sprite\nor include layers in JSON data"))
, m_listSlices(m_po.add("list-slices").description("List slices of the next given sprite\nor include slices in JSON data")) , m_listLayerHierarchy(
m_po.add("list-layer-hierarchy")
.description(
"List layers with groups of the next given sprite\nor include layers hierarchy in JSON data"))
, m_listTags(
m_po.add("list-tags")
.description("List tags of the next given sprite\nor include frame tags in JSON data"))
, m_listSlices(
m_po.add("list-slices")
.description("List slices of the next given sprite\nor include slices in JSON data"))
, m_oneFrame(m_po.add("oneframe").description("Load just the first frame")) , m_oneFrame(m_po.add("oneframe").description("Load just the first frame"))
, m_exportTileset(m_po.add("export-tileset").description("Export only tilesets from visible tilemap layers")) , m_exportTileset(
m_po.add("export-tileset").description("Export only tilesets from visible tilemap layers"))
, m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done")) , m_verbose(m_po.add("verbose").mnemonic('v').description("Explain what is being done"))
, m_debug(m_po.add("debug").description("Extreme verbose mode and\ncopy log to desktop")) , m_debug(m_po.add("debug").description("Extreme verbose mode and\ncopy log to desktop"))
#ifdef ENABLE_STEAM #ifdef ENABLE_STEAM
, m_noInApp(m_po.add("noinapp").description("Disable \"in game\" visibility on Steam\nDoesn't count playtime")) , m_noInApp(m_po.add("noinapp").description(
"Disable \"in game\" visibility on Steam\nDoesn't count playtime"))
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
, m_disableWintab(m_po.add("disable-wintab").description("Don't load wintab32.dll library")) , m_disableWintab(m_po.add("disable-wintab").description("Don't load wintab32.dll library"))
@ -105,10 +190,7 @@ AppOptions::AppOptions(int argc, const char* argv[])
m_showHelp = m_po.enabled(m_help); m_showHelp = m_po.enabled(m_help);
m_showVersion = m_po.enabled(m_version); m_showVersion = m_po.enabled(m_version);
if (m_startShell || if (m_startShell || m_showHelp || m_showVersion || m_po.enabled(m_batch)) {
m_showHelp ||
m_showVersion ||
m_po.enabled(m_batch)) {
m_startUI = false; m_startUI = false;
} }
} }
@ -121,9 +203,7 @@ AppOptions::AppOptions(int argc, const char* argv[])
bool AppOptions::hasExporterParams() const bool AppOptions::hasExporterParams() const
{ {
return return m_po.enabled(m_data) || m_po.enabled(m_sheet);
m_po.enabled(m_data) ||
m_po.enabled(m_sheet);
} }
#ifdef ENABLE_STEAM #ifdef ENABLE_STEAM
@ -140,4 +220,4 @@ bool AppOptions::disableWintab() const
} }
#endif #endif
} } // namespace app

View File

@ -21,8 +21,8 @@ class AppOptions {
public: public:
enum VerboseLevel { enum VerboseLevel {
kNoVerbose, kNoVerbose,
kVerbose, // --verbose kVerbose, // --verbose
kHighlyVerbose, // --debug kHighlyVerbose, // --debug
}; };
typedef base::ProgramOptions PO; typedef base::ProgramOptions PO;
@ -41,9 +41,7 @@ public:
bool showVersion() const { return m_showVersion; } bool showVersion() const { return m_showVersion; }
VerboseLevel verboseLevel() const { return m_verboseLevel; } VerboseLevel verboseLevel() const { return m_verboseLevel; }
const ValueList& values() const { const ValueList& values() const { return m_po.values(); }
return m_po.values();
}
// Export options // Export options
const Option& saveAs() const { return m_saveAs; } const Option& saveAs() const { return m_saveAs; }
@ -181,7 +179,6 @@ private:
#endif #endif
Option& m_help; Option& m_help;
Option& m_version; Option& m_version;
}; };
} // namespace app } // namespace app

View File

@ -13,32 +13,29 @@
namespace app { namespace app {
class AppOptions; class AppOptions;
class Context; class Context;
class DocExporter; class DocExporter;
class Params; class Params;
struct CliOpenFile; struct CliOpenFile;
class CliDelegate { class CliDelegate {
public: public:
virtual ~CliDelegate() { } virtual ~CliDelegate() {}
virtual void showHelp(const AppOptions& options) { } virtual void showHelp(const AppOptions& options) {}
virtual void showVersion() { } virtual void showVersion() {}
virtual void uiMode() { } virtual void uiMode() {}
virtual void shellMode() { } virtual void shellMode() {}
virtual void batchMode() { } virtual void batchMode() {}
virtual void beforeOpenFile(const CliOpenFile& cof) { } virtual void beforeOpenFile(const CliOpenFile& cof) {}
virtual void afterOpenFile(const CliOpenFile& cof) { } virtual void afterOpenFile(const CliOpenFile& cof) {}
virtual void saveFile(Context* ctx, const CliOpenFile& cof) { } virtual void saveFile(Context* ctx, const CliOpenFile& cof) {}
virtual void loadPalette(Context* ctx, const std::string& filename) { } virtual void loadPalette(Context* ctx, const std::string& filename) {}
virtual void exportFiles(Context* ctx, DocExporter& exporter) { } virtual void exportFiles(Context* ctx, DocExporter& exporter) {}
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
virtual int execScript(const std::string& filename, virtual int execScript(const std::string& filename, const Params& params) { return 0; }
const Params& params) {
return 0;
}
#endif // ENABLE_SCRIPTING #endif // ENABLE_SCRIPTING
}; };
} // namespace app } // namespace app

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cli/cli_open_file.h" #include "app/cli/cli_open_file.h"

View File

@ -17,56 +17,47 @@
namespace app { namespace app {
class Doc; class Doc;
class FileOpROI; class FileOpROI;
struct CliOpenFile { struct CliOpenFile {
Doc* document = nullptr; Doc* document = nullptr;
std::string filename; std::string filename;
std::string filenameFormat; std::string filenameFormat;
std::string tagnameFormat; std::string tagnameFormat;
std::string tag; std::string tag;
std::string slice; std::string slice;
std::vector<std::string> includeLayers; std::vector<std::string> includeLayers;
std::vector<std::string> excludeLayers; std::vector<std::string> excludeLayers;
doc::frame_t fromFrame = -1; doc::frame_t fromFrame = -1;
doc::frame_t toFrame = -1; doc::frame_t toFrame = -1;
bool splitLayers = false; bool splitLayers = false;
bool splitTags = false; bool splitTags = false;
bool splitSlices = false; bool splitSlices = false;
bool splitGrid = false; bool splitGrid = false;
bool allLayers = false; bool allLayers = false;
bool listLayers = false; bool listLayers = false;
bool listLayerHierarchy = false; bool listLayerHierarchy = false;
bool listTags = false; bool listTags = false;
bool listSlices = false; bool listSlices = false;
bool ignoreEmpty = false; bool ignoreEmpty = false;
bool trim = false; bool trim = false;
bool trimByGrid = false; bool trimByGrid = false;
bool oneFrame = false; bool oneFrame = false;
bool exportTileset = false; bool exportTileset = false;
bool playSubtags = false; bool playSubtags = false;
gfx::Rect crop; gfx::Rect crop;
bool hasTag() const { bool hasTag() const { return (!tag.empty()); }
return (!tag.empty());
}
bool hasSlice() const { bool hasSlice() const { return (!slice.empty()); }
return (!slice.empty());
}
bool hasFrameRange() const { bool hasFrameRange() const { return (fromFrame >= 0 && toFrame >= 0); }
return (fromFrame >= 0 && toFrame >= 0);
}
bool hasLayersFilter() const { bool hasLayersFilter() const { return (!includeLayers.empty() || !excludeLayers.empty()); }
return (!includeLayers.empty() ||
!excludeLayers.empty());
}
FileOpROI roi() const; FileOpROI roi() const;
}; };
} // namespace app } // namespace app

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cli/cli_processor.h" #include "app/cli/cli_processor.h"
@ -44,9 +44,7 @@ namespace app {
namespace { namespace {
bool match_path(const std::string& filter, bool match_path(const std::string& filter, const std::string& layer_path, const bool exclude)
const std::string& layer_path,
const bool exclude)
{ {
if (filter == layer_path) if (filter == layer_path)
return true; return true;
@ -55,21 +53,18 @@ bool match_path(const std::string& filter,
base::split_string(filter, a, "/"); base::split_string(filter, a, "/");
base::split_string(layer_path, b, "/"); base::split_string(layer_path, b, "/");
for (std::size_t i=0; i<a.size() && i<b.size(); ++i) { for (std::size_t i = 0; i < a.size() && i < b.size(); ++i) {
if (a[i] != b[i] && a[i] != "*") if (a[i] != b[i] && a[i] != "*")
return false; return false;
} }
const bool wildcard = (!a.empty() && a[a.size()-1] == "*"); const bool wildcard = (!a.empty() && a[a.size() - 1] == "*");
// Exclude group itself when all children are excluded. This special // Exclude group itself when all children are excluded. This special
// case is only for exclusion because if we leave the group // case is only for exclusion because if we leave the group
// selected, the propagation of the selection will include all // selected, the propagation of the selection will include all
// visible children too (see SelectedLayers::propagateSelection()). // visible children too (see SelectedLayers::propagateSelection()).
if (exclude && if (exclude && a.size() > 1 && a.size() == b.size() + 1 && wildcard) {
a.size() > 1 &&
a.size() == b.size()+1 &&
wildcard) {
return true; return true;
} }
@ -95,9 +90,8 @@ bool filter_layer(const std::string& layer_path,
// If there is one layer with the given name "filter", we can convert // If there is one layer with the given name "filter", we can convert
// the filter to a full path to the layer (e.g. to match child layers // the filter to a full path to the layer (e.g. to match child layers
// of a group). // of a group).
std::string convert_filter_to_layer_path_if_possible( std::string convert_filter_to_layer_path_if_possible(const Sprite* sprite,
const Sprite* sprite, const std::string& filter)
const std::string& filter)
{ {
std::string fullName; std::string fullName;
std::queue<Layer*> layers; std::queue<Layer*> layers;
@ -107,8 +101,7 @@ std::string convert_filter_to_layer_path_if_possible(
const Layer* layer = layers.front(); const Layer* layer = layers.front();
layers.pop(); layers.pop();
if (layer != sprite->root() && if (layer != sprite->root() && layer->name() == filter) {
layer->name() == filter) {
if (fullName.empty()) { if (fullName.empty()) {
fullName = get_layer_path(layer); fullName = get_layer_path(layer);
} }
@ -152,16 +145,14 @@ void CliProcessor::FilterLayers(const Sprite* sprite,
(!includes.empty() && !filter_layer(layer_path, includes, true))) (!includes.empty() && !filter_layer(layer_path, includes, true)))
continue; continue;
if (!excludes.empty() && if (!excludes.empty() && !filter_layer(layer_path, excludes, false))
!filter_layer(layer_path, excludes, false))
continue; continue;
filteredLayers.insert(layer); filteredLayers.insert(layer);
} }
} }
CliProcessor::CliProcessor(CliDelegate* delegate, CliProcessor::CliProcessor(CliDelegate* delegate, const AppOptions& options)
const AppOptions& options)
: m_delegate(delegate) : m_delegate(delegate)
, m_options(options) , m_options(options)
, m_exporter(nullptr) , m_exporter(nullptr)
@ -307,7 +298,7 @@ int CliProcessor::process(Context* ctx)
"E.g. --frame-range 0,99"); "E.g. --frame-range 0,99");
cof.fromFrame = base::convert_to<frame_t>(splitRange[0]); cof.fromFrame = base::convert_to<frame_t>(splitRange[0]);
cof.toFrame = base::convert_to<frame_t>(splitRange[1]); cof.toFrame = base::convert_to<frame_t>(splitRange[1]);
} }
// --ignore-empty // --ignore-empty
else if (opt == &m_options.ignoreEmpty()) { else if (opt == &m_options.ignoreEmpty()) {
@ -403,7 +394,7 @@ int CliProcessor::process(Context* ctx)
// in case the output filename already contains {layer}, // in case the output filename already contains {layer},
// {tag}, or {slice} template elements. // {tag}, or {slice} template elements.
bool hasLayerTemplate = (is_layer_in_filename_format(fn) || bool hasLayerTemplate = (is_layer_in_filename_format(fn) ||
is_group_in_filename_format(fn)); is_group_in_filename_format(fn));
bool hasTagTemplate = is_tag_in_filename_format(fn); bool hasTagTemplate = is_tag_in_filename_format(fn);
bool hasSliceTemplate = is_slice_in_filename_format(fn); bool hasSliceTemplate = is_slice_in_filename_format(fn);
@ -451,8 +442,7 @@ int CliProcessor::process(Context* ctx)
// Scale all sprites // Scale all sprites
for (auto doc : ctx->documents()) { for (auto doc : ctx->documents()) {
ctx->setActiveDocument(doc); ctx->setActiveDocument(doc);
ctx->executeCommand(Commands::instance()->byId(CommandId::SpriteSize()), ctx->executeCommand(Commands::instance()->byId(CommandId::SpriteSize()), params);
params);
} }
} }
// --dithering-algorithm <algorithm> // --dithering-algorithm <algorithm>
@ -466,9 +456,10 @@ int CliProcessor::process(Context* ctx)
else if (value.value() == "error-diffusion") else if (value.value() == "error-diffusion")
ditheringAlgorithm = render::DitheringAlgorithm::ErrorDiffusion; ditheringAlgorithm = render::DitheringAlgorithm::ErrorDiffusion;
else else
throw std::runtime_error("--dithering-algorithm needs a valid algorithm name\n" throw std::runtime_error(
"Usage: --dithering-algorithm <algorithm>\n" "--dithering-algorithm needs a valid algorithm name\n"
"Where <algorithm> can be none, ordered, old, or error-diffusion"); "Usage: --dithering-algorithm <algorithm>\n"
"Where <algorithm> can be none, ordered, old, or error-diffusion");
} }
// --dithering-matrix <id> // --dithering-matrix <id>
else if (opt == &m_options.ditheringMatrix()) { else if (opt == &m_options.ditheringMatrix()) {
@ -487,15 +478,9 @@ int CliProcessor::process(Context* ctx)
else if (value.value() == "indexed") { else if (value.value() == "indexed") {
params.set("format", "indexed"); params.set("format", "indexed");
switch (ditheringAlgorithm) { switch (ditheringAlgorithm) {
case render::DitheringAlgorithm::None: case render::DitheringAlgorithm::None: params.set("dithering", "none"); break;
params.set("dithering", "none"); case render::DitheringAlgorithm::Ordered: params.set("dithering", "ordered"); break;
break; case render::DitheringAlgorithm::Old: params.set("dithering", "old"); break;
case render::DitheringAlgorithm::Ordered:
params.set("dithering", "ordered");
break;
case render::DitheringAlgorithm::Old:
params.set("dithering", "old");
break;
case render::DitheringAlgorithm::ErrorDiffusion: case render::DitheringAlgorithm::ErrorDiffusion:
params.set("dithering", "error-diffusion"); params.set("dithering", "error-diffusion");
break; break;
@ -539,8 +524,7 @@ int CliProcessor::process(Context* ctx)
scale = std::min(scaleWidth, scaleHeight); scale = std::min(scaleWidth, scaleHeight);
Params params; Params params;
params.set("scale", base::convert_to<std::string>(scale).c_str()); params.set("scale", base::convert_to<std::string>(scale).c_str());
ctx->executeCommand(Commands::instance()->byId(CommandId::SpriteSize()), ctx->executeCommand(Commands::instance()->byId(CommandId::SpriteSize()), params);
params);
} }
} }
} }
@ -564,8 +548,7 @@ int CliProcessor::process(Context* ctx)
const std::string& v = value.value(); const std::string& v = value.value();
auto i = v.find('='); auto i = v.find('=');
if (i != std::string::npos) if (i != std::string::npos)
scriptParams.set(v.substr(0, i).c_str(), scriptParams.set(v.substr(0, i).c_str(), v.substr(i + 1).c_str());
v.substr(i+1).c_str());
else else
scriptParams.set(v.c_str(), "1"); scriptParams.set(v.c_str(), "1");
} }
@ -612,11 +595,11 @@ int CliProcessor::process(Context* ctx)
cof.document = nullptr; cof.document = nullptr;
cof.filename = base::normalize_path(value.value()); cof.filename = base::normalize_path(value.value());
if (// Check that the filename wasn't used loading a sequence if ( // Check that the filename wasn't used loading a sequence
// of images as one sprite // of images as one sprite
m_usedFiles.find(cof.filename) == m_usedFiles.end() && m_usedFiles.find(cof.filename) == m_usedFiles.end() &&
// Open sprite // Open sprite
openFile(ctx, cof)) { openFile(ctx, cof)) {
lastDoc = cof.document; lastDoc = cof.document;
} }
} }
@ -652,9 +635,7 @@ bool CliProcessor::openFile(Context* ctx, CliOpenFile& cof)
Doc* oldDoc = ctx->activeDocument(); Doc* oldDoc = ctx->activeDocument();
m_batch.open(ctx, m_batch.open(ctx, cof.filename, cof.oneFrame);
cof.filename,
cof.oneFrame);
// Mark used file names as "already processed" so we don't try to // Mark used file names as "already processed" so we don't try to
// open then again // open then again
@ -691,9 +672,8 @@ bool CliProcessor::openFile(Context* ctx, CliOpenFile& cof)
if (cof.hasFrameRange()) { if (cof.hasFrameRange()) {
// --frame-range with --frame-tag // --frame-range with --frame-tag
if (tag) { if (tag) {
selFrames.insert( selFrames.insert(tag->fromFrame() + std::clamp(cof.fromFrame, 0, tag->frames() - 1),
tag->fromFrame()+std::clamp(cof.fromFrame, 0, tag->frames()-1), tag->fromFrame() + std::clamp(cof.toFrame, 0, tag->frames() - 1));
tag->fromFrame()+std::clamp(cof.toFrame, 0, tag->frames()-1));
} }
// --frame-range without --frame-tag // --frame-range without --frame-tag
else { else {
@ -706,25 +686,23 @@ bool CliProcessor::openFile(Context* ctx, CliOpenFile& cof)
filterLayers(doc->sprite(), cof, filteredLayers); filterLayers(doc->sprite(), cof, filteredLayers);
if (cof.exportTileset) { if (cof.exportTileset) {
m_exporter->addTilesetsSamples( m_exporter->addTilesetsSamples(doc, (cof.hasLayersFilter() ? &filteredLayers : nullptr));
doc,
(cof.hasLayersFilter() ? &filteredLayers: nullptr));
} }
else { else {
m_exporter->addDocumentSamples( m_exporter->addDocumentSamples(doc,
doc, tag, tag,
cof.splitLayers, cof.splitLayers,
cof.splitTags, cof.splitTags,
cof.splitGrid, cof.splitGrid,
(cof.hasLayersFilter() ? &filteredLayers: nullptr), (cof.hasLayersFilter() ? &filteredLayers : nullptr),
(!selFrames.empty() ? &selFrames: nullptr)); (!selFrames.empty() ? &selFrames : nullptr));
} }
} }
} }
m_delegate->afterOpenFile(cof); m_delegate->afterOpenFile(cof);
return (doc ? true: false); return (doc ? true : false);
} }
void CliProcessor::saveFile(Context* ctx, const CliOpenFile& cof) void CliProcessor::saveFile(Context* ctx, const CliOpenFile& cof)
@ -742,21 +720,18 @@ void CliProcessor::saveFile(Context* ctx, const CliOpenFile& cof)
cropParams.set("y", base::convert_to<std::string>(cof.crop.y).c_str()); cropParams.set("y", base::convert_to<std::string>(cof.crop.y).c_str());
cropParams.set("width", base::convert_to<std::string>(cof.crop.w).c_str()); cropParams.set("width", base::convert_to<std::string>(cof.crop.w).c_str());
cropParams.set("height", base::convert_to<std::string>(cof.crop.h).c_str()); cropParams.set("height", base::convert_to<std::string>(cof.crop.h).c_str());
ctx->executeCommand( ctx->executeCommand(Commands::instance()->byId(CommandId::CropSprite()), cropParams);
Commands::instance()->byId(CommandId::CropSprite()),
cropParams);
} }
std::string fn = cof.filename; std::string fn = cof.filename;
std::string filenameFormat = cof.filenameFormat; std::string filenameFormat = cof.filenameFormat;
if (filenameFormat.empty()) { // Default format if (filenameFormat.empty()) { // Default format
bool hasFrames = (cof.roi().frames() > 1); bool hasFrames = (cof.roi().frames() > 1);
filenameFormat = get_default_filename_format( filenameFormat = get_default_filename_format(fn,
fn, true, // With path
true, // With path hasFrames, // Has frames
hasFrames, // Has frames cof.splitLayers, // Has layer
cof.splitLayers, // Has layer cof.splitTags); // Has frame tag
cof.splitTags); // Has frame tag
} }
SelectedLayers filteredLayers; SelectedLayers filteredLayers;
@ -777,8 +752,7 @@ void CliProcessor::saveFile(Context* ctx, const CliOpenFile& cof)
std::vector<doc::Tag*> tags; std::vector<doc::Tag*> tags;
if (cof.hasTag()) { if (cof.hasTag()) {
tags.push_back( tags.push_back(doc->sprite()->tags().getByName(cof.tag));
doc->sprite()->tags().getByName(cof.tag));
} }
else { else {
doc::Tags& origTags = cof.document->sprite()->tags(); doc::Tags& origTags = cof.document->sprite()->tags();
@ -786,8 +760,7 @@ void CliProcessor::saveFile(Context* ctx, const CliOpenFile& cof)
for (doc::Tag* tag : origTags) { for (doc::Tag* tag : origTags) {
// In case the tag is outside the given --frame-range // In case the tag is outside the given --frame-range
if (cof.hasFrameRange()) { if (cof.hasFrameRange()) {
if (tag->toFrame() < cof.fromFrame || if (tag->toFrame() < cof.fromFrame || tag->fromFrame() > cof.toFrame)
tag->fromFrame() > cof.toFrame)
continue; continue;
} }
tags.push_back(tag); tags.push_back(tag);
@ -799,8 +772,7 @@ void CliProcessor::saveFile(Context* ctx, const CliOpenFile& cof)
std::vector<doc::Slice*> slices; std::vector<doc::Slice*> slices;
if (cof.hasSlice()) { if (cof.hasSlice()) {
slices.push_back( slices.push_back(doc->sprite()->slices().getByName(cof.slice));
doc->sprite()->slices().getByName(cof.slice));
} }
else { else {
doc::Slices& origSlices = cof.document->sprite()->slices(); doc::Slices& origSlices = cof.document->sprite()->slices();
@ -826,7 +798,7 @@ void CliProcessor::saveFile(Context* ctx, const CliOpenFile& cof)
// If the user doesn't want all layers and this one is hidden. // If the user doesn't want all layers and this one is hidden.
if (!layer->isVisible()) if (!layer->isVisible())
continue; // Just ignore this layer. continue; // Just ignore this layer.
// Make this layer ("show") the only one visible. // Make this layer ("show") the only one visible.
layersVisibility.showLayer(layer); layersVisibility.showLayer(layer);
@ -868,9 +840,7 @@ void CliProcessor::saveFile(Context* ctx, const CliOpenFile& cof)
itemCof.includeLayers.push_back(layer->name()); itemCof.includeLayers.push_back(layer->name());
} }
if (tag) { if (tag) {
fnInfo fnInfo.innerTagName(tag->name()).outerTagName(tag->name());
.innerTagName(tag->name())
.outerTagName(tag->name());
itemCof.tag = tag->name(); itemCof.tag = tag->name();
} }
if (slice) { if (slice) {

View File

@ -21,51 +21,47 @@
#include <vector> #include <vector>
namespace doc { namespace doc {
class Sprite; class Sprite;
} }
namespace app { namespace app {
class AppOptions; class AppOptions;
class Context; class Context;
class DocExporter; class DocExporter;
class CliProcessor { class CliProcessor {
public: public:
CliProcessor(CliDelegate* delegate, CliProcessor(CliDelegate* delegate, const AppOptions& options);
const AppOptions& options); int process(Context* ctx);
int process(Context* ctx);
// Public so it can be tested // Public so it can be tested
static void FilterLayers(const doc::Sprite* sprite, static void FilterLayers(const doc::Sprite* sprite,
// By value because these vectors will be modified inside // By value because these vectors will be modified inside
std::vector<std::string> includes, std::vector<std::string> includes,
std::vector<std::string> excludes, std::vector<std::string> excludes,
doc::SelectedLayers& filteredLayers); doc::SelectedLayers& filteredLayers);
private: private:
bool openFile(Context* ctx, CliOpenFile& cof); bool openFile(Context* ctx, CliOpenFile& cof);
void saveFile(Context* ctx, const CliOpenFile& cof); void saveFile(Context* ctx, const CliOpenFile& cof);
void filterLayers(const doc::Sprite* sprite, void filterLayers(const doc::Sprite* sprite,
const CliOpenFile& cof, const CliOpenFile& cof,
doc::SelectedLayers& filteredLayers) { doc::SelectedLayers& filteredLayers)
CliProcessor::FilterLayers( {
sprite, CliProcessor::FilterLayers(sprite, cof.includeLayers, cof.excludeLayers, filteredLayers);
cof.includeLayers, }
cof.excludeLayers,
filteredLayers);
}
CliDelegate* m_delegate; CliDelegate* m_delegate;
const AppOptions& m_options; const AppOptions& m_options;
std::unique_ptr<DocExporter> m_exporter; std::unique_ptr<DocExporter> m_exporter;
// Files already used in the CLI processing (e.g. when used to // Files already used in the CLI processing (e.g. when used to
// load a sequence of files) so we don't ask for them again. // load a sequence of files) so we don't ask for them again.
std::set<std::string> m_usedFiles; std::set<std::string> m_usedFiles;
OpenBatchOfFiles m_batch; OpenBatchOfFiles m_batch;
}; };
} // namespace app } // namespace app

View File

@ -17,7 +17,8 @@ using namespace app;
class CliTestDelegate : public CliDelegate { class CliTestDelegate : public CliDelegate {
public: public:
CliTestDelegate() { CliTestDelegate()
{
m_helpWasShown = false; m_helpWasShown = false;
m_versionWasShown = false; m_versionWasShown = false;
m_uiMode = false; m_uiMode = false;
@ -30,15 +31,12 @@ public:
void uiMode() override { m_uiMode = true; } void uiMode() override { m_uiMode = true; }
void shellMode() override { m_shellMode = true; } void shellMode() override { m_shellMode = true; }
void batchMode() override { m_batchMode = true; } void batchMode() override { m_batchMode = true; }
void beforeOpenFile(const CliOpenFile& cof) override { } void beforeOpenFile(const CliOpenFile& cof) override {}
void afterOpenFile(const CliOpenFile& cof) override { } void afterOpenFile(const CliOpenFile& cof) override {}
void saveFile(Context* ctx, const CliOpenFile& cof) override { } void saveFile(Context* ctx, const CliOpenFile& cof) override {}
void exportFiles(Context* ctx, DocExporter& exporter) override { } void exportFiles(Context* ctx, DocExporter& exporter) override {}
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
int execScript(const std::string& filename, int execScript(const std::string& filename, const Params& params) override { return 0; }
const Params& params) override {
return 0;
}
#endif #endif
bool helpWasShown() const { return m_helpWasShown; } bool helpWasShown() const { return m_helpWasShown; }
@ -52,12 +50,13 @@ private:
bool m_batchMode; bool m_batchMode;
}; };
std::unique_ptr<AppOptions> args(std::initializer_list<const char*> l) { std::unique_ptr<AppOptions> args(std::initializer_list<const char*> l)
int argc = l.size()+1; {
int argc = l.size() + 1;
const char** argv = new const char*[argc]; const char** argv = new const char*[argc];
argv[0] = "aseprite.exe"; argv[0] = "aseprite.exe";
auto it = l.begin(); auto it = l.begin();
for (int i=1; i<argc; ++i, ++it) { for (int i = 1; i < argc; ++i, ++it) {
argv[i] = *it; argv[i] = *it;
TRACE("argv[%d] = %s\n", i, argv[i]); TRACE("argv[%d] = %s\n", i, argv[i]);
} }
@ -69,7 +68,7 @@ std::unique_ptr<AppOptions> args(std::initializer_list<const char*> l) {
TEST(Cli, None) TEST(Cli, None)
{ {
CliTestDelegate d; CliTestDelegate d;
auto a = args({ }); auto a = args({});
CliProcessor p(&d, *a); CliProcessor p(&d, *a);
p.process(nullptr); p.process(nullptr);
EXPECT_TRUE(!d.helpWasShown()); EXPECT_TRUE(!d.helpWasShown());

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cli/default_cli_delegate.h" #include "app/cli/default_cli_delegate.h"
@ -42,16 +42,12 @@ namespace app {
void DefaultCliDelegate::showHelp(const AppOptions& options) void DefaultCliDelegate::showHelp(const AppOptions& options)
{ {
std::cout std::cout << get_app_name() << " v" << get_app_version() << " | A pixel art program\n"
<< get_app_name() << " v" << get_app_version() << get_app_copyright() << "\n\nUsage:\n"
<< " | A pixel art program\n" << " " << options.exeName() << " [OPTIONS] [FILES]...\n\n"
<< get_app_copyright() << "Options:\n"
<< "\n\nUsage:\n" << options.programOptions() << "\nFind more information in " << get_app_name()
<< " " << options.exeName() << " [OPTIONS] [FILES]...\n\n" << " web site: " << get_app_url() << "\n\n";
<< "Options:\n"
<< options.programOptions()
<< "\nFind more information in " << get_app_name()
<< " web site: " << get_app_url() << "\n\n";
} }
void DefaultCliDelegate::showVersion() void DefaultCliDelegate::showVersion()
@ -61,7 +57,7 @@ void DefaultCliDelegate::showVersion()
void DefaultCliDelegate::afterOpenFile(const CliOpenFile& cof) void DefaultCliDelegate::afterOpenFile(const CliOpenFile& cof)
{ {
if (!cof.document) // Do nothing if (!cof.document) // Do nothing
return; return;
if (cof.listLayers) { if (cof.listLayers) {
@ -111,8 +107,7 @@ void DefaultCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
ctx->executeCommand(saveAsCommand, params); ctx->executeCommand(saveAsCommand, params);
} }
void DefaultCliDelegate::loadPalette(Context* ctx, void DefaultCliDelegate::loadPalette(Context* ctx, const std::string& filename)
const std::string& filename)
{ {
std::unique_ptr<doc::Palette> palette(load_palette(filename.c_str())); std::unique_ptr<doc::Palette> palette(load_palette(filename.c_str()));
if (palette) { if (palette) {
@ -123,8 +118,7 @@ void DefaultCliDelegate::loadPalette(Context* ctx,
ctx->executeCommand(loadPalCommand, params); ctx->executeCommand(loadPalCommand, params);
} }
else { else {
Console().printf("Error loading palette in --palette '%s'\n", Console().printf("Error loading palette in --palette '%s'\n", filename.c_str());
filename.c_str());
} }
} }
@ -133,8 +127,7 @@ void DefaultCliDelegate::exportFiles(Context* ctx, DocExporter& exporter)
LOG("APP: Exporting sheet...\n"); LOG("APP: Exporting sheet...\n");
base::task_token token; base::task_token token;
std::unique_ptr<Doc> spriteSheet( std::unique_ptr<Doc> spriteSheet(exporter.exportSheet(ctx, token));
exporter.exportSheet(ctx, token));
// Sprite sheet isn't used, we just delete it. // Sprite sheet isn't used, we just delete it.
@ -142,8 +135,7 @@ void DefaultCliDelegate::exportFiles(Context* ctx, DocExporter& exporter)
} }
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
int DefaultCliDelegate::execScript(const std::string& filename, int DefaultCliDelegate::execScript(const std::string& filename, const Params& params)
const Params& params)
{ {
ScriptInputChain scriptInputChain; ScriptInputChain scriptInputChain;
if (!App::instance()->isGui()) { if (!App::instance()->isGui()) {

View File

@ -13,19 +13,18 @@
namespace app { namespace app {
class DefaultCliDelegate : public CliDelegate { class DefaultCliDelegate : public CliDelegate {
public: public:
void showHelp(const AppOptions& programOptions) override; void showHelp(const AppOptions& programOptions) override;
void showVersion() override; void showVersion() override;
void afterOpenFile(const CliOpenFile& cof) override; void afterOpenFile(const CliOpenFile& cof) override;
void saveFile(Context* ctx, const CliOpenFile& cof) override; void saveFile(Context* ctx, const CliOpenFile& cof) override;
void loadPalette(Context* ctx, const std::string& filename) override; void loadPalette(Context* ctx, const std::string& filename) override;
void exportFiles(Context* ctx, DocExporter& exporter) override; void exportFiles(Context* ctx, DocExporter& exporter) override;
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
int execScript(const std::string& filename, int execScript(const std::string& filename, const Params& params) override;
const Params& params) override;
#endif #endif
}; };
} // namespace app } // namespace app

View File

@ -15,8 +15,7 @@ using namespace doc;
class FilterLayers : public ::testing::Test { class FilterLayers : public ::testing::Test {
public: public:
FilterLayers() FilterLayers() : sprite(ImageSpec(ColorMode::RGB, 32, 32))
: sprite(ImageSpec(ColorMode::RGB, 32, 32))
{ {
a->setName("a"); a->setName("a");
b->setName("b"); b->setName("b");
@ -33,12 +32,9 @@ public:
b->addLayer(bb); b->addLayer(bb);
} }
void filter( void filter(std::vector<std::string> includes, std::vector<std::string> excludes)
std::vector<std::string> includes,
std::vector<std::string> excludes)
{ {
CliProcessor::FilterLayers( CliProcessor::FilterLayers(&sprite, std::move(includes), std::move(excludes), sel);
&sprite, std::move(includes), std::move(excludes), sel);
} }
Sprite sprite; Sprite sprite;

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cli/preview_cli_delegate.h" #include "app/cli/preview_cli_delegate.h"
@ -94,10 +94,7 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
<< " - Sprite: '" << cof.document->filename() << "'\n"; << " - Sprite: '" << cof.document->filename() << "'\n";
if (!cof.crop.isEmpty()) { if (!cof.crop.isEmpty()) {
std::cout << " - Crop: " std::cout << " - Crop: " << cof.crop.x << "," << cof.crop.y << " " << cof.crop.w << "x"
<< cof.crop.x << ","
<< cof.crop.y << " "
<< cof.crop.w << "x"
<< cof.crop.h << "\n"; << cof.crop.h << "\n";
} }
@ -112,8 +109,7 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
std::cout << " - Ignore empty frames\n"; std::cout << " - Ignore empty frames\n";
} }
std::cout << " - Size: " std::cout << " - Size: " << cof.document->sprite()->width() << "x"
<< cof.document->sprite()->width() << "x"
<< cof.document->sprite()->height() << "\n"; << cof.document->sprite()->height() << "\n";
showLayersFilter(cof); showLayersFilter(cof);
@ -136,8 +132,7 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
const auto& selFrames = cof.roi().framesSequence(); const auto& selFrames = cof.roi().framesSequence();
if (!selFrames.empty()) { if (!selFrames.empty()) {
if (selFrames.ranges() == 1) if (selFrames.ranges() == 1)
std::cout << " - Frame range from " std::cout << " - Frame range from " << selFrames.firstFrame() << " to "
<< selFrames.firstFrame() << " to "
<< selFrames.lastFrame() << "\n"; << selFrames.lastFrame() << "\n";
else { else {
std::cout << " - Specific frames:"; std::cout << " - Specific frames:";
@ -151,13 +146,11 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
if (!cof.filenameFormat.empty()) if (!cof.filenameFormat.empty())
std::cout << " - Filename format: '" << cof.filenameFormat << "'\n"; std::cout << " - Filename format: '" << cof.filenameFormat << "'\n";
std::unique_ptr<FileOp> fop( std::unique_ptr<FileOp> fop(FileOp::createSaveDocumentOperation(ctx,
FileOp::createSaveDocumentOperation( cof.roi(),
ctx, cof.filename,
cof.roi(), cof.filenameFormat,
cof.filename, cof.ignoreEmpty));
cof.filenameFormat,
cof.ignoreEmpty));
if (fop) { if (fop) {
base::paths files; base::paths files;
@ -173,8 +166,7 @@ void PreviewCliDelegate::saveFile(Context* ctx, const CliOpenFile& cof)
std::cout << " - No output\n"; std::cout << " - No output\n";
} }
void PreviewCliDelegate::loadPalette(Context* ctx, void PreviewCliDelegate::loadPalette(Context* ctx, const std::string& filename)
const std::string& filename)
{ {
std::cout << "- Load palette:\n" std::cout << "- Load palette:\n"
<< " - Palette: '" << filename << "'\n"; << " - Palette: '" << filename << "'\n";
@ -185,10 +177,10 @@ void PreviewCliDelegate::exportFiles(Context* ctx, DocExporter& exporter)
std::string type = "None"; std::string type = "None";
switch (exporter.spriteSheetType()) { switch (exporter.spriteSheetType()) {
case SpriteSheetType::Horizontal: type = "Horizontal"; break; case SpriteSheetType::Horizontal: type = "Horizontal"; break;
case SpriteSheetType::Vertical: type = "Vertical"; break; case SpriteSheetType::Vertical: type = "Vertical"; break;
case SpriteSheetType::Rows: type = "Rows"; break; case SpriteSheetType::Rows: type = "Rows"; break;
case SpriteSheetType::Columns: type = "Columns"; break; case SpriteSheetType::Columns: type = "Columns"; break;
case SpriteSheetType::Packed: type = "Packed"; break; case SpriteSheetType::Packed: type = "Packed"; break;
} }
gfx::Size size = exporter.calculateSheetSize(); gfx::Size size = exporter.calculateSheetSize();
@ -197,29 +189,26 @@ void PreviewCliDelegate::exportFiles(Context* ctx, DocExporter& exporter)
<< " - Size: " << size.w << "x" << size.h << "\n"; << " - Size: " << size.w << "x" << size.h << "\n";
if (!exporter.textureFilename().empty()) { if (!exporter.textureFilename().empty()) {
std::cout << " - Save texture file: '" std::cout << " - Save texture file: '" << exporter.textureFilename() << "'\n";
<< exporter.textureFilename() << "'\n";
} }
if (!exporter.dataFilename().empty()) { if (!exporter.dataFilename().empty()) {
std::string format = "Unknown"; std::string format = "Unknown";
switch (exporter.dataFormat()) { switch (exporter.dataFormat()) {
case SpriteSheetDataFormat::JsonHash: format = "JSON Hash"; break; case SpriteSheetDataFormat::JsonHash: format = "JSON Hash"; break;
case SpriteSheetDataFormat::JsonArray: format = "JSON Array"; break; case SpriteSheetDataFormat::JsonArray: format = "JSON Array"; break;
} }
std::cout << " - Save data file: '" << exporter.dataFilename() << "'\n" std::cout << " - Save data file: '" << exporter.dataFilename() << "'\n"
<< " - Data format: " << format << "\n"; << " - Data format: " << format << "\n";
if (!exporter.filenameFormat().empty()) { if (!exporter.filenameFormat().empty()) {
std::cout << " - Filename format for JSON items: '" std::cout << " - Filename format for JSON items: '" << exporter.filenameFormat() << "'\n";
<< exporter.filenameFormat() << "'\n";
} }
} }
} }
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
int PreviewCliDelegate::execScript(const std::string& filename, int PreviewCliDelegate::execScript(const std::string& filename, const Params& params)
const Params& params)
{ {
std::cout << "- Run script: '" << filename << "'\n"; std::cout << "- Run script: '" << filename << "'\n";
if (!params.empty()) { if (!params.empty()) {
@ -257,8 +246,7 @@ void PreviewCliDelegate::showLayerVisibility(const doc::LayerGroup* group,
continue; continue;
std::cout << indent << "- " << layer->name() << "\n"; std::cout << indent << "- " << layer->name() << "\n";
if (layer->isGroup()) if (layer->isGroup())
showLayerVisibility(static_cast<const LayerGroup*>(layer), showLayerVisibility(static_cast<const LayerGroup*>(layer), indent + " ");
indent + " ");
} }
} }

View File

@ -14,33 +14,31 @@
#include <string> #include <string>
namespace doc { namespace doc {
class LayerGroup; class LayerGroup;
} }
namespace app { namespace app {
class PreviewCliDelegate : public CliDelegate { class PreviewCliDelegate : public CliDelegate {
public: public:
void showHelp(const AppOptions& programOptions) override; void showHelp(const AppOptions& programOptions) override;
void showVersion() override; void showVersion() override;
void uiMode() override; void uiMode() override;
void shellMode() override; void shellMode() override;
void batchMode() override; void batchMode() override;
void beforeOpenFile(const CliOpenFile& cof) override; void beforeOpenFile(const CliOpenFile& cof) override;
void afterOpenFile(const CliOpenFile& cof) override; void afterOpenFile(const CliOpenFile& cof) override;
void saveFile(Context* ctx, const CliOpenFile& cof) override; void saveFile(Context* ctx, const CliOpenFile& cof) override;
void loadPalette(Context* ctx, const std::string& filename) override; void loadPalette(Context* ctx, const std::string& filename) override;
void exportFiles(Context* ctx, DocExporter& exporter) override; void exportFiles(Context* ctx, DocExporter& exporter) override;
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
int execScript(const std::string& filename, int execScript(const std::string& filename, const Params& params) override;
const Params& params) override;
#endif // ENABLE_SCRIPTING #endif // ENABLE_SCRIPTING
private: private:
void showLayersFilter(const CliOpenFile& cof); void showLayersFilter(const CliOpenFile& cof);
void showLayerVisibility(const doc::LayerGroup* group, void showLayerVisibility(const doc::LayerGroup* group, const std::string& indent);
const std::string& indent); };
};
} // namespace app } // namespace app

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/closed_docs.h" #include "app/closed_docs.h"
@ -20,22 +20,23 @@
namespace app { namespace app {
ClosedDocs::ClosedDocs(const Preferences& pref) ClosedDocs::ClosedDocs(const Preferences& pref) : m_done(false)
: m_done(false)
{ {
if (pref.general.dataRecovery()) if (pref.general.dataRecovery())
m_dataRecoveryPeriodMSecs = int(1000.0*60.0*pref.general.dataRecoveryPeriod()); m_dataRecoveryPeriodMSecs = int(1000.0 * 60.0 * pref.general.dataRecoveryPeriod());
else else
m_dataRecoveryPeriodMSecs = 0; m_dataRecoveryPeriodMSecs = 0;
if (pref.general.keepClosedSpriteOnMemory()) if (pref.general.keepClosedSpriteOnMemory())
m_keepClosedDocAliveForMSecs = int(1000.0*60.0*pref.general.keepClosedSpriteOnMemoryFor()); m_keepClosedDocAliveForMSecs = int(1000.0 * 60.0 * pref.general.keepClosedSpriteOnMemoryFor());
else else
m_keepClosedDocAliveForMSecs = 0; m_keepClosedDocAliveForMSecs = 0;
CLOSEDOC_TRACE("CLOSEDOC: Init", CLOSEDOC_TRACE("CLOSEDOC: Init",
"dataRecoveryPeriod", m_dataRecoveryPeriodMSecs, "dataRecoveryPeriod",
"keepClosedDocs", m_keepClosedDocAliveForMSecs); m_dataRecoveryPeriodMSecs,
"keepClosedDocs",
m_keepClosedDocAliveForMSecs);
} }
ClosedDocs::~ClosedDocs() ClosedDocs::~ClosedDocs()
@ -62,8 +63,7 @@ bool ClosedDocs::hasClosedDocs()
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::mutex> lock(m_mutex);
result = !m_docs.empty(); result = !m_docs.empty();
} }
CLOSEDOC_TRACE("CLOSEDOC: Has closed docs?", CLOSEDOC_TRACE("CLOSEDOC: Has closed docs?", (result ? "true" : "false"));
(result ? "true": "false"));
return result; return result;
} }
@ -80,7 +80,7 @@ void ClosedDocs::addClosedDoc(Doc* doc)
m_docs.insert(m_docs.begin(), std::move(closedDoc)); m_docs.insert(m_docs.begin(), std::move(closedDoc));
if (!m_thread.joinable()) if (!m_thread.joinable())
m_thread = std::thread([this]{ backgroundThread(); }); m_thread = std::thread([this] { backgroundThread(); });
else else
m_cv.notify_one(); m_cv.notify_one();
} }
@ -126,18 +126,18 @@ void ClosedDocs::backgroundThread()
base::tick_t now = base::current_tick(); base::tick_t now = base::current_tick();
base::tick_t waitForMSecs = std::numeric_limits<base::tick_t>::max(); base::tick_t waitForMSecs = std::numeric_limits<base::tick_t>::max();
for (auto it=m_docs.begin(); it != m_docs.end(); ) { for (auto it = m_docs.begin(); it != m_docs.end();) {
const ClosedDoc& closedDoc = *it; const ClosedDoc& closedDoc = *it;
auto doc = closedDoc.doc; auto doc = closedDoc.doc;
base::tick_t diff = now - closedDoc.timestamp; base::tick_t diff = now - closedDoc.timestamp;
if (diff >= m_keepClosedDocAliveForMSecs) { if (diff >= m_keepClosedDocAliveForMSecs) {
if (// If we backup process is disabled if ( // If we backup process is disabled
m_dataRecoveryPeriodMSecs == 0 || m_dataRecoveryPeriodMSecs == 0 ||
// Or this document doesn't need a backup (e.g. an unmodified document) // Or this document doesn't need a backup (e.g. an unmodified document)
!doc->needsBackup() || !doc->needsBackup() ||
// Or the document already has the backup done // Or the document already has the backup done
doc->isFullyBackedUp()) { doc->isFullyBackedUp()) {
// Finally delete the document (this is the place where we // Finally delete the document (this is the place where we
// delete all documents created/loaded by the user) // delete all documents created/loaded by the user)
CLOSEDOC_TRACE("CLOSEDOC: [BG] Delete doc", doc); CLOSEDOC_TRACE("CLOSEDOC: [BG] Delete doc", doc);
@ -150,7 +150,7 @@ void ClosedDocs::backgroundThread()
} }
} }
else { else {
waitForMSecs = std::min(waitForMSecs, m_keepClosedDocAliveForMSecs-diff); waitForMSecs = std::min(waitForMSecs, m_keepClosedDocAliveForMSecs - diff);
++it; ++it;
} }
} }

View File

@ -18,47 +18,47 @@
namespace app { namespace app {
class Doc; class Doc;
class Preferences; class Preferences;
// Handle the list of closed docs: // Handle the list of closed docs:
// * When a document is closed, we keep it for some time so the user // * When a document is closed, we keep it for some time so the user
// can undo the close command without losing the undo history. // can undo the close command without losing the undo history.
// * For the first closed document, a thread is launched to wait // * For the first closed document, a thread is launched to wait
// until we can definitely delete the doc after X minutes (like a // until we can definitely delete the doc after X minutes (like a
// garbage collector). // garbage collector).
// * If the document was not restore, we delete it from memory, if // * If the document was not restore, we delete it from memory, if
// the document was restore, we remove it from the m_docs. // the document was restore, we remove it from the m_docs.
class ClosedDocs { class ClosedDocs {
public: public:
ClosedDocs(const Preferences& pref); ClosedDocs(const Preferences& pref);
~ClosedDocs(); ~ClosedDocs();
bool hasClosedDocs(); bool hasClosedDocs();
void addClosedDoc(Doc* doc); void addClosedDoc(Doc* doc);
Doc* reopenLastClosedDoc(); Doc* reopenLastClosedDoc();
// Called at the very end to get all closed docs, remove them from // Called at the very end to get all closed docs, remove them from
// the list of closed docs, and stop the thread. // the list of closed docs, and stop the thread.
std::vector<Doc*> getAndRemoveAllClosedDocs(); std::vector<Doc*> getAndRemoveAllClosedDocs();
private: private:
void backgroundThread(); void backgroundThread();
struct ClosedDoc { struct ClosedDoc {
Doc* doc; Doc* doc;
base::tick_t timestamp; base::tick_t timestamp;
};
std::atomic<bool> m_done;
base::tick_t m_dataRecoveryPeriodMSecs;
base::tick_t m_keepClosedDocAliveForMSecs;
std::vector<ClosedDoc> m_docs;
std::mutex m_mutex;
std::condition_variable m_cv;
std::thread m_thread;
}; };
std::atomic<bool> m_done;
base::tick_t m_dataRecoveryPeriodMSecs;
base::tick_t m_keepClosedDocAliveForMSecs;
std::vector<ClosedDoc> m_docs;
std::mutex m_mutex;
std::condition_variable m_cv;
std::thread m_thread;
};
} // namespace app } // namespace app
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd.h" #include "app/cmd.h"
@ -115,7 +115,8 @@ std::string Cmd::onLabel() const
return ""; return "";
} }
size_t Cmd::onMemSize() const { size_t Cmd::onMemSize() const
{
return sizeof(*this); return sizeof(*this);
} }

View File

@ -16,44 +16,44 @@
namespace app { namespace app {
class Context; class Context;
class Cmd : public undo::UndoCommand { class Cmd : public undo::UndoCommand {
public: public:
Cmd(); Cmd();
virtual ~Cmd(); virtual ~Cmd();
void execute(Context* ctx); void execute(Context* ctx);
// undo::UndoCommand impl // undo::UndoCommand impl
void undo() override; void undo() override;
void redo() override; void redo() override;
void dispose() override; void dispose() override;
std::string label() const; std::string label() const;
size_t memSize() const; size_t memSize() const;
Context* context() const { return m_ctx; } Context* context() const { return m_ctx; }
protected: protected:
virtual void onExecute(); virtual void onExecute();
virtual void onUndo(); virtual void onUndo();
virtual void onRedo(); virtual void onRedo();
virtual void onFireNotifications(); virtual void onFireNotifications();
virtual std::string onLabel() const; virtual std::string onLabel() const;
virtual size_t onMemSize() const; virtual size_t onMemSize() const;
private: private:
// TODO I think we could just remove this field (but we'll need to // TODO I think we could just remove this field (but we'll need to
// include the Context* in all onEvent() member functions) // include the Context* in all onEvent() member functions)
Context* m_ctx; Context* m_ctx;
#if _DEBUG #if _DEBUG
enum class State { NotExecuted, Executed, Undone, Redone }; enum class State { NotExecuted, Executed, Undone, Redone };
State m_state; State m_state;
#endif #endif
DISABLE_COPYING(Cmd); DISABLE_COPYING(Cmd);
}; };
} // namespace app } // namespace app

View File

@ -1,11 +1,11 @@
## Shared pointers ## Shared pointers
Do not keep `ImageRef` or any kind of smart pointer to `doc::` Do not keep `ImageRef` or any kind of smart pointer to `doc::`
entities. As several `cmd` can persist in parallel with other `cmd` entities. As several `cmd` can persist in parallel with other `cmd`
(due the tree structure of the [undo history](../../undo/undo_history.h)) (due the tree structure of the [undo history](../../undo/undo_history.h))
these smart pointers can generate conflicts in the logic layer. these smart pointers can generate conflicts in the logic layer.
E.g. If we keep an `ImageRef` inside a `cmd`, the image is E.g. If we keep an `ImageRef` inside a `cmd`, the image is
not removed from the [objects hash table](../../doc/object.cpp), not removed from the [objects hash table](../../doc/object.cpp),
so two or more `cmd` could try to add/remove the same object so two or more `cmd` could try to add/remove the same object
in the hash table (there are asserts to check this state, were in the hash table (there are asserts to check this state, were
someone is trying to add the same `ObjectId` in the hash table). someone is trying to add the same `ObjectId` in the hash table).

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/add_cel.h" #include "app/cmd/add_cel.h"
@ -21,17 +21,13 @@
#include "doc/layer.h" #include "doc/layer.h"
#include "doc/subobjects_io.h" #include "doc/subobjects_io.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace base::serialization; using namespace base::serialization;
using namespace base::serialization::little_endian; using namespace base::serialization::little_endian;
using namespace doc; using namespace doc;
AddCel::AddCel(Layer* layer, Cel* cel) AddCel::AddCel(Layer* layer, Cel* cel) : WithLayer(layer), WithCel(cel), m_size(0)
: WithLayer(layer)
, WithCel(cel)
, m_size(0)
{ {
} }
@ -54,7 +50,7 @@ void AddCel::onUndo()
// Save the CelData only if the cel isn't linked // Save the CelData only if the cel isn't linked
bool has_data = (cel->links() == 0); bool has_data = (cel->links() == 0);
write8(m_stream, has_data ? 1: 0); write8(m_stream, has_data ? 1 : 0);
if (has_data) { if (has_data) {
write_image(m_stream, cel->image()); write_image(m_stream, cel->image());
write_celdata(m_stream, cel->data()); write_celdata(m_stream, cel->data());
@ -119,5 +115,4 @@ void AddCel::removeCel(Layer* layer, Cel* cel)
delete cel; delete cel;
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -15,37 +15,33 @@
#include <sstream> #include <sstream>
namespace doc { namespace doc {
class Cel; class Cel;
class Layer; class Layer;
} } // namespace doc
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class AddCel : public Cmd class AddCel : public Cmd,
, public WithLayer public WithLayer,
, public WithCel { public WithCel {
public: public:
AddCel(Layer* layer, Cel* cel); AddCel(Layer* layer, Cel* cel);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
void onRedo() override; void onRedo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + m_size; }
return sizeof(*this) + m_size;
}
private: private:
void addCel(Layer* layer, Cel* cel); void addCel(Layer* layer, Cel* cel);
void removeCel(Layer* layer, Cel* cel); void removeCel(Layer* layer, Cel* cel);
size_t m_size; size_t m_size;
std::stringstream m_stream; std::stringstream m_stream;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/add_frame.h" #include "app/cmd/add_frame.h"
@ -18,8 +18,7 @@
#include "doc/primitives.h" #include "doc/primitives.h"
#include "doc/sprite.h" #include "doc/sprite.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace doc; using namespace doc;
@ -77,5 +76,4 @@ void AddFrame::onUndo()
doc->notify_observers<DocEvent&>(&DocObserver::onRemoveFrame, ev); doc->notify_observers<DocEvent&>(&DocObserver::onRemoveFrame, ev);
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -16,34 +16,29 @@
#include <memory> #include <memory>
namespace doc { namespace doc {
class Sprite; class Sprite;
} }
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class AddFrame : public Cmd class AddFrame : public Cmd,
, public WithSprite { public WithSprite {
public: public:
AddFrame(Sprite* sprite, frame_t frame); AddFrame(Sprite* sprite, frame_t frame);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + (m_addCel ? m_addCel->memSize() : 0); }
return sizeof(*this) +
(m_addCel ? m_addCel->memSize() : 0);
}
private: private:
void moveFrames(Layer* layer, frame_t fromThis, frame_t delta); void moveFrames(Layer* layer, frame_t fromThis, frame_t delta);
frame_t m_newFrame; frame_t m_newFrame;
std::unique_ptr<AddCel> m_addCel; std::unique_ptr<AddCel> m_addCel;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/add_layer.h" #include "app/cmd/add_layer.h"
@ -16,8 +16,7 @@
#include "doc/layer_io.h" #include "doc/layer_io.h"
#include "doc/subobjects_io.h" #include "doc/subobjects_io.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace doc; using namespace doc;
@ -93,5 +92,4 @@ void AddLayer::removeLayer(Layer* group, Layer* layer)
delete layer; delete layer;
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -14,37 +14,33 @@
#include <sstream> #include <sstream>
namespace doc { namespace doc {
class Layer; class Layer;
} }
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class AddLayer : public Cmd { class AddLayer : public Cmd {
public: public:
AddLayer(Layer* group, Layer* newLayer, Layer* afterThis); AddLayer(Layer* group, Layer* newLayer, Layer* afterThis);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
void onRedo() override; void onRedo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + m_size; }
return sizeof(*this) + m_size;
}
private: private:
void addLayer(Layer* group, Layer* newLayer, Layer* afterThis); void addLayer(Layer* group, Layer* newLayer, Layer* afterThis);
void removeLayer(Layer* group, Layer* layer); void removeLayer(Layer* group, Layer* layer);
WithLayer m_group; WithLayer m_group;
WithLayer m_newLayer; WithLayer m_newLayer;
WithLayer m_afterThis; WithLayer m_afterThis;
size_t m_size; size_t m_size;
std::stringstream m_stream; std::stringstream m_stream;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -5,17 +5,16 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/add_palette.h" #include "app/cmd/add_palette.h"
#include "doc/sprite.h"
#include "doc/palette.h" #include "doc/palette.h"
#include "doc/palette_io.h" #include "doc/palette_io.h"
#include "doc/sprite.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace doc; using namespace doc;
@ -47,5 +46,4 @@ void AddPalette::onUndo()
sprite->incrementVersion(); sprite->incrementVersion();
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -15,33 +15,29 @@
#include <sstream> #include <sstream>
namespace doc { namespace doc {
class Palette; class Palette;
class Sprite; class Sprite;
} } // namespace doc
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class AddPalette : public Cmd class AddPalette : public Cmd,
, public WithSprite { public WithSprite {
public: public:
AddPalette(Sprite* sprite, Palette* pal); AddPalette(Sprite* sprite, Palette* pal);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + m_size; }
return sizeof(*this) + m_size;
}
private: private:
size_t m_size; size_t m_size;
std::stringstream m_stream; std::stringstream m_stream;
frame_t m_frame; frame_t m_frame;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif // CMD_ADD_PALETTE_H_INCLUDED #endif // CMD_ADD_PALETTE_H_INCLUDED

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/add_slice.h" #include "app/cmd/add_slice.h"
@ -17,15 +17,11 @@
#include "doc/slice_io.h" #include "doc/slice_io.h"
#include "doc/sprite.h" #include "doc/sprite.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace doc; using namespace doc;
AddSlice::AddSlice(Sprite* sprite, Slice* slice) AddSlice::AddSlice(Sprite* sprite, Slice* slice) : WithSprite(sprite), WithSlice(slice), m_size(0)
: WithSprite(sprite)
, WithSlice(slice)
, m_size(0)
{ {
} }
@ -84,5 +80,4 @@ void AddSlice::removeSlice(Sprite* sprite, Slice* slice)
delete slice; delete slice;
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -15,33 +15,29 @@
#include <sstream> #include <sstream>
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class AddSlice : public Cmd class AddSlice : public Cmd,
, public WithSprite public WithSprite,
, public WithSlice { public WithSlice {
public: public:
AddSlice(Sprite* sprite, Slice* slice); AddSlice(Sprite* sprite, Slice* slice);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
void onRedo() override; void onRedo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + m_size; }
return sizeof(*this) + m_size;
}
private: private:
void addSlice(Sprite* sprite, Slice* slice); void addSlice(Sprite* sprite, Slice* slice);
void removeSlice(Sprite* sprite, Slice* slice); void removeSlice(Sprite* sprite, Slice* slice);
size_t m_size; size_t m_size;
std::stringstream m_stream; std::stringstream m_stream;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/add_tag.h" #include "app/cmd/add_tag.h"
@ -17,15 +17,11 @@
#include "doc/tag.h" #include "doc/tag.h"
#include "doc/tag_io.h" #include "doc/tag_io.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace doc; using namespace doc;
AddTag::AddTag(Sprite* sprite, Tag* tag) AddTag::AddTag(Sprite* sprite, Tag* tag) : WithSprite(sprite), WithTag(tag), m_size(0)
: WithSprite(sprite)
, WithTag(tag)
, m_size(0)
{ {
} }
@ -86,5 +82,4 @@ void AddTag::onRedo()
doc->notify_observers<DocEvent&>(&DocObserver::onAddTag, ev); doc->notify_observers<DocEvent&>(&DocObserver::onAddTag, ev);
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -10,35 +10,31 @@
#pragma once #pragma once
#include "app/cmd.h" #include "app/cmd.h"
#include "app/cmd/with_tag.h"
#include "app/cmd/with_sprite.h" #include "app/cmd/with_sprite.h"
#include "app/cmd/with_tag.h"
#include <sstream> #include <sstream>
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class AddTag : public Cmd class AddTag : public Cmd,
, public WithSprite public WithSprite,
, public WithTag { public WithTag {
public: public:
AddTag(Sprite* sprite, Tag* tag); AddTag(Sprite* sprite, Tag* tag);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
void onRedo() override; void onRedo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + m_size; }
return sizeof(*this) + m_size;
}
private: private:
size_t m_size; size_t m_size;
std::stringstream m_stream; std::stringstream m_stream;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/add_tile.h" #include "app/cmd/add_tile.h"
@ -16,12 +16,9 @@
#include "doc/tileset.h" #include "doc/tileset.h"
#include "doc/tilesets.h" #include "doc/tilesets.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
AddTile::AddTile(doc::Tileset* tileset, AddTile::AddTile(doc::Tileset* tileset, const doc::ImageRef& image, const doc::UserData& userData)
const doc::ImageRef& image,
const doc::UserData& userData)
: WithTileset(tileset) : WithTileset(tileset)
, WithImage(image.get()) , WithImage(image.get())
, m_size(0) , m_size(0)
@ -31,8 +28,7 @@ AddTile::AddTile(doc::Tileset* tileset,
{ {
} }
AddTile::AddTile(doc::Tileset* tileset, AddTile::AddTile(doc::Tileset* tileset, const doc::tile_index ti)
const doc::tile_index ti)
: WithTileset(tileset) : WithTileset(tileset)
, WithImage(tileset->get(ti).get()) , WithImage(tileset->get(ti).get())
, m_size(0) , m_size(0)
@ -94,8 +90,7 @@ void AddTile::onFireNotifications()
doc::Tileset* tileset = this->tileset(); doc::Tileset* tileset = this->tileset();
// Notify that the tileset's changed // Notify that the tileset's changed
static_cast<Doc*>(tileset->sprite()->document()) static_cast<Doc*>(tileset->sprite()->document())->notifyTilesetChanged(tileset);
->notifyTilesetChanged(tileset);
} }
void AddTile::addTile(doc::Tileset* tileset, void AddTile::addTile(doc::Tileset* tileset,
@ -111,5 +106,4 @@ void AddTile::addTile(doc::Tileset* tileset,
tileset->incrementVersion(); tileset->incrementVersion();
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -18,47 +18,43 @@
#include <sstream> #include <sstream>
namespace doc { namespace doc {
class Tileset; class Tileset;
} }
namespace app { namespace app { namespace cmd {
namespace cmd {
class AddTile : public Cmd class AddTile : public Cmd,
, public WithTileset public WithTileset,
, public WithImage { public WithImage {
public: public:
AddTile(doc::Tileset* tileset, AddTile(doc::Tileset* tileset,
const doc::ImageRef& image, const doc::ImageRef& image,
const doc::UserData& userData = UserData()); const doc::UserData& userData = UserData());
AddTile(doc::Tileset* tileset, AddTile(doc::Tileset* tileset, const doc::tile_index ti);
const doc::tile_index ti);
doc::tile_index tileIndex() const { return m_tileIndex; } doc::tile_index tileIndex() const { return m_tileIndex; }
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
void onRedo() override; void onRedo() override;
void onFireNotifications() override; void onFireNotifications() override;
size_t onMemSize() const override { size_t onMemSize() const override
// TODO add m_userData size {
return sizeof(*this) + m_size; // TODO add m_userData size
} return sizeof(*this) + m_size;
}
private: private:
void addTile(doc::Tileset* tileset, void addTile(doc::Tileset* tileset, const doc::ImageRef& image, const doc::UserData& userData);
const doc::ImageRef& image,
const doc::UserData& userData);
size_t m_size; size_t m_size;
std::stringstream m_stream; std::stringstream m_stream;
doc::tile_index m_tileIndex; doc::tile_index m_tileIndex;
doc::ImageRef m_imageRef; doc::ImageRef m_imageRef;
doc::UserData m_userData; doc::UserData m_userData;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/add_tileset.h" #include "app/cmd/add_tileset.h"
@ -16,8 +16,7 @@
#include "doc/tileset_io.h" #include "doc/tileset_io.h"
#include "doc/tilesets.h" #include "doc/tilesets.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace doc; using namespace doc;
@ -84,5 +83,4 @@ void AddTileset::addTileset(doc::Tileset* tileset)
sprite->tilesets()->incrementVersion(); sprite->tilesets()->incrementVersion();
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -16,38 +16,34 @@
#include <sstream> #include <sstream>
namespace doc { namespace doc {
class Tileset; class Tileset;
} }
namespace app { namespace app { namespace cmd {
namespace cmd {
class AddTileset : public Cmd class AddTileset : public Cmd,
, public WithSprite public WithSprite,
, public WithTileset { public WithTileset {
public: public:
AddTileset(doc::Sprite* sprite, doc::Tileset* tileset); AddTileset(doc::Sprite* sprite, doc::Tileset* tileset);
AddTileset(doc::Sprite* sprite, const doc::tileset_index tsi); AddTileset(doc::Sprite* sprite, const doc::tileset_index tsi);
doc::tileset_index tilesetIndex() const { return m_tilesetIndex; } doc::tileset_index tilesetIndex() const { return m_tilesetIndex; }
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
void onRedo() override; void onRedo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + m_size; }
return sizeof(*this) + m_size;
}
private: private:
void addTileset(doc::Tileset* tileset); void addTileset(doc::Tileset* tileset);
size_t m_size; size_t m_size;
std::stringstream m_stream; std::stringstream m_stream;
doc::tileset_index m_tilesetIndex; doc::tileset_index m_tilesetIndex;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/assign_color_profile.h" #include "app/cmd/assign_color_profile.h"
@ -14,8 +14,7 @@
#include "app/doc_event.h" #include "app/doc_event.h"
#include "doc/sprite.h" #include "doc/sprite.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
AssignColorProfile::AssignColorProfile(doc::Sprite* sprite, const gfx::ColorSpaceRef& cs) AssignColorProfile::AssignColorProfile(doc::Sprite* sprite, const gfx::ColorSpaceRef& cs)
: WithSprite(sprite) : WithSprite(sprite)
@ -45,5 +44,4 @@ void AssignColorProfile::onFireNotifications()
doc->notifyColorSpaceChanged(); doc->notifyColorSpaceChanged();
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -12,31 +12,27 @@
#include "app/cmd/with_sprite.h" #include "app/cmd/with_sprite.h"
#include "gfx/color_space.h" #include "gfx/color_space.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
class AssignColorProfile : public Cmd, class AssignColorProfile : public Cmd,
public WithSprite { public WithSprite {
public: public:
AssignColorProfile(doc::Sprite* sprite, const gfx::ColorSpaceRef& cs); AssignColorProfile(doc::Sprite* sprite, const gfx::ColorSpaceRef& cs);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
void onFireNotifications() override; void onFireNotifications() override;
size_t onMemSize() const override { size_t onMemSize() const override
return sizeof(*this) + {
2*sizeof(gfx::ColorSpace) + return sizeof(*this) + 2 * sizeof(gfx::ColorSpace) + m_oldCS->iccSize() + m_newCS->iccSize();
m_oldCS->iccSize() + }
m_newCS->iccSize();
}
private: private:
gfx::ColorSpaceRef m_oldCS; gfx::ColorSpaceRef m_oldCS;
gfx::ColorSpaceRef m_newCS; gfx::ColorSpaceRef m_newCS;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -6,7 +6,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/background_from_layer.h" #include "app/cmd/background_from_layer.h"
@ -25,11 +25,9 @@
#include "doc/sprite.h" #include "doc/sprite.h"
#include "render/render.h" #include "render/render.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
BackgroundFromLayer::BackgroundFromLayer(Layer* layer) BackgroundFromLayer::BackgroundFromLayer(Layer* layer) : WithLayer(layer)
: WithLayer(layer)
{ {
ASSERT(layer); ASSERT(layer);
ASSERT(layer->isVisible()); ASSERT(layer->isVisible());
@ -42,7 +40,7 @@ BackgroundFromLayer::BackgroundFromLayer(Layer* layer)
void BackgroundFromLayer::onExecute() void BackgroundFromLayer::onExecute()
{ {
Layer* layer = this->layer(); Layer* layer = this->layer();
ASSERT(!layer->isTilemap()); // TODO support background tilemaps ASSERT(!layer->isTilemap()); // TODO support background tilemaps
Sprite* sprite = layer->sprite(); Sprite* sprite = layer->sprite();
auto doc = static_cast<Doc*>(sprite->document()); auto doc = static_cast<Doc*>(sprite->document());
@ -60,12 +58,13 @@ void BackgroundFromLayer::onExecute()
ASSERT(cel_image->pixelFormat() != IMAGE_TILEMAP); ASSERT(cel_image->pixelFormat() != IMAGE_TILEMAP);
clear_image(bg_image.get(), bgcolor); clear_image(bg_image.get(), bgcolor);
render::composite_image( render::composite_image(bg_image.get(),
bg_image.get(), cel_image, cel_image,
sprite->palette(cel->frame()), sprite->palette(cel->frame()),
cel->x(), cel->y(), cel->x(),
std::clamp(cel->opacity(), 0, 255), cel->y(),
static_cast<LayerImage*>(layer)->blendMode()); std::clamp(cel->opacity(), 0, 255),
static_cast<LayerImage*>(layer)->blendMode());
// now we have to copy the new image (bg_image) to the cel... // now we have to copy the new image (bg_image) to the cel...
executeAndAdd(new cmd::SetCelPosition(cel, 0, 0)); executeAndAdd(new cmd::SetCelPosition(cel, 0, 0));
@ -76,10 +75,8 @@ void BackgroundFromLayer::onExecute()
// Same size of cel image and background image, we can just // Same size of cel image and background image, we can just
// replace pixels. // replace pixels.
if (bg_image->width() == cel_image->width() && if (bg_image->width() == cel_image->width() && bg_image->height() == cel_image->height()) {
bg_image->height() == cel_image->height()) { executeAndAdd(new CopyRect(cel_image, bg_image.get(), gfx::Clip(0, 0, cel_image->bounds())));
executeAndAdd(new CopyRect(cel_image, bg_image.get(),
gfx::Clip(0, 0, cel_image->bounds())));
} }
// In other case we have to replace the whole image (this is the // In other case we have to replace the whole image (this is the
// most common case, a smaller transparent cel that is converted // most common case, a smaller transparent cel that is converted
@ -91,11 +88,10 @@ void BackgroundFromLayer::onExecute()
} }
// Fill all empty cels with a flat image filled with bgcolor // Fill all empty cels with a flat image filled with bgcolor
for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) { for (frame_t frame(0); frame < sprite->totalFrames(); ++frame) {
Cel* cel = layer->cel(frame); Cel* cel = layer->cel(frame);
if (!cel) { if (!cel) {
ImageRef cel_image(Image::create(sprite->pixelFormat(), ImageRef cel_image(Image::create(sprite->pixelFormat(), sprite->width(), sprite->height()));
sprite->width(), sprite->height()));
clear_image(cel_image.get(), bgcolor); clear_image(cel_image.get(), bgcolor);
// Create the new cel and add it to the new background layer // Create the new cel and add it to the new background layer
@ -107,5 +103,4 @@ void BackgroundFromLayer::onExecute()
executeAndAdd(new cmd::ConfigureBackground(layer)); executeAndAdd(new cmd::ConfigureBackground(layer));
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -11,20 +11,18 @@
#include "app/cmd/with_layer.h" #include "app/cmd/with_layer.h"
#include "app/cmd_sequence.h" #include "app/cmd_sequence.h"
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class BackgroundFromLayer : public CmdSequence class BackgroundFromLayer : public CmdSequence,
, public WithLayer { public WithLayer {
public: public:
BackgroundFromLayer(Layer* layer); BackgroundFromLayer(Layer* layer);
protected: protected:
void onExecute() override; void onExecute() override;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/clear_cel.h" #include "app/cmd/clear_cel.h"
@ -16,13 +16,11 @@
#include "doc/cel.h" #include "doc/cel.h"
#include "doc/layer.h" #include "doc/layer.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace doc; using namespace doc;
ClearCel::ClearCel(Cel* cel) ClearCel::ClearCel(Cel* cel) : WithCel(cel)
: WithCel(cel)
{ {
Doc* doc = static_cast<Doc*>(cel->document()); Doc* doc = static_cast<Doc*>(cel->document());
@ -30,8 +28,7 @@ ClearCel::ClearCel(Cel* cel)
Image* image = cel->image(); Image* image = cel->image();
ASSERT(image); ASSERT(image);
if (image) if (image)
m_seq.add(new cmd::ClearImage(image, m_seq.add(new cmd::ClearImage(image, doc->bgColor(cel->layer())));
doc->bgColor(cel->layer())));
} }
else { else {
m_seq.add(new cmd::RemoveCel(cel)); m_seq.add(new cmd::RemoveCel(cel));
@ -53,5 +50,4 @@ void ClearCel::onRedo()
m_seq.redo(); m_seq.redo();
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -12,28 +12,24 @@
#include "app/cmd/with_cel.h" #include "app/cmd/with_cel.h"
#include "app/cmd_sequence.h" #include "app/cmd_sequence.h"
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class ClearCel : public Cmd class ClearCel : public Cmd,
, public WithCel { public WithCel {
public: public:
ClearCel(Cel* cel); ClearCel(Cel* cel);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
void onRedo() override; void onRedo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + m_seq.memSize(); }
return sizeof(*this) + m_seq.memSize();
}
private: private:
CmdSequence m_seq; CmdSequence m_seq;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

View File

@ -5,7 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "app/cmd/clear_image.h" #include "app/cmd/clear_image.h"
@ -14,14 +14,11 @@
#include "doc/image.h" #include "doc/image.h"
#include "doc/primitives.h" #include "doc/primitives.h"
namespace app { namespace app { namespace cmd {
namespace cmd {
using namespace doc; using namespace doc;
ClearImage::ClearImage(Image* image, color_t color) ClearImage::ClearImage(Image* image, color_t color) : WithImage(image), m_color(color)
: WithImage(image)
, m_color(color)
{ {
} }
@ -46,5 +43,4 @@ void ClearImage::onUndo()
image->incrementVersion(); image->incrementVersion();
} }
} // namespace cmd }} // namespace app::cmd
} // namespace app

View File

@ -13,28 +13,24 @@
#include "doc/color.h" #include "doc/color.h"
#include "doc/image_ref.h" #include "doc/image_ref.h"
namespace app { namespace app { namespace cmd {
namespace cmd { using namespace doc;
using namespace doc;
class ClearImage : public Cmd class ClearImage : public Cmd,
, public WithImage { public WithImage {
public: public:
ClearImage(Image* image, color_t color); ClearImage(Image* image, color_t color);
protected: protected:
void onExecute() override; void onExecute() override;
void onUndo() override; void onUndo() override;
size_t onMemSize() const override { size_t onMemSize() const override { return sizeof(*this) + (m_copy ? m_copy->getMemSize() : 0); }
return sizeof(*this) + (m_copy ? m_copy->getMemSize(): 0);
}
private: private:
ImageRef m_copy; ImageRef m_copy;
color_t m_color; color_t m_color;
}; };
} // namespace cmd }} // namespace app::cmd
} // namespace app
#endif #endif

Some files were not shown because too many files have changed in this diff Show More