Introduction to Filedini Python Scripting

This document is a tutorial for learning how to use the application’s scripting features. Starting with basic operations, you will gradually learn to create advanced dialogs.


日本語 (Japanese)

Introduction: Basic Script Structure and Dev Environment Tips

All scripts interact with the application through a global object named host. When defining a function that uses the host object’s features, you must always accept (host: HostAPI) as an argument.

# Example: A simple function that logs a message
def my_script_function(host: HostAPI):
    host.log("Script was executed!")

Leveraging Type Hints and Autocompletion

By adding the following “Type Checking Block” to the top of your script file, you can enable powerful autocompletion (IntelliSense) for the host object’s methods and properties in Integrated Development Environments (IDEs) like VS Code. This can greatly improve your development efficiency.

from __future__ import annotations
from typing import TYPE_CHECKING

# =============================================================================
# Type Checking Block - Enables autocompletion in IDEs
# =============================================================================
# This block is used only by code editors (like VS Code) to provide
# intelligent code completion. It does not run during actual script execution.
if TYPE_CHECKING:
    try:
        # Import the type definition for 'HostAPI' from 'host_stubs'.
        # This is a virtual module that doesn't exist at runtime.
        from host_stubs import HostAPI
    except ImportError:
        pass

# This allows you to write 'host: HostAPI' in your function definitions,
# enabling autocompletion for the host object's methods.

Chapter 1: Basic Operations

As a first step in scripting, let’s learn how to get the application’s state and display simple messages. The content of this chapter is mainly based on command_sample.py.

1.1 Logging Messages

To check your script’s behavior, you can output messages to the application’s log. This is very useful for debugging.

Use the host.log() method.

def log_example(host: HostAPI):
    # Outputs a message to the application log
    host.log("Hello, World!")

1.2 Getting Application State

You can use the host.state module to get the path of the currently open folder or information about selected items.

  • host.state.get_current_folder_path(): Gets the current folder path.
  • host.state.get_cursor_path(): Gets the path of the item under the cursor.
  • host.state.get_selected_paths(): Gets a list of paths for all selected items.

Example: Calculate the total size of selected items

import os

# Helper function (assumed to be defined in the file)
def get_directory_size(folder_path: str) -> int:
    total_size = 0
    if not os.path.exists(folder_path) or not os.path.isdir(folder_path):
        return 0
    for dirpath, dirnames, filenames in os.walk(folder_path):
        for f in filenames:
            fp = os.path.join(dirpath, f)
            if not os.path.islink(fp):
                try:
                    total_size += os.path.getsize(fp)
                except OSError:
                    pass
    return total_size

def get_readable_size(total_bytes: int) -> str:
    # ... logic for formatting size ...
    if total_bytes < 1024:
        return f"{total_bytes} Bytes"
    elif total_bytes < (1024**2):
        return f"{total_bytes / 1024:.2f} KB"
    elif total_bytes < (1024**3):
        return f"{total_bytes / (1024**2):.2f} MB"
    else:
        return f"{total_bytes / (1024**3):.2f} GB"

def calculate_selected_size(host: HostAPI):
    # 1. Get the paths of all selected items
    selected_paths = host.state.get_selected_paths()

    if not selected_paths:
        host.ui.ok_dialog("Selected Size", "No items are selected.")
        return

    total_bytes = 0

    # 2. Sum the size of each item
    for path in selected_paths:
        if os.path.isdir(path):
            total_bytes += get_directory_size(path)
        elif os.path.isfile(path):
            total_bytes += os.path.getsize(path)

    # 3. Display the result in a dialog
    host.ui.ok_dialog(
        "Selected Items Size",
        f"Items: {len(selected_paths)}\nTotal Size: {get_readable_size(total_bytes)}"
    )

1.3 Displaying Simple Dialogs

To inform the user of a script’s result, you can display simple dialog boxes. The host.ui module provides several predefined dialogs.

  • host.ui.ok_dialog(title, message): A dialog with only an [OK] button.
  • host.ui.ok_cancel_dialog(title, message): A dialog with [OK] and [Cancel] buttons.
  • host.ui.input_text_dialog(title, message, initial_text): A dialog with a text input field. It returns an InputTextDialogResponse object.
  • host.ui.yes_no_dialog(title, message): A dialog with [Yes] and [No] buttons. It returns DialogResult.YES or DialogResult.NO depending on the user’s choice.

Example: Displaying an [OK] Dialog

