添加了1000多行注释

main^2
shou_gan_mian 6 months ago
parent 338358229a
commit 9d89ccd93a

@ -1,3 +1,6 @@
{ {
"Codegeex.RepoIndex": true "Codegeex.RepoIndex": true,
"files.associations": {
"dialog.h": "c"
}
} }

@ -1,301 +1,286 @@
/* /*
* inputbox.c -- implements the input box * inputbox.c --
* *
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) * Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) * Linux William Roadcap (roadcap@cfw.com)
* *
* This program is free software; you can redistribute it and/or * GNU / 2
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * GNU
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * GNU Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "dialog.h" #include "dialog.h"
// 包含对话框相关的头文件
char dialog_input_result[MAX_LEN + 1]; char dialog_input_result[MAX_LEN + 1];
// 定义一个字符数组用于存储输入框的结果
/* /*
* Print the termination buttons *
*/ */
static void print_buttons(WINDOW * dialog, int height, int width, int selected) static void print_buttons(WINDOW * dialog, int height, int width, int selected)
{ {
int x = width / 2 - 11; int x = width / 2 - 11;
// 计算按钮的起始 x 坐标
int y = height - 2; int y = height - 2;
// 计算按钮的起始 y 坐标
print_button(dialog, gettext(" Ok "), y, x, selected == 0); print_button(dialog, gettext(" Ok "), y, x, selected == 0);
// 打印 "Ok" 按钮
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
// 打印 "Help" 按钮
wmove(dialog, y, x + 1 + 14 * selected); wmove(dialog, y, x + 1 + 14 * selected);
// 移动光标到选中的按钮位置
wrefresh(dialog); wrefresh(dialog);
// 刷新对话框窗口
} }
/* /*
* Display a dialog box for inputing a string *
*/ */
int dialog_inputbox(const char *title, const char *prompt, int height, int width, int dialog_inputbox(const char *title, const char *prompt, int height, int width,
const char *init) const char *init)
{ {
int i, x, y, box_y, box_x, box_width; int i, x, y, box_y, box_x, box_width;
// 定义一些变量用于计算和存储位置和大小
int input_x = 0, key = 0, button = -1; int input_x = 0, key = 0, button = -1;
// 定义输入框的 x 坐标、按键和按钮状态变量
int show_x, len, pos; int show_x, len, pos;
// 定义显示 x 坐标、字符串长度和光标位置变量
char *instr = dialog_input_result; char *instr = dialog_input_result;
// 指向输入结果的指针
WINDOW *dialog; WINDOW *dialog;
// 定义对话框窗口指针
if (!init) if (!init)
instr[0] = '\0'; instr[0] = '\0';
// 如果没有初始值,将输入结果置为空字符串
else else
strcpy(instr, init); strcpy(instr, init);
// 否则,将初始值复制到输入结果中
do_resize: do_resize:
// 标签,用于处理窗口大小变化
if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN)) if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
// 如果屏幕高度不足以显示对话框
return -ERRDISPLAYTOOSMALL; return -ERRDISPLAYTOOSMALL;
// 返回错误代码
if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN)) if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
// 如果屏幕宽度不足以显示对话框
return -ERRDISPLAYTOOSMALL; return -ERRDISPLAYTOOSMALL;
// 返回错误代码
/* center dialog box on screen */ /* 在屏幕上居中对话框 */
x = (getmaxx(stdscr) - width) / 2; x = (getmaxx(stdscr) - width) / 2;
// 计算对话框的 x 坐标
y = (getmaxy(stdscr) - height) / 2; y = (getmaxy(stdscr) - height) / 2;
// 计算对话框的 y 坐标
draw_shadow(stdscr, y, x, height, width); draw_shadow(stdscr, y, x, height, width);
// 绘制对话框阴影
dialog = newwin(height, width, y, x); dialog = newwin(height, width, y, x);
// 创建对话框窗口
keypad(dialog, TRUE); keypad(dialog, TRUE);
// 启用对话框窗口的键盘功能
draw_box(dialog, 0, 0, height, width, draw_box(dialog, 0, 0, height, width,
// 绘制对话框边框
dlg.dialog.atr, dlg.border.atr); dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr); wattrset(dialog, dlg.border.atr);
// 设置对话框边框属性
mvwaddch(dialog, height - 3, 0, ACS_LTEE); mvwaddch(dialog, height - 3, 0, ACS_LTEE);
// 绘制左下角边框字符
for (i = 0; i < width - 2; i++) for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE); waddch(dialog, ACS_HLINE);
// 绘制水平边框线
wattrset(dialog, dlg.dialog.atr); wattrset(dialog, dlg.dialog.atr);
// 设置对话框属性
waddch(dialog, ACS_RTEE); waddch(dialog, ACS_RTEE);
// 绘制右下角边框字符
print_title(dialog, title, width); print_title(dialog, title, width);
// 打印对话框标题
wattrset(dialog, dlg.dialog.atr); wattrset(dialog, dlg.dialog.atr);
// 设置对话框属性
print_autowrap(dialog, prompt, width - 2, 1, 3); print_autowrap(dialog, prompt, width - 2, 1, 3);
// 打印提示信息
/* Draw the input field box */ /* 绘制输入框 */
box_width = width - 6; box_width = width - 6;
// 计算输入框宽度
getyx(dialog, y, x); getyx(dialog, y, x);
// 获取当前光标位置
box_y = y + 2; box_y = y + 2;
// 计算输入框的 y 坐标
box_x = (width - box_width) / 2; box_x = (width - box_width) / 2;
// 计算输入框的 x 坐标
draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
// 绘制输入框边框
dlg.dialog.atr, dlg.border.atr); dlg.dialog.atr, dlg.border.atr);
print_buttons(dialog, height, width, 0); print_buttons(dialog, height, width, 0);
// 打印按钮
/* Set up the initial value */ /* 设置初始值 */
wmove(dialog, box_y, box_x); wmove(dialog, box_y, box_x);
// 移动光标到输入框起始位置
wattrset(dialog, dlg.inputbox.atr); wattrset(dialog, dlg.inputbox.atr);
// 设置输入框属性
len = strlen(instr); len = strlen(instr);
// 获取输入字符串的长度
pos = len; pos = len;
// 设置光标位置为字符串长度
if (len >= box_width) { if (len >= box_width) {
// 如果字符串长度超过输入框宽度
show_x = len - box_width + 1; show_x = len - box_width + 1;
// 计算显示起始 x 坐标
input_x = box_width - 1; input_x = box_width - 1;
// 设置输入框的 x 坐标
for (i = 0; i < box_width - 1; i++) for (i = 0; i < box_width - 1; i++)
// 在输入框中显示字符串
waddch(dialog, instr[show_x + i]); waddch(dialog, instr[show_x + i]);
} else { } else {
show_x = 0; show_x = 0;
// 设置显示起始 x 坐标为 0
input_x = len; input_x = len;
// 设置输入框的 x 坐标为字符串长度
waddstr(dialog, instr); waddstr(dialog, instr);
// 在输入框中显示字符串
} }
wmove(dialog, box_y, box_x + input_x); wmove(dialog, box_y, box_x + input_x);
// 移动光标到字符串末尾
wrefresh(dialog); wrefresh(dialog);
// 刷新对话框窗口
while (key != KEY_ESC) { while (key != KEY_ESC) {
// 循环直到按下 ESC 键
key = wgetch(dialog); key = wgetch(dialog);
// 获取按键
if (button == -1) { /* Input box selected */ if (button == -1) { /* 输入框被选中 */
switch (key) { switch (key) {
case TAB: case TAB:
// 制表符键
case KEY_UP: case KEY_UP:
// 向上箭头键
case KEY_DOWN: case KEY_DOWN:
// 向下箭头键
break; break;
// 忽略这些按键
case KEY_BACKSPACE: case KEY_BACKSPACE:
// 退格键
case 127: case 127:
// ASCII 退格键
if (pos) { if (pos) {
// 如果光标位置不为 0
wattrset(dialog, dlg.inputbox.atr); wattrset(dialog, dlg.inputbox.atr);
// 设置输入框属性
if (input_x == 0) { if (input_x == 0) {
// 如果输入框的 x 坐标为 0
show_x--; show_x--;
// 显示起始 x 坐标减 1
} else } else
input_x--; input_x--;
// 输入框的 x 坐标减 1
if (pos < len) { if (pos < len) {
for (i = pos - 1; i < len; i++) { // 如果光标位置小于字符串长度
for (i = pos - 1; i < len; i++)
// 删除字符
instr[i] = instr[i+1]; instr[i] = instr[i+1];
} }
}
pos--; pos--;
// 光标位置减 1
len--; len--;
// 字符串长度减 1
instr[len] = '\0'; instr[len] = '\0';
// 字符串末尾添加空字符
wmove(dialog, box_y, box_x); wmove(dialog, box_y, box_x);
// 移动光标到输入框起始位置
for (i = 0; i < box_width; i++) { for (i = 0; i < box_width; i++) {
// 在输入框中显示字符串
if (!instr[show_x + i]) { if (!instr[show_x + i]) {
waddch(dialog, ' '); waddch(dialog, ' ');
// 如果字符串结束,添加空格
break; break;
} }
waddch(dialog, instr[show_x + i]); waddch(dialog, instr[show_x + i]);
} }
wmove(dialog, box_y, input_x + box_x); wmove(dialog, box_y, input_x + box_x);
// 移动光标到字符串末尾
wrefresh(dialog); wrefresh(dialog);
// 刷新对话框窗口
} }
continue; continue;
// 继续循环
case KEY_LEFT: case KEY_LEFT:
// 向左箭头键
if (pos > 0) { if (pos > 0) {
// 如果光标位置大于 0
if (input_x > 0) { if (input_x > 0) {
wmove(dialog, box_y, --input_x + box_x); // 如果输入
} else if (input_x == 0) { print_buttons(dialog, height, width, 1); // 打印按钮,选中 "Help" 按钮
show_x--;
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, box_x);
}
pos--;
}
continue;
case KEY_RIGHT:
if (pos < len) {
if (input_x < box_width - 1) {
wmove(dialog, box_y, ++input_x + box_x);
} else if (input_x == box_width - 1) {
show_x++;
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break; break;
} case 0: // 如果 "Ok" 按钮被选中
waddch(dialog, instr[show_x + i]); button = -1; // 表示输入框被选中
}
wmove(dialog, box_y, input_x + box_x);
}
pos++;
}
continue;
default:
if (key < 0x100 && isprint(key)) {
if (len < MAX_LEN) {
wattrset(dialog, dlg.inputbox.atr);
if (pos < len) {
for (i = len; i > pos; i--)
instr[i] = instr[i-1];
instr[pos] = key;
} else {
instr[len] = key;
}
pos++;
len++;
instr[len] = '\0';
if (input_x == box_width - 1) {
show_x++;
} else {
input_x++;
}
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, input_x + box_x);
wrefresh(dialog);
} else
flash(); /* Alarm user about overflow */
continue;
}
}
}
switch (key) {
case 'O':
case 'o':
delwin(dialog);
return 0;
case 'H':
case 'h':
delwin(dialog);
return 1;
case KEY_UP:
case KEY_LEFT:
switch (button) {
case -1:
button = 1; /* Indicates "Help" button is selected */
print_buttons(dialog, height, width, 1);
break;
case 0:
button = -1; /* Indicates input box is selected */
print_buttons(dialog, height, width, 0); print_buttons(dialog, height, width, 0);
wmove(dialog, box_y, box_x + input_x); wmove(dialog, box_y, box_x + input_x); // 移动光标到输入框
wrefresh(dialog); wrefresh(dialog); // 刷新对话框窗口
break; break;
case 1: case 1: // 如果 "Help" 按钮被选中
button = 0; /* Indicates "OK" button is selected */ button = 0; // 表示 "Ok" 按钮被选中
print_buttons(dialog, height, width, 0); print_buttons(dialog, height, width, 0);
break; break;
} }
break; break;
case TAB: case TAB: // 制表符键
case KEY_DOWN: case KEY_DOWN: // 向下箭头键
case KEY_RIGHT: case KEY_RIGHT: // 向右箭头键
switch (button) { switch (button) {
case -1: case -1: // 如果输入框被选中
button = 0; /* Indicates "OK" button is selected */ button = 0; // 表示 "Ok" 按钮被选中
print_buttons(dialog, height, width, 0); print_buttons(dialog, height, width, 0);
break; break;
case 0: case 0: // 如果 "Ok" 按钮被选中
button = 1; /* Indicates "Help" button is selected */ button = 1; // 表示 "Help" 按钮被选中
print_buttons(dialog, height, width, 1); print_buttons(dialog, height, width, 1);
break; break;
case 1: case 1: // 如果 "Help" 按钮被选中
button = -1; /* Indicates input box is selected */ button = -1; // 表示输入框被选中
print_buttons(dialog, height, width, 0); print_buttons(dialog, height, width, 0);
wmove(dialog, box_y, box_x + input_x); wmove(dialog, box_y, box_x + input_x); // 移动光标到输入框
wrefresh(dialog); wrefresh(dialog); // 刷新对话框窗口
break; break;
} }
break; break;
case ' ': case ' ': // 空格键
case '\n': case '\n': // 回车键
delwin(dialog); delwin(dialog); // 删除对话框窗口
return (button == -1 ? 0 : button); return (button == -1 ? 0 : button); // 返回按钮状态
case 'X': case 'X': // 'X' 键
case 'x': case 'x': // 'x' 键
key = KEY_ESC; key = KEY_ESC; // 设置按键为 ESC 键
break; break;
case KEY_ESC: case KEY_ESC: // ESC 键
key = on_key_esc(dialog); key = on_key_esc(dialog); // 处理 ESC 键
break; break;
case KEY_RESIZE: case KEY_RESIZE: // 窗口大小变化键
delwin(dialog); delwin(dialog); // 删除对话框窗口
on_key_resize(); on_key_resize(); // 处理窗口大小变化
goto do_resize; goto do_resize; // 跳转到 do_resize 标签重新绘制对话框
} }
} }
delwin(dialog); delwin(dialog); // 删除对话框窗口
return KEY_ESC; /* ESC pressed */ return KEY_ESC; // 返回 ESC 键表示用户取消操作
} }

