diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 7cd5d302e..95ee0f102 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -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 diff --git a/src/app/commands/commands_list.h b/src/app/commands/commands_list.h index 36db32f91..64fde251b 100644 --- a/src/app/commands/commands_list.h +++ b/src/app/commands/commands_list.h @@ -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) diff --git a/src/app/commands/filters/cmd_replace_color.cpp b/src/app/commands/filters/cmd_replace_color.cpp index 0e76080af..d631f04c4 100644 --- a/src/app/commands/filters/cmd_replace_color.cpp +++ b/src/app/commands/filters/cmd_replace_color.cpp @@ -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 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 { 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); } } diff --git a/src/app/commands/filters/filter_manager_impl.cpp b/src/app/commands/filters/filter_manager_impl.cpp index d09b5e78c..6dd1624ec 100644 --- a/src/app/commands/filters/filter_manager_impl.cpp +++ b/src/app/commands/filters/filter_manager_impl.cpp @@ -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(); diff --git a/src/app/commands/filters/filter_manager_impl.h b/src/app/commands/filters/filter_manager_impl.h index 19aa312ee..28bd2de55 100644 --- a/src/app/commands/filters/filter_manager_impl.h +++ b/src/app/commands/filters/filter_manager_impl.h @@ -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 m_previewMask; diff --git a/src/app/commands/filters/filter_worker.cpp b/src/app/commands/filters/filter_worker.cpp index 8a5edd465..c9a6806ff 100644 --- a/src/app/commands/filters/filter_worker.cpp +++ b/src/app/commands/filters/filter_worker.cpp @@ -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 #include +#include +#include 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&& 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 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. // diff --git a/src/app/site.cpp b/src/app/site.cpp index 3d6c9473f..2bbdc027a 100644 --- a/src/app/site.cpp +++ b/src/app/site.cpp @@ -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 diff --git a/src/app/site.h b/src/app/site.h index da2fd5373..89a881d1a 100644 --- a/src/app/site.h +++ b/src/app/site.h @@ -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; }; diff --git a/src/app/ui_context.cpp b/src/app/ui_context.cpp index bd31912ba..1b301c354 100644 --- a/src/app/ui_context.cpp +++ b/src/app/ui_context.cpp @@ -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();