1// Aseprite
2// Copyright (C) 2019-2020 Igara Studio S.A.
3// Copyright (C) 2016-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/app.h"
13#include "app/cmd/set_palette.h"
14#include "app/commands/command.h"
15#include "app/commands/new_params.h"
16#include "app/console.h"
17#include "app/context.h"
18#include "app/context_access.h"
19#include "app/i18n/strings.h"
20#include "app/pref/preferences.h"
21#include "app/tx.h"
22#include "doc/palette.h"
23#include "fmt/format.h"
24
25#ifdef ENABLE_SCRIPTING
26#include "app/script/luacpp.h"
27#endif
28
29namespace app {
30
31enum class AddColorSource { Fg, Bg, Color };
32
33template<>
34void Param<AddColorSource>::fromString(const std::string& value)
35{
36 if (value == "fg" ||
37 value == "foreground")
38 setValue(AddColorSource::Fg);
39 else if (value == "bg" ||
40 value == "background")
41 setValue(AddColorSource::Bg);
42 else
43 setValue(AddColorSource::Color);
44}
45
46#ifdef ENABLE_SCRIPTING
47template<>
48void Param<AddColorSource>::fromLua(lua_State* L, int index)
49{
50 fromString(lua_tostring(L, index));
51}
52#endif // ENABLE_SCRIPTING
53
54struct AddColorParams : public NewParams {
55 Param<AddColorSource> source { this, AddColorSource::Color, "source" };
56 Param<app::Color> color { this, app::Color::fromMask(), "color" };
57};
58
59class AddColorCommand : public CommandWithNewParams<AddColorParams> {
60public:
61 AddColorCommand();
62protected:
63 bool onEnabled(Context* ctx) override;
64 void onExecute(Context* ctx) override;
65 std::string onGetFriendlyName() const override;
66};
67
68AddColorCommand::AddColorCommand()
69 : CommandWithNewParams<AddColorParams>(CommandId::AddColor(), CmdUIOnlyFlag)
70{
71}
72
73bool AddColorCommand::onEnabled(Context* ctx)
74{
75 return ctx->checkFlags(ContextFlags::ActiveDocumentIsWritable);
76}
77
78void AddColorCommand::onExecute(Context* ctx)
79{
80 app::Color appColor;
81
82 switch (params().source()) {
83 case AddColorSource::Fg:
84 appColor = Preferences::instance().colorBar.fgColor();
85 break;
86 case AddColorSource::Bg:
87 appColor = Preferences::instance().colorBar.bgColor();
88 break;
89 case AddColorSource::Color:
90 appColor = params().color();
91 break;
92 }
93
94 Palette* pal = ctx->activeSite().palette();
95 ASSERT(pal);
96 if (!pal)
97 return;
98
99 try {
100 std::unique_ptr<Palette> newPalette(new Palette(*pal));
101 color_t color = doc::rgba(
102 appColor.getRed(),
103 appColor.getGreen(),
104 appColor.getBlue(),
105 appColor.getAlpha());
106 int index = newPalette->findExactMatch(
107 appColor.getRed(),
108 appColor.getGreen(),
109 appColor.getBlue(),
110 appColor.getAlpha(), -1);
111
112 // It should be -1, because the user has pressed the warning
113 // button that is available only when the color isn't in the
114 // palette.
115 ASSERT(index < 0);
116 if (index >= 0)
117 return;
118
119 ContextWriter writer(ctx);
120 Doc* document(writer.document());
121 Sprite* sprite = writer.sprite();
122 if (!document || !sprite) {
123 ASSERT(false);
124 return;
125 }
126
127 newPalette->addEntry(color);
128 index = newPalette->size()-1;
129
130 if (document) {
131 frame_t frame = writer.frame();
132
133 Tx tx(writer.context(), friendlyName(), ModifyDocument);
134 tx(new cmd::SetPalette(sprite, frame, newPalette.get()));
135 tx.commit();
136 }
137 }
138 catch (base::Exception& e) {
139 Console::showException(e);
140 }
141}
142
143std::string AddColorCommand::onGetFriendlyName() const
144{
145 std::string source;
146 switch (params().source()) {
147 case AddColorSource::Fg: source = Strings::commands_AddColor_Foreground(); break;
148 case AddColorSource::Bg: source = Strings::commands_AddColor_Background(); break;
149 case AddColorSource::Color: source = Strings::commands_AddColor_Specific(); break;
150 }
151 return fmt::format(getBaseFriendlyName(), source);
152}
153
154Command* CommandFactory::createAddColorCommand()
155{
156 return new AddColorCommand;
157}
158
159} // namespace app
160