def show_simple_ok_dialog(host: HostAPI):
    host.ui.ok_dialog("Folder Size", "The total size is 123 MB.")

Using the Text Input Dialog

The host.ui.input_text_dialog is used to get text input from the user. This function returns an InputTextDialogResponse object, which contains the dialog’s result (.result) and the text the user entered (.text).

Example: Asking the user for their name

def ask_for_name(host: HostAPI):
    # Show the text input dialog and receive the response
    response = host.ui.input_text_dialog("User Info", "Please enter your name:", "Anonymous")

    # Check the result to branch the logic
    if response.result == host.ui.DialogResult.OK:
        # If OK was pressed, get the entered text
        name = response.text
        host.log(f"User entered name: {name}")
        host.ui.ok_dialog("Hello", f"Hello, {name}!")
    else:
        # If Cancel was pressed
        host.log("User cancelled name entry.")
        host.ui.ok_dialog("Cancelled", "Name entry was cancelled.")

Branching Logic with Return Values

Dialogs with multiple buttons, like ok_cancel_dialog and yes_no_dialog, return a value depending on which button was pressed. By checking this return value (host.ui.DialogResult), you can change your script’s behavior based on the user’s choice.

Example: Confirming an action with the user

def confirm_action(host: HostAPI):
    # Display an OK/Cancel dialog and get the user's choice
    result = host.ui.ok_cancel_dialog("Confirm", "Do you want to proceed?")

    # Check the return value to branch the logic
    if result == host.ui.DialogResult.OK:
        # Action for when OK is pressed
        host.log("User chose to proceed.")
        host.ui.ok_dialog("Proceeding", "The action will be performed.")
    else:
        # Action for when Cancel is pressed or the dialog is closed
        host.log("User cancelled the action.")
        host.ui.ok_dialog("Cancelled", "The action was cancelled.")

1.4 Using Python Libraries

In your scripts, you can freely import and use Python’s standard libraries (such as os, sys, datetime, etc.). This allows you to easily perform complex tasks like file operations and date calculations.

Installing and Using External Libraries

Furthermore, by using the host.install() method, you can install and use external libraries published on PyPI (e.g., numpy, requests, pandas) during script execution.

host.install() will only perform the installation if the library is not already installed. If it’s already available, it does nothing.

Example: Installing and using the numpy library

def use_numpy_example(host: HostAPI):
    # 1. Request the installation of the 'numpy' package.
    #    This ensures the library is available before importing.
    if host.install("numpy"):
        # 2. Import the library.
        import numpy as np

        # 3. Use the library's features.
        arr = np.array([1, 2, 3])
        
        # 4. Display the result in a dialog.
        host.ui.ok_dialog(
            "NumPy Example",
            f"NumPy version {np.__version__} is available.\nCreated array: {arr}"
        )
    else:
        host.ui.ok_dialog(
            "NumPy Example",
            "Failed to install NumPy."
        )

Chapter 2: Creating Custom Dialogs

The host.ui feature allows you to create custom dialogs with freely arranged text inputs and buttons. This chapter is based on custom_dialog_sample.py.

2.1 Basic Dialog Structure

  1. Start the dialog builder with host.ui.dialog(title).
  2. Add controls (text boxes, buttons, etc.) to the builder.
  3. Display the dialog modally with dlg.show_modal() and wait for the user to close it.
  4. Use the return value of show_modal() to determine which button was pressed.

2.2 Adding Controls and Handling Events

  • Text Input: dlg.text(label, initial_text)
  • Button: dlg.button(text)

The action for a button click is defined by adding a lambda expression or a function to the .clicked event with +=.

To close the dialog, call dlg.close(result), where result can be host.ui.DialogResult.OK, host.ui.DialogResult.CANCEL, etc.

Example: A simple input dialog

def show_modal_dialog_example(host: HostAPI):
    # 1. Create a dialog builder
    dlg = host.ui.dialog("Modal Dialog Sample")

    # 2. Add a text input control with the label "Enter your name"
    name_input = dlg.text("Enter your name", "no-name")

    # 3. Add a button and define its click event
    #    When the "Close" button is pressed, close the dialog with an OK result
    close_button = dlg.button("Close")
    close_button.clicked += lambda s, e: dlg.close(host.ui.DialogResult.OK)

    # 4. Show the dialog and wait for the user\'s action
    result = dlg.show_modal()

    # 5. Process after the user presses the "Close" button
    if result == host.ui.DialogResult.OK:
        # Get the value from the text input and log it
        host.log(f"Name entered: {name_input.text}")

2.3 Grouping Controls

You can arrange controls horizontally or vertically using dlg.group(direction).

  • host.ui.LayoutDirection.HORIZONTAL: Arrange horizontally
  • host.ui.LayoutDirection.VERTICAL: Arrange vertically (default)

Example: Arranging buttons horizontally

def show_horizontal_buttons(host: HostAPI):
    dlg = host.ui.dialog("Confirmation")
    # Create a horizontal group
    buttons_group = dlg.group(host.ui.LayoutDirection.HORIZONTAL)

    # Controls added to this group will be arranged side-by-side
    buttons_group.button("Yes").clicked += lambda s, e: dlg.close(host.ui.DialogResult.YES)
    buttons_group.button("No").clicked += lambda s, e: dlg.close(host.ui.DialogResult.NO)

    dlg.show_modal()

Chapter 3: Building Advanced UIs

Based on advanced_dialog_sample.py, let’s learn how to create dialogs with more complex layouts and a variety of controls.

3.1 Diverse Controls

In custom dialogs, you can use many controls besides text inputs and buttons.

  • Checkbox: dlg.bool(label, initial_value)
  • Integer Slider: dlg.int(label, initial_value, min, max)
  • Float Slider: dlg.float(label, initial_value, min, max)
  • Choice (Dropdown/Radio Button): dlg.choice(label, items_list, initial_index, style)
  • Label: dlg.label(text)
  • Separator: dlg.separator()

You can access the current value of each control through its value property.

3.2 Advanced Layouts

To build complex UIs, you can nest groups and use tabs or group boxes.

  • Group Box: dlg.group_box(title, direction)
    • Surrounds controls with a titled border.
  • Tab: dlg.tab()
    • Add tab pages with tab.page(title) and place controls on them.

Example: A settings-like dialog

def show_settings_dialog(host: HostAPI):
    dlg = host.ui.dialog("Settings")

    # 1. Create a tab control
    tab = dlg.tab()

    # 2. Create a "General" tab page and add controls
    general_page = tab.page("General")
    general_page.bool("Auto-save", True)
    general_page.int("Font size:", 12, 8, 24)

    # 3. Create an "Appearance" tab page and add controls
    appearance_page = tab.page("Appearance")
    themes = ["Light", "Dark", "Auto"]
    theme_choice = appearance_page.choice("Theme", themes, 0)
    scale_slider = appearance_page.float("UI Scale:", 1.0, 0.5, 2.0)

    # 4. Add OK/Cancel buttons
    buttons = dlg.group(host.ui.LayoutDirection.HORIZONTAL)
    buttons.button("Apply").clicked += lambda s, e: dlg.close(host.ui.DialogResult.OK)
    buttons.button("Cancel").clicked += lambda s, e: dlg.close(host.ui.DialogResult.CANCEL)

    # Show the dialog
    result = dlg.show_modal()

    # If OK, log the settings
    if result == host.ui.DialogResult.OK:
        host.log("Settings applied!")
        host.log(f"  Theme: {theme_choice.selected_item}")
        host.log(f"  UI Scale: {scale_slider.value}")

3.3 Leveraging Events

Each control has events that fire when its value changes (e.g., text_changed, value_changed, selected_changed). Using these, you can create dynamic dialogs that react to user actions in real-time.

Example: Linking a checkbox and a slider

def show_linked_controls_dialog(host: HostAPI):
    dlg = host.ui.dialog("Linked Controls")
    left = dlg.group(host.ui.LayoutDirection.VERTICAL)

    # "Enabled" checkbox
    enabled_check = left.bool("Enabled", True)

    # Integer slider
    int_slider = left.int("Int", 10, -100, 100)

    # Toggle the slider\'s enabled state when the checkbox value changes
    def on_enabled_changed(s, e):
        int_slider.enabled = enabled_check.value

    enabled_check.value_changed += on_enabled_changed

    dlg.group(host.ui.LayoutDirection.HORIZONTAL).button("Close").clicked += \
        lambda s, e: dlg.close(host.ui.DialogResult.OK)
    dlg.show_modal()

In this tutorial, you’ve learned everything from the basics of scripting to more advanced topics. Try modifying these samples or consulting the API reference to create your own useful scripts.


The API is still under development and is not yet fully sufficient. Please feel free to share any requests you may have.