tab management

This commit is contained in:
Face
2025-07-21 19:31:07 +03:00
parent 438beb01dc
commit b3526927cb
22 changed files with 475 additions and 82 deletions

1
Icons/plus.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-plus-icon lucide-plus"><path d="M5 12h14"/><path d="M12 5v14"/></svg>

After

Width:  |  Height:  |  Size: 266 B

37
Icons/plus.svg.import Normal file
View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cehbtwq6gq0cn"
path="res://.godot/imported/plus.svg-dfcf01023e04ffbd2a1c50b2672d981c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Icons/plus.svg"
dest_files=["res://.godot/imported/plus.svg-dfcf01023e04ffbd2a1c50b2672d981c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

1
Icons/x.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>

After

Width:  |  Height:  |  Size: 264 B

37
Icons/x.svg.import Normal file
View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://gq8g7t4s3ryg"
path="res://.godot/imported/x.svg-4402340e2f725e924f2e7d83afde3bea.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Icons/x.svg"
dest_files=["res://.godot/imported/x.svg-4402340e2f725e924f2e7d83afde3bea.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,8 @@
[gd_resource type="StyleBoxFlat" format=3 uid="uid://dn8exdnk8tjce"]
[resource]
bg_color = Color(0, 0, 0, 1)
corner_radius_top_left = 15
corner_radius_top_right = 15
corner_radius_bottom_right = 15
corner_radius_bottom_left = 15

View File

@@ -0,0 +1,9 @@
[gd_resource type="StyleBoxFlat" format=3 uid="uid://dn6r16retee3l"]
[resource]
bg_color = Color(0.109804, 0.109804, 0.109804, 1)
draw_center = false
corner_radius_top_left = 15
corner_radius_top_right = 15
corner_radius_bottom_right = 15
corner_radius_bottom_left = 15

View File

@@ -0,0 +1,9 @@
[gd_resource type="StyleBoxFlat" format=3 uid="uid://bx3sgro1ageff"]
[resource]
content_margin_left = 8.0
content_margin_right = 8.0
bg_color = Color(0.152476, 0.152476, 0.152476, 1)
draw_center = false
corner_radius_top_left = 15
corner_radius_top_right = 15

View File

@@ -0,0 +1,9 @@
[gd_resource type="GradientTexture2D" load_steps=2 format=3 uid="uid://cwyl6cm0wktuc"]
[sub_resource type="Gradient" id="Gradient_344ge"]
offsets = PackedFloat32Array(0, 0.513423)
colors = PackedColorArray(0.109804, 0.109804, 0.109804, 0, 0.109804, 0.109804, 0.109804, 1)
[resource]
gradient = SubResource("Gradient_344ge")
height = 48

View File

@@ -0,0 +1,9 @@
[gd_resource type="GradientTexture2D" load_steps=2 format=3 uid="uid://c7u7a1u1v04bx"]
[sub_resource type="Gradient" id="Gradient_344ge"]
offsets = PackedFloat32Array(0, 0.52439)
colors = PackedColorArray(0.168627, 0.168627, 0.168627, 0, 0.168627, 0.168627, 0.168627, 1)
[resource]
gradient = SubResource("Gradient_344ge")
height = 48

View File

@@ -0,0 +1,9 @@
[gd_resource type="GradientTexture2D" load_steps=2 format=3 uid="uid://c6mhjt6pk8hox"]
[sub_resource type="Gradient" id="Gradient_344ge"]
offsets = PackedFloat32Array(0, 0.52439)
colors = PackedColorArray(0.137255, 0.137255, 0.137255, 0, 0.137255, 0.137255, 0.137255, 1)
[resource]
gradient = SubResource("Gradient_344ge")
height = 48

View File

@@ -0,0 +1,8 @@
[gd_resource type="StyleBoxFlat" format=3 uid="uid://cbbqlhtiuqmr1"]
[resource]
content_margin_left = 8.0
content_margin_right = 8.0
bg_color = Color(0, 0, 0, 1)
corner_radius_top_left = 15
corner_radius_top_right = 15

View File

@@ -0,0 +1,8 @@
[gd_resource type="StyleBoxFlat" format=3 uid="uid://fd1nftmqox32"]
[resource]
content_margin_left = 8.0
content_margin_right = 8.0
bg_color = Color(0.138034, 0.138034, 0.138034, 1)
corner_radius_top_left = 15
corner_radius_top_right = 15

View File

@@ -0,0 +1,8 @@
[gd_resource type="StyleBoxFlat" format=3 uid="uid://b7oid7im3n5nj"]
[resource]
content_margin_left = 8.0
content_margin_right = 8.0
bg_color = Color(0.109804, 0.109804, 0.109804, 1)
corner_radius_top_left = 15
corner_radius_top_right = 15

73
Scenes/Tab.tscn Normal file
View File

@@ -0,0 +1,73 @@
[gd_scene load_steps=11 format=3 uid="uid://sqhcxhcre081"]
[ext_resource type="Script" uid="uid://crpnnfqm3k5xv" path="res://Scripts/Tab.gd" id="1_q3baj"]
[ext_resource type="Texture2D" uid="uid://gq8g7t4s3ryg" path="res://Icons/x.svg" id="2_pisds"]
[ext_resource type="StyleBox" uid="uid://fd1nftmqox32" path="res://Scenes/Styles/TabHoverDefault.tres" id="3_kjcxk"]
[ext_resource type="Texture2D" uid="uid://c7u7a1u1v04bx" path="res://Scenes/Styles/TabGradientDefault.tres" id="3_q3baj"]
[ext_resource type="StyleBox" uid="uid://bx3sgro1ageff" path="res://Scenes/Styles/TabDefault.tres" id="4_ib6pj"]
[ext_resource type="Texture2D" uid="uid://dioe63fr47oq7" path="res://Scripts/youtube.png" id="6_bdsd2"]
[ext_resource type="StyleBox" uid="uid://dn8exdnk8tjce" path="res://Scenes/Styles/CloseButtonHover.tres" id="6_pisds"]
[ext_resource type="StyleBox" uid="uid://dn6r16retee3l" path="res://Scenes/Styles/CloseButtonNormal.tres" id="7_1ohlo"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6bp64"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_344ge"]
[node name="Tab1" type="Control"]
custom_minimum_size = Vector2(350, 50)
layout_mode = 3
anchors_preset = 0
script = ExtResource("1_q3baj")
[node name="GradientTexture" type="TextureRect" parent="."]
z_index = 1
layout_mode = 0
offset_left = 278.0
offset_top = 2.0
offset_right = 342.0
offset_bottom = 50.0
texture = ExtResource("3_q3baj")
[node name="Button" type="Button" parent="."]
z_index = -2
custom_minimum_size = Vector2(350, 50)
layout_mode = 2
offset_right = 350.0
offset_bottom = 50.0
focus_mode = 0
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_constants/h_separation = 8
theme_override_constants/icon_max_width = 23
theme_override_styles/focus = SubResource("StyleBoxEmpty_6bp64")
theme_override_styles/hover = ExtResource("3_kjcxk")
theme_override_styles/pressed = ExtResource("3_kjcxk")
theme_override_styles/normal = ExtResource("4_ib6pj")
action_mode = 0
text = "(2) YouTube - STOP PLAYING WITH ME BITCHES FR"
icon = ExtResource("6_bdsd2")
alignment = 0
text_overrun_behavior = 3
[node name="CloseButton" type="Button" parent="."]
z_index = 2
custom_minimum_size = Vector2(34, 34)
layout_mode = 0
offset_left = 319.0
offset_top = 12.0
offset_right = 353.0
offset_bottom = 46.0
scale = Vector2(0.75, 0.75)
focus_mode = 0
mouse_filter = 2
mouse_default_cursor_shape = 2
theme_override_styles/focus = SubResource("StyleBoxEmpty_344ge")
theme_override_styles/hover = ExtResource("6_pisds")
theme_override_styles/pressed = ExtResource("7_1ohlo")
theme_override_styles/normal = ExtResource("7_1ohlo")
icon = ExtResource("2_pisds")
icon_alignment = 1
[connection signal="mouse_entered" from="Button" to="." method="_on_button_mouse_entered"]
[connection signal="mouse_exited" from="Button" to="." method="_on_button_mouse_exited"]
[connection signal="pressed" from="Button" to="." method="_on_button_pressed"]

View File

@@ -2,18 +2,20 @@
[ext_resource type="Script" uid="uid://bg5iqnwic1rio" path="res://Scripts/main.gd" id="1_8q3xr"]
[ext_resource type="Texture2D" uid="uid://df1m4j7uxi63v" path="res://Icons/chevron-down.svg" id="2_6bp64"]
[ext_resource type="Texture2D" uid="uid://dioe63fr47oq7" path="res://Scripts/youtube.png" id="2_bo1nx"]
[ext_resource type="Script" uid="uid://cy0c74thgjwok" path="res://Scripts/TabContainer.gd" id="2_hptm8"]
[ext_resource type="Texture2D" uid="uid://bf0vx7qwo28k6" path="res://Icons/search.svg" id="3_8gbba"]
[ext_resource type="Texture2D" uid="uid://bp42ccs2nmbmw" path="res://Icons/arrow-left.svg" id="3_21xkr"]
[ext_resource type="Texture2D" uid="uid://dyyylow47qd0k" path="res://Icons/arrow-right.svg" id="4_6bp64"]
[ext_resource type="PackedScene" uid="uid://sqhcxhcre081" path="res://Scenes/Tab.tscn" id="4_344ge"]
[ext_resource type="Texture2D" uid="uid://cu4hjoba6etf" path="res://Icons/rotate-cw.svg" id="5_344ge"]
[ext_resource type="Texture2D" uid="uid://cehbtwq6gq0cn" path="res://Icons/plus.svg" id="5_ynf5e"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_344ge"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hptm8"]
content_margin_left = 8.0
content_margin_right = 8.0
bg_color = Color(0.169245, 0.169245, 0.169245, 1)
bg_color = Color(0, 0, 0, 1)
corner_radius_top_left = 15
corner_radius_top_right = 15
corner_radius_bottom_right = 15
@@ -21,35 +23,30 @@ corner_radius_bottom_left = 15
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6bp64"]
bg_color = Color(0.109804, 0.109804, 0.109804, 1)
corner_radius_top_left = 15
corner_radius_top_right = 15
corner_radius_bottom_right = 15
corner_radius_bottom_left = 15
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6bp64"]
draw_center = false
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ynf5e"]
content_margin_left = 8.0
content_margin_right = 8.0
bg_color = Color(0.169245, 0.169245, 0.169245, 1)
corner_radius_top_left = 15
corner_radius_top_right = 15
bg_color = Color(0, 0, 0, 1)
corner_radius_top_left = 50
corner_radius_top_right = 50
corner_radius_bottom_right = 50
corner_radius_bottom_left = 50
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_344ge"]
content_margin_left = 8.0
content_margin_right = 8.0
bg_color = Color(0.109804, 0.109804, 0.109804, 1)
corner_radius_top_left = 15
corner_radius_top_right = 15
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_d1ilt"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fdnlq"]
bg_color = Color(0.168627, 0.168627, 0.168627, 1)
corner_radius_top_left = 50
corner_radius_top_right = 50
corner_radius_bottom_right = 50
corner_radius_bottom_left = 50
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_d1ilt"]
bg_color = Color(0.6, 0.6, 0.6, 0)
draw_center = false
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ynf5e"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_hptm8"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_8gbba"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8gbba"]
@@ -92,74 +89,36 @@ layout_mode = 2
[node name="TabContainer" type="HFlowContainer" parent="VBoxContainer"]
layout_mode = 2
script = ExtResource("2_hptm8")
[node name="Spacer" type="Control" parent="VBoxContainer/TabContainer"]
layout_mode = 2
[node name="Popup" type="Button" parent="VBoxContainer/TabContainer"]
custom_minimum_size = Vector2(42, 0)
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_styles/focus = SubResource("StyleBoxEmpty_344ge")
theme_override_styles/hover = SubResource("StyleBoxFlat_hptm8")
theme_override_styles/pressed = SubResource("StyleBoxFlat_6bp64")
theme_override_styles/normal = SubResource("StyleBoxFlat_6bp64")
icon = ExtResource("2_6bp64")
icon_alignment = 1
[node name="Button" type="Button" parent="VBoxContainer/TabContainer"]
custom_minimum_size = Vector2(250, 42)
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/TabContainer"]
layout_mode = 2
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_constants/h_separation = 8
theme_override_constants/icon_max_width = 23
theme_override_styles/focus = SubResource("StyleBoxEmpty_6bp64")
theme_override_styles/hover = SubResource("StyleBoxFlat_ynf5e")
theme_override_styles/normal = SubResource("StyleBoxFlat_344ge")
text = "(2) YouTube - Home Page testing"
icon = ExtResource("2_bo1nx")
alignment = 0
text_overrun_behavior = 3
[node name="Button2" type="Button" parent="VBoxContainer/TabContainer"]
custom_minimum_size = Vector2(250, 42)
[node name="Tab1" parent="VBoxContainer/TabContainer/HBoxContainer" instance=ExtResource("4_344ge")]
layout_mode = 2
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_constants/h_separation = 8
theme_override_constants/icon_max_width = 23
theme_override_styles/focus = SubResource("StyleBoxEmpty_6bp64")
theme_override_styles/hover = SubResource("StyleBoxFlat_ynf5e")
theme_override_styles/normal = SubResource("StyleBoxFlat_344ge")
text = "(2) YouTube - Home Page testing"
icon = ExtResource("2_bo1nx")
alignment = 0
text_overrun_behavior = 3
[node name="Button3" type="Button" parent="VBoxContainer/TabContainer"]
custom_minimum_size = Vector2(250, 42)
[node name="NewTabButton" type="Button" parent="VBoxContainer/TabContainer"]
custom_minimum_size = Vector2(50, 0)
layout_mode = 2
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_constants/h_separation = 8
theme_override_constants/icon_max_width = 23
theme_override_styles/focus = SubResource("StyleBoxEmpty_6bp64")
theme_override_styles/focus = SubResource("StyleBoxEmpty_344ge")
theme_override_styles/hover = SubResource("StyleBoxFlat_ynf5e")
theme_override_styles/normal = SubResource("StyleBoxFlat_344ge")
text = "(2) YouTube - Home Page testing"
icon = ExtResource("2_bo1nx")
alignment = 0
text_overrun_behavior = 3
[node name="Button4" type="Button" parent="VBoxContainer/TabContainer"]
custom_minimum_size = Vector2(250, 42)
layout_mode = 2
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_constants/h_separation = 8
theme_override_constants/icon_max_width = 23
theme_override_styles/focus = SubResource("StyleBoxEmpty_6bp64")
theme_override_styles/hover = SubResource("StyleBoxFlat_ynf5e")
theme_override_styles/normal = SubResource("StyleBoxFlat_344ge")
text = "(2) YouTube - Home Page testing"
icon = ExtResource("2_bo1nx")
alignment = 0
text_overrun_behavior = 3
theme_override_styles/pressed = SubResource("StyleBoxFlat_6bp64")
theme_override_styles/normal = SubResource("StyleBoxFlat_6bp64")
icon = ExtResource("5_ynf5e")
icon_alignment = 1
[node name="Spacer2" type="Control" parent="VBoxContainer"]
custom_minimum_size = Vector2(0, 5)
@@ -168,30 +127,39 @@ layout_mode = 2
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
custom_minimum_size = Vector2(0, 45)
layout_mode = 2
theme_override_constants/separation = 14
theme_override_constants/separation = 12
[node name="Spacer" type="Control" parent="VBoxContainer/HBoxContainer"]
custom_minimum_size = Vector2(5, 0)
layout_mode = 2
[node name="BackButton" type="Button" parent="VBoxContainer/HBoxContainer"]
custom_minimum_size = Vector2(30, 30)
custom_minimum_size = Vector2(45, 0)
layout_mode = 2
theme_override_styles/focus = SubResource("StyleBoxEmpty_d1ilt")
theme_override_styles/hover = SubResource("StyleBoxFlat_fdnlq")
theme_override_styles/pressed = SubResource("StyleBoxFlat_d1ilt")
theme_override_styles/normal = SubResource("StyleBoxFlat_d1ilt")
icon = ExtResource("3_21xkr")
icon_alignment = 1
[node name="ForwardButton" type="Button" parent="VBoxContainer/HBoxContainer"]
custom_minimum_size = Vector2(30, 30)
custom_minimum_size = Vector2(45, 0)
layout_mode = 2
theme_override_styles/normal = SubResource("StyleBoxEmpty_ynf5e")
theme_override_styles/focus = SubResource("StyleBoxEmpty_d1ilt")
theme_override_styles/hover = SubResource("StyleBoxFlat_fdnlq")
theme_override_styles/pressed = SubResource("StyleBoxFlat_d1ilt")
theme_override_styles/normal = SubResource("StyleBoxFlat_d1ilt")
icon = ExtResource("4_6bp64")
icon_alignment = 1
[node name="ReloadButton" type="Button" parent="VBoxContainer/HBoxContainer"]
custom_minimum_size = Vector2(30, 30)
[node name="RefreshButton" type="Button" parent="VBoxContainer/HBoxContainer"]
custom_minimum_size = Vector2(45, 0)
layout_mode = 2
theme_override_styles/normal = SubResource("StyleBoxEmpty_hptm8")
theme_override_styles/focus = SubResource("StyleBoxEmpty_d1ilt")
theme_override_styles/hover = SubResource("StyleBoxFlat_fdnlq")
theme_override_styles/pressed = SubResource("StyleBoxFlat_d1ilt")
theme_override_styles/normal = SubResource("StyleBoxFlat_d1ilt")
icon = ExtResource("5_344ge")
icon_alignment = 1
@@ -232,18 +200,20 @@ grow_horizontal = 2
grow_vertical = 2
[node name="Panel" type="Panel" parent="."]
z_index = -1
z_index = -5
layout_mode = 2
offset_top = 50.0
offset_top = 58.0
offset_right = 1920.0
offset_bottom = 117.0
offset_bottom = 125.0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_6iyac")
[node name="Panel2" type="Panel" parent="."]
z_index = -2
z_index = -6
layout_mode = 2
offset_right = 1920.0
offset_bottom = 117.0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_21xkr")
[connection signal="pressed" from="VBoxContainer/TabContainer/NewTabButton" to="VBoxContainer/TabContainer" method="_on_new_tab_button_pressed"]