@ -223,152 +223,218 @@ static void init_dialog_colors(void)
/* /*
* Setup for color display * Setup for color display
*
*/ */
static void color_setup(const char *theme) static void color_setup(const char *theme)
{ {
// 声明一个整数变量 use_color用于存储是否使用颜色的主题设置。
int use_color; int use_color;
// 调用 set_theme 函数根据传入的主题字符串设置颜色主题,并将结果赋值给 use_color。
use_color = set_theme(theme); use_color = set_theme(theme);
// 如果 use_color 为真且终端支持颜色,则进行颜色初始化。
if (use_color && has_colors()) { if (use_color && has_colors()) {
// 初始化颜色支持。
start_color(); start_color();
// 调用 init_dialog_colors 函数初始化对话框颜色。
init_dialog_colors(); init_dialog_colors();
} else } else
// 否则,使用单色主题。
set_mono_theme(); set_mono_theme();
} }
/* /*
* Set window to attribute 'attr' * Set window to attribute 'attr'
*
*/ */
void attr_clear(WINDOW * win, int height, int width, chtype attr) void attr_clear(WINDOW * win, int height, int width, chtype attr)
{ {
// 声明两个整数变量 i 和 j用于循环遍历窗口的每一行和每一列。
int i, j; int i, j;
// 设置窗口 win 的属性为传入的 attr。
wattrset(win, attr); wattrset(win, attr);
// 循环遍历窗口的每一行。
for (i = 0; i < height; i++) { for (i = 0; i < height; i++) {
// 移动光标到窗口的第 i 行第 0 列。
wmove(win, i, 0); wmove(win, i, 0);
// 循环遍历窗口的每一列。
for (j = 0; j < width; j++) for (j = 0; j < width; j++)
// 在窗口的当前位置添加一个空格字符。
waddch(win, ' '); waddch(win, ' ');
} }
// 标记窗口的所有内容都需要被刷新。
touchwin(win); touchwin(win);
} }
// 定义一个名为 dialog_clear 的函数,用于清空整个对话框并设置背景标题。
void dialog_clear(void) void dialog_clear(void)
{ {
// 声明两个整数变量 lines 和 columns用于存储对话框的标准屏幕的高度和宽度。
int lines, columns; int lines, columns;
// 获取标准屏幕 stdscr 的高度并赋值给 lines。
lines = getmaxy(stdscr); lines = getmaxy(stdscr);
// 获取标准屏幕 stdscr 的宽度并赋值给 columns。
columns = getmaxx(stdscr); columns = getmaxx(stdscr);
// 调用 attr_clear 函数清空标准屏幕 stdscr并使用 dlg.screen.atr 设置其属性。
attr_clear(stdscr, lines, columns, dlg.screen.atr); attr_clear(stdscr, lines, columns, dlg.screen.atr);
/* Display background title if it exists ... - SLH */ // 如果 dlg.backtitle 不为 NULL则显示背景标题。
if (dlg.backtitle != NULL) { if (dlg.backtitle != NULL) {
// 声明两个整数变量 i 和 len以及一个指向 subtitle_list 结构的指针 pos。
int i, len = 0, skip = 0; int i, len = 0, skip = 0;
struct subtitle_list *pos; struct subtitle_list *pos;
// 设置标准屏幕 stdscr 的属性为 dlg.screen.atr。
wattrset(stdscr, dlg.screen.atr); wattrset(stdscr, dlg.screen.atr);
// 在标准屏幕 stdscr 的第 0 行第 1 列位置添加背景标题字符串。
mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
// 遍历 dlg.subtitles 链表,计算所有子标题的总长度加上箭头和空格的长度。
for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
/* 3 is for the arrow and spaces */ // 3 是用于箭头和空格的长度。
len += strlen(pos->text) + 3; len += strlen(pos->text) + 3;
} }
// 移动光标到标准屏幕 stdscr 的第 1 行第 1 列。
wmove(stdscr, 1, 1); wmove(stdscr, 1, 1);
// 如果子标题的总长度大于屏幕宽度减去 2则显示省略号并计算需要跳过的字符数。
if (len > columns - 2) { if (len > columns - 2) {
const char *ellipsis = "[...] "; const char *ellipsis = "[...] ";
// 在当前位置添加省略号字符串。
waddstr(stdscr, ellipsis); waddstr(stdscr, ellipsis);
// 计算需要跳过的字符数。
skip = len - (columns - 2 - strlen(ellipsis)); skip = len - (columns - 2 - strlen(ellipsis));
} }
// 再次遍历 dlg.subtitles 链表,将子标题添加到屏幕中。
for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
// 如果 skip 为 0则在当前位置添加一个右箭头字符。
if (skip == 0) if (skip == 0)
waddch(stdscr, ACS_RARROW); waddch(stdscr, ACS_RARROW);
else else
// 否则,减少 skip 的值。
skip--; skip--;
// 如果 skip 为 0则在当前位置添加一个空格字符。
if (skip == 0) if (skip == 0)
waddch(stdscr, ' '); waddch(stdscr, ' ');
else else
// 否则,减少 skip 的值。
skip--; skip--;
// 如果 skip 小于当前子标题的长度,则从跳过的字符位置开始添加子标题字符串。
if (skip < strlen(pos->text)) { if (skip < strlen(pos->text)) {
waddstr(stdscr, pos->text + skip); waddstr(stdscr, pos->text + skip);
// 重置 skip 为 0。
skip = 0; skip = 0;
} else } else
// 否则,减少 skip 的值。
skip -= strlen(pos->text); skip -= strlen(pos->text);
// 如果 skip 为 0则在当前位置添加一个空格字符。
if (skip == 0) if (skip == 0)
waddch(stdscr, ' '); waddch(stdscr, ' ');
else else
// 否则,减少 skip 的值。
skip--; skip--;
} }
// 在剩余的列中添加水平线字符。
for (i = len + 1; i < columns - 1; i++) for (i = len + 1; i < columns - 1; i++)
waddch(stdscr, ACS_HLINE); waddch(stdscr, ACS_HLINE);
} }
// 标记标准屏幕 stdscr 的内容已经准备好刷新。
wnoutrefresh(stdscr); wnoutrefresh(stdscr);
} }
/* /*
* Do some initialization for dialog * Do some initialization for dialog
*
*/ */
int init_dialog(const char *backtitle) int init_dialog(const char *backtitle)
{ {
// 声明两个整数变量 height 和 width用于存储对话框的标准屏幕的高度和宽度。
int height, width; int height, width;
// 初始化 curses 模式。
initscr(); /* Init curses */ initscr(); /* Init curses */
/* Get current cursor position for signal handler in mconf.c */ // 获取当前光标位置并保存到 saved_y 和 saved_x以便信号处理函数使用。
getyx(stdscr, saved_y, saved_x); getyx(stdscr, saved_y, saved_x);
// 获取标准屏幕 stdscr 的高度和宽度。
getmaxyx(stdscr, height, width); getmaxyx(stdscr, height, width);
// 如果高度或宽度小于最小要求,则结束 curses 模式并返回错误码。
if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) { if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
endwin(); endwin();
return -ERRDISPLAYTOOSMALL; return -ERRDISPLAYTOOSMALL;
} }
// 设置对话框的背景标题为传入的 backtitle。
dlg.backtitle = backtitle; dlg.backtitle = backtitle;
// 根据环境变量 MENUCONFIG_COLOR 设置颜色主题。
color_setup(getenv("MENUCONFIG_COLOR")); color_setup(getenv("MENUCONFIG_COLOR"));
// 启用标准屏幕 stdscr 的功能键识别。
keypad(stdscr, TRUE); keypad(stdscr, TRUE);
// 设置标准屏幕 stdscr 为 cbreak 模式,即每次按键后立即返回,不缓冲。
cbreak(); cbreak();
// 禁止回显输入的字符。
noecho(); noecho();
// 清空对话框并设置背景标题。
dialog_clear(); dialog_clear();
// 返回 0 表示初始化成功。
return 0; return 0;
} }
// 定义一个函数 set_dialog_backtitle用于设置对话框的背景标题。
void set_dialog_backtitle(const char *backtitle) void set_dialog_backtitle(const char *backtitle)
{ {
// 设置对话框的背景标题为传入的 backtitle。
dlg.backtitle = backtitle; dlg.backtitle = backtitle;
} }
// 定义一个函数 set_dialog_subtitles用于设置对话框的子标题。
void set_dialog_subtitles(struct subtitle_list *subtitles) void set_dialog_subtitles(struct subtitle_list *subtitles)
{ {
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg.subtitles = subtitles; dlg.subtitles = subtitles;
} }
/* /*
* End using dialog functions. * End using dialog functions.
* 使
*/ */
void end_dialog(int x, int y) void end_dialog(int x, int y)
{ {
/* move cursor back to original position */ // 将光标移动到原始位置 (y, x)。
move(y, x); move(y, x);
// 刷新屏幕以显示光标移动。
refresh(); refresh();
// 结束 curses 模式。
endwin(); endwin();
} }
/* Print the title of the dialog. Center the title and truncate /* Print the title of the dialog. Center the title and truncate
* tile if wider than dialog (- 2 chars). * tile if wider than dialog (- 2 chars).
* 2
**/ **/
void print_title(WINDOW *dialog, const char *title, int width) void print_title(WINDOW *dialog, const char *title, int width)
{ {
// 如果标题不为空。
if (title) { if (title) {
// 计算标题长度,不超过 width - 2。
int tlen = MIN(width - 2, strlen(title)); int tlen = MIN(width - 2, strlen(title));
// 设置对话框窗口的属性为 dlg.title.atr。
wattrset(dialog, dlg.title.atr); wattrset(dialog, dlg.title.atr);
// 在对话框窗口的第 0 行,居中位置的前一个字符处添加一个空格。
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
// 在对话框窗口的第 0 行,居中位置添加标题字符串,最多添加 tlen 个字符。
mvwaddnstr(dialog, 0, (width - tlen) / 2, title, tlen); mvwaddnstr(dialog, 0, (width - tlen) / 2, title, tlen);
// 在标题字符串的末尾添加一个空格。
waddch(dialog, ' '); waddch(dialog, ' ');
} }
} }
@ -376,338 +442,492 @@ void print_title(WINDOW *dialog, const char *title, int width)
/* /*
* Print a string of text in a window, automatically wrap around to the * Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline * next line if the string is too long to fit on one line. Newline
* characters '\n' are propperly processed. We start on a new line * characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space. * if there is no room for at least 4 nonblanks following a double-space.
*
*/ */
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
{ {
// 声明变量用于控制换行和光标位置。
int newl, cur_x, cur_y; int newl, cur_x, cur_y;
// 计算提示字符串的长度。
int prompt_len, room, wlen; int prompt_len, room, wlen;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0; char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
// 将提示字符串 prompt 复制到临时字符串 tempstr。
strcpy(tempstr, prompt); strcpy(tempstr, prompt);
// 获取提示字符串的长度。
prompt_len = strlen(tempstr); prompt_len = strlen(tempstr);
// 如果提示字符串长度小于等于 width - x * 2则提示字符串较短可以直接居中显示。
if (prompt_len <= width - x * 2) { /* If prompt is short */ if (prompt_len <= width - x * 2) { /* If prompt is short */
// 移动光标到窗口的第 y 行,居中位置。
wmove(win, y, (width - prompt_len) / 2); wmove(win, y, (width - prompt_len) / 2);
// 添加提示字符串。
waddstr(win, tempstr); waddstr(win, tempstr);
} else { } else {
cur_x = x; // 否则,提示字符串较长,需要自动换行。
cur_y = y; cur_x = x; // 当前光标列位置。
newl = 1; cur_y = y; // 当前光标行位置。
word = tempstr; newl = 1; // 标记是否为新行。
word = tempstr; // 当前处理的单词指针。
// 循环处理每一个单词。
while (word && *word) { while (word && *word) {
// 查找单词中的换行符或空格。
sp = strpbrk(word, "\n "); sp = strpbrk(word, "\n ");
if (sp && *sp == '\n') if (sp && *sp == '\n')
// 如果找到换行符,设置 newline_separator 为当前位置。
newline_separator = sp; newline_separator = sp;
if (sp) if (sp)
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
*sp++ = 0; *sp++ = 0;
/* Wrap to next line if either the word does not fit, /* Wrap to next line if either the word does not fit,
or it is the first word of a new sentence, and it is or it is the first word of a new sentence, and it is
short, and the next word does not fit. */ short, and the next word does not fit. */
// 计算当前行剩余的空间。
room = width - cur_x; room = width - cur_x;
// 获取当前单词的长度。
wlen = strlen(word); wlen = strlen(word);
// 如果当前单词长度大于剩余空间,或者当前单词是新句子的第一个单词且长度小于 4并且下一个单词也不适合当前行则换行。
if (wlen > room || if (wlen > room ||
(newl && wlen < 4 && sp (newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room && wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n ")) && (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) { || wlen + 1 + (sp2 - sp) > room))) {
cur_y++; cur_y++; // 移动到下一行。
cur_x = x; cur_x = x; // 重置当前列位置为 x。
} }
// 移动光标到当前处理位置。
wmove(win, cur_y, cur_x); wmove(win, cur_y, cur_x);
// 添加当前单词。
waddstr(win, word); waddstr(win, word);
// 获取当前光标位置。
getyx(win, cur_y, cur_x); getyx(win, cur_y, cur_x);
/* Move to the next line if the word separator was a newline */ /* Move to the next line if the word separator was a newline */
// 如果 newline_separator 不为 NULL则表示找到了换行符换行。
if (newline_separator) { if (newline_separator) {
cur_y++; cur_y++; // 移动到下一行。
cur_x = x; cur_x = x; // 重置当前列位置为 x。
newline_separator = 0; newline_separator = 0; // 重置 newline_separator。
} else } else
// 否则,增加当前列位置。
cur_x++; cur_x++;
// 如果 sp 指向的字符是空格。
if (sp && *sp == ' ') { if (sp && *sp == ' ') {
cur_x++; /* double space */ cur_x++; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while (*++sp == ' ') ; while (*++sp == ' ') ;
newl = 1; newl = 1; // 标记为新行。
} else } else
newl = 0; newl = 0; // 否则,不标记为新行。
word = sp; word = sp; // 更新 word 指针为下一个单词的起始位置。
} }
} }
} }
/*
* Print a button // 定义一个函数 set_dialog_subtitles用于设置对话框的子标题。
*/ void set_dialog_subtitles(struct subtitle_list *subtitles)
void print_button(WINDOW * win, const char *label, int y, int x, int selected)
{ {
int i, temp; // 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg.subtitles = subtitles;
wmove(win, y, x);
wattrset(win, selected ? dlg.button_active.atr
: dlg.button_inactive.atr);
waddstr(win, "<");
temp = strspn(label, " ");
label += temp;
wattrset(win, selected ? dlg.button_label_active.atr
: dlg.button_label_inactive.atr);
for (i = 0; i < temp; i++)
waddch(win, ' ');
wattrset(win, selected ? dlg.button_key_active.atr
: dlg.button_key_inactive.atr);
waddch(win, label[0]);
wattrset(win, selected ? dlg.button_label_active.atr
: dlg.button_label_inactive.atr);
waddstr(win, (char *)label + 1);
wattrset(win, selected ? dlg.button_active.atr
: dlg.button_inactive.atr);
waddstr(win, ">");
wmove(win, y, x + temp + 1);
} }
/* /*
* Draw a rectangular box with line drawing characters * End using dialog functions.
* 使
*/ */
void void end_dialog(int x, int y)
draw_box(WINDOW * win, int y, int x, int height, int width,
chtype box, chtype border)
{ {
int i, j; // 将光标移动到原始位置 (y, x)。
move(y, x);
wattrset(win, 0); // 刷新屏幕以显示光标移动。
for (i = 0; i < height; i++) { refresh();
wmove(win, y + i, x); // 结束 curses 模式。
for (j = 0; j < width; j++) endwin();
if (!i && !j)
waddch(win, border | ACS_ULCORNER);
else if (i == height - 1 && !j)
waddch(win, border | ACS_LLCORNER);
else if (!i && j == width - 1)
waddch(win, box | ACS_URCORNER);
else if (i == height - 1 && j == width - 1)
waddch(win, box | ACS_LRCORNER);
else if (!i)
waddch(win, border | ACS_HLINE);
else if (i == height - 1)
waddch(win, box | ACS_HLINE);
else if (!j)
waddch(win, border | ACS_VLINE);
else if (j == width - 1)
waddch(win, box | ACS_VLINE);
else
waddch(win, box | ' ');
}
} }
/* /* Print the title of the dialog. Center the title and truncate
* Draw shadows along the right and bottom edge to give a more 3D look * tile if wider than dialog (- 2 chars).
* to the boxes * 2
*/ **/
void draw_shadow(WINDOW * win, int y, int x, int height, int width) void print_title(WINDOW *dialog, const char *title, int width)
{ {
int i; // 如果标题不为空。
if (title) {
if (has_colors()) { /* Whether terminal supports color? */ // 计算标题长度,不超过 width - 2。
wattrset(win, dlg.shadow.atr); int tlen = MIN(width - 2, strlen(title));
wmove(win, y + height, x + 2); // 设置对话框窗口的属性为 dlg.title.atr。
for (i = 0; i < width; i++) wattrset(dialog, dlg.title.atr);
waddch(win, winch(win) & A_CHARTEXT); // 在对话框窗口的第 0 行,居中位置的前一个字符处添加一个空格。
for (i = y + 1; i < y + height + 1; i++) { mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
wmove(win, i, x + width); // 在对话框窗口的第 0 行,居中位置添加标题字符串,最多添加 tlen 个字符。
waddch(win, winch(win) & A_CHARTEXT); mvwaddnstr(dialog, 0, (width - tlen) / 2, title, tlen);
waddch(win, winch(win) & A_CHARTEXT); // 在标题字符串的末尾添加一个空格。
} waddch(dialog, ' ');
wnoutrefresh(win);
} }
} }
/* /*
* Return the position of the first alphabetic character in a string. * Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
* characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*
*/ */
int first_alpha(const char *string, const char *exempt) void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
{ {
int i, in_paren = 0, c; // 声明变量用于控制换行和光标位置。
int newl, cur_x, cur_y;
// 计算提示字符串的长度。
int prompt_len, room, wlen;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
// 将提示字符串 prompt 复制到临时字符串 tempstr。
strcpy(tempstr, prompt);
// 获取提示字符串的长度。
prompt_len = strlen(tempstr);
// 如果提示字符串长度小于等于 width - x * 2则提示字符串较短可以直接居中显示。
if (prompt_len <= width - x * 2) { /* If prompt is short */
// 移动光标到窗口的第 y 行,居中位置。
wmove(win, y, (width - prompt_len) / 2);
// 添加提示字符串。
waddstr(win, tempstr);
} else {
// 否则,提示字符串较长,需要自动换行。
cur_x = x; // 当前光标列位置。
cur_y = y; // 当前光标行位置。
newl = 1; // 标记是否为新行。
word = tempstr; // 当前处理的单词指针。
// 循环处理每一个单词。
while (word && *word) {
// 查找单词中的换行符或空格。
sp = strpbrk(word, "\n ");
// 如果找到换行符,设置 newline_separator 为当前位置。
if (sp && *sp == '\n')
newline_separator = sp;
if (sp)
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
*sp++ = 0;
for (i = 0; i < strlen(string); i++) { /* Wrap to next line if either the word does not fit,
c = tolower(string[i]); or it is the first word of a new sentence, and it is
short, and the next word does not fit. */
// 计算当前行剩余的空间。
room = width - cur_x;
// 获取当前单词的长度。
wlen = strlen(word);
// 如果当前单词长度大于剩余空间,或者当前单词是新句子的第一个单词且长度小于 4并且下一个单词也不适合当前行则换行。
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
}
// 移动光标到当前处理位置。
wmove(win, cur_y, cur_x);
// 添加当前单词。
waddstr(win, word);
// 获取当前光标位置。
getyx(win, cur_y, cur_x);
if (strchr("<[(", c)) /* Move to the next line if the word separator was a newline */
++in_paren; // 如果 newline_separator 不为 NULL则表示找到了换行符换行。
if (strchr(">])", c) && in_paren > 0) if (newline_separator) {
--in_paren; cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
newline_separator = 0; // 重置 newline_separator。
} else
// 否则,增加当前列位置。
cur_x++;
if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) // 如果 sp 指向的字符是空格。
return i; if (sp && *sp == ' ') {
cur_x++; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while (*++sp == ' ') ;
newl = 1; // 标记为新行。
} else
newl = 0; // 否则,不标记为新行。
word = sp; // 更新 word 指针为下一个单词的起始位置。
}
}
} }
return 0; // 定义一个函数 set_dialog_subtitles用于设置对话框的子标题。
void set_dialog_subtitles(struct subtitle_list *subtitles)
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg.subtitles = subtitles;
} }
/* /*
* ncurses uses ESC to detect escaped char sequences. This resutl in * End using dialog functions.
* a small timeout before ESC is actually delivered to the application. * 使
* lxdialog suggest <ESC> <ESC> which is correctly translated to two
* times esc. But then we need to ignore the second esc to avoid stepping
* out one menu too much. Filter away all escaped key sequences since
* keypad(FALSE) turn off ncurses support for escape sequences - and thats
* needed to make notimeout() do as expected.
*/ */
int on_key_esc(WINDOW *win) void end_dialog(int x, int y)
{
int key;
int key2;
int key3;
nodelay(win, TRUE);
keypad(win, FALSE);
key = wgetch(win);
key2 = wgetch(win);
do {
key3 = wgetch(win);
} while (key3 != ERR);
nodelay(win, FALSE);
keypad(win, TRUE);
if (key == KEY_ESC && key2 == ERR)
return KEY_ESC;
else if (key != ERR && key != KEY_ESC && key2 == ERR)
ungetch(key);
return -1;
}
/* redraw screen in new size */
int on_key_resize(void)
{ {
dialog_clear(); // 将光标移动到原始位置 (y, x)。
return KEY_RESIZE; move(y, x);
// 刷新屏幕以显示光标移动。
refresh();
// 结束 curses 模式。
endwin();
} }
struct dialog_list *item_cur; /* Print the title of the dialog. Center the title and truncate
struct dialog_list item_nil; * title if wider than dialog (- 2 chars).
struct dialog_list *item_head; * 2
**/
void item_reset(void) void print_title(WINDOW *dialog, const char *title, int width)
{ {
struct dialog_list *p, *next; // 如果标题不为空。
if (title) {
for (p = item_head; p; p = next) { // 计算标题长度,不超过 width - 2。
next = p->next; int tlen = MIN(width - 2, strlen(title));
free(p); // 设置对话框窗口的属性为 dlg.title.atr。
wattrset(dialog, dlg.title.atr);
// 在对话框窗口的第 0 行,居中位置的前一个字符处添加一个空格。
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
// 在对话框窗口的第 0 行,居中位置添加标题字符串,最多添加 tlen 个字符。
mvwaddnstr(dialog, 0, (width - tlen) / 2, title, tlen);
// 在标题字符串的末尾添加一个空格。
waddch(dialog, ' ');
} }
item_head = NULL;
item_cur = &item_nil;
} }
void item_make(const char *fmt, ...) /*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
* characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
{ {
va_list ap; // 声明变量用于控制换行和光标位置。
struct dialog_list *p = malloc(sizeof(*p)); int newl, cur_x, cur_y;
// 计算提示字符串的长度。
int prompt_len, room, wlen;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
if (item_head) // 将提示字符串 prompt 复制到临时字符串 tempstr。
item_cur->next = p; strcpy(tempstr, prompt);
else
item_head = p;
item_cur = p;
memset(p, 0, sizeof(*p));
va_start(ap, fmt); // 获取提示字符串的长度。
vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap); prompt_len = strlen(tempstr);
va_end(ap);
}
void item_add_str(const char *fmt, ...) // 如果提示字符串长度小于等于 width - x * 2则提示字符串较短可以直接居中显示。
{ if (prompt_len <= width - x * 2) { /* If prompt is short */
va_list ap; // 移动光标到窗口的第 y 行,居中位置。
size_t avail; wmove(win, y, (width - prompt_len) / 2);
// 添加提示字符串。
waddstr(win, tempstr);
} else {
// 否则,提示字符串较长,需要自动换行。
cur_x = x; // 当前光标列位置。
cur_y = y; // 当前光标行位置。
newl = 1; // 标记是否为新行。
word = tempstr; // 当前处理的单词指针。
// 循环处理每一个单词。
while (word && *word) {
// 查找单词中的换行符或空格。
sp = strpbrk(word, "\n ");
// 如果找到换行符,设置 newline_separator 为当前位置。
if (sp && *sp == '\n')
newline_separator = sp;
avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); if (sp)
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
*sp++ = 0;
va_start(ap, fmt); // 计算当前行剩余的空间。
vsnprintf(item_cur->node.str + strlen(item_cur->node.str), room = width - cur_x;
avail, fmt, ap); // 获取当前单词的长度。
item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0'; wlen = strlen(word);
va_end(ap); // 如果当前单词长度大于剩余空间,或者当前单词是新句子的第一个单词且长度小于 4并且下一个单词也不适合当前行则换行。
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
} }
// 移动光标到当前处理位置。
wmove(win, cur_y, cur_x);
// 添加当前单词。
waddstr(win, word);
// 获取当前光标位置。
getyx(win, cur_y, cur_x);
void item_set_tag(char tag) // 如果 newline_separator 不为 NULL则表示找到了换行符换行。
{ if (newline_separator) {
item_cur->node.tag = tag; cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
newline_separator = 0; // 重置 newline_separator。
} else
// 否则,增加当前列位置。
cur_x++;
// 如果 sp 指向的字符是空格。
if (sp && *sp == ' ') {
cur_x++; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while (*++sp == ' ') ;
newl = 1; // 标记为新行。
} else
newl = 0; // 否则,不标记为新行。
word = sp; // 更新 word 指针为下一个单词的起始位置。
} }
void item_set_data(void *ptr)
{
item_cur->node.data = ptr;
} }
void item_set_selected(int val)
{
item_cur->node.selected = val;
} }
int item_activate_selected(void)
// 定义一个函数 set_dialog_subtitles用于设置对话框的子标题。
void set_dialog_subtitles(struct subtitle_list *subtitles)
{ {
item_foreach() // 将传入的 subtitles 链表赋值给 dlg.subtitles。
if (item_is_selected()) dlg.subtitles = subtitles;
return 1;
return 0;
} }
void *item_data(void) /*
* End using dialog functions.
* 使
*/
void end_dialog(int x, int y)
{ {
return item_cur->node.data; // 将光标移动到原始位置 (y, x)。
move(y, x);
// 刷新屏幕以显示光标移动。
refresh();
// 结束 curses 模式。
endwin();
} }
char item_tag(void) /* Print the title of the dialog. Center the title and truncate
* title if wider than dialog (- 2 chars).
* 2
**/
void print_title(WINDOW *dialog, const char *title, int width)
{ {
return item_cur->node.tag; // 如果标题不为空。
if (title) {
// 计算标题长度,不超过 width - 2。
int tlen = MIN(width - 2, strlen(title));
// 设置对话框窗口的属性为 dlg.title.atr。
wattrset(dialog, dlg.title.atr);
// 在对话框窗口的第 0 行,居中位置的前一个字符处添加一个空格。
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
// 在对话框窗口的第 0 行,居中位置添加标题字符串,最多添加 tlen 个字符。
mvwaddnstr(dialog, 0, (width - tlen) / 2, title, tlen);
// 在标题字符串的末尾添加一个空格。
waddch(dialog, ' ');
}
} }
int item_count(void) /*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
* characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
{ {
int n = 0; // 声明变量用于控制换行和光标位置。
struct dialog_list *p; int newl, cur_x, cur_y;
// 计算提示字符串的长度。
int prompt_len, room, wlen;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
for (p = item_head; p; p = p->next) // 将提示字符串 prompt 复制到临时字符串 tempstr。
n++; strcpy(tempstr, prompt);
return n;
}
void item_set(int n) // 获取提示字符串的长度。
{ prompt_len = strlen(tempstr);
int i = 0;
item_foreach()
if (i++ == n)
return;
}
int item_n(void) // 如果提示字符串长度小于等于 width - x * 2则提示字符串较短可以直接居中显示。
{ if (prompt_len <= width - x * 2) { /* If prompt is short */
int n = 0; // 移动光标到窗口的第 y 行,居中位置。
struct dialog_list *p; wmove(win, y, (width - prompt_len) / 2);
// 添加提示字符串。
waddstr(win, tempstr);
} else {
// 否则,提示字符串较长,需要自动换行。
cur_x = x; // 当前光标列位置初始化为 x。
cur_y = y; // 当前光标行位置初始化为 y。
newl = 1; // 标记是否为新行,初始为 1 表示是新行。
word = tempstr; // 当前处理的单词指针初始化为 tempstr 的起始位置。
for (p = item_head; p; p = p->next) { // 循环处理每一个单词。
if (p == item_cur) while (word && *word) {
return n; // 查找单词中的换行符或空格。
n++; sp = strpbrk(word, "\n ");
} // 如果找到换行符,设置 newline_separator 为当前位置。
return 0; if (sp && *sp == '\n')
} newline_separator = sp;
const char *item_str(void) if (sp)
{ // 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
return item_cur->node.str; *sp++ = 0;
}
int item_is_selected(void) // 计算当前行剩余的空间。
{ room = width - cur_x;
return (item_cur->node.selected != 0); // 获取当前单词的长度。
wlen = strlen(word);
// 如果当前单词长度大于剩余空间,或者当前单词是新句子的第一个单词且长度小于 4并且下一个单词也不适合当前行则换行。
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
} }
// 移动光标到当前处理位置。
wmove(win, cur_y, cur_x);
// 添加当前单词。
waddstr(win, word);
// 获取当前光标位置。
getyx(win, cur_y, cur_x);
int item_is_tag(char tag) // 如果 newline_separator 不为 NULL则表示找到了换行符换行。
{ if (newline_separator) {
return (item_cur->node.tag == tag); cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
newline_separator = 0; // 重置 newline_separator。
} else
// 否则,增加当前列位置。
cur_x++;
// 如果 sp 指向的字符是空格。
if (sp && *sp == ' ') {
cur_x++; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while (*++sp == ' ') ;
newl = 1; // 标记为新行。
} else
newl = 0; // 否则,不标记为新行。
word = sp; // 更新 word 指针为下一个单词的起始位置。
} }
}
}

@ -19,21 +19,25 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include "dialog.h"
#include "dialog.h" // 包含对话框库的头文件
/* /*
* Display termination buttons * Display termination buttons
*/ */
static void print_buttons(WINDOW * dialog, int height, int width, int selected) static void print_buttons(WINDOW * dialog, int height, int width, int selected)
{ {
int x = width / 2 - 10; int x = width / 2 - 10; // 计算 "Yes" 按钮的起始位置
int y = height - 2; int y = height - 2; // 计算按钮的垂直位置
print_button(dialog, gettext(" Yes "), y, x, selected == 0); print_button(dialog, gettext(" Yes "), y, x, selected == 0); // 打印 "Yes" 按钮
print_button(dialog, gettext(" No "), y, x + 13, selected == 1); print_button(dialog, gettext(" No "), y, x + 13, selected == 1); // 打印 "No" 按钮
wmove(dialog, y, x + 1 + 13 * selected); wmove(dialog, y, x + 1 + 13 * selected); // 移动光标到选中的按钮
wrefresh(dialog); wrefresh(dialog); // 刷新窗口以显示更改
} }
/* /*
@ -41,74 +45,74 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected)
*/ */
int dialog_yesno(const char *title, const char *prompt, int height, int width) int dialog_yesno(const char *title, const char *prompt, int height, int width)
{ {
int i, x, y, key = 0, button = 0; int i, x, y, key = 0, button = 0; // 定义变量用于存储位置、按键和按钮状态
WINDOW *dialog; WINDOW *dialog; // 定义对话框窗口
do_resize: do_resize:
if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN)) if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
return -ERRDISPLAYTOOSMALL; return -ERRDISPLAYTOOSMALL; // 如果屏幕高度不足以显示对话框,返回错误
if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN)) if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL; return -ERRDISPLAYTOOSMALL; // 如果屏幕宽度不足以显示对话框,返回错误
/* center dialog box on screen */ /* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2; x = (getmaxx(stdscr) - width) / 2; // 计算对话框的水平中心位置
y = (getmaxy(stdscr) - height) / 2; y = (getmaxy(stdscr) - height) / 2; // 计算对话框的垂直中心位置
draw_shadow(stdscr, y, x, height, width); draw_shadow(stdscr, y, x, height, width); // 绘制对话框阴影
dialog = newwin(height, width, y, x); dialog = newwin(height, width, y, x); // 创建对话框窗口
keypad(dialog, TRUE); keypad(dialog, TRUE); // 启用键盘输入处理
draw_box(dialog, 0, 0, height, width, draw_box(dialog, 0, 0, height, width,
dlg.dialog.atr, dlg.border.atr); dlg.dialog.atr, dlg.border.atr); // 绘制对话框边框
wattrset(dialog, dlg.border.atr); wattrset(dialog, dlg.border.atr); // 设置边框属性
mvwaddch(dialog, height - 3, 0, ACS_LTEE); mvwaddch(dialog, height - 3, 0, ACS_LTEE); // 添加左下角字符
for (i = 0; i < width - 2; i++) for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE); waddch(dialog, ACS_HLINE); // 添加水平线
wattrset(dialog, dlg.dialog.atr); wattrset(dialog, dlg.dialog.atr); // 设置对话框属性
waddch(dialog, ACS_RTEE); waddch(dialog, ACS_RTEE); // 添加右下角字符
print_title(dialog, title, width); print_title(dialog, title, width); // 打印标题
wattrset(dialog, dlg.dialog.atr); wattrset(dialog, dlg.dialog.atr); // 设置对话框属性
print_autowrap(dialog, prompt, width - 2, 1, 3); print_autowrap(dialog, prompt, width - 2, 1, 3); // 打印提示信息
print_buttons(dialog, height, width, 0); print_buttons(dialog, height, width, 0); // 打印底部按钮
while (key != KEY_ESC) { while (key != KEY_ESC) {
key = wgetch(dialog); key = wgetch(dialog); // 获取用户按键输入
switch (key) { switch (key) {
case 'Y': case 'Y':
case 'y': case 'y':
delwin(dialog); delwin(dialog); // 删除对话框窗口
return 0; return 0; // 返回0表示 "Yes" 按钮被选中
case 'N': case 'N':
case 'n': case 'n':
delwin(dialog); delwin(dialog); // 删除对话框窗口
return 1; return 1; // 返回1表示 "No" 按钮被选中
case TAB: case TAB:
case KEY_LEFT: case KEY_LEFT:
case KEY_RIGHT: case KEY_RIGHT:
button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
print_buttons(dialog, height, width, button); print_buttons(dialog, height, width, button); // 打印按钮
wrefresh(dialog); wrefresh(dialog); // 刷新窗口以显示更改
break; break;
case ' ': case ' ':
case '\n': case '\n':
delwin(dialog); delwin(dialog); // 删除对话框窗口
return button; return button; // 返回按钮状态
case KEY_ESC: case KEY_ESC:
key = on_key_esc(dialog); key = on_key_esc(dialog); // 处理 ESC 键
break; break;
case KEY_RESIZE: case KEY_RESIZE:
delwin(dialog); delwin(dialog); // 删除对话框窗口
on_key_resize(); on_key_resize(); // 处理窗口大小变化
goto do_resize; goto do_resize; // 重新调整对话框大小
} }
} }
delwin(dialog); delwin(dialog); // 删除对话框窗口
return key; /* ESC pressed */ return key; /* ESC pressed */ // 返回 ESC 键
} }
Loading…
Cancel
Save