482 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//阅读器应用
#include "stdio.h"
#include "sys.h"
#include "systick.h"
#include "key.h"
#include "lcd.h"
#include "GameEngine.h"
#include "SD.h"
#include "APP_Reader.h"
/**************************************** 私有定义 ****************************************/
typedef struct
{
FSIZE_t page_ptr;
uint32_t page_size;
} Page; //页结构定义
typedef struct
{
uint8_t font_size;
uint32_t page_num;
uint32_t page_amount;
} Save; //存档结构定义
/*****************************************************************************************/
/**************************************** 全局变量 ****************************************/
FIL file; //文件
char filename[32]; //文件名
char filepath[32]; //文件路径
FIL page_file; //分页文件
char page_filepath[32]; //分页文件名
char page_filename[32]; //分页文件路径
FIL save_file; //存档文件
char save_filepath[32]; //存档文件名
char save_filename[32]; //存档文件路径
uint32_t page_amount = 1; //页数
uint8_t current_font_size = FONT_24; //当前字体设置
uint32_t current_page = 1; //当前页码
/*****************************************************************************************/
/**************************************** 私有函数 ****************************************/
uint8_t APP_Reader_ReadPage(uint8_t font_size, uint32_t page_num);
uint8_t APP_Reader_SplitPages(uint8_t font_size);
uint8_t APP_Reader_Menu(void);
uint8_t APP_Reader_SaveWrite(void);
uint8_t APP_Reader_SaveRead(void);
void APP_Reader_Msg(uint8_t *head, uint8_t *content);
void APP_Reader_Msg_NoBlock(uint8_t *head, uint8_t *content);
/*****************************************************************************************/
/**
* @brief 启动阅读器
*/
void APP_Reader_Launcher(void)
{
//GUI 选取文件
uint8_t ret;
if ((ret = SD_SelectFile(filename, "txt")) != SD_OK)
{
if (ret == SD_ERROR)
APP_Reader_Msg("警告", "选取文件出错!\n\n请按任意键返回");
return;
}
SD_GetPath(filepath, filename);
//打开文件
if (f_open(&file, filepath, FA_OPEN_EXISTING | FA_READ) != FR_OK)
{
APP_Reader_Msg("警告", "打开文件出错!\n\n请按任意键返回");
return;
}
//读存档
uint8_t is_saved = 0;
if (APP_Reader_SaveRead() == 0)
is_saved = 1;
uint32_t save_page_amount = page_amount;
//分页
if (APP_Reader_SplitPages(current_font_size) != 0)
{
APP_Reader_Msg("警告", "分页出错!\n\n请按任意键返回");
return;
}
if (is_saved == 0 || save_page_amount != page_amount)
current_page = 1;
//开始阅读
f_open(&page_file, page_filepath, FA_OPEN_EXISTING | FA_READ); //打开分页文件
while (1)
{
GE_Draw_ClrAll(WHITE);
if (APP_Reader_ReadPage(current_font_size, current_page) != 0)
{
GE_Draw_ClrAll(WHITE);
APP_Reader_Msg("警告", "发生错误!\n\n请按任意键返回");
return;
}
switch (KEY_GetKeyWait())
{
case JOY_L_UP: //设置菜单
{
if (APP_Reader_Menu() != 0)
return;
}
break;
case JOY_D_DOWN: //向后翻页
{
if (current_page == page_amount)
APP_Reader_Msg("提示", "已到最后一页!");
else
current_page++;
}
break;
case JOY_U_DOWN: //向前翻页
{
if (current_page == 1)
APP_Reader_Msg("提示", "已到第一页!");
else
current_page--;
}
}
}
}
/**
* @brief 显示某一页
* @param font_size: 字体大小
* @param page_num: 页码,从 1 开始
* @retval 成功返回 0失败返回 1
*/
uint8_t APP_Reader_ReadPage(uint8_t font_size, uint32_t page_num)
{
FRESULT f_res;
uint32_t br;
uint32_t page_br;
Page page;
//读分页信息
f_res = f_lseek(&page_file, (page_num - 1) * sizeof(Page));
f_res = f_read(&page_file, &page, sizeof(Page), &page_br);
//读取文件
uint8_t buffer[1500];
f_res = f_lseek(&file, page.page_ptr);
f_res = f_read(&file, buffer, page.page_size, &br);
if (f_res != FR_OK)
return 1;
*((uint8_t *)buffer + page.page_size) = '\0';
GE_Font_Print(0, 0, BORDER_MAX, BORDER_MAX, font_size, BLACK, WHITE, TRUE, buffer);
GE_Font_Print(
1,
223,
BORDER_MAX,
BORDER_MAX,
FONT_16,
BLUE,
WHITE,
TRUE,
"页数:%d/%d %.1f%%",
page_num,
page_amount,
(float)page_num / (float)page_amount * 100.0);
GE_Draw_Disp();
return 0;
}
/**
* @brief 对文本文件分页
* @param font_size: 字体大小
* @retval 成功返回 0失败返回 1
*/
uint8_t APP_Reader_SplitPages(uint8_t font_size)
{
APP_Reader_Msg_NoBlock("提示", "正在分页中...\n\n请稍等");
uint32_t br;
FRESULT f_res;
char ch;
uint8_t x, y;
Page page;
FSIZE_t fptr = 0;
uint32_t page_bw;
uint8_t x_max, y_max;
if (font_size == FONT_16)
{
x_max = 40;
y_max = 13;
}
else
{
x_max = 26;
y_max = 9;
}
strcpy(page_filename, filename);
strcat(page_filename, ".page");
SD_GetPath(page_filepath, page_filename);
f_res = f_open(&page_file, page_filepath, FA_CREATE_ALWAYS | FA_WRITE);
page_amount = 1;
f_lseek(&file, 0);
page.page_size = 0;
while (1)
{
x = 0;
y = 0;
while (1)
{
if (f_res != FR_OK)
return 1;
f_res = f_read(&file, &ch, 1, &br); //读一个字符
page.page_size++;
if (br == 0) //分页完毕
{
page.page_ptr = fptr;
f_res = f_write(&page_file, &page, sizeof(Page), &page_bw);
f_res = f_close(&page_file);
if (f_res != FR_OK)
return 1;
else
return 0;
}
if (ch <= 0x80) //ASCII 字符
{
if (ch == '\r' || ch == '\0') //忽略的字符
continue;
if ((x + 1 > x_max) || (ch == '\n'))
{
x = 0;
y++;
if (y + 1 > y_max)
{
if (ch != '\n')
f_res = f_lseek(&file, file.fptr - 1);
page.page_size--;
break;
}
}
if (ch != '\n')
x++;
}
else //GBK 字符
{
f_res = f_lseek(&file, file.fptr + 1);
page.page_size++;
if (x + 2 > x_max)
{
x = 0;
y++;
if (y + 1 > y_max)
{
f_res = f_lseek(&file, file.fptr - 2);
page.page_size -= 2;
break;
}
}
x += 2;
}
}
page_amount++; //页数增加
page.page_ptr = fptr; //本页起始指针
f_res = f_write(&page_file, &page, sizeof(Page), &page_bw); //写入分页文件
page.page_size = 0; //页大小归零
fptr = file.fptr; //下页起始指针
}
}
/**
* @brief 设置菜单
* @retval 返回阅读器返回 0结束阅读返回 1
*/
uint8_t APP_Reader_Menu(void)
{
uint8_t content[3][GE_GUI_MENUBOX_CONTENT_LEN] = {"字体设置", "退出阅读器", "返回"};
GE_Draw_Fill(50, 50, 220, 140, WHITE);
switch (GE_GUI_MenuBox(50, 50, 220, 140, "菜单", 3, content, NULL))
{
case 0: //返回
{
KEY_ClearKey();
}
break;
case 1: //字体设置
{
GE_Draw_Fill(50, 50, 220, 140, WHITE);
uint8_t content[2][GE_GUI_MENUBOX_CONTENT_LEN] = {"大号字体", "小号字体"};
if (GE_GUI_MenuBox(50, 50, 220, 140, "字体设置", 2, content, NULL) == 1)
{
if (current_font_size == FONT_24)
{
APP_Reader_Msg("提示", "您正在使用大号字体!");
current_page--;
}
else
{
float read_pos = (float)current_page / (float)page_amount;
current_font_size = FONT_24;
f_close(&page_file);
APP_Reader_SplitPages(current_font_size);
f_open(&page_file, page_filepath, FA_OPEN_EXISTING | FA_READ);
current_page = (float)page_amount * read_pos;
}
}
else
{
if (current_font_size == FONT_16)
{
APP_Reader_Msg("提示", "您正在使用小号字体!");
current_page--;
}
else
{
float read_pos = (float)current_page / (float)page_amount;
current_font_size = FONT_16;
f_close(&page_file);
APP_Reader_SplitPages(current_font_size);
f_open(&page_file, page_filepath, FA_OPEN_EXISTING | FA_READ);
current_page = (float)page_amount * read_pos;
}
}
}
break;
case 2: //退出
{
//关闭文件
f_close(&page_file);
f_close(&file);
APP_Reader_SaveWrite();
return 1;
}
break;
case 3: //返回
{
}
}
return 0;
}
/**
* @brief 读存档
* @retval 有存档返回 0无存档返回 1
*/
uint8_t APP_Reader_SaveRead(void)
{
uint32_t save_br;
Save save;
strcpy(save_filename, filename);
strcat(save_filename, ".save");
SD_GetPath(save_filepath, save_filename);
if (f_open(&save_file, save_filepath, FA_OPEN_EXISTING | FA_READ) != FR_OK ||
f_read(&save_file, &save, sizeof(Save), &save_br) != FR_OK)
{
f_close(&save_file);
return 1;
}
f_close(&save_file);
if (save.font_size == FONT_16)
current_font_size = FONT_16;
else if (save.font_size == FONT_24)
current_font_size = FONT_24;
else
return 1;
current_page = save.page_num;
page_amount = save.page_amount;
return 0;
}
/**
* @brief 写存档
* @retval 成功返回 0失败返回 1
*/
uint8_t APP_Reader_SaveWrite(void)
{
uint32_t save_bw;
Save save;
save.font_size = current_font_size;
save.page_num = current_page;
save.page_amount = page_amount;
strcpy(save_filename, filename);
strcat(save_filename, ".save");
SD_GetPath(save_filepath, save_filename);
f_open(&save_file, save_filepath, FA_CREATE_ALWAYS | FA_WRITE);
f_write(&save_file, &save, sizeof(Save), &save_bw);
f_close(&save_file);
return 0;
}
/**
* @brief 消息框,任意键按下后退出
* @param head: 标题
* @param content: 内容
*/
void APP_Reader_Msg(uint8_t *head, uint8_t *content)
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, head, content, NULL);
KEY_WaitKey(JOY_L);
}
/**
* @brief 消息框,任意键按下后退出
* @param head: 标题
* @param content: 内容
*/
void APP_Reader_Msg_NoBlock(uint8_t *head, uint8_t *content)
{
GE_Draw_Fill(60, 75, 200, 90, WHITE);
GE_GUI_MsgBox(60, 75, 200, 90, head, content, NULL);
}