mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Initial plan * Enable VT processing in WindowsOutput to support hyperlink detection Co-authored-by: tig <585482+tig@users.noreply.github.com> * Address code review feedback - track VT enablement and add error handling Co-authored-by: tig <585482+tig@users.noreply.github.com> * Revert VT processing changes - investigating actual root cause Co-authored-by: tig <585482+tig@users.noreply.github.com> * Implement OSC 8 hyperlink support in Attribute and OutputBase Co-authored-by: tig <585482+tig@users.noreply.github.com> * Implement automatic URL detection with OSC 8 at driver level Co-authored-by: tig <585482+tig@users.noreply.github.com> * Fix OSC 8 URL wrapping to handle ANSI escape sequences properly Co-authored-by: tig <585482+tig@users.noreply.github.com> * Update newinv2.md Terminal.Gui v2 introduces a reimagined architecture, removing redundant and overly complex code from v1. Key changes include: - Added TrueColor support with 24-bit RGB handling. - Introduced modular adornments framework (Margin, Border, Padding). - Enhanced Unicode and wide character support for internationalization. - Simplified API with centralized navigation and modern .NET standards. - Added built-in scrolling via `Viewport` and improved `ScrollBar`. - Introduced new views (Bar, CharMap, ColorPicker, etc.) and enhanced existing ones. - Added `ConfigurationManager` for customizable themes and settings. - Improved visual fidelity with `LineCanvas`, gradients, and borders. - Introduced logging, metrics, and Sixel image support. - Enhanced keyboard and mouse APIs for better interaction handling. - Ensured AOT compatibility for simplified deployment. These changes modernize the library, improve usability, and expand its capabilities for terminal-based applications. * Remove automatic URL detection - reverting to clean state Co-authored-by: tig <585482+tig@users.noreply.github.com> * Revamp View.md documentation for clarity and depth Comprehensively restructured and enhanced the `View.md` documentation for the `Terminal.Gui` library to improve usability and completeness. - Added a Table of Contents for easier navigation. - Rewrote the "View Hierarchy" section to clarify terminology and key properties, with links to relevant API references. - Expanded "View Composition" and "Core Concepts" sections with detailed explanations of layers, adornments, and scrolling. - Detailed the "View Lifecycle" with step-by-step processes and code examples for initialization, layout, drawing, input handling, and disposal. - Reorganized and expanded the "Subsystems" section, covering commands, input handling, layout, drawing, navigation, and scrolling. - Updated the "Modal Views" section with examples for dialogs, wizards, and modal view types. - Introduced a "Common View Patterns" section with practical examples for creating custom views, adding subviews, and implementing scrolling. - Added an "Advanced Topics" section covering diagnostics, view states, and shadow effects. - Included numerous inline code examples to illustrate key concepts. - Concluded with a "See Also" section linking to related deep-dive documentation. These changes significantly improve the structure, clarity, and accessibility of the documentation, making it easier for developers to understand and use the library effectively. * Restore working automatic URL detection with fix for URLs containing ANSI sequences Co-authored-by: tig <585482+tig@users.noreply.github.com> * Fix URL regex to handle underscores and trailing punctuation + add comprehensive tests Co-authored-by: tig <585482+tig@users.noreply.github.com> * Update and expand Configuration Management documentation The document title was updated to "Configuration Management Deep Dive" to reflect its expanded scope. A new Table of Contents was added for improved navigation. The introduction and "Overview" sections were rewritten to provide a clearer explanation of the `ConfigurationManager` class and its key features. New sections were added, including "Getting Started," "Themes and Schemes," "Defining Configuration Properties," "Events," and "Best Practices." These sections provide detailed explanations, examples, and recommendations for using the `ConfigurationManager` effectively. The "Configuration Scopes" and "Configuration Locations and Precedence" sections were restructured and expanded with detailed explanations, diagrams, and examples. Advanced topics such as JSON error handling, runtime configuration, and file system watching were introduced. The document now includes several new examples, such as theme switching and custom application settings, along with references to related topics and UICatalog examples. The content was reorganized for clarity, with redundant sections removed. * Refactor and expand Arrangement system documentation Updated the title to "View Arrangement Deep Dive" and added a Table of Contents for better navigation. Expanded the "Overview" section and restructured "Arrangement Modes" with detailed examples. Added new sections for "Arrange Mode (Interactive)," "Movable Views," "Resizable Views," and "Creating Resizable Splitters," with practical code samples. Enhanced "Tiled vs Overlapped Layouts" and "Modal Views" sections, and introduced "Runnable Views" to explain non-modal behavior. Expanded the "Examples" section with multiple use cases and added advanced topics like Z-order management and arrangement events. Updated `arrangement-lexicon.md` with API links for key terms. Improved formatting and consistency throughout the document to enhance clarity and usability. * Update CONTRIBUTING.md references and add critical note Updated the reference to `CONTRIBUTING.md` to use a relative path (`../CONTRIBUTING.md`) for accurate resolution. Enhanced instructions for AI agents, including CoPilot and Cursor, to strictly follow the updated guidelines. Added a **CRITICAL** note requiring CoPilot to internalize and adhere to the guidelines, including when operating in Agent mode. * Refactor URL handling and add OSC 8 hyperlink support Replaced `UrlRegex` with the new `Osc8UrlLinker` utility to handle URL detection and wrapping with OSC 8 hyperlink sequences, improving modularity and maintainability. Updated `OutputBase` to use `Osc8UrlLinker.WrapOsc8` for URL processing and removed legacy `WrapUrlsWithHyperlinks` logic. Added the `Osc8UrlLinker` class with robust URL parsing, support for allowed schemes, and handling of edge cases like trailing punctuation and ANSI escape sequences. Improved performance with efficient `StringBuilder` usage. Enhanced `AnimationScenario` to ensure URLs with underscores are drawn correctly. Improved code readability by renaming constants, simplifying nullable handling, and updating documentation. Replaced legacy `UrlDetectionTests` with `Osc8UrlLinkerTests`, covering standalone URLs, URLs in text, multiple URLs, and edge cases. Verified hyperlink wrapping correctness and visible content integrity. Updated `Terminal.sln.ToDo.DotSettings` to disable auto-opening of the Stack Trace Explorer. Cleaned up unused code, enabled nullable reference types, and improved XML documentation formatting. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tig <585482+tig@users.noreply.github.com> Co-authored-by: Tig <tig@users.noreply.github.com>
736 lines
20 KiB
Markdown
736 lines
20 KiB
Markdown
# 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
|