1// Aseprite
2// Copyright (C) 2020-2021 Igara Studio S.A.
3// Copyright (C) 2001-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/color.h"
13#include "app/color_picker.h"
14#include "app/commands/cmd_eyedropper.h"
15#include "app/commands/commands.h"
16#include "app/commands/params.h"
17#include "app/context.h"
18#include "app/pref/preferences.h"
19#include "app/site.h"
20#include "app/tools/tool.h"
21#include "app/tools/tool_box.h"
22#include "app/ui/color_bar.h"
23#include "app/ui/editor/editor.h"
24#include "ui/manager.h"
25#include "ui/system.h"
26
27namespace app {
28
29using namespace ui;
30
31EyedropperCommand::EyedropperCommand()
32 : Command(CommandId::Eyedropper(), CmdUIOnlyFlag)
33{
34 m_background = false;
35}
36
37void EyedropperCommand::pickSample(const Site& site,
38 const gfx::PointF& pixelPos,
39 const render::Projection& proj,
40 app::Color& color,
41 doc::tile_t& tile)
42{
43 // Check if we've to grab alpha channel or the merged color.
44 Preferences& pref = Preferences::instance();
45 ColorPicker::Mode mode = ColorPicker::FromComposition;
46 switch (pref.eyedropper.sample()) {
47 case app::gen::EyedropperSample::ALL_LAYERS:
48 mode = ColorPicker::FromComposition;
49 break;
50 case app::gen::EyedropperSample::CURRENT_LAYER:
51 mode = ColorPicker::FromActiveLayer;
52 break;
53 case app::gen::EyedropperSample::FIRST_REFERENCE_LAYER:
54 mode = ColorPicker::FromFirstReferenceLayer;
55 break;
56 }
57
58 ColorPicker picker;
59 picker.pickColor(site, pixelPos, proj, mode);
60
61 app::gen::EyedropperChannel channel =
62 pref.eyedropper.channel();
63
64 if (site.tilemapMode() == TilemapMode::Tiles) {
65 tile = picker.tile();
66 return;
67 }
68
69 app::Color picked = picker.color();
70 switch (channel) {
71 case app::gen::EyedropperChannel::COLOR_ALPHA:
72 color = picked;
73 break;
74 case app::gen::EyedropperChannel::COLOR:
75 if (picked.getAlpha() > 0)
76 color = app::Color::fromRgb(picked.getRed(),
77 picked.getGreen(),
78 picked.getBlue(),
79 color.getAlpha());
80 break;
81 case app::gen::EyedropperChannel::ALPHA:
82 switch (color.getType()) {
83
84 case app::Color::RgbType:
85 case app::Color::IndexType:
86 color = app::Color::fromRgb(color.getRed(),
87 color.getGreen(),
88 color.getBlue(),
89 picked.getAlpha());
90 break;
91
92 case app::Color::HsvType:
93 color = app::Color::fromHsv(color.getHsvHue(),
94 color.getHsvSaturation(),
95 color.getHsvValue(),
96 picked.getAlpha());
97 break;
98
99 case app::Color::HslType:
100 color = app::Color::fromHsl(color.getHslHue(),
101 color.getHslSaturation(),
102 color.getHslLightness(),
103 picked.getAlpha());
104 break;
105
106 case app::Color::GrayType:
107 color = app::Color::fromGray(color.getGray(),
108 picked.getAlpha());
109 break;
110
111 }
112 break;
113 case app::gen::EyedropperChannel::RGBA:
114 if (picked.getType() == app::Color::RgbType)
115 color = picked;
116 else
117 color = app::Color::fromRgb(picked.getRed(),
118 picked.getGreen(),
119 picked.getBlue(),
120 picked.getAlpha());
121 break;
122 case app::gen::EyedropperChannel::RGB:
123 if (picked.getAlpha() > 0)
124 color = app::Color::fromRgb(picked.getRed(),
125 picked.getGreen(),
126 picked.getBlue(),
127 color.getAlpha());
128 break;
129 case app::gen::EyedropperChannel::HSVA:
130 if (picked.getType() == app::Color::HsvType)
131 color = picked;
132 else
133 color = app::Color::fromHsv(picked.getHsvHue(),
134 picked.getHsvSaturation(),
135 picked.getHsvValue(),
136 picked.getAlpha());
137 break;
138 case app::gen::EyedropperChannel::HSV:
139 if (picked.getAlpha() > 0)
140 color = app::Color::fromHsv(picked.getHsvHue(),
141 picked.getHsvSaturation(),
142 picked.getHsvValue(),
143 color.getAlpha());
144 break;
145 case app::gen::EyedropperChannel::HSLA:
146 if (picked.getType() == app::Color::HslType)
147 color = picked;
148 else
149 color = app::Color::fromHsl(picked.getHslHue(),
150 picked.getHslSaturation(),
151 picked.getHslLightness(),
152 picked.getAlpha());
153 break;
154 case app::gen::EyedropperChannel::HSL:
155 if (picked.getAlpha() > 0)
156 color = app::Color::fromHsl(picked.getHslHue(),
157 picked.getHslSaturation(),
158 picked.getHslLightness(),
159 color.getAlpha());
160 break;
161 case app::gen::EyedropperChannel::GRAYA:
162 if (picked.getType() == app::Color::GrayType)
163 color = picked;
164 else
165 color = app::Color::fromGray(picked.getGray(),
166 picked.getAlpha());
167 break;
168 case app::gen::EyedropperChannel::GRAY:
169 if (picked.getAlpha() > 0)
170 color = app::Color::fromGray(picked.getGray(),
171 color.getAlpha());
172 break;
173 case app::gen::EyedropperChannel::INDEX:
174 color = app::Color::fromIndex(picked.getIndex());
175 break;
176 }
177}
178
179void EyedropperCommand::onLoadParams(const Params& params)
180{
181 std::string target = params.get("target");
182 if (target == "foreground") m_background = false;
183 else if (target == "background") m_background = true;
184}
185
186void EyedropperCommand::onExecute(Context* context)
187{
188 gfx::Point mousePos = ui::get_mouse_position();
189 Widget* widget = ui::Manager::getDefault()->pickFromScreenPos(mousePos);
190 if (!widget || widget->type() != Editor::Type())
191 return;
192
193 Editor* editor = static_cast<Editor*>(widget);
194 executeOnMousePos(
195 context,
196 editor,
197 editor->display()->nativeWindow()->pointFromScreen(mousePos),
198 !m_background);
199}
200
201void EyedropperCommand::executeOnMousePos(Context* context,
202 Editor* editor,
203 const gfx::Point& mousePos,
204 const bool foreground)
205{
206 ASSERT(editor);
207
208 Sprite* sprite = editor->sprite();
209 if (!sprite)
210 return;
211
212 // Discard current image brush
213 if (Preferences::instance().eyedropper.discardBrush()) {
214 Command* discardBrush = Commands::instance()->byId(CommandId::DiscardBrush());
215 context->executeCommand(discardBrush);
216 }
217
218 // Pixel position to get
219 gfx::PointF pixelPos = editor->screenToEditorF(mousePos);
220
221 // Start with fg/bg color
222 DisableColorBarEditMode disable;
223 Preferences& pref = Preferences::instance();
224 app::Color color =
225 (foreground ? pref.colorBar.fgColor():
226 pref.colorBar.bgColor());
227 doc::tile_t tile =
228 (foreground ? pref.colorBar.fgTile():
229 pref.colorBar.bgTile());
230
231 Site site = editor->getSite();
232 pickSample(site,
233 pixelPos,
234 editor->projection(),
235 color, tile);
236
237 if (site.tilemapMode() == TilemapMode::Tiles) {
238 if (foreground)
239 pref.colorBar.fgTile(tile);
240 else
241 pref.colorBar.bgTile(tile);
242 }
243 else {
244 if (foreground)
245 pref.colorBar.fgColor(color);
246 else
247 pref.colorBar.bgColor(color);
248 }
249}
250
251Command* CommandFactory::createEyedropperCommand()
252{
253 return new EyedropperCommand;
254}
255
256} // namespace app
257