diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 27d3a614a..640b463aa 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -404,7 +404,6 @@ add_library(app-lib pref/preferences.cpp project.cpp recent_files.cpp - render_task_job.cpp res/http_loader.cpp res/palettes_loader_delegate.cpp res/resources_loader.cpp @@ -414,7 +413,9 @@ add_library(app-lib send_crash.cpp shade.cpp snap_to_grid.cpp + sprite_job.cpp thumbnail_generator.cpp + thumbnails.cpp tools/active_tool.cpp tools/ink_type.cpp tools/intertwine.cpp @@ -508,7 +509,6 @@ add_library(app-lib ui/workspace_tabs.cpp ui/zoom_entry.cpp ui_context.cpp - thumbnails.cpp util/autocrop.cpp util/clipboard.cpp util/clipboard_native.cpp diff --git a/src/app/commands/cmd_change_pixel_format.cpp b/src/app/commands/cmd_change_pixel_format.cpp index 2009d4525..1c0621d51 100644 --- a/src/app/commands/cmd_change_pixel_format.cpp +++ b/src/app/commands/cmd_change_pixel_format.cpp @@ -19,7 +19,7 @@ #include "app/modules/editors.h" #include "app/modules/gui.h" #include "app/modules/palettes.h" -#include "app/render_task_job.h" +#include "app/sprite_job.h" #include "app/transaction.h" #include "app/ui/dithering_selector.h" #include "app/ui/editor/editor.h" @@ -462,23 +462,21 @@ void ChangePixelFormatCommand::onExecute(Context* context) return; { - RenderTaskJob job("Converting Color Mode"); - job.startJob( - [this, &job, context, flatten]{ - ContextWriter writer(context); - Transaction transaction(writer.context(), "Color Mode Change"); - Sprite* sprite(writer.sprite()); + const ContextReader reader(context); + SpriteJob job(reader, "Color Mode Change"); + job.startJobWithCallback( + [this, &job, flatten] { + Sprite* sprite(job.sprite()); if (flatten) - transaction.execute(new cmd::FlattenLayers(sprite)); + job.transaction().execute(new cmd::FlattenLayers(sprite)); - transaction.execute( + job.transaction().execute( new cmd::SetPixelFormat( sprite, m_format, m_ditheringAlgorithm, - m_ditheringMatrix, &job)); - if (!job.isCanceled()) - transaction.commit(); + m_ditheringMatrix, + &job)); // SpriteJob is a render::TaskDelegate }); job.waitJob(); } diff --git a/src/app/commands/cmd_color_quantization.cpp b/src/app/commands/cmd_color_quantization.cpp index aab5bbdd3..ce82e3e89 100644 --- a/src/app/commands/cmd_color_quantization.cpp +++ b/src/app/commands/cmd_color_quantization.cpp @@ -17,7 +17,7 @@ #include "app/job.h" #include "app/modules/palettes.h" #include "app/pref/preferences.h" -#include "app/render_task_job.h" +#include "app/sprite_job.h" #include "app/transaction.h" #include "app/ui/color_bar.h" #include "app/ui_context.h" @@ -114,12 +114,14 @@ void ColorQuantizationCommand::onExecute(Context* context) Palette tmpPalette(frame, entries.picks()); - RenderTaskJob job("Creating Palette"); - job.startJob( + ContextReader reader(context); + SpriteJob job(reader, "Color Quantization"); + job.startJobWithCallback( [sprite, withAlpha, &tmpPalette, &job]{ render::create_palette_from_sprite( sprite, 0, sprite->lastFrame(), - withAlpha, &tmpPalette, &job); + withAlpha, &tmpPalette, + &job); // SpriteJob is a render::TaskDelegate }); job.waitJob(); if (job.isCanceled()) @@ -141,17 +143,13 @@ void ColorQuantizationCommand::onExecute(Context* context) ++i; } - if (*curPalette != *newPalette) { - ContextWriter writer(UIContext::instance(), 500); - Transaction transaction(writer.context(), "Color Quantization", ModifyDocument); - transaction.execute(new cmd::SetPalette(sprite, frame, newPalette.get())); - transaction.commit(); + if (*curPalette != *newPalette) + job.transaction().execute(new cmd::SetPalette(sprite, frame, newPalette.get())); - set_current_palette(newPalette.get(), false); - ui::Manager::getDefault()->invalidate(); - } + set_current_palette(newPalette.get(), false); + ui::Manager::getDefault()->invalidate(); } - catch (base::Exception& e) { + catch (const base::Exception& e) { Console::showException(e); } } diff --git a/src/app/commands/cmd_rotate.cpp b/src/app/commands/cmd_rotate.cpp index dd38cccbb..ff2db98c1 100644 --- a/src/app/commands/cmd_rotate.cpp +++ b/src/app/commands/cmd_rotate.cpp @@ -15,9 +15,9 @@ #include "app/context_access.h" #include "app/document_api.h" #include "app/document_range.h" -#include "app/job.h" #include "app/modules/editors.h" #include "app/modules/gui.h" +#include "app/sprite_job.h" #include "app/tools/tool_box.h" #include "app/transaction.h" #include "app/ui/color_bar.h" @@ -35,10 +35,7 @@ namespace app { -class RotateJob : public Job { - ContextWriter m_writer; - Document* m_document; - Sprite* m_sprite; +class RotateJob : public SpriteJob { int m_angle; CelList m_cels; bool m_rotateSprite; @@ -46,13 +43,9 @@ class RotateJob : public Job { public: RotateJob(const ContextReader& reader, int angle, const CelList& cels, bool rotateSprite) - : Job("Rotate Canvas") - , m_writer(reader) - , m_document(m_writer.document()) - , m_sprite(m_writer.sprite()) + : SpriteJob(reader, "Rotate Canvas") , m_cels(cels) - , m_rotateSprite(rotateSprite) - { + , m_rotateSprite(rotateSprite) { m_angle = angle; } @@ -63,18 +56,18 @@ protected: const gfx::RectT bounds = newBounds; switch (m_angle) { case 180: - newBounds.x = m_sprite->width() - bounds.x - bounds.w; - newBounds.y = m_sprite->height() - bounds.y - bounds.h; + newBounds.x = sprite()->width() - bounds.x - bounds.w; + newBounds.y = sprite()->height() - bounds.y - bounds.h; break; case 90: - newBounds.x = m_sprite->height() - bounds.y - bounds.h; + newBounds.x = sprite()->height() - bounds.y - bounds.h; newBounds.y = bounds.x; newBounds.w = bounds.h; newBounds.h = bounds.w; break; case -90: newBounds.x = bounds.y; - newBounds.y = m_sprite->width() - bounds.x - bounds.w; + newBounds.y = sprite()->width() - bounds.x - bounds.w; newBounds.w = bounds.h; newBounds.h = bounds.w; break; @@ -82,10 +75,8 @@ protected: } // [working thread] - virtual void onJob() - { - Transaction transaction(m_writer.context(), "Rotate Canvas"); - DocumentApi api = m_document->getApi(transaction); + void onJob() override { + DocumentApi api = document()->getApi(transaction()); // 1) Rotate cel positions for (Cel* cel : m_cels) { @@ -97,13 +88,13 @@ protected: gfx::RectF bounds = cel->boundsF(); rotate_rect(bounds); if (cel->boundsF() != bounds) - transaction.execute(new cmd::SetCelBoundsF(cel, bounds)); + transaction().execute(new cmd::SetCelBoundsF(cel, bounds)); } else { gfx::Rect bounds = cel->bounds(); rotate_rect(bounds); if (bounds.origin() != cel->bounds().origin()) - api.setCelPosition(m_sprite, cel, bounds.x, bounds.y); + api.setCelPosition(sprite(), cel, bounds.x, bounds.y); } } @@ -118,7 +109,7 @@ protected: new_image->setMaskColor(image->maskColor()); doc::rotate_image(image, new_image.get(), m_angle); - api.replaceImage(m_sprite, cel->imageRef(), new_image); + api.replaceImage(sprite(), cel->imageRef(), new_image); } jobProgress((float)i / m_cels.size()); @@ -130,24 +121,24 @@ protected: } // rotate mask - if (m_document->isMaskVisible()) { - Mask* origMask = m_document->mask(); + if (document()->isMaskVisible()) { + Mask* origMask = document()->mask(); base::UniquePtr new_mask(new Mask()); const gfx::Rect& origBounds = origMask->bounds(); int x = 0, y = 0; switch (m_angle) { case 180: - x = m_sprite->width() - origBounds.x - origBounds.w; - y = m_sprite->height() - origBounds.y - origBounds.h; + x = sprite()->width() - origBounds.x - origBounds.w; + y = sprite()->height() - origBounds.y - origBounds.h; break; case 90: - x = m_sprite->height() - origBounds.y - origBounds.h; + x = sprite()->height() - origBounds.y - origBounds.h; y = origBounds.x; break; case -90: x = origBounds.y; - y = m_sprite->width() - origBounds.x - origBounds.w; + y = sprite()->width() - origBounds.x - origBounds.w; break; } @@ -162,16 +153,13 @@ protected: api.copyToCurrentMask(new_mask); // Regenerate mask - m_document->resetTransformation(); - m_document->generateMaskBoundaries(); + document()->resetTransformation(); + document()->generateMaskBoundaries(); } // change the sprite's size if (m_rotateSprite && m_angle != 180) - api.setSpriteSize(m_sprite, m_sprite->height(), m_sprite->width()); - - // commit changes - transaction.commit(); + api.setSpriteSize(sprite(), sprite()->height(), sprite()->width()); } }; diff --git a/src/app/commands/cmd_sprite_size.cpp b/src/app/commands/cmd_sprite_size.cpp index e7e49d0f1..94a2fe9f9 100644 --- a/src/app/commands/cmd_sprite_size.cpp +++ b/src/app/commands/cmd_sprite_size.cpp @@ -13,14 +13,11 @@ #include "app/commands/cmd_sprite_size.h" #include "app/commands/command.h" #include "app/commands/params.h" -#include "app/context.h" -#include "app/context_access.h" #include "app/document_api.h" #include "app/ini_file.h" -#include "app/job.h" #include "app/modules/gui.h" #include "app/modules/palettes.h" -#include "app/transaction.h" +#include "app/sprite_job.h" #include "base/bind.h" #include "base/unique_ptr.h" #include "doc/algorithm/resize_image.h" @@ -43,19 +40,16 @@ namespace app { using namespace ui; using doc::algorithm::ResizeMethod; -class SpriteSizeJob : public Job { - ContextWriter m_writer; - Document* m_document; - Sprite* m_sprite; +class SpriteSizeJob : public SpriteJob { int m_new_width; int m_new_height; ResizeMethod m_resize_method; template - T scale_x(T x) const { return x * T(m_new_width) / T(m_sprite->width()); } + T scale_x(T x) const { return x * T(m_new_width) / T(sprite()->width()); } template - T scale_y(T y) const { return y * T(m_new_height) / T(m_sprite->height()); } + T scale_y(T y) const { return y * T(m_new_height) / T(sprite()->height()); } template gfx::RectT scale_rect(const gfx::RectT& rc) const { @@ -69,11 +63,7 @@ class SpriteSizeJob : public Job { public: SpriteSizeJob(const ContextReader& reader, int new_width, int new_height, ResizeMethod resize_method) - : Job("Sprite Size") - , m_writer(reader) - , m_document(m_writer.document()) - , m_sprite(m_writer.sprite()) - { + : SpriteJob(reader, "Sprite Size") { m_new_width = new_width; m_new_height = new_height; m_resize_method = resize_method; @@ -81,34 +71,30 @@ public: protected: - /** - * [working thread] - */ - virtual void onJob() - { - Transaction transaction(m_writer.context(), "Sprite Size"); - DocumentApi api = m_writer.document()->getApi(transaction); + // [working thread] + void onJob() override { + DocumentApi api = writer().document()->getApi(transaction()); int cels_count = 0; - for (Cel* cel : m_sprite->uniqueCels()) { // TODO add size() member function to CelsRange + for (Cel* cel : sprite()->uniqueCels()) { // TODO add size() member function to CelsRange (void)cel; ++cels_count; } // For each cel... int progress = 0; - for (Cel* cel : m_sprite->uniqueCels()) { + for (Cel* cel : sprite()->uniqueCels()) { // Get cel's image Image* image = cel->image(); if (image && !cel->link()) { // Resize the cel bounds only if it's from a reference layer if (cel->layer()->isReference()) { gfx::RectF newBounds = scale_rect(cel->boundsF()); - transaction.execute(new cmd::SetCelBoundsF(cel, newBounds)); + transaction().execute(new cmd::SetCelBoundsF(cel, newBounds)); } else { // Change its location - api.setCelPosition(m_sprite, cel, scale_x(cel->x()), scale_y(cel->y())); + api.setCelPosition(sprite(), cel, scale_x(cel->x()), scale_y(cel->y())); // Resize the image int w = scale_x(image->width()); @@ -120,11 +106,11 @@ protected: doc::algorithm::resize_image( image, new_image.get(), m_resize_method, - m_sprite->palette(cel->frame()), - m_sprite->rgbMap(cel->frame()), - (cel->layer()->isBackground() ? -1: m_sprite->transparentColor())); + sprite()->palette(cel->frame()), + sprite()->rgbMap(cel->frame()), + (cel->layer()->isBackground() ? -1: sprite()->transparentColor())); - api.replaceImage(m_sprite, cel->imageRef(), new_image); + api.replaceImage(sprite(), cel->imageRef(), new_image); } } @@ -137,24 +123,24 @@ protected: } // Resize mask - if (m_document->isMaskVisible()) { + if (document()->isMaskVisible()) { ImageRef old_bitmap - (crop_image(m_document->mask()->bitmap(), -1, -1, - m_document->mask()->bitmap()->width()+2, - m_document->mask()->bitmap()->height()+2, 0)); + (crop_image(document()->mask()->bitmap(), -1, -1, + document()->mask()->bitmap()->width()+2, + document()->mask()->bitmap()->height()+2, 0)); int w = scale_x(old_bitmap->width()); int h = scale_y(old_bitmap->height()); base::UniquePtr new_mask(new Mask); new_mask->replace( gfx::Rect( - scale_x(m_document->mask()->bounds().x-1), - scale_y(m_document->mask()->bounds().y-1), MAX(1, w), MAX(1, h))); + scale_x(document()->mask()->bounds().x-1), + scale_y(document()->mask()->bounds().y-1), MAX(1, w), MAX(1, h))); algorithm::resize_image( old_bitmap.get(), new_mask->bitmap(), m_resize_method, - m_sprite->palette(0), // Ignored - m_sprite->rgbMap(0), // Ignored + sprite()->palette(0), // Ignored + sprite()->rgbMap(0), // Ignored -1); // Ignored // Reshrink @@ -164,12 +150,12 @@ protected: api.copyToCurrentMask(new_mask); // Regenerate mask - m_document->resetTransformation(); - m_document->generateMaskBoundaries(); + document()->resetTransformation(); + document()->generateMaskBoundaries(); } // Resize slices - for (auto& slice : m_document->sprite()->slices()) { + for (auto& slice : sprite()->slices()) { for (auto& k : *slice) { const SliceKey& key = *k.value(); if (key.isEmpty()) @@ -185,16 +171,13 @@ protected: newKey.setPivot(gfx::Point(scale_x(newKey.pivot().x), scale_y(newKey.pivot().y))); - transaction.execute( + transaction().execute( new cmd::SetSliceKey(slice, k.frame(), newKey)); } } // Resize Sprite - api.setSpriteSize(m_sprite, m_new_width, m_new_height); - - // Commit changes - transaction.commit(); + api.setSpriteSize(sprite(), m_new_width, m_new_height); } }; diff --git a/src/app/render_task_job.cpp b/src/app/render_task_job.cpp deleted file mode 100644 index 68e2bb2aa..000000000 --- a/src/app/render_task_job.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Aseprite -// Copyright (C) 2017 David Capello -// -// 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/render_task_job.h" - -namespace app { - -void RenderTaskJob::onJob() -{ - try { - m_func(); - } - catch (const std::exception&) { - // TODO show the exception - } -} - -bool RenderTaskJob::continueTask() -{ - return !isCanceled(); -} - -void RenderTaskJob::notifyTaskProgress(double progress) -{ - jobProgress(progress); -} - -} // namespace app diff --git a/src/app/render_task_job.h b/src/app/render_task_job.h deleted file mode 100644 index 5c2b2c395..000000000 --- a/src/app/render_task_job.h +++ /dev/null @@ -1,43 +0,0 @@ -// Aseprite -// Copyright (C) 2017 David Capello -// -// This program is distributed under the terms of -// the End-User License Agreement for Aseprite. - -#ifndef APP_RENDER_TASK_JOB_H_INCLUDED -#define APP_RENDER_TASK_JOB_H_INCLUDED -#pragma once - -#include "app/job.h" -#include "render/task_delegate.h" - -#include - -namespace app { - -class RenderTaskJob : public Job, - public render::TaskDelegate { -public: - RenderTaskJob(const char* jobName) - : Job(jobName) { - } - - template - void startJob(T&& func) { - m_func = std::move(func); - Job::startJob(); - } - -private: - void onJob() override; - - // render::TaskDelegate impl - bool continueTask() override; - void notifyTaskProgress(double progress) override; - - std::function m_func; -}; - -} // namespace app - -#endif diff --git a/src/app/sprite_job.cpp b/src/app/sprite_job.cpp new file mode 100644 index 000000000..f65bbf5f8 --- /dev/null +++ b/src/app/sprite_job.cpp @@ -0,0 +1,45 @@ +// Aseprite +// Copyright (C) 2017 David Capello +// +// 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/sprite_job.h" + +namespace app { + +SpriteJob::SpriteJob(const ContextReader& reader, const char* jobName) + : Job(jobName) + , m_writer(reader, 500) + , m_document(m_writer.document()) + , m_sprite(m_writer.sprite()) + , m_transaction(m_writer.context(), jobName, ModifyDocument) +{ +} + +SpriteJob::~SpriteJob() +{ + if (!isCanceled()) + m_transaction.commit(); +} + +void SpriteJob::onJob() +{ + m_callback(); +} + +bool SpriteJob::continueTask() +{ + return !isCanceled(); +} + +void SpriteJob::notifyTaskProgress(double progress) +{ + jobProgress(progress); +} + +} // namespace app diff --git a/src/app/sprite_job.h b/src/app/sprite_job.h new file mode 100644 index 000000000..6cc7c658a --- /dev/null +++ b/src/app/sprite_job.h @@ -0,0 +1,60 @@ +// Aseprite +// Copyright (C) 2017 David Capello +// +// This program is distributed under the terms of +// the End-User License Agreement for Aseprite. + +#ifndef APP_SPRITE_JOB_H_INCLUDED +#define APP_SPRITE_JOB_H_INCLUDED +#pragma once + +#include "app/context.h" +#include "app/context_access.h" +#include "app/job.h" +#include "app/transaction.h" +#include "render/task_delegate.h" + +#include + +namespace app { + +class SpriteJob : public Job, + public render::TaskDelegate { +public: + SpriteJob(const ContextReader& reader, const char* jobName); + ~SpriteJob(); + + ContextWriter& writer() { return m_writer; } + Document* document() const { return m_document; } + Sprite* sprite() const { return m_sprite; } + Transaction& transaction() { return m_transaction; } + + template + void startJobWithCallback(T&& callback) { + m_callback = std::move(callback); + Job::startJob(); + } + +private: + // Job impl + void onJob() override; + + // render::TaskDelegate impl just in case you need to use this + // Job as a delegate in render::create_palette_from_sprite() + bool continueTask() override; + void notifyTaskProgress(double progress) override; + + ContextWriter m_writer; + Document* m_document; + Sprite* m_sprite; + Transaction m_transaction; + + // Default implementation calls the given function in + // startJob(). Anyway you can just extended the SpriteJob and + // override onJob(). + std::function m_callback; +}; + +} // namespace app + +#endif // APP_SPRITE_JOB_H_INCLUDED