// demo_ui.m —— **最新 UI 接口**示范（Objective-C）
// demo_ui.m — a demo of the **newest UI interface** (Objective-C)
//
// 四层示范的第四层：开 `ui_*` 绘图窗口 + **查屏幕方向** + 画图元 + `ui_2d_present` +
// Layer 4 of the four-layer demo: open a `ui_*` drawing window + **query the screen orientation** + draw primitives + `ui_2d_present` +
// 处理触摸/按键，**有界**（收到任意键就退出，否则画满 60 帧自动退出），正常结束。
// handle touch/keys, **bounded** (exit on any key, otherwise auto-exit after 60 frames), terminating normally.
//
// 四条关键差别（与第三层 BGI 相比）：① 开窗显式（宽高来自 `ui_scr_get_w/h`，不写死分辨率）；
// Four key differences (compared with layer 3, BGI): ① opening the window is explicit (width/height come from `ui_scr_get_w/h`, no hardcoded resolution);
// ② 方向要问 `ui_scr_get_orientation()`（0=竖屏 / 1=横屏，**开窗前就能问**）；
// ② Ask the orientation with `ui_scr_get_orientation()` (0=portrait / 1=landscape, **askable before opening the window**);
// ③ `ui_2d_present()` 才是"这一帧画完了"的帧边界；④ 输入是**统一消息队列**
// ③ `ui_2d_present()` is what marks the frame boundary of "this frame is finished"; ④ input is a **single unified message queue**
// （键盘/触摸/定时器/窗口事件同一个队列，`ui_msg_fetch_wait` / `ui_msg_get_a` / `ui_win_is_closed`）。
// (keyboard/touch/timer/window events all in one queue: `ui_msg_fetch_wait` / `ui_msg_get_a` / `ui_win_is_closed`).
//
// ◆ 跑法与"画面怎么看"（桌面 vmlcli）
// ◆ How to run it and "how to look at the picture" (desktop vmlcli)
//
//   dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll \
//       third_party/vml/Examples/objc/demo_ui.m --screen 480x640 --frames /tmp/out_frames/
//
// ⚠ **要看画面请用 `--frames 目录`，不要用 `--frame 单个文件`**：`ui_win_close()`（#521）
// ⚠ **To see the picture use `--frames <dir>`, not `--frame <single file>`**: `ui_win_close()` (#521)
//   在宿主侧把**整个场景置空**，程序跑完之后 `--frame` 那一刀已经无场景可取，只会打一行
//   blanks out **the whole scene** on the host side, so once the program has finished there is no scene left for `--frame` to take; it only prints a line
//   「没有可导出的帧（场景是空的）」。`--frames` 是每帧 present 当场拍快照，照常出图。
//   "no frame to export (the scene is empty)". `--frames` snapshots at each present and exports as usual.
//   这是桌面脚手架的行为，不是本程序写错了。
//   This is the behavior of the desktop scaffold, not a mistake in this program.
//
// ◆ 写法（ObjC 前端的实测约束）
// ◆ Style (measured constraints of the ObjC frontend)
//
//   · **`#import <vml_ui.h>`**（ObjC 惯用的显式引用形态；`#include` 等价）。
//   · **`#import <vml_ui.h>`** (the ObjC-idiomatic explicit reference; `#include` is equivalent).
//     ⚠ 旧注释写「ObjC 前端解析不了那个头文件（`expected ) (got IdType 'id'`）」——
//     ⚠ The old note said "the ObjC frontend cannot parse that header (`expected ) (got IdType 'id')`)" —
//     那是 **v0.96.263 修之前**的事实（头里两个形参叫 `id`），已改名 `timerId` / `gradId`；
//     that was true **before v0.96.263** (two parameters named `id`), now renamed to `timerId` / `gradId`;
//     2026-10-01 实测这一行真加载了头文件，`ui_*` 与 `VML_*` 常量都从它来。
//     measured 2026-10-01: this line really loads the header, and both `ui_*` and the `VML_*` constants come from it.
//   · 循环更新写 `i = i + 1`，**不要写 `i++`**（`++` 只 `ADD R0` 不写回 ⇒ 死循环）。
//   · Write the loop update as `i = i + 1`, **never `i++`** (`++` only does `ADD R0` without writing back ⇒ infinite loop).
//   · 颜色写**负数十进制**（词法器十进制专用，不认 `0x`）。
//   · Write colors as **negative decimals** (the lexer is decimal-only and does not recognize `0x`).
//
// 跑法：命令行页输入  vml run examples/objc/demo_ui.m
// How to run: on the command-line page type  vml run examples/objc/demo_ui.m

#include <vml_ui.h>
#import <vml_ui.h>

