
1. Ad hoc dialogs and Progress bars
This page describes features introduced in ACF Plugin version 1.7.9.3. The native user interface is currently available in the macOS plugin.
- Ad hoc dialogs and Progress bars
1.1. Introduction ↑
The ACF Plugin can create native input dialogs and progress windows without requiring a dedicated FileMaker layout. This is useful for parameter collection, settings, report options, imports, exports, and other tasks that would otherwise require global fields and utility layouts.
Both features can be used from:
- FileMaker calculations, including calculations evaluated by scripts.
- Compiled ACF functions.
Progress windows can additionally be updated and closed with native FileMaker script steps.
1.2. Ad hoc dialogs ↑
An ad hoc dialog is described by a JSON object. The object defines the window title, size, fields, initial values, buttons, and optional alternative layouts. The dialog is modal: execution pauses until the user presses a button or closes the window, after which the entered values are returned as JSON.
No FileMaker layout, global field, or card window is needed.
1.3. Start with the Dialog Configurator ↑
The recommended way to create a dialog is the visual Dialog Configurator:

https://horneks.no/manuals/ACF/tools/dialog-configurator-1.7.9.7.html
The configurator lets you:
- Add and arrange fields and columns.
- Select field types and initial values.
- Configure labels, widths, buttons, field buttons, and dialog dimensions.
- Create variations controlled by a master selector.
- Configure action callbacks for buttons and field changes.
- Preview an approximation of the native dialog.
- Generate serialized JSON for
ACF_OpenDialog. - Generate ACF source using
JSON,JSONarray, andopen_dialog. - Download a JSON definition and load it again for later editing.
The generated JSON can normally be used directly. You only need the technical specification later if you want to build or modify dialog definitions dynamically.

1.4. Opening a dialog from FileMaker ↑
Use the external plugin function:
ACF_OpenDialog ( dialogJSON )
dialogJSON is a text parameter containing a serialized JSON object. The function returns the result as serialized JSON text.
For example, use FileMaker's Insert Text script step to place the JSON copied from the configurator in a variable. Select $definition as the target, then paste the JSON into the text window provided by the script step:
Insert Text [ Select ; Target: $definition ; "{ ...dialog JSON from the configurator... }" ]
Set Variable [ $result ; Value: ACF_OpenDialog ( $definition ) ]
Using Insert Text avoids having to escape every double quote in the JSON as required by a FileMaker calculation string.
You can then read the selected button and field values with FileMaker's JSON functions:
JSONGetElement ( $result ; "button" )
JSONGetElement ( $result ; "values.Customer" )
Because ACF_OpenDialog is a calculation function, it can be used in script calculations without compiling an ACF package.
1.5. Opening a dialog from an ACF function ↑
Inside ACF, open_dialog accepts one native JSON value and returns a native JSON result:
JSON result = open_dialog(definition);
The configurator can generate the complete ACF definition. A small example is:
function AskForCustomer()
JSON definition = JSON(
"title", "Customer search",
"subtitle", "Enter the search parameters.",
"size", JSONarray(520, 330),
"labelPosition", "left",
"fields", JSONarray(
JSON("name", "Customer", "label", "Customer", "type", "text", "width", "full"),
JSON("name", "FromDate", "label", "From date", "type", "date")
),
"values", JSONarray("", "2026-06-15"),
"buttons", JSONarray(
JSON("id", "search", "label", "Search", "default", true),
JSON("id", "cancel", "label", "Cancel", "cancel", true)
)
);
JSON result = open_dialog(definition);
return result;
end
The ACF function is blocked while the modal dialog is open. When the user closes the dialog, execution resumes with the returned JSON value.

