Files
agame/addons/asset_drawer/plugin.gd
T
2026-10-03 06:39:17 +08:00

129 lines
4.7 KiB
GDScript

@tool
extends EditorPlugin
const Drawer := preload("res://addons/asset_drawer/drawer.gd")
const L := preload("res://addons/asset_drawer/lang.gd")
# true : Ctrl+Space opens the drawer even when the script editor has focus
# (Ctrl+Space autocompletion is then replaced by the drawer).
# false : in the script editor, Ctrl+Space stays autocompletion.
const OPEN_IN_CODE_EDITOR := true
# true : the open shortcut is ignored while the camera is in free look
# (right mouse button held in the 3D view, or free look toggled with Shift+F).
# This avoids opening the drawer when Ctrl (move down) + Space (move up)
# are pressed together to move around.
const BLOCK_IN_FREELOOK := true
var drawer: Control
var _toolbar_btn: Button
var _theme_check_queued := false
func _enter_tree() -> void:
_create_drawer()
_toolbar_btn = Button.new()
_toolbar_btn.flat = true
_toolbar_btn.tooltip_text = L.t("Asset Drawer (Ctrl+Espace)")
_toolbar_btn.focus_mode = Control.FOCUS_NONE
var base := EditorInterface.get_base_control()
var icon_name := "FolderBrowse" if base.has_theme_icon("FolderBrowse", "EditorIcons") else "Folder"
_toolbar_btn.icon = base.get_theme_icon(icon_name, "EditorIcons")
_toolbar_btn.pressed.connect(func() -> void:
if is_instance_valid(drawer):
drawer.toggle())
add_control_to_container(CONTAINER_TOOLBAR, _toolbar_btn)
add_tool_menu_item("Asset Drawer", Callable(self, "_on_menu_toggle"))
set_process_input(true)
# The drawer follows the editor theme (base color, contrast, accent).
var es := EditorInterface.get_editor_settings()
if not es.settings_changed.is_connected(_on_settings_changed):
es.settings_changed.connect(_on_settings_changed)
func _create_drawer() -> void:
drawer = Drawer.new()
drawer.name = "AssetDrawer"
EditorInterface.get_base_control().add_child(drawer)
func _on_settings_changed() -> void:
# Deferred: we first let the editor regenerate its theme before re-reading the colors.
if _theme_check_queued:
return
_theme_check_queued = true
_check_theme.call_deferred()
func _check_theme() -> void:
_theme_check_queued = false
if not is_instance_valid(drawer) or not drawer.palette_changed():
return
# Recreates the drawer with the new palette. Its state (folder, height, favorites...)
# is already in the config, and is read back by the new drawer.
var was_open: bool = drawer.is_open
var old := drawer
drawer = null
old.get_parent().remove_child(old) # triggers _exit_tree: save + cleanup
old.queue_free()
await get_tree().process_frame # lets the old pill / overlay go away (same names)
if not is_inside_tree():
return
_create_drawer()
if was_open:
drawer.open.call_deferred()
func _exit_tree() -> void:
var es := EditorInterface.get_editor_settings()
if is_instance_valid(es) and es.settings_changed.is_connected(_on_settings_changed):
es.settings_changed.disconnect(_on_settings_changed)
remove_tool_menu_item("Asset Drawer")
if is_instance_valid(_toolbar_btn):
remove_control_from_container(CONTAINER_TOOLBAR, _toolbar_btn)
_toolbar_btn.queue_free()
_toolbar_btn = null
if is_instance_valid(drawer):
drawer.queue_free()
drawer = null
func _on_menu_toggle() -> void:
if is_instance_valid(drawer):
drawer.toggle()
func _is_freelook_active() -> bool:
# During free look, Godot captures the mouse (right button held OR free look
# toggled with Shift+F). The right-click test acts as a safety net.
return Input.mouse_mode == Input.MOUSE_MODE_CAPTURED \
or Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT)
func _input(event: InputEvent) -> void:
if not is_instance_valid(drawer):
return
if not (event is InputEventKey and event.pressed and not event.echo):
return
var key := event as InputEventKey
if key.keycode == KEY_SPACE and key.ctrl_pressed and not key.alt_pressed and not key.shift_pressed and not key.meta_pressed:
# Free look active: we let the key through to the editor (camera movement).
if BLOCK_IN_FREELOOK and _is_freelook_active():
return
# Ctrl+Space is also used for autocompletion: see OPEN_IN_CODE_EDITOR at the top of the file.
if not OPEN_IN_CODE_EDITOR:
var focus := EditorInterface.get_base_control().get_viewport().gui_get_focus_owner()
if focus is TextEdit and not drawer.is_ancestor_of(focus):
return
drawer.toggle()
get_viewport().set_input_as_handled()
elif key.keycode == KEY_ESCAPE and drawer.is_open and not drawer.pinned:
drawer.close()
get_viewport().set_input_as_handled()
elif key.keycode == KEY_V and key.alt_pressed and not key.ctrl_pressed and not key.shift_pressed and not key.meta_pressed:
# Pastes the copied resource from the drawer onto the Inspector resource field hovered by the mouse.
if drawer.try_paste_resource_at_mouse():
get_viewport().set_input_as_handled()