Skip to content

Feat: implement custom property ordering system - #159

Open
dimbodek wants to merge 2 commits into
arimger:masterfrom
dimbodek:feature/property-ordering
Open

dimbodek wants to merge 2 commits into
arimger:masterfrom
dimbodek:feature/property-ordering

Conversation

@dimbodek

Copy link
Copy Markdown

Description

This PR introduces a robust, zero-allocation property ordering system for the Inspector. It allows developers to explicitly define the rendering order of serialized fields without relying on their declaration order in the script.

Changes Made

  • Added [Sortable] attribute: A class-level opt-in attribute. Properties will only be sorted if the parent class is marked with this attribute, ensuring zero performance overhead for standard classes.

  • Added [Order(int)] attribute: A field-level attribute to define explicit rendering priority. Lower numbers are drawn first.

  • Modified ToolboxPropertyHandler.cs:

    • Caches the [Order] attribute data.

    • Provides a static, zero-GC Comparison delegate (ToolboxPropertyHandler.Comparison) to prevent memory allocations during Inspector repaints.

  • Updated ToolboxEditorGui.cs:

    • Modified DrawPropertyChildren to support dynamic sorting.

    • Implemented ListPool to collect properties without generating garbage.

    • Default properties (without [Order]) retain their natural index but are shifted (propsList.Count + 1) to ensure [Order(0)] always takes absolute priority and is pushed to the very top.

Usage Example

To enable sorting, the class must be marked with [Sortable]. Fields can then be reordered using [Order(int)], regardless of where they are declared in the code.

using UnityEngine;

[Sortable] // 1. Opt-in for sorting on the class level
public class CustomOrderingExample : MonoBehaviour
{
    // Declared FIRST in the script, but will be drawn later in the Inspector
    // because they don't have an explicit Order attribute.
    public int someStandardValue = 10;
    public float anotherStandardValue = 20.5f;

    // Declared in the middle, but will be pushed to the very bottom
    [Order(100)] 
    public bool advancedDebugMode = false;

    // Declared at the BOTTOM of the script, but will be drawn FIRST in the Inspector!
    [Order(0)] 
    public string primaryHeader = "Main Settings";

    // Declared at the BOTTOM, but will be drawn SECOND
    [Order(1)]
    [BoxGroup("Data")]
    public Vector3 spawnPoint;
}

Performance Note

The sorting algorithm is executed dynamically during the OnGUI layout pass, but it is heavily optimized. It utilizes ListPool for temporary data collection and a cached static delegate for comparisons, resulting in 0 Bytes of GC Allocation per frame.

- Added `[Sortable]` attribute for class-level opt-in to custom sorting.
- Added `[Order]` attribute for defining explicit property priorities[cite: 2].
- Modified `ToolboxPropertyHandler.cs` to cache order data and provide a zero-GC Comparison delegate[cite: 2].
- Updated `ToolboxEditorGUI.cs` to dynamically sort child properties using `ListPool` with stable indexing[cite: 2].
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant