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

View File

@ -12,19 +12,15 @@
* [Issues with Retina displays](#issues-with-retina-displays)
* [Linux details](#linux-details)
* [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
You should be able to compile Aseprite successfully on the following
platforms:
* Windows 10 + [Visual Studio Community 2019 + Windows 10.0.17763.0 SDK](https://imgur.com/4Pq2Cbv)
* macOS 10.14.4 Mojave + Xcode 10.2.1 + macOS 10.14 SDK
* Linux + gcc 4.8 or clang 7.0
* Windows 10 + [Visual Studio Community 2019 + Windows 10.0.18362.0 SDK](https://imgur.com/a/7zs51IT)
* macOS 10.15.3 Mojave + Xcode 11.2.1 + macOS 10.15 SDK (older version might work)
* Linux + gcc 9.2 or clang 9.0
# 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)
* [Ninja](https://ninja-build.org) build system
* You will need a compiled version of the Skia library.
Please check the details about [how to build Skia](#building-skia-dependency)
on your platform.
* And a compiled version of the `aseprite-m81` branch of
the [Skia library](https://github.com/aseprite/skia#readme).
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
First of all, you will need:
* 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/)
* 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
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
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).
You must also compile [Skia](#skia-on-macos) before starting with the
[compilation](#compiling).
## Linux dependencies
You will need the following dependencies on Ubuntu/Debian:
@ -88,10 +76,7 @@ You will need the following dependencies on Ubuntu/Debian:
On Fedora:
sudo yum 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).
sudo dnf install -y gcc-c++ cmake ninja-build libX11-devel libXcursor-devel mesa-libGL-devel fontconfig-devel
# 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`:
cd C:\aseprite\build
cmake -G Ninja ..
cmake -G Ninja -DLAF_BACKEND=skia ..
Here `cmake` needs different options depending on your
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
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:
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" -arch=x64
@ -140,16 +124,15 @@ And then
cd aseprite
mkdir 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
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
After [compiling Skia](#skia-on-macos), you should run `cmake` with
the following parameters and then `ninja`:
Run `cmake` with the following parameters and then `ninja`:
cd aseprite
mkdir build
@ -158,19 +141,18 @@ the following parameters and then `ninja`:
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 \
-DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk \
-DLAF_OS_BACKEND=skia \
-DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk \
-DLAF_BACKEND=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 \
..
ninja aseprite
In this case, `$HOME/deps/skia` is the directory where Skia was
compiled as described in [Skia on macOS](#skia-on-macos) section.
Make sure that `CMAKE_OSX_SYSROOT` is pointing to the correct SDK
directory (in this case
`/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk`),
compiled or downloaded. Make sure that `CMAKE_OSX_SYSROOT` is
pointing to the correct SDK directory (in this case
`/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk`),
but it could be different in your Mac.
### Issues with Retina displays
@ -181,23 +163,22 @@ If you have a Retina display, check the following issue:
## Linux details
First you have to [compile Skia](#skia-on-linux), then you should run
`cmake` with the following parameters and then `ninja`:
Run `cmake` with the following parameters and then `ninja`:
cd aseprite
mkdir build
cd build
cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DLAF_OS_BACKEND=skia \
-DLAF_BACKEND=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 \
..
ninja aseprite
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
@ -208,116 +189,3 @@ configuring each `USE_SHARED_` option.
After running `cmake -G`, you can edit `build/CMakeCache.txt` file,
and enable the `USE_SHARED_` flag (set its value to `ON`) of the
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
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
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).
* Export/import animations to/from **Sprite Sheets**.
* **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).
* [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.
* [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.
* [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:

View File

@ -35,38 +35,15 @@ include(FindPkgConfig)
pkg_check_modules(PC_HARFBUZZ harfbuzz>=0.9.7)
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
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 ()
HINTS ${PC_HARFBUZZ_LIBRARY_DIRS} ${PC_HARFBUZZ_LIBDIR})
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(HarfBuzz DEFAULT_MSG HARFBUZZ_INCLUDE_DIRS
HARFBUZZ_LIBRARIES ${_HARFBUZZ_EXTRA_REQUIRED_VAR})
HARFBUZZ_LIBRARIES)
mark_as_advanced(
HARFBUZZ_ICU_LIBRARIES
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 -->
<!-- Copyright (C) 2018-2020 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2018 David Capello -->
<gui version="1.3-dev">
<gui>
<!-- Keyboard shortcuts -->
<keyboard version="1">

2
laf

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

View File

@ -1,5 +1,5 @@
# Aseprite
# Copyright (C) 2019 Igara Studio S.A.
# Copyright (C) 2019-2020 Igara Studio S.A.
# Copyright (C) 2001-2018 David Capello
######################################################################
@ -37,13 +37,6 @@ if(WIN32)
include_directories(..)
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
@ -106,6 +99,7 @@ add_subdirectory(flic)
add_subdirectory(render)
add_subdirectory(dio)
add_subdirectory(ui)
add_subdirectory(ver)
if(REQUIRE_CURL)
add_subdirectory(net)
@ -182,6 +176,7 @@ if(ENABLE_ASEPRITE_EXE)
if(WIN32 AND ENABLE_UI)
set_target_properties(aseprite PROPERTIES WIN32_EXECUTABLE true)
endif()
set_target_properties(aseprite PROPERTIES LINK_FLAGS "${LAF_BACKEND_LINK_FLAGS}")
target_link_libraries(aseprite app-lib)
add_dependencies(aseprite copy_data)

View File

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

View File

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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -117,6 +117,9 @@ namespace app {
script::Engine* scriptEngine() { return m_engine.get(); }
#endif
const std::string& memoryDumpFilename() const { return m_memoryDumpFilename; }
void memoryDumpFilename(const std::string& fn) { m_memoryDumpFilename = fn; }
// App Signals
obs::signal<void()> Exit;
obs::signal<void()> PaletteChange;
@ -145,13 +148,16 @@ namespace app {
#ifdef ENABLE_SCRIPTING
std::unique_ptr<script::Engine> m_engine;
#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_rebuild_documents_tabs();
PixelFormat app_get_current_pixel_format();
int app_get_color_to_clear_layer(doc::Layer* layer);
std::string memory_dump_filename();
} // namespace app

View File

@ -29,9 +29,11 @@
#include "base/bind.h"
#include "base/fs.h"
#include "base/string.h"
#include "fmt/format.h"
#include "os/menus.h"
#include "os/system.h"
#include "ui/ui.h"
#include "ver/info.h"
#include "tinyxml.h"
@ -337,12 +339,6 @@ void AppMenus::reload()
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");
m_tabPopupMenu.reset(loadMenuById(handle, "tab_popup_menu"));
@ -633,20 +629,6 @@ Widget* AppMenus::convertXmlelemToMenuitem(TiXmlElement* elem)
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,
const Params& params,
const KeyPtr& key)
@ -732,7 +714,7 @@ void AppMenus::createNativeMenus()
#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());
about.shortcut = native.shortcut;
about.execute = [native]{
@ -758,10 +740,10 @@ void AppMenus::createNativeMenus()
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);
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);
os::Menu* appMenu = menus->createMenu();

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -22,8 +22,6 @@ namespace app {
ClosedDocs::ClosedDocs(const Preferences& pref)
: m_done(false)
{
CLOSEDOC_TRACE("CLOSEDOC: Init");
if (pref.general.dataRecovery())
m_dataRecoveryPeriodMSecs = int(1000.0*60.0*pref.general.dataRecoveryPeriod());
else
@ -33,6 +31,10 @@ ClosedDocs::ClosedDocs(const Preferences& pref)
m_keepClosedDocAliveForMSecs = int(1000.0*60.0*pref.general.keepClosedSpriteOnMemoryFor());
else
m_keepClosedDocAliveForMSecs = 0;
CLOSEDOC_TRACE("CLOSEDOC: Init",
"dataRecoveryPeriod", m_dataRecoveryPeriodMSecs,
"keepClosedDocs", m_keepClosedDocAliveForMSecs);
}
ClosedDocs::~ClosedDocs()
@ -123,15 +125,20 @@ void ClosedDocs::backgroundThread()
for (auto it=m_docs.begin(); it != m_docs.end(); ) {
const ClosedDoc& closedDoc = *it;
auto doc = closedDoc.doc;
base::tick_t diff = now - closedDoc.timestamp;
if (diff >= m_keepClosedDocAliveForMSecs) {
if (m_dataRecoveryPeriodMSecs == 0 ||
closedDoc.doc->isFullyBackedUp()) {
if (// If we backup process is disabled
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
// delete all documents created/loaded by the user)
CLOSEDOC_TRACE("CLOSEDOC: [BG] Delete doc", closedDoc.doc);
delete closedDoc.doc;
CLOSEDOC_TRACE("CLOSEDOC: [BG] Delete doc", doc);
delete doc;
it = m_docs.erase(it);
}
else {

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -13,6 +14,8 @@
#include "app/modules/gui.h"
#include "app/ui/main_window.h"
#include "base/bind.h"
#include "fmt/format.h"
#include "ver/info.h"
#include "about.xml.h"
@ -36,7 +39,7 @@ AboutCommand::AboutCommand()
void AboutCommand::onExecute(Context* context)
{
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]{
window.closeWindow(nullptr);

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -12,6 +13,7 @@
#include "app/commands/params.h"
#include "app/launcher.h"
#include "base/fs.h"
#include "ver/info.h"
namespace app {
@ -42,7 +44,7 @@ void LaunchCommand::onLoadParams(const Params& params)
m_path = params.get("path");
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/chrono.h"
#include "base/convert_to.h"
#include "base/scoped_value.h"
#include "doc/image.h"
#include "doc/mask.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
ColorButton* m_buttonColor;
CheckBox* m_checkPreview;
Slider* m_sliderTolerance;
SelModeField* m_selMode;
Window* m_window = nullptr;
ColorButton* m_buttonColor = nullptr;
CheckBox* m_checkPreview = nullptr;
Slider* m_sliderTolerance = nullptr;
SelModeField* m_selMode = nullptr;
};
MaskByColorCommand::MaskByColorCommand()
@ -91,6 +92,8 @@ bool MaskByColorCommand::onEnabled(Context* context)
void MaskByColorCommand::onExecute(Context* context)
{
ASSERT(!m_window);
const ContextReader reader(context);
const Sprite* sprite = reader.sprite();
@ -102,7 +105,8 @@ void MaskByColorCommand::onExecute(Context* context)
if (!image)
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();
m_window->addChild(tooltipManager);
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_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_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)));
@ -198,7 +201,6 @@ void MaskByColorCommand::onExecute(Context* context)
// Save window configuration.
save_window_pos(m_window, "MaskColor");
delete m_window;
}
Mask* MaskByColorCommand::generateMask(const Mask& origMask,
@ -245,7 +247,8 @@ Mask* MaskByColorCommand::generateMask(const Mask& origMask,
void MaskByColorCommand::maskPreview(const ContextReader& reader)
{
if (m_checkPreview->isSelected()) {
ASSERT(m_window);
if (m_window && m_checkPreview->isSelected()) {
int xpos, ypos;
const Image* image = reader.image(&xpos, &ypos);
std::unique_ptr<Mask> mask(generateMask(*reader.document()->mask(),

View File

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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// 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);
base::remove_from_container(m_documents, doc);
}
if (m_config->keepEditedSpriteDataFor > 0 &&
doc->needsBackup() &&
if (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
// document is destroyed from a script with Sprite:close(), the
// backup is disabled)
!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);
}
else {
TRACE("RECO: Removing doc %p from session\n", doc);
m_session->removeDocument(doc);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// 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)
#ifdef _WIN32
static SFGAOF get_pidl_attrib(FileItem* fileitem, SFGAOF attrib);
static void update_by_pidl(FileItem* fileitem, SFGAOF attrib);
static LPITEMIDLIST concat_pidl(LPITEMIDLIST pidlHead, LPITEMIDLIST pidlTail);
static UINT get_pidl_size(LPITEMIDLIST pidl);
@ -453,7 +454,7 @@ const FileItemList& FileItem::children()
IEnumIDList *pEnum = NULL;
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()),
SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnum);
@ -461,16 +462,16 @@ const FileItemList& FileItem::children()
LPITEMIDLIST itempidl[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) {
/* request the SFGAO_FOLDER attribute to know what of the
item is a folder */
// Request the SFGAO_FOLDER attribute to know what of the
// item is file or a folder
for (c=0; c<fetched; ++c) {
attribs[c] = SFGAO_FOLDER;
pFolder->GetAttributesOf(1, (LPCITEMIDLIST *)itempidl, attribs+c);
}
/* generate the FileItems */
// Generate the FileItems
for (c=0; c<fetched; ++c) {
LPITEMIDLIST fullpidl = concat_pidl(m_fullpidl,
itempidl[c]);
@ -680,6 +681,34 @@ static bool calc_is_folder(std::string filename, SFGAOF attrib)
&& ((!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
static void update_by_pidl(FileItem* fileitem, SFGAOF attrib)
{
@ -693,7 +722,7 @@ static void update_by_pidl(FileItem* fileitem, SFGAOF attrib)
else {
ASSERT(fileitem->m_parent);
hr = shl_idesktop->BindToObject(fileitem->m_parent->m_fullpidl,
NULL, IID_IShellFolder, (LPVOID *)&pFolder);
nullptr, IID_IShellFolder, (LPVOID*)&pFolder);
if (hr != S_OK)
pFolder = NULL;
}
@ -921,7 +950,7 @@ static FileItem* get_fileitem_by_fullpidl(LPITEMIDLIST fullpidl, bool create_if_
if (!create_if_not)
return nullptr;
// Check if the pidl exists
// Validate if the fullpidl exists.
SFGAOF attrib = SFGAO_FOLDER | SFGAO_VALIDATE;
HRESULT hr = shl_idesktop->GetAttributesOf(1, (LPCITEMIDLIST*)&fullpidl, &attrib);
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);
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);
@ -949,9 +984,7 @@ static FileItem* get_fileitem_by_fullpidl(LPITEMIDLIST fullpidl, bool create_if_
return fileitem;
}
/**
* Inserts the @a fileitem in the hash map of items.
*/
// Inserts the fileitem in the hash map of items.
static void put_fileitem(FileItem* fileitem)
{
ASSERT(fileitem->m_filename != NOTINITIALIZED);

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
@ -40,17 +41,4 @@ GuiXml::GuiXml()
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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
@ -18,6 +19,7 @@
#include "base/string.h"
#include "net/http_request.h"
#include "net/http_response.h"
#include "ver/info.h"
#include <fstream>
@ -49,7 +51,7 @@ void HttpLoader::threadHttpRequest()
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);
std::string fn = m_url;

View File

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

View File

@ -44,6 +44,7 @@
#include "doc/tag.h"
#include "render/render.h"
#include "ui/alert.h"
#include "ver/info.h"
#include <iostream>
@ -490,7 +491,7 @@ int App_get_isUIAvailable(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
push_version(L, base::Version(ver));
return 1;

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -14,26 +15,105 @@
#include "app/console.h"
#include "app/i18n/strings.h"
#include "app/resource_finder.h"
#include "app/task.h"
#include "base/bind.h"
#include "base/fs.h"
#include "base/launcher.h"
#include "fmt/format.h"
#include "ui/alert.h"
#include "ui/system.h"
#include "ver/info.h"
#include "send_crash.xml.h"
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()
{
#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)) {
App::instance()->showNotification(this);
m_dumpFilename = SendCrash::DefaultMemoryDumpFilename();
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
}
#ifdef ENABLE_UI
std::string SendCrash::notificationText()
{
return "Report last crash";
@ -48,15 +128,24 @@ void SendCrash::notificationClick()
app::gen::SendCrash dlg;
// The current version is a "development" version if the VERSION
// macro contains the "dev" word.
bool isDev = (std::string(VERSION).find("dev") != std::string::npos);
#if _WIN32
// Only on Windows, if the current version is a development version
// (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) {
dlg.official()->setVisible(false);
dlg.devFilename()->setText(m_dumpFilename);
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.filename()->setText(m_dumpFilename);
dlg.filename()->Click.connect(base::Bind(&SendCrash::onClickFilename, this));
@ -84,4 +173,6 @@ void SendCrash::onClickDevFilename()
base::launcher::open_file(m_dumpFilename);
}
#endif // ENABLE_UI
} // namespace app

View File

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

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
@ -14,7 +15,9 @@
#include "app/shell.h"
#include "fmt/format.h"
#include "script/engine.h"
#include "ver/info.h"
#include <iostream>
#include <string>
@ -31,7 +34,8 @@ Shell::~Shell()
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;
while (std::getline(std::cin, line)) {
engine.evalCode(line);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -11,6 +11,7 @@
#include "app/task.h"
#include "base/task.h"
#include "base/thread.h"
#include "base/thread_pool.h"
namespace app {
@ -32,4 +33,12 @@ void Task::run(base::task::func_t&& func)
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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -20,6 +20,7 @@ namespace app {
~Task();
void run(base::task::func_t&& func);
void wait();
// Returns true when the task is completed (whether it was
// canceled or not)
@ -27,6 +28,10 @@ namespace app {
return m_task.completed();
}
bool running() const {
return m_task.running();
}
bool canceled() const {
if (m_token)
return m_token->canceled();

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018 Igara Studio S.A.
// Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -102,6 +102,9 @@ namespace app {
// Called for each point shape.
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 prepareForStrokes(ToolLoop* loop, Strokes& strokes) { }
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;
@ -1124,8 +1127,51 @@ public:
void prepareForPointShape(ToolLoop* loop, bool firstPoint, int x, int y) override {
if ((m_brush->pattern() == BrushPattern::ALIGNED_TO_DST && firstPoint) ||
(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;
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
// Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -34,6 +34,21 @@ public:
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:
void setProc(BaseInkProcessing* proc) {
m_proc.reset(proc);

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2015 David Capello
//
// This program is distributed under the terms of
@ -13,7 +14,9 @@
#include "app/tools/ink.h"
#include "app/tools/tool_loop.h"
#include "app/util/wrap_value.h"
#include "doc/brush.h"
#include "doc/image.h"
#include "doc/sprite.h"
namespace app {
namespace tools {
@ -53,13 +56,20 @@ void PointShape::doInkHline(int x1, int y, int x2, ToolLoop* loop)
if (w >= size)
loop->getInk()->inkHline(0, y, size-1, loop);
else {
x = x1;
x = wrap_value(x, size);
if (x+w-1 <= size-1)
x = wrap_value(x1, loop->sprite()->width());
if (x+w <= loop->sprite()->width()) {
// Here we asure that tile limit line does not bisect the current
// 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);
}
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()->prepareUForPointShapeSlicedScanline(loop, false, x1);// false = right slice
loop->getInk()->inkHline(0, y, w-(size-x)-1, loop);
}
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -7,6 +7,8 @@
#include "app/util/wrap_point.h"
#include "app/tools/ink.h"
namespace app {
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);
for (auto scanline : *m_compressedImage) {
int u = x+scanline.x;
loop->getInk()->prepareVForPointShape(loop, y+scanline.y);
doInkHline(u, y+scanline.y, u+scanline.w-1, loop);
}
m_firstPoint = false;
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018 Igara Studio S.A.
// Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2016-2018 David Capello
//
// This program is distributed under the terms of
@ -113,7 +113,10 @@ public:
auto oldCanvas = m_canvas;
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) {
m_canvas->drawSurface(oldCanvas, 0, 0);
oldCanvas->dispose();

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -18,11 +19,13 @@
#include "app/app_menus.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/workspace.h"
#include "fmt/format.h"
#include "ui/entry.h"
#include "ui/message.h"
#include "ui/system.h"
#include "ui/textbox.h"
#include "ui/view.h"
#include "ver/info.h"
namespace app {
@ -64,7 +67,8 @@ protected:
DevConsoleView::DevConsoleView()
: 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_entry(new CommmandEntry)
, 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)
{
Sprite* sprite = ev.sprite();
Layer* layer = ev.layer();
// If the layer that was removed is the selected one
if (layer == m_editor->layer()) {
// If the layer that was removed is the selected one in the editor,
// 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();
Layer* layer_select = NULL;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018 Igara Studio S.A.
// Copyright (C) 2018-2020 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -142,8 +142,10 @@ private:
{
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);
}
{
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
// updated after this, because convert_image_to_surface()
// 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),

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
@ -92,6 +92,36 @@ bool MovingSliceState::onMouseMove(Editor* editor, MouseMessage* msg)
rc.x += delta.x;
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 {
if (m_hit.border() & LEFT) {
rc.x += delta.x * (totalBounds.x2() - rc.x) / totalBounds.w;

View File

@ -57,6 +57,8 @@
#include "render/render.h"
#include "ui/ui.h"
#include <algorithm>
namespace app {
using namespace ui;
@ -601,6 +603,8 @@ public:
if (!m_editor->selectSliceBox(bounds) &&
(bounds.w > 1 || bounds.h > 1)) {
Slice* slice = new Slice;
slice->setName(getUniqueSliceName());
SliceKey key(bounds);
slice->insert(getFrame(), key);
@ -622,6 +626,21 @@ public:
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// 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") {
const char* fileStr = xmlFont->Attribute("file");
if (fileStr) {
font.reset(new FontData(os::FontType::kSpriteSheet));
font.reset(new FontData(os::FontType::SpriteSheet));
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
// want to keep the font information (e.g. to use the fallback
// information of this font).
font.reset(new FontData(os::FontType::kTrueType));
font.reset(new FontData(os::FontType::FreeType));
font->setFilename(fontFilename);
font->setAntialias(antialias);
@ -934,7 +934,7 @@ int SkinTheme::getScrollbarSize()
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());
else
return gfx::Size(2*guiscale(), widget->textHeight()+2*guiscale());
@ -986,7 +986,8 @@ public:
void preProcessChar(const int index,
const int codepoint,
gfx::Color& fg,
gfx::Color& bg) override {
gfx::Color& bg,
const gfx::Rect& charBounds) override {
// Normal text
auto& colors = SkinTheme::instance()->colors;
bg = ColorNone;

View File

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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -936,7 +936,10 @@ void Tabs::createFloatingOverlay(Tab* tab)
// Fill the surface with pink color
{
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);

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

View File

@ -1,15 +1,15 @@
// Aseprite
// Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2018-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef __ASE_CONFIG_H
#ifdef __ASEPRITE_CONFIG_H
#error You cannot use config.h two times
#endif
#define __ASE_CONFIG_H
#define __ASEPRITE_CONFIG_H
// In MSVC
#ifdef _MSC_VER
@ -26,21 +26,6 @@
#pragma warning(disable:4710)
#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/debug.h"
#include "base/log.h"

View File

@ -1,6 +1,6 @@
// Aseprite Document Library
// Copyright (c) 2019 Igara Studio S.A.
// Copyright (c) 2001-2018 David Capello
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -179,6 +179,17 @@ bool Layer::isEditableHierarchy() const
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
{
return nullptr;

View File

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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello
//
// 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)));
#ifdef _WIN32
::CoInitialize(NULL);
::CoInitialize(nullptr);
#endif
try {
@ -70,11 +70,12 @@ int app_main(int argc, char* argv[])
os::ScopedHandle<os::System> system(os::create_system());
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();
if (!filename.empty())
memoryDump.setFileName(filename);
const std::string fn = app::SendCrash::DefaultMemoryDumpFilename();
if (!fn.empty())
memoryDump.setFileName(fn);
}
const int code = app.initialize(options);

View File

@ -1,5 +1,5 @@
// 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
//
// This file is released under the terms of the MIT license.
@ -845,7 +845,9 @@ public:
void preProcessChar(const int index,
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())
m_boxes.back().to = index;

View File

@ -1,5 +1,5 @@
// Aseprite UI Library
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// 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));
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)
@ -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));
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)
@ -135,7 +139,9 @@ void Graphics::drawLine(gfx::Color color, const gfx::Point& _a, const gfx::Point
dirty(gfx::Rect(a, b));
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)
@ -145,7 +151,10 @@ void Graphics::drawRect(gfx::Color color, const gfx::Rect& rcOrig)
dirty(rc);
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)
@ -155,7 +164,10 @@ void Graphics::fillRect(gfx::Color color, const gfx::Rect& rcOrig)
dirty(rc);
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)
@ -321,7 +333,8 @@ public:
void preProcessChar(const int index,
const int codepoint,
gfx::Color& fg,
gfx::Color& bg) override {
gfx::Color& bg,
const gfx::Rect& charBounds) override {
if (m_surface) {
if (m_mnemonic &&
// TODO use ICU library to lower unicode chars
@ -344,11 +357,16 @@ public:
if (!gfx::is_transparent(m_underscoreColor)) {
// TODO underscore height = guiscale() should be configurable from ui::Theme
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();
gfx::Rect underscoreBounds(charBounds.x, charBounds.y+charBounds.h+dy,
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;
}
}

View File

@ -1,5 +1,5 @@
// 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
//
// This file is released under the terms of the MIT license.
@ -302,10 +302,11 @@ Widget* Menu::findItemById(const char* id)
return result;
for (auto child : children()) {
if (child->type() == kMenuItemWidget) {
result = static_cast<MenuItem*>(child)
->getSubmenu()->findItemById(id);
if (result)
return result;
if (Menu* submenu = static_cast<MenuItem*>(child)->getSubmenu()) {
result = submenu->findItemById(id);
if (result)
return result;
}
}
}
return nullptr;

View File

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

View File

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

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -9,6 +9,9 @@
#include "config.h"
#endif
#include "updater/user_agent.h"
#include "ver/info.h"
#include <string>
#include <sstream>
@ -39,18 +42,7 @@ std::string getUserAgent()
std::stringstream userAgent;
// App name and 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 << " (";
userAgent << get_app_name() << "/" << get_app_version() << " (";
#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