Skip to content

Refactor/rewrite TabView to use modern v2 capabilities #4183

@tig

Description

@tig

These built-in Views have been introduced in v2 or re-written in v2 to remove massive amounts of complex custom code and complexity by leveraging the fact that v2 has better infrastructure for compound/nested views.

  • Menuv2 etc...
  • Shortcut
  • StatusBar
  • OptionSelector (RadioGroup)
  • FlagSelector
  • ColorPicker
  • ScrollBar
  • DatePicker
  • NumericUpDown

These Views remain using mostly the v1-legacy model and thus are good candidates for cleanup. Listed in priority order based on how I perceive how much bang-for-the-buck there is in re-working them.

  • TabView
  • ComboBox
  • Slider
  • TableView
  • TreeView

I think we should tackle TabView because:

  • TabView is a great control for testing the library. It has a lot of capabilities that stretch the library. The v1 version was internally very complex in order to work around limitations in TG. In theory, v2 should enable making this control a lot simpler.
  • Like Shortcut, StatusBar, and Menuv2 it is a container for arbitrary other Views. This means it can both take advantage of and prove out things like Command propagation, Content Scrolling,, KeyBindings, MouseBindings, Adornments, ViewArrangement, and so forth.
  • It is a bug-farm. The code is full of duplicative code, complex switch statements, and complex overrides and interactions that can and should be simplified.

I had a PR going (#3832) where I experimented with this but gave up to focus on other things. In it, I suggested a design incorporating things like this:

  • Content scrolling - The TabRowView can/should just be a horizontally scrolling View where each Tab is just a subview. All the complex TabView logic for renering the Tabs and supporting scrolling can go away.
  • Layout - Dim.Auto, deferred layout, etc... should reduce the need for a lot of the internal complexity. Especially the complex layout math scattered around.
  • Drawing - There should be no need for TabView to draw lines directly. Each element can just be a View and leverage Border an automatic line joins currently enabled by SuperViewRendersLineCanvas
  • Navigation - How a user navs with the keyboard across Tabs, TabRowView, and the tab content is complex. The new v2 Nav system should make this easier.

Rough Design Proposal

  • TabView - A host of mutiple Tabs which are displayed horizontally above or below. One tab at a time can have focus, and when it does, that tab's content is displayed and the user can interact. The TabView class has ONE subview of type TabRowView. This subview is aligned either at the top (Y = 0) or bottom (Y = Pos.AnchorEnd) and fills the TabView horizontally.
    • Uses an int based system for indexing on the tabs (e.g. SelectedTabIndex)
    • Listens to the Selecting event on TabRow - the index of the tab that was clicked on is passed in the CommandContext. The SelectedTabIndex is set based on this.
  • **TabRow ** - The host of the Tab objects for a TabView. Each Tab is simply added as a Subview, thus the list of Tabs is stored in this class (and accessable via the strongly typed TabRow.Tabs). Scrolls the Tabs horizontally within it's Viewport (the ContentSize is set to the sum of the widths of all the Tabs). Includes two scroll buttons that are made visible when needed to enable mouse scrolling across the tabs.
    • When the user clicks on a tab, presses it's hotkey, or changes focus to a tab and presses Space, the Selecting event is raised (see above).
  • Tab - Represents one of the tabs in the TabView. Holds a reference to a developer provided View as Tab.View that is activated when the Tab has focus.
    • When added to TabView via TabView.AddTab the Tab gets added to TabView._tabRow as a subview. TabRow takes care of changing the Tab.Border and Tab.Margin (as well as dimensions) such that the tabs render nicely as "tabs" simply leveraging the Border line rendering code. (Not complete in current WIP).

Screenshot of some code from that abandoned PR:

image

This is in AllViewsTester utilizing this

    public bool EnableForDesign ()
    {
        AddTab (new () { Text = "Tab_1", Id = "tab1", View = new Label { Text = "Label in Tab1" } }, false);
        AddTab (new () { Text = "Tab _2", Id = "tab2", View = new TextField { Text = "TextField in Tab2", Width = 10 } }, false);
        AddTab (new () { Text = "Tab _Three", Id = "tab3", View = new Label { Text = "Label in Tab3" } }, false);
        AddTab (new () { Text = "Tab _Quattro", Id = "tab4", View = new TextField { Text = "TextField in Tab4", Width = 10 } }, false);

        return true;
    }

This is vastly different design than the old design that SHOULD result in a far simpler and performant system. It aslo completely leverages new v2 infrastructure.

The current prototype has the following issues that need to be addressed:

  • The bottom line in the TabRow does not go all the way to the right past the last tab.
  • Scrolling of the Tabs in TabRow is not quite right. Needs tweaking.
  • A bunch of legacy code still exists in TabView

I think we should revisit this and I hope someone besides me finds the motivation to do so!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions