Why did my left click become right-click godot 4.3

Godot 4.3

Help I’m really stuck. Left click become right-click when resolution change.
Here some scripts.

extends Control

@warning_ignore("UNUSED_SIGNAL")
signal video_confirmed
@warning_ignore("UNUSED_SIGNAL")
signal popup_closed

# ⇨ LINE A: Referenca na UI elemente
@onready var label_full_screen = $Panel/HBoxContainer/VBoxContainerLabels/LabelFullScreen
@onready var label_borderless = $Panel/HBoxContainer/VBoxContainerLabels/LabelBorderless
@onready var label_v_sync = $Panel/HBoxContainer/VBoxContainerLabels/LabelVSync
@onready var label_scr_res = $Panel/HBoxContainer/VBoxContainerLabels/LabelScrRes
@onready var label_scr_settings = $Panel/LabelScrSettings
@onready var button_ok = $Panel/ButtonOk

@onready var check_box_full_scr = $Panel/HBoxContainer/VBoxContainerCheckBoxes/CheckBoxFullScr
@onready var check_box_borderless = $Panel/HBoxContainer/VBoxContainerCheckBoxes/CheckBoxBorderless
@onready var option_button_v_sync = $Panel/HBoxContainer/VBoxContainerCheckBoxes/OptionButtonVSync
@onready var option_button_resolution = $Panel/HBoxContainer/VBoxContainerCheckBoxes/OptionButtonResolution

# ⇨ LINE B: Eksterni elementi (iz glavne scene)
@export var fullscreen : CheckBox
@export var borderless : CheckBox
@export var vsync : OptionButton
@export var resolutions : OptionButton

var config := ConfigFile.new()

# ⇨ LINE C: Lokalizacija (teksti)
var translations = {
	"en": ["FULL SCREEN", "BORDERLESS", "VERT.SYNCH.", "SCREEN RES.", "SCREEN SETTINGS", "OK"],
	"sr": ["ЦЕО ЕКРАН", "БЕЗ ОКВИРА", "ВЕРТ.СИНХ.", "РЕЗ.ЕКРАНА", "ПОДЕШАВАЊА ЕКРАНА", "УРЕДУ"],
	"cmn": ["全屏", "无边框", "垂直同步", "屏幕分辨率", "屏幕设置", "确定"],
	"ar": ["شاشة كاملة", "بلا حدود", "المزامنة الرأسية", "دقة الشاشة", "إعدادات الشاشة", "موافق"]
}

var vsync_translations = {
	"en": ["DISABLED", "ENABLED", "ADAPTIVE", "MAILBOX"],
	"sr": ["ИСКЉУЧЕНО", "УКЉУЧЕНО", "АДАПТИВНО", "ПОШТАНСКО САНДУЧЕ"],
	"cmn": ["禁用", "启用", "自适应", "邮箱"],
	"ar": ["معطل", "مفعل", "تكيفي", "صندوق البريد"]
}

# ⇨ LINE D: Inicijalizacija
func _ready():




	_test_mouse_filter_validnosti()  # 🧪 Poziva test

	set_visible_safe_recursive(false)  # popup startuje sakriven

	# Postavi tekst po jeziku
	var lm = get_node_or_null("/root/LanguageManager")
	if lm:
		_set_language_text(lm.current_language)

	if has_node("Panel"):
		$Panel.layout_direction = 0

	# Učitaj prethodne vrednosti iz konfiguracije
	if config.load("user://settings.cfg") == OK:
		check_box_full_scr.button_pressed = config.get_value("video", "fullscreen", false)
		check_box_borderless.button_pressed = config.get_value("video", "borderless", false)
		var vsync_index = config.get_value("video", "vsync", 0)
		option_button_v_sync.select(vsync_index)
		DisplayServer.window_set_vsync_mode(vsync_index)

		var res_key = config.get_value("video", "resolution", "1152x648")
		if res_key in ScreenResolutions.resolutions:
			get_window().size = ScreenResolutions.resolutions[res_key]
			ScreenResolutions.center_window()
			for i in range(option_button_resolution.item_count):
				if option_button_resolution.get_item_text(i) == res_key:
					option_button_resolution.select(i)
					break

	add_resolution()            # ⇨ LINE E
	update_button_values()      # ⇨ LINE F

	option_button_v_sync.focus_entered.connect(_on_option_button_v_sync_opened)
	option_button_resolution.focus_entered.connect(_on_option_button_resolution_opened)


	# Popuni listu dostupnih rezolucija
	#for res in ScreenResolutions.resolutions.keys():
		#option_button_resolution.add_item(res)

	option_button_resolution.item_selected.connect(on_resolution_selected)


	await get_tree().process_frame
	update_button_interactivity_based_on_size()

	# Opcionalno: centriraj dugme pri pokretanju
	await get_tree().process_frame  # Sačekaj 1 frame da svi čvorovi budu spremni

	var screen_size = get_viewport_rect().size

	for button in get_tree().get_nodes_in_group("interactive_buttons"):
		if button is Button:
			button.position = (screen_size - button.size) / 2  # centriraj (ili primeni tvoju logiku)



func _input(event):
	if event is InputEventMouseButton and event.pressed:
		var click_pos = event.position

		for button in get_tree().get_nodes_in_group("ui"):
			if button.get_global_rect().has_point(click_pos):
				print("Kliknuto na:", button.name)



func on_resolution_selected(index: int):
	var key = option_button_resolution.get_item_text(index)
	get_window().size = ScreenResolutions.resolutions[key]

	await get_tree().process_frame
	queue_redraw()

	# Osvježi mouse_filter u glavnom meniju (ako postoji)
	var main_menu = get_tree().root.get_node_or_null("MainMenu")
	if main_menu:
		main_menu.refresh_ui_mouse_filters()
		
# ⇨ LINE E: Dodavanje rezolucija u dropdown
func add_resolution():
	option_button_resolution.clear()
	var screen_res = get_node_or_null("/root/ScreenResolutions")
	if screen_res:
		for res in screen_res.resolutions.keys():
			option_button_resolution.add_item(res)

# ⇨ LINE F: Ažuriranje UI vrednosti i povezivanje sa menjačem jezika
func update_button_values():
	var current_res = str(get_window().size.x, "x", get_window().size.y)
	var idx = ScreenResolutions.resolutions.keys().find(current_res)
	option_button_resolution.selected = idx



