-
Notifications
You must be signed in to change notification settings - Fork 731
Description
This PR is for a major rehaul of how Terminal.Gui deals with non-Tiled view arrangements and "runnable" views.
@BDisp, @tznind, @dodexahedron, and @migueldeicaza - PLEASE READ AND TURN ON YOUR BRAINSTORM MODE
We have a chance to get the design of how all this works in v2 right. We should approach this throwing away existing notions of how Terminal.Gui has always worked in these regards. This does not mean we WILL throw all those things away, but that we should not constrain our thinking at this point.
I've written the below in the spirit of generating debate and ideas. I'm highly motivated to start working on this as I've been noodling on it for years. But my thinking is still very far from clear.
We will need a new "Multiple overlapped, MDI-like views" example (see #3636).
Related Issues & PRs
- Master Issue: Finish Adornments #2994
- Add mouse/keyboard resizing of views #2537
- Overlapped broken on the v2_develop branch using the BackgroundWorkerCollection scenario. #3636
- Preps for and partially Fixes #2491 - Refactors
ToplevelandApplicationNavigation #3634 - Partially Adresses #2491. Refactors how
Focusworks #3627 Slider: API for setting options is clunky #3735- Fix focus and keyboard nav with
Adornments#3406
Background
In v2, we have the following layout abilities:
- Arrangement - Includes
View.Arrangementand code inBorder.csfor determining how a view (viaBorder) can be moved and sized. Right now onlyViewArrangement.FixedandViewArrangement.Movablehave any implementation. - Tiled - By default, there is no 'z-order` to the Subviews of a View. And in mose use-cases, subviews do not overlap with each other (the exception being when it's done intentionally to create some effect). As a result, the default layout for most TUI apps is "tiled".
- Modal - A modal view is one that is run as an "application" via
Application.Run(Toplevel)whereModal == true.Dialog,Messagebox, andWizardare the prototypical examples. When run this way, there IS az-orderbut it is highly-constrained: the modal view has a z-order of 1 and everything else is at 0. - 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 ownRunStateand is, effectively, a self-contained "application".Application.Run()non-preemptively dispatches events (screen, keyboard, mouse , Timers, and Idle handlers) to the associatedToplevel. It is possible for such aToplevelto create a thread and callApplication.Run(someotherToplevel)on that thread, enabling pre-emptive user-interface multitasking (BackgroundWorkerCollectiondoes this). - 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. Today, all Overlapped views are Runnable and have
Modal = true. There are a few Scenarios (BackgroundWorkerCollection) that utilize this to provide multiple "windows" that have a z-ordering and are NOT tiled. This is enabled by a bunch of crufty code inToplevel(mostly inToplevelOverlapped.cs) and a few other places. While there is a psuedo-z-order provided byToplevel._toplevels, which is aStack<Toplevel>, the API is confused and bug-ridden (e.g. not ALLToplevelsare added to this stack, bothToplevel.CurrentandToplevel.Topexist...along with whatever_toplevels.TryPeek()returns).
Assertions (these are up for challenge/debate!)
Applicationshould havepublic Stack<IRunnable> Runnableswhere user-input events go only toRunnables.TryPeek(), but all get timer, idle, and screen events. This is effectively how the Win32 non-pre-emptive multitasking system works.- There's no need for Overlapped views to need to be Runnable (just as in Win32, any Window could either tile or be overlapped).
- Modal means
IRunnable,ViewArrangement.OverlappedwheremodalView.Z > allOtherViews.Max (v = v.Z), and exclusive key/mouse input. - If a developer has a need for pre-emptive UI multi-tasking, they still can spin up a thread and call
Application.Run(someView).someViewcan be Overlapped or tiled. There's really no reasonsubviewA.X = Pos.Bottom(someView)orsomeView.Width = Dim.Width (subviewA)can't work. - Runnable should be via an interface
IRunnable - Overlapped uses
ViewArrangement- We should addViewArrangement.Overlapped. This is already done in Partially Adresses #2491. Refactors howFocusworks #3627. - Overlapped views do not need a "close" command.
Visible = falseis sufficient as a default behavior for a user action that "closes" an Overlapped view (e.g. the equivalent of Alt-F4 for Windows or the (coming soon) close button inBorder). If an app really wants an Overlapped to beDisposedit can subscribe toVisibleChanging/VisibleChangedevents (TBI). - Related to the above point, a Modal does need a "close" command. This is already provided by
Command.QuitToplevel, which should be renamedCommand.QuitRunnable. - Key Bindings current in
TopLevelfor subview should be Application scoped. This is already done in Partially Adresses #2491. Refactors howFocusworks #3627.
Keyboard Nav
Requirements
- Enable
Overlappedas 1st class concept, not tightly coupled withRunnable, with a well-designed, clean, API and implementation. -
MenuBarandStatusBarshould not be coupled withToplevel, which prevents non-Toplevel-dervived views from hosting them. See RefactorMenuBarandStatusBarto be adornments #2488 - Make it possible to move and resize any
Viewwith the mouse and keyboard. Partially addressed in #RefactorMenuBarandStatusBarto be adornments #2488. Full Issue: Add mouse/keyboard resizing of views #2537 - We have many requests to support non-full-screen apps. See Make non-fullscreen apps possible #272
Justification / Issues with current systems (very old text; ignore if you want)
Overlapped is partially supported in v1 using Toplevel views. However, the v1 design is lacking:
- MenuBar and StatusBar are tied to Toplevel, preventing non-Toplevel views from hosting them.
- Only TopLevel views can be run via
Application.Run<view>(need a separateRunState). It is not clear why ANY VIEW can't be run this way, but it seems to be a limitation of the current implementation. - Views that can be used as a pop-up (modal) (e.g.
Dialog). As proven byWizard, it is possible to build a View that works well both ways. But it's way too hard to do this today. - Views that can be moved by the user must inherit from
Windowtoday. It should be possible to enable the moving and resizing of any View (e.g.View.CanMove = true). - The
MdiContainerstuff is complex, perhaps overly so. It's also misnamed because Terminal.Gui doesn't support "documents" nor does it have a full "MDI" system like Windows (used to). It seems to represent features useful in overlapping Views, but it is super confusing on how this works, and the naming doesn't help. This all can be refactored to support specific scenarios and thus be simplified. - There is no facility for users' resizing of Views. @tznind's awesome work on
LineCanvasandTileViewcombined with @tig's experiments show it could be done in a great way for both modal (overlapping) and tiled Views. - We have many requests to support non-full-screen apps. We need to ensure the
Viewclass hierarchy supports this in a simple, understandable way. In a world with non-full-screen (where screen is defined as the visible terminal view) apps, the idea thatFrameis "screen relative" is broken. Although we COULD just define "screen" as "the area that bounds the Terminal.GUI app." - The
MdiContainer/Overlappedstuff is complex, perhaps overly so. It's also misnamed as Terminal.Gui doesn't support "documents" nor does it have a full "MDI" system like Windows (used to). It seems to represent features useful in overlapping Views, but it is super confusing on how this works, and the naming doesn't help. This all can be refactored to support specific scenarios and thus be simplified.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status