2.6. Creating User Interface

Our project has already defined a User Interface in the scr/dialogs.ycp file. This section should explain some important parts of defining and handling the UI using some simple examples:

2.6.1. Dialog Wizard

Wizard is a YCP module which do many annoying things on its own. It can do many things by a simple function call:

  • It automatically applies the current UI theme

  • Wizard::CreateDialog() - opens up a standardized dialog with correct width and height.

  • Wizard::SetContentsButtons(caption, dialog_content, dialog_help, back_button_label, next_button_label) - sets the dialog caption, content and buttons.

  • Wizard::DisableBackButton() - hides the Back button. It needs to be restored then.

  • Wizard::RestoreBackButton() - restores the hidden Back button

  • Wizard::SetNextButton(new_id, new_label) - changes the id and label of the Next button.

  • ...

All these functions are used in the dialogs.ycp for creating and handling the dialogs.

See the Wizard module documentation for the detailed information.

2.6.2. Dialog Content

Dialogs contents are stored in variables with the term data-type.

Fore more details about creating UI, widgets and layout see the YaST2 UI Layout and Events documentation.

[Important]Important

All widgets are case-sensitive.

There can be no missing or extra comma separating widgets.

term contents = `VBox (
    `Left(`Label(_("SSHD TCP Ports"))) // <--- missing a comma
    `Left(
	...
    )
);

term contents = `VBox (
    `Left(`Label(_("SSHD TCP Ports"))),
    `Left(
	...
    ), // <--- an extra comma
);

The `Left, `Right, `Top, `Bottom and `Frame widgets accept only one term argument. If you want to put more widgets inside, surround them with the `VBox or `HBox widget:

`Frame (
        /* a dialog frame caption */
        _("Server Features"),
        `VBox (
            /* a check box */
            `Left(`CheckBox(`id("AllowTcpForwarding"), _("Allow &TCP Forwarding"))),
            /* a check box */
            `Left(`CheckBox(`id("X11Forwarding"),      _("Allow &X11 Forwarding"))),
            /* a check box */
            `Left(`CheckBox(`id("Compression"),        _("Allow &Compression")))
	)
)

2.6.3. Standard Dialog Handling by a While-Loop

Every pressed `PushButton widget returns its id on the user event query (UI::UserInput()). See AAA_All-Widgets for more details about all possible general options for widgets.

2.6.3.1. Simple Loop Example

This script creates a Wizard dialog with two push buttons and the Back-Abort-Next navigation at the bottom.

If you press any of those two push buttons, the AnnounceKeyPress() function is called and reports the event by a pop-up window.

When Back or Next button is pressed, it reports the event by a pop-up window and then the script finishes. When pressed the Abort button or when you try to close the window by your window manager's Close [x] button a confirmation of closing the script is required.

// loop_example.ycp
{
    /* --- importing needed modules --- */
    import "Wizard";
    import "Report";
    import "Label";
    import "Popup";
    /* --- importing needed modules --- */

    /* --- definition of functions --- */
    // dialog definition
    term dialog_content = `HBox (
	`PushButton(`id("pb_1"), "Button &1"),
	`PushButton(`id("pb_2"), "Button &2")
    );

    // function definition
    void AnnounceKeyPress (any key_pressed) {
	y2milestone("Pressed %1", key_pressed);
	// sformat replaces %1 with the value stored in key_pressed variable
	Report::Message(sformat("Button with id '%1' has been pressed.",
	    key_pressed)
	);
    }
    /* --- definition of functions --- */


    /* --- setting UI up --- */
    // Opening up a standard Wizard dialog
    Wizard::CreateDialog();
    Wizard::SetContentsButtons("Caption", dialog_content, "dialog help",
	Label::BackButton(), Label::NextButton());
    /* --- setting UI up --- */


    /* --- handling user input --- */
    any ret = nil;
    // starting the endless while (true) { do... } loop
    while ("hell" != "frozen over") {
	ret = UI::UserInput();
      
	// One of those dialog buttons have been pressed
	if (ret == "pb_1" || ret == "pb_2") {
	    AnnounceKeyPress(ret);

	// Back or Next navigation button have been pressed
	} else if (ret == `back || ret == `next) {
	    AnnounceKeyPress(ret);
	    // exits from the loop
	    break;

	// Confirmation question before closing the script
	} else if (ret == `abort || ret == `cancel) {
	    // exits from the loop when user confirms
	    if (Popup::ContinueCancel("Do you really want to abort?")) break;

	// unexpected return code
	} else {
	    Report::Error(sformat("Unexpected retcode %1", ret));
	}
    }
    /* --- handling user input --- */


    // Every opened dialog must be properly closed
    UI::CloseDialog();
}