# ⇨ LINE G: Jezičke funkcije
func _on_language_changed(new_lang):
	_set_language_text(new_lang)

func _set_language_text(lang_code: String):
	if translations.has(lang_code):
		var texts = translations[lang_code]
		label_full_screen.text = texts[0]
		label_borderless.text = texts[1]
		label_v_sync.text = texts[2]
		label_scr_res.text = texts[3]
		label_scr_settings.text = texts[4]
		button_ok.text = texts[5]
	_update_vsync_options(lang_code)  # ⇨ LINE H

# ⇨ LINE H: Lokalizacija VSync opcija
func _update_vsync_options(lang_code: String):
	if vsync_translations.has(lang_code):
		var selected = option_button_v_sync.get_selected_id()
		option_button_v_sync.clear()
		for i in range(vsync_translations[lang_code].size()):
			if i <= DisplayServer.VSYNC_ADAPTIVE:
				option_button_v_sync.add_item(vsync_translations[lang_code][i], i)
		option_button_v_sync.select(selected)

# ⇨ LINE I: Potvrda (OK dugme)
func _on_button_ok_pressed():
	emit_signal("popup_closed")
	queue_free()

# ⇨ LINE J: Reakcije na promene checkbox-ova i dropdown-a
func _on_check_box_full_scr_toggled(toggled_on):
	DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN if toggled_on else DisplayServer.WINDOW_MODE_WINDOWED)
	option_button_resolution.disabled = toggled_on
	if not toggled_on:
		var res_key = config.get_value("video", "resolution", "1152x648")
		if res_key in ScreenResolutions.resolutions:
			get_window().size = ScreenResolutions.resolutions[res_key]
			ScreenResolutions.center_window()
			for i in range(option_button_resolution.item_count):
				if option_button_resolution.get_item_text(i) == res_key:
					option_button_resolution.select(i)
					break
	config.set_value("video", "fullscreen", toggled_on)
	save_settings()
	_force_ui_refresh()  # ✅ osveži UI nakon promene


func _on_check_box_borderless_toggled(toggled_on):
	DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_BORDERLESS, toggled_on)
	config.set_value("video", "borderless", toggled_on)
	save_settings()
	_force_ui_refresh()  # ✅ osveži UI nakon promene

func _on_option_button_v_sync_item_selected(index):
	DisplayServer.window_set_vsync_mode(index)
	config.set_value("video", "vsync", index)
	save_settings()

func _on_option_button_resolution_item_selected(index):
	var key = option_button_resolution.get_item_text(index)
	if key in ScreenResolutions.resolutions:
		get_window().size = ScreenResolutions.resolutions[key]
		ScreenResolutions.center_window()
		option_button_resolution.select(index)
		config.set_value("video", "resolution", key)
		save_settings()
		_force_ui_refresh()  # ✅ osveži UI nakon promene

func save_settings():
	config.save("user://settings.cfg")

# ⇨ LINE K: Debug info
func _on_option_button_v_sync_opened():
	print("[VSYNC MENU] Opened")

func _on_option_button_resolution_opened():
	print("[RESOLUTION MENU] Opened")

# ⇨ LINE L: Prikazuje popup (aktivira UI i input)
func show_popup():
	set_visible_safe_recursive(true)  # ⇨ LINE M
	button_ok.grab_focus()
	button_ok.mouse_filter = Control.MOUSE_FILTER_STOP



func update_button_interactivity_based_on_size(node: Node = self) -> void:
	if node is Button:
		var size = node.size
		var is_visible = size.x > 1 and size.y > 1

		if is_visible:
			node.mouse_filter = Control.MOUSE_FILTER_STOP
			node.focus_mode = Control.FOCUS_ALL
		else:
			node.mouse_filter = Control.MOUSE_FILTER_IGNORE
			node.focus_mode = Control.FOCUS_NONE

		# Debug (uključi po potrebi)
		print("🛠️ Dugme: ", node.name, " | Size: ", size, " | Interaktivno: ", is_visible)

	for child in node.get_children():
		update_button_interactivity_based_on_size(child)



# ⇨ LINE M: Postavlja vidljivost i interaktivnost
func set_visible_safe_recursive(video_visible: bool) -> void:
	if not video_visible:
		release_focus()
	self.visible = video_visible
	_set_interaction_recursive(self, video_visible)  # ⇨ LINE N

# ⇨ LINE N: Rekurzivna interaktivnost
func _set_interaction_recursive(node: Node, enable: bool) -> void:
	if node is Control:
		node.mouse_filter = Control.MOUSE_FILTER_STOP if enable else Control.MOUSE_FILTER_IGNORE
		node.focus_mode = Control.FOCUS_ALL if enable else Control.FOCUS_NONE
		if not enable:
			node.release_focus()

		# Dodato: Ako dugmad imaju pogrešan mouse_filter, popravi ih ručno
		if node is Button and enable:
			node.mouse_filter = Control.MOUSE_FILTER_STOP

	for child in node.get_children():
		_set_interaction_recursive(child, enable)

# ⇨ LINE O: Zatvara popup
func hide_popup():
	emit_signal("popup_closed")
	queue_free()

# ✅ DODATO: Privremeni debug – vizuelni fokus za ButtonOK, CheckBoxes i OptionButtons
func _process(_delta):
	# OK dugme – bela kad ima fokus, poluprovidna kad nema
	if button_ok.has_focus():
		button_ok.modulate = Color(1, 1, 1)
	else:
		button_ok.modulate = Color(1, 1, 1, 0.5)

	# CheckBox elementi – žuta kad imaju fokus
	var checkboxes = [check_box_full_scr, check_box_borderless]
	for cb in checkboxes:
		if cb.has_focus():
			cb.modulate = Color(1, 1, 0)  # žuta
		else:
			cb.modulate = Color(1, 1, 1)

	# OptionButton elementi – plava kad imaju fokus
	var options = [option_button_v_sync, option_button_resolution]
	for ob in options:
		if ob.has_focus():
			ob.modulate = Color(0.5, 0.5, 1)  # plava
		else:
			ob.modulate = Color(1, 1, 1)