1.6. Dialog result ↑
A successful result contains the selected button and a flat object of field values:
{
"button": "search",
"buttonLabel": "Search",
"values": {
"Customer": "Horneks",
"FromDate": "2026-06-15"
}
}
The button value is the button's id. buttonLabel is the visible label. If the window is closed without a configured cancel button, button can be null.
Field names become keys below values. If the same field name occurs more than once in the active layout, the returned value for that name is an array:
{
"values": {
"Tag": ["First", "Second"]
}
}
If the definition cannot be parsed or displayed, the result includes an error member:
{
"button": null,
"values": {},
"error": "Dialog definition must be a JSON object"
}
1.7. Dialog JSON specification ↑
1.7.1. Root object ↑
| Key | Type | Description | Default |
|---|---|---|---|
title |
string | Window title. | Dialog |
subtitle |
string | Optional explanatory text below the title bar. | Empty |
size |
array | Dialog width and height in pixels, for example [620, 430]. Minimum dimensions are applied internally. |
[560, 440] |
labelPosition |
string | above places labels above controls. left aligns labels in a shared label area within each column. |
above |
fields |
array | Fields for a single-column dialog. | Empty |
values |
array | Initial values corresponding by position to fields. |
Empty |
columns |
array | Alternative to root-level fields; each column contains its own fields and values. |
None |
buttons |
array | Button strings or button objects. | OK and Cancel |
selector |
object | Optional master selector for switching between alternative field sets. | None |
variants |
object | Field layouts keyed by selector values. | None |
Use either fields and values, or columns, for a given layout section.
1.7.2. Fields and initial values ↑
The shortest field definition is a string:
{
"fields": ["Customer", "Reference"],
"values": ["Horneks", ""]
}
The string is used as both the field name and its label, and the control type is text.
For full control, use a field object:
{
"name": "Notes",
"label": "Notes for the report",
"type": "textarea",
"width": "full",
"height": 120
}
| Field key | Type | Description |
|---|---|---|
name |
string | Key used in the returned values object. |
label |
string | Label shown to the user. Defaults to name. |
type |
string | Control type. Defaults to text. |
width |
number or string | Fixed pixel width, or full/max to use the available column width. |
height |
number | Text area height in pixels. The minimum is 50. |
options |
array | Stored values for select and radio fields. |
labels |
array | Optional display labels corresponding to options. |
value |
any JSON value | Initial value used when no matching entry exists in the section's values array. |
The section-level values array is positional: its first item belongs to the first field, its second item to the second field, and so on.
1.7.3. Supported field types ↑
| Type | Description | Returned value |
|---|---|---|
text |
Single-line text field. | string |
textarea |
Multiline text area with vertical scrolling. It fills the available width. | string |
checkbox |
Checkbox. | boolean |
select |
Popup selection list. | selected option value |
radio |
Vertical group of radio buttons. radiobuttons is also accepted. |
selected option value |
date |
Editable date field with a popup calendar. | YYYY-MM-DD string |
time |
Time field with a native time picker. | HH:mm:ss string |
For select and radio, options contains the returned values. An optional labels array can provide different user-facing text:
{
"name": "Status",
"label": "Order status",
"type": "select",
"options": ["open", "complete"],
"labels": ["Open orders", "Completed orders"]
}
1.7.4. Multiple columns ↑
Use columns when fields should be arranged side by side. Each column is a field section with its own fields and values arrays:
{
"columns": [
{
"fields": [
{ "name": "LastName", "label": "Last name", "type": "text" },
{ "name": "BirthDate", "label": "Birth date", "type": "date" }
],
"values": ["", ""]
},
{
"fields": [
{ "name": "FirstName", "label": "First name", "type": "text" },
{ "name": "Active", "label": "Active", "type": "checkbox" }
],
"values": ["", true]
}
]
}
A field with "width": "full" fills its own column, not the complete dialog width.
1.7.5. Buttons ↑
A button can be defined by a simple label:
"buttons": ["OK", "Cancel"]
For stable result identifiers and keyboard behavior, button objects are recommended:
"buttons": [
{ "id": "run", "label": "Run report", "default": true },
{ "id": "cancel", "label": "Cancel", "cancel": true }
]
| Button key | Type | Description |
|---|---|---|
id |
string | Value returned in button. |
label |
string | Visible button title. |
default |
boolean | Makes the button respond to Return/Enter. |
cancel |
boolean | Makes the button respond to Escape and identifies the result used when the window is closed. |
1.7.6. Variations and a master selector ↑
A dialog can change its field layout when the user selects an option. This is useful when one settings dialog supports several related operations, such as Offers, Orders, and Invoices.
The root selector defines the master selection control. The root variants object contains one field section for each selector option:
| Selector key | Type | Description |
|---|---|---|
name |
string | Key used for the selected value in the returned values object. |
label |
string | Label displayed beside the master selector. |
options |
array | Selector values. Each value must have a corresponding key in variants. |
labels |
array | Optional display labels corresponding to options. |
value |
string | Initially selected option. The first option is used when this is omitted. |
Each member of variants is a normal layout section containing either fields and values, or columns.
{
"title": "Report settings",
"selector": {
"name": "ReportSource",
"label": "Report source",
"options": ["offers", "orders", "invoices"],
"labels": ["Offers", "Orders", "Invoices"],
"value": "orders"
},
"variants": {
"offers": {
"fields": [
{ "name": "Customer", "label": "Customer", "type": "text" }
],
"values": [""]
},
"orders": {
"fields": [
{ "name": "OrderNumber", "label": "Order number", "type": "text" },
{ "name": "Completed", "label": "Include completed orders", "type": "checkbox" }
],
"values": ["", false]
},
"invoices": {
"fields": [
{ "name": "InvoiceNumber", "label": "Invoice number", "type": "text" },
{ "name": "PaymentStatus", "label": "Payment status", "type": "radio", "options": ["all", "paid", "unpaid"], "labels": ["All", "Paid", "Unpaid"] }
],
"values": ["", "all"]
}
},
"buttons": [
{ "id": "run", "label": "Run report", "default": true },
{ "id": "cancel", "label": "Cancel", "cancel": true }
]
}
The selected option is returned in values under the selector's name, together with the values from the active variant:
{
"button": "run",
"values": {
"ReportSource": "orders",
"OrderNumber": "10452",
"Completed": false
}
}
Each variant can use either a single fields/values section or its own columns array. Values entered in a variant are retained if the user switches to another option and then returns before closing the dialog.
1.8. Progress bars ↑
Progress bars provide visible feedback while a FileMaker script or ACF function performs lengthy work. A progress window has a title, status message, progress indicator, and numeric handle.
The handle identifies the window in later update and close calls. Several progress windows can exist at the same time; they are independent and are stacked around the active FileMaker window.
Two display modes are available:
- Determinate: use values from zero through the configured maximum.
- Indeterminate: pass a negative value to an update call to display the animated barber-pole indicator. A later non-negative value returns it to determinate mode.
1.8. Progress bars ↑ in ACF functions
The ACF language provides three operations:
int handle = progress_open(title, message, maximum);
progress_update(handle, value, message);
progress_close(handle);
progress_open returns a numeric handle. progress_update and progress_close are statements and do not return values.
Example:
function ProcessRecords(int recordCount)
int handle = progress_open(
"Updating records",
"Preparing...",
recordCount
);
int i;
for (i = 1, recordCount)
// Perform work for record i here.
progress_update(
handle,
i,
format("Processing record %d of %d", i, recordCount)
);
end for
progress_close(handle);
return recordCount;
end
For work where the total cannot be calculated in advance:
int handle = progress_open("Import", "Connecting...", 100);
progress_update(handle, -1, "Receiving data...");
// Perform work with an unknown duration.
progress_update(handle, 80, "Finishing import...");
progress_close(handle);
The progress window remains responsive while the ACF function runs.
1.8. Progress bars ↑ in FileMaker calculations

