init
This commit is contained in:
commit
029c00736b
59 changed files with 3819 additions and 0 deletions
85
addons/script-ide/tabbar/custom_tab.gd
Normal file
85
addons/script-ide/tabbar/custom_tab.gd
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
@tool
|
||||
extends Button
|
||||
|
||||
signal close_pressed
|
||||
signal right_clicked
|
||||
signal dragged_over
|
||||
signal dropped(source_index: int, target_index: int)
|
||||
|
||||
var close_button: Button
|
||||
|
||||
func _ready() -> void:
|
||||
icon_alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
action_mode = ACTION_MODE_BUTTON_PRESS
|
||||
auto_translate_mode = Node.AUTO_TRANSLATE_MODE_DISABLED
|
||||
toggle_mode = true
|
||||
|
||||
func show_close_button():
|
||||
if (close_button == null):
|
||||
close_button = create_close_button()
|
||||
|
||||
add_child(close_button)
|
||||
close_button.set_anchors_and_offsets_preset(Control.PRESET_CENTER_RIGHT)
|
||||
|
||||
func hide_close_button():
|
||||
if (close_button != null):
|
||||
remove_child(close_button)
|
||||
|
||||
func create_close_button() -> Button:
|
||||
close_button = Button.new()
|
||||
close_button.icon = EditorInterface.get_editor_theme().get_icon(&"Close", &"EditorIcons")
|
||||
close_button.flat = true
|
||||
close_button.focus_mode = Control.FOCUS_NONE
|
||||
close_button.pressed.connect(on_close_pressed)
|
||||
|
||||
return close_button
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton && event.pressed:
|
||||
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
||||
on_close_pressed()
|
||||
elif (event.button_index == MOUSE_BUTTON_RIGHT):
|
||||
button_pressed = true
|
||||
on_right_click()
|
||||
|
||||
func on_right_click():
|
||||
right_clicked.emit()
|
||||
|
||||
func on_close_pressed() -> void:
|
||||
close_pressed.emit()
|
||||
|
||||
func _get_drag_data(at_position: Vector2) -> Variant:
|
||||
var preview: Button = Button.new()
|
||||
preview.text = text
|
||||
preview.icon = icon
|
||||
preview.icon_alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
preview.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
preview.auto_translate_mode = Node.AUTO_TRANSLATE_MODE_DISABLED
|
||||
preview.add_theme_stylebox_override(&"normal", get_theme_stylebox(&"normal"))
|
||||
|
||||
set_drag_preview(preview)
|
||||
|
||||
var drag_data: Dictionary[String, Variant]
|
||||
drag_data["type"] = "script_list_element"
|
||||
drag_data["script_list_element"] = EditorInterface.get_script_editor().get_current_editor()
|
||||
drag_data["index"] = get_index()
|
||||
|
||||
return drag_data
|
||||
|
||||
func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
|
||||
if !(data is Dictionary):
|
||||
return false
|
||||
|
||||
var can_drop: bool = data.has("index")
|
||||
|
||||
if (can_drop):
|
||||
dragged_over.emit()
|
||||
|
||||
return can_drop
|
||||
|
||||
func _drop_data(at_position: Vector2, data: Variant) -> void:
|
||||
if (!_can_drop_data(at_position, data)):
|
||||
return
|
||||
|
||||
dropped.emit(data["index"], get_index())
|
||||
1
addons/script-ide/tabbar/custom_tab.gd.uid
Normal file
1
addons/script-ide/tabbar/custom_tab.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bppomxp4mri2o
|
||||
434
addons/script-ide/tabbar/multiline_tab_container.gd
Normal file
434
addons/script-ide/tabbar/multiline_tab_container.gd
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
@tool
|
||||
extends PanelContainer
|
||||
|
||||
const CLOSE_BTN_SPACER: String = " "
|
||||
|
||||
const CustomTab := preload("custom_tab.gd")
|
||||
|
||||
@onready var multiline_tab_bar: HFlowContainer = %MultilineTabBar
|
||||
@onready var popup_btn: Button = %PopupBtn
|
||||
|
||||
var tab_hovered: StyleBoxFlat
|
||||
var tab_focus: StyleBoxFlat
|
||||
var tab_selected: StyleBoxFlat
|
||||
var tab_unselected: StyleBoxFlat
|
||||
|
||||
var font_selected_color: Color
|
||||
var font_unselected_color: Color
|
||||
var font_hovered_color: Color
|
||||
|
||||
var show_close_button_always: bool = false : set = set_show_close_button_always
|
||||
var is_singleline_tabs: bool = false : set = set_singleline_tabs
|
||||
|
||||
var tab_group: ButtonGroup = ButtonGroup.new()
|
||||
|
||||
var script_filter_txt: LineEdit
|
||||
var scripts_item_list: ItemList
|
||||
var scripts_tab_container: TabContainer
|
||||
var popup: PopupPanel
|
||||
|
||||
var plugin: EditorPlugin
|
||||
|
||||
var suppress_theme_changed: bool
|
||||
|
||||
var last_drag_over_tab: CustomTab
|
||||
var drag_marker: ColorRect
|
||||
var current_tab: CustomTab
|
||||
|
||||
func _init() -> void:
|
||||
tab_group.pressed.connect(on_new_tab_selected)
|
||||
|
||||
#region Plugin and related tab handling processing
|
||||
func _ready() -> void:
|
||||
popup_btn.pressed.connect(show_popup)
|
||||
|
||||
set_process(false)
|
||||
|
||||
if (plugin != null):
|
||||
schedule_update()
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if (what == NOTIFICATION_DRAG_END || what == NOTIFICATION_MOUSE_EXIT):
|
||||
clear_drag_mark()
|
||||
return
|
||||
|
||||
if (what == NOTIFICATION_THEME_CHANGED):
|
||||
if (suppress_theme_changed):
|
||||
return
|
||||
|
||||
suppress_theme_changed = true
|
||||
add_theme_stylebox_override(&"panel", EditorInterface.get_editor_theme().get_stylebox(&"tabbar_background", &"TabContainer"))
|
||||
suppress_theme_changed = false
|
||||
|
||||
tab_hovered = EditorInterface.get_editor_theme().get_stylebox(&"tab_hovered", &"TabContainer")
|
||||
tab_focus = EditorInterface.get_editor_theme().get_stylebox(&"tab_focus", &"TabContainer")
|
||||
tab_selected = EditorInterface.get_editor_theme().get_stylebox(&"tab_selected", &"TabContainer")
|
||||
tab_unselected = EditorInterface.get_editor_theme().get_stylebox(&"tab_unselected", &"TabContainer")
|
||||
|
||||
if (drag_marker == null):
|
||||
drag_marker = ColorRect.new()
|
||||
drag_marker.set_anchors_and_offsets_preset(PRESET_LEFT_WIDE)
|
||||
drag_marker.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
drag_marker.custom_minimum_size.x = 4 * EditorInterface.get_editor_scale()
|
||||
drag_marker.color = EditorInterface.get_editor_theme().get_color(&"drop_mark_color", &"TabContainer")
|
||||
|
||||
font_hovered_color = EditorInterface.get_editor_theme().get_color(&"font_hovered_color", &"TabContainer")
|
||||
font_selected_color = EditorInterface.get_editor_theme().get_color(&"font_selected_color", &"TabContainer")
|
||||
font_unselected_color = EditorInterface.get_editor_theme().get_color(&"font_unselected_color", &"TabContainer")
|
||||
|
||||
if (plugin == null || multiline_tab_bar == null):
|
||||
return
|
||||
|
||||
for tab: CustomTab in get_tabs():
|
||||
update_tab_style(tab)
|
||||
|
||||
func update_tab_style(tab: CustomTab):
|
||||
tab.add_theme_stylebox_override(&"normal", tab_unselected)
|
||||
tab.add_theme_stylebox_override(&"hover", tab_hovered)
|
||||
tab.add_theme_stylebox_override(&"hover_pressed", tab_hovered)
|
||||
tab.add_theme_stylebox_override(&"focus", tab_focus)
|
||||
tab.add_theme_stylebox_override(&"pressed", tab_selected)
|
||||
|
||||
tab.add_theme_color_override(&"font_color", font_unselected_color)
|
||||
tab.add_theme_color_override(&"font_hover_color", font_hovered_color)
|
||||
tab.add_theme_color_override(&"font_pressed_color", font_selected_color)
|
||||
|
||||
func update_icon_color(tab: CustomTab, color: Color):
|
||||
tab.add_theme_color_override(&"icon_normal_color", color)
|
||||
tab.add_theme_color_override(&"icon_hover_color", color)
|
||||
tab.add_theme_color_override(&"icon_hover_pressed_color", color)
|
||||
tab.add_theme_color_override(&"icon_pressed_color", color)
|
||||
tab.add_theme_color_override(&"icon_focus_color", color)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
sync_tabs_with_item_list()
|
||||
|
||||
if (is_singleline_tabs):
|
||||
shift_singleline_tabs_to(current_tab)
|
||||
|
||||
set_process(false)
|
||||
|
||||
func _shortcut_input(event: InputEvent) -> void:
|
||||
if (!event.is_pressed() || event.is_echo()):
|
||||
return
|
||||
|
||||
if (!is_visible_in_tree()):
|
||||
return
|
||||
|
||||
if (current_tab == null):
|
||||
return
|
||||
|
||||
if (plugin.tab_cycle_forward_shc.matches_event(event)):
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
var tab_count: int = get_tab_count()
|
||||
if (tab_count <= 1):
|
||||
return
|
||||
|
||||
var index: int = current_tab.get_index()
|
||||
var new_tab: int = index + 1
|
||||
if (new_tab == tab_count):
|
||||
new_tab = 0
|
||||
|
||||
var tab: CustomTab = get_tab(new_tab)
|
||||
tab.button_pressed = true
|
||||
elif (plugin.tab_cycle_backward_shc.matches_event(event)):
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
var tab_count: int = get_tab_count()
|
||||
if (tab_count <= 1):
|
||||
return
|
||||
|
||||
var index: int = current_tab.get_index()
|
||||
var new_tab: int = index - 1
|
||||
if (new_tab == -1):
|
||||
new_tab = tab_count - 1
|
||||
|
||||
var tab: CustomTab = get_tab(new_tab)
|
||||
tab.button_pressed = true
|
||||
|
||||
func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
|
||||
if !(data is Dictionary):
|
||||
return false
|
||||
|
||||
var can_drop: bool = data.has("index") && data["index"] != get_tab_count() - 1
|
||||
|
||||
if (can_drop):
|
||||
on_drag_over(get_tab(get_tab_count() - 1))
|
||||
|
||||
return can_drop
|
||||
|
||||
func _drop_data(at_position: Vector2, data: Variant) -> void:
|
||||
if (!_can_drop_data(at_position, data)):
|
||||
return
|
||||
|
||||
on_drag_drop(data["index"], get_tab_count() - 1)
|
||||
#endregion
|
||||
|
||||
func schedule_update():
|
||||
set_process(true)
|
||||
|
||||
func on_drag_drop(source_index: int, target_index: int):
|
||||
var child: Node = scripts_tab_container.get_child(source_index)
|
||||
scripts_tab_container.move_child(child, target_index);
|
||||
|
||||
var tab: CustomTab = get_tab(target_index)
|
||||
tab.grab_focus()
|
||||
|
||||
func on_drag_over(tab: CustomTab):
|
||||
if (last_drag_over_tab == tab):
|
||||
return
|
||||
|
||||
# The drag marker should always be orphan when here.
|
||||
tab.add_child(drag_marker)
|
||||
|
||||
last_drag_over_tab = tab
|
||||
|
||||
func clear_drag_mark():
|
||||
if (last_drag_over_tab == null):
|
||||
return
|
||||
|
||||
last_drag_over_tab = null
|
||||
if (drag_marker.get_parent() != null):
|
||||
drag_marker.get_parent().remove_child(drag_marker)
|
||||
|
||||
func update_tabs():
|
||||
update_script_text_filter()
|
||||
|
||||
for tab: CustomTab in get_tabs():
|
||||
update_tab(tab)
|
||||
|
||||
func get_tabs() -> Array[Node]:
|
||||
return multiline_tab_bar.get_children()
|
||||
|
||||
func update_selected_tab():
|
||||
update_tab(tab_group.get_pressed_button())
|
||||
|
||||
func update_tab(tab: CustomTab):
|
||||
if (tab == null):
|
||||
return
|
||||
|
||||
var index: int = tab.get_index()
|
||||
|
||||
tab.text = scripts_item_list.get_item_text(index)
|
||||
tab.icon = scripts_item_list.get_item_icon(index)
|
||||
tab.tooltip_text = scripts_item_list.get_item_tooltip(index)
|
||||
|
||||
update_icon_color(tab, scripts_item_list.get_item_icon_modulate(index))
|
||||
|
||||
if (scripts_item_list.is_selected(index)):
|
||||
tab.button_pressed = true
|
||||
tab.text += CLOSE_BTN_SPACER
|
||||
elif (show_close_button_always):
|
||||
tab.text += CLOSE_BTN_SPACER
|
||||
|
||||
func get_tab(index: int) -> CustomTab:
|
||||
if (index < 0 || index >= get_tab_count()):
|
||||
return null
|
||||
|
||||
return multiline_tab_bar.get_child(index)
|
||||
|
||||
func get_tab_count() -> int:
|
||||
return multiline_tab_bar.get_child_count()
|
||||
|
||||
func add_tab() -> CustomTab:
|
||||
var tab: CustomTab = CustomTab.new()
|
||||
tab.button_group = tab_group
|
||||
|
||||
if (show_close_button_always):
|
||||
tab.show_close_button()
|
||||
|
||||
update_tab_style(tab)
|
||||
|
||||
tab.close_pressed.connect(on_tab_close_pressed.bind(tab))
|
||||
tab.right_clicked.connect(on_tab_right_click.bind(tab))
|
||||
tab.mouse_exited.connect(clear_drag_mark)
|
||||
tab.dragged_over.connect(on_drag_over.bind(tab))
|
||||
tab.dropped.connect(on_drag_drop)
|
||||
|
||||
multiline_tab_bar.add_child(tab)
|
||||
return tab
|
||||
|
||||
func on_tab_right_click(tab: CustomTab):
|
||||
var index: int = tab.get_index()
|
||||
scripts_item_list.item_clicked.emit(index, scripts_item_list.get_local_mouse_position(), MOUSE_BUTTON_RIGHT)
|
||||
|
||||
func on_new_tab_selected(tab: CustomTab):
|
||||
# Hide and show close button.
|
||||
if (!show_close_button_always):
|
||||
if (current_tab != null):
|
||||
current_tab.hide_close_button()
|
||||
|
||||
if (tab != null):
|
||||
tab.show_close_button()
|
||||
|
||||
update_script_text_filter()
|
||||
|
||||
var index: int = tab.get_index()
|
||||
if (scripts_item_list != null && !scripts_item_list.is_selected(index)):
|
||||
scripts_item_list.select(index)
|
||||
scripts_item_list.item_selected.emit(index)
|
||||
scripts_item_list.ensure_current_is_visible()
|
||||
|
||||
# Remove spacing from previous tab.
|
||||
if (!show_close_button_always && current_tab != null):
|
||||
update_tab(current_tab)
|
||||
current_tab = tab
|
||||
|
||||
## Removes the script filter text and emits the signal so that the tabs stay
|
||||
## and we do not break anything there.
|
||||
func update_script_text_filter():
|
||||
if (script_filter_txt.text != &""):
|
||||
script_filter_txt.text = &""
|
||||
script_filter_txt.text_changed.emit(&"")
|
||||
|
||||
func on_tab_close_pressed(tab: CustomTab) -> void:
|
||||
scripts_item_list.item_clicked.emit(tab.get_index(), scripts_item_list.get_local_mouse_position(), MOUSE_BUTTON_MIDDLE)
|
||||
|
||||
func sync_tabs_with_item_list() -> void:
|
||||
if (plugin == null):
|
||||
return
|
||||
|
||||
if (get_tab_count() > scripts_item_list.item_count):
|
||||
for index: int in range(get_tab_count() - 1, scripts_item_list.item_count - 1, -1):
|
||||
var tab: CustomTab = get_tab(index)
|
||||
|
||||
if (tab == current_tab):
|
||||
current_tab = null
|
||||
|
||||
multiline_tab_bar.remove_child(tab)
|
||||
tab.free()
|
||||
|
||||
for index: int in scripts_item_list.item_count:
|
||||
var tab: CustomTab = get_tab(index)
|
||||
if (tab == null):
|
||||
tab = add_tab()
|
||||
|
||||
update_tab(tab)
|
||||
|
||||
func tab_changed():
|
||||
update_script_text_filter()
|
||||
|
||||
# When the tab change was not triggered by our component,
|
||||
# we need to sync the selection.
|
||||
update_tab(get_tab(scripts_tab_container.current_tab))
|
||||
|
||||
func script_order_changed() -> void:
|
||||
schedule_update()
|
||||
|
||||
func set_popup(new_popup: PopupPanel) -> void:
|
||||
popup = new_popup
|
||||
|
||||
func show_popup() -> void:
|
||||
if (popup == null):
|
||||
return
|
||||
|
||||
scripts_item_list.get_parent().reparent(popup)
|
||||
scripts_item_list.get_parent().visible = true
|
||||
|
||||
popup.size = Vector2(250 * get_editor_scale(), get_parent().size.y - size.y)
|
||||
popup.position = popup_btn.get_screen_position() - Vector2(popup.size.x, 0)
|
||||
popup.popup()
|
||||
|
||||
script_filter_txt.grab_focus()
|
||||
|
||||
func get_editor_scale() -> float:
|
||||
return EditorInterface.get_editor_scale()
|
||||
|
||||
func set_show_close_button_always(new_value: bool):
|
||||
if (show_close_button_always == new_value):
|
||||
return
|
||||
|
||||
show_close_button_always = new_value
|
||||
|
||||
if (multiline_tab_bar == null):
|
||||
return
|
||||
|
||||
for tab: CustomTab in get_tabs():
|
||||
tab.text = scripts_item_list.get_item_text(tab.get_index())
|
||||
if (show_close_button_always):
|
||||
tab.text += CLOSE_BTN_SPACER
|
||||
if (!tab.button_pressed):
|
||||
tab.show_close_button()
|
||||
else:
|
||||
if (!tab.button_pressed):
|
||||
tab.hide_close_button()
|
||||
else:
|
||||
tab.text += CLOSE_BTN_SPACER
|
||||
|
||||
#region Singeline handling
|
||||
func set_singleline_tabs(new_value: bool):
|
||||
if (is_singleline_tabs == new_value):
|
||||
return
|
||||
|
||||
is_singleline_tabs = new_value
|
||||
|
||||
if (is_singleline_tabs):
|
||||
item_rect_changed.connect(update_singleline_tabs_width)
|
||||
tab_group.pressed.connect(ensure_singleline_tab_visible.unbind(1))
|
||||
|
||||
if (multiline_tab_bar == null):
|
||||
return
|
||||
|
||||
shift_singleline_tabs_to(current_tab)
|
||||
else:
|
||||
item_rect_changed.disconnect(update_singleline_tabs_width)
|
||||
tab_group.pressed.disconnect(ensure_singleline_tab_visible)
|
||||
|
||||
if (multiline_tab_bar == null):
|
||||
return
|
||||
|
||||
for tab: CustomTab in get_tabs():
|
||||
tab.visible = true
|
||||
|
||||
func ensure_singleline_tab_visible():
|
||||
if (current_tab != null && current_tab.visible):
|
||||
return
|
||||
|
||||
shift_singleline_tabs_to(current_tab)
|
||||
|
||||
func update_singleline_tabs_width():
|
||||
if (current_tab != null && !current_tab.visible):
|
||||
shift_singleline_tabs_to(current_tab)
|
||||
return
|
||||
|
||||
for tab: CustomTab in get_tabs():
|
||||
if (tab.visible):
|
||||
shift_singleline_tabs_to(tab)
|
||||
break
|
||||
|
||||
func shift_singleline_tabs_to(start_tab: CustomTab):
|
||||
var start: bool
|
||||
var tab_bar_width: float = multiline_tab_bar.size.x
|
||||
var tabs_width: float
|
||||
var one_fit: bool = true
|
||||
|
||||
for tab: CustomTab in get_tabs():
|
||||
if (start_tab == null || tab == start_tab):
|
||||
start = true
|
||||
|
||||
if (start):
|
||||
tabs_width += tab.size.x
|
||||
|
||||
tab.visible = tabs_width <= tab_bar_width
|
||||
one_fit = one_fit || tab.visible
|
||||
else:
|
||||
tab.visible = false
|
||||
|
||||
if (current_tab != null && !current_tab.visible):
|
||||
if (start_tab != current_tab):
|
||||
shift_singleline_tabs_to(current_tab)
|
||||
return
|
||||
|
||||
if (start_tab == null):
|
||||
return
|
||||
|
||||
for index: int in range(start_tab.get_index() - 1, -1, -1):
|
||||
var tab: CustomTab = get_tabs().get(index)
|
||||
|
||||
tabs_width += tab.size.x
|
||||
if (tabs_width > tab_bar_width):
|
||||
return
|
||||
|
||||
tab.visible = true
|
||||
#endregion
|
||||
1
addons/script-ide/tabbar/multiline_tab_container.gd.uid
Normal file
1
addons/script-ide/tabbar/multiline_tab_container.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://l1rdargfn67o
|
||||
39
addons/script-ide/tabbar/multiline_tab_container.tscn
Normal file
39
addons/script-ide/tabbar/multiline_tab_container.tscn
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
[gd_scene format=3 uid="uid://vjuhunm2uboy"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://l1rdargfn67o" path="res://addons/script-ide/tabbar/multiline_tab_container.gd" id="1_8jr3v"]
|
||||
|
||||
[sub_resource type="DPITexture" id="DPITexture_p4126"]
|
||||
_source = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\"><path fill=\"#e0e0e0\" fill-opacity=\".4\" d=\"M8 0a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm0 6a2 2 0 0 0 0 4 2 2 0 0 0 0-4z\"/></svg>
|
||||
"
|
||||
saturation = 1.8
|
||||
color_map = {
|
||||
Color(1, 0.37254903, 0.37254903, 1): Color(1, 0.47, 0.42, 1),
|
||||
Color(0.37254903, 1, 0.5921569, 1): Color(0.45, 0.95, 0.5, 1),
|
||||
Color(1, 0.8666667, 0.39607844, 1): Color(1, 0.87, 0.4, 1)
|
||||
}
|
||||
|
||||
[node name="MultilineTabContainer" type="PanelContainer" unique_id=635880120]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_bottom = 28.0
|
||||
grow_horizontal = 2
|
||||
size_flags_horizontal = 3
|
||||
script = ExtResource("1_8jr3v")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=932291510]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 0
|
||||
|
||||
[node name="MultilineTabBar" type="HFlowContainer" parent="HBoxContainer" unique_id=2135340034]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/h_separation = 0
|
||||
theme_override_constants/v_separation = 0
|
||||
|
||||
[node name="PopupBtn" type="Button" parent="HBoxContainer" unique_id=1586924518]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 8
|
||||
icon = SubResource("DPITexture_p4126")
|
||||
Loading…
Add table
Add a link
Reference in a new issue