func _force_ui_refresh():
	await get_tree().process_frame  # sačekaj jedan frame da se prozor postavi

	var window_size = DisplayServer.window_get_size()
	DisplayServer.window_set_size(window_size)  # 🩹 Forsiraj novu veličinu

	DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED)  # 🩹 GPU refresh

	# Repozicioniraj centriranjem ako treba
	if Engine.has_singleton("ScreenResolutions"):
		ScreenResolutions.center_window()

	# Forsiraj layout refresh
	queue_redraw()  # Godot 4.2+

	# Refokusiraj aktivnu kontrolu
	if is_instance_valid(button_ok):
		button_ok.grab_focus()


# 🧪 Testira sve Control node-ove da li imaju ispravno postavljen mouse_filter
func _test_mouse_filter_validnosti(node: Node = self) -> void:
	if node is Control:
		if node.mouse_filter not in [Control.MOUSE_FILTER_STOP, Control.MOUSE_FILTER_IGNORE]:
			print("⚠️ Neispravan mouse_filter na: ", node.name, " (", node.mouse_filter, ")")

	for child in node.get_children():
		_test_mouse_filter_validnosti(child)

As close as I could get to a solution. But clickable surface of a buttons is not on precise position.

settings 

extends CanvasLayer

# ⚙️ Glavni meni za podešavanja

# ✅ Signal koji obaveštava kada su podešavanja potvrđena
@warning_ignore("UNUSED_SIGNAL")
signal settings_confirmed

# 🏷️ UI elementi
@onready var label_settings = $DebugOverlay/Panel/LabelSettings

@onready var button_video = $DebugOverlay/Panel/Panel/VBoxContainer/ButtonVideo
@onready var button_audio = $DebugOverlay/Panel/Panel/VBoxContainer/ButtonAudio
@onready var button_keys = $DebugOverlay/Panel/Panel/VBoxContainer/ButtonKeys
@onready var button_quit = $DebugOverlay/Panel/Panel/VBoxContainer/ButtonQuit
@onready var button_load = $DebugOverlay/Panel/Panel/VBoxContainer/ButtonLoad

@onready var button_back_to_main = $DebugOverlay/Panel/Panel2/ButtonBackToMain

@onready var debug_overlay = $DebugOverlay



# 🌐 Višejezični prevodi
var translations = {
	"en": ["SETTINGS", "VIDEO SETTINGS", "AUDIO SETTINGS", "CONTROL KEYS", "QUIT>ESC", "BACK TO MENU", "LOAD SAVED"],
	"sr": ["ПОДЕШАВАЊА", "ЕКРАН", "ЗВУК", "ДУГМАД ЗА КОНТРОЛУ", "ОДУСТАНИ>ESC", "НАЗАД У МЕНИ", "УЧИТАЈ САЧУВАНО"],
	"cmn": ["设置", "视频设置", "音频设置", "控制键", "退出>ESC", "返回菜单", "加载已保存"],
	"ar": ["الإعدادات", "إعدادات الفيديو", "إعدادات الصوت", "أزرار التحكم", "إلغاء>ESC", "العودة إلى القائمة", "تحميل المحفوظ"]
}

# 🔒 Stati za popup-ove
var is_quit_popup_open := false
var is_video_popup_open := false
var is_audio_popup_open := false
var is_control_popup_open := false

@export var return_to_scene: String = "" # autloa briši posle 2 u 1 scene 

# 🚀 Inicijalizacija scene
func _ready():


	_test_mouse_filter_validnosti()  # 🧪 Poziva test
	validate_button_focus_modes()

	fix_control_properties(self)


	print("SETTINGS scena učitana.")


	_set_language_text(LanguageManager.current_language)

	var lm = get_node_or_null("/root/LanguageManager")
	if lm:
		lm.language_changed.connect(_set_language_text)

	if has_node("Panel"):
		$Panel.layout_direction = 0

	emit_signal("settings_confirmed")  # Obaveštava da je scena spremna
	set_controls_enabled(true)

	# 🎯 Postavi fokus na BACK dugme
	button_back_to_main.grab_focus()


	await get_tree().process_frame
	update_button_interactivity_based_on_size()


	button_video.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	button_audio.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	button_keys.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	button_quit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	button_back_to_main.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	button_load.size_flags_horizontal = Control.SIZE_EXPAND_FILL


	force_layout_refresh()
	await get_tree().process_frame
	fix_buttons_in_vbox($DebugOverlay/Panel/Panel/VBoxContainer)

	adjust_ui_scaling(get_node("DebugOverlay/Panel/Panel/VBoxContainer/ButtonQuit"))

func force_layout_refresh():
	await get_tree().process_frame  # Sačekaj jedan frame
	var container = $DebugOverlay/Panel/Panel/VBoxContainer
	container.queue_sort()



func fix_buttons_in_vbox(container: VBoxContainer) -> void:
	for child in container.get_children():
		if child is Button:
			child.size_flags_horizontal = Control.SIZE_EXPAND
			child.size_flags_vertical = Control.SIZE_FILL
			child.focus_mode = Control.FOCUS_ALL
			child.mouse_filter = Control.MOUSE_FILTER_STOP


func print_button_sizes(node: Node = self):
	for child in node.get_children():
		if child is Button:
			print("📏 Dugme ", child.name, " size: ", child.size)
		print_button_sizes(child)



func adjust_ui_scaling(node: Node) -> void:
	if node is Control:
		# Postavi Full Rect samo ako roditelj nije layout container
		var parent := node.get_parent()
		var parent_is_layout := parent is VBoxContainer or parent is HBoxContainer or parent is GridContainer or parent is MarginContainer

		if not parent_is_layout:
			node.anchor_left = 0
			node.anchor_top = 0
			node.anchor_right = 1
			node.anchor_bottom = 1
			node.offset_left = 0
			node.offset_top = 0
			node.offset_right = 0
			node.offset_bottom = 0

		# Ako je dugme – postavi veličinu, fokus i input
		if node is Button:
			node.size_flags_horizontal = Control.SIZE_EXPAND
			node.size_flags_vertical = Control.SIZE_FILL
			node.focus_mode = Control.FOCUS_ALL
			node.mouse_filter = Control.MOUSE_FILTER_STOP

		# Ako je VBox/HBox/GridContainer – omogući širenje elemenata
		if node is BoxContainer or node is GridContainer:
			node.size_flags_horizontal = Control.SIZE_EXPAND
			node.size_flags_vertical = Control.SIZE_EXPAND

	# Rekurzivno idi kroz decu
	for child in node.get_children():
		if child is Node:
			adjust_ui_scaling(child)





