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