175 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			GDScript
		
	
	
	
	
	
			
		
		
	
	
			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)
 |