# 🌐 Postavi tekst u skladu sa jezikom
func _set_language_text(lang_code: String):
	if translations.has(lang_code):
		var t = translations[lang_code]
		label_settings.text       = t[0]
		button_video.text         = t[1]
		button_audio.text         = t[2]
		button_keys.text          = t[3]
		button_quit.text          = t[4]
		button_back_to_main.text  = t[5]
		button_load.text          = t[6]

# ⌨️ Detekcija ESC komande
func _input(event):
	#if event is InputEventMouseButton:
		#if event.button_index == MOUSE_BUTTON_RIGHT:
			## Stop event from propagating
			#get_viewport().set_input_as_handled()
			#return

	# Tvoj postojeći ESC handler
	if event.is_action_pressed("quit"):
		if is_quit_popup_open or is_video_popup_open or is_audio_popup_open or is_control_popup_open:
			return
		show_quit_popup()

# ⏪ Povratak u glavni meni
func _on_button_back_to_main_pressed():
	#print("Iz SETTINGS se prelazi u MAIN MENU")
	var main = get_node_or_null("/root/MainMenu")
	if main:
		main.show()
#		main.set_controls_enabled(true)
		emit_signal("settings_confirmed")
		queue_free()
	else:
		get_tree().change_scene_to_file("res://Scenes/main_menu.tscn")

# 🧭 Dugmad za podešavanja
func _on_button_video_pressed(): show_video_popup()
func _on_button_audio_pressed(): show_audio_popup()
func _on_button_keys_pressed(): show_control_popup()
func _on_button_quit_pressed():
	#print("ESC pritisnuto (dugme quit) u SETTINGS")
	show_quit_popup()

func _on_quit_confirmed():
	print("Quit potvrđen iz popup-a")
	get_tree().quit()

# ⇨ LINE D: Potvrđen izlazak
func _on_button_yes_pressed():
	emit_signal("quit_confirmed")
	get_tree().quit()

func _on_button_no_pressed():
	hide_popup()  # ⇨ LINE G
	get_tree().paused = false
	emit_signal("popup_closed")

# ⇨ LINE G: Sakriva popup
func hide_popup():
	emit_signal("popup_closed")
	queue_free()

# 🧩 Omogući/onemogući sve kontrole
func set_controls_enabled(enabled: bool) -> void:
	_update_controls_state(self, enabled)

func _update_controls_state(node: Node, enable: bool) -> void:
	if node is Control:
		node.mouse_filter = Control.MOUSE_FILTER_STOP if enable else Control.MOUSE_FILTER_IGNORE
		node.focus_mode = Control.FOCUS_ALL if enable else Control.FOCUS_NONE
		if not enable:
			node.release_focus()

		# Dodato: Ako dugmad imaju pogrešan mouse_filter, popravi ih ručno
		if node is Button and enable:
			node.mouse_filter = Control.MOUSE_FILTER_STOP

	for child in node.get_children():
		_update_controls_state(child, enable)

# ----------------------- POPUP FUNKCIJE -----------------------

func show_quit_popup():
	if is_quit_popup_open:
		return
	var popup = preload("res://Scenes/popup_quit.tscn").instantiate()
	add_child(popup)

	popup.quit_confirmed.connect(_on_quit_confirmed)
	popup.popup_closed.connect(func(): _on_popup_closed("quit"))

	is_quit_popup_open = true
	set_controls_enabled(true)
	popup.show_popup()

func show_video_popup():
	if is_video_popup_open:
		return
	var popup = preload("res://Scenes/popup_video_settings.tscn").instantiate()
	add_child(popup)

	popup.video_confirmed.connect(_on_button_video_pressed)
	popup.popup_closed.connect(func(): _on_popup_closed("video"))

	is_video_popup_open = true
	set_controls_enabled(true)
	popup.show_popup()

func show_audio_popup():
	if is_audio_popup_open:
		return
	var popup = preload("res://Scenes/popup_audio_settings.tscn").instantiate()
	add_child(popup)

	popup.audio_confirmed.connect(_on_button_audio_pressed)
	popup.popup_closed.connect(func(): _on_popup_closed("audio"))

	is_audio_popup_open = true
	set_controls_enabled(true)
	popup.show_popup()

func show_control_popup():
	if is_control_popup_open:
		return
	var popup = preload("res://Scenes/popup_control_keys.tscn").instantiate()
	add_child(popup)

	popup.control_confirmed.connect(_on_button_keys_pressed)
	popup.popup_closed.connect(func(): _on_popup_closed("control"))

	is_control_popup_open = true
	set_controls_enabled(true)
	popup.show_popup()

# 🔁 Resetuje status popup-a nakon zatvaranja
func _on_popup_closed(type := ""):
	match type:
		"quit":    is_quit_popup_open = false
		"video":   is_video_popup_open = false
		"audio":   is_audio_popup_open = false
		"control": is_control_popup_open = false
	set_controls_enabled(true)
	await get_tree().process_frame  # Sačekaj jedan frame da se popup skloni
	button_back_to_main.grab_focus()        # Sad bezbedno vraća fokus


func _on_button_load_pressed():
	DvAuJedaNscene.return_to_scene = "res://Scenes/settings.tscn"
	get_tree().change_scene_to_file("res://Scenes/warning.tscn")


func update_button_interactivity_based_on_size(node: Node = self) -> void:
	if node is Button:
		var size = node.size
		var is_visible = size.x > 1 and size.y > 1

		if is_visible:
			node.mouse_filter = Control.MOUSE_FILTER_STOP
			node.focus_mode = Control.FOCUS_ALL
		else:
			node.mouse_filter = Control.MOUSE_FILTER_IGNORE
			node.focus_mode = Control.FOCUS_NONE

		# Debug (uključi po potrebi)
		print("🛠️ Dugme: ", node.name, " | Size: ", size, " | Interaktivno: ", is_visible)

	for child in node.get_children():
		update_button_interactivity_based_on_size(child)



func fix_control_properties(node: Node = self) -> void:
	if node is Control:
		# 🖱️ Osiguraj da mouse_filter radi za kontrole koje reaguju na klik
		if node is Button:
			node.mouse_filter = Control.MOUSE_FILTER_STOP
			node.focus_mode = Control.FOCUS_ALL
		else:
			# Ostali Control elementi – za svaki slučaj
			if node.mouse_filter == Control.MOUSE_FILTER_IGNORE:
				node.mouse_filter = Control.MOUSE_FILTER_STOP

		# 📐 Size flags za fleksibilan layout
		node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
		node.size_flags_vertical = Control.SIZE_EXPAND_FILL

		# 💡 Debug info
		print("Popravljeno: ", node.name)

	for child in node.get_children():
		fix_control_properties(child)


