Skip to content

Instantly share code, notes, and snippets.

@Qubus0
Last active September 8, 2023 12:38
Show Gist options
  • Save Qubus0/8ed13010b6e26bdb529f36336b38e500 to your computer and use it in GitHub Desktop.
Save Qubus0/8ed13010b6e26bdb529f36336b38e500 to your computer and use it in GitHub Desktop.
godot 4 port of custom context menu

Ported by senormagichands on the Godot Discord - thanks!

Quote:

i only listed the methods that have changes - other than it being @tool the rest of the script you wrote should be identical to what i have here.

#DIFFERENCES:
#arrays have is_empty() instead of empty()
#get_signal_connection_list() has callables instead of methods and takes a stringname (&constructed)
#get_method() returns more information about the callable name they are connected to
#popupmenus now have about_to_popup instead of about_to_show
#obviously, new connect syntax
func connect_file_system_context_actions(file_system : FileSystemDock) -> void:
	var file_tree : Tree
	var file_list : ItemList

	for node in file_system.get_children():
		if is_instance_of(node, VSplitContainer):
			file_tree = node.get_child(0)
			file_list = node.get_child(1).get_child(1)
			break

	for node in file_system.get_children():
		var context_menu : PopupMenu = node as PopupMenu
		if not context_menu:
			continue

		var signals := context_menu.get_signal_connection_list(&"id_pressed")
		if not signals.is_empty():
			match signals[0]["callable"].get_method():
				&"FileSystemDock::_tree_rmb_option":
					context_menu.about_to_popup.connect(_on_file_tree_context_actions_about_to_popup.bind(context_menu, file_tree))
				&"FileSystemDock::_file_list_rmb_option":
					context_menu.about_to_popup.connect(_on_file_list_context_actions_about_to_popup.bind(context_menu, file_tree))

#DIFFERENCES:
#one minor one - if doing multiselection you'll need tree.get_next_selected()
#first with a null argument to get the first selected item, and then with the previous selected afterwards
func _on_file_tree_context_actions_about_to_show(context_menu: PopupMenu, tree: Tree) -> void:
    var selected := tree.get_selected()
    if not selected:		# Empty space was clicked
        add_custom_context_actions(context_menu, "")
        return

    # The file system tree only has one column
    var file_path := selected.get_metadata(0) as String
    printt(selected, file_path)
    add_custom_context_actions(context_menu, file_path)

       # If you need multiselection you can modify add_custom_context_actions to take an array
    var selected := tree.get_next_selected(null)
    var file_paths := []
    while selected: 		
        file_paths.append(selected.get_metadata(0))
        selected = tree.get_next_selected(selected)

#DIFFERENCES:
#FileAccess and DirAccess instead of File and Directory
#file_exists was moved to FileAccess since it is a singleton
#DirAccess has dir_exists (relative) and dir_exists_absolute (expectedly, absolute)
func add_custom_context_actions(context_menu: PopupMenu, file_path: String) -> void:
    var dir := Directory.new()
    context_menu.add_separator()

    if file_path == "":
        context_menu.add_item("Clicked empty space")
        # return # ignore the focused item if empty space was clicked

    if DirAccess.dir_exists_absolute(file_path):
        print(file_path)
        context_menu.add_item("A directory is selected")

    if FileAccess.file_exists(file_path):
        context_menu.add_item("A file is selected")

    if "res://addons" in file_path:
        context_menu.add_item("Something in the addons directory is selected")

#get_signal_connection_list() has callables instead of methods and takes a stringname (&constructed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment