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,18 +114,11 @@ 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).
|
||||||
return;
|
if (!filterMgr->isMaskActive())
|
||||||
|
|
||||||
m_picks = fid->getPalettePicks();
|
|
||||||
if (m_picks.picks() == 0)
|
|
||||||
m_picks.all();
|
|
||||||
|
|
||||||
applyToPalette(filterMgr);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// Apply filter to color region
|
// Apply filter to color region
|
||||||
const Target target = filterMgr->getTarget();
|
const Target target = filterMgr->getTarget();
|
||||||
|
|
@ -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;
|
|
||||||
|
|
||||||
m_picks = fid->getPalettePicks();
|
|
||||||
if (m_picks.picks() == 0)
|
|
||||||
m_picks.all();
|
|
||||||
|
|
||||||
applyToPalette(filterMgr);
|
|
||||||
return;
|
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