# Table/Popup concept

Table/Popup superwidget is quite complex, that's why it has an extra section.

The Table/Popup (TP for short) widget exists in order to make development of modules using this UI concept easier. It contains required widgets and helpful handling functions.

The CWM module contains widget for the whole table and most used popups. Each option is described by a map specifying the type and behavior of the table option.

In the following text distinguishing between "option id" and "option key" is needed. See .

## Basic table attributes

Following text will refer on .

Usage of the Table/Popup widget - basic case

           map<string,map<string,any> > options = $[
               "popup1" : popup1_description_map,
               "popup2" : popup2_description_map,
           ];

           define list getTableContents (map<string,any> descr) {
               return ["a", "b", "c"]; // to display 3 items
                                       // in the table
           }

           define map<string,any> getGlobalTableWidget () {
    (1)        map<string,any> ret = CWM::CreateTableDescr (
                   $[
                       "add_delete_buttons" : true,
                       "edit_button" : true,
                       "up_down_buttons" : true
                   ],
                   $[
    (2)                "init" : TableInit,
    (3)                "handle" : CWM::TableHandleWrapper,
    (4)                "options" : options,
    (5)                "ids" : getTableContents,
                   ]
               );
               return ret;
           }

Notes:

1. Many of the TP related values of the widget description map are used only by the predefined functions from the CWM module. If you use your own "init" and "handle" functions and they don't use the predefined function from the CWM module, you do not need to specify other table-related functions and attributes.

2. All other keys that can be used by handlers can be defined according to the needs of the component developer.

3. If you don't specify the "init" and "handle" functions, the defaults given as an argument in the ShowAndRun or Run function won't be used, but instead of them table-widget-specific defaults are used.

### Creating the table container (1)

For getting the initial map the function map<string,any> CWM::CreateTableDescr () can be used. It takes as a parameters a map specifying the attributes of the table and a map specifying additional settings that will be merged to the description map (see below). Currently supported attributes are:

- "add_delete_buttons" : boolean - if the Add and Delete buttons are wanted, set to true. If false, they will not be shown. Default (if key not present) is true.

- "edit_button" : boolean - if the Edit button is wanted, set to true. If false, it will not be shown. Default (if key not present) is true.

- "up_down_buttons" : boolean - if the Up and Down (reorder) buttons are wanted, set to true. Otherwise, they will not be shown. Default (if not present) is false.

- "unique_keys" : boolean - if true, then no key can be present in the table more times than once. Otherwise, it must be explicitly forbidden for such options. Default (if not present) is false.

For id of the widgets related to the table see .

### Setting the initialize and handle functions (2-3)

This is the same as for normal widgets. Set the functions according to your needs.

There are predefined functions for this stuff. In most cases, they can be used as they are, or via a wrapper. Typical case is that the initialize function copies the data from the global storage to some temporary variable (because of the Back button behavior), and then calls the predefined initialization function.

CWM::TableInit () function asks for the list of entries that should be displayed in the table, and for each of them gets the option label (for the left column) and value (for the right column of the table). Then changes the contents of the table.

CWM::TableHandle () function handles the events on the table. According to the event and selected item it asks for a new option to add, displays an option editing popup, calls the delete handler or makes the event loop finish. It redraws whole table only if it is needed (reorder, add or delete an item), otherwise only changes affected items.

Note that CWM::TableInit () and CWM::TableHandle () cannot be specified directly in the widget description map as these functions have one additional parameter. Use CWM::TableInitWrapper () resp. CWM::TableHandleWrapper () instead.

### Transforming option key to option description map (4)

To operate the options, the TP mechanism requires the option description maps (see ). The options description map is stored under the "options" key.

### The contents of the table (5)

Specify here the contents of the table that will be displayed. Should return the list of option ids. The function has one argument, the table widget description map.

## Basic table option attributes

Option description map describes the behavior of one single option in the table. It describes its widget, user-readable description, user-readable value, location of the value and many others.

Option description map is separated into 2 parts. One contains keys related to the table, the other one contains keys related to the option popup.

Note: The smallest possible option description map is empty map. In this case widget type is (by default) text entry, and instead of option specific handlers (init, store, summary) the table's fallback handlers are used as label the option name is used.

Following text will refer to .