# 🧪 Testira sve Control node-ove da li imaju ispravno postavljen mouse_filter
func _test_mouse_filter_validnosti(node: Node = self) -> void:
	if node is Control:
		if node.mouse_filter not in [Control.MOUSE_FILTER_STOP, Control.MOUSE_FILTER_IGNORE]:
			print("⚠️ Neispravan mouse_filter na: ", node.name, " (", node.mouse_filter, ")")

	for child in node.get_children():
		_test_mouse_filter_validnosti(child)

func validate_button_focus_modes(node: Node = self) -> void:
	for child in node.get_children():
		if child is Button:
			if child.focus_mode != Control.FOCUS_ALL:
				print("⚠️ Neispravan focus_mode na dugmetu: ", child.name, " (", child.focus_mode, ")")

			# Poveži signale za debug kretanja kursora ako već nisu povezani
			if not child.mouse_entered.is_connected(self._on_button_mouse_entered):
				child.mouse_entered.connect(_on_button_mouse_entered.bind(child))
			if not child.mouse_exited.is_connected(self._on_button_mouse_exited):
				child.mouse_exited.connect(_on_button_mouse_exited.bind(child))
		
		# Rekurzivno proveri decu
		validate_button_focus_modes(child)

# Debug signali
func _on_button_mouse_entered(button: Button) -> void:
	print("🟡 Kursor ušao u dugme: ", button.name)

func _on_button_mouse_exited(button: Button) -> void:
	print("🟠 Kursor izašao iz dugmeta: ", button.name)


func _on_screen_resized():
	print("🔄 Rezolucija promenjena – ažuriram dugmad i layout")
	await get_tree().process_frame
	update_button_interactivity_based_on_size()
	fix_control_properties()

Hi,

That’s a veeeeery long post that probably no one is going to read fully. Your problem seems related to a specific part of your code, so, could you please share only that part?

Sorry for the long also wrong and illegible code. I will try to correct it. Code migrated from godot 4.2.1. It was written by ChatGPT. I barely know how to write a single line of code. If I knew which part of the code is responsible for that it would be great.

I think mistake is here ( somewhere ).

extends AnimatedSprite2D

# --- Podesivi parametri ---
var speed := 200.0 # Brzina kretanja kursora
var last_mouse_pos := Vector2.ZERO # Zadnja pozicija miša

var cursor_position: Vector2 = Vector2.ZERO
var scaled_cursor_position: Vector2 = Vector2.ZERO

const BASE_RESOLUTION := Vector2(1152, 648)
var _scale := Vector2.ONE

# --- Last Action Wins ---
enum InputDevice { MOUSE, KEYBOARD, GAMEPAD }
var last_input_device : InputDevice = InputDevice.MOUSE

var left_pressed := false # Da li je levi "klik" trenutno pritisnut
var right_pressed := false # Da li je desni "klik" trenutno pritisnut

@onready var audio_stream_player = $AudioStreamPlayer # Audio za klik zvuk
@onready var cursor_layer = $".." # Parent node za kursor da bi išao iznad menija

# --- Hover efekat za UI kontrole (test) ---
@onready var sprite := $"." # Sprite koji menja boju na hover
var default_modulate := Color(1, 1, 1) # Originalna boja kursora

# --- Stati za pomoćne funkcije ---
var hovering_ui: bool = false # Da li je kursor iznad UI kontrole
var last_hovered_control: Control = null # (dodaj ovu promenljivu u tvojoj skripti)

# Ažuriraj poziciju kursora kada se promeni veličina prozora
var last_viewport_size = Vector2.ZERO
var simulate_input := false

func _ready():

	_test_mouse_filter_validnosti()  #  Poziva test

	_update_scale()

	# Postavljanje kursora iznad ostalih UI elemenata
	cursor_layer.set_layer(1025)
	
	Input.mouse_mode = Input.MOUSE_MODE_HIDDEN
	cursor_position = Vector2.ZERO
	last_mouse_pos = get_viewport().get_mouse_position()
	last_viewport_size = get_viewport_rect().size # <-- Dodaj ovo
	global_position = cursor_position
	get_window().connect("size_changed", Callable(self, "_on_window_resized"))

func _update_scale():
	var current_size = get_viewport().get_visible_rect().size
	_scale = current_size / BASE_RESOLUTION
	print(" Novi scale:", _scale)

func _on_window_resized():
	var new_size = get_viewport_rect().size
	if last_viewport_size != Vector2.ZERO:
		var _scale = new_size / last_viewport_size
		cursor_position = cursor_position * _scale

	# Nakon skaliranja, opet se osiguraj da kursor ne izađe van ekrana
	cursor_position.x = clamp(cursor_position.x, 0, new_size.x)
	cursor_position.y = clamp(cursor_position.y, 0, new_size.y)
	
	global_position = cursor_position
	
	last_viewport_size = new_size
	
	simulate_hover() # Obnavlja hover da se UI ponovo registruje


