clipboard_ui.gd
· 6.2 KiB · GDScript3
Eredeti
extends Node
class_name ClipboardUIHelper
# Builds the Network tab content into a provided container page
static func build_network_ui(page_container: Node, engine: Node) -> void:
## 1. CLEANUP PREVIOUS RENDERS: Safely look for and wipe old structural layout node
var old_wrapper = page_container.get_node_or_null("NetworkMarginWrapper")
if old_wrapper:
old_wrapper.queue_free()
page_container.remove_child(old_wrapper)
## 2. MAIN PAGE LAYOUT: The root wrapper for this specific tab page
var margin_wrapper = MarginContainer.new()
margin_wrapper.name = "NetworkMarginWrapper"
margin_wrapper.add_theme_constant_override("margin_left", 50)
margin_wrapper.add_theme_constant_override("margin_top", 40)
page_container.add_child(margin_wrapper)
var main_stack = VBoxContainer.new()
main_stack.add_theme_constant_override("separation", 15)
margin_wrapper.add_child(main_stack)
# ----------------------------------------------------
# ROW 1: Connection Actions (Start Server / Connect Client)
# ----------------------------------------------------
var row_actions = HBoxContainer.new()
row_actions.add_theme_constant_override("separation", 15)
main_stack.add_child(row_actions)
var btn_server = Button.new()
btn_server.text = "Start Server"
btn_server.pressed.connect(func(): _on_start_server_pressed(engine))
row_actions.add_child(btn_server)
var btn_client = Button.new()
btn_client.text = "Connect Client"
btn_client.pressed.connect(func(): _on_start_client_pressed(engine))
row_actions.add_child(btn_client)
# ----------------------------------------------------
# ROW 2: Address Info (IP Input & Port Input)
# ----------------------------------------------------
var row_address = HBoxContainer.new()
row_address.add_theme_constant_override("separation", 15)
main_stack.add_child(row_address)
var ip_input = LineEdit.new()
ip_input.text = engine.server_ip
ip_input.placeholder_text = "Target Server IP"
ip_input.custom_minimum_size = Vector2(180, 35)
row_address.add_child(ip_input)
var port_input = LineEdit.new()
port_input.text = str(engine.port_number)
port_input.placeholder_text = "Port"
port_input.custom_minimum_size = Vector2(100, 35)
row_address.add_child(port_input)
# ----------------------------------------------------
# ROW 3: Security & Utility (Passphrase, Generate, Copy)
# ----------------------------------------------------
var row_security = HBoxContainer.new()
row_security.add_theme_constant_override("separation", 15)
main_stack.add_child(row_security)
var key_input = LineEdit.new()
key_input.text = engine.secret_key
key_input.secret = true
key_input.placeholder_text = "Shared Secret Key Passphrase"
key_input.custom_minimum_size = Vector2(300, 35)
row_security.add_child(key_input)
var btn_generate = Button.new()
btn_generate.text = "New Key"
btn_generate.custom_minimum_size = Vector2(0, 35)
btn_generate.pressed.connect(func(): _on_generate_key(engine, key_input))
row_security.add_child(btn_generate)
var btn_copy = Button.new()
btn_copy.text = "Copy Key"
btn_copy.custom_minimum_size = Vector2(0, 35)
btn_copy.pressed.connect(func(): engine.copy_key_to_clipboard())
row_security.add_child(btn_copy)
# ----------------------------------------------------
# ROW 4: Manual Sync Input
# ----------------------------------------------------
var row_input = HBoxContainer.new()
row_address.add_theme_constant_override("separation", 15)
main_stack.add_child(row_input)
var line_edit = LineEdit.new()
line_edit.custom_minimum_size = Vector2(400, 40)
line_edit.placeholder_text = "Type and press Enter to securely sync..."
# Wire the UI input directly to the engine's RPC method using encryption
line_edit.text_submitted.connect(func(new_text): engine.receive_secure_clipboard(engine.encrypt_string(new_text)))
row_input.add_child(line_edit)
# ----------------------------------------------------
# ROW 5: Status Panel (Replaces draw_rect entirely)
# ----------------------------------------------------
var row_status = HBoxContainer.new()
row_status.add_theme_constant_override("separation", 15)
main_stack.add_child(row_status)
var status_card = PanelContainer.new()
status_card.custom_minimum_size = Vector2(400, 80)
status_card.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
var card_padding = MarginContainer.new()
card_padding.add_theme_constant_override("margin_left", 30)
card_padding.add_theme_constant_override("margin_right", 30)
card_padding.add_theme_constant_override("margin_top", 15)
card_padding.add_theme_constant_override("margin_bottom", 15)
status_card.add_child(card_padding)
var status_label = RichTextLabel.new()
status_label.text = "Loading..."
status_label.selection_enabled = true
status_label.add_theme_font_size_override("font_size", 18)
status_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
card_padding.add_child(status_label)
# StyleBoxFlat to mimic your old draw_rect background
var custom_style = StyleBoxFlat.new()
custom_style.bg_color = Color(0.13, 0.13, 0.13, 1.0)
custom_style.set_corner_radius_all(4)
status_card.add_theme_stylebox_override("panel", custom_style)
main_stack.add_child(status_card)
# Listen for engine status updates and wire them to the label
engine.status_changed.connect(func(new_status_text): _update_status_label(status_label, new_status_text))
# -- Static Helper Functions for UI Wiring --
static func _on_start_server_pressed(engine: Node) -> void:
# Reads current properties. In a real app you might pass inputs as arguments instead.
engine.start_server(int(engine.port_number))
static func _on_start_client_pressed(engine: Node) -> void:
engine.start_client(str(engine.server_ip), int(engine.port_number))
static func _on_generate_key(engine: Node, key_input: LineEdit) -> void:
var new_key = engine.generate_random_key(16)
engine.secret_key = new_key
key_input.text = new_key
static func _update_status_label(label: RichTextLabel, text: String) -> void:
label.text = text
# Calculate dynamic color state based on connection status
var target_color: Color = Color.GREEN
if "Disconnected" in text or "Offline" in text:
target_color = Color.YELLOW
elif "Reconnecting" in text:
target_color = Color.ORANGE
label.add_theme_color_override("default_color", target_color)
| 1 | extends Node |
| 2 | class_name ClipboardUIHelper |
| 3 | |
| 4 | # Builds the Network tab content into a provided container page |
| 5 | static func build_network_ui(page_container: Node, engine: Node) -> void: |
| 6 | ## 1. CLEANUP PREVIOUS RENDERS: Safely look for and wipe old structural layout node |
| 7 | var old_wrapper = page_container.get_node_or_null("NetworkMarginWrapper") |
| 8 | if old_wrapper: |
| 9 | old_wrapper.queue_free() |
| 10 | page_container.remove_child(old_wrapper) |
| 11 | |
| 12 | ## 2. MAIN PAGE LAYOUT: The root wrapper for this specific tab page |
| 13 | var margin_wrapper = MarginContainer.new() |
| 14 | margin_wrapper.name = "NetworkMarginWrapper" |
| 15 | margin_wrapper.add_theme_constant_override("margin_left", 50) |
| 16 | margin_wrapper.add_theme_constant_override("margin_top", 40) |
| 17 | page_container.add_child(margin_wrapper) |
| 18 | |
| 19 | var main_stack = VBoxContainer.new() |
| 20 | main_stack.add_theme_constant_override("separation", 15) |
| 21 | margin_wrapper.add_child(main_stack) |
| 22 | |
| 23 | # ---------------------------------------------------- |
| 24 | # ROW 1: Connection Actions (Start Server / Connect Client) |
| 25 | # ---------------------------------------------------- |
| 26 | var row_actions = HBoxContainer.new() |
| 27 | row_actions.add_theme_constant_override("separation", 15) |
| 28 | main_stack.add_child(row_actions) |
| 29 | |
| 30 | var btn_server = Button.new() |
| 31 | btn_server.text = "Start Server" |
| 32 | btn_server.pressed.connect(func(): _on_start_server_pressed(engine)) |
| 33 | row_actions.add_child(btn_server) |
| 34 | |
| 35 | var btn_client = Button.new() |
| 36 | btn_client.text = "Connect Client" |
| 37 | btn_client.pressed.connect(func(): _on_start_client_pressed(engine)) |
| 38 | row_actions.add_child(btn_client) |
| 39 | |
| 40 | # ---------------------------------------------------- |
| 41 | # ROW 2: Address Info (IP Input & Port Input) |
| 42 | # ---------------------------------------------------- |
| 43 | var row_address = HBoxContainer.new() |
| 44 | row_address.add_theme_constant_override("separation", 15) |
| 45 | main_stack.add_child(row_address) |
| 46 | |
| 47 | var ip_input = LineEdit.new() |
| 48 | ip_input.text = engine.server_ip |
| 49 | ip_input.placeholder_text = "Target Server IP" |
| 50 | ip_input.custom_minimum_size = Vector2(180, 35) |
| 51 | row_address.add_child(ip_input) |
| 52 | |
| 53 | var port_input = LineEdit.new() |
| 54 | port_input.text = str(engine.port_number) |
| 55 | port_input.placeholder_text = "Port" |
| 56 | port_input.custom_minimum_size = Vector2(100, 35) |
| 57 | row_address.add_child(port_input) |
| 58 | |
| 59 | # ---------------------------------------------------- |
| 60 | # ROW 3: Security & Utility (Passphrase, Generate, Copy) |
| 61 | # ---------------------------------------------------- |
| 62 | var row_security = HBoxContainer.new() |
| 63 | row_security.add_theme_constant_override("separation", 15) |
| 64 | main_stack.add_child(row_security) |
| 65 | |
| 66 | var key_input = LineEdit.new() |
| 67 | key_input.text = engine.secret_key |
| 68 | key_input.secret = true |
| 69 | key_input.placeholder_text = "Shared Secret Key Passphrase" |
| 70 | key_input.custom_minimum_size = Vector2(300, 35) |
| 71 | row_security.add_child(key_input) |
| 72 | |
| 73 | var btn_generate = Button.new() |
| 74 | btn_generate.text = "New Key" |
| 75 | btn_generate.custom_minimum_size = Vector2(0, 35) |
| 76 | btn_generate.pressed.connect(func(): _on_generate_key(engine, key_input)) |
| 77 | row_security.add_child(btn_generate) |
| 78 | |
| 79 | var btn_copy = Button.new() |
| 80 | btn_copy.text = "Copy Key" |
| 81 | btn_copy.custom_minimum_size = Vector2(0, 35) |
| 82 | btn_copy.pressed.connect(func(): engine.copy_key_to_clipboard()) |
| 83 | row_security.add_child(btn_copy) |
| 84 | |
| 85 | # ---------------------------------------------------- |
| 86 | # ROW 4: Manual Sync Input |
| 87 | # ---------------------------------------------------- |
| 88 | var row_input = HBoxContainer.new() |
| 89 | row_address.add_theme_constant_override("separation", 15) |
| 90 | main_stack.add_child(row_input) |
| 91 | |
| 92 | var line_edit = LineEdit.new() |
| 93 | line_edit.custom_minimum_size = Vector2(400, 40) |
| 94 | line_edit.placeholder_text = "Type and press Enter to securely sync..." |
| 95 | # Wire the UI input directly to the engine's RPC method using encryption |
| 96 | line_edit.text_submitted.connect(func(new_text): engine.receive_secure_clipboard(engine.encrypt_string(new_text))) |
| 97 | row_input.add_child(line_edit) |
| 98 | |
| 99 | # ---------------------------------------------------- |
| 100 | # ROW 5: Status Panel (Replaces draw_rect entirely) |
| 101 | # ---------------------------------------------------- |
| 102 | var row_status = HBoxContainer.new() |
| 103 | row_status.add_theme_constant_override("separation", 15) |
| 104 | main_stack.add_child(row_status) |
| 105 | |
| 106 | var status_card = PanelContainer.new() |
| 107 | status_card.custom_minimum_size = Vector2(400, 80) |
| 108 | status_card.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN |
| 109 | |
| 110 | var card_padding = MarginContainer.new() |
| 111 | card_padding.add_theme_constant_override("margin_left", 30) |
| 112 | card_padding.add_theme_constant_override("margin_right", 30) |
| 113 | card_padding.add_theme_constant_override("margin_top", 15) |
| 114 | card_padding.add_theme_constant_override("margin_bottom", 15) |
| 115 | |
| 116 | status_card.add_child(card_padding) |
| 117 | |
| 118 | var status_label = RichTextLabel.new() |
| 119 | status_label.text = "Loading..." |
| 120 | status_label.selection_enabled = true |
| 121 | status_label.add_theme_font_size_override("font_size", 18) |
| 122 | status_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL |
| 123 | card_padding.add_child(status_label) |
| 124 | |
| 125 | # StyleBoxFlat to mimic your old draw_rect background |
| 126 | var custom_style = StyleBoxFlat.new() |
| 127 | custom_style.bg_color = Color(0.13, 0.13, 0.13, 1.0) |
| 128 | custom_style.set_corner_radius_all(4) |
| 129 | status_card.add_theme_stylebox_override("panel", custom_style) |
| 130 | |
| 131 | main_stack.add_child(status_card) |
| 132 | |
| 133 | # Listen for engine status updates and wire them to the label |
| 134 | engine.status_changed.connect(func(new_status_text): _update_status_label(status_label, new_status_text)) |
| 135 | |
| 136 | # -- Static Helper Functions for UI Wiring -- |
| 137 | |
| 138 | static func _on_start_server_pressed(engine: Node) -> void: |
| 139 | # Reads current properties. In a real app you might pass inputs as arguments instead. |
| 140 | engine.start_server(int(engine.port_number)) |
| 141 | |
| 142 | static func _on_start_client_pressed(engine: Node) -> void: |
| 143 | engine.start_client(str(engine.server_ip), int(engine.port_number)) |
| 144 | |
| 145 | static func _on_generate_key(engine: Node, key_input: LineEdit) -> void: |
| 146 | var new_key = engine.generate_random_key(16) |
| 147 | engine.secret_key = new_key |
| 148 | key_input.text = new_key |
| 149 | |
| 150 | static func _update_status_label(label: RichTextLabel, text: String) -> void: |
| 151 | label.text = text |
| 152 | # Calculate dynamic color state based on connection status |
| 153 | var target_color: Color = Color.GREEN |
| 154 | if "Disconnected" in text or "Offline" in text: |
| 155 | target_color = Color.YELLOW |
| 156 | elif "Reconnecting" in text: |
| 157 | target_color = Color.ORANGE |
| 158 | |
| 159 | label.add_theme_color_override("default_color", target_color) |
| 160 |