Files
Terminal.Gui/docfx/docs/arrangement.md
Copilot 7a810b0b87 Remove TileView; use View.Arrangement instead (#4271)
* Initial plan

* Remove TileView and refactor to use View.Arrangement

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Fix FileDialog container focus behavior - all tests passing

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Remove obsolete TileView comment from View.Hierarchy.cs

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Add resizable splitter example to View.Arrangement docs

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Refactored `TreeView` and `TableView` containersto use View.Arrangment.

Removed unused `_btnToggleSplitterCollapse` and related logic due to the new splitter design.

Simplified collection initialization and feedback/state handling. Improved code readability by replacing magic strings and redundant null checks.

Refactor FileDialog for null safety and UI improvements

Enabled nullable reference types to improve null safety across the codebase. Refactored constants to follow uppercase naming conventions. Introduced nullable annotations for fields and method parameters.

Updated test cases to reflect the removal of deprecated features. Skipped tests related to the removed splitter button. Made miscellaneous improvements, including adding comments and suppressing warnings.

* Add "_Find:" label to FileDialog search field

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Fixes Parallel unit test intermittent failure case.

Removed the initialization of the `Navigation` object in the `ResetState` method of the `Application` class, indicating a potential shift in its lifecycle management. Enhanced comments to clarify the role of `Shutdown` as a counterpart to `Init`, emphasizing resource cleanup and defensive coding for multithreaded scenarios. Referenced Issue #537 for additional context.

---------

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>
2025-10-20 14:51:14 -06:00

6.0 KiB

View Layout Arrangement

Terminal.Gui provides a feature of Layout known as Arrangement, which controls how the user can use the mouse and keyboard to arrange views and enables either Tiled or Overlapped layouts. Arrangement is a sub-topic of Layout.

Arrangement Taxonomy & Lexicon

[!INCLUDE Arrangement Lexicon]

Arrangement

Describes the feature of Layout which controls how the user can use the mouse and keyboard to arrange views and enables either Tiled or Overlapped layouts. The @Terminal.Gui.ViewBase.View.Arrangement property controls the arrangement behavior for each view.

Arrange Mode

The Arrange Modes are set via the @Terminal.Gui.ViewBase.View.Arrangement property. When a user presses Ctrl+F5 (configurable via the @Terminal.Gui.App.Application.ArrangeKey property) the application goes into Arrange Mode.

In this mode, indicators are displayed on an arrangeable view indicating which aspect of the View can be arranged:

  • If @Terminal.Gui.ViewBase.ViewArrangement.Movable, a will be displayed in the top-left corner of the @Terminal.Gui.ViewBase.View.Border
  • If @Terminal.Gui.ViewBase.ViewArrangement.Resizable, pressing Tab (or Shift+Tab) will cycle to an indicator in the bottom-right corner of the Border

The up/down/left/right cursor keys will act appropriately. Esc, Ctrl+F5 or clicking outside of the Border will exit Arrange Mode.

Modal

A modal view is one that is run as an "application" via @Terminal.Gui.App.Application.Run(System.Func{System.Exception,System.Boolean},Terminal.Gui.Drivers.IConsoleDriver) where Modal == true.

Dialog, MessageBox, and Wizard are the prototypical examples. When run this way, there IS a z-order but it is highly-constrained: the modal view has a z-order of 1 and everything else is at 0.

Movable

Describes a View that can be moved by the user using the keyboard or mouse. Movable is enabled on a per-View basis by setting the @Terminal.Gui.ViewBase.ViewArrangement.Movable flag on @Terminal.Gui.ViewBase.View.Arrangement.

Dragging on the top @Terminal.Gui.ViewBase.View.Border of a View will move such a view. Pressing Ctrl+F5 will activate Arrange Mode letting the user move the view with the up/down/left/right cursor keys.

Overlapped

A form of layout where SubViews of a View are visually arranged such that their Frames overlap. In Overlap view arrangements there is a Z-axis (Z-order) in addition to the X and Y dimension. The Z-order indicates which Views are shown above other views.

Overlapped is enabled on a per-View basis by setting the @Terminal.Gui.ViewBase.ViewArrangement.Overlapped flag on @Terminal.Gui.ViewBase.View.Arrangement.

Resizable

Describes a View that can be sized by the user using the keyboard or mouse. Resizable is enabled on a per-View basis by setting the @Terminal.Gui.ViewBase.ViewArrangement.Resizable flag on @Terminal.Gui.ViewBase.View.Arrangement.

Dragging on the left, right, or bottom @Terminal.Gui.ViewBase.View.Border of a View will size that side of such a view. Pressing Ctrl+F5 will activate Arrange Mode letting the user size the view with the up/down/left/right cursor keys.

Tiled

A form of layout where SubViews of a View are visually arranged such that their Frames do not typically overlap. With Tiled views, there is no 'z-order` to the SubViews of a View.

In most use-cases, subviews do not overlap with each other (the exception being when it's done intentionally to create some visual effect). As a result, the default layout for most TUI apps is "tiled", and by default @Terminal.Gui.ViewBase.View.Arrangement is set to @Terminal.Gui.ViewBase.ViewArrangement.Fixed.

Creating a Resizable Splitter

A common pattern in tiled layouts is to create a resizable splitter between two views. This can be achieved using the @Terminal.Gui.ViewBase.ViewArrangement.LeftResizable, @Terminal.Gui.ViewBase.ViewArrangement.RightResizable, @Terminal.Gui.ViewBase.ViewArrangement.TopResizable, or @Terminal.Gui.ViewBase.ViewArrangement.BottomResizable flags.

Here's an example of creating a horizontal resizable splitter between two views:

// Create left pane that fills remaining space
View leftPane = new ()
{
    X = 0,
    Y = 0,
    Width = Dim.Fill (Dim.Func (_ => rightPane.Frame.Width)),
    Height = Dim.Fill (),
    CanFocus = true
};

// Create right pane with resizable left border (acts as splitter)
View rightPane = new ()
{
    X = Pos.Right (leftPane) - 1,
    Y = 0,
    Width = Dim.Fill (),
    Height = Dim.Fill (),
    Arrangement = ViewArrangement.LeftResizable,
    BorderStyle = LineStyle.Single,
    SuperViewRendersLineCanvas = true,
    CanFocus = true
};
rightPane.Border!.Thickness = new (1, 0, 0, 0); // Only left border

container.Add (leftPane, rightPane);

In this example:

  • The rightPane has ViewArrangement.LeftResizable which makes its left border draggable
  • The left border acts as a splitter that users can drag to resize both panes
  • The leftPane uses Dim.Fill with a function that subtracts the rightPane's width to automatically fill the remaining space
  • The rightPane has SuperViewRendersLineCanvas = true to ensure the border is rendered properly
  • Only the left border is shown by setting Border.Thickness to (1, 0, 0, 0)

For a vertical splitter (top and bottom panes), use ViewArrangement.TopResizable or ViewArrangement.BottomResizable instead.

Runnable

Today, Overlapped and Runnable are intrinsically linked. A runnable view is one where Application.Run(Toplevel) is called. Each Runnable view where (Modal == false) has it's own RunState and is, effectively, a self-contained "application".

Application.Run() non-preemptively dispatches events (screen, keyboard, mouse, Timers, and Idle handlers) to the associated Toplevel. It is possible for such a Toplevel to create a thread and call Application.Run(someotherToplevel) on that thread, enabling pre-emptive user-interface multitasking (BackgroundWorkerCollection does this).