79 lines
2.9 KiB
GDScript
79 lines
2.9 KiB
GDScript
@tool
|
|
extends VBoxContainer
|
|
|
|
## Dock subpanel — port-change escape hatch surfaced inside the spawn-failure
|
|
## crash panel when the HTTP port is contested (PORT_EXCLUDED, FOREIGN_PORT).
|
|
## Emits `port_apply_requested(new_port)` after range-validation; the dock
|
|
## handles writing the EditorSetting and reloading the plugin.
|
|
##
|
|
## Extracted from mcp_dock.gd as part of audit-v2 #360 — see the comment at
|
|
## the top of mcp_dock.gd for the broader extraction story.
|
|
|
|
const ClientConfigurator := preload("res://addons/godot_ai/client_configurator.gd")
|
|
|
|
signal port_apply_requested(new_port: int)
|
|
|
|
var _spinbox: SpinBox
|
|
|
|
|
|
## Build the UI synchronously here so callers (and detached-tree tests that
|
|
## instantiate the dock with `McpDockScript.new()` and never enter the tree)
|
|
## can interact with the panel's controls right after `setup()`. Mirrors the
|
|
## pre-extraction inline-build behavior that test_dock.gd relies on.
|
|
##
|
|
## Idempotent: `_spinbox == null` covers an unlikely double-`setup()` call
|
|
## without rebuilding (which would orphan the prior controls).
|
|
func setup() -> void:
|
|
if _spinbox == null:
|
|
_build_ui()
|
|
|
|
|
|
func _build_ui() -> void:
|
|
add_theme_constant_override("separation", 4)
|
|
visible = false
|
|
|
|
var picker_row := HBoxContainer.new()
|
|
picker_row.add_theme_constant_override("separation", 6)
|
|
|
|
_spinbox = SpinBox.new()
|
|
_spinbox.min_value = ClientConfigurator.MIN_PORT
|
|
_spinbox.max_value = ClientConfigurator.MAX_PORT
|
|
_spinbox.step = 1
|
|
_spinbox.value = ClientConfigurator.http_port()
|
|
_spinbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
picker_row.add_child(_spinbox)
|
|
|
|
var apply_btn := Button.new()
|
|
apply_btn.text = "Apply + Reload"
|
|
apply_btn.tooltip_text = (
|
|
"Saves godot_ai/http_port to Editor Settings and reloads the plugin so"
|
|
+ " the server spawns on the new port."
|
|
)
|
|
apply_btn.pressed.connect(_on_apply_pressed)
|
|
picker_row.add_child(apply_btn)
|
|
|
|
add_child(picker_row)
|
|
|
|
|
|
## Re-seed the spinbox with a fresh suggestion every time the panel surfaces,
|
|
## so a stale value from a previous spawn-failure round can't carry over. Note
|
|
## that this OVERWRITES any unsaved user input — fine in practice because the
|
|
## dock's `_update_crash_panel` only calls this on `server_status` transitions
|
|
## (`if server_status == _last_server_status: return` short-circuit), so a
|
|
## user typing into the spinbox between transitions keeps their value. If the
|
|
## state flips while the picker is visible (e.g. `PORT_EXCLUDED` → `FOREIGN_PORT`),
|
|
## the in-flight edit is clobbered — accept that, the suggestion is more current.
|
|
func seed_suggested_port() -> void:
|
|
if _spinbox == null:
|
|
return
|
|
_spinbox.value = ClientConfigurator.suggest_free_port(
|
|
ClientConfigurator.http_port() + 1
|
|
)
|
|
|
|
|
|
func _on_apply_pressed() -> void:
|
|
var new_port: int = int(_spinbox.value)
|
|
if new_port < ClientConfigurator.MIN_PORT or new_port > ClientConfigurator.MAX_PORT:
|
|
return
|
|
port_apply_requested.emit(new_port)
|