Merge branch 'master' into tilemap-editor

This commit is contained in:
David Capello 2020-03-17 00:25:24 -03:00
commit 7319309630
81 changed files with 769 additions and 510 deletions

View File

@ -1,4 +1,5 @@
# Aseprite # Aseprite
# Copyright (C) 2018-2020 Igara Studio S.A.
# Copyright (C) 2001-2018 David Capello # Copyright (C) 2001-2018 David Capello
cmake_minimum_required(VERSION 3.4) cmake_minimum_required(VERSION 3.4)
@ -23,12 +24,8 @@ if(NOT CMAKE_BUILD_TYPE)
FORCE) FORCE)
endif() endif()
# Restrict configuration types to the selected build type. set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_SOURCE_DIR}/laf/cmake/c_flag_overrides.cmake)
# Note: This needs to be done before the project command set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/laf/cmake/cxx_flag_overrides.cmake)
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_BUILD_TYPE}" CACHE INTERNAL "internal")
set(CMAKE_USER_MAKE_RULES_OVERRIDE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/c_flag_overrides.cmake)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_flag_overrides.cmake)
# Aseprite project # Aseprite project
project(aseprite C CXX) project(aseprite C CXX)

View File

@ -12,19 +12,15 @@
* [Issues with Retina displays](#issues-with-retina-displays) * [Issues with Retina displays](#issues-with-retina-displays)
* [Linux details](#linux-details) * [Linux details](#linux-details)
* [Using shared third party libraries](#using-shared-third-party-libraries) * [Using shared third party libraries](#using-shared-third-party-libraries)
* [Building Skia dependency](#building-skia-dependency)
* [Skia on Windows](#skia-on-windows)
* [Skia on macOS](#skia-on-macos)
* [Skia on Linux](#skia-on-linux)
# Platforms # Platforms
You should be able to compile Aseprite successfully on the following You should be able to compile Aseprite successfully on the following
platforms: platforms:
* Windows 10 + [Visual Studio Community 2019 + Windows 10.0.17763.0 SDK](https://imgur.com/4Pq2Cbv) * Windows 10 + [Visual Studio Community 2019 + Windows 10.0.18362.0 SDK](https://imgur.com/a/7zs51IT)
* macOS 10.14.4 Mojave + Xcode 10.2.1 + macOS 10.14 SDK * macOS 10.15.3 Mojave + Xcode 11.2.1 + macOS 10.15 SDK (older version might work)
* Linux + gcc 4.8 or clang 7.0 * Linux + gcc 9.2 or clang 9.0
# Get the source code # Get the source code
@ -54,32 +50,24 @@ To compile Aseprite you will need:
* The latest version of [CMake](https://cmake.org) (3.14 or greater) * The latest version of [CMake](https://cmake.org) (3.14 or greater)
* [Ninja](https://ninja-build.org) build system * [Ninja](https://ninja-build.org) build system
* You will need a compiled version of the Skia library. * And a compiled version of the `aseprite-m81` branch of
Please check the details about [how to build Skia](#building-skia-dependency) the [Skia library](https://github.com/aseprite/skia#readme).
on your platform. There are [pre-built packages available](https://github.com/aseprite/skia/releases).
You can get some extra information in
the [*laf* dependencies](https://github.com/aseprite/laf#dependencies) page.
## Windows dependencies ## Windows dependencies
First of all, you will need:
* Windows 10 (**we don't support cross-compiling and don't know if this would be possible**) * Windows 10 (**we don't support cross-compiling and don't know if this would be possible**)
* [Visual Studio Community 2019](https://visualstudio.microsoft.com/downloads/) * [Visual Studio Community 2019](https://visualstudio.microsoft.com/downloads/)
* The [Desktop development with C++ item + Windows 10.0.17763.0 SDK](https://imgur.com/4Pq2Cbv) * The [Desktop development with C++ item + Windows 10.0.18362.0 SDK](https://imgur.com/a/7zs51IT)
from the Visual Studio installer from the Visual Studio installer
You will need to [compile Skia](#skia-on-windows) before and then
continue in the [Compiling](#compiling) section. Remember to check the
[Windows details](#windows-details) section to know how to call
`cmake` correctly.
## macOS dependencies ## macOS dependencies
On macOS you will need macOS 10.14 SDK and Xcode 10.2.1 (older On macOS you will need macOS 10.15 SDK and Xcode 11.2.1 (older
versions might work). versions might work).
You must also compile [Skia](#skia-on-macos) before starting with the
[compilation](#compiling).
## Linux dependencies ## Linux dependencies
You will need the following dependencies on Ubuntu/Debian: You will need the following dependencies on Ubuntu/Debian:
@ -88,10 +76,7 @@ You will need the following dependencies on Ubuntu/Debian:
On Fedora: On Fedora:
sudo yum install -y gcc-c++ cmake ninja-build libX11-devel libXcursor-devel mesa-libGL-devel fontconfig-devel sudo dnf install -y gcc-c++ cmake ninja-build libX11-devel libXcursor-devel mesa-libGL-devel fontconfig-devel
You must also compile [Skia](#skia-on-linux) before starting with the
[compilation](#compiling).
# Compiling # Compiling
@ -109,7 +94,7 @@ You must also compile [Skia](#skia-on-linux) before starting with the
2. Enter in the new directory and execute `cmake`: 2. Enter in the new directory and execute `cmake`:
cd C:\aseprite\build cd C:\aseprite\build
cmake -G Ninja .. cmake -G Ninja -DLAF_BACKEND=skia ..
Here `cmake` needs different options depending on your Here `cmake` needs different options depending on your
platform. You must check the details for platform. You must check the details for
@ -129,8 +114,7 @@ You must also compile [Skia](#skia-on-linux) before starting with the
## Windows details ## Windows details
After you've [compiled Skia](#skia-on-windows), Open a [developer command prompt](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs)
open a [developer command prompt](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs)
or in the command line (`cmd.exe`) call: or in the command line (`cmd.exe`) call:
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" -arch=x64 call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" -arch=x64
@ -140,16 +124,15 @@ And then
cd aseprite cd aseprite
mkdir build mkdir build
cd build cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLAF_OS_BACKEND=skia -DSKIA_DIR=C:\deps\skia -DSKIA_OUT_DIR=C:\deps\skia\out\Release -G Ninja .. cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLAF_BACKEND=skia -DSKIA_DIR=C:\deps\skia -DSKIA_LIBRARY_DIR=C:\deps\skia\out\Release-x64 -G Ninja ..
ninja aseprite ninja aseprite
In this case, `C:\deps\skia` is the directory where Skia was compiled In this case, `C:\deps\skia` is the directory where Skia was compiled
as described in [Skia on Windows](#skia-on-windows) section. or uncompressed.
## macOS details ## macOS details
After [compiling Skia](#skia-on-macos), you should run `cmake` with Run `cmake` with the following parameters and then `ninja`:
the following parameters and then `ninja`:
cd aseprite cd aseprite
mkdir build mkdir build
@ -158,19 +141,18 @@ the following parameters and then `ninja`:
-DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \ -DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 \
-DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk \ -DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk \
-DLAF_OS_BACKEND=skia \ -DLAF_BACKEND=skia \
-DSKIA_DIR=$HOME/deps/skia \ -DSKIA_DIR=$HOME/deps/skia \
-DSKIA_OUT_DIR=$HOME/deps/skia/out/Release \ -DSKIA_LIBRARY_DIR=$HOME/deps/skia/out/Release-x64 \
-G Ninja \ -G Ninja \
.. ..
ninja aseprite ninja aseprite
In this case, `$HOME/deps/skia` is the directory where Skia was In this case, `$HOME/deps/skia` is the directory where Skia was
compiled as described in [Skia on macOS](#skia-on-macos) section. compiled or downloaded. Make sure that `CMAKE_OSX_SYSROOT` is
Make sure that `CMAKE_OSX_SYSROOT` is pointing to the correct SDK pointing to the correct SDK directory (in this case
directory (in this case `/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk`),
`/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk`),
but it could be different in your Mac. but it could be different in your Mac.
### Issues with Retina displays ### Issues with Retina displays
@ -181,23 +163,22 @@ If you have a Retina display, check the following issue:
## Linux details ## Linux details
First you have to [compile Skia](#skia-on-linux), then you should run Run `cmake` with the following parameters and then `ninja`:
`cmake` with the following parameters and then `ninja`:
cd aseprite cd aseprite
mkdir build mkdir build
cd build cd build
cmake \ cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DLAF_OS_BACKEND=skia \ -DLAF_BACKEND=skia \
-DSKIA_DIR=$HOME/deps/skia \ -DSKIA_DIR=$HOME/deps/skia \
-DSKIA_OUT_DIR=$HOME/deps/skia/out/Release \ -DSKIA_LIBRARY_DIR=$HOME/deps/skia/out/Release-x64 \
-G Ninja \ -G Ninja \
.. ..
ninja aseprite ninja aseprite
In this case, `$HOME/deps/skia` is the directory where Skia was In this case, `$HOME/deps/skia` is the directory where Skia was
compiled as described in [Skia on Linux](#skia-on-linux) section. compiled or uncompressed.
# Using shared third party libraries # Using shared third party libraries
@ -208,116 +189,3 @@ configuring each `USE_SHARED_` option.
After running `cmake -G`, you can edit `build/CMakeCache.txt` file, After running `cmake -G`, you can edit `build/CMakeCache.txt` file,
and enable the `USE_SHARED_` flag (set its value to `ON`) of the and enable the `USE_SHARED_` flag (set its value to `ON`) of the
library that you want to be linked dynamically. library that you want to be linked dynamically.
# Building Skia dependency
When you compile Aseprite with [Skia](https://skia.org) as back-end on
Windows or macOS, you need to compile a specific version of Skia. In
the following sections you will find straightforward steps to compile
Skia.
You can always check the
[official Skia instructions](https://skia.org/user/build) and select
the OS you are building for. Aseprite uses the `aseprite-m71` Skia
branch from `https://github.com/aseprite/skia`.
## Skia on Windows
Download
[Google depot tools](https://storage.googleapis.com/chrome-infra/depot_tools.zip)
and uncompress it in some place like `C:\deps\depot_tools`.
[It's recommended to compile Skia with Clang](https://github.com/google/skia/blob/master/site/user/build.md#a-note-on-software-backend-performance)
to get better performance. So you will need to [download Clang](http://releases.llvm.org/8.0.0/LLVM-8.0.0-win64.exe),
and install it on a folder like `C:\deps\llvm` (a folder without whitespaces).
Open a [developer command prompt](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs)
or command line (`cmd.exe`) and call:
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" -arch=x64
Then:
set PATH=C:\deps\depot_tools;%PATH%
cd C:\deps\depot_tools
gclient sync
(The `gclient` command might print an error like
`Error: client not configured; see 'gclient config'`.
Just ignore it.)
cd C:\deps
git clone -b aseprite-m71 https://github.com/aseprite/skia.git
cd skia
set GIT_EXECUTABLE=git.bat
python tools/git-sync-deps
(The `tools/git-sync-deps` will take some minutes because it downloads
a lot of packages, please wait and re-run the same command in case it
fails.)
Finally, if you've downloaded Clang, use this command:
set PATH=C:\deps\llvm\bin;%PATH%
gn gen out/Release --args="is_official_build=true skia_use_system_expat=false skia_use_system_libjpeg_turbo=false skia_use_system_libpng=false skia_use_system_libwebp=false skia_use_system_zlib=false target_cpu=""x64"" cc=""clang"" cxx=""clang++"" clang_win=""c:\deps\llvm"" win_vc=""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC"""
ninja -C out/Release skia
If you haven't installed Clang, and want to compile Skia with MSVC
(anyway it's not recommended because the performance penalty is too
big), you can use the following commands instead:
gn gen out/Release --args="is_official_build=true skia_use_system_expat=false skia_use_system_libjpeg_turbo=false skia_use_system_libpng=false skia_use_system_libwebp=false skia_use_system_zlib=false target_cpu=""x64"" win_vc=""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC"""
ninja -C out/Release skia
More information about these steps in the
[official Skia documentation](https://skia.org/user/build).
## Skia on macOS
These steps will create a `deps` folder in your home directory with a
couple of subdirectories needed to build Skia (you can change the
`$HOME/deps` with other directory). Some of these commands will take
several minutes to finish:
mkdir $HOME/deps
cd $HOME/deps
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
git clone -b aseprite-m71 https://github.com/aseprite/skia.git
export PATH="${PWD}/depot_tools:${PATH}"
cd skia
python tools/git-sync-deps
gn gen out/Release --args="is_official_build=true skia_use_system_expat=false skia_use_system_icu=false skia_use_libjpeg_turbo=false skia_use_system_libpng=false skia_use_system_libwebp=false skia_use_system_zlib=false extra_cflags_cc=[\"-frtti\"]"
ninja -C out/Release skia
After this you should have all Skia libraries compiled. When you
[compile Aseprite](#compiling), remember to add
`-DSKIA_DIR=$HOME/deps/skia` parameter to your `cmake` call as
described in the [macOS details](#macos-details) section.
More information about these steps in the
[official Skia documentation](https://skia.org/user/build).
## Skia on Linux
These steps will create a `deps` folder in your home directory with a
couple of subdirectories needed to build Skia (you can change the
`$HOME/deps` with other directory). Some of these commands will take
several minutes to finish:
mkdir $HOME/deps
cd $HOME/deps
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
git clone -b aseprite-m71 https://github.com/aseprite/skia.git
export PATH="${PWD}/depot_tools:${PATH}"
cd skia
python tools/git-sync-deps
gn gen out/Release --args="is_debug=false is_official_build=true skia_use_system_expat=false skia_use_system_icu=false skia_use_system_libjpeg_turbo=false skia_use_system_libpng=false skia_use_system_libwebp=false skia_use_system_zlib=false"
ninja -C out/Release skia
After this you should have all Skia libraries compiled. When you
[compile Aseprite](#compiling), remember to add
`-DSKIA_DIR=$HOME/deps/skia` parameter to your `cmake` call as
described in the [Linux details](#linux-details) section.
More information about these steps in the
[official Skia documentation](https://skia.org/user/build).

View File

@ -10,10 +10,10 @@
**Aseprite** is a program to create animated sprites. Its main **Aseprite** is a program to create animated sprites. Its main
features are: features are:
* Sprites are composed by [**layers** & **frames**](http://www.aseprite.org/docs/timeline/) (as separated concepts). * Sprites are composed of [**layers** & **frames**](http://www.aseprite.org/docs/timeline/) (as separated concepts).
* Supported [color modes](http://www.aseprite.org/docs/color/): **RGBA**, **Indexed** (palettes up to 256 * Supported [color modes](http://www.aseprite.org/docs/color/): **RGBA**, **Indexed** (palettes up to 256
colors), and Grayscale. colors), and Grayscale.
* Load/save sequence of **PNG** files and **GIF** animations (and * Load/save a sequence of **PNG** files and **GIF** animations (and
FLC, FLI, JPG, BMP, PCX, TGA). FLC, FLI, JPG, BMP, PCX, TGA).
* Export/import animations to/from **Sprite Sheets**. * Export/import animations to/from **Sprite Sheets**.
* **Tiled** drawing mode, useful to draw **patterns** and textures. * **Tiled** drawing mode, useful to draw **patterns** and textures.
@ -64,12 +64,12 @@ 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:

View File

@ -35,38 +35,15 @@ include(FindPkgConfig)
pkg_check_modules(PC_HARFBUZZ harfbuzz>=0.9.7) pkg_check_modules(PC_HARFBUZZ harfbuzz>=0.9.7)
find_path(HARFBUZZ_INCLUDE_DIRS NAMES hb.h find_path(HARFBUZZ_INCLUDE_DIRS NAMES hb.h
HINTS ${PC_HARFBUZZ_INCLUDE_DIRS} ${PC_HARFBUZZ_INCLUDEDIR} HINTS ${PC_HARFBUZZ_INCLUDE_DIRS} ${PC_HARFBUZZ_INCLUDEDIR})
)
find_library(HARFBUZZ_LIBRARIES NAMES harfbuzz find_library(HARFBUZZ_LIBRARIES NAMES harfbuzz
HINTS ${PC_HARFBUZZ_LIBRARY_DIRS} ${PC_HARFBUZZ_LIBDIR} HINTS ${PC_HARFBUZZ_LIBRARY_DIRS} ${PC_HARFBUZZ_LIBDIR})
)
# HarfBuzz 0.9.18 split ICU support into a separate harfbuzz-icu library.
if ("${PC_HARFBUZZ_VERSION}" VERSION_GREATER "0.9.17")
if (HarfBuzz_FIND_REQUIRED)
set(_HARFBUZZ_REQUIRED REQUIRED)
else ()
set(_HARFBUZZ_REQUIRED "")
endif ()
pkg_check_modules(PC_HARFBUZZ_ICU harfbuzz-icu>=0.9.18 ${_HARFBUZZ_REQUIRED})
find_library(HARFBUZZ_ICU_LIBRARIES NAMES harfbuzz-icu
HINTS ${PC_HARFBUZZ_ICU_LIBRARY_DIRS} ${PC_HARFBUZZ_ICU_LIBDIR}
)
if (HARFBUZZ_ICU_LIBRARIES)
list(APPEND HARFBUZZ_LIBRARIES "${HARFBUZZ_ICU_LIBRARIES}")
endif ()
set(_HARFBUZZ_EXTRA_REQUIRED_VAR "HARFBUZZ_ICU_LIBRARIES")
else ()
set(_HARFBUZZ_EXTRA_REQUIRED_VAR "")
endif ()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(HarfBuzz DEFAULT_MSG HARFBUZZ_INCLUDE_DIRS FIND_PACKAGE_HANDLE_STANDARD_ARGS(HarfBuzz DEFAULT_MSG HARFBUZZ_INCLUDE_DIRS
HARFBUZZ_LIBRARIES ${_HARFBUZZ_EXTRA_REQUIRED_VAR}) HARFBUZZ_LIBRARIES)
mark_as_advanced( mark_as_advanced(
HARFBUZZ_ICU_LIBRARIES
HARFBUZZ_INCLUDE_DIRS HARFBUZZ_INCLUDE_DIRS
HARFBUZZ_LIBRARIES HARFBUZZ_LIBRARIES)
)

View File

@ -1,6 +0,0 @@
if(MSVC)
set(CMAKE_C_FLAGS_DEBUG_INIT "/D_DEBUG /MTd /Zi /Ob0 /Od /RTC1")
set(CMAKE_C_FLAGS_MINSIZEREL_INIT "/MT /O1 /Ob1 /D NDEBUG")
set(CMAKE_C_FLAGS_RELEASE_INIT "/MT /O2 /Ob2 /D NDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1 /D NDEBUG")
endif()

View File

@ -1,6 +0,0 @@
if(MSVC)
set(CMAKE_CXX_FLAGS_DEBUG_INIT "/D_DEBUG /MTd /Zi /Ob0 /Od /RTC1")
set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "/MT /O1 /Ob1 /D NDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "/MT /O2 /Ob2 /D NDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1 /D NDEBUG")
endif()

View File

@ -2,7 +2,7 @@
<!-- Aseprite --> <!-- Aseprite -->
<!-- Copyright (C) 2018-2020 Igara Studio S.A. --> <!-- Copyright (C) 2018-2020 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2018 David Capello --> <!-- Copyright (C) 2001-2018 David Capello -->
<gui version="1.3-dev"> <gui>
<!-- Keyboard shortcuts --> <!-- Keyboard shortcuts -->
<keyboard version="1"> <keyboard version="1">

2
laf

@ -1 +1 @@
Subproject commit 60b2e83ce159a79368141c5386a764e16ede0c27 Subproject commit 98506341d68a318f4916a891ab12351a5db05f98

View File

@ -1,5 +1,5 @@
# Aseprite # Aseprite
# Copyright (C) 2019 Igara Studio S.A. # Copyright (C) 2019-2020 Igara Studio S.A.
# Copyright (C) 2001-2018 David Capello # Copyright (C) 2001-2018 David Capello
###################################################################### ######################################################################
@ -37,13 +37,6 @@ if(WIN32)
include_directories(..) include_directories(..)
endif() endif()
######################################################################
# Custom Aseprite website (for testing server-side)
if(NOT "${CUSTOM_WEBSITE_URL}" STREQUAL "")
add_definitions(-DCUSTOM_WEBSITE_URL="${CUSTOM_WEBSITE_URL}")
endif()
###################################################################### ######################################################################
# With static libcurl # With static libcurl
@ -106,6 +99,7 @@ add_subdirectory(flic)
add_subdirectory(render) add_subdirectory(render)
add_subdirectory(dio) add_subdirectory(dio)
add_subdirectory(ui) add_subdirectory(ui)
add_subdirectory(ver)
if(REQUIRE_CURL) if(REQUIRE_CURL)
add_subdirectory(net) add_subdirectory(net)
@ -182,6 +176,7 @@ if(ENABLE_ASEPRITE_EXE)
if(WIN32 AND ENABLE_UI) if(WIN32 AND ENABLE_UI)
set_target_properties(aseprite PROPERTIES WIN32_EXECUTABLE true) set_target_properties(aseprite PROPERTIES WIN32_EXECUTABLE true)
endif() endif()
set_target_properties(aseprite PROPERTIES LINK_FLAGS "${LAF_BACKEND_LINK_FLAGS}")
target_link_libraries(aseprite app-lib) target_link_libraries(aseprite app-lib)
add_dependencies(aseprite copy_data) add_dependencies(aseprite copy_data)

View File

@ -1,5 +1,5 @@
# Aseprite # Aseprite
# Copyright (C) 2018-2019 Igara Studio S.A. # Copyright (C) 2018-2020 Igara Studio S.A.
# Copyright (C) 2001-2018 David Capello # Copyright (C) 2001-2018 David Capello
# Generate a ui::Widget for each widget in a XML file # Generate a ui::Widget for each widget in a XML file
@ -305,7 +305,6 @@ if(ENABLE_UI)
modules/editors.cpp modules/editors.cpp
modules/gfx.cpp modules/gfx.cpp
modules/gui.cpp modules/gui.cpp
send_crash.cpp
ui/app_menuitem.cpp ui/app_menuitem.cpp
ui/backup_indicator.cpp ui/backup_indicator.cpp
ui/browser_view.cpp ui/browser_view.cpp
@ -585,6 +584,7 @@ add_library(app-lib
res/resources_loader.cpp res/resources_loader.cpp
resource_finder.cpp resource_finder.cpp
restore_visible_layers.cpp restore_visible_layers.cpp
send_crash.cpp
shade.cpp shade.cpp
site.cpp site.cpp
snap_to_grid.cpp snap_to_grid.cpp
@ -629,6 +629,10 @@ add_library(app-lib
${scripting_files} ${scripting_files}
${generated_files}) ${generated_files})
if(TARGET generated_version)
add_dependencies(app-lib generated_version)
endif()
target_link_libraries(app-lib target_link_libraries(app-lib
laf-base laf-base
cfg-lib cfg-lib
@ -643,6 +647,7 @@ target_link_libraries(app-lib
laf-ft laf-ft
laf-os laf-os
ui-lib ui-lib
ver-lib
undo undo
${CMARK_LIBRARIES} ${CMARK_LIBRARIES}
${TINYXML_LIBRARY} ${TINYXML_LIBRARY}

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -67,6 +67,7 @@
#include "render/render.h" #include "render/render.h"
#include "ui/intern.h" #include "ui/intern.h"
#include "ui/ui.h" #include "ui/ui.h"
#include "ver/info.h"
#include <iostream> #include <iostream>
#include <memory> #include <memory>
@ -514,7 +515,7 @@ App::~App()
// no re-throw // no re-throw
} }
catch (...) { catch (...) {
os::error_message("Error closing " PACKAGE ".\n(uncaught exception)"); os::error_message("Error closing the program.\n(uncaught exception)");
// no re-throw // no re-throw
} }
@ -606,7 +607,8 @@ crash::DataRecovery* App::dataRecovery() const
#ifdef ENABLE_UI #ifdef ENABLE_UI
void App::showNotification(INotificationDelegate* del) void App::showNotification(INotificationDelegate* del)
{ {
m_mainWindow->showNotification(del); if (m_mainWindow)
m_mainWindow->showNotification(del);
} }
void App::showBackupNotification(bool state) void App::showBackupNotification(bool state)
@ -625,7 +627,7 @@ void App::showBackupNotification(bool state)
void App::updateDisplayTitleBar() void App::updateDisplayTitleBar()
{ {
std::string defaultTitle = PACKAGE " v" VERSION; std::string defaultTitle = fmt::format("{} v{}", get_app_name(), get_app_version());
std::string title; std::string title;
DocView* docView = UIContext::instance()->activeView(); DocView* docView = UIContext::instance()->activeView();
@ -636,7 +638,7 @@ void App::updateDisplayTitleBar()
} }
title += defaultTitle; title += defaultTitle;
os::instance()->defaultDisplay()->setTitleBar(title); os::instance()->defaultDisplay()->setTitle(title);
} }
InputChain& App::inputChain() InputChain& App::inputChain()
@ -709,18 +711,4 @@ int app_get_color_to_clear_layer(Layer* layer)
return color_utils::color_for_layer(color, layer); return color_utils::color_for_layer(color, layer);
} }
std::string memory_dump_filename()
{
#ifdef _WIN32
static const char* kDefaultCrashName = PACKAGE "-crash-" VERSION ".dmp";
app::ResourceFinder rf;
rf.includeUserDir(kDefaultCrashName);
return rf.getFirstOrCreateDefault();
#else
return "";
#endif
}
} // namespace app } // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -117,6 +117,9 @@ namespace app {
script::Engine* scriptEngine() { return m_engine.get(); } script::Engine* scriptEngine() { return m_engine.get(); }
#endif #endif
const std::string& memoryDumpFilename() const { return m_memoryDumpFilename; }
void memoryDumpFilename(const std::string& fn) { m_memoryDumpFilename = fn; }
// App Signals // App Signals
obs::signal<void()> Exit; obs::signal<void()> Exit;
obs::signal<void()> PaletteChange; obs::signal<void()> PaletteChange;
@ -145,13 +148,16 @@ namespace app {
#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
// or the "send crash" dialog. It's set by the SendCrash class.
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);
std::string memory_dump_filename();
} // namespace app } // namespace app

View File

@ -29,9 +29,11 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/fs.h" #include "base/fs.h"
#include "base/string.h" #include "base/string.h"
#include "fmt/format.h"
#include "os/menus.h" #include "os/menus.h"
#include "os/system.h" #include "os/system.h"
#include "ui/ui.h" #include "ui/ui.h"
#include "ver/info.h"
#include "tinyxml.h" #include "tinyxml.h"
@ -337,12 +339,6 @@ void AppMenus::reload()
m_rootMenu.reset(loadMenuById(handle, "main_menu")); m_rootMenu.reset(loadMenuById(handle, "main_menu"));
#if _DEBUG
// Add a warning element because the user is not using the last well-known gui.xml file.
if (GuiXml::instance()->version() != VERSION)
m_rootMenu->insertChild(0, createInvalidVersionMenuitem());
#endif
LOG("MENU: Main menu loaded.\n"); LOG("MENU: Main menu loaded.\n");
m_tabPopupMenu.reset(loadMenuById(handle, "tab_popup_menu")); m_tabPopupMenu.reset(loadMenuById(handle, "tab_popup_menu"));
@ -633,20 +629,6 @@ Widget* AppMenus::convertXmlelemToMenuitem(TiXmlElement* elem)
return menuitem; return menuitem;
} }
Widget* AppMenus::createInvalidVersionMenuitem()
{
AppMenuItem* menuitem = new AppMenuItem("WARNING!");
Menu* subMenu = new Menu();
subMenu->addChild(new AppMenuItem(PACKAGE " is using a customized gui.xml (maybe from your HOME directory)."));
subMenu->addChild(new AppMenuItem("You should update your customized gui.xml file to the new version to get"));
subMenu->addChild(new AppMenuItem("the latest commands available."));
subMenu->addChild(new MenuSeparator);
subMenu->addChild(new AppMenuItem("You can bypass this validation adding the correct version"));
subMenu->addChild(new AppMenuItem("number in <gui version=\"" VERSION "\"> element."));
menuitem->setSubmenu(subMenu);
return menuitem;
}
void AppMenus::applyShortcutToMenuitemsWithCommand(Command* command, void AppMenus::applyShortcutToMenuitemsWithCommand(Command* command,
const Params& params, const Params& params,
const KeyPtr& key) const KeyPtr& key)
@ -732,7 +714,7 @@ void AppMenus::createNativeMenus()
#ifdef __APPLE__ // Create default macOS app menus (App ... Window) #ifdef __APPLE__ // Create default macOS app menus (App ... Window)
{ {
os::MenuItemInfo about("About " PACKAGE); 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]{
@ -758,10 +740,10 @@ void AppMenus::createNativeMenus()
item->setEnabled(can_call_global_shortcut(&native)); item->setEnabled(can_call_global_shortcut(&native));
}; };
os::MenuItemInfo hide("Hide " PACKAGE, os::MenuItemInfo::Hide); os::MenuItemInfo hide(fmt::format("Hide {}", get_app_name()), os::MenuItemInfo::Hide);
hide.shortcut = os::Shortcut('h', os::kKeyCmdModifier); hide.shortcut = os::Shortcut('h', os::kKeyCmdModifier);
os::MenuItemInfo quit("Quit " PACKAGE, os::MenuItemInfo::Quit); os::MenuItemInfo quit(fmt::format("Quit {}", get_app_name()), os::MenuItemInfo::Quit);
quit.shortcut = os::Shortcut('q', os::kKeyCmdModifier); quit.shortcut = os::Shortcut('q', os::kKeyCmdModifier);
os::Menu* appMenu = menus->createMenu(); os::Menu* appMenu = menus->createMenu();

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -69,7 +69,6 @@ namespace app {
Menu* loadMenuById(TiXmlHandle& handle, const char *id); Menu* loadMenuById(TiXmlHandle& handle, const char *id);
Menu* convertXmlelemToMenu(TiXmlElement* elem); Menu* convertXmlelemToMenu(TiXmlElement* elem);
Widget* convertXmlelemToMenuitem(TiXmlElement* elem); Widget* convertXmlelemToMenuitem(TiXmlElement* elem);
Widget* createInvalidVersionMenuitem();
void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, const Params& params, void applyShortcutToMenuitemsWithCommand(Menu* menu, Command* command, const Params& params,
const KeyPtr& key); const KeyPtr& key);
void syncNativeMenuItemKeyShortcuts(Menu* menu); void syncNativeMenuItemKeyShortcuts(Menu* menu);

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -19,6 +20,7 @@
#include "base/launcher.h" #include "base/launcher.h"
#include "base/replace_string.h" #include "base/replace_string.h"
#include "base/version.h" #include "base/version.h"
#include "ver/info.h"
#include <ctime> #include <ctime>
#include <sstream> #include <sstream>
@ -202,7 +204,7 @@ void CheckUpdateThreadLauncher::checkForUpdates()
void CheckUpdateThreadLauncher::showUI() void CheckUpdateThreadLauncher::showUI()
{ {
std::string localVersionStr = VERSION; std::string localVersionStr = get_app_version();
base::replace_string(localVersionStr, "-x64", ""); base::replace_string(localVersionStr, "-x64", "");
bool newVer = false; bool newVer = false;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2016-2018 David Capello // Copyright (C) 2016-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -26,6 +26,7 @@
#include "doc/slice.h" #include "doc/slice.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "doc/tag.h" #include "doc/tag.h"
#include "ver/info.h"
#ifdef ENABLE_SCRIPTING #ifdef ENABLE_SCRIPTING
#include "app/app.h" #include "app/app.h"
@ -40,18 +41,20 @@ namespace app {
void DefaultCliDelegate::showHelp(const AppOptions& options) void DefaultCliDelegate::showHelp(const AppOptions& options)
{ {
std::cout std::cout
<< PACKAGE << " v" << VERSION << " | A pixel art program\n" << COPYRIGHT << get_app_name() << " v" << get_app_version()
<< " | A pixel art program\n"
<< get_app_copyright()
<< "\n\nUsage:\n" << "\n\nUsage:\n"
<< " " << options.exeName() << " [OPTIONS] [FILES]...\n\n" << " " << options.exeName() << " [OPTIONS] [FILES]...\n\n"
<< "Options:\n" << "Options:\n"
<< options.programOptions() << options.programOptions()
<< "\nFind more information in " << PACKAGE << "\nFind more information in " << get_app_name()
<< " web site: " << WEBSITE << "\n\n"; << " web site: " << get_app_url() << "\n\n";
} }
void DefaultCliDelegate::showVersion() void DefaultCliDelegate::showVersion()
{ {
std::cout << PACKAGE << ' ' << VERSION << '\n'; std::cout << get_app_name() << ' ' << get_app_version() << '\n';
} }
void DefaultCliDelegate::afterOpenFile(const CliOpenFile& cof) void DefaultCliDelegate::afterOpenFile(const CliOpenFile& cof)

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2016-2018 David Capello // Copyright (C) 2016-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -19,6 +19,8 @@
#include "base/fs.h" #include "base/fs.h"
#include "doc/layer.h" #include "doc/layer.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "fmt/format.h"
#include "ver/info.h"
#include <iostream> #include <iostream>
#include <memory> #include <memory>
@ -27,12 +29,12 @@ namespace app {
void PreviewCliDelegate::showHelp(const AppOptions& options) void PreviewCliDelegate::showHelp(const AppOptions& options)
{ {
std::cout << "- Show " PACKAGE " CLI usage\n"; std::cout << fmt::format("- Show {} CLI usage\n", get_app_name());
} }
void PreviewCliDelegate::showVersion() void PreviewCliDelegate::showVersion()
{ {
std::cout << "- Show " PACKAGE " version\n"; std::cout << fmt::format("- Show {} version\n", get_app_name());
} }
void PreviewCliDelegate::uiMode() void PreviewCliDelegate::uiMode()

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// //
// 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.
@ -22,8 +22,6 @@ namespace app {
ClosedDocs::ClosedDocs(const Preferences& pref) ClosedDocs::ClosedDocs(const Preferences& pref)
: m_done(false) : m_done(false)
{ {
CLOSEDOC_TRACE("CLOSEDOC: Init");
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
@ -33,6 +31,10 @@ ClosedDocs::ClosedDocs(const Preferences& pref)
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",
"dataRecoveryPeriod", m_dataRecoveryPeriodMSecs,
"keepClosedDocs", m_keepClosedDocAliveForMSecs);
} }
ClosedDocs::~ClosedDocs() ClosedDocs::~ClosedDocs()
@ -123,15 +125,20 @@ void ClosedDocs::backgroundThread()
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;
base::tick_t diff = now - closedDoc.timestamp; base::tick_t diff = now - closedDoc.timestamp;
if (diff >= m_keepClosedDocAliveForMSecs) { if (diff >= m_keepClosedDocAliveForMSecs) {
if (m_dataRecoveryPeriodMSecs == 0 || if (// If we backup process is disabled
closedDoc.doc->isFullyBackedUp()) { m_dataRecoveryPeriodMSecs == 0 ||
// Or this document doesn't need a backup (e.g. an unmodified document)
!doc->needsBackup() ||
// Or the document already has the backup done
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", closedDoc.doc); CLOSEDOC_TRACE("CLOSEDOC: [BG] Delete doc", doc);
delete closedDoc.doc; delete doc;
it = m_docs.erase(it); it = m_docs.erase(it);
} }
else { else {

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -13,6 +14,8 @@
#include "app/modules/gui.h" #include "app/modules/gui.h"
#include "app/ui/main_window.h" #include "app/ui/main_window.h"
#include "base/bind.h" #include "base/bind.h"
#include "fmt/format.h"
#include "ver/info.h"
#include "about.xml.h" #include "about.xml.h"
@ -36,7 +39,7 @@ AboutCommand::AboutCommand()
void AboutCommand::onExecute(Context* context) void AboutCommand::onExecute(Context* context)
{ {
gen::About window; gen::About window;
window.title()->setText(PACKAGE " v" VERSION); window.title()->setText(fmt::format("{} v{}", get_app_name(), get_app_version()));
window.licenses()->Click.connect( window.licenses()->Click.connect(
[&window]{ [&window]{
window.closeWindow(nullptr); window.closeWindow(nullptr);

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -12,6 +13,7 @@
#include "app/commands/params.h" #include "app/commands/params.h"
#include "app/launcher.h" #include "app/launcher.h"
#include "base/fs.h" #include "base/fs.h"
#include "ver/info.h"
namespace app { namespace app {
@ -42,7 +44,7 @@ void LaunchCommand::onLoadParams(const Params& params)
m_path = params.get("path"); m_path = params.get("path");
if (m_type == Url && !m_path.empty() && m_path[0] == '/') { if (m_type == Url && !m_path.empty() && m_path[0] == '/') {
m_path = WEBSITE + m_path.substr(1); m_path = std::string(get_app_url()) + m_path.substr(1);
} }
} }

View File

@ -27,6 +27,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/chrono.h" #include "base/chrono.h"
#include "base/convert_to.h" #include "base/convert_to.h"
#include "base/scoped_value.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/mask.h" #include "doc/mask.h"
#include "doc/sprite.h" #include "doc/sprite.h"
@ -70,11 +71,11 @@ private:
} }
}; };
Window* m_window; // TODO we cannot use a std::unique_ptr because clone() needs a copy ctor Window* m_window = nullptr;
ColorButton* m_buttonColor; ColorButton* m_buttonColor = nullptr;
CheckBox* m_checkPreview; CheckBox* m_checkPreview = nullptr;
Slider* m_sliderTolerance; Slider* m_sliderTolerance = nullptr;
SelModeField* m_selMode; SelModeField* m_selMode = nullptr;
}; };
MaskByColorCommand::MaskByColorCommand() MaskByColorCommand::MaskByColorCommand()
@ -91,6 +92,8 @@ bool MaskByColorCommand::onEnabled(Context* context)
void MaskByColorCommand::onExecute(Context* context) void MaskByColorCommand::onExecute(Context* context)
{ {
ASSERT(!m_window);
const ContextReader reader(context); const ContextReader reader(context);
const Sprite* sprite = reader.sprite(); const Sprite* sprite = reader.sprite();
@ -102,7 +105,8 @@ void MaskByColorCommand::onExecute(Context* context)
if (!image) if (!image)
return; return;
m_window = new Window(Window::WithTitleBar, "Mask by Color"); std::unique_ptr<Window> win(new Window(Window::WithTitleBar, "Mask by Color"));
base::ScopedValue<Window*> setWindow(m_window, win.get(), nullptr);
TooltipManager* tooltipManager = new TooltipManager(); TooltipManager* tooltipManager = new TooltipManager();
m_window->addChild(tooltipManager); m_window->addChild(tooltipManager);
auto box1 = new Box(VERTICAL); auto box1 = new Box(VERTICAL);
@ -135,7 +139,6 @@ void MaskByColorCommand::onExecute(Context* context)
button_ok->Click.connect(base::Bind<void>(&Window::closeWindow, m_window, button_ok)); button_ok->Click.connect(base::Bind<void>(&Window::closeWindow, m_window, button_ok));
button_cancel->Click.connect(base::Bind<void>(&Window::closeWindow, m_window, button_cancel)); button_cancel->Click.connect(base::Bind<void>(&Window::closeWindow, m_window, button_cancel));
m_buttonColor->Change.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader))); m_buttonColor->Change.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
m_sliderTolerance->Change.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader))); m_sliderTolerance->Change.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
m_checkPreview->Click.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader))); m_checkPreview->Click.connect(base::Bind<void>(&MaskByColorCommand::maskPreview, this, base::Ref(reader)));
@ -198,7 +201,6 @@ void MaskByColorCommand::onExecute(Context* context)
// Save window configuration. // Save window configuration.
save_window_pos(m_window, "MaskColor"); save_window_pos(m_window, "MaskColor");
delete m_window;
} }
Mask* MaskByColorCommand::generateMask(const Mask& origMask, Mask* MaskByColorCommand::generateMask(const Mask& origMask,
@ -245,7 +247,8 @@ Mask* MaskByColorCommand::generateMask(const Mask& origMask,
void MaskByColorCommand::maskPreview(const ContextReader& reader) void MaskByColorCommand::maskPreview(const ContextReader& reader)
{ {
if (m_checkPreview->isSelected()) { ASSERT(m_window);
if (m_window && m_checkPreview->isSelected()) {
int xpos, ypos; int xpos, ypos;
const Image* image = reader.image(&xpos, &ypos); const Image* image = reader.image(&xpos, &ypos);
std::unique_ptr<Mask> mask(generateMask(*reader.document()->mask(), std::unique_ptr<Mask> mask(generateMask(*reader.document()->mask(),

View File

@ -421,11 +421,10 @@ public:
// Links // Links
locateFile()->Click.connect(base::Bind<void>(&OptionsWindow::onLocateConfigFile, this)); locateFile()->Click.connect(base::Bind<void>(&OptionsWindow::onLocateConfigFile, this));
#if _WIN32 if (!App::instance()->memoryDumpFilename().empty())
locateCrashFolder()->Click.connect(base::Bind<void>(&OptionsWindow::onLocateCrashFolder, this)); locateCrashFolder()->Click.connect(base::Bind<void>(&OptionsWindow::onLocateCrashFolder, this));
#else else
locateCrashFolder()->setVisible(false); locateCrashFolder()->setVisible(false);
#endif
// Undo preferences // Undo preferences
limitUndo()->Click.connect(base::Bind<void>(&OptionsWindow::onLimitUndoCheck, this)); limitUndo()->Click.connect(base::Bind<void>(&OptionsWindow::onLimitUndoCheck, this));
@ -1017,7 +1016,8 @@ private:
} }
void onLocateCrashFolder() { void onLocateCrashFolder() {
app::launcher::open_folder(base::get_file_path(app::memory_dump_filename())); app::launcher::open_folder(
base::get_file_path(App::instance()->memoryDumpFilename()));
} }
void onLocateConfigFile() { void onLocateConfigFile() {

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -97,15 +97,23 @@ void BackupObserver::onRemoveDocument(Doc* doc)
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::mutex> lock(m_mutex);
base::remove_from_container(m_documents, doc); base::remove_from_container(m_documents, doc);
} }
if (m_config->keepEditedSpriteDataFor > 0 && if (doc->needsBackup() &&
doc->needsBackup() && // If the document is already fully backed up, we don't need to
// add it to the background thread to create its backup
!doc->isFullyBackedUp() &&
// If the backup is disabled, we don't need it (e.g. when the // If the backup is disabled, we don't need it (e.g. when the
// document is destroyed from a script with Sprite:close(), the // document is destroyed from a script with Sprite:close(), the
// backup is disabled) // backup is disabled)
!doc->inhibitBackup()) { !doc->inhibitBackup()) {
// If m_config->keepEditedSpriteDataFor == 0 we add the document
// in m_closedDocs list anyway so we call markAsBackedUp(), and
// then it's deleted from ClosedDocs::backgroundThread()
TRACE("RECO: Adding to CLOSEDOC %p\n", doc);
m_closedDocs.push_back(doc); m_closedDocs.push_back(doc);
} }
else { else {
TRACE("RECO: Removing doc %p from session\n", doc);
m_session->removeDocument(doc); m_session->removeDocument(doc);
} }
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -31,6 +31,7 @@
#include "base/time.h" #include "base/time.h"
#include "doc/cancel_io.h" #include "doc/cancel_io.h"
#include "fmt/format.h" #include "fmt/format.h"
#include "ver/info.h"
namespace app { namespace app {
namespace crash { namespace crash {
@ -170,7 +171,7 @@ void Session::create(base::pid pid)
std::ofstream verf(FSTREAM_PATH(verFilename())); std::ofstream verf(FSTREAM_PATH(verFilename()));
pidf << m_pid; pidf << m_pid;
verf << VERSION; verf << get_app_version();
} }
void Session::close() void Session::close()

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -39,6 +39,8 @@
#include <limits> #include <limits>
#include <map> #include <map>
#define DOC_TRACE(...) // TRACEARGS
namespace app { namespace app {
using namespace base; using namespace base;
@ -61,10 +63,12 @@ Doc::Doc(Sprite* sprite)
sprites().add(sprite); sprites().add(sprite);
updateOSColorSpace(false); updateOSColorSpace(false);
DOC_TRACE("DOC: New", this);
} }
Doc::~Doc() Doc::~Doc()
{ {
DOC_TRACE("DOC: Deleting", this);
removeFromContext(); removeFromContext();
} }
@ -77,6 +81,8 @@ void Doc::setContext(Context* ctx)
m_ctx = ctx; m_ctx = ctx;
if (ctx) { if (ctx) {
DOC_TRACE("DOC: Removing as fully backed up", this);
// Remove the flag that indicates that this doc is fully backed // Remove the flag that indicates that this doc is fully backed
// up, because now we are inside a context, so the user can change // up, because now we are inside a context, so the user can change
// it again and the backup will be outdated. // it again and the backup will be outdated.
@ -263,6 +269,8 @@ void Doc::setInhibitBackup(const bool inhibitBackup)
void Doc::markAsBackedUp() void Doc::markAsBackedUp()
{ {
DOC_TRACE("DOC: Mark as fully backed up", this);
m_flags |= kFullyBackedUp; m_flags |= kFullyBackedUp;
} }

View File

@ -44,6 +44,7 @@
#include "render/dithering.h" #include "render/dithering.h"
#include "render/ordered_dither.h" #include "render/ordered_dither.h"
#include "render/render.h" #include "render/render.h"
#include "ver/info.h"
#include <cstdio> #include <cstdio>
#include <fstream> #include <fstream>
@ -1303,8 +1304,8 @@ void DocExporter::createDataFile(const Samples& samples,
// "meta" property // "meta" property
os << ",\n" os << ",\n"
<< " \"meta\": {\n" << " \"meta\": {\n"
<< " \"app\": \"" << WEBSITE << "\",\n" << " \"app\": \"" << get_app_url() << "\",\n"
<< " \"version\": \"" << VERSION << "\",\n"; << " \"version\": \"" << get_app_version() << "\",\n";
if (!m_textureFilename.empty()) if (!m_textureFilename.empty())
os << " \"image\": \"" os << " \"image\": \""

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -27,6 +27,7 @@
#include "fixmath/fixmath.h" #include "fixmath/fixmath.h"
#include "fmt/format.h" #include "fmt/format.h"
#include "ui/alert.h" #include "ui/alert.h"
#include "ver/info.h"
#include "zlib.h" #include "zlib.h"
#include <cstdio> #include <cstdio>
@ -288,7 +289,7 @@ bool AseFormat::onPostLoad(FileOp* fop)
// Forward Compatibility: In 1.1 we convert a file with layer groups // Forward Compatibility: In 1.1 we convert a file with layer groups
// (saved with 1.2) as top level layers // (saved with 1.2) as top level layers
std::string ver = VERSION; std::string ver = get_app_version();
bool flat = (ver[0] == '1' && bool flat = (ver[0] == '1' &&
ver[1] == '.' && ver[1] == '.' &&
ver[2] == '1'); ver[2] == '1');
@ -305,7 +306,7 @@ bool AseFormat::onPostLoad(FileOp* fop)
"<<Note: Layers inside groups will be converted to top level layers." "<<Note: Layers inside groups will be converted to top level layers."
"||&Yes||&No", "||&Yes||&No",
base::get_file_name(fop->filename()), base::get_file_name(fop->filename()),
PACKAGE, ver)) != 1) { get_app_name(), ver)) != 1) {
return false; return false;
} }
ase_ungroup_all(group); ase_ungroup_all(group);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -41,6 +41,7 @@
#include "ui/alert.h" #include "ui/alert.h"
#include "ui/listitem.h" #include "ui/listitem.h"
#include "ui/system.h" #include "ui/system.h"
#include "ver/info.h"
#include "ask_for_color_profile.xml.h" #include "ask_for_color_profile.xml.h"
#include "open_sequence.xml.h" #include "open_sequence.xml.h"
@ -200,7 +201,7 @@ FileOp* FileOp::createLoadDocumentOperation(Context* context,
dio::detect_format(filename)); dio::detect_format(filename));
if (!fop->m_format || if (!fop->m_format ||
!fop->m_format->support(FILE_SUPPORT_LOAD)) { !fop->m_format->support(FILE_SUPPORT_LOAD)) {
fop->setError("%s can't load \"%s\" file (\"%s\")\n", PACKAGE, fop->setError("%s can't load \"%s\" file (\"%s\")\n", get_app_name(),
filename.c_str(), base::get_file_extension(filename).c_str()); filename.c_str(), base::get_file_extension(filename).c_str());
goto done; goto done;
} }
@ -354,7 +355,7 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context,
dio::detect_format_by_file_extension(filename)); dio::detect_format_by_file_extension(filename));
if (!fop->m_format || if (!fop->m_format ||
!fop->m_format->support(FILE_SUPPORT_SAVE)) { !fop->m_format->support(FILE_SUPPORT_SAVE)) {
fop->setError("%s can't save \"%s\" file (\"%s\")\n", PACKAGE, fop->setError("%s can't save \"%s\" file (\"%s\")\n", get_app_name(),
filename.c_str(), base::get_file_extension(filename).c_str()); filename.c_str(), base::get_file_extension(filename).c_str());
return fop.release(); return fop.release();
} }
@ -835,8 +836,9 @@ void FileOp::operate(IFileOpProgress* progress)
} }
#else #else
setError( setError(
"Save operation is not supported in trial version.\n" fmt::format("Save operation is not supported in trial version.\n"
"Go to " WEBSITE_DOWNLOAD " and get the full-version."); "Go to {} and get the full-version.",
get_app_download_url()));
#endif #endif
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -154,6 +154,7 @@ public:
// A more easy PIDLs interface (without using the SH* & IL* routines of W2K) // A more easy PIDLs interface (without using the SH* & IL* routines of W2K)
#ifdef _WIN32 #ifdef _WIN32
static SFGAOF get_pidl_attrib(FileItem* fileitem, SFGAOF attrib);
static void update_by_pidl(FileItem* fileitem, SFGAOF attrib); static void update_by_pidl(FileItem* fileitem, SFGAOF attrib);
static LPITEMIDLIST concat_pidl(LPITEMIDLIST pidlHead, LPITEMIDLIST pidlTail); static LPITEMIDLIST concat_pidl(LPITEMIDLIST pidlHead, LPITEMIDLIST pidlTail);
static UINT get_pidl_size(LPITEMIDLIST pidl); static UINT get_pidl_size(LPITEMIDLIST pidl);
@ -453,7 +454,7 @@ const FileItemList& FileItem::children()
IEnumIDList *pEnum = NULL; IEnumIDList *pEnum = NULL;
ULONG c, fetched; ULONG c, fetched;
/* get the interface to enumerate subitems */ // Get the interface to enumerate subitems
hr = pFolder->EnumObjects(reinterpret_cast<HWND>(os::instance()->defaultDisplay()->nativeHandle()), hr = pFolder->EnumObjects(reinterpret_cast<HWND>(os::instance()->defaultDisplay()->nativeHandle()),
SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnum); SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnum);
@ -461,16 +462,16 @@ const FileItemList& FileItem::children()
LPITEMIDLIST itempidl[256]; LPITEMIDLIST itempidl[256];
SFGAOF attribs[256]; SFGAOF attribs[256];
/* enumerate the items in the folder */ // Enumerate the items in the folder
while (pEnum->Next(256, itempidl, &fetched) == S_OK && fetched > 0) { while (pEnum->Next(256, itempidl, &fetched) == S_OK && fetched > 0) {
/* request the SFGAO_FOLDER attribute to know what of the // Request the SFGAO_FOLDER attribute to know what of the
item is a folder */ // item is file or a folder
for (c=0; c<fetched; ++c) { for (c=0; c<fetched; ++c) {
attribs[c] = SFGAO_FOLDER; attribs[c] = SFGAO_FOLDER;
pFolder->GetAttributesOf(1, (LPCITEMIDLIST *)itempidl, attribs+c); pFolder->GetAttributesOf(1, (LPCITEMIDLIST *)itempidl, attribs+c);
} }
/* generate the FileItems */ // Generate the FileItems
for (c=0; c<fetched; ++c) { for (c=0; c<fetched; ++c) {
LPITEMIDLIST fullpidl = concat_pidl(m_fullpidl, LPITEMIDLIST fullpidl = concat_pidl(m_fullpidl,
itempidl[c]); itempidl[c]);
@ -680,6 +681,34 @@ static bool calc_is_folder(std::string filename, SFGAOF attrib)
&& ((!filename.empty() && (*filename.begin()) != ':') || (filename == MYPC_CSLID)); && ((!filename.empty() && (*filename.begin()) != ':') || (filename == MYPC_CSLID));
} }
static SFGAOF get_pidl_attrib(FileItem* fileitem, SFGAOF attrib)
{
ASSERT(fileitem->m_pidl);
ASSERT(fileitem->m_parent);
HRESULT hr;
IShellFolder* pFolder = nullptr;
if (fileitem->m_parent == rootitem)
pFolder = shl_idesktop;
else {
hr = shl_idesktop->BindToObject(fileitem->m_parent->m_fullpidl,
nullptr, IID_IShellFolder, (LPVOID*)&pFolder);
if (hr != S_OK)
pFolder = nullptr;
}
if (pFolder) {
SFGAOF attrib2 = SFGAO_FOLDER;
hr = pFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&fileitem->m_pidl, &attrib2);
if (hr == S_OK)
attrib = attrib2;
if (pFolder && pFolder != shl_idesktop)
pFolder->Release();
}
return attrib;
}
// Updates the names of the file-item through its PIDL // Updates the names of the file-item through its PIDL
static void update_by_pidl(FileItem* fileitem, SFGAOF attrib) static void update_by_pidl(FileItem* fileitem, SFGAOF attrib)
{ {
@ -693,7 +722,7 @@ static void update_by_pidl(FileItem* fileitem, SFGAOF attrib)
else { else {
ASSERT(fileitem->m_parent); ASSERT(fileitem->m_parent);
hr = shl_idesktop->BindToObject(fileitem->m_parent->m_fullpidl, hr = shl_idesktop->BindToObject(fileitem->m_parent->m_fullpidl,
NULL, IID_IShellFolder, (LPVOID *)&pFolder); nullptr, IID_IShellFolder, (LPVOID*)&pFolder);
if (hr != S_OK) if (hr != S_OK)
pFolder = NULL; pFolder = NULL;
} }
@ -921,7 +950,7 @@ static FileItem* get_fileitem_by_fullpidl(LPITEMIDLIST fullpidl, bool create_if_
if (!create_if_not) if (!create_if_not)
return nullptr; return nullptr;
// Check if the pidl exists // Validate if the fullpidl exists.
SFGAOF attrib = SFGAO_FOLDER | SFGAO_VALIDATE; SFGAOF attrib = SFGAO_FOLDER | SFGAO_VALIDATE;
HRESULT hr = shl_idesktop->GetAttributesOf(1, (LPCITEMIDLIST*)&fullpidl, &attrib); HRESULT hr = shl_idesktop->GetAttributesOf(1, (LPCITEMIDLIST*)&fullpidl, &attrib);
if (hr != S_OK) if (hr != S_OK)
@ -939,6 +968,12 @@ static FileItem* get_fileitem_by_fullpidl(LPITEMIDLIST fullpidl, bool create_if_
fileitem->m_parent = get_fileitem_by_fullpidl(parent_fullpidl, true); fileitem->m_parent = get_fileitem_by_fullpidl(parent_fullpidl, true);
free_pidl(parent_fullpidl); free_pidl(parent_fullpidl);
// Get specific pidl attributes
if (fileitem->m_pidl &&
fileitem->m_parent) {
attrib = get_pidl_attrib(fileitem, attrib);
}
} }
update_by_pidl(fileitem, attrib); update_by_pidl(fileitem, attrib);
@ -949,9 +984,7 @@ static FileItem* get_fileitem_by_fullpidl(LPITEMIDLIST fullpidl, bool create_if_
return fileitem; return fileitem;
} }
/** // Inserts the fileitem in the hash map of items.
* Inserts the @a fileitem in the hash map of items.
*/
static void put_fileitem(FileItem* fileitem) static void put_fileitem(FileItem* fileitem)
{ {
ASSERT(fileitem->m_filename != NOTINITIALIZED); ASSERT(fileitem->m_filename != NOTINITIALIZED);

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -40,17 +41,4 @@ GuiXml::GuiXml()
m_doc = app::open_xml(rf.filename()); m_doc = app::open_xml(rf.filename());
} }
std::string GuiXml::version()
{
TiXmlHandle handle(m_doc.get());
TiXmlElement* xmlKey = handle.FirstChild("gui").ToElement();
if (xmlKey && xmlKey->Attribute("version")) {
const char* guixml_version = xmlKey->Attribute("version");
return guixml_version;
}
else
return "";
}
} // namespace app } // namespace app

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2015 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -32,8 +33,6 @@ namespace app {
return m_doc->Value(); return m_doc->Value();
} }
std::string version();
private: private:
GuiXml(); GuiXml();

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -13,6 +14,8 @@
#include "app/app.h" #include "app/app.h"
#include "app/resource_finder.h" #include "app/resource_finder.h"
#include "base/log.h" #include "base/log.h"
#include "fmt/format.h"
#include "ver/info.h"
namespace app { namespace app {
@ -20,10 +23,14 @@ LoggerModule::LoggerModule(bool createLogInDesktop)
{ {
app::ResourceFinder rf(false); app::ResourceFinder rf(false);
if (createLogInDesktop) if (createLogInDesktop) {
rf.includeDesktopDir(PACKAGE "-v" VERSION "-DebugOutput.txt"); rf.includeDesktopDir(fmt::format("{}-v{}-DebugOutput.txt",
else get_app_name(),
rf.includeUserDir("aseprite.log"); get_app_version()).c_str());
}
else {
rf.includeUserDir(fmt::format("{}.log", get_app_name()).c_str());
}
auto filename = rf.defaultFilename(); auto filename = rf.defaultFilename();
base::set_log_filename(filename.c_str()); base::set_log_filename(filename.c_str());

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -217,18 +217,19 @@ void draw_alpha_slider(os::Surface* s,
color.getGreen(), color.getGreen(),
color.getBlue(), 255): 0); color.getBlue(), 255): 0);
os::Paint paint;
for (int x=0; x<rc.w; ++x) { for (int x=0; x<rc.w; ++x) {
const int a = (255 * x / xmax); const int a = (255 * x / xmax);
const doc::color_t c1 = doc::rgba_blender_normal(gridColor1, c, a); const doc::color_t c1 = doc::rgba_blender_normal(gridColor1, c, a);
const doc::color_t c2 = doc::rgba_blender_normal(gridColor2, c, a); const doc::color_t c2 = doc::rgba_blender_normal(gridColor2, c, a);
const int mid = rc.h/2; const int mid = rc.h/2;
const int odd = (x / rc.h) & 1; const int odd = (x / rc.h) & 1;
s->drawVLine(
app::color_utils::color_for_ui(app::Color::fromImage(IMAGE_RGB, odd ? c2: c1)), paint.color(app::color_utils::color_for_ui(app::Color::fromImage(IMAGE_RGB, odd ? c2: c1)));
rc.x+x, rc.y, mid); s->drawRect(gfx::Rect(rc.x+x, rc.y, 1, mid), paint);
s->drawVLine(
app::color_utils::color_for_ui(app::Color::fromImage(IMAGE_RGB, odd ? c1: c2)), paint.color(app::color_utils::color_for_ui(app::Color::fromImage(IMAGE_RGB, odd ? c1: c2)));
rc.x+x, rc.y+mid, rc.h-mid); s->drawRect(gfx::Rect(rc.x+x, rc.y+mid, 1, rc.h-mid), paint);
} }
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -18,6 +19,7 @@
#include "base/string.h" #include "base/string.h"
#include "net/http_request.h" #include "net/http_request.h"
#include "net/http_response.h" #include "net/http_response.h"
#include "ver/info.h"
#include <fstream> #include <fstream>
@ -49,7 +51,7 @@ void HttpLoader::threadHttpRequest()
LOG("HTTP: Sending http request to %s\n", m_url.c_str()); LOG("HTTP: Sending http request to %s\n", m_url.c_str());
std::string dir = base::join_path(base::get_temp_path(), PACKAGE); std::string dir = base::join_path(base::get_temp_path(), get_app_name());
base::make_all_directories(dir); base::make_all_directories(dir);
std::string fn = m_url; std::string fn = m_url;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -14,6 +14,7 @@
#include "app/app.h" #include "app/app.h"
#include "base/fs.h" #include "base/fs.h"
#include "base/string.h" #include "base/string.h"
#include "ver/info.h"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@ -178,7 +179,7 @@ void ResourceFinder::includeUserDir(const char* filename)
// $HOME/Library/Application Support/Aseprite/filename // $HOME/Library/Application Support/Aseprite/filename
addPath( addPath(
base::join_path( base::join_path(
base::join_path(base::get_lib_app_support_path(), PACKAGE), base::join_path(base::get_lib_app_support_path(), get_app_name()),
filename).c_str()); filename).c_str());
#else // !__APPLE__ #else // !__APPLE__

View File

@ -44,6 +44,7 @@
#include "doc/tag.h" #include "doc/tag.h"
#include "render/render.h" #include "render/render.h"
#include "ui/alert.h" #include "ui/alert.h"
#include "ver/info.h"
#include <iostream> #include <iostream>
@ -490,7 +491,7 @@ int App_get_isUIAvailable(lua_State* L)
int App_get_version(lua_State* L) int App_get_version(lua_State* L)
{ {
std::string ver = VERSION; std::string ver = get_app_version();
base::replace_string(ver, "-x64", ""); // Remove "-x64" suffix base::replace_string(ver, "-x64", ""); // Remove "-x64" suffix
push_version(L, base::Version(ver)); push_version(L, base::Version(ver));
return 1; return 1;

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -14,26 +15,105 @@
#include "app/console.h" #include "app/console.h"
#include "app/i18n/strings.h" #include "app/i18n/strings.h"
#include "app/resource_finder.h" #include "app/resource_finder.h"
#include "app/task.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/fs.h" #include "base/fs.h"
#include "base/launcher.h" #include "base/launcher.h"
#include "fmt/format.h"
#include "ui/alert.h" #include "ui/alert.h"
#include "ui/system.h"
#include "ver/info.h"
#include "send_crash.xml.h" #include "send_crash.xml.h"
namespace app { namespace app {
// static
std::string SendCrash::DefaultMemoryDumpFilename()
{
#ifdef _WIN32
std::string kDefaultCrashName = fmt::format("{}-crash-{}.dmp",
get_app_name(),
get_app_version());
ResourceFinder rf;
rf.includeUserDir(kDefaultCrashName.c_str());
return rf.getFirstOrCreateDefault();
#else
return std::string();
#endif
}
SendCrash::~SendCrash()
{
if (m_task.running()) {
m_task.cancel();
m_task.wait();
}
}
void SendCrash::search() void SendCrash::search()
{ {
#ifdef _WIN32 #ifdef _WIN32
m_dumpFilename = memory_dump_filename(); // On Windows we use one mini-dump to report bugs, then we can open
// this .dmp file locally along with the .exe + .pdb to check the
// stack trace and detect the cause of the bug.
if (base::is_file(m_dumpFilename)) { m_dumpFilename = SendCrash::DefaultMemoryDumpFilename();
App::instance()->showNotification(this); if (!m_dumpFilename.empty() &&
base::is_file(m_dumpFilename)) {
auto app = App::instance();
app->memoryDumpFilename(m_dumpFilename);
#ifdef ENABLE_UI
app->showNotification(this);
#endif
} }
#elif defined(__APPLE__)
// On macOS we can show the possibility to send the latest crash
// report from ~/Library/Logs/DiagnosticReports which is the
// location where crash reports (.crash files) are located.
m_task.run(
[this](base::task_token&){
ResourceFinder rf;
rf.includeHomeDir("Library/Logs/DiagnosticReports");
std::string dir = rf.defaultFilename();
if (base::is_directory(dir)) {
std::vector<std::string> candidates;
int n = std::strlen(get_app_name());
for (const auto& fn : base::list_files(dir)) {
// Cancel everything
if (m_task.canceled())
return;
if (base::utf8_icmp(get_app_name(), fn, n) == 0) {
candidates.push_back(fn);
}
}
std::sort(candidates.begin(), candidates.end());
if (!candidates.empty()) {
std::string fn = base::join_path(dir, candidates.back());
if (base::is_file(fn)) {
ui::execute_from_ui_thread(
[this, fn]{
m_dumpFilename = fn;
if (auto app = App::instance()) {
app->memoryDumpFilename(fn);
#ifdef ENABLE_UI
app->showNotification(this);
#endif
}
});
}
}
}
});
#endif #endif
} }
#ifdef ENABLE_UI
std::string SendCrash::notificationText() std::string SendCrash::notificationText()
{ {
return "Report last crash"; return "Report last crash";
@ -48,15 +128,24 @@ void SendCrash::notificationClick()
app::gen::SendCrash dlg; app::gen::SendCrash dlg;
// The current version is a "development" version if the VERSION #if _WIN32
// macro contains the "dev" word. // Only on Windows, if the current version is a development version
bool isDev = (std::string(VERSION).find("dev") != std::string::npos); // (i.e. the get_app_version() contains "-dev"), the .dmp
// file is useless for us. This is because we need the .exe + .pdb +
// source code used in the compilation process to make some sense of
// the .dmp file.
bool isDev = (std::string(get_app_version()).find("-dev") != std::string::npos);
if (isDev) { if (isDev) {
dlg.official()->setVisible(false); dlg.official()->setVisible(false);
dlg.devFilename()->setText(m_dumpFilename); dlg.devFilename()->setText(m_dumpFilename);
dlg.devFilename()->Click.connect(base::Bind(&SendCrash::onClickDevFilename, this)); dlg.devFilename()->Click.connect(base::Bind(&SendCrash::onClickDevFilename, this));
} }
else { else
#endif // On other platforms the crash file might be useful even in
// the "-dev" version (e.g. on macOS it's a text file with
// stack traces).
{
dlg.dev()->setVisible(false); dlg.dev()->setVisible(false);
dlg.filename()->setText(m_dumpFilename); dlg.filename()->setText(m_dumpFilename);
dlg.filename()->Click.connect(base::Bind(&SendCrash::onClickFilename, this)); dlg.filename()->Click.connect(base::Bind(&SendCrash::onClickFilename, this));
@ -84,4 +173,6 @@ void SendCrash::onClickDevFilename()
base::launcher::open_file(m_dumpFilename); base::launcher::open_file(m_dumpFilename);
} }
#endif // ENABLE_UI
} // namespace app } // namespace app

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -9,22 +10,36 @@
#pragma once #pragma once
#include "app/notification_delegate.h" #include "app/notification_delegate.h"
#include "app/task.h"
#include <string> #include <string>
namespace app { namespace app {
class SendCrash : public INotificationDelegate { class SendCrash
#ifdef ENABLE_UI
: public INotificationDelegate
#endif
{
public: public:
static std::string DefaultMemoryDumpFilename();
~SendCrash();
void search(); void search();
#ifdef ENABLE_UI
public: // INotificationDelegate impl
virtual std::string notificationText() override; virtual std::string notificationText() override;
virtual void notificationClick() override; virtual void notificationClick() override;
private: private:
void onClickFilename(); void onClickFilename();
void onClickDevFilename(); void onClickDevFilename();
#endif // ENABLE_UI
private:
Task m_task;
std::string m_dumpFilename; std::string m_dumpFilename;
}; };

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -14,7 +15,9 @@
#include "app/shell.h" #include "app/shell.h"
#include "fmt/format.h"
#include "script/engine.h" #include "script/engine.h"
#include "ver/info.h"
#include <iostream> #include <iostream>
#include <string> #include <string>
@ -31,7 +34,8 @@ Shell::~Shell()
void Shell::run(script::Engine& engine) void Shell::run(script::Engine& engine)
{ {
std::cout << "Welcome to " PACKAGE " v" VERSION " Interactive Console" << std::endl; std::cout << fmt::format("Welcome to {} v{} Interactive Console",
get_app_name(), get_app_version()) << std::endl;
std::string line; std::string line;
while (std::getline(std::cin, line)) { while (std::getline(std::cin, line)) {
engine.evalCode(line); engine.evalCode(line);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// //
// 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.
@ -11,6 +11,7 @@
#include "app/task.h" #include "app/task.h"
#include "base/task.h" #include "base/task.h"
#include "base/thread.h"
#include "base/thread_pool.h" #include "base/thread_pool.h"
namespace app { namespace app {
@ -32,4 +33,12 @@ void Task::run(base::task::func_t&& func)
m_token = &m_task.start(tasks_pool); m_token = &m_task.start(tasks_pool);
} }
void Task::wait()
{
// TODO wait a condition variable
while (!m_task.completed()) {
base::this_thread::sleep_for(0.1);
}
}
} // namespace app } // namespace app

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// //
// 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.
@ -20,6 +20,7 @@ namespace app {
~Task(); ~Task();
void run(base::task::func_t&& func); void run(base::task::func_t&& func);
void wait();
// Returns true when the task is completed (whether it was // Returns true when the task is completed (whether it was
// canceled or not) // canceled or not)
@ -27,6 +28,10 @@ namespace app {
return m_task.completed(); return m_task.completed();
} }
bool running() const {
return m_task.running();
}
bool canceled() const { bool canceled() const {
if (m_token) if (m_token)
return m_token->canceled(); return m_token->canceled();

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -102,6 +102,9 @@ namespace app {
// Called for each point shape. // Called for each point shape.
virtual void prepareForPointShape(ToolLoop* loop, bool firstPoint, int x, int y) { } virtual void prepareForPointShape(ToolLoop* loop, bool firstPoint, int x, int y) { }
virtual void prepareVForPointShape(ToolLoop* loop, int y) { }
virtual void prepareUForPointShapeWholeScanline(ToolLoop* loop, int x1) { }
virtual void prepareUForPointShapeSlicedScanline(ToolLoop* loop, bool leftSlice, int x1) { }
}; };

View File

@ -34,6 +34,9 @@ public:
virtual void processScanline(int x1, int y, int x2, ToolLoop* loop) = 0; virtual void processScanline(int x1, int y, int x2, ToolLoop* loop) = 0;
virtual void prepareForStrokes(ToolLoop* loop, Strokes& strokes) { } virtual void prepareForStrokes(ToolLoop* loop, Strokes& strokes) { }
virtual void prepareForPointShape(ToolLoop* loop, bool firstPoint, int x, int y) { } virtual void prepareForPointShape(ToolLoop* loop, bool firstPoint, int x, int y) { }
virtual void prepareVForPointShape(ToolLoop* loop, int y) { }
virtual void prepareUForPointShapeWholeScanline(ToolLoop* loop, int x1) { }
virtual void prepareUForPointShapeSlicedScanline(ToolLoop* loop, bool leftSlice, int x1) { }
}; };
typedef std::unique_ptr<BaseInkProcessing> InkProcessingPtr; typedef std::unique_ptr<BaseInkProcessing> InkProcessingPtr;
@ -1124,8 +1127,51 @@ public:
void prepareForPointShape(ToolLoop* loop, bool firstPoint, int x, int y) override { void prepareForPointShape(ToolLoop* loop, bool firstPoint, int x, int y) override {
if ((m_brush->pattern() == BrushPattern::ALIGNED_TO_DST && firstPoint) || if ((m_brush->pattern() == BrushPattern::ALIGNED_TO_DST && firstPoint) ||
(m_brush->pattern() == BrushPattern::PAINT_BRUSH)) { (m_brush->pattern() == BrushPattern::PAINT_BRUSH)) {
m_u = (m_brush->patternOrigin().x - loop->getCelOrigin().x) % m_width; m_u = ((m_brush->patternOrigin().x % loop->sprite()->width()) - loop->getCelOrigin().x) % m_width;
m_v = ((m_brush->patternOrigin().y % loop->sprite()->height()) - loop->getCelOrigin().y) % m_height;
}
}
void prepareVForPointShape(ToolLoop* loop, int y) override {
if (m_brush->pattern() == doc::BrushPattern::ALIGNED_TO_SRC) {
m_v = (m_brush->patternOrigin().y - loop->getCelOrigin().y) % m_height; m_v = (m_brush->patternOrigin().y - loop->getCelOrigin().y) % m_height;
if (m_v < 0) m_v += m_height;
}
else {
int spriteH = loop->sprite()->height();
if (y/spriteH > 0)
// 'y' is outside of the center tile.
m_v = (m_brush->patternOrigin().y + m_height - (y/spriteH) * spriteH) % m_height;
else
// 'y' is inside of the center tile.
m_v = ((m_brush->patternOrigin().y % spriteH) - loop->getCelOrigin().y) % m_height;
}
}
void prepareUForPointShapeWholeScanline(ToolLoop* loop, int x1) override {
if (m_brush->pattern() == doc::BrushPattern::ALIGNED_TO_SRC) {
m_u = (m_brush->patternOrigin().x - loop->getCelOrigin().x) % m_width;
if (m_u < 0) m_u += m_height;
}
else {
m_u = ((m_brush->patternOrigin().x % loop->sprite()->width()) - loop->getCelOrigin().x ) % m_width;
if (x1/loop->sprite()->width() > 0)
m_u = (m_brush->patternOrigin().x + m_width - (x1/loop->sprite()->width()) * loop->sprite()->width()) % m_width;
}
}
void prepareUForPointShapeSlicedScanline(ToolLoop* loop, bool leftSlice, int x1) override {
if (loop->getBrush()->pattern() == doc::BrushPattern::ALIGNED_TO_SRC) {
m_u = (m_brush->patternOrigin().x - loop->getCelOrigin().x) % m_width;
if (m_u < 0) m_u += m_height;
return;
}
else {
if (leftSlice)
m_u = ((m_brush->patternOrigin().x % loop->sprite()->width()) - loop->getCelOrigin().x ) % m_width;
else
m_u = (m_brush->patternOrigin().x + m_width - (x1/loop->sprite()->width() + 1) * loop->sprite()->width()) % m_width;
} }
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -34,6 +34,21 @@ public:
m_proc->prepareForPointShape(loop, firstPoint, x, y); m_proc->prepareForPointShape(loop, firstPoint, x, y);
} }
void prepareVForPointShape(ToolLoop* loop, int y) override {
ASSERT(m_proc);
m_proc->prepareVForPointShape(loop, y);
}
void prepareUForPointShapeWholeScanline(ToolLoop* loop, int x1) override {
ASSERT(m_proc);
m_proc->prepareUForPointShapeWholeScanline(loop, x1);
}
void prepareUForPointShapeSlicedScanline(ToolLoop* loop, bool leftSlice, int x1) override {
ASSERT(m_proc);
m_proc->prepareUForPointShapeSlicedScanline(loop, leftSlice, x1);
}
protected: protected:
void setProc(BaseInkProcessing* proc) { void setProc(BaseInkProcessing* proc) {
m_proc.reset(proc); m_proc.reset(proc);

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2015 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -13,7 +14,9 @@
#include "app/tools/ink.h" #include "app/tools/ink.h"
#include "app/tools/tool_loop.h" #include "app/tools/tool_loop.h"
#include "app/util/wrap_value.h" #include "app/util/wrap_value.h"
#include "doc/brush.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/sprite.h"
namespace app { namespace app {
namespace tools { namespace tools {
@ -53,13 +56,20 @@ void PointShape::doInkHline(int x1, int y, int x2, ToolLoop* loop)
if (w >= size) if (w >= size)
loop->getInk()->inkHline(0, y, size-1, loop); loop->getInk()->inkHline(0, y, size-1, loop);
else { else {
x = x1; x = wrap_value(x1, loop->sprite()->width());
x = wrap_value(x, size); if (x+w <= loop->sprite()->width()) {
// Here we asure that tile limit line does not bisect the current
if (x+w-1 <= size-1) // scanline, i.e. the scanline is enterely contained inside the tile.
loop->getInk()->prepareUForPointShapeWholeScanline(loop, x1);
loop->getInk()->inkHline(x, y, x+w-1, loop); loop->getInk()->inkHline(x, y, x+w-1, loop);
}
else { else {
// Here the tile limit line bisect the current scanline.
// So we need to execute TWO times the inkHline function, each one with a different m_u.
loop->getInk()->prepareUForPointShapeSlicedScanline(loop, true, x1);// true = left slice
loop->getInk()->inkHline(x, y, size-1, loop); loop->getInk()->inkHline(x, y, size-1, loop);
loop->getInk()->prepareUForPointShapeSlicedScanline(loop, false, x1);// false = right slice
loop->getInk()->inkHline(0, y, w-(size-x)-1, loop); loop->getInk()->inkHline(0, y, w-(size-x)-1, loop);
} }
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -7,6 +7,8 @@
#include "app/util/wrap_point.h" #include "app/util/wrap_point.h"
#include "app/tools/ink.h"
namespace app { namespace app {
namespace tools { namespace tools {
@ -67,13 +69,24 @@ public:
} }
} }
if (int(loop->getTiledMode()) & int(TiledMode::X_AXIS)) {
int wrappedPatternOriginX = wrap_value(m_brush->patternOrigin().x, loop->sprite()->width()) % m_brush->bounds().w;
m_brush->setPatternOrigin(gfx::Point(wrappedPatternOriginX, m_brush->patternOrigin().y));
x = wrap_value(x, loop->sprite()->width());
}
if (int(loop->getTiledMode()) & int(TiledMode::Y_AXIS)) {
int wrappedPatternOriginY = wrap_value(m_brush->patternOrigin().y, loop->sprite()->height()) % m_brush->bounds().h;
m_brush->setPatternOrigin(gfx::Point(m_brush->patternOrigin().x, wrappedPatternOriginY));
y = wrap_value(y, loop->sprite()->height());
}
loop->getInk()->prepareForPointShape(loop, m_firstPoint, x, y); loop->getInk()->prepareForPointShape(loop, m_firstPoint, x, y);
for (auto scanline : *m_compressedImage) { for (auto scanline : *m_compressedImage) {
int u = x+scanline.x; int u = x+scanline.x;
loop->getInk()->prepareVForPointShape(loop, y+scanline.y);
doInkHline(u, y+scanline.y, u+scanline.w-1, loop); doInkHline(u, y+scanline.y, u+scanline.w-1, loop);
} }
m_firstPoint = false; m_firstPoint = false;
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2016-2018 David Capello // Copyright (C) 2016-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -113,7 +113,10 @@ public:
auto oldCanvas = m_canvas; auto oldCanvas = m_canvas;
m_canvas = os::instance()->createSurface(w, h, activeCS); m_canvas = os::instance()->createSurface(w, h, activeCS);
m_canvas->fillRect(bgColor, gfx::Rect(0, 0, w, h)); os::Paint paint;
paint.color(bgColor);
paint.style(os::Paint::Fill);
m_canvas->drawRect(gfx::Rect(0, 0, w, h), paint);
if (oldCanvas) { if (oldCanvas) {
m_canvas->drawSurface(oldCanvas, 0, 0); m_canvas->drawSurface(oldCanvas, 0, 0);
oldCanvas->dispose(); oldCanvas->dispose();

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -111,11 +112,12 @@ void ColorSpectrum::onPaintSurfaceInBgThread(
if (m_paintFlags & BottomBarFlag) { if (m_paintFlags & BottomBarFlag) {
double lit = m_color.getHslLightness(); double lit = m_color.getHslLightness();
double hue = m_color.getHslHue(); double hue = m_color.getHslHue();
os::Paint paint;
for (int x=0; x<bottom.w && !stop; ++x) { for (int x=0; x<bottom.w && !stop; ++x) {
gfx::Color color = color_utils::color_for_ui( paint.color(
app::Color::fromHsl(hue, double(x) / double(bottom.w), lit)); color_utils::color_for_ui(
app::Color::fromHsl(hue, double(x) / double(bottom.w), lit)));
s->drawVLine(color, bottom.x+x, bottom.y, bottom.h); s->drawRect(gfx::Rect(bottom.x+x, bottom.y, 1, bottom.h), paint);
} }
if (stop) if (stop)
return; return;

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2016-2018 David Capello // Copyright (C) 2016-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -100,12 +101,14 @@ void ColorTintShadeTone::onPaintSurfaceInBgThread(
} }
if (m_paintFlags & BottomBarFlag) { if (m_paintFlags & BottomBarFlag) {
os::Paint paint;
for (int x=0; x<bottom.w && !stop; ++x) { for (int x=0; x<bottom.w && !stop; ++x) {
gfx::Color color = color_utils::color_for_ui( paint.color(
app::Color::fromHsv( color_utils::color_for_ui(
(360.0 * x / bottom.w), 1.0, 1.0)); app::Color::fromHsv(
(360.0 * x / bottom.w), 1.0, 1.0)));
s->drawVLine(color, bottom.x+x, bottom.y, bottom.h); s->drawRect(gfx::Rect(bottom.x+x, bottom.y, 1, bottom.h), paint);
} }
if (stop) if (stop)
return; return;

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -275,12 +276,13 @@ void ColorWheel::onPaintSurfaceInBgThread(os::Surface* s,
if (m_paintFlags & BottomBarFlag) { if (m_paintFlags & BottomBarFlag) {
double hue = m_color.getHsvHue(); double hue = m_color.getHsvHue();
double sat = m_color.getHsvSaturation(); double sat = m_color.getHsvSaturation();
os::Paint paint;
for (int x=0; x<bottom.w && !stop; ++x) { for (int x=0; x<bottom.w && !stop; ++x) {
gfx::Color color = color_utils::color_for_ui( paint.color(
app::Color::fromHsv(hue, sat, double(x) / double(bottom.w))); color_utils::color_for_ui(
app::Color::fromHsv(hue, sat, double(x) / double(bottom.w))));
s->drawVLine(color, bottom.x+x, bottom.y, bottom.h); s->drawRect(gfx::Rect(bottom.x+x, bottom.y, 1, bottom.h), paint);
} }
if (stop) if (stop)
return; return;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -40,6 +40,7 @@
#include "ui/size_hint_event.h" #include "ui/size_hint_event.h"
#include "ui/system.h" #include "ui/system.h"
#include "ui/view.h" #include "ui/view.h"
#include "ver/info.h"
#include <algorithm> #include <algorithm>
@ -314,7 +315,7 @@ void DataRecoveryView::fillListWith(const bool crashes)
} }
std::string title = session->name(); std::string title = session->name();
if (session->version() != VERSION) if (session->version() != get_app_version())
title = title =
fmt::format(Strings::recover_files_incompatible(), fmt::format(Strings::recover_files_incompatible(),
title, session->version()); title, session->version());

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -18,11 +19,13 @@
#include "app/app_menus.h" #include "app/app_menus.h"
#include "app/ui/skin/skin_theme.h" #include "app/ui/skin/skin_theme.h"
#include "app/ui/workspace.h" #include "app/ui/workspace.h"
#include "fmt/format.h"
#include "ui/entry.h" #include "ui/entry.h"
#include "ui/message.h" #include "ui/message.h"
#include "ui/system.h" #include "ui/system.h"
#include "ui/textbox.h" #include "ui/textbox.h"
#include "ui/view.h" #include "ui/view.h"
#include "ver/info.h"
namespace app { namespace app {
@ -64,7 +67,8 @@ protected:
DevConsoleView::DevConsoleView() DevConsoleView::DevConsoleView()
: Box(VERTICAL) : Box(VERTICAL)
, m_textBox("Welcome to " PACKAGE " v" VERSION " Console\n(Experimental)", LEFT) , m_textBox(fmt::format("Welcome to {} v{} Console\n(Experimental)",
get_app_name(), get_app_version()), LEFT)
, m_label(">") , m_label(">")
, m_entry(new CommmandEntry) , m_entry(new CommmandEntry)
, m_engine(App::instance()->scriptEngine()) , m_engine(App::instance()->scriptEngine())

View File

@ -394,13 +394,17 @@ void DocView::onAddLayer(DocEvent& ev)
} }
} }
// TODO why note move this code to Editor::onBeforeRemoveLayer?
void DocView::onBeforeRemoveLayer(DocEvent& ev) void DocView::onBeforeRemoveLayer(DocEvent& ev)
{ {
Sprite* sprite = ev.sprite(); Sprite* sprite = ev.sprite();
Layer* layer = ev.layer(); Layer* layer = ev.layer();
// If the layer that was removed is the selected one // If the layer that was removed is the selected one in the editor,
if (layer == m_editor->layer()) { // or is an ancestor of the selected one.
if ((m_editor->layer() == layer) ||
(m_editor->layer() &&
m_editor->layer()->hasAncestor(layer))) {
LayerGroup* parent = layer->parent(); LayerGroup* parent = layer->parent();
Layer* layer_select = NULL; Layer* layer_select = NULL;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// //
// 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.
@ -142,8 +142,10 @@ private:
{ {
os::SurfaceLock lock(surface); os::SurfaceLock lock(surface);
surface->fillRect(gfx::rgba(0, 0, 0, 0), os::Paint paint;
gfx::Rect(0, 0, surface->width(), surface->height())); paint.color(gfx::rgba(0, 0, 0, 0));
paint.style(os::Paint::Fill);
surface->drawRect(gfx::Rect(0, 0, surface->width(), surface->height()), paint);
} }
{ {
ui::Graphics g(surface, 0, 0); ui::Graphics g(surface, 0, 0);

View File

@ -716,7 +716,9 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
// internal state of a SkCanvas or SkBitmap thing is // internal state of a SkCanvas or SkBitmap thing is
// updated after this, because convert_image_to_surface() // updated after this, because convert_image_to_surface()
// will overwrite these pixels anyway. // will overwrite these pixels anyway.
tmp->drawRect(gfx::rgba(0, 0, 0, 255), gfx::Rect(0, 0, 1, 1)); os::Paint paint;
paint.color(gfx::rgba(0, 0, 0, 255));
tmp->drawRect(gfx::Rect(0, 0, 1, 1), paint);
} }
convert_image_to_surface(rendered.get(), m_sprite->palette(m_frame), convert_image_to_surface(rendered.get(), m_sprite->palette(m_frame),

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2017-2018 David Capello // Copyright (C) 2017-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -92,6 +92,36 @@ bool MovingSliceState::onMouseMove(Editor* editor, MouseMessage* msg)
rc.x += delta.x; rc.x += delta.x;
rc.y += delta.y; rc.y += delta.y;
} }
// Move/resize 9-slices center
else if (m_hit.type() == EditorHit::SliceCenter) {
if (m_hit.border() & LEFT) {
rc.x += delta.x;
rc.w -= delta.x;
if (rc.w < 1) {
rc.x += rc.w-1;
rc.w = 1;
}
}
if (m_hit.border() & TOP) {
rc.y += delta.y;
rc.h -= delta.y;
if (rc.h < 1) {
rc.y += rc.h-1;
rc.h = 1;
}
}
if (m_hit.border() & RIGHT) {
rc.w += delta.x;
if (rc.w < 1)
rc.w = 1;
}
if (m_hit.border() & BOTTOM) {
rc.h += delta.y;
if (rc.h < 1)
rc.h = 1;
}
}
// Move/resize bounds
else { else {
if (m_hit.border() & LEFT) { if (m_hit.border() & LEFT) {
rc.x += delta.x * (totalBounds.x2() - rc.x) / totalBounds.w; rc.x += delta.x * (totalBounds.x2() - rc.x) / totalBounds.w;

View File

@ -57,6 +57,8 @@
#include "render/render.h" #include "render/render.h"
#include "ui/ui.h" #include "ui/ui.h"
#include <algorithm>
namespace app { namespace app {
using namespace ui; using namespace ui;
@ -601,6 +603,8 @@ public:
if (!m_editor->selectSliceBox(bounds) && if (!m_editor->selectSliceBox(bounds) &&
(bounds.w > 1 || bounds.h > 1)) { (bounds.w > 1 || bounds.h > 1)) {
Slice* slice = new Slice; Slice* slice = new Slice;
slice->setName(getUniqueSliceName());
SliceKey key(bounds); SliceKey key(bounds);
slice->insert(getFrame(), key); slice->insert(getFrame(), key);
@ -622,6 +626,21 @@ public:
m_canceled = true; m_canceled = true;
} }
private:
#ifdef ENABLE_UI
std::string getUniqueSliceName() const {
std::string prefix = "Slice";
int max = 0;
for (Slice* slice : m_sprite->slices())
if (std::strncmp(slice->name().c_str(), prefix.c_str(), prefix.size()) == 0)
max = std::max(max, (int)std::strtol(slice->name().c_str()+prefix.size(), nullptr, 10));
return fmt::format("{} {}", prefix, max+1);
}
#endif
}; };
#ifdef ENABLE_UI #ifdef ENABLE_UI

View File

@ -613,37 +613,34 @@ again:
} }
// else file-name specified in the entry is really a file to open... // else file-name specified in the entry is really a file to open...
// check if the filename doesn't contain slashes or other ilegal characters...
bool has_invalid_char = (fn.find('/') != std::string::npos);
#ifdef _WIN32 #ifdef _WIN32
has_invalid_char = // Check that the filename doesn't contain ilegal characters.
has_invalid_char || // Linux allows all kind of characters, only '/' is disallowed,
(fn.find('\\') != std::string::npos || // but in that case we consider that a full path was entered in
fn.find(':') != std::string::npos || // the filename and we can enter to the full path folder.
fn.find('*') != std::string::npos || if (!enter_folder) {
fn.find('?') != std::string::npos || const bool has_invalid_char =
fn.find('\"') != std::string::npos || (fn.find(':') != std::string::npos ||
fn.find('<') != std::string::npos || fn.find('*') != std::string::npos ||
fn.find('>') != std::string::npos || fn.find('?') != std::string::npos ||
fn.find('|') != std::string::npos); fn.find('\"') != std::string::npos ||
#endif fn.find('<') != std::string::npos ||
if (has_invalid_char) { fn.find('>') != std::string::npos ||
const char* invalid_chars = fn.find('|') != std::string::npos);
"/" if (has_invalid_char) {
#ifdef _WIN32 const char* invalid_chars = ": * ? \" < > |";
" \\ : * ? \" < > |"
#endif
;
ui::Alert::show( ui::Alert::show(
fmt::format( fmt::format(
Strings::alerts_invalid_chars_in_filename(), Strings::alerts_invalid_chars_in_filename(),
invalid_chars)); invalid_chars));
// show the window again // show the window again
setVisible(true); setVisible(true);
goto again; goto again;
}
} }
#endif
// does it not have extension? ...we should add the extension // does it not have extension? ...we should add the extension
// selected in the filetype combo-box // selected in the filetype combo-box

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -33,6 +33,7 @@
#include "ui/system.h" #include "ui/system.h"
#include "ui/textbox.h" #include "ui/textbox.h"
#include "ui/view.h" #include "ui/view.h"
#include "ver/info.h"
#ifdef ENABLE_NEWS #ifdef ENABLE_NEWS
#include "app/ui/news_listbox.h" #include "app/ui/news_listbox.h"
@ -177,7 +178,7 @@ void HomeView::onCheckingUpdates()
void HomeView::onUpToDate() void HomeView::onUpToDate()
{ {
checkUpdate()->setText( checkUpdate()->setText(
fmt::format(Strings::home_view_is_up_to_date(), PACKAGE)); fmt::format(Strings::home_view_is_up_to_date(), get_app_name()));
checkUpdate()->setVisible(true); checkUpdate()->setVisible(true);
layout(); layout();
@ -186,7 +187,8 @@ void HomeView::onUpToDate()
void HomeView::onNewUpdate(const std::string& url, const std::string& version) void HomeView::onNewUpdate(const std::string& url, const std::string& version)
{ {
checkUpdate()->setText( checkUpdate()->setText(
fmt::format(Strings::home_view_new_version_available(), PACKAGE, version)); fmt::format(Strings::home_view_new_version_available(),
get_app_name(), version));
checkUpdate()->setUrl(url); checkUpdate()->setUrl(url);
checkUpdate()->setVisible(true); checkUpdate()->setVisible(true);
checkUpdate()->InitTheme.connect( checkUpdate()->InitTheme.connect(

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -23,6 +24,7 @@
#include "ui/paint_event.h" #include "ui/paint_event.h"
#include "ui/size_hint_event.h" #include "ui/size_hint_event.h"
#include "ui/view.h" #include "ui/view.h"
#include "ver/info.h"
#include "tinyxml.h" #include "tinyxml.h"
@ -209,7 +211,7 @@ void NewsListBox::reload()
if (view) if (view)
view->updateView(); view->updateView();
m_loader = new HttpLoader(WEBSITE_NEWS_RSS); m_loader = new HttpLoader(get_app_news_rss_url());
m_timer.start(); m_timer.start();
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -100,6 +100,7 @@ public:
void setPlaying(bool state) { void setPlaying(bool state) {
m_isPlaying = state; m_isPlaying = state;
setupIcons(); setupIcons();
invalidate();
} }
obs::signal<void()> Popup; obs::signal<void()> Popup;
@ -209,8 +210,7 @@ void PreviewEditorWindow::setPreviewEnabled(bool state)
void PreviewEditorWindow::pressPlayButton() void PreviewEditorWindow::pressPlayButton()
{ {
m_playButton->setSelected( m_playButton->setPlaying(!m_playButton->isPlaying());
!m_playButton->isSelected());
onPlayClicked(); onPlayClicked();
} }

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -51,7 +52,7 @@ FontData::~FontData()
os::Font* FontData::getFont(int size) os::Font* FontData::getFont(int size)
{ {
if (m_type == os::FontType::kSpriteSheet) if (m_type == os::FontType::SpriteSheet)
size = 1; // Same size always size = 1; // Same size always
// Use cache // Use cache
@ -63,10 +64,10 @@ os::Font* FontData::getFont(int size)
os::Font* font = nullptr; os::Font* font = nullptr;
switch (m_type) { switch (m_type) {
case os::FontType::kSpriteSheet: case os::FontType::SpriteSheet:
font = os::instance()->loadSpriteSheetFont(m_filename.c_str(), size); font = os::instance()->loadSpriteSheetFont(m_filename.c_str(), size);
break; break;
case os::FontType::kTrueType: { case os::FontType::FreeType: {
font = os::instance()->loadTrueTypeFont(m_filename.c_str(), size); font = os::instance()->loadTrueTypeFont(m_filename.c_str(), size);
if (font) if (font)
font->setAntialias(m_antialias); font->setAntialias(m_antialias);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -113,7 +113,7 @@ static FontData* load_font(std::map<std::string, FontData*>& fonts,
if (type == "spritesheet") { if (type == "spritesheet") {
const char* fileStr = xmlFont->Attribute("file"); const char* fileStr = xmlFont->Attribute("file");
if (fileStr) { if (fileStr) {
font.reset(new FontData(os::FontType::kSpriteSheet)); font.reset(new FontData(os::FontType::SpriteSheet));
font->setFilename(base::join_path(xmlDir, fileStr)); font->setFilename(base::join_path(xmlDir, fileStr));
} }
} }
@ -143,7 +143,7 @@ static FontData* load_font(std::map<std::string, FontData*>& fonts,
// The filename can be empty if the font was not found, anyway we // The filename can be empty if the font was not found, anyway we
// want to keep the font information (e.g. to use the fallback // want to keep the font information (e.g. to use the fallback
// information of this font). // information of this font).
font.reset(new FontData(os::FontType::kTrueType)); font.reset(new FontData(os::FontType::FreeType));
font->setFilename(fontFilename); font->setFilename(fontFilename);
font->setAntialias(antialias); font->setAntialias(antialias);
@ -934,7 +934,7 @@ int SkinTheme::getScrollbarSize()
gfx::Size SkinTheme::getEntryCaretSize(Widget* widget) gfx::Size SkinTheme::getEntryCaretSize(Widget* widget)
{ {
if (widget->font()->type() == os::FontType::kTrueType) if (widget->font()->type() == os::FontType::FreeType)
return gfx::Size(2*guiscale(), widget->textHeight()); return gfx::Size(2*guiscale(), widget->textHeight());
else else
return gfx::Size(2*guiscale(), widget->textHeight()+2*guiscale()); return gfx::Size(2*guiscale(), widget->textHeight()+2*guiscale());
@ -986,7 +986,8 @@ public:
void preProcessChar(const int index, void preProcessChar(const int index,
const int codepoint, const int codepoint,
gfx::Color& fg, gfx::Color& fg,
gfx::Color& bg) override { gfx::Color& bg,
const gfx::Rect& charBounds) override {
// Normal text // Normal text
auto& colors = SkinTheme::instance()->colors; auto& colors = SkinTheme::instance()->colors;
bg = ColorNone; bg = ColorNone;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -46,6 +46,7 @@
#include "os/font.h" #include "os/font.h"
#include "os/surface.h" #include "os/surface.h"
#include "ui/ui.h" #include "ui/ui.h"
#include "ver/info.h"
#include <algorithm> #include <algorithm>
#include <cstdarg> #include <cstdarg>
@ -621,7 +622,7 @@ void StatusBar::showDefaultText()
} }
else if (App::instance()->mainWindow()->isHomeSelected()) { else if (App::instance()->mainWindow()->isHomeSelected()) {
setStatusText(0, "-- %s %s by David & Gaspar Capello -- Igara Studio --", setStatusText(0, "-- %s %s by David & Gaspar Capello -- Igara Studio --",
PACKAGE, VERSION); get_app_name(), get_app_version());
} }
else { else {
clearText(); clearText();

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -936,7 +936,10 @@ void Tabs::createFloatingOverlay(Tab* tab)
// Fill the surface with pink color // Fill the surface with pink color
{ {
os::SurfaceLock lock(surface); os::SurfaceLock lock(surface);
surface->fillRect(gfx::rgba(0, 0, 0, 0), gfx::Rect(0, 0, surface->width(), surface->height())); os::Paint paint;
paint.color(gfx::rgba(0, 0, 0, 0));
paint.style(os::Paint::Fill);
surface->drawRect(gfx::Rect(0, 0, surface->width(), surface->height()), paint);
} }
{ {
Graphics g(surface, 0, 0); Graphics g(surface, 0, 0);

@ -1 +1 @@
Subproject commit 04fa07966a4d413f102f9c26cde229f0ef369943 Subproject commit 8b026c048d775a2e3139e1059636fc5e65ef45b1

View File

@ -1,15 +1,15 @@
// Aseprite // Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// 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 __ASE_CONFIG_H #ifdef __ASEPRITE_CONFIG_H
#error You cannot use config.h two times #error You cannot use config.h two times
#endif #endif
#define __ASE_CONFIG_H #define __ASEPRITE_CONFIG_H
// In MSVC // In MSVC
#ifdef _MSC_VER #ifdef _MSC_VER
@ -26,21 +26,6 @@
#pragma warning(disable:4710) #pragma warning(disable:4710)
#endif #endif
// General information
#define PACKAGE "Aseprite"
#define VERSION "1.3-dev"
#ifdef CUSTOM_WEBSITE_URL
#define WEBSITE CUSTOM_WEBSITE_URL // To test web server
#else
#define WEBSITE "http://www.aseprite.org/"
#endif
#define WEBSITE_DOWNLOAD WEBSITE "download/"
#define WEBSITE_CONTRIBUTORS WEBSITE "contributors/"
#define WEBSITE_NEWS_RSS "http://blog.aseprite.org/rss"
#define UPDATE_URL WEBSITE "update/?xml=1"
#define COPYRIGHT "Copyright (C) 2001-2019 Igara Studio S.A."
#include "base/base.h" #include "base/base.h"
#include "base/debug.h" #include "base/debug.h"
#include "base/log.h" #include "base/log.h"

View File

@ -1,6 +1,6 @@
// Aseprite Document Library // Aseprite Document Library
// Copyright (c) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (c) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -179,6 +179,17 @@ bool Layer::isEditableHierarchy() const
return true; return true;
} }
bool Layer::hasAncestor(const Layer* ancestor) const
{
Layer* it = parent();
while (it) {
if (it == ancestor)
return true;
it = it->parent();
}
return false;
}
Cel* Layer::cel(frame_t frame) const Cel* Layer::cel(frame_t frame) const
{ {
return nullptr; return nullptr;

View File

@ -1,6 +1,6 @@
// Aseprite Document Library // Aseprite Document Library
// Copyright (c) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (c) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -91,6 +91,7 @@ namespace doc {
bool isVisibleHierarchy() const; bool isVisibleHierarchy() const;
bool isEditableHierarchy() const; bool isEditableHierarchy() const;
bool hasAncestor(const Layer* ancestor) const;
void setBackground(bool state) { switchFlags(LayerFlags::Background, state); } void setBackground(bool state) { switchFlags(LayerFlags::Background, state); }
void setVisible (bool state) { switchFlags(LayerFlags::Visible, state); } void setVisible (bool state) { switchFlags(LayerFlags::Visible, state); }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -59,7 +59,7 @@ int app_main(int argc, char* argv[])
std::srand(static_cast<unsigned int>(std::time(nullptr))); std::srand(static_cast<unsigned int>(std::time(nullptr)));
#ifdef _WIN32 #ifdef _WIN32
::CoInitialize(NULL); ::CoInitialize(nullptr);
#endif #endif
try { try {
@ -70,11 +70,12 @@ int app_main(int argc, char* argv[])
os::ScopedHandle<os::System> system(os::create_system()); os::ScopedHandle<os::System> system(os::create_system());
app::App app; app::App app;
// Change the name of the memory dump file // Change the memory dump filename to save on disk (.dmp
// file). Note: Only useful on Windows.
{ {
const std::string filename = app::memory_dump_filename(); const std::string fn = app::SendCrash::DefaultMemoryDumpFilename();
if (!filename.empty()) if (!fn.empty())
memoryDump.setFileName(filename); memoryDump.setFileName(fn);
} }
const int code = app.initialize(options); const int code = app.initialize(options);

View File

@ -1,5 +1,5 @@
// Aseprite UI Library // Aseprite UI Library
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
@ -845,7 +845,9 @@ public:
void preProcessChar(const int index, void preProcessChar(const int index,
const int codepoint, const int codepoint,
gfx::Color& fg, gfx::Color& bg) override { gfx::Color& fg,
gfx::Color& bg,
const gfx::Rect& charBounds) override {
if (!m_boxes.empty()) if (!m_boxes.empty())
m_boxes.back().to = index; m_boxes.back().to = index;

View File

@ -1,5 +1,5 @@
// Aseprite UI Library // Aseprite UI Library
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
@ -117,7 +117,9 @@ void Graphics::drawHLine(gfx::Color color, int x, int y, int w)
dirty(gfx::Rect(m_dx+x, m_dy+y, w, 1)); dirty(gfx::Rect(m_dx+x, m_dy+y, w, 1));
os::SurfaceLock lock(m_surface); os::SurfaceLock lock(m_surface);
m_surface->drawHLine(color, m_dx+x, m_dy+y, w); os::Paint paint;
paint.color(color);
m_surface->drawRect(gfx::Rect(m_dx+x, m_dy+y, w, 1), paint);
} }
void Graphics::drawVLine(gfx::Color color, int x, int y, int h) void Graphics::drawVLine(gfx::Color color, int x, int y, int h)
@ -125,7 +127,9 @@ void Graphics::drawVLine(gfx::Color color, int x, int y, int h)
dirty(gfx::Rect(m_dx+x, m_dy+y, 1, h)); dirty(gfx::Rect(m_dx+x, m_dy+y, 1, h));
os::SurfaceLock lock(m_surface); os::SurfaceLock lock(m_surface);
m_surface->drawVLine(color, m_dx+x, m_dy+y, h); os::Paint paint;
paint.color(color);
m_surface->drawRect(gfx::Rect(m_dx+x, m_dy+y, 1, h), paint);
} }
void Graphics::drawLine(gfx::Color color, const gfx::Point& _a, const gfx::Point& _b) void Graphics::drawLine(gfx::Color color, const gfx::Point& _a, const gfx::Point& _b)
@ -135,7 +139,9 @@ void Graphics::drawLine(gfx::Color color, const gfx::Point& _a, const gfx::Point
dirty(gfx::Rect(a, b)); dirty(gfx::Rect(a, b));
os::SurfaceLock lock(m_surface); os::SurfaceLock lock(m_surface);
m_surface->drawLine(color, a, b); os::Paint paint;
paint.color(color);
m_surface->drawLine(a, b, paint);
} }
void Graphics::drawRect(gfx::Color color, const gfx::Rect& rcOrig) void Graphics::drawRect(gfx::Color color, const gfx::Rect& rcOrig)
@ -145,7 +151,10 @@ void Graphics::drawRect(gfx::Color color, const gfx::Rect& rcOrig)
dirty(rc); dirty(rc);
os::SurfaceLock lock(m_surface); os::SurfaceLock lock(m_surface);
m_surface->drawRect(color, rc); os::Paint paint;
paint.color(color);
paint.style(os::Paint::Stroke);
m_surface->drawRect(rc, paint);
} }
void Graphics::fillRect(gfx::Color color, const gfx::Rect& rcOrig) void Graphics::fillRect(gfx::Color color, const gfx::Rect& rcOrig)
@ -155,7 +164,10 @@ void Graphics::fillRect(gfx::Color color, const gfx::Rect& rcOrig)
dirty(rc); dirty(rc);
os::SurfaceLock lock(m_surface); os::SurfaceLock lock(m_surface);
m_surface->fillRect(color, rc); os::Paint paint;
paint.color(color);
paint.style(os::Paint::Fill);
m_surface->drawRect(rc, paint);
} }
void Graphics::fillRegion(gfx::Color color, const gfx::Region& rgn) void Graphics::fillRegion(gfx::Color color, const gfx::Region& rgn)
@ -321,7 +333,8 @@ public:
void preProcessChar(const int index, void preProcessChar(const int index,
const int codepoint, const int codepoint,
gfx::Color& fg, gfx::Color& fg,
gfx::Color& bg) override { gfx::Color& bg,
const gfx::Rect& charBounds) override {
if (m_surface) { if (m_surface) {
if (m_mnemonic && if (m_mnemonic &&
// TODO use ICU library to lower unicode chars // TODO use ICU library to lower unicode chars
@ -344,11 +357,16 @@ public:
if (!gfx::is_transparent(m_underscoreColor)) { if (!gfx::is_transparent(m_underscoreColor)) {
// TODO underscore height = guiscale() should be configurable from ui::Theme // TODO underscore height = guiscale() should be configurable from ui::Theme
int dy = 0; int dy = 0;
if (m_font->type() == os::FontType::kTrueType) // TODO use other method to locate the underline if (m_font->type() == os::FontType::FreeType) // TODO use other method to locate the underline
dy += guiscale(); dy += guiscale();
gfx::Rect underscoreBounds(charBounds.x, charBounds.y+charBounds.h+dy, gfx::Rect underscoreBounds(charBounds.x, charBounds.y+charBounds.h+dy,
charBounds.w, guiscale()); charBounds.w, guiscale());
m_surface->fillRect(m_underscoreColor, underscoreBounds);
os::Paint paint;
paint.color(m_underscoreColor);
paint.style(os::Paint::Fill);
m_surface->drawRect(underscoreBounds, paint);
m_bounds |= underscoreBounds; m_bounds |= underscoreBounds;
} }
} }

View File

@ -1,5 +1,5 @@
// Aseprite UI Library // Aseprite UI Library
// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
@ -302,10 +302,11 @@ Widget* Menu::findItemById(const char* id)
return result; return result;
for (auto child : children()) { for (auto child : children()) {
if (child->type() == kMenuItemWidget) { if (child->type() == kMenuItemWidget) {
result = static_cast<MenuItem*>(child) if (Menu* submenu = static_cast<MenuItem*>(child)->getSubmenu()) {
->getSubmenu()->findItemById(id); result = submenu->findItemById(id);
if (result) if (result)
return result; return result;
}
} }
} }
return nullptr; return nullptr;

View File

@ -1,4 +1,5 @@
# ASEPRITE # ASEPRITE
# Copyright (C) 2020 Igara Studio S.A.
# Copyright (C) 2001-2017 David Capello # Copyright (C) 2001-2017 David Capello
set(UPDATER_LIB_SOURCES set(UPDATER_LIB_SOURCES
@ -16,4 +17,5 @@ add_library(updater-lib ${UPDATER_LIB_SOURCES})
target_link_libraries(updater-lib target_link_libraries(updater-lib
net-lib net-lib
cfg-lib cfg-lib
ver-lib
${TINYXML_LIBRARY}) ${TINYXML_LIBRARY})

View File

@ -1,4 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -18,6 +19,7 @@
#include "net/http_response.h" #include "net/http_response.h"
#include "tinyxml.h" #include "tinyxml.h"
#include "updater/user_agent.h" #include "updater/user_agent.h"
#include "ver/info.h"
#include <iostream> #include <iostream>
#include <memory> #include <memory>
@ -97,12 +99,7 @@ public:
bool checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate) bool checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate)
{ {
#ifndef UPDATE_URL std::string url = get_app_update_url();
#define UPDATE_URL ""
#pragma message("warning: Define UPDATE_URL macro")
#endif
std::string url = UPDATE_URL;
if (!uuid.empty()) { if (!uuid.empty()) {
url += "&uuid="; url += "&uuid=";
url += uuid; url += uuid;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
@ -9,6 +9,9 @@
#include "config.h" #include "config.h"
#endif #endif
#include "updater/user_agent.h"
#include "ver/info.h"
#include <string> #include <string>
#include <sstream> #include <sstream>
@ -39,18 +42,7 @@ std::string getUserAgent()
std::stringstream userAgent; std::stringstream userAgent;
// App name and version // App name and version
userAgent << get_app_name() << "/" << get_app_version() << " (";
#ifndef PACKAGE
#define PACKAGE ""
#pragma message("warning: Define PACKAGE macro")
#endif
#ifndef VERSION
#define VERSION ""
#pragma message("warning: Define VERSION macro")
#endif
userAgent << PACKAGE << "/" << VERSION << " (";
#if _WIN32 #if _WIN32

18
src/ver/CMakeLists.txt Normal file
View File

@ -0,0 +1,18 @@
# ASEPRITE
# Copyright (C) 2020 Igara Studio S.A.
# Version of Aseprite
set(VERSION "1.x-dev")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/generated_version.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/generated_version.h")
# Custom Aseprite website (for testing server-side)
if(NOT "${CUSTOM_WEBSITE_URL}" STREQUAL "")
add_definitions(-DCUSTOM_WEBSITE_URL="${CUSTOM_WEBSITE_URL}")
endif()
add_library(ver-lib info.c ${gen_ver_fn})
add_dependencies(ver-lib generated_version_h)
target_include_directories(ver-lib PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")

View File

@ -0,0 +1 @@
#cmakedefine VERSION "@VERSION@"

31
src/ver/info.c Normal file
View File

@ -0,0 +1,31 @@
/* Aseprite
Copyright (C) 2020 Igara Studio S.A.
This program is distributed under the terms of
the End-User License Agreement for Aseprite. */
#include "ver/info.h"
#include "generated_version.h" /* It defines the VERSION macro */
#define PACKAGE "Aseprite"
#define COPYRIGHT "Copyright (C) 2001-2020 Igara Studio S.A."
#ifdef CUSTOM_WEBSITE_URL
#define WEBSITE CUSTOM_WEBSITE_URL /* To test web server */
#else
#define WEBSITE "http://www.aseprite.org/"
#endif
#define WEBSITE_DOWNLOAD WEBSITE "download/"
#define WEBSITE_CONTRIBUTORS WEBSITE "contributors/"
#define WEBSITE_NEWS_RSS "http://blog.aseprite.org/rss"
#define WEBSITE_UPDATE WEBSITE "update/?xml=1"
const char* get_app_name() { return PACKAGE; }
const char* get_app_version() { return VERSION; }
const char* get_app_copyright() { return COPYRIGHT; }
const char* get_app_url() { return WEBSITE; }
const char* get_app_download_url() { return WEBSITE_DOWNLOAD; }
const char* get_app_contributors_url() { return WEBSITE_CONTRIBUTORS; }
const char* get_app_news_rss_url() { return WEBSITE_NEWS_RSS; }
const char* get_app_update_url() { return WEBSITE_UPDATE; }

29
src/ver/info.h Normal file
View File

@ -0,0 +1,29 @@
/* Aseprite
Copyright (C) 2020 Igara Studio S.A.
This program is distributed under the terms of
the End-User License Agreement for Aseprite. */
#ifndef VER_INFO_H_INCLUDED
#define VER_INFO_H_INCLUDED
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
const char* get_app_name();
const char* get_app_version();
const char* get_app_copyright();
const char* get_app_url();
const char* get_app_download_url();
const char* get_app_contributors_url();
const char* get_app_news_rss_url();
const char* get_app_update_url();
#ifdef __cplusplus
}
#endif
#endif /* VER_INFO_H_INCLUDED */

@ -1 +1 @@
Subproject commit ca48183b244c549841c33a2863672b46ed3cbe88 Subproject commit e1309af03a4bcea2f0f0bb1f48530f2b794cc8b2