func _process(delta):

	# --- Upravljanje kursorom ---
	var direction := Vector2.ZERO

	# Tastatura input
	if Input.is_action_pressed("right"):
		direction.x += 1
	if Input.is_action_pressed("left"):
		direction.x -= 1
	if Input.is_action_pressed("down"):
		direction.y += 1
	if Input.is_action_pressed("up"):
		direction.y -= 1

	# Džojstik input
	direction.x += Input.get_joy_axis(0, JOY_AXIS_LEFT_X)
	direction.y += Input.get_joy_axis(0, JOY_AXIS_LEFT_Y)

	# Ako ima inputa — pomeri
	if direction.length() > 0.1 and last_input_device != InputDevice.MOUSE:
		direction = direction.normalized()
		cursor_position += direction * speed * delta
	else:
		var current_mouse_pos := get_viewport().get_mouse_position()
		if current_mouse_pos != last_mouse_pos:
			cursor_position = current_mouse_pos
			last_mouse_pos = current_mouse_pos

	cursor_position = get_viewport().get_mouse_position()
	scaled_cursor_position = cursor_position * _scale
	position = scaled_cursor_position  # Prikaz kursora na ekranu

	if Input.is_action_just_pressed("jump"):
		_simulate_left_click(cursor_position)

	# Ograničenje kretanja unutar ekrana
	var viewport_rect = get_viewport_rect()
	cursor_position.x = clamp(cursor_position.x, 0, viewport_rect.size.x)
	cursor_position.y = clamp(cursor_position.y, 0, viewport_rect.size.y)

	global_position = cursor_position

	simulate_hover()

	# --- Klik levi dugmić ---
	var is_left_down := (
		Input.is_action_pressed("jump")
		or Input.is_joy_button_pressed(0, JOY_BUTTON_X)
		or Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)
		or Input.is_action_pressed("ui_accept")
	)
	handle_left_input(is_left_down)

	if is_left_down and animation == "LCL" and is_playing() and frame == 3:
		pause()
		audio_stream_player.stop()
	elif not is_left_down and animation == "LCL" and frame == 3 and not is_playing():
		play("LCL")
		play_audio_if_stopped()

	# --- Klik desni dugmić ---
	var is_right_down := (
		Input.is_action_pressed("attack")
		or Input.is_joy_button_pressed(0, JOY_BUTTON_B)
		or Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
	)
	handle_right_input(is_right_down)

	if is_right_down and animation == "RCL" and is_playing() and frame == 3:
		pause()
		audio_stream_player.stop()
	elif not is_right_down and animation == "RCL" and frame == 3 and not is_playing():
		play("RCL")
		play_audio_if_stopped()

	# --- Posebne akcije ---
	if Input.is_action_just_pressed("ui_accept"):
		simulate_mouse_click()

	if Input.is_action_just_pressed("start"):
		print("START pritisnut")
		get_tree().change_scene_to_file("res://Levels/Test/test_level_00.tscn")

	if Input.is_action_just_pressed("pause"):
		print("PAUSE pritisnut")
		get_tree().paused = not get_tree().paused

	# --- Hover efekat za UI (možeš brisati ceo ovaj blok) ---
	var hovered_control = _get_control_under_cursor()
	if hovered_control and hovered_control is OptionButton:
		sprite.modulate = Color(1, 0, 0) # Crvena boja kad je iznad OptionButton
	else:
		sprite.modulate = default_modulate

func _simulate_left_click(pos: Vector2):
	var click_event := InputEventMouseButton.new()
	click_event.button_index = MOUSE_BUTTON_LEFT
	click_event.pressed = true
	click_event.position = pos
	click_event.global_position = pos
	Input.parse_input_event(click_event)

	# Isti za release ako treba
	var release_event := InputEventMouseButton.new()
	release_event.button_index = MOUSE_BUTTON_LEFT
	release_event.pressed = false
	release_event.position = pos
	release_event.global_position = pos
	Input.parse_input_event(release_event)

	print("Simuliran klik na:", pos)

# --- Obrada input događaja za Last Action Wins ---
func _input(event):

	if simulate_input:
		return

	if event is InputEventMouseMotion or event is InputEventMouseButton:
		last_input_device = InputDevice.MOUSE
	elif event is InputEventKey:
		last_input_device = InputDevice.KEYBOARD
	elif event is InputEventJoypadButton or event is InputEventJoypadMotion:
		last_input_device = InputDevice.GAMEPAD

	# --- Uvek sakrij sistemski miš ---
	if Input.mouse_mode != Input.MOUSE_MODE_HIDDEN:
		Input.mouse_mode = Input.MOUSE_MODE_HIDDEN

# --- Input Obrada --- 
func handle_left_input(is_down: bool):
	if is_down and not left_pressed:
		simulate_mouse_click()
		on_left_click()
	left_pressed = is_down

func handle_right_input(is_down: bool):
	if is_down and not right_pressed:
		simulate_mouse_click()
		on_right_click()
	right_pressed = is_down


func on_left_click():
	if not left_pressed:
		print("Left click triggered at:", cursor_position)
		if not is_playing():
			play("LCL")
			print("Pokrećem animaciju LCL")
		play_audio_if_stopped()
	left_pressed = true

func on_right_click():
	if not right_pressed:
		if not is_playing():
			play("RCL")
		play_audio_if_stopped()
	right_pressed = true

# --- Helper funkcije ---
func simulate_mouse_click():
	var control = _get_control_under_cursor()
	# Ako kliknemo na kontrolu, tretiramo normalno
	if control:
		print("Klikujem na:", control.name)

		if control is OptionButton:
			control.show_popup()
			return

		if control is CheckBox:
			control.button_pressed = not control.button_pressed
			control.emit_signal("toggled", control.button_pressed)
			return

		var click_event := InputEventMouseButton.new()
		click_event.position = cursor_position
		click_event.global_position = cursor_position
		click_event.button_index = MOUSE_BUTTON_LEFT
		click_event.pressed = true
		click_event.button_mask = MOUSE_BUTTON_MASK_LEFT
		click_event.double_click = false

		Input.parse_input_event(click_event)

	simulate_mouse_release()

func simulate_mouse_release():
	var control = _get_control_under_cursor()

	if control:
		var release_event := InputEventMouseButton.new()
		release_event.position = cursor_position
		release_event.global_position = cursor_position
		release_event.button_index = MOUSE_BUTTON_LEFT
		release_event.pressed = false
		release_event.button_mask = MOUSE_BUTTON_MASK_LEFT
		release_event.double_click = false

		Input.parse_input_event(release_event)

### --- Samo hover ---
func simulate_hover():
	var control = _get_control_under_cursor()

	if last_hovered_control != control:
		if is_instance_valid(last_hovered_control):
			last_hovered_control.emit_signal("mouse_exited")
			#print("[HOVER] Emitovao 'mouse_exited' za:", last_hovered_control.name)

		if is_instance_valid(control):
			control.emit_signal("mouse_entered")
			#print("[HOVER] Emitovao 'mouse_entered' za:", control.name)

	last_hovered_control = control

# --- Dodatak: Hover nad stavkama u PopupMenu-u ---
	var hovered_control = _get_control_under_cursor()
	if hovered_control and hovered_control.is_in_group("ui") and hovered_control != last_hovered_control:
		if is_instance_valid(last_hovered_control):
			last_hovered_control.emit_signal("mouse_exited")
			print("[Hover] Izašao sa:", last_hovered_control.name)

		hovered_control.emit_signal("mouse_entered")
		print("[Hover] Ušao u:", hovered_control.name)
		last_hovered_control = hovered_control

