1 | /**************************************************************************/ |
2 | /* color_picker.cpp */ |
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 | #include "color_picker.h" |
32 | |
33 | #include "core/input/input.h" |
34 | #include "core/io/image.h" |
35 | #include "core/math/color.h" |
36 | #include "core/os/keyboard.h" |
37 | #include "core/os/os.h" |
38 | #include "scene/gui/color_mode.h" |
39 | #include "scene/resources/image_texture.h" |
40 | #include "scene/resources/style_box_flat.h" |
41 | #include "scene/resources/style_box_texture.h" |
42 | #include "scene/theme/theme_db.h" |
43 | #include "servers/display_server.h" |
44 | #include "thirdparty/misc/ok_color.h" |
45 | #include "thirdparty/misc/ok_color_shader.h" |
46 | |
47 | List<Color> ColorPicker::preset_cache; |
48 | List<Color> ColorPicker::recent_preset_cache; |
49 | |
50 | void ColorPicker::_notification(int p_what) { |
51 | switch (p_what) { |
52 | case NOTIFICATION_ENTER_TREE: { |
53 | _update_color(); |
54 | } break; |
55 | |
56 | case NOTIFICATION_THEME_CHANGED: { |
57 | btn_pick->set_icon(theme_cache.screen_picker); |
58 | _update_drop_down_arrow(btn_preset->is_pressed(), btn_preset); |
59 | _update_drop_down_arrow(btn_recent_preset->is_pressed(), btn_recent_preset); |
60 | btn_add_preset->set_icon(theme_cache.add_preset); |
61 | |
62 | btn_pick->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0)); |
63 | btn_shape->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0)); |
64 | btn_mode->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0)); |
65 | |
66 | uv_edit->set_custom_minimum_size(Size2(theme_cache.sv_width, theme_cache.sv_height)); |
67 | w_edit->set_custom_minimum_size(Size2(theme_cache.h_width, 0)); |
68 | |
69 | wheel_edit->set_custom_minimum_size(Size2(theme_cache.sv_width, theme_cache.sv_height)); |
70 | wheel_margin->add_theme_constant_override("margin_bottom" , 8 * theme_cache.base_scale); |
71 | |
72 | for (int i = 0; i < SLIDER_COUNT; i++) { |
73 | labels[i]->set_custom_minimum_size(Size2(theme_cache.label_width, 0)); |
74 | sliders[i]->add_theme_constant_override(SNAME("center_grabber" ), theme_cache.center_slider_grabbers); |
75 | } |
76 | alpha_label->set_custom_minimum_size(Size2(theme_cache.label_width, 0)); |
77 | alpha_label->add_theme_constant_override(SNAME("center_grabber" ), theme_cache.center_slider_grabbers); |
78 | |
79 | for (int i = 0; i < MODE_BUTTON_COUNT; i++) { |
80 | mode_btns[i]->add_theme_style_override(SNAME("pressed" ), theme_cache.mode_button_pressed); |
81 | mode_btns[i]->add_theme_style_override(SNAME("normal" ), theme_cache.mode_button_normal); |
82 | mode_btns[i]->add_theme_style_override(SNAME("hover" ), theme_cache.mode_button_hover); |
83 | } |
84 | |
85 | shape_popup->set_item_icon(shape_popup->get_item_index(SHAPE_HSV_RECTANGLE), theme_cache.shape_rect); |
86 | shape_popup->set_item_icon(shape_popup->get_item_index(SHAPE_HSV_WHEEL), theme_cache.shape_rect_wheel); |
87 | shape_popup->set_item_icon(shape_popup->get_item_index(SHAPE_VHS_CIRCLE), theme_cache.shape_circle); |
88 | shape_popup->set_item_icon(shape_popup->get_item_index(SHAPE_OKHSL_CIRCLE), theme_cache.shape_circle); |
89 | |
90 | internal_margin->add_theme_constant_override(SNAME("margin_bottom" ), theme_cache.content_margin); |
91 | internal_margin->add_theme_constant_override(SNAME("margin_left" ), theme_cache.content_margin); |
92 | internal_margin->add_theme_constant_override(SNAME("margin_right" ), theme_cache.content_margin); |
93 | internal_margin->add_theme_constant_override(SNAME("margin_top" ), theme_cache.content_margin); |
94 | |
95 | _reset_sliders_theme(); |
96 | |
97 | if (Engine::get_singleton()->is_editor_hint()) { |
98 | // Adjust for the width of the "Script" icon. |
99 | text_type->set_custom_minimum_size(Size2(28 * theme_cache.base_scale, 0)); |
100 | } |
101 | |
102 | _update_presets(); |
103 | _update_recent_presets(); |
104 | _update_controls(); |
105 | } break; |
106 | |
107 | case NOTIFICATION_WM_CLOSE_REQUEST: { |
108 | if (picker_window != nullptr && picker_window->is_visible()) { |
109 | picker_window->hide(); |
110 | } |
111 | } break; |
112 | |
113 | case NOTIFICATION_INTERNAL_PROCESS: { |
114 | if (!is_picking_color) { |
115 | return; |
116 | } |
117 | set_pick_color(DisplayServer::get_singleton()->screen_get_pixel(DisplayServer::get_singleton()->mouse_get_position())); |
118 | } |
119 | } |
120 | } |
121 | |
122 | void ColorPicker::_update_theme_item_cache() { |
123 | VBoxContainer::_update_theme_item_cache(); |
124 | |
125 | theme_cache.base_scale = get_theme_default_base_scale(); |
126 | } |
127 | |
128 | Ref<Shader> ColorPicker::wheel_shader; |
129 | Ref<Shader> ColorPicker::circle_shader; |
130 | Ref<Shader> ColorPicker::circle_ok_color_shader; |
131 | |
132 | void ColorPicker::init_shaders() { |
133 | wheel_shader.instantiate(); |
134 | wheel_shader->set_code(R"( |
135 | // ColorPicker wheel shader. |
136 | |
137 | shader_type canvas_item; |
138 | |
139 | void fragment() { |
140 | float x = UV.x - 0.5; |
141 | float y = UV.y - 0.5; |
142 | float a = atan(y, x); |
143 | x += 0.001; |
144 | y += 0.001; |
145 | float b = float(sqrt(x * x + y * y) < 0.5) * float(sqrt(x * x + y * y) > 0.42); |
146 | x -= 0.002; |
147 | float b2 = float(sqrt(x * x + y * y) < 0.5) * float(sqrt(x * x + y * y) > 0.42); |
148 | y -= 0.002; |
149 | float b3 = float(sqrt(x * x + y * y) < 0.5) * float(sqrt(x * x + y * y) > 0.42); |
150 | x += 0.002; |
151 | float b4 = float(sqrt(x * x + y * y) < 0.5) * float(sqrt(x * x + y * y) > 0.42); |
152 | |
153 | COLOR = vec4(clamp((abs(fract(((a - TAU) / TAU) + vec3(3.0, 2.0, 1.0) / 3.0) * 6.0 - 3.0) - 1.0), 0.0, 1.0), (b + b2 + b3 + b4) / 4.00); |
154 | } |
155 | )" ); |
156 | |
157 | circle_shader.instantiate(); |
158 | circle_shader->set_code(R"( |
159 | // ColorPicker circle shader. |
160 | |
161 | shader_type canvas_item; |
162 | |
163 | uniform float v = 1.0; |
164 | |
165 | void fragment() { |
166 | float x = UV.x - 0.5; |
167 | float y = UV.y - 0.5; |
168 | float a = atan(y, x); |
169 | x += 0.001; |
170 | y += 0.001; |
171 | float b = float(sqrt(x * x + y * y) < 0.5); |
172 | x -= 0.002; |
173 | float b2 = float(sqrt(x * x + y * y) < 0.5); |
174 | y -= 0.002; |
175 | float b3 = float(sqrt(x * x + y * y) < 0.5); |
176 | x += 0.002; |
177 | float b4 = float(sqrt(x * x + y * y) < 0.5); |
178 | |
179 | COLOR = vec4(mix(vec3(1.0), clamp(abs(fract(vec3((a - TAU) / TAU) + vec3(1.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - vec3(3.0)) - vec3(1.0), 0.0, 1.0), ((float(sqrt(x * x + y * y)) * 2.0)) / 1.0) * vec3(v), (b + b2 + b3 + b4) / 4.00); |
180 | })" ); |
181 | |
182 | circle_ok_color_shader.instantiate(); |
183 | circle_ok_color_shader->set_code(OK_COLOR_SHADER + R"( |
184 | // ColorPicker ok color hsv circle shader. |
185 | |
186 | uniform float v = 1.0; |
187 | |
188 | void fragment() { |
189 | float x = UV.x - 0.5; |
190 | float y = UV.y - 0.5; |
191 | float h = atan(y, x) / (2.0 * M_PI); |
192 | float s = sqrt(x * x + y * y) * 2.0; |
193 | vec3 col = okhsl_to_srgb(vec3(h, s, v)); |
194 | x += 0.001; |
195 | y += 0.001; |
196 | float b = float(sqrt(x * x + y * y) < 0.5); |
197 | x -= 0.002; |
198 | float b2 = float(sqrt(x * x + y * y) < 0.5); |
199 | y -= 0.002; |
200 | float b3 = float(sqrt(x * x + y * y) < 0.5); |
201 | x += 0.002; |
202 | float b4 = float(sqrt(x * x + y * y) < 0.5); |
203 | COLOR = vec4(col, (b + b2 + b3 + b4) / 4.00); |
204 | })" ); |
205 | } |
206 | |
207 | void ColorPicker::finish_shaders() { |
208 | wheel_shader.unref(); |
209 | circle_shader.unref(); |
210 | circle_ok_color_shader.unref(); |
211 | } |
212 | |
213 | void ColorPicker::set_focus_on_line_edit() { |
214 | c_text->call_deferred(SNAME("grab_focus" )); |
215 | } |
216 | |
217 | void ColorPicker::_update_controls() { |
218 | int mode_sliders_count = modes[current_mode]->get_slider_count(); |
219 | |
220 | for (int i = current_slider_count; i < mode_sliders_count; i++) { |
221 | sliders[i]->show(); |
222 | labels[i]->show(); |
223 | values[i]->show(); |
224 | } |
225 | for (int i = mode_sliders_count; i < current_slider_count; i++) { |
226 | sliders[i]->hide(); |
227 | labels[i]->hide(); |
228 | values[i]->hide(); |
229 | } |
230 | current_slider_count = mode_sliders_count; |
231 | |
232 | for (int i = 0; i < current_slider_count; i++) { |
233 | labels[i]->set_text(modes[current_mode]->get_slider_label(i)); |
234 | } |
235 | alpha_label->set_text("A" ); |
236 | |
237 | slider_theme_modified = modes[current_mode]->apply_theme(); |
238 | |
239 | if (edit_alpha) { |
240 | alpha_value->show(); |
241 | alpha_slider->show(); |
242 | alpha_label->show(); |
243 | } else { |
244 | alpha_value->hide(); |
245 | alpha_slider->hide(); |
246 | alpha_label->hide(); |
247 | } |
248 | |
249 | switch (_get_actual_shape()) { |
250 | case SHAPE_HSV_RECTANGLE: |
251 | wheel_edit->hide(); |
252 | w_edit->show(); |
253 | uv_edit->show(); |
254 | btn_shape->show(); |
255 | break; |
256 | case SHAPE_HSV_WHEEL: |
257 | wheel_edit->show(); |
258 | w_edit->hide(); |
259 | uv_edit->hide(); |
260 | btn_shape->show(); |
261 | wheel->set_material(wheel_mat); |
262 | break; |
263 | case SHAPE_VHS_CIRCLE: |
264 | wheel_edit->show(); |
265 | w_edit->show(); |
266 | uv_edit->hide(); |
267 | btn_shape->show(); |
268 | wheel->set_material(circle_mat); |
269 | circle_mat->set_shader(circle_shader); |
270 | break; |
271 | case SHAPE_OKHSL_CIRCLE: |
272 | wheel_edit->show(); |
273 | w_edit->show(); |
274 | uv_edit->hide(); |
275 | btn_shape->show(); |
276 | wheel->set_material(circle_mat); |
277 | circle_mat->set_shader(circle_ok_color_shader); |
278 | break; |
279 | case SHAPE_NONE: |
280 | wheel_edit->hide(); |
281 | w_edit->hide(); |
282 | uv_edit->hide(); |
283 | btn_shape->hide(); |
284 | break; |
285 | default: { |
286 | } |
287 | } |
288 | } |
289 | |
290 | void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) { |
291 | if (text_changed) { |
292 | add_recent_preset(color); |
293 | text_changed = false; |
294 | } |
295 | |
296 | color = p_color; |
297 | if (color != last_color) { |
298 | _copy_color_to_hsv(); |
299 | last_color = color; |
300 | } |
301 | |
302 | if (!is_inside_tree()) { |
303 | return; |
304 | } |
305 | |
306 | _update_color(p_update_sliders); |
307 | } |
308 | |
309 | void ColorPicker::set_pick_color(const Color &p_color) { |
310 | _set_pick_color(p_color, true); //because setters can't have more arguments |
311 | } |
312 | |
313 | void ColorPicker::set_old_color(const Color &p_color) { |
314 | old_color = p_color; |
315 | } |
316 | |
317 | void ColorPicker::set_display_old_color(bool p_enabled) { |
318 | display_old_color = p_enabled; |
319 | } |
320 | |
321 | bool ColorPicker::is_displaying_old_color() const { |
322 | return display_old_color; |
323 | } |
324 | |
325 | void ColorPicker::set_edit_alpha(bool p_show) { |
326 | if (edit_alpha == p_show) { |
327 | return; |
328 | } |
329 | edit_alpha = p_show; |
330 | _update_controls(); |
331 | |
332 | if (!is_inside_tree()) { |
333 | return; |
334 | } |
335 | |
336 | _update_color(); |
337 | sample->queue_redraw(); |
338 | } |
339 | |
340 | bool ColorPicker::is_editing_alpha() const { |
341 | return edit_alpha; |
342 | } |
343 | |
344 | void ColorPicker::_value_changed(double) { |
345 | if (updating) { |
346 | return; |
347 | } |
348 | |
349 | color = modes[current_mode]->get_color(); |
350 | modes[current_mode]->_value_changed(); |
351 | |
352 | if (current_mode == MODE_HSV || current_mode == MODE_OKHSL) { |
353 | h = sliders[0]->get_value() / 360.0; |
354 | s = sliders[1]->get_value() / 100.0; |
355 | v = sliders[2]->get_value() / 100.0; |
356 | last_color = color; |
357 | } |
358 | |
359 | _set_pick_color(color, false); |
360 | emit_signal(SNAME("color_changed" ), color); |
361 | } |
362 | |
363 | void ColorPicker::add_mode(ColorMode *p_mode) { |
364 | modes.push_back(p_mode); |
365 | } |
366 | |
367 | void ColorPicker::create_slider(GridContainer *gc, int idx) { |
368 | Label *lbl = memnew(Label()); |
369 | lbl->set_v_size_flags(SIZE_SHRINK_CENTER); |
370 | gc->add_child(lbl); |
371 | |
372 | HSlider *slider = memnew(HSlider); |
373 | slider->set_v_size_flags(SIZE_SHRINK_CENTER); |
374 | slider->set_focus_mode(FOCUS_NONE); |
375 | gc->add_child(slider); |
376 | |
377 | SpinBox *val = memnew(SpinBox); |
378 | slider->share(val); |
379 | val->set_select_all_on_focus(true); |
380 | gc->add_child(val); |
381 | |
382 | LineEdit *vle = val->get_line_edit(); |
383 | vle->connect("text_changed" , callable_mp(this, &ColorPicker::_text_changed)); |
384 | vle->connect("gui_input" , callable_mp(this, &ColorPicker::_line_edit_input)); |
385 | vle->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); |
386 | |
387 | val->connect("gui_input" , callable_mp(this, &ColorPicker::_slider_or_spin_input)); |
388 | |
389 | slider->set_h_size_flags(SIZE_EXPAND_FILL); |
390 | |
391 | slider->connect("value_changed" , callable_mp(this, &ColorPicker::_value_changed)); |
392 | slider->connect("draw" , callable_mp(this, &ColorPicker::_slider_draw).bind(idx)); |
393 | slider->connect("gui_input" , callable_mp(this, &ColorPicker::_slider_or_spin_input)); |
394 | |
395 | if (idx < SLIDER_COUNT) { |
396 | sliders[idx] = slider; |
397 | values[idx] = val; |
398 | labels[idx] = lbl; |
399 | } else { |
400 | alpha_slider = slider; |
401 | alpha_value = val; |
402 | alpha_label = lbl; |
403 | } |
404 | } |
405 | |
406 | #ifdef TOOLS_ENABLED |
407 | void ColorPicker::set_editor_settings(Object *p_editor_settings) { |
408 | if (editor_settings) { |
409 | return; |
410 | } |
411 | editor_settings = p_editor_settings; |
412 | |
413 | if (preset_cache.is_empty()) { |
414 | PackedColorArray saved_presets = editor_settings->call(SNAME("get_project_metadata" ), "color_picker" , "presets" , PackedColorArray()); |
415 | for (int i = 0; i < saved_presets.size(); i++) { |
416 | preset_cache.push_back(saved_presets[i]); |
417 | } |
418 | } |
419 | |
420 | for (int i = 0; i < preset_cache.size(); i++) { |
421 | presets.push_back(preset_cache[i]); |
422 | } |
423 | |
424 | if (recent_preset_cache.is_empty()) { |
425 | PackedColorArray saved_recent_presets = editor_settings->call(SNAME("get_project_metadata" ), "color_picker" , "recent_presets" , PackedColorArray()); |
426 | for (int i = 0; i < saved_recent_presets.size(); i++) { |
427 | recent_preset_cache.push_back(saved_recent_presets[i]); |
428 | } |
429 | } |
430 | |
431 | for (int i = 0; i < recent_preset_cache.size(); i++) { |
432 | recent_presets.push_back(recent_preset_cache[i]); |
433 | } |
434 | |
435 | _update_presets(); |
436 | _update_recent_presets(); |
437 | } |
438 | #endif |
439 | |
440 | HSlider *ColorPicker::get_slider(int p_idx) { |
441 | if (p_idx < SLIDER_COUNT) { |
442 | return sliders[p_idx]; |
443 | } |
444 | return alpha_slider; |
445 | } |
446 | |
447 | Vector<float> ColorPicker::get_active_slider_values() { |
448 | Vector<float> cur_values; |
449 | for (int i = 0; i < current_slider_count; i++) { |
450 | cur_values.push_back(sliders[i]->get_value()); |
451 | } |
452 | cur_values.push_back(alpha_slider->get_value()); |
453 | return cur_values; |
454 | } |
455 | |
456 | void ColorPicker::_copy_color_to_hsv() { |
457 | if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) { |
458 | h = color.get_ok_hsl_h(); |
459 | s = color.get_ok_hsl_s(); |
460 | v = color.get_ok_hsl_l(); |
461 | } else { |
462 | h = color.get_h(); |
463 | s = color.get_s(); |
464 | v = color.get_v(); |
465 | } |
466 | } |
467 | |
468 | void ColorPicker::_copy_hsv_to_color() { |
469 | if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) { |
470 | color.set_ok_hsl(h, s, v, color.a); |
471 | } else { |
472 | color.set_hsv(h, s, v, color.a); |
473 | } |
474 | } |
475 | |
476 | void ColorPicker::_select_from_preset_container(const Color &p_color) { |
477 | if (preset_group->get_pressed_button()) { |
478 | preset_group->get_pressed_button()->set_pressed(false); |
479 | } |
480 | |
481 | for (int i = 1; i < preset_container->get_child_count(); i++) { |
482 | ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i)); |
483 | if (current_btn && p_color == current_btn->get_preset_color()) { |
484 | current_btn->set_pressed(true); |
485 | break; |
486 | } |
487 | } |
488 | } |
489 | |
490 | bool ColorPicker::_select_from_recent_preset_hbc(const Color &p_color) { |
491 | for (int i = 0; i < recent_preset_hbc->get_child_count(); i++) { |
492 | ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(recent_preset_hbc->get_child(i)); |
493 | if (current_btn && p_color == current_btn->get_preset_color()) { |
494 | current_btn->set_pressed(true); |
495 | return true; |
496 | } |
497 | } |
498 | return false; |
499 | } |
500 | |
501 | ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const { |
502 | return modes[current_mode]->get_shape_override() != SHAPE_MAX ? modes[current_mode]->get_shape_override() : current_shape; |
503 | } |
504 | |
505 | void ColorPicker::_reset_sliders_theme() { |
506 | Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat)); |
507 | style_box_flat->set_content_margin(SIDE_TOP, 16 * theme_cache.base_scale); |
508 | style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp()); |
509 | for (int i = 0; i < SLIDER_COUNT; i++) { |
510 | sliders[i]->add_theme_icon_override("grabber" , theme_cache.bar_arrow); |
511 | sliders[i]->add_theme_icon_override("grabber_highlight" , theme_cache.bar_arrow); |
512 | sliders[i]->add_theme_constant_override("grabber_offset" , 8 * theme_cache.base_scale); |
513 | if (!colorize_sliders) { |
514 | sliders[i]->add_theme_style_override("slider" , style_box_flat); |
515 | } |
516 | } |
517 | alpha_slider->add_theme_icon_override("grabber" , theme_cache.bar_arrow); |
518 | alpha_slider->add_theme_icon_override("grabber_highlight" , theme_cache.bar_arrow); |
519 | alpha_slider->add_theme_constant_override("grabber_offset" , 8 * theme_cache.base_scale); |
520 | if (!colorize_sliders) { |
521 | alpha_slider->add_theme_style_override("slider" , style_box_flat); |
522 | } |
523 | } |
524 | |
525 | void ColorPicker::_html_submitted(const String &p_html) { |
526 | if (updating || text_is_constructor || !c_text->is_visible()) { |
527 | return; |
528 | } |
529 | |
530 | const Color previous_color = color; |
531 | color = Color::from_string(p_html.strip_edges(), previous_color); |
532 | |
533 | if (!is_editing_alpha()) { |
534 | color.a = previous_color.a; |
535 | } |
536 | |
537 | if (color == previous_color) { |
538 | return; |
539 | } |
540 | if (!is_inside_tree()) { |
541 | return; |
542 | } |
543 | |
544 | set_pick_color(color); |
545 | emit_signal(SNAME("color_changed" ), color); |
546 | } |
547 | |
548 | void ColorPicker::_update_color(bool p_update_sliders) { |
549 | updating = true; |
550 | |
551 | if (p_update_sliders) { |
552 | float step = modes[current_mode]->get_slider_step(); |
553 | for (int i = 0; i < current_slider_count; i++) { |
554 | sliders[i]->set_max(modes[current_mode]->get_slider_max(i)); |
555 | sliders[i]->set_step(step); |
556 | sliders[i]->set_value(modes[current_mode]->get_slider_value(i)); |
557 | } |
558 | alpha_slider->set_max(modes[current_mode]->get_slider_max(current_slider_count)); |
559 | alpha_slider->set_step(step); |
560 | alpha_slider->set_value(modes[current_mode]->get_slider_value(current_slider_count)); |
561 | } |
562 | |
563 | _update_text_value(); |
564 | |
565 | sample->queue_redraw(); |
566 | uv_edit->queue_redraw(); |
567 | w_edit->queue_redraw(); |
568 | for (int i = 0; i < current_slider_count; i++) { |
569 | sliders[i]->queue_redraw(); |
570 | } |
571 | alpha_slider->queue_redraw(); |
572 | wheel->queue_redraw(); |
573 | wheel_uv->queue_redraw(); |
574 | updating = false; |
575 | } |
576 | |
577 | void ColorPicker::_update_presets() { |
578 | int preset_size = _get_preset_size(); |
579 | // Only update the preset button size if it has changed. |
580 | if (preset_size != prev_preset_size) { |
581 | prev_preset_size = preset_size; |
582 | btn_add_preset->set_custom_minimum_size(Size2(preset_size, preset_size)); |
583 | for (int i = 1; i < preset_container->get_child_count(); i++) { |
584 | ColorPresetButton *cpb = Object::cast_to<ColorPresetButton>(preset_container->get_child(i)); |
585 | cpb->set_custom_minimum_size(Size2(preset_size, preset_size)); |
586 | } |
587 | } |
588 | |
589 | #ifdef TOOLS_ENABLED |
590 | if (editor_settings) { |
591 | // Rebuild swatch color buttons, keeping the add-preset button in the first position. |
592 | for (int i = 1; i < preset_container->get_child_count(); i++) { |
593 | preset_container->get_child(i)->queue_free(); |
594 | } |
595 | for (int i = 0; i < preset_cache.size(); i++) { |
596 | _add_preset_button(preset_size, preset_cache[i]); |
597 | } |
598 | _notification(NOTIFICATION_VISIBILITY_CHANGED); |
599 | } |
600 | #endif |
601 | } |
602 | |
603 | void ColorPicker::_update_recent_presets() { |
604 | #ifdef TOOLS_ENABLED |
605 | if (editor_settings) { |
606 | int recent_preset_count = recent_preset_hbc->get_child_count(); |
607 | for (int i = 0; i < recent_preset_count; i++) { |
608 | memdelete(recent_preset_hbc->get_child(0)); |
609 | } |
610 | |
611 | recent_presets.clear(); |
612 | for (int i = 0; i < recent_preset_cache.size(); i++) { |
613 | recent_presets.push_back(recent_preset_cache[i]); |
614 | } |
615 | |
616 | int preset_size = _get_preset_size(); |
617 | for (int i = 0; i < recent_presets.size(); i++) { |
618 | _add_recent_preset_button(preset_size, recent_presets[i]); |
619 | } |
620 | |
621 | _notification(NOTIFICATION_VISIBILITY_CHANGED); |
622 | } |
623 | #endif |
624 | } |
625 | |
626 | void ColorPicker::_text_type_toggled() { |
627 | text_is_constructor = !text_is_constructor; |
628 | if (text_is_constructor) { |
629 | text_type->set_text("" ); |
630 | #ifdef TOOLS_ENABLED |
631 | text_type->set_icon(get_editor_theme_icon(SNAME("Script" ))); |
632 | #endif |
633 | |
634 | c_text->set_editable(false); |
635 | c_text->set_tooltip_text(RTR("Copy this constructor in a script." )); |
636 | } else { |
637 | text_type->set_text("#" ); |
638 | text_type->set_icon(nullptr); |
639 | |
640 | c_text->set_editable(true); |
641 | c_text->set_tooltip_text(RTR("Enter a hex code (\"#ff0000\") or named color (\"red\")." )); |
642 | } |
643 | _update_color(); |
644 | } |
645 | |
646 | Color ColorPicker::get_pick_color() const { |
647 | return color; |
648 | } |
649 | |
650 | void ColorPicker::set_picker_shape(PickerShapeType p_shape) { |
651 | ERR_FAIL_INDEX(p_shape, SHAPE_MAX); |
652 | if (p_shape == current_shape) { |
653 | return; |
654 | } |
655 | if (current_shape != SHAPE_NONE) { |
656 | shape_popup->set_item_checked(current_shape, false); |
657 | } |
658 | if (p_shape != SHAPE_NONE) { |
659 | shape_popup->set_item_checked(p_shape, true); |
660 | btn_shape->set_icon(shape_popup->get_item_icon(p_shape)); |
661 | } |
662 | |
663 | current_shape = p_shape; |
664 | |
665 | _copy_color_to_hsv(); |
666 | |
667 | _update_controls(); |
668 | _update_color(); |
669 | } |
670 | |
671 | ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const { |
672 | return current_shape; |
673 | } |
674 | |
675 | inline int ColorPicker::_get_preset_size() { |
676 | return (int(get_minimum_size().width) - (preset_container->get_h_separation() * (PRESET_COLUMN_COUNT - 1))) / PRESET_COLUMN_COUNT; |
677 | } |
678 | |
679 | void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { |
680 | ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size)); |
681 | btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset" ), p_color.to_html(p_color.a < 1))); |
682 | SET_DRAG_FORWARDING_GCDU(btn_preset_new, ColorPicker); |
683 | btn_preset_new->set_button_group(preset_group); |
684 | preset_container->add_child(btn_preset_new); |
685 | btn_preset_new->set_pressed(true); |
686 | btn_preset_new->connect("gui_input" , callable_mp(this, &ColorPicker::_preset_input).bind(p_color)); |
687 | } |
688 | |
689 | void ColorPicker::_add_recent_preset_button(int p_size, const Color &p_color) { |
690 | ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size)); |
691 | btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color" ), p_color.to_html(p_color.a < 1))); |
692 | btn_preset_new->set_button_group(recent_preset_group); |
693 | recent_preset_hbc->add_child(btn_preset_new); |
694 | recent_preset_hbc->move_child(btn_preset_new, 0); |
695 | btn_preset_new->set_pressed(true); |
696 | btn_preset_new->connect("toggled" , callable_mp(this, &ColorPicker::_recent_preset_pressed).bind(btn_preset_new)); |
697 | } |
698 | |
699 | void ColorPicker::_show_hide_preset(const bool &p_is_btn_pressed, Button *p_btn_preset, Container *p_preset_container) { |
700 | if (p_is_btn_pressed) { |
701 | p_preset_container->show(); |
702 | } else { |
703 | p_preset_container->hide(); |
704 | } |
705 | _update_drop_down_arrow(p_is_btn_pressed, p_btn_preset); |
706 | } |
707 | |
708 | void ColorPicker::_update_drop_down_arrow(const bool &p_is_btn_pressed, Button *p_btn_preset) { |
709 | if (p_is_btn_pressed) { |
710 | p_btn_preset->set_icon(theme_cache.expanded_arrow); |
711 | } else { |
712 | p_btn_preset->set_icon(theme_cache.folded_arrow); |
713 | } |
714 | } |
715 | |
716 | void ColorPicker::(ColorModeType p_mode) { |
717 | ERR_FAIL_INDEX(p_mode, MODE_MAX + 1); |
718 | |
719 | if (p_mode == MODE_MAX) { |
720 | set_colorize_sliders(!colorize_sliders); |
721 | } else { |
722 | set_color_mode(p_mode); |
723 | } |
724 | } |
725 | |
726 | Variant ColorPicker::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) { |
727 | ColorPresetButton *dragged_preset_button = Object::cast_to<ColorPresetButton>(p_from_control); |
728 | |
729 | if (!dragged_preset_button) { |
730 | return Variant(); |
731 | } |
732 | |
733 | ColorPresetButton *drag_preview = memnew(ColorPresetButton(dragged_preset_button->get_preset_color(), _get_preset_size())); |
734 | set_drag_preview(drag_preview); |
735 | |
736 | Dictionary drag_data; |
737 | drag_data["type" ] = "color_preset" ; |
738 | drag_data["color_preset" ] = dragged_preset_button->get_index(); |
739 | |
740 | return drag_data; |
741 | } |
742 | |
743 | bool ColorPicker::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const { |
744 | Dictionary d = p_data; |
745 | if (!d.has("type" ) || String(d["type" ]) != "color_preset" ) { |
746 | return false; |
747 | } |
748 | return true; |
749 | } |
750 | |
751 | void ColorPicker::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) { |
752 | Dictionary d = p_data; |
753 | if (!d.has("type" )) { |
754 | return; |
755 | } |
756 | |
757 | if (String(d["type" ]) == "color_preset" ) { |
758 | int preset_from_id = d["color_preset" ]; |
759 | int hover_now = p_from_control->get_index(); |
760 | |
761 | if (preset_from_id == hover_now || hover_now == -1) { |
762 | return; |
763 | } |
764 | preset_container->move_child(preset_container->get_child(preset_from_id), hover_now); |
765 | } |
766 | } |
767 | |
768 | void ColorPicker::add_preset(const Color &p_color) { |
769 | List<Color>::Element *e = presets.find(p_color); |
770 | if (e) { |
771 | presets.move_to_back(e); |
772 | preset_cache.move_to_back(preset_cache.find(p_color)); |
773 | |
774 | preset_container->move_child(preset_group->get_pressed_button(), preset_container->get_child_count() - 1); |
775 | } else { |
776 | presets.push_back(p_color); |
777 | preset_cache.push_back(p_color); |
778 | |
779 | _add_preset_button(_get_preset_size(), p_color); |
780 | } |
781 | |
782 | #ifdef TOOLS_ENABLED |
783 | if (editor_settings) { |
784 | PackedColorArray arr_to_save = get_presets(); |
785 | editor_settings->call(SNAME("set_project_metadata" ), "color_picker" , "presets" , arr_to_save); |
786 | } |
787 | #endif |
788 | } |
789 | |
790 | void ColorPicker::add_recent_preset(const Color &p_color) { |
791 | if (!_select_from_recent_preset_hbc(p_color)) { |
792 | if (recent_preset_hbc->get_child_count() >= PRESET_COLUMN_COUNT) { |
793 | recent_preset_cache.pop_front(); |
794 | recent_presets.pop_front(); |
795 | recent_preset_hbc->get_child(PRESET_COLUMN_COUNT - 1)->queue_free(); |
796 | } |
797 | recent_presets.push_back(p_color); |
798 | recent_preset_cache.push_back(p_color); |
799 | _add_recent_preset_button(_get_preset_size(), p_color); |
800 | } |
801 | _select_from_preset_container(p_color); |
802 | |
803 | #ifdef TOOLS_ENABLED |
804 | if (editor_settings) { |
805 | PackedColorArray arr_to_save = get_recent_presets(); |
806 | editor_settings->call(SNAME("set_project_metadata" ), "color_picker" , "recent_presets" , arr_to_save); |
807 | } |
808 | #endif |
809 | } |
810 | |
811 | void ColorPicker::erase_preset(const Color &p_color) { |
812 | List<Color>::Element *e = presets.find(p_color); |
813 | if (e) { |
814 | presets.erase(e); |
815 | preset_cache.erase(preset_cache.find(p_color)); |
816 | |
817 | // Find preset button to remove. |
818 | for (int i = 1; i < preset_container->get_child_count(); i++) { |
819 | ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i)); |
820 | if (current_btn && p_color == current_btn->get_preset_color()) { |
821 | current_btn->queue_free(); |
822 | break; |
823 | } |
824 | } |
825 | |
826 | #ifdef TOOLS_ENABLED |
827 | if (editor_settings) { |
828 | PackedColorArray arr_to_save = get_presets(); |
829 | editor_settings->call(SNAME("set_project_metadata" ), "color_picker" , "presets" , arr_to_save); |
830 | } |
831 | #endif |
832 | } |
833 | } |
834 | |
835 | void ColorPicker::erase_recent_preset(const Color &p_color) { |
836 | List<Color>::Element *e = recent_presets.find(p_color); |
837 | if (e) { |
838 | recent_presets.erase(e); |
839 | recent_preset_cache.erase(recent_preset_cache.find(p_color)); |
840 | |
841 | // Find recent preset button to remove. |
842 | for (int i = 1; i < recent_preset_hbc->get_child_count(); i++) { |
843 | ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(recent_preset_hbc->get_child(i)); |
844 | if (current_btn && p_color == current_btn->get_preset_color()) { |
845 | current_btn->queue_free(); |
846 | break; |
847 | } |
848 | } |
849 | |
850 | #ifdef TOOLS_ENABLED |
851 | if (editor_settings) { |
852 | PackedColorArray arr_to_save = get_recent_presets(); |
853 | editor_settings->call(SNAME("set_project_metadata" ), "color_picker" , "recent_presets" , arr_to_save); |
854 | } |
855 | #endif |
856 | } |
857 | } |
858 | |
859 | PackedColorArray ColorPicker::get_presets() const { |
860 | PackedColorArray arr; |
861 | arr.resize(presets.size()); |
862 | for (int i = 0; i < presets.size(); i++) { |
863 | arr.set(i, presets[i]); |
864 | } |
865 | return arr; |
866 | } |
867 | |
868 | PackedColorArray ColorPicker::get_recent_presets() const { |
869 | PackedColorArray arr; |
870 | arr.resize(recent_presets.size()); |
871 | for (int i = 0; i < recent_presets.size(); i++) { |
872 | arr.set(i, recent_presets[i]); |
873 | } |
874 | return arr; |
875 | } |
876 | |
877 | void ColorPicker::set_color_mode(ColorModeType p_mode) { |
878 | ERR_FAIL_INDEX(p_mode, MODE_MAX); |
879 | |
880 | if (current_mode == p_mode) { |
881 | return; |
882 | } |
883 | |
884 | if (slider_theme_modified) { |
885 | _reset_sliders_theme(); |
886 | } |
887 | |
888 | mode_popup->set_item_checked(current_mode, false); |
889 | mode_popup->set_item_checked(p_mode, true); |
890 | |
891 | if (p_mode < MODE_BUTTON_COUNT) { |
892 | mode_btns[p_mode]->set_pressed(true); |
893 | } else if (current_mode < MODE_BUTTON_COUNT) { |
894 | mode_btns[current_mode]->set_pressed(false); |
895 | } |
896 | |
897 | current_mode = p_mode; |
898 | |
899 | if (!is_inside_tree()) { |
900 | return; |
901 | } |
902 | |
903 | _update_controls(); |
904 | _update_color(); |
905 | } |
906 | |
907 | ColorPicker::ColorModeType ColorPicker::get_color_mode() const { |
908 | return current_mode; |
909 | } |
910 | |
911 | void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) { |
912 | if (colorize_sliders == p_colorize_sliders) { |
913 | return; |
914 | } |
915 | |
916 | colorize_sliders = p_colorize_sliders; |
917 | mode_popup->set_item_checked(MODE_MAX + 1, colorize_sliders); |
918 | |
919 | if (colorize_sliders) { |
920 | Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty)); |
921 | |
922 | if (!slider_theme_modified) { |
923 | for (int i = 0; i < SLIDER_COUNT; i++) { |
924 | sliders[i]->add_theme_style_override("slider" , style_box_empty); |
925 | } |
926 | } |
927 | alpha_slider->add_theme_style_override("slider" , style_box_empty); |
928 | } else { |
929 | Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat)); |
930 | style_box_flat->set_content_margin(SIDE_TOP, 16 * theme_cache.base_scale); |
931 | style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp()); |
932 | |
933 | if (!slider_theme_modified) { |
934 | for (int i = 0; i < SLIDER_COUNT; i++) { |
935 | sliders[i]->add_theme_style_override("slider" , style_box_flat); |
936 | } |
937 | } |
938 | alpha_slider->add_theme_style_override("slider" , style_box_flat); |
939 | } |
940 | } |
941 | |
942 | bool ColorPicker::is_colorizing_sliders() const { |
943 | return colorize_sliders; |
944 | } |
945 | |
946 | void ColorPicker::set_deferred_mode(bool p_enabled) { |
947 | deferred_mode_enabled = p_enabled; |
948 | } |
949 | |
950 | bool ColorPicker::is_deferred_mode() const { |
951 | return deferred_mode_enabled; |
952 | } |
953 | |
954 | void ColorPicker::_update_text_value() { |
955 | bool text_visible = true; |
956 | if (text_is_constructor) { |
957 | String t = "Color(" + String::num(color.r, 3) + ", " + String::num(color.g, 3) + ", " + String::num(color.b, 3); |
958 | if (edit_alpha && color.a < 1) { |
959 | t += ", " + String::num(color.a, 3) + ")" ; |
960 | } else { |
961 | t += ")" ; |
962 | } |
963 | c_text->set_text(t); |
964 | } |
965 | |
966 | if (color.r > 1 || color.g > 1 || color.b > 1 || color.r < 0 || color.g < 0 || color.b < 0) { |
967 | text_visible = false; |
968 | } else if (!text_is_constructor) { |
969 | c_text->set_text(color.to_html(edit_alpha && color.a < 1)); |
970 | } |
971 | |
972 | text_type->set_visible(text_visible); |
973 | c_text->set_visible(text_visible); |
974 | } |
975 | |
976 | void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) { |
977 | const Ref<InputEventMouseButton> mb = p_event; |
978 | if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { |
979 | const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); |
980 | if (rect_old.has_point(mb->get_position())) { |
981 | // Revert to the old color when left-clicking the old color sample. |
982 | set_pick_color(old_color); |
983 | emit_signal(SNAME("color_changed" ), color); |
984 | } |
985 | } |
986 | } |
987 | |
988 | void ColorPicker::_sample_draw() { |
989 | // Covers the right half of the sample if the old color is being displayed, |
990 | // or the whole sample if it's not being displayed. |
991 | Rect2 rect_new; |
992 | |
993 | if (display_old_color) { |
994 | rect_new = Rect2(Point2(sample->get_size().width * 0.5, 0), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); |
995 | |
996 | // Draw both old and new colors for easier comparison (only if spawned from a ColorPickerButton). |
997 | const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95)); |
998 | |
999 | if (old_color.a < 1.0) { |
1000 | sample->draw_texture_rect(theme_cache.sample_bg, rect_old, true); |
1001 | } |
1002 | |
1003 | sample->draw_rect(rect_old, old_color); |
1004 | |
1005 | if (old_color.r > 1 || old_color.g > 1 || old_color.b > 1) { |
1006 | // Draw an indicator to denote that the old color is "overbright" and can't be displayed accurately in the preview. |
1007 | sample->draw_texture(theme_cache.overbright_indicator, Point2()); |
1008 | } |
1009 | } else { |
1010 | rect_new = Rect2(Point2(), Size2(sample->get_size().width, sample->get_size().height * 0.95)); |
1011 | } |
1012 | |
1013 | if (color.a < 1.0) { |
1014 | sample->draw_texture_rect(theme_cache.sample_bg, rect_new, true); |
1015 | } |
1016 | |
1017 | sample->draw_rect(rect_new, color); |
1018 | |
1019 | if (color.r > 1 || color.g > 1 || color.b > 1) { |
1020 | // Draw an indicator to denote that the new color is "overbright" and can't be displayed accurately in the preview. |
1021 | sample->draw_texture(theme_cache.overbright_indicator, Point2(uv_edit->get_size().width * 0.5, 0)); |
1022 | } |
1023 | } |
1024 | |
1025 | void ColorPicker::_hsv_draw(int p_which, Control *c) { |
1026 | if (!c) { |
1027 | return; |
1028 | } |
1029 | |
1030 | PickerShapeType actual_shape = _get_actual_shape(); |
1031 | if (p_which == 0) { |
1032 | Vector<Point2> points; |
1033 | Vector<Color> colors; |
1034 | Vector<Color> colors2; |
1035 | Color col = color; |
1036 | Vector2 center = c->get_size() / 2.0; |
1037 | |
1038 | switch (actual_shape) { |
1039 | case SHAPE_HSV_WHEEL: { |
1040 | points.resize(4); |
1041 | colors.resize(4); |
1042 | colors2.resize(4); |
1043 | real_t ring_radius_x = Math_SQRT12 * c->get_size().width * 0.42; |
1044 | real_t ring_radius_y = Math_SQRT12 * c->get_size().height * 0.42; |
1045 | |
1046 | points.set(0, center - Vector2(ring_radius_x, ring_radius_y)); |
1047 | points.set(1, center + Vector2(ring_radius_x, -ring_radius_y)); |
1048 | points.set(2, center + Vector2(ring_radius_x, ring_radius_y)); |
1049 | points.set(3, center + Vector2(-ring_radius_x, ring_radius_y)); |
1050 | colors.set(0, Color(1, 1, 1, 1)); |
1051 | colors.set(1, Color(1, 1, 1, 1)); |
1052 | colors.set(2, Color(0, 0, 0, 1)); |
1053 | colors.set(3, Color(0, 0, 0, 1)); |
1054 | c->draw_polygon(points, colors); |
1055 | |
1056 | col.set_hsv(h, 1, 1); |
1057 | col.a = 0; |
1058 | colors2.set(0, col); |
1059 | col.a = 1; |
1060 | colors2.set(1, col); |
1061 | col.set_hsv(h, 1, 0); |
1062 | colors2.set(2, col); |
1063 | col.a = 0; |
1064 | colors2.set(3, col); |
1065 | c->draw_polygon(points, colors2); |
1066 | break; |
1067 | } |
1068 | case SHAPE_HSV_RECTANGLE: { |
1069 | points.resize(4); |
1070 | colors.resize(4); |
1071 | colors2.resize(4); |
1072 | points.set(0, Vector2()); |
1073 | points.set(1, Vector2(c->get_size().x, 0)); |
1074 | points.set(2, c->get_size()); |
1075 | points.set(3, Vector2(0, c->get_size().y)); |
1076 | colors.set(0, Color(1, 1, 1, 1)); |
1077 | colors.set(1, Color(1, 1, 1, 1)); |
1078 | colors.set(2, Color(0, 0, 0, 1)); |
1079 | colors.set(3, Color(0, 0, 0, 1)); |
1080 | c->draw_polygon(points, colors); |
1081 | col = color; |
1082 | col.set_hsv(h, 1, 1); |
1083 | col.a = 0; |
1084 | colors2.set(0, col); |
1085 | col.a = 1; |
1086 | colors2.set(1, col); |
1087 | col.set_hsv(h, 1, 0); |
1088 | colors2.set(2, col); |
1089 | col.a = 0; |
1090 | colors2.set(3, col); |
1091 | c->draw_polygon(points, colors2); |
1092 | break; |
1093 | } |
1094 | default: { |
1095 | } |
1096 | } |
1097 | |
1098 | int x; |
1099 | int y; |
1100 | if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { |
1101 | x = center.x + (center.x * Math::cos(h * Math_TAU) * s) - (theme_cache.picker_cursor->get_width() / 2); |
1102 | y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (theme_cache.picker_cursor->get_height() / 2); |
1103 | } else { |
1104 | real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0; |
1105 | real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0; |
1106 | |
1107 | Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2); |
1108 | x = CLAMP(real_size.x * s, 0, real_size.x) + corner_x - (theme_cache.picker_cursor->get_width() / 2); |
1109 | y = CLAMP(real_size.y - real_size.y * v, 0, real_size.y) + corner_y - (theme_cache.picker_cursor->get_height() / 2); |
1110 | } |
1111 | c->draw_texture(theme_cache.picker_cursor, Point2(x, y)); |
1112 | |
1113 | col.set_hsv(h, 1, 1); |
1114 | if (actual_shape == SHAPE_HSV_WHEEL) { |
1115 | points.resize(4); |
1116 | double h1 = h - (0.5 / 360); |
1117 | double h2 = h + (0.5 / 360); |
1118 | points.set(0, Point2(center.x + (center.x * Math::cos(h1 * Math_TAU)), center.y + (center.y * Math::sin(h1 * Math_TAU)))); |
1119 | points.set(1, Point2(center.x + (center.x * Math::cos(h1 * Math_TAU) * 0.84), center.y + (center.y * Math::sin(h1 * Math_TAU) * 0.84))); |
1120 | points.set(2, Point2(center.x + (center.x * Math::cos(h2 * Math_TAU)), center.y + (center.y * Math::sin(h2 * Math_TAU)))); |
1121 | points.set(3, Point2(center.x + (center.x * Math::cos(h2 * Math_TAU) * 0.84), center.y + (center.y * Math::sin(h2 * Math_TAU) * 0.84))); |
1122 | c->draw_multiline(points, col.inverted()); |
1123 | } |
1124 | |
1125 | } else if (p_which == 1) { |
1126 | if (actual_shape == SHAPE_HSV_RECTANGLE) { |
1127 | c->draw_set_transform(Point2(), -Math_PI / 2, Size2(c->get_size().x, -c->get_size().y)); |
1128 | c->draw_texture_rect(theme_cache.color_hue, Rect2(Point2(), Size2(1, 1))); |
1129 | c->draw_set_transform(Point2(), 0, Size2(1, 1)); |
1130 | int y = c->get_size().y - c->get_size().y * (1.0 - h); |
1131 | Color col; |
1132 | col.set_hsv(h, 1, 1); |
1133 | c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); |
1134 | } else if (actual_shape == SHAPE_OKHSL_CIRCLE) { |
1135 | Vector<Point2> points; |
1136 | Vector<Color> colors; |
1137 | Color col; |
1138 | col.set_ok_hsl(h, s, 1); |
1139 | Color col2; |
1140 | col2.set_ok_hsl(h, s, 0.5); |
1141 | Color col3; |
1142 | col3.set_ok_hsl(h, s, 0); |
1143 | points.resize(6); |
1144 | colors.resize(6); |
1145 | points.set(0, Vector2(c->get_size().x, 0)); |
1146 | points.set(1, Vector2(c->get_size().x, c->get_size().y * 0.5)); |
1147 | points.set(2, c->get_size()); |
1148 | points.set(3, Vector2(0, c->get_size().y)); |
1149 | points.set(4, Vector2(0, c->get_size().y * 0.5)); |
1150 | points.set(5, Vector2()); |
1151 | colors.set(0, col); |
1152 | colors.set(1, col2); |
1153 | colors.set(2, col3); |
1154 | colors.set(3, col3); |
1155 | colors.set(4, col2); |
1156 | colors.set(5, col); |
1157 | c->draw_polygon(points, colors); |
1158 | int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1); |
1159 | col.set_ok_hsl(h, 1, v); |
1160 | c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); |
1161 | } else if (actual_shape == SHAPE_VHS_CIRCLE) { |
1162 | Vector<Point2> points; |
1163 | Vector<Color> colors; |
1164 | Color col; |
1165 | col.set_hsv(h, s, 1); |
1166 | points.resize(4); |
1167 | colors.resize(4); |
1168 | points.set(0, Vector2()); |
1169 | points.set(1, Vector2(c->get_size().x, 0)); |
1170 | points.set(2, c->get_size()); |
1171 | points.set(3, Vector2(0, c->get_size().y)); |
1172 | colors.set(0, col); |
1173 | colors.set(1, col); |
1174 | colors.set(2, Color(0, 0, 0)); |
1175 | colors.set(3, Color(0, 0, 0)); |
1176 | c->draw_polygon(points, colors); |
1177 | int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1); |
1178 | col.set_hsv(h, 1, v); |
1179 | c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); |
1180 | } |
1181 | } else if (p_which == 2) { |
1182 | c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1)); |
1183 | if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { |
1184 | circle_mat->set_shader_parameter("v" , v); |
1185 | } |
1186 | } |
1187 | } |
1188 | |
1189 | void ColorPicker::_slider_draw(int p_which) { |
1190 | if (colorize_sliders) { |
1191 | modes[current_mode]->slider_draw(p_which); |
1192 | } |
1193 | } |
1194 | |
1195 | void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { |
1196 | Ref<InputEventMouseButton> bev = p_event; |
1197 | PickerShapeType actual_shape = _get_actual_shape(); |
1198 | |
1199 | if (bev.is_valid()) { |
1200 | if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { |
1201 | Vector2 center = c->get_size() / 2.0; |
1202 | if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { |
1203 | real_t dist = center.distance_to(bev->get_position()); |
1204 | if (dist <= center.x) { |
1205 | real_t rad = center.angle_to_point(bev->get_position()); |
1206 | h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; |
1207 | s = CLAMP(dist / center.x, 0, 1); |
1208 | } else { |
1209 | return; |
1210 | } |
1211 | } else { |
1212 | real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0; |
1213 | real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0; |
1214 | Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2); |
1215 | |
1216 | if (bev->get_position().x < corner_x || bev->get_position().x > c->get_size().x - corner_x || |
1217 | bev->get_position().y < corner_y || bev->get_position().y > c->get_size().y - corner_y) { |
1218 | { |
1219 | real_t dist = center.distance_to(bev->get_position()); |
1220 | |
1221 | if (dist >= center.x * 0.84 && dist <= center.x) { |
1222 | real_t rad = center.angle_to_point(bev->get_position()); |
1223 | h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; |
1224 | spinning = true; |
1225 | } else { |
1226 | return; |
1227 | } |
1228 | } |
1229 | } |
1230 | |
1231 | if (!spinning) { |
1232 | real_t x = CLAMP(bev->get_position().x - corner_x, 0, real_size.x); |
1233 | real_t y = CLAMP(bev->get_position().y - corner_y, 0, real_size.y); |
1234 | |
1235 | s = x / real_size.x; |
1236 | v = 1.0 - y / real_size.y; |
1237 | } |
1238 | } |
1239 | |
1240 | changing_color = true; |
1241 | |
1242 | _copy_hsv_to_color(); |
1243 | last_color = color; |
1244 | set_pick_color(color); |
1245 | _update_color(); |
1246 | |
1247 | if (!deferred_mode_enabled) { |
1248 | emit_signal(SNAME("color_changed" ), color); |
1249 | } |
1250 | } else if (!bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { |
1251 | if (deferred_mode_enabled) { |
1252 | emit_signal(SNAME("color_changed" ), color); |
1253 | } |
1254 | add_recent_preset(color); |
1255 | changing_color = false; |
1256 | spinning = false; |
1257 | } else { |
1258 | changing_color = false; |
1259 | spinning = false; |
1260 | } |
1261 | } |
1262 | |
1263 | Ref<InputEventMouseMotion> mev = p_event; |
1264 | |
1265 | if (mev.is_valid()) { |
1266 | if (!changing_color) { |
1267 | return; |
1268 | } |
1269 | |
1270 | Vector2 center = c->get_size() / 2.0; |
1271 | if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { |
1272 | real_t dist = center.distance_to(mev->get_position()); |
1273 | real_t rad = center.angle_to_point(mev->get_position()); |
1274 | h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; |
1275 | s = CLAMP(dist / center.x, 0, 1); |
1276 | } else { |
1277 | if (spinning) { |
1278 | real_t rad = center.angle_to_point(mev->get_position()); |
1279 | h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; |
1280 | } else { |
1281 | real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0; |
1282 | real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0; |
1283 | Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2); |
1284 | |
1285 | real_t x = CLAMP(mev->get_position().x - corner_x, 0, real_size.x); |
1286 | real_t y = CLAMP(mev->get_position().y - corner_y, 0, real_size.y); |
1287 | |
1288 | s = x / real_size.x; |
1289 | v = 1.0 - y / real_size.y; |
1290 | } |
1291 | } |
1292 | |
1293 | _copy_hsv_to_color(); |
1294 | last_color = color; |
1295 | set_pick_color(color); |
1296 | _update_color(); |
1297 | |
1298 | if (!deferred_mode_enabled) { |
1299 | emit_signal(SNAME("color_changed" ), color); |
1300 | } |
1301 | } |
1302 | } |
1303 | |
1304 | void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { |
1305 | Ref<InputEventMouseButton> bev = p_event; |
1306 | PickerShapeType actual_shape = _get_actual_shape(); |
1307 | |
1308 | if (bev.is_valid()) { |
1309 | if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { |
1310 | changing_color = true; |
1311 | float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height); |
1312 | if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { |
1313 | v = 1.0 - (y / w_edit->get_size().height); |
1314 | } else { |
1315 | h = y / w_edit->get_size().height; |
1316 | } |
1317 | } else { |
1318 | changing_color = false; |
1319 | } |
1320 | |
1321 | _copy_hsv_to_color(); |
1322 | last_color = color; |
1323 | set_pick_color(color); |
1324 | _update_color(); |
1325 | |
1326 | if (!bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { |
1327 | add_recent_preset(color); |
1328 | emit_signal(SNAME("color_changed" ), color); |
1329 | } else if (!deferred_mode_enabled) { |
1330 | emit_signal(SNAME("color_changed" ), color); |
1331 | } |
1332 | } |
1333 | |
1334 | Ref<InputEventMouseMotion> mev = p_event; |
1335 | |
1336 | if (mev.is_valid()) { |
1337 | if (!changing_color) { |
1338 | return; |
1339 | } |
1340 | float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height); |
1341 | if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { |
1342 | v = 1.0 - (y / w_edit->get_size().height); |
1343 | } else { |
1344 | h = y / w_edit->get_size().height; |
1345 | } |
1346 | |
1347 | _copy_hsv_to_color(); |
1348 | last_color = color; |
1349 | set_pick_color(color); |
1350 | _update_color(); |
1351 | |
1352 | if (!deferred_mode_enabled) { |
1353 | emit_signal(SNAME("color_changed" ), color); |
1354 | } |
1355 | } |
1356 | } |
1357 | |
1358 | void ColorPicker::_slider_or_spin_input(const Ref<InputEvent> &p_event) { |
1359 | if (line_edit_mouse_release) { |
1360 | line_edit_mouse_release = false; |
1361 | return; |
1362 | } |
1363 | Ref<InputEventMouseButton> bev = p_event; |
1364 | if (bev.is_valid() && !bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { |
1365 | add_recent_preset(color); |
1366 | } |
1367 | } |
1368 | |
1369 | void ColorPicker::_line_edit_input(const Ref<InputEvent> &p_event) { |
1370 | Ref<InputEventMouseButton> bev = p_event; |
1371 | if (bev.is_valid() && !bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { |
1372 | line_edit_mouse_release = true; |
1373 | } |
1374 | } |
1375 | |
1376 | void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_color) { |
1377 | Ref<InputEventMouseButton> bev = p_event; |
1378 | |
1379 | if (bev.is_valid()) { |
1380 | if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { |
1381 | set_pick_color(p_color); |
1382 | add_recent_preset(color); |
1383 | emit_signal(SNAME("color_changed" ), p_color); |
1384 | } else if (bev->is_pressed() && bev->get_button_index() == MouseButton::RIGHT && can_add_swatches) { |
1385 | erase_preset(p_color); |
1386 | emit_signal(SNAME("preset_removed" ), p_color); |
1387 | } |
1388 | } |
1389 | } |
1390 | |
1391 | void ColorPicker::_recent_preset_pressed(const bool p_pressed, ColorPresetButton *p_preset) { |
1392 | if (!p_pressed) { |
1393 | return; |
1394 | } |
1395 | set_pick_color(p_preset->get_preset_color()); |
1396 | |
1397 | recent_presets.move_to_back(recent_presets.find(p_preset->get_preset_color())); |
1398 | List<Color>::Element *e = recent_preset_cache.find(p_preset->get_preset_color()); |
1399 | if (e) { |
1400 | recent_preset_cache.move_to_back(e); |
1401 | } |
1402 | |
1403 | recent_preset_hbc->move_child(p_preset, 0); |
1404 | emit_signal(SNAME("color_changed" ), p_preset->get_preset_color()); |
1405 | } |
1406 | |
1407 | void ColorPicker::_text_changed(const String &) { |
1408 | text_changed = true; |
1409 | } |
1410 | |
1411 | void ColorPicker::_add_preset_pressed() { |
1412 | add_preset(color); |
1413 | emit_signal(SNAME("preset_added" ), color); |
1414 | } |
1415 | |
1416 | void ColorPicker::_pick_button_pressed() { |
1417 | is_picking_color = true; |
1418 | set_process_internal(true); |
1419 | |
1420 | if (!picker_window) { |
1421 | picker_window = memnew(Popup); |
1422 | picker_window->set_size(Vector2i(1, 1)); |
1423 | picker_window->connect("visibility_changed" , callable_mp(this, &ColorPicker::_pick_finished)); |
1424 | add_child(picker_window, false, INTERNAL_MODE_FRONT); |
1425 | } |
1426 | picker_window->popup(); |
1427 | } |
1428 | |
1429 | void ColorPicker::_pick_finished() { |
1430 | if (picker_window->is_visible()) { |
1431 | return; |
1432 | } |
1433 | |
1434 | if (Input::get_singleton()->is_key_pressed(Key::ESCAPE)) { |
1435 | set_pick_color(old_color); |
1436 | } else { |
1437 | emit_signal(SNAME("color_changed" ), color); |
1438 | } |
1439 | is_picking_color = false; |
1440 | set_process_internal(false); |
1441 | picker_window->hide(); |
1442 | } |
1443 | |
1444 | void ColorPicker::_pick_button_pressed_legacy() { |
1445 | if (!is_inside_tree()) { |
1446 | return; |
1447 | } |
1448 | |
1449 | if (!picker_window) { |
1450 | picker_window = memnew(Popup); |
1451 | picker_window->hide(); |
1452 | picker_window->set_transient(true); |
1453 | add_child(picker_window, false, INTERNAL_MODE_FRONT); |
1454 | |
1455 | picker_texture_rect = memnew(TextureRect); |
1456 | picker_texture_rect->set_anchors_preset(Control::PRESET_FULL_RECT); |
1457 | picker_window->add_child(picker_texture_rect); |
1458 | picker_texture_rect->set_default_cursor_shape(CURSOR_POINTING_HAND); |
1459 | picker_texture_rect->connect("gui_input" , callable_mp(this, &ColorPicker::_picker_texture_input)); |
1460 | |
1461 | picker_preview = memnew(Panel); |
1462 | picker_preview->set_anchors_preset(Control::PRESET_CENTER_TOP); |
1463 | picker_preview->set_mouse_filter(MOUSE_FILTER_IGNORE); |
1464 | picker_window->add_child(picker_preview); |
1465 | |
1466 | picker_preview_label = memnew(Label); |
1467 | picker_preview->set_anchors_preset(Control::PRESET_CENTER_TOP); |
1468 | picker_preview_label->set_text("Color Picking active" ); |
1469 | picker_preview->add_child(picker_preview_label); |
1470 | |
1471 | picker_preview_style_box = (Ref<StyleBoxFlat>)memnew(StyleBoxFlat); |
1472 | picker_preview_style_box->set_bg_color(Color(1.0, 1.0, 1.0)); |
1473 | picker_preview->add_theme_style_override("panel" , picker_preview_style_box); |
1474 | } |
1475 | |
1476 | Rect2i screen_rect; |
1477 | if (picker_window->is_embedded()) { |
1478 | screen_rect = picker_window->get_embedder()->get_visible_rect(); |
1479 | picker_window->set_position(Point2i()); |
1480 | picker_texture_rect->set_texture(ImageTexture::create_from_image(picker_window->get_embedder()->get_texture()->get_image())); |
1481 | } else { |
1482 | screen_rect = picker_window->get_parent_rect(); |
1483 | picker_window->set_position(screen_rect.position); |
1484 | |
1485 | Ref<Image> target_image = Image::create_empty(screen_rect.size.x, screen_rect.size.y, false, Image::FORMAT_RGB8); |
1486 | DisplayServer *ds = DisplayServer::get_singleton(); |
1487 | |
1488 | // Add the Texture of each Window to the Image. |
1489 | Vector<DisplayServer::WindowID> wl = ds->get_window_list(); |
1490 | // FIXME: sort windows by visibility. |
1491 | for (int index = 0; index < wl.size(); index++) { |
1492 | DisplayServer::WindowID wid = wl[index]; |
1493 | if (wid == DisplayServer::INVALID_WINDOW_ID) { |
1494 | continue; |
1495 | } |
1496 | |
1497 | ObjectID woid = DisplayServer::get_singleton()->window_get_attached_instance_id(wid); |
1498 | if (woid == ObjectID()) { |
1499 | continue; |
1500 | } |
1501 | |
1502 | Window *w = Object::cast_to<Window>(ObjectDB::get_instance(woid)); |
1503 | Ref<Image> img = w->get_texture()->get_image(); |
1504 | if (!img.is_valid() || img->is_empty()) { |
1505 | continue; |
1506 | } |
1507 | img->convert(Image::FORMAT_RGB8); |
1508 | target_image->blit_rect(img, Rect2i(Point2i(0, 0), img->get_size()), w->get_position()); |
1509 | } |
1510 | |
1511 | picker_texture_rect->set_texture(ImageTexture::create_from_image(target_image)); |
1512 | } |
1513 | |
1514 | picker_window->set_size(screen_rect.size); |
1515 | picker_preview->set_size(screen_rect.size / 10.0); // 10% of size in each axis. |
1516 | picker_window->popup(); |
1517 | } |
1518 | |
1519 | void ColorPicker::_picker_texture_input(const Ref<InputEvent> &p_event) { |
1520 | if (!is_inside_tree()) { |
1521 | return; |
1522 | } |
1523 | |
1524 | Ref<InputEventMouseButton> bev = p_event; |
1525 | if (bev.is_valid() && bev->get_button_index() == MouseButton::LEFT && !bev->is_pressed()) { |
1526 | set_pick_color(picker_color); |
1527 | emit_signal(SNAME("color_changed" ), color); |
1528 | picker_window->hide(); |
1529 | } |
1530 | |
1531 | Ref<InputEventMouseMotion> mev = p_event; |
1532 | if (mev.is_valid()) { |
1533 | Ref<Image> img = picker_texture_rect->get_texture()->get_image(); |
1534 | if (img.is_valid() && !img->is_empty()) { |
1535 | Vector2 ofs = mev->get_position(); |
1536 | picker_color = img->get_pixel(ofs.x, ofs.y); |
1537 | picker_preview_style_box->set_bg_color(picker_color); |
1538 | picker_preview_label->set_self_modulate(picker_color.get_luminance() < 0.5 ? Color(1.0f, 1.0f, 1.0f) : Color(0.0f, 0.0f, 0.0f)); |
1539 | } |
1540 | } |
1541 | } |
1542 | |
1543 | void ColorPicker::_html_focus_exit() { |
1544 | if (c_text->is_menu_visible()) { |
1545 | return; |
1546 | } |
1547 | _html_submitted(c_text->get_text()); |
1548 | } |
1549 | |
1550 | void ColorPicker::set_can_add_swatches(bool p_enabled) { |
1551 | if (can_add_swatches == p_enabled) { |
1552 | return; |
1553 | } |
1554 | can_add_swatches = p_enabled; |
1555 | if (!p_enabled) { |
1556 | btn_add_preset->set_disabled(true); |
1557 | btn_add_preset->set_focus_mode(FOCUS_NONE); |
1558 | } else { |
1559 | btn_add_preset->set_disabled(false); |
1560 | btn_add_preset->set_focus_mode(FOCUS_ALL); |
1561 | } |
1562 | } |
1563 | |
1564 | bool ColorPicker::are_swatches_enabled() const { |
1565 | return can_add_swatches; |
1566 | } |
1567 | |
1568 | void ColorPicker::set_presets_visible(bool p_visible) { |
1569 | if (presets_visible == p_visible) { |
1570 | return; |
1571 | } |
1572 | presets_visible = p_visible; |
1573 | btn_preset->set_visible(p_visible); |
1574 | btn_recent_preset->set_visible(p_visible); |
1575 | } |
1576 | |
1577 | bool ColorPicker::are_presets_visible() const { |
1578 | return presets_visible; |
1579 | } |
1580 | |
1581 | void ColorPicker::set_modes_visible(bool p_visible) { |
1582 | if (color_modes_visible == p_visible) { |
1583 | return; |
1584 | } |
1585 | color_modes_visible = p_visible; |
1586 | mode_hbc->set_visible(p_visible); |
1587 | } |
1588 | |
1589 | bool ColorPicker::are_modes_visible() const { |
1590 | return color_modes_visible; |
1591 | } |
1592 | |
1593 | void ColorPicker::set_sampler_visible(bool p_visible) { |
1594 | if (sampler_visible == p_visible) { |
1595 | return; |
1596 | } |
1597 | sampler_visible = p_visible; |
1598 | sample_hbc->set_visible(p_visible); |
1599 | } |
1600 | |
1601 | bool ColorPicker::is_sampler_visible() const { |
1602 | return sampler_visible; |
1603 | } |
1604 | |
1605 | void ColorPicker::set_sliders_visible(bool p_visible) { |
1606 | if (sliders_visible == p_visible) { |
1607 | return; |
1608 | } |
1609 | sliders_visible = p_visible; |
1610 | slider_gc->set_visible(p_visible); |
1611 | } |
1612 | |
1613 | bool ColorPicker::are_sliders_visible() const { |
1614 | return sliders_visible; |
1615 | } |
1616 | |
1617 | void ColorPicker::set_hex_visible(bool p_visible) { |
1618 | if (hex_visible == p_visible) { |
1619 | return; |
1620 | } |
1621 | hex_visible = p_visible; |
1622 | hex_hbc->set_visible(p_visible); |
1623 | } |
1624 | |
1625 | bool ColorPicker::is_hex_visible() const { |
1626 | return hex_visible; |
1627 | } |
1628 | |
1629 | void ColorPicker::_bind_methods() { |
1630 | ClassDB::bind_method(D_METHOD("set_pick_color" , "color" ), &ColorPicker::set_pick_color); |
1631 | ClassDB::bind_method(D_METHOD("get_pick_color" ), &ColorPicker::get_pick_color); |
1632 | ClassDB::bind_method(D_METHOD("set_deferred_mode" , "mode" ), &ColorPicker::set_deferred_mode); |
1633 | ClassDB::bind_method(D_METHOD("is_deferred_mode" ), &ColorPicker::is_deferred_mode); |
1634 | ClassDB::bind_method(D_METHOD("set_color_mode" , "color_mode" ), &ColorPicker::set_color_mode); |
1635 | ClassDB::bind_method(D_METHOD("get_color_mode" ), &ColorPicker::get_color_mode); |
1636 | ClassDB::bind_method(D_METHOD("set_edit_alpha" , "show" ), &ColorPicker::set_edit_alpha); |
1637 | ClassDB::bind_method(D_METHOD("is_editing_alpha" ), &ColorPicker::is_editing_alpha); |
1638 | ClassDB::bind_method(D_METHOD("set_can_add_swatches" , "enabled" ), &ColorPicker::set_can_add_swatches); |
1639 | ClassDB::bind_method(D_METHOD("are_swatches_enabled" ), &ColorPicker::are_swatches_enabled); |
1640 | ClassDB::bind_method(D_METHOD("set_presets_visible" , "visible" ), &ColorPicker::set_presets_visible); |
1641 | ClassDB::bind_method(D_METHOD("are_presets_visible" ), &ColorPicker::are_presets_visible); |
1642 | ClassDB::bind_method(D_METHOD("set_modes_visible" , "visible" ), &ColorPicker::set_modes_visible); |
1643 | ClassDB::bind_method(D_METHOD("are_modes_visible" ), &ColorPicker::are_modes_visible); |
1644 | ClassDB::bind_method(D_METHOD("set_sampler_visible" , "visible" ), &ColorPicker::set_sampler_visible); |
1645 | ClassDB::bind_method(D_METHOD("is_sampler_visible" ), &ColorPicker::is_sampler_visible); |
1646 | ClassDB::bind_method(D_METHOD("set_sliders_visible" , "visible" ), &ColorPicker::set_sliders_visible); |
1647 | ClassDB::bind_method(D_METHOD("are_sliders_visible" ), &ColorPicker::are_sliders_visible); |
1648 | ClassDB::bind_method(D_METHOD("set_hex_visible" , "visible" ), &ColorPicker::set_hex_visible); |
1649 | ClassDB::bind_method(D_METHOD("is_hex_visible" ), &ColorPicker::is_hex_visible); |
1650 | ClassDB::bind_method(D_METHOD("add_preset" , "color" ), &ColorPicker::add_preset); |
1651 | ClassDB::bind_method(D_METHOD("erase_preset" , "color" ), &ColorPicker::erase_preset); |
1652 | ClassDB::bind_method(D_METHOD("get_presets" ), &ColorPicker::get_presets); |
1653 | ClassDB::bind_method(D_METHOD("add_recent_preset" , "color" ), &ColorPicker::add_recent_preset); |
1654 | ClassDB::bind_method(D_METHOD("erase_recent_preset" , "color" ), &ColorPicker::erase_recent_preset); |
1655 | ClassDB::bind_method(D_METHOD("get_recent_presets" ), &ColorPicker::get_recent_presets); |
1656 | ClassDB::bind_method(D_METHOD("set_picker_shape" , "shape" ), &ColorPicker::set_picker_shape); |
1657 | ClassDB::bind_method(D_METHOD("get_picker_shape" ), &ColorPicker::get_picker_shape); |
1658 | |
1659 | ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color" ), "set_pick_color" , "get_pick_color" ); |
1660 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha" ), "set_edit_alpha" , "is_editing_alpha" ); |
1661 | ADD_PROPERTY(PropertyInfo(Variant::INT, "color_mode" , PROPERTY_HINT_ENUM, "RGB,HSV,RAW,OKHSL" ), "set_color_mode" , "get_color_mode" ); |
1662 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode" ), "set_deferred_mode" , "is_deferred_mode" ); |
1663 | ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape" , PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,None" ), "set_picker_shape" , "get_picker_shape" ); |
1664 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_add_swatches" ), "set_can_add_swatches" , "are_swatches_enabled" ); |
1665 | ADD_GROUP("Customization" , "" ); |
1666 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sampler_visible" ), "set_sampler_visible" , "is_sampler_visible" ); |
1667 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "color_modes_visible" ), "set_modes_visible" , "are_modes_visible" ); |
1668 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sliders_visible" ), "set_sliders_visible" , "are_sliders_visible" ); |
1669 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hex_visible" ), "set_hex_visible" , "is_hex_visible" ); |
1670 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible" ), "set_presets_visible" , "are_presets_visible" ); |
1671 | |
1672 | ADD_SIGNAL(MethodInfo("color_changed" , PropertyInfo(Variant::COLOR, "color" ))); |
1673 | ADD_SIGNAL(MethodInfo("preset_added" , PropertyInfo(Variant::COLOR, "color" ))); |
1674 | ADD_SIGNAL(MethodInfo("preset_removed" , PropertyInfo(Variant::COLOR, "color" ))); |
1675 | |
1676 | BIND_ENUM_CONSTANT(MODE_RGB); |
1677 | BIND_ENUM_CONSTANT(MODE_HSV); |
1678 | BIND_ENUM_CONSTANT(MODE_RAW); |
1679 | BIND_ENUM_CONSTANT(MODE_OKHSL); |
1680 | |
1681 | BIND_ENUM_CONSTANT(SHAPE_HSV_RECTANGLE); |
1682 | BIND_ENUM_CONSTANT(SHAPE_HSV_WHEEL); |
1683 | BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE); |
1684 | BIND_ENUM_CONSTANT(SHAPE_OKHSL_CIRCLE); |
1685 | BIND_ENUM_CONSTANT(SHAPE_NONE); |
1686 | |
1687 | BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, ColorPicker, content_margin, "margin" ); |
1688 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, label_width); |
1689 | |
1690 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, sv_width); |
1691 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, sv_height); |
1692 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, h_width); |
1693 | |
1694 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, center_slider_grabbers); |
1695 | |
1696 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, screen_picker); |
1697 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, expanded_arrow); |
1698 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, folded_arrow); |
1699 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, add_preset); |
1700 | |
1701 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, shape_rect); |
1702 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, shape_rect_wheel); |
1703 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, shape_circle); |
1704 | |
1705 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, bar_arrow); |
1706 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, sample_bg); |
1707 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, overbright_indicator); |
1708 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, picker_cursor); |
1709 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, color_hue); |
1710 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, color_okhsl_hue); |
1711 | |
1712 | BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_normal, "tab_unselected" , "TabContainer" ); |
1713 | BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_pressed, "tab_selected" , "TabContainer" ); |
1714 | BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_hover, "tab_selected" , "TabContainer" ); |
1715 | } |
1716 | |
1717 | ColorPicker::ColorPicker() { |
1718 | internal_margin = memnew(MarginContainer); |
1719 | add_child(internal_margin, false, INTERNAL_MODE_FRONT); |
1720 | |
1721 | VBoxContainer *real_vbox = memnew(VBoxContainer); |
1722 | internal_margin->add_child(real_vbox); |
1723 | |
1724 | HBoxContainer *hb_edit = memnew(HBoxContainer); |
1725 | real_vbox->add_child(hb_edit); |
1726 | hb_edit->set_v_size_flags(SIZE_SHRINK_BEGIN); |
1727 | |
1728 | uv_edit = memnew(Control); |
1729 | hb_edit->add_child(uv_edit); |
1730 | uv_edit->connect("gui_input" , callable_mp(this, &ColorPicker::_uv_input).bind(uv_edit)); |
1731 | uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); |
1732 | uv_edit->set_h_size_flags(SIZE_EXPAND_FILL); |
1733 | uv_edit->set_v_size_flags(SIZE_EXPAND_FILL); |
1734 | uv_edit->connect("draw" , callable_mp(this, &ColorPicker::_hsv_draw).bind(0, uv_edit)); |
1735 | |
1736 | sample_hbc = memnew(HBoxContainer); |
1737 | real_vbox->add_child(sample_hbc); |
1738 | |
1739 | btn_pick = memnew(Button); |
1740 | sample_hbc->add_child(btn_pick); |
1741 | if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SCREEN_CAPTURE)) { |
1742 | btn_pick->set_tooltip_text(RTR("Pick a color from the screen." )); |
1743 | btn_pick->connect(SNAME("pressed" ), callable_mp(this, &ColorPicker::_pick_button_pressed)); |
1744 | } else { |
1745 | // On unsupported platforms, use a legacy method for color picking. |
1746 | btn_pick->set_tooltip_text(RTR("Pick a color from the application window." )); |
1747 | btn_pick->connect(SNAME("pressed" ), callable_mp(this, &ColorPicker::_pick_button_pressed_legacy)); |
1748 | } |
1749 | |
1750 | sample = memnew(TextureRect); |
1751 | sample_hbc->add_child(sample); |
1752 | sample->set_h_size_flags(SIZE_EXPAND_FILL); |
1753 | sample->connect("gui_input" , callable_mp(this, &ColorPicker::_sample_input)); |
1754 | sample->connect("draw" , callable_mp(this, &ColorPicker::_sample_draw)); |
1755 | |
1756 | btn_shape = memnew(MenuButton); |
1757 | btn_shape->set_flat(false); |
1758 | sample_hbc->add_child(btn_shape); |
1759 | btn_shape->set_toggle_mode(true); |
1760 | btn_shape->set_tooltip_text(RTR("Select a picker shape." )); |
1761 | |
1762 | current_shape = SHAPE_HSV_RECTANGLE; |
1763 | |
1764 | shape_popup = btn_shape->get_popup(); |
1765 | shape_popup->add_radio_check_item("HSV Rectangle" , SHAPE_HSV_RECTANGLE); |
1766 | shape_popup->add_radio_check_item("HSV Wheel" , SHAPE_HSV_WHEEL); |
1767 | shape_popup->add_radio_check_item("VHS Circle" , SHAPE_VHS_CIRCLE); |
1768 | shape_popup->add_radio_check_item("OKHSL Circle" , SHAPE_OKHSL_CIRCLE); |
1769 | shape_popup->set_item_checked(current_shape, true); |
1770 | shape_popup->connect("id_pressed" , callable_mp(this, &ColorPicker::set_picker_shape)); |
1771 | |
1772 | btn_shape->set_icon(shape_popup->get_item_icon(current_shape)); |
1773 | |
1774 | add_mode(new ColorModeRGB(this)); |
1775 | add_mode(new ColorModeHSV(this)); |
1776 | add_mode(new ColorModeRAW(this)); |
1777 | add_mode(new ColorModeOKHSL(this)); |
1778 | |
1779 | mode_hbc = memnew(HBoxContainer); |
1780 | real_vbox->add_child(mode_hbc); |
1781 | |
1782 | mode_group.instantiate(); |
1783 | |
1784 | for (int i = 0; i < MODE_BUTTON_COUNT; i++) { |
1785 | mode_btns[i] = memnew(Button); |
1786 | mode_hbc->add_child(mode_btns[i]); |
1787 | mode_btns[i]->set_focus_mode(FOCUS_NONE); |
1788 | mode_btns[i]->set_h_size_flags(SIZE_EXPAND_FILL); |
1789 | mode_btns[i]->set_toggle_mode(true); |
1790 | mode_btns[i]->set_text(modes[i]->get_name()); |
1791 | mode_btns[i]->set_button_group(mode_group); |
1792 | mode_btns[i]->connect("pressed" , callable_mp(this, &ColorPicker::set_color_mode).bind((ColorModeType)i)); |
1793 | } |
1794 | mode_btns[0]->set_pressed(true); |
1795 | |
1796 | btn_mode = memnew(MenuButton); |
1797 | btn_mode->set_text("..." ); |
1798 | btn_mode->set_flat(false); |
1799 | mode_hbc->add_child(btn_mode); |
1800 | btn_mode->set_toggle_mode(true); |
1801 | btn_mode->set_tooltip_text(RTR("Select a picker mode." )); |
1802 | |
1803 | current_mode = MODE_RGB; |
1804 | |
1805 | mode_popup = btn_mode->get_popup(); |
1806 | for (int i = 0; i < modes.size(); i++) { |
1807 | mode_popup->add_radio_check_item(modes[i]->get_name(), i); |
1808 | } |
1809 | mode_popup->add_separator(); |
1810 | mode_popup->add_check_item("Colorized Sliders" , MODE_MAX); |
1811 | mode_popup->set_item_checked(current_mode, true); |
1812 | mode_popup->set_item_checked(MODE_MAX + 1, true); |
1813 | mode_popup->connect("id_pressed" , callable_mp(this, &ColorPicker::_set_mode_popup_value)); |
1814 | VBoxContainer *vbl = memnew(VBoxContainer); |
1815 | real_vbox->add_child(vbl); |
1816 | |
1817 | VBoxContainer *vbr = memnew(VBoxContainer); |
1818 | |
1819 | real_vbox->add_child(vbr); |
1820 | vbr->set_h_size_flags(SIZE_EXPAND_FILL); |
1821 | |
1822 | slider_gc = memnew(GridContainer); |
1823 | |
1824 | vbr->add_child(slider_gc); |
1825 | slider_gc->set_h_size_flags(SIZE_EXPAND_FILL); |
1826 | slider_gc->set_columns(3); |
1827 | |
1828 | for (int i = 0; i < SLIDER_COUNT + 1; i++) { |
1829 | create_slider(slider_gc, i); |
1830 | } |
1831 | |
1832 | alpha_label->set_text("A" ); |
1833 | |
1834 | hex_hbc = memnew(HBoxContainer); |
1835 | hex_hbc->set_alignment(ALIGNMENT_BEGIN); |
1836 | vbr->add_child(hex_hbc); |
1837 | |
1838 | hex_hbc->add_child(memnew(Label("Hex" ))); |
1839 | |
1840 | text_type = memnew(Button); |
1841 | hex_hbc->add_child(text_type); |
1842 | text_type->set_text("#" ); |
1843 | text_type->set_tooltip_text(RTR("Switch between hexadecimal and code values." )); |
1844 | if (Engine::get_singleton()->is_editor_hint()) { |
1845 | text_type->connect("pressed" , callable_mp(this, &ColorPicker::_text_type_toggled)); |
1846 | } else { |
1847 | text_type->set_flat(true); |
1848 | text_type->set_mouse_filter(MOUSE_FILTER_IGNORE); |
1849 | } |
1850 | |
1851 | c_text = memnew(LineEdit); |
1852 | hex_hbc->add_child(c_text); |
1853 | c_text->set_h_size_flags(SIZE_EXPAND_FILL); |
1854 | c_text->set_select_all_on_focus(true); |
1855 | c_text->set_tooltip_text(RTR("Enter a hex code (\"#ff0000\") or named color (\"red\")." )); |
1856 | c_text->set_placeholder(RTR("Hex code or named color" )); |
1857 | c_text->connect("text_submitted" , callable_mp(this, &ColorPicker::_html_submitted)); |
1858 | c_text->connect("text_changed" , callable_mp(this, &ColorPicker::_text_changed)); |
1859 | c_text->connect("focus_exited" , callable_mp(this, &ColorPicker::_html_focus_exit)); |
1860 | |
1861 | wheel_edit = memnew(AspectRatioContainer); |
1862 | wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL); |
1863 | wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL); |
1864 | hb_edit->add_child(wheel_edit); |
1865 | |
1866 | wheel_mat.instantiate(); |
1867 | wheel_mat->set_shader(wheel_shader); |
1868 | circle_mat.instantiate(); |
1869 | circle_mat->set_shader(circle_shader); |
1870 | |
1871 | wheel_margin = memnew(MarginContainer); |
1872 | wheel_margin->add_theme_constant_override("margin_bottom" , 8); |
1873 | wheel_edit->add_child(wheel_margin); |
1874 | |
1875 | wheel = memnew(Control); |
1876 | wheel_margin->add_child(wheel); |
1877 | wheel->set_mouse_filter(MOUSE_FILTER_PASS); |
1878 | wheel->connect("draw" , callable_mp(this, &ColorPicker::_hsv_draw).bind(2, wheel)); |
1879 | |
1880 | wheel_uv = memnew(Control); |
1881 | wheel_margin->add_child(wheel_uv); |
1882 | wheel_uv->connect("gui_input" , callable_mp(this, &ColorPicker::_uv_input).bind(wheel_uv)); |
1883 | wheel_uv->connect("draw" , callable_mp(this, &ColorPicker::_hsv_draw).bind(0, wheel_uv)); |
1884 | |
1885 | w_edit = memnew(Control); |
1886 | hb_edit->add_child(w_edit); |
1887 | w_edit->set_h_size_flags(SIZE_FILL); |
1888 | w_edit->set_v_size_flags(SIZE_EXPAND_FILL); |
1889 | w_edit->connect("gui_input" , callable_mp(this, &ColorPicker::_w_input)); |
1890 | w_edit->connect("draw" , callable_mp(this, &ColorPicker::_hsv_draw).bind(1, w_edit)); |
1891 | |
1892 | _update_controls(); |
1893 | updating = false; |
1894 | |
1895 | preset_container = memnew(GridContainer); |
1896 | preset_container->set_h_size_flags(SIZE_EXPAND_FILL); |
1897 | preset_container->set_columns(PRESET_COLUMN_COUNT); |
1898 | preset_container->hide(); |
1899 | |
1900 | preset_group.instantiate(); |
1901 | |
1902 | btn_preset = memnew(Button); |
1903 | btn_preset->set_text("Swatches" ); |
1904 | btn_preset->set_flat(true); |
1905 | btn_preset->set_toggle_mode(true); |
1906 | btn_preset->set_focus_mode(FOCUS_NONE); |
1907 | btn_preset->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); |
1908 | btn_preset->connect("toggled" , callable_mp(this, &ColorPicker::_show_hide_preset).bind(btn_preset, preset_container)); |
1909 | real_vbox->add_child(btn_preset); |
1910 | |
1911 | real_vbox->add_child(preset_container); |
1912 | |
1913 | recent_preset_hbc = memnew(HBoxContainer); |
1914 | recent_preset_hbc->set_v_size_flags(SIZE_SHRINK_BEGIN); |
1915 | recent_preset_hbc->hide(); |
1916 | |
1917 | recent_preset_group.instantiate(); |
1918 | |
1919 | btn_recent_preset = memnew(Button); |
1920 | btn_recent_preset->set_text("Recent Colors" ); |
1921 | btn_recent_preset->set_flat(true); |
1922 | btn_recent_preset->set_toggle_mode(true); |
1923 | btn_recent_preset->set_focus_mode(FOCUS_NONE); |
1924 | btn_recent_preset->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); |
1925 | btn_recent_preset->connect("toggled" , callable_mp(this, &ColorPicker::_show_hide_preset).bind(btn_recent_preset, recent_preset_hbc)); |
1926 | real_vbox->add_child(btn_recent_preset); |
1927 | |
1928 | real_vbox->add_child(recent_preset_hbc); |
1929 | |
1930 | set_pick_color(Color(1, 1, 1)); |
1931 | |
1932 | btn_add_preset = memnew(Button); |
1933 | btn_add_preset->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER); |
1934 | btn_add_preset->set_tooltip_text(RTR("Add current color as a preset." )); |
1935 | btn_add_preset->connect("pressed" , callable_mp(this, &ColorPicker::_add_preset_pressed)); |
1936 | preset_container->add_child(btn_add_preset); |
1937 | } |
1938 | |
1939 | ColorPicker::~ColorPicker() { |
1940 | for (int i = 0; i < modes.size(); i++) { |
1941 | delete modes[i]; |
1942 | } |
1943 | } |
1944 | |
1945 | ///////////////// |
1946 | |
1947 | void ColorPickerButton::() { |
1948 | set_pressed(true); |
1949 | if (picker) { |
1950 | picker->set_old_color(color); |
1951 | } |
1952 | } |
1953 | |
1954 | void ColorPickerButton::_color_changed(const Color &p_color) { |
1955 | color = p_color; |
1956 | queue_redraw(); |
1957 | emit_signal(SNAME("color_changed" ), color); |
1958 | } |
1959 | |
1960 | void ColorPickerButton::_modal_closed() { |
1961 | emit_signal(SNAME("popup_closed" )); |
1962 | set_pressed(false); |
1963 | } |
1964 | |
1965 | void ColorPickerButton::pressed() { |
1966 | _update_picker(); |
1967 | |
1968 | Size2 minsize = popup->get_contents_minimum_size(); |
1969 | float viewport_height = get_viewport_rect().size.y; |
1970 | |
1971 | popup->reset_size(); |
1972 | picker->_update_presets(); |
1973 | picker->_update_recent_presets(); |
1974 | |
1975 | // Determine in which direction to show the popup. By default popup horizontally centered below the button. |
1976 | // But if the popup doesn't fit below and the button is in the bottom half of the viewport, show above. |
1977 | bool show_above = false; |
1978 | if (get_global_position().y + get_size().y + minsize.y > viewport_height && get_global_position().y * 2 + get_size().y > viewport_height) { |
1979 | show_above = true; |
1980 | } |
1981 | |
1982 | float h_offset = (get_size().x - minsize.x) / 2; |
1983 | float v_offset = show_above ? -minsize.y : get_size().y; |
1984 | popup->set_position(get_screen_position() + Vector2(h_offset, v_offset)); |
1985 | popup->popup(); |
1986 | picker->set_focus_on_line_edit(); |
1987 | } |
1988 | |
1989 | void ColorPickerButton::_notification(int p_what) { |
1990 | switch (p_what) { |
1991 | case NOTIFICATION_DRAW: { |
1992 | const Rect2 r = Rect2(theme_cache.normal_style->get_offset(), get_size() - theme_cache.normal_style->get_minimum_size()); |
1993 | draw_texture_rect(theme_cache.background_icon, r, true); |
1994 | draw_rect(r, color); |
1995 | |
1996 | if (color.r > 1 || color.g > 1 || color.b > 1) { |
1997 | // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview |
1998 | draw_texture(theme_cache.overbright_indicator, theme_cache.normal_style->get_offset()); |
1999 | } |
2000 | } break; |
2001 | |
2002 | case NOTIFICATION_WM_CLOSE_REQUEST: { |
2003 | if (popup) { |
2004 | popup->hide(); |
2005 | } |
2006 | } break; |
2007 | |
2008 | case NOTIFICATION_VISIBILITY_CHANGED: { |
2009 | if (popup && !is_visible_in_tree()) { |
2010 | popup->hide(); |
2011 | } |
2012 | } break; |
2013 | } |
2014 | } |
2015 | |
2016 | void ColorPickerButton::set_pick_color(const Color &p_color) { |
2017 | if (color == p_color) { |
2018 | return; |
2019 | } |
2020 | color = p_color; |
2021 | if (picker) { |
2022 | picker->set_pick_color(p_color); |
2023 | } |
2024 | |
2025 | queue_redraw(); |
2026 | } |
2027 | |
2028 | Color ColorPickerButton::get_pick_color() const { |
2029 | return color; |
2030 | } |
2031 | |
2032 | void ColorPickerButton::set_edit_alpha(bool p_show) { |
2033 | if (edit_alpha == p_show) { |
2034 | return; |
2035 | } |
2036 | edit_alpha = p_show; |
2037 | if (picker) { |
2038 | picker->set_edit_alpha(p_show); |
2039 | } |
2040 | } |
2041 | |
2042 | bool ColorPickerButton::is_editing_alpha() const { |
2043 | return edit_alpha; |
2044 | } |
2045 | |
2046 | ColorPicker *ColorPickerButton::get_picker() { |
2047 | _update_picker(); |
2048 | return picker; |
2049 | } |
2050 | |
2051 | PopupPanel *ColorPickerButton::() { |
2052 | _update_picker(); |
2053 | return popup; |
2054 | } |
2055 | |
2056 | void ColorPickerButton::_update_picker() { |
2057 | if (!picker) { |
2058 | popup = memnew(PopupPanel); |
2059 | popup->set_wrap_controls(true); |
2060 | picker = memnew(ColorPicker); |
2061 | picker->set_anchors_and_offsets_preset(PRESET_FULL_RECT); |
2062 | popup->add_child(picker); |
2063 | add_child(popup, false, INTERNAL_MODE_FRONT); |
2064 | picker->connect("color_changed" , callable_mp(this, &ColorPickerButton::_color_changed)); |
2065 | popup->connect("about_to_popup" , callable_mp(this, &ColorPickerButton::_about_to_popup)); |
2066 | popup->connect("popup_hide" , callable_mp(this, &ColorPickerButton::_modal_closed)); |
2067 | picker->connect("minimum_size_changed" , callable_mp((Window *)popup, &Window::reset_size)); |
2068 | picker->set_pick_color(color); |
2069 | picker->set_edit_alpha(edit_alpha); |
2070 | picker->set_display_old_color(true); |
2071 | emit_signal(SNAME("picker_created" )); |
2072 | } |
2073 | } |
2074 | |
2075 | void ColorPickerButton::_bind_methods() { |
2076 | ClassDB::bind_method(D_METHOD("set_pick_color" , "color" ), &ColorPickerButton::set_pick_color); |
2077 | ClassDB::bind_method(D_METHOD("get_pick_color" ), &ColorPickerButton::get_pick_color); |
2078 | ClassDB::bind_method(D_METHOD("get_picker" ), &ColorPickerButton::get_picker); |
2079 | ClassDB::bind_method(D_METHOD("get_popup" ), &ColorPickerButton::get_popup); |
2080 | ClassDB::bind_method(D_METHOD("set_edit_alpha" , "show" ), &ColorPickerButton::set_edit_alpha); |
2081 | ClassDB::bind_method(D_METHOD("is_editing_alpha" ), &ColorPickerButton::is_editing_alpha); |
2082 | ClassDB::bind_method(D_METHOD("_about_to_popup" ), &ColorPickerButton::_about_to_popup); |
2083 | |
2084 | ADD_SIGNAL(MethodInfo("color_changed" , PropertyInfo(Variant::COLOR, "color" ))); |
2085 | ADD_SIGNAL(MethodInfo("popup_closed" )); |
2086 | ADD_SIGNAL(MethodInfo("picker_created" )); |
2087 | ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color" ), "set_pick_color" , "get_pick_color" ); |
2088 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha" ), "set_edit_alpha" , "is_editing_alpha" ); |
2089 | |
2090 | BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ColorPickerButton, normal_style, "normal" ); |
2091 | BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ColorPickerButton, background_icon, "bg" ); |
2092 | BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, ColorPickerButton, overbright_indicator, "overbright_indicator" , "ColorPicker" ); |
2093 | } |
2094 | |
2095 | ColorPickerButton::ColorPickerButton(const String &p_text) : |
2096 | Button(p_text) { |
2097 | set_toggle_mode(true); |
2098 | } |
2099 | |
2100 | ///////////////// |
2101 | |
2102 | void ColorPresetButton::_notification(int p_what) { |
2103 | switch (p_what) { |
2104 | case NOTIFICATION_DRAW: { |
2105 | const Rect2 r = Rect2(Point2(0, 0), get_size()); |
2106 | Ref<StyleBox> sb_raw = theme_cache.foreground_style->duplicate(); |
2107 | Ref<StyleBoxFlat> sb_flat = sb_raw; |
2108 | Ref<StyleBoxTexture> sb_texture = sb_raw; |
2109 | |
2110 | if (sb_flat.is_valid()) { |
2111 | sb_flat->set_border_width(SIDE_BOTTOM, 2); |
2112 | if (get_draw_mode() == DRAW_PRESSED || get_draw_mode() == DRAW_HOVER_PRESSED) { |
2113 | sb_flat->set_border_color(Color(1, 1, 1, 1)); |
2114 | } else { |
2115 | sb_flat->set_border_color(Color(0, 0, 0, 1)); |
2116 | } |
2117 | |
2118 | if (preset_color.a < 1) { |
2119 | // Draw a background pattern when the color is transparent. |
2120 | sb_flat->set_bg_color(Color(1, 1, 1)); |
2121 | sb_flat->draw(get_canvas_item(), r); |
2122 | |
2123 | Rect2 bg_texture_rect = r.grow_side(SIDE_LEFT, -sb_flat->get_margin(SIDE_LEFT)); |
2124 | bg_texture_rect = bg_texture_rect.grow_side(SIDE_RIGHT, -sb_flat->get_margin(SIDE_RIGHT)); |
2125 | bg_texture_rect = bg_texture_rect.grow_side(SIDE_TOP, -sb_flat->get_margin(SIDE_TOP)); |
2126 | bg_texture_rect = bg_texture_rect.grow_side(SIDE_BOTTOM, -sb_flat->get_margin(SIDE_BOTTOM)); |
2127 | |
2128 | draw_texture_rect(theme_cache.background_icon, bg_texture_rect, true); |
2129 | sb_flat->set_bg_color(preset_color); |
2130 | } |
2131 | sb_flat->set_bg_color(preset_color); |
2132 | sb_flat->draw(get_canvas_item(), r); |
2133 | } else if (sb_texture.is_valid()) { |
2134 | if (preset_color.a < 1) { |
2135 | // Draw a background pattern when the color is transparent. |
2136 | bool use_tile_texture = (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE) || (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE_FIT); |
2137 | draw_texture_rect(theme_cache.background_icon, r, use_tile_texture); |
2138 | } |
2139 | sb_texture->set_modulate(preset_color); |
2140 | sb_texture->draw(get_canvas_item(), r); |
2141 | } else { |
2142 | WARN_PRINT("Unsupported StyleBox used for ColorPresetButton. Use StyleBoxFlat or StyleBoxTexture instead." ); |
2143 | } |
2144 | if (preset_color.r > 1 || preset_color.g > 1 || preset_color.b > 1) { |
2145 | // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview |
2146 | draw_texture(theme_cache.overbright_indicator, Vector2(0, 0)); |
2147 | } |
2148 | |
2149 | } break; |
2150 | } |
2151 | } |
2152 | |
2153 | void ColorPresetButton::set_preset_color(const Color &p_color) { |
2154 | preset_color = p_color; |
2155 | } |
2156 | |
2157 | Color ColorPresetButton::get_preset_color() const { |
2158 | return preset_color; |
2159 | } |
2160 | |
2161 | void ColorPresetButton::_bind_methods() { |
2162 | BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ColorPresetButton, foreground_style, "preset_fg" ); |
2163 | BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ColorPresetButton, background_icon, "preset_bg" ); |
2164 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPresetButton, overbright_indicator); |
2165 | } |
2166 | |
2167 | ColorPresetButton::ColorPresetButton(Color p_color, int p_size) { |
2168 | preset_color = p_color; |
2169 | set_toggle_mode(true); |
2170 | set_custom_minimum_size(Size2(p_size, p_size)); |
2171 | } |
2172 | |
2173 | ColorPresetButton::~ColorPresetButton() { |
2174 | } |
2175 | |