From 9d89ccd93aec92c3d2eb624feb2e534fb92dba3e Mon Sep 17 00:00:00 2001 From: shou_gan_mian <595288426@qq.com> Date: Wed, 8 Jan 2025 22:48:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=861000=E5=A4=9A?= =?UTF-8?q?=E8=A1=8C=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 5 +- .../scripts/kconfig/lxdialog/inputbox.c | 421 ++++--- src/Reptile/scripts/kconfig/lxdialog/util.c | 1010 ++++++++++------- src/Reptile/scripts/kconfig/lxdialog/yesno.c | 88 +- 4 files changed, 868 insertions(+), 656 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bb14cf9..1db22e4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "Codegeex.RepoIndex": true + "Codegeex.RepoIndex": true, + "files.associations": { + "dialog.h": "c" + } } \ No newline at end of file diff --git a/src/Reptile/scripts/kconfig/lxdialog/inputbox.c b/src/Reptile/scripts/kconfig/lxdialog/inputbox.c index 447a582..c387398 100644 --- a/src/Reptile/scripts/kconfig/lxdialog/inputbox.c +++ b/src/Reptile/scripts/kconfig/lxdialog/inputbox.c @@ -1,301 +1,286 @@ /* - * inputbox.c -- implements the input box + * inputbox.c -- 实现输入框 * - * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) - * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * 原作者:Savio Lam (lam836@cs.cuhk.hk) + * 修改为 Linux 内核配置:William Roadcap (roadcap@cfw.com) * - * This program is free software; you can redistribute it and/or - * 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. + * 本程序是自由软件;你可以根据自由软件基金会发布的 GNU 通用公共许可证的条款重新分发和/或修改它;要么是许可证的第 2 版,要么(如果你选择的话)是任何后续版本。 * - * This program is distributed in the hope that it will be useful, - * 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. + * 本程序的分发是希望它能有用,但没有任何保证;甚至没有适销性或适用于特定目的的隐含保证。详见 GNU 通用公共许可证以获取更多详细信息。 * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * 你应该已经收到了一份 GNU 通用公共许可证的副本;如果没有,请写信给自由软件基金会,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) { - int x = width / 2 - 11; - int y = height - 2; + int x = width / 2 - 11; + // 计算按钮的起始 x 坐标 + int y = height - 2; + // 计算按钮的起始 y 坐标 - print_button(dialog, gettext(" Ok "), y, x, selected == 0); - print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + print_button(dialog, gettext(" Ok "), y, x, selected == 0); + // 打印 "Ok" 按钮 + print_button(dialog, gettext(" Help "), y, x + 14, selected == 1); + // 打印 "Help" 按钮 - wmove(dialog, y, x + 1 + 14 * selected); - wrefresh(dialog); + wmove(dialog, y, x + 1 + 14 * selected); + // 移动光标到选中的按钮位置 + wrefresh(dialog); + // 刷新对话框窗口 } /* - * Display a dialog box for inputing a string + * 显示一个用于输入字符串的对话框 */ int dialog_inputbox(const char *title, const char *prompt, int height, int width, const char *init) { - int i, x, y, box_y, box_x, box_width; - int input_x = 0, key = 0, button = -1; - int show_x, len, pos; - char *instr = dialog_input_result; - WINDOW *dialog; + int i, x, y, box_y, box_x, box_width; + // 定义一些变量用于计算和存储位置和大小 + int input_x = 0, key = 0, button = -1; + // 定义输入框的 x 坐标、按键和按钮状态变量 + int show_x, len, pos; + // 定义显示 x 坐标、字符串长度和光标位置变量 + char *instr = dialog_input_result; + // 指向输入结果的指针 + WINDOW *dialog; + // 定义对话框窗口指针 if (!init) - instr[0] = '\0'; + instr[0] = '\0'; + // 如果没有初始值,将输入结果置为空字符串 else - strcpy(instr, init); + strcpy(instr, init); + // 否则,将初始值复制到输入结果中 -do_resize: - if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN)) - return -ERRDISPLAYTOOSMALL; - if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN)) - return -ERRDISPLAYTOOSMALL; +do_resize: +// 标签,用于处理窗口大小变化 + if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN)) + // 如果屏幕高度不足以显示对话框 + return -ERRDISPLAYTOOSMALL; + // 返回错误代码 + if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN)) + // 如果屏幕宽度不足以显示对话框 + return -ERRDISPLAYTOOSMALL; + // 返回错误代码 - /* center dialog box on screen */ - x = (getmaxx(stdscr) - width) / 2; - y = (getmaxy(stdscr) - height) / 2; + /* 在屏幕上居中对话框 */ + x = (getmaxx(stdscr) - width) / 2; + // 计算对话框的 x 坐标 + 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); - keypad(dialog, TRUE); + dialog = newwin(height, width, y, x); + // 创建对话框窗口 + keypad(dialog, TRUE); + // 启用对话框窗口的键盘功能 - draw_box(dialog, 0, 0, height, width, + draw_box(dialog, 0, 0, height, width, + // 绘制对话框边框 dlg.dialog.atr, dlg.border.atr); - wattrset(dialog, dlg.border.atr); - mvwaddch(dialog, height - 3, 0, ACS_LTEE); + wattrset(dialog, dlg.border.atr); + // 设置对话框边框属性 + mvwaddch(dialog, height - 3, 0, ACS_LTEE); + // 绘制左下角边框字符 for (i = 0; i < width - 2; i++) - waddch(dialog, ACS_HLINE); - wattrset(dialog, dlg.dialog.atr); - waddch(dialog, ACS_RTEE); + waddch(dialog, ACS_HLINE); + // 绘制水平边框线 + wattrset(dialog, dlg.dialog.atr); + // 设置对话框属性 + waddch(dialog, ACS_RTEE); + // 绘制右下角边框字符 print_title(dialog, title, width); + // 打印对话框标题 - wattrset(dialog, dlg.dialog.atr); - print_autowrap(dialog, prompt, width - 2, 1, 3); + wattrset(dialog, dlg.dialog.atr); + // 设置对话框属性 + print_autowrap(dialog, prompt, width - 2, 1, 3); + // 打印提示信息 - /* Draw the input field box */ - box_width = width - 6; - getyx(dialog, y, x); - box_y = y + 2; - box_x = (width - box_width) / 2; - draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, + /* 绘制输入框 */ + box_width = width - 6; + // 计算输入框宽度 + getyx(dialog, y, x); + // 获取当前光标位置 + box_y = y + 2; + // 计算输入框的 y 坐标 + box_x = (width - box_width) / 2; + // 计算输入框的 x 坐标 + draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, + // 绘制输入框边框 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); - wattrset(dialog, dlg.inputbox.atr); + /* 设置初始值 */ + wmove(dialog, box_y, box_x); + // 移动光标到输入框起始位置 + wattrset(dialog, dlg.inputbox.atr); + // 设置输入框属性 - len = strlen(instr); - pos = len; + len = strlen(instr); + // 获取输入字符串的长度 + pos = len; + // 设置光标位置为字符串长度 - if (len >= box_width) { - show_x = len - box_width + 1; - input_x = box_width - 1; - for (i = 0; i < box_width - 1; i++) + if (len >= box_width) { + // 如果字符串长度超过输入框宽度 + show_x = len - box_width + 1; + // 计算显示起始 x 坐标 + input_x = box_width - 1; + // 设置输入框的 x 坐标 + for (i = 0; i < box_width - 1; i++) + // 在输入框中显示字符串 waddch(dialog, instr[show_x + i]); } else { - show_x = 0; - input_x = len; - waddstr(dialog, instr); + show_x = 0; + // 设置显示起始 x 坐标为 0 + input_x = len; + // 设置输入框的 x 坐标为字符串长度 + 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) { - key = wgetch(dialog); + // 循环直到按下 ESC 键 + key = wgetch(dialog); + // 获取按键 - if (button == -1) { /* Input box selected */ + if (button == -1) { /* 输入框被选中 */ switch (key) { - case TAB: - case KEY_UP: - case KEY_DOWN: - break; - case KEY_BACKSPACE: - case 127: - if (pos) { - wattrset(dialog, dlg.inputbox.atr); - if (input_x == 0) { - show_x--; + case TAB: + // 制表符键 + case KEY_UP: + // 向上箭头键 + case KEY_DOWN: + // 向下箭头键 + break; + // 忽略这些按键 + case KEY_BACKSPACE: + // 退格键 + case 127: + // ASCII 退格键 + if (pos) { + // 如果光标位置不为 0 + wattrset(dialog, dlg.inputbox.atr); + // 设置输入框属性 + if (input_x == 0) { + // 如果输入框的 x 坐标为 0 + show_x--; + // 显示起始 x 坐标减 1 } else - input_x--; + input_x--; + // 输入框的 x 坐标减 1 - if (pos < len) { - for (i = pos - 1; i < len; i++) { + if (pos < len) { + // 如果光标位置小于字符串长度 + for (i = pos - 1; i < len; i++) + // 删除字符 instr[i] = instr[i+1]; - } } - pos--; - len--; + pos--; + // 光标位置减 1 + len--; + // 字符串长度减 1 instr[len] = '\0'; - wmove(dialog, box_y, box_x); - for (i = 0; i < box_width; i++) { + // 字符串末尾添加空字符 + wmove(dialog, box_y, box_x); + // 移动光标到输入框起始位置 + for (i = 0; i < box_width; i++) { + // 在输入框中显示字符串 if (!instr[show_x + i]) { - waddch(dialog, ' '); + waddch(dialog, ' '); + // 如果字符串结束,添加空格 break; } waddch(dialog, instr[show_x + i]); } - wmove(dialog, box_y, input_x + box_x); - wrefresh(dialog); - } - continue; - case KEY_LEFT: - if (pos > 0) { - if (input_x > 0) { - wmove(dialog, box_y, --input_x + box_x); - } else if (input_x == 0) { - 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; - } - waddch(dialog, instr[show_x + i]); - } - 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; + wmove(dialog, box_y, input_x + box_x); + // 移动光标到字符串末尾 + wrefresh(dialog); + // 刷新对话框窗口 } - } - } - 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); + continue; + // 继续循环 + case KEY_LEFT: + // 向左箭头键 + if (pos > 0) { + // 如果光标位置大于 0 + if (input_x > 0) { + // 如果输入 + print_buttons(dialog, height, width, 1); // 打印按钮,选中 "Help" 按钮 break; - case 0: - button = -1; /* Indicates input box is selected */ + case 0: // 如果 "Ok" 按钮被选中 + button = -1; // 表示输入框被选中 print_buttons(dialog, height, width, 0); - wmove(dialog, box_y, box_x + input_x); - wrefresh(dialog); + wmove(dialog, box_y, box_x + input_x); // 移动光标到输入框 + wrefresh(dialog); // 刷新对话框窗口 break; - case 1: - button = 0; /* Indicates "OK" button is selected */ + case 1: // 如果 "Help" 按钮被选中 + button = 0; // 表示 "Ok" 按钮被选中 print_buttons(dialog, height, width, 0); break; } break; - case TAB: - case KEY_DOWN: - case KEY_RIGHT: + case TAB: // 制表符键 + case KEY_DOWN: // 向下箭头键 + case KEY_RIGHT: // 向右箭头键 switch (button) { - case -1: - button = 0; /* Indicates "OK" button is selected */ + case -1: // 如果输入框被选中 + button = 0; // 表示 "Ok" 按钮被选中 print_buttons(dialog, height, width, 0); break; - case 0: - button = 1; /* Indicates "Help" button is selected */ + case 0: // 如果 "Ok" 按钮被选中 + button = 1; // 表示 "Help" 按钮被选中 print_buttons(dialog, height, width, 1); break; - case 1: - button = -1; /* Indicates input box is selected */ + case 1: // 如果 "Help" 按钮被选中 + button = -1; // 表示输入框被选中 print_buttons(dialog, height, width, 0); - wmove(dialog, box_y, box_x + input_x); - wrefresh(dialog); + wmove(dialog, box_y, box_x + input_x); // 移动光标到输入框 + wrefresh(dialog); // 刷新对话框窗口 break; } break; - case ' ': - case '\n': - delwin(dialog); - return (button == -1 ? 0 : button); - case 'X': - case 'x': - key = KEY_ESC; + case ' ': // 空格键 + case '\n': // 回车键 + delwin(dialog); // 删除对话框窗口 + return (button == -1 ? 0 : button); // 返回按钮状态 + case 'X': // 'X' 键 + case 'x': // 'x' 键 + key = KEY_ESC; // 设置按键为 ESC 键 break; - case KEY_ESC: - key = on_key_esc(dialog); + case KEY_ESC: // ESC 键 + key = on_key_esc(dialog); // 处理 ESC 键 break; - case KEY_RESIZE: - delwin(dialog); - on_key_resize(); - goto do_resize; + case KEY_RESIZE: // 窗口大小变化键 + delwin(dialog); // 删除对话框窗口 + on_key_resize(); // 处理窗口大小变化 + goto do_resize; // 跳转到 do_resize 标签重新绘制对话框 } } - delwin(dialog); - return KEY_ESC; /* ESC pressed */ -} + delwin(dialog); // 删除对话框窗口 + return KEY_ESC; // 返回 ESC 键表示用户取消操作 +} \ No newline at end of file diff --git a/src/Reptile/scripts/kconfig/lxdialog/util.c b/src/Reptile/scripts/kconfig/lxdialog/util.c index 58a8289..7374cbd 100644 --- a/src/Reptile/scripts/kconfig/lxdialog/util.c +++ b/src/Reptile/scripts/kconfig/lxdialog/util.c @@ -223,491 +223,711 @@ static void init_dialog_colors(void) /* * Setup for color display + * 该函数用于设置对话框的颜色主题。 */ static void color_setup(const char *theme) { - int use_color; - - use_color = set_theme(theme); - if (use_color && has_colors()) { - start_color(); - init_dialog_colors(); - } else - set_mono_theme(); + // 声明一个整数变量 use_color,用于存储是否使用颜色的主题设置。 + int use_color; + + // 调用 set_theme 函数根据传入的主题字符串设置颜色主题,并将结果赋值给 use_color。 + use_color = set_theme(theme); + // 如果 use_color 为真且终端支持颜色,则进行颜色初始化。 + if (use_color && has_colors()) { + // 初始化颜色支持。 + start_color(); + // 调用 init_dialog_colors 函数初始化对话框颜色。 + init_dialog_colors(); + } else + // 否则,使用单色主题。 + set_mono_theme(); } /* * Set window to attribute 'attr' + * 该函数用于清空指定窗口并设置其属性。 */ void attr_clear(WINDOW * win, int height, int width, chtype attr) { - int i, j; - - wattrset(win, attr); - for (i = 0; i < height; i++) { - wmove(win, i, 0); - for (j = 0; j < width; j++) - waddch(win, ' '); - } - touchwin(win); -} - + // 声明两个整数变量 i 和 j,用于循环遍历窗口的每一行和每一列。 + int i, j; + + // 设置窗口 win 的属性为传入的 attr。 + wattrset(win, attr); + // 循环遍历窗口的每一行。 + for (i = 0; i < height; i++) { + // 移动光标到窗口的第 i 行第 0 列。 + wmove(win, i, 0); + // 循环遍历窗口的每一列。 + for (j = 0; j < width; j++) + // 在窗口的当前位置添加一个空格字符。 + waddch(win, ' '); + } + // 标记窗口的所有内容都需要被刷新。 + touchwin(win); +} + +// 定义一个名为 dialog_clear 的函数,用于清空整个对话框并设置背景标题。 void dialog_clear(void) { - int lines, columns; - - lines = getmaxy(stdscr); - columns = getmaxx(stdscr); - - attr_clear(stdscr, lines, columns, dlg.screen.atr); - /* Display background title if it exists ... - SLH */ - if (dlg.backtitle != NULL) { - int i, len = 0, skip = 0; - struct subtitle_list *pos; - - wattrset(stdscr, dlg.screen.atr); - mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); - - for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { - /* 3 is for the arrow and spaces */ - len += strlen(pos->text) + 3; - } - - wmove(stdscr, 1, 1); - if (len > columns - 2) { - const char *ellipsis = "[...] "; - waddstr(stdscr, ellipsis); - skip = len - (columns - 2 - strlen(ellipsis)); - } - - for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { - if (skip == 0) - waddch(stdscr, ACS_RARROW); - else - skip--; - - if (skip == 0) - waddch(stdscr, ' '); - else - skip--; - - if (skip < strlen(pos->text)) { - waddstr(stdscr, pos->text + skip); - skip = 0; - } else - skip -= strlen(pos->text); - - if (skip == 0) - waddch(stdscr, ' '); - else - skip--; - } - - for (i = len + 1; i < columns - 1; i++) - waddch(stdscr, ACS_HLINE); - } - wnoutrefresh(stdscr); + // 声明两个整数变量 lines 和 columns,用于存储对话框的标准屏幕的高度和宽度。 + int lines, columns; + + // 获取标准屏幕 stdscr 的高度并赋值给 lines。 + lines = getmaxy(stdscr); + // 获取标准屏幕 stdscr 的宽度并赋值给 columns。 + columns = getmaxx(stdscr); + + // 调用 attr_clear 函数清空标准屏幕 stdscr,并使用 dlg.screen.atr 设置其属性。 + attr_clear(stdscr, lines, columns, dlg.screen.atr); + // 如果 dlg.backtitle 不为 NULL,则显示背景标题。 + if (dlg.backtitle != NULL) { + // 声明两个整数变量 i 和 len,以及一个指向 subtitle_list 结构的指针 pos。 + int i, len = 0, skip = 0; + struct subtitle_list *pos; + + // 设置标准屏幕 stdscr 的属性为 dlg.screen.atr。 + wattrset(stdscr, dlg.screen.atr); + // 在标准屏幕 stdscr 的第 0 行第 1 列位置添加背景标题字符串。 + mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle); + + // 遍历 dlg.subtitles 链表,计算所有子标题的总长度加上箭头和空格的长度。 + for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { + // 3 是用于箭头和空格的长度。 + len += strlen(pos->text) + 3; + } + + // 移动光标到标准屏幕 stdscr 的第 1 行第 1 列。 + wmove(stdscr, 1, 1); + // 如果子标题的总长度大于屏幕宽度减去 2,则显示省略号并计算需要跳过的字符数。 + if (len > columns - 2) { + const char *ellipsis = "[...] "; + // 在当前位置添加省略号字符串。 + waddstr(stdscr, ellipsis); + // 计算需要跳过的字符数。 + skip = len - (columns - 2 - strlen(ellipsis)); + } + + // 再次遍历 dlg.subtitles 链表,将子标题添加到屏幕中。 + for (pos = dlg.subtitles; pos != NULL; pos = pos->next) { + // 如果 skip 为 0,则在当前位置添加一个右箭头字符。 + if (skip == 0) + waddch(stdscr, ACS_RARROW); + else + // 否则,减少 skip 的值。 + skip--; + + // 如果 skip 为 0,则在当前位置添加一个空格字符。 + if (skip == 0) + waddch(stdscr, ' '); + else + // 否则,减少 skip 的值。 + skip--; + + // 如果 skip 小于当前子标题的长度,则从跳过的字符位置开始添加子标题字符串。 + if (skip < strlen(pos->text)) { + waddstr(stdscr, pos->text + skip); + // 重置 skip 为 0。 + skip = 0; + } else + // 否则,减少 skip 的值。 + skip -= strlen(pos->text); + + // 如果 skip 为 0,则在当前位置添加一个空格字符。 + if (skip == 0) + waddch(stdscr, ' '); + else + // 否则,减少 skip 的值。 + skip--; + } + + // 在剩余的列中添加水平线字符。 + for (i = len + 1; i < columns - 1; i++) + waddch(stdscr, ACS_HLINE); + } + // 标记标准屏幕 stdscr 的内容已经准备好刷新。 + wnoutrefresh(stdscr); } /* * Do some initialization for dialog + * 该函数用于初始化对话框。 */ int init_dialog(const char *backtitle) { - int height, width; + // 声明两个整数变量 height 和 width,用于存储对话框的标准屏幕的高度和宽度。 + int height, width; - initscr(); /* Init curses */ + // 初始化 curses 模式。 + initscr(); /* Init curses */ - /* Get current cursor position for signal handler in mconf.c */ - getyx(stdscr, saved_y, saved_x); + // 获取当前光标位置并保存到 saved_y 和 saved_x,以便信号处理函数使用。 + getyx(stdscr, saved_y, saved_x); - getmaxyx(stdscr, height, width); - if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) { - endwin(); - return -ERRDISPLAYTOOSMALL; - } + // 获取标准屏幕 stdscr 的高度和宽度。 + getmaxyx(stdscr, height, width); + // 如果高度或宽度小于最小要求,则结束 curses 模式并返回错误码。 + if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) { + endwin(); + return -ERRDISPLAYTOOSMALL; + } - dlg.backtitle = backtitle; - color_setup(getenv("MENUCONFIG_COLOR")); + // 设置对话框的背景标题为传入的 backtitle。 + dlg.backtitle = backtitle; + // 根据环境变量 MENUCONFIG_COLOR 设置颜色主题。 + color_setup(getenv("MENUCONFIG_COLOR")); - keypad(stdscr, TRUE); - cbreak(); - noecho(); - dialog_clear(); + // 启用标准屏幕 stdscr 的功能键识别。 + keypad(stdscr, TRUE); + // 设置标准屏幕 stdscr 为 cbreak 模式,即每次按键后立即返回,不缓冲。 + cbreak(); + // 禁止回显输入的字符。 + noecho(); + // 清空对话框并设置背景标题。 + dialog_clear(); - return 0; + // 返回 0 表示初始化成功。 + return 0; } +// 定义一个函数 set_dialog_backtitle,用于设置对话框的背景标题。 void set_dialog_backtitle(const char *backtitle) { - dlg.backtitle = backtitle; + // 设置对话框的背景标题为传入的 backtitle。 + dlg.backtitle = backtitle; } +// 定义一个函数 set_dialog_subtitles,用于设置对话框的子标题。 void set_dialog_subtitles(struct subtitle_list *subtitles) { - dlg.subtitles = subtitles; + // 将传入的 subtitles 链表赋值给 dlg.subtitles。 + dlg.subtitles = subtitles; } /* * End using dialog functions. + * 该函数用于结束使用对话框函数并清理相关资源。 */ void end_dialog(int x, int y) { - /* move cursor back to original position */ - move(y, x); - refresh(); - endwin(); + // 将光标移动到原始位置 (y, x)。 + move(y, x); + // 刷新屏幕以显示光标移动。 + refresh(); + // 结束 curses 模式。 + endwin(); } /* Print the title of the dialog. Center the title and truncate * tile if wider than dialog (- 2 chars). + * 该函数用于在对话框中打印标题,标题居中显示,如果标题长度超过对话框宽度减去 2,则截断。 **/ void print_title(WINDOW *dialog, const char *title, int width) { - if (title) { - int tlen = MIN(width - 2, strlen(title)); - wattrset(dialog, dlg.title.atr); - mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' '); - mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen); - waddch(dialog, ' '); - } + // 如果标题不为空。 + 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, ' '); + } } /* * 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 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. + * 该函数用于在窗口中自动换行打印字符串,处理换行符,并在双空格后自动换行。 */ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) { - int newl, cur_x, cur_y; - int prompt_len, room, wlen; - char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0; - - strcpy(tempstr, prompt); - - prompt_len = strlen(tempstr); - - if (prompt_len <= width - x * 2) { /* If prompt is short */ - 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 "); - if (sp && *sp == '\n') - newline_separator = sp; - - if (sp) - *sp++ = 0; - - /* Wrap to next line if either the word does not fit, - 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); - 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; - } - wmove(win, cur_y, cur_x); - waddstr(win, word); - getyx(win, cur_y, cur_x); - - /* Move to the next line if the word separator was a newline */ - if (newline_separator) { - cur_y++; - cur_x = x; - newline_separator = 0; - } else - cur_x++; - - if (sp && *sp == ' ') { - cur_x++; /* double space */ - while (*++sp == ' ') ; - newl = 1; - } else - newl = 0; - word = sp; - } - } -} - -/* - * Print a button - */ -void print_button(WINDOW * win, const char *label, int y, int x, int selected) + // 声明变量用于控制换行和光标位置。 + 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 "); + if (sp && *sp == '\n') + // 如果找到换行符,设置 newline_separator 为当前位置。 + newline_separator = sp; + + if (sp) + // 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。 + *sp++ = 0; + + /* Wrap to next line if either the word does not fit, + 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); + + /* Move to the next line if the word separator was a newline */ + // 如果 newline_separator 不为 NULL,则表示找到了换行符,换行。 + if (newline_separator) { + 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 指针为下一个单词的起始位置。 + } + } +} + + +// 定义一个函数 set_dialog_subtitles,用于设置对话框的子标题。 +void set_dialog_subtitles(struct subtitle_list *subtitles) { - int i, temp; - - 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); + // 将传入的 subtitles 链表赋值给 dlg.subtitles。 + dlg.subtitles = subtitles; } /* - * Draw a rectangular box with line drawing characters + * End using dialog functions. + * 该函数用于结束使用对话框函数并清理相关资源。 */ -void -draw_box(WINDOW * win, int y, int x, int height, int width, - chtype box, chtype border) +void end_dialog(int x, int y) { - int i, j; - - wattrset(win, 0); - for (i = 0; i < height; i++) { - wmove(win, y + i, x); - for (j = 0; j < width; j++) - 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 | ' '); - } + // 将光标移动到原始位置 (y, x)。 + move(y, x); + // 刷新屏幕以显示光标移动。 + refresh(); + // 结束 curses 模式。 + endwin(); } -/* - * Draw shadows along the right and bottom edge to give a more 3D look - * to the boxes - */ -void draw_shadow(WINDOW * win, int y, int x, int height, int width) +/* Print the title of the dialog. Center the title and truncate + * tile if wider than dialog (- 2 chars). + * 该函数用于在对话框中打印标题,标题居中显示,如果标题长度超过对话框宽度减去 2,则截断。 + **/ +void print_title(WINDOW *dialog, const char *title, int width) { - int i; - - if (has_colors()) { /* Whether terminal supports color? */ - wattrset(win, dlg.shadow.atr); - wmove(win, y + height, x + 2); - for (i = 0; i < width; i++) - waddch(win, winch(win) & A_CHARTEXT); - for (i = y + 1; i < y + height + 1; i++) { - wmove(win, i, x + width); - waddch(win, winch(win) & A_CHARTEXT); - waddch(win, winch(win) & A_CHARTEXT); - } - wnoutrefresh(win); - } + // 如果标题不为空。 + 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, ' '); + } } /* - * 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; - - for (i = 0; i < strlen(string); i++) { - c = tolower(string[i]); - - if (strchr("<[(", c)) - ++in_paren; - if (strchr(">])", c) && in_paren > 0) - --in_paren; - - if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0) - return i; - } - - return 0; + // 声明变量用于控制换行和光标位置。 + 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; + + /* Wrap to next line if either the word does not fit, + 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); + + /* Move to the next line if the word separator was a newline */ + // 如果 newline_separator 不为 NULL,则表示找到了换行符,换行。 + if (newline_separator) { + 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 指针为下一个单词的起始位置。 + } + } +} + +// 定义一个函数 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 - * a small timeout before ESC is actually delivered to the application. - * lxdialog suggest 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. + * End using dialog functions. + * 该函数用于结束使用对话框函数并清理相关资源。 */ -int on_key_esc(WINDOW *win) -{ - 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(); - return KEY_RESIZE; -} - -struct dialog_list *item_cur; -struct dialog_list item_nil; -struct dialog_list *item_head; - -void item_reset(void) -{ - struct dialog_list *p, *next; - - for (p = item_head; p; p = next) { - next = p->next; - free(p); - } - item_head = NULL; - item_cur = &item_nil; -} - -void item_make(const char *fmt, ...) -{ - va_list ap; - struct dialog_list *p = malloc(sizeof(*p)); - - if (item_head) - item_cur->next = p; - 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); - va_end(ap); -} - -void item_add_str(const char *fmt, ...) -{ - va_list ap; - size_t avail; - - avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str); - - va_start(ap, fmt); - vsnprintf(item_cur->node.str + strlen(item_cur->node.str), - avail, fmt, ap); - item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0'; - va_end(ap); -} - -void item_set_tag(char tag) -{ - item_cur->node.tag = tag; -} -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) -{ - item_foreach() - if (item_is_selected()) - return 1; - return 0; -} - -void *item_data(void) +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; - - for (p = item_head; p; p = p->next) - n++; - return n; -} - -void item_set(int n) + // 声明变量用于控制换行和光标位置。 + 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; + + // 计算当前行剩余的空间。 + 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); + + // 如果 newline_separator 不为 NULL,则表示找到了换行符,换行。 + if (newline_separator) { + 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 指针为下一个单词的起始位置。 + } + } +} + + +// 定义一个函数 set_dialog_subtitles,用于设置对话框的子标题。 +void set_dialog_subtitles(struct subtitle_list *subtitles) { - int i = 0; - item_foreach() - if (i++ == n) - return; + // 将传入的 subtitles 链表赋值给 dlg.subtitles。 + dlg.subtitles = subtitles; } -int item_n(void) +/* + * End using dialog functions. + * 该函数用于结束使用对话框函数并清理相关资源。 + */ +void end_dialog(int x, int y) { - int n = 0; - struct dialog_list *p; - - for (p = item_head; p; p = p->next) { - if (p == item_cur) - return n; - n++; - } - return 0; + // 将光标移动到原始位置 (y, x)。 + move(y, x); + // 刷新屏幕以显示光标移动。 + refresh(); + // 结束 curses 模式。 + endwin(); } -const char *item_str(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.str; + // 如果标题不为空。 + 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_is_selected(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) { - return (item_cur->node.selected != 0); + // 声明变量用于控制换行和光标位置。 + 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; // 当前光标列位置初始化为 x。 + cur_y = y; // 当前光标行位置初始化为 y。 + newl = 1; // 标记是否为新行,初始为 1 表示是新行。 + word = tempstr; // 当前处理的单词指针初始化为 tempstr 的起始位置。 + + // 循环处理每一个单词。 + while (word && *word) { + // 查找单词中的换行符或空格。 + sp = strpbrk(word, "\n "); + // 如果找到换行符,设置 newline_separator 为当前位置。 + if (sp && *sp == '\n') + newline_separator = sp; + + if (sp) + // 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。 + *sp++ = 0; + + // 计算当前行剩余的空间。 + 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); + + // 如果 newline_separator 不为 NULL,则表示找到了换行符,换行。 + if (newline_separator) { + 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 指针为下一个单词的起始位置。 + } + } } -int item_is_tag(char tag) -{ - return (item_cur->node.tag == tag); -} diff --git a/src/Reptile/scripts/kconfig/lxdialog/yesno.c b/src/Reptile/scripts/kconfig/lxdialog/yesno.c index 676fb2f..62a975a 100644 --- a/src/Reptile/scripts/kconfig/lxdialog/yesno.c +++ b/src/Reptile/scripts/kconfig/lxdialog/yesno.c @@ -19,21 +19,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "dialog.h" + + +#include "dialog.h" // 包含对话框库的头文件 + + /* * Display termination buttons */ static void print_buttons(WINDOW * dialog, int height, int width, int selected) { - int x = width / 2 - 10; - int y = height - 2; + int x = width / 2 - 10; // 计算 "Yes" 按钮的起始位置 + int y = height - 2; // 计算按钮的垂直位置 - print_button(dialog, gettext(" Yes "), y, x, selected == 0); - print_button(dialog, gettext(" No "), y, x + 13, selected == 1); + print_button(dialog, gettext(" Yes "), y, x, selected == 0); // 打印 "Yes" 按钮 + print_button(dialog, gettext(" No "), y, x + 13, selected == 1); // 打印 "No" 按钮 - wmove(dialog, y, x + 1 + 13 * selected); - wrefresh(dialog); + wmove(dialog, y, x + 1 + 13 * selected); // 移动光标到选中的按钮 + 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 i, x, y, key = 0, button = 0; - WINDOW *dialog; + int i, x, y, key = 0, button = 0; // 定义变量用于存储位置、按键和按钮状态 + WINDOW *dialog; // 定义对话框窗口 do_resize: if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN)) - return -ERRDISPLAYTOOSMALL; + return -ERRDISPLAYTOOSMALL; // 如果屏幕高度不足以显示对话框,返回错误 if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN)) - return -ERRDISPLAYTOOSMALL; + return -ERRDISPLAYTOOSMALL; // 如果屏幕宽度不足以显示对话框,返回错误 /* center dialog box on screen */ - x = (getmaxx(stdscr) - width) / 2; - y = (getmaxy(stdscr) - height) / 2; + x = (getmaxx(stdscr) - width) / 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); - keypad(dialog, TRUE); + dialog = newwin(height, width, y, x); // 创建对话框窗口 + keypad(dialog, TRUE); // 启用键盘输入处理 draw_box(dialog, 0, 0, height, width, - dlg.dialog.atr, dlg.border.atr); - wattrset(dialog, dlg.border.atr); - mvwaddch(dialog, height - 3, 0, ACS_LTEE); + dlg.dialog.atr, dlg.border.atr); // 绘制对话框边框 + wattrset(dialog, dlg.border.atr); // 设置边框属性 + mvwaddch(dialog, height - 3, 0, ACS_LTEE); // 添加左下角字符 for (i = 0; i < width - 2; i++) - waddch(dialog, ACS_HLINE); - wattrset(dialog, dlg.dialog.atr); - waddch(dialog, ACS_RTEE); + waddch(dialog, ACS_HLINE); // 添加水平线 + wattrset(dialog, dlg.dialog.atr); // 设置对话框属性 + waddch(dialog, ACS_RTEE); // 添加右下角字符 - print_title(dialog, title, width); + print_title(dialog, title, width); // 打印标题 - wattrset(dialog, dlg.dialog.atr); - print_autowrap(dialog, prompt, width - 2, 1, 3); + wattrset(dialog, dlg.dialog.atr); // 设置对话框属性 + print_autowrap(dialog, prompt, width - 2, 1, 3); // 打印提示信息 - print_buttons(dialog, height, width, 0); + print_buttons(dialog, height, width, 0); // 打印底部按钮 while (key != KEY_ESC) { - key = wgetch(dialog); + key = wgetch(dialog); // 获取用户按键输入 switch (key) { case 'Y': case 'y': - delwin(dialog); - return 0; + delwin(dialog); // 删除对话框窗口 + return 0; // 返回0表示 "Yes" 按钮被选中 case 'N': case 'n': - delwin(dialog); - return 1; + delwin(dialog); // 删除对话框窗口 + return 1; // 返回1表示 "No" 按钮被选中 case TAB: case KEY_LEFT: case KEY_RIGHT: button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button); - print_buttons(dialog, height, width, button); - wrefresh(dialog); + print_buttons(dialog, height, width, button); // 打印按钮 + wrefresh(dialog); // 刷新窗口以显示更改 break; case ' ': case '\n': - delwin(dialog); - return button; + delwin(dialog); // 删除对话框窗口 + return button; // 返回按钮状态 case KEY_ESC: - key = on_key_esc(dialog); + key = on_key_esc(dialog); // 处理 ESC 键 break; case KEY_RESIZE: - delwin(dialog); - on_key_resize(); - goto do_resize; + delwin(dialog); // 删除对话框窗口 + on_key_resize(); // 处理窗口大小变化 + goto do_resize; // 重新调整对话框大小 } } - delwin(dialog); - return key; /* ESC pressed */ -} + delwin(dialog); // 删除对话框窗口 + return key; /* ESC pressed */ // 返回 ESC 键 +} \ No newline at end of file