mirror of https://github.com/aseprite/aseprite.git
Merge branch 'main' into beta
This commit is contained in:
commit
68d5262c48
|
@ -48,6 +48,7 @@ Checks: >
|
|||
portability-*,
|
||||
readability-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-narrowing-conversions,
|
||||
-misc-use-anonymous-namespace,
|
||||
-readability-braces-around-statements,
|
||||
-readability-function-cognitive-complexity,
|
||||
|
|
|
@ -14,3 +14,4 @@
|
|||
.vs
|
||||
tests/_test*
|
||||
build
|
||||
CMakeSettings.json
|
||||
|
|
|
@ -59,6 +59,7 @@ option(ENABLE_DRM "Compile the DRM-enabled version (e.g. for automatic
|
|||
option(ENABLE_STEAM "Compile with Steam library" off)
|
||||
option(ENABLE_DEVMODE "Compile vesion for developers" off)
|
||||
option(ENABLE_UI "Compile UI (turn off to compile CLI-only version)" on)
|
||||
option(ENABLE_I18N_STRINGS "Clone i18n strings repo (https://github.com/aseprite/strings) to bin/data/strings.git" off)
|
||||
option(FULLSCREEN_PLATFORM "Enable fullscreen by default" off)
|
||||
option(ENABLE_CLANG_TIDY "Enable static analysis" off)
|
||||
option(ENABLE_CCACHE "Use CCache to improve recompilation speed (optional)" on)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
We have a [code of conduct](CODE_OF_CONDUCT.md) that we all must
|
||||
follow. Be polite to everyone. If you are not in your best day, take a
|
||||
deep breath and try again. Smile :smile:
|
||||
deep breath and try again.
|
||||
|
||||
# New Issues
|
||||
|
||||
|
|
15
INSTALL.md
15
INSTALL.md
|
@ -85,7 +85,7 @@ On Fedora:
|
|||
|
||||
On Arch:
|
||||
|
||||
sudo pacman -S gcc clang libc++ cmake ninja libx11 libxcursor mesa-libgl fontconfig
|
||||
sudo pacman -S gcc clang libc++ cmake ninja libx11 libxcursor mesa-libgl fontconfig libwebp
|
||||
|
||||
On SUSE:
|
||||
|
||||
|
@ -127,11 +127,16 @@ On SUSE:
|
|||
|
||||
## Windows details
|
||||
|
||||
Open a command prompt window (`cmd.exe`) and call:
|
||||
Open a command prompt window with the VS 2022 tools. For this you can
|
||||
search for `x64 Native Tools Command Prompt for VS 2022` in the Start
|
||||
menu, or open a `cmd.exe` terminal and run:
|
||||
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" -arch=x64
|
||||
|
||||
The command above is required while using the 64-bit version of skia. When compiling with the 32-bit version, it is possible to open a [developer command prompt](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs) instead.
|
||||
The command above is required while using the 64-bit version of
|
||||
Skia. When compiling with the 32-bit version, it is possible to open a
|
||||
[developer command prompt](https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs)
|
||||
instead.
|
||||
|
||||
And then
|
||||
|
||||
|
@ -190,7 +195,7 @@ but it could be different in your Mac.
|
|||
### Apple Silicon
|
||||
|
||||
If you running macOS on an ARM64/AArch64/Apple Silicon Mac (e.g. M1),
|
||||
you can compile a native ARM64 version of Aseprite following similar
|
||||
you can compile a native ARM64 version of Aseprite following similar
|
||||
steps as above but when we call `cmake`, we have some differences:
|
||||
|
||||
cd aseprite
|
||||
|
@ -208,7 +213,7 @@ steps as above but when we call `cmake`, we have some differences:
|
|||
-DPNG_ARM_NEON:STRING=on \
|
||||
-G Ninja \
|
||||
..
|
||||
ninja aseprite
|
||||
ninja aseprite
|
||||
|
||||
### Issues with Retina displays
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
@ -171,6 +171,7 @@
|
|||
<part id="window_play_icon" x="21" y="11" w="5" h="6" />
|
||||
<part id="window_stop_icon" x="26" y="11" w="5" h="6" />
|
||||
<part id="window_center_icon" x="31" y="11" w="5" h="6" />
|
||||
<part id="window_help_icon" x="36" y="11" w="5" h="6" />
|
||||
<part id="slider_full" x="0" y="144" w1="5" w2="6" w3="5" h1="5" h2="5" h3="6" />
|
||||
<part id="slider_empty" x="16" y="144" w1="5" w2="6" w3="5" h1="5" h2="5" h3="6" />
|
||||
<part id="slider_full_focused" x="0" y="160" w1="5" w2="6" w3="5" h1="5" h2="5" h3="6" />
|
||||
|
@ -389,6 +390,7 @@
|
|||
<part id="icon_slice" x="248" y="264" w="8" h="8" />
|
||||
<part id="icon_aspect_ratio" x="256" y="264" w="10" h="8" />
|
||||
<part id="icon_delta" x="266" y="264" w="6" h="8" />
|
||||
<part id="icon_add" x="184" y="200" w="5" h="5" />
|
||||
<part id="tool_rectangular_marquee" x="144" y="0" w="16" h="16" />
|
||||
<part id="tool_elliptical_marquee" x="160" y="0" w="16" h="16" />
|
||||
<part id="tool_lasso" x="176" y="0" w="16" h="16" />
|
||||
|
@ -498,6 +500,12 @@
|
|||
<icon part="window_stop_icon" color="button_hot_text" state="mouse" />
|
||||
<icon part="window_stop_icon" color="button_selected_text" state="selected" />
|
||||
</style>
|
||||
<style id="window_help_button" extends="window_button" margin-top="3" margin-right="2">
|
||||
<newlayer />
|
||||
<icon part="window_help_icon" color="button_normal_text" />
|
||||
<icon part="window_help_icon" color="button_hot_text" state="mouse" />
|
||||
<icon part="window_help_icon" color="button_selected_text" state="selected" />
|
||||
</style>
|
||||
<style id="popup_window">
|
||||
<background color="window_face" />
|
||||
<border part="menu" />
|
||||
|
@ -687,7 +695,9 @@
|
|||
<background color="check_hot_face" state="selected" />
|
||||
<icon part="pal_options" />
|
||||
</style>
|
||||
<style id="new_frame_button" extends="mini_button" />
|
||||
<style id="new_frame_button" extends="mini_button" padding-bottom="1">
|
||||
<icon part="icon_add" />
|
||||
</style>
|
||||
<style id="color_button" extends="mini_button" font="mini" padding-bottom="1" />
|
||||
<style id="splitter">
|
||||
<background color="face" />
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
@ -167,6 +167,7 @@
|
|||
<part id="window_play_icon" x="21" y="11" w="5" h="6" />
|
||||
<part id="window_stop_icon" x="26" y="11" w="5" h="6" />
|
||||
<part id="window_center_icon" x="31" y="11" w="5" h="6" />
|
||||
<part id="window_help_icon" x="36" y="11" w="5" h="6" />
|
||||
<part id="slider_full" x="0" y="144" w1="5" w2="6" w3="5" h1="5" h2="5" h3="6" />
|
||||
<part id="slider_empty" x="16" y="144" w1="5" w2="6" w3="5" h1="5" h2="5" h3="6" />
|
||||
<part id="slider_full_focused" x="0" y="160" w1="5" w2="6" w3="5" h1="5" h2="5" h3="6" />
|
||||
|
@ -385,6 +386,7 @@
|
|||
<part id="icon_slice" x="248" y="264" w="8" h="8" />
|
||||
<part id="icon_aspect_ratio" x="256" y="264" w="10" h="8" />
|
||||
<part id="icon_delta" x="266" y="264" w="6" h="8" />
|
||||
<part id="icon_add" x="184" y="200" w="5" h="5" />
|
||||
<part id="tool_rectangular_marquee" x="144" y="0" w="16" h="16" />
|
||||
<part id="tool_elliptical_marquee" x="160" y="0" w="16" h="16" />
|
||||
<part id="tool_lasso" x="176" y="0" w="16" h="16" />
|
||||
|
@ -494,6 +496,12 @@
|
|||
<icon part="window_stop_icon" color="button_hot_text" state="mouse" />
|
||||
<icon part="window_stop_icon" color="button_selected_text" state="selected" />
|
||||
</style>
|
||||
<style id="window_help_button" extends="window_button" margin-top="3" margin-right="2">
|
||||
<newlayer />
|
||||
<icon part="window_help_icon" color="button_normal_text" />
|
||||
<icon part="window_help_icon" color="button_hot_text" state="mouse" />
|
||||
<icon part="window_help_icon" color="button_selected_text" state="selected" />
|
||||
</style>
|
||||
<style id="popup_window">
|
||||
<background color="window_face" />
|
||||
<border part="menu" />
|
||||
|
@ -680,7 +688,9 @@
|
|||
<background color="check_hot_face" state="selected" />
|
||||
<icon part="pal_options" />
|
||||
</style>
|
||||
<style id="new_frame_button" extends="mini_button" />
|
||||
<style id="new_frame_button" extends="mini_button" padding-bottom="1">
|
||||
<icon part="icon_add" />
|
||||
</style>
|
||||
<style id="color_button" extends="mini_button" font="mini" padding-bottom="1" />
|
||||
<style id="splitter">
|
||||
<background color="face" />
|
||||
|
|
13
data/gui.xml
13
data/gui.xml
|
@ -1089,6 +1089,19 @@
|
|||
</menu>
|
||||
</menu>
|
||||
|
||||
<menu id="new_frame_popup_menu">
|
||||
<item command="NewFrame" text="@main_menu.frame_duplicate_linked_cels">
|
||||
<param name="content" value="cellinked" />
|
||||
</item>
|
||||
<item command="NewFrame" text="@main_menu.frame_duplicate_cels">
|
||||
<param name="content" value="celcopies" />
|
||||
</item>
|
||||
<item command="NewFrame" text="@main_menu.frame_new_empty_frame">
|
||||
<param name="content" value="empty" />
|
||||
</item>
|
||||
<item command="NewFrame" text="@main_menu.frame_new_frame" />
|
||||
</menu>
|
||||
|
||||
<menu id="tab_popup_menu">
|
||||
<item command="CloseFile" text="@.close" group="tab_close" />
|
||||
</menu>
|
||||
|
|
|
@ -38,7 +38,7 @@ disable_snap_grid = Disable Snap to Grid
|
|||
frame = Frame:
|
||||
current_frame = Current Frame
|
||||
zoom_level = Zoom Level
|
||||
new_frame = New Frame
|
||||
new_frame = New Frame\nRight-click for more options
|
||||
locked_layers = There are locked layers
|
||||
no_active_layers = There is no active layer
|
||||
layer_x_is_hidden = Layer "{}" is hidden
|
||||
|
@ -90,6 +90,7 @@ job_working = {0}<<Working...||&Cancel
|
|||
nothing_to_report = Crash Report<<Nothing to report||&OK
|
||||
install_extension = Warning\n<<Do you really want to install the given extension?\n<<"{0}"\n||&Install||&Cancel
|
||||
uninstall_extension_warning = Warning\n<<Do you really want to uninstall "{0}" extension?\n||&Yes||&No
|
||||
cannot_install_default_extension = Error<<This extension cannot be installed because tries to replace the default theme.<<Contact the developer so they fix the theme ID or theme name string<<from \"default\" to something else.||&OK
|
||||
unknown_output_file_format_error = Aseprite\n<<Unknown file format "{0}" in output filename\n||&OK
|
||||
update_screen_ui_scaling_with_theme_values = Update Screen/UI Scaling\n<<The new theme "{0}" wants to adjust some values for you:\n<< Screen Scaling: {1}% -> {2}%\n<< UI Scaling: {3}% -> {4}%\n<<Allow these changes?\n||&Adjust Scaling||&Don't Adjust Scaling
|
||||
update_extension = Update Extension\n<<The extension "{0}" already exists.\n<<Do you want to {1} from v{2} to v{3}?\n||&Yes||&No
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2019 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2019-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="canvas_size" text="@.title">
|
||||
<window id="canvas_size" text="@.title" help="canvas">
|
||||
<vbox>
|
||||
<separator text="@.size" left="true" horizontal="true" />
|
||||
<hbox>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2022 by Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2022-2024 by Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2016-2018 by David Capello -->
|
||||
<gui>
|
||||
<window id="export_file" text="@.title">
|
||||
<window id="export_file" text="@.title" help="exporting">
|
||||
<grid columns="3">
|
||||
<label text="@.output_file" />
|
||||
<entry id="output_filename" cell_align="horizontal" maxsize="1024" maxwidth="256" />
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2019-2022 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2019-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="export_sprite_sheet" text="@.title">
|
||||
<window id="export_sprite_sheet" text="@.title" help="sprite-sheet#export">
|
||||
<vbox expansive="true">
|
||||
|
||||
<!-- Tabs -->
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2019 by Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2019-2024 by Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 by David Capello -->
|
||||
<gui>
|
||||
<window id="import_sprite_sheet" text="@.title">
|
||||
<window id="import_sprite_sheet" text="@.title" help="sprite-sheet#import">
|
||||
<vbox>
|
||||
<grid columns="4">
|
||||
<button id="select_file" text="@select_file.text" cell_hspan="4" />
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018-2022 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2016 David Capello -->
|
||||
<gui>
|
||||
<window id="keyboard_shortcuts" text="@keyboard_shortcuts.title">
|
||||
<window id="keyboard_shortcuts" text="@keyboard_shortcuts.title" help="keyboard-shortcuts">
|
||||
<vbox>
|
||||
<splitter horizontal="true" expansive="true" noborders="true" childspacing="2"
|
||||
by="pixel" position="80" id="section_splitter">
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2019 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2019-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2016 David Capello -->
|
||||
<gui>
|
||||
<window id="new_layer" text="@.title">
|
||||
<window id="new_layer" text="@.title" help="new-layer">
|
||||
<vbox>
|
||||
<grid columns="2">
|
||||
<label text="@.name" />
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (c) 2020 Igara Studio S.A. -->
|
||||
<!-- Copyright (c) 2020-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (c) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="new_sprite" text="@.title">
|
||||
<window id="new_sprite" text="@.title" help="new-sprite">
|
||||
<box vertical="true">
|
||||
|
||||
<separator text="@.size" left="true" horizontal="true" />
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<!-- Copyright (C) 2018-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="options" text="@.title">
|
||||
<window id="options" text="@.title" help="preferences">
|
||||
<vbox>
|
||||
<hbox expansive="true">
|
||||
<view maxsize="true">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2019-2021 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2019-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2017-2018 David Capello -->
|
||||
<gui>
|
||||
<window id="slice_properties" text="@.title">
|
||||
<window id="slice_properties" text="@.title" help="slices#slice-properties">
|
||||
<vbox>
|
||||
<grid id="properties_grid" columns="3">
|
||||
<label id="label1" text="@.name" />
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2018-2020 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2018-2024 Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2016 David Capello -->
|
||||
<gui>
|
||||
<window id="sprite_properties" text="@.title">
|
||||
<window id="sprite_properties" text="@.title" help="sprite-properties">
|
||||
<vbox>
|
||||
<grid id="properties_grid" columns="3">
|
||||
<label text="@.filename" />
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2024 by Igara Studio S.A. -->
|
||||
<!-- Copyright (C) 2001-2018 by David Capello -->
|
||||
<gui>
|
||||
<window id="sprite_size" text="@.title">
|
||||
<window id="sprite_size" text="@.title" help="resize">
|
||||
<box vertical="true">
|
||||
<box vertical="true">
|
||||
<separator text="@.pixels" left="true" horizontal="true" />
|
||||
|
|
|
@ -1,5 +1,22 @@
|
|||
# Code Style Guidelines
|
||||
|
||||
Some general rules to write code: Try to follow the same style/format
|
||||
of the file that you are editing (naming, indentation, etc.) or the
|
||||
style of the module (some [submodules](https://github.com/aseprite/aseprite/blob/main/.gitmodules),
|
||||
created by us, or by third-parties, have their own style).
|
||||
|
||||
There is a [.clang-format](https://github.com/aseprite/aseprite/blob/main/.clang-format)
|
||||
file available but we are not using it at the moment, probably we
|
||||
should start using some
|
||||
[clang-format-diff.py](https://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting)
|
||||
for patches, but this wasn't yet adopted in the development process.
|
||||
|
||||
There is a [.clang-tidy](https://github.com/aseprite/aseprite/blob/main/.clang-tidy)
|
||||
file used [in the GitHub actions](https://github.com/aseprite/aseprite/blob/main/.github/workflows/clang_tidy.yml)
|
||||
executed on each PR. These rules are adopted progressively on patches
|
||||
because are only executed in the diff, and if some rule is violated a
|
||||
comment by [aseprite-bot](https://github.com/aseprite-bot) is made.
|
||||
|
||||
## Basics
|
||||
|
||||
Basic statements:
|
||||
|
@ -120,7 +137,7 @@ public:
|
|||
Special();
|
||||
|
||||
protected:
|
||||
void onEvent2() override {
|
||||
void onEvent2() override { // No need to repeat virtual in overridden methods
|
||||
...
|
||||
}
|
||||
};
|
||||
|
@ -128,21 +145,27 @@ protected:
|
|||
|
||||
## Const
|
||||
|
||||
We use the const-west notation:
|
||||
|
||||
* [NL.26: Use conventional const notation](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#nl26-use-conventional-const-notation)
|
||||
|
||||
There is a problem with `clang-tidy` that will make comments using
|
||||
East const notation: [#4361](https://github.com/aseprite/aseprite/issues/4361)
|
||||
|
||||
## C++17
|
||||
|
||||
We are using C++17 standard. Some things cannot be used because we're
|
||||
targetting macOS 10.9, some notes are added about this:
|
||||
|
||||
* Use `nullptr` instead of `NULL` macro
|
||||
* Use `auto` for complex types, iterators, or when the variable type
|
||||
is obvious (e.g. `auto s = new Sprite;`)
|
||||
* Use `auto`/`auto*` for complex types/pointers, iterators, or when
|
||||
the variable type is obvious (e.g. `auto* s = new Sprite;`)
|
||||
* Use range-based for loops (`for (const auto& item : values) { ... }`)
|
||||
* Use template alias (`template<typename T> alias = orig<T>;`)
|
||||
* Use generic lambda functions
|
||||
* Use `std::shared_ptr`, `std::unique_ptr`, or `base::Ref`
|
||||
* Use `std::clamp`
|
||||
* Use `std::shared_ptr`, `std::unique_ptr`, or `base::Ref`, but
|
||||
generally we'd prefer value semantics instead of smart pointers
|
||||
* Use `std::min`/`std::max`/`std::clamp`
|
||||
* Use `std::optional` but taking care of some limitations from macOS 10.9:
|
||||
* Use `std::optional::has_value()` instead of `std::optional::operator bool()` ([example](https://github.com/aseprite/laf/commit/81622fcbb9e4a0edc14a02250c387bd6fa878708))
|
||||
* Use `std::optional::operator*()` instead of `std::optional::value()` ([example](https://github.com/aseprite/aseprite/commit/4471dab289cdd45762155ce0b16472e95a7f8642))
|
||||
|
@ -156,5 +179,11 @@ targetting macOS 10.9, some notes are added about this:
|
|||
* You can use `<atomic>`, `<thread>`, `<mutex>`, and `<condition_variable>`
|
||||
* Prefer `using T = ...;` instead of `typedef ... T`
|
||||
* Use `[[fallthrough]]` if needed
|
||||
* Use `= {}` only to specify a default argument value of an
|
||||
user-defined type in a function declaration, e.g.
|
||||
`void func(const std::string& s = {}) { ... }`.
|
||||
In other cases (e.g. a member variable of an user-defined type)
|
||||
it's not required or we prefer to use the explicit value
|
||||
for built-in types (`int m_var = 0;`).
|
||||
* We use gcc 9.2 or clang 9.0 on Linux, so check the features available in
|
||||
https://en.cppreference.com/w/cpp/compiler_support
|
||||
|
|
2
laf
2
laf
|
@ -1 +1 @@
|
|||
Subproject commit 188d31f0cbd6aebdb8c1a685505d3ed5e37dcd12
|
||||
Subproject commit b2a77b3216ee63edf0d288683d459c85b9b0b125
|
|
@ -102,21 +102,24 @@ set(DATA_OUTPUT_DIR ${CMAKE_BINARY_DIR}/bin/data)
|
|||
######################################################################
|
||||
# Clone "strings" repo with translations into bin/data/strings.git
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
FetchContent_Declare(
|
||||
clone_strings
|
||||
GIT_REPOSITORY https://github.com/aseprite/strings.git
|
||||
GIT_TAG origin/main
|
||||
SOURCE_DIR ${DATA_OUTPUT_DIR}/strings.git
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND "")
|
||||
FetchContent_MakeAvailable(clone_strings)
|
||||
add_custom_target(clone_strings DEPENDS clone_strings)
|
||||
if(ENABLE_I18N_STRINGS_REPO)
|
||||
include(FetchContent)
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
FetchContent_Declare(
|
||||
clone_strings
|
||||
GIT_REPOSITORY https://github.com/aseprite/strings.git
|
||||
GIT_TAG origin/main
|
||||
SOURCE_DIR ${DATA_OUTPUT_DIR}/strings.git
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND "")
|
||||
FetchContent_MakeAvailable(clone_strings)
|
||||
add_custom_target(clone_strings DEPENDS clone_strings)
|
||||
else()
|
||||
add_custom_target(clone_strings)
|
||||
endif()
|
||||
else()
|
||||
add_custom_target(clone_strings)
|
||||
endif()
|
||||
|
@ -134,7 +137,7 @@ foreach(fn ${src_data_files})
|
|||
list(APPEND out_data_files ${DATA_OUTPUT_DIR}/${fn})
|
||||
endforeach()
|
||||
|
||||
if(GIT_FOUND)
|
||||
if(ENABLE_I18N_STRINGS_REPO AND GIT_FOUND)
|
||||
# Copy original en.ini to strings.git/en.ini to keep it updated. We
|
||||
# have to manually sync the "en.ini" file in the "strings" repo from
|
||||
# the "aseprite" repo.
|
||||
|
|
|
@ -422,6 +422,7 @@ if(ENABLE_UI)
|
|||
ui/keyboard_shortcuts.cpp
|
||||
ui/main_menu_bar.cpp
|
||||
ui/main_window.cpp
|
||||
ui/mini_help_button.cpp
|
||||
ui/notifications.cpp
|
||||
ui/optional_alert.cpp
|
||||
ui/palette_popup.cpp
|
||||
|
|
|
@ -382,6 +382,7 @@ void AppMenus::reload()
|
|||
m_slicePopupMenu.reset(loadMenuById(handle, "slice_popup_menu"));
|
||||
m_palettePopupMenu.reset(loadMenuById(handle, "palette_popup_menu"));
|
||||
m_inkPopupMenu.reset(loadMenuById(handle, "ink_popup_menu"));
|
||||
m_newFramePopupMenu.reset(loadMenuById(handle, "new_frame_popup_menu"));
|
||||
|
||||
// Add one menu item to run each script from the user scripts/ folder
|
||||
{
|
||||
|
@ -920,6 +921,7 @@ void AppMenus::updateMenusList()
|
|||
m_menus.push_back(m_slicePopupMenu.get());
|
||||
m_menus.push_back(m_palettePopupMenu.get());
|
||||
m_menus.push_back(m_inkPopupMenu.get());
|
||||
m_menus.push_back(m_newFramePopupMenu.get());
|
||||
}
|
||||
|
||||
void AppMenus::createNativeMenus()
|
||||
|
|
|
@ -57,6 +57,7 @@ namespace app {
|
|||
Menu* getPalettePopupMenu() { return m_palettePopupMenu.get(); }
|
||||
Menu* getInkPopupMenu() { return m_inkPopupMenu.get(); }
|
||||
Menu* getAnimationMenu();
|
||||
Menu* getNewFrameMenu() { return m_newFramePopupMenu.get(); }
|
||||
|
||||
void applyShortcutToMenuitemsWithCommand(Command* command, const Params& params,
|
||||
const KeyPtr& key);
|
||||
|
@ -111,6 +112,7 @@ namespace app {
|
|||
std::unique_ptr<Menu> m_slicePopupMenu;
|
||||
std::unique_ptr<Menu> m_palettePopupMenu;
|
||||
std::unique_ptr<Menu> m_inkPopupMenu;
|
||||
std::unique_ptr<Menu> m_newFramePopupMenu;
|
||||
obs::scoped_connection m_recentFilesConn;
|
||||
std::vector<Menu*> m_menus;
|
||||
// List of recent menu items pointing to recent files.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -20,7 +20,6 @@
|
|||
#include "app/pref/preferences.h"
|
||||
#include "app/tx.h"
|
||||
#include "doc/palette.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
#include "app/script/luacpp.h"
|
||||
|
@ -148,7 +147,7 @@ std::string AddColorCommand::onGetFriendlyName() const
|
|||
case AddColorSource::Bg: source = Strings::commands_AddColor_Background(); break;
|
||||
case AddColorSource::Color: source = Strings::commands_AddColor_Specific(); break;
|
||||
}
|
||||
return fmt::format(getBaseFriendlyName(), source);
|
||||
return Strings::commands_AddColor(source);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createAddColorCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -22,7 +22,6 @@
|
|||
#include "doc/cel.h"
|
||||
#include "doc/cels_range.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -109,9 +108,8 @@ void CelOpacityCommand::onExecute(Context* context)
|
|||
|
||||
std::string CelOpacityCommand::onGetFriendlyName() const
|
||||
{
|
||||
return fmt::format(getBaseFriendlyName(),
|
||||
m_opacity,
|
||||
int(100.0 * m_opacity / 255.0));
|
||||
return Strings::commands_CelOpacity(m_opacity,
|
||||
int(100.0 * m_opacity / 255.0));
|
||||
}
|
||||
|
||||
Command* CommandFactory::createCelOpacityCommand()
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "doc/image_ref.h"
|
||||
#include "doc/primitives.h"
|
||||
#include "doc/tile.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
@ -328,10 +327,10 @@ std::string ChangeBrushCommand::onGetFriendlyName() const
|
|||
case FlipD: change = Strings::commands_ChangeBrush_FlipD(); break;
|
||||
case Rotate90CW: change = Strings::commands_ChangeBrush_Rotate90CW(); break;
|
||||
case CustomBrush:
|
||||
change = fmt::format(Strings::commands_ChangeBrush_CustomBrush(), m_slot);
|
||||
change = Strings::commands_ChangeBrush_CustomBrush(m_slot);
|
||||
break;
|
||||
}
|
||||
return fmt::format(getBaseFriendlyName(), change);
|
||||
return Strings::commands_ChangeBrush(change);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createChangeBrushCommand()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -17,7 +18,6 @@
|
|||
#include "app/modules/palettes.h"
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "doc/palette.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -120,7 +120,7 @@ std::string ChangeColorCommand::onGetFriendlyName() const
|
|||
break;
|
||||
}
|
||||
|
||||
return fmt::format(getBaseFriendlyName(), action);
|
||||
return Strings::commands_ChangeColor(action);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createChangeColorCommand()
|
||||
|
|
|
@ -727,7 +727,7 @@ std::string ChangePixelFormatCommand::onGetFriendlyName() const
|
|||
else
|
||||
conversion = Strings::commands_ChangePixelFormat_MoreOptions();
|
||||
|
||||
return fmt::format(getBaseFriendlyName(), conversion);
|
||||
return Strings::commands_ChangePixelFormat(conversion);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createChangePixelFormatCommand()
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include "export_sprite_sheet.xml.h"
|
||||
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -93,20 +93,19 @@ bool ask_overwrite(const bool askFilename, const std::string& filename,
|
|||
(askDataname &&
|
||||
!dataname.empty() &&
|
||||
base::is_file(dataname))) {
|
||||
std::stringstream text;
|
||||
std::string text;
|
||||
|
||||
if (base::is_file(filename))
|
||||
text << "<<" << base::get_file_name(filename).c_str();
|
||||
text += "<<" + base::get_file_name(filename);
|
||||
|
||||
if (base::is_file(dataname))
|
||||
text << "<<" << base::get_file_name(dataname).c_str();
|
||||
text += "<<" + base::get_file_name(dataname);
|
||||
|
||||
const int ret =
|
||||
OptionalAlert::show(
|
||||
Preferences::instance().spriteSheet.showOverwriteFilesAlert,
|
||||
1, // Yes is the default option when the alert dialog is disabled
|
||||
fmt::format(Strings::alerts_overwrite_files_on_export_sprite_sheet(),
|
||||
text.str()));
|
||||
Strings::alerts_overwrite_files_on_export_sprite_sheet(text));
|
||||
if (ret != 1)
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -39,7 +39,6 @@
|
|||
#include "doc/layer.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "gfx/size.h"
|
||||
|
||||
|
||||
|
@ -256,7 +255,7 @@ std::string FlipCommand::onGetFriendlyName() const
|
|||
else
|
||||
orientation = Strings::commands_Flip_Vertically();
|
||||
|
||||
return fmt::format(getBaseFriendlyName(), content, orientation);
|
||||
return Strings::commands_Flip(content, orientation);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createFlipCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -31,7 +31,6 @@
|
|||
#include "base/scoped_value.h"
|
||||
#include "base/split_string.h"
|
||||
#include "base/string.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/fit_bounds.h"
|
||||
#include "ui/graphics.h"
|
||||
|
@ -239,9 +238,7 @@ private:
|
|||
ui::Accelerator accel = m_key->accels()[index];
|
||||
|
||||
if (ui::Alert::show(
|
||||
fmt::format(
|
||||
Strings::alerts_delete_shortcut(),
|
||||
accel.toString())) != 1)
|
||||
Strings::alerts_delete_shortcut(accel.toString())) != 1)
|
||||
return;
|
||||
|
||||
m_key->disableAccel(accel, KeySource::UserDefined);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -20,7 +20,6 @@
|
|||
#include "app/tx.h"
|
||||
#include "app/ui/timeline/timeline.h"
|
||||
#include "doc/layer.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -94,9 +93,8 @@ void LayerOpacityCommand::onExecute(Context* context)
|
|||
|
||||
std::string LayerOpacityCommand::onGetFriendlyName() const
|
||||
{
|
||||
return fmt::format(getBaseFriendlyName(),
|
||||
m_opacity,
|
||||
int(100.0 * m_opacity / 255.0));
|
||||
return Strings::commands_LayerOpacity(m_opacity,
|
||||
int(100.0 * m_opacity / 255.0));
|
||||
}
|
||||
|
||||
Command* CommandFactory::createLayerOpacityCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -20,7 +20,6 @@
|
|||
#include "app/util/msk_file.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -70,7 +69,7 @@ void LoadMaskCommand::onExecute(Context* context)
|
|||
|
||||
std::unique_ptr<Mask> mask(load_msk_file(m_filename.c_str()));
|
||||
if (!mask) {
|
||||
ui::Alert::show(fmt::format(Strings::alerts_error_loading_file(), m_filename));
|
||||
ui::Alert::show(Strings::alerts_error_loading_file(m_filename));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
// Copyright (C) 2023-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -19,7 +19,6 @@
|
|||
#include "app/modules/palettes.h"
|
||||
#include "base/fs.h"
|
||||
#include "doc/palette.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -81,7 +80,7 @@ void LoadPaletteCommand::onExecute(Context* context)
|
|||
std::unique_ptr<doc::Palette> palette(load_palette(filename.c_str()));
|
||||
if (!palette) {
|
||||
if (context->isUIAvailable())
|
||||
ui::Alert::show(fmt::format(Strings::alerts_error_loading_file(), filename));
|
||||
ui::Alert::show(Strings::alerts_error_loading_file(filename));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -23,7 +23,6 @@
|
|||
#include "doc/brush_type.h"
|
||||
#include "doc/mask.h"
|
||||
#include "filters/neighboring_pixels.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "modify_selection.xml.h"
|
||||
|
||||
|
@ -151,11 +150,9 @@ std::string ModifySelectionCommand::onGetFriendlyName() const
|
|||
{
|
||||
std::string quantity;
|
||||
if (m_quantity > 0)
|
||||
quantity = fmt::format(Strings::commands_ModifySelection_Quantity(), m_quantity);
|
||||
quantity = Strings::commands_ModifySelection_Quantity(m_quantity);
|
||||
|
||||
return fmt::format(getBaseFriendlyName(),
|
||||
getActionName(),
|
||||
quantity);
|
||||
return Strings::commands_ModifySelection(getActionName(), quantity);
|
||||
}
|
||||
|
||||
std::string ModifySelectionCommand::getActionName() const
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -26,7 +26,6 @@
|
|||
#include "base/convert_to.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/view.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -124,8 +123,8 @@ std::string MoveMaskCommand::onGetFriendlyName() const
|
|||
case Boundaries: content = Strings::commands_MoveMask_Boundaries(); break;
|
||||
case Content: content = Strings::commands_MoveMask_Content(); break;
|
||||
}
|
||||
return fmt::format(getBaseFriendlyName(),
|
||||
content, m_moveThing.getFriendlyString());
|
||||
return Strings::commands_MoveMask(content,
|
||||
m_moveThing.getFriendlyString());
|
||||
}
|
||||
|
||||
Command* CommandFactory::createMoveMaskCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -285,9 +285,9 @@ void NewFileCommand::onExecute(Context* ctx)
|
|||
std::string NewFileCommand::onGetFriendlyName() const
|
||||
{
|
||||
if (params().fromClipboard())
|
||||
return fmt::format(Strings::commands_NewFile_FromClipboard());
|
||||
return Strings::commands_NewFile_FromClipboard();
|
||||
else
|
||||
return fmt::format(Strings::commands_NewFile());
|
||||
return Strings::commands_NewFile();
|
||||
}
|
||||
|
||||
Command* CommandFactory::createNewFileCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -29,7 +29,6 @@
|
|||
#include "doc/image.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
@ -181,8 +180,7 @@ void NewFrameCommand::onExecute(Context* context)
|
|||
update_screen_for_document(document);
|
||||
|
||||
StatusBar::instance()->showTip(
|
||||
1000, fmt::format(
|
||||
Strings::commands_NewFrame_tooltip(),
|
||||
1000, Strings::commands_NewFrame_tooltip(
|
||||
(int)context->activeSite().frame()+1,
|
||||
(int)sprite->totalFrames()));
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -274,8 +274,7 @@ void NewLayerCommand::onExecute(Context* context)
|
|||
Layer* layer = nullptr;
|
||||
{
|
||||
ContextWriter writer(reader);
|
||||
Tx tx(writer,
|
||||
fmt::format(Strings::commands_NewLayer(), layerPrefix()));
|
||||
Tx tx(writer, Strings::commands_NewLayer(layerPrefix()));
|
||||
DocApi api = document->getApi(tx);
|
||||
bool afterBackground = false;
|
||||
|
||||
|
@ -513,17 +512,17 @@ std::string NewLayerCommand::onGetFriendlyName() const
|
|||
{
|
||||
std::string text;
|
||||
if (m_place == Place::BeforeActiveLayer)
|
||||
text = fmt::format(Strings::commands_NewLayer_BeforeActiveLayer(), layerPrefix());
|
||||
text = Strings::commands_NewLayer_BeforeActiveLayer(layerPrefix());
|
||||
else
|
||||
text = fmt::format(Strings::commands_NewLayer(), layerPrefix());
|
||||
text = Strings::commands_NewLayer(layerPrefix());
|
||||
if (params().fromClipboard())
|
||||
text = fmt::format(Strings::commands_NewLayer_FromClipboard(), text);
|
||||
text = Strings::commands_NewLayer_FromClipboard(text);
|
||||
if (params().viaCopy())
|
||||
text = fmt::format(Strings::commands_NewLayer_ViaCopy(), text);
|
||||
text = Strings::commands_NewLayer_ViaCopy(text);
|
||||
if (params().viaCut())
|
||||
text = fmt::format(Strings::commands_NewLayer_ViaCut(), text);
|
||||
text = Strings::commands_NewLayer_ViaCut(text);
|
||||
if (params().ask())
|
||||
text = fmt::format(Strings::commands_NewLayer_WithDialog(), text);
|
||||
text = Strings::commands_NewLayer_WithDialog(text);
|
||||
return text;
|
||||
}
|
||||
|
||||
|
|
|
@ -888,9 +888,7 @@ public:
|
|||
m_pref.save();
|
||||
|
||||
if (!warnings.empty()) {
|
||||
ui::Alert::show(
|
||||
fmt::format(Strings::alerts_restart_by_preferences(),
|
||||
warnings));
|
||||
ui::Alert::show(Strings::alerts_restart_by_preferences(warnings));
|
||||
}
|
||||
|
||||
// Probably it's safe to switch this flag in runtime
|
||||
|
@ -928,9 +926,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Get the extension information from the compressed
|
||||
// package.json file.
|
||||
const ExtensionInfo info =
|
||||
App::instance()->extensions().getCompressedExtensionInfo(filename);
|
||||
// Check if the filename corresponds to aseprite-default theme
|
||||
if (base::string_to_lower(info.name) ==
|
||||
Extension::kAsepriteDefaultThemeExtensionName) {
|
||||
ui::Alert::show(Strings::alerts_cannot_install_default_extension());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Install?
|
||||
if (ui::Alert::show(
|
||||
fmt::format(Strings::alerts_install_extension(), filename)) != 1)
|
||||
if (ui::Alert::show(Strings::alerts_install_extension(filename)) != 1)
|
||||
return false;
|
||||
|
||||
installExtension(filename);
|
||||
|
@ -1380,7 +1388,8 @@ private:
|
|||
if (!ext->isEnabled())
|
||||
continue;
|
||||
|
||||
if (ext->themes().empty())
|
||||
if (ext->themes().empty() ||
|
||||
isExtensionADuplicatedDefaultTheme(ext))
|
||||
continue;
|
||||
|
||||
if (first) {
|
||||
|
@ -1412,6 +1421,9 @@ private:
|
|||
extensionsList()->addChild(sep);
|
||||
for (auto e : App::instance()->extensions()) {
|
||||
if (e->category() == category) {
|
||||
if (category == Extension::Category::Themes &&
|
||||
isExtensionADuplicatedDefaultTheme(e))
|
||||
continue;
|
||||
ExtensionItem* item = new ExtensionItem(e);
|
||||
extensionsList()->addChild(item);
|
||||
hasItems = true;
|
||||
|
@ -1494,8 +1506,7 @@ private:
|
|||
// Ask if the user want to adjust the Screen/UI Scaling
|
||||
const int result =
|
||||
ui::Alert::show(
|
||||
fmt::format(
|
||||
Strings::alerts_update_screen_ui_scaling_with_theme_values(),
|
||||
Strings::alerts_update_screen_ui_scaling_with_theme_values(
|
||||
themeName,
|
||||
100 * m_pref.general.screenScale(),
|
||||
100 * (newScreenScale > 0 ? newScreenScale: m_pref.general.screenScale()),
|
||||
|
@ -1574,6 +1585,10 @@ private:
|
|||
// package.json file.
|
||||
ExtensionInfo info = exts.getCompressedExtensionInfo(filename);
|
||||
|
||||
if (info.defaultTheme) {
|
||||
ui::Alert::show(Strings::alerts_cannot_install_default_extension());
|
||||
return;
|
||||
}
|
||||
// Check if the extension already exist
|
||||
for (auto ext : exts) {
|
||||
if (base::string_to_lower(ext->name()) !=
|
||||
|
@ -1586,8 +1601,7 @@ private:
|
|||
|
||||
// Uninstall?
|
||||
if (ui::Alert::show(
|
||||
fmt::format(
|
||||
Strings::alerts_update_extension(),
|
||||
Strings::alerts_update_extension(
|
||||
ext->name(),
|
||||
(isDowngrade ? Strings::alerts_update_extension_downgrade():
|
||||
Strings::alerts_update_extension_upgrade()),
|
||||
|
@ -1663,8 +1677,7 @@ private:
|
|||
return;
|
||||
|
||||
if (ui::Alert::show(
|
||||
fmt::format(
|
||||
Strings::alerts_uninstall_extension_warning(),
|
||||
Strings::alerts_uninstall_extension_warning(
|
||||
item->text())) != 1)
|
||||
return;
|
||||
|
||||
|
@ -1754,6 +1767,17 @@ private:
|
|||
return paths;
|
||||
}
|
||||
|
||||
static base::paths getUserDirPaths(const base::paths& dirNames) {
|
||||
ResourceFinder rf;
|
||||
for (auto& fn : dirNames)
|
||||
rf.includeUserDir(fn.c_str());
|
||||
|
||||
base::paths paths;
|
||||
while (rf.next())
|
||||
paths.push_back(base::normalize_path(rf.filename()));
|
||||
return paths;
|
||||
}
|
||||
|
||||
void updateCategoryVisibility() {
|
||||
bool visibleCategories[int(Extension::Category::Max)];
|
||||
for (auto& v : visibleCategories)
|
||||
|
@ -1769,6 +1793,20 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
// Function to determine if the input extension is the default theme
|
||||
static bool isExtensionADuplicatedDefaultTheme(const Extension* e) {
|
||||
if (!e->isDefaultTheme())
|
||||
return false;
|
||||
auto userThemePaths =
|
||||
getUserDirPaths({"extensions", skin::SkinTheme::kThemesFolderName});
|
||||
for (auto& p : userThemePaths) {
|
||||
// Has the user path (p) the same path of the extension (e->path())?
|
||||
if (std::strncmp(e->path().c_str(), p.c_str(), p.size()) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef LAF_WINDOWS
|
||||
void onTabletAPIChange() {
|
||||
const bool pointerApi = tabletApiWindowsPointer()->isSelected();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
// Copyright (C) 2023-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -15,7 +15,6 @@
|
|||
#include "app/ui/color_bar.h"
|
||||
#include "base/replace_string.h"
|
||||
#include "base/trim_string.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -107,7 +106,7 @@ std::string PaletteEditorCommand::onGetFriendlyName() const
|
|||
popup = Strings::commands_PaletteEditor_FgPopup();
|
||||
}
|
||||
|
||||
std::string result = fmt::format(getBaseFriendlyName(), edit, plus, popup);
|
||||
std::string result = Strings::commands_PaletteEditor(edit, plus, popup);
|
||||
// TODO create a new function to remove duplicate whitespaces
|
||||
base::replace_string(result, " ", " ");
|
||||
base::replace_string(result, " ", " ");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -24,7 +24,6 @@
|
|||
#include "doc/layer_tilemap.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "doc/tilesets.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
|
@ -90,7 +89,7 @@ static bool continue_deleting_unused_tilesets(
|
|||
|
||||
std::string message;
|
||||
if (tsiToDelete.size() >= 1)
|
||||
message = fmt::format(Strings::alerts_deleting_tilemaps_will_delete_tilesets(), layerNames);
|
||||
message = Strings::alerts_deleting_tilemaps_will_delete_tilesets(layerNames);
|
||||
|
||||
return tsiToDelete.empty() ||
|
||||
app::OptionalAlert::show(
|
||||
|
@ -205,12 +204,14 @@ void RemoveLayerCommand::onExecute(Context* context)
|
|||
update_screen_for_document(document);
|
||||
|
||||
StatusBar::instance()->invalidate();
|
||||
if (!layerName.empty())
|
||||
if (!layerName.empty()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, fmt::format(Strings::remove_layer_x_removed(), layerName));
|
||||
else
|
||||
StatusBar::instance()->showTip(1000,
|
||||
Strings::remove_layer_layers_removed());
|
||||
1000, Strings::remove_layer_x_removed(layerName));
|
||||
}
|
||||
else {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, Strings::remove_layer_layers_removed());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -22,7 +22,6 @@
|
|||
#include "doc/selected_objects.h"
|
||||
#include "doc/slice.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
|
@ -121,14 +120,14 @@ void RemoveSliceCommand::onExecute(Context* context)
|
|||
}
|
||||
|
||||
StatusBar::instance()->invalidate();
|
||||
if (!sliceName.empty())
|
||||
if (!sliceName.empty()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, fmt::format(Strings::remove_slice_x_removed(), sliceName));
|
||||
else
|
||||
1000, Strings::remove_slice_x_removed(sliceName));
|
||||
}
|
||||
else {
|
||||
StatusBar::instance()->showTip(
|
||||
1000,
|
||||
fmt::format(Strings::remove_slice_n_slices_removed(),
|
||||
slicesToDelete.size()));
|
||||
1000, Strings::remove_slice_n_slices_removed(slicesToDelete.size()));
|
||||
}
|
||||
}
|
||||
|
||||
Command* CommandFactory::createRemoveSliceCommand()
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "doc/image.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -261,8 +260,8 @@ std::string RotateCommand::onGetFriendlyName() const
|
|||
content = Strings::commands_Rotate_Selection();
|
||||
else
|
||||
content = Strings::commands_Rotate_Sprite();
|
||||
return fmt::format(getBaseFriendlyName(),
|
||||
content, base::convert_to<std::string>(m_angle));
|
||||
return Strings::commands_Rotate(content,
|
||||
base::convert_to<std::string>(m_angle));
|
||||
}
|
||||
|
||||
Command* CommandFactory::createRotateCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -70,7 +70,7 @@ void RunScriptCommand::onExecute(Context* context)
|
|||
int ret = OptionalAlert::show(
|
||||
Preferences::instance().scripts.showRunScriptAlert,
|
||||
1, // Yes is the default option when the alert dialog is disabled
|
||||
fmt::format(Strings::alerts_run_script(), m_filename));
|
||||
Strings::alerts_run_script(m_filename));
|
||||
if (ret != 1)
|
||||
return;
|
||||
}
|
||||
|
@ -89,11 +89,11 @@ void RunScriptCommand::onExecute(Context* context)
|
|||
std::string RunScriptCommand::onGetFriendlyName() const
|
||||
{
|
||||
if (m_filename.empty())
|
||||
return getBaseFriendlyName();
|
||||
else
|
||||
return fmt::format("{0}: {1}",
|
||||
getBaseFriendlyName(),
|
||||
base::get_file_name(m_filename));
|
||||
return Strings::commands_RunScript();
|
||||
|
||||
return fmt::format("{0}: {1}",
|
||||
Strings::commands_RunScript(),
|
||||
base::get_file_name(m_filename));
|
||||
}
|
||||
|
||||
Command* CommandFactory::createRunScriptCommand()
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "doc/tag.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/ui.h"
|
||||
#include "undo/undo_state.h"
|
||||
|
||||
|
@ -269,8 +268,7 @@ void SaveFileBaseCommand::saveDocumentInBackground(
|
|||
#ifdef ENABLE_UI
|
||||
if (context->isUIAvailable() && params().ui()) {
|
||||
StatusBar::instance()->setStatusText(
|
||||
2000, fmt::format(Strings::save_file_saved(),
|
||||
base::get_file_name(filename)));
|
||||
2000, Strings::save_file_saved(base::get_file_name(filename)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -428,8 +426,7 @@ void SaveFileCopyAsCommand::onExecute(Context* context)
|
|||
int ret = OptionalAlert::show(
|
||||
Preferences::instance().exportFile.showOverwriteFilesAlert,
|
||||
1, // Yes is the default option when the alert dialog is disabled
|
||||
fmt::format(Strings::alerts_overwrite_files_on_export(),
|
||||
outputFilename));
|
||||
Strings::alerts_overwrite_files_on_export(outputFilename));
|
||||
if (ret != 1)
|
||||
goto again;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -16,7 +17,6 @@
|
|||
#include "base/fs.h"
|
||||
#include "doc/mask.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -55,7 +55,7 @@ void SaveMaskCommand::onExecute(Context* context)
|
|||
std::string filename = selFilename.front();
|
||||
|
||||
if (save_msk_file(document->mask(), filename.c_str()) != 0)
|
||||
ui::Alert::show(fmt::format(Strings::alerts_error_saving_file(), filename));
|
||||
ui::Alert::show(Strings::alerts_error_saving_file(filename));
|
||||
}
|
||||
|
||||
Command* CommandFactory::createSaveMaskCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio S.A.
|
||||
// Copyright (C) 2021-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -21,7 +21,6 @@
|
|||
#include "app/modules/palettes.h"
|
||||
#include "base/fs.h"
|
||||
#include "doc/palette.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -78,8 +77,8 @@ void SavePaletteCommand::onExecute(Context* ctx)
|
|||
if (!base::has_file_extension(filename, exts)) {
|
||||
if (ctx->isUIAvailable()) {
|
||||
ui::Alert::show(
|
||||
fmt::format(Strings::alerts_file_format_doesnt_support_palette(),
|
||||
base::get_file_extension(filename)));
|
||||
Strings::alerts_file_format_doesnt_support_palette(
|
||||
base::get_file_extension(filename)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -90,7 +89,7 @@ void SavePaletteCommand::onExecute(Context* ctx)
|
|||
colorSpace = activeDoc->sprite()->colorSpace();
|
||||
|
||||
if (!save_palette(filename.c_str(), palette, 16, colorSpace)) // TODO 16 should be configurable
|
||||
ui::Alert::show(fmt::format(Strings::alerts_error_saving_file(), filename));
|
||||
ui::Alert::show(Strings::alerts_error_saving_file(filename));
|
||||
|
||||
if (m_preset == get_default_palette_preset_name()) {
|
||||
set_default_palette(palette);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -17,7 +17,6 @@
|
|||
#include "app/i18n/strings.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/view.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -64,8 +63,7 @@ void ScrollCommand::onExecute(Context* context)
|
|||
|
||||
std::string ScrollCommand::onGetFriendlyName() const
|
||||
{
|
||||
return fmt::format(getBaseFriendlyName(),
|
||||
m_moveThing.getFriendlyString());
|
||||
return Strings::commands_Scroll(m_moveThing.getFriendlyString());
|
||||
}
|
||||
|
||||
Command* CommandFactory::createScrollCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2021 Igara Studio SA
|
||||
// Copyright (C) 2021-2024 Igara Studio SA
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -229,7 +229,7 @@ std::string SelectPaletteColorsCommand::onGetFriendlyName() const
|
|||
case UsedTiles: return Strings::commands_SelectPaletteColors_UsedTiles();
|
||||
case UnusedTiles: return Strings::commands_SelectPaletteColors_UnusedTiles();
|
||||
}
|
||||
return getBaseFriendlyName();
|
||||
return Strings::commands_SelectPaletteColors();
|
||||
}
|
||||
|
||||
Command* CommandFactory::createSelectPaletteColorsCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2015-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -19,7 +19,6 @@
|
|||
#include "app/tx.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "doc/mask.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/system.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -124,7 +123,7 @@ std::string SelectTileCommand::onGetFriendlyName() const
|
|||
text = Strings::commands_SelectTile_Intersect();
|
||||
break;
|
||||
default:
|
||||
text = getBaseFriendlyName();
|
||||
text = Strings::commands_SelectTile();
|
||||
break;
|
||||
}
|
||||
return text;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -13,7 +14,6 @@
|
|||
#include "app/commands/params.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -90,7 +90,7 @@ std::string SetColorSelectorCommand::onGetFriendlyName() const
|
|||
type = Strings::commands_SetColorSelector_NormalMapWheel();
|
||||
break;
|
||||
}
|
||||
return fmt::format(getBaseFriendlyName() + ": {0}", type);
|
||||
return fmt::format("{0}: {1}", Command::onGetFriendlyName(), type);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createSetColorSelectorCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -16,7 +16,6 @@
|
|||
#include "app/i18n/strings.h"
|
||||
#include "app/tools/ink_type.h"
|
||||
#include "app/ui/context_bar.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -72,7 +71,7 @@ std::string SetInkTypeCommand::onGetFriendlyName() const
|
|||
ink = Strings::inks_shading();
|
||||
break;
|
||||
}
|
||||
return fmt::format(getBaseFriendlyName(), ink);
|
||||
return Strings::commands_SetInkType(ink);
|
||||
}
|
||||
|
||||
Command* CommandFactory::createSetInkTypeCommand()
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "doc/sprite.h"
|
||||
#include "doc/tilesets.h"
|
||||
#include "doc/user_data.h"
|
||||
#include "fmt/format.h"
|
||||
#include "os/color_space.h"
|
||||
#include "os/system.h"
|
||||
#include "ui/ui.h"
|
||||
|
@ -100,7 +99,7 @@ private:
|
|||
auto sprite = tileset->sprite();
|
||||
auto tilesetClone = Tileset::MakeCopyCopyingImages(tileset);
|
||||
|
||||
Tx tx(sprite, fmt::format(Strings::commands_TilesetDuplicate()));
|
||||
Tx tx(sprite, Strings::commands_TilesetDuplicate());
|
||||
tx(new cmd::AddTileset(sprite, tilesetClone));
|
||||
tx.commit();
|
||||
|
||||
|
@ -119,12 +118,12 @@ private:
|
|||
}
|
||||
if (!tilemapsNames.empty()) {
|
||||
tilemapsNames = tilemapsNames.substr(0, tilemapsNames.size()-2);
|
||||
ui::Alert::show(fmt::format(Strings::alerts_cannot_delete_used_tileset(), tilemapsNames));
|
||||
ui::Alert::show(Strings::alerts_cannot_delete_used_tileset(tilemapsNames));
|
||||
return;
|
||||
}
|
||||
|
||||
auto sprite = tileset->sprite();
|
||||
Tx tx(sprite, fmt::format(Strings::commands_TilesetDelete()));
|
||||
Tx tx(sprite, Strings::commands_TilesetDelete());
|
||||
tx(new cmd::RemoveTileset(sprite, tsi));
|
||||
tx.commit();
|
||||
|
||||
|
@ -277,8 +276,8 @@ void SpritePropertiesCommand::onExecute(Context* context)
|
|||
imgtype_text = Strings::sprite_properties_grayscale();
|
||||
break;
|
||||
case IMAGE_INDEXED:
|
||||
imgtype_text = fmt::format(Strings::sprite_properties_indexed_color(),
|
||||
sprite->palette(0)->size());
|
||||
imgtype_text = Strings::sprite_properties_indexed_color(
|
||||
sprite->palette(0)->size());
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2021-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2021-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -16,7 +16,6 @@
|
|||
#include "app/pref/preferences.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "fmt/format.h"
|
||||
#include "render/zoom.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/system.h"
|
||||
|
@ -130,8 +129,7 @@ std::string ZoomCommand::onGetFriendlyName() const
|
|||
text = Strings::commands_Zoom_Out();
|
||||
break;
|
||||
case Action::Set:
|
||||
text = fmt::format(Strings::commands_Zoom_Set(),
|
||||
int(100.0*m_zoom.scale()));
|
||||
text = Strings::commands_Zoom_Set(int(100.0*m_zoom.scale()));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -20,18 +20,12 @@ Command::Command(const char* id, CommandFlags flags)
|
|||
: m_id(id)
|
||||
, m_flags(flags)
|
||||
{
|
||||
generateFriendlyName();
|
||||
}
|
||||
|
||||
Command::~Command()
|
||||
{
|
||||
}
|
||||
|
||||
std::string Command::friendlyName() const
|
||||
{
|
||||
return onGetFriendlyName();
|
||||
}
|
||||
|
||||
bool Command::needsParams() const
|
||||
{
|
||||
return onNeedsParams();
|
||||
|
@ -64,15 +58,6 @@ bool Command::isChecked(Context* context)
|
|||
}
|
||||
}
|
||||
|
||||
void Command::generateFriendlyName()
|
||||
{
|
||||
std::string strId = "commands." + this->id();
|
||||
if (auto s = Strings::instance())
|
||||
m_friendlyName = s->translate(strId.c_str());
|
||||
else
|
||||
m_friendlyName = strId;
|
||||
}
|
||||
|
||||
void Command::execute(Context* context)
|
||||
{
|
||||
onExecute(context);
|
||||
|
@ -110,7 +95,9 @@ void Command::onExecute(Context* context)
|
|||
|
||||
std::string Command::onGetFriendlyName() const
|
||||
{
|
||||
return m_friendlyName;
|
||||
if (auto* strings = Strings::instance())
|
||||
return strings->translate(("commands." + id()).c_str());
|
||||
return id();
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -29,13 +30,12 @@ namespace app {
|
|||
virtual ~Command();
|
||||
|
||||
const std::string& id() const { return m_id; }
|
||||
std::string friendlyName() const;
|
||||
std::string friendlyName() const { return onGetFriendlyName(); }
|
||||
|
||||
bool needsParams() const;
|
||||
void loadParams(const Params& params);
|
||||
bool isEnabled(Context* context);
|
||||
bool isChecked(Context* context);
|
||||
void generateFriendlyName();
|
||||
|
||||
protected:
|
||||
virtual bool onNeedsParams() const;
|
||||
|
@ -45,16 +45,11 @@ namespace app {
|
|||
virtual void onExecute(Context* context);
|
||||
virtual std::string onGetFriendlyName() const;
|
||||
|
||||
const std::string& getBaseFriendlyName() const {
|
||||
return m_friendlyName;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Context;
|
||||
void execute(Context* context);
|
||||
|
||||
std::string m_id;
|
||||
std::string m_friendlyName;
|
||||
CommandFlags m_flags;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2021-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2021-2024 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -303,7 +303,7 @@ std::string ConvertLayerCommand::onGetFriendlyName() const
|
|||
case ConvertLayerParam::Background: return Strings::commands_ConvertLayer_Background(); break;
|
||||
case ConvertLayerParam::Layer: return Strings::commands_ConvertLayer_Layer(); break;
|
||||
case ConvertLayerParam::Tilemap: return Strings::commands_ConvertLayer_Tilemap(); break;
|
||||
default: return getBaseFriendlyName();
|
||||
default: return Strings::commands_ConvertLayer();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -16,7 +16,6 @@
|
|||
#include "app/ui/doc_view.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -66,8 +65,7 @@ std::string MoveThing::getFriendlyString() const
|
|||
case Down: dir = Strings::commands_Move_Down(); break;
|
||||
}
|
||||
|
||||
return fmt::format(Strings::commands_Move_Thing(),
|
||||
quantity, dim, dir);
|
||||
return Strings::commands_Move_Thing(quantity, dim, dir);
|
||||
}
|
||||
|
||||
gfx::Point MoveThing::getDelta(Context* context) const
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (c) 2023 Igara Studio S.A.
|
||||
// Copyright (c) 2023-2024 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -9,9 +9,9 @@
|
|||
#endif
|
||||
|
||||
#include "app/commands/new_params.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "fmt/format.h"
|
||||
#include "app/ui_context.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -55,7 +55,7 @@ void SetPlaybackSpeedCommand::onExecute(Context* ctx)
|
|||
|
||||
std::string SetPlaybackSpeedCommand::onGetFriendlyName() const
|
||||
{
|
||||
return fmt::format(getBaseFriendlyName(), params().multiplier());
|
||||
return Strings::commands_SetPlaybackSpeed(params().multiplier());
|
||||
}
|
||||
|
||||
Command* CommandFactory::createSetPlaybackSpeedCommand()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2022-2024 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -13,7 +13,6 @@
|
|||
#include "app/commands/new_params.h"
|
||||
#include "app/context.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -55,7 +54,7 @@ std::string ShowMenuCommand::onGetFriendlyName() const
|
|||
name = menuitem->text();
|
||||
else
|
||||
name = params().menu();
|
||||
return fmt::format(Strings::commands_ShowMenu(), name);
|
||||
return Strings::commands_ShowMenu(name);
|
||||
}
|
||||
|
||||
MenuItem* ShowMenuCommand::findMenuItem() const
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -13,7 +13,6 @@
|
|||
#include "app/commands/params.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
|
@ -52,7 +51,7 @@ protected:
|
|||
case TilesetMode::Auto: mode = Strings::commands_TilesetMode_Auto(); break;
|
||||
case TilesetMode::Stack: mode = Strings::commands_TilesetMode_Stack(); break;
|
||||
}
|
||||
return fmt::format(getBaseFriendlyName(), mode);
|
||||
return Strings::commands_TilesetMode(mode);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
// Aseprite
|
||||
// Copyright (c) 2020 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_CRASH_DOC_FORMAT_H_INCLUDED
|
||||
#define APP_CRASH_DOC_FORMAT_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#define DOC_FORMAT_VERSION_0 0 // Old version
|
||||
#define DOC_FORMAT_VERSION_1 1 // New version with tilesets
|
||||
#define DOC_FORMAT_VERSION_2 2 // Version 2 adds custom properties to user data
|
||||
#define DOC_FORMAT_VERSION_LAST 2
|
||||
|
||||
#endif
|
|
@ -12,7 +12,6 @@
|
|||
#include "app/crash/read_document.h"
|
||||
|
||||
#include "app/console.h"
|
||||
#include "app/crash/doc_format.h"
|
||||
#include "app/crash/internals.h"
|
||||
#include "app/crash/log.h"
|
||||
#include "app/doc.h"
|
||||
|
@ -32,6 +31,7 @@
|
|||
#include "doc/layer_tilemap.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/palette_io.h"
|
||||
#include "doc/serial_format.h"
|
||||
#include "doc/slice.h"
|
||||
#include "doc/slice_io.h"
|
||||
#include "doc/sprite.h"
|
||||
|
@ -70,7 +70,7 @@ class Reader : public SubObjectsIO {
|
|||
public:
|
||||
Reader(const std::string& dir,
|
||||
base::task_token* t)
|
||||
: m_docFormatVer(DOC_FORMAT_VERSION_0)
|
||||
: m_serial(SerialFormat::Ver0)
|
||||
, m_sprite(nullptr)
|
||||
, m_dir(dir)
|
||||
, m_docId(0)
|
||||
|
@ -198,10 +198,11 @@ private:
|
|||
Doc* readDocument(std::ifstream& s) {
|
||||
ObjectId sprId = read32(s);
|
||||
std::string filename = read_string(s);
|
||||
m_docFormatVer = read16(s);
|
||||
if (s.eof()) m_docFormatVer = DOC_FORMAT_VERSION_0;
|
||||
m_serial = SerialFormat(read16(s));
|
||||
if (s.eof())
|
||||
m_serial = SerialFormat::Ver0;
|
||||
|
||||
RECO_TRACE("RECO: internal format version=%d\n", m_docFormatVer);
|
||||
RECO_TRACE("RECO: internal format version=%d\n", int(m_serial));
|
||||
|
||||
// Load DocumentInfo only
|
||||
if (m_loadInfo) {
|
||||
|
@ -268,7 +269,7 @@ private:
|
|||
}
|
||||
|
||||
// IDs of all tilesets
|
||||
if (m_docFormatVer >= DOC_FORMAT_VERSION_1) {
|
||||
if (m_serial >= SerialFormat::Ver1) {
|
||||
int ntilesets = read32(s);
|
||||
if (ntilesets > 0 && ntilesets < 0xffffff) {
|
||||
for (int i=0; i<ntilesets; ++i) {
|
||||
|
@ -399,7 +400,7 @@ private:
|
|||
|
||||
// Read Sprite User Data
|
||||
if (!s.eof()) {
|
||||
UserData userData = read_user_data(s, m_docFormatVer);
|
||||
UserData userData = read_user_data(s, m_serial);
|
||||
if (!userData.isEmpty())
|
||||
spr->setUserData(userData);
|
||||
}
|
||||
|
@ -497,7 +498,7 @@ private:
|
|||
}
|
||||
|
||||
if (lay) {
|
||||
UserData userData = read_user_data(s, m_docFormatVer);
|
||||
UserData userData = read_user_data(s, m_serial);
|
||||
lay->setUserData(userData);
|
||||
return lay.release();
|
||||
}
|
||||
|
@ -510,7 +511,7 @@ private:
|
|||
}
|
||||
|
||||
CelData* readCelData(std::ifstream& s) {
|
||||
return read_celdata(s, this, false, m_docFormatVer);
|
||||
return read_celdata(s, this, false, m_serial);
|
||||
}
|
||||
|
||||
Image* readImage(std::ifstream& s) {
|
||||
|
@ -522,19 +523,19 @@ private:
|
|||
}
|
||||
|
||||
Tileset* readTileset(std::ifstream& s) {
|
||||
uint32_t tilesetVer;
|
||||
Tileset* tileset = read_tileset(s, m_sprite, false, &tilesetVer, m_docFormatVer);
|
||||
if (tileset && tilesetVer < TILESET_VER1)
|
||||
TilesetSerialFormat tilesetVer = TilesetSerialFormat::Ver0;
|
||||
Tileset* tileset = read_tileset(s, m_sprite, false, &tilesetVer, m_serial);
|
||||
if (tileset && tilesetVer < TilesetSerialFormat::Ver1)
|
||||
m_updateOldTilemapWithTileset.insert(tileset->id());
|
||||
return tileset;
|
||||
}
|
||||
|
||||
Tag* readTag(std::ifstream& s) {
|
||||
return read_tag(s, false, m_docFormatVer);
|
||||
return read_tag(s, false, m_serial);
|
||||
}
|
||||
|
||||
Slice* readSlice(std::ifstream& s) {
|
||||
return read_slice(s, false, m_docFormatVer);
|
||||
return read_slice(s, false, m_serial);
|
||||
}
|
||||
|
||||
// Fix issues that the restoration process could produce.
|
||||
|
@ -586,7 +587,7 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
int m_docFormatVer;
|
||||
SerialFormat m_serial;
|
||||
Sprite* m_sprite; // Used to pass the sprite in LayerImage() ctor
|
||||
std::string m_dir;
|
||||
ObjectVersion m_docId;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "app/crash/write_document.h"
|
||||
|
||||
#include "app/crash/doc_format.h"
|
||||
#include "app/crash/internals.h"
|
||||
#include "app/crash/log.h"
|
||||
#include "app/doc.h"
|
||||
|
@ -31,6 +30,7 @@
|
|||
#include "doc/layer_tilemap.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/palette_io.h"
|
||||
#include "doc/serial_format.h"
|
||||
#include "doc/slice.h"
|
||||
#include "doc/slice_io.h"
|
||||
#include "doc/sprite.h"
|
||||
|
@ -152,7 +152,7 @@ private:
|
|||
bool writeDocumentFile(std::ofstream& s, Doc* doc) {
|
||||
write32(s, doc->sprite()->id());
|
||||
write_string(s, doc->filename());
|
||||
write16(s, DOC_FORMAT_VERSION_LAST);
|
||||
write16(s, uint16_t(doc::SerialFormat::LastVer));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1570,6 +1570,9 @@ void DocExporter::createDataFile(const Samples& samples,
|
|||
os << ", ";
|
||||
|
||||
os << "{ \"frame\": " << cel->frame();
|
||||
if (cel->opacity() != 255) {
|
||||
os << ", \"opacity\": " << cel->opacity();
|
||||
}
|
||||
if (cel->zIndex() != 0) {
|
||||
os << ", \"zIndex\": " << cel->zIndex();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -51,12 +51,14 @@
|
|||
|
||||
namespace app {
|
||||
|
||||
const char* Extension::kAsepriteDefaultThemeExtensionName = "aseprite-theme";
|
||||
const char* Extension::kAsepriteDefaultThemeId = "default";
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kPackageJson = "package.json";
|
||||
const char* kInfoJson = "__info.json";
|
||||
const char* kPrefLua = "__pref.lua";
|
||||
const char* kAsepriteDefaultThemeExtensionName = "aseprite-theme";
|
||||
|
||||
class ReadArchive {
|
||||
public:
|
||||
|
@ -283,6 +285,8 @@ void Extension::addTheme(const std::string& id,
|
|||
const std::string& path,
|
||||
const std::string& variant)
|
||||
{
|
||||
if (id == kAsepriteDefaultThemeId && !isDefaultTheme())
|
||||
return;
|
||||
m_themes[id] = ThemeInfo(path, variant);
|
||||
updateCategory(Category::Themes);
|
||||
}
|
||||
|
@ -1003,6 +1007,21 @@ ExtensionInfo Extensions::getCompressedExtensionInfo(const std::string& zipFn)
|
|||
std::string err;
|
||||
auto json = json11::Json::parse(out.str(), err);
|
||||
if (err.empty()) {
|
||||
if (json["contributes"].is_object()) {
|
||||
auto themes = json["contributes"]["themes"];
|
||||
if (json["name"].string_value() == Extension::kAsepriteDefaultThemeExtensionName)
|
||||
info.defaultTheme = true;
|
||||
else {
|
||||
if (themes.is_array()) {
|
||||
for (int i = 0; i < themes.array_items().size(); i++) {
|
||||
if (themes[i]["id"].string_value() == Extension::kAsepriteDefaultThemeId) {
|
||||
info.defaultTheme = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
info.name = json["name"].string_value();
|
||||
info.version = json["version"].string_value();
|
||||
info.dstPath = base::join_path(m_userExtensionsPath, info.name);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -34,6 +34,7 @@ namespace app {
|
|||
std::string version;
|
||||
std::string dstPath;
|
||||
std::string commonPath;
|
||||
bool defaultTheme = false;
|
||||
};
|
||||
|
||||
enum DeletePluginPref { kNo, kYes };
|
||||
|
@ -41,6 +42,8 @@ namespace app {
|
|||
class Extension {
|
||||
friend class Extensions;
|
||||
public:
|
||||
static const char* kAsepriteDefaultThemeExtensionName;
|
||||
static const char* kAsepriteDefaultThemeId;
|
||||
|
||||
enum class Category {
|
||||
None,
|
||||
|
@ -54,6 +57,8 @@ namespace app {
|
|||
Max
|
||||
};
|
||||
|
||||
bool isDefaultTheme() const;
|
||||
|
||||
class DitheringMatrixInfo {
|
||||
public:
|
||||
DitheringMatrixInfo();
|
||||
|
@ -150,7 +155,6 @@ namespace app {
|
|||
void uninstall(const DeletePluginPref delPref);
|
||||
void uninstallFiles(const std::string& path,
|
||||
const DeletePluginPref delPref);
|
||||
bool isDefaultTheme() const;
|
||||
void updateCategory(const Category newCategory);
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
void initScripts();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -704,8 +704,7 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
|||
// show the alert dialog.
|
||||
if (fatal) {
|
||||
ui::Alert::show(
|
||||
fmt::format(
|
||||
Strings::alerts_file_format_doesnt_support_error(),
|
||||
Strings::alerts_file_format_doesnt_support_error(
|
||||
format->name(),
|
||||
warnings));
|
||||
ret = 1;
|
||||
|
@ -714,8 +713,7 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
|||
ret = OptionalAlert::show(
|
||||
Preferences::instance().saveFile.showFileFormatDoesntSupportAlert,
|
||||
1, // Yes is the default option when the alert dialog is disabled
|
||||
fmt::format(
|
||||
Strings::alerts_file_format_doesnt_support_warning(),
|
||||
Strings::alerts_file_format_doesnt_support_warning(
|
||||
format->name(),
|
||||
warnings));
|
||||
}
|
||||
|
@ -785,8 +783,7 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context,
|
|||
OptionalAlert::show(
|
||||
Preferences::instance().saveFile.showExportAnimationInSequenceAlert,
|
||||
1,
|
||||
fmt::format(
|
||||
Strings::alerts_export_animation_in_sequence(),
|
||||
Strings::alerts_export_animation_in_sequence(
|
||||
int(fop->m_seq.filename_list.size()),
|
||||
base::get_file_name(fop->m_seq.filename_list[0]),
|
||||
base::get_file_name(fop->m_seq.filename_list[1]))) != 1) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "app/resource_finder.h"
|
||||
#include "app/xml_document.h"
|
||||
#include "app/xml_exception.h"
|
||||
#include "base/debug.h"
|
||||
#include "base/fs.h"
|
||||
#include "cfg/cfg.h"
|
||||
|
||||
|
@ -116,10 +117,49 @@ void Strings::setCurrentLanguage(const std::string& langId)
|
|||
LanguageChange();
|
||||
}
|
||||
|
||||
void Strings::logError(const char* id, const char* error) const
|
||||
{
|
||||
LOG(ERROR, "I18N: Error in \"%s.ini\" file, string id \"%s\" is \"%s\", threw \"%s\" error\n",
|
||||
currentLanguage().c_str(), id, translate(id).c_str(), error);
|
||||
}
|
||||
|
||||
// static
|
||||
std::string Strings::VFormat(const char* id, const fmt::format_args& vargs)
|
||||
{
|
||||
Strings* s = Strings::instance();
|
||||
|
||||
// First we try to translate the ID string with the current
|
||||
// translation. If it fails (e.g. a fmt::format_error) it can be
|
||||
// because an ill-formed string for the fmt library.
|
||||
//
|
||||
// In that case then we try to use the regular English string from
|
||||
// the en.ini (which can fail too if the user modified the en.ini
|
||||
// file by hand).
|
||||
try {
|
||||
return fmt::vformat(s->translate(id), vargs);
|
||||
}
|
||||
catch (const std::runtime_error& e) {
|
||||
s->logError(id, e.what());
|
||||
// Continue with default translation (English)...
|
||||
}
|
||||
|
||||
try {
|
||||
return fmt::vformat(s->defaultString(id), vargs);
|
||||
}
|
||||
catch (const std::runtime_error& e) {
|
||||
// This is unexpected, invalid en.ini file
|
||||
ASSERT(false);
|
||||
s->logError(id, e.what());
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
void Strings::loadLanguage(const std::string& langId)
|
||||
{
|
||||
m_strings.clear();
|
||||
loadStringsFromDataDir(kDefLanguage);
|
||||
m_default = m_strings;
|
||||
|
||||
if (langId != kDefLanguage) {
|
||||
loadStringsFromDataDir(langId);
|
||||
loadStringsFromExtension(langId);
|
||||
|
@ -201,8 +241,15 @@ const std::string& Strings::translate(const char* id) const
|
|||
auto it = m_strings.find(id);
|
||||
if (it != m_strings.end())
|
||||
return it->second;
|
||||
else
|
||||
return m_strings[id] = id;
|
||||
return m_strings[id] = id;
|
||||
}
|
||||
|
||||
const std::string& Strings::defaultString(const char* id) const
|
||||
{
|
||||
auto it = m_default.find(id);
|
||||
if (it != m_default.end())
|
||||
return it->second;
|
||||
return m_default[id] = id;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "app/i18n/lang_info.h"
|
||||
#include "fmt/core.h"
|
||||
#include "obs/signal.h"
|
||||
#include "strings.ini.h"
|
||||
|
||||
|
@ -32,11 +33,30 @@ namespace app {
|
|||
static Strings* instance();
|
||||
|
||||
const std::string& translate(const char* id) const;
|
||||
const std::string& defaultString(const char* id) const;
|
||||
|
||||
std::set<LangInfo> availableLanguages() const;
|
||||
std::string currentLanguage() const;
|
||||
void setCurrentLanguage(const std::string& langId);
|
||||
|
||||
void logError(const char* id, const char* error) const;
|
||||
|
||||
static const std::string& Translate(const char* id) {
|
||||
Strings* s = Strings::instance();
|
||||
return s->translate(id);
|
||||
}
|
||||
|
||||
// Formats a string with the given arguments, if it fails
|
||||
// (e.g. because the translation contains an invalid formatted
|
||||
// string) it tries to return the original string from the default
|
||||
// en.ini file.
|
||||
template<typename...Args>
|
||||
static std::string Format(const char* id, Args&&...args) {
|
||||
return VFormat(id, fmt::make_format_args(args...));
|
||||
}
|
||||
|
||||
static std::string VFormat(const char* id, const fmt::format_args& vargs);
|
||||
|
||||
obs::signal<void()> LanguageChange;
|
||||
|
||||
private:
|
||||
|
@ -50,7 +70,8 @@ namespace app {
|
|||
|
||||
Preferences& m_pref;
|
||||
Extensions& m_exts;
|
||||
mutable std::unordered_map<std::string, std::string> m_strings;
|
||||
mutable std::unordered_map<std::string, std::string> m_default; // Default strings from en.ini
|
||||
mutable std::unordered_map<std::string, std::string> m_strings; // Strings from current language
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -26,9 +26,9 @@ std::string XmlTranslator::operator()(const XMLElement* elem,
|
|||
return std::string();
|
||||
else if (value[0] == '@') { // Translate string
|
||||
if (value[1] == '.')
|
||||
return Strings::instance()->translate((m_stringIdPrefix + (value+1)).c_str());
|
||||
return Strings::Translate((m_stringIdPrefix + (value+1)).c_str());
|
||||
else
|
||||
return Strings::instance()->translate(value+1);
|
||||
return Strings::Translate(value+1);
|
||||
}
|
||||
else if (value[0] == '!') // Raw string
|
||||
return std::string(value+1);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "app/console.h"
|
||||
#include "app/context.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/widget.h"
|
||||
#include "ui/window.h"
|
||||
|
@ -41,8 +40,7 @@ Job::Job(const std::string& jobName,
|
|||
m_canceled_flag = false;
|
||||
|
||||
if (showProgress && App::instance()->isGui()) {
|
||||
m_alert_window = ui::Alert::create(
|
||||
fmt::format(Strings::alerts_job_working(), jobName));
|
||||
m_alert_window = ui::Alert::create(Strings::alerts_job_working(jobName));
|
||||
m_alert_window->addProgress();
|
||||
|
||||
m_timer = std::make_unique<ui::Timer>(kMonitoringPeriod, m_alert_window.get());
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2001-2015, 2017 David Capello
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
@ -13,7 +14,6 @@
|
|||
#include "app/i18n/strings.h"
|
||||
#include "base/exception.h"
|
||||
#include "base/launcher.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -27,13 +27,13 @@ void open_url(const std::string& url)
|
|||
void open_file(const std::string& file)
|
||||
{
|
||||
if (!base::launcher::open_file(file))
|
||||
ui::Alert::show(fmt::format(Strings::alerts_cannot_open_file(), file));
|
||||
ui::Alert::show(Strings::alerts_cannot_open_file(file));
|
||||
}
|
||||
|
||||
void open_folder(const std::string& file)
|
||||
{
|
||||
if (!base::launcher::open_folder(file))
|
||||
ui::Alert::show(fmt::format(Strings::alerts_cannot_open_folder(), file));
|
||||
ui::Alert::show(Strings::alerts_cannot_open_folder(file));
|
||||
}
|
||||
|
||||
} // namespace launcher
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -18,12 +19,12 @@ namespace app {
|
|||
|
||||
class MatchWords {
|
||||
public:
|
||||
MatchWords(const std::string& search) {
|
||||
MatchWords(const std::string& search = {}) {
|
||||
base::split_string(base::string_to_lower(search),
|
||||
m_parts, " ");
|
||||
}
|
||||
|
||||
bool operator()(const std::string& item) {
|
||||
bool operator()(const std::string& item) const {
|
||||
std::string lowerItem = base::string_to_lower(item);
|
||||
std::size_t matches = 0;
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include "app/modules/gui.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "fmt/format.h"
|
||||
#include "gfx/color.h"
|
||||
#include "os/surface.h"
|
||||
#include "ui/box.h"
|
||||
|
|
|
@ -45,11 +45,11 @@
|
|||
#include "app/ui/expr_entry.h"
|
||||
#include "app/ui/icon_button.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui/layer_frame_comboboxes.h"
|
||||
#include "app/ui/sampling_selector.h"
|
||||
#include "app/ui/selection_mode_field.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/pi.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/brush.h"
|
||||
|
@ -1436,30 +1436,24 @@ protected:
|
|||
class ContextBar::EyedropperField : public HBox {
|
||||
public:
|
||||
EyedropperField() {
|
||||
const auto combined = Strings::context_bar_eyedropper_combined();
|
||||
m_channel.addItem(fmt::format(
|
||||
combined,
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_combined(
|
||||
Strings::context_bar_eyedropper_color(),
|
||||
Strings::context_bar_eyedropper_alpha()));
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_color());
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_alpha());
|
||||
m_channel.addItem(fmt::format(
|
||||
combined,
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_combined(
|
||||
Strings::context_bar_eyedropper_rgb(),
|
||||
Strings::context_bar_eyedropper_alpha()));
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_rgb());
|
||||
m_channel.addItem(fmt::format(
|
||||
combined,
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_combined(
|
||||
Strings::context_bar_eyedropper_hsv(),
|
||||
Strings::context_bar_eyedropper_alpha()));
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_hsv());
|
||||
m_channel.addItem(fmt::format(
|
||||
combined,
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_combined(
|
||||
Strings::context_bar_eyedropper_hsl(),
|
||||
Strings::context_bar_eyedropper_alpha()));
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_hsl());
|
||||
m_channel.addItem(fmt::format(
|
||||
combined,
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_combined(
|
||||
Strings::context_bar_eyedropper_gray(),
|
||||
Strings::context_bar_eyedropper_alpha()));
|
||||
m_channel.addItem(Strings::context_bar_eyedropper_gray());
|
||||
|
@ -1744,19 +1738,8 @@ private:
|
|||
void fillSlices() {
|
||||
m_combobox.deleteAllItems();
|
||||
if (m_doc && m_doc->sprite()) {
|
||||
MatchWords match(m_filter);
|
||||
|
||||
std::vector<doc::Slice*> slices;
|
||||
for (auto slice : m_doc->sprite()->slices()) {
|
||||
if (match(slice->name()))
|
||||
slices.push_back(slice);
|
||||
}
|
||||
std::sort(slices.begin(), slices.end(),
|
||||
[](const doc::Slice* a, const doc::Slice* b){
|
||||
return (base::compare_filenames(a->name(), b->name()) < 0);
|
||||
});
|
||||
|
||||
for (auto slice : slices) {
|
||||
for (auto* slice : sort_slices_by_name(m_doc->sprite()->slices(),
|
||||
MatchWords(m_filter))) {
|
||||
Item* item = new Item(slice);
|
||||
m_combobox.addItem(item);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -30,7 +30,6 @@
|
|||
#include "app/ui/workspace.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/fs.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/alert.h"
|
||||
#include "ui/button.h"
|
||||
#include "ui/entry.h"
|
||||
|
@ -346,9 +345,7 @@ void DataRecoveryView::fillListWith(const bool crashes)
|
|||
|
||||
std::string title = session->name();
|
||||
if (session->version() != get_app_version())
|
||||
title =
|
||||
fmt::format(Strings::recover_files_incompatible(),
|
||||
title, session->version());
|
||||
title = Strings::recover_files_incompatible(title, session->version());
|
||||
|
||||
auto sep = new SeparatorInView(title, HORIZONTAL);
|
||||
sep->InitTheme.connect(
|
||||
|
@ -492,8 +489,7 @@ void DataRecoveryView::onDelete()
|
|||
return;
|
||||
|
||||
// Delete one backup
|
||||
if (Alert::show(
|
||||
fmt::format(Strings::alerts_delete_selected_backups(),
|
||||
if (Alert::show(Strings::alerts_delete_selected_backups(
|
||||
int(items.size()))) != 1)
|
||||
return; // Cancel
|
||||
|
||||
|
@ -531,11 +527,11 @@ void DataRecoveryView::onChangeSelection()
|
|||
m_openButton.setEnabled(count > 0);
|
||||
if (count < 2) {
|
||||
m_openButton.mainButton()->setText(
|
||||
fmt::format(Strings::recover_files_recover_sprite(), count));
|
||||
Strings::recover_files_recover_sprite());
|
||||
}
|
||||
else {
|
||||
m_openButton.mainButton()->setText(
|
||||
fmt::format(Strings::recover_files_recover_n_sprites(), count));
|
||||
Strings::recover_files_recover_n_sprites(count));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -317,8 +317,7 @@ bool DocView::onCloseView(Workspace* workspace, bool quitting)
|
|||
while (m_document->isModified()) {
|
||||
// ask what want to do the user with the changes in the sprite
|
||||
int ret = Alert::show(
|
||||
fmt::format(
|
||||
Strings::alerts_save_sprite_changes(),
|
||||
Strings::alerts_save_sprite_changes(
|
||||
m_document->name(),
|
||||
(quitting ? Strings::alerts_save_sprite_changes_quitting():
|
||||
Strings::alerts_save_sprite_changes_closing())));
|
||||
|
|
|
@ -755,8 +755,11 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
|
|||
}
|
||||
|
||||
if (rendered && rendered->nativeHandle()) {
|
||||
os::Paint p;
|
||||
if (newEngine) {
|
||||
os::Sampling sampling;
|
||||
p.srcEdges(os::Paint::SrcEdges::Fast); // Enable mipmaps if possible
|
||||
|
||||
if (m_proj.scaleX() < 1.0) {
|
||||
switch (pref.editor.downsampling()) {
|
||||
case gen::Downsampling::NEAREST:
|
||||
|
@ -776,7 +779,6 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
|
|||
}
|
||||
}
|
||||
|
||||
os::Paint p;
|
||||
if (renderProperties.requiresRgbaBackbuffer)
|
||||
p.blendMode(os::BlendMode::SrcOver);
|
||||
else
|
||||
|
@ -789,7 +791,11 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
|
|||
&p);
|
||||
}
|
||||
else {
|
||||
g->blit(rendered.get(), 0, 0, dest.x, dest.y, dest.w, dest.h);
|
||||
g->drawSurface(rendered.get(),
|
||||
gfx::Rect(0, 0, dest.w, dest.h),
|
||||
gfx::Rect(dest.x, dest.y, dest.w, dest.h),
|
||||
os::Sampling(os::Sampling::Filter::Nearest),
|
||||
&p);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -187,13 +187,11 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
|
|||
}
|
||||
else if (!layer->isVisibleHierarchy()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000,
|
||||
fmt::format(Strings::statusbar_tips_layer_x_is_hidden(),
|
||||
layer->name()));
|
||||
1000, Strings::statusbar_tips_layer_x_is_hidden(layer->name()));
|
||||
}
|
||||
else if (!layer->isMovable() || !layer->isEditableHierarchy()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000, fmt::format(Strings::statusbar_tips_layer_locked(), layer->name()));
|
||||
1000, Strings::statusbar_tips_layer_locked(layer->name()));
|
||||
}
|
||||
else {
|
||||
MovingCelCollect collect(editor, layer);
|
||||
|
@ -698,7 +696,7 @@ bool StandbyState::checkStartDrawingStraightLine(Editor* editor,
|
|||
if (drawingState) {
|
||||
// Disable stabilizer so that it does not affect the line preview
|
||||
drawingState->disableMouseStabilizer();
|
||||
|
||||
|
||||
drawingState->sendMovementToToolLoop(
|
||||
tools::Pointer(
|
||||
pointer ? pointer->point(): editor->screenToEditor(editor->mousePosInDisplay()),
|
||||
|
@ -760,9 +758,7 @@ void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleT
|
|||
Layer* layer = editor->layer();
|
||||
if (layer && layer->isReference()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000,
|
||||
fmt::format(Strings::statusbar_tips_non_transformable_reference_layer(),
|
||||
layer->name()));
|
||||
1000, Strings::statusbar_tips_non_transformable_reference_layer(layer->name()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -869,9 +869,7 @@ tools::ToolLoop* create_tool_loop(
|
|||
if (toolPref.floodfill.referTo() ==
|
||||
app::gen::FillReferTo::ACTIVE_LAYER) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000,
|
||||
fmt::format(Strings::statusbar_tips_layer_x_is_hidden(),
|
||||
layer->name()));
|
||||
1000, Strings::statusbar_tips_layer_x_is_hidden(layer->name()));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -883,8 +881,7 @@ tools::ToolLoop* create_tool_loop(
|
|||
else if (layer->isReference()) {
|
||||
StatusBar::instance()->showTip(
|
||||
1000,
|
||||
fmt::format(Strings::statusbar_tips_unmodifiable_reference_layer(),
|
||||
layer->name()));
|
||||
Strings::statusbar_tips_unmodifiable_reference_layer(layer->name()));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -256,9 +256,10 @@ void ExportFileWindow::updateAdjustResizeButton()
|
|||
|
||||
if (adjustResize()->isVisible() != newState) {
|
||||
adjustResize()->setVisible(newState);
|
||||
if (newState)
|
||||
adjustResize()->setText(fmt::format(Strings::export_file_adjust_resize(),
|
||||
100 * m_preferredResize));
|
||||
if (newState) {
|
||||
adjustResize()->setText(
|
||||
Strings::export_file_adjust_resize(100 * m_preferredResize));
|
||||
}
|
||||
adjustResize()->parent()->layout();
|
||||
}
|
||||
}
|
||||
|
@ -286,7 +287,7 @@ void ExportFileWindow::onOK()
|
|||
}
|
||||
else {
|
||||
ui::Alert::show(
|
||||
fmt::format(Strings::alerts_unknown_output_file_format_error(), ext));
|
||||
Strings::alerts_unknown_output_file_format_error(ext));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "base/fs.h"
|
||||
#include "base/paths.h"
|
||||
#include "base/string.h"
|
||||
#include "fmt/format.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#include "new_folder_window.xml.h"
|
||||
|
@ -638,9 +637,8 @@ again:
|
|||
const char* invalid_chars = ": * ? \" < > |";
|
||||
|
||||
ui::Alert::show(
|
||||
fmt::format(
|
||||
Strings::alerts_invalid_chars_in_filename(),
|
||||
invalid_chars));
|
||||
Strings::alerts_invalid_chars_in_filename(
|
||||
invalid_chars));
|
||||
|
||||
// show the window again
|
||||
setVisible(true);
|
||||
|
@ -659,9 +657,7 @@ again:
|
|||
|
||||
if (m_type == FileSelectorType::Save && base::is_file(buf)) {
|
||||
int ret = Alert::show(
|
||||
fmt::format(
|
||||
Strings::alerts_overwrite_existent_file(),
|
||||
base::get_file_name(buf)));
|
||||
Strings::alerts_overwrite_existent_file(base::get_file_name(buf)));
|
||||
if (ret == 2) {
|
||||
setVisible(true);
|
||||
goto again;
|
||||
|
|
|
@ -303,8 +303,7 @@ void HomeView::onUpToDate()
|
|||
void HomeView::onNewUpdate(const std::string& url, const std::string& version)
|
||||
{
|
||||
checkUpdate()->setText(
|
||||
fmt::format(Strings::home_view_new_version_available(),
|
||||
get_app_name(), version));
|
||||
Strings::home_view_new_version_available(get_app_name(), version));
|
||||
#ifdef ENABLE_DRM
|
||||
DRM_INVALID {
|
||||
checkUpdate()->setUrl(url);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -13,17 +13,19 @@
|
|||
|
||||
#include "app/doc.h"
|
||||
#include "app/i18n/strings.h"
|
||||
#include "app/match_words.h"
|
||||
#include "app/restore_visible_layers.h"
|
||||
#include "app/site.h"
|
||||
#include "base/fs.h"
|
||||
#include "doc/anidir.h"
|
||||
#include "doc/frames_sequence.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/playback.h"
|
||||
#include "doc/selected_frames.h"
|
||||
#include "doc/selected_layers.h"
|
||||
#include "doc/slice.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "doc/tag.h"
|
||||
#include "doc/playback.h"
|
||||
#include "ui/combobox.h"
|
||||
|
||||
namespace app {
|
||||
|
@ -84,7 +86,8 @@ void fill_area_combobox(const doc::Sprite* sprite, ui::ComboBox* area, const std
|
|||
if (defArea == kSelectedCanvas)
|
||||
area->setSelectedItemIndex(i);
|
||||
|
||||
for (auto slice : sprite->slices()) {
|
||||
for (auto* slice : sort_slices_by_name(sprite->slices(),
|
||||
MatchWords())) {
|
||||
if (slice->name().empty())
|
||||
continue;
|
||||
|
||||
|
@ -313,4 +316,20 @@ doc::Tag* calculate_selected_frames(const Site& site,
|
|||
return tag;
|
||||
}
|
||||
|
||||
std::vector<doc::Slice*> sort_slices_by_name(const doc::Slices& slices,
|
||||
const MatchWords& match)
|
||||
{
|
||||
std::vector<doc::Slice*> result;
|
||||
for (auto* slice : slices) {
|
||||
if (match(slice->name()))
|
||||
result.push_back(slice);
|
||||
}
|
||||
std::sort(result.begin(),
|
||||
result.end(),
|
||||
[](const doc::Slice* a, const doc::Slice* b) {
|
||||
return (base::compare_filenames(a->name(), b->name()) < 0);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -13,6 +13,7 @@
|
|||
#include "ui/listitem.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace doc {
|
||||
class Layer;
|
||||
|
@ -20,6 +21,7 @@ namespace doc {
|
|||
class FramesSequence;
|
||||
class SelectedLayers;
|
||||
class Slice;
|
||||
class Slices;
|
||||
class Sprite;
|
||||
class Tag;
|
||||
}
|
||||
|
@ -29,6 +31,7 @@ namespace ui {
|
|||
}
|
||||
|
||||
namespace app {
|
||||
class MatchWords;
|
||||
class RestoreVisibleLayers;
|
||||
class Site;
|
||||
|
||||
|
@ -85,6 +88,9 @@ namespace app {
|
|||
const std::string& framesValue,
|
||||
doc::SelectedFrames& selFrames);
|
||||
|
||||
std::vector<doc::Slice*> sort_slices_by_name(const doc::Slices& slices,
|
||||
const MatchWords& match);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
||||
|
|
|
@ -217,15 +217,6 @@ MainWindow::~MainWindow()
|
|||
|
||||
void MainWindow::onLanguageChange()
|
||||
{
|
||||
auto commands = Commands::instance();
|
||||
std::vector<std::string> commandIDs;
|
||||
commands->getAllIds(commandIDs);
|
||||
|
||||
for (const auto& commandID : commandIDs) {
|
||||
Command* command = commands->byId(commandID.c_str());
|
||||
command->generateFriendlyName();
|
||||
}
|
||||
|
||||
m_menuBar->reload();
|
||||
layout();
|
||||
invalidate();
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/ui/mini_help_button.h"
|
||||
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
#include "base/launcher.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/system.h"
|
||||
#include "ver/info.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace app::skin;
|
||||
using namespace ui;
|
||||
|
||||
MiniHelpButton::MiniHelpButton(const std::string& link)
|
||||
: Button(std::string())
|
||||
, m_link(link)
|
||||
{
|
||||
setDecorative(true);
|
||||
initTheme();
|
||||
}
|
||||
|
||||
void MiniHelpButton::onInitTheme(InitThemeEvent& ev)
|
||||
{
|
||||
Button::onInitTheme(ev);
|
||||
|
||||
auto* theme = SkinTheme::get(this);
|
||||
setStyle(theme->styles.windowHelpButton());
|
||||
}
|
||||
|
||||
void MiniHelpButton::onClick()
|
||||
{
|
||||
Button::onClick();
|
||||
|
||||
std::string url;
|
||||
if (m_link.find("http") != std::string::npos) {
|
||||
url = m_link;
|
||||
}
|
||||
else {
|
||||
url = get_app_url();
|
||||
url += "docs/";
|
||||
url += m_link;
|
||||
}
|
||||
|
||||
base::launcher::open_url(url);
|
||||
}
|
||||
|
||||
void MiniHelpButton::onSetDecorativeWidgetBounds()
|
||||
{
|
||||
auto* theme = SkinTheme::get(this);
|
||||
Widget* window = parent();
|
||||
gfx::Rect rect(0, 0, 0, 0);
|
||||
const gfx::Size thisSize = this->sizeHint();
|
||||
const gfx::Size closeSize = theme->calcSizeHint(this, theme->styles.windowCloseButton());
|
||||
const gfx::Border margin(0, 0, 0, 0);
|
||||
|
||||
rect.w = thisSize.w;
|
||||
rect.h = thisSize.h;
|
||||
rect.offset(window->bounds().x2()
|
||||
- theme->styles.windowCloseButton()->margin().width() - closeSize.w
|
||||
- style()->margin().right() - thisSize.w,
|
||||
window->bounds().y + style()->margin().top());
|
||||
|
||||
setBounds(rect);
|
||||
}
|
||||
|
||||
} // namespace app
|
|
@ -0,0 +1,29 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UI_MINI_HELP_BUTTON_H_INCLUDED
|
||||
#define APP_UI_MINI_HELP_BUTTON_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "ui/button.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
class MiniHelpButton : public ui::Button {
|
||||
public:
|
||||
MiniHelpButton(const std::string& link);
|
||||
|
||||
private:
|
||||
void onInitTheme(ui::InitThemeEvent& ev) override;
|
||||
void onClick() override;
|
||||
void onSetDecorativeWidgetBounds() override;
|
||||
|
||||
std::string m_link;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
|
@ -10,6 +10,7 @@
|
|||
#endif
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/app_menus.h"
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/context_access.h"
|
||||
|
@ -694,13 +695,19 @@ StatusBar::StatusBar(TooltipManager* tooltipManager)
|
|||
|
||||
// Construct the commands box
|
||||
{
|
||||
auto theme = SkinTheme::get(this);
|
||||
Box* box1 = new Box(HORIZONTAL);
|
||||
Box* box4 = new Box(HORIZONTAL);
|
||||
|
||||
m_frameLabel = new Label(Strings::statusbar_tips_frame());
|
||||
m_currentFrame = new GotoFrameEntry();
|
||||
m_newFrame = new Button("+");
|
||||
m_newFrame->Click.connect([this]{ newFrame(); });
|
||||
m_newFrame = new Button("");
|
||||
if (!theme->parts.iconAdd())
|
||||
m_newFrame->setText("+"); // Fallback for themes without the icon.
|
||||
|
||||
m_newFrame->Click.connect(&StatusBar::newFrame, this);
|
||||
m_newFrame->RightClick.connect(&StatusBar::showNewFramePopupMenu, this);
|
||||
|
||||
m_zoomEntry = new ZoomEntry;
|
||||
m_zoomEntry->ZoomChange.connect(&StatusBar::onChangeZoom, this);
|
||||
|
||||
|
@ -922,7 +929,7 @@ void StatusBar::onInitTheme(ui::InitThemeEvent& ev)
|
|||
textHeight()+8*guiscale()));
|
||||
|
||||
m_newFrame->setStyle(theme->styles.newFrameButton());
|
||||
m_commandsBox->setBorder(gfx::Border(2, 1, 2, 2)*guiscale());
|
||||
m_commandsBox->setBorder(gfx::Border(2, 2, 2, 2)*guiscale());
|
||||
|
||||
if (m_snapToGridWindow) {
|
||||
m_snapToGridWindow->initTheme();
|
||||
|
@ -996,6 +1003,11 @@ void StatusBar::newFrame()
|
|||
UIContext::instance()->executeCommandFromMenuOrShortcut(cmd);
|
||||
}
|
||||
|
||||
void StatusBar::showNewFramePopupMenu()
|
||||
{
|
||||
AppMenus::instance()->getNewFrameMenu()->showPopup(mousePosInDisplay(), display());
|
||||
}
|
||||
|
||||
void StatusBar::onChangeZoom(const render::Zoom& zoom)
|
||||
{
|
||||
if (auto editor = Editor::activeEditor())
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace app {
|
|||
private:
|
||||
void onCelOpacitySliderChange();
|
||||
void newFrame();
|
||||
void showNewFramePopupMenu();
|
||||
void onChangeZoom(const render::Zoom& zoom);
|
||||
void updateSnapToGridWindowPosition();
|
||||
void showIndicators();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite
|
||||
// Copyright (C) 2018-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
|
@ -518,8 +518,7 @@ void ToolBar::openTipWindow(int group_index, Tool* tool)
|
|||
KeyPtr key = KeyboardShortcuts::instance()->tool(tool);
|
||||
if (key && !key->accels().empty()) {
|
||||
tooltip += "\n\n";
|
||||
tooltip += fmt::format(Strings::tools_shortcut(),
|
||||
key->accels().front().toString());
|
||||
tooltip += Strings::tools_shortcut(key->accels().front().toString());
|
||||
}
|
||||
}
|
||||
else if (group_index == PreviewVisibilityIndex) {
|
||||
|
|
|
@ -56,8 +56,7 @@ bool layer_is_locked(Editor* editor)
|
|||
#ifdef ENABLE_UI
|
||||
if (statusBar) {
|
||||
statusBar->showTip(
|
||||
1000, fmt::format(Strings::statusbar_tips_layer_x_is_hidden(),
|
||||
layer->name()));
|
||||
1000, Strings::statusbar_tips_layer_x_is_hidden(layer->name()));
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
|
@ -67,7 +66,7 @@ bool layer_is_locked(Editor* editor)
|
|||
#ifdef ENABLE_UI
|
||||
if (statusBar) {
|
||||
statusBar->showTip(
|
||||
1000, fmt::format(Strings::statusbar_tips_layer_locked(), layer->name()));
|
||||
1000, Strings::statusbar_tips_layer_locked(layer->name()));
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "doc/sprite.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
|
||||
namespace app {
|
||||
|
@ -33,8 +34,8 @@ doc::Image* resize_image(
|
|||
const RgbMap* rgbmap)
|
||||
{
|
||||
doc::ImageSpec spec = image->spec();
|
||||
spec.setWidth(std::max(1, int(scale.w*image->width())));
|
||||
spec.setHeight(std::max(1, int(scale.h*image->height())));
|
||||
spec.setWidth(std::max(1, int(std::round(scale.w*image->width()))));
|
||||
spec.setHeight(std::max(1, int(std::round(scale.h*image->height()))));
|
||||
std::unique_ptr<doc::Image> newImage(
|
||||
doc::Image::create(spec));
|
||||
newImage->setMaskColor(image->maskColor());
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue