mirror of https://github.com/aseprite/aseprite.git
				
				
				
			[lua] Add app.range.colors + Move/CopyColors commands
Closes: https://community.aseprite.org/t/2512
This commit is contained in:
		
							parent
							
								
									1995d67759
								
							
						
					
					
						commit
						35aaa18ee3
					
				|  | @ -249,6 +249,7 @@ Outline = Outline | ||||||
| ConvolutionMatrix = Convolution Matrix | ConvolutionMatrix = Convolution Matrix | ||||||
| Copy = Copy | Copy = Copy | ||||||
| CopyCel = Copy Cel | CopyCel = Copy Cel | ||||||
|  | CopyColors = Copy Colors | ||||||
| CopyMerged = Copy Merged | CopyMerged = Copy Merged | ||||||
| CropSprite = Crop Sprite | CropSprite = Crop Sprite | ||||||
| Cut = Cut | Cut = Cut | ||||||
|  | @ -327,6 +328,7 @@ Move_Right = right | ||||||
| Move_Up = up | Move_Up = up | ||||||
| Move_Down = down | Move_Down = down | ||||||
| MoveCel = Move Cel | MoveCel = Move Cel | ||||||
|  | MoveColors = Move Colors | ||||||
| MoveMask = Move {0} {1} | MoveMask = Move {0} {1} | ||||||
| MoveMask_Boundaries = Selection Boundaries | MoveMask_Boundaries = Selection Boundaries | ||||||
| MoveMask_Content = Selection Content | MoveMask_Content = Selection Content | ||||||
|  |  | ||||||
|  | @ -523,6 +523,7 @@ add_library(app-lib | ||||||
|   commands/filters/convolution_matrix_stock.cpp |   commands/filters/convolution_matrix_stock.cpp | ||||||
|   commands/filters/filter_manager_impl.cpp |   commands/filters/filter_manager_impl.cpp | ||||||
|   commands/filters/filter_worker.cpp |   commands/filters/filter_worker.cpp | ||||||
|  |   commands/move_colors_command.cpp | ||||||
|   commands/move_thing.cpp |   commands/move_thing.cpp | ||||||
|   commands/new_params.cpp |   commands/new_params.cpp | ||||||
|   commands/quick_command.cpp |   commands/quick_command.cpp | ||||||
|  | @ -596,6 +597,7 @@ add_library(app-lib | ||||||
|   util/layer_boundaries.cpp |   util/layer_boundaries.cpp | ||||||
|   util/msk_file.cpp |   util/msk_file.cpp | ||||||
|   util/new_image_from_mask.cpp |   util/new_image_from_mask.cpp | ||||||
|  |   util/pal_ops.cpp | ||||||
|   util/pic_file.cpp |   util/pic_file.cpp | ||||||
|   util/pixel_ratio.cpp |   util/pixel_ratio.cpp | ||||||
|   util/range_utils.cpp |   util/range_utils.cpp | ||||||
|  |  | ||||||
|  | @ -64,6 +64,7 @@ void ActiveSiteHandler::getActiveSiteForDoc(Doc* doc, Site* site) | ||||||
|   site->sprite(doc->sprite()); |   site->sprite(doc->sprite()); | ||||||
|   site->layer(doc::get<doc::Layer>(data.layer)); |   site->layer(doc::get<doc::Layer>(data.layer)); | ||||||
|   site->frame(data.frame); |   site->frame(data.frame); | ||||||
|  |   site->selectedColors(data.selectedColors); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ActiveSiteHandler::setActiveLayerInDoc(Doc* doc, doc::Layer* layer) | void ActiveSiteHandler::setActiveLayerInDoc(Doc* doc, doc::Layer* layer) | ||||||
|  | @ -78,6 +79,12 @@ void ActiveSiteHandler::setActiveFrameInDoc(Doc* doc, doc::frame_t frame) | ||||||
|   data.frame = frame; |   data.frame = frame; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ActiveSiteHandler::setSelectedColorsInDoc(Doc* doc, const doc::PalettePicks& picks) | ||||||
|  | { | ||||||
|  |   Data& data = getData(doc); | ||||||
|  |   data.selectedColors = picks; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ActiveSiteHandler::onAddLayer(DocEvent& ev) | void ActiveSiteHandler::onAddLayer(DocEvent& ev) | ||||||
| { | { | ||||||
|   Data& data = getData(ev.document()); |   Data& data = getData(ev.document()); | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| #include "app/doc_observer.h" | #include "app/doc_observer.h" | ||||||
| #include "doc/frame.h" | #include "doc/frame.h" | ||||||
| #include "doc/object_id.h" | #include "doc/object_id.h" | ||||||
|  | #include "doc/palette_picks.h" | ||||||
| 
 | 
 | ||||||
| #include <map> | #include <map> | ||||||
| 
 | 
 | ||||||
|  | @ -37,6 +38,7 @@ namespace app { | ||||||
|     void getActiveSiteForDoc(Doc* doc, Site* site); |     void getActiveSiteForDoc(Doc* doc, Site* site); | ||||||
|     void setActiveLayerInDoc(Doc* doc, doc::Layer* layer); |     void setActiveLayerInDoc(Doc* doc, doc::Layer* layer); | ||||||
|     void setActiveFrameInDoc(Doc* doc, doc::frame_t frame); |     void setActiveFrameInDoc(Doc* doc, doc::frame_t frame); | ||||||
|  |     void setSelectedColorsInDoc(Doc* doc, const doc::PalettePicks& picks); | ||||||
| 
 | 
 | ||||||
|   private: |   private: | ||||||
|     // DocObserver impl
 |     // DocObserver impl
 | ||||||
|  | @ -49,6 +51,7 @@ namespace app { | ||||||
|     struct Data { |     struct Data { | ||||||
|       doc::ObjectId layer; |       doc::ObjectId layer; | ||||||
|       doc::frame_t frame; |       doc::frame_t frame; | ||||||
|  |       doc::PalettePicks selectedColors; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     Data& getData(Doc* doc); |     Data& getData(Doc* doc); | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ FOR_EACH_COMMAND(CelOpacity) | ||||||
| FOR_EACH_COMMAND(ChangePixelFormat) | FOR_EACH_COMMAND(ChangePixelFormat) | ||||||
| FOR_EACH_COMMAND(ColorCurve) | FOR_EACH_COMMAND(ColorCurve) | ||||||
| FOR_EACH_COMMAND(ConvolutionMatrix) | FOR_EACH_COMMAND(ConvolutionMatrix) | ||||||
|  | FOR_EACH_COMMAND(CopyColors) | ||||||
| FOR_EACH_COMMAND(CropSprite) | FOR_EACH_COMMAND(CropSprite) | ||||||
| FOR_EACH_COMMAND(Despeckle) | FOR_EACH_COMMAND(Despeckle) | ||||||
| FOR_EACH_COMMAND(ExportSpriteSheet) | FOR_EACH_COMMAND(ExportSpriteSheet) | ||||||
|  | @ -22,6 +23,7 @@ FOR_EACH_COMMAND(InvertColor) | ||||||
| FOR_EACH_COMMAND(LayerFromBackground) | FOR_EACH_COMMAND(LayerFromBackground) | ||||||
| FOR_EACH_COMMAND(LoadPalette) | FOR_EACH_COMMAND(LoadPalette) | ||||||
| FOR_EACH_COMMAND(MergeDownLayer) | FOR_EACH_COMMAND(MergeDownLayer) | ||||||
|  | FOR_EACH_COMMAND(MoveColors) | ||||||
| FOR_EACH_COMMAND(NewFile) | FOR_EACH_COMMAND(NewFile) | ||||||
| FOR_EACH_COMMAND(NewFrame) | FOR_EACH_COMMAND(NewFrame) | ||||||
| FOR_EACH_COMMAND(NewLayer) | FOR_EACH_COMMAND(NewLayer) | ||||||
|  |  | ||||||
|  | @ -189,6 +189,10 @@ bool FilterManagerImpl::applyStep() | ||||||
|     m_maskIterator = m_maskBits.begin(); |     m_maskIterator = m_maskBits.begin(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   if (m_row == 0) { | ||||||
|  |     applyToPaletteIfNeeded(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   switch (m_site.sprite()->pixelFormat()) { |   switch (m_site.sprite()->pixelFormat()) { | ||||||
|     case IMAGE_RGB:       m_filter->applyToRgba(this); break; |     case IMAGE_RGB:       m_filter->applyToRgba(this); break; | ||||||
|     case IMAGE_GRAYSCALE: m_filter->applyToGrayscale(this); break; |     case IMAGE_GRAYSCALE: m_filter->applyToGrayscale(this); break; | ||||||
|  | @ -240,6 +244,8 @@ void FilterManagerImpl::apply() | ||||||
| 
 | 
 | ||||||
| void FilterManagerImpl::applyToTarget() | void FilterManagerImpl::applyToTarget() | ||||||
| { | { | ||||||
|  |   applyToPaletteIfNeeded(); | ||||||
|  | 
 | ||||||
|   const bool paletteChange = paletteHasChanged(); |   const bool paletteChange = paletteHasChanged(); | ||||||
|   bool cancelled = false; |   bool cancelled = false; | ||||||
| 
 | 
 | ||||||
|  | @ -441,15 +447,7 @@ Palette* FilterManagerImpl::getNewPalette() | ||||||
| 
 | 
 | ||||||
| doc::PalettePicks FilterManagerImpl::getPalettePicks() | doc::PalettePicks FilterManagerImpl::getPalettePicks() | ||||||
| { | { | ||||||
|   doc::PalettePicks picks; |   return m_site.selectedColors(); | ||||||
| #ifdef ENABLE_UI                // TODO add palette entries in Site and use activeSite here
 |  | ||||||
|   if (auto colorBar = ColorBar::instance()) { |  | ||||||
|     colorBar |  | ||||||
|       ->getPaletteView() |  | ||||||
|       ->getSelectedEntries(picks); |  | ||||||
|   } |  | ||||||
| #endif |  | ||||||
|   return picks; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FilterManagerImpl::init(Cel* cel) | void FilterManagerImpl::init(Cel* cel) | ||||||
|  | @ -512,6 +510,11 @@ void FilterManagerImpl::restoreSpritePalette() | ||||||
|     m_site.sprite()->setPalette(m_oldPalette.get(), false); |     m_site.sprite()->setPalette(m_oldPalette.get(), false); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void FilterManagerImpl::applyToPaletteIfNeeded() | ||||||
|  | { | ||||||
|  |   m_filter->applyToPalette(this); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #ifdef ENABLE_UI | #ifdef ENABLE_UI | ||||||
| 
 | 
 | ||||||
| void FilterManagerImpl::redrawColorPalette() | void FilterManagerImpl::redrawColorPalette() | ||||||
|  |  | ||||||
|  | @ -78,8 +78,6 @@ namespace app { | ||||||
| 
 | 
 | ||||||
|     void setProgressDelegate(IProgressDelegate* progressDelegate); |     void setProgressDelegate(IProgressDelegate* progressDelegate); | ||||||
| 
 | 
 | ||||||
|     doc::PixelFormat pixelFormat() const; |  | ||||||
| 
 |  | ||||||
|     void setTarget(Target target); |     void setTarget(Target target); | ||||||
|     void setCelsTarget(CelsTarget celsTarget); |     void setCelsTarget(CelsTarget celsTarget); | ||||||
| 
 | 
 | ||||||
|  | @ -109,6 +107,7 @@ namespace app { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     // FilterManager implementation
 |     // FilterManager implementation
 | ||||||
|  |     doc::PixelFormat pixelFormat() const override; | ||||||
|     const void* getSourceAddress() override; |     const void* getSourceAddress() override; | ||||||
|     void* getDestinationAddress() override; |     void* getDestinationAddress() override; | ||||||
|     int getWidth() override { return m_bounds.w; } |     int getWidth() override { return m_bounds.w; } | ||||||
|  | @ -137,6 +136,7 @@ namespace app { | ||||||
|     // modifies the palette).
 |     // modifies the palette).
 | ||||||
|     bool paletteHasChanged(); |     bool paletteHasChanged(); | ||||||
|     void restoreSpritePalette(); |     void restoreSpritePalette(); | ||||||
|  |     void applyToPaletteIfNeeded(); | ||||||
| 
 | 
 | ||||||
| #ifdef ENABLE_UI | #ifdef ENABLE_UI | ||||||
|     void redrawColorPalette(); |     void redrawColorPalette(); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,107 @@ | ||||||
|  | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
|  | //
 | ||||||
|  | // 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/app.h" | ||||||
|  | #include "app/commands/cmd_set_palette.h" | ||||||
|  | #include "app/commands/new_params.h" | ||||||
|  | #include "app/context.h" | ||||||
|  | #include "app/context_access.h" | ||||||
|  | #include "app/doc_api.h" | ||||||
|  | #include "app/pref/preferences.h" | ||||||
|  | #include "app/tx.h" | ||||||
|  | #include "app/util/pal_ops.h" | ||||||
|  | #include "doc/palette.h" | ||||||
|  | #include "doc/palette_picks.h" | ||||||
|  | #include "doc/remap.h" | ||||||
|  | 
 | ||||||
|  | namespace app { | ||||||
|  | 
 | ||||||
|  | using namespace ui; | ||||||
|  | 
 | ||||||
|  | struct MoveColorsParams : public NewParams { | ||||||
|  |   Param<int> before { this, 0, "before" }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class MoveColorsCommand : public CommandWithNewParams<MoveColorsParams> { | ||||||
|  | public: | ||||||
|  |   MoveColorsCommand(bool copy) | ||||||
|  |     : CommandWithNewParams<MoveColorsParams>( | ||||||
|  |         (copy ? CommandId::CopyColors(): | ||||||
|  |                 CommandId::MoveColors()), CmdRecordableFlag), | ||||||
|  |       m_copy(copy) { } | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |   bool onEnabled(Context* ctx) override { | ||||||
|  |     return ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable | | ||||||
|  |                            ContextFlags::HasSelectedColors); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void onExecute(Context* ctx) override { | ||||||
|  |     ContextWriter writer(ctx); | ||||||
|  |     Site site = ctx->activeSite(); | ||||||
|  | 
 | ||||||
|  |     PalettePicks picks = site.selectedColors(); | ||||||
|  |     if (picks.picks() == 0) | ||||||
|  |       return;                   // Do nothing
 | ||||||
|  | 
 | ||||||
|  |     ASSERT(writer.palette()); | ||||||
|  |     if (!writer.palette()) | ||||||
|  |       return; | ||||||
|  | 
 | ||||||
|  |     Tx tx(writer.context(), friendlyName(), ModifyDocument); | ||||||
|  |     const int beforeIndex = params().before(); | ||||||
|  |     int currentEntry = picks.firstPick(); | ||||||
|  | 
 | ||||||
|  | #ifdef ENABLE_UI | ||||||
|  |     if (ctx->isUIAvailable()) { | ||||||
|  |       auto& fgColor = Preferences::instance().colorBar.fgColor; | ||||||
|  |       if (fgColor().getType() == app::Color::IndexType) | ||||||
|  |         currentEntry = fgColor().getIndex(); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     doc::Palette palette(*writer.palette()); | ||||||
|  |     doc::Palette newPalette(palette); | ||||||
|  |     move_or_copy_palette_colors(palette, newPalette, picks, | ||||||
|  |                                 currentEntry, | ||||||
|  |                                 beforeIndex, | ||||||
|  |                                 m_copy); | ||||||
|  | 
 | ||||||
|  |     writer.document()->getApi(tx) | ||||||
|  |       .setPalette(writer.sprite(), writer.frame(), &newPalette); | ||||||
|  | 
 | ||||||
|  |     ctx->setSelectedColors(picks); | ||||||
|  | 
 | ||||||
|  | #ifdef ENABLE_UI | ||||||
|  |     if (ctx->isUIAvailable()) { | ||||||
|  |       auto& fgColor = Preferences::instance().colorBar.fgColor; | ||||||
|  |       if (fgColor().getType() == app::Color::IndexType) | ||||||
|  |         fgColor(Color::fromIndex(currentEntry)); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     tx.commit(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |   bool m_copy; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Command* CommandFactory::createMoveColorsCommand() | ||||||
|  | { | ||||||
|  |   return new MoveColorsCommand(false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Command* CommandFactory::createCopyColorsCommand() | ||||||
|  | { | ||||||
|  |   return new MoveColorsCommand(true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace app
 | ||||||
|  | @ -81,6 +81,11 @@ void Context::setActiveFrame(const doc::frame_t frame) | ||||||
|   onSetActiveFrame(frame); |   onSetActiveFrame(frame); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Context::setSelectedColors(const doc::PalettePicks& picks) | ||||||
|  | { | ||||||
|  |   onSetSelectedColors(picks); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool Context::hasModifiedDocuments() const | bool Context::hasModifiedDocuments() const | ||||||
| { | { | ||||||
|   for (auto doc : documents()) |   for (auto doc : documents()) | ||||||
|  | @ -217,6 +222,12 @@ void Context::onSetActiveFrame(const doc::frame_t frame) | ||||||
|     activeSiteHandler()->setActiveFrameInDoc(m_lastSelectedDoc, frame); |     activeSiteHandler()->setActiveFrameInDoc(m_lastSelectedDoc, frame); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Context::onSetSelectedColors(const doc::PalettePicks& picks) | ||||||
|  | { | ||||||
|  |   if (m_lastSelectedDoc) | ||||||
|  |     activeSiteHandler()->setSelectedColorsInDoc(m_lastSelectedDoc, picks); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Context::setTransaction(Transaction* transaction) | void Context::setTransaction(Transaction* transaction) | ||||||
| { | { | ||||||
|   if (transaction) { |   if (transaction) { | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace doc { | namespace doc { | ||||||
|   class Layer; |   class Layer; | ||||||
|  |   class PalettePicks; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| namespace app { | namespace app { | ||||||
|  | @ -85,6 +86,7 @@ namespace app { | ||||||
|     void setActiveDocument(Doc* document); |     void setActiveDocument(Doc* document); | ||||||
|     void setActiveLayer(doc::Layer* layer); |     void setActiveLayer(doc::Layer* layer); | ||||||
|     void setActiveFrame(doc::frame_t frame); |     void setActiveFrame(doc::frame_t frame); | ||||||
|  |     void setSelectedColors(const doc::PalettePicks& picks); | ||||||
|     bool hasModifiedDocuments() const; |     bool hasModifiedDocuments() const; | ||||||
|     void notifyActiveSiteChanged(); |     void notifyActiveSiteChanged(); | ||||||
| 
 | 
 | ||||||
|  | @ -111,6 +113,7 @@ namespace app { | ||||||
|     virtual void onSetActiveDocument(Doc* doc); |     virtual void onSetActiveDocument(Doc* doc); | ||||||
|     virtual void onSetActiveLayer(doc::Layer* layer); |     virtual void onSetActiveLayer(doc::Layer* layer); | ||||||
|     virtual void onSetActiveFrame(const doc::frame_t frame); |     virtual void onSetActiveFrame(const doc::frame_t frame); | ||||||
|  |     virtual void onSetSelectedColors(const doc::PalettePicks& picks); | ||||||
|     virtual void onCloseDocument(Doc* doc); |     virtual void onCloseDocument(Doc* doc); | ||||||
| 
 | 
 | ||||||
|     Doc* lastSelectedDoc() { return m_lastSelectedDoc; } |     Doc* lastSelectedDoc() { return m_lastSelectedDoc; } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| // Aseprite
 | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
| // Copyright (C) 2001-2018  David Capello
 | // Copyright (C) 2001-2018  David Capello
 | ||||||
| //
 | //
 | ||||||
| // This program is distributed under the terms of
 | // This program is distributed under the terms of
 | ||||||
|  | @ -109,6 +110,9 @@ void ContextFlags::updateFlagsFromSite(const Site& site) | ||||||
|         m_flags |= HasActiveImage; |         m_flags |= HasActiveImage; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   if (site.selectedColors().picks() > 0) | ||||||
|  |     m_flags |= HasSelectedColors; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace app
 | } // namespace app
 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| // Aseprite
 | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
| // Copyright (C) 2001-2018  David Capello
 | // Copyright (C) 2001-2018  David Capello
 | ||||||
| //
 | //
 | ||||||
| // This program is distributed under the terms of
 | // This program is distributed under the terms of
 | ||||||
|  | @ -32,6 +33,7 @@ namespace app { | ||||||
|       ActiveLayerIsVisible        = 1 << 11, |       ActiveLayerIsVisible        = 1 << 11, | ||||||
|       ActiveLayerIsEditable       = 1 << 12, |       ActiveLayerIsEditable       = 1 << 12, | ||||||
|       ActiveLayerIsReference      = 1 << 13, |       ActiveLayerIsReference      = 1 << 13, | ||||||
|  |       HasSelectedColors           = 1 << 14, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     ContextFlags(); |     ContextFlags(); | ||||||
|  |  | ||||||
|  | @ -466,18 +466,9 @@ int App_get_site(lua_State* L) | ||||||
| 
 | 
 | ||||||
| int App_get_range(lua_State* L) | int App_get_range(lua_State* L) | ||||||
| { | { | ||||||
| #ifdef ENABLE_UI |  | ||||||
|   app::Context* ctx = App::instance()->context(); |   app::Context* ctx = App::instance()->context(); | ||||||
|   Site site = ctx->activeSite(); |   Site site = ctx->activeSite(); | ||||||
|   if (site.sprite() && App::instance()->timeline()) { |   push_doc_range(L, site); | ||||||
|     push_doc_range(L, site, App::instance()->timeline()->range()); |  | ||||||
|   } |  | ||||||
|   else { |  | ||||||
|     lua_pushnil(L); |  | ||||||
|   } |  | ||||||
| #else |  | ||||||
|   lua_pushnil(L); |  | ||||||
| #endif |  | ||||||
|   return 1; |   return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -51,7 +51,6 @@ namespace tools { | ||||||
| 
 | 
 | ||||||
| namespace app { | namespace app { | ||||||
| 
 | 
 | ||||||
|   class DocRange; |  | ||||||
|   class Site; |   class Site; | ||||||
| 
 | 
 | ||||||
|   namespace script { |   namespace script { | ||||||
|  | @ -119,7 +118,7 @@ namespace app { | ||||||
|   void push_cels(lua_State* L, doc::Layer* layer); |   void push_cels(lua_State* L, doc::Layer* layer); | ||||||
|   void push_cels(lua_State* L, doc::Sprite* sprite); |   void push_cels(lua_State* L, doc::Sprite* sprite); | ||||||
|   void push_color_space(lua_State* L, const gfx::ColorSpace& cs); |   void push_color_space(lua_State* L, const gfx::ColorSpace& cs); | ||||||
|   void push_doc_range(lua_State* L, Site& site, const DocRange& docRange); |   void push_doc_range(lua_State* L, Site& site); | ||||||
|   void push_image(lua_State* L, doc::Image* image); |   void push_image(lua_State* L, doc::Image* image); | ||||||
|   void push_images(lua_State* L, const doc::ObjectIds& images); |   void push_images(lua_State* L, const doc::ObjectIds& images); | ||||||
|   void push_layers(lua_State* L, const doc::ObjectIds& layers); |   void push_layers(lua_State* L, const doc::ObjectIds& layers); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // Aseprite
 | // Aseprite
 | ||||||
| // Copyright (C) 2018  Igara Studio S.A.
 | // Copyright (C) 2018-2019  Igara Studio S.A.
 | ||||||
| //
 | //
 | ||||||
| // This program is distributed under the terms of
 | // This program is distributed under the terms of
 | ||||||
| // the End-User License Agreement for Aseprite.
 | // the End-User License Agreement for Aseprite.
 | ||||||
|  | @ -8,6 +8,8 @@ | ||||||
| #include "config.h" | #include "config.h" | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #include "app/app.h" | ||||||
|  | #include "app/context.h" | ||||||
| #include "app/doc_range.h" | #include "app/doc_range.h" | ||||||
| #include "app/script/docobj.h" | #include "app/script/docobj.h" | ||||||
| #include "app/script/engine.h" | #include "app/script/engine.h" | ||||||
|  | @ -34,8 +36,11 @@ struct RangeObj { // This is like DocRange but referencing objects with IDs | ||||||
|   std::set<ObjectId> layers; |   std::set<ObjectId> layers; | ||||||
|   std::vector<frame_t> frames; |   std::vector<frame_t> frames; | ||||||
|   std::set<ObjectId> cels; |   std::set<ObjectId> cels; | ||||||
|  |   std::vector<color_t> colors; | ||||||
|  | 
 | ||||||
|  |   RangeObj(Site& site) { | ||||||
|  |     const DocRange& docRange = site.range(); | ||||||
| 
 | 
 | ||||||
|   RangeObj(Site& site, const DocRange& docRange) { |  | ||||||
|     spriteId = site.sprite()->id(); |     spriteId = site.sprite()->id(); | ||||||
|     type = docRange.type(); |     type = docRange.type(); | ||||||
| 
 | 
 | ||||||
|  | @ -59,6 +64,9 @@ struct RangeObj { // This is like DocRange but referencing objects with IDs | ||||||
|       if (site.layer()) layers.insert(site.layer()->id()); |       if (site.layer()) layers.insert(site.layer()->id()); | ||||||
|       if (site.cel()) cels.insert(site.cel()->id()); |       if (site.cel()) cels.insert(site.cel()->id()); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     if (site.selectedColors().picks() > 0) | ||||||
|  |       colors = site.selectedColors().toVectorOfIndexes(); | ||||||
|   } |   } | ||||||
|   RangeObj(const RangeObj&) = delete; |   RangeObj(const RangeObj&) = delete; | ||||||
|   RangeObj& operator=(const RangeObj&) = delete; |   RangeObj& operator=(const RangeObj&) = delete; | ||||||
|  | @ -74,6 +82,9 @@ struct RangeObj { // This is like DocRange but referencing objects with IDs | ||||||
|   bool contains(const Cel* cel) const { |   bool contains(const Cel* cel) const { | ||||||
|     return cels.find(cel->id()) != cels.end(); |     return cels.find(cel->id()) != cels.end(); | ||||||
|   } |   } | ||||||
|  |   bool containsColor(const color_t color) const { | ||||||
|  |     return (std::find(colors.begin(), colors.end(), color) != colors.end()); | ||||||
|  |   } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int Range_gc(lua_State* L) | int Range_gc(lua_State* L) | ||||||
|  | @ -114,6 +125,14 @@ int Range_contains(lua_State* L) | ||||||
|   return 1; |   return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int Range_containsColor(lua_State* L) | ||||||
|  | { | ||||||
|  |   auto obj = get_obj<RangeObj>(L, 1); | ||||||
|  |   color_t color = lua_tointeger(L, 2); | ||||||
|  |   lua_pushboolean(L, obj->containsColor(color)); | ||||||
|  |   return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int Range_get_isEmpty(lua_State* L) | int Range_get_isEmpty(lua_State* L) | ||||||
| { | { | ||||||
|   auto obj = get_obj<RangeObj>(L, 1); |   auto obj = get_obj<RangeObj>(L, 1); | ||||||
|  | @ -181,9 +200,40 @@ int Range_get_editableImages(lua_State* L) | ||||||
|   return 1; |   return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int Range_get_colors(lua_State* L) | ||||||
|  | { | ||||||
|  |   auto obj = get_obj<RangeObj>(L, 1); | ||||||
|  |   lua_newtable(L); | ||||||
|  |   int j = 1; | ||||||
|  |   for (color_t i : obj->colors) { | ||||||
|  |     lua_pushinteger(L, i); | ||||||
|  |     lua_rawseti(L, -2, j++); | ||||||
|  |   } | ||||||
|  |   return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int Range_set_colors(lua_State* L) | ||||||
|  | { | ||||||
|  |   app::Context* ctx = App::instance()->context(); | ||||||
|  |   doc::PalettePicks picks; | ||||||
|  |   if (lua_istable(L, 2)) { | ||||||
|  |     lua_pushnil(L); | ||||||
|  |     while (lua_next(L, 2) != 0) { | ||||||
|  |       int i = lua_tointeger(L, -1); | ||||||
|  |       if (i >= picks.size()) | ||||||
|  |         picks.resize(i+1); | ||||||
|  |       picks[i] = true; | ||||||
|  |       lua_pop(L, 1); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   ctx->setSelectedColors(picks); | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const luaL_Reg Range_methods[] = { | const luaL_Reg Range_methods[] = { | ||||||
|   { "__gc", Range_gc }, |   { "__gc", Range_gc }, | ||||||
|   { "contains", Range_contains }, |   { "contains", Range_contains }, | ||||||
|  |   { "containsColor", Range_containsColor }, | ||||||
|   { nullptr, nullptr } |   { nullptr, nullptr } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -196,6 +246,7 @@ const Property Range_properties[] = { | ||||||
|   { "cels", Range_get_cels, nullptr }, |   { "cels", Range_get_cels, nullptr }, | ||||||
|   { "images", Range_get_images, nullptr }, |   { "images", Range_get_images, nullptr }, | ||||||
|   { "editableImages", Range_get_editableImages, nullptr }, |   { "editableImages", Range_get_editableImages, nullptr }, | ||||||
|  |   { "colors", Range_get_colors, Range_set_colors }, | ||||||
|   { nullptr, nullptr, nullptr } |   { nullptr, nullptr, nullptr } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -210,9 +261,9 @@ void register_range_class(lua_State* L) | ||||||
|   REG_CLASS_PROPERTIES(L, Range); |   REG_CLASS_PROPERTIES(L, Range); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void push_doc_range(lua_State* L, Site& site, const DocRange& docRange) | void push_doc_range(lua_State* L, Site& site) | ||||||
| { | { | ||||||
|   push_new<RangeObj>(L, site, docRange); |   push_new<RangeObj>(L, site); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace script
 | } // namespace script
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "app/doc_range.h" | #include "app/doc_range.h" | ||||||
| #include "doc/frame.h" | #include "doc/frame.h" | ||||||
|  | #include "doc/palette_picks.h" | ||||||
| #include "doc/selected_objects.h" | #include "doc/selected_objects.h" | ||||||
| 
 | 
 | ||||||
| namespace doc { | namespace doc { | ||||||
|  | @ -78,6 +79,13 @@ namespace app { | ||||||
|     const doc::SelectedLayers& selectedLayers() const { return m_range.selectedLayers(); } |     const doc::SelectedLayers& selectedLayers() const { return m_range.selectedLayers(); } | ||||||
|     const doc::SelectedFrames& selectedFrames() const { return m_range.selectedFrames(); } |     const doc::SelectedFrames& selectedFrames() const { return m_range.selectedFrames(); } | ||||||
| 
 | 
 | ||||||
|  |     // Selected colors selected in the ColorBar
 | ||||||
|  |     const doc::PalettePicks& selectedColors() const { return m_selectedColors; } | ||||||
|  |     doc::PalettePicks& selectedColors() { return m_selectedColors; } | ||||||
|  |     void selectedColors(const doc::PalettePicks& colors) { | ||||||
|  |       m_selectedColors = colors; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     const doc::SelectedObjects& selectedSlices() const { return m_selectedSlices; } |     const doc::SelectedObjects& selectedSlices() const { return m_selectedSlices; } | ||||||
|     doc::SelectedObjects& selectedSlices() { return m_selectedSlices; } |     doc::SelectedObjects& selectedSlices() { return m_selectedSlices; } | ||||||
|     void selectedSlices(const doc::SelectedObjects& set) { |     void selectedSlices(const doc::SelectedObjects& set) { | ||||||
|  | @ -95,6 +103,7 @@ namespace app { | ||||||
|     doc::Layer* m_layer; |     doc::Layer* m_layer; | ||||||
|     doc::frame_t m_frame; |     doc::frame_t m_frame; | ||||||
|     DocRange m_range; |     DocRange m_range; | ||||||
|  |     doc::PalettePicks m_selectedColors; | ||||||
|     doc::SelectedObjects m_selectedSlices; |     doc::SelectedObjects m_selectedSlices; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ | ||||||
| #include "app/ui/skin/skin_theme.h" | #include "app/ui/skin/skin_theme.h" | ||||||
| #include "app/ui/status_bar.h" | #include "app/ui/status_bar.h" | ||||||
| #include "app/util/clipboard.h" | #include "app/util/clipboard.h" | ||||||
|  | #include "app/util/pal_ops.h" | ||||||
| #include "base/bind.h" | #include "base/bind.h" | ||||||
| #include "base/convert_to.h" | #include "base/convert_to.h" | ||||||
| #include "doc/image.h" | #include "doc/image.h" | ||||||
|  | @ -189,6 +190,18 @@ int PaletteView::getSelectedEntriesCount() const | ||||||
|   return m_selectedEntries.picks(); |   return m_selectedEntries.picks(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void PaletteView::setSelectedEntries(const doc::PalettePicks& entries) | ||||||
|  | { | ||||||
|  |   ASSERT(currentPalette()); | ||||||
|  |   if (!currentPalette()) | ||||||
|  |     return; | ||||||
|  | 
 | ||||||
|  |   m_selectedEntries = entries; | ||||||
|  |   m_selectedEntries.resize(currentPalette()->size()); | ||||||
|  |   m_currentEntry = m_selectedEntries.firstPick(); | ||||||
|  |   invalidate(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| app::Color PaletteView::getColorByPosition(const gfx::Point& pos) | app::Color PaletteView::getColorByPosition(const gfx::Point& pos) | ||||||
| { | { | ||||||
|   gfx::Point relPos = pos - bounds().origin(); |   gfx::Point relPos = pos - bounds().origin(); | ||||||
|  | @ -777,58 +790,14 @@ PaletteView::Hit PaletteView::hitTest(const gfx::Point& pos) | ||||||
| void PaletteView::dropColors(int beforeIndex) | void PaletteView::dropColors(int beforeIndex) | ||||||
| { | { | ||||||
|   Palette palette(*currentPalette()); |   Palette palette(*currentPalette()); | ||||||
|   if (beforeIndex >= palette.size()) { |  | ||||||
|     palette.resize(beforeIndex); |  | ||||||
|     m_selectedEntries.resize(palette.size()); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   Palette newPalette(palette); |   Palette newPalette(palette); | ||||||
|   Remap remap(palette.size()); |   move_or_copy_palette_colors( | ||||||
| 
 |     palette, | ||||||
|   // Copy colors
 |     newPalette, | ||||||
|   if (m_copy) { |     m_selectedEntries, | ||||||
|     int picks = m_selectedEntries.picks(); |     m_currentEntry, | ||||||
|     ASSERT(picks >= 1); |     beforeIndex, | ||||||
| 
 |     m_copy); | ||||||
|     remap = create_remap_to_expand_palette(palette.size()+picks, |  | ||||||
|                                            picks, |  | ||||||
|                                            beforeIndex); |  | ||||||
| 
 |  | ||||||
|     newPalette.resize(palette.size()+picks); |  | ||||||
|     for (int i=0; i<palette.size(); ++i) |  | ||||||
|       newPalette.setEntry(remap[i], palette.getEntry(i)); |  | ||||||
| 
 |  | ||||||
|     for (int i=0, j=0; i<palette.size(); ++i) { |  | ||||||
|       if (m_selectedEntries[i]) |  | ||||||
|         newPalette.setEntry(beforeIndex + (j++), palette.getEntry(i)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for (int i=0, j=0; i<palette.size(); ++i) { |  | ||||||
|       if (m_selectedEntries[i]) { |  | ||||||
|         if (m_currentEntry == i) { |  | ||||||
|           m_currentEntry = beforeIndex + j; |  | ||||||
|           break; |  | ||||||
|         } |  | ||||||
|         ++j; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     for (int i=0; i<palette.size(); ++i) |  | ||||||
|       m_selectedEntries[i] = (i >= beforeIndex && i < beforeIndex + picks); |  | ||||||
|   } |  | ||||||
|   // Move colors
 |  | ||||||
|   else { |  | ||||||
|     remap = create_remap_to_move_picks(m_selectedEntries, beforeIndex); |  | ||||||
| 
 |  | ||||||
|     auto oldSelectedCopies = m_selectedEntries; |  | ||||||
|     for (int i=0; i<palette.size(); ++i) { |  | ||||||
|       newPalette.setEntry(remap[i], palette.getEntry(i)); |  | ||||||
|       m_selectedEntries[remap[i]] = oldSelectedCopies[i]; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     m_currentEntry = remap[m_currentEntry]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   setNewPalette(&palette, &newPalette, |   setNewPalette(&palette, &newPalette, | ||||||
|                 PaletteViewModification::DRAGANDDROP); |                 PaletteViewModification::DRAGANDDROP); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -70,6 +70,7 @@ namespace app { | ||||||
|     bool getSelectedRange(int& index1, int& index2) const; |     bool getSelectedRange(int& index1, int& index2) const; | ||||||
|     void getSelectedEntries(doc::PalettePicks& entries) const; |     void getSelectedEntries(doc::PalettePicks& entries) const; | ||||||
|     int getSelectedEntriesCount() const; |     int getSelectedEntriesCount() const; | ||||||
|  |     void setSelectedEntries(const doc::PalettePicks& entries); | ||||||
| 
 | 
 | ||||||
|     // IColorSource
 |     // IColorSource
 | ||||||
|     app::Color getColorByPosition(const gfx::Point& pos) override; |     app::Color getColorByPosition(const gfx::Point& pos) override; | ||||||
|  |  | ||||||
|  | @ -166,6 +166,16 @@ void UIContext::onSetActiveFrame(const doc::frame_t frame) | ||||||
|     Context::onSetActiveFrame(frame); |     Context::onSetActiveFrame(frame); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void UIContext::onSetSelectedColors(const doc::PalettePicks& picks) | ||||||
|  | { | ||||||
|  |   if (DocView* docView = activeView()) { | ||||||
|  |     if (ColorBar* colorBar = ColorBar::instance()) | ||||||
|  |       colorBar->getPaletteView()->setSelectedEntries(picks); | ||||||
|  |   } | ||||||
|  |   else if (!isUIAvailable()) | ||||||
|  |     Context::onSetSelectedColors(picks); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| DocView* UIContext::getFirstDocView(Doc* document) const | DocView* UIContext::getFirstDocView(Doc* document) const | ||||||
| { | { | ||||||
|   Workspace* workspace = App::instance()->workspace(); |   Workspace* workspace = App::instance()->workspace(); | ||||||
|  | @ -294,7 +304,7 @@ void UIContext::onGetActiveSite(Site* site) const | ||||||
|     view->getSite(site); |     view->getSite(site); | ||||||
| 
 | 
 | ||||||
|     if (site->sprite()) { |     if (site->sprite()) { | ||||||
|       // Selected layers
 |       // Selected range in the timeline
 | ||||||
|       Timeline* timeline = App::instance()->timeline(); |       Timeline* timeline = App::instance()->timeline(); | ||||||
|       if (timeline && |       if (timeline && | ||||||
|           timeline->range().enabled()) { |           timeline->range().enabled()) { | ||||||
|  | @ -305,6 +315,10 @@ void UIContext::onGetActiveSite(Site* site) const | ||||||
|         if (colorBar && |         if (colorBar && | ||||||
|             colorBar->getPaletteView()->getSelectedEntriesCount() > 0) { |             colorBar->getPaletteView()->getSelectedEntriesCount() > 0) { | ||||||
|           site->focus(Site::InColorBar); |           site->focus(Site::InColorBar); | ||||||
|  | 
 | ||||||
|  |           doc::PalettePicks picks; | ||||||
|  |           colorBar->getPaletteView()->getSelectedEntries(picks); | ||||||
|  |           site->selectedColors(picks); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|           site->focus(Site::InEditor); |           site->focus(Site::InEditor); | ||||||
|  |  | ||||||
|  | @ -56,6 +56,7 @@ namespace app { | ||||||
|     void onSetActiveDocument(Doc* doc) override; |     void onSetActiveDocument(Doc* doc) override; | ||||||
|     void onSetActiveLayer(doc::Layer* layer) override; |     void onSetActiveLayer(doc::Layer* layer) override; | ||||||
|     void onSetActiveFrame(const doc::frame_t frame) override; |     void onSetActiveFrame(const doc::frame_t frame) override; | ||||||
|  |     void onSetSelectedColors(const doc::PalettePicks& picks) override; | ||||||
|     void onCloseDocument(Doc* doc) override; |     void onCloseDocument(Doc* doc) override; | ||||||
| 
 | 
 | ||||||
|   private: |   private: | ||||||
|  |  | ||||||
|  | @ -0,0 +1,80 @@ | ||||||
|  | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
|  | //
 | ||||||
|  | // 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/util/pal_ops.h" | ||||||
|  | 
 | ||||||
|  | #include "doc/palette.h" | ||||||
|  | #include "doc/palette_picks.h" | ||||||
|  | #include "doc/remap.h" | ||||||
|  | 
 | ||||||
|  | namespace app { | ||||||
|  | 
 | ||||||
|  | void move_or_copy_palette_colors( | ||||||
|  |   doc::Palette& palette, | ||||||
|  |   doc::Palette& newPalette, | ||||||
|  |   doc::PalettePicks& picks, | ||||||
|  |   int& currentEntry, | ||||||
|  |   const int beforeIndex, | ||||||
|  |   const bool copy) | ||||||
|  | { | ||||||
|  |   if (beforeIndex >= palette.size()) { | ||||||
|  |     palette.resize(beforeIndex); // TODO is need to resize the
 | ||||||
|  |                                  // palette? why not "const Palette& palette"
 | ||||||
|  |     picks.resize(palette.size()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   palette.copyColorsTo(&newPalette); | ||||||
|  |   doc::Remap remap(palette.size()); | ||||||
|  | 
 | ||||||
|  |   // Copy colors
 | ||||||
|  |   if (copy) { | ||||||
|  |     int npicks = picks.picks(); | ||||||
|  |     ASSERT(npicks >= 1); | ||||||
|  | 
 | ||||||
|  |     remap = doc::create_remap_to_expand_palette(palette.size()+npicks, | ||||||
|  |                                                 npicks, beforeIndex); | ||||||
|  | 
 | ||||||
|  |     newPalette.resize(palette.size()+npicks); | ||||||
|  |     for (int i=0; i<palette.size(); ++i) | ||||||
|  |       newPalette.setEntry(remap[i], palette.getEntry(i)); | ||||||
|  | 
 | ||||||
|  |     for (int i=0, j=0; i<palette.size(); ++i) { | ||||||
|  |       if (picks[i]) | ||||||
|  |         newPalette.setEntry(beforeIndex + (j++), palette.getEntry(i)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (int i=0, j=0; i<palette.size(); ++i) { | ||||||
|  |       if (picks[i]) { | ||||||
|  |         if (currentEntry == i) { | ||||||
|  |           currentEntry = beforeIndex + j; | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |         ++j; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (int i=0; i<palette.size(); ++i) | ||||||
|  |       picks[i] = (i >= beforeIndex && i < beforeIndex + npicks); | ||||||
|  |   } | ||||||
|  |   // Move colors
 | ||||||
|  |   else { | ||||||
|  |     remap = doc::create_remap_to_move_picks(picks, beforeIndex); | ||||||
|  | 
 | ||||||
|  |     auto oldPicks = picks; | ||||||
|  |     for (int i=0; i<palette.size(); ++i) { | ||||||
|  |       newPalette.setEntry(remap[i], palette.getEntry(i)); | ||||||
|  |       picks[remap[i]] = oldPicks[i]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     currentEntry = remap[currentEntry]; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace app
 | ||||||
|  | @ -0,0 +1,29 @@ | ||||||
|  | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
|  | //
 | ||||||
|  | // This program is distributed under the terms of
 | ||||||
|  | // the End-User License Agreement for Aseprite.
 | ||||||
|  | 
 | ||||||
|  | #ifndef APP_UTIL_PAL_OPS_H_INCLUDED | ||||||
|  | #define APP_UTIL_PAL_OPS_H_INCLUDED | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | namespace doc { | ||||||
|  |   class Palette; | ||||||
|  |   class PalettePicks; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace app { | ||||||
|  |   class Tx; | ||||||
|  | 
 | ||||||
|  |   void move_or_copy_palette_colors( | ||||||
|  |     doc::Palette& palette, | ||||||
|  |     doc::Palette& newPalette, | ||||||
|  |     doc::PalettePicks& picks, | ||||||
|  |     int& currentEntry, | ||||||
|  |     const int beforeIndex, | ||||||
|  |     const bool copy); | ||||||
|  | 
 | ||||||
|  | } // namespace app
 | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| // Aseprite Document Library
 | // Aseprite Document Library
 | ||||||
|  | // Copyright (c) 2019 Igara Studio S.A.
 | ||||||
| // Copyright (c) 2001-2017 David Capello
 | // Copyright (c) 2001-2017 David Capello
 | ||||||
| //
 | //
 | ||||||
| // This file is released under the terms of the MIT license.
 | // This file is released under the terms of the MIT license.
 | ||||||
|  | @ -8,6 +9,8 @@ | ||||||
| #define DOC_PALETTE_PICKS_H_INCLUDED | #define DOC_PALETTE_PICKS_H_INCLUDED | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include "doc/color.h" | ||||||
|  | 
 | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <vector> | #include <vector> | ||||||
| 
 | 
 | ||||||
|  | @ -68,6 +71,15 @@ namespace doc { | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     std::vector<color_t> toVectorOfIndexes() const { | ||||||
|  |       std::vector<color_t> result(picks()); | ||||||
|  |       for (color_t i=0, j=0; i<size(); ++i) { | ||||||
|  |         if (m_items[i]) | ||||||
|  |           result[j++] = i; | ||||||
|  |       } | ||||||
|  |       return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|   private: |   private: | ||||||
|     list_type m_items; |     list_type m_items; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| # Aseprite | # Aseprite | ||||||
|  | # Copyright (C) 2019  Igara Studio S.A. | ||||||
| # Copyright (C) 2001-2017  David Capello | # Copyright (C) 2001-2017  David Capello | ||||||
| 
 | 
 | ||||||
| add_library(filters-lib | add_library(filters-lib | ||||||
|  | @ -7,6 +8,7 @@ add_library(filters-lib | ||||||
|   color_curve_filter.cpp |   color_curve_filter.cpp | ||||||
|   convolution_matrix.cpp |   convolution_matrix.cpp | ||||||
|   convolution_matrix_filter.cpp |   convolution_matrix_filter.cpp | ||||||
|  |   filter.cpp | ||||||
|   hue_saturation_filter.cpp |   hue_saturation_filter.cpp | ||||||
|   invert_color_filter.cpp |   invert_color_filter.cpp | ||||||
|   median_filter.cpp |   median_filter.cpp | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| // Aseprite
 | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
| // Copyright (C) 2017  David Capello
 | // Copyright (C) 2017  David Capello
 | ||||||
| //
 | //
 | ||||||
| // This program is distributed under the terms of
 | // This program is distributed under the terms of
 | ||||||
|  | @ -52,15 +53,8 @@ void BrightnessContrastFilter::setContrast(double contrast) | ||||||
| void BrightnessContrastFilter::applyToRgba(FilterManager* filterMgr) | void BrightnessContrastFilter::applyToRgba(FilterManager* filterMgr) | ||||||
| { | { | ||||||
|   FilterIndexedData* fid = filterMgr->getIndexedData(); |   FilterIndexedData* fid = filterMgr->getIndexedData(); | ||||||
| 
 |  | ||||||
|   if (filterMgr->isFirstRow()) { |  | ||||||
|     m_picks = fid->getPalettePicks(); |  | ||||||
|     m_usePalette = (m_picks.picks() > 0); |  | ||||||
|     if (m_usePalette) |  | ||||||
|       applyToPalette(filterMgr); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   const Palette* pal = fid->getPalette(); |   const Palette* pal = fid->getPalette(); | ||||||
|  |   Palette* newPal = (m_usePaletteOnRGB ? fid->getNewPalette(): nullptr); | ||||||
|   const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress(); |   const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress(); | ||||||
|   uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); |   uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); | ||||||
|   const int w = filterMgr->getWidth(); |   const int w = filterMgr->getWidth(); | ||||||
|  | @ -75,14 +69,14 @@ void BrightnessContrastFilter::applyToRgba(FilterManager* filterMgr) | ||||||
| 
 | 
 | ||||||
|     color_t c = *(src_address++); |     color_t c = *(src_address++); | ||||||
| 
 | 
 | ||||||
|     if (m_usePalette) { |     if (newPal) { | ||||||
|       int i = |       int i = | ||||||
|         pal->findExactMatch(rgba_getr(c), |         pal->findExactMatch(rgba_getr(c), | ||||||
|                             rgba_getg(c), |                             rgba_getg(c), | ||||||
|                             rgba_getb(c), |                             rgba_getb(c), | ||||||
|                             rgba_geta(c), -1); |                             rgba_geta(c), -1); | ||||||
|       if (i >= 0) |       if (i >= 0) | ||||||
|         c = fid->getNewPalette()->getEntry(i); |         c = newPal->getEntry(i); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       applyFilterToRgb(target, c); |       applyFilterToRgb(target, c); | ||||||
|  | @ -120,19 +114,12 @@ void BrightnessContrastFilter::applyToIndexed(FilterManager* filterMgr) | ||||||
| { | { | ||||||
|   FilterIndexedData* fid = filterMgr->getIndexedData(); |   FilterIndexedData* fid = filterMgr->getIndexedData(); | ||||||
| 
 | 
 | ||||||
|   // Apply filter to color palette if there is no selection
 |   // Apply filter to pixels if there is selection (in other case, the
 | ||||||
|   if (!filterMgr->isMaskActive()) { |   // change is global, so we have already applied the filter to the
 | ||||||
|     if (!filterMgr->isFirstRow()) |   // palette).
 | ||||||
|  |   if (!filterMgr->isMaskActive()) | ||||||
|     return; |     return; | ||||||
| 
 | 
 | ||||||
|     m_picks = fid->getPalettePicks(); |  | ||||||
|     if (m_picks.picks() == 0) |  | ||||||
|       m_picks.all(); |  | ||||||
| 
 |  | ||||||
|     applyToPalette(filterMgr); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // Apply filter to color region
 |   // Apply filter to color region
 | ||||||
|   const Target target = filterMgr->getTarget(); |   const Target target = filterMgr->getTarget(); | ||||||
|   const Palette* pal = fid->getPalette(); |   const Palette* pal = fid->getPalette(); | ||||||
|  | @ -157,7 +144,8 @@ void BrightnessContrastFilter::applyToIndexed(FilterManager* filterMgr) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void BrightnessContrastFilter::applyToPalette(FilterManager* filterMgr) | void BrightnessContrastFilter::onApplyToPalette(FilterManager* filterMgr, | ||||||
|  |                                                 const PalettePicks& picks) | ||||||
| { | { | ||||||
|   const Target target = filterMgr->getTarget(); |   const Target target = filterMgr->getTarget(); | ||||||
|   FilterIndexedData* fid = filterMgr->getIndexedData(); |   FilterIndexedData* fid = filterMgr->getIndexedData(); | ||||||
|  | @ -165,7 +153,7 @@ void BrightnessContrastFilter::applyToPalette(FilterManager* filterMgr) | ||||||
|   Palette* newPal = fid->getNewPalette(); |   Palette* newPal = fid->getNewPalette(); | ||||||
| 
 | 
 | ||||||
|   int i = 0; |   int i = 0; | ||||||
|   for (bool state : m_picks) { |   for (bool state : picks) { | ||||||
|     if (!state) { |     if (!state) { | ||||||
|       ++i; |       ++i; | ||||||
|       continue; |       continue; | ||||||
|  |  | ||||||
|  | @ -18,7 +18,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace filters { | namespace filters { | ||||||
| 
 | 
 | ||||||
|   class BrightnessContrastFilter : public Filter { |   class BrightnessContrastFilter : public FilterWithPalette { | ||||||
|   public: |   public: | ||||||
|     BrightnessContrastFilter(); |     BrightnessContrastFilter(); | ||||||
| 
 | 
 | ||||||
|  | @ -28,19 +28,18 @@ namespace filters { | ||||||
|     void setContrast(double contrast); |     void setContrast(double contrast); | ||||||
| 
 | 
 | ||||||
|     // Filter implementation
 |     // Filter implementation
 | ||||||
|     const char* getName(); |     const char* getName() override; | ||||||
|     void applyToRgba(FilterManager* filterMgr); |     void applyToRgba(FilterManager* filterMgr) override; | ||||||
|     void applyToGrayscale(FilterManager* filterMgr); |     void applyToGrayscale(FilterManager* filterMgr) override; | ||||||
|     void applyToIndexed(FilterManager* filterMgr); |     void applyToIndexed(FilterManager* filterMgr) override; | ||||||
| 
 | 
 | ||||||
|   private: |   private: | ||||||
|     void applyToPalette(FilterManager* filterMgr); |     void onApplyToPalette(FilterManager* filterMgr, | ||||||
|  |                           const doc::PalettePicks& picks) override; | ||||||
|     void applyFilterToRgb(const Target target, doc::color_t& color); |     void applyFilterToRgb(const Target target, doc::color_t& color); | ||||||
|     void updateMap(); |     void updateMap(); | ||||||
| 
 | 
 | ||||||
|     double m_brightness, m_contrast; |     double m_brightness, m_contrast; | ||||||
|     doc::PalettePicks m_picks; |  | ||||||
|     bool m_usePalette; |  | ||||||
|     std::vector<int> m_cmap; |     std::vector<int> m_cmap; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,60 @@ | ||||||
|  | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
|  | //
 | ||||||
|  | // This program is distributed under the terms of
 | ||||||
|  | // the End-User License Agreement for Aseprite.
 | ||||||
|  | 
 | ||||||
|  | #ifdef HAVE_CONFIG_H | ||||||
|  | #include "config.h" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include "filters/filter.h" | ||||||
|  | 
 | ||||||
|  | #include "doc/palette.h" | ||||||
|  | #include "doc/palette_picks.h" | ||||||
|  | #include "filters/filter_indexed_data.h" | ||||||
|  | #include "filters/filter_manager.h" | ||||||
|  | 
 | ||||||
|  | namespace filters { | ||||||
|  | 
 | ||||||
|  | FilterWithPalette::FilterWithPalette() | ||||||
|  |   : m_usePaletteOnRGB(false) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void FilterWithPalette::applyToPalette(FilterManager* filterMgr) | ||||||
|  | { | ||||||
|  |   FilterIndexedData* fid = filterMgr->getIndexedData(); | ||||||
|  |   doc::PalettePicks picks = fid->getPalettePicks(); | ||||||
|  | 
 | ||||||
|  |   switch (filterMgr->pixelFormat()) { | ||||||
|  | 
 | ||||||
|  |     case doc::IMAGE_RGB: | ||||||
|  |       m_usePaletteOnRGB = (picks.picks() > 0); | ||||||
|  |       if (!m_usePaletteOnRGB) | ||||||
|  |         return; | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |     case doc::IMAGE_INDEXED: | ||||||
|  |       // If there is a selection, we don't apply the filter to color
 | ||||||
|  |       // palette, instead we apply the filter to the pixels as an RGB
 | ||||||
|  |       // image (using closest colors from the palette)
 | ||||||
|  |       if (filterMgr->isMaskActive()) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |       // If there are no picks, we apply the filter to the whole palette.
 | ||||||
|  |       if (picks.picks() == 0) { | ||||||
|  |         picks.resize(fid->getPalette()->size()); | ||||||
|  |         picks.all(); | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |     default: | ||||||
|  |       // We cannot change the palette of a grayscale image
 | ||||||
|  |       return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   onApplyToPalette(filterMgr, picks); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace filters
 | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| // Aseprite
 | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
| // Copyright (C) 2001-2015  David Capello
 | // Copyright (C) 2001-2015  David Capello
 | ||||||
| //
 | //
 | ||||||
| // This program is distributed under the terms of
 | // This program is distributed under the terms of
 | ||||||
|  | @ -8,6 +9,10 @@ | ||||||
| #define FILTERS_FILTER_H_INCLUDED | #define FILTERS_FILTER_H_INCLUDED | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | namespace doc { | ||||||
|  |   class PalettePicks; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| namespace filters { | namespace filters { | ||||||
| 
 | 
 | ||||||
|   class FilterManager; |   class FilterManager; | ||||||
|  | @ -37,6 +42,22 @@ namespace filters { | ||||||
|     // each pixel.
 |     // each pixel.
 | ||||||
|     virtual void applyToIndexed(FilterManager* filterMgr) = 0; |     virtual void applyToIndexed(FilterManager* filterMgr) = 0; | ||||||
| 
 | 
 | ||||||
|  |     // Applies the filter to the color palette.
 | ||||||
|  |     virtual void applyToPalette(FilterManager* filterMgr) { } | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   // Filter that support applying it only to palette colors.
 | ||||||
|  |   class FilterWithPalette : public Filter { | ||||||
|  |   public: | ||||||
|  |     FilterWithPalette(); | ||||||
|  |     void applyToPalette(FilterManager* filterMgr) override; | ||||||
|  | 
 | ||||||
|  |   protected: | ||||||
|  |     virtual void onApplyToPalette(FilterManager* filterMgr, | ||||||
|  |                                   const doc::PalettePicks& picks) = 0; | ||||||
|  | 
 | ||||||
|  |     // Use the palette to replace colors in RGB images
 | ||||||
|  |     bool m_usePaletteOnRGB; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| } // namespace filters
 | } // namespace filters
 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| // Aseprite
 | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
| // Copyright (C) 2001-2017  David Capello
 | // Copyright (C) 2001-2017  David Capello
 | ||||||
| //
 | //
 | ||||||
| // This program is distributed under the terms of
 | // This program is distributed under the terms of
 | ||||||
|  | @ -8,6 +9,7 @@ | ||||||
| #define FILTERS_FILTER_MANAGER_H_INCLUDED | #define FILTERS_FILTER_MANAGER_H_INCLUDED | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include "doc/pixel_format.h" | ||||||
| #include "filters/target.h" | #include "filters/target.h" | ||||||
| 
 | 
 | ||||||
| namespace doc { | namespace doc { | ||||||
|  | @ -27,6 +29,8 @@ namespace filters { | ||||||
|   public: |   public: | ||||||
|     virtual ~FilterManager() { } |     virtual ~FilterManager() { } | ||||||
| 
 | 
 | ||||||
|  |     virtual doc::PixelFormat pixelFormat() const = 0; | ||||||
|  | 
 | ||||||
|     // Gets the address of the first pixel which has the original color
 |     // Gets the address of the first pixel which has the original color
 | ||||||
|     // to apply the filter.
 |     // to apply the filter.
 | ||||||
|     virtual const void* getSourceAddress() = 0; |     virtual const void* getSourceAddress() = 0; | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| // Aseprite
 | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
| // Copyright (C) 2017-2018  David Capello
 | // Copyright (C) 2017-2018  David Capello
 | ||||||
| //
 | //
 | ||||||
| // This program is distributed under the terms of
 | // This program is distributed under the terms of
 | ||||||
|  | @ -12,6 +13,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "doc/image.h" | #include "doc/image.h" | ||||||
| #include "doc/palette.h" | #include "doc/palette.h" | ||||||
|  | #include "doc/palette_picks.h" | ||||||
| #include "doc/rgbmap.h" | #include "doc/rgbmap.h" | ||||||
| #include "filters/filter_indexed_data.h" | #include "filters/filter_indexed_data.h" | ||||||
| #include "filters/filter_manager.h" | #include "filters/filter_manager.h" | ||||||
|  | @ -67,15 +69,8 @@ void HueSaturationFilter::setAlpha(double a) | ||||||
| void HueSaturationFilter::applyToRgba(FilterManager* filterMgr) | void HueSaturationFilter::applyToRgba(FilterManager* filterMgr) | ||||||
| { | { | ||||||
|   FilterIndexedData* fid = filterMgr->getIndexedData(); |   FilterIndexedData* fid = filterMgr->getIndexedData(); | ||||||
| 
 |  | ||||||
|   if (filterMgr->isFirstRow()) { |  | ||||||
|     m_picks = fid->getPalettePicks(); |  | ||||||
|     m_usePalette = (m_picks.picks() > 0); |  | ||||||
|     if (m_usePalette) |  | ||||||
|       applyToPalette(filterMgr); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   const Palette* pal = fid->getPalette(); |   const Palette* pal = fid->getPalette(); | ||||||
|  |   Palette* newPal = (m_usePaletteOnRGB ? fid->getNewPalette(): nullptr); | ||||||
|   const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress(); |   const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress(); | ||||||
|   uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); |   uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); | ||||||
|   const int w = filterMgr->getWidth(); |   const int w = filterMgr->getWidth(); | ||||||
|  | @ -90,14 +85,14 @@ void HueSaturationFilter::applyToRgba(FilterManager* filterMgr) | ||||||
| 
 | 
 | ||||||
|     color_t c = *(src_address++); |     color_t c = *(src_address++); | ||||||
| 
 | 
 | ||||||
|     if (m_usePalette) { |     if (newPal) { | ||||||
|       int i = |       int i = | ||||||
|         pal->findExactMatch(rgba_getr(c), |         pal->findExactMatch(rgba_getr(c), | ||||||
|                             rgba_getg(c), |                             rgba_getg(c), | ||||||
|                             rgba_getb(c), |                             rgba_getb(c), | ||||||
|                             rgba_geta(c), -1); |                             rgba_geta(c), -1); | ||||||
|       if (i >= 0) |       if (i >= 0) | ||||||
|         c = fid->getNewPalette()->getEntry(i); |         c = newPal->getEntry(i); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       applyFilterToRgb(target, c); |       applyFilterToRgb(target, c); | ||||||
|  | @ -148,22 +143,14 @@ void HueSaturationFilter::applyToGrayscale(FilterManager* filterMgr) | ||||||
| 
 | 
 | ||||||
| void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr) | void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr) | ||||||
| { | { | ||||||
|   FilterIndexedData* fid = filterMgr->getIndexedData(); |   // Apply filter to pixels if there is selection (in other case, the
 | ||||||
| 
 |   // change is global, so we have already applied the filter to the
 | ||||||
|   // Apply filter to color palette if there is no selection
 |   // palette).
 | ||||||
|   if (!filterMgr->isMaskActive()) { |   if (!filterMgr->isMaskActive()) | ||||||
|     if (!filterMgr->isFirstRow()) |  | ||||||
|     return; |     return; | ||||||
| 
 | 
 | ||||||
|     m_picks = fid->getPalettePicks(); |  | ||||||
|     if (m_picks.picks() == 0) |  | ||||||
|       m_picks.all(); |  | ||||||
| 
 |  | ||||||
|     applyToPalette(filterMgr); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // Apply filter to color region
 |   // Apply filter to color region
 | ||||||
|  |   FilterIndexedData* fid = filterMgr->getIndexedData(); | ||||||
|   const Target target = filterMgr->getTarget(); |   const Target target = filterMgr->getTarget(); | ||||||
|   const Palette* pal = fid->getPalette(); |   const Palette* pal = fid->getPalette(); | ||||||
|   const RgbMap* rgbmap = fid->getRgbMap(); |   const RgbMap* rgbmap = fid->getRgbMap(); | ||||||
|  | @ -187,15 +174,16 @@ void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HueSaturationFilter::applyToPalette(FilterManager* filterMgr) | void HueSaturationFilter::onApplyToPalette(FilterManager* filterMgr, | ||||||
|  |                                            const PalettePicks& picks) | ||||||
| { | { | ||||||
|   const Target target = filterMgr->getTarget(); |  | ||||||
|   FilterIndexedData* fid = filterMgr->getIndexedData(); |   FilterIndexedData* fid = filterMgr->getIndexedData(); | ||||||
|  |   const Target target = filterMgr->getTarget(); | ||||||
|   const Palette* pal = fid->getPalette(); |   const Palette* pal = fid->getPalette(); | ||||||
|   Palette* newPal = fid->getNewPalette(); |   Palette* newPal = fid->getNewPalette(); | ||||||
| 
 | 
 | ||||||
|   int i = 0; |   int i = 0; | ||||||
|   for (bool state : m_picks) { |   for (bool state : picks) { | ||||||
|     if (!state) { |     if (!state) { | ||||||
|       ++i; |       ++i; | ||||||
|       continue; |       continue; | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| // Aseprite
 | // Aseprite
 | ||||||
|  | // Copyright (C) 2019  Igara Studio S.A.
 | ||||||
| // Copyright (C) 2017-2018  David Capello
 | // Copyright (C) 2017-2018  David Capello
 | ||||||
| //
 | //
 | ||||||
| // This program is distributed under the terms of
 | // This program is distributed under the terms of
 | ||||||
|  | @ -9,13 +10,12 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "doc/color.h" | #include "doc/color.h" | ||||||
| #include "doc/palette_picks.h" |  | ||||||
| #include "filters/filter.h" | #include "filters/filter.h" | ||||||
| #include "filters/target.h" | #include "filters/target.h" | ||||||
| 
 | 
 | ||||||
| namespace filters { | namespace filters { | ||||||
| 
 | 
 | ||||||
|   class HueSaturationFilter : public Filter { |   class HueSaturationFilter : public FilterWithPalette { | ||||||
|   public: |   public: | ||||||
|     enum class Mode { HSL, HSV }; |     enum class Mode { HSL, HSV }; | ||||||
| 
 | 
 | ||||||
|  | @ -28,13 +28,15 @@ namespace filters { | ||||||
|     void setAlpha(double a); |     void setAlpha(double a); | ||||||
| 
 | 
 | ||||||
|     // Filter implementation
 |     // Filter implementation
 | ||||||
|     const char* getName(); |     const char* getName() override; | ||||||
|     void applyToRgba(FilterManager* filterMgr); |     void applyToRgba(FilterManager* filterMgr) override; | ||||||
|     void applyToGrayscale(FilterManager* filterMgr); |     void applyToGrayscale(FilterManager* filterMgr) override; | ||||||
|     void applyToIndexed(FilterManager* filterMgr); |     void applyToIndexed(FilterManager* filterMgr) override; | ||||||
| 
 | 
 | ||||||
|   private: |   private: | ||||||
|     void applyToPalette(FilterManager* filterMgr); |     void onApplyToPalette(FilterManager* filterMgr, | ||||||
|  |                           const doc::PalettePicks& picks) override; | ||||||
|  | 
 | ||||||
|     template<class T, |     template<class T, | ||||||
|              double (T::*get_lightness)() const, |              double (T::*get_lightness)() const, | ||||||
|              void (T::*set_lightness)(double)> |              void (T::*set_lightness)(double)> | ||||||
|  | @ -43,8 +45,6 @@ namespace filters { | ||||||
| 
 | 
 | ||||||
|     Mode m_mode; |     Mode m_mode; | ||||||
|     double m_h, m_s, m_l, m_a; |     double m_h, m_s, m_l, m_a; | ||||||
|     doc::PalettePicks m_picks; |  | ||||||
|     bool m_usePalette; |  | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| } // namespace filters
 | } // namespace filters
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue