← 都来码 / Dolaima← 例程索引forth/ui/demo_ui.fth原文

forth/ui/demo_ui.fth · 7243 字节 · 下载原文

\ demo_ui.fth —— Forth 第四层:**最新 UI 接口**(`ui_*`)

\ demo_ui.fth —— Forth layer four: **the newest UI interface** (`ui_*`)

\

\ ## 这份文件为什么现在才存在

\ ## Why this file exists only now

\

\ 此前 Forth **没有** UI 例程,而且**写不出来**:用户词的调用约定把返回地址

\ Until now Forth had **no** UI example and **could not have one**: the user-word calling

\ `R15` 压在**数据栈上、插在实参中间**(`POP R1 / PUSH R15 / PUSH R1 / CALL`)——

\ convention pushed the return address `R15` onto the **data stack, between the arguments** (`POP R1 / PUSH R15 / PUSH R1 / CALL`)--

\ 一个参数的词碰巧对,**两个以上就串位**。`ui_2d_rect` 有 **8 个参数**,所以这一层根本调不动。

\ fine for a one-argument word, but **anything with two or more arguments went out of step**. `ui_2d_rect` takes **8**, so this layer was unreachable.

\

\ 2026-10-01 改成**内存返回栈**(`__forth_rp` / `__forth_rstack`,见

\ 2026-10-01: switched to an **in-memory return stack** (`__forth_rp` / `__forth_rstack`; see the call site in

\ `VMLPrepares/ForthCompiler/CodeGenerator.Words.cs` 的调用点注释):数据栈一个字节都不动,

\ `VMLPrepares/ForthCompiler/CodeGenerator.Words.cs`): the data stack is left untouched, so arguments land

\ 实参原样落在词该看到的位置。实测 `: ADD2 ( a b -- c ) + ; 5 7 ADD2 .` 从 **7** 变成 **12**。

\ exactly where the callee expects them. Measured: `5 7 ADD2 .` went from **7** to **12**.

\

\ ## 调库的两条 Forth 特有规矩(写错**不报错、只是输出不对**)

\ ## Two Forth-specific rules when calling into the library (getting them wrong **raises no error, it just misbehaves**)

\

\   ① **实参倒序压栈**:最后压的 = C 的第 1 个实参。

\   ① **Push arguments in reverse**: the last push is C's first argument.

\      所以 `ui_2d_rect(x,y,w,h,color,fill,lw,radius)` 写成

\      So `ui_2d_rect(x,y,w,h,color,fill,lw,radius)` is written

\      `radius lw fill color h w y x ui_2d_rect`(这里是"先压" ⇒ 写在最左)。

\      `radius lw fill color h w y x ui_2d_rect` (pushed first ⇒ written leftmost).

\   ② `S" ..."` 压的是 **(地址, 长度) 两个单元**,而 `char*` 形参只要一个指针

\   ② `S" ..."` pushes **two cells** (address, length) while a `char*` parameter wants

\      ⇒ **长度必须 `DROP`**,否则宿主收到空串。

\      one pointer ⇒ the length **must be `DROP`ped**, otherwise the host sees an empty string.

\

\ 跑法(桌面 vmlcli):

\   dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll Examples/forth/demo_ui.fth


#include "../../../Lib/forth/vml_ui.fth"

\ 画布尺寸(开窗之后才知道,见下面的 ui_scr_get_w / ui_scr_get_h)

\ Canvas size (only known after the window opens; see ui_scr_get_w / ui_scr_get_h below)

\ ⚠ 这个前端**不认 `VALUE` / `TO`**(实测「未定义的函数 'word_VALUE'」)⇒ 用 `VARIABLE` + `@` / `!`。

\ ⚠ This frontend has **no `VALUE` / `TO`** (measured: "undefined function 'word_VALUE'")⇒ use `VARIABLE` with `@` / `!`.

VARIABLE SW
VARIABLE SH

\ ── 开窗:ui_win_open(title, w, h) ────────────────────────────────────────

\ ── Open the window: ui_win_open(title, w, h) ────────────────────────────

\ 开窗:尺寸传 0 ⇒ **交给宿主用真实可用区**。开窗**之前** `ui_scr_get_w/h` 只能估算,而估算与

\ Open the window: pass size 0 ⇒ **the host uses the real available area**. **Before** the open,

\ 实际总有出入(这就是"内容偏上"的根因)⇒ 所以下面两句问出来的才是真实画布。

\ `ui_scr_get_w/h` can only estimate and the estimate differs from reality (exactly why the content sat high) ⇒ the two statements below query the real canvas.

\ 倒序:h → w → title。`S" ..."` 后面紧跟 `DROP` 掉长度。

\ Reverse order: h → w → title. Each `S" ..."` is followed by `DROP` on its length.

0 0 S" demo_ui.fth (Forth)" DROP ui_win_open DROP
\ 库函数的结果回到数据栈:`ui_scr_get_h` 先算(栈上先有 h),再 `ui_scr_get_w`

\ Library results come back on the data stack: compute `ui_scr_get_h` first (h lands first), then `ui_scr_get_w`.

ui_scr_get_h SH !
ui_scr_get_w SW !

\ 排版一律走 `SW @` / `SH @`(两个全局单元)。

\ Layout always goes through `SW @` / `SH @` (two global cells).


\ ── 清屏:ui_2d_clear(color) ────────────────────────────────────────────────

\ ── Clear the screen: ui_2d_clear(color) ──────────────────────────────────

0xFF101820 ui_2d_clear

\ ── 图元 ─────────────────────────────────────────────────────────────────

\ ui_2d_rect(x, y, w, h, color, fill, lw, radius)

\   最里层那块深色面板

\   the innermost dark panel

16 12 SW @ 16 - 120 0xFF1A1A24 1 0 10 ui_2d_rect
\   面板上的标题条(渐变蓝那种感觉先用纯色)

\   the title bar on that panel (a flat color stands in for the gradient blue for now)

22 18 SW @ 24 - 24 0xFF4A90D9 1 0 6 ui_2d_rect

\ ui_2d_circle(cx, cy, r, color, fill, lw)

SW @ 2 / 200 46 0xFFE06C50 1 0 ui_2d_circle

\ ui_2d_line(x1, y1, x2, y2, color, lw)

16 268 SW @ 16 - 268 0xFF3A3A4A 2 ui_2d_line

\ ── 文字:ui_2d_text(x, y, s, color, size, anchor) ───────────────────────────

\ ── Text: ui_2d_text(x, y, s, color, size, anchor) ─────────────────────────

\   `VML_ANCHOR_CENTER` 来自 `lib/forth/vml_ui.fth`(声明文件里带常量)

\   `VML_ANCHOR_CENTER` comes from `lib/forth/vml_ui.fth` (its declaration file carries constants)

20 22 S" UI / demo_ui (Forth)" DROP 0xFFE8E8F0 15 VML_ANCHOR_LEFT ui_2d_text
20 44 S" rect / line / circle / text" DROP 0xFF9AA0B0 12 VML_ANCHOR_LEFT ui_2d_text

\ ── 交帧 + 关窗 ──────────────────────────────────────────────────────────

\ ── Present the frame + close the window ─────────────────────────────────

\ ui_2d_present 是"这一帧画完了"的唯一信号;ui_win_close 收尾(宿主也会兜底)。

\ ui_2d_present is the only signal that "this frame is done"; ui_win_close wraps up (the host has a fallback too).

ui_2d_present
ui_win_close

\ 一行确认输出(判据脚本按它判断这份例程真的跑完了)

\ one-line confirmation output (the criteria script uses it to tell that this example really finished)

." demo_ui.fth: OK" CR