ci-server-engineer/.claude/skills/graphics/tasks/layouts.md
cliu 516729ff24 R1.05 findings from a user project (tested only)
Tested on the R1.05 test server 2026-10-09..12 with a user project (own
objects only); not yet on CI-Eng-Sample (ISS-188). Only results that
were tested are included; inferences, code-only and manual-only points
and the untested sample layout change were left out.
- layouts: 'logout' is a secondary logout, always disabled on the R1.05
  web client; 'exit' closes the window and ends the session (ISS-182).
- create-display: R1.05 web client table (String items in text vs
  textField, fixed text alignment, start-hidden limits ISS-183, two
  visibility conditions, On entry display actions, rectangle blinking,
  verified connections, first load).
- java-class 4a: signal arrays at scale, write on change, attribute
  arrays, offline javac/javap check; change-reset-class: new signals need
  the object recreated, attributes lost (ISS-185); opcdbg reset in cmd,
  TRIGGER_1 via dssqld -m.
- string-items (ISS-187), users-groups, modbus-station (400 registers,
  comm loss), export-dataset (NAME range filter), item-alarming.
- new task system-management/package-project.md; tools/ModbusSim.java
  (tested on R1.05: FC03/04/06/16, exceptions, modes); AMSI (ISS-186).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:57:08 +11:00

