gduibasics/scenes/scripts/dynamic_tabs.gd
2021-08-21 17:15:07 +02:00

175 lines
4.7 KiB
GDScript

extends Control
enum CloseButtonPolicy {
SHOW_NEVER = 0,
SHOW_ACTIVE_ONLY = 1,
SHOW_ALWAYS = 2
}
enum TabAlign {
ALIGN_LEFT = 0,
ALIGN_CENTER = 1,
ALIGN_RIGHT = 2
}
export var current_tab := 0 setget _set_current_tab, _get_current_tab
export var drag_to_rearrange_enabled := false setget _set_drag_to_rearrange_enabled
export var drag_out_enabled := false
export var show_tabs := true setget _set_show_tabs
export(CloseButtonPolicy) var tab_close_display_policy := CloseButtonPolicy.SHOW_NEVER setget _set_tab_close_display_policy
export(TabAlign) var tab_align := TabAlign.ALIGN_CENTER setget _set_tab_align
var __mouse_was_inside := false
#############
# overrides #
#############
func _ready() -> void:
$tabs.connect("tab_changed", self, "_on_tabs_tab_changed")
$tabs.connect("tab_close", self, "_on_tabs_tab_close")
$tabs.connect("reposition_active_tab_request", self, "_on_tabs_reposition_active_tab_request")
$tabs.connect("gui_input", self, "_on_tabs_gui_input")
set_process(false) # only enabled for dragging
func _process(delta : float) -> void:
if !Input.is_mouse_button_pressed(BUTTON_LEFT):
__stop_tab_dragging()
return
var mouse_pos := get_viewport().get_mouse_position()
var mouse_is_inside : bool = $tabs.get_global_rect().has_point(mouse_pos)
if mouse_is_inside == __mouse_was_inside:
return
__mouse_was_inside = mouse_is_inside
if mouse_is_inside:
emit_signal("tab_dragged_in", _get_current_tab(), mouse_pos)
else:
emit_signal("tab_dragged_out", _get_current_tab(), mouse_pos)
################
# public stuff #
################
func add_tab(title : String, control : Control, icon : Texture = null) -> int:
$tabs.add_tab(title, icon)
$container.add_child(control)
var tab := control.get_position_in_parent()
emit_signal("tab_added", tab)
return tab
func move_tab(from : int, to : int) -> void:
$tabs.move_tab(from, to)
$container.move_child($container.get_child(from), to)
func remove_tab(tab : int) -> void:
if tab == current_tab && __is_tab_dragging():
__stop_tab_dragging()
$tabs.remove_tab(tab)
$container.remove_child($container.get_child(tab))
emit_signal("tab_removed", tab)
func find_tab(control : Control) -> int:
for tab in range(get_tab_count()):
if get_tab_control(tab) == control:
return tab
return -1
func remove_all_tabs() -> void:
while $tabs.get_tab_count() > 0:
$tabs.remove_tab(0)
while $container.get_child_count() > 0:
$container.remove_child($container.get_child(0))
func get_tab_control(tab : int) -> Control:
return $container.get_tab_control(tab)
func get_tab_title(tab : int) -> String:
return $tabs.get_tab_title(tab)
func get_tabs() -> Array:
return $container.get_children()
func get_tab_count() -> int:
return $container.get_child_count()
func get_tab_rect(tab : int) -> Rect2:
var rect : Rect2 = $tabs.get_tab_rect(tab)
return $tabs.get_transform().xform_inv(rect)
#################
# private stuff #
#################
func __handle_tabs_gui_input(event : InputEvent) -> void:
if drag_out_enabled \
&& event is InputEventMouseButton \
&& event.pressed \
&& event.button_index == BUTTON_LEFT:
yield(get_tree(), "idle_frame") # wait for the original control to handle the input
var tab_rect : Rect2 = $tabs.get_tab_rect(_get_current_tab())
if tab_rect.has_point(event.position):
__start_tab_dragging()
func __start_tab_dragging() -> void:
__mouse_was_inside = true
set_process(true)
func __stop_tab_dragging() -> void:
set_process(false)
func __is_tab_dragging() -> bool:
return is_processing()
###########
# setters #
###########
func _set_current_tab(tab : int) -> void:
current_tab = tab
$tabs.current_tab = current_tab
func _get_current_tab() -> int:
return $tabs.current_tab
func _set_drag_to_rearrange_enabled(enabled : bool) -> void:
drag_to_rearrange_enabled = enabled
$tabs.drag_to_rearrange_enabled = enabled
func _set_tab_close_display_policy(policy : int) -> void:
tab_close_display_policy = policy
$tabs.tab_close_display_policy = policy
func _set_tab_align(align : int) -> void:
tab_align = align
$tabs.tab_align = align
func _set_show_tabs(show : bool) -> void:
show_tabs = show
$tabs.visible = show
###################
# signal handlers #
###################
func _on_tabs_tab_changed(tab : int) -> void:
current_tab = tab
$container.current_tab = tab
func _on_tabs_tab_close(tab : int) -> void:
emit_signal("tab_close", tab)
func _on_tabs_reposition_active_tab_request(to : int) -> void:
$container.move_child($container.get_child(_get_current_tab()), to)
current_tab = to
func _on_tabs_gui_input(event : InputEvent) -> void:
__handle_tabs_gui_input(event)
###########
# signals #
###########
signal tab_added(tab)
signal tab_removed(tab)
signal tab_close(tab)
signal tab_dragged_out(tab, position)
signal tab_dragged_in(tab, position)