# eduwin 菜单 API

eduwin 支持三种菜单：**主菜单**（窗口菜单栏）、**系统菜单**（标题栏图标菜单）、**上下文菜单**（右键弹出）。

---

## 主菜单

```c
HMENU create_main_menu(HWND win);
HMENU add_main_menu(HMENU main, const WCHAR *text);
int add_menu_item(HMENU popup, const WCHAR *text);
void add_menu_separator(HMENU popup);
HMENU add_sub_menu(HMENU parent, const WCHAR *text);
void on_menu_click(int id, void (*callback)(void *), void *data);
```

`create_main_menu` 创建菜单栏并附加到窗口，返回菜单栏句柄。`add_main_menu` 在菜单栏添加一个顶级弹出菜单（如"文件"），返回该弹出菜单句柄。

`add_menu_item` 向弹出菜单添加可点击的菜单项，返回自动分配的 ID。`add_menu_separator` 添加分隔线。`add_sub_menu` 添加子菜单，返回子菜单句柄。`on_menu_click` 注册点击回调。

菜单项文本中可以用 `(&F)` 指定助记符（Alt+F 快捷访问），用 `\t` 分隔快捷键提示文字（仅显示，快捷键注册见 `set_menu_shortcut`）。

```c
HMENU main = create_main_menu(win);

HMENU file = add_main_menu(main, L"文件(&F)");
int id_new  = add_menu_item(file, L"新建\tCtrl+N");
int id_open = add_menu_item(file, L"打开\tCtrl+O");
add_menu_separator(file);
int id_exit = add_menu_item(file, L"退出");

on_menu_click(id_new,  on_new,  NULL);
on_menu_click(id_open, on_open, NULL);
on_menu_click(id_exit, on_exit, NULL);

// 带子菜单的"视图"菜单
HMENU view = add_main_menu(main, L"视图(&V)");
int id_status = add_menu_item(view, L"状态栏");
set_menu_checked(id_status, 1);

HMENU sort_sub = add_sub_menu(view, L"排序方式");
int id_sort_name = add_menu_item(sort_sub, L"按名称");
on_menu_click(id_sort_name, on_sort_name, NULL);
```

---

## 系统菜单

```c
int create_sys_menu(HWND win, const WCHAR *text);
void add_sys_separator(HWND win);
```

向系统菜单（标题栏图标右键菜单）添加自定义项。`create_sys_menu` 添加一个菜单项并返回自动分配的 ID，`add_sys_separator` 添加分隔线。回调通过 `on_menu_click` 注册。

```c
add_sys_separator(win);
int id_sys = create_sys_menu(win, L"关于 (&A)");
on_menu_click(id_sys, on_sys_about, NULL);
```

---

## 上下文菜单

```c
HMENU create_context_menu(void);
void show_context_menu(HMENU menu, HWND relative, int x, int y);
```

`create_context_menu` 创建一个空的上下文菜单，`add_menu_item` / `add_menu_separator` 添加菜单项。

`show_context_menu` 在屏幕坐标 `(x, y)` 处弹出菜单。`relative` 用于确定菜单弹出后的归属。

```c
HMENU ctx = create_context_menu();
int id_info   = add_menu_item(ctx, L"查看详情");
add_menu_separator(ctx);
int id_delete = add_menu_item(ctx, L"删除");
on_menu_click(id_info,   on_ctx_info,   NULL);
on_menu_click(id_delete, on_ctx_delete, NULL);
```

### 上下文菜单的坐标处理

`show_context_menu` 要求 **屏幕坐标**，不同场景下获取坐标的方式不同：

**普通窗口（`WM_CONTEXTMENU`）：**

右键消息自带的坐标已经是屏幕坐标，可直接使用。

```c
// 子类化窗口过程截获 WM_CONTEXTMENU
if (msg == WM_CONTEXTMENU) {
    POINT pt = {LOWORD(lp), HIWORD(lp)};
    show_context_menu(ctx_menu, (HWND)wp, pt.x, pt.y);
}
```

**画布控件（`canvas_on_mouse` 回调）：**

画布鼠标回调中的 `x, y` 是**画布客户区坐标**，必须用 `ClientToScreen` 转换为屏幕坐标：

```c
void on_mouse_down(int btn, int x, int y)
{
    if (btn != 1) return; // 只处理右键

    POINT pt = {x, y};
    ClientToScreen(canvas, &pt);
    show_context_menu(ctx_menu, canvas, pt.x, pt.y);
}
```

> 不能直接用 `GetCursorPos` 替代，因为右键消息不一定来自鼠标（也可能是键盘 Shift+F10 或触控）。

---

## 菜单状态控制

```c
void set_menu_checked(int id, int checked);
void set_menu_enabled(int id, int enabled);
```

`set_menu_checked` 设置菜单项勾选状态（前面打勾 ✓）。`set_menu_enabled` 设置菜单项启用/禁用（灰色不可点击）。

```c
set_menu_checked(id_status, 1);   // 勾选
set_menu_enabled(id_paste, 0);    // 禁用
```

---

## 快捷键

```c
void set_menu_shortcut(int id, BYTE vkey, int ctrl, int shift);
```

为菜单项注册真正的键盘快捷键（加速键）。`vkey` 是虚拟键码（如 `'N'`、`'Z'`、`VK_F5`），`ctrl` 和 `shift` 表示是否需要按下 Ctrl / Shift 键。

```c
set_menu_shortcut(id_new,  'N', 1, 0);    // Ctrl+N
set_menu_shortcut(id_undo, 'Z', 1, 0);   // Ctrl+Z
```

> 快捷键提示文字需要在 `add_menu_item` 的文本中用 `\t` 指定（如 `L"新建\tCtrl+N"`），`set_menu_shortcut` 只负责实际的键盘响应，不修改菜单文字。