int main() {
    // ── 开窗之前就问方向（这一层与 BGI 最"新"的一条）────────────
    // ── Ask the orientation before opening the window (the most "new-style" thing about this layer vs BGI) ────────────
    int ori = ui_scr_get_orientation();
    int lang;
    lang = ui_scr_get_language();

    // 开窗：尺寸传 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 size is now queried **after** the open, when it is the real canvas.
    if (lang == 0) ui_win_open("UI 接口演示", 0, 0);
    else ui_win_open("UI API demo", 0, 0);
    ui_scr_set_keep_on(1);

    // 尺寸：开窗之后再问一次（拿不到就退到竖屏默认值）
    // Size: re-queried after the open (falling back to the portrait default if unavailable)
    int w = ui_scr_get_w();
    int h = ui_scr_get_h();
    if (w <= 0) { w = 360; }
    if (h <= 0) { h = 620; }
    int tid = ui_timer_set(30, 1);

    int frames = 0;
    int keys = 0;
    int tx = 0;
    int ty = 0;
    int touched = 0;
    int running = 1;

    while (running != 0) {
        if (ui_win_is_closed() != 0) { break; }
        if (frames >= 60) { break; }

        // ── ① 底色 + 标题（居中锚点 = 1）────────────────────────
        // ── ① Background + title (center anchor = 1) ────────────────────────
        ui_2d_clear(-15724520);
        if (lang == 0) ui_2d_text(w / 2, 26, "Dolaima  ui_*  接口演示 (Objective-C)", -6643536, 16, VML_ANCHOR_CENTER);
        else ui_2d_text(w / 2, 26, "Dolaima  ui_*  API demo (Objective-C)", -6643536, 16, VML_ANCHOR_CENTER);
        if (lang == 0) ui_2d_text(w / 2, 50, "开窗 / 方向 / 图元 / present / 消息队列", -6643536, 12, VML_ANCHOR_CENTER);
        else ui_2d_text(w / 2, 50, "window / orientation / primitives / present / message queue", -6643536, 12, VML_ANCHOR_CENTER);

        // ── ② 屏幕方向（0=竖屏 1=横屏）──────────────────────────
        // ── ② Screen orientation (0=portrait 1=landscape) ──────────────────────────
        if (lang == 0) ui_2d_text(14, 80, "屏幕方向 =", -11409298, 13, VML_ANCHOR_LEFT);
        else ui_2d_text(14, 80, "Orientation =", -11409298, 13, VML_ANCHOR_LEFT);
        ui_2d_text(96, 80, int_to_str(ori), -11409298, 13, VML_ANCHOR_LEFT);
        if (ori == 1) { if (lang == 0) { ui_2d_text(126, 80, "(横屏)", -11409298, 13, VML_ANCHOR_LEFT); } else { ui_2d_text(126, 80, "(LANDSCAPE)", -11409298, 13, VML_ANCHOR_LEFT); } }
        else { if (lang == 0) { ui_2d_text(126, 80, "(竖屏)", -11409298, 13, VML_ANCHOR_LEFT); } else { ui_2d_text(126, 80, "(PORTRAIT)", -11409298, 13, VML_ANCHOR_LEFT); } }

        // ── ③ 图元：矩形（实心 / 空心 / 圆角）──────────────────
        // ── ③ Primitives: rectangles (filled / outlined / rounded) ──────────────────
        if (lang == 0) ui_2d_text(14, 108, "图元：矩形", -6643536, 13, VML_ANCHOR_LEFT);
        else ui_2d_text(14, 108, "Primitives: rect", -6643536, 13, VML_ANCHOR_LEFT);
        ui_2d_rect(14, 126, 84, 46, -11409298, 1, 0, 0);
        ui_2d_rect(108, 126, 84, 46, -131246, 0, 2, 0);
        ui_2d_rect(202, 126, 84, 46, -63488, 1, 0, 12);

        // ── ④ 图元：圆 / 椭圆 / 线 ──────────────────────────────
        // ── ④ Primitives: circle / ellipse / line ─────────────────────────────
        if (lang == 0) ui_2d_text(14, 196, "图元：圆 / 椭圆 / 线", -6643536, 13, VML_ANCHOR_LEFT);
        else ui_2d_text(14, 196, "Primitives: circle / ellipse / line", -6643536, 13, VML_ANCHOR_LEFT);
        ui_2d_circle(46, 250, 30, -131246, 1, 0);
        ui_2d_circle(120, 250, 30, -11409298, 0, 3);
        ui_2d_ellipse(210, 250, 44, 26, -63488, 1, 0);
        int i = 0;
        while (i < 8) {
            ui_2d_line(14, 300 + i * 6, w - 14, 300 + i * 6, -15263713, 2);
            i = i + 1;
        }

        // ── ⑤ 8 级灰度色带（0xAARRGGBB 真彩）───────────────────
        // ── ⑤ 8-step grayscale bar (0xAARRGGBB true color) ───────────────────
        if (lang == 0) ui_2d_text(14, 358, "真彩（0xAARRGGBB）：", -6643536, 13, VML_ANCHOR_LEFT);
        else ui_2d_text(14, 358, "Truecolor (0xAARRGGBB):", -6643536, 13, VML_ANCHOR_LEFT);
        int s = 0;
        while (s < 8) {
            if (s == 0) { ui_2d_rect(14 + s * 40, 376, 36, 26, -16777216, 1, 0, 0); }
            if (s == 1) { ui_2d_rect(14 + s * 40, 376, 36, 26, -14671840, 1, 0, 0); }
            if (s == 2) { ui_2d_rect(14 + s * 40, 376, 36, 26, -12566464, 1, 0, 0); }
            if (s == 3) { ui_2d_rect(14 + s * 40, 376, 36, 26, -10066330, 1, 0, 0); }
            if (s == 4) { ui_2d_rect(14 + s * 40, 376, 36, 26, -8355712, 1, 0, 0); }
            if (s == 5) { ui_2d_rect(14 + s * 40, 376, 36, 26, -6250336, 1, 0, 0); }
            if (s == 6) { ui_2d_rect(14 + s * 40, 376, 36, 26, -4210753, 1, 0, 0); }
            if (s == 7) { ui_2d_rect(14 + s * 40, 376, 36, 26, -1, 1, 0, 0); }
            s = s + 1;
        }

        // ── ⑥ 动画 + 帧进度条（证明每帧确实在重画）─────────────
        // ── ⑥ Animation + frame progress bar (proof that every frame really redraws) ─────────────
        int col = 14 + frames - (frames / 20) * 20;
        col = 14 + col * 10;
        if (col > w - 46) { col = 14; }
        ui_2d_circle(col, 448, 18, -63488, 1, 0);
        ui_2d_rect(14, 480, (w - 28) * frames / 60, 10, -11409298, 1, 0, 4);

        // ── ⑦ 消息队列：帧数 / 最后一次按键 / 最后一次触摸 ──────
        // ── ⑦ Message queue: frame count / last key / last touch ──────
        if (lang == 0) ui_2d_text(14, 506, "已画帧数 =", -6643536, 13, VML_ANCHOR_LEFT);
        else ui_2d_text(14, 506, "Frames drawn =", -6643536, 13, VML_ANCHOR_LEFT);
        ui_2d_text(112, 506, int_to_str(frames), -6643536, 13, VML_ANCHOR_LEFT);
        if (lang == 0) ui_2d_text(14, 528, "最后一次按键 =", -6643536, 13, VML_ANCHOR_LEFT);
        else ui_2d_text(14, 528, "Last key =", -6643536, 13, VML_ANCHOR_LEFT);
        ui_2d_text(140, 528, int_to_str(keys), -6643536, 13, VML_ANCHOR_LEFT);
        if (touched == 1) {
            if (lang == 0) ui_2d_text(14, 550, "最后一次触摸 =", -6643536, 13, VML_ANCHOR_LEFT);
            else ui_2d_text(14, 550, "Last touch =", -6643536, 13, VML_ANCHOR_LEFT);
            ui_2d_text(140, 550, int_to_str(tx), -6643536, 13, VML_ANCHOR_LEFT);
            ui_2d_text(190, 550, int_to_str(ty), -6643536, 13, VML_ANCHOR_LEFT);
            ui_2d_circle(tx, ty, 26, -131246, 0, 3);
        } else {
            if (lang == 0) ui_2d_text(14, 550, "最后一次触摸 = 无（点一下试试）", -6643536, 13, VML_ANCHOR_LEFT);
            else ui_2d_text(14, 550, "Last touch = none (try tapping)", -6643536, 13, VML_ANCHOR_LEFT);
        }

        if (lang == 0) ui_2d_text(w / 2, h - 24, "按任意键退出，或画满 60 帧自动退出", -6643536, 12, VML_ANCHOR_CENTER);
        else ui_2d_text(w / 2, h - 24, "Press any key to exit, or it exits after 60 frames", -6643536, 12, VML_ANCHOR_CENTER);

        // ── ⑧ 帧边界 ────────────────────────────────────────────
        // ── ⑧ Frame boundary ────────────────────────────────────────────
        ui_2d_present();

        // ── ⑨ 收一条消息（最多等 30ms，保证循环有界）────────────
        // ── ⑨ Take one message (wait at most 30ms, keeping the loop bounded) ────────────
        int t = ui_msg_fetch_wait(30);
        if (t == 10) { running = 0; }
        else if (t == 1) { keys = ui_msg_get_a(); running = 0; }
        else if (t == 6) { tx = ui_msg_get_a(); ty = ui_msg_get_b(); touched = 1; }
        else if (t == 4) { tx = ui_msg_get_a(); ty = ui_msg_get_b(); touched = 1; }

        frames = frames + 1;
    }

    // ── 收尾：关定时器、放开屏幕常亮、关窗 ──────────────────────
    // ── Wrap-up: kill the timer, release keep-screen-on, close the window ──────────────────────
    ui_timer_kill(tid);
    ui_scr_set_keep_on(0);
    ui_win_close();
    return 0;
}
