Files
Lizzy 6cd6b9c25c Switch UI icons to Material Symbols
Replaces custom SVG UI icons with Material Symbols assets across player controls, details, and sidebar navigation, including updated import metadata and icon mappings for library types and skip controls. Adds in-player control labels that appear on hover/focus (including timeline and pause/play state changes), plus a new `test_player_tooltips` coverage path wired into Linux and Windows CI. Updates README usage/licensing notes and export presets to bundle Material icon attribution/license files.
2026-09-28 01:42:26 +02:00

98 lines
4.2 KiB
GDScript

class_name PlayerOverlay
extends MeshInstance3D
signal action(name: String)
signal seek_requested(milliseconds: int)
var viewport: SubViewport
var title: Label
var timeline: PlaybackTimeline
var pause_button: Button
var panel_size := Vector2(3.4, 0.75)
var play_icon: Texture2D
var pause_icon: Texture2D
var tooltip: Label
var hovered_control: Control
func _ready() -> void:
play_icon = load("res://assets/icons/material/play_arrow.svg")
pause_icon = load("res://assets/icons/material/pause.svg")
viewport = SubViewport.new()
viewport.size = Vector2i(1400, 300)
viewport.transparent_bg = true
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
add_child(viewport)
var material := StandardMaterial3D.new()
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
material.albedo_texture = viewport.get_texture()
material_override = material
var panel := PanelContainer.new()
panel.theme = Widgets.theme()
panel.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
panel.add_theme_stylebox_override("panel", Widgets.surface(Color("101624db"), 22, 24))
viewport.add_child(panel)
var body := VBoxContainer.new()
body.add_theme_constant_override("separation", 8)
panel.add_child(body)
title = Widgets.label("Now playing", body, 26)
title.clip_text = true
timeline = PlaybackTimeline.new()
body.add_child(timeline)
timeline.seek_requested.connect(func(value: int): seek_requested.emit(value))
timeline.slider.tooltip_text = ""
timeline.slider.accessibility_name = "Seek to a time"
timeline.slider.mouse_entered.connect(_show_tooltip.bind(timeline.slider))
timeline.slider.mouse_exited.connect(_hide_tooltip.bind(timeline.slider))
timeline.slider.focus_entered.connect(_show_tooltip.bind(timeline.slider))
timeline.slider.focus_exited.connect(_hide_tooltip.bind(timeline.slider))
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 12)
body.add_child(row)
for entry in [["Pause", "pause", "pause"], ["Stop", "stop", "stop"], ["Back 10 seconds", "back", "replay_10"], ["Forward 30 seconds", "forward", "forward_30"], ["Settings", "settings", "settings"], ["Library", "library", "video_library"], ["Hide controls", "hide", "visibility_off"]]:
var button := Widgets.button("", func(): action.emit(entry[1]), row)
button.icon = load("res://assets/icons/material/%s.svg" % entry[2])
button.accessibility_name = entry[0]
button.custom_minimum_size = Vector2(140, 72)
button.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER
button.add_theme_constant_override("icon_max_width", 44)
button.mouse_entered.connect(_show_tooltip.bind(button))
button.mouse_exited.connect(_hide_tooltip.bind(button))
button.focus_entered.connect(_show_tooltip.bind(button))
button.focus_exited.connect(_hide_tooltip.bind(button))
if entry[1] == "pause": pause_button = button
tooltip = Widgets.label("", body, 20)
tooltip.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
tooltip.mouse_filter = Control.MOUSE_FILTER_IGNORE
tooltip.custom_minimum_size.y = 28
hide()
func _show_tooltip(control: Control) -> void:
hovered_control = control
tooltip.text = control.accessibility_name
func _hide_tooltip(control: Control) -> void:
if hovered_control != control: return
hovered_control = null
tooltip.text = ""
func _process(_delta: float) -> void:
if not is_visible_in_tree():
hovered_control = null
tooltip.text = ""
elif is_instance_valid(hovered_control):
tooltip.text = hovered_control.accessibility_name
func fit_screen(width: float, aspect: float, curvature: float) -> void:
panel_size = Vector2(width * 0.94, width * 0.94 * 300.0 / 1400.0)
var quad := QuadMesh.new()
quad.size = panel_size
mesh = quad
position.y = -width / aspect / 2.0 + panel_size.y / 2.0 + width * 0.02
position.z = (1.0 - cos(curvature / 2.0)) * width / curvature + 0.025 if curvature > 0.001 else 0.025
func update_time(position_ms: int, duration_ms: int, ready: bool, paused: bool) -> void:
timeline.update_time(position_ms, duration_ms, ready)
pause_button.icon = play_icon if paused else pause_icon
pause_button.accessibility_name = "Play" if paused else "Pause"
if hovered_control == pause_button: tooltip.text = pause_button.accessibility_name