Skip to content

Talking to the VDC Client

So far the client has rendered whatever your forms describe. Sometimes you want to talk to it more directly from your program: set a window title, hide a field that does not apply, fill a drop-down at run time, or pop up a friendly notification. The VDC client exposes a small, practical API for exactly this.

All of these are ordinary 4GL calls — no GUI programming, just CALL. This chapter covers the ones you reach for daily; for the complete catalogue of ui.* functions, see the UI Function Reference.

Window title and styles

Set the title shown for the current program:

CALL ui.Interface.setText("Product Entry")

Load the application's visual style (textures, button look). The style itself is a file maintained centrally; your program just asks for it by name:

CALL ui.Interface.loadStyles("default")

You do not hand-colour buttons. The client colours actions by meaning — confirming actions (OK, Save, Yes) in green, cancelling actions (Cancel, No) in red, function keys in neutral tones — automatically. Write your logic and let the client present it consistently.

The client colours confirming and cancelling actions automatically
The client colours actions by meaning — confirming (Yes/OK/Save) in green, cancelling (No/Cancel) in red — and lays out the action sidebar for you. You write the logic, not the colours.

Hiding and showing fields at run time

A field can be present on the form but irrelevant in a given situation (for example, a "discount reason" that only matters when a discount is entered). Hide and reveal it from code.

Get the current window, get its form, then toggle the field. 1 hides, 0 shows:

DEFINE w ui.Window
DEFINE f ui.Form

LET w = ui.Window.getCurrent()
IF w IS NULL THEN RETURN END IF

LET f = w.getForm()
IF f IS NULL THEN RETURN END IF

CALL f.setFieldHidden("discount_reason", 1)    -- hide
CALL f.setFieldHidden("discount_reason", 0)    -- show

Which name do I pass? Use the variable/column name — the part after the = in the form's ATTRIBUTES line, not the layout tag. For Edit f_reason = FORMONLY.discount_reason; you pass "discount_reason".

(There is a sister call, setElementHidden, for hiding non-field elements such as labels and group boxes.)

Filling a drop-down from code

In chapter 3 we filled a ComboBox with a static ITEMS=(...) list. To fill it from the database or compute it at run time, get the combo by its field name, clear it, and add items. Each item has a value (what your variable receives) and a label (what the user sees).

DEFINE cb ui.ComboBox

LET cb = ui.ComboBox.forName("category")
CALL cb.clear()
CALL cb.addItem("F", "Food")
CALL cb.addItem("D", "Drink")
CALL cb.addItem("O", "Other")

A common pattern is to fill the combo from a query:

LET cb = ui.ComboBox.forName("category")
CALL cb.clear()
DECLARE c_cat CURSOR FOR SELECT code, label FROM categories ORDER BY label
FOREACH c_cat INTO rl_code, rl_label
    CALL cb.addItem(rl_code, rl_label CLIPPED)
END FOREACH

Toast notifications

A toast is a small, non-blocking message that appears briefly (typically bottom-right) and disappears on its own — perfect for "Saved", "Sent", "Nothing found" feedback that should not interrupt the user with a dialog.

CALL ui.vdc.toast("Record saved", 0, 3000)      -- green success, 3 seconds
CALL ui.vdc.toast("Could not save", 1, 5000)    -- red error, 5 seconds
CALL ui.vdc.toast("Please check input", 2, 4000) -- yellow warning
CALL ui.vdc.toast("Import started", 3, 4000)     -- blue info

The arguments are (text, type, duration_ms):

type Meaning Colour
0 Success Green
1 Error Red
2 Warning Yellow
3 Info Blue

Toast vs. a blocking message. Use a toast for "it worked / it didn't" feedback the user does not need to acknowledge. When the user must read and confirm something before continuing, use a blocking dialog (a MENU with a confirmation option) instead.

Toast notifications in the VDC client
Non-blocking toasts — success, error, warning and info — that appear briefly and fade on their own.

Light and dark mode

The user chooses Automatic, Light or Dark at login, and the client re-themes every window, menu and dialog to match — including your application's forms. There is nothing to do in your code: build your forms normally and they adapt.

The same application in light and dark themes
The same forms, re-themed light or dark — the user chooses, the client does the rest.

What the client gives your app for free

Because your program speaks a protocol rather than drawing pixels, every application automatically gains the client's features without any code on your side:

Feature What the user gets
Quick search Jump to recently used records and commands
Window navigator See and switch between all open windows
Grouped windows (MDI) Related forms shown together in one container
Context help Field- and screen-level help on a key press
Mobile client The same program runs on a mobile client, unchanged
Several related forms grouped in one window container
Related forms grouped together (MDI) in one window — a client feature your program gets for free.

One program, many clients. The desktop client and the mobile client speak the same XML protocol to your program. You write and compile your application once; the client — desktop or mobile — renders it. You do not write separate code or separate forms for mobile.

The same program running on the mobile client
The same compiled program on the mobile client — your forms, menus and lists render natively, with no extra code and no separate mobile project.

You now know how to drive the client. The last piece is shipping: how to compile everything from the command line. Continue to Building and Running.