fix: harden controller UI interactions
This commit is contained in:
parent
c260472d8a
commit
275de4dfa1
6 changed files with 214 additions and 23 deletions
|
|
@ -399,6 +399,35 @@ func _run() -> void:
|
||||||
assert(hide_button.button_group.allow_unpress)
|
assert(hide_button.button_group.allow_unpress)
|
||||||
assert(brush_option.item_count == 4)
|
assert(brush_option.item_count == 4)
|
||||||
assert(grid_option.item_count == 4)
|
assert(grid_option.item_count == 4)
|
||||||
|
for pointer_only_control: Control in [
|
||||||
|
brush_option,
|
||||||
|
grid_option,
|
||||||
|
mode_button,
|
||||||
|
eraser_button,
|
||||||
|
undo_button,
|
||||||
|
hide_button,
|
||||||
|
restore_button,
|
||||||
|
finalize_button,
|
||||||
|
]:
|
||||||
|
assert(pointer_only_control.focus_mode == Control.FOCUS_NONE)
|
||||||
|
assert(brush_option.get_popup().unfocusable)
|
||||||
|
assert(grid_option.get_popup().unfocusable)
|
||||||
|
brush_option.get_popup().popup(Rect2i(100, 100, 220, 220))
|
||||||
|
await process_frame
|
||||||
|
game_ui.call("_begin_virtual_mouse", 0)
|
||||||
|
game_ui.call("_update_virtual_cursor_position", Vector2(160.0, 160.0))
|
||||||
|
var brush_popup_cursor := toolbar.get(
|
||||||
|
"_brush_popup_cursor"
|
||||||
|
) as ControllerVirtualCursor
|
||||||
|
assert(brush_popup_cursor != null and brush_popup_cursor.visible)
|
||||||
|
assert(brush_popup_cursor.get_parent() == brush_option.get_popup())
|
||||||
|
assert(brush_popup_cursor.z_index == RenderingServer.CANVAS_ITEM_Z_MAX)
|
||||||
|
assert(not virtual_cursor.visible)
|
||||||
|
brush_option.get_popup().hide()
|
||||||
|
game_ui.call("_update_virtual_cursor_position", Vector2(160.0, 160.0))
|
||||||
|
assert(not brush_popup_cursor.visible)
|
||||||
|
assert(virtual_cursor.visible)
|
||||||
|
game_ui.call("_end_virtual_mouse")
|
||||||
var expected_brush_icons: Array[String] = [
|
var expected_brush_icons: Array[String] = [
|
||||||
"art_kit_marker_tip_fine.png",
|
"art_kit_marker_tip_fine.png",
|
||||||
"art_kit_marker_tip_thin.png",
|
"art_kit_marker_tip_thin.png",
|
||||||
|
|
@ -417,7 +446,9 @@ func _run() -> void:
|
||||||
assert(brush_option.get_item_icon(index) != null)
|
assert(brush_option.get_item_icon(index) != null)
|
||||||
assert(grid_option.get_item_icon(index) != null)
|
assert(grid_option.get_item_icon(index) != null)
|
||||||
assert(
|
assert(
|
||||||
brush_option.get_item_icon(index).resource_path.ends_with(
|
str(brush_option.get_item_icon(index).get_meta(
|
||||||
|
&"channel_mask_source", ""
|
||||||
|
)).ends_with(
|
||||||
expected_brush_icons[index]
|
expected_brush_icons[index]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -432,6 +463,8 @@ func _run() -> void:
|
||||||
assert(grid_option.get_popup().is_item_disabled(1))
|
assert(grid_option.get_popup().is_item_disabled(1))
|
||||||
var color_buttons: Dictionary = toolbar.get("_color_buttons")
|
var color_buttons: Dictionary = toolbar.get("_color_buttons")
|
||||||
assert(color_buttons.size() == SurfaceDrawingPalette.COLORS.size())
|
assert(color_buttons.size() == SurfaceDrawingPalette.COLORS.size())
|
||||||
|
for color_button: Button in color_buttons.values():
|
||||||
|
assert(color_button.focus_mode == Control.FOCUS_NONE)
|
||||||
assert(not (color_buttons[&"chalk_white"] as Button).disabled)
|
assert(not (color_buttons[&"chalk_white"] as Button).disabled)
|
||||||
assert((color_buttons[&"ocean_teal"] as Button).disabled)
|
assert((color_buttons[&"ocean_teal"] as Button).disabled)
|
||||||
|
|
||||||
|
|
@ -451,6 +484,8 @@ func _run() -> void:
|
||||||
assert(service.get_grid_size() == 128)
|
assert(service.get_grid_size() == 128)
|
||||||
var marker_mode_material := mode_button.material as ShaderMaterial
|
var marker_mode_material := mode_button.material as ShaderMaterial
|
||||||
assert(marker_mode_material != null)
|
assert(marker_mode_material != null)
|
||||||
|
assert(brush_option.material == null)
|
||||||
|
assert(grid_option.material == null)
|
||||||
assert(
|
assert(
|
||||||
marker_mode_material.shader.resource_path.ends_with(
|
marker_mode_material.shader.resource_path.ends_with(
|
||||||
"/ui/art_kit_marker_icon.gdshader"
|
"/ui/art_kit_marker_icon.gdshader"
|
||||||
|
|
|
||||||
|
|
@ -296,6 +296,9 @@ func _validate_page() -> void:
|
||||||
(page.get("_portrait_overlay_backdrop") as Button).pressed.emit()
|
(page.get("_portrait_overlay_backdrop") as Button).pressed.emit()
|
||||||
await process_frame
|
await process_frame
|
||||||
assert(not portrait_overlay.visible)
|
assert(not portrait_overlay.visible)
|
||||||
|
detail_buttons = page.get("_detail_buttons") as Array
|
||||||
|
assert(detail_buttons.size() == 4)
|
||||||
|
facts_detail = detail_buttons[1] as Button
|
||||||
facts_detail.pressed.emit()
|
facts_detail.pressed.emit()
|
||||||
await process_frame
|
await process_frame
|
||||||
var overlay_text := page.get("_portrait_overlay_text") as Label
|
var overlay_text := page.get("_portrait_overlay_text") as Label
|
||||||
|
|
|
||||||
|
|
@ -264,8 +264,11 @@ func set_controller_text_entry_request(
|
||||||
|
|
||||||
|
|
||||||
func request_controller_text_entry_for(control: Control = null) -> bool:
|
func request_controller_text_entry_for(control: Control = null) -> bool:
|
||||||
|
var target: Control = control
|
||||||
|
if target == null:
|
||||||
|
target = get_viewport().gui_get_focus_owner()
|
||||||
return (
|
return (
|
||||||
bool(_controller_text_entry_request.call(control))
|
bool(_controller_text_entry_request.call(target))
|
||||||
if _controller_text_entry_request.is_valid()
|
if _controller_text_entry_request.is_valid()
|
||||||
else false
|
else false
|
||||||
)
|
)
|
||||||
|
|
@ -844,9 +847,8 @@ func _begin_virtual_mouse(device_id: int) -> void:
|
||||||
_virtual_mouse_window_position = _clamp_virtual_mouse_window_position(
|
_virtual_mouse_window_position = _clamp_virtual_mouse_window_position(
|
||||||
Vector2(get_window().size) * 0.5
|
Vector2(get_window().size) * 0.5
|
||||||
)
|
)
|
||||||
_controller_virtual_cursor.visible = true
|
|
||||||
_update_virtual_cursor_position(_virtual_mouse_window_position)
|
|
||||||
_emit_virtual_mouse_motion(Vector2.ZERO)
|
_emit_virtual_mouse_motion(Vector2.ZERO)
|
||||||
|
_update_virtual_cursor_position(_virtual_mouse_window_position)
|
||||||
|
|
||||||
|
|
||||||
func _end_virtual_mouse() -> void:
|
func _end_virtual_mouse() -> void:
|
||||||
|
|
@ -860,6 +862,7 @@ func _end_virtual_mouse() -> void:
|
||||||
_virtual_mouse_trigger_strength = 0.0
|
_virtual_mouse_trigger_strength = 0.0
|
||||||
_virtual_mouse_stick = Vector2.ZERO
|
_virtual_mouse_stick = Vector2.ZERO
|
||||||
_controller_virtual_cursor.visible = false
|
_controller_virtual_cursor.visible = false
|
||||||
|
_surface_drawing_toolbar.hide_virtual_pointer_overlay()
|
||||||
if _fishing_spot != null:
|
if _fishing_spot != null:
|
||||||
_fishing_spot.set_local_menu_input_suppressed(
|
_fishing_spot.set_local_menu_input_suppressed(
|
||||||
VIRTUAL_MOUSE_INPUT_OWNER,
|
VIRTUAL_MOUSE_INPUT_OWNER,
|
||||||
|
|
@ -884,6 +887,7 @@ func _update_virtual_mouse(delta: float) -> void:
|
||||||
var stick: Vector2 = _virtual_mouse_stick
|
var stick: Vector2 = _virtual_mouse_stick
|
||||||
var stick_length: float = stick.length()
|
var stick_length: float = stick.length()
|
||||||
if stick_length <= VIRTUAL_MOUSE_STICK_DEADZONE:
|
if stick_length <= VIRTUAL_MOUSE_STICK_DEADZONE:
|
||||||
|
_update_virtual_cursor_position(_virtual_mouse_window_position)
|
||||||
return
|
return
|
||||||
var adjusted_strength: float = (
|
var adjusted_strength: float = (
|
||||||
(stick_length - VIRTUAL_MOUSE_STICK_DEADZONE)
|
(stick_length - VIRTUAL_MOUSE_STICK_DEADZONE)
|
||||||
|
|
@ -902,8 +906,8 @@ func _update_virtual_mouse(delta: float) -> void:
|
||||||
_virtual_mouse_window_position = _clamp_virtual_mouse_window_position(
|
_virtual_mouse_window_position = _clamp_virtual_mouse_window_position(
|
||||||
_virtual_mouse_window_position + relative_motion
|
_virtual_mouse_window_position + relative_motion
|
||||||
)
|
)
|
||||||
_update_virtual_cursor_position(_virtual_mouse_window_position)
|
|
||||||
_emit_virtual_mouse_motion(relative_motion)
|
_emit_virtual_mouse_motion(relative_motion)
|
||||||
|
_update_virtual_cursor_position(_virtual_mouse_window_position)
|
||||||
|
|
||||||
|
|
||||||
func _poll_virtual_mouse_controller_state() -> void:
|
func _poll_virtual_mouse_controller_state() -> void:
|
||||||
|
|
@ -1082,6 +1086,7 @@ func _set_virtual_mouse_button(button: MouseButton, pressed: bool) -> void:
|
||||||
mouse_event.pressed = pressed
|
mouse_event.pressed = pressed
|
||||||
mouse_event.factor = 1.0
|
mouse_event.factor = 1.0
|
||||||
_parse_virtual_mouse_event(mouse_event)
|
_parse_virtual_mouse_event(mouse_event)
|
||||||
|
_update_virtual_cursor_position(_virtual_mouse_window_position)
|
||||||
|
|
||||||
|
|
||||||
func _emit_virtual_mouse_motion(relative_motion: Vector2) -> void:
|
func _emit_virtual_mouse_motion(relative_motion: Vector2) -> void:
|
||||||
|
|
@ -1098,6 +1103,12 @@ func _parse_virtual_mouse_event(event: InputEventMouse) -> void:
|
||||||
|
|
||||||
|
|
||||||
func _update_virtual_cursor_position(viewport_position: Vector2) -> void:
|
func _update_virtual_cursor_position(viewport_position: Vector2) -> void:
|
||||||
|
if _surface_drawing_toolbar.update_virtual_pointer_overlay(
|
||||||
|
_virtual_mouse_active
|
||||||
|
):
|
||||||
|
_controller_virtual_cursor.visible = false
|
||||||
|
return
|
||||||
|
_controller_virtual_cursor.visible = _virtual_mouse_active
|
||||||
var output_scale: float = UIReferencePresentationType.get_scale(
|
var output_scale: float = UIReferencePresentationType.get_scale(
|
||||||
Vector2(get_window().size)
|
Vector2(get_window().size)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -484,7 +484,7 @@ script = ExtResource("9_chat")
|
||||||
|
|
||||||
[node name="ControllerVirtualCursor" type="Control" parent="UIRoot"]
|
[node name="ControllerVirtualCursor" type="Control" parent="UIRoot"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
z_index = 500
|
z_index = 4096
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
script = ExtResource("13_cursor")
|
script = ExtResource("13_cursor")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,7 @@ func _ready() -> void:
|
||||||
_back_button.pressed.connect(_on_back_pressed)
|
_back_button.pressed.connect(_on_back_pressed)
|
||||||
_address.text_submitted.connect(func(_value: String) -> void:
|
_address.text_submitted.connect(func(_value: String) -> void:
|
||||||
if _name_entry_active:
|
if _name_entry_active:
|
||||||
_name_edit.grab_focus()
|
_focus_control(_name_edit, true)
|
||||||
_name_edit.select_all()
|
|
||||||
else:
|
else:
|
||||||
_request_join()
|
_request_join()
|
||||||
)
|
)
|
||||||
|
|
@ -190,10 +189,7 @@ func open_page(preserved_endpoint: String = "") -> void:
|
||||||
UtilityPageStyle.animate_in(self)
|
UtilityPageStyle.animate_in(self)
|
||||||
_set_mode(_mode, false)
|
_set_mode(_mode, false)
|
||||||
if _mode == Mode.DIRECT:
|
if _mode == Mode.DIRECT:
|
||||||
_address.grab_focus()
|
|
||||||
_address.select_all()
|
_address.select_all()
|
||||||
else:
|
|
||||||
_server_list.grab_focus()
|
|
||||||
|
|
||||||
|
|
||||||
func close_page() -> void:
|
func close_page() -> void:
|
||||||
|
|
@ -261,10 +257,7 @@ func _set_mode(mode: Mode, clear_connection_error: bool = true) -> void:
|
||||||
_discovery_refresh_timer.stop()
|
_discovery_refresh_timer.stop()
|
||||||
if not is_visible_in_tree():
|
if not is_visible_in_tree():
|
||||||
return
|
return
|
||||||
if mode == Mode.DIRECT:
|
_defer_focus_control(_address if mode == Mode.DIRECT else _server_list)
|
||||||
_address.grab_focus()
|
|
||||||
else:
|
|
||||||
_server_list.grab_focus()
|
|
||||||
|
|
||||||
|
|
||||||
func _request_join() -> void:
|
func _request_join() -> void:
|
||||||
|
|
@ -365,9 +358,8 @@ func _on_save_pressed() -> void:
|
||||||
_name_entry_active = true
|
_name_entry_active = true
|
||||||
_name_edit.show()
|
_name_edit.show()
|
||||||
_save_button.text = "save"
|
_save_button.text = "save"
|
||||||
_name_edit.grab_focus()
|
|
||||||
_name_edit.select_all()
|
|
||||||
_refresh()
|
_refresh()
|
||||||
|
_defer_focus_control(_name_edit, true)
|
||||||
|
|
||||||
|
|
||||||
func _commit_name_entry() -> void:
|
func _commit_name_entry() -> void:
|
||||||
|
|
@ -408,9 +400,8 @@ func _on_edit_pressed() -> void:
|
||||||
_name_entry_active = true
|
_name_entry_active = true
|
||||||
_name_edit.show()
|
_name_edit.show()
|
||||||
_save_button.text = "save"
|
_save_button.text = "save"
|
||||||
_name_edit.grab_focus()
|
|
||||||
_name_edit.select_all()
|
|
||||||
_refresh()
|
_refresh()
|
||||||
|
_defer_focus_control(_name_edit, true)
|
||||||
|
|
||||||
|
|
||||||
func _on_favorite_pressed() -> void:
|
func _on_favorite_pressed() -> void:
|
||||||
|
|
@ -469,7 +460,7 @@ func _confirm_delete() -> void:
|
||||||
func _cancel_delete() -> void:
|
func _cancel_delete() -> void:
|
||||||
_delete_armed = false
|
_delete_armed = false
|
||||||
_delete_confirmation.hide_page()
|
_delete_confirmation.hide_page()
|
||||||
_delete_button.grab_focus()
|
_defer_focus_control(_delete_button)
|
||||||
|
|
||||||
|
|
||||||
func _on_list_item_selected(index: int) -> void:
|
func _on_list_item_selected(index: int) -> void:
|
||||||
|
|
@ -762,6 +753,30 @@ func _controller_focus_eligible(control: Control) -> bool:
|
||||||
return line_edit == null or line_edit.editable
|
return line_edit == null or line_edit.editable
|
||||||
|
|
||||||
|
|
||||||
|
func _focus_control(control: Control, select_all: bool = false) -> void:
|
||||||
|
if (
|
||||||
|
control == null
|
||||||
|
or not is_instance_valid(control)
|
||||||
|
or not control.is_inside_tree()
|
||||||
|
or not control.is_visible_in_tree()
|
||||||
|
or control.focus_mode not in [Control.FOCUS_CLICK, Control.FOCUS_ALL]
|
||||||
|
):
|
||||||
|
return
|
||||||
|
var button := control as BaseButton
|
||||||
|
if button != null and button.disabled:
|
||||||
|
return
|
||||||
|
var line_edit := control as LineEdit
|
||||||
|
if line_edit != null and not line_edit.editable:
|
||||||
|
return
|
||||||
|
control.grab_focus()
|
||||||
|
if select_all and line_edit != null:
|
||||||
|
line_edit.select_all()
|
||||||
|
|
||||||
|
|
||||||
|
func _defer_focus_control(control: Control, select_all: bool = false) -> void:
|
||||||
|
_focus_control.call_deferred(control, select_all)
|
||||||
|
|
||||||
|
|
||||||
func _set_controller_neighbors(
|
func _set_controller_neighbors(
|
||||||
control: Control,
|
control: Control,
|
||||||
left: Control,
|
left: Control,
|
||||||
|
|
@ -787,7 +802,7 @@ func _recover_controller_focus(
|
||||||
if owner != null and _delete_confirmation.is_ancestor_of(owner):
|
if owner != null and _delete_confirmation.is_ancestor_of(owner):
|
||||||
return
|
return
|
||||||
if fallback != null:
|
if fallback != null:
|
||||||
fallback.call_deferred("grab_focus")
|
_defer_focus_control(fallback)
|
||||||
|
|
||||||
|
|
||||||
func _format_entry_details(entry: SavedServerEntry) -> String:
|
func _format_entry_details(entry: SavedServerEntry) -> String:
|
||||||
|
|
@ -978,7 +993,7 @@ func _on_back_pressed() -> void:
|
||||||
_clear_edit_state()
|
_clear_edit_state()
|
||||||
_refresh()
|
_refresh()
|
||||||
var content: Control = _address if _mode == Mode.DIRECT else _server_list
|
var content: Control = _address if _mode == Mode.DIRECT else _server_list
|
||||||
content.call_deferred("grab_focus")
|
_defer_focus_control(content)
|
||||||
return
|
return
|
||||||
if (
|
if (
|
||||||
_network_session != null
|
_network_session != null
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ class_name SurfaceDrawingToolbar
|
||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
const UtilityPageStyleType = preload("res://ui/utility_page_style.gd")
|
const UtilityPageStyleType = preload("res://ui/utility_page_style.gd")
|
||||||
|
const ControllerVirtualCursorType = preload(
|
||||||
|
"res://ui/controller_virtual_cursor.gd"
|
||||||
|
)
|
||||||
const MARKER_MODE_ICON: Texture2D = preload(
|
const MARKER_MODE_ICON: Texture2D = preload(
|
||||||
"res://items/icons/art/art_kit_marker.png"
|
"res://items/icons/art/art_kit_marker.png"
|
||||||
)
|
)
|
||||||
|
|
@ -44,6 +47,9 @@ var _unlocks: PlayerArtUnlocks
|
||||||
var _color_buttons: Dictionary[StringName, Button] = {}
|
var _color_buttons: Dictionary[StringName, Button] = {}
|
||||||
var _dock_right: bool = true
|
var _dock_right: bool = true
|
||||||
var _marker_mode_material: ShaderMaterial
|
var _marker_mode_material: ShaderMaterial
|
||||||
|
var _brush_popup_cursor: ControllerVirtualCursorType
|
||||||
|
var _grid_popup_cursor: ControllerVirtualCursorType
|
||||||
|
var _applied_marker_icon_color: Color = Color(-1.0, -1.0, -1.0, -1.0)
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
@ -89,7 +95,13 @@ func _ready() -> void:
|
||||||
)
|
)
|
||||||
_brush_option.item_selected.connect(_select_brush)
|
_brush_option.item_selected.connect(_select_brush)
|
||||||
_grid_option.item_selected.connect(_select_grid)
|
_grid_option.item_selected.connect(_select_grid)
|
||||||
|
_configure_pointer_only_controls()
|
||||||
|
_brush_popup_cursor = _add_popup_cursor(_brush_option.get_popup())
|
||||||
|
_grid_popup_cursor = _add_popup_cursor(_grid_option.get_popup())
|
||||||
_build_options()
|
_build_options()
|
||||||
|
_apply_marker_color_to_brush_icons(
|
||||||
|
SurfaceDrawingPalette.get_color(SurfaceDrawingPalette.DEFAULT_COLOR_ID)
|
||||||
|
)
|
||||||
_apply_dock_side()
|
_apply_dock_side()
|
||||||
hide()
|
hide()
|
||||||
|
|
||||||
|
|
@ -203,6 +215,64 @@ func owns_pointer_event(event: InputEvent) -> bool:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func update_virtual_pointer_overlay(is_pointer_visible: bool) -> bool:
|
||||||
|
var active_popup: PopupMenu
|
||||||
|
var active_cursor: ControllerVirtualCursorType
|
||||||
|
if _brush_option.get_popup().visible:
|
||||||
|
active_popup = _brush_option.get_popup()
|
||||||
|
active_cursor = _brush_popup_cursor
|
||||||
|
elif _grid_option.get_popup().visible:
|
||||||
|
active_popup = _grid_option.get_popup()
|
||||||
|
active_cursor = _grid_popup_cursor
|
||||||
|
for popup_cursor: ControllerVirtualCursorType in [
|
||||||
|
_brush_popup_cursor, _grid_popup_cursor,
|
||||||
|
]:
|
||||||
|
if popup_cursor != null:
|
||||||
|
popup_cursor.visible = (
|
||||||
|
is_pointer_visible and popup_cursor == active_cursor
|
||||||
|
)
|
||||||
|
if not is_pointer_visible or active_popup == null or active_cursor == null:
|
||||||
|
return false
|
||||||
|
active_cursor.set_pointer_position(active_popup.get_mouse_position())
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
func hide_virtual_pointer_overlay() -> void:
|
||||||
|
update_virtual_pointer_overlay(false)
|
||||||
|
|
||||||
|
|
||||||
|
func _configure_pointer_only_controls() -> void:
|
||||||
|
for control: Control in [
|
||||||
|
_mode_button,
|
||||||
|
_brush_option,
|
||||||
|
_grid_option,
|
||||||
|
_eraser_button,
|
||||||
|
_undo_button,
|
||||||
|
_hide_guide_button,
|
||||||
|
_restore_guide_button,
|
||||||
|
_finalize_guide_button,
|
||||||
|
]:
|
||||||
|
control.focus_mode = Control.FOCUS_NONE
|
||||||
|
control.focus_neighbor_left = NodePath()
|
||||||
|
control.focus_neighbor_top = NodePath()
|
||||||
|
control.focus_neighbor_right = NodePath()
|
||||||
|
control.focus_neighbor_bottom = NodePath()
|
||||||
|
control.focus_next = NodePath()
|
||||||
|
control.focus_previous = NodePath()
|
||||||
|
for popup: PopupMenu in [
|
||||||
|
_brush_option.get_popup(), _grid_option.get_popup(),
|
||||||
|
]:
|
||||||
|
popup.unfocusable = true
|
||||||
|
|
||||||
|
|
||||||
|
func _add_popup_cursor(popup: PopupMenu) -> ControllerVirtualCursorType:
|
||||||
|
var cursor := ControllerVirtualCursorType.new()
|
||||||
|
cursor.z_index = RenderingServer.CANVAS_ITEM_Z_MAX
|
||||||
|
cursor.z_as_relative = false
|
||||||
|
popup.add_child(cursor)
|
||||||
|
return cursor
|
||||||
|
|
||||||
|
|
||||||
func _build_options() -> void:
|
func _build_options() -> void:
|
||||||
_brush_option.clear()
|
_brush_option.clear()
|
||||||
for brush_size: int in PlayerArtUnlocks.BRUSH_SIZES:
|
for brush_size: int in PlayerArtUnlocks.BRUSH_SIZES:
|
||||||
|
|
@ -232,7 +302,7 @@ func _build_options() -> void:
|
||||||
for color_id: StringName in SurfaceDrawingPalette.get_color_ids():
|
for color_id: StringName in SurfaceDrawingPalette.get_color_ids():
|
||||||
var button := Button.new()
|
var button := Button.new()
|
||||||
button.custom_minimum_size = Vector2(34, 34)
|
button.custom_minimum_size = Vector2(34, 34)
|
||||||
button.focus_mode = Control.FOCUS_ALL
|
button.focus_mode = Control.FOCUS_NONE
|
||||||
button.tooltip_text = SurfaceDrawingPalette.get_display_name(color_id)
|
button.tooltip_text = SurfaceDrawingPalette.get_display_name(color_id)
|
||||||
button.pressed.connect(_select_color.bind(color_id))
|
button.pressed.connect(_select_color.bind(color_id))
|
||||||
_color_list.add_child(button)
|
_color_list.add_child(button)
|
||||||
|
|
@ -240,6 +310,61 @@ func _build_options() -> void:
|
||||||
_apply_color_button_style(button, color_id, false)
|
_apply_color_button_style(button, color_id, false)
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_marker_color_to_brush_icons(marker_color: Color) -> void:
|
||||||
|
if _applied_marker_icon_color.is_equal_approx(marker_color):
|
||||||
|
return
|
||||||
|
_applied_marker_icon_color = marker_color
|
||||||
|
for index: int in range(_brush_option.item_count):
|
||||||
|
var brush_size: int = _brush_option.get_item_id(index)
|
||||||
|
_brush_option.set_item_icon(
|
||||||
|
index,
|
||||||
|
_channel_masked_icon(BRUSH_SIZE_ICONS[brush_size], marker_color),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _channel_masked_icon(source: Texture2D, marker_color: Color) -> Texture2D:
|
||||||
|
var source_image: Image = source.get_image()
|
||||||
|
if source_image == null or source_image.is_empty():
|
||||||
|
return source
|
||||||
|
var image := source_image.duplicate() as Image
|
||||||
|
if image.is_compressed():
|
||||||
|
if image.decompress() != OK:
|
||||||
|
return source
|
||||||
|
image.convert(Image.FORMAT_RGBA8)
|
||||||
|
for y: int in image.get_height():
|
||||||
|
for x: int in image.get_width():
|
||||||
|
var source_color: Color = image.get_pixel(x, y)
|
||||||
|
var red_dominance: float = (
|
||||||
|
source_color.r - maxf(source_color.g, source_color.b)
|
||||||
|
)
|
||||||
|
var marker_mask: float = smoothstep(0.04, 0.18, red_dominance)
|
||||||
|
image.set_pixel(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
Color(
|
||||||
|
lerpf(
|
||||||
|
source_color.r,
|
||||||
|
marker_color.r * source_color.r,
|
||||||
|
marker_mask,
|
||||||
|
),
|
||||||
|
lerpf(
|
||||||
|
source_color.g,
|
||||||
|
marker_color.g * source_color.r,
|
||||||
|
marker_mask,
|
||||||
|
),
|
||||||
|
lerpf(
|
||||||
|
source_color.b,
|
||||||
|
marker_color.b * source_color.r,
|
||||||
|
marker_mask,
|
||||||
|
),
|
||||||
|
source_color.a * marker_color.a,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
var texture := ImageTexture.create_from_image(image)
|
||||||
|
texture.set_meta(&"channel_mask_source", source.resource_path)
|
||||||
|
return texture
|
||||||
|
|
||||||
|
|
||||||
func _refresh_unlocks() -> void:
|
func _refresh_unlocks() -> void:
|
||||||
if not is_node_ready() or _unlocks == null:
|
if not is_node_ready() or _unlocks == null:
|
||||||
return
|
return
|
||||||
|
|
@ -342,11 +467,13 @@ func _on_service_state_changed(
|
||||||
) -> void:
|
) -> void:
|
||||||
visible = is_active
|
visible = is_active
|
||||||
if not is_active:
|
if not is_active:
|
||||||
|
hide_virtual_pointer_overlay()
|
||||||
return
|
return
|
||||||
_mode_button.icon = (
|
_mode_button.icon = (
|
||||||
GRID_MODE_ICON if mode_name == "place grid" else MARKER_MODE_ICON
|
GRID_MODE_ICON if mode_name == "place grid" else MARKER_MODE_ICON
|
||||||
)
|
)
|
||||||
_marker_mode_material.set_shader_parameter("marker_color", color_value)
|
_marker_mode_material.set_shader_parameter("marker_color", color_value)
|
||||||
|
_apply_marker_color_to_brush_icons(color_value)
|
||||||
_mode_button.accessibility_name = (
|
_mode_button.accessibility_name = (
|
||||||
"switch to marker mode"
|
"switch to marker mode"
|
||||||
if mode_name == "place grid"
|
if mode_name == "place grid"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue