# eduwin 控件 API

## 辅助函数

以下函数适用于多种控件类型。

### 文本内容

```c
void set_text(HWND hwnd, const WCHAR *text);
const WCHAR *get_text(HWND hwnd);
```

设置/获取控件的文本内容。适用于按钮、标签、文本框、输入框、状态栏等。

> `get_text` 内部为每个控件独立分配缓冲区，多次调用返回不同指针，互不干扰。缓冲区在下次对同一控件调用 `get_text` 时自动释放。

### 只读控制

```c
void set_readonly(HWND hwnd, int readonly);
```

将文本框、多行文本框、密码框设为只读或可编辑。`readonly` 为 1 时只读，为 0 时可编辑。

```c
HWND text = create_text(win, L"只读内容", 10, 10, 200, 24);
set_readonly(text, 1);   // 设为只读
set_readonly(text, 0);   // 恢复可编辑
```

### 启用禁用

```c
void set_enable(HWND hwnd, int enable);
```

启用或禁用控件。`enable` 为 1 时可用，为 0 时禁用（灰显且不可操作）。

```c
set_enable(btn_delete, 0);  // 禁用删除按钮
set_enable(btn_delete, 1);  // 启用删除按钮
```

### 显隐

```c
void show(HWND hwnd);
void hide(HWND hwnd);
int  is_visible(HWND hwnd);
```

显示或隐藏控件。`is_visible` 返回 1 表示可见，0 表示隐藏。

### 布局

```c
void move(HWND hwnd, int x, int y);
```

移动控件到指定位置（仅改变位置，不改变尺寸）。

```c
void set_size(HWND hwnd, int w, int h);
void get_size(HWND hwnd, int *w, int *h);
```

设置或获取控件的客户区尺寸。`w` 或 `h` 可传 `NULL` 跳过读取。

```c
int cw, ch;
get_size(win, &cw, &ch);    // 获取窗口客户区宽高
set_size(btn, 120, 30);     // 调整按钮尺寸
```

### 窗口样式与扩展属性

```c
LONG_PTR get_style(HWND hwnd);
void set_style(HWND hwnd, LONG_PTR style);
LONG_PTR get_attr(HWND hwnd);
void set_attr(HWND hwnd, LONG_PTR attr);
```

- `get_style` / `set_style` 读取或设置窗口样式（`GWL_STYLE`，对应 `WS_*` 常量，如 `WS_THICKFRAME`、`WS_BORDER`）
- `get_attr` / `set_attr` 读取或设置窗口扩展样式（`GWL_EXSTYLE`，对应 `WS_EX_*` 常量，如 `WS_EX_TOOLWINDOW`）

`set_style` / `set_attr` 调用后会自动刷新窗口的非客户区，确保样式变更立即生效。

```c
// 为窗口添加可缩放边框和最大化按钮
set_style(win, get_style(win) | WS_THICKFRAME | WS_MAXIMIZEBOX);
```

---

## 控件参考

### 按钮

```c
HWND create_button(HWND parent, const WCHAR *text, int x, int y, int w, int h);
void on_button_click(HWND btn, void (*callback)(void *), void *data);
```

创建一个按钮，通过 `on_button_click` 注册点击事件回调。

```c
void btn_click(void *data) {
    set_text(label, L"按钮被点击");
}
HWND btn = create_button(win, L"点击我", 10, 10, 100, 30);
on_button_click(btn, btn_click, NULL);
```

---

### 标签

```c
HWND create_label(HWND parent, const WCHAR *text, int x, int y, int w, int h);
```

创建一个标签（静态文本），用于显示文字。

> **提示：** C 语言中，相邻的字符串字面量会被自动拼接。多行文本可以拆成多行写，提高可读性：
>
> ```c
> create_label(win, L"第一行\n"
>                   L"第二行\n"
>                   L"第三行",
>              10, 40, 200, 80);
> ```
>
> 编译器会自动合并为 `L"第一行\n第二行\n第三行"`。这个技巧适用于所有接受 `const WCHAR *` 参数的函数。

```c
HWND label = create_label(win, L"用户名：", 10, 40, 200, 24);
set_text(label, L"新文字");
```

---

### 文本框

```c
HWND create_text(HWND parent, const WCHAR *text, int x, int y, int w, int h);
```

创建一个单行文本框，`text` 为初始文本。可通过 `set_text` / `get_text` 读写内容。

---

### 多行文本

```c
HWND create_textarea(HWND parent, const WCHAR *text, int x, int y, int w, int h);
```

创建一个多行文本输入框，带垂直滚动条，支持换行和中文。可通过 `set_text` / `get_text` 读写内容。

---

### 密码框

```c
HWND create_password(HWND parent, int x, int y, int w, int h);
```

创建一个密码输入框，输入内容显示为黑点（•）。可通过 `set_text` / `get_text` 读写密码文本。

---

### 复选框

```c
HWND create_checkbox(HWND parent, const WCHAR *text, int x, int y, int w, int h);
int is_checked(HWND hwnd);
void set_checked(HWND hwnd, int checked);
```

创建一个复选框。点击时自动切换选中/未选状态。`is_checked` 返回 1 表示已选中；`set_checked(1)` 设选中，`set_checked(0)` 取消。

---

### 单选按钮

```c
HWND create_radio(HWND parent, const WCHAR *text, int x, int y, int w, int h);
int is_checked(HWND hwnd);
void set_checked(HWND hwnd, int checked);
```

创建一个单选按钮。同一父窗口下的单选按钮自动互斥。通过 `is_checked` 和 `set_checked` 读取/设定状态。

---

### 分组框

```c
HWND create_groupbox(HWND parent, const WCHAR *text, int x, int y, int w, int h);
```

创建一个分组框（视觉框线 + 标题），常用来包裹按钮、单选等控件。

---

### 下拉框

```c
HWND create_combobox(HWND parent, int x, int y, int w, int h);
void combobox_add_text(HWND combobox, const WCHAR *text);
int combobox_selected_index(HWND combobox);
const WCHAR *combobox_selected_text(HWND combobox);
```

创建一个下拉选择框（不可编辑）。`combobox_add_text` 添加选项；`combobox_selected_index` 返回选中索引（-1 表示未选中）；`combobox_selected_text` 返回选中项的文本。

---

### 列表框

```c
HWND create_listbox(HWND parent, int x, int y, int w, int h);
void listbox_add_text(HWND listbox, const WCHAR *text);
int listbox_selected_index(HWND listbox);
int listbox_count(HWND listbox);
const WCHAR *listbox_selected_text(HWND listbox);
```

创建一个列表框。`listbox_add_text` 添加选项；`listbox_selected_index` 返回选中索引；`listbox_count` 返回总项数；`listbox_selected_text` 返回选中项的文本。

---

### 进度条

```c
HWND create_progressbar(HWND parent, int x, int y, int w, int h);
void set_progress(HWND progress, int value);
```

创建一个进度条，默认范围 0–100，`set_progress` 设定当前进度值。

---

### 滑块

```c
HWND create_slider(HWND parent, int x, int y, int w, int h);
int slider_get_pos(HWND slider);
void slider_set_pos(HWND slider, int value);
```

创建一个滑块（带刻度线），默认范围 0–100。`slider_get_pos` 读取位置，`slider_set_pos` 设定位置。

---

### 滚动条

```c
HWND create_scrollbar(HWND parent, int x, int y, int w, int h);
int scrollbar_get_pos(HWND scrollbar);
void scrollbar_set_pos(HWND scrollbar, int pos);
```

创建一个滚动条。根据宽高比自动决定水平或垂直（宽 > 高为水平，高 > 宽为垂直）。`scrollbar_get_pos` / `scrollbar_set_pos` 读取/设定位置。

---

### 数值调节

```c
HWND create_spin(HWND parent, int x, int y, int w, int h);
void spin_set_range(HWND spin, int min, int max);
int spin_get_pos(HWND spin);
```

创建一个数值调节按钮（Spin/Up-Down）。自动绑定前面的编辑框作为伙伴。`spin_set_range` 设定范围，`spin_get_pos` 读取当前数值。

---

### 状态栏

```c
HWND create_statusbar(HWND parent);
void statusbar_set_text(HWND statusbar, const WCHAR *text);
```

创建一个底部状态栏，自动吸附在窗口底部。`statusbar_set_text` 设置显示文本。

```c
HWND sb = create_statusbar(win);
statusbar_set_text(sb, L"就绪");
```

---

### 工具栏

```c
HWND create_toolbar(HWND parent);
void toolbar_add_button(HWND toolbar, const WCHAR *text);
```

创建一个顶部工具栏。`toolbar_add_button` 添加文字按钮。

---

### 树状列表

```c
HWND create_treeview(HWND parent, int x, int y, int w, int h);
HWND treeview_add_text(HWND treeview, const WCHAR *text);
HWND treeview_add_child(HWND treeview, HWND parent_item, const WCHAR *text);
HWND treeview_selected(HWND treeview);
const WCHAR *treeview_selected_text(HWND treeview);
void treeview_delete(HWND treeview, HWND item);
void treeview_set_text(HWND treeview, HWND item, const WCHAR *text);
void treeview_expand(HWND treeview, HWND item);
void treeview_collapse(HWND treeview, HWND item);
```

创建一个树状列表视图。

- `treeview_add_text` 添加根节点，返回节点句柄
- `treeview_add_child` 在指定父节点下添加子节点，返回节点句柄
- `treeview_selected` 返回当前选中节点句柄（`NULL` 表示无选中）
- `treeview_selected_text` 返回当前选中节点的文本
- `treeview_delete` 删除指定节点及其所有子节点
- `treeview_set_text` 修改指定节点的显示文本
- `treeview_expand` / `treeview_collapse` 展开/折叠指定节点

```c
HWND root  = treeview_add_text(tree, L"中国");
HWND city1 = treeview_add_child(tree, root, L"北京");
HWND city2 = treeview_add_child(tree, root, L"上海");
treeview_expand(tree, root);
```

---

### 详细列表

```c
HWND create_listview(HWND parent, int x, int y, int w, int h);
void listview_add_column(HWND listview, const WCHAR *text, int width);
HWND listview_add_text(HWND listview, const WCHAR *text);
void listview_set_text(HWND listview, int row, int col, const WCHAR *text);
int listview_count(HWND listview);
int listview_selected_index(HWND listview);
```

创建一个详细列表视图（报表模式）。先 `listview_add_column` 添加列（指定列名和宽度），再 `listview_add_text` 添加行。

`listview_set_text` 设置指定行列的文本，用于在多列模式下填充第 2 列及之后的列：

```c
listview_add_text(listview, L"北京");                    // 第 0 列（姓名）
listview_set_text(listview, 0, 1, L"beijing@test.com");  // 第 1 列（邮箱）
listview_set_text(listview, 0, 2, L"010-1234");          // 第 2 列（电话）
```

`listview_count` 返回当前总行数，`listview_selected_index` 返回选中行的索引（-1 表示未选中）。

```c
void listview_delete_all(HWND listview);
```

清空列表视图的所有行。

```c
void listview_get_text(HWND listview, int row, int col, WCHAR *buf, int size);
```

读取列表视图指定行列的文本到缓冲区。常用于获取选中行的某列数据（如 PID）。

```c
void on_listview_dblclick(HWND listview, void (*callback)(void *), void *data);
```

注册列表视图的双击回调。双击某行时触发，配合 `listview_selected_index` 获取被双击的行。

---

### 标签页

```c
HWND create_tabbar(HWND parent, int x, int y, int w, int h);
void tabbar_add_text(HWND tabbar, const WCHAR *text);
int tabbar_selected_index(HWND tabbar);
void on_tabbar_select(HWND tabbar, void (*callback)(void *), void *data);
```

创建一个标签页控件。`tabbar_add_text` 添加标签页，`tabbar_selected_index` 返回当前选中标签的索引。

`on_tabbar_select` 注册标签切换回调。用户点击不同标签页时触发，回调中通过 `tabbar_selected_index` 获取当前选中索引。

```c
void on_tab_changed(void *d) {
    int idx = tabbar_selected_index(g_tab);
    // 切换到 idx 对应的面板
}
on_tabbar_select(g_tab, on_tab_changed, NULL);
```

---

### 日期选择

```c
HWND create_datepicker(HWND parent, int x, int y, int w, int h);
```

创建一个日期选择器。

---

### IP 输入

```c
HWND create_ip_input(HWND parent, int x, int y, int w, int h);
void get_ip(HWND ip_input, int ip[4]);
void set_ip(HWND ip_input, int a, int b, int c, int d);
```

创建一个 IP 地址输入控件（4 段式）。`get_ip` 获取 4 个段，`set_ip` 设置 IP 地址。

---

### 动画

```c
HWND create_animation(HWND parent, int x, int y, int w, int h);
void play_animation(HWND anim, int res_id);
```

创建一个 AVI 动画控件。`play_animation` 播放资源中指定 ID 的 AVI 文件。

---

### 富文本

```c
HWND create_richedit(HWND parent, int x, int y, int w, int h);
```

创建一个富文本编辑框，支持多行文本、中文和换行。可通过 `set_text` / `get_text` 读写内容。

---

### 日志面板（LogView）

基于 ListView 的自定义日志面板组件。三列：时间 | 级别 | 消息，自动管理行数上限，新日志自动滚底。

```c
HWND create_logview(HWND parent, int x, int y, int w, int h);
```

创建日志面板。返回 ListView 句柄，后续 `logview_info/warn/error` 通过该句柄写入日志。

```c
void logview_info(HWND hwnd, const WCHAR *fmt, ...);
void logview_warn(HWND hwnd, const WCHAR *fmt, ...);
void logview_error(HWND hwnd, const WCHAR *fmt, ...);
```

添加日志行，支持 `printf` 风格变参格式化。自动附加时间戳，分别标记为 `INFO` / `WARN` / `ERROR`。

```c
void logview_clear(HWND hwnd);
```

清空面板所有日志行。

```c
void logview_set_max_rows(HWND hwnd, int max_rows);
```

设置最大行数（默认 500）。超出时自动删除最旧行。

```c
HWND lv = create_logview(win, 860, 10, 330, 780);
logview_info(lv, L"应用已启动，端口 %d", 9099);
logview_warn(lv, L"连接超时 (conn_id=%d)", 5);
logview_error(lv, L"无效 JSON: %s", raw);
```

> **注意：** LogView 在非 GUI 线程（如后台工作线程）中调用 `logview_info` 等函数是安全的。但创建 `create_logview` 必须在 GUI 线程中执行。

---

## 对话框

### 打开文件对话框

```c
int open_file_dialog(HWND parent, WCHAR *buf, int size, const WCHAR *filter);
```

弹出打开文件对话框。`buf` 接收选中文件的完整路径；`filter` 为筛选器字符串，格式如 `L"文本文件\0*.txt\0所有文件\0*.*\0"`（注意用 `\0` 分隔）。成功返回 1，取消返回 0。

### 保存文件对话框

```c
int save_file_dialog(HWND parent, WCHAR *buf, int size, const WCHAR *filter);
```

弹出保存文件对话框。参数含义同 `open_file_dialog`，已选择的文件会提示覆盖确认。

### 浏览目录对话框

```c
int browse_folder_dialog(HWND parent, WCHAR *buf, int size);
```

弹出选择目录对话框。`buf` 接收选中目录的完整路径。成功返回 1，取消返回 0。

---

## 消息框

### alert

```c
void alert(const WCHAR *title, const WCHAR *message);
```

弹出仅含"确定"按钮的消息框。

### confirm

```c
int confirm(const WCHAR *title, const WCHAR *message);
```

弹出"确定/取消"对话框，返回 1 表示确定。

### ask

```c
int ask(const WCHAR *title, const WCHAR *message);
```

弹出"是/否"对话框，返回 1 表示是。
