156 lines
3.6 KiB
GDScript
156 lines
3.6 KiB
GDScript
class_name MultiplayerChatUI
|
|
extends Control
|
|
|
|
signal message_sent(message_text: String)
|
|
|
|
const MAX_CHAT_MESSAGES: int = 100
|
|
const MAX_VISIBLE_MESSAGES: int = 8
|
|
const FEED_VISIBLE_SECONDS: float = 6.0
|
|
const FEED_FADE_SECONDS: float = 0.35
|
|
const SAFE_AREA_MARGIN := 16.0
|
|
const MIN_CHAT_WIDTH := 280.0
|
|
const MAX_CHAT_WIDTH := 480.0
|
|
const MAX_CHAT_HEIGHT := 268.0
|
|
|
|
var chat_visible: bool = false
|
|
var chat_history: Array[String] = []
|
|
var fade_tween: Tween
|
|
|
|
@onready var chat: RichTextLabel = $ChatLayout/Chat
|
|
@onready var message: LineEdit = $ChatLayout/Message
|
|
@onready var feed_timer: Timer = $FeedTimer
|
|
|
|
|
|
func _ready() -> void:
|
|
message.text_submitted.connect(_on_message_submitted)
|
|
feed_timer.timeout.connect(_on_feed_timer_timeout)
|
|
feed_timer.wait_time = FEED_VISIBLE_SECONDS
|
|
get_viewport().size_changed.connect(_update_responsive_layout)
|
|
_update_responsive_layout()
|
|
show()
|
|
clear_chat()
|
|
|
|
|
|
func _update_responsive_layout() -> void:
|
|
var viewport_size := get_viewport().get_visible_rect().size
|
|
var available_width := maxf(1.0, viewport_size.x - SAFE_AREA_MARGIN * 2.0)
|
|
var preferred_width := clampf(viewport_size.x * 0.42, MIN_CHAT_WIDTH, MAX_CHAT_WIDTH)
|
|
var target_width := minf(available_width, preferred_width)
|
|
var target_height := minf(MAX_CHAT_HEIGHT, maxf(1.0, viewport_size.y - SAFE_AREA_MARGIN * 2.0))
|
|
|
|
offset_left = SAFE_AREA_MARGIN
|
|
offset_right = SAFE_AREA_MARGIN + target_width
|
|
offset_bottom = -SAFE_AREA_MARGIN
|
|
offset_top = -SAFE_AREA_MARGIN - target_height
|
|
|
|
|
|
func toggle_chat() -> void:
|
|
if chat_visible:
|
|
close_chat()
|
|
return
|
|
|
|
chat_visible = true
|
|
_stop_feed_animation()
|
|
_show_feed()
|
|
message.show()
|
|
await get_tree().process_frame
|
|
if not chat_visible:
|
|
return
|
|
message.grab_focus()
|
|
|
|
|
|
func close_chat() -> void:
|
|
chat_visible = false
|
|
message.text = ""
|
|
message.release_focus()
|
|
message.hide()
|
|
|
|
if chat_history.is_empty():
|
|
chat.hide()
|
|
else:
|
|
_show_feed_temporarily()
|
|
|
|
|
|
func is_chat_visible() -> bool:
|
|
return chat_visible
|
|
|
|
|
|
func _on_message_submitted(_submitted_text: String) -> void:
|
|
var message_text := message.text.strip_edges()
|
|
if message_text.is_empty():
|
|
return
|
|
|
|
close_chat()
|
|
message_sent.emit(message_text)
|
|
|
|
|
|
func add_message(nick: String, msg: String) -> void:
|
|
var formatted_message := _escape_bbcode("%s: %s" % [nick, msg])
|
|
chat_history.append(formatted_message)
|
|
while chat_history.size() > MAX_CHAT_MESSAGES:
|
|
chat_history.pop_front()
|
|
|
|
_render_chat_history()
|
|
if chat_visible:
|
|
_stop_feed_animation()
|
|
_show_feed()
|
|
else:
|
|
_show_feed_temporarily()
|
|
|
|
|
|
func _render_chat_history() -> void:
|
|
chat.clear()
|
|
var first_message := maxi(0, chat_history.size() - MAX_VISIBLE_MESSAGES)
|
|
for index in range(first_message, chat_history.size()):
|
|
chat.append_text(chat_history[index])
|
|
if index < chat_history.size() - 1:
|
|
chat.append_text("\n")
|
|
|
|
|
|
func _show_feed_temporarily() -> void:
|
|
_stop_feed_animation()
|
|
_show_feed()
|
|
feed_timer.start()
|
|
|
|
|
|
func _show_feed() -> void:
|
|
chat.modulate.a = 1.0
|
|
chat.show()
|
|
|
|
|
|
func _on_feed_timer_timeout() -> void:
|
|
if chat_visible:
|
|
return
|
|
|
|
_stop_fade_tween()
|
|
fade_tween = create_tween()
|
|
fade_tween.tween_property(chat, "modulate:a", 0.0, FEED_FADE_SECONDS)
|
|
fade_tween.tween_callback(chat.hide)
|
|
|
|
|
|
func _stop_feed_animation() -> void:
|
|
feed_timer.stop()
|
|
_stop_fade_tween()
|
|
|
|
|
|
func _stop_fade_tween() -> void:
|
|
if fade_tween and fade_tween.is_valid():
|
|
fade_tween.kill()
|
|
fade_tween = null
|
|
|
|
|
|
func _escape_bbcode(text: String) -> String:
|
|
return text.replace("[", "[lb]")
|
|
|
|
|
|
func clear_chat() -> void:
|
|
_stop_feed_animation()
|
|
chat_history.clear()
|
|
chat.clear()
|
|
chat.modulate.a = 1.0
|
|
chat.hide()
|
|
message.text = ""
|
|
message.release_focus()
|
|
message.hide()
|
|
chat_visible = false
|