实现退出功能

退出Shell功能

我们来加入一条exit命令用来退出Shell,这个功能实现起来非常容易,只需对shell.c中的shell函数稍作修改即可(代码7.4)。

void shell(void)
{
    unsigned short com[MAX_COMMAND_LEN];
    struct RECT r = {10, 10, 100, 200};
    unsigned char is_exit = FALSE;  /* 新增 */

    while (!is_exit) {  /* 更改 */
        /* ...省略... */
        } else if (!strcmp(L"exit", com))  /* 新增 */
            is_exit = TRUE;                /* 新增 */
        else
            puts(L"Command not found.\r\n");
    }
}

代码7.4: 在sample_poios/shell.c:shell实现exit命令

退出GUI功能

接下来,我们在GUI的右上角放一个[X]按钮,并且实现点击这个按钮来退出GUI的功能。

这里要修改的只有gui.c这个源文件。首先,我们创建两个函数,一个名为put_exit_button,用来在右上角绘制[X]按钮;另一个名为update_exit_button,用来更新按钮状态(是否高亮)和判定点击事件(代码7.5)。

/* ...省略... */
#define EXIT_BUTTON_WIDTH   20
#define EXIT_BUTTON_HEIGHT  20
/* ...省略... */
struct FILE rect_exit_button;
/* ...省略... */
void put_exit_button(void)
{
    unsigned int hr = GOP->Mode->Info->HorizontalResolution;
    unsigned int x;

    rect_exit_button.rect.x = hr - EXIT_BUTTON_WIDTH;
    rect_exit_button.rect.y = 0;
    rect_exit_button.rect.w = EXIT_BUTTON_WIDTH;
    rect_exit_button.rect.h = EXIT_BUTTON_HEIGHT;
    rect_exit_button.is_highlight = FALSE;
    draw_rect(rect_exit_button.rect, white);

    /* 绘制按钮中的X图案 */
    for (x = 3; x < rect_exit_button.rect.w - 3; x++) {
        draw_pixel(x + rect_exit_button.rect.x, x, white);
        draw_pixel(x + rect_exit_button.rect.x,
               rect_exit_button.rect.w - x, white);
    }
}

unsigned char update_exit_button(int px, int py, unsigned char is_clicked)
{
    unsigned char is_exit = FALSE;

    if (is_in_rect(px, py, rect_exit_button.rect)) {
        if (!rect_exit_button.is_highlight) {
            draw_rect(rect_exit_button.rect, yellow);
            rect_exit_button.is_highlight = TRUE;
        }
        if (is_clicked)
            is_exit = TRUE;
    } else {
        if (rect_exit_button.is_highlight) {
            draw_rect(rect_exit_button.rect, white);
            rect_exit_button.is_highlight = FALSE;
        }
    }

    return is_exit;
}

代码7.5: sample_poios/gui.c:put_exit_button&update_exit_button

代码7.5中,put_exit_button函数在屏幕右上角绘制[X]按钮,并将这个按钮的坐标、大小和高亮状态放置在全局变量struct FILE rect_exit_button中。而update_exit_button则根据当前的鼠标状态(指针位置、点击状态)来更新[X]按钮的的高亮状态,并返回[X]按钮是否被按下。

接着,我们在gui函数中调用上面两个函数来实现退出GUI的功能(代码7.6)。

void gui(void)
{
    /* ...省略... */
    unsigned char is_exit = FALSE;  /* 新增 */

    SPP->Reset(SPP, FALSE);
    file_num = ls_gui();
    put_exit_button();  /* 新增 */

    while (!is_exit) {  /* 更改 */
        ST->BootServices->WaitForEvent(1, &(SPP->WaitForInput), &waitidx);
        status = SPP->GetState(SPP, &s);
        if (!status) {
            /* ...省略... */

            /* 处理文件图标 */
            for (idx = 0; idx < file_num; idx++) {
                if (is_in_rect(px, py, file_list[idx].rect)) {
                    /* ...省略... */
                    if (prev_lb && !s.LeftButton) {
                        /* ...省略... */
                        file_num = ls_gui();
                        put_exit_button();  /* 追加 */
                    }
                    if (prev_rb && !s.RightButton) {
                        edit(file_list[idx].name);
                        file_num = ls_gui();
                        put_exit_button();  /* 追加 */
                        executed_rb = TRUE;
                    }
                } else {
                    /* ...省略... */
                }
            }

            /* 新建文件 */
            if ((prev_rb && !s.RightButton) && !executed_rb) {
                /* 处理文件图标外的右键单击事件 */
                dialogue_get_filename(file_num);
                edit(file_list[file_num].name);
                ST->ConOut->ClearScreen(ST->ConOut);
                file_num = ls_gui();
                put_exit_button();  /* 新增 */
            }

            /* 新增(此处开始) */
            /* 更新退出按钮状态 */
            is_exit = update_exit_button(px, py, prev_lb && !s.LeftButton);
            /* 新增(此处结束) */

            /* ...省略... */
        }
    }
}

代码7.6: sample_poios/gui.c:gui

上面这段代码中,在第一次进入至GUI或是从其它界面回到GUI时(例如从cat命令返回),我们调用put_exit_button函数来绘制[X]按钮。并且在主循环的最后调用update_exit_button函数来更新[X]按钮的状态,并通过这个函数的返回值来决定是否要跳出主循环。