## --- Helper: Pronalazenje kontrole ispod kursora ---
# Vrati kontrolu preko koje se nalazi kursor (za hover efekat)
func _get_control_under_cursor() -> Control:
	var mouse_pos = cursor_position
	var candidates: Array[Control] = []

	for node in get_tree().get_nodes_in_group("ui"):
		if node is Control and is_instance_valid(node):
			if node.visible and not node.disabled:
				if node.mouse_filter != Control.MOUSE_FILTER_IGNORE:
					if node.get_global_rect().has_point(mouse_pos):
						candidates.append(node)

	candidates.sort_custom(func(a, b): return a.z_index > b.z_index)

	return candidates[0] if !candidates.is_empty() else null

func _compare_z_index(a: Control, b: Control) -> bool:
	if a.get_canvas_layer() != b.get_canvas_layer():
		return a.get_canvas_layer() > b.get_canvas_layer()
	return a.z_index > b.z_index

# Pusti audio ako trenutno ne svira
func play_audio_if_stopped():
	if not audio_stream_player.playing:
		audio_stream_player.play()

# Testira sve Control node-ove da li imaju ispravno postavljen mouse_filter
func _test_mouse_filter_validnosti(node: Node = self) -> void:
	if node is Control:
		if node.mouse_filter not in [Control.MOUSE_FILTER_STOP, Control.MOUSE_FILTER_IGNORE]:
			print("⚠️ Neispravan mouse_filter na: ", node.name, " (", node.mouse_filter, ")")

	for child in node.get_children():
		_test_mouse_filter_validnosti(child)`Preformatted text`

Nope can’t be shorter !

Never tried writing gdscript code with ChatGPT, but from what I’ve read, it seems to be pretty bad at it atm. I understand you may not be familiar with programming, but using ChatGPT for such a huge script will only be a source of trouble, so you may want to try learning some gdscript basics?

Anyway, your second post still has an enormous number of lines of code. For the issue you have, it should be located at a very specific spot of your code. Not gonna lie, I’m not going to look for it, and I’m not sure anybody will :sweat_smile:

3 Likes

