Skip to content

Commit 6744f78

Browse files
authored
More safe color picker rework progress (#1631)
1 parent 0a3981e commit 6744f78

File tree

10 files changed

+173
-193
lines changed

10 files changed

+173
-193
lines changed

src/ui_widgets/color_picker_layout_popup.gd

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ signal color_model_changed
66

77
@onready var shape_button: Button = %ShapeButton
88
@onready var section_label: Label = %SectionLabel
9-
@onready var color_models_container: HBoxContainer = %ColorModelsContainer
9+
@onready var color_model_buttons_array: Array[Button] = [%ColorModelsContainer/ColorModelButton1,
10+
%ColorModelsContainer/ColorModelButton2, %ColorModelsContainer/ColorModelButton3]
1011

1112
func _ready() -> void:
1213
shape_button.text = "VHS Circle"
1314
shape_button.pressed.connect(_on_shape_button_pressed)
14-
section_label.text = Translator.translate("Color models")
15+
section_label.text = Translator.translate("Color models") + ":"
1516
color_model_changed.connect(sync_color_models)
1617
sync_color_models()
18+
var focus_sequence: Array[Control] = [shape_button]
19+
focus_sequence.append_array(color_model_buttons_array)
20+
HandlerGUI.register_focus_sequence(self, focus_sequence, true)
1721

1822
func _on_shape_button_pressed() -> void:
1923
var btn_arr: Array[ContextButton] = []
@@ -25,25 +29,23 @@ func _on_shape_button_pressed() -> void:
2529
HandlerGUI.popup_under_rect(cp, shape_button.get_global_rect(), get_viewport())
2630

2731
func sync_color_models() -> void:
28-
for child in color_models_container.get_children():
29-
color_models_container.remove_child(child)
30-
child.queue_free()
31-
3232
for idx in 3:
33-
var btn := Button.new()
34-
btn.theme_type_variation = "TranslucentButton"
35-
btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
36-
color_models_container.add_child(btn)
37-
if idx < Configs.savedata.color_picker_active_models.size():
38-
btn.text = ColorPickerUtils.color_model_to_string(Configs.savedata.color_picker_active_models[idx])
39-
btn.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
40-
btn.pressed.connect(_on_occupied_color_space_button_pressed.bind(idx, btn))
41-
elif idx == Configs.savedata.color_picker_active_models.size():
42-
btn.text = "..."
43-
btn.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
44-
btn.pressed.connect(_on_free_color_space_button_pressed.bind(idx, btn))
45-
else:
33+
var btn := color_model_buttons_array[idx]
34+
if btn.pressed.is_connected(_on_occupied_color_space_button_pressed):
35+
btn.pressed.disconnect(_on_occupied_color_space_button_pressed)
36+
if btn.pressed.is_connected(_on_free_color_space_button_pressed):
37+
btn.pressed.disconnect(_on_free_color_space_button_pressed)
38+
39+
if idx > Configs.savedata.color_picker_active_models.size():
4640
btn.disabled = true
41+
else:
42+
btn.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
43+
if idx == Configs.savedata.color_picker_active_models.size():
44+
btn.text = "..."
45+
btn.pressed.connect(_on_free_color_space_button_pressed.bind(idx, btn))
46+
else:
47+
btn.text = ColorPickerUtils.color_model_to_string(Configs.savedata.color_picker_active_models[idx])
48+
btn.pressed.connect(_on_occupied_color_space_button_pressed.bind(idx, btn))
4749

4850
func _on_occupied_color_space_button_pressed(index: int, button: Button) -> void:
4951
var btn_arr: Array[ContextButton] = [
@@ -53,10 +55,9 @@ func _on_occupied_color_space_button_pressed(index: int, button: Button) -> void
5355
if index > 0:
5456
btn_arr.append(ContextButton.create_custom(Translator.translate("Move left"),
5557
move_color_model_index.bind(index, false), preload("res://assets/icons/MoveLeft.svg")))
56-
elif index < Configs.savedata.color_picker_active_models.size() - 1:
58+
if index < Configs.savedata.color_picker_active_models.size() - 1:
5759
btn_arr.append(ContextButton.create_custom(Translator.translate("Move right"),
5860
move_color_model_index.bind(index, true), preload("res://assets/icons/MoveRight.svg")))
59-
return
6061

6162
btn_arr.append(ContextButton.create_custom(Translator.translate("Delete"), delete_color_model.bind(index), preload("res://assets/icons/Delete.svg")))
6263
HandlerGUI.popup_under_rect_center(ContextPopup.create(btn_arr), button.get_global_rect(), get_viewport())
@@ -85,4 +86,5 @@ func move_color_model_index(index: int, move_right: bool) -> void:
8586
var model_to_move := Configs.savedata.color_picker_active_models[index]
8687
Configs.savedata.color_picker_active_models[index] = Configs.savedata.color_picker_active_models[new_index]
8788
Configs.savedata.color_picker_active_models[new_index] = model_to_move
89+
color_model_buttons_array[new_index].grab_focus(not get_viewport().gui_get_focus_owner().has_focus(true))
8890
color_model_changed.emit()

src/ui_widgets/color_picker_layout_popup.tscn

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ layout_mode = 2
2121
unique_name_in_owner = true
2222
layout_mode = 2
2323
mouse_default_cursor_shape = 2
24-
theme_type_variation = &"TranslucentButton"
24+
theme_type_variation = &"TranslucentButtonThin"
2525

2626
[node name="SectionLabel" type="Label" parent="MarginContainer/VBoxContainer" unique_id=197757298]
2727
unique_name_in_owner = true
@@ -32,3 +32,21 @@ horizontal_alignment = 1
3232
unique_name_in_owner = true
3333
custom_minimum_size = Vector2(150, 0)
3434
layout_mode = 2
35+
36+
[node name="ColorModelButton1" type="Button" parent="MarginContainer/VBoxContainer/ColorModelsContainer" unique_id=1591411056]
37+
layout_mode = 2
38+
size_flags_horizontal = 3
39+
mouse_default_cursor_shape = 2
40+
theme_type_variation = &"TranslucentButtonThin"
41+
42+
[node name="ColorModelButton2" type="Button" parent="MarginContainer/VBoxContainer/ColorModelsContainer" unique_id=611526861]
43+
layout_mode = 2
44+
size_flags_horizontal = 3
45+
mouse_default_cursor_shape = 2
46+
theme_type_variation = &"TranslucentButtonThin"
47+
48+
[node name="ColorModelButton3" type="Button" parent="MarginContainer/VBoxContainer/ColorModelsContainer" unique_id=1251329165]
49+
layout_mode = 2
50+
size_flags_horizontal = 3
51+
mouse_default_cursor_shape = 2
52+
theme_type_variation = &"TranslucentButtonThin"

src/ui_widgets/color_popup.gd

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@ func sync_theming() -> void:
4343
panel_sb.content_margin_top = 2
4444
panel_sb.content_margin_bottom = 2
4545
navigation_panel.add_theme_stylebox_override("panel", panel_sb)
46-
47-
var CONST_ARR: PackedStringArray = ["normal", "hover", "pressed"]
48-
for theme_item in CONST_ARR:
49-
var sb := switch_mode_button.get_theme_stylebox(theme_item).duplicate()
50-
sb.content_margin_top -= 2
51-
sb.content_margin_bottom -= 2
52-
sb.content_margin_left -= 2
53-
switch_mode_button.add_theme_stylebox_override(theme_item, sb)
5446

5547

5648
# Switching between palette mode and color picker mode.

src/ui_widgets/color_popup.tscn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ custom_minimum_size = Vector2(150, 0)
3131
layout_mode = 2
3232
size_flags_horizontal = 6
3333
mouse_default_cursor_shape = 2
34-
theme_type_variation = &"TranslucentButton"
34+
theme_type_variation = &"TranslucentButtonThin"

src/ui_widgets/good_color_picker.gd

Lines changed: 41 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -162,26 +162,26 @@ func _ready() -> void:
162162
reset_color_button.pressed.connect(_on_reset_color_button_pressed)
163163

164164
widgets_arr[0].draw.connect(_on_side_slider_draw)
165-
widgets_arr[1].draw.connect(_on_slider1_draw)
166-
widgets_arr[2].draw.connect(_on_slider2_draw)
167-
widgets_arr[3].draw.connect(_on_slider3_draw)
165+
widgets_arr[1].draw.connect(_on_hslider_draw.bind(1))
166+
widgets_arr[2].draw.connect(_on_hslider_draw.bind(2))
167+
widgets_arr[3].draw.connect(_on_hslider_draw.bind(3))
168168
widgets_arr[0].gui_input.connect(parse_slider_input.bind(0))
169169
widgets_arr[1].gui_input.connect(parse_slider_input.bind(1))
170170
widgets_arr[2].gui_input.connect(parse_slider_input.bind(2))
171171
widgets_arr[3].gui_input.connect(parse_slider_input.bind(3))
172-
tracks_arr[1].resized.connect(_on_track_resized)
173-
tracks_arr[2].resized.connect(_on_track_resized)
174-
tracks_arr[3].resized.connect(_on_track_resized)
175-
fields_arr[1].text_submitted.connect(_on_slider1_text_submitted)
176-
fields_arr[2].text_submitted.connect(_on_slider2_text_submitted)
177-
fields_arr[3].text_submitted.connect(_on_slider3_text_submitted)
172+
tracks_arr[1].resized.connect(queue_redraw_widgets)
173+
tracks_arr[2].resized.connect(queue_redraw_widgets)
174+
tracks_arr[3].resized.connect(queue_redraw_widgets)
175+
fields_arr[1].text_submitted.connect(_on_slider_text_submitted.bind(1))
176+
fields_arr[2].text_submitted.connect(_on_slider_text_submitted.bind(2))
177+
fields_arr[3].text_submitted.connect(_on_slider_text_submitted.bind(3))
178178
_on_color_model_changed()
179179
if alpha_enabled:
180180
alpha_slider.visible = alpha_enabled
181-
widgets_arr[4].draw.connect(_on_slider4_draw)
181+
widgets_arr[4].draw.connect(_on_hslider_draw.bind(4))
182182
widgets_arr[4].gui_input.connect(parse_slider_input.bind(4))
183-
tracks_arr[4].resized.connect(_on_track_resized)
184-
fields_arr[4].text_submitted.connect(_on_slider4_text_submitted)
183+
tracks_arr[4].resized.connect(queue_redraw_widgets)
184+
fields_arr[4].text_submitted.connect(_on_slider_text_submitted.bind(4))
185185

186186
update_keyword_button()
187187
color_models_button.pressed.connect(_on_color_models_button_pressed)
@@ -196,7 +196,10 @@ func _ready() -> void:
196196
focus_sequence.append(color_models_button)
197197
focus_sequence.append_array(fields_arr.slice(1))
198198
HandlerGUI.register_focus_sequence(self, focus_sequence)
199-
keyword_button.grab_focus(true)
199+
if keyword_button.visible:
200+
keyword_button.grab_focus(true)
201+
else:
202+
eyedropper_button.grab_focus(true)
200203

201204
func _exit_tree() -> void:
202205
RenderingServer.free_rid(color_wheel_surface)
@@ -274,10 +277,10 @@ func update() -> void:
274277
color_wheel_drawn.queue_redraw()
275278
queue_redraw_widgets()
276279
# Set the text of the color fields.
277-
slider1_update()
278-
slider2_update()
279-
slider3_update()
280-
slider4_update()
280+
slider_update(1)
281+
slider_update(2)
282+
slider_update(3)
283+
slider_update(4)
281284
# Ensure that the HSV values are never exactly 0 or 1 to make everything draggable.
282285
backup_display_color.h = clampf(backup_display_color.h, 0.0, 0.9999)
283286
backup_display_color.v = clampf(backup_display_color.v, 0.0001, 1.0)
@@ -379,73 +382,18 @@ func parse_slider_input(event: InputEvent, idx: int) -> void:
379382

380383
# When slider text is submitted, it should be clamped, used, and then the slider should
381384
# be updated again so the text reflects the new value even if the color didn't change.
382-
func _on_slider1_text_submitted(new_text: String) -> void:
383-
var new_value := NumstringParser.evaluate(new_text)
384-
if is_nan(new_value):
385-
slider1_update()
386-
return
387-
match Configs.savedata.color_picker_current_model:
388-
ColorPickerUtils.ColorModel.RGB: set_slider_offset(1, new_value / 255.0, true)
389-
ColorPickerUtils.ColorModel.HSV, ColorPickerUtils.ColorModel.HSL: set_slider_offset(1, new_value / 360.0, true)
390-
slider1_update()
391-
392-
func _on_slider2_text_submitted(new_text: String) -> void:
385+
func _on_slider_text_submitted(index: int, new_text: String) -> void:
393386
var new_value := NumstringParser.evaluate(new_text)
394387
if is_nan(new_value):
395-
slider2_update()
388+
slider_update(index)
396389
return
397-
match Configs.savedata.color_picker_current_model:
398-
ColorPickerUtils.ColorModel.RGB: set_slider_offset(2, new_value / 255.0, true)
399-
ColorPickerUtils.ColorModel.HSV, ColorPickerUtils.ColorModel.HSL: set_slider_offset(2, new_value / 100.0, true)
390+
set_slider_offset(index, new_value / ColorPickerUtils.get_channel_fidelity(index - 1), true)
400391
register_visual_change(display_color, false)
401-
slider2_update()
402-
403-
func _on_slider3_text_submitted(new_text: String) -> void:
404-
var new_value := NumstringParser.evaluate(new_text)
405-
if is_nan(new_value):
406-
slider3_update()
407-
return
408-
match Configs.savedata.color_picker_current_model:
409-
ColorPickerUtils.ColorModel.RGB: set_slider_offset(3, new_value / 255.0, true)
410-
ColorPickerUtils.ColorModel.HSV, ColorPickerUtils.ColorModel.HSL: set_slider_offset(3, new_value / 100.0, true)
411-
register_visual_change(display_color, false)
412-
slider3_update()
413-
414-
func _on_slider4_text_submitted(new_text: String) -> void:
415-
var new_value := NumstringParser.evaluate(new_text)
416-
if is_nan(new_value):
417-
slider4_update()
418-
return
419-
set_slider_offset(4, new_value / 255.0, true)
420-
register_visual_change(display_color, false)
421-
slider4_update()
422-
423-
func slider1_update() -> void:
424-
var number: float
425-
match Configs.savedata.color_picker_current_model:
426-
ColorPickerUtils.ColorModel.RGB: number = display_color.r * 255
427-
ColorPickerUtils.ColorModel.HSV, ColorPickerUtils.ColorModel.HSL: number = display_color.h * 360
428-
_slider_set_text(fields_arr[1], number)
429-
430-
func slider2_update() -> void:
431-
var number: float
432-
match Configs.savedata.color_picker_current_model:
433-
ColorPickerUtils.ColorModel.RGB: number = display_color.g * 255
434-
ColorPickerUtils.ColorModel.HSV, ColorPickerUtils.ColorModel.HSL: number = display_color.s * 100
435-
_slider_set_text(fields_arr[2], number)
436-
437-
func slider3_update() -> void:
438-
var number: float
439-
match Configs.savedata.color_picker_current_model:
440-
ColorPickerUtils.ColorModel.RGB: number = display_color.b * 255
441-
ColorPickerUtils.ColorModel.HSV, ColorPickerUtils.ColorModel.HSL: number = display_color.v * 100
442-
_slider_set_text(fields_arr[3], number)
392+
slider_update(index)
443393

444-
func slider4_update() -> void:
445-
_slider_set_text(fields_arr[4], display_color.a * 255)
446-
447-
func _slider_set_text(field: BetterLineEdit, number: float) -> void:
448-
field.text = String.num_uint64(roundi(number))
394+
func slider_update(index: int) -> void:
395+
fields_arr[index].text = String.num_uint64(roundi(
396+
ColorPickerUtils.get_channel_offset(display_color, index - 1) * ColorPickerUtils.get_channel_fidelity(index - 1)))
449397

450398

451399
func _on_keyword_button_pressed() -> void:
@@ -518,46 +466,23 @@ func _draw() -> void:
518466
var point_pos := center + Vector2(center.x * cos(display_color.h * TAU), center.y * sin(display_color.h * TAU)) * display_color.s
519467
RenderingServer.canvas_item_add_texture_rect(color_wheel_surface, Rect2(point_pos - handle_texture_size / 2, handle_texture_size), handle_texture)
520468

521-
# Helper for drawing the horizontal sliders.
522-
func draw_hslider(idx: int, offset: float, chr: String) -> void:
523-
var arrow_modulate := ThemeUtils.tinted_contrast_color
524-
if not sliders_dragged[idx]:
525-
arrow_modulate.a = 0.7
526-
widgets_arr[idx].draw_texture(slider_arrow, Vector2(tracks_arr[idx].position.x + tracks_arr[idx].size.x * offset - slider_arrow.get_width() / 2.0,
527-
tracks_arr[idx].size.y), arrow_modulate)
528-
widgets_arr[idx].draw_string(get_theme_default_font(), Vector2(-12, 11), chr, HORIZONTAL_ALIGNMENT_CENTER, 12, 14, ThemeUtils.text_color)
529-
530-
# Make sure the arrows are redrawn when the tracks finish resizing.
531-
func _on_track_resized() -> void:
532-
if not widgets_arr.is_empty():
533-
queue_redraw_widgets()
534469

535470
func queue_redraw_widgets() -> void:
536-
widgets_arr[0].queue_redraw()
537-
widgets_arr[1].queue_redraw()
538-
widgets_arr[2].queue_redraw()
539-
widgets_arr[3].queue_redraw()
540-
if alpha_enabled:
541-
widgets_arr[4].queue_redraw()
542-
543-
func _on_slider1_draw() -> void:
544-
match Configs.savedata.color_picker_current_model:
545-
ColorPickerUtils.ColorModel.RGB: draw_hslider(1, display_color.r, "R")
546-
ColorPickerUtils.ColorModel.HSV, ColorPickerUtils.ColorModel.HSL: draw_hslider(1, display_color.h, "H")
547-
548-
func _on_slider2_draw() -> void:
549-
match Configs.savedata.color_picker_current_model:
550-
ColorPickerUtils.ColorModel.RGB: draw_hslider(2, display_color.g, "G")
551-
ColorPickerUtils.ColorModel.HSV, ColorPickerUtils.ColorModel.HSL: draw_hslider(2, display_color.s, "S")
471+
for i in 5:
472+
var widget := widgets_arr[i]
473+
if is_instance_valid(widget):
474+
widget.queue_redraw()
552475

553-
func _on_slider3_draw() -> void:
554-
match Configs.savedata.color_picker_current_model:
555-
ColorPickerUtils.ColorModel.RGB: draw_hslider(3, display_color.b, "B")
556-
ColorPickerUtils.ColorModel.HSV: draw_hslider(3, display_color.v, "V")
557-
ColorPickerUtils.ColorModel.HSL: draw_hslider(3, display_color.v, "L")
558-
559-
func _on_slider4_draw() -> void:
560-
draw_hslider(4, display_color.a, "A")
476+
# Helper for drawing the horizontal sliders.
477+
func _on_hslider_draw(channel_index: int) -> void:
478+
var arrow_modulate := ThemeUtils.tinted_contrast_color
479+
if not sliders_dragged[channel_index]:
480+
arrow_modulate.a *= 0.7
481+
widgets_arr[channel_index].draw_texture(slider_arrow, Vector2(tracks_arr[channel_index].position.x + tracks_arr[channel_index].size.x *\
482+
ColorPickerUtils.get_channel_offset(display_color, channel_index - 1) -\
483+
slider_arrow.get_width() / 2.0, tracks_arr[channel_index].size.y), arrow_modulate)
484+
widgets_arr[channel_index].draw_string(get_theme_default_font(), Vector2(-12, 11),
485+
ColorPickerUtils.get_channel_letter(channel_index - 1), HORIZONTAL_ALIGNMENT_CENTER, 12, 14, ThemeUtils.text_color)
561486

562487

563488
func update_color_button() -> void:

src/ui_widgets/presented_shortcut.gd

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,7 @@ func sync() -> void:
2626
var new_btn := Button.new()
2727
new_btn.custom_minimum_size = Vector2(160, 24)
2828
new_btn.size_flags_horizontal = Control.SIZE_FILL
29-
new_btn.theme_type_variation = "TranslucentButton"
30-
var shortcut_stylebox := get_theme_stylebox("disabled", "TranslucentButton").duplicate()
31-
shortcut_stylebox.content_margin_top = 0.0
32-
shortcut_stylebox.content_margin_bottom = 0.0
33-
new_btn.add_theme_stylebox_override("disabled", shortcut_stylebox)
34-
29+
new_btn.theme_type_variation = "TranslucentButtonThin"
3530
new_btn.focus_mode = Control.FOCUS_NONE
3631
new_btn.disabled = true
3732
new_btn.text = events[i].as_text_keycode()

src/ui_widgets/profile_frame.gd

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ func setup_dropdown(values: Array, value_text_map: Dictionary) -> void:
2828
dropdown.value_text_map = value_text_map
2929

3030
func _ready() -> void:
31-
Configs.theme_changed.connect(sync_theming)
32-
sync_theming()
3331
button.text = Translator.translate("Apply")
3432
button.tooltip_text = Translator.translate("Apply all of this preset's defaults")
3533
control.add_child(dropdown)
@@ -43,14 +41,6 @@ func _ready() -> void:
4341
control.resized.connect(setup_size.call_deferred)
4442
setup_size.call_deferred()
4543

46-
func sync_theming() -> void:
47-
const CONST_ARR: PackedStringArray = ["normal", "hover", "pressed", "disabled"]
48-
for theme_style in CONST_ARR:
49-
var theme_sb := get_theme_stylebox(theme_style, "TranslucentButton").duplicate()
50-
theme_sb.content_margin_top -= 1
51-
theme_sb.content_margin_bottom -= 1
52-
button.add_theme_stylebox_override(theme_style, theme_sb)
53-
5444
func button_update_disabled() -> void:
5545
var should_disable: bool = disabled_check_callback.call()
5646
button.disabled = should_disable

0 commit comments

Comments
 (0)