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