Files
whale-town-front-v2/scenes/ui/FriendListPanel.gd

648 lines
24 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Control
# ============================================================================
# FriendListPanel.gd - 右下角好友列表面板
# ============================================================================
# 独立展示好友在线、好友请求和好友选择。点击好友后通过事件驱动 ChatUI
# 切换到对应好友会话,不在面板内承载聊天内容。
# ============================================================================
const PANEL_SIZE: Vector2 = Vector2(384, 492)
const PANEL_MARGIN: Vector2 = Vector2(32, 32)
const ONLINE_COLOR: Color = Color(0.286, 0.765, 0.486)
const OFFLINE_COLOR: Color = Color(0.678, 0.725, 0.773)
const TEXT_COLOR: Color = Color(0.188, 0.294, 0.424)
const MUTED_COLOR: Color = Color(0.560, 0.639, 0.733)
const ACCENT_COLOR: Color = Color(0.258824, 0.627451, 0.913725)
const SURFACE_COLOR: Color = Color(1.0, 0.996, 0.984, 0.97)
const SURFACE_RAISED_COLOR: Color = Color(1.0, 1.0, 1.0, 0.9)
const BORDER_COLOR: Color = Color(0.788, 0.851, 0.910, 0.52)
const FRIEND_AVATAR_SIZE: Vector2 = Vector2(48, 48)
const FRIEND_AVATAR_CORNER_RADIUS: int = 12
@export var autoRequestFriendList: bool = true
var _panel: PanelContainer
var _titleLabel: Label
var _summaryLabel: Label
var _closeButton: Button
var _requestList: VBoxContainer
var _friendList: VBoxContainer
var _statusLabel: Label
var _friends: Array[Dictionary] = []
var _requests: Array[Dictionary] = []
var _supported: bool = true
var _statusMessage: String = ""
var _isOpen: bool = false
var _hasRequestedFriendList: bool = false
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
_build_ui()
set_panel_open(false)
_subscribe_to_events()
func _exit_tree() -> void:
var eventSystem := _get_event_system()
if eventSystem != null:
eventSystem.call("disconnect_event", EventNames.CHAT_FRIENDS_UPDATED, _on_friends_updated, self)
eventSystem.call("disconnect_event", EventNames.HUD_FRIEND_LIST_TOGGLE, _on_friend_list_toggle, self)
eventSystem.call("disconnect_event", EventNames.SETTINGS_CHANGED, _on_settings_changed, self)
func set_panel_open(open: bool) -> void:
_isOpen = open
if is_instance_valid(_panel):
_panel.visible = _isOpen
if _isOpen and autoRequestFriendList and not _hasRequestedFriendList:
_request_initial_friend_list()
func is_panel_open() -> bool:
return _isOpen
func toggle_panel() -> void:
set_panel_open(not _isOpen)
func _build_ui() -> void:
_panel = PanelContainer.new()
_panel.name = "FriendListCard"
_panel.custom_minimum_size = PANEL_SIZE
_panel.mouse_filter = Control.MOUSE_FILTER_STOP
_panel.add_theme_stylebox_override("panel", _create_panel_style())
add_child(_panel)
_anchor_panel()
var margin := MarginContainer.new()
margin.add_theme_constant_override("margin_left", 18)
margin.add_theme_constant_override("margin_top", 18)
margin.add_theme_constant_override("margin_right", 18)
margin.add_theme_constant_override("margin_bottom", 18)
_panel.add_child(margin)
var content := VBoxContainer.new()
content.add_theme_constant_override("separation", 12)
margin.add_child(content)
var header := HBoxContainer.new()
header.custom_minimum_size = Vector2(0, 48)
header.add_theme_constant_override("separation", 12)
content.add_child(header)
var titleStack := VBoxContainer.new()
titleStack.size_flags_horizontal = Control.SIZE_EXPAND_FILL
titleStack.alignment = BoxContainer.ALIGNMENT_CENTER
titleStack.add_theme_constant_override("separation", 1)
header.add_child(titleStack)
_titleLabel = Label.new()
_titleLabel.text = "好友"
_titleLabel.add_theme_color_override("font_color", TEXT_COLOR)
_titleLabel.add_theme_font_size_override("font_size", 22)
titleStack.add_child(_titleLabel)
var subtitleLabel := Label.new()
subtitleLabel.text = "和鲸落镇的伙伴保持联系"
subtitleLabel.add_theme_color_override("font_color", MUTED_COLOR)
subtitleLabel.add_theme_font_size_override("font_size", 12)
titleStack.add_child(subtitleLabel)
_closeButton = Button.new()
_closeButton.text = "×"
_closeButton.tooltip_text = "收起好友列表"
_closeButton.custom_minimum_size = Vector2(36, 36)
_closeButton.focus_mode = Control.FOCUS_NONE
_closeButton.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
_closeButton.add_theme_font_size_override("font_size", 22)
_closeButton.add_theme_color_override("font_color", MUTED_COLOR)
_closeButton.add_theme_color_override("font_hover_color", ACCENT_COLOR)
_closeButton.add_theme_color_override("font_pressed_color", ACCENT_COLOR.darkened(0.12))
_closeButton.add_theme_color_override("font_disabled_color", Color(0.37, 0.48, 0.58, 0.55))
_closeButton.add_theme_stylebox_override("normal", _create_empty_style())
_closeButton.add_theme_stylebox_override("hover", _create_pill_style(Color(0.918, 0.961, 0.992, 0.96), 12))
_closeButton.add_theme_stylebox_override("pressed", _create_pill_style(Color(0.858, 0.925, 0.980, 1.0), 12))
_closeButton.add_theme_stylebox_override("focus", _create_empty_style())
_closeButton.pressed.connect(func() -> void: set_panel_open(false))
header.add_child(_closeButton)
var summaryCard := PanelContainer.new()
summaryCard.custom_minimum_size = Vector2(0, 54)
summaryCard.add_theme_stylebox_override("panel", _create_summary_style())
content.add_child(summaryCard)
var summaryRow := HBoxContainer.new()
summaryRow.add_theme_constant_override("separation", 10)
summaryCard.add_child(summaryRow)
var onlineDot := PanelContainer.new()
onlineDot.custom_minimum_size = Vector2(10, 10)
onlineDot.size_flags_vertical = Control.SIZE_SHRINK_CENTER
onlineDot.add_theme_stylebox_override("panel", _create_dot_style(ONLINE_COLOR))
summaryRow.add_child(onlineDot)
_summaryLabel = Label.new()
_summaryLabel.text = "暂无在线好友"
_summaryLabel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_summaryLabel.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_summaryLabel.add_theme_color_override("font_color", Color(0.207843, 0.427451, 0.686275))
_summaryLabel.add_theme_font_size_override("font_size", 15)
summaryRow.add_child(_summaryLabel)
var chatHint := Label.new()
chatHint.text = "选择好友开始私聊"
chatHint.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
chatHint.add_theme_color_override("font_color", MUTED_COLOR)
chatHint.add_theme_font_size_override("font_size", 12)
summaryRow.add_child(chatHint)
_statusLabel = Label.new()
_statusLabel.visible = false
_statusLabel.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_statusLabel.add_theme_color_override("font_color", MUTED_COLOR)
_statusLabel.add_theme_font_size_override("font_size", 15)
content.add_child(_statusLabel)
_requestList = VBoxContainer.new()
_requestList.add_theme_constant_override("separation", 8)
content.add_child(_requestList)
var friendsHeading := Label.new()
friendsHeading.text = "全部好友"
friendsHeading.add_theme_color_override("font_color", MUTED_COLOR)
friendsHeading.add_theme_font_size_override("font_size", 13)
content.add_child(friendsHeading)
var scroll := ScrollContainer.new()
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
scroll.add_theme_stylebox_override("panel", _create_empty_style())
content.add_child(scroll)
_friendList = VBoxContainer.new()
_friendList.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_friendList.add_theme_constant_override("separation", 8)
scroll.add_child(_friendList)
_render()
func _anchor_panel() -> void:
_panel.set_anchors_preset(Control.PRESET_BOTTOM_RIGHT)
_panel.offset_left = -PANEL_SIZE.x - PANEL_MARGIN.x
_panel.offset_top = -PANEL_SIZE.y - PANEL_MARGIN.y
_panel.offset_right = -PANEL_MARGIN.x
_panel.offset_bottom = -PANEL_MARGIN.y
_panel.grow_horizontal = Control.GROW_DIRECTION_BEGIN
_panel.grow_vertical = Control.GROW_DIRECTION_BEGIN
func _subscribe_to_events() -> void:
var eventSystem := _get_event_system()
if eventSystem == null:
push_warning("FriendListPanel: EventSystem autoload is not available.")
return
eventSystem.call("connect_event", EventNames.CHAT_FRIENDS_UPDATED, _on_friends_updated, self)
eventSystem.call("connect_event", EventNames.HUD_FRIEND_LIST_TOGGLE, _on_friend_list_toggle, self)
eventSystem.call("connect_event", EventNames.SETTINGS_CHANGED, _on_settings_changed, self)
func _request_initial_friend_list() -> void:
_hasRequestedFriendList = true
var chatManager := get_node_or_null("/root/ChatManager")
if chatManager != null and chatManager.has_method("request_friend_list"):
chatManager.call_deferred("request_friend_list")
func _on_friend_list_toggle(_data: Variant = null) -> void:
toggle_panel()
func _on_friends_updated(data: Dictionary) -> void:
_friends.clear()
_requests.clear()
_supported = bool(data.get("supported", true))
_statusMessage = str(data.get("status", "")).strip_edges()
var friendsVariant: Variant = data.get("friends", [])
if friendsVariant is Array:
for friendVariant in friendsVariant:
if friendVariant is Dictionary:
_friends.append(friendVariant)
var requestsVariant: Variant = data.get("requests", [])
if requestsVariant is Array:
for requestVariant in requestsVariant:
if requestVariant is Dictionary:
_requests.append(requestVariant)
_render()
func _on_settings_changed(_data: Dictionary) -> void:
_render()
func _render() -> void:
if not is_instance_valid(_friendList) or not is_instance_valid(_requestList):
return
_clear_children(_friendList)
_clear_children(_requestList)
var onlineCount := _count_online_friends()
_titleLabel.text = "好友"
if is_instance_valid(_summaryLabel):
if _friends.is_empty():
_summaryLabel.text = "暂无好友,去广场认识新伙伴吧"
else:
_summaryLabel.text = "%d 位好友在线,共 %d 位伙伴" % [onlineCount, _friends.size()]
if not _supported:
_show_status(_statusMessage if not _statusMessage.is_empty() else "当前后端暂不支持好友功能")
return
_statusLabel.visible = false
_render_requests()
_render_friends()
func _render_requests() -> void:
if _requests.is_empty() or not _settings_bool("friend_request_notifications", true):
_requestList.visible = false
return
_requestList.visible = true
var titleCard := PanelContainer.new()
titleCard.custom_minimum_size = Vector2(0, 34)
titleCard.add_theme_stylebox_override("panel", _create_section_style())
_requestList.add_child(titleCard)
var title := Label.new()
title.text = "待处理请求 %d" % _requests.size()
title.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
title.add_theme_color_override("font_color", Color(0.207843, 0.427451, 0.686275))
title.add_theme_font_size_override("font_size", 13)
titleCard.add_child(title)
for request in _requests:
_requestList.add_child(_create_request_row(request))
func _render_friends() -> void:
if _friends.is_empty():
var emptyCard := PanelContainer.new()
emptyCard.custom_minimum_size = Vector2(0, 100)
emptyCard.add_theme_stylebox_override("panel", _create_empty_state_style())
_friendList.add_child(emptyCard)
var emptyLabel := Label.new()
emptyLabel.text = "暂无好友\n靠近玩家按 F 发送好友请求"
emptyLabel.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
emptyLabel.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
emptyLabel.add_theme_color_override("font_color", MUTED_COLOR)
emptyLabel.add_theme_font_size_override("font_size", 14)
emptyCard.add_child(emptyLabel)
return
for friend in _sorted_friends():
_friendList.add_child(_create_friend_row(friend))
func _create_friend_row(friend: Dictionary) -> Control:
var userId := _read_user_id(friend)
var username := str(friend.get("username", "好友")).strip_edges()
if username.is_empty():
username = "好友"
var online := bool(friend.get("online", false))
var button := Button.new()
button.focus_mode = Control.FOCUS_NONE
button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
button.disabled = userId.is_empty()
button.custom_minimum_size = Vector2(0, 68)
button.text = ""
button.add_theme_stylebox_override("normal", _create_friend_row_style(false, online))
button.add_theme_stylebox_override("hover", _create_friend_row_style(true, online))
button.add_theme_stylebox_override("pressed", _create_friend_row_style(true, online, true))
button.add_theme_stylebox_override("disabled", _create_friend_row_style(false, false))
button.add_theme_stylebox_override("focus", _create_empty_style())
button.pressed.connect(func() -> void: _select_friend(userId, username, online))
var row := HBoxContainer.new()
row.mouse_filter = Control.MOUSE_FILTER_IGNORE
row.set_anchors_preset(Control.PRESET_FULL_RECT)
row.offset_left = 10
row.offset_top = 8
row.offset_right = -10
row.offset_bottom = -8
row.add_theme_constant_override("separation", 12)
button.add_child(row)
row.add_child(_create_avatar(username, online))
var textBox := VBoxContainer.new()
textBox.mouse_filter = Control.MOUSE_FILTER_IGNORE
textBox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
textBox.alignment = BoxContainer.ALIGNMENT_CENTER
textBox.add_theme_constant_override("separation", 3)
row.add_child(textBox)
var nameLabel := Label.new()
nameLabel.mouse_filter = Control.MOUSE_FILTER_IGNORE
nameLabel.text = username
nameLabel.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
nameLabel.add_theme_color_override("font_color", TEXT_COLOR if online else MUTED_COLOR)
nameLabel.add_theme_font_size_override("font_size", 16)
textBox.add_child(nameLabel)
var statusLabel := Label.new()
statusLabel.mouse_filter = Control.MOUSE_FILTER_IGNORE
statusLabel.text = "正在鲸落镇" if online else "暂时离线"
statusLabel.add_theme_color_override("font_color", ONLINE_COLOR if online else MUTED_COLOR)
statusLabel.add_theme_font_size_override("font_size", 12)
textBox.add_child(statusLabel)
var dot := PanelContainer.new()
dot.name = "FriendOnlineIndicator"
dot.custom_minimum_size = Vector2(8, 8)
dot.size_flags_vertical = Control.SIZE_SHRINK_CENTER
dot.mouse_filter = Control.MOUSE_FILTER_IGNORE
dot.add_theme_stylebox_override("panel", _create_dot_style(ONLINE_COLOR if online else OFFLINE_COLOR))
row.add_child(dot)
return button
func _create_request_row(request: Dictionary) -> Control:
var userId := _read_user_id(request)
var username := str(request.get("username", "玩家")).strip_edges()
if username.is_empty():
username = "玩家"
var rowPanel := PanelContainer.new()
rowPanel.custom_minimum_size = Vector2(0, 48)
rowPanel.add_theme_stylebox_override("panel", _create_request_style())
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 8)
rowPanel.add_child(row)
var nameLabel := Label.new()
nameLabel.mouse_filter = Control.MOUSE_FILTER_IGNORE
nameLabel.text = username
nameLabel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
nameLabel.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
nameLabel.add_theme_color_override("font_color", TEXT_COLOR)
nameLabel.add_theme_font_size_override("font_size", 14)
row.add_child(nameLabel)
var acceptButton := _create_small_button("接受", Color(0.333, 0.761, 0.514))
acceptButton.pressed.connect(func() -> void: _respond_request(userId, username, true))
row.add_child(acceptButton)
var rejectButton := _create_small_button("拒绝", Color(0.812, 0.553, 0.553))
rejectButton.pressed.connect(func() -> void: _respond_request(userId, username, false))
row.add_child(rejectButton)
return rowPanel
func _select_friend(userId: String, username: String, _online: bool) -> void:
if userId.strip_edges().is_empty():
return
var eventSystem := _get_event_system()
if eventSystem != null:
eventSystem.call("emit_event", EventNames.CHAT_FRIEND_SELECTED, {
"user_id": userId,
"username": username
})
func _respond_request(userId: String, username: String, accepted: bool) -> void:
if userId.strip_edges().is_empty():
return
var chatManager := get_node_or_null("/root/ChatManager")
if chatManager == null:
return
var ok := false
if accepted and chatManager.has_method("accept_friend_request"):
ok = bool(chatManager.call("accept_friend_request", userId, username))
elif not accepted and chatManager.has_method("reject_friend_request"):
ok = bool(chatManager.call("reject_friend_request", userId, username))
if ok:
for i in range(_requests.size() - 1, -1, -1):
if _read_user_id(_requests[i]) == userId:
_requests.remove_at(i)
_render()
func _show_status(message: String) -> void:
_statusLabel.text = message
_statusLabel.visible = true
_requestList.visible = false
func _count_online_friends() -> int:
var count := 0
for friend in _friends:
if bool(friend.get("online", false)):
count += 1
return count
func _sorted_friends() -> Array[Dictionary]:
var sortedFriends := _friends.duplicate(true)
sortedFriends.sort_custom(func(a: Dictionary, b: Dictionary) -> bool:
var onlineA := bool(a.get("online", false))
var onlineB := bool(b.get("online", false))
if onlineA != onlineB:
return onlineA
return str(a.get("username", "")).nocasecmp_to(str(b.get("username", ""))) < 0
)
return sortedFriends
func _read_user_id(data: Dictionary) -> String:
return str(data.get("user_id", data.get("userId", ""))).strip_edges()
func _create_avatar(username: String, online: bool) -> PanelContainer:
var avatar := PanelContainer.new()
avatar.name = "FriendAvatarPanel"
avatar.custom_minimum_size = FRIEND_AVATAR_SIZE
avatar.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
avatar.size_flags_vertical = Control.SIZE_SHRINK_CENTER
avatar.mouse_filter = Control.MOUSE_FILTER_IGNORE
avatar.add_theme_stylebox_override("panel", _create_avatar_style(online))
var label := Label.new()
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
label.text = _avatar_text(username)
label.custom_minimum_size = FRIEND_AVATAR_SIZE
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
label.add_theme_color_override("font_color", Color.WHITE)
label.add_theme_font_size_override("font_size", 16)
avatar.add_child(label)
return avatar
func _avatar_text(username: String) -> String:
var normalized := username.strip_edges()
if normalized.is_empty():
return ""
return normalized.substr(0, 1).to_upper()
func _create_small_button(text: String, color: Color) -> Button:
var button := Button.new()
button.text = text
button.custom_minimum_size = Vector2(52, 30)
button.focus_mode = Control.FOCUS_NONE
button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
button.add_theme_font_size_override("font_size", 13)
button.add_theme_color_override("font_color", Color.WHITE)
button.add_theme_stylebox_override("normal", _create_pill_style(color, 9))
button.add_theme_stylebox_override("hover", _create_pill_style(color.lightened(0.08), 9))
button.add_theme_stylebox_override("pressed", _create_pill_style(color.darkened(0.08), 9))
button.add_theme_stylebox_override("focus", _create_empty_style())
return button
func _create_panel_style() -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = SURFACE_COLOR
style.border_width_left = 1
style.border_width_top = 1
style.border_width_right = 1
style.border_width_bottom = 1
style.border_color = BORDER_COLOR
style.corner_radius_top_left = 20
style.corner_radius_top_right = 20
style.corner_radius_bottom_left = 20
style.corner_radius_bottom_right = 20
style.shadow_color = Color(0.12549, 0.282353, 0.407843, 0.18)
style.shadow_size = 18
style.shadow_offset = Vector2(0, 7)
return style
func _create_avatar_style(online: bool) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.361, 0.690, 0.914) if online else Color(0.678, 0.725, 0.773)
style.corner_radius_top_left = FRIEND_AVATAR_CORNER_RADIUS
style.corner_radius_top_right = FRIEND_AVATAR_CORNER_RADIUS
style.corner_radius_bottom_left = FRIEND_AVATAR_CORNER_RADIUS
style.corner_radius_bottom_right = FRIEND_AVATAR_CORNER_RADIUS
style.border_width_left = 1
style.border_width_top = 1
style.border_width_right = 1
style.border_width_bottom = 1
style.border_color = Color(1, 1, 1, 0.82)
return style
func _create_summary_style() -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.918, 0.961, 0.992, 0.96)
style.border_width_left = 1
style.border_width_top = 1
style.border_width_right = 1
style.border_width_bottom = 1
style.border_color = Color(0.76, 0.86, 0.94, 0.62)
style.corner_radius_top_left = 12
style.corner_radius_top_right = 12
style.corner_radius_bottom_left = 12
style.corner_radius_bottom_right = 12
style.content_margin_left = 14
style.content_margin_right = 14
return style
func _create_dot_style(color: Color) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = color
style.corner_radius_top_left = 5
style.corner_radius_top_right = 5
style.corner_radius_bottom_left = 5
style.corner_radius_bottom_right = 5
return style
func _create_section_style() -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.948, 0.974, 0.996, 0.96)
style.border_width_left = 1
style.border_width_top = 1
style.border_width_right = 1
style.border_width_bottom = 1
style.border_color = Color(0.78, 0.87, 0.94, 0.54)
style.corner_radius_top_left = 9
style.corner_radius_top_right = 9
style.corner_radius_bottom_left = 9
style.corner_radius_bottom_right = 9
style.content_margin_left = 12
style.content_margin_right = 12
return style
func _create_empty_state_style() -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.965, 0.982, 0.996, 0.86)
style.border_width_left = 1
style.border_width_top = 1
style.border_width_right = 1
style.border_width_bottom = 1
style.border_color = Color(0.80, 0.88, 0.94, 0.52)
style.corner_radius_top_left = 12
style.corner_radius_top_right = 12
style.corner_radius_bottom_left = 12
style.corner_radius_bottom_right = 12
return style
func _create_request_style() -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color(1, 1, 1, 0.94)
style.border_width_left = 1
style.border_width_top = 1
style.border_width_right = 1
style.border_width_bottom = 1
style.border_color = Color(0.78, 0.86, 0.93, 0.64)
style.corner_radius_top_left = 10
style.corner_radius_top_right = 10
style.corner_radius_bottom_left = 10
style.corner_radius_bottom_right = 10
style.content_margin_left = 10
style.content_margin_top = 8
style.content_margin_right = 10
style.content_margin_bottom = 8
return style
func _create_friend_row_style(isHovered: bool, isOnline: bool, isPressed: bool = false) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = SURFACE_RAISED_COLOR if isOnline else Color(0.965, 0.973, 0.982, 0.86)
if isHovered:
style.bg_color = Color(0.918, 0.961, 0.992, 0.98)
if isPressed:
style.bg_color = style.bg_color.darkened(0.12)
style.border_width_left = 1
style.border_width_top = 1
style.border_width_right = 1
style.border_width_bottom = 1
style.border_color = Color(0.55, 0.78, 0.95, 0.72) if isHovered else Color(0.80, 0.87, 0.93, 0.56)
style.corner_radius_top_left = 12
style.corner_radius_top_right = 12
style.corner_radius_bottom_left = 12
style.corner_radius_bottom_right = 12
return style
func _create_pill_style(color: Color, radius: int) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = color
style.corner_radius_top_left = radius
style.corner_radius_top_right = radius
style.corner_radius_bottom_left = radius
style.corner_radius_bottom_right = radius
style.content_margin_left = 10
style.content_margin_right = 10
style.content_margin_top = 5
style.content_margin_bottom = 5
return style
func _create_empty_style() -> StyleBoxEmpty:
return StyleBoxEmpty.new()
func _clear_children(container: Node) -> void:
for child in container.get_children():
container.remove_child(child)
child.queue_free()
func _get_event_system() -> Node:
return get_node_or_null("/root/EventSystem")
func _settings_bool(key: String, defaultValue: bool) -> bool:
var settingsManager := get_node_or_null("/root/SettingsManager")
if settingsManager != null and settingsManager.has_method("get_bool"):
return bool(settingsManager.call("get_bool", key))
return defaultValue