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 | |
27 | namespace app { |
28 | |
29 | using namespace ui; |
30 | |
31 | EyedropperCommand::EyedropperCommand() |
32 | : Command(CommandId::Eyedropper(), CmdUIOnlyFlag) |
33 | { |
34 | m_background = false; |
35 | } |
36 | |
37 | void 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 | |
179 | void 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 | |
186 | void 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 | |
201 | void 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 | |
251 | Command* CommandFactory::createEyedropperCommand() |
252 | { |
253 | return new EyedropperCommand; |
254 | } |
255 | |
256 | } // namespace app |
257 | |