mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-29 19:20:09 +00:00
Add support to call ReplaceColor from scripts when the UI is disabled (e.g. from CLI)
This commit is contained in:
parent
9143523827
commit
814250e325
@ -300,14 +300,11 @@ if(ENABLE_UI)
|
||||
commands/filters/cmd_hue_saturation.cpp
|
||||
commands/filters/cmd_invert_color.cpp
|
||||
commands/filters/cmd_outline.cpp
|
||||
commands/filters/cmd_replace_color.cpp
|
||||
commands/filters/color_curve_editor.cpp
|
||||
commands/filters/convolution_matrix_stock.cpp
|
||||
commands/filters/filter_manager_impl.cpp
|
||||
commands/filters/filter_preview.cpp
|
||||
commands/filters/filter_target_buttons.cpp
|
||||
commands/filters/filter_window.cpp
|
||||
commands/filters/filter_worker.cpp
|
||||
file_selector.cpp
|
||||
modules/editors.cpp
|
||||
modules/gfx.cpp
|
||||
@ -523,6 +520,9 @@ add_library(app-lib
|
||||
commands/cmd_undo.cpp
|
||||
commands/command.cpp
|
||||
commands/commands.cpp
|
||||
commands/filters/cmd_replace_color.cpp
|
||||
commands/filters/filter_manager_impl.cpp
|
||||
commands/filters/filter_worker.cpp
|
||||
commands/move_thing.cpp
|
||||
commands/new_params.cpp
|
||||
commands/quick_command.cpp
|
||||
|
@ -23,6 +23,7 @@ FOR_EACH_COMMAND(OpenFile)
|
||||
FOR_EACH_COMMAND(PaletteSize)
|
||||
FOR_EACH_COMMAND(Redo)
|
||||
FOR_EACH_COMMAND(RemoveLayer)
|
||||
FOR_EACH_COMMAND(ReplaceColor)
|
||||
FOR_EACH_COMMAND(SaveFile)
|
||||
FOR_EACH_COMMAND(SaveFileAs)
|
||||
FOR_EACH_COMMAND(SaveFileCopyAs)
|
||||
@ -119,7 +120,6 @@ FOR_EACH_COMMAND(RemoveFrameTag)
|
||||
FOR_EACH_COMMAND(RemoveSlice)
|
||||
FOR_EACH_COMMAND(ReopenClosedFile)
|
||||
FOR_EACH_COMMAND(RepeatLastExport)
|
||||
FOR_EACH_COMMAND(ReplaceColor)
|
||||
FOR_EACH_COMMAND(ReselectMask)
|
||||
FOR_EACH_COMMAND(ReverseFrames)
|
||||
FOR_EACH_COMMAND(Rotate)
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "app/find_widget.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/load_widget.h"
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/site.h"
|
||||
#include "app/ui/color_bar.h"
|
||||
#include "app/ui/color_button.h"
|
||||
@ -38,7 +39,9 @@
|
||||
|
||||
namespace app {
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
static const char* ConfigSection = "ReplaceColor";
|
||||
#endif
|
||||
|
||||
struct ReplaceColorParams : public NewParams {
|
||||
Param<bool> ui { this, true, "ui" };
|
||||
@ -73,6 +76,8 @@ private:
|
||||
app::Color m_to;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
|
||||
class ReplaceColorWindow : public FilterWindow {
|
||||
public:
|
||||
ReplaceColorWindow(ReplaceColorFilterWrapper& filter, FilterManagerImpl& filterMgr)
|
||||
@ -138,6 +143,8 @@ private:
|
||||
ui::Slider* m_toleranceSlider;
|
||||
};
|
||||
|
||||
#endif // ENABLE_UI
|
||||
|
||||
class ReplaceColorCommand : public CommandWithNewParams<ReplaceColorParams> {
|
||||
public:
|
||||
ReplaceColorCommand();
|
||||
@ -160,7 +167,9 @@ bool ReplaceColorCommand::onEnabled(Context* context)
|
||||
|
||||
void ReplaceColorCommand::onExecute(Context* context)
|
||||
{
|
||||
#ifdef ENABLE_UI
|
||||
const bool ui = (params().ui() && context->isUIAvailable());
|
||||
#endif
|
||||
Site site = context->activeSite();
|
||||
|
||||
ReplaceColorFilterWrapper filter(site.layer());
|
||||
@ -174,14 +183,17 @@ void ReplaceColorCommand::onExecute(Context* context)
|
||||
TARGET_GRAY_CHANNEL |
|
||||
TARGET_ALPHA_CHANNEL);
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
if (ui) {
|
||||
filter.setFrom(get_config_color(ConfigSection, "Color1", ColorBar::instance()->getFgColor()));
|
||||
filter.setTo(get_config_color(ConfigSection, "Color2", ColorBar::instance()->getBgColor()));
|
||||
filter.setFrom(get_config_color(ConfigSection, "Color1", Preferences::instance().colorBar.fgColor()));
|
||||
filter.setTo(get_config_color(ConfigSection, "Color2", Preferences::instance().colorBar.bgColor()));
|
||||
filter.setTolerance(get_config_int(ConfigSection, "Tolerance", 0));
|
||||
}
|
||||
else {
|
||||
filter.setFrom(ColorBar::instance()->getFgColor());
|
||||
filter.setTo(ColorBar::instance()->getBgColor());
|
||||
else
|
||||
#endif // ENABLE_UI
|
||||
{
|
||||
filter.setFrom(Preferences::instance().colorBar.fgColor());
|
||||
filter.setTo(Preferences::instance().colorBar.bgColor());
|
||||
filter.setTolerance(params().tolerance());
|
||||
}
|
||||
|
||||
@ -190,6 +202,7 @@ void ReplaceColorCommand::onExecute(Context* context)
|
||||
if (params().tolerance.isSet()) filter.setTolerance(params().tolerance());
|
||||
if (params().target.isSet()) filterMgr.setTarget(params().target());
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
if (ui) {
|
||||
ReplaceColorWindow window(filter, filterMgr);
|
||||
if (window.doModal()) {
|
||||
@ -198,7 +211,9 @@ void ReplaceColorCommand::onExecute(Context* context)
|
||||
set_config_int(ConfigSection, "Tolerance", filter.getTolerance());
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
#endif // ENABLE_UI
|
||||
{
|
||||
start_filter_worker(&filterMgr);
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +123,8 @@ void FilterManagerImpl::begin()
|
||||
updateBounds(m_mask);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
|
||||
void FilterManagerImpl::beginForPreview()
|
||||
{
|
||||
Doc* document = m_site.document();
|
||||
@ -161,6 +163,8 @@ void FilterManagerImpl::beginForPreview()
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ENABLE_UI
|
||||
|
||||
void FilterManagerImpl::end()
|
||||
{
|
||||
m_maskBits.unlock();
|
||||
@ -244,7 +248,7 @@ void FilterManagerImpl::applyToTarget()
|
||||
switch (m_celsTarget) {
|
||||
|
||||
case CelsTarget::Selected: {
|
||||
auto range = App::instance()->timeline()->range();
|
||||
auto range = m_site.range();
|
||||
if (range.enabled()) {
|
||||
for (Cel* cel : get_unlocked_unique_cels(m_site.sprite(), range)) {
|
||||
if (!cel->layer()->isReference())
|
||||
@ -332,6 +336,8 @@ void FilterManagerImpl::commitTransaction()
|
||||
m_tx->commit();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
|
||||
void FilterManagerImpl::flush()
|
||||
{
|
||||
int h = m_row - m_nextRowToFlush;
|
||||
@ -382,6 +388,8 @@ void FilterManagerImpl::disablePreview()
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ENABLE_UI
|
||||
|
||||
const void* FilterManagerImpl::getSourceAddress()
|
||||
{
|
||||
return m_src->getPixelAddress(m_bounds.x, m_bounds.y+m_row);
|
||||
@ -429,9 +437,11 @@ Palette* FilterManagerImpl::getNewPalette()
|
||||
doc::PalettePicks FilterManagerImpl::getPalettePicks()
|
||||
{
|
||||
doc::PalettePicks picks;
|
||||
#ifdef ENABLE_UI // TODO add palette entries in Site and use activeSite here
|
||||
ColorBar::instance()
|
||||
->getPaletteView()
|
||||
->getSelectedEntries(picks);
|
||||
#endif
|
||||
return picks;
|
||||
}
|
||||
|
||||
@ -495,12 +505,16 @@ void FilterManagerImpl::restoreSpritePalette()
|
||||
m_site.sprite()->setPalette(m_oldPalette.get(), false);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
|
||||
void FilterManagerImpl::redrawColorPalette()
|
||||
{
|
||||
set_current_palette(getNewPalette(), false);
|
||||
ColorBar::instance()->invalidate();
|
||||
}
|
||||
|
||||
#endif // ENABLE_UI
|
||||
|
||||
bool FilterManagerImpl::isMaskActive() const
|
||||
{
|
||||
return m_site.document()->isMaskVisible();
|
||||
|
@ -83,7 +83,9 @@ namespace app {
|
||||
void setCelsTarget(CelsTarget celsTarget);
|
||||
|
||||
void begin();
|
||||
#ifdef ENABLE_UI
|
||||
void beginForPreview();
|
||||
#endif
|
||||
void end();
|
||||
bool applyStep();
|
||||
void applyToTarget();
|
||||
@ -97,10 +99,11 @@ namespace app {
|
||||
doc::Image* destinationImage() const { return m_dst.get(); }
|
||||
gfx::Point position() const { return gfx::Point(0, 0); }
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
// Updates the current editor to show the progress of the preview.
|
||||
void flush();
|
||||
|
||||
void disablePreview();
|
||||
#endif
|
||||
|
||||
// FilterManager implementation
|
||||
const void* getSourceAddress() override;
|
||||
@ -131,7 +134,10 @@ namespace app {
|
||||
// modifies the palette).
|
||||
bool paletteHasChanged();
|
||||
void restoreSpritePalette();
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
void redrawColorPalette();
|
||||
#endif
|
||||
|
||||
Context* m_context;
|
||||
Site m_site;
|
||||
@ -140,7 +146,9 @@ namespace app {
|
||||
doc::ImageRef m_src;
|
||||
doc::ImageRef m_dst;
|
||||
int m_row;
|
||||
#ifdef ENABLE_UI
|
||||
int m_nextRowToFlush;
|
||||
#endif
|
||||
gfx::Rect m_bounds;
|
||||
doc::Mask* m_mask;
|
||||
std::unique_ptr<doc::Mask> m_previewMask;
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -25,13 +26,54 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace base;
|
||||
using namespace ui;
|
||||
|
||||
static const int kMonitoringPeriod = 100;
|
||||
#ifdef ENABLE_UI
|
||||
|
||||
namespace {
|
||||
|
||||
const int kMonitoringPeriod = 100;
|
||||
|
||||
class FilterWorkerAlert {
|
||||
public:
|
||||
FilterWorkerAlert(std::function<void()>&& onTick)
|
||||
: m_timer(kMonitoringPeriod)
|
||||
, m_window(ui::Alert::create(Strings::alerts_applying_filter())) {
|
||||
m_window->addProgress();
|
||||
|
||||
m_timer.Tick.connect(std::move(onTick));
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
void openAndWait() {
|
||||
m_window->openWindowInForeground();
|
||||
|
||||
// Stop the monitoring timer.
|
||||
m_timer.stop();
|
||||
}
|
||||
|
||||
void close() {
|
||||
m_window->closeWindow(nullptr);
|
||||
}
|
||||
|
||||
void setProgress(double progress) {
|
||||
m_window->setProgress(progress);
|
||||
}
|
||||
|
||||
private:
|
||||
ui::Timer m_timer; // Monitoring timer to update the progress-bar
|
||||
AlertPtr m_window; // Alert for the user to cancel the filter-progress if he wants.
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#endif // ENABLE_UI
|
||||
|
||||
// Applies filters in two threads: a background worker thread to
|
||||
// modify the sprite, and the main thread to monitoring the progress
|
||||
@ -50,12 +92,9 @@ public:
|
||||
|
||||
private:
|
||||
void applyFilterInBackground();
|
||||
#ifdef ENABLE_UI
|
||||
void onMonitoringTick();
|
||||
|
||||
static void thread_proxy(void* data) {
|
||||
FilterWorker* filterWorker = (FilterWorker*)data;
|
||||
filterWorker->applyFilterInBackground();
|
||||
}
|
||||
#endif
|
||||
|
||||
FilterManagerImpl* m_filterMgr; // Effect to be applied.
|
||||
base::mutex m_mutex; // Mutex to access to 'pos', 'done' and 'cancelled' fields in different threads.
|
||||
@ -63,14 +102,14 @@ private:
|
||||
bool m_done; // Was the effect completely applied?
|
||||
bool m_cancelled; // Was the effect cancelled by the user?
|
||||
bool m_abort; // An exception was thrown
|
||||
ui::Timer m_timer; // Monitoring timer to update the progress-bar
|
||||
AlertPtr m_alertWindow; // Alert for the user to cancel the filter-progress if he wants.
|
||||
std::string m_error;
|
||||
#ifdef ENABLE_UI
|
||||
std::unique_ptr<FilterWorkerAlert> m_alert;
|
||||
#endif
|
||||
};
|
||||
|
||||
FilterWorker::FilterWorker(FilterManagerImpl* filterMgr)
|
||||
: m_filterMgr(filterMgr)
|
||||
, m_timer(kMonitoringPeriod)
|
||||
{
|
||||
m_filterMgr->setProgressDelegate(this);
|
||||
|
||||
@ -79,29 +118,36 @@ FilterWorker::FilterWorker(FilterManagerImpl* filterMgr)
|
||||
m_cancelled = false;
|
||||
m_abort = false;
|
||||
|
||||
m_alertWindow = ui::Alert::create(Strings::alerts_applying_filter());
|
||||
m_alertWindow->addProgress();
|
||||
|
||||
m_timer.Tick.connect(&FilterWorker::onMonitoringTick, this);
|
||||
m_timer.start();
|
||||
#ifdef ENABLE_UI
|
||||
if (Manager::getDefault())
|
||||
m_alert.reset(new FilterWorkerAlert([this]{ onMonitoringTick(); }));
|
||||
#endif
|
||||
}
|
||||
|
||||
FilterWorker::~FilterWorker()
|
||||
{
|
||||
if (m_alertWindow)
|
||||
m_alertWindow->closeWindow(NULL);
|
||||
#ifdef ENABLE_UI
|
||||
if (m_alert)
|
||||
m_alert->close();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FilterWorker::run()
|
||||
{
|
||||
// Launch the thread to apply the effect in background
|
||||
base::thread thread(&FilterWorker::thread_proxy, this);
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
std::thread thread;
|
||||
// Open the alert window in foreground (this is modal, locks the main thread)
|
||||
m_alertWindow->openWindowInForeground();
|
||||
|
||||
// Stop the monitoring timer.
|
||||
m_timer.stop();
|
||||
if (m_alert) {
|
||||
// Launch the thread to apply the effect in background
|
||||
thread = std::thread([this]{ applyFilterInBackground(); });
|
||||
m_alert->openAndWait();
|
||||
}
|
||||
else
|
||||
#endif // ENABLE_UI
|
||||
{
|
||||
// Without UI? Apply filter from the main thread
|
||||
applyFilterInBackground();
|
||||
}
|
||||
|
||||
{
|
||||
scoped_lock lock(m_mutex);
|
||||
@ -111,8 +157,10 @@ void FilterWorker::run()
|
||||
m_cancelled = true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
// Wait the `effect_bg' thread
|
||||
thread.join();
|
||||
if (thread.joinable())
|
||||
thread.join();
|
||||
|
||||
if (!m_error.empty()) {
|
||||
Console console;
|
||||
@ -122,6 +170,7 @@ void FilterWorker::run()
|
||||
StatusBar::instance()
|
||||
->showTip(2500, "No unlocked layers to apply filter");
|
||||
}
|
||||
#endif // ENABLE_UI
|
||||
}
|
||||
|
||||
// Called by FilterManagerImpl to informate the progress of the filter.
|
||||
@ -168,19 +217,24 @@ void FilterWorker::applyFilterInBackground()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
|
||||
// Called by the GUI monitor (a timer in the gui module that is called
|
||||
// every 100 milliseconds).
|
||||
void FilterWorker::onMonitoringTick()
|
||||
{
|
||||
scoped_lock lock(m_mutex);
|
||||
|
||||
if (m_alertWindow)
|
||||
m_alertWindow->setProgress(m_pos);
|
||||
if (m_alert) {
|
||||
m_alert->setProgress(m_pos);
|
||||
|
||||
if (m_done || m_abort)
|
||||
m_alertWindow->closeWindow(NULL);
|
||||
if (m_done || m_abort)
|
||||
m_alert->close();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Applies the filter in a background thread meanwhile a progress bar
|
||||
// is shown to the user.
|
||||
//
|
||||
|
@ -1,5 +1,6 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -61,4 +62,14 @@ Palette* Site::palette() const
|
||||
return (m_sprite ? m_sprite->palette(m_frame): nullptr);
|
||||
}
|
||||
|
||||
void Site::range(const DocRange& range)
|
||||
{
|
||||
m_range = range;
|
||||
switch (range.type()) {
|
||||
case DocRange::kCels: m_focus = Site::InCels; break;
|
||||
case DocRange::kFrames: m_focus = Site::InFrames; break;
|
||||
case DocRange::kLayers: m_focus = Site::InLayers; break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -9,9 +9,8 @@
|
||||
#define APP_SITE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/doc_range.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/selected_frames.h"
|
||||
#include "doc/selected_layers.h"
|
||||
#include "doc/selected_objects.h"
|
||||
|
||||
namespace doc {
|
||||
@ -67,24 +66,17 @@ namespace app {
|
||||
doc::Sprite* sprite() { return m_sprite; }
|
||||
doc::Layer* layer() { return m_layer; }
|
||||
doc::Cel* cel();
|
||||
const DocRange& range() const { return m_range; }
|
||||
|
||||
void focus(Focus focus) { m_focus = focus; }
|
||||
void document(Doc* document) { m_document = document; }
|
||||
void sprite(doc::Sprite* sprite) { m_sprite = sprite; }
|
||||
void layer(doc::Layer* layer) { m_layer = layer; }
|
||||
void frame(doc::frame_t frame) { m_frame = frame; }
|
||||
void range(const DocRange& range);
|
||||
|
||||
const doc::SelectedLayers& selectedLayers() const { return m_selectedLayers; }
|
||||
doc::SelectedLayers& selectedLayers() { return m_selectedLayers; }
|
||||
void selectedLayers(const doc::SelectedLayers& selectedLayers) {
|
||||
m_selectedLayers = selectedLayers;
|
||||
}
|
||||
|
||||
const doc::SelectedFrames& selectedFrames() const { return m_selectedFrames; }
|
||||
doc::SelectedFrames& selectedFrames() { return m_selectedFrames; }
|
||||
void selectedFrames(const doc::SelectedFrames& selectedFrames) {
|
||||
m_selectedFrames = selectedFrames;
|
||||
}
|
||||
const doc::SelectedLayers& selectedLayers() const { return m_range.selectedLayers(); }
|
||||
const doc::SelectedFrames& selectedFrames() const { return m_range.selectedFrames(); }
|
||||
|
||||
const doc::SelectedObjects& selectedSlices() const { return m_selectedSlices; }
|
||||
doc::SelectedObjects& selectedSlices() { return m_selectedSlices; }
|
||||
@ -102,8 +94,7 @@ namespace app {
|
||||
doc::Sprite* m_sprite;
|
||||
doc::Layer* m_layer;
|
||||
doc::frame_t m_frame;
|
||||
doc::SelectedLayers m_selectedLayers;
|
||||
doc::SelectedFrames m_selectedFrames;
|
||||
DocRange m_range;
|
||||
doc::SelectedObjects m_selectedSlices;
|
||||
};
|
||||
|
||||
|
@ -291,13 +291,7 @@ void UIContext::onGetActiveSite(Site* site) const
|
||||
Timeline* timeline = App::instance()->timeline();
|
||||
if (timeline &&
|
||||
timeline->range().enabled()) {
|
||||
switch (timeline->range().type()) {
|
||||
case DocRange::kCels: site->focus(Site::InCels); break;
|
||||
case DocRange::kFrames: site->focus(Site::InFrames); break;
|
||||
case DocRange::kLayers: site->focus(Site::InLayers); break;
|
||||
}
|
||||
site->selectedLayers(timeline->selectedLayers());
|
||||
site->selectedFrames(timeline->selectedFrames());
|
||||
site->range(timeline->range());
|
||||
}
|
||||
else {
|
||||
ColorBar* colorBar = ColorBar::instance();
|
||||
|
Loading…
x
Reference in New Issue
Block a user