DrawGUI.Scope

Abstract base class for IDisposable layout scopes in the Paragon Editor. Scopes wrap Unity's Begin/End IMGUI patterns into using blocks with support for chaining multiple scopes via Push(). Concrete implementations (HorizontalLayout, VerticalLayout, Box, Colorize, etc.) live in the Scopes/ subsystem.

Definition

Namespace: Paragon.Editor Assembly: Paragon.Editor.dll

public static partial class DrawGUI
{
    public abstract class Scope : IDisposable
}

Implements: IDisposable

Remarks

Unity's IMGUI requires explicit Begin/End call pairs (e.g., BeginHorizontal/EndHorizontal). Forgetting an End call causes layout errors. DrawGUI.Scope solves this by wrapping these pairs into IDisposable objects that can be used with using blocks, guaranteeing End is called even if exceptions occur.

Scope Lifecycle

  1. Constructor — Concrete scope is created, calls Begin() which calls OnBegin()

  2. Content — GUI code runs inside the using block

  3. Dispose — When the using block exits, Dispose() is called:

    • First, all pushed (nested) scopes are disposed in LIFO order

    • Then End() calls OnEnd() on the outer scope

Scope Chaining

The Push() method enables composing multiple scopes in a single using block. Each pushed scope is stored on an internal stack and disposed before the parent scope when the using block exits:

Extension methods on Scope (defined in the Scopes/ subsystem files) provide fluent chaining syntax like .HorizontalLayout(), .Colorize(), etc.

Quick Lookup

Goal
How

Use a scope

using (DrawGUI.HorizontalLayout()) { ... }

Chain scopes

using (DrawGUI.VerticalLayout().HorizontalLayout()) { ... }

Push a scope manually

scope.Push(new MyScope())

Create a custom scope

Subclass Scope, override OnBegin() and OnEnd()

Fields

Field
Type
Access
Description

stack

Stack<Scope>

private

Lazily-initialized stack of pushed child scopes

Methods

Push

Pushes a child scope onto this scope's internal stack. The child will be disposed before this scope when the using block exits. Returns this for fluent chaining.

Parameter
Type
Description

scope

Scope

The child scope to push

Returns: this — enables fluent chaining.

Begin (protected)

Calls OnBegin(). Invoked by concrete scope constructors.

OnBegin (abstract)

Override to implement the Begin call (e.g., EditorGUILayout.BeginHorizontal).

OnEnd (abstract)

Override to implement the End call (e.g., EditorGUILayout.EndHorizontal).

Dispose (explicit IDisposable)

Unwinds all pushed scopes (LIFO order), then calls End() on this scope.

Algorithm:

  1. While the stack has scopes, pop and dispose each one

  2. Null out the stack

  3. Call End()OnEnd()

Extension Points

Creating a Custom Scope

Subclass Scope and override OnBegin() / OnEnd(). Call Begin() in the constructor:

Implementation Requirements

When subclassing Scope, you MUST:

  1. Override OnBegin() — called when the scope starts

  2. Override OnEnd() — called when the scope is disposed (cleanup/restore)

  3. Call Begin() in the constructor — this triggers OnBegin()

You SHOULD:

  • Provide a static factory method on DrawGUI for creation (e.g., DrawGUI.MyScope())

  • Provide an extension method on Scope for chaining (e.g., scope.MyScope())

  • Store and restore any modified GUI state in OnBegin/OnEnd

You MUST NOT:

  • Override Dispose() — it is explicitly implemented and handles the push stack

  • Call End() directly — it is private; use Dispose() (via using)

Common Pitfalls

circle-exclamation
circle-exclamation
circle-exclamation

Examples

Basic Layout Scope

Chained Scopes

Nested Scopes

See Also

Last updated