265 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
task: Configure operator layouts (Layouts.xml): windows, menus, toolbars, frames, popups; open displays in frames and layouts
version: R1.05 (first written for R1.03)
source: Layouts.readme (installed, %TLS_WAP_PATH%\cfg\operatorInterfaces\DEPLOY\layouts; R1.03 copy); IM 36K10R30-01EN §1, §4.4, §4.7 (R1.05 4th ed. Feb. 2026); IM 36K10C50-01EN §4.12; practiced with CI-Eng-Sample (layout CIENG_Operator) in the Operator Interface (desktop) and the HTML display 2026-10-01; parameter-by-parameter test (§6) on both clients 2026-10-02, web behaviour also read from the installed web client code (mobileoperator fasttools.min.js); sample operator HMI (layouts CIENG_Operator with a tab set and CIENG_Popup, user CIENG) and test layouts on both clients 2026-10-06
status: verified on R1.03 (parameters tested on desktop and web 2026-10-02 except print orientation/margins, playback, multi-screen positions and the maximumTabs limit for new tabs). R1.05: R30 ch. 1 (layouts) unchanged apart from wording (re-checked 2026-10-08, from docs); the installed R1.05 `Layouts.readme` / `Layouts-original.xml` and the web client were not compared yet (awaiting user verification, ISS-092); no layout may be changed on the shared R1.05 test server
---
# Operator layouts
A **layout** is a window of the Operator Interface: optional menu and toolbars, a **frame set**
(required) holding displays, and a status line. All layouts of a deployment are in one file,
`%TLS_WAP_PATH%\cfg\operatorInterfaces\DEPLOY\layouts\Layouts.xml`, used by **both** the
Operator Interface (desktop) and the HTML display (web). The complete option and command
reference is `Layouts.readme` in the same folder; `Layouts-original.xml` is the factory copy.
## 1. Rules
- `Layouts.xml` is shared by every operator: back it up and change it only with the user's
approval. Keep project layouts in a marked block so they can be removed cleanly (sample:
`examples/CI-Eng-Sample/layouts/layout.ps1` + `CIENG_Operator.xml`; the script checks the XML
is well-formed, keeps UTF-8 without BOM and CRLF, and `-Remove` restores the file byte for byte).
- **The Operator Interface reads `Layouts.xml` only when it starts.** After a change, close and
restart it. A running client does not know a new layout: opening a display in it only reloads
the current window ("blink"). The Edit Module also needs a restart to offer the new name in
the *Open display* action.
- Name the main frame **`default`**: the factory and AOG displays (alarm lists, faceplates,
toolbar commands) open their targets in a frame called `default`. At login the user profile's
*Initial display* replaces the `initialDisplay` of frame `default` (desktop; web: `?d=`).
- Layouts used by **both** clients must have the web-compatible shape (§6.1): per frame set at
most one `n*` division, and at most one nested frame set, placed in that `n*` slot. A `<tab>`
set must be the **last** child of its frame set (§6.6). Always
set `title` and `drawBorder`.
- Menu items whose command has an on/off state (`toolbar`, `statusline`, `playback record`)
**must** be `type="check"`: otherwise the Operator Interface fails at start
(`ClassCastException … JCheckBoxMenuItem`).
## 2. Structure
```xml
<layout name="<Name>" title="<text> $default" icon="poi.png" drawBorder="true"
sizingAllowed="true" minimizingAllowed="true" closingAllowed="true" alwaysOnTop="false"
initialPosition="centreScreen" initialSize="pixels" initialSizeWidth="1600"
initialSizeHeight="900" maximumOpen="1">
<menu> <menu-item name="m.file" label="File"> <menu-item … command="exit"/> </menu-item> … </menu>
<toolbar name="t1" floatable="false" position="top"> <toolbar-item icon="ciNavLeft32.png"
tooltip="Back to $" command="navigate back default"/> … </toolbar>
<frame-set rows="1*,fitDisplay"> <!-- main area, alarm banner below -->
<frame-set cols="fitDisplay,1*"> <!-- navigation left, main right -->
<frame name="nav" initialDisplay="<NavDisplay>" zoomingAllowed="false"/>
<frame name="default" initialDisplay="<Overview>" stackSize="10" zoom="fitDisplay"/>
</frame-set>
<frame name="alarmBannerFrame" initialDisplay="AOG_AlarmBanner" zoom="stretchDisplay"/>
</frame-set>
<status-line> <status-line-item type="statusText"/> <status-line-separator/> … </status-line>
</layout>
```
- `title`: `$<frame>` = title of the display in that frame (verified: *CI-Eng-Sample - Current
Alarm Overview*).
- Window: `initialPosition` (`centreScreen`, `atCursor`, `pixelsScreen2`, `centreLayout`, …),
`initialSize` (`pixels`, `screenSize`, `desktopSize`, `fitFrames`), `maximumOpen`, `modal`,
`alwaysOnTop`, print options.
- Frame sets: `rows` / `cols` with pixels, `n*` or `fitDisplay` (fractions are not honoured and
the web client limits nesting: §6.1); a `<tab>`
holds several frames as tabs (`tabPosition`, `maximumTabs`, `closeTabAllowed`). Frame options:
`name`, `initialDisplay` (= home display), `stackSize` (back/forward history), `zoom`
(`fitDisplay`, `stretchDisplay`, `<n>%`), `zoomingAllowed`, `scrollingAllowed`, `borderStyle`.
- Menu (max. two levels; `type` normal/check/radio/sub; `mnemonic`, `accelerator` like `F5`,
`CONTROL P`) and toolbar items (`icon` from the factory set such as `ciNavLeft32.png`,
`ciProAlar32.png`, `ciZoomFull32.png`; `type` combo/editableCombo/dropdownList) run commands:
| Command | Effect |
|---|---|
| `navigate to <frame> <display> [<zoom>] [<p>=<v>;…]` | Open a display in a frame (with parameters) |
| `navigate back/forward/up/home/history <frame>` | Frame history (`$` in the tooltip = target name) |
| `reload <frame>` / `reload all` | Reload displays (keeps the session in the HTML display) |
| `zoom <level> <frame>` | 0 = fit, 1 = 100 %, 10–1000 = relative % |
| `toggleSize fullScreen [n]` / `toggleSize x,y,WxH` | Full screen / given size and back |
| `print frame|frameWithSetup|preview|setup|selectFrame` | Printing (desktop only) |
| `login`, `logout`, `exit`, `toolbar`, `statusline`, `playback record|view`, `shell client|server <cmd>`, `lookfeel <class>` | |
| `help` | Listed in the readme but fails in R1.03: *Unrecognized keyword* (ISS-062) — do not use |
The installed status line also uses item types `displayName`, `playbackIndicator` and
`dateTime`, which the readme does not list (ISS-042).
- `<translations name="nl">` blocks translate labels per locale (key = item name + `.label`).
## 3. Opening displays in frames and layouts
| From | How |
|---|---|
| Button / component (Edit Module, *Actions* sheet → *Open display*) | Display, **Layout** (empty = current window), **Frame**, parameters; stored as `<action type="actionActivateDisplay">` with `<type … value="ActivateSpecific"/>`, `<display>`, `<layout>`, `<layoutFrame>` |
| Menu / toolbar | `navigate to <frame> <display>` (current window only) |
| Login | User profile *Layout* and *Initial display* (Engineering Module, Authorization > Users, or `USER_DF` `LAYOUT` / `INITIAL_DISPLAY`); empty layout = `default`. Verified 2026-10-06 with the sample user `CIENG` (layout `CIENG_Operator`, display `CIENG_Overview`): applied on the desktop **and** at web logon without `?l=` |
| HTML display | URL `?d=<display>&l=<layout>` |
| Script on a component | *Execute command* (client side) with `ACTION <layout command>`, e.g. `ACTION toggleSize 50,50,710x520`. Desktop only: the web client ignores it (2026-10-02). **One command at a time**: a second `ACTION` while the first runs fails with *IllegalStateException: A command is already being executed* (desktop, tested 2026-10-06 with two `ACTION reload all` on one button) |
Verified behaviour (desktop, 2026-10-01, with the former sample layout `CIENG_Operator`): a button with that layout opened a **second window**
(1600 × 900, own menu/toolbar/frames); buttons without layout opened their display in the main
frame of the current window; **Back** returned. A button with layout `popup` opened a separate
window: always on top, only a close button, sized to the display (`fitFrames`), and minimised
together with the window that opened it — use popups only for small displays (faceplates,
setpoint dialogs).
## 4. Typical project layouts
- **Operator main window**: navigation frame + main frame `default` (+ tabs) + alarm banner,
project menu/toolbar, assigned to operators via the user profile *Layout*.
- **Kiosk / control-room screen**: `drawBorder="false"`, `alwaysOnTop="true"`,
`initialSize="screenSize"`, `closingAllowed="false"`, `minimizingAllowed="false"`.
`toggleSize fullScreen` covers the taskbar only when `alwaysOnTop="true"` (verified: with
`false` the title bar and taskbar stay).
- **Popups / faceplates**: small layout with one frame `default`, `initialSize="fitFrames"`,
`initialPosition="atCursor"`, `alwaysOnTop="true"`, `maximumOpen` > 1 for several faceplates
(factory: `popup`, `FixedPopup`, `ResizablePopup`, `faceplate`, `tuningpanel`, `Setpoint`,
`SelectMode`).
- **Several screens**: one layout per screen with `initialPosition="pixelsScreen2"` /
`centreScreen2`, or the dual-screen pattern of IM 36K10R30 §1.10.
## 5. HTML display differences
The browser window is the main layout (its size and window options are ignored); other layouts
open as windows inside the page; print, look-and-feel and the debug key are not supported; pick
the layout with `&l=`, or let the user profile choose it (§3). Verified 2026-10-06:
`?l=CIENG_Operator` (and a plain logon as `CIENG`) showed the sample menu, navigation toolbar,
header, tab set and banner. The web client does not zoom displays (§6.1), so size them for the
browser window. The manual agrees: IM 36K10R30-01EN §4.4 (R1.03 and R1.05) marks the profile's
*Layout* as supported on the HTML display; the earlier reading "layout not" came from a garbled
text extraction of that table (ISS-074, ISS-095). In R1.05 the *Enterprise* profile settings are
also marked supported on the web.
## 6. Parameter reference: desktop vs web (tested 2026-10-02)
Test method: a marked test block in `Layouts.xml`; each layout started on the desktop with
`jwuipoi.cmd -layout <name>` (start options from the installed client: `-layout`, `-display`,
`-host`, `-port`, `-secure`, `-hide`, `-timeout`, `-readtimeout`, `-ssotoken`) and in the browser
with `?d=<display>&l=<layout>`. Desktop windows checked with window captures, web pages in the
browser and in the web client code. "n/a" = the browser window is the main layout.
### 6.1 Frames
| Parameter | Desktop | Web |
|---|---|---|
| `rows`/`cols` in pixels | exact | exact |
| `fitDisplay` | fits the display | edge panel only; default 200 px (left/right) or 50 px (top) |
| `n*` fractions (`2*,1*`) | **not honoured** (sizes follow the displays, e.g. 800:88 px) | every `n*` becomes the *main* panel; two `n*` overwrite each other, only the last display shows |
| Divisions per frame set | any | first = top/left, last = bottom/right, `n*` = main; more do not fit |
| Nested `frame-set` | anywhere, several | **always placed in the parent's main panel**; two nested sets, or one in an edge position, break the page (stays on *Loading…*) |
| Frame `zoom` (`fitDisplay`, `stretchDisplay`, `n%`) | applied, **except for frames inside a `<tab>`** (shown at 100 %; use `navigate to <frame> <display> fitDisplay|stretchDisplay`, tested 2026-10-06) | ignored (always 100 %) |
| `borderStyle` | drawn | only with `drawBorder="true"`; every value except `none` becomes a 1 px line |
| `stackSize` | honoured | honoured; default when missing = 1 |
| `zoomingAllowed="false"` | `zoom` commands on that frame do nothing | zoom not supported at all |
| `scrollingAllowed` | scrollbars when the display is larger | panel overflow auto/hidden |
| `initialDisplay` of frame `default` | replaced by the user profile's initial display | replaced by `?d=` |
### 6.2 Window (`<layout>`)
| Parameter | Desktop | Web |
|---|---|---|
| `title` | `$<frame>` → display **title** | `$<frame>` → display title or name; **missing `title` → tab shows "undefined"** and a script error |
| `icon` | title bar and taskbar | favicon |
| `drawBorder` | default **false** = no title bar and no border | frame borders only |
| `sizingAllowed`, `minimizingAllowed` | default **false** | n/a |
| `closingAllowed="false"` | close button still shown, closing is ignored; closing the last window ends the client | n/a |
| `alwaysOnTop` | topmost window | n/a |
| `initialPosition` `pixels`, `pixelsScreen1`, `centreScreen` | exact | n/a |
| `initialSize` `pixels` / `fitFrames` / `screenSize` / `desktopSize` | exact / wraps the display / whole screen incl. taskbar (same on one screen) | n/a |
| Defaults (nothing set) | borderless, at 0,0, sized to the display | works |
| `lookAndFeel` (Metal) | applied; adds a second (Metal) title bar inside the window | n/a |
### 6.3 Menu, toolbars, status line
| Item | Desktop | Web |
|---|---|---|
| `type="sub"` / `check` / `radio` | work (radio bullet, check tick) | **not shown** (items dropped) |
| `accelerator` | F11 works; F5 / ALT keys not confirmed | — |
| `$` in `tooltip` | resolved | resolved |
| Toolbar `position="top"` | shown | shown |
| Toolbar `left` / `right` | shown | **not shown** |
| Toolbar `bottom` | **not shown** (two layouts tried) | not shown |
| Toolbar item `combo`, `editableCombo`, `dropdownList` | shown | shown |
| Status line, all 8 types | shown | 7 shown; **`connectionState` breaks the layout**: at login `createStatusline` fails (*Cannot read properties of undefined (reading 'split')*) and no frame is created (tested 2026-10-06, ISS-068) |
### 6.4 Commands
| Command | Desktop | Web |
|---|---|---|
| `navigate to <frame> <display> [zoom] [params]` | works, zoom applied | works, **zoom ignored** |
| `navigate back/forward/home/up/history/backList/forwardList` | work | work (`home` is added to the history) |
| `reload <frame>` / `reload all` | work | work |
| `zoom <level> <frame>` (0, 1, 2, 0.5, 150) | work | not supported |
| `toggleSize fullScreen [n]` | work area (taskbar stays unless `alwaysOnTop`); again = back | browser full screen; screen number ignored |
| `toggleSize x,y,WxH` | works; again = back | not possible in a browser tab |
| `toolbar` (check) | hides/shows **all** toolbars; `toolbar false` behaves as a toggle too | no effect |
| `statusline` (check) | hides/shows (a piece of the date field stays painted) | no effect |
| `print …` | preview / setup dialogs open | disabled |
| `login` / `logout` / `exit` | — / — / closes | login disabled; **`logout` disabled on R1.05** (greyed; see note); `exit` closes the window and ends the session |
| `shell client <cmd>` | runs on the client (Notepad opened) | sent to the server; `shell client ACTION <layout command>` runs a layout command |
| `lookfeel <class>` | — | no effect |
| `playback record` (check) / `view` | — | not supported (view disabled) |
| `help` | **error** *Unrecognized keyword* | — |
**`logout` is a secondary logout (R1.05, verified 2026-10-12).** The factory layout labels it *Secondary logout* (pair of `login`). The R1.05 web client always disables it (`LayoutWindow.js`: `setEnabled(false)` for `logout`; the command calls `secondaryLogout()`), so a toolbar or menu item with `logout` is greyed out. To let a user leave on the web, use **`exit`**: it closes the layout window and, for the last window, ends the session; the browser then closes the tab (reopening the URL shows the login page). Label the item *Exit* rather than *Log out*. Tested on the web client; the desktop Operator Interface was not tried. The sample layout `CIENG_Operator` still has a *Log out* (`logout`) menu item.
"—" = not checked.
### 6.5 Layouts opened from a display, translations, debug key
Tested with a launcher display (copy of `CIENG_Menu` whose buttons use *Open display* with a
layout and frame `default`).
| Parameter | Desktop | Web |
|---|---|---|
| `modal="true"` | dialog window (no min/max); the opener is disabled until it closes | in-page window with a full-page lock; centred |
| `maximumOpen="2"` | 2 windows; the 3rd click: *The display '…' cannot be activated because the maximum number of windows is reached* | same (in-page windows, same message) |
| Popup size (`initialSize="pixels"`) | applied | applied (500×350, 450×300) |
| `initialPosition="centreFrame"` | **at 0,0** (not centred) | centred in the page |
| `initialPosition="centreLayout"` | near the opener, not exactly centred (opener partly off-screen) | centred in the page |
| `atCursor` / `awayFromCursor` | opened at 1677,363 near the launcher click (cursor position not logged) / at 10,890, the far bottom-left corner | — |
| `<translations name="<locale>">` | applied for the exact JVM locale (`en_AU` here): layout `title`, menu and toolbar `label`, `tooltip`; **no fallback** from `en_AU` to `en` | browser locale `en-US`: neither `en_AU` nor `en` applied |
| `debugActivationKey` (`CONTROL SHIFT F6`) | opens the *Graphics debugger* (connections and parameters of the display) | not supported (see §5) |
Keys: `<layout name>.title`, `<item name>.label|tooltip|mnemonic|accelerator`. The desktop
locale comes from Windows (the start script sets no `-Duser.language`).
### 6.6 Tabs (`<tab>`)
Factory pattern (works on both clients): a `<tab name="default">` holding frames `tab1`,
`tab2`, … in the `n*` slot of a **nested** frame set, next to the navigation frame.
| Parameter | Desktop | Web |
|---|---|---|
| Tab labels | display title (the profile's initial display goes into the first tab) | display **title** (`_` until the display is loaded; verified 2026-10-06 with the sample tabs) |
| Frame `zoom` on a tab frame or on `<tab>` | ignored (100 %); `navigate to <tab frame> <display> stretchDisplay` applies it (sample: toolbar, menu and an *On entry* `ACTION` of the banner) | not supported |
| Active tab after login | the profile's initial display tab | the **last** tab whose display loaded; the sample banner (loaded after the tab set) opens `CIENG_Overview` in its tab with an *On entry* action to bring Overview to the front |
| Position of `<tab>` in its frame set | any | must be the **last** child: the tab click handler uses the last panel created in the frame set; tab set first (banner after it): labels stay `_`, *Unable to switch/load requested display*, tab clicks fail, the banner frame is missing (tested 2026-10-06, ISS-069) |
| `tabPosition` `bottom` / `left` | applied | **ignored** (always top) |
| `navigate to <tab set name> <display>` | replaces the display in the **active** tab; no new tab | — |
| `navigate to <tab frame name> <display>` | shows it in that tab | — |
| `closeTabAllowed` on a tab frame | `true` = close button, `false` = none; closing works | same |
| `closeTabAllowed` (and other defaults) on `<tab>` only | **not inherited** by the frames (no close buttons) | not inherited |
| `maximumTabs` | does not limit the initial tabs (`1` with 2 frames shows 2); the limit for new tabs was not reached by `navigate`, so not confirmed | initial tabs not limited |
| `minimumTabLabelWidth`, `tabButtonGap` | no visible effect | — |
| Frame with `initialDisplay=""` | empty tab | — |
| Tab set next to the nav frame at the **top level** (with menu, empty tab) | works | **hangs** on *Loading…* (nav frame not created); the factory shape works |
## Verified (CI-Eng-Sample, 2026-10-01)
`layout.ps1` add / remove / add (removal identical to the original, backup kept); Operator
Interface restart required before the layout was found; desktop and web windows as described
above; F11 (`toggleSize fullScreen`) worked within the taskbar limits; after restarting the
Operator Interface the main window still used the factory `default` layout (Admin profile
unchanged).
2026-10-06 (sample operator HMI): `layout.ps1` add / remove / add with `CIENG_Operator` (tab set
in a nested frame set, last child) and `CIENG_Popup`; removal restored `Layouts.xml` byte for
byte. User `CIENG` lands in `CIENG_Operator` on Overview on both clients; ADMIN keeps the
default layout. Test layouts (removed again): tab set first in its frame set (web broken),
`maximumTabs` 8 with 2 tab frames (no extra tab on the web), status line with `connectionState`
(web broken).
## R1.05 test server (V5, 2026-10-09, read-only)
`Layouts.readme` is identical to R1.03. No factory copy `Layouts-original.xml` was found in the
R1.05 `DEPLOY\layouts` folder (only the live `Layouts.xml` and backups made by projects): keep
your own backup before changing `Layouts.xml` (`layout.ps1` does this).