class_name FloatingWindow extends Window ## Emitted when the window's position or size changes, or when it's closed. signal data_changed var window_content: Control var prevent_data_erasure := false var _is_initialized := false func _init(content: Control, data := {}) -> void: window_content = content title = window_content.name name = window_content.name min_size = window_content.get_minimum_size() unresizable = false wrap_controls = true always_on_top = true ready.connect(_deserialize.bind(data)) func _ready() -> void: set_deferred(&"size", Vector2(300, 300)) await get_tree().process_frame await get_tree().process_frame if get_tree().current_scene.get_window().gui_embed_subwindows: position = DisplayServer.window_get_size() / 2 - size / 2 else: position = DisplayServer.screen_get_usable_rect().size / 2 - size / 2 func _input(event: InputEvent) -> void: if event is InputEventMouse: # Emit `data_changed` when the window is being moved. if not window_content.get_rect().has_point(event.position) and _is_initialized: data_changed.emit(name, serialize()) func serialize() -> Dictionary: return {"size": size, "position": position} func _deserialize(data: Dictionary) -> void: window_content.get_parent().remove_child(window_content) window_content.visible = true window_content.global_position = Vector2.ZERO add_child(window_content) size_changed.connect(window_size_changed) if "position" in data: await get_tree().process_frame await get_tree().process_frame position = data["position"] if "size" in data: set_deferred(&"size", data["size"]) _is_initialized = true func window_size_changed() -> void: window_content.size = size window_content.position = Vector2.ZERO if _is_initialized: data_changed.emit(name, serialize()) func destroy() -> void: size_changed.disconnect(window_size_changed) queue_free() func _exit_tree() -> void: if _is_initialized and !prevent_data_erasure: data_changed.emit(name, {})