Input focus and selection lists or tables

The pane layout manager uses focusable widgets internally, specifically the dividing sliders between the individual panes, and the scroll-bars that scroll the elements bigger than their pane, into view. This is why the pane layout manager gets used with create_focusable_container().

The pane layout manager automatically manages the individual tabbing order for its scroll-bars and sliders. The focusable container is considered to be a single focusable widget, and moving its tabbing order moves the order of all the scroll-bars and sliders as a group. Setting a focusable widget's tabbing order before or after the pane's focusable container moves the input focus to it before or after all of the pane's sliders and scroll-bars; with one exception.

The exceptions are selection lists and tables. Putting a selection list or a table into a pane automatically incorporates the selection list or table into the pane's own natural tabbing order. The input focus gets tabbed in and out of the selection list or table in order with the pane's focusable elements.

Configuring lists and tables in panes

auto pf=plm->append_panes();

x::w::new_listlayoutmanager nlm{highlighted_list};

nlm.columns=3;
pf->configure_new_list(nlm);

x::w::const_pane_appearance custom=pf->appearance->modify
    ([]
     (const x::w::pane_appearance &appearance)
     {
         appearance->size=30.0;
     });

pf->size=custom;

pf->create_focusable_container([]
                   (const auto &creator)
                   {
                       // ...
                   },
                   nlm)->show();

panelayoutmanager.C shows how to use configure_new_list() with a pane factory when adding a selection list or a table, for optimal appearance.

configure_new_list()'s parameter is either a x::w::new_listlayoutmanager or a x::w::new_tablelayoutmanager; and configure_new_list() gets called just before using the pane factory to create a new focusable container with a list layout manager or the table layout manager.

configure_new_list() installs new appearance objects in both the pane factory's and the passed-in x::w::new_listlayoutmanager or x::w::new_tablelayoutmanager; which also get adjusted for these alternative appearance objects with optimal settings:

  • Specifying a variable_height() for the new selection list or table, so that it automatically matches its pane's height, when the pane's height gets adjusted by its dividing sliders.

  • The list's or table's appearance object does not specify a drawn border for the list or the table, because the pane layout manager provides a border for all of its panes, already.

  • Disabling the pane's scroll-bar. The selection list or table provides its own scroll-bar, as needed, in the list.

  • Removing the small amount of padding in the list's pane. The selection list provides the same amount of padding itself.

  • Setting the pane widget alignment options to fill out the widget in the pane to always match the size of the pane. This automatically adjusts the list's height to match the pane's, making the selection list responsible for its own scrolling.

Since configure_new_list() installs new appearance objects, any customizations to them must occur after configure_new_list().

Panes with synchronized lists

auto pf=plm->append_panes();

x::w::new_listlayoutmanager nlm{highlighted_list};

nlm.columns=3;
pf->configure_new_list(nlm);

auto custom=pf->appearance->modify
    ([]
     (const auto &appearance)
     {
          appearance->size=30;
     });
pf->appearance=custom;

pf->create_focusable_container([]
                   (const auto &creator)
                   {
                       // ...
                   },
                   nlm)->show();

pf->configure_new_list(nlm);

custom=pf->appearance->modify
    ([]
     (const auto &appearance)
     {
          appearance->size=50;
     });

pf->appearance=custom;

pf->create_focusable_container([]
                   (const auto &creator)
                   {
                       // ...
                   },
                   nlm)->show();

This example creates two panes with selection lists. Each selection list has three columns. What's not explicitly apparent is that both lists' columns' widths are synchronized.

Normally each selection list controls its columns individually; and they're wide enough to accomodate the widest individual item in all rows in that column, in that selection list. The two selection lists are independent of each other. The first one's columns' widths get computed based on the first list's items' widths. The widths of columns in the second list are set based on the widths of the individual items in the second list. So, normally, the widths of columns in the two lists are different because the lists have different items; and the same column will has a different width in each list.

In this example, the two selection lists appear as two panes, one list on top of each other, and their columns will always line up. This looks like a single list, with a divider widget that splits them. But they're really two independent selection lists.

This is an indirect result of the two selection lists getting created from the same x::w::new_listlayoutmanager. x::w::new_listlayoutmanager's constructor creates a new x::w::synchronized_axis object for its synchronized_columns member.

A new selection list container that's created by an x::w::new_listlayoutmanager's gets linked to the synchronized_columns from the x::w::new_listlayoutmanager instance. The computed widths of the selection list's columns are based not only on that selection list's items, but also based on the items of all other selection list's that link to the same synchronized_columns object. It's possible to create selection lists from different x::w::new_listlayoutmanagers provided that the first one's synchronized_columns class member gets manually copied to the second one's.

Additionally, merely linking multiple selection lists to the same synchronized_columns is not sufficient by itself. To have lists' columns line up with each other requires taking some additional steps:

  • The selection lists must have the same number of columns.

  • The selection lists' scroll-bars' visibility status must be the same. All of the lists' scroll-bars must be visible, or invisible. It's possible to have a mixture of lists with visible and invisible scroll-bar's, if their visibility is x::w::scrollbar_visibility::automatic_reserved.

  • The selection lists have to be sized to the same width, by their respective containers.

The above example ticks off each requirement as follows:

  • Both selection lists have three columns, and a vertical_scrollbar with x::w::scrollbar_visibility::automatic_reserved.

  • They get placed into the same (vertical) pane container. The vertical pane container automatically sizes itself to accomodate the widest pane, and x::w::halign::fill make sure that the two selection lists get stretched horizontally to the pane container's full width.