6
Scripts/Constants.gd Normal file
View File

@@ -0,0 +1,6 @@
extends Node
const MAIN_COLOR = Color(27/255.0, 27/255.0, 27/255.0, 1)
const SECONDARY_COLOR = Color(43/255.0, 43/255.0, 43/255.0, 1)
const HOVER_COLOR = Color(0, 0, 0, 1)

1
Scripts/Constants.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://b4qt7eno8g41p

65
Scripts/Tab.gd Normal file
View File

@@ -0,0 +1,65 @@
class_name Tab
extends Control
signal tab_pressed
signal tab_closed
@onready var gradient_texture: TextureRect = $GradientTexture
@onready var button: Button = $Button
@onready var close_button: Button = $CloseButton
const TAB_GRADIENT: GradientTexture2D = preload("res://Scenes/Styles/TabGradient.tres")
const TAB_GRADIENT_DEFAULT: GradientTexture2D = preload("res://Scenes/Styles/TabGradientDefault.tres")
const TAB_GRADIENT_INACTIVE: GradientTexture2D = preload("res://Scenes/Styles/TabGradientInactive.tres")
const TAB_HOVER: StyleBoxFlat = preload("res://Scenes/Styles/TabHover.tres")
const TAB_DEFAULT: StyleBoxFlat = preload("res://Scenes/Styles/TabDefault.tres")
const CLOSE_BUTTON_HOVER: StyleBoxFlat = preload("res://Scenes/Styles/CloseButtonHover.tres")
const CLOSE_BUTTON_NORMAL: StyleBoxFlat = preload("res://Scenes/Styles/CloseButtonNormal.tres")
var is_active := false
var mouse_over_tab := false
func _ready():
add_to_group("tabs")
gradient_texture.texture = gradient_texture.texture.duplicate()
gradient_texture.texture.gradient = gradient_texture.texture.gradient.duplicate()
func _process(_delta):
# NOTE: probably very inefficient
if mouse_over_tab:
var mouse_pos = get_global_mouse_position()
var close_button_rect = Rect2(close_button.global_position, close_button.size * close_button.scale)
if close_button_rect.has_point(mouse_pos):
close_button.add_theme_stylebox_override("normal", CLOSE_BUTTON_HOVER)
else:
close_button.add_theme_stylebox_override("normal", CLOSE_BUTTON_NORMAL)
func _on_button_mouse_entered() -> void:
mouse_over_tab = true
if is_active: return
gradient_texture.texture = TAB_GRADIENT_INACTIVE
func _on_button_mouse_exited() -> void:
mouse_over_tab = false
if is_active: return
gradient_texture.texture = TAB_GRADIENT_DEFAULT
func _exit_tree():
remove_from_group("tabs")
func _on_button_pressed() -> void:
# Check if click was on close button area
var mouse_pos = get_global_mouse_position()
var close_button_rect = Rect2(close_button.global_position, close_button.size * close_button.scale)
if close_button_rect.has_point(mouse_pos):
_on_close_button_pressed()
else:
# Handle tab button click
tab_pressed.emit()
func _on_close_button_pressed() -> void:
tab_closed.emit()
queue_free()

