# UI System

Spark provides a panel-based UI framework for managing game windows (inventory, quest log, character sheet, settings, etc.) and a drag-and-drop system for moving items, abilities, and other objects between UI elements.

## UI Panels

### ISparkUIPanel Interface

Every UI panel in Spark implements `ISparkUIPanel`:

```csharp
public interface ISparkUIPanel
{
    string PanelId { get; }
    string DisplayName { get; }
    bool IsVisible { get; }
    int Priority { get; }
    bool IsModal { get; }

    void Show();
    void Hide();
    void Toggle();
    void RefreshDisplay();

    event System.Action OnPanelShown;
    event System.Action OnPanelHidden;
}
```

| Property      | Description                                                                 |
| ------------- | --------------------------------------------------------------------------- |
| `PanelId`     | Unique identifier for this panel. Auto-generated from type name if not set. |
| `DisplayName` | Human-readable name for debugging and UI.                                   |
| `IsVisible`   | Current visibility state.                                                   |
| `Priority`    | Display priority. Higher priority panels render on top.                     |
| `IsModal`     | Whether this panel blocks interaction with panels behind it.                |

### SparkUIPanelBase

The standard base class for UI panels. Inherit from this instead of implementing `ISparkUIPanel` directly:

```csharp
public class InventoryPanel : SparkUIPanelBase
{
    protected override void OnShowPanel()
    {
        // Called when the panel becomes visible
        RefreshInventoryDisplay();
    }

    protected override void OnHidePanel()
    {
        // Called when the panel is hidden
    }

    protected override void OnRefreshDisplay()
    {
        // Called when RefreshDisplay() is invoked
        RefreshInventoryDisplay();
    }

    private void RefreshInventoryDisplay()
    {
        // Update UI elements
    }
}
```

`SparkUIPanelBase` handles:

* CanvasGroup detection for show/hide transitions
* Auto-registration with `SparkUIPanelManager` on `Start()`
* Event publishing when shown/hidden
* Panel ID generation from the type name

Override these virtual methods to add your logic:

| Method               | When It Runs                      |
| -------------------- | --------------------------------- |
| `OnShowPanel()`      | After the panel becomes visible   |
| `OnHidePanel()`      | After the panel is hidden         |
| `OnRefreshDisplay()` | When `RefreshDisplay()` is called |

### SparkUIPanelManager

The static manager tracks all registered panels and provides query and bulk operations:

```csharp
// Find a specific panel
var panel = SparkUIPanelManager.FindPanelById("inventory_panel");

// Find panels by type
var questPanels = SparkUIPanelManager.FindPanelsOfType<QuestPanel>();

// Check state
bool anyOpen = SparkUIPanelManager.HasVisiblePanels;
int openCount = SparkUIPanelManager.VisiblePanelCount;

// Get panels
List<ISparkUIPanel> registered = SparkUIPanelManager.GetRegisteredPanels();
List<ISparkUIPanel> visible = SparkUIPanelManager.GetVisiblePanels();
List<ISparkUIPanel> byPriority = SparkUIPanelManager.GetVisiblePanelsByPriority();

// Bulk operations
SparkUIPanelManager.HideAllPanels();
SparkUIPanelManager.HideAllPanelsExcept(inventoryPanel);
```

### Panel Events

The manager publishes events when panels open or close:

* `UIPanelShownEvent`: A panel became visible.
* `UIPanelHiddenEvent`: A panel was hidden.
* `FirstUIPanelOpenedEvent`: The first panel opened (none were open before).
* `AllUIPanelsClosedEvent`: All panels are now closed.

These events are useful for pausing gameplay, changing input modes, or updating other UI elements.

## Drag and Drop System

Spark includes a complete drag-and-drop framework for moving data between UI slots (inventory items, ability bar slots, equipment slots, etc.).

### Core Components

| Class                    | Role                                                                          |
| ------------------------ | ----------------------------------------------------------------------------- |
| `DragDropManager`        | Central registry for drag-drop handlers.                                      |
| `IDragDropHandler`       | Interface for handling drop operations.                                       |
| `DropSource`             | Component on a UI element that can be dragged from.                           |
| `DropTarget`             | Component on a UI element that can be dropped onto.                           |
| `DragDropCommand`        | Command that carries drop operation data.                                     |
| `DragDropCommandHandler` | Default handler that routes to registered `IDragDropHandler` implementations. |

### IDragDropHandler

Implement this to define what happens when something is dropped:

```csharp
public class InventoryToEquipmentHandler : IDragDropHandler
{
    public bool CanHandle(DragDropCommand command)
    {
        return command.SourceType == "inventory_slot"
            && command.TargetType == "equipment_slot";
    }

    public void Handle(DragDropCommand command)
    {
        // Equip the item from inventory to equipment slot
        string itemId = command.SourceData;
        string slotId = command.TargetData;
        // ...
    }
}
```

### Registering Handlers

Register your drag-drop handlers with the manager:

```csharp
DragDropManager.RegisterHandler(new InventoryToEquipmentHandler());
```

Multiple handlers can be registered. When a drop occurs, the manager finds the first handler where `CanHandle()` returns true.

### DropSource and DropTarget

Add `DropSource` to any UI element that the player can drag from, and `DropTarget` to any element they can drop onto. These components handle the visual feedback and input, and emit `DragDropCommand` instances when a drop completes.

### Debug Visualization

`DragDropDebugUtility` provides visual debugging for drag-and-drop operations during development. Enable it to see source/target highlighting and data flow in the editor.

## Creating a Custom Panel

Here is a complete example of a custom UI panel:

```csharp
using UnityEngine;
using UnityEngine.UI;

public class MountPanel : SparkUIPanelBase
{
    [SerializeField] private Text mountNameText;
    [SerializeField] private Image mountIconImage;
    [SerializeField] private Slider staminaSlider;

    private string _currentMountId;

    public void ShowForMount(string mountId)
    {
        _currentMountId = mountId;
        Show();
    }

    protected override void OnShowPanel()
    {
        RefreshDisplay();
    }

    protected override void OnRefreshDisplay()
    {
        if (string.IsNullOrEmpty(_currentMountId)) return;

        var entry = SparkDatabaseRegistry.GetEntry<MountEntry>(_currentMountId);
        if (entry == null) return;

        mountNameText.text = entry.DisplayName;
        mountIconImage.sprite = entry.Icon;
    }
}
```

Attach it to a Canvas GameObject with a CanvasGroup component. The base class uses the CanvasGroup's alpha and interactable properties to show and hide the panel.

## Best Practices

* Always inherit from `SparkUIPanelBase` rather than implementing `ISparkUIPanel` directly.
* Use `RefreshDisplay()` to update panel contents. Don't update in `Update()` every frame.
* Subscribe to relevant events to know when to refresh (e.g., subscribe to `ItemAddedEvent` for an inventory panel).
* Use `IsModal` for panels that should block interaction (confirmations, settings).
* Clean up subscriptions in `OnHidePanel()` or `OnDestroy()`.
* For drag-and-drop, make `CanHandle()` specific. The first matching handler wins.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sparkframework.dev/documentation/developer-guide/core-systems/ui-system.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
