1/**************************************************************************/
2/* color_picker.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef COLOR_PICKER_H
32#define COLOR_PICKER_H
33
34#include "scene/gui/aspect_ratio_container.h"
35#include "scene/gui/box_container.h"
36#include "scene/gui/button.h"
37#include "scene/gui/control.h"
38#include "scene/gui/grid_container.h"
39#include "scene/gui/label.h"
40#include "scene/gui/line_edit.h"
41#include "scene/gui/menu_button.h"
42#include "scene/gui/option_button.h"
43#include "scene/gui/panel.h"
44#include "scene/gui/popup.h"
45#include "scene/gui/separator.h"
46#include "scene/gui/slider.h"
47#include "scene/gui/spin_box.h"
48#include "scene/gui/texture_rect.h"
49#include "scene/resources/style_box_flat.h"
50
51class ColorMode;
52class ColorModeRGB;
53class ColorModeHSV;
54class ColorModeRAW;
55class ColorModeOKHSL;
56
57class ColorPresetButton : public BaseButton {
58 GDCLASS(ColorPresetButton, BaseButton);
59
60 Color preset_color;
61
62 struct ThemeCache {
63 Ref<StyleBox> foreground_style;
64
65 Ref<Texture2D> background_icon;
66 Ref<Texture2D> overbright_indicator;
67 } theme_cache;
68
69protected:
70 void _notification(int);
71 static void _bind_methods();
72
73public:
74 void set_preset_color(const Color &p_color);
75 Color get_preset_color() const;
76
77 ColorPresetButton(Color p_color, int p_size);
78 ~ColorPresetButton();
79};
80
81class ColorPicker : public VBoxContainer {
82 GDCLASS(ColorPicker, VBoxContainer);
83
84 // These classes poke into theme items for their internal logic.
85 friend class ColorModeRGB;
86 friend class ColorModeHSV;
87 friend class ColorModeRAW;
88 friend class ColorModeOKHSL;
89
90public:
91 enum ColorModeType {
92 MODE_RGB,
93 MODE_HSV,
94 MODE_RAW,
95 MODE_OKHSL,
96
97 MODE_MAX
98 };
99
100 enum PickerShapeType {
101 SHAPE_HSV_RECTANGLE,
102 SHAPE_HSV_WHEEL,
103 SHAPE_VHS_CIRCLE,
104 SHAPE_OKHSL_CIRCLE,
105 SHAPE_NONE,
106
107 SHAPE_MAX
108 };
109
110 static const int SLIDER_COUNT = 4;
111
112private:
113 static Ref<Shader> wheel_shader;
114 static Ref<Shader> circle_shader;
115 static Ref<Shader> circle_ok_color_shader;
116 static List<Color> preset_cache;
117 static List<Color> recent_preset_cache;
118
119#ifdef TOOLS_ENABLED
120 Object *editor_settings = nullptr;
121#endif
122
123 int current_slider_count = SLIDER_COUNT;
124 static const int MODE_BUTTON_COUNT = 3;
125
126 bool slider_theme_modified = true;
127
128 Vector<ColorMode *> modes;
129
130 Popup *picker_window = nullptr;
131 // Legacy color picking.
132 TextureRect *picker_texture_rect = nullptr;
133 Panel *picker_preview = nullptr;
134 Label *picker_preview_label = nullptr;
135 Ref<StyleBoxFlat> picker_preview_style_box;
136 Color picker_color;
137
138 MarginContainer *internal_margin = nullptr;
139 Control *uv_edit = nullptr;
140 Control *w_edit = nullptr;
141 AspectRatioContainer *wheel_edit = nullptr;
142 MarginContainer *wheel_margin = nullptr;
143 Ref<ShaderMaterial> wheel_mat;
144 Ref<ShaderMaterial> circle_mat;
145 Control *wheel = nullptr;
146 Control *wheel_uv = nullptr;
147 TextureRect *sample = nullptr;
148 GridContainer *preset_container = nullptr;
149 HBoxContainer *recent_preset_hbc = nullptr;
150 Button *btn_add_preset = nullptr;
151 Button *btn_pick = nullptr;
152 Button *btn_preset = nullptr;
153 Button *btn_recent_preset = nullptr;
154 PopupMenu *shape_popup = nullptr;
155 PopupMenu *mode_popup = nullptr;
156 MenuButton *btn_shape = nullptr;
157 HBoxContainer *mode_hbc = nullptr;
158 HBoxContainer *sample_hbc = nullptr;
159 GridContainer *slider_gc = nullptr;
160 HBoxContainer *hex_hbc = nullptr;
161 MenuButton *btn_mode = nullptr;
162 Button *mode_btns[MODE_BUTTON_COUNT];
163 Ref<ButtonGroup> mode_group = nullptr;
164 ColorPresetButton *selected_recent_preset = nullptr;
165 Ref<ButtonGroup> preset_group;
166 Ref<ButtonGroup> recent_preset_group;
167
168 OptionButton *mode_option_button = nullptr;
169
170 HSlider *sliders[SLIDER_COUNT];
171 SpinBox *values[SLIDER_COUNT];
172 Label *labels[SLIDER_COUNT];
173 Button *text_type = nullptr;
174 LineEdit *c_text = nullptr;
175
176 HSlider *alpha_slider = nullptr;
177 SpinBox *alpha_value = nullptr;
178 Label *alpha_label = nullptr;
179
180 bool edit_alpha = true;
181 Size2i ms;
182 bool text_is_constructor = false;
183 PickerShapeType current_shape = SHAPE_HSV_RECTANGLE;
184 ColorModeType current_mode = MODE_RGB;
185 bool colorize_sliders = true;
186
187 const int PRESET_COLUMN_COUNT = 9;
188 int prev_preset_size = 0;
189 int prev_rencet_preset_size = 0;
190 List<Color> presets;
191 List<Color> recent_presets;
192
193 Color color;
194 Color old_color;
195 bool is_picking_color = false;
196
197 bool display_old_color = false;
198 bool deferred_mode_enabled = false;
199 bool updating = true;
200 bool changing_color = false;
201 bool spinning = false;
202 bool can_add_swatches = true;
203 bool presets_visible = true;
204 bool color_modes_visible = true;
205 bool sampler_visible = true;
206 bool sliders_visible = true;
207 bool hex_visible = true;
208 bool line_edit_mouse_release = false;
209 bool text_changed = false;
210
211 float h = 0.0;
212 float s = 0.0;
213 float v = 0.0;
214 Color last_color;
215
216 struct ThemeCache {
217 float base_scale = 1.0;
218
219 int content_margin = 0;
220 int label_width = 0;
221
222 int sv_height = 0;
223 int sv_width = 0;
224 int h_width = 0;
225
226 bool center_slider_grabbers = true;
227
228 Ref<Texture2D> screen_picker;
229 Ref<Texture2D> expanded_arrow;
230 Ref<Texture2D> folded_arrow;
231 Ref<Texture2D> add_preset;
232
233 Ref<Texture2D> shape_rect;
234 Ref<Texture2D> shape_rect_wheel;
235 Ref<Texture2D> shape_circle;
236
237 Ref<Texture2D> bar_arrow;
238 Ref<Texture2D> sample_bg;
239 Ref<Texture2D> overbright_indicator;
240 Ref<Texture2D> picker_cursor;
241 Ref<Texture2D> color_hue;
242 Ref<Texture2D> color_okhsl_hue;
243
244 /* Mode buttons */
245 Ref<StyleBox> mode_button_normal;
246 Ref<StyleBox> mode_button_pressed;
247 Ref<StyleBox> mode_button_hover;
248 } theme_cache;
249
250 void _copy_color_to_hsv();
251 void _copy_hsv_to_color();
252
253 PickerShapeType _get_actual_shape() const;
254 void create_slider(GridContainer *gc, int idx);
255 void _reset_sliders_theme();
256 void _html_submitted(const String &p_html);
257 void _value_changed(double);
258 void _update_controls();
259 void _update_color(bool p_update_sliders = true);
260 void _update_text_value();
261 void _text_type_toggled();
262 void _sample_input(const Ref<InputEvent> &p_event);
263 void _sample_draw();
264 void _hsv_draw(int p_which, Control *c);
265 void _slider_draw(int p_which);
266
267 void _uv_input(const Ref<InputEvent> &p_event, Control *c);
268 void _w_input(const Ref<InputEvent> &p_event);
269 void _slider_or_spin_input(const Ref<InputEvent> &p_event);
270 void _line_edit_input(const Ref<InputEvent> &p_event);
271 void _preset_input(const Ref<InputEvent> &p_event, const Color &p_color);
272 void _recent_preset_pressed(const bool pressed, ColorPresetButton *p_preset);
273 void _text_changed(const String &p_new_text);
274 void _add_preset_pressed();
275 void _html_focus_exit();
276 void _pick_button_pressed();
277 void _pick_finished();
278 // Legacy color picking.
279 void _pick_button_pressed_legacy();
280 void _picker_texture_input(const Ref<InputEvent> &p_event);
281
282 inline int _get_preset_size();
283 void _add_preset_button(int p_size, const Color &p_color);
284 void _add_recent_preset_button(int p_size, const Color &p_color);
285
286 void _show_hide_preset(const bool &p_is_btn_pressed, Button *p_btn_preset, Container *p_preset_container);
287 void _update_drop_down_arrow(const bool &p_is_btn_pressed, Button *p_btn_preset);
288
289 void _set_mode_popup_value(ColorModeType p_mode);
290
291 Variant _get_drag_data_fw(const Point2 &p_point, Control *p_from_control);
292 bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const;
293 void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control);
294
295protected:
296 virtual void _update_theme_item_cache() override;
297
298 void _notification(int);
299 static void _bind_methods();
300
301public:
302#ifdef TOOLS_ENABLED
303 void set_editor_settings(Object *p_editor_settings);
304#endif
305 HSlider *get_slider(int idx);
306 Vector<float> get_active_slider_values();
307
308 static void init_shaders();
309 static void finish_shaders();
310
311 void add_mode(ColorMode *p_mode);
312
313 void set_edit_alpha(bool p_show);
314 bool is_editing_alpha() const;
315
316 int get_preset_size();
317
318 void _set_pick_color(const Color &p_color, bool p_update_sliders);
319 void set_pick_color(const Color &p_color);
320 Color get_pick_color() const;
321 void set_old_color(const Color &p_color);
322
323 void set_display_old_color(bool p_enabled);
324 bool is_displaying_old_color() const;
325
326 void set_picker_shape(PickerShapeType p_shape);
327 PickerShapeType get_picker_shape() const;
328
329 void add_preset(const Color &p_color);
330 void add_recent_preset(const Color &p_color);
331 void erase_preset(const Color &p_color);
332 void erase_recent_preset(const Color &p_color);
333 PackedColorArray get_presets() const;
334 PackedColorArray get_recent_presets() const;
335 void _update_presets();
336 void _update_recent_presets();
337
338 void _select_from_preset_container(const Color &p_color);
339 bool _select_from_recent_preset_hbc(const Color &p_color);
340
341 void set_color_mode(ColorModeType p_mode);
342 ColorModeType get_color_mode() const;
343
344 void set_colorize_sliders(bool p_colorize_sliders);
345 bool is_colorizing_sliders() const;
346
347 void set_deferred_mode(bool p_enabled);
348 bool is_deferred_mode() const;
349
350 void set_can_add_swatches(bool p_enabled);
351 bool are_swatches_enabled() const;
352
353 void set_presets_visible(bool p_visible);
354 bool are_presets_visible() const;
355
356 void set_modes_visible(bool p_visible);
357 bool are_modes_visible() const;
358
359 void set_sampler_visible(bool p_visible);
360 bool is_sampler_visible() const;
361
362 void set_sliders_visible(bool p_visible);
363 bool are_sliders_visible() const;
364
365 void set_hex_visible(bool p_visible);
366 bool is_hex_visible() const;
367
368 void set_focus_on_line_edit();
369
370 ColorPicker();
371 ~ColorPicker();
372};
373
374class ColorPickerButton : public Button {
375 GDCLASS(ColorPickerButton, Button);
376
377 // Initialization is now done deferred,
378 // this improves performance in the inspector as the color picker
379 // can be expensive to initialize.
380
381 PopupPanel *popup = nullptr;
382 ColorPicker *picker = nullptr;
383 Color color;
384 bool edit_alpha = true;
385
386 struct ThemeCache {
387 Ref<StyleBox> normal_style;
388 Ref<Texture2D> background_icon;
389
390 Ref<Texture2D> overbright_indicator;
391 } theme_cache;
392
393 void _about_to_popup();
394 void _color_changed(const Color &p_color);
395 void _modal_closed();
396
397 virtual void pressed() override;
398
399 void _update_picker();
400
401protected:
402 void _notification(int);
403 static void _bind_methods();
404
405public:
406 void set_pick_color(const Color &p_color);
407 Color get_pick_color() const;
408
409 void set_edit_alpha(bool p_show);
410 bool is_editing_alpha() const;
411
412 ColorPicker *get_picker();
413 PopupPanel *get_popup();
414
415 ColorPickerButton(const String &p_text = String());
416};
417
418VARIANT_ENUM_CAST(ColorPicker::PickerShapeType);
419VARIANT_ENUM_CAST(ColorPicker::ColorModeType);
420
421#endif // COLOR_PICKER_H
422