extends CanvasLayer const MAX_LOG_SIZE = 100 const CLEAN_BUCKET = 10 var message_count = 0 @onready var scroll_container: ScrollContainer = $ScrollContainer @onready var chat_log_lines_container: VBoxContainer = $ScrollContainer/ChatLogLinesContainer @onready var chat_log_line = preload("res://scenes/ui_elements/chat_log_line.tscn") var scroll_bar = null var scroll_value = 0 var current_max_scroll = 0 var mouse_dragging = false var mouse_scrolling = false var mouse_dragging_initial_scroll_value = 0 var mouse_dragging_initial_pos = 0 var mouse_dragging_last_pos = Vector2.ZERO func _ready(): scroll_bar = scroll_container.get_v_scroll_bar() scroll_bar.changed.connect(_on_scroll_bar_changed) scroll_bar.gui_input.connect(_on_scroll_bar_gui_input) scroll_bar.set_deferred("custom_minimum_size", Vector2(20, scroll_bar.custom_minimum_size.y)) scroll_bar.set_deferred("position", Vector2(scroll_container.size.x - 20, 0)) #scroll_value = scroll_bar.max_value #scroll_container.scroll_vertical = scroll_value func _process(delta): if visible: if not %MuteButton.has_focus() and not %VolumeSlider.has_focus(): #print(Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down", 0.1)) set_scroll_vertical(scroll_value + Input.get_axis("ui_up", "ui_down") * delta * 1000) func add_line(speaker_text: String, speaker_name: String = ""): clean_log() var line = chat_log_line.instantiate() if speaker_name: line.get_node("NameLabel").text = speaker_name else: line.get_node("NameLabel").visible = false line.get_node("TextLabel").text = " %s" % speaker_text chat_log_lines_container.add_child(line) message_count += 1 func add_selected_option_text(selected_option_text: String): clean_log() var line = chat_log_line.instantiate() line.get_node("NameLabel").text = "◆ Option ◆" line.get_node("TextLabel").text = " %s" % selected_option_text chat_log_lines_container.add_child(line) message_count += 1 func clean_log(): if message_count >= MAX_LOG_SIZE: var children = chat_log_lines_container.get_children() for i in CLEAN_BUCKET: var child = children[i] chat_log_lines_container.remove_child(child) child.visible = false child.queue_free() message_count -= CLEAN_BUCKET func set_scroll_vertical(value): scroll_value = clamp(value, 0, current_max_scroll - scroll_container.size.y) scroll_container.scroll_vertical = scroll_value func _on_scroll_bar_changed(): if scroll_bar.max_value != current_max_scroll: current_max_scroll = scroll_bar.max_value scroll_value = max(0, current_max_scroll - scroll_container.size.y) scroll_container.scroll_vertical = scroll_value func _on_scroll_container_gui_input(event: InputEvent): if event is InputEventMouseButton: match event.button_index: MOUSE_BUTTON_LEFT: if event.pressed and not mouse_dragging: mouse_dragging = true mouse_scrolling = false mouse_dragging_initial_pos = event.global_position.y mouse_dragging_last_pos = event.global_position mouse_dragging_initial_scroll_value = scroll_value #scroll_value = mouse_dragging_initial_scroll_value elif not event.pressed and mouse_dragging: mouse_dragging = false mouse_scrolling = false MOUSE_BUTTON_WHEEL_UP: set_scroll_vertical(scroll_value - 40) MOUSE_BUTTON_WHEEL_DOWN: set_scroll_vertical(scroll_value + 40) elif event is InputEventMouseMotion and mouse_dragging: # Fix for mobile touch and release not being detected; assume any instant jump in cursor distance of ~350px or more is a reset if event.global_position.distance_squared_to(mouse_dragging_last_pos) >= 120_000: mouse_dragging_initial_pos = event.global_position.y mouse_dragging_initial_scroll_value = scroll_value else: set_scroll_vertical(mouse_dragging_initial_scroll_value - (event.global_position.y - mouse_dragging_initial_pos)) mouse_dragging_last_pos = event.global_position func _on_scroll_bar_gui_input(event: InputEvent): if event is InputEventMouseButton: if event.button_index == MOUSE_BUTTON_LEFT: if event.pressed and not mouse_scrolling: mouse_dragging = false mouse_scrolling = true mouse_dragging_initial_pos = event.global_position.y mouse_dragging_last_pos = event.global_position mouse_dragging_initial_scroll_value = scroll_value #scroll_value = mouse_dragging_initial_scroll_value elif not event.pressed and mouse_scrolling: mouse_dragging = false mouse_scrolling = false elif event is InputEventMouseMotion and mouse_scrolling: # Fix for mobile touch and release not being detected; assume any instant jump in cursor distance of ~350px or more is a reset if event.global_position.distance_squared_to(mouse_dragging_last_pos) >= 120_000: mouse_dragging_initial_pos = event.global_position.y mouse_dragging_initial_scroll_value = scroll_value else: set_scroll_vertical(mouse_dragging_initial_scroll_value + (current_max_scroll / scroll_bar.page) * (event.global_position.y - mouse_dragging_initial_pos)) mouse_dragging_last_pos = event.global_position