# View Arrangement Deep Dive

Terminal.Gui provides a powerful **Arrangement** system that enables users to interactively move and resize views using the keyboard and mouse. This system supports both **Tiled** and **Overlapped** layout modes, allowing for flexible UI organization.

See the [Layout Deep Dive](layout.md) for the broader layout system context.

## Table of Contents

- [Overview](#overview)
- [Arrangement Modes](#arrangement-modes)
- [Arrange Mode (Interactive)](#arrange-mode-interactive)
- [Tiled vs Overlapped Layouts](#tiled-vs-overlapped-layouts)
- [Movable Views](#movable-views)
- [Resizable Views](#resizable-views)
- [Creating Resizable Splitters](#creating-resizable-splitters)
- [Modal Views](#modal-views)
- [Runnable Views](#runnable-views)
- [Examples](#examples)

---

## Overview

The [View.Arrangement](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_Arrangement) property controls how users can arrange views within their [SuperView](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_SuperView). The [ViewArrangement](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml) enum provides flags that can be combined to specify arrangement behavior.

### Arrangement Lexicon

[!INCLUDE [Arrangement Lexicon](~/includes/arrangement-lexicon.md)]

### ViewArrangement Flags

The [ViewArrangement](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml) enum supports these flags (can be combined):

- **Fixed** (0) - View cannot be moved or resized (default)
- **Movable** (1) - View can be moved by the user
- **LeftResizable** (2) - Left edge can be resized
- **RightResizable** (4) - Right edge can be resized
- **TopResizable** (8) - Top edge can be resized
- **BottomResizable** (16) - Bottom edge can be resized
- **Resizable** (30) - All edges can be resized (combines all resize flags)
- **Overlapped** (32) - View overlaps other views (enables Z-order)

---

## Arrangement Modes

### Fixed (Default)

Views with [ViewArrangement.Fixed](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml) cannot be moved or resized by the user:

```csharp
var view = new View
{
    Arrangement = ViewArrangement.Fixed // Default
};
```

### Movable

Views with [ViewArrangement.Movable](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml) can be dragged with the mouse or moved with keyboard:

```csharp
var window = new Window
{
    Title = "Movable Window",
    Arrangement = ViewArrangement.Movable
};
```

**User Interaction:**
- **Mouse**: Drag the top [Border](~/api/Terminal.Gui.ViewBase.Border.yml)
- **Keyboard**: Press `Ctrl+F5` to enter Arrange Mode, use arrow keys to move

### Resizable

Views with [ViewArrangement.Resizable](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml) can be resized by the user:

```csharp
var window = new Window
{
    Title = "Resizable Window",
    Arrangement = ViewArrangement.Resizable
};
```

**User Interaction:**
- **Mouse**: Drag any border edge
- **Keyboard**: Press `Ctrl+F5` to enter Arrange Mode, press `Tab` to cycle resize handles

### Movable and Resizable

Combine flags for full desktop-like experience:

```csharp
var window = new Window
{
    Title = "Movable and Resizable",
    Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable
};
```

**Note:** When both `Movable` and `Resizable` are set, the top edge cannot be resized (Movable takes precedence).

### Individual Edge Resizing

For fine-grained control, use individual edge flags:

```csharp
// Only bottom edge resizable
var view = new View
{
    Arrangement = ViewArrangement.BottomResizable
};

// Left and right edges resizable
var view2 = new View
{
    Arrangement = ViewArrangement.LeftResizable | ViewArrangement.RightResizable
};
```

---

## Arrange Mode (Interactive)

**Arrange Mode** is an interactive mode for arranging views using the keyboard. It is activated by pressing the **Arrange Key** (default: `Ctrl+F5`, configurable via [Application.ArrangeKey](~/api/Terminal.Gui.App.Application.yml#Terminal_Gui_App_Application_ArrangeKey)).

### Entering Arrange Mode

When the user presses `Ctrl+F5`:

1. Visual indicators appear on arrangeable views
2. If [ViewArrangement.Movable](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml), a move indicator (`◊`) appears in top-left corner
3. If [ViewArrangement.Resizable](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml), pressing `Tab` cycles to resize indicators
4. Arrow keys move or resize the view
5. Press `Esc`, `Ctrl+F5`, or click outside to exit

### Arrange Mode Indicators

The [Border](~/api/Terminal.Gui.ViewBase.Border.yml) shows visual indicators based on arrangement options:

| Arrangement Flag | Indicator | Location |
|------------------|-----------|----------|
| Movable | `◊` (Glyphs.Move) | Top-left corner |
| Resizable | `⇲` (Glyphs.SizeBottomRight) | Bottom-right corner |
| LeftResizable | `↔` (Glyphs.SizeHorizontal) | Left edge, centered |
| RightResizable | `↔` (Glyphs.SizeHorizontal) | Right edge, centered |
| TopResizable | `↕` (Glyphs.SizeVertical) | Top edge, centered |
| BottomResizable | `↕` (Glyphs.SizeVertical) | Bottom edge, centered |

### Keyboard Controls in Arrange Mode

- **Arrow Keys** - Move or resize based on active mode
- **Tab** - Cycle between move and resize modes (if both available)
- **Shift+Tab** - Cycle backwards
- **Esc** - Exit Arrange Mode
- **Ctrl+F5** - Exit Arrange Mode

### Requirements for Arrangement

For a View to be arrangeable:

1. Must be part of a [SuperView](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_SuperView)
2. Position and dimensions must be independent of other SubViews
3. Must have [View.Arrangement](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_Arrangement) flags set
4. Typically needs a [Border](~/api/Terminal.Gui.ViewBase.Border.yml) for mouse interaction

---

## Tiled vs Overlapped Layouts

### Tiled Layout

In **Tiled** layouts, SubViews typically do not overlap. There is no Z-order; all views are at the same layer.

```csharp
var container = new View { Arrangement = ViewArrangement.Fixed };

var view1 = new View { X = 0, Y = 0, Width = 20, Height = 10 };
var view2 = new View { X = 21, Y = 0, Width = 20, Height = 10 };

container.Add(view1, view2);
// Views are side-by-side, non-overlapping
```

**Characteristics:**
- Default mode for most TUI applications
- Views use [Pos](~/api/Terminal.Gui.Pos.yml) and [Dim](~/api/Terminal.Gui.Dim.yml) for relative positioning
- No Z-order management needed
- More predictable layout behavior

### Overlapped Layout

In **Overlapped** layouts, SubViews can overlap with Z-order determining visual stacking.

Enable overlapped mode with [ViewArrangement.Overlapped](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml):

```csharp
var container = new View 
{ 
    Arrangement = ViewArrangement.Overlapped 
};

var window1 = new Window 
{ 
    X = 5, Y = 3, Width = 40, Height = 15,
    Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped
};

var window2 = new Window 
{ 
    X = 15, Y = 8, Width = 40, Height = 15,
    Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped
};

container.Add(window1, window2);
// window2 will overlap window1
```

**Characteristics:**
- Z-order determined by SubViews collection order
- Later views appear above earlier views
- Tab navigation constrained to current overlapped view
- Use `Ctrl+Tab` / `Ctrl+Shift+Tab` to switch between overlapped views

---

## Movable Views

Views with [ViewArrangement.Movable](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml) can be repositioned by the user.

### Enabling Movable

```csharp
var window = new Window
{
    Title = "Drag Me!",
    X = 10,
    Y = 5,
    Width = 40,
    Height = 15,
    Arrangement = ViewArrangement.Movable,
    BorderStyle = LineStyle.Single
};
```

### Moving with Mouse

- **Click and drag** the top [Border](~/api/Terminal.Gui.ViewBase.Border.yml) to move the view
- The view's [Frame](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_Frame) updates as it moves
- Release the mouse to complete the move

### Moving with Keyboard

1. Press `Ctrl+F5` to enter **Arrange Mode**
2. A move indicator (`◊`) appears in the top-left corner
3. Use **arrow keys** to move the view
4. Press `Esc` or `Ctrl+F5` to exit Arrange Mode

---

## Resizable Views

Views with resizable flags can be resized by the user on specific edges.

### All Edges Resizable

```csharp
var window = new Window
{
    Title = "Resize Me!",
    Arrangement = ViewArrangement.Resizable,
    BorderStyle = LineStyle.Single
};
```

### Specific Edge Resizable

```csharp
// Only right and bottom edges resizable
var view = new View
{
    Arrangement = ViewArrangement.RightResizable | ViewArrangement.BottomResizable,
    BorderStyle = LineStyle.Single
};
```

### Resizing with Mouse

- **Click and drag** any enabled border edge
- Resize indicators appear on hover
- The view's [Width](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_Width) and [Height](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_Height) update

### Resizing with Keyboard

1. Press `Ctrl+F5` to enter **Arrange Mode**
2. Press `Tab` to cycle to resize mode
3. Resize indicator (`⇲`) appears
4. Use **arrow keys** to resize
5. Press `Esc` or `Ctrl+F5` to exit

---

## Creating Resizable Splitters

A common pattern in tiled layouts is creating a resizable splitter between two panes.

### Horizontal Splitter (Left/Right Panes)

```csharp
View leftPane = new ()
{
    X = 0,
    Y = 0,
    Width = Dim.Fill(Dim.Func(_ => rightPane.Frame.Width)),
    Height = Dim.Fill(),
    BorderStyle = LineStyle.Single
};

View rightPane = new ()
{
    X = Pos.Right(leftPane) - 1,
    Y = 0,
    Width = Dim.Fill(),
    Height = Dim.Fill(),
    Arrangement = ViewArrangement.LeftResizable,
    BorderStyle = LineStyle.Single,
    SuperViewRendersLineCanvas = true
};
rightPane.Border.Thickness = new Thickness(1, 0, 0, 0); // Only left border

container.Add(leftPane, rightPane);
```

**How it works:**
- `rightPane` has [ViewArrangement.LeftResizable](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml) - its left border is draggable
- `leftPane` uses [Dim.Fill](~/api/Terminal.Gui.Dim.yml) with a function to fill remaining space
- `SuperViewRendersLineCanvas = true` ensures proper line rendering
- Only the left border is visible, acting as the splitter

### Vertical Splitter (Top/Bottom Panes)

```csharp
View topPane = new ()
{
    X = 0,
    Y = 0,
    Width = Dim.Fill(),
    Height = Dim.Fill(Dim.Func(_ => bottomPane.Frame.Height)),
    BorderStyle = LineStyle.Single
};

View bottomPane = new ()
{
    X = 0,
    Y = Pos.Bottom(topPane) - 1,
    Width = Dim.Fill(),
    Height = Dim.Fill(),
    Arrangement = ViewArrangement.TopResizable,
    BorderStyle = LineStyle.Single,
    SuperViewRendersLineCanvas = true
};
bottomPane.Border.Thickness = new Thickness(1, 0, 0, 0); // Only top border

container.Add(topPane, bottomPane);
```

---

## Modal Views

**Modal** views run as exclusive applications that capture all user input until closed.

See the [Multitasking Deep Dive](multitasking.md) for complete details on modal execution.

### What Makes a View Modal

A view is modal when:
- Run via [Application.Run](~/api/Terminal.Gui.App.Application.yml#Terminal_Gui_App_Application_Run_Terminal_Gui_Views_Toplevel_System_Func_System_Exception_System_Boolean__)
- [Toplevel.Modal](~/api/Terminal.Gui.Views.Toplevel.yml#Terminal_Gui_Views_Toplevel_Modal) = `true`

### Modal Characteristics

- **Exclusive Input** - All keyboard and mouse input goes to the modal view
- **Constrained Z-Order** - Modal view has Z-order of 1, everything else at 0
- **Blocks Execution** - `Application.Run` blocks until [Application.RequestStop](~/api/Terminal.Gui.App.Application.yml#Terminal_Gui_App_Application_RequestStop_Terminal_Gui_Views_Toplevel_) is called
- **Own RunState** - Each modal view has its own [RunState](~/api/Terminal.Gui.App.RunState.yml)

### Modal View Types

- [Dialog](~/api/Terminal.Gui.Views.Dialog.yml) - Centered modal window with button support
- [MessageBox](~/api/Terminal.Gui.Views.MessageBox.yml) - Simple message dialogs
- [Wizard](~/api/Terminal.Gui.Views.Wizard.yml) - Multi-step modal dialogs

### Modal Example

```csharp
var dialog = new Dialog
{
    Title = "Confirm",
    Width = 40,
    Height = 10
};

var label = new Label 
{ 
    Text = "Are you sure?", 
    X = Pos.Center(), 
    Y = 2 
};
dialog.Add(label);

var ok = new Button { Text = "OK" };
ok.Accepting += (s, e) => Application.RequestStop();
dialog.AddButton(ok);

// Run modally - blocks until closed
Application.Run(dialog);

// Dialog has been closed
```

---

## Runnable Views

**Runnable** views are those run via [Application.Run](~/api/Terminal.Gui.App.Application.yml). Each non-modal Runnable view operates as a self-contained "application" with its own [RunState](~/api/Terminal.Gui.App.RunState.yml).

See the [Multitasking Deep Dive](multitasking.md) for complete details.

### Non-Modal Runnable Views

```csharp
var toplevel = new Toplevel
{
    Modal = false // Non-modal
};

// Runs as independent application
Application.Run(toplevel);
```

**Characteristics:**
- Has its own `RunState`
- Events dispatched independently
- Can run on separate threads
- See `BackgroundWorkerCollection` for multi-threaded examples

### Modal vs Non-Modal Runnable

| Aspect | Modal | Non-Modal |
|--------|-------|-----------|
| Input | Exclusive | Shared |
| Z-Order | Constrained (1 vs 0) | Full Z-order support |
| Blocks Execution | Yes | No |
| Use Case | Dialogs, confirmations | Multi-window apps |

---

## Tiled vs Overlapped Layouts

### Tiled Layout (Default)

SubViews do not overlap, positioned side-by-side or top-to-bottom:

```csharp
var container = new View();

var left = new View 
{ 
    X = 0, 
    Y = 0, 
    Width = Dim.Percent(50), 
    Height = Dim.Fill() 
};

var right = new View 
{ 
    X = Pos.Right(left), 
    Y = 0, 
    Width = Dim.Fill(), 
    Height = Dim.Fill() 
};

container.Add(left, right);
```

**Benefits:**
- Simpler layout logic
- No Z-order management
- More predictable behavior
- Standard for most TUI applications

### Overlapped Layout

SubViews can overlap with Z-order determining which is on top:

```csharp
var container = new View 
{ 
    Arrangement = ViewArrangement.Overlapped 
};

var window1 = new Window 
{ 
    X = 5, 
    Y = 3, 
    Width = 40, 
    Height = 15,
    Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped
};

var window2 = new Window 
{ 
    X = 15, 
    Y = 8, 
    Width = 40, 
    Height = 15,
    Arrangement = ViewArrangement.Movable | ViewArrangement.Overlapped
};

container.Add(window1, window2);
// window2 appears on top of window1
```

**Z-Order:**
- Order in [View.SubViews](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_SubViews) determines Z-order
- Later views appear above earlier views
- Use [View.BringSubviewToFront](~/api/Terminal.Gui.ViewBase.View.yml) to change Z-order

**Navigation:**
- `Tab` / `Shift+Tab` - Navigate within current overlapped view
- `Ctrl+Tab` (`Ctrl+PageDown`) - Switch to next overlapped view
- `Ctrl+Shift+Tab` (`Ctrl+PageUp`) - Switch to previous overlapped view

---

## Examples

### Example 1: Movable and Resizable Window

```csharp
using Terminal.Gui;

Application.Init();

var window = new Window
{
    Title = "Drag and Resize Me! (Ctrl+F5 for keyboard mode)",
    X = Pos.Center(),
    Y = Pos.Center(),
    Width = 50,
    Height = 15,
    Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable,
    BorderStyle = LineStyle.Double
};

var label = new Label
{
    Text = "Try dragging the border with mouse\nor press Ctrl+F5!",
    X = Pos.Center(),
    Y = Pos.Center()
};
window.Add(label);

Application.Run(window);
Application.Shutdown();
```

### Example 2: Horizontal Resizable Splitter

```csharp
Application.Init();

var top = new Toplevel();

var leftPane = new FrameView
{
    Title = "Left Pane",
    X = 0,
    Y = 0,
    Width = Dim.Fill(Dim.Func(_ => rightPane.Frame.Width)),
    Height = Dim.Fill()
};

var rightPane = new FrameView
{
    Title = "Right Pane (drag left edge)",
    X = Pos.Right(leftPane) - 1,
    Y = 0,
    Width = Dim.Fill(),
    Height = Dim.Fill(),
    Arrangement = ViewArrangement.LeftResizable,
    SuperViewRendersLineCanvas = true
};
rightPane.Border.Thickness = new Thickness(1, 0, 0, 0);

top.Add(leftPane, rightPane);

Application.Run(top);
Application.Shutdown();
```

### Example 3: Overlapped Windows

```csharp
Application.Init();

var desktop = new Toplevel 
{ 
    Arrangement = ViewArrangement.Overlapped 
};

var window1 = new Window
{
    Title = "Window 1",
    X = 5,
    Y = 3,
    Width = 40,
    Height = 12,
    Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable | ViewArrangement.Overlapped
};

var window2 = new Window
{
    Title = "Window 2 (overlaps Window 1)",
    X = 15,
    Y = 8,
    Width = 40,
    Height = 12,
    Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable | ViewArrangement.Overlapped
};

desktop.Add(window1, window2);

Application.Run(desktop);
Application.Shutdown();
```

### Example 4: Custom Arrange Key

```csharp
using Terminal.Gui;
using Terminal.Gui.Configuration;

// Change the arrange key
Application.ArrangeKey = Key.F2;

var window = new Window
{
    Title = "Press F2 to enter arrange mode",
    Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable
};

Application.Run(window);
```

---

## Advanced Topics

### Constraints and Limitations

Arrangement only works when:

1. **View has a SuperView** - Root views cannot be arranged
2. **Independent Position/Size** - Views with [Pos.Align](~/api/Terminal.Gui.Pos.yml) or complex [Dim](~/api/Terminal.Gui.Dim.yml) constraints may not resize properly
3. **Border Required** - Mouse-based arrangement requires a visible [Border](~/api/Terminal.Gui.ViewBase.Border.yml)

### SuperViewRendersLineCanvas

When creating splitters, set [View.SuperViewRendersLineCanvas](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_SuperViewRendersLineCanvas) = `true`:

```csharp
rightPane.SuperViewRendersLineCanvas = true;
```

This ensures [LineCanvas](~/api/Terminal.Gui.Drawing.LineCanvas.yml) properly handles line intersections at borders.

### Z-Order Management

For overlapped views, manage Z-order with:

```csharp
// Bring a view to the front
container.BringSubviewToFront(window1);

// Send a view to the back
container.SendSubviewToBack(window2);

// Check current order
int index = container.SubViews.IndexOf(window1);
```

### Arrangement Events

Monitor arrangement changes by handling layout events:

```csharp
view.FrameChanged += (s, e) =>
{
    Console.WriteLine($"View moved/resized to {e.NewValue}");
};

view.LayoutComplete += (s, e) =>
{
    // Layout has completed after arrangement change
};
```

---

## See Also

- **[Layout Deep Dive](layout.md)** - Overall layout system
- **[View Deep Dive](View.md)** - View base class
- **[Multitasking Deep Dive](multitasking.md)** - Modal and runnable views
- **[Drawing Deep Dive](drawing.md)** - LineCanvas and borders
- **[Configuration Deep Dive](config.md)** - Configuring Application.ArrangeKey

### API Reference

- [View.Arrangement](~/api/Terminal.Gui.ViewBase.View.yml#Terminal_Gui_ViewBase_View_Arrangement)
- [ViewArrangement](~/api/Terminal.Gui.ViewBase.ViewArrangement.yml)
- [Border](~/api/Terminal.Gui.ViewBase.Border.yml)
- [Application.ArrangeKey](~/api/Terminal.Gui.App.Application.yml#Terminal_Gui_App_Application_ArrangeKey)
- [Toplevel.Modal](~/api/Terminal.Gui.Views.Toplevel.yml#Terminal_Gui_Views_Toplevel_Modal)

### UICatalog Examples

The UICatalog application demonstrates arrangement:

- **Arrangement Editor** - Interactive arrangement demonstration
- **Overlapped** scenario - Shows overlapped window management
- **Splitter** examples - Various splitter configurations
