@ -223,218 +223,152 @@ static void init_dialog_colors(void)
/*
* Setup for color display
* 该 函 数 用 于 设 置 对 话 框 的 颜 色 主 题 。
*/
static void color_setup ( const char * 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 )
{
// 声明两个整数变量 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 )
{
// 声明两个整数变量 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, 则显示背景标题。
/* Display background title if it exists ... - SLH */
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 是用于箭头和空格的长度。
/* 3 is for the arrow and spaces */
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 )
{
// 声明两个整数变量 height 和 width, 用于存储对话框的标准屏幕的高度和宽度。
int height , width ;
// 初始化 curses 模式。
initscr ( ) ; /* Init curses */
// 获取当前光标位置并保存到 saved_y 和 saved_x, 以便信号处理函数使用。
/* Get current cursor position for signal handler in mconf.c */
getyx ( stdscr , saved_y , saved_x ) ;
// 获取标准屏幕 stdscr 的高度和宽度。
getmaxyx ( stdscr , height , width ) ;
// 如果高度或宽度小于最小要求,则结束 curses 模式并返回错误码。
if ( height < WINDOW_HEIGTH_MIN | | width < WINDOW_WIDTH_MIN ) {
endwin ( ) ;
return - ERRDISPLAYTOOSMALL ;
}
// 设置对话框的背景标题为传入的 backtitle。
dlg . backtitle = backtitle ;
// 根据环境变量 MENUCONFIG_COLOR 设置颜色主题。
color_setup ( getenv ( " MENUCONFIG_COLOR " ) ) ;
// 启用标准屏幕 stdscr 的功能键识别。
keypad ( stdscr , TRUE ) ;
// 设置标准屏幕 stdscr 为 cbreak 模式,即每次按键后立即返回,不缓冲。
cbreak ( ) ;
// 禁止回显输入的字符。
noecho ( ) ;
// 清空对话框并设置背景标题。
dialog_clear ( ) ;
// 返回 0 表示初始化成功。
return 0 ;
}
// 定义一个函数 set_dialog_backtitle, 用于设置对话框的背景标题。
void set_dialog_backtitle ( const char * backtitle )
{
// 设置对话框的背景标题为传入的 backtitle。
dlg . backtitle = backtitle ;
}
// 定义一个函数 set_dialog_subtitles, 用于设置对话框的子标题。
void set_dialog_subtitles ( struct subtitle_list * subtitles )
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg . subtitles = subtitles ;
}
/*
* End using dialog functions .
* 该 函 数 用 于 结 束 使 用 对 话 框 函 数 并 清 理 相 关 资 源 。
*/
void end_dialog ( int x , int y )
{
// 将光标移动到原始位置 (y, x)。
/* move cursor back to original position */
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 ) {
// 计算标题长度,不超过 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 , ' ' ) ;
}
}
@ -442,492 +376,338 @@ void print_title(WINDOW *dialog, const char *title, int width)
/*
* 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 prop erly processed . We start on a new line
* characters ' \n ' are prop p erly 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 ;
// 声明一个临时字符串 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 ; // 当前处理的单词指针。
// 循环处理每一个单词。
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。
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 */
// 如果 newline_separator 不为 NULL, 则表示找到了换行符, 换行。
if ( newline_separator ) {
cur_y + + ; // 移动到下一行。
cur_x = x ; // 重置当前列位置为 x。
newline_separator = 0 ; // 重置 newline_separator。
cur_y + + ;
cur_x = x ;
newline_separator = 0 ;
} else
// 否则,增加当前列位置。
cur_x + + ;
// 如果 sp 指向的字符是空格。
if ( sp & & * sp = = ' ' ) {
cur_x + + ; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
cur_x + + ; /* double space */
while ( * + + sp = = ' ' ) ;
newl = 1 ; // 标记为新行。
newl = 1 ;
} else
newl = 0 ; // 否则,不标记为新行。
word = sp ; // 更新 word 指针为下一个单词的起始位置。
newl = 0 ;
word = sp ;
}
}
}
// 定义一个函数 set_dialog_subtitles, 用于设置对话框的子标题。
void set_dialog_subtitles ( struct subtitle_list * subtitles )
/*
* Print a button
*/
void print_button ( WINDOW * win , const char * label , int y , int x , int selected )
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg . subtitles = 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 ) ;
}
/*
* End using dialog functions .
* 该 函 数 用 于 结 束 使 用 对 话 框 函 数 并 清 理 相 关 资 源 。
* Draw a rectangular box with line drawing characters
*/
void end_dialog ( int x , int y )
void
draw_box ( WINDOW * win , int y , int x , int height , int width ,
chtype box , chtype border )
{
// 将光标移动到原始位置 (y, x)。
move ( y , x ) ;
// 刷新屏幕以显示光标移动。
refresh ( ) ;
// 结束 curses 模式。
endwin ( ) ;
}
int i , j ;
/* 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 ) {
// 计算标题长度,不超过 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 , ' ' ) ;
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 | ' ' ) ;
}
}
/*
* 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 .
* 该 函 数 用 于 在 窗 口 中 自 动 换 行 打 印 字 符 串 , 处 理 换 行 符 , 并 在 双 空 格 后 自 动 换 行 。
* Draw shadows along the right and bottom edge to give a more 3 D look
* to the boxes
*/
void print_autowrap( WINDOW * win , const char * prompt , int width , int y , int x )
void draw_shadow ( WINDOW * win , int y , int x , int height , int width )
{
// 声明变量用于控制换行和光标位置。
int newl , cur_x , cur_y ;
// 计算提示字符串的长度。
int prompt_len , room , wlen ;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr [ MAX_LEN + 1 ] , * word , * sp , * sp2 , * newline_separator = 0 ;
int i ;
// 将提示字符串 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 ( 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 ( sp )
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
* sp + + = 0 ;
/*
* Return the position of the first alphabetic character in a string .
*/
int first_alpha ( const char * string , const char * exempt )
{
int i , in_paren = 0 , c ;
/* 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 ) ;
for ( i = 0 ; i < strlen ( string ) ; i + + ) {
c = tolower ( string [ i ] ) ;
/* 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 + + ;
if ( strchr ( " <[( " , c ) )
+ + in_paren ;
if ( strchr ( " >]) " , c ) & & in_paren > 0 )
- - in_paren ;
// 如果 sp 指向的字符是空格。
if ( sp & & * sp = = ' ' ) {
cur_x + + ; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while ( * + + sp = = ' ' ) ;
newl = 1 ; // 标记为新行。
} else
newl = 0 ; // 否则,不标记为新行。
word = sp ; // 更新 word 指针为下一个单词的起始位置。
}
}
if ( ( ! in_paren ) & & isalpha ( c ) & & strchr ( exempt , c ) = = 0 )
return i ;
}
// 定义一个函数 set_dialog_subtitles, 用于设置对话框的子标题。
void set_dialog_subtitles ( struct subtitle_list * subtitles )
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg . subtitles = subtitles ;
return 0 ;
}
/*
* End using dialog functions .
* 该 函 数 用 于 结 束 使 用 对 话 框 函 数 并 清 理 相 关 资 源 。
* ncurses uses ESC to detect escaped char sequences . This resutl in
* 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 .
*/
void end_dialog ( int x , int y )
int on_key_esc ( WINDOW * win )
{
// 将光标移动到原始位置 (y, x)。
move ( y , x ) ;
// 刷新屏幕以显示光标移动。
refresh ( ) ;
// 结束 curses 模式。
endwin ( ) ;
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 ;
}
/* 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 )
struct dialog_list * item_cur ;
struct dialog_list item_nil ;
struct dialog_list * item_head ;
void item_reset( void )
{
// 如果标题不为空。
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 , ' ' ) ;
struct dialog_list * p , * next ;
for ( p = item_head ; p ; p = next ) {
next = p - > next ;
free ( p ) ;
}
item_head = NULL ;
item_cur = & item_nil ;
}
/*
* 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 )
void item_make ( const char * fmt , . . . )
{
// 声明变量用于控制换行和光标位置。
int newl , cur_x , cur_y ;
// 计算提示字符串的长度。
int prompt_len , room , wlen ;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr [ MAX_LEN + 1 ] , * word , * sp , * sp2 , * newline_separator = 0 ;
va_list ap ;
struct dialog_list * p = malloc ( sizeof ( * p ) ) ;
// 将提示字符串 prompt 复制到临时字符串 tempstr。
strcpy ( tempstr , prompt ) ;
// 获取提示字符串的长度。
prompt_len = strlen ( tempstr ) ;
if ( item_head )
item_cur - > next = p ;
else
item_head = p ;
item_cur = p ;
memset ( p , 0 , sizeof ( * p ) ) ;
// 如果提示字符串长度小于等于 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 ; // 当前处理的单词指针。
va_start ( ap , fmt ) ;
vsnprintf ( item_cur - > node . str , sizeof ( item_cur - > node . str ) , fmt , ap ) ;
va_end ( ap ) ;
}
// 循环处理每一个单词。
while ( word & & * word ) {
// 查找单词中的换行符或空格。
sp = strpbrk ( word , " \n " ) ;
// 如果找到换行符,设置 newline_separator 为当前位置。
if ( sp & & * sp = = ' \n ' )
newline_separator = sp ;
void item_add_str ( const char * fmt , . . . )
{
va_list ap ;
size_t avail ;
if ( sp )
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
* sp + + = 0 ;
avail = sizeof ( item_cur - > node . str ) - strlen ( item_cur - > node . str ) ;
// 计算当前行剩余的空间。
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。
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 ) ;
}
// 移动光标到当前处理位置。
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 指针为下一个单词的起始位置。
}
void item_set_tag ( char tag )
{
item_cur - > node . tag = tag ;
}
void item_set_data ( void * ptr )
{
item_cur - > node . data = ptr ;
}
// 定义一个函数 set_dialog_subtitles, 用于设置对话框的子标题。
void set_dialog_subtitles ( struct subtitle_list * subtitles )
void item_set_selected ( int val )
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg . subtitles = subtitles ;
item_cur - > node . selected = val ;
}
/*
* End using dialog functions .
* 该 函 数 用 于 结 束 使 用 对 话 框 函 数 并 清 理 相 关 资 源 。
*/
void end_dialog ( int x , int y )
int item_activate_selected ( void )
{
// 将光标移动到原始位置 (y, x)。
move ( y , x ) ;
// 刷新屏幕以显示光标移动。
refresh ( ) ;
// 结束 curses 模式。
endwin ( ) ;
item_foreach ( )
if ( item_is_selected ( ) )
return 1 ;
return 0 ;
}
/* 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 )
void * item_data ( void )
{
// 如果标题不为空。
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 item_cur - > node . data ;
}
/*
* 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 )
char item_tag ( void )
{
// 声明变量用于控制换行和光标位置。
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 的起始位置。
return item_cur - > node . tag ;
}
// 循环处理每一个单词。
while ( word & & * word ) {
// 查找单词中的换行符或空格。
sp = strpbrk ( word , " \n " ) ;
// 如果找到换行符,设置 newline_separator 为当前位置。
if ( sp & & * sp = = ' \n ' )
newline_separator = sp ;
int item_count ( void )
{
int n = 0 ;
struct dialog_list * p ;
if ( sp )
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
* sp + + = 0 ;
for ( p = item_head ; p ; p = p - > next )
n + + ;
return n ;
}
// 计算当前行剩余的空间。
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。
void item_set ( int n )
{
int i = 0 ;
item_foreach ( )
if ( i + + = = n )
return ;
}
// 移动光标到当前处理位置。
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 + + ;
int item_n ( void )
{
int n = 0 ;
struct dialog_list * p ;
// 如果 sp 指向的字符是空格。
if ( sp & & * sp = = ' ' ) {
cur_x + + ; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while ( * + + sp = = ' ' ) ;
newl = 1 ; // 标记为新行。
} else
newl = 0 ; // 否则,不标记为新行。
word = sp ; // 更新 word 指针为下一个单词的起始位置。
for ( p = item_head ; p ; p = p - > next ) {
if ( p = = item_cur )
return n ;
n + + ;
}
return 0 ;
}
const char * item_str ( void )
{
return item_cur - > node . str ;
}
int item_is_selected ( void )
{
return ( item_cur - > node . selected ! = 0 ) ;
}
int item_is_tag ( char tag )
{
return ( item_cur - > node . tag = = tag ) ;
}