Basic option description map

    define string EnableServiceSummary (
        any opt_id, string opt_key)
    {
        if (settings["enable_service"]:false)
        {
            return _("Yes");
        }
        else
        {
            return _("No");
        }
    }

    define void EnableServiceInit (
        any opt_id, string opt_key)
    {
        UI::ChangeWidget (`id ("enable_service"), `Value,
            settings["__run_dhcp_server"]:false);
    }

    define void EnableServiceStore (
        any opt_id, string opt_key)
    {
        settings["__run_dhcp_server"]
            = UI::QueryWidget (`id ("enable_service"), `Value);
    }

    map<string,map<string,any> > options = $[
        "enable_service" : $[
    	"table" : $[
    (1)         "label" : _("Enable DHCP server at boot time"),
    (2)         "summary" : EnableServiceSummary,
            ],
            "popup" : $[
    (3)         "init" : EnableServiceInit,
    (4)         "store" : EnableServiceStore,
    (5)         "widget" : `checkbox,
            ],
        ],
    ];

This example describes a simple option, that is represented by a check box in the popup, has label "Enable DHCP server at boot time" and own functions to initialize the check box after the popup is displayed, store its status before the dialog hides after user clicked the OK button, and generate the text for the right column of the table.

### Option label (1)

Option label specifies the label that will be displayed in the left column of the table. Contains a (translated) string. If not present, the option name is used instead.

### Summary function (2)

Summary function is used to get the (localizable) value for the right column of the table. The "summary" key contains a function reference, the function has two arguments - option id (any) and option key (string), returns the value description for the table (string).

### Popup initialization (3)

The initialization function is called immediately after the popup is displayed. Its task is to set appropriate value to the displayed widget. Has two parameters - option id (any) and option key (string), return value is void.

### Popup state storing (4)

The state storing function is called before the popup is closed via the "OK" button. Its task is to grab the values from the popup and store them to appropriate variables. Has two parameters - option id (any) and option key (string), return value is void.

### Widget specification (5)

The widget specification works the same way as for dialog widgets. See for list of possible widgets.

## Advanced table attributes

### Fallback handlers

For table entries that have no own handlers, fallback handlers init, store, and summary can be defined in the table description map. They are defined in the "fallback" submap of the widget description map. Init and store are related to popups, summary to table entries. See .

Note, that because the TP mechanism doesn't know where the data are stored, fallback handler or option-specific handler for every option must be defined.

Fallback handlers definition

    define map<string,any> getTableWidget () {
        map<string,any> ret = CWM::CreateTableDescr (
            $[],
            $[
                "fallback" : $[
                    "init" : commonPopupInit;
                    "store" : commonPopupSave;
                    "summary" : commonTableEntrySummary;
                // other options of the widget description map come here
                ],
            ]
        );
        return ret;
    }

### Deleting entry

For deleting an entry from the table (via the Delete button below it), this handler is used. The handler has two parameter - the option id (any) and the option key (string). If return value is true, then it is assumed, that the entry was really deleted, and the table should be redrawn. Otherwise, the table is left as is.

Deleting entry from table

    define map<string,any> getTableWidget () {
        map<string,any> ret = CWM::CreateTableDescr (
            $[],
            $[
                "option_delete" :
                    commonTableEntryDelete,
                // other options of the widget description map come here
            ]
        );
        return ret;
    }

### Items for adding

If the table has the "Add" button, this contains the options to be offered in the combo that can be added. The add_unlisted entry can specify if the combo box will be editable and any option can be entered (if true), or the combobox will not be editable, and the option list is fixed (if false). If not present, default is true.

Entries for adding to the table

    define map<string,any> getTableWidget () {
        map<string,any> ret = CWM::CreateTableDescr (
            $[],
            $[
                "add_items" : ["a", "b", `item (`id ("c"), "C") ],
                "add_unlisted" : false,
                // other options of the widget description map come here
    	]
        );
        return ret;
    }

This will allow to add only these 3 entries.

### Transforming option id to option key

If you don't use the 1:1 mapping between the option id and option key, set the function that will transform the option id to option key. Before evaluation, the table description map and the option id will be added to the term . If not present, then option key is the same as option id.

Transforming option id to option key

    define string id2key (map<string,any> descr, any opt_id) {
        return opt_id; // 1:1 translation
    }

    define map<string,any> getTableWidget () {
        map<string,any> ret = CWM::CreateTableDescr (
            $[],
            $[
                "id2key" : d2key,
                // other options of the widget description map come here
            ]
        );
        return ret;
    }

### Specifying reordering function

If the order of items makes sense, then it is needed to specify a function that changes the order of items in appropriate structures. This function must be specified (if Up and Down buttons are to be displayed) via the "option_move" key in the table description map as a term. Has parameters option id (any), option key (string) and direction (symbol `up or `down). Must return true if the order was really changed (in order to redraw the table).

Specifying reordering function

    global define any optMove (any opt_id, string opt_key, symbol direction) {
        // modify internal structure appropriate way here
        return true;
    }

    global define map<string,any> getTableWidget () {
        map<string,any> ret = CWM::CreateTableDescr (
            $[],
            $[
                "option_move" : optMove;
                // other options of the widget description map come here
            ]
        );
        return ret;
    }

## Advanced table option attributes

### Table - related

#### Optional values

An entry in the table may be mandatory (and not be possible to be deleted), or optional (and be possible to be deleted). The "optional" key in the "table" submap specifies if the entry is allowed be removed. If not present, default is true.

#### Ordering

It is possible to allow or forbid to move the option in the table up or down. If the "ordering" key in the "table" submap is set to true (default), then it is possible to move this option up or down. Otherwise, the up and down buttons are grayed if this option is selected. If the up and down buttons aren't displayed at all (see ), this option is ignored.

#### Duplicate keys

In some cases it makes sense to have one key in the table more than once. It usually doesn't make too much sense for all keys, but only for some. If the "unique_key" of the "table" submap is set to true, the key can be present in the map only once. Default if false (if multiple occurrences of a key in map aren't disabled at all, see ).

#### Label as function

If the option label isn't static, a function that creates it can be specified. Specify in the "table" submap the key "label_func" and set it as value a function that takes as arguments the widget id (any), widget key (string) and returns the label to the table (string).

#### Option handlers

In some cases the generic behavior (display popup, initialize it, handle UI events and store the settings) may be unusable. If the "handle" key in the "table" submap is specified, then if the table entry is selected and Edit button clicked, then it is evaluated instead of the usual handling of this event.

It can be two types. If it is a symbol, then the symbol is immediately returned and the event loop finishes.

If it is a function reference, then it is called with parameters option id (any), option key (string) and event that occurred (map). If returned value is nil, then the event loop continues with handler of next widget in the dialog or next event. If a symbol is returned, then the event loop is finished, and returned value passed to wizard sequencer. If a special symbol `_tp_normal is returned, then normal generic handler is run (displays a popup, initializes it, handles the events, store the settings via appropriate handlers).

### Popup related

#### Help

If it is needed, it is possible to enter some help. The help is displayed as a label above the option, and is specified as a string with the "help" key in the "popup" submap.

#### Popup validating

Popup validation works the same way as the validation of normal widget. See for details. The validation parameters must be defined in the "popup" submap. The only difference is in parameters added to the validation function before evaluation, parameters option id, option key and action are added before evaluation.

#### UI events handling

To handle the UI events, use the "handle" key in the "popup" submap. It must contain a function with parameters option id (any), option key (string) and event (map, return value of UI::WaitForEvent). It is called every time the UI::WaitForEvent returns. If not set, no handling function is run.

#### Widget attributes

The popup widgets have the same attributes as the dialog widgets. For more information see .

The only difference is that if the "label" key is not present in the "popup" submap, the "label" key in the "table" submap is used, and if it isn't present, then generic label "Value" is used. Remember, that the "label" in the "table" submap shouldn't have any keyboard shortcut, but the "label" in the "popup" submap should have some.

The "custom_widget" entry has the same behavior as for dialog widgets, see .

## More complex option example

More complex option

    map popups = $[
      "loader_type" : $[
        "table" : $[
          // label, that will be shown in the table
          "label" : _("Boot Loader Type"),
          // will return "GRUB" if grub is selected,
          // "LILO" if lilo is selected,...
          "summary" : loaderTypeSummary,
          // some bootloader must be always selected
          "optional" : false,
          // the order of this entry in global
          // options doesn't make sense
          "ordering" : false,
          // bootloader can't be specified more than once
          "unique_key" : true,
          // not needed, nil is default value,
          // really has a normal popup
          "handle" : nil,
        ],
        "popup" : $[
          // sets appropriate radio button selected
          "init" : loaderTypeInit,
          // queries for the active radio button, stores the result
          "store" : loaderTypeSave,
          // no validation is done, validation always successful
    //    "validate" : not needed
          // generic widget is used, this option is not needed
    //    "custom_widget" : not needed
          // simple help for the user
          "help" : _("Select bootloader you want to use"),
          // label of the widget in the popup. Will be shown
          // as the title of the frame holding radio buttons
          "label" : _("&Boot Loader Type"),
          // set of radio buttons is shown
          "widget" : `radio_buttons,
          // specification of the radio buttons
          "items" : [ [ "grub", "&GRUB" ], [ "lilo", "&LILO" ]]
        ]
      ],
      ....
    ]

## Misc

### Separator

If a table separator is wanted (in order to make the table more transparent), it should be specified as an option with the key "____sep". Options with this key are automatically skipped when selected. You can modify the label of the option in order to display the separator the way you want to. It behaves like a normal option, with the only difference that it isn't selectable.

## Reserved UI events

Some UI events (return values of UI::UserInput ()) are used internally by the handling mechanism, and can't be used for other widgets.

In popups following widget ids are reserved:

- `_tp_ok - the OK button

- `_tp_cancel - the Cancel button

The table widget contains following ids:

- `_tp_add - Add button - don't use although it is not present

- `_tp_edit - Edit button

- `_tp_delete - Delete button - don't use although it is not present

- `_tp_table - The table

- `_tp_up - The Up button

- `_tp_down - The Down button

- `_tp_table_rp - The replace point on the right bottom of the table superwidget

Additionally, if some popup widget has the "t_no_popup" not nil, return values of the evaluation of the term may be also results of the actions on the table widget.