← 都来码 / Dolaima← 例程索引cpp/tty/demo_tty.cpp原文

cpp/tty/demo_tty.cpp · 10245 字节 · 下载原文

// demo_tty.cpp —— **第 2 层:彩色命令行**(`tty_*` / `Lib/c/tty.h`)

// demo_tty.cpp — **Layer 2: the colorful command line** (`tty_*` / `Lib/c/tty.h`)

//

// 与 `Examples/c/demo_tty.c` 是**同一个界面、同一串调用**,只是用 C++ 前端再编一遍。

// It is **the same interface with the same sequence of calls** as `Examples/c/demo_tty.c`, just compiled again with the C++ frontend.

// C 与 C++ 是两个独立前端,同一份源码两边行为不保证一致,所以两份都要有。

// C and C++ are two independent frontends, and the same source is not guaranteed to behave the same on both, so both copies are needed.

//

// ⚠ **新程序用 `tty_*`,老程序才用 `conio` / `Crt`**(用户定的分层标准)。

// ⚠ **New programs use `tty_*`; only old programs use `conio` / `Crt`** (the layering standard set by the user).

//   `tty_*` 只有字符、没有任何图形功能;要画图用 BGI(`graphics.h`)或 `ui_*`。

//   `tty_*` is characters only and has no graphics at all; to draw, use BGI (`graphics.h`) or `ui_*`.

//   坐标 **1 起算**、颜色 **0–15 索引色**。

//   Coordinates are **1-based**; colors are **indexed 0–15**.

//

// ## ⚠⚠ 两条实测出来的坑(都是 C++ 前端特有的)

// ## ⚠⚠ Two pitfalls measured in practice (both specific to the C++ frontend)

//

// ### ① `#param lib("tty")` 在 C++ 上**不生效** —— 必须用 `--lib`

// ### ① `#param lib("tty")` **has no effect** on C++ — you must use `--lib`

//

// 协调文档说「C++ 前端不处理 C 头文件里的 `#param`,要自己在源码顶部写」。

// The coordination document says "the C++ frontend does not process `#param` in C headers; you have to write it yourself at the top of the source".

// 实测(2026-09-24):**在源码顶部写也不行**。五种写法全试过,一个都没链上:

// Measured (2026-09-24): **writing it at the top of the source does not work either**. All five forms were tried, and not one of them linked:

//

//     #param lib(tty)            → 未定义的函数 'tty_init'(引用 1 次)

//     #param lib(tty)            → undefined function 'tty_init' (referenced 1 time)

//     #param lib(tty.vml)        → 同上

//     #param lib(tty.vml)        → same as above

//     #param lib(shared/tty.vml) → 同上

//     #param lib(shared/tty.vml) → same as above

//     #param lib("tty.vml")      → 同上

//     #param lib("tty.vml")      → same as above

//     #param lib("shared/tty.vml")→ 同上

//     #param lib("shared/tty.vml")→ same as above

//

//   而**同一份内容换个扩展名给 C 编(`.c`)就 0 个未定义** ⇒ 是 C++ 前端不处理

//   Yet **the same content compiled as C under a different extension (`.c`) gives 0 undefined** ⇒ it is the C++ frontend that does not handle

//   `#param`,不是写法问题。(本文件顶部仍然留着那一行 —— 它没有副作用,

//   `#param` is simply not processed, so it is not a syntax problem. (The line is still kept at the top of this file — it has no side effects,

//   而且等前端补上之后就该由它起作用。)

//   and once the frontend catches up it should take effect.)

//

//   ⇒ **跑法**(`--lib` 是桌面脚手架的路子;手机上要靠 `vmltool.config.xml`

//   ⇒ **How to run** (`--lib` is the desktop-scaffold route; on the phone you rely on `vmltool.config.xml`

//     给 cpp 的 `Libs=` 补上 `tty.vml`,那是共享配置,本份例程没有代改):

//     to add `tty.vml` to cpp's `Libs=`; that is shared configuration, and this example does not change it on your behalf):

//

//         vmlcli Examples/cpp/demo_tty.cpp --lib Lib/shared/tty.vml

//

// ### ② UTF-8 的字节预算(与 C 那份同一个理由)

// ### ② The UTF-8 byte budget (the same reason as the C copy)

//

// `conio.c` 的 `putch()` 把**字节**当**列**计数(每字节 `conX++`、到 80 折行),

// `conio.c`'s `putch()` counts **bytes** as **columns** (`conX++` per byte, wrapping at 80),

// 一个汉字/框线字符是 3 字节 ⇒ 某段连续输出**跨过第 80 列**时,折行会落在字符中间,

// and a CJK character or a box-drawing character is 3 bytes ⇒ when a stretch of output **crosses column 80**, the wrap lands in the middle of a character,

// 宿主按字节重组 UTF-8 的校验随即失败并**粘性**切成单字节老编码 ⇒ 之后整份输出全乱。

// the host's byte-wise UTF-8 reassembly check then fails and **stickily** switches to a single-byte legacy encoding ⇒ all output after that is garbled.

// 所以版面遵守「**起始列 + 3×字符数 ≤ 80**」,细节见 `demo_tty.c` 的文件头。

// So the layout obeys "**start column + 3 × character count ≤ 80**"; for details see the file header of `demo_tty.c`.

//

// 跑法(桌面):vmlcli Examples/cpp/demo_tty.cpp --lib Lib/shared/tty.vml

// How to run (desktop): vmlcli Examples/cpp/demo_tty.cpp --lib Lib/shared/tty.vml


#param lib("tty")
#include <tty.h>
#include <vml_ui.h>     /* 只为 `ui_scr_get_language()` 的声明(本头文件只给声明与常量,不会让程序变大) */
                            /* only for the `ui_scr_get_language()` declaration (this header carries declarations and constants only; it does not make the program bigger) */

#define ROWS 25

// 在第 (x,y) 处用指定前景/背景打一串(打完颜色恢复成 7/0)

// Print a string at (x,y) with the given foreground/background (colors are restored to 7/0 afterwards)

static void say(int x, int y, int fg, int bg, char *s)
{
    tty_print_at(x, y, s, fg, bg);
}

int main()
{
    int i;
    // 界面语言:开局查一次(`ui_scr_get_language` 是 syscall,别每帧调)—— 文案按它取

    // UI language: queried once at startup (`ui_scr_get_language` is a syscall, do not call it every frame) — the text is picked by it

    int Lang = ui_scr_get_language();

    // ── 1. 初始化 + 清屏 ──

    // ── 1. Initialize + clear the screen ──

    tty_init(0, 0, 0);
    tty_cls();

    // ── 2. 标题栏:亮黄字 + 蓝底,铺满第 1 行 ──

    // ── 2. Title bar: bright yellow text on a blue background, filling row 1 ──

    tty_color(14, 1);
    tty_goto(1, 1);
    tty_puts("                                                                                ");
    tty_goto(3, 1);
    tty_puts("Dolaima  tty_* demo (C++)  --  color / cursor / box / int");

    tty_color(8, 0);
    tty_goto(3, 2);
    tty_puts("tty.h: tty_init / tty_cls / tty_color / tty_goto / tty_box / tty_put_int");

    // ── 3. ASCII 面板(61 列,安全)──

    // ── 3. ASCII panel (61 columns, safe) ──

    tty_color(7, 0);
    tty_box(2, 3, 62, 12, 0);              // style 0 = ASCII(`+ - |`)


    // 面板里的内容:每行一种前景色

    // Content inside the panel: one foreground color per line

    say(4, 4,  7,  0, Lang == 0 ? "color  7  lightgray    普通正文" : "color  7  lightgray    body text");
    say(4, 5,  11, 0, Lang == 0 ? "color 11  lightcyan    次要信息" : "color 11  lightcyan    secondary info");
    say(4, 6,  10, 0, Lang == 0 ? "color 10  lightgreen   ok / 成功" : "color 10  lightgreen   ok / success");
    say(4, 7,  14, 0, Lang == 0 ? "color 14  yellow       状态栏高亮" : "color 14  yellow       status bar highlight");
    say(4, 8,  12, 0, Lang == 0 ? "color 12  lightred     错误 / 警告" : "color 12  lightred     error / warning");
    say(4, 9,  13, 0, Lang == 0 ? "color 13  lightmagenta 强调" : "color 13  lightmagenta emphasis");

    // 反白一行("选中项"的长相):黑字白底

    // One reversed line (what a "selected item" looks like): black text on a white background

    say(4, 11, 0, 7, "  > Open     (reversed: fg=0 bg=7)                              ");

    // ── 4. UTF-8 单线框(19 格宽 × 3 字节 = 57,从第 4 列起 ⇒ 61 字节,安全)──

    // ── 4. UTF-8 single-line box (19 cells wide × 3 bytes = 57, starting at column 4 ⇒ 61 bytes, safe) ──

    tty_color(11, 0);
    tty_box(4, 14, 22, 19, 1);             // style 1 = ┌ ─ │ ┐ └ ┘ 单线框

    // style 1 = ┌ ─ │ ┐ └ ┘ single-line box


    say(6, 16, 14, 0, Lang == 0 ? "中文也" : "Chinese too");
    say(6, 17, 10, 0, Lang == 0 ? "没问题" : "works fine");

    // ── 5. 右侧说明(ASCII,列 26 起)──

    // ── 5. Notes on the right (ASCII, starting at column 26) ──

    say(26, 14, 11, 0, "tty_box(..., style=1)");
    say(26, 15, 7,  0, "  = UTF-8 single-line box");
    say(26, 17, 11, 0, "tty_box(..., style=0)");
    say(26, 18, 7,  0, "  = ASCII box (used above)");

    // ── 6. 16 色色带 ──

    // ── 6. The 16-color band ──

    for (i = 0; i < 16; i++) {
        tty_color(0, i);
        tty_goto(3 + i * 4, 21);
        tty_puts("    ");
    }
    tty_color(7, 0);
    tty_goto(3, 22);
    tty_puts("index 0..15: black blue green cyan red magenta brown gray / +8 = bright");

    // ── 7. 数字与光标 ──

    // ── 7. Numbers and the cursor ──

    tty_color(11, 0);
    tty_goto(3, 24);
    tty_puts("tty_put_int: ");
    tty_color(14, 0);
    tty_put_int(2026);
    tty_color(11, 0);
    tty_puts(" / ");
    tty_color(14, 0);
    tty_put_int(-42);
    tty_color(11, 0);
    tty_puts("   cursor=");
    tty_put_int(tty_wherex());
    tty_puts(",");
    tty_put_int(tty_wherey());
    tty_puts("   screen=");
    tty_put_int(tty_width());
    tty_puts("x");
    tty_put_int(tty_height());

    // ── 8. 状态栏 + 收尾 ──

    // ── 8. Status bar + wrap-up ──

    tty_color(0, 3);
    tty_goto(1, ROWS - 1);
    tty_puts(" tty_* demo done -- no key wait, exits by itself                              ");
    tty_color(8, 0);
    tty_goto(3, ROWS);
    tty_puts(Lang == 0 ? "demo_tty (C++) 结束 —— 画完即退出" : "demo_tty (C++) done -- exits by itself");

    tty_color(7, 0);
    return 0;
}