The corresponding external calculation functions are:
ACF_ProgressOpen ( title ; message ; maximum )
ACF_ProgressUpdate ( handle ; value ; message )
ACF_ProgressClose ( handle )
ACF_ProgressOpen returns the handle. The update and close functions return 1 when the handle was found and the operation succeeded.
A FileMaker script can control a progress window entirely through calculations:
Set Variable [ $progress ; Value: ACF_ProgressOpen ( "Export" ; "Preparing..." ; $recordCount ) ]
# Perform work and update $current in a loop.
Set Variable [ $updated ; Value: ACF_ProgressUpdate ( $progress ; $current ; "Exporting record " & $current ) ]
Set Variable [ $closed ; Value: ACF_ProgressClose ( $progress ) ]
The handle is not tied to the individual calculation call. It can be stored in a FileMaker variable, passed between scripts, or returned from an ACF function and used in later calls.
1.11. Progress script steps ↑
FileMaker also registers these native plugin script steps:
- ACF Progress Update
Handle- calculation returning the progress handle.Value- calculation returning the new progress value. A negative value selects indeterminate mode.Message- calculation returning the new status text.
- ACF Progress Close
Handle- calculation returning the progress handle.
A common pattern is to open the progress window with ACF_ProgressOpen in a Set Variable step, update it with ACF Progress Update inside a loop, and finish with ACF Progress Close.
The same handle can cross the boundary between ACF and FileMaker. For example, an ACF function can open a progress window and return its handle, after which a FileMaker script can update or close it. Likewise, a FileMaker calculation can open a window whose handle is passed into an ACF function.
1.12. Practical notes ↑
- Always close a progress window when the operation completes or is cancelled.
- Keep the handle in a variable whose lifetime covers all update and close calls.
- Use determinate progress when the total amount of work is known; use a negative update value otherwise.
- Dialogs are modal and intentionally block their calling ACF function or FileMaker calculation until dismissed.
- Progress windows are non-modal and are intended to remain visible while work continues.
- These native windows require a graphical FileMaker client and are not available in headless FileMaker Server execution.
