Tab UI Issues Help

Godot Version

4.5

Question

I’m attempting to make a UI system where you can add and remove tabs that you can edit. The tabs are added from top to bottom and there’s a max of 25. There’s 3 by default, and you can scroll through them with a slider. I’ve figured out adding the tabs, but I can’t figure out how to remove them and move the tabs below the removed tab upward. Right now, I have a button in the scene for individual tabs that queues the tab to be removed and sets 2 global variables, one is to see which rotation was removed and one decreases the total number of tabs. In the main scene, this code runs in the physics process:

if not GlobalVars.rotationRemove > 0:
	if GlobalVars.removed:
		GlobalVars.removed = true
		GlobalVars.rotationRemove = 0
	else:
		GlobalVars.removed = false

The goal of this was to detect that it changed on the first frame, then stop the tabs from moving down on the next frame. This is the code that moves the tabs down in their physics process function after detecting the removal of a tab above them:

if GlobalVars.rotationRemove < rotationID and not GlobalVars.removed:
	rotationID -= 1

You never mentioned what is the specific problem you have. What happens vs what do you want to happen?

On a side note, there are a couple of questionable choices in your design, which confuse me as to how you make this whole system work. It would help if you posted your code in its entirety with screenshot of the scene tree.

Why is it handled by global variables?

Why physics process and not just process?

The issue is whenever one is removed, the tabs that are below the one that got removed should move upward. Instead, they stay in the same spot.

I went ahead and switched physics process to process. I’m not sure what else to use instead of global variables, I’m still new to this whole thing.

Tab scene:

extends Panel

var rotationID: int

func _ready() -> void:
	# If the panel does not have any metadata to start, sets up ID and position.
	if get_meta("RotationID") == 0:
		rotationID = GlobalVars.rotationsTotal
		set_meta("RotationID",rotationID)
	else:
		rotationID = get_meta("RotationID")


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
	# Positions the panel to the slider.
	if GlobalVars.rotationRemove < rotationID and not GlobalVars.removed:
		rotationID -= 1
	position = Vector2(20,rotationID * 100 - GlobalVars.sliderValue * 100)


# Removes the rotation.
func _on_remove_pressed() -> void:
	GlobalVars.rotationRemove = rotationID
	GlobalVars.rotationsTotal -= 1
	queue_free()

Main scene:

extends Control

var guardRotation = preload("res://Scenes/rotation.tscn")

@onready var add_rotation: Button = $"Add Rotation"
@onready var rotation_scroll: VScrollBar = $"Rotation scroll"
@onready var top_panel: Panel = $"Top panel"

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
	# Sets values based on the slider which can be used for positioning.
	var slider: float = rotation_scroll.value
	GlobalVars.sliderValue = slider
	add_rotation.position.y = (GlobalVars.rotationsTotal * 100 + 100) - (slider * 100)
	# Sets the slider up.
	if GlobalVars.rotationsTotal > 5:
		rotation_scroll.visible = true
		var scrollMax: int = GlobalVars.rotationsTotal - 5
		if scrollMax <= 19:
			rotation_scroll.max_value = scrollMax
	else:
		rotation_scroll.visible = false
	# Used to remove rotations.
	if not GlobalVars.rotationRemove > 0:
		if GlobalVars.removed:
			GlobalVars.removed = true
			GlobalVars.rotationRemove = 0
		else:
			GlobalVars.removed = false


func _on_add_rotation_pressed() -> void:
	# Adds a new rotation for guards and positions top pannel.
	GlobalVars.rotationsTotal += 1
	add_child(guardRotation.instantiate())
	move_child(top_panel,get_child_count())

Global variables:

extends Node

# Used to hold value of the website slider.
var sliderValue: float = 0.0
# Used to track how many rotations there are.
var rotationsTotal: int = 3
# Used to remove a specific rotation.
var rotationRemove: int
# Used to see if the rotation to remove has been removed.
var removed: bool = true

I’m still looking to fix this. I removed the global variables that I intended to move the panels. Here’s what I have now:

extends Panel

var rotationID: int

func _ready() -> void:
	# If the panel does not have any metadata to start, sets up ID and position.
	if get_meta("RotationID") == 0:
		rotationID = GlobalVars.rotationsTotal
		set_meta("RotationID",rotationID)
	else:
		rotationID = get_meta("RotationID")


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
	# Positions the panel to the slider.
	position = Vector2(20,rotationID * 100 - GlobalVars.sliderValue * 100)


# Removes the rotation.
func _on_remove_pressed() -> void:
	GlobalVars.rotationsTotal -= 1
	queue_free()

extends Control

var guardRotation = preload("res://Scenes/rotation.tscn")

@onready var add_rotation: Button = $"Add Rotation"
@onready var rotation_scroll: VScrollBar = $"Rotation scroll"
@onready var top_panel: Panel = $"Top panel"

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
	# Sets values based on the slider which can be used for positioning.
	var slider: float = rotation_scroll.value
	GlobalVars.sliderValue = slider
	add_rotation.position.y = (GlobalVars.rotationsTotal * 100 + 100) - (slider * 100)
	# Sets the slider up.
	if GlobalVars.rotationsTotal > 5:
		rotation_scroll.visible = true
		var scrollMax: int = GlobalVars.rotationsTotal - 5
		if scrollMax <= 19:
			rotation_scroll.max_value = scrollMax
	else:
		rotation_scroll.visible = false


func _on_add_rotation_pressed() -> void:
	# Adds a new rotation for guards and positions top pannel.
	GlobalVars.rotationsTotal += 1
	add_child(guardRotation.instantiate())
	move_child(top_panel,get_child_count())

Global variables:

extends Node

# Used to hold value of the website slider.
var sliderValue: float = 0.0
# Used to track how many rotations there are.
var rotationsTotal: int = 3

Here is a visual of what is happening. I hope it will be apparent what the issue is now: