Add progress dialog/bar when we change color mode

Added a new app::RenderTaskJob to execute a lambda function as in a
background thread in a app::Job that can be used as a
render::TaskDelegate by some render functions.
This commit is contained in:
David Capello 2017-05-17 16:40:19 -03:00
parent 573cad4777
commit 131336d015
7 changed files with 130 additions and 49 deletions

View File

@ -24,34 +24,74 @@
#include "doc/palette.h"
#include "doc/sprite.h"
#include "render/quantization.h"
#include "render/task_delegate.h"
namespace app {
namespace cmd {
using namespace doc;
namespace {
class SuperDelegate : public render::TaskDelegate {
public:
SuperDelegate(int ncels, render::TaskDelegate* delegate)
: m_ncels(ncels)
, m_curCel(0)
, m_delegate(delegate) {
}
void notifyTaskProgress(double progress) override {
if (m_delegate)
m_delegate->notifyTaskProgress(
(progress + m_curCel) / m_ncels);
}
bool continueTask() override {
if (m_delegate)
return m_delegate->continueTask();
else
return true;
}
void nextCel() {
++m_curCel;
}
private:
int m_ncels;
int m_curCel;
TaskDelegate* m_delegate;
};
} // anonymous namespace
SetPixelFormat::SetPixelFormat(Sprite* sprite,
const PixelFormat newFormat,
const render::DitheringAlgorithm dithering)
const render::DitheringAlgorithm dithering,
render::TaskDelegate* delegate)
: WithSprite(sprite)
, m_oldFormat(sprite->pixelFormat())
, m_newFormat(newFormat)
, m_dithering(dithering)
{
if (sprite->pixelFormat() == newFormat)
return;
SuperDelegate superDel(sprite->uniqueCels().size(), delegate);
for (Cel* cel : sprite->uniqueCels()) {
ImageRef old_image = cel->imageRef();
ImageRef new_image(
render::convert_pixel_format
(old_image.get(), NULL, newFormat, m_dithering,
(old_image.get(), NULL, newFormat, dithering,
sprite->rgbMap(cel->frame()),
sprite->palette(cel->frame()),
cel->layer()->isBackground(),
old_image->maskColor()));
old_image->maskColor(),
&superDel));
m_seq.add(new cmd::ReplaceImage(sprite, old_image, new_image));
superDel.nextCel();
}
// Set all cels opacity to 100% if we are converting to indexed.

View File

@ -17,6 +17,10 @@ namespace doc {
class Sprite;
}
namespace render {
class TaskDelegate;
}
namespace app {
namespace cmd {
@ -25,7 +29,8 @@ namespace cmd {
public:
SetPixelFormat(doc::Sprite* sprite,
const doc::PixelFormat newFormat,
const render::DitheringAlgorithm dithering);
const render::DitheringAlgorithm dithering,
render::TaskDelegate* delegate);
protected:
void onExecute() override;
@ -40,7 +45,6 @@ namespace cmd {
doc::PixelFormat m_oldFormat;
doc::PixelFormat m_newFormat;
render::DitheringAlgorithm m_dithering;
CmdSequence m_seq;
};

View File

@ -16,6 +16,7 @@
#include "app/modules/editors.h"
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
#include "app/render_task_job.h"
#include "app/transaction.h"
#include "app/ui/editor/editor.h"
#include "app/ui/skin/skin_theme.h"
@ -397,14 +398,20 @@ void ChangePixelFormatCommand::onExecute(Context* context)
if (context->activeDocument()->sprite()->pixelFormat() == m_format)
return;
{
ContextWriter writer(context);
Transaction transaction(writer.context(), "Color Mode Change");
Sprite* sprite(writer.sprite());
transaction.execute(new cmd::SetPixelFormat(sprite, m_format, m_dithering));
transaction.commit();
}
RenderTaskJob job(
"Converting Color Mode",
[this, &job, context]{
ContextWriter writer(context);
Transaction transaction(writer.context(), "Color Mode Change");
Sprite* sprite(writer.sprite());
transaction.execute(
new cmd::SetPixelFormat(
sprite, m_format, m_dithering, &job));
if (!job.isCanceled())
transaction.commit();
});
job.startJob();
job.waitJob();
if (context->isUIAvailable())
app_refresh_screen();

View File

@ -17,6 +17,7 @@
#include "app/job.h"
#include "app/modules/palettes.h"
#include "app/pref/preferences.h"
#include "app/render_task_job.h"
#include "app/transaction.h"
#include "app/ui/color_bar.h"
#include "app/ui_context.h"
@ -25,7 +26,6 @@
#include "doc/palette.h"
#include "doc/sprite.h"
#include "render/quantization.h"
#include "render/task_delegate.h"
#include "ui/manager.h"
#include "palette_from_sprite.xml.h"
@ -42,37 +42,6 @@ protected:
void onExecute(Context* context) override;
};
class ColorQuantizationJob : public Job,
public render::TaskDelegate {
public:
ColorQuantizationJob(Sprite* sprite, bool withAlpha, Palette* palette)
: Job("Creating Palette")
, m_sprite(sprite)
, m_withAlpha(withAlpha)
, m_palette(palette) {
}
private:
void onJob() override {
render::create_palette_from_sprite(
m_sprite, 0, m_sprite->lastFrame(),
m_withAlpha, m_palette, this);
}
bool continueTask() override {
return !isCanceled();
}
void notifyTaskProgress(double progress) override {
jobProgress(progress);
}
Sprite* m_sprite;
bool m_withAlpha;
Palette* m_palette;
};
ColorQuantizationCommand::ColorQuantizationCommand()
: Command("ColorQuantization",
"Create Palette from Current Sprite (Color Quantization)",
@ -144,7 +113,14 @@ void ColorQuantizationCommand::onExecute(Context* context)
return;
Palette tmpPalette(frame, entries.picks());
ColorQuantizationJob job(sprite, withAlpha, &tmpPalette);
RenderTaskJob job(
"Creating Palette",
[sprite, withAlpha, &tmpPalette, &job]{
render::create_palette_from_sprite(
sprite, 0, sprite->lastFrame(),
withAlpha, &tmpPalette, &job);
});
job.startJob();
job.waitJob();
if (job.isCanceled())

View File

@ -707,7 +707,8 @@ void DocumentExporter::renderTexture(const Samples& samples, Image* textureImage
cmd::SetPixelFormat(
sample.sprite(),
textureImage->pixelFormat(),
render::DitheringAlgorithm::None)
render::DitheringAlgorithm::None,
nullptr) // TODO add a delegate to show progress
.execute(UIContext::instance());
}

46
src/app/render_task_job.h Normal file
View File

@ -0,0 +1,46 @@
// 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 <functional>
namespace app {
class RenderTaskJob : public Job,
public render::TaskDelegate {
public:
template<typename T>
RenderTaskJob(const char* jobName, T&& func)
: Job(jobName)
, m_func(std::move(func)) {
}
private:
void onJob() override {
m_func();
}
// render::TaskDelegate impl
bool continueTask() override {
return !isCanceled();
}
void notifyTaskProgress(double progress) override {
jobProgress(progress);
}
std::function<void()> m_func;
};
} // namespace app
#endif

View File

@ -1,5 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2001-2016 David Capello
// Copyright (c) 2001-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -64,6 +64,13 @@ namespace doc {
iterator begin() { return m_begin; }
iterator end() { return m_end; }
int size() {
int count = 0;
for (auto it=begin(), e=end(); it!=e; ++it)
++count;
return count;
}
private:
SelectedFrames m_selFrames;
iterator m_begin, m_end;