Godot Version
4.7
Question
I’m kinda confused ass to why or how this is happening, but the title says it, I’m trying to recreate a “fake OS” for a game, and so far so good, but i had to make a custom window since the window node can’t have custom styles
I’ve managed to implement the basic of the ui (dragging from the top, resizing from a little icon on the bottom right, close, hide, minimize/maximize) this is what i have so far
Now this is where the issue comes in you see the UI inside the window (the items and then the button)? that UI won’t accept any mouse input nothing at all i made a signal to detect whether the mouse enter it but nothing
The window itself is just a script and through it i assemble the UI in the _ready() function i’m sure i set all the ui filter mode to pass, this is how the scene tree looks relative to the image above:
Base window is just the window with nothing and then scroll container have all of the labels and the button as seen in the image above
This is the code for the base window (without any ui added):
@tool
class_name BaseWindow extends Panel
@export var window_name: String = "Window"
@export var resize_image: Texture2D
@export var window_icon: Texture2D
var ui_container: Control
var window_title: Label
var header_panel: Panel
var resize_icon: TextureRect
var close_btn: TextureButton
var minimize_btn: TextureButton
var hide_tab_btn: TextureButton
var pickup_initial_position: Vector2 = Vector2.ZERO
var mouse_pos: Vector2 = Vector2.ZERO
var is_holding_resize: bool = false
var is_grabbed: bool = false
var is_focused: bool = true
var is_minimized: bool = true
const MINIMUM_SIZE: Vector2 = Vector2(300, 100)
const HEADER_MINIMUM_SIZE: Vector2 = Vector2(MINIMUM_SIZE.x, 40)
const BTN_MINIMUM_SIZE: Vector2 = Vector2(32, 32)
const BTN_CONTAINER_OFFSET: float = -112.0
const HEADER_STYLEBOX: StyleBoxTexture = preload("uid://cdip1tf3mffjj")
const HEADER_STYLEBOX_UNFOCUSED: StyleBoxTexture = preload("uid://c4xogvurfn8e3")
const CLOSE_BTN_STATES: ButtonStates = preload("uid://q4jcid8euesy")
const MINI_BTN_STATES: ButtonStates = preload("uid://bsbc206hb24vf")
const HIDE_BTN_STATES: ButtonStates = preload("uid://bbkkv7mr5opoq")
#======================================================#
func _ready() -> void:
create_scene()
func create_scene() -> void:
clip_contents = true
custom_minimum_size = MINIMUM_SIZE
pivot_offset_ratio = Vector2(0.5, 0.5)
var resize_icon_node_inst: TextureRect = TextureRect.new()
resize_icon_node_inst.texture = resize_image
resize_icon_node_inst.set_anchors_preset(Control.PRESET_BOTTOM_RIGHT)
resize_icon_node_inst.set_anchor_and_offset(SIDE_LEFT, 1, -28)
resize_icon_node_inst.set_anchor_and_offset(SIDE_TOP, 1, -28)
resize_icon = resize_icon_node_inst
add_child(resize_icon_node_inst)
var vBoxContainer: VBoxContainer = VBoxContainer.new()
vBoxContainer.set_anchors_preset(Control.PRESET_FULL_RECT)
var panel: Panel = Panel.new()
panel.custom_minimum_size = HEADER_MINIMUM_SIZE
panel.mouse_filter = Control.MOUSE_FILTER_PASS
panel.add_theme_stylebox_override("panel", HEADER_STYLEBOX)
header_panel = panel
vBoxContainer.add_child(panel)
#==================== Title Label + Icons ===================#
var title_container: HBoxContainer = HBoxContainer.new()
title_container.set_anchors_preset(Control.PRESET_CENTER_LEFT)
title_container.grow_vertical = Control.GROW_DIRECTION_BOTH
title_container.set_anchor_and_offset(SIDE_LEFT, 1, 5)
var window_icon_node: TextureRect = TextureRect.new()
window_icon_node.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
window_icon_node.texture = window_icon
window_icon_node.custom_minimum_size = Vector2(24, 24)
var title_lbl: Label = Label.new()
title_lbl.add_theme_color_override("font_color", Color.WHITE)
title_lbl.text = window_name
title_container.add_child(window_icon_node)
title_container.add_child(title_lbl)
#==================== Buttons Label + Icons ===================#
var btns_container: HBoxContainer = HBoxContainer.new()
btns_container.set_anchors_preset(Control.PRESET_CENTER_RIGHT)
btns_container.grow_vertical = Control.GROW_DIRECTION_BOTH
btns_container.grow_horizontal = Control.GROW_DIRECTION_BOTH
btns_container.set_anchor_and_offset(SIDE_RIGHT, 1, BTN_CONTAINER_OFFSET)
var quit_btn: TextureButton = TextureButton.new()
quit_btn.stretch_mode = TextureButton.STRETCH_SCALE
quit_btn.custom_minimum_size = BTN_MINIMUM_SIZE
quit_btn.texture_normal = CLOSE_BTN_STATES.button_normal
quit_btn.texture_hover = CLOSE_BTN_STATES.button_normal
quit_btn.texture_pressed = CLOSE_BTN_STATES.button_pressed
quit_btn.texture_disabled = CLOSE_BTN_STATES.button_disabled
quit_btn.pressed.connect(_on_quit_window_btn_pressed)
close_btn = quit_btn
var mini_btn: TextureButton = TextureButton.new()
mini_btn.stretch_mode = TextureButton.STRETCH_SCALE
mini_btn.custom_minimum_size = BTN_MINIMUM_SIZE
mini_btn.texture_normal = MINI_BTN_STATES.button_normal
mini_btn.texture_hover = MINI_BTN_STATES.button_normal
mini_btn.texture_pressed = MINI_BTN_STATES.button_pressed
mini_btn.texture_disabled = MINI_BTN_STATES.button_disabled
mini_btn.pressed.connect(_on_minimize_btn_pressed)
minimize_btn = mini_btn
var hide_btn: TextureButton = TextureButton.new()
hide_btn.stretch_mode = TextureButton.STRETCH_SCALE
hide_btn.custom_minimum_size = BTN_MINIMUM_SIZE
hide_btn.texture_normal = HIDE_BTN_STATES.button_normal
hide_btn.texture_hover = HIDE_BTN_STATES.button_normal
hide_btn.texture_pressed = HIDE_BTN_STATES.button_pressed
hide_btn.texture_disabled = HIDE_BTN_STATES.button_disabled
hide_btn.pressed.connect(_on_hide_tab_btn_pressed)
hide_tab_btn = hide_btn
btns_container.add_child(hide_btn)
btns_container.add_child(mini_btn)
btns_container.add_child(quit_btn)
#==============================================================#
panel.add_child(title_container)
panel.add_child(btns_container)
#var scroll_cont: ScrollContainer = ScrollContainer.new()
#scroll_cont.size_flags_vertical = Control.SIZE_EXPAND_FILL
#scroll_cont.size_flags_horizontal = Control.SIZE_EXPAND_FILL
#
#var margin_node: MarginContainer = MarginContainer.new()
#margin_node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
#margin_node.size_flags_vertical = Control.SIZE_EXPAND_FILL
#margin_node.add_theme_constant_override("margin_left", 15)
#margin_node.add_theme_constant_override("margin_right", 15)
#margin_node.add_theme_constant_override("margin_top", 15)
#margin_node.add_theme_constant_override("margin_bottom", 15)
#
#ui_container = margin_node
#scroll_cont.add_child(margin_node)
#
#vBoxContainer.add_child(scroll_cont)
vBoxContainer.mouse_filter = Control.MOUSE_FILTER_PASS
add_child(vBoxContainer)
func _physics_process(_delta: float) -> void:
if not Engine.is_editor_hint():
mouse_pos = get_global_mouse_position()
if not is_holding_resize:
_handel_panel_placement()
_resize_panel()
_set_focus_state()
func _set_focus_state() -> void:
if Input.is_action_just_pressed("mouse_1"):
is_focused = get_global_rect().has_point(mouse_pos)
if is_focused or is_holding_resize:
header_panel.add_theme_stylebox_override("panel", HEADER_STYLEBOX)
z_index = 1
else:
header_panel.add_theme_stylebox_override("panel", HEADER_STYLEBOX_UNFOCUSED)
z_index = 0
func _handel_panel_placement() -> void:
var viewport_size: Vector2 = get_viewport_rect().size
if Input.is_action_pressed("mouse_1"):
if header_panel.get_global_rect().has_point(mouse_pos):
is_grabbed = true
if pickup_initial_position == Vector2.ZERO:
pickup_initial_position = mouse_pos - global_position
else:
is_grabbed = false
pickup_initial_position = Vector2.ZERO
if is_grabbed:
global_position = mouse_pos - pickup_initial_position
global_position = global_position.clamp(Vector2.ZERO, viewport_size - Vector2(50,header_panel.size.y))
func _resize_panel() -> void:
if Input.is_action_pressed("mouse_1"):
if resize_icon.get_global_rect().has_point(mouse_pos):
is_holding_resize = true
if Input.is_action_just_released("mouse_1") and is_holding_resize:
is_holding_resize = false
if is_holding_resize and mouse_pos > global_position:
var actual_size: Vector2 = mouse_pos - global_position
size = (get_minimum_size() + actual_size.abs())
header_panel.size.x = size.x
func _on_quit_window_btn_pressed() -> void:
hide()
func _on_hide_tab_btn_pressed() -> void:
hide()
func _on_minimize_btn_pressed() -> void:
if not is_minimized:
# make minimized
global_position = (size / 2)- MINIMUM_SIZE/2
size = MINIMUM_SIZE
is_minimized = true
else:
# make fullscreen
global_position = Vector2.ZERO
size = get_parent().size
is_minimized = false
I’ve also tried using the misc tab in the debugger but it dosen’t detect the scroll container:
Right here i clicked in the center which should show the scroll container node but it only detect the VBoxContainer that was created in the _ready() function when the window panel was added
I have no idea why this happens or how, so i hope i didn’t hit an engine limitation or something