The problem isn’t the length of the code, it is the unformatted display that makes it unreadable.
On the tool bar above the message box that you pasted this code is a button that wraps code in a tag that preserves its formatting. The button looks like this </>.
This surrounds your code with ```
You can even go one step further and change the leading ``` to ```gdscript and it will highlight the code syntax accurately.
Also, you can edit your posts so you don’t have to post them all over again.

I think the length of the code is an issue too, it’s too much code to look through. You need to find what part of the code is relevant and only post that part.

2 Likes

Tnx man this is very helpful , Fixed . I mean fixed appearance of code, problem is not solved .

I will try to input this.
https://forum.godotengine.org/t/input-mouse-button-event-click-doesnt-work-with-scaled-viewports/65796

I succeed to find out what is wrong. I’m just gonna leave it here. Because nobody want to help. Am hoping that will help to someone.

# --- Helper funkcije ---
func simulate_mouse_click():
	var control = _get_control_under_cursor()
	# Ako kliknemo na kontrolu, tretiramo normalno
	if control:
		print("Klikujem na:", control.name)

		if control is OptionButton:
			control.show_popup()
			return

		if control is CheckBox:
			control.button_pressed = not control.button_pressed
			control.emit_signal("toggled", control.button_pressed)
			return

		var click_event := InputEventMouseButton.new()
		click_event.position = cursor_position
		click_event.global_position = cursor_position
		click_event.button_index = MOUSE_BUTTON_RIGHT
		click_event.pressed = true
		click_event.button_mask = MOUSE_BUTTON_MASK_RIGHT
		click_event.double_click = false

		Input.parse_input_event(click_event)

	simulate_mouse_release()

func simulate_mouse_release():
	var control = _get_control_under_cursor()

	if control:
		var release_event := InputEventMouseButton.new()
		release_event.position = cursor_position
		release_event.global_position = cursor_position
		release_event.button_index = MOUSE_BUTTON_RIGHT
		release_event.pressed = false
		release_event.button_mask = MOUSE_BUTTON_MASK_RIGHT
		release_event.double_click = false

		Input.parse_input_event(release_event)

Everything i have to do is to change MOUSE_BUTTON_ and MOUSE_BUTTON_MASK_ from LEFT to RIGHT. Thanks for helping me guys to understand I’m not a asshole.
EDIT:
I’m WRONG this is NOT really solution!!!

This is SOLUTION.

extends AnimatedSprite2D

# --- Podesivi parametri ---
var speed := 200.0 # Brzina kretanja kursora

var cursor_position := Vector2.ZERO # Pozicija kursora
var last_mouse_pos := Vector2.ZERO # Zadnja pozicija miša

var left_pressed := false # Da li je levi "klik" trenutno pritisnut
var right_pressed := false # Da li je desni "klik" trenutno pritisnut

@onready var audio_stream_player = $AudioStreamPlayer # Audio za klik zvuk
 # Parent node za kursor da bi išao iznad menija
@onready var cursor_layer = $".."
# --- Hover efekat za UI kontrole (test) ---
@onready var sprite := $"." # Sprite koji menja boju na hover
var default_modulate := Color(1, 1, 1) # Originalna boja kursora


func _ready():

# Postavljanje kursora iznad ostalih UI elemenata
	cursor_layer.set_layer(1025)
	# Sakrivanje pravog miša
	Input.mouse_mode = Input.MOUSE_MODE_HIDDEN
# Inicijalizacija pozicije
	cursor_position = Vector2.ZERO
	last_mouse_pos = get_viewport().get_mouse_position()
	global_position = cursor_position
# Povezivanje na promenu veličine prozora
	get_window().connect("size_changed", Callable(self, "_on_window_resized"))

func _process(delta):

# --- Upravljanje kursorom ---
	var direction := Vector2.ZERO
# Tastatura input
	if Input.is_action_pressed("right"):
		direction.x += 1
	if Input.is_action_pressed("left"):
		direction.x -= 1
	if Input.is_action_pressed("down"):
		direction.y += 1
	if Input.is_action_pressed("up"):
		direction.y -= 1
# Džojstik input
	direction.x += Input.get_joy_axis(0, JOY_AXIS_LEFT_X)
	direction.y += Input.get_joy_axis(0, JOY_AXIS_LEFT_Y)
# Ako ima inputa — pomeri
	if direction.length() > 0.1:
		direction = direction.normalized()
		cursor_position += direction * speed * delta
	else:
# Ako se mišem pomerilo — prati miš
		var current_mouse_pos := get_viewport().get_mouse_position()
		if current_mouse_pos != last_mouse_pos:
			cursor_position = current_mouse_pos
			last_mouse_pos = current_mouse_pos
# Ograničenje kretanja unutar ekrana
	var viewport_rect = get_viewport_rect()
	cursor_position.x = clamp(cursor_position.x, 0, viewport_rect.size.x)
	cursor_position.y = clamp(cursor_position.y, 0, viewport_rect.size.y)
	global_position = cursor_position

# --- Klik levi ---
	var is_left_down := (
		Input.is_action_pressed("jump")
		or Input.is_joy_button_pressed(0, JOY_BUTTON_X)
		or Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)
		or Input.is_action_pressed("ui_accept")
	)
	handle_left_input(is_left_down)
	if is_left_down and animation == "LCL" and is_playing() and frame == 3:
		pause()
		audio_stream_player.stop()
	elif not is_left_down and animation == "LCL" and frame == 3 and not \
	is_playing():
		play("LCL")
		play_audio_if_stopped()

# --- Klik desni ---
	var is_right_down := (
		Input.is_action_pressed("attack")
		or Input.is_joy_button_pressed(0, JOY_BUTTON_B)
		or Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
	)
	handle_right_input(is_right_down)
	if is_right_down and animation == "RCL" and is_playing() and frame == 3:
		pause()
		audio_stream_player.stop()
	elif not is_right_down and animation == "RCL" and frame == 3 and not \
	is_playing():
		play("RCL")
		play_audio_if_stopped()

# --- Posebne akcije ---
	if Input.is_action_just_pressed("ui_accept"):
		_simulate_click_on_control()

	if Input.is_action_just_pressed("start"):
		get_tree().change_scene_to_file("res://Levels/Test/test_level_00.tscn")

	if Input.is_action_just_pressed("pause"):
		get_tree().paused = not get_tree().paused


# --- Hover efekat za UI (možeš brisati ceo ovaj blok) ---
	var hovered_control = _get_control_under_cursor()
	if hovered_control and hovered_control is OptionButton:
		sprite.modulate = Color(1, 0, 0) # Crvena boja kad je iznad OptionButton
	else:
		sprite.modulate = default_modulate


# --- Input Obrada --- 
func handle_left_input(is_down: bool):
	if is_down and not left_pressed:
		_simulate_click_on_control()
		on_left_click()
	left_pressed = is_down

func handle_right_input(is_down: bool):
	if is_down and not right_pressed:
		_simulate_click_on_control()
		on_right_click()
	right_pressed = is_down

func on_left_click():
	if not left_pressed:
		if not is_playing():
			play("LCL")
		play_audio_if_stopped()
	left_pressed = true

func on_right_click():
	if not right_pressed:
		if not is_playing():
			play("RCL")
		play_audio_if_stopped()
	right_pressed = true

# --- Helper funkcije ---
# --- Klik kad se pritisne dugme ---
func _simulate_click_on_control():

	var control_under_cursor := _get_control_under_cursor()
	if control_under_cursor:
		if control_under_cursor is OptionButton:
			control_under_cursor.show_popup()
			return

		if control_under_cursor is CheckBox:
			control_under_cursor.button_pressed = not control_under_cursor\
			.button_pressed
			control_under_cursor.emit_signal("toggled", control_under_cursor\
			.button_pressed)
			return

		if control_under_cursor is Button:
# Ako je dugme, direktno šaljemo pressed signal
			control_under_cursor.emit_signal("pressed")

		else:
# Ako NIJE dugme, simuliramo klik kroz viewport
			var click_event := InputEventMouseButton.new()
			click_event.position = cursor_position
			click_event.global_position = cursor_position
			click_event.button_index = MOUSE_BUTTON_LEFT
			click_event.pressed = true
			click_event.button_mask = MOUSE_BUTTON_MASK_LEFT
			click_event.double_click = false
			get_viewport().push_input(click_event)

# --- Klik kad se pusti dugme ---
func simulate_release_on_control():

	var control_under_cursor := _get_control_under_cursor()
	if control_under_cursor:
		if control_under_cursor is OptionButton:
# Opcioni button već reaguje na show_popup, ovde ne moraš ništa raditi
			return
	if control_under_cursor is CheckBox:
# CheckBox već je prebačen (toggle-ovan) u _simulate_click_on_control
# Ali možemo emitovati released signal ako postoji
		if control_under_cursor.has_signal("released"):
			control_under_cursor.emit_signal("released")

		if control_under_cursor is Button:
# Ako je dugme, možemo ručno emitovati released ako želimo (nije obavezno)
			if control_under_cursor.has_signal("released"):
				control_under_cursor.emit_signal("released")

		else:
# Ako NIJE dugme, simuliramo release kroz viewport
			var release_event := InputEventMouseButton.new()
			release_event.position = cursor_position
			release_event.global_position = cursor_position
			release_event.button_index = MOUSE_BUTTON_LEFT
			release_event.pressed = false
			release_event.button_mask = MOUSE_BUTTON_MASK_LEFT
			release_event.double_click = false
			get_viewport().push_input(release_event)

# Vrati kontrolu preko koje se nalazi kursor (za hover efekat)
func _get_control_under_cursor() -> Control:
	var _viewport := get_viewport()
# svi UI elementi su u grupi "ui"
	var ui_nodes = get_tree().get_nodes_in_group("ui")  
	for node in ui_nodes:
		if node is Control and node.visible:
			var rect = node.get_global_rect()
# KONTROLA: koristi cursor_position (ne miš!) 
			if rect.has_point(cursor_position):
				return node
	return null

# Pusti audio ako trenutno ne svira
func play_audio_if_stopped():
	if not audio_stream_player.playing:
		audio_stream_player.play()

# Ažuriraj poziciju kursora kada se promeni veličina prozora
func _on_window_resized():
	var new_size = get_viewport_rect().size
	cursor_position.x = clamp(cursor_position.x, 0, new_size.x)
	cursor_position.y = clamp(cursor_position.y, 0, new_size.y)
	global_position = cursor_position