1
Scripts/Tab.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://crpnnfqm3k5xv

96
Scripts/TabContainer.gd Normal file
View File

@@ -0,0 +1,96 @@
extends HFlowContainer
var tabs: Array[Tab] = []
var active_tab := 0
const TAB = preload("res://Scenes/Tab.tscn")
const TAB_NORMAL: StyleBoxFlat = preload("res://Scenes/Styles/TabNormal.tres")
const TAB_HOVER: StyleBoxFlat = preload("res://Scenes/Styles/TabHover.tres")
const TAB_DEFAULT: StyleBoxFlat = preload("res://Scenes/Styles/TabDefault.tres")
const TAB_HOVER_DEFAULT: StyleBoxFlat = preload("res://Scenes/Styles/TabHoverDefault.tres")
const TAB_GRADIENT: GradientTexture2D = preload("res://Scenes/Styles/TabGradient.tres")
const TAB_GRADIENT_DEFAULT: GradientTexture2D = preload("res://Scenes/Styles/TabGradientDefault.tres")
@onready var h_box_container: HBoxContainer = $HBoxContainer
func _ready() -> void:
tabs.assign(get_tree().get_nodes_in_group("tabs"))
set_active_tab(0)
for i in tabs.size():
tabs[i].tab_pressed.connect(_tab_pressed.bind(i))
tabs[i].tab_closed.connect(_tab_closed.bind(i))
func _tab_pressed(index: int) -> void:
set_active_tab(index)
func _tab_closed(index: int) -> void:
tabs.remove_at(index)
if tabs.is_empty():
get_tree().quit()
return
if index <= active_tab:
if index == active_tab:
# Closed tab was active, select right neighbor (or last tab if at end)
if index >= tabs.size():
active_tab = tabs.size() - 1
else:
active_tab = index
else:
# Closed tab was before active tab, shift active index down
active_tab -= 1
# Reconnect signals with updated indices
for i in tabs.size():
tabs[i].tab_pressed.disconnect(_tab_pressed)
tabs[i].tab_closed.disconnect(_tab_closed)
tabs[i].tab_pressed.connect(_tab_pressed.bind(i))
tabs[i].tab_closed.connect(_tab_closed.bind(i))
set_active_tab(active_tab)
func set_active_tab(index: int) -> void:
# old tab
tabs[active_tab].is_active = false
tabs[active_tab].button.add_theme_stylebox_override("normal", TAB_DEFAULT)
tabs[active_tab].button.add_theme_stylebox_override("pressed", TAB_DEFAULT)
tabs[active_tab].button.add_theme_stylebox_override("hover", TAB_HOVER_DEFAULT)
tabs[active_tab].gradient_texture.texture = TAB_GRADIENT_DEFAULT
# new tab
tabs[index].is_active = true
tabs[index].button.add_theme_stylebox_override("normal", TAB_NORMAL)
tabs[index].button.add_theme_stylebox_override("pressed", TAB_NORMAL)
tabs[index].button.add_theme_stylebox_override("hover", TAB_NORMAL)
tabs[index].gradient_texture.texture = TAB_GRADIENT
active_tab = index
func create_tab() -> void:
var index = tabs.size();
var tab = TAB.instantiate()
tabs.append(tab)
tab.tab_pressed.connect(_tab_pressed.bind(index))
tab.tab_closed.connect(_tab_closed.bind(index))
h_box_container.add_child(tab)
set_active_tab(index)
func _input(event: InputEvent) -> void:
if Input.is_action_just_pressed("NewTab"):
create_tab()
if Input.is_action_just_pressed("CloseTab"):
tabs[active_tab]._on_close_button_pressed()
if Input.is_action_just_pressed("NextTab"):
var next_tab = (active_tab + 1) % tabs.size()
set_active_tab(next_tab)
if Input.is_action_just_pressed("PreviousTab"):
var prev_tab = (active_tab - 1 + tabs.size()) % tabs.size()
set_active_tab(prev_tab - 1)
func _on_new_tab_button_pressed() -> void:
create_tab()

View File

@@ -0,0 +1 @@
uid://cy0c74thgjwok

View File

@@ -15,8 +15,35 @@ run/main_scene="uid://bytm7bt2s4ak8"
config/features=PackedStringArray("4.4", "Forward Plus")
config/icon="res://icon.svg"
[autoload]
Constants="*res://Scripts/Constants.gd"
[display]
window/size/viewport_width=1920
window/size/viewport_height=1080
window/stretch/aspect="ignore"
[input]
NewTab={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":84,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
CloseTab={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
NextTab={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
PreviousTab={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":true,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}