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)