mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-30 04:20:23 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
a6d9e5243f
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -24,9 +24,6 @@
|
||||
[submodule "third_party/libpng"]
|
||||
path = third_party/libpng
|
||||
url = https://github.com/aseprite/libpng.git
|
||||
[submodule "src/clip"]
|
||||
path = src/clip
|
||||
url = https://github.com/aseprite/clip.git
|
||||
[submodule "src/observable"]
|
||||
path = src/observable
|
||||
url = https://github.com/aseprite/observable.git
|
||||
|
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit 946fdf956b8a41a33337c9e1f0046bf4a4471b48
|
||||
Subproject commit f32d3918ddf6774b643f68f6525463cdacfb52ba
|
@ -95,12 +95,6 @@ set(OBSERVABLE_TESTS OFF CACHE BOOL "Compile observable tests")
|
||||
add_subdirectory(observable)
|
||||
include_directories(observable)
|
||||
|
||||
# Disable clip examples and tests
|
||||
set(CLIP_EXAMPLES OFF CACHE BOOL "Compile clip examples")
|
||||
set(CLIP_TESTS OFF CACHE BOOL "Compile clip tests")
|
||||
set(CLIP_X11_PNG_LIBRARY "${PNG_LIBRARY}")
|
||||
add_subdirectory(clip)
|
||||
|
||||
# Disable undo tests
|
||||
set(UNDO_TESTS OFF CACHE BOOL "Compile undo tests")
|
||||
add_subdirectory(undo)
|
||||
|
@ -101,23 +101,20 @@ add_definitions(-DLIBARCHIVE_STATIC)
|
||||
######################################################################
|
||||
# app-lib target
|
||||
|
||||
add_library(app-lib ${generated_files})
|
||||
|
||||
# These specific-platform files should be in an external library
|
||||
# (e.g. "base" or "os").
|
||||
set(app_platform_files)
|
||||
if(WIN32)
|
||||
set(app_platform_files
|
||||
font_path_win.cpp)
|
||||
target_sources(app-lib PRIVATE font_path_win.cpp)
|
||||
elseif(APPLE)
|
||||
set(app_platform_files
|
||||
font_path_osx.mm)
|
||||
target_sources(app-lib PRIVATE font_path_osx.mm)
|
||||
else()
|
||||
set(app_platform_files
|
||||
font_path_unix.cpp)
|
||||
target_sources(app-lib PRIVATE font_path_unix.cpp)
|
||||
endif()
|
||||
|
||||
set(data_recovery_files)
|
||||
if(ENABLE_DATA_RECOVERY)
|
||||
set(data_recovery_files
|
||||
target_sources(app-lib PRIVATE
|
||||
crash/backup_observer.cpp
|
||||
crash/data_recovery.cpp
|
||||
crash/read_document.cpp
|
||||
@ -126,7 +123,7 @@ if(ENABLE_DATA_RECOVERY)
|
||||
ui/data_recovery_view.cpp)
|
||||
endif()
|
||||
|
||||
set(file_formats
|
||||
target_sources(app-lib PRIVATE
|
||||
file/ase_format.cpp
|
||||
file/bmp_format.cpp
|
||||
file/css_format.cpp
|
||||
@ -140,27 +137,27 @@ set(file_formats
|
||||
file/svg_format.cpp
|
||||
file/tga_format.cpp)
|
||||
if(ENABLE_WEBP)
|
||||
list(APPEND file_formats file/webp_format.cpp)
|
||||
target_sources(app-lib PRIVATE
|
||||
file/webp_format.cpp)
|
||||
endif()
|
||||
if(ENABLE_PSD)
|
||||
list(APPEND file_formats file/psd_format.cpp)
|
||||
target_sources(app-lib PRIVATE
|
||||
file/psd_format.cpp)
|
||||
endif()
|
||||
|
||||
set(scripting_files)
|
||||
if(ENABLE_SCRIPTING)
|
||||
set(scripting_files_ui)
|
||||
if(ENABLE_UI)
|
||||
set(scripting_files_ui
|
||||
target_sources(app-lib PRIVATE
|
||||
commands/cmd_developer_console.cpp
|
||||
commands/cmd_open_script_folder.cpp
|
||||
commands/debugger.cpp
|
||||
ui/devconsole_view.cpp)
|
||||
endif()
|
||||
if(ENABLE_WEBSOCKET)
|
||||
set(scripting_files_ws
|
||||
target_sources(app-lib PRIVATE
|
||||
script/websocket_class.cpp)
|
||||
endif()
|
||||
set(scripting_files
|
||||
target_sources(app-lib PRIVATE
|
||||
commands/cmd_run_script.cpp
|
||||
script/app_command_object.cpp
|
||||
script/app_fs_object.cpp
|
||||
@ -219,14 +216,11 @@ if(ENABLE_SCRIPTING)
|
||||
script/values.cpp
|
||||
script/version_class.cpp
|
||||
script/window_class.cpp
|
||||
shell.cpp
|
||||
${scripting_files_ws}
|
||||
${scripting_files_ui})
|
||||
shell.cpp)
|
||||
endif()
|
||||
|
||||
set(ui_app_files)
|
||||
if(ENABLE_UI)
|
||||
set(ui_app_files
|
||||
target_sources(app-lib PRIVATE
|
||||
app_brushes.cpp
|
||||
app_menus.cpp
|
||||
closed_docs.cpp
|
||||
@ -436,34 +430,30 @@ if(ENABLE_UI)
|
||||
ui_context.cpp
|
||||
widget_loader.cpp)
|
||||
if(ENABLE_NEWS)
|
||||
set(ui_app_files
|
||||
target_sources(app-lib PRIVATE
|
||||
res/http_loader.cpp
|
||||
ui/news_listbox.cpp
|
||||
${ui_app_files})
|
||||
ui/news_listbox.cpp)
|
||||
endif()
|
||||
if(ENABLE_DRM)
|
||||
set(ui_app_files
|
||||
target_sources(app-lib PRIVATE
|
||||
ui/enter_license.cpp
|
||||
ui/aseprite_update.cpp
|
||||
${ui_app_files})
|
||||
ui/aseprite_update.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(send_crash_files)
|
||||
if(ENABLE_SENTRY)
|
||||
set(send_crash_files sentry_wrapper.cpp)
|
||||
target_sources(app-lib PRIVATE sentry_wrapper.cpp)
|
||||
else()
|
||||
set(send_crash_files send_crash.cpp)
|
||||
target_sources(app-lib PRIVATE send_crash.cpp)
|
||||
endif()
|
||||
|
||||
add_library(app-lib
|
||||
target_sources(app-lib PRIVATE
|
||||
active_site_handler.cpp
|
||||
app.cpp
|
||||
check_update.cpp
|
||||
cli/app_options.cpp
|
||||
cli/cli_open_file.cpp
|
||||
cli/cli_processor.cpp
|
||||
${file_formats}
|
||||
cli/default_cli_delegate.cpp
|
||||
cli/preview_cli_delegate.cpp
|
||||
cmd.cpp
|
||||
@ -704,13 +694,7 @@ add_library(app-lib
|
||||
util/tileset_utils.cpp
|
||||
util/wrap_point.cpp
|
||||
xml_document.cpp
|
||||
xml_exception.cpp
|
||||
${send_crash_files}
|
||||
${ui_app_files}
|
||||
${app_platform_files}
|
||||
${data_recovery_files}
|
||||
${scripting_files}
|
||||
${generated_files})
|
||||
xml_exception.cpp)
|
||||
|
||||
if(TARGET generated_version)
|
||||
add_dependencies(app-lib generated_version)
|
||||
|
@ -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
|
||||
@ -646,12 +646,12 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
||||
#endif // ENABLE_UI
|
||||
|
||||
// No conversion needed
|
||||
if (context->activeDocument()->sprite()->pixelFormat() == m_format)
|
||||
Doc* doc = context->activeDocument();
|
||||
if (doc->sprite()->pixelFormat() == m_format)
|
||||
return;
|
||||
|
||||
{
|
||||
const ContextReader reader(context);
|
||||
SpriteJob job(reader, Strings::color_mode_title().c_str());
|
||||
SpriteJob job(context, doc, Strings::color_mode_title());
|
||||
Sprite* sprite(job.sprite());
|
||||
|
||||
// TODO this was moved in the main UI thread because
|
||||
@ -662,16 +662,17 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
||||
// https://github.com/aseprite/aseprite/issues/509
|
||||
// https://github.com/aseprite/aseprite/issues/378
|
||||
if (flatten) {
|
||||
Tx tx(Tx::LockDoc, context, doc);
|
||||
const bool newBlend = Preferences::instance().experimental.newBlend();
|
||||
SelectedLayers selLayers;
|
||||
for (auto layer : sprite->root()->layers())
|
||||
selLayers.insert(layer);
|
||||
job.tx()(new cmd::FlattenLayers(sprite, selLayers, newBlend));
|
||||
tx(new cmd::FlattenLayers(sprite, selLayers, newBlend));
|
||||
}
|
||||
|
||||
job.startJobWithCallback(
|
||||
[this, &job, sprite] {
|
||||
job.tx()(
|
||||
[this, &job, sprite](Tx& tx) {
|
||||
tx(
|
||||
new cmd::SetPixelFormat(
|
||||
sprite, m_format,
|
||||
m_dithering,
|
||||
|
@ -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
|
||||
@ -177,45 +177,46 @@ void ColorQuantizationCommand::onExecute(Context* ctx)
|
||||
return;
|
||||
|
||||
try {
|
||||
ContextReader reader(ctx);
|
||||
Doc* doc = site.document();
|
||||
Sprite* sprite = site.sprite();
|
||||
frame_t frame = site.frame();
|
||||
const Palette* curPalette = site.sprite()->palette(frame);
|
||||
Palette tmpPalette(frame, entries.picks());
|
||||
|
||||
SpriteJob job(reader, "Color Quantization");
|
||||
SpriteJob job(ctx, doc, "Color Quantization");
|
||||
const bool newBlend = pref.experimental.newBlend();
|
||||
job.startJobWithCallback(
|
||||
[sprite, withAlpha, &tmpPalette, &job, newBlend, algorithm]{
|
||||
[sprite, withAlpha, curPalette, &tmpPalette, &job, &entries,
|
||||
newBlend, algorithm, createPal, site, frame](Tx& tx) {
|
||||
render::create_palette_from_sprite(
|
||||
sprite, 0, sprite->lastFrame(),
|
||||
withAlpha, &tmpPalette,
|
||||
&job, // SpriteJob is a render::TaskDelegate
|
||||
newBlend,
|
||||
algorithm);
|
||||
|
||||
std::unique_ptr<Palette> newPalette(
|
||||
new Palette(createPal ? tmpPalette:
|
||||
*site.palette()));
|
||||
|
||||
if (createPal) {
|
||||
entries = PalettePicks(newPalette->size());
|
||||
entries.all();
|
||||
}
|
||||
|
||||
int i = 0, j = 0;
|
||||
for (bool state : entries) {
|
||||
if (state)
|
||||
newPalette->setEntry(i, tmpPalette.getEntry(j++));
|
||||
++i;
|
||||
}
|
||||
|
||||
if (*curPalette != *newPalette)
|
||||
tx(new cmd::SetPalette(sprite, frame, newPalette.get()));
|
||||
});
|
||||
job.waitJob();
|
||||
if (job.isCanceled())
|
||||
return;
|
||||
|
||||
std::unique_ptr<Palette> newPalette(
|
||||
new Palette(createPal ? tmpPalette:
|
||||
*site.palette()));
|
||||
|
||||
if (createPal) {
|
||||
entries = PalettePicks(newPalette->size());
|
||||
entries.all();
|
||||
}
|
||||
|
||||
int i = 0, j = 0;
|
||||
for (bool state : entries) {
|
||||
if (state)
|
||||
newPalette->setEntry(i, tmpPalette.getEntry(j++));
|
||||
++i;
|
||||
}
|
||||
|
||||
if (*curPalette != *newPalette)
|
||||
job.tx()(new cmd::SetPalette(sprite, frame, newPalette.get()));
|
||||
}
|
||||
catch (const base::Exception& e) {
|
||||
Console::showException(e);
|
||||
|
@ -1316,9 +1316,20 @@ private:
|
||||
if (language()->getItemCount() > 0)
|
||||
return;
|
||||
|
||||
// Select current language by lang ID
|
||||
// Check if the current language exists, in other case select English.
|
||||
Strings* strings = Strings::instance();
|
||||
std::string curLang = strings->currentLanguage();
|
||||
bool found = false;
|
||||
for (const LangInfo& lang : strings->availableLanguages()) {
|
||||
if (lang.id == curLang) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
curLang = Strings::kDefLanguage;
|
||||
|
||||
// Select current language by lang ID
|
||||
for (const LangInfo& lang : strings->availableLanguages()) {
|
||||
int i = language()->addItem(new LangItem(lang));
|
||||
if (lang.id == curLang)
|
||||
|
@ -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
|
||||
@ -13,7 +13,6 @@
|
||||
#include "app/cmd/set_cel_bounds.h"
|
||||
#include "app/commands/cmd_rotate.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/context_access.h"
|
||||
#include "app/doc_api.h"
|
||||
#include "app/doc_range.h"
|
||||
#include "app/i18n/strings.h"
|
||||
@ -45,10 +44,10 @@ class RotateJob : public SpriteJob {
|
||||
|
||||
public:
|
||||
|
||||
RotateJob(const ContextReader& reader,
|
||||
RotateJob(Context* ctx, Doc* doc,
|
||||
const std::string& jobName,
|
||||
int angle, const CelList& cels, bool rotateSprite)
|
||||
: SpriteJob(reader, jobName.c_str())
|
||||
: SpriteJob(ctx, doc, jobName)
|
||||
, m_cels(cels)
|
||||
, m_rotateSprite(rotateSprite) {
|
||||
m_angle = angle;
|
||||
@ -80,8 +79,8 @@ protected:
|
||||
}
|
||||
|
||||
// [working thread]
|
||||
void onJob() override {
|
||||
DocApi api = document()->getApi(tx());
|
||||
void onSpriteJob(Tx& tx) override {
|
||||
DocApi api = document()->getApi(tx);
|
||||
|
||||
// 1) Rotate cel positions
|
||||
for (Cel* cel : m_cels) {
|
||||
@ -93,7 +92,7 @@ protected:
|
||||
gfx::RectF bounds = cel->boundsF();
|
||||
rotate_rect(bounds);
|
||||
if (cel->boundsF() != bounds)
|
||||
tx()(new cmd::SetCelBoundsF(cel, bounds));
|
||||
tx(new cmd::SetCelBoundsF(cel, bounds));
|
||||
}
|
||||
else {
|
||||
gfx::Rect bounds = cel->bounds();
|
||||
@ -192,6 +191,7 @@ void RotateCommand::onExecute(Context* context)
|
||||
{
|
||||
{
|
||||
Site site = context->activeSite();
|
||||
Doc* doc = site.document();
|
||||
CelList cels;
|
||||
bool rotateSprite = false;
|
||||
|
||||
@ -203,7 +203,7 @@ void RotateCommand::onExecute(Context* context)
|
||||
// If we want to rotate the visible mask, we can go to
|
||||
// MovingPixelsState (even when the range is enabled, because
|
||||
// now PixelsMovement support ranges).
|
||||
if (site.document()->isMaskVisible()) {
|
||||
if (doc->isMaskVisible()) {
|
||||
// Select marquee tool
|
||||
if (tools::Tool* tool = App::instance()->toolBox()
|
||||
->getToolById(tools::WellKnownTools::RectangularMarquee)) {
|
||||
@ -237,13 +237,12 @@ void RotateCommand::onExecute(Context* context)
|
||||
rotateSprite = true;
|
||||
}
|
||||
|
||||
ContextReader reader(context);
|
||||
{
|
||||
RotateJob job(reader, friendlyName(), m_angle, cels, rotateSprite);
|
||||
RotateJob job(context, doc, friendlyName(), m_angle, cels, rotateSprite);
|
||||
job.startJob();
|
||||
job.waitJob();
|
||||
}
|
||||
update_screen_for_document(reader.document());
|
||||
update_screen_for_document(doc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -80,8 +80,11 @@ class SpriteSizeJob : public SpriteJob {
|
||||
|
||||
public:
|
||||
|
||||
SpriteSizeJob(const ContextReader& reader, int new_width, int new_height, ResizeMethod resize_method)
|
||||
: SpriteJob(reader, Strings::sprite_size_title().c_str()) {
|
||||
SpriteSizeJob(Context* ctx, Doc* doc,
|
||||
const int new_width,
|
||||
const int new_height,
|
||||
const ResizeMethod resize_method)
|
||||
: SpriteJob(ctx, doc, Strings::sprite_size_title()) {
|
||||
m_new_width = new_width;
|
||||
m_new_height = new_height;
|
||||
m_resize_method = resize_method;
|
||||
@ -90,8 +93,8 @@ public:
|
||||
protected:
|
||||
|
||||
// [working thread]
|
||||
void onJob() override {
|
||||
DocApi api = writer().document()->getApi(tx());
|
||||
void onSpriteJob(Tx& tx) override {
|
||||
DocApi api = document()->getApi(tx);
|
||||
Tilesets* tilesets = sprite()->tilesets();
|
||||
|
||||
int img_count = 0;
|
||||
@ -147,7 +150,7 @@ protected:
|
||||
++progress;
|
||||
++idx;
|
||||
}
|
||||
tx()(new cmd::ReplaceTileset(sprite(), tsi, newTileset));
|
||||
tx(new cmd::ReplaceTileset(sprite(), tsi, newTileset));
|
||||
|
||||
// Cancel all the operation?
|
||||
if (isCanceled())
|
||||
@ -170,11 +173,11 @@ protected:
|
||||
cel->y()*scale.h,
|
||||
canvasSize.w,
|
||||
canvasSize.h);
|
||||
tx()(new cmd::SetCelBoundsF(cel, newBounds));
|
||||
tx(new cmd::SetCelBoundsF(cel, newBounds));
|
||||
}
|
||||
else {
|
||||
resize_cel_image(
|
||||
tx(), cel, scale,
|
||||
tx, cel, scale,
|
||||
m_resize_method,
|
||||
cel->layer()->isReference() ?
|
||||
-cel->boundsF().origin():
|
||||
@ -239,7 +242,7 @@ protected:
|
||||
newKey.setPivot(gfx::Point(scale_x(newKey.pivot().x),
|
||||
scale_y(newKey.pivot().y)));
|
||||
|
||||
tx()(new cmd::SetSliceKey(slice, k.frame(), newKey));
|
||||
tx(new cmd::SetSliceKey(slice, k.frame(), newKey));
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,8 +376,9 @@ void SpriteSizeCommand::onExecute(Context* context)
|
||||
#ifdef ENABLE_UI
|
||||
const bool ui = (params().ui() && context->isUIAvailable());
|
||||
#endif
|
||||
const ContextReader reader(context);
|
||||
const Sprite* sprite(reader.sprite());
|
||||
const Site site = context->activeSite();
|
||||
Doc* doc = site.document();
|
||||
Sprite* sprite = site.sprite();
|
||||
auto& params = this->params();
|
||||
|
||||
double ratio = sprite->width() / double(sprite->height());
|
||||
@ -461,13 +465,13 @@ void SpriteSizeCommand::onExecute(Context* context)
|
||||
new_height = std::clamp(new_height, 1, DOC_SPRITE_MAX_HEIGHT);
|
||||
|
||||
{
|
||||
SpriteSizeJob job(reader, new_width, new_height, resize_method);
|
||||
SpriteSizeJob job(context, doc, new_width, new_height, resize_method);
|
||||
job.startJob();
|
||||
job.waitJob();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
update_screen_for_document(reader.document());
|
||||
update_screen_for_document(doc);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,8 @@
|
||||
namespace app {
|
||||
|
||||
static Strings* singleton = nullptr;
|
||||
static const char* kDefLanguage = "en";
|
||||
|
||||
const char* Strings::kDefLanguage = "en";
|
||||
|
||||
// static
|
||||
void Strings::createInstance(Preferences& pref,
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
// Copyright (C) 2023-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2016-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -25,6 +25,8 @@ namespace app {
|
||||
// Singleton class to load and access "strings/en.ini" file.
|
||||
class Strings : public app::gen::Strings<app::Strings> {
|
||||
public:
|
||||
static const char* kDefLanguage;
|
||||
|
||||
static void createInstance(Preferences& pref,
|
||||
Extensions& exts);
|
||||
static Strings* instance();
|
||||
|
@ -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
|
||||
@ -33,7 +33,7 @@ int Job::runningJobs()
|
||||
return g_runningJobs;
|
||||
}
|
||||
|
||||
Job::Job(const char* jobName)
|
||||
Job::Job(const std::string& jobName)
|
||||
{
|
||||
m_last_progress = 0.0;
|
||||
m_done_flag = false;
|
||||
|
@ -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
|
||||
@ -15,6 +15,7 @@
|
||||
#include <atomic>
|
||||
#include <exception>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace app {
|
||||
@ -23,7 +24,7 @@ namespace app {
|
||||
public:
|
||||
static int runningJobs();
|
||||
|
||||
Job(const char* jobName);
|
||||
Job(const std::string& jobName);
|
||||
virtual ~Job();
|
||||
|
||||
// Starts the job calling onJob() event in another thread and
|
||||
|
@ -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
|
||||
@ -10,26 +11,49 @@
|
||||
|
||||
#include "app/sprite_job.h"
|
||||
|
||||
#include "base/log.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
SpriteJob::SpriteJob(const ContextReader& reader, const char* jobName)
|
||||
SpriteJob::SpriteJob(Context* ctx, Doc* doc,
|
||||
const std::string& jobName)
|
||||
: Job(jobName)
|
||||
, m_writer(reader, 500)
|
||||
, m_document(m_writer.document())
|
||||
, m_sprite(m_writer.sprite())
|
||||
, m_tx(m_writer, jobName, ModifyDocument)
|
||||
, m_doc(doc)
|
||||
, m_sprite(doc->sprite())
|
||||
, m_tx(Tx::DontLockDoc, ctx, doc, jobName, ModifyDocument)
|
||||
, m_lockAction(Tx::LockDoc)
|
||||
{
|
||||
// Try to write-lock the document to see if we have to lock the
|
||||
// document in the background thread.
|
||||
auto lockResult = m_doc->writeLock(500);
|
||||
if (lockResult != Doc::LockResult::Fail) {
|
||||
if (lockResult == Doc::LockResult::Reentrant)
|
||||
m_lockAction = Tx::DontLockDoc;
|
||||
m_doc->unlock(lockResult);
|
||||
}
|
||||
}
|
||||
|
||||
SpriteJob::~SpriteJob()
|
||||
{
|
||||
if (!isCanceled())
|
||||
m_tx.commit();
|
||||
try {
|
||||
if (!isCanceled())
|
||||
m_tx.commit();
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
LOG(ERROR, "Error committing changes: %s\n", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteJob::onSpriteJob(Tx& tx)
|
||||
{
|
||||
if (m_callback)
|
||||
m_callback(tx);
|
||||
}
|
||||
|
||||
void SpriteJob::onJob()
|
||||
{
|
||||
m_callback();
|
||||
Tx subtx(m_lockAction, m_ctx, m_doc);
|
||||
onSpriteJob(subtx);
|
||||
}
|
||||
|
||||
bool SpriteJob::continueTask()
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2024 Igara Studio S.A.
|
||||
// Copyright (C) 2017-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -15,19 +16,32 @@
|
||||
#include "render/task_delegate.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
|
||||
class Context;
|
||||
|
||||
// Creates a Job to run a task in a background thread. At the same
|
||||
// time it creates a new Tx in the main thread (to group all sub-Txs)
|
||||
// without locking the sprite. You have to lock the sprite with a sub
|
||||
// Tx (the onSpriteJob(Tx) already has the sprite locked for write
|
||||
// access).
|
||||
//
|
||||
// This class takes care to lock the sprite in the background thread
|
||||
// for write access, or to avoid re-locking the sprite in case it's
|
||||
// already locked from the main thread (where SpriteJob was created,
|
||||
// generally true when we're running a script).
|
||||
class SpriteJob : public Job,
|
||||
public render::TaskDelegate {
|
||||
public:
|
||||
SpriteJob(const ContextReader& reader, const char* jobName);
|
||||
SpriteJob(Context* ctx, Doc* doc,
|
||||
const std::string& jobName);
|
||||
~SpriteJob();
|
||||
|
||||
ContextWriter& writer() { return m_writer; }
|
||||
Doc* document() const { return m_document; }
|
||||
Doc* document() const { return m_doc; }
|
||||
Sprite* sprite() const { return m_sprite; }
|
||||
Tx& tx() { return m_tx; }
|
||||
|
||||
template<typename T>
|
||||
void startJobWithCallback(T&& callback) {
|
||||
@ -36,6 +50,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void onSpriteJob(Tx& tx);
|
||||
|
||||
// Job impl
|
||||
void onJob() override;
|
||||
|
||||
@ -44,15 +60,21 @@ private:
|
||||
bool continueTask() override;
|
||||
void notifyTaskProgress(double progress) override;
|
||||
|
||||
ContextWriter m_writer;
|
||||
Doc* m_document;
|
||||
Context* m_ctx;
|
||||
Doc* m_doc;
|
||||
Sprite* m_sprite;
|
||||
Tx m_tx;
|
||||
|
||||
// What action to do with the sub-Tx inside the background thread.
|
||||
// This is required to check if the sprite is already locked for
|
||||
// write access in the main thread, in that case we don't need to
|
||||
// lock it again from the background thread.
|
||||
Tx::LockAction m_lockAction;
|
||||
|
||||
// Default implementation calls the given function in
|
||||
// startJob(). Anyway you can just extended the SpriteJob and
|
||||
// override onJob().
|
||||
std::function<void()> m_callback;
|
||||
std::function<void(Tx&)> m_callback;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
@ -1770,7 +1770,9 @@ private:
|
||||
}
|
||||
|
||||
void updateLayout() {
|
||||
const bool visible = (m_doc && !m_doc->sprite()->slices().empty());
|
||||
const bool visible = (m_doc &&
|
||||
m_doc->sprite() &&
|
||||
!m_doc->sprite()->slices().empty());
|
||||
const bool relayout = (visible != m_combobox.isVisible() ||
|
||||
visible != m_action.isVisible());
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -56,7 +56,17 @@ ExportFileWindow::ExportFileWindow(const Doc* doc)
|
||||
fill_layers_combobox(m_doc->sprite(), layers(), m_docPref.saveCopy.layer(), m_docPref.saveCopy.layerIndex());
|
||||
fill_frames_combobox(m_doc->sprite(), frames(), m_docPref.saveCopy.frameTag());
|
||||
fill_anidir_combobox(anidir(), m_docPref.saveCopy.aniDir());
|
||||
pixelRatio()->setSelected(m_docPref.saveCopy.applyPixelRatio());
|
||||
|
||||
if (doc->sprite()->hasPixelRatio()) {
|
||||
pixelRatio()->setSelected(m_docPref.saveCopy.applyPixelRatio());
|
||||
}
|
||||
else {
|
||||
// Hide "Apply pixel ratio" checkbox when there is no pixel aspect
|
||||
// ratio to apply.
|
||||
pixelRatio()->setSelected(false);
|
||||
pixelRatio()->setVisible(false);
|
||||
}
|
||||
|
||||
forTwitter()->setSelected(m_docPref.saveCopy.forTwitter());
|
||||
adjustResize()->setVisible(false);
|
||||
playSubtags()->setSelected(m_docPref.saveCopy.playSubtags());
|
||||
@ -218,7 +228,9 @@ void ExportFileWindow::updateAniDir()
|
||||
void ExportFileWindow::updatePlaySubtags()
|
||||
{
|
||||
std::string framesValue = this->framesValue();
|
||||
playSubtags()->setVisible(framesValue != kSelectedFrames);
|
||||
playSubtags()->setVisible(framesValue != kSelectedFrames &&
|
||||
// We hide the option if there is no tag
|
||||
!m_doc->sprite()->tags().empty());
|
||||
layout();
|
||||
}
|
||||
|
||||
|
@ -2093,7 +2093,10 @@ void Timeline::setCursor(ui::Message* msg, const Hit& hit)
|
||||
ui::set_mouse_cursor(kSizeECursor);
|
||||
}
|
||||
else if (hit.part == PART_RANGE_OUTLINE) {
|
||||
ui::set_mouse_cursor(kMoveCursor);
|
||||
if (is_copy_key_pressed(msg))
|
||||
ui::set_mouse_cursor(kArrowPlusCursor);
|
||||
else
|
||||
ui::set_mouse_cursor(kMoveCursor);
|
||||
}
|
||||
else if (hit.part == PART_SEPARATOR) {
|
||||
ui::set_mouse_cursor(kSizeWECursor);
|
||||
|
1
src/clip
1
src/clip
@ -1 +0,0 @@
|
||||
Subproject commit 835cd0f7e7a964bb969482117856bc56a0ac12bf
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -198,6 +198,11 @@ Sprite* Sprite::MakeStdTilemapSpriteWithTileset(const ImageSpec& spec,
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Main properties
|
||||
|
||||
bool Sprite::hasPixelRatio() const
|
||||
{
|
||||
return m_pixelRatio != PixelRatio(1, 1);
|
||||
}
|
||||
|
||||
void Sprite::setPixelFormat(PixelFormat format)
|
||||
{
|
||||
m_spec.setColorMode((ColorMode)format);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -93,6 +93,7 @@ namespace doc {
|
||||
PixelFormat pixelFormat() const { return (PixelFormat)m_spec.colorMode(); }
|
||||
ColorMode colorMode() const { return m_spec.colorMode(); }
|
||||
const PixelRatio& pixelRatio() const { return m_pixelRatio; }
|
||||
bool hasPixelRatio() const;
|
||||
gfx::Size size() const { return m_spec.size(); }
|
||||
gfx::Rect bounds() const { return m_spec.bounds(); }
|
||||
int width() const { return m_spec.width(); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user