From 9500b677dd18045a5eb161b1ec77946bc33b72b8 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Wed, 14 Jan 2026 10:57:46 +0800 Subject: [PATCH 01/25] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=92=8C=E4=B8=BB=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 121 +----- epdiy-epub/src/SConscript | 2 +- .../boards/controls/SF32_TouchControls.cpp | 76 +++- .../src/boards/controls/SF32_TouchControls.h | 8 +- epdiy-epub/src/epub_screen.cpp | 358 ++++++++++++++++++ epdiy-epub/src/epub_screen.h | 24 ++ epdiy-epub/src/main.cpp | 112 +++--- 7 files changed, 527 insertions(+), 174 deletions(-) create mode 100644 epdiy-epub/src/epub_screen.cpp create mode 100644 epdiy-epub/src/epub_screen.h diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index efd6603..2998a34 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -16,45 +16,24 @@ static const char *TAG = "PUBLIST"; #define PADDING 20 #define EPUBS_PER_PAGE 5 -#define BOTTOM_AREA_HEIGHT 50 -#define BOTTOM_AREA_ITEM_INDEX -1 void EpubList::next() { - // 如果当前选中的是最后一个电子书项,则切换到底部区域 - if (state.selected_item == state.num_epubs - 1) - { - state.selected_item = BOTTOM_AREA_ITEM_INDEX; - } - else if (state.selected_item == BOTTOM_AREA_ITEM_INDEX) - { - // 如果当前已在底部区域,则回到第一个电子书项 + if (state.num_epubs == 0) return; + // 正常切换到下一个电子书项 + if (state.selected_item >= 0 && state.selected_item < state.num_epubs - 1) + state.selected_item++; + else state.selected_item = 0; - } - else - { - // 正常切换到下一个电子书项 - state.selected_item = (state.selected_item + 1) % state.num_epubs; - } } void EpubList::prev() { - if (state.selected_item == 0) - { - // 如果当前是第一个电子书项,则切换到底部区域 - state.selected_item = BOTTOM_AREA_ITEM_INDEX; - } - else if (state.selected_item == BOTTOM_AREA_ITEM_INDEX) - { - // 如果当前已在底部区域,则切换到最后一个电子书项 - state.selected_item = state.num_epubs > 0 ? state.num_epubs - 1 : 0; - } - else - { - // 正常切换到上一个电子书项 - state.selected_item = (state.selected_item - 1 + state.num_epubs) % state.num_epubs; - } + if (state.num_epubs == 0) return; + if (state.selected_item <= 0) + state.selected_item = state.num_epubs - 1; + else + state.selected_item--; } bool EpubList::load(const char *path) @@ -149,8 +128,8 @@ void EpubList::render() ulog_d(TAG, "Rendering EPUB list"); // what page are we on? int current_page = state.selected_item / EPUBS_PER_PAGE; - // 计算单元格高度,减去底部区域的高度 - int cell_height = (renderer->get_page_height() - BOTTOM_AREA_HEIGHT) / EPUBS_PER_PAGE; + // 计算单元格高度(不再预留底部区域) + int cell_height = (renderer->get_page_height()) / EPUBS_PER_PAGE; ulog_d(TAG, "Cell height is %d", cell_height); int start_index = current_page * EPUBS_PER_PAGE; int ypos = 0; @@ -225,79 +204,5 @@ void EpubList::render() state.previous_selected_item = state.selected_item; state.previous_rendered_page = current_page; - // touch 开关底部区域 - - int screen_height = renderer->get_page_height(); - int bottom_area_y = screen_height - BOTTOM_AREA_HEIGHT - 11; - - - int original_width = renderer->get_page_width() - 2 * PADDING; - int rect_width = original_width * 2 / 3; - int rect_x = PADDING + (original_width - rect_width) / 2; - - int rect_height = BOTTOM_AREA_HEIGHT; - - if (bottom_area_y < 0) - { - bottom_area_y = 5; - rect_height = BOTTOM_AREA_HEIGHT; - } - - - renderer->fill_rect(rect_x, bottom_area_y, rect_width, rect_height, 255); - - bool touch_state = touch_controls ? touch_controls->isTouchEnabled() : false; - const char* text = touch_state ? "Touch : On" : "Touch : Off"; - - int text_height = renderer->get_line_height(); - int text_y = bottom_area_y + (rect_height - text_height) / 2; - - if (text_y < bottom_area_y + 2) - { - text_y = bottom_area_y + 2; - } - if (text_y + text_height > bottom_area_y + rect_height - 2) - { - text_y = bottom_area_y + rect_height - text_height - 2; - } - - int text_length = strlen(text); - int estimated_text_width = text_length * 12; - int text_x = rect_x + (rect_width - estimated_text_width) / 2; - - - if (text_x < rect_x + 5) - { - text_x = rect_x + 5; - } - if (text_x + estimated_text_width > rect_x + rect_width - 5) - { - text_x = rect_x + rect_width - estimated_text_width - 5; - } - - renderer->draw_text(text_x, text_y, text, 0); - - if (state.selected_item == BOTTOM_AREA_ITEM_INDEX) - { - int border_thickness = 3; - for (int i = 0; i < border_thickness; i++) - { - renderer->draw_rect(rect_x + i, bottom_area_y + i, - rect_width - 2 * i, - rect_height - 2 * i, 0); - } - } - else - { - if (state.previous_selected_item == BOTTOM_AREA_ITEM_INDEX) - { - int border_thickness = 3; - for (int i = 0; i < border_thickness; i++) - { - renderer->draw_rect(rect_x + i, bottom_area_y + i, - rect_width - 2 * i, - rect_height - 2 * i, 255); - } - } - } + // 移除书库页底部触控开关区域 } \ No newline at end of file diff --git a/epdiy-epub/src/SConscript b/epdiy-epub/src/SConscript index dd9b659..6c590b3 100644 --- a/epdiy-epub/src/SConscript +++ b/epdiy-epub/src/SConscript @@ -4,7 +4,7 @@ from building import * import rtconfig cwd = GetCurrentDir() -src = ['main.cpp','epub_mem.c','epub_fonts.c'] +src = ['main.cpp','epub_screen.cpp','epub_mem.c','epub_fonts.c'] src = src + Glob('./assets/*.c') CPPPATH = [cwd] diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index a2f85c9..9d17027 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -6,6 +6,9 @@ #include "drv_touch.h" #endif +volatile int g_touch_last_settings_row = -1; +volatile int g_touch_last_settings_dir = 0; + rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) { SF32_TouchControls *instance = static_cast (dev->user_data); @@ -29,24 +32,65 @@ rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) UIAction action = NONE; // LOG_I("TOUCH", "Received touch event %d,%d", x, y); - if (x >= 10 && x <= 10 + instance->ui_button_width && y < 200) - { - action = DOWN; - instance->renderPressedState(instance->renderer, UP, false); - } - else if (x >= 150 && x <= 150 + instance->ui_button_width && y < 200) - { - action = UP; - instance->renderPressedState(instance->renderer, DOWN, false); - } - else if (x >= 300 && x <= 300 + instance->ui_button_width && y < 200) + // 主页面底部按键区域:左"<"、右">"、中间文本框 + int page_w = instance->renderer->get_page_width(); + int page_h = instance->renderer->get_page_height(); + int margin_side = 10; + int margin_bottom = 60; + int rect_w = 80; + int rect_h = 40; + int y_bottom = page_h - rect_h - margin_bottom; + int left_x = margin_side; + int right_x = page_w - rect_w - margin_side; + int mid_x = left_x + rect_w + margin_side; + int mid_w = right_x - margin_side - mid_x; + + if (x >= left_x && x <= left_x + rect_w && y >= y_bottom && y <= y_bottom + rect_h) + { + rt_kprintf("Touch left < \n"); + action = UP; + } + + else if (x >= right_x && x <= right_x + rect_w && y >= y_bottom && y <= y_bottom + rect_h) + { + action = DOWN; + rt_kprintf("Touch right > \n"); + } + + // 设置页面每行左右箭头触控区域(与设置页布局一致) + if (action == NONE) { - action = SELECT; + int page_w2 = instance->renderer->get_page_width(); + int margin_lr2 = 6; + int item_h2 = 100; + int gap2 = 54; + int arrow_col_w2 = 40; + int lh2 = instance->renderer->get_line_height(); + int y_start2 = 40 + lh2 + 20; + g_touch_last_settings_row = -1; + g_touch_last_settings_dir = 0; + for (int row = 0; row < 3; ++row) + { + int ry = y_start2 + row * (item_h2 + gap2); + int left_ax = margin_lr2; + int right_ax = page_w2 - margin_lr2 - arrow_col_w2; + if (x >= left_ax && x <= left_ax + arrow_col_w2 && y >= ry && y <= ry + item_h2) + { + action = UP; + g_touch_last_settings_row = row; + g_touch_last_settings_dir = -1; // 左=减 + break; + } + if (x >= right_ax && x <= right_ax + arrow_col_w2 && y >= ry && y <= ry + item_h2) + { + action = DOWN; + g_touch_last_settings_row = row; + g_touch_last_settings_dir = +1; // 右=加 + break; + } + } } - else - { - } instance->last_action = action; if (action != NONE) { @@ -157,6 +201,8 @@ void SF32_TouchControls::renderPressedState(Renderer *renderer, UIAction action, case LAST_INTERACTION: case NONE: break; + default: + break; } renderer->set_margin_top(35); } \ No newline at end of file diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.h b/epdiy-epub/src/boards/controls/SF32_TouchControls.h index 23f2c56..d9dfba6 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.h +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.h @@ -23,4 +23,10 @@ class SF32_TouchControls : public TouchControls void renderPressedState(Renderer *renderer, UIAction action, bool state = true) override; void powerOnTouch() override; void powerOffTouch() override; -}; \ No newline at end of file +}; + +// 最近一次设置页左右箭头触控标记 +// 行号:0=触控开关,1=超时关机,2=全刷周期;-1=无 +extern volatile int g_touch_last_settings_row; +// 方向:-1=左(减),+1=右(加),0=无 +extern volatile int g_touch_last_settings_dir; \ No newline at end of file diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp new file mode 100644 index 0000000..ede9f23 --- /dev/null +++ b/epdiy-epub/src/epub_screen.cpp @@ -0,0 +1,358 @@ +#include "epub_screen.h" +#include + + +extern TouchControls *touch_controls; + +// 主页面选项 +typedef enum +{ + OPTION_OPEN_LIBRARY = 0, + OPTION_CONTINUE_READING, + OPTION_ENTER_SETTINGS +} MainOption; + +static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” +static int full_refresh_period = 10; // 全刷周期次数,仅用于设置页显示 + +// 设置页列表项 +typedef enum { SET_TOUCH = 0, SET_TIMEOUT = 1, SET_FULL_REFRESH = 2, SET_CONFIRM = 3 } SettingsItem; +static int settings_selected_idx = 0; + +// 超时关机:1/3/5/7/10/不关机(0) +static const int kTimeoutOptions[] = {1, 3, 5, 7, 10, 0}; +static const int kTimeoutOptionsCount = sizeof(kTimeoutOptions) / sizeof(kTimeoutOptions[0]); +static int timeout_shutdown_hours = 5; // 运行时关机超时(小时),0 表示不关机 +static int timeout_idx = -1; // 指向 kTimeoutOptions 的索引 + +static int find_timeout_idx(int hours) +{ + for (int i = 0; i < kTimeoutOptionsCount; ++i) + { + if (kTimeoutOptions[i] == hours) return i; + } + return 2; // 默认索引:5小时 +} + +static void adjust_timeout(bool increase) +{ + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_hours); + if (increase) + { + timeout_idx = (timeout_idx + 1) % kTimeoutOptionsCount; + } + else + { + timeout_idx = (timeout_idx - 1 + kTimeoutOptionsCount) % kTimeoutOptionsCount; + } + timeout_shutdown_hours = kTimeoutOptions[timeout_idx]; +} + +void screen_init(int default_timeout_hours) +{ + timeout_shutdown_hours = default_timeout_hours; + timeout_idx = find_timeout_idx(timeout_shutdown_hours); +} + +int screen_get_timeout_shutdown_hours() +{ + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_hours); + return timeout_shutdown_hours; +} + +int screen_get_main_selected_option() +{ + return (int)main_option; // 0: 打开书库, 1: 继续阅读, 2: 进入设置 +} + +// 主页面 +static void render_main_page(Renderer *renderer) +{ + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); + + const char *title = "S I F L I"; + int title_w = renderer->get_text_width(title); + int title_h = renderer->get_line_height(); + int center_x = renderer->get_page_width() / 2; + int center_y = 35 + (renderer->get_page_height() - 35) / 2; + renderer->draw_text(center_x - title_w / 2, center_y - title_h / 2, title, true, true); + + int margin_side = 10; + int margin_bottom = 60; // 与底部距离 + int rect_w = 80; + int rect_h = 40; + int y = renderer->get_page_height() - rect_h - margin_bottom; + int left_x = margin_side; + int right_x = renderer->get_page_width() - rect_w - margin_side; + + // 左 "<" + const char *lt = "<"; + int lt_w = renderer->get_text_width(lt); + int lt_h = renderer->get_line_height(); + renderer->draw_text(left_x + (rect_w - lt_w) / 2, y + (rect_h - lt_h) / 2, lt, false, true); + + // 右 ">" + const char *gt = ">"; + int gt_w = renderer->get_text_width(gt); + int gt_h = renderer->get_line_height(); + renderer->draw_text(right_x + (rect_w - gt_w) / 2, y + (rect_h - gt_h) / 2, gt, false, true); + + // 中间选项文本 + int mid_x = left_x + rect_w + margin_side; + int mid_w = right_x - margin_side - mid_x; + + const char *opt_text = NULL; + switch (main_option) + { + case OPTION_OPEN_LIBRARY: opt_text = "打开书库"; break; + case OPTION_CONTINUE_READING: opt_text = "继续阅读"; break; + case OPTION_ENTER_SETTINGS: opt_text = "进入设置"; break; + } + int opt_w = renderer->get_text_width(opt_text); + int opt_h = renderer->get_line_height(); + renderer->draw_text(mid_x + (mid_w - opt_w) / 2, y + (rect_h - opt_h) / 2, opt_text, false, true); +} + +void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw) +{ + if (needs_redraw || action == NONE) + { + render_main_page(renderer); + return; + } + switch (action) + { + case UP: // 左切换 + if (main_option == OPTION_OPEN_LIBRARY) main_option = OPTION_ENTER_SETTINGS; + else if (main_option == OPTION_CONTINUE_READING) main_option = OPTION_OPEN_LIBRARY; + else main_option = OPTION_CONTINUE_READING; + render_main_page(renderer); + break; + case DOWN: // 右切换 + if (main_option == OPTION_OPEN_LIBRARY) main_option = OPTION_CONTINUE_READING; + else if (main_option == OPTION_CONTINUE_READING) main_option = OPTION_ENTER_SETTINGS; + else main_option = OPTION_OPEN_LIBRARY; + render_main_page(renderer); + break; + case SELECT: + // 由上层 main.cpp 负责切换 页面UIState + switch (main_option) + { + case OPTION_OPEN_LIBRARY: + rt_kprintf("1\n"); + break; + case OPTION_CONTINUE_READING: + rt_kprintf("2\n"); + break; + case OPTION_ENTER_SETTINGS: + rt_kprintf("3\n"); + break; + } + break; + default: + break; + } +} + +// 设置页面 +static void render_settings_page(Renderer *renderer) +{ + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); + + // 标题 + const char *title = "设置"; + int title_w = renderer->get_text_width(title); + int title_h = renderer->get_line_height(); + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + renderer->draw_text((page_w - title_w) / 2, 40, title, true, true); + + // 列表项布局参数 + int margin_lr = 6; // 左右边距,给左右触控箭头 + int item_h = 100; // 矩形高度 + int gap = 54; // 列表项之间的间距 + int arrow_col_w = 40; // 左右触控箭头列宽度 + int y = 40 + title_h + 20; // 第一项起始Y + + // 1) 触控开关 + int item_w = page_w - margin_lr * 2 - arrow_col_w * 2; // 为左右箭头列留边 + int item_x = margin_lr + arrow_col_w; + { + const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); + const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); + } + if (settings_selected_idx == SET_TOUCH) + { + for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + } + else + { + renderer->draw_rect(item_x, y, item_w, item_h, 0); //画框线 + } + bool touch_on = touch_controls ? touch_controls->isTouchEnabled() : false; + char buf1[48]; + rt_snprintf(buf1, sizeof(buf1), "触控开关:%s", touch_on ? "开" : "关"); + int t1_w = renderer->get_text_width(buf1); + int lh = renderer->get_line_height(); + { + int tx = item_x + (item_w - t1_w) / 2; + if (tx < item_x + 4) tx = item_x + 4; + if (tx + t1_w > item_x + item_w - 4) tx = item_x + item_w - t1_w - 4; + renderer->draw_text(tx, y + (item_h - lh) / 2, buf1, false, true); + } + y += item_h + gap; + + // 2) 超时关机 + { + const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); + const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); + } + if (settings_selected_idx == SET_TIMEOUT) + { + for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + } + else + { + renderer->draw_rect(item_x, y, item_w, item_h, 0); + } + char buf2[64]; + if (timeout_shutdown_hours == 0) + { + rt_snprintf(buf2, sizeof(buf2), "超时关机:不关机"); + } + else + { + rt_snprintf(buf2, sizeof(buf2), "超时关机:%d 小时", timeout_shutdown_hours); + } + { + int t2_w = renderer->get_text_width(buf2); + int tx = item_x + (item_w - t2_w) / 2; + if (tx < item_x + 4) tx = item_x + 4; + if (tx + t2_w > item_x + item_w - 4) tx = item_x + item_w - t2_w - 4; + renderer->draw_text(tx, y + (item_h - lh) / 2, buf2, false, true); + } + y += item_h + gap; + + // 3) 全刷周期 + { + const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); + const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); + } + if (settings_selected_idx == SET_FULL_REFRESH) + { + for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + } + else + { + renderer->draw_rect(item_x, y, item_w, item_h, 0); + } + char buf3[64]; + rt_snprintf(buf3, sizeof(buf3), "全刷周期:%d 次", full_refresh_period); + { + int t3_w = renderer->get_text_width(buf3); + int tx = item_x + (item_w - t3_w) / 2; + if (tx < item_x + 4) tx = item_x + 4; + if (tx + t3_w > item_x + item_w - 4) tx = item_x + item_w - t3_w - 4; + renderer->draw_text(tx, y + (item_h - lh) / 2, buf3, false, true); + } + y += item_h + gap; + + // 底部 确认 按钮 + int confirm_h = 120; // 矩形框高度 + int confirm_w = item_w; // 宽度 + int confirm_x = (page_w - confirm_w) / 2; // 居中 + int confirm_y = page_h - confirm_h - 60; // 距离底部位置 + if (settings_selected_idx == SET_CONFIRM) + { + for (int i = 0; i < 2; ++i) renderer->draw_rect(confirm_x + i, confirm_y + i, confirm_w - 2 * i, confirm_h - 2 * i, 0); + } + else + { + renderer->draw_rect(confirm_x, confirm_y, confirm_w, confirm_h, 0); + } + const char *confirm = "确认"; + int c_w = renderer->get_text_width(confirm); + int c_h = renderer->get_line_height(); + renderer->draw_text(confirm_x + (confirm_w - c_w) / 2, confirm_y + (confirm_h - c_h) / 2, confirm, false, true); +} + +bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) +{ + // 读取并清除一次性的触控箭头标记,避免后续硬件按键误用 + int touch_row = g_touch_last_settings_row; + int touch_dir = g_touch_last_settings_dir; + g_touch_last_settings_row = -1; + g_touch_last_settings_dir = 0; + + if (needs_redraw || action == NONE) + { + render_settings_page(renderer); + return false; + } + + switch (action) + { + case UP: + // 触控箭头若命中“超时关机”行且为左箭头(减),执行减;否则执行上下选择 + if (settings_selected_idx == SET_TIMEOUT && touch_row == 1 && touch_dir == -1) + { + adjust_timeout(false); + render_settings_page(renderer); + } + else + { + if (settings_selected_idx > 0) settings_selected_idx--; else settings_selected_idx = SET_CONFIRM; + render_settings_page(renderer); + } + break; + case DOWN: + // 触控箭头若命中“超时关机”行且为右箭头(加),执行加;否则执行上下选择 + if (settings_selected_idx == SET_TIMEOUT && touch_row == 1 && touch_dir == +1) + { + adjust_timeout(true); + render_settings_page(renderer); + } + else + { + if (settings_selected_idx < SET_CONFIRM) settings_selected_idx++; else settings_selected_idx = SET_TOUCH; + render_settings_page(renderer); + } + break; + case SELECT: + if (settings_selected_idx == SET_TOUCH) + { + bool current_state = touch_controls ? touch_controls->isTouchEnabled() : false; + if (touch_controls) + { + touch_controls->setTouchEnable(!current_state); + if (!current_state) touch_controls->powerOnTouch(); + else touch_controls->powerOffTouch(); + } + render_settings_page(renderer); + break; + } + if (settings_selected_idx == SET_TIMEOUT) + { + // SELECT 在超时关机项上为加操作(循环) + adjust_timeout(true); + render_settings_page(renderer); + break; + } + if (settings_selected_idx == SET_CONFIRM) + { + // 由上层切回主页面 + return true; + } + // 其他项当前不处理 + break; + default: + break; + } + return false; +} diff --git a/epdiy-epub/src/epub_screen.h b/epdiy-epub/src/epub_screen.h new file mode 100644 index 0000000..c97c3c4 --- /dev/null +++ b/epdiy-epub/src/epub_screen.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include "boards/SF32PaperRenderer.h" +#include "boards/controls/Actions.h" +#include "boards/controls/TouchControls.h" +#include "boards/controls/SF32_TouchControls.h" + + +// 初始化屏幕模块(设置默认的关机超时小时数,0 表示不关机) +void screen_init(int default_timeout_hours); + +// 获取当前关机超时设置(小时;0 表示不关机) +int screen_get_timeout_shutdown_hours(); + +// 获取当前主页面选中的选项(0: 打开书库, 1: 继续阅读, 2: 进入设置) +int screen_get_main_selected_option(); + +// 主页面交互与渲染 +void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw); + +// 设置页面交互与渲染;返回 true 表示确认并退出到主页面 +bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw); + diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 835fa0f..ebe3d87 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -6,6 +6,7 @@ #include #include "boards/Board.h" #include "boards/controls/SF32_TouchControls.h" +#include "epub_screen.h" #include "boards/SF32PaperRenderer.h" #include "gui_app_pm.h" #include "bf0_pm.h" @@ -15,7 +16,7 @@ #undef DBG_LEVEL #define DBG_LEVEL DBG_LOG //DBG_INFO // #define LOG_TAG "EPUB.main" - +#define TIMEOUT_SHUTDOWN_TIME 5 // 默认关机超时(小时);0 表示不关机 #include @@ -35,9 +36,11 @@ const char *TAG = "main"; typedef enum { - SELECTING_EPUB, + MAIN_PAGE, // 新主页面 + SELECTING_EPUB, SELECTING_TABLE_CONTENTS, READING_EPUB, + SETTINGS_PAGE // 通用功能设置页面 } UIState; typedef enum { @@ -47,8 +50,8 @@ typedef enum CHARGING_PAGE } UIState2; -// default to showing the list of epubs to the user -UIState ui_state = SELECTING_EPUB; +// 默认显示新主页面,而非书库页面 +UIState ui_state = MAIN_PAGE; UIState2 lowpower_ui_state = MAIN_MENU; // the state data for the epub list and reader EpubListState epub_list_state; @@ -61,13 +64,21 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw); static EpubList *epub_list = nullptr; static EpubReader *reader = nullptr; static EpubToc *contents = nullptr; +static bool charge_full = false; Battery *battery = nullptr; -// 声明全局变量,以便open_tp_lcd和close_tp_lcd函数可以访问 +// 给open_tp_lcd和close_tp_lcd用的 Renderer *renderer = nullptr; TouchControls *touch_controls = nullptr; rt_mq_t ui_queue = RT_NULL; +// 主页面选项 +typedef enum { + OPTION_OPEN_LIBRARY = 0, // 打开书库 -> 打印 1 + OPTION_CONTINUE_READING, // 继续阅读 -> 打印 2 + OPTION_ENTER_SETTINGS // 进入设置 -> 打印 3 +} MainOption; + void handleEpub(Renderer *renderer, UIAction action) { if (!reader) @@ -167,30 +178,6 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) epub_list->next(); break; case SELECT: - // 检查是否选中了底部特殊区域 - if (epub_list_state.selected_item == -1) { - // 打印"1" - rt_kprintf("touch open or off\n"); - bool current_state = touch_controls->isTouchEnabled(); - touch_controls->setTouchEnable(!current_state); - - // 刷新屏幕以更新底部区域的文本显示 - if (!current_state) // 之前是关闭状态,现在要打开 - { - touch_controls->powerOnTouch(); - } - else // 之前是打开状态,现在要关闭 - { - touch_controls->powerOffTouch(); - } - - epub_list->render(); - - - return; - } - else - { // switch to reading the epub // setup the reader state ui_state = SELECTING_TABLE_CONTENTS; @@ -200,7 +187,6 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) contents->set_needs_redraw(); handleEpubTableContents(renderer, NONE, true); return; - } case NONE: default: // nothing to do @@ -287,13 +273,31 @@ void handleUserInteraction(Renderer *renderer, UIAction ui_action, bool needs_re uint32_t start_tick = rt_tick_get(); switch (ui_state) { + case MAIN_PAGE: // 新主页面 + handleMainPage(renderer, ui_action, needs_redraw); + if (ui_action == SELECT && screen_get_main_selected_option() == 2) + { + ui_state = SETTINGS_PAGE; + (void)handleSettingsPage(renderer, NONE, true); + } + break; case READING_EPUB: //阅读界面 handleEpub(renderer, ui_action); break; case SELECTING_TABLE_CONTENTS: //目录界面 handleEpubTableContents(renderer, ui_action, needs_redraw); break; - case SELECTING_EPUB: //电子书列表(主界面) + case SETTINGS_PAGE: // 设置页面 + { + bool exit_to_main = handleSettingsPage(renderer, ui_action, needs_redraw); + if (exit_to_main) + { + ui_state = MAIN_PAGE; + handleMainPage(renderer, NONE, true); + } + break; + } + case SELECTING_EPUB: //电子书列表页面(书库页面) default: handleEpubList(renderer, ui_action, needs_redraw); break; @@ -337,15 +341,8 @@ void back_to_main_page() renderer->set_margin_top(35); renderer->set_margin_left(10); renderer->set_margin_right(10); - - if (!epub_list) - { - epub_list = new EpubList(renderer, epub_list_state); - if (epub_list->load("/")) - { - ulog_i("main", "Epub files loaded"); - } - } + // 返回新的主页面,不再默认进入书库页面 + ui_state = MAIN_PAGE; handleUserInteraction(renderer, NONE, true); if (battery) @@ -537,6 +534,7 @@ void main_task(void *param) // reset the screen renderer->reset(); // make sure the UI is in the right state + ui_state = MAIN_PAGE; handleUserInteraction(renderer, NONE, true); } @@ -556,9 +554,12 @@ void main_task(void *param) // keep track of when the user last interacted and go to sleep after N seconds rt_tick_t last_user_interaction = rt_tick_get_millisecond(); + // 初始化屏幕模块默认关机超时 + screen_init(TIMEOUT_SHUTDOWN_TIME); -while (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 *5) //5小时无操作自动关机 -{ + while ((screen_get_timeout_shutdown_hours() == 0) || + (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 * screen_get_timeout_shutdown_hours())) // 按设置的小时数无操作自动关机;0为不关机 + { // 检查是否超过5分钟无操作,如果是在欢迎页面、充电页面或低电量页面则不跳转 if (rt_tick_get_millisecond() - last_user_interaction >= 60 * 1000 *5 && @@ -576,13 +577,26 @@ while (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 *5) // // 检查是否是更新充电状态的消息 if (ui_action == MSG_UPDATE_CHARGE_STATUS) - { - rt_kprintf("Charge status changed\n"); + { + if (battery) { - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - renderer->flush_display(); + int percentage = battery->get_percentage(); + if (percentage >= 98 && charge_full == false) + { + clear_charge_icon(renderer); + renderer->flush_display(); + charge_full = true; + rt_kprintf("Battery level is full, skip sending charge status update message\n"); + } + else if(percentage < 98) + { + rt_kprintf("Charge status changed\n"); + charge_full = false; + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + renderer->flush_display(); + } } continue; } @@ -673,7 +687,7 @@ extern "C" int main() { // dump out the epub list state - //rt_pm_request(PM_SLEEP_MODE_IDLE); + rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item); @@ -687,4 +701,4 @@ extern "C" } return 0; } -} \ No newline at end of file +} From 682170b496a9ec83a3ece786eaf154ac4cc6cdad Mon Sep 17 00:00:00 2001 From: smiling boy Date: Wed, 14 Jan 2026 16:28:44 +0800 Subject: [PATCH 02/25] =?UTF-8?q?1.=E5=AE=8C=E5=96=84=20=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=EF=BC=8C=E4=B9=A6=E5=BA=93=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=EF=BC=8C=E7=9B=AE=E5=BD=95=E9=A1=B5=E9=9D=A2=EF=BC=9A=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=AF=B9=E5=BA=94=E4=B8=8B=E6=A0=8F=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=202.=E5=A2=9E=E5=8A=A0=E9=98=85=E8=AF=BB=E8=A6=86=E7=9B=96?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=EF=BC=88=E7=B2=97=E7=B3=99=E7=89=88=EF=BC=9A?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86=E5=B8=83=E5=B1=80=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E8=BF=9B=E5=85=A5=E5=92=8C=E9=80=80=E5=87=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 51 ++- epdiy-epub/lib/Epub/EpubList/EpubList.h | 7 + epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 79 +++++ epdiy-epub/lib/Epub/EpubList/EpubReader.h | 11 + epdiy-epub/lib/Epub/EpubList/EpubToc.cpp | 47 ++- epdiy-epub/lib/Epub/EpubList/EpubToc.h | 7 + epdiy-epub/src/boards/controls/Actions.h | 1 + .../boards/controls/SF32_ButtonControls.cpp | 11 +- epdiy-epub/src/epub_screen.cpp | 9 +- epdiy-epub/src/main.cpp | 309 +++++++++++++++--- 10 files changed, 472 insertions(+), 60 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index 2998a34..2853941 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -15,7 +15,7 @@ static const char *TAG = "PUBLIST"; #define PADDING 20 -#define EPUBS_PER_PAGE 5 +#define EPUBS_PER_PAGE 4 void EpubList::next() { @@ -128,8 +128,10 @@ void EpubList::render() ulog_d(TAG, "Rendering EPUB list"); // what page are we on? int current_page = state.selected_item / EPUBS_PER_PAGE; - // 计算单元格高度(不再预留底部区域) - int cell_height = (renderer->get_page_height()) / EPUBS_PER_PAGE; + // 计算单元格高度,并为底部按钮预留区域与底部间距 + const int bottom_area_height = 100; // 底部三按钮区域高度 + const int bottom_margin = 30; // 与屏幕底部的间距 + int cell_height = (renderer->get_page_height() - bottom_area_height - bottom_margin) / EPUBS_PER_PAGE; ulog_d(TAG, "Cell height is %d", cell_height); int start_index = current_page * EPUBS_PER_PAGE; int ypos = 0; @@ -203,6 +205,45 @@ void EpubList::render() } state.previous_selected_item = state.selected_item; state.previous_rendered_page = current_page; - - // 移除书库页底部触控开关区域 + // 绘制底部三按钮区域 + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + int area_y = page_h - bottom_area_height - bottom_margin; + // 背景 + renderer->fill_rect(0, area_y, page_w, bottom_area_height, 255); + // 三个等宽按钮 + int btn_gap = 10; + int btn_w = (page_w - btn_gap * 4) / 3; + int btn_h = 80; + int btn_y = area_y + (bottom_area_height - btn_h) / 2; + int btn_x0 = btn_gap; // 上一页 + int btn_x1 = btn_gap * 2 + btn_w; // 主页面 + int btn_x2 = btn_gap * 3 + btn_w * 2; // 下一页 + + // 高亮边框:当处于底部模式时,高亮当前选择 + auto draw_button = [&](int x, const char* text, bool selected) + { + if (selected) + { + // 加粗描边,表示选中 + for (int i = 0; i < 5; ++i) + { + renderer->draw_rect(x + i, btn_y + i, btn_w - 2 * i, btn_h - 2 * i, 0); + } + } + else + { + // 非选中用细描边 + renderer->draw_rect(x, btn_y, btn_w, btn_h, 80); + } + int t_w = renderer->get_text_width(text); + int t_h = renderer->get_line_height(); + int tx = x + (btn_w - t_w) / 2; + int ty = btn_y + (btn_h - t_h) / 2; + renderer->draw_text(tx, ty, text, false, true); + }; + + draw_button(btn_x0, "上一页", m_bottom_mode && m_bottom_idx == 0); + draw_button(btn_x1, "主页面", m_bottom_mode && m_bottom_idx == 1); + draw_button(btn_x2, "下一页", m_bottom_mode && m_bottom_idx == 2); } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.h b/epdiy-epub/lib/Epub/EpubList/EpubList.h index c70a727..da2c910 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.h @@ -31,9 +31,16 @@ class EpubList EpubListState &state; bool m_needs_redraw = false; TouchControls* touch_controls = nullptr; + // 底部按钮选择状态:是否处于底部按钮选择模式与当前索引(0:上一页,1:主页面,2:下一页) + bool m_bottom_mode = false; + int m_bottom_idx = 1; public: EpubList(Renderer *renderer, EpubListState &state) : renderer(renderer), state(state){}; void setTouchControls(TouchControls* controls) { touch_controls = controls; } + // 设置底部按钮选择状态 + void set_bottom_selection(bool enabled, int idx) { m_bottom_mode = enabled; m_bottom_idx = idx; } + bool is_bottom_mode() const { return m_bottom_mode; } + int bottom_index() const { return m_bottom_idx; } ~EpubList() {} bool load(const char *path); void set_needs_redraw() { m_needs_redraw = true; } diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index 5be05ac..dc7b515 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -103,9 +103,88 @@ void EpubReader::render() parser->render_page(state.current_page, renderer, epub); ulog_d(TAG, "rendered page %d of %d", state.current_page, parser->get_page_count()); ulog_d(TAG, "after render: %d", heap_free_size()); + // 绘制半屏覆盖操作层 + if (overlay_active) + { + render_overlay(); + } } void EpubReader::set_state_section(uint16_t current_section) { ulog_i(TAG, "go to section:%d", current_section); state.current_section = current_section; +} + +void EpubReader::render_overlay() +{ + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + int area_y = (page_h * 2) / 3; // 覆盖下方 1/3 屏幕 + int area_h = page_h - area_y; + // 半透明效果不可用,使用浅灰底区分 + renderer->fill_rect(0, area_y, page_w, area_h, 240); + + // 三行布局:3,5,3 + const int rows = 3; + const int cols[rows] = {3, 5, 3}; + const int gap_h = 20; // 行间距 + const int gap_w = 10; + const int row_h = 80; // 每行高度 + // 纵向居中放置三行 + int content_h = rows * row_h + (rows + 1) * gap_h; + int y0 = area_y + (area_h - content_h) / 2; + if (y0 < area_y + 4) y0 = area_y + 4; + + int index = 0; + for (int r = 0; r < rows; ++r) + { + int c = cols[r]; + int usable_w = page_w - (c + 1) * gap_w; + int btn_w = usable_w / c; + int y = y0 + gap_h + r * (row_h + gap_h); + for (int i = 0; i < c; ++i) + { + int x = gap_w + i * (btn_w + gap_w); + bool selected = (index == overlay_selected); + if (selected) + { + for (int k = 0; k < 5; ++k) + { + renderer->draw_rect(x + k, y + k, btn_w - 2 * k, row_h - 2 * k, 0); + } + } + else + { + renderer->draw_rect(x, y, btn_w, row_h, 80); + } + // 文本:第9个显示"确认",其余显示编号 + char label[16]; + if (index == 8) + { + rt_snprintf(label, sizeof(label), "确认"); + } + else + { + rt_snprintf(label, sizeof(label), "%d", index + 1); + } + int t_w = renderer->get_text_width(label); + int t_h = renderer->get_line_height(); + int tx = x + (btn_w - t_w) / 2; + int ty = y + (row_h - t_h) / 2; + renderer->draw_text(tx, ty, label, false, true); + index++; + } + } +} + +void EpubReader::overlay_move_left() +{ + if (!overlay_active) return; + overlay_selected = (overlay_selected - 1 + 11) % 11; +} + +void EpubReader::overlay_move_right() +{ + if (!overlay_active) return; + overlay_selected = (overlay_selected + 1) % 11; } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index 5d46081..75f10ae 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -13,8 +13,12 @@ class EpubReader Epub *epub = nullptr; Renderer *renderer = nullptr; RubbishHtmlParser *parser = nullptr; + // 阅读页半屏覆盖操作层状态 + bool overlay_active = false; + int overlay_selected = 0; // 0..10,共11个 void parse_and_layout_current_section(); + void render_overlay(); public: EpubReader(EpubListItem &state, Renderer *renderer) : state(state), renderer(renderer){}; @@ -24,4 +28,11 @@ class EpubReader void prev(); void render(); void set_state_section(uint16_t current_section); + // 覆盖层控制 + void start_overlay() { overlay_active = true; overlay_selected = 0; } + void stop_overlay() { overlay_active = false; } + bool is_overlay_active() const { return overlay_active; } + void overlay_move_left(); + void overlay_move_right(); + int get_overlay_selected() const { return overlay_selected; } }; \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp index 46ca552..c6c5061 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp @@ -60,8 +60,10 @@ void EpubToc::render() ulog_d(TAG, "Rendering EPUB index"); // what page are we on? int current_page = state.selected_item / ITEMS_PER_PAGE; - // show five items per page - int cell_height = renderer->get_page_height() / ITEMS_PER_PAGE; + // 为底部按钮预留区域与底部间距 + const int bottom_area_height = 100; + const int bottom_margin = 30; + int cell_height = (renderer->get_page_height() - bottom_area_height - bottom_margin) / ITEMS_PER_PAGE; int start_index = current_page * ITEMS_PER_PAGE; int ypos = 0; // starting a fresh page or rendering from scratch? @@ -118,6 +120,47 @@ void EpubToc::render() } state.previous_selected_item = state.selected_item; state.previous_rendered_page = current_page; + + // 绘制底部三按钮区域 + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + int area_y = page_h - bottom_area_height - bottom_margin; + // 背景 + renderer->fill_rect(0, area_y, page_w, bottom_area_height, 255); + // 三个等宽按钮 + int btn_gap = 10; + int btn_w = (page_w - btn_gap * 4) / 3; // 左右边距各一个gap,再加中间两个gap + int btn_h = 80; + int btn_y = area_y + (bottom_area_height - btn_h) / 2; + int btn_x0 = btn_gap; // 上一页 + int btn_x1 = btn_gap * 2 + btn_w; // 主页面 + int btn_x2 = btn_gap * 3 + btn_w * 2; // 下一页 + + auto draw_button = [&](int x, const char* text, bool selected) + { + if (selected) + { + // 多重描边(黑色),与列表选中效果一致 + for (int i = 0; i < 5; ++i) + { + renderer->draw_rect(x + i, btn_y + i, btn_w - 2 * i, btn_h - 2 * i, 0); + } + } + else + { + // 非选中用细描边(灰色) + renderer->draw_rect(x, btn_y, btn_w, btn_h, 80); + } + int t_w = renderer->get_text_width(text); + int t_h = renderer->get_line_height(); + int tx = x + (btn_w - t_w) / 2; + int ty = btn_y + (btn_h - t_h) / 2; + renderer->draw_text(tx, ty, text, false, true); + }; + + draw_button(btn_x0, "上一页", m_bottom_mode && m_bottom_idx == 0); + draw_button(btn_x1, "书库", m_bottom_mode && m_bottom_idx == 1); + draw_button(btn_x2, "下一页", m_bottom_mode && m_bottom_idx == 2); } uint16_t EpubToc::get_selected_toc() diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.h b/epdiy-epub/lib/Epub/EpubList/EpubToc.h index 5ef96a8..56563f0 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.h @@ -32,6 +32,9 @@ class EpubToc EpubListItem &selected_epub; EpubTocState &state; bool m_needs_redraw = false; + // 底部按钮选择状态:是否处于底部按钮选择模式与当前索引(0:上一页,1:主页面,2:下一页) + bool m_bottom_mode = false; + int m_bottom_idx = 1; public: EpubToc(EpubListItem &selected_epub, EpubTocState &state, Renderer *renderer) : renderer(renderer), selected_epub(selected_epub), state(state){}; @@ -42,4 +45,8 @@ class EpubToc void render(); void set_needs_redraw() { m_needs_redraw = true; } uint16_t get_selected_toc(); + // 目录项总数 + int get_items_count() const { return epub ? epub->get_toc_items_count() : 0; } + // 设置底部按钮选择状态 + void set_bottom_selection(bool enabled, int idx) { m_bottom_mode = enabled; m_bottom_idx = idx; } }; \ No newline at end of file diff --git a/epdiy-epub/src/boards/controls/Actions.h b/epdiy-epub/src/boards/controls/Actions.h index 785384d..8e83835 100644 --- a/epdiy-epub/src/boards/controls/Actions.h +++ b/epdiy-epub/src/boards/controls/Actions.h @@ -8,6 +8,7 @@ typedef enum UP, DOWN, SELECT, + UPGLIDE, // 长按触发的上滑操作,用于阅读页半屏操作覆盖 LAST_INTERACTION, MSG_DRAW_LOW_POWER_PAGE, MSG_DRAW_CHARGE_PAGE, diff --git a/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp b/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp index 4f075d2..ebb4e74 100644 --- a/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp @@ -12,6 +12,11 @@ void button_event_handler(int32_t pin, button_action_t action) { action_cbk(UIAction::UP); } + else if (action == BUTTON_LONG_PRESSED) + { + rt_kprintf("长按 1"); + action_cbk(UIAction::UPGLIDE); + } } #else if (pin == EPD_KEY1) @@ -28,10 +33,7 @@ void button_event_handler(int32_t pin, button_action_t action) { action_cbk(UIAction::SELECT); } - else if (action == BUTTON_LONG_PRESSED) - { - rt_kprintf("长按 1"); - } + } else if (pin == EPD_KEY3) { @@ -39,6 +41,7 @@ void button_event_handler(int32_t pin, button_action_t action) { action_cbk(UIAction::UP); } + } #endif diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index ede9f23..d58ca7b 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -185,7 +185,8 @@ static void render_settings_page(Renderer *renderer) } if (settings_selected_idx == SET_TOUCH) { - for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + // 选中强化:多重描边,提高可见度 + for (int i = 0; i < 5; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); } else { @@ -213,7 +214,7 @@ static void render_settings_page(Renderer *renderer) } if (settings_selected_idx == SET_TIMEOUT) { - for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + for (int i = 0; i < 5; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); } else { @@ -246,7 +247,7 @@ static void render_settings_page(Renderer *renderer) } if (settings_selected_idx == SET_FULL_REFRESH) { - for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + for (int i = 0; i < 5; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); } else { @@ -270,7 +271,7 @@ static void render_settings_page(Renderer *renderer) int confirm_y = page_h - confirm_h - 60; // 距离底部位置 if (settings_selected_idx == SET_CONFIRM) { - for (int i = 0; i < 2; ++i) renderer->draw_rect(confirm_x + i, confirm_y + i, confirm_w - 2 * i, confirm_h - 2 * i, 0); + for (int i = 0; i < 5; ++i) renderer->draw_rect(confirm_x + i, confirm_y + i, confirm_w - 2 * i, confirm_h - 2 * i, 0); } else { diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index ebe3d87..b765824 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -37,9 +37,9 @@ const char *TAG = "main"; typedef enum { MAIN_PAGE, // 新主页面 - SELECTING_EPUB, - SELECTING_TABLE_CONTENTS, - READING_EPUB, + SELECTING_EPUB, // 电子书列表页面(书库) + SELECTING_TABLE_CONTENTS, // 电子书目录页面 + READING_EPUB, // 阅读页面 SETTINGS_PAGE // 通用功能设置页面 } UIState; typedef enum @@ -60,6 +60,7 @@ EpubTocState epub_index_state; void handleEpub(Renderer *renderer, UIAction action); void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw); +void back_to_main_page(); static EpubList *epub_list = nullptr; static EpubReader *reader = nullptr; @@ -70,6 +71,10 @@ Battery *battery = nullptr; Renderer *renderer = nullptr; TouchControls *touch_controls = nullptr; +// 书库页底部按钮选择状态 +static bool library_bottom_mode = false; // 是否处于底部三按钮选择模式 +static int library_bottom_idx = 1; // 当前底部按钮索引:0上一页,1主页面,2下一页 + rt_mq_t ui_queue = RT_NULL; // 主页面选项 @@ -89,34 +94,64 @@ void handleEpub(Renderer *renderer, UIAction action) switch (action) { case UP: - reader->prev(); + if (reader->is_overlay_active()) + { + reader->overlay_move_left(); + } + else + { + reader->prev(); + } break; case DOWN: - reader->next(); + if (reader->is_overlay_active()) + { + reader->overlay_move_right(); + } + else + { + reader->next(); + } break; case SELECT: - - // switch back to main screen - ui_state = SELECTING_EPUB; - renderer->clear_screen(); - // clear the epub reader away - delete reader; - reader = nullptr; - // force a redraw - if (!epub_list) + if (reader->is_overlay_active()) { - epub_list = new EpubList(renderer, epub_list_state); + // 在覆盖层中,SELECT仅作用于覆盖区域:当选中"确认"时关闭覆盖层 + if (reader->get_overlay_selected() == 8) + { + reader->stop_overlay(); + } + // 非“确认”暂不执行其他操作 } - handleEpubList(renderer, NONE, true); + else + { + // switch back to main screen + ui_state = SELECTING_EPUB; + renderer->clear_screen(); + // clear the epub reader away + delete reader; + reader = nullptr; + // force a redraw + if (!epub_list) + { + epub_list = new EpubList(renderer, epub_list_state); + } + handleEpubList(renderer, NONE, true); - return; + return; + } + break; + case UPGLIDE: + // 激活阅读页下半屏覆盖操作层 + reader->start_overlay(); + break; case NONE: default: break; } reader->render(); } - +//目录页的处理 void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw) { if (!contents) @@ -125,32 +160,122 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red contents->set_needs_redraw(); contents->load(); } + static bool toc_bottom_mode = false; + static int toc_bottom_idx = 1; // 0:上一页,1:主页面,2:下一页 + if (needs_redraw) + { + toc_bottom_mode = false; + toc_bottom_idx = 1; + } switch (action) { case UP: - contents->prev(); + if (toc_bottom_mode) + { + toc_bottom_idx = (toc_bottom_idx + 2) % 3; // 左移 + } + else + { + int per_page = 6; + int start_idx = (epub_index_state.selected_item / per_page) * per_page; + if (contents->get_items_count() > 0 && epub_index_state.selected_item == start_idx) + { + toc_bottom_mode = true; + } + else + { + contents->prev(); + } + } break; case DOWN: - contents->next(); + if (toc_bottom_mode) + { + toc_bottom_idx = (toc_bottom_idx + 1) % 3; // 右移 + } + else + { + int per_page = 6; + int start_idx = (epub_index_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + int count = contents->get_items_count(); + if (end_idx >= count) end_idx = count - 1; + if (count > 0 && epub_index_state.selected_item == end_idx) + { + toc_bottom_mode = true; + } + else + { + contents->next(); + } + } break; case SELECT: - // setup the reader state - ui_state = READING_EPUB; - // create the reader and load the book - reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); - reader->set_state_section(contents->get_selected_toc()); - reader->load(); - //switch to reading the epub - delete contents; - handleEpub(renderer, NONE); - return; + if (toc_bottom_mode) + { + int per_page = 6; + int count = contents->get_items_count(); + int current_page = (count > 0) ? (epub_index_state.selected_item / per_page) : 0; + int max_page = (count == 0) ? 0 : ((count - 1) / per_page); + if (toc_bottom_idx == 1) + { + // 书库:切换到书库页面 + rt_kprintf("从目录页返回书库页\n"); + ui_state = SELECTING_EPUB; + if (contents) + { + delete contents; + contents = nullptr; + } + handleEpubList(renderer, NONE, true); + return; + } + else if (toc_bottom_idx == 0) + { + // 上一页 + if (current_page > 0) + { + epub_index_state.selected_item -= per_page; + if (epub_index_state.selected_item < 0) epub_index_state.selected_item = 0; + contents->set_needs_redraw(); + } + toc_bottom_mode = false; + } + else if (toc_bottom_idx == 2) + { + // 下一页 + if (current_page < max_page) + { + epub_index_state.selected_item += per_page; + if (epub_index_state.selected_item >= count) + epub_index_state.selected_item = count - 1; + contents->set_needs_redraw(); + } + toc_bottom_mode = false; + } + } + else + { + // 进入阅读界面 + ui_state = READING_EPUB; + reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); + reader->set_state_section(contents->get_selected_toc()); + reader->load(); + delete contents; + handleEpub(renderer, NONE); + return; + } + break; case NONE: default: break; } + // 将底部选择状态传递给目录渲染 + contents->set_bottom_selection(toc_bottom_mode, toc_bottom_idx); contents->render(); } +//书库页的处理 void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) { // load up the epub list from the filesystem @@ -167,31 +292,114 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) if (needs_redraw) { epub_list->set_needs_redraw(); + // 进入书库页时重置底部选择状态 + library_bottom_mode = false; + library_bottom_idx = 1; } // work out what the user wants us to do switch (action) { case UP: - epub_list->prev(); + if (library_bottom_mode) + { + // UP 表示向左选择 + library_bottom_idx = (library_bottom_idx + 2) % 3; + } + else + { + // 若处于当前页第一个条目,UP 切换到底部按钮模式 + int per_page = 4; + int start_idx = (epub_list_state.selected_item / per_page) * per_page; + if (epub_list_state.num_epubs > 0 && epub_list_state.selected_item == start_idx) + { + library_bottom_mode = true; + } + else + { + epub_list->prev(); + } + } break; case DOWN: - epub_list->next(); + if (library_bottom_mode) + { + // DOWN 表示向右选择 + library_bottom_idx = (library_bottom_idx + 1) % 3; + } + else + { + int per_page = 4; + int start_idx = (epub_list_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + if (end_idx >= epub_list_state.num_epubs) end_idx = epub_list_state.num_epubs - 1; + // 若处于当前页最后一个条目,DOWN 切换到底部按钮模式 + if (epub_list_state.num_epubs > 0 && epub_list_state.selected_item == end_idx) + { + library_bottom_mode = true; + } + else + { + epub_list->next(); + } + } break; case SELECT: - // switch to reading the epub - // setup the reader state - ui_state = SELECTING_TABLE_CONTENTS; - // create the reader and load the book - contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); - contents->load(); - contents->set_needs_redraw(); - handleEpubTableContents(renderer, NONE, true); - return; + if (library_bottom_mode) + { + int per_page = 4; + int current_page = epub_list_state.selected_item / per_page; + int max_page = (epub_list_state.num_epubs == 0) ? 0 : ( (epub_list_state.num_epubs - 1) / per_page ); + if (library_bottom_idx == 1) + { + // 主页面:返回主页面 + rt_kprintf("从书库页返回主页面\n"); + back_to_main_page(); + return; + } + else if (library_bottom_idx == 0) + { + // 上一页 + if (current_page > 0) + { + epub_list_state.selected_item -= per_page; + if (epub_list_state.selected_item < 0) epub_list_state.selected_item = 0; + epub_list->set_needs_redraw(); + } + // 切回条目选择模式 + library_bottom_mode = false; + } + else if (library_bottom_idx == 2) + { + // 下一页 + if (current_page < max_page) + { + epub_list_state.selected_item += per_page; + if (epub_list_state.selected_item >= epub_list_state.num_epubs) + epub_list_state.selected_item = epub_list_state.num_epubs - 1; + epub_list->set_needs_redraw(); + } + // 切回条目选择模式 + library_bottom_mode = false; + } + } + else + { + // 进入目录选择页面 + ui_state = SELECTING_TABLE_CONTENTS; + contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); + contents->load(); + contents->set_needs_redraw(); + handleEpubTableContents(renderer, NONE, true); + return; + } + break; case NONE: default: // nothing to do break; } + // 将底部选择状态传递给列表渲染 + epub_list->set_bottom_selection(library_bottom_mode, library_bottom_idx); epub_list->render(); } // TODO - add the battery level @@ -275,10 +483,20 @@ void handleUserInteraction(Renderer *renderer, UIAction ui_action, bool needs_re { case MAIN_PAGE: // 新主页面 handleMainPage(renderer, ui_action, needs_redraw); - if (ui_action == SELECT && screen_get_main_selected_option() == 2) + if (ui_action == SELECT && screen_get_main_selected_option() == 2) //切换到设置页面 { ui_state = SETTINGS_PAGE; - (void)handleSettingsPage(renderer, NONE, true); + (void)handleSettingsPage(renderer, NONE, true); + } + else if (ui_action == SELECT && screen_get_main_selected_option() == 1) //切换到阅读页面 + { + // ui_state = READING_EPUB; + // handleEpub(renderer, NONE); + } + else if (ui_action == SELECT && screen_get_main_selected_option() == 0) //切换到书库页面 + { + ui_state = SELECTING_EPUB; + handleEpubList(renderer, NONE, true); } break; case READING_EPUB: //阅读界面 @@ -322,8 +540,9 @@ const char* getCurrentPageName() { //回到主界面接口 void back_to_main_page() { - if (strcmp(getCurrentPageName(), "MAIN_MENU") == 0) + if (ui_state == MAIN_PAGE) { + rt_kprintf("已经在主页面,无需返回\n"); return; } lowpower_ui_state = MAIN_MENU; @@ -389,7 +608,7 @@ void draw_welcome_page(Battery *battery) } -// 绘制低电量页面 +// 低电量页面 void draw_low_power_page(Battery *battery) { if (strcmp(getCurrentPageName(), "LOW_POWER_PAGE") == 0) From b120464dc10447ef874a20f4091d3aef5dfbd5ab Mon Sep 17 00:00:00 2001 From: smiling boy Date: Wed, 14 Jan 2026 17:58:27 +0800 Subject: [PATCH 03/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=98=85=E8=AF=BB?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=EF=BC=9A1.=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20=E7=9B=AE=E5=BD=95=E9=A1=B5=E9=9D=A2=20=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=20=E4=B9=A6=E5=BA=93=E9=A1=B5=E9=9D=A2=E7=9A=84?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD=202.=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=B4=AF=E7=A7=AF=E8=B7=B3=E8=BD=AC=E9=A1=B5=E9=9D=A2=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 70 ++++++++++++++++++--- epdiy-epub/lib/Epub/EpubList/EpubReader.h | 8 ++- epdiy-epub/src/main.cpp | 56 +++++++++++++++-- 3 files changed, 122 insertions(+), 12 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index dc7b515..a13ace7 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -157,15 +157,24 @@ void EpubReader::render_overlay() { renderer->draw_rect(x, y, btn_w, row_h, 80); } - // 文本:第9个显示"确认",其余显示编号 + // 文本映射: + // 1:"<" 2:保留原编号 3:">" 4:"-5" 5:"-1" 6:"acc" 7:"+1" 8:"+5" 9:"确认" 10:"目录" 11:"书库" char label[16]; - if (index == 8) + switch (index) { - rt_snprintf(label, sizeof(label), "确认"); - } - else - { - rt_snprintf(label, sizeof(label), "%d", index + 1); + case 0: rt_snprintf(label, sizeof(label), "<"); break; + case 1: rt_snprintf(label, sizeof(label), "2"); break; + case 2: rt_snprintf(label, sizeof(label), ">"); break; + case 3: rt_snprintf(label, sizeof(label), "-5"); break; + case 4: rt_snprintf(label, sizeof(label), "-1"); break; + case 5: rt_snprintf(label, sizeof(label), "%d", overlay_jump_acc); break; + case 6: rt_snprintf(label, sizeof(label), "+1"); break; + case 7: rt_snprintf(label, sizeof(label), "+5"); break; + case 8: rt_snprintf(label, sizeof(label), "确认"); break; + case 9: rt_snprintf(label, sizeof(label), "目录"); break; + case 10: rt_snprintf(label, sizeof(label), "书库"); break; + default: + break; } int t_w = renderer->get_text_width(label); int t_h = renderer->get_line_height(); @@ -187,4 +196,51 @@ void EpubReader::overlay_move_right() { if (!overlay_active) return; overlay_selected = (overlay_selected + 1) % 11; +} + +void EpubReader::jump_pages(int delta) +{ + if (delta == 0) return; + if (!parser) //没解析的情况下 则解析当前节 + { + parse_and_layout_current_section(); + } + int spine_count = epub ? epub->get_spine_items_count() : 0; //获取章节总数 + if (spine_count <= 0) return; + + auto at_book_start = [&]() -> bool { + return state.current_section == 0 && state.current_page == 0; + }; + auto at_book_end = [&]() -> bool { + // 需要知道当前节页数;parser 非空时有效 + if (!parser) return false; + return (state.current_section == spine_count - 1) && (state.current_page >= state.pages_in_current_section - 1); + }; + // 开始实现页面跳转 + if (delta > 0) + { + for (int i = 0; i < delta; ++i) + { + if (at_book_end()) break; + next(); + // 如果跨节,parser 在 next() 时会置空;后续渲染时会自动 parse + if (!parser) + { + parse_and_layout_current_section(); + } + } + } + else // delta < 0 + { + for (int i = 0; i < -delta; ++i) + { + if (at_book_start()) break; + prev(); + if (!parser) + { + //空则解析 + parse_and_layout_current_section(); + } + } + } } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index 75f10ae..1ceebe8 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -16,6 +16,7 @@ class EpubReader // 阅读页半屏覆盖操作层状态 bool overlay_active = false; int overlay_selected = 0; // 0..10,共11个 + int overlay_jump_acc = 0; // 覆盖层累积跳页值(可为负) void parse_and_layout_current_section(); void render_overlay(); @@ -26,13 +27,18 @@ class EpubReader bool load(); void next(); void prev(); + void jump_pages(int delta); void render(); void set_state_section(uint16_t current_section); // 覆盖层控制 - void start_overlay() { overlay_active = true; overlay_selected = 0; } + void start_overlay() { overlay_active = true; overlay_selected = 0; overlay_jump_acc = 0; } void stop_overlay() { overlay_active = false; } bool is_overlay_active() const { return overlay_active; } void overlay_move_left(); void overlay_move_right(); int get_overlay_selected() const { return overlay_selected; } + // 覆盖层跳页累积控制 + void overlay_add_jump(int d) { overlay_jump_acc += d; } + void overlay_reset_jump() { overlay_jump_acc = 0; } + int overlay_get_jump() const { return overlay_jump_acc; } }; \ No newline at end of file diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index b765824..adaecd9 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -83,7 +83,7 @@ typedef enum { OPTION_CONTINUE_READING, // 继续阅读 -> 打印 2 OPTION_ENTER_SETTINGS // 进入设置 -> 打印 3 } MainOption; - +void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw); void handleEpub(Renderer *renderer, UIAction action) { if (!reader) @@ -116,12 +116,60 @@ void handleEpub(Renderer *renderer, UIAction action) case SELECT: if (reader->is_overlay_active()) { - // 在覆盖层中,SELECT仅作用于覆盖区域:当选中"确认"时关闭覆盖层 - if (reader->get_overlay_selected() == 8) + int sel = reader->get_overlay_selected(); + if (sel == 9) //目录 { + ui_state = SELECTING_TABLE_CONTENTS; reader->stop_overlay(); + delete reader; + reader = nullptr; + contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); + contents->load(); + contents->set_needs_redraw(); + handleEpubTableContents(renderer, NONE, true); + return; } - // 非“确认”暂不执行其他操作 + else if (sel == 8) //确认:1.按第六格累积值跳页 + { + int delta = reader->overlay_get_jump(); + if (delta != 0) + { + reader->jump_pages(delta); + } + reader->overlay_reset_jump(); + reader->stop_overlay(); + } + else if (sel == 10) //书库 + { + ui_state = SELECTING_EPUB; + reader->stop_overlay(); + renderer->clear_screen(); + delete reader; + reader = nullptr; + if (!epub_list) + { + epub_list = new EpubList(renderer, epub_list_state); + } + handleEpubList(renderer, NONE, true); + return; + } + else if (sel == 3) + { + reader->overlay_add_jump(-5); + } + else if (sel == 4) + { + reader->overlay_add_jump(-1); + } + else if (sel == 6) + { + reader->overlay_add_jump(1); + } + else if (sel == 7) + { + reader->overlay_add_jump(5); + } + } else { From 07a122cf835bfb3b2657cac825e4f5a4366a4f01 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Thu, 15 Jan 2026 11:22:33 +0800 Subject: [PATCH 04/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=98=85=E8=AF=BB?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E9=A1=B5=EF=BC=9A1=EF=BC=8C2=EF=BC=8C3?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E7=9F=A9=E5=BD=A2=E5=AE=9E=E7=8E=B0=20?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E8=A7=A6=E6=8E=A7=20=E4=B8=8E=20=E5=85=A8?= =?UTF-8?q?=E5=88=B7=E5=91=A8=E6=9C=9F=E6=AC=A1=E6=95=B0=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8A=9F=E8=83=BD=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=EF=BC=9A=E5=85=A8=E5=88=B7?= =?UTF-8?q?=E5=91=A8=E6=9C=9F=E6=AC=A1=E6=95=B0=E5=8A=A8=E6=80=81=E6=98=BE?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 125 +++++++++++++++----- epdiy-epub/lib/Epub/EpubList/EpubReader.h | 15 +++ epdiy-epub/src/epub_screen.cpp | 42 ++++++- epdiy-epub/src/epub_screen.h | 5 +- epdiy-epub/src/main.cpp | 46 +++++++ 5 files changed, 202 insertions(+), 31 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index a13ace7..c885238 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -12,6 +12,7 @@ #include "../RubbishHtmlParser/RubbishHtmlParser.h" #include "../Renderer/Renderer.h" #include "epub_mem.h" +#include "epub_screen.h" static const char *TAG = "EREADER"; extern "C" rt_uint32_t heap_free_size(void); @@ -121,7 +122,7 @@ void EpubReader::render_overlay() int page_h = renderer->get_page_height(); int area_y = (page_h * 2) / 3; // 覆盖下方 1/3 屏幕 int area_h = page_h - area_y; - // 半透明效果不可用,使用浅灰底区分 + renderer->fill_rect(0, area_y, page_w, area_h, 240); // 三行布局:3,5,3 @@ -136,15 +137,86 @@ void EpubReader::render_overlay() if (y0 < area_y + 4) y0 = area_y + 4; int index = 0; + auto fill_label = [&](int idx, char *label, size_t cap) { + switch (idx) + { + case 0: rt_snprintf(label, cap, "<"); break; + case 1: + { + if (overlay_center_mode == CENTER_TOUCH) + { + rt_snprintf(label, cap, "触摸开关:%s", overlay_touch_enabled ? "开" : "关"); + } + else + { + int v = overlay_get_full_refresh_value(); + if (v == 0) + rt_snprintf(label, cap, "全刷周期:不刷新"); + else + rt_snprintf(label, cap, "全刷周期:%d次", v); + } + break; + } + case 2: rt_snprintf(label, cap, ">"); break; + case 3: rt_snprintf(label, cap, "-5"); break; + case 4: rt_snprintf(label, cap, "-1"); break; + case 5: rt_snprintf(label, cap, "%d", overlay_jump_acc); break; + case 6: rt_snprintf(label, cap, "+1"); break; + case 7: rt_snprintf(label, cap, "+5"); break; + case 8: rt_snprintf(label, cap, "确认"); break; + case 9: rt_snprintf(label, cap, "目录"); break; + case 10: rt_snprintf(label, cap, "书库"); break; + default: label[0] = '\0'; break; + } + }; for (int r = 0; r < rows; ++r) { int c = cols[r]; - int usable_w = page_w - (c + 1) * gap_w; - int btn_w = usable_w / c; int y = y0 + gap_h + r * (row_h + gap_h); - for (int i = 0; i < c; ++i) + // 顶部第1行(3列)采用不等宽布局:1/3半宽,2双宽 + if (r == 0) { - int x = gap_w + i * (btn_w + gap_w); + int usable_w = page_w - (c + 1) * gap_w; + // 宽度权重为 1:3:1(约 左20% / 中60% / 右20%) + int w0 = (usable_w * 1) / 5; + int w1 = (usable_w * 3) / 5; + int w2 = usable_w - w0 - w1; + int widths[3] = { w0, w1, w2 }; + int cur_x = gap_w; + for (int i = 0; i < c; ++i) + { + int w = widths[i]; + int x = cur_x; + bool selected = (index == overlay_selected); + if (selected) + { + for (int k = 0; k < 5; ++k) + { + renderer->draw_rect(x + k, y + k, w - 2 * k, row_h - 2 * k, 0); + } + } + else + { + renderer->draw_rect(x, y, w, row_h, 80); + } + char label[32]; + fill_label(index, label, sizeof(label)); + int t_w = renderer->get_text_width(label); + int t_h = renderer->get_line_height(); + int tx = x + (w - t_w) / 2; + int ty = y + (row_h - t_h) / 2; + renderer->draw_text(tx, ty, label, false, true); + index++; + cur_x = x + w + gap_w; + } + } + else + { + int usable_w = page_w - (c + 1) * gap_w; + int btn_w = usable_w / c; + for (int i = 0; i < c; ++i) + { + int x = gap_w + i * (btn_w + gap_w); bool selected = (index == overlay_selected); if (selected) { @@ -157,31 +229,15 @@ void EpubReader::render_overlay() { renderer->draw_rect(x, y, btn_w, row_h, 80); } - // 文本映射: - // 1:"<" 2:保留原编号 3:">" 4:"-5" 5:"-1" 6:"acc" 7:"+1" 8:"+5" 9:"确认" 10:"目录" 11:"书库" - char label[16]; - switch (index) - { - case 0: rt_snprintf(label, sizeof(label), "<"); break; - case 1: rt_snprintf(label, sizeof(label), "2"); break; - case 2: rt_snprintf(label, sizeof(label), ">"); break; - case 3: rt_snprintf(label, sizeof(label), "-5"); break; - case 4: rt_snprintf(label, sizeof(label), "-1"); break; - case 5: rt_snprintf(label, sizeof(label), "%d", overlay_jump_acc); break; - case 6: rt_snprintf(label, sizeof(label), "+1"); break; - case 7: rt_snprintf(label, sizeof(label), "+5"); break; - case 8: rt_snprintf(label, sizeof(label), "确认"); break; - case 9: rt_snprintf(label, sizeof(label), "目录"); break; - case 10: rt_snprintf(label, sizeof(label), "书库"); break; - default: - break; - } + char label[32]; + fill_label(index, label, sizeof(label)); int t_w = renderer->get_text_width(label); int t_h = renderer->get_line_height(); int tx = x + (btn_w - t_w) / 2; int ty = y + (row_h - t_h) / 2; renderer->draw_text(tx, ty, label, false, true); index++; + } } } } @@ -208,11 +264,14 @@ void EpubReader::jump_pages(int delta) int spine_count = epub ? epub->get_spine_items_count() : 0; //获取章节总数 if (spine_count <= 0) return; - auto at_book_start = [&]() -> bool { + //检查是不是第一页 + auto at_book_start = [&]() -> bool + { return state.current_section == 0 && state.current_page == 0; }; - auto at_book_end = [&]() -> bool { - // 需要知道当前节页数;parser 非空时有效 + //检查是不是最后一页 + auto at_book_end = [&]() -> bool + { if (!parser) return false; return (state.current_section == spine_count - 1) && (state.current_page >= state.pages_in_current_section - 1); }; @@ -238,9 +297,19 @@ void EpubReader::jump_pages(int delta) prev(); if (!parser) { - //空则解析 + //空就解析 parse_and_layout_current_section(); } } } +} + +void EpubReader::overlay_cycle_full_refresh() +{ + screen_cycle_full_refresh_period(); +} + +int EpubReader::overlay_get_full_refresh_value() const +{ + return screen_get_full_refresh_period(); } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index 1ceebe8..355278f 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -17,6 +17,13 @@ class EpubReader bool overlay_active = false; int overlay_selected = 0; // 0..10,共11个 int overlay_jump_acc = 0; // 覆盖层累积跳页值(可为负) + // 覆盖层中心属性模式:触控开关 或 全刷周期 + enum OverlayCenterMode { CENTER_TOUCH = 0, CENTER_FULL_REFRESH = 1 }; + OverlayCenterMode overlay_center_mode = CENTER_TOUCH; + // 触控开关当前状态(由上层同步) + bool overlay_touch_enabled = false; + // 全刷周期索引:0->5, 1->10, 2->20, 3->不刷新(0) + int overlay_fr_idx = 0; void parse_and_layout_current_section(); void render_overlay(); @@ -41,4 +48,12 @@ class EpubReader void overlay_add_jump(int d) { overlay_jump_acc += d; } void overlay_reset_jump() { overlay_jump_acc = 0; } int overlay_get_jump() const { return overlay_jump_acc; } + // 覆盖层中心属性控制 + void overlay_set_center_mode_touch() { overlay_center_mode = CENTER_TOUCH; } + void overlay_set_center_mode_full_refresh() { overlay_center_mode = CENTER_FULL_REFRESH; } + bool overlay_is_center_touch() const { return overlay_center_mode == CENTER_TOUCH; } + void overlay_set_touch_enabled(bool en) { overlay_touch_enabled = en; } + bool overlay_get_touch_enabled() const { return overlay_touch_enabled; } + void overlay_cycle_full_refresh(); + int overlay_get_full_refresh_value() const; }; \ No newline at end of file diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index d58ca7b..1750d5d 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -13,7 +13,34 @@ typedef enum } MainOption; static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” -static int full_refresh_period = 10; // 全刷周期次数,仅用于设置页显示 +// 全刷周期选项:5、10、20、不刷新(0) +static const int kFullRefreshOptions[] = {5, 10, 20, 0}; +static const int kFullRefreshOptionsCount = sizeof(kFullRefreshOptions) / sizeof(kFullRefreshOptions[0]); +static int full_refresh_idx = 1; // 默认10次 + +// 获取当前全刷周期值 +int screen_get_full_refresh_period() +{ + return kFullRefreshOptions[full_refresh_idx]; +} + +// 切换全刷周期(循环) +void screen_cycle_full_refresh_period() +{ + full_refresh_idx = (full_refresh_idx + 1) % kFullRefreshOptionsCount; // ?% 4 +} + +// 设置全刷周期索引 +void screen_set_full_refresh_idx(int idx) +{ + if (idx >= 0 && idx < kFullRefreshOptionsCount) full_refresh_idx = idx; +} + +// 获取当前全刷周期索引 +int screen_get_full_refresh_idx() +{ + return full_refresh_idx; +} // 设置页列表项 typedef enum { SET_TOUCH = 0, SET_TIMEOUT = 1, SET_FULL_REFRESH = 2, SET_CONFIRM = 3 } SettingsItem; @@ -254,7 +281,11 @@ static void render_settings_page(Renderer *renderer) renderer->draw_rect(item_x, y, item_w, item_h, 0); } char buf3[64]; - rt_snprintf(buf3, sizeof(buf3), "全刷周期:%d 次", full_refresh_period); + int fr_val = screen_get_full_refresh_period(); + if (fr_val == 0) + rt_snprintf(buf3, sizeof(buf3), "全刷周期:不刷新"); + else + rt_snprintf(buf3, sizeof(buf3), "全刷周期:%d 次", fr_val); { int t3_w = renderer->get_text_width(buf3); int tx = item_x + (item_w - t3_w) / 2; @@ -345,6 +376,13 @@ bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) render_settings_page(renderer); break; } + if (settings_selected_idx == SET_FULL_REFRESH) + { + // SELECT 在全刷周期项上为加操作(循环) + screen_cycle_full_refresh_period(); + render_settings_page(renderer); + break; + } if (settings_selected_idx == SET_CONFIRM) { // 由上层切回主页面 diff --git a/epdiy-epub/src/epub_screen.h b/epdiy-epub/src/epub_screen.h index c97c3c4..a1b589d 100644 --- a/epdiy-epub/src/epub_screen.h +++ b/epdiy-epub/src/epub_screen.h @@ -21,4 +21,7 @@ void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw); // 设置页面交互与渲染;返回 true 表示确认并退出到主页面 bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw); - +// 切换全刷周期(循环) +void screen_cycle_full_refresh_period(); +// 获取当前全刷周期值 +int screen_get_full_refresh_period(); \ No newline at end of file diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index adaecd9..8e34237 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -117,6 +117,48 @@ void handleEpub(Renderer *renderer, UIAction action) if (reader->is_overlay_active()) { int sel = reader->get_overlay_selected(); + // 1/3:改变中心属性;2:执行当前属性(触控取反 / 全刷周期循环) + if (sel == 0) + { + if(reader->overlay_is_center_touch()) + { + reader->overlay_set_center_mode_full_refresh(); + } + else + { + reader->overlay_set_center_mode_touch(); + } + } + else if (sel == 2) + { + if(reader->overlay_is_center_touch()) + { + reader->overlay_set_center_mode_full_refresh(); + } + else + { + reader->overlay_set_center_mode_touch(); + } + + } + else if (sel == 1) + { + // 中心矩形:根据当前属性执行 + if (reader->overlay_is_center_touch()) + { + bool cur = touch_controls ? touch_controls->isTouchEnabled() : false; + if (touch_controls) + { + touch_controls->setTouchEnable(!cur); + if (!cur) touch_controls->powerOnTouch(); else touch_controls->powerOffTouch(); + } + reader->overlay_set_touch_enabled(!cur); + } + else + { + reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/不刷新 之间循环 + } + } if (sel == 9) //目录 { ui_state = SELECTING_TABLE_CONTENTS; @@ -192,6 +234,10 @@ void handleEpub(Renderer *renderer, UIAction action) case UPGLIDE: // 激活阅读页下半屏覆盖操作层 reader->start_overlay(); + // 默认中心属性为触控开关,初始同步当前触控状态 + reader->overlay_set_center_mode_touch(); + if (touch_controls) + reader->overlay_set_touch_enabled(touch_controls->isTouchEnabled()); break; case NONE: default: From e651519d2939077d7717cb334e1cea2d268221e2 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Thu, 15 Jan 2026 16:33:03 +0800 Subject: [PATCH 05/25] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=85=A8=E5=88=B7=E5=91=A8=E6=9C=9F=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 2 +- epdiy-epub/lib/Epub/EpubList/EpubReader.h | 2 +- .../boards/display_dbi/epd_configs_custom.c | 8 +---- .../boards/display_dbi/epd_configs_r7d005.c | 6 +--- .../boards/display_dbi/epd_configs_yzc085.c | 7 ++-- .../src/boards/display_dbi/epd_display.c | 30 +++++++++++++++-- .../src/boards/display_spi/epd_display.c | 32 +++++++++++++------ epdiy-epub/src/epub_screen.cpp | 9 ++++-- epdiy-epub/src/main.cpp | 5 ++- 9 files changed, 67 insertions(+), 34 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index c885238..90685cb 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -151,7 +151,7 @@ void EpubReader::render_overlay() { int v = overlay_get_full_refresh_value(); if (v == 0) - rt_snprintf(label, cap, "全刷周期:不刷新"); + rt_snprintf(label, cap, "全刷周期:每次"); else rt_snprintf(label, cap, "全刷周期:%d次", v); } diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index 355278f..a5a71b0 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -22,7 +22,7 @@ class EpubReader OverlayCenterMode overlay_center_mode = CENTER_TOUCH; // 触控开关当前状态(由上层同步) bool overlay_touch_enabled = false; - // 全刷周期索引:0->5, 1->10, 2->20, 3->不刷新(0) + // 全刷周期索引:0->5, 1->10, 2->20, 3->每次(0) int overlay_fr_idx = 0; void parse_and_layout_current_section(); diff --git a/epdiy-epub/src/boards/display_dbi/epd_configs_custom.c b/epdiy-epub/src/boards/display_dbi/epd_configs_custom.c index 439b08f..7fd95f0 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_configs_custom.c +++ b/epdiy-epub/src/boards/display_dbi/epd_configs_custom.c @@ -11,9 +11,6 @@ -#define PART_DISP_TIMES 10 // After PART_DISP_TIMES-1 partial refreshes, perform a full refresh once -static int reflesh_times = 0; - void epd_wave_table(void) { @@ -28,14 +25,11 @@ void epd_wave_table(void) uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) { uint32_t frames = 0; - if (reflesh_times % PART_DISP_TIMES == 0) { + if (mode = = EPD_DRAW_MODE_FULL) { frames = waveform_bin_reader_get_frames(temperature, EPD_DRAW_MODE_FULL); - reflesh_times = 0; } else { frames = waveform_bin_reader_get_frames(temperature, EPD_DRAW_MODE_PARTIAL); } - reflesh_times++; - return frames; } diff --git a/epdiy-epub/src/boards/display_dbi/epd_configs_r7d005.c b/epdiy-epub/src/boards/display_dbi/epd_configs_r7d005.c index 8e78e44..733a806 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_configs_r7d005.c +++ b/epdiy-epub/src/boards/display_dbi/epd_configs_r7d005.c @@ -3,8 +3,6 @@ #include "mem_section.h" #include "string.h" #ifdef LCD_USING_EPD_R7D005 -#define PART_DISP_TIMES 10 // After PART_DISP_TIMES-1 partial refreshes, perform a full refresh once -static int reflesh_times = 0; // 8bit lookup table for the current frame (high 4 bits: old data, low 4 bits: new data). // The output is 2-bit data. @@ -83,8 +81,7 @@ void epd_wave_table(void) uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) { const WaveTableEntry *selected_table = NULL; - - if (reflesh_times % PART_DISP_TIMES == 0) { + if (EPD_DRAW_MODE_FULL == mode) { selected_table = &full_wave_table; } else { @@ -95,7 +92,6 @@ uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) selected_table = &full_wave_table; } p_current_wave_from = (const uint8_t *)&selected_table->wave_table[0][0]; - reflesh_times++; return selected_table->frame_count; } diff --git a/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c b/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c index fd9556b..4d6e60e 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c +++ b/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c @@ -3,8 +3,7 @@ #include "mem_section.h" #include "string.h" #if defined(LCD_USING_EPD_YZC085_V100) || defined(LCD_USING_EPD_YZC146_V100) -#define PART_DISP_TIMES 10 // After PART_DISP_TIMES-1 partial refreshes, perform a full refresh once -static int reflesh_times = 0; + // 8bit lookup table for the current frame (high 4 bits: old data, low 4 bits: new data). // The output is 2-bit data. @@ -84,8 +83,7 @@ void epd_wave_table(void) uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) { const WaveTableEntry *wave_table = NULL; - - if (reflesh_times % PART_DISP_TIMES == 0) { + if (EPD_DRAW_MODE_FULL == mode) { wave_table = &full_wave_table; } else { @@ -96,7 +94,6 @@ uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) wave_table = &full_wave_table; } p_current_wave_from = (const uint8_t *)&wave_table->wave_table[0][0]; - reflesh_times++; return wave_table->frame_count; } diff --git a/epdiy-epub/src/boards/display_dbi/epd_display.c b/epdiy-epub/src/boards/display_dbi/epd_display.c index 600b260..8cf0ebf 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_display.c +++ b/epdiy-epub/src/boards/display_dbi/epd_display.c @@ -91,6 +91,9 @@ static uint32_t wait_lcd_ticks; static uint16_t epic_out_buffer_idx = 0; static uint16_t epic_out_buffer[2][LCD_HOR_RES_MAX]; static uint32_t lut_copy_ticks; + +static int g_part_disp_times = 10; // After g_part_disp_times-1 partial refreshes, perform a full refresh once +static int reflesh_times = 0; // Total number of refreshes performed /* Define a mixed grey framebuffer on PSRAM high 4 bits for old pixel and low 4 bits for new pixel in every byte. @@ -525,6 +528,15 @@ void epd_load_and_send_pic(LCDC_HandleTypeDef *hlcdc, uint32_t line_type, const } } +void set_part_disp_times(int val) +{ + g_part_disp_times = val > 0 ? val : 1; + reflesh_times = 1; +} +int get_part_disp_times(void) +{ + return g_part_disp_times; +} L1_RET_CODE_SECT(epd_codes, static void LCD_WriteMultiplePixels(LCDC_HandleTypeDef *hlcdc, const uint8_t *RGBCode, uint16_t Xpos0, uint16_t Ypos0, uint16_t Xpos1, uint16_t Ypos1)) { @@ -554,9 +566,21 @@ L1_RET_CODE_SECT(epd_codes, static void LCD_WriteMultiplePixels(LCDC_HandleTypeD uint8_t temperature = 26; + EpdDrawMode mode; + if (reflesh_times % g_part_disp_times == 0) + { + rt_kprintf("cleared all \n"); + mode = EPD_DRAW_MODE_FULL; + } + else + { + rt_kprintf("executing partial refresh, this is the %dth partial refresh (there are %d partial refreshes left until the next full refresh)\n", + (reflesh_times % g_part_disp_times), + g_part_disp_times - (reflesh_times % g_part_disp_times)); + mode = EPD_DRAW_MODE_PARTIAL; + } - - frame_times = epd_wave_table_get_frames(temperature, EPD_DRAW_MODE_AUTO); + frame_times = epd_wave_table_get_frames(temperature, mode); CopyToMixedGrayBuffer(hlcdc, RGBCode, Xpos0, Ypos0, Xpos1, Ypos1); LOG_I("Convert layer data take=%d(ms) \r\n", rt_tick_get() - start_tick); @@ -664,6 +688,8 @@ L1_RET_CODE_SECT(epd_codes, static void LCD_WriteMultiplePixels(LCDC_HandleTypeD rt_tick_get() - start_tick, wait_lcd_ticks / 240, lut_copy_ticks / 240); + reflesh_times++; + EPD_GMODE_L_hs(); EPD_STV_L_hs(); TPS_WAKEUP_L_hs(); diff --git a/epdiy-epub/src/boards/display_spi/epd_display.c b/epdiy-epub/src/boards/display_spi/epd_display.c index 60860bd..09f0563 100644 --- a/epdiy-epub/src/boards/display_spi/epd_display.c +++ b/epdiy-epub/src/boards/display_spi/epd_display.c @@ -47,10 +47,11 @@ #define REG_VDCS 0x82 #define REG_WRITE_NEW_DATA 0x13 -static int reflesh_times; +static int reflesh_times = 0; static uint8_t current_refresh_mode; static unsigned char LUT_Flag = 0; // LUT切换标志 static unsigned char Var_Temp = 0; // 温度值 +static int g_part_disp_times = 10; // After g_part_disp_times-1 partial refreshes, perform a full refresh once static LCDC_InitTypeDef lcdc_int_cfg = { .lcd_itf = LCDC_INTF_SPI_DCX_1DATA, @@ -79,6 +80,16 @@ static void EPD_LoadLUT(LCDC_HandleTypeDef *hlcdc, uint8_t lut_mode); static rt_sem_t epd_busy_sem = RT_NULL; +void set_part_disp_times(int val) +{ + g_part_disp_times = val > 0 ? val : 1; + reflesh_times = 1; +} +int get_part_disp_times(void) +{ + return g_part_disp_times; +} + static void epd_busy_callback(void *args) { rt_sem_release(epd_busy_sem); @@ -123,18 +134,19 @@ static void EPD_ReadBusy(void) } static uint8_t epd_get_refresh_mode(void) { - uint8_t mode = 2; // 默认局刷(DU模式) - - if (reflesh_times % PART_DISP_TIMES == 0) + uint8_t mode; + if (reflesh_times % g_part_disp_times == 0) { - mode = 1; // 全刷(GC模式) - } - - if (Var_Temp < 0 || Var_Temp > 50) + rt_kprintf("cleared all \n"); + mode = 1; //全刷 + } + else { - mode = 1; + rt_kprintf("executing partial refresh, this is the %dth partial refresh (there are %d partial refreshes left until the next full refresh)\n", + (reflesh_times % g_part_disp_times), + g_part_disp_times - (reflesh_times % g_part_disp_times)); + mode = 2; //局刷 } - current_refresh_mode = mode; return mode; } diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index 1750d5d..fbfdc7e 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -3,6 +3,10 @@ extern TouchControls *touch_controls; +extern "C" +{ + extern void set_part_disp_times(int val); +} // 主页面选项 typedef enum @@ -13,7 +17,7 @@ typedef enum } MainOption; static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” -// 全刷周期选项:5、10、20、不刷新(0) +// 全刷周期选项:5、10、20、每次(0) static const int kFullRefreshOptions[] = {5, 10, 20, 0}; static const int kFullRefreshOptionsCount = sizeof(kFullRefreshOptions) / sizeof(kFullRefreshOptions[0]); static int full_refresh_idx = 1; // 默认10次 @@ -283,7 +287,7 @@ static void render_settings_page(Renderer *renderer) char buf3[64]; int fr_val = screen_get_full_refresh_period(); if (fr_val == 0) - rt_snprintf(buf3, sizeof(buf3), "全刷周期:不刷新"); + rt_snprintf(buf3, sizeof(buf3), "全刷周期:每次"); else rt_snprintf(buf3, sizeof(buf3), "全刷周期:%d 次", fr_val); { @@ -380,6 +384,7 @@ bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) { // SELECT 在全刷周期项上为加操作(循环) screen_cycle_full_refresh_period(); + set_part_disp_times(screen_get_full_refresh_period()); render_settings_page(renderer); break; } diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 8e34237..7d020f9 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -25,6 +25,7 @@ extern "C" { int main(); rt_uint32_t heap_free_size(void); + extern void set_part_disp_times(int val); extern const uint8_t low_power_map[]; extern const uint8_t chargeing_map[]; extern const uint8_t welcome_map[]; @@ -84,6 +85,7 @@ typedef enum { OPTION_ENTER_SETTINGS // 进入设置 -> 打印 3 } MainOption; void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw); + void handleEpub(Renderer *renderer, UIAction action) { if (!reader) @@ -156,7 +158,8 @@ void handleEpub(Renderer *renderer, UIAction action) } else { - reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/不刷新 之间循环 + reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/每次(0) 之间循环 + set_part_disp_times(reader->overlay_get_full_refresh_value()); } } if (sel == 9) //目录 From d1c8625da96de25443c457f3da500f25e1d9f2dc Mon Sep 17 00:00:00 2001 From: smiling boy Date: Fri, 16 Jan 2026 14:05:04 +0800 Subject: [PATCH 06/25] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=EF=BC=9A=20=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E9=98=85=E8=AF=BB=E8=BF=9B=E5=BA=A6=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E9=A1=B5=E9=9D=A2=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E7=BC=BA=E9=99=B7=EF=BC=8C=E5=AE=8C=E5=96=84=E7=BB=A7=E7=BB=AD?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 23 +- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 18 + epdiy-epub/lib/Epub/EpubList/EpubToc.cpp | 21 +- .../boards/controls/SF32_TouchControls.cpp | 59 ---- epdiy-epub/src/epub_screen.cpp | 52 ++- epdiy-epub/src/epub_screen.h | 2 +- epdiy-epub/src/main.cpp | 326 ++++++++++-------- 7 files changed, 262 insertions(+), 239 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index 2853941..0394e57 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -193,12 +193,27 @@ void EpubList::render() renderer->draw_rect(i, ypos + PADDING / 2 + i, renderer->get_page_width() - 2 * i, cell_height - PADDING - 2 * i, 255); } } - // draw the selection box around the current selection - if (state.selected_item == i) + // 当不处于底部按钮选择模式时,绘制列表高亮 + // 若处于底部模式,则擦除列表高亮,避免同时双高亮 + if (!m_bottom_mode) { - for (int i = 0; i < 5; i++) + if (state.selected_item == i) + { + for (int line = 0; line < 5; line++) + { + renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 0); + } + } + } + else + { + if (state.selected_item == i) { - renderer->draw_rect(i, ypos + PADDING / 2 + i, renderer->get_page_width() - 2 * i, cell_height - PADDING - 2 * i, 0); + // 擦除之前的黑色高亮边框 + for (int line = 0; line < 5; line++) + { + renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 255); + } } } ypos += cell_height; diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index 90685cb..ca3c17b 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -58,6 +58,9 @@ void EpubReader::parse_and_layout_current_section() parser = new RubbishHtmlParser(html, strlen(html), base_path); epub_mem_free(html); ulog_d(TAG, "After parse: %d", heap_free_size()); + // 为底部章节进度预留高度 + int reserved_bottom = renderer->get_line_height() + 10; + renderer->set_margin_bottom(reserved_bottom); parser->layout(renderer, epub); ulog_d(TAG, "After layout: %d", heap_free_size()); state.pages_in_current_section = parser->get_page_count(); @@ -104,6 +107,21 @@ void EpubReader::render() parser->render_page(state.current_page, renderer, epub); ulog_d(TAG, "rendered page %d of %d", state.current_page, parser->get_page_count()); ulog_d(TAG, "after render: %d", heap_free_size()); + // 章节进度 + if (state.pages_in_current_section > 0) + { + char buf[32]; + rt_snprintf(buf, sizeof(buf), "%d页/%d页", state.current_page + 1, state.pages_in_current_section); + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + int text_w = renderer->get_text_width(buf); + int text_h = renderer->get_line_height(); + int x = (page_w - text_w) / 2; + int reserved_bottom = renderer->get_line_height() + 4; + const int progress_up = 6; // 上抬 + int y = page_h - text_h - 10 + reserved_bottom - progress_up; + renderer->draw_text(x, y, buf, false, true); + } // 绘制半屏覆盖操作层 if (overlay_active) { diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp index c6c5061..6f08ff5 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp @@ -108,12 +108,25 @@ void EpubToc::render() renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 255); } } - // draw the selection box around the current selection - if (state.selected_item == i) + // 目录页:仅在非底部按钮模式时显示列表高亮;底部模式下擦除列表高亮 + if (!m_bottom_mode) { - for (int line = 0; line < 3; line++) + if (state.selected_item == i) + { + for (int line = 0; line < 3; line++) + { + renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 0); + } + } + } + else + { + if (state.selected_item == i) { - renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 0); + for (int line = 0; line < 3; line++) + { + renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 255); + } } } ypos += cell_height; diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index 9d17027..43f4a5a 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -120,21 +120,6 @@ SF32_TouchControls::SF32_TouchControls(Renderer *renderer, ActionCallback_t on_a void SF32_TouchControls::render(Renderer *renderer) { - renderer->set_margin_top(0); - uint16_t x_offset = 10; - uint16_t x_triangle = x_offset + 70; - // DOWN - renderer->draw_rect(x_offset, 1, ui_button_width, ui_button_height, 0); - renderer->draw_triangle(x_triangle, 20, x_triangle - 5, 6, x_triangle + 5, 6, 0); - // UP - x_offset = ui_button_width + 30; - x_triangle = x_offset + 70; - renderer->draw_rect(x_offset, 1, ui_button_width, ui_button_height, 0); - renderer->draw_triangle(x_triangle, 6, x_triangle - 5, 20, x_triangle + 5, 20, 0); - // SELECT - x_offset = ui_button_width * 2 + 60; - renderer->draw_rect(x_offset, 1, ui_button_width, ui_button_height, 0); - renderer->draw_circle(x_offset + (ui_button_width / 2) + 9, 15, 5, 0); renderer->set_margin_top(35); } @@ -160,49 +145,5 @@ void SF32_TouchControls::powerOnTouch() } void SF32_TouchControls::renderPressedState(Renderer *renderer, UIAction action, bool state) { - renderer->set_margin_top(0); - switch (action) - { - case DOWN: - { - if (state) - { - renderer->fill_triangle(80, 20, 75, 6, 85, 6, 0); - } - else - { - renderer->fill_triangle(81, 19, 76, 7, 86, 7, 255); - } - //renderer->flush_area(76, 6, 10, 15); - break; - } - case UP: - { - if (state) - { - renderer->fill_triangle(220, 6, 220 - 5, 20, 220 + 5, 20, 0); - } - else - { - renderer->fill_triangle(221, 7, 221 - 5, 19, 221 + 5, 19, 255); - } - //renderer->flush_area(195, 225, 10, 15); - } - break; - case SELECT: - { - uint16_t x_circle = (ui_button_width * 2 + 60) + (ui_button_width / 2) + 9; - renderer->fill_circle(x_circle, 15, 5, 0); - //renderer->flush_area(x_circle - 3, 12, 6, 6); - // TODO - this causes a stack overflow when select is picked - // renderPressedState(renderer, last_action, false); - } - break; - case LAST_INTERACTION: - case NONE: - break; - default: - break; - } renderer->set_margin_top(35); } \ No newline at end of file diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index fbfdc7e..b06ae54 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -1,3 +1,5 @@ + +#include "EpubList/EpubList.h" #include "epub_screen.h" #include @@ -8,6 +10,9 @@ extern "C" extern void set_part_disp_times(int val); } +// 最近一次真实打开并阅读的书本索引(由 main.cpp 维护) +extern int g_last_read_index; + // 主页面选项 typedef enum { @@ -50,24 +55,24 @@ int screen_get_full_refresh_idx() typedef enum { SET_TOUCH = 0, SET_TIMEOUT = 1, SET_FULL_REFRESH = 2, SET_CONFIRM = 3 } SettingsItem; static int settings_selected_idx = 0; -// 超时关机:1/3/5/7/10/不关机(0) -static const int kTimeoutOptions[] = {1, 3, 5, 7, 10, 0}; +// 超时关机:5/10/30分钟、1小时、不关机(0) +static const int kTimeoutOptions[] = {5, 10, 30, 60, 0}; // 单位:分钟,0为不关机 static const int kTimeoutOptionsCount = sizeof(kTimeoutOptions) / sizeof(kTimeoutOptions[0]); -static int timeout_shutdown_hours = 5; // 运行时关机超时(小时),0 表示不关机 -static int timeout_idx = -1; // 指向 kTimeoutOptions 的索引 +static int timeout_shutdown_minutes = 30; // 默认30分钟 +static int timeout_idx = -1; // -static int find_timeout_idx(int hours) +static int find_timeout_idx(int minutes) { for (int i = 0; i < kTimeoutOptionsCount; ++i) { - if (kTimeoutOptions[i] == hours) return i; + if (kTimeoutOptions[i] == minutes) return i; } - return 2; // 默认索引:5小时 + return 2; // 默认索引:30分钟 } static void adjust_timeout(bool increase) { - if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_hours); + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_minutes); if (increase) { timeout_idx = (timeout_idx + 1) % kTimeoutOptionsCount; @@ -76,19 +81,19 @@ static void adjust_timeout(bool increase) { timeout_idx = (timeout_idx - 1 + kTimeoutOptionsCount) % kTimeoutOptionsCount; } - timeout_shutdown_hours = kTimeoutOptions[timeout_idx]; + timeout_shutdown_minutes = kTimeoutOptions[timeout_idx]; } -void screen_init(int default_timeout_hours) +void screen_init(int default_timeout_minutes) { - timeout_shutdown_hours = default_timeout_hours; - timeout_idx = find_timeout_idx(timeout_shutdown_hours); + timeout_shutdown_minutes = default_timeout_minutes; + timeout_idx = find_timeout_idx(timeout_shutdown_minutes); } -int screen_get_timeout_shutdown_hours() +int screen_get_timeout_shutdown_minutes() { - if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_hours); - return timeout_shutdown_hours; + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_minutes); + return timeout_shutdown_minutes; } int screen_get_main_selected_option() @@ -133,10 +138,14 @@ static void render_main_page(Renderer *renderer) int mid_w = right_x - margin_side - mid_x; const char *opt_text = NULL; + extern EpubListState epub_list_state; + bool has_continue_reading = (epub_list_state.num_epubs > 0 && g_last_read_index >= 0 && g_last_read_index < epub_list_state.num_epubs); switch (main_option) { case OPTION_OPEN_LIBRARY: opt_text = "打开书库"; break; - case OPTION_CONTINUE_READING: opt_text = "继续阅读"; break; + case OPTION_CONTINUE_READING: + opt_text = has_continue_reading ? "继续阅读" : "无阅读记录"; + break; case OPTION_ENTER_SETTINGS: opt_text = "进入设置"; break; } int opt_w = renderer->get_text_width(opt_text); @@ -208,6 +217,7 @@ static void render_settings_page(Renderer *renderer) // 1) 触控开关 int item_w = page_w - margin_lr * 2 - arrow_col_w * 2; // 为左右箭头列留边 int item_x = margin_lr + arrow_col_w; + if (settings_selected_idx == SET_TOUCH) { const char *lt = "<"; int lt_w = renderer->get_text_width(lt); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); @@ -237,6 +247,7 @@ static void render_settings_page(Renderer *renderer) y += item_h + gap; // 2) 超时关机 + if (settings_selected_idx == SET_TIMEOUT) { const char *lt = "<"; int lt_w = renderer->get_text_width(lt); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); @@ -252,13 +263,17 @@ static void render_settings_page(Renderer *renderer) renderer->draw_rect(item_x, y, item_w, item_h, 0); } char buf2[64]; - if (timeout_shutdown_hours == 0) + if (timeout_shutdown_minutes == 0) { rt_snprintf(buf2, sizeof(buf2), "超时关机:不关机"); } + else if (timeout_shutdown_minutes < 60) + { + rt_snprintf(buf2, sizeof(buf2), "超时关机:%d分钟", timeout_shutdown_minutes); + } else { - rt_snprintf(buf2, sizeof(buf2), "超时关机:%d 小时", timeout_shutdown_hours); + rt_snprintf(buf2, sizeof(buf2), "超时关机:%d小时", timeout_shutdown_minutes / 60); } { int t2_w = renderer->get_text_width(buf2); @@ -270,6 +285,7 @@ static void render_settings_page(Renderer *renderer) y += item_h + gap; // 3) 全刷周期 + if (settings_selected_idx == SET_FULL_REFRESH) { const char *lt = "<"; int lt_w = renderer->get_text_width(lt); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); diff --git a/epdiy-epub/src/epub_screen.h b/epdiy-epub/src/epub_screen.h index a1b589d..d3f1646 100644 --- a/epdiy-epub/src/epub_screen.h +++ b/epdiy-epub/src/epub_screen.h @@ -11,7 +11,7 @@ void screen_init(int default_timeout_hours); // 获取当前关机超时设置(小时;0 表示不关机) -int screen_get_timeout_shutdown_hours(); +int screen_get_timeout_shutdown_minutes(); // 获取当前主页面选中的选项(0: 打开书库, 1: 继续阅读, 2: 进入设置) int screen_get_main_selected_option(); diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 7d020f9..cd3c7ae 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -35,30 +35,28 @@ extern "C" const char *TAG = "main"; -typedef enum -{ +typedef enum { MAIN_PAGE, // 新主页面 - SELECTING_EPUB, // 电子书列表页面(书库) + SELECTING_EPUB, // 电子书列表页面(书库) SELECTING_TABLE_CONTENTS, // 电子书目录页面 - READING_EPUB, // 阅读页面 - SETTINGS_PAGE // 通用功能设置页面 -} UIState; -typedef enum -{ - MAIN_MENU, - WELCOME_PAGE, - LOW_POWER_PAGE, - CHARGING_PAGE -} UIState2; + READING_EPUB, // 阅读页面 + SETTINGS_PAGE, // 通用功能设置页面 + WELCOME_PAGE, // 欢迎页面 + LOW_POWER_PAGE, // 低电量页面 + CHARGING_PAGE, // 充电页面 + SHUTDOWN_PAGE // 关机页面 +} AppUIState; // 默认显示新主页面,而非书库页面 -UIState ui_state = MAIN_PAGE; -UIState2 lowpower_ui_state = MAIN_MENU; +AppUIState ui_state = MAIN_PAGE; // the state data for the epub list and reader EpubListState epub_list_state; // the state data for the epub index list EpubTocState epub_index_state; +// 最近一次真实打开并阅读的书本索引(-1 表示无记录) +int g_last_read_index = -1; + void handleEpub(Renderer *renderer, UIAction action); void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw); void back_to_main_page(); @@ -92,6 +90,8 @@ void handleEpub(Renderer *renderer, UIAction action) { reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); reader->load(); + // 记录最近一次进入阅读的书籍索引 + g_last_read_index = epub_list_state.selected_item; } switch (action) { @@ -165,6 +165,7 @@ void handleEpub(Renderer *renderer, UIAction action) if (sel == 9) //目录 { ui_state = SELECTING_TABLE_CONTENTS; + renderer->set_margin_bottom(0); reader->stop_overlay(); delete reader; reader = nullptr; @@ -187,6 +188,7 @@ void handleEpub(Renderer *renderer, UIAction action) else if (sel == 10) //书库 { ui_state = SELECTING_EPUB; + renderer->set_margin_bottom(0); reader->stop_overlay(); renderer->clear_screen(); delete reader; @@ -219,7 +221,6 @@ void handleEpub(Renderer *renderer, UIAction action) else { // switch back to main screen - ui_state = SELECTING_EPUB; renderer->clear_screen(); // clear the epub reader away delete reader; @@ -229,7 +230,8 @@ void handleEpub(Renderer *renderer, UIAction action) { epub_list = new EpubList(renderer, epub_list_state); } - handleEpubList(renderer, NONE, true); + renderer->set_margin_bottom(0); + back_to_main_page(); return; } @@ -358,6 +360,8 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); reader->set_state_section(contents->get_selected_toc()); reader->load(); + // 记录最近一次进入阅读的书籍索引 + g_last_read_index = epub_list_state.selected_item; delete contents; handleEpub(renderer, NONE); return; @@ -585,10 +589,21 @@ void handleUserInteraction(Renderer *renderer, UIAction ui_action, bool needs_re ui_state = SETTINGS_PAGE; (void)handleSettingsPage(renderer, NONE, true); } - else if (ui_action == SELECT && screen_get_main_selected_option() == 1) //切换到阅读页面 + else if (ui_action == SELECT && screen_get_main_selected_option() == 1) //继续阅读 { - // ui_state = READING_EPUB; - // handleEpub(renderer, NONE); + // 判断是否有继续阅读记录 + if (!(g_last_read_index >= 0 && g_last_read_index < epub_list_state.num_epubs)) { + return; // 无记录,忽略 + } + // 有记录,恢复阅读 + if (reader) { delete reader; reader = nullptr; } + int last_idx = g_last_read_index; + EpubListItem &last_item = epub_list_state.epub_list[last_idx]; + reader = new EpubReader(last_item, renderer); + reader->set_state_section(last_item.current_section); + reader->load(); + ui_state = READING_EPUB; + handleEpub(renderer, NONE); } else if (ui_action == SELECT && screen_get_main_selected_option() == 0) //切换到书库页面 { @@ -620,151 +635,154 @@ void handleUserInteraction(Renderer *renderer, UIAction ui_action, bool needs_re rt_kprintf("Renderer time=%d \r\n", rt_tick_get() - start_tick); } const char* getCurrentPageName() { - switch (lowpower_ui_state) - { - case MAIN_MENU: - return "MAIN_MENU"; - case WELCOME_PAGE: - return "WELCOME_PAGE"; - case LOW_POWER_PAGE: - return "LOW_POWER_PAGE"; - case CHARGING_PAGE: - return "CHARGING_PAGE"; - default: - return "UNKNOWN_PAGE"; - } + switch (ui_state) + { + case MAIN_PAGE: + return "MAIN_PAGE"; + case SELECTING_EPUB: + return "SELECTING_EPUB"; + case SELECTING_TABLE_CONTENTS: + return "SELECTING_TABLE_CONTENTS"; + case READING_EPUB: + return "READING_EPUB"; + case SETTINGS_PAGE: + return "SETTINGS_PAGE"; + case WELCOME_PAGE: + return "WELCOME_PAGE"; + case LOW_POWER_PAGE: + return "LOW_POWER_PAGE"; + case CHARGING_PAGE: + return "CHARGING_PAGE"; + case SHUTDOWN_PAGE: + return "SHUTDOWN_PAGE"; + default: + return "UNKNOWN_PAGE"; + } } //回到主界面接口 void back_to_main_page() -{ - if (ui_state == MAIN_PAGE) - { - rt_kprintf("已经在主页面,无需返回\n"); - return; - } - lowpower_ui_state = MAIN_MENU; - if (ui_state == SELECTING_TABLE_CONTENTS) - { - if (contents) - { - delete contents; - contents = nullptr; - } +{ + if (ui_state == MAIN_PAGE) + { + rt_kprintf("已经在主页面,无需返回\n"); + return; + } + if (ui_state == SELECTING_TABLE_CONTENTS) + { + if (contents) + { + delete contents; + contents = nullptr; } - bool hydrate_success = renderer->hydrate(); - - renderer->reset(); - renderer->set_margin_top(35); - renderer->set_margin_left(10); - renderer->set_margin_right(10); - // 返回新的主页面,不再默认进入书库页面 - ui_state = MAIN_PAGE; - handleUserInteraction(renderer, NONE, true); - - if (battery) - { - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - } - touch_controls->render(renderer); - renderer->flush_display(); + } + bool hydrate_success = renderer->hydrate(); + + renderer->reset(); + renderer->set_margin_top(35); + renderer->set_margin_left(10); + renderer->set_margin_right(10); + // 返回新的主页面,不再默认进入书库页面 + ui_state = MAIN_PAGE; + handleUserInteraction(renderer, NONE, true); + if (battery) + { + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + } + touch_controls->render(renderer); + renderer->flush_display(); } //欢迎页面 void draw_welcome_page(Battery *battery) { - if (strcmp(getCurrentPageName(), "WELCOME_PAGE") == 0) - { - return; - } - lowpower_ui_state = WELCOME_PAGE; - touch_controls->powerOffTouch(); - touch_controls->setTouchEnable(false); - // 设置黑色背景 - renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); - if (battery) { - renderer->set_margin_top(35); - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - } + if (ui_state == WELCOME_PAGE) + { + return; + } + ui_state = WELCOME_PAGE; + // 设置黑色背景 + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); + if (battery) { + renderer->set_margin_top(35); + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + } - const int img_width = 649; - const int img_height = 150; - - int center_x = renderer->get_page_width() / 2; - int center_y = 35 + (renderer->get_page_height() - 35) / 2; - int x_pos = center_x - img_width / 2; - int y_pos = center_y - img_height / 2; - - EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); - fb_renderer->show_img(x_pos, y_pos, img_width, img_height, welcome_map); + const int img_width = 649; + const int img_height = 150; - // 显示 - renderer->flush_display(); - + int center_x = renderer->get_page_width() / 2; + int center_y = 35 + (renderer->get_page_height() - 35) / 2; + int x_pos = center_x - img_width / 2; + int y_pos = center_y - img_height / 2; + + EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); + fb_renderer->show_img(x_pos, y_pos, img_width, img_height, welcome_map); + + // 显示 + renderer->flush_display(); } // 低电量页面 void draw_low_power_page(Battery *battery) { - if (strcmp(getCurrentPageName(), "LOW_POWER_PAGE") == 0) - { - return; - } - lowpower_ui_state = LOW_POWER_PAGE; - - // 设置黑色背景 - renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); - if (battery) { - renderer->set_margin_top(35); - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - } + if (ui_state == LOW_POWER_PAGE) + { + return; + } + ui_state = LOW_POWER_PAGE; + // 设置黑色背景 + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); + if (battery) { + renderer->set_margin_top(35); + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + } - const int img_width = 200; - const int img_height = 200; - - int center_x = renderer->get_page_width() / 2; - int center_y = 35 + (renderer->get_page_height() - 35) / 2; - int x_pos = center_x - img_width / 2; - int y_pos = center_y - img_height / 2; - - EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); - fb_renderer->show_img(x_pos, y_pos, img_width, img_height, low_power_map); - // 显示 - renderer->flush_display(); - + const int img_width = 200; + const int img_height = 200; + + int center_x = renderer->get_page_width() / 2; + int center_y = 35 + (renderer->get_page_height() - 35) / 2; + int x_pos = center_x - img_width / 2; + int y_pos = center_y - img_height / 2; + + EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); + fb_renderer->show_img(x_pos, y_pos, img_width, img_height, low_power_map); + // 显示 + renderer->flush_display(); } //充电页面 void draw_charge_page(Battery *battery) { - if (strcmp(getCurrentPageName(), "CHARGING_PAGE") == 0) - { - return; - } - lowpower_ui_state = CHARGING_PAGE; - // 设置黑色背景 - renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); - if (battery) { - renderer->set_margin_top(35); - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - } + if (ui_state == CHARGING_PAGE) + { + return; + } + ui_state = CHARGING_PAGE; + // 设置黑色背景 + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); + if (battery) { + renderer->set_margin_top(35); + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + } - const int img_width = 200; - const int img_height = 200; - - int center_x = renderer->get_page_width() / 2; - int center_y = 35 + (renderer->get_page_height() - 35) / 2; - int x_pos = center_x - img_width / 2; - int y_pos = center_y - img_height / 2; - - EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); - fb_renderer->show_img(x_pos, y_pos, img_width, img_height, chargeing_map); - // 显示 - renderer->flush_display(); + const int img_width = 200; + const int img_height = 200; + + int center_x = renderer->get_page_width() / 2; + int center_y = 35 + (renderer->get_page_height() - 35) / 2; + int x_pos = center_x - img_width / 2; + int y_pos = center_y - img_height / 2; + + EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); + fb_renderer->show_img(x_pos, y_pos, img_width, img_height, chargeing_map); + // 显示 + renderer->flush_display(); } //关机页面 @@ -873,18 +891,19 @@ void main_task(void *param) // 初始化屏幕模块默认关机超时 screen_init(TIMEOUT_SHUTDOWN_TIME); - while ((screen_get_timeout_shutdown_hours() == 0) || - (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 * screen_get_timeout_shutdown_hours())) // 按设置的小时数无操作自动关机;0为不关机 + while ((rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 * TIMEOUT_SHUTDOWN_TIME)) // 5小时 { - // 检查是否超过5分钟无操作,如果是在欢迎页面、充电页面或低电量页面则不跳转 - if (rt_tick_get_millisecond() - last_user_interaction >= 60 * 1000 *5 && - battery && battery->get_low_power_state() != 1 && - strcmp(getCurrentPageName(), "WELCOME_PAGE") != 0 && - strcmp(getCurrentPageName(), "CHARGING_PAGE") != 0 && - strcmp(getCurrentPageName(), "LOW_POWER_PAGE") != 0) + // 检查是否超过设置分钟无操作,如果是在欢迎页面、充电页面或低电量页面则不跳转 + if (rt_tick_get_millisecond() - last_user_interaction >= 60 * 1000 * screen_get_timeout_shutdown_minutes() && + battery && battery->get_low_power_state() != 1 && + ui_state != WELCOME_PAGE && + ui_state != CHARGING_PAGE && + ui_state != LOW_POWER_PAGE && + screen_get_timeout_shutdown_minutes()) { - draw_welcome_page(battery); + renderer->set_margin_bottom(0); + draw_welcome_page(battery); } uint32_t msg_data; if (rt_mq_recv(ui_queue, &msg_data, sizeof(uint32_t), rt_tick_from_millisecond(60500)) == RT_EOK) //一分钟自动刷一下 @@ -924,6 +943,7 @@ void main_task(void *param) { case MSG_DRAW_LOW_POWER_PAGE: rt_kprintf("low_power\n"); + renderer->set_margin_bottom(0); draw_low_power_page(battery); break; case MSG_DRAW_CHARGE_PAGE: @@ -946,14 +966,13 @@ void main_task(void *param) if (ui_action != NONE) { // 如果之前在欢迎页面,现在需要返回主界面 - if(strcmp(getCurrentPageName(), "WELCOME_PAGE") == 0) + if(ui_state == WELCOME_PAGE) { back_to_main_page(); - last_user_interaction = rt_tick_get_millisecond(); board->sleep_filesystem(); continue; - } + } //rt_kprintf("ui_action = %d\n", ui_action); // something happened! last_user_interaction = rt_tick_get_millisecond(); @@ -987,6 +1006,7 @@ void main_task(void *param) // turn off the filesystem board->stop_filesystem(); // get ready to go to sleep + renderer->set_margin_bottom(0); draw_shutdown_page(); board->prepare_to_sleep(); //ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup()); From 850369333673f9c2ec31e5fbdd6b56fd48a7125f Mon Sep 17 00:00:00 2001 From: smiling boy Date: Fri, 16 Jan 2026 14:14:53 +0800 Subject: [PATCH 07/25] =?UTF-8?q?=E5=BC=80=E5=90=AF=E4=BD=8E=E5=8A=9F?= =?UTF-8?q?=E8=80=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index cd3c7ae..24f875a 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -1023,7 +1023,7 @@ extern "C" int main() { // dump out the epub list state - rt_pm_request(PM_SLEEP_MODE_IDLE); + //rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item); From 8e650b323d8aecd3e250b3028aff7b3cec8af35b Mon Sep 17 00:00:00 2001 From: smiling boy Date: Fri, 16 Jan 2026 18:55:56 +0800 Subject: [PATCH 08/25] =?UTF-8?q?1.=E4=BF=AE=E6=94=B9=E7=B4=AF=E7=A7=AF?= =?UTF-8?q?=E8=B7=B3=E9=A1=B5=E4=BD=BF=E7=94=A8=E9=80=BB=E8=BE=91=202.?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B9=A6=E5=BA=93=E4=BB=A5=E5=8F=8A=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E9=A1=B5=E7=9A=84up=EF=BC=8Cdown=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 34 +++++++- epdiy-epub/lib/Epub/EpubList/EpubReader.h | 9 +- epdiy-epub/src/main.cpp | 95 ++++++++++++++++----- 3 files changed, 114 insertions(+), 24 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index ca3c17b..8e0a4e5 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -103,6 +103,11 @@ void EpubReader::render() { parse_and_layout_current_section(); } + // 确保覆盖层目标页初始与当前页同步(1-based) + if (overlay_active && overlay_target_page < 1) + { + overlay_set_target_page(state.current_page + 1); + } ulog_d(TAG, "rendering page %d of %d", state.current_page, parser->get_page_count()); parser->render_page(state.current_page, renderer, epub); ulog_d(TAG, "rendered page %d of %d", state.current_page, parser->get_page_count()); @@ -178,7 +183,15 @@ void EpubReader::render_overlay() case 2: rt_snprintf(label, cap, ">"); break; case 3: rt_snprintf(label, cap, "-5"); break; case 4: rt_snprintf(label, cap, "-1"); break; - case 5: rt_snprintf(label, cap, "%d", overlay_jump_acc); break; + // 第六格显示:x/n 页 + case 5: + { + int total = state.pages_in_current_section; + if (total <= 0 && parser) total = parser->get_page_count(); + if (total <= 0) total = 1; + rt_snprintf(label, cap, "%d/%d", overlay_target_page, total); + break; + } case 6: rt_snprintf(label, cap, "+1"); break; case 7: rt_snprintf(label, cap, "+5"); break; case 8: rt_snprintf(label, cap, "确认"); break; @@ -330,4 +343,23 @@ void EpubReader::overlay_cycle_full_refresh() int EpubReader::overlay_get_full_refresh_value() const { return screen_get_full_refresh_period(); +} + +void EpubReader::overlay_set_target_page(int p) +{ + if (p < 1) p = 1; + int maxp = state.pages_in_current_section; + if (maxp <= 0 && parser) + { + maxp = parser->get_page_count(); + } + if (maxp <= 0) maxp = 1; + if (p > maxp) p = maxp; + overlay_target_page = p; +} + +void EpubReader::overlay_adjust_target_page(int d) +{ + int p = overlay_target_page + d; + overlay_set_target_page(p); } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index a5a71b0..d65ef72 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -17,6 +17,8 @@ class EpubReader bool overlay_active = false; int overlay_selected = 0; // 0..10,共11个 int overlay_jump_acc = 0; // 覆盖层累积跳页值(可为负) + // 覆盖层目标页(当前章节内的页,1-based) + int overlay_target_page = 1; // 覆盖层中心属性模式:触控开关 或 全刷周期 enum OverlayCenterMode { CENTER_TOUCH = 0, CENTER_FULL_REFRESH = 1 }; OverlayCenterMode overlay_center_mode = CENTER_TOUCH; @@ -38,16 +40,19 @@ class EpubReader void render(); void set_state_section(uint16_t current_section); // 覆盖层控制 - void start_overlay() { overlay_active = true; overlay_selected = 0; overlay_jump_acc = 0; } + void start_overlay() { overlay_active = true; overlay_selected = 0; overlay_jump_acc = 0; overlay_target_page = state.current_page + 1; } void stop_overlay() { overlay_active = false; } bool is_overlay_active() const { return overlay_active; } void overlay_move_left(); void overlay_move_right(); int get_overlay_selected() const { return overlay_selected; } // 覆盖层跳页累积控制 - void overlay_add_jump(int d) { overlay_jump_acc += d; } void overlay_reset_jump() { overlay_jump_acc = 0; } int overlay_get_jump() const { return overlay_jump_acc; } + // 覆盖层目标页控制 + void overlay_set_target_page(int p); + void overlay_adjust_target_page(int d); + int overlay_get_target_page() const { return overlay_target_page; } // 覆盖层中心属性控制 void overlay_set_center_mode_touch() { overlay_center_mode = CENTER_TOUCH; } void overlay_set_center_mode_full_refresh() { overlay_center_mode = CENTER_FULL_REFRESH; } diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 24f875a..4d61b12 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -177,11 +177,11 @@ void handleEpub(Renderer *renderer, UIAction action) } else if (sel == 8) //确认:1.按第六格累积值跳页 { - int delta = reader->overlay_get_jump(); - if (delta != 0) - { - reader->jump_pages(delta); - } + // 跳转到第六格显示的目标页 + int target = reader->overlay_get_target_page(); + if (target < 1) target = 1; + extern EpubListState epub_list_state; + epub_list_state.epub_list[epub_list_state.selected_item].current_page = (uint16_t)(target - 1); reader->overlay_reset_jump(); reader->stop_overlay(); } @@ -202,19 +202,19 @@ void handleEpub(Renderer *renderer, UIAction action) } else if (sel == 3) { - reader->overlay_add_jump(-5); + reader->overlay_adjust_target_page(-5); } else if (sel == 4) { - reader->overlay_add_jump(-1); + reader->overlay_adjust_target_page(-1); } else if (sel == 6) { - reader->overlay_add_jump(1); + reader->overlay_adjust_target_page(1); } else if (sel == 7) { - reader->overlay_add_jump(5); + reader->overlay_adjust_target_page(5); } } @@ -271,15 +271,31 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red case UP: if (toc_bottom_mode) { - toc_bottom_idx = (toc_bottom_idx + 2) % 3; // 左移 + // 底部模式下:UP 向左移动;若已在最左(上一页),则返回当前页目录的最后一项 + if (toc_bottom_idx > 0) + { + toc_bottom_idx--; + } + else + { + int per_page = 6; + int start_idx = (epub_index_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + int count = contents->get_items_count(); + if (end_idx >= count) end_idx = count - 1; + toc_bottom_mode = false; + epub_index_state.selected_item = end_idx; + } } else { + // 若处于当前页第一个条目,UP 切换到底部按钮模式并选择“下一页” int per_page = 6; int start_idx = (epub_index_state.selected_item / per_page) * per_page; if (contents->get_items_count() > 0 && epub_index_state.selected_item == start_idx) { toc_bottom_mode = true; + toc_bottom_idx = 2; // 下一页 } else { @@ -290,7 +306,18 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red case DOWN: if (toc_bottom_mode) { - toc_bottom_idx = (toc_bottom_idx + 1) % 3; // 右移 + // 底部模式下:DOWN 向右移动;若已在最右(下一页),则返回当前页目录的第一项 + if (toc_bottom_idx < 2) + { + toc_bottom_idx++; + } + else + { + int per_page = 6; + int start_idx = (epub_index_state.selected_item / per_page) * per_page; + toc_bottom_mode = false; + epub_index_state.selected_item = start_idx; + } } else { @@ -299,9 +326,11 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red int end_idx = start_idx + per_page - 1; int count = contents->get_items_count(); if (end_idx >= count) end_idx = count - 1; + // 若处于当前页最后一个条目,DOWN 切换到底部按钮模式并选择“上一页” if (count > 0 && epub_index_state.selected_item == end_idx) { toc_bottom_mode = true; + toc_bottom_idx = 0; // 上一页 } else { @@ -338,7 +367,7 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red if (epub_index_state.selected_item < 0) epub_index_state.selected_item = 0; contents->set_needs_redraw(); } - toc_bottom_mode = false; + // 保持底部模式,允许连续翻页 } else if (toc_bottom_idx == 2) { @@ -350,7 +379,7 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red epub_index_state.selected_item = count - 1; contents->set_needs_redraw(); } - toc_bottom_mode = false; + // 保持底部模式,允许连续翻页 } } else @@ -403,8 +432,20 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) case UP: if (library_bottom_mode) { - // UP 表示向左选择 - library_bottom_idx = (library_bottom_idx + 2) % 3; + // 底部模式下:UP 向左移动;若已在最左(上一页),则返回当前页的列表最后一项 + if (library_bottom_idx > 0) + { + library_bottom_idx--; + } + else + { + int per_page = 4; + int start_idx = (epub_list_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + if (end_idx >= epub_list_state.num_epubs) end_idx = epub_list_state.num_epubs - 1; + library_bottom_mode = false; + epub_list_state.selected_item = end_idx; + } } else { @@ -414,6 +455,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) if (epub_list_state.num_epubs > 0 && epub_list_state.selected_item == start_idx) { library_bottom_mode = true; + library_bottom_idx = 2; // 下一页 } else { @@ -424,8 +466,20 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) case DOWN: if (library_bottom_mode) { - // DOWN 表示向右选择 - library_bottom_idx = (library_bottom_idx + 1) % 3; + // 底部模式下:DOWN 向右移动;若已在最右(下一页),则返回当前页的列表第一项 + if (library_bottom_idx < 2) + { + library_bottom_idx++; + } + else + { + int per_page = 4; + int start_idx = (epub_list_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + if (end_idx >= epub_list_state.num_epubs) end_idx = epub_list_state.num_epubs - 1; + library_bottom_mode = false; + epub_list_state.selected_item = start_idx; + } } else { @@ -437,6 +491,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) if (epub_list_state.num_epubs > 0 && epub_list_state.selected_item == end_idx) { library_bottom_mode = true; + library_bottom_idx = 0; // 上一页 } else { @@ -466,8 +521,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) if (epub_list_state.selected_item < 0) epub_list_state.selected_item = 0; epub_list->set_needs_redraw(); } - // 切回条目选择模式 - library_bottom_mode = false; + } else if (library_bottom_idx == 2) { @@ -479,8 +533,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) epub_list_state.selected_item = epub_list_state.num_epubs - 1; epub_list->set_needs_redraw(); } - // 切回条目选择模式 - library_bottom_mode = false; + } } else From db02039c6fdf957f5eb2c0029b705978667b79cf Mon Sep 17 00:00:00 2001 From: minjiezhong Date: Tue, 20 Jan 2026 11:19:36 +0800 Subject: [PATCH 09/25] =?UTF-8?q?1=E3=80=82=E6=B7=BB=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E6=89=80=E6=9C=89=E9=A1=B5=E9=9D=A2=E7=9A=84=E8=A7=A6=E6=8E=A7?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 9 + epdiy-epub/lib/Epub/EpubList/EpubList.h | 1 + epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 2 +- epdiy-epub/lib/Epub/EpubList/EpubToc.cpp | 9 + epdiy-epub/lib/Epub/EpubList/EpubToc.h | 1 + epdiy-epub/lib/Epub/EpubList/State.h | 16 +- epdiy-epub/project/Kconfig.proj | 10 +- epdiy-epub/src/boards/controls/Actions.h | 3 + .../boards/controls/SF32_TouchControls.cpp | 412 +++++++++++++++--- .../src/boards/controls/SF32_TouchControls.h | 9 +- .../src/boards/controls/TouchControls.h | 2 +- epdiy-epub/src/boards/touch/gt967/SConscript | 8 + epdiy-epub/src/boards/touch/gt967/gt967.c | 262 +++++++++++ epdiy-epub/src/boards/touch/gt967/gt967.h | 25 ++ epdiy-epub/src/epub_screen.cpp | 89 +++- epdiy-epub/src/epub_screen.h | 2 +- epdiy-epub/src/main.cpp | 398 ++++++++++------- epdiy-epub/src/type.h | 38 ++ 18 files changed, 1049 insertions(+), 247 deletions(-) create mode 100644 epdiy-epub/src/boards/touch/gt967/SConscript create mode 100644 epdiy-epub/src/boards/touch/gt967/gt967.c create mode 100644 epdiy-epub/src/boards/touch/gt967/gt967.h create mode 100644 epdiy-epub/src/type.h diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index 0394e57..55f42d0 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -36,6 +36,15 @@ void EpubList::prev() state.selected_item--; } +void EpubList::switch_book(int target_index) +{ + if (state.num_epubs == 0) return; + if (target_index < 0 || target_index >= state.num_epubs) + return; + state.selected_item = target_index; +} + + bool EpubList::load(const char *path) { if (state.is_loaded) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.h b/epdiy-epub/lib/Epub/EpubList/EpubList.h index da2c910..f73eec5 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.h @@ -47,4 +47,5 @@ class EpubList void next(); void prev(); void render(); + void switch_book(int target_index); }; \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index 8e0a4e5..201478f 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -337,7 +337,7 @@ void EpubReader::jump_pages(int delta) void EpubReader::overlay_cycle_full_refresh() { - screen_cycle_full_refresh_period(); + screen_cycle_full_refresh_period(true); } int EpubReader::overlay_get_full_refresh_value() const diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp index 6f08ff5..88c45d2 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp @@ -31,6 +31,15 @@ void EpubToc::prev() } state.selected_item = (state.selected_item - 1 + epub->get_toc_items_count()) % epub->get_toc_items_count(); } +void EpubToc::switch_book(int target_index) +{ + if (!epub) + { + load(); + } + state.selected_item = target_index % epub->get_toc_items_count(); + +} bool EpubToc::load() { diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.h b/epdiy-epub/lib/Epub/EpubList/EpubToc.h index 56563f0..4fc09d9 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.h @@ -43,6 +43,7 @@ class EpubToc void next(); void prev(); void render(); + void switch_book(int target_index); void set_needs_redraw() { m_needs_redraw = true; } uint16_t get_selected_toc(); // 目录项总数 diff --git a/epdiy-epub/lib/Epub/EpubList/State.h b/epdiy-epub/lib/Epub/EpubList/State.h index d5e5999..fe8c4a0 100644 --- a/epdiy-epub/lib/Epub/EpubList/State.h +++ b/epdiy-epub/lib/Epub/EpubList/State.h @@ -9,11 +9,11 @@ const int MAX_TITLE_SIZE = 100; // nice and simple state that can be persisted easily typedef struct { - char path[MAX_PATH_SIZE]; - char title[MAX_TITLE_SIZE]; - uint16_t current_section; - uint16_t current_page; - uint16_t pages_in_current_section; + char path[MAX_PATH_SIZE];//存储 EPUB 文件的路径 + char title[MAX_TITLE_SIZE];//存储 EPUB 文件的标题 + uint16_t current_section;//记录当前阅读的章节编号(从0开始) + uint16_t current_page;//记录当前章节内的页码(从0开始) + uint16_t pages_in_current_section;//记录当前章节总共有多少页 } EpubListItem; // this is held in the RTC memory @@ -30,7 +30,7 @@ typedef struct // this is held in the RTC memory typedef struct { - int previous_rendered_page; - int previous_selected_item; - int selected_item; + int previous_rendered_page;//记录当前选中的目录项索引 + int previous_selected_item;//记录上一次选中的目录项索引 + int selected_item;//记录上次渲染的页面索引 } EpubTocState; diff --git a/epdiy-epub/project/Kconfig.proj b/epdiy-epub/project/Kconfig.proj index 67fb310..fc9ba05 100644 --- a/epdiy-epub/project/Kconfig.proj +++ b/epdiy-epub/project/Kconfig.proj @@ -48,26 +48,28 @@ if !BSP_USING_BUILT_LCD config LCD_USING_EPD_CUSTOM bool default n - + config TSC_USING_GT967 + bool + default n choice prompt "Custom LCD driver" default LCD_USING_EPD_YZC085_V100 config LCD_USING_EPD_R7D005 bool "6.0 rect electronic paper display(EPD R7D005_-1.30 1448x1072)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD + select TSC_USING_GT967 if BSP_USING_TOUCHD select LCD_USING_R7D005_130 select BSP_LCDC_USING_EPD_8BIT config LCD_USING_EPD_YZC085_V100 bool "6.0 rect electronic paper display(EPD YZC085_V1.05 1032x758)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD + select TSC_USING_GT967 if BSP_USING_TOUCHD select LCD_USING_YZC085_V100 select BSP_LCDC_USING_EPD_8BIT config LCD_USING_EPD_YZC146_V100 bool "6.0 rect electronic paper display(EPD YZC146_1.00 1032x758)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD + select TSC_TSC_USING_GT967USING_FT5446U_V01 if BSP_USING_TOUCHD select LCD_USING_YZC085_V100 select BSP_LCDC_USING_EPD_8BIT diff --git a/epdiy-epub/src/boards/controls/Actions.h b/epdiy-epub/src/boards/controls/Actions.h index 8e83835..5e22d6b 100644 --- a/epdiy-epub/src/boards/controls/Actions.h +++ b/epdiy-epub/src/boards/controls/Actions.h @@ -9,6 +9,9 @@ typedef enum DOWN, SELECT, UPGLIDE, // 长按触发的上滑操作,用于阅读页半屏操作覆盖 + PREV_OPTION, // 上一选项(用于列表选择) + NEXT_OPTION, // 下一选项(用于列表选择) + SELECT_BOX, // 选择框(用于触控选择) LAST_INTERACTION, MSG_DRAW_LOW_POWER_PAGE, MSG_DRAW_CHARGE_PAGE, diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index 43f4a5a..c8e73c8 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -1,13 +1,31 @@ - #include "SF32_TouchControls.h" #include +#include "Actions.h" #include "epd_driver.h" +#include "type.h" +#include "epub_screen.h" +#include "EpubReader.h" #ifdef BSP_USING_TOUCHD #include "drv_touch.h" #endif volatile int g_touch_last_settings_row = -1; volatile int g_touch_last_settings_dir = 0; +extern int settings_selected_idx; +extern AppUIState ui_state; +extern int book_index; +extern bool library_bottom_mode; +extern int library_bottom_idx; +extern int toc_index; +extern int toc_bottom_idx; +extern bool toc_bottom_mode;//控制目录页面中功能选项的开关 +static int last_clicked_toc_index = -1; // -1 表示没有目录项被选中 +// 添加一个变量来记录上次点击的书籍索引 +static int last_clicked_book_index = -1; // -1 表示没有书籍被选中 +static bool waiting_for_confirmation = false; // 是否正在等待确认 +extern int touch_sel; +extern EpubReader *reader; + rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) { @@ -23,73 +41,362 @@ rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) y = touch_data.x; - if (TOUCH_EVENT_DOWN == touch_data.event) + // if (TOUCH_EVENT_DOWN == touch_data.event) + // rt_kprintf("Touch down [%d,%d]\r\n", x, y); + // else + // rt_kprintf("Touch up [%d,%d]\r\n", x, y); + if (TOUCH_EVENT_DOWN == touch_data.event) + { rt_kprintf("Touch down [%d,%d]\r\n", x, y); + + // 记录按下时的位置 + instance->touch_start_x = x; + instance->touch_start_y = y; + + instance->is_touch_down = true; + + // 处理其他触控逻辑... + } else - rt_kprintf("Touch up [%d,%d]\r\n", x, y); - + { + rt_kprintf("Touch up [%d,%d]\r\n", x, y); + instance->touch_current_x = x; + instance->touch_current_y = y; + + // 检查是否构成向上滑动手势 + if (instance->is_touch_down) { + int y_diff = instance->touch_start_y - touch_data.y; // 注意坐标转换 + int x_diff = abs(instance->touch_start_x - touch_data.x); + rt_kprintf("Touch up diff Y: %d, X: %d\r\n", y_diff, x_diff); + + // 检查时间间隔,防止连续触发 + rt_tick_t current_time = rt_tick_get(); + if(reader->is_overlay_active() == false) + { + if (y_diff > instance->SWIPE_THRESHOLD && y_diff > abs(x_diff)) + { + rt_kprintf("Up swipe detected! Diff: %d\n", y_diff); + + // 发送向上滑动动作 + UIAction action = UPGLIDE; + instance->last_action = action; + instance->on_action(action); + + + // 重置状态 + instance->is_touch_down = false; + return RT_EOK; + } + } + } + + // 重置触摸状态 + instance->is_touch_down = false; + } + // 只处理按下事件,忽略释放事件 + if (TOUCH_EVENT_UP == touch_data.event) { + return RT_EOK; + } UIAction action = NONE; // LOG_I("TOUCH", "Received touch event %d,%d", x, y); // 主页面底部按键区域:左"<"、右">"、中间文本框 - int page_w = instance->renderer->get_page_width(); - int page_h = instance->renderer->get_page_height(); - int margin_side = 10; - int margin_bottom = 60; - int rect_w = 80; - int rect_h = 40; - int y_bottom = page_h - rect_h - margin_bottom; - int left_x = margin_side; - int right_x = page_w - rect_w - margin_side; - int mid_x = left_x + rect_w + margin_side; - int mid_w = right_x - margin_side - mid_x; - - if (x >= left_x && x <= left_x + rect_w && y >= y_bottom && y <= y_bottom + rect_h) +switch (ui_state) +{ + case MAIN_PAGE://主页面 + if (x >= 10 && x <= 80 && y >= 950 && y <= 1000) { rt_kprintf("Touch left < \n"); - action = UP; + action = UP; // 对应 KEY3 功能 } - - else if (x >= right_x && x <= right_x + rect_w && y >= y_bottom && y <= y_bottom + rect_h) + else if (x >= 650 && x <= 750 && y >= 950 && y <= 1000) { - action = DOWN; + action = DOWN; // 对应 KEY1 功能 rt_kprintf("Touch right > \n"); } - - // 设置页面每行左右箭头触控区域(与设置页布局一致) - if (action == NONE) - { - int page_w2 = instance->renderer->get_page_width(); - int margin_lr2 = 6; - int item_h2 = 100; - int gap2 = 54; - int arrow_col_w2 = 40; - int lh2 = instance->renderer->get_line_height(); - int y_start2 = 40 + lh2 + 20; - g_touch_last_settings_row = -1; - g_touch_last_settings_dir = 0; - for (int row = 0; row < 3; ++row) - { - int ry = y_start2 + row * (item_h2 + gap2); - int left_ax = margin_lr2; - int right_ax = page_w2 - margin_lr2 - arrow_col_w2; - if (x >= left_ax && x <= left_ax + arrow_col_w2 && y >= ry && y <= ry + item_h2) - { + else if (x >= 250 && x <= 500 && y >= 950 && y <= 1000) + { + action = SELECT; // 对应 KEY2 功能 + rt_kprintf("Touch middle SELECT \n"); + } + break; + case SELECTING_EPUB://书库页面 + // 检查是否点击了功能控制按钮 + if(x >= 10 && x <= 250 && y >= 920 && y <= 1010) + { + library_bottom_mode = true; + library_bottom_idx = 0; + action = SELECT; + } + else if(x >= 280 && x <= 500 && y >= 920 && y <= 1010) + { + library_bottom_mode = true; + library_bottom_idx = 1; + action = SELECT; + } + else if(x >= 520 && x <= 750 && y >= 920 && y <= 1010) + { + library_bottom_mode = true; + library_bottom_idx = 2; + action = SELECT; + } + else + { + // 处理书籍选择区域 + int clicked_book_index = -1; + + if(x >= 10 && x <= 740 && y >= 60 && y <= 240) + { + clicked_book_index = 0; + } + else if(x >= 10 && x <= 740 && y >= 270 && y <= 450) + { + clicked_book_index = 1; + } + else if(x >= 10 && x <= 740 && y >= 470 && y <= 680) + { + clicked_book_index = 2; + } + else if(x >= 10 && x <= 740 && y >= 700 && y <= 900) + { + clicked_book_index = 3; + } + + // 如果点击了书籍区域 + if(clicked_book_index != -1) + { + // 判断是第一次点击还是第二次点击 + if(waiting_for_confirmation && last_clicked_book_index == clicked_book_index) + { + // 第二次点击:执行打开操作 + book_index = clicked_book_index; + library_bottom_mode = false; + rt_kprintf("Open book%d %d\n", book_index, book_index); + action = SELECT; + + // 重置状态 + waiting_for_confirmation = false; + last_clicked_book_index = -1; + } + else + { + // 第一次点击:选择书籍并等待确认 + book_index = clicked_book_index; + last_clicked_book_index = clicked_book_index; + waiting_for_confirmation = true; + action = SELECT_BOX; + rt_kprintf("Select book%d for confirmation, waiting for second click\n", book_index); + } + } + } + break; + case READING_EPUB: //阅读界面 + //翻页操作 + if(x >= 10 && x <= 200 && y >=10 && y <= 1010 && reader->is_overlay_active() == false) + { action = UP; - g_touch_last_settings_row = row; - g_touch_last_settings_dir = -1; // 左=减 - break; - } - if (x >= right_ax && x <= right_ax + arrow_col_w2 && y >= ry && y <= ry + item_h2) - { + } + else if(x >= 550 && x <= 750 && y >=10 && y <= 1010 && reader->is_overlay_active() == false) + { action = DOWN; - g_touch_last_settings_row = row; - g_touch_last_settings_dir = +1; // 右=加 - break; - } } - } + //点击正文,推出阅读设置 + if(x >= 10 && x <= 750 && y >=10 && y <= 630 && reader->is_overlay_active()) + { + touch_sel = 8; + action = SELECT; + } + + //阅读页面控制区域设置 + if(x >= 10 && x <= 250 && y >= 900 && y <= 960 && reader->is_overlay_active()) + { + touch_sel = 8; + action = SELECT; + } + else if(x >= 280 && x <= 480 && y >= 900 && y <= 960 && reader->is_overlay_active()) + { + touch_sel = 9; + action = SELECT; + } + else if(x >= 520 && x <= 750 && y >= 900 && y <= 960 && reader->is_overlay_active()) + { + touch_sel = 10; + action = SELECT; + } + else if(x >= 10 && x <= 150 && y >= 690 && y <= 750 && reader->is_overlay_active()) + { + touch_sel= 0; + rt_kprintf("Touch middle SELECT %d\n",touch_sel); + action = SELECT; + } + else if(x >= 170 && x <= 570 && y >= 690 && y <= 750 && reader->is_overlay_active()) + { + touch_sel= 1; + rt_kprintf("Touch middle SELECT %d\n",touch_sel); + action = SELECT; + } + else if(x >= 610 && x <= 750 && y >= 690 && y <= 750 && reader->is_overlay_active()) + { + touch_sel= 2; + rt_kprintf("Touch middle SELECT %d\n",touch_sel); + action = SELECT; + } + else if(x >= 10 && x <= 140 && y >= 790 && y <= 850 && reader->is_overlay_active()) + { + touch_sel = 3;//跳转-5页 + action = SELECT; + } + else if(x >= 165 && x <=300 && y >= 790 && y <= 850 && reader->is_overlay_active()) + { + touch_sel = 4;//跳转-1页 + action = SELECT; + } + else if(x >= 480 && x <= 570 && y >= 790 && y <= 850 && reader->is_overlay_active()) + { + touch_sel = 6;//跳转+1页 + action = SELECT; + } + else if(x >= 620 && x <= 750 && y >= 790 && y <= 850 && reader->is_overlay_active()) + { + touch_sel = 7;//跳转5页 + action = SELECT; + } + + break; + case SELECTING_TABLE_CONTENTS: //目录界面 + if(x >= 10 && x <= 250 && y >= 920 && y <= 1010) + { + toc_bottom_mode = true; + toc_bottom_idx = 0; + action = SELECT; + } + else if(x >= 280 && x <= 500 && y >= 920 && y <= 1010) + { + toc_bottom_mode = true; + toc_bottom_idx = 1; + action = SELECT; + } + else if(x >= 520 && x <= 750 && y >= 920 && y <= 1010) + { + toc_bottom_mode = true; + toc_bottom_idx = 2; + action = SELECT; + } + else// 目录项选择区域 + { + int clicked_toc_index = -1; + + if(x >= 10 && x <= 750 && y >= 20 && y <= 170) + { + clicked_toc_index = 0; + } + else if(x >= 10 && x <= 750 && y >= 180 && y <= 310) + { + clicked_toc_index = 1; + } + else if(x >= 10 && x <= 750 && y >= 330 && y <= 450) + { + clicked_toc_index = 2; + } + else if(x >= 10 && x <= 750 && y >= 470 && y <= 590) + { + clicked_toc_index = 3; + } + else if(x >= 10 && x <= 750 && y >= 620 && y <= 750) + { + clicked_toc_index = 4; + } + else if(x >= 10 && x <= 750 && y >= 770 && y <= 890) + { + clicked_toc_index = 5; + } + // 如果点击了目录项区域 + if(clicked_toc_index != -1) + { + // 判断是第一次点击还是第二次点击 + if(waiting_for_confirmation && last_clicked_toc_index == clicked_toc_index) + { + // 第二次点击:执行打开操作 + toc_index = clicked_toc_index; + library_bottom_mode = false; + rt_kprintf("Open book%d %d\n", toc_index, toc_index); + action = SELECT; + + // 重置状态 + waiting_for_confirmation = false; + last_clicked_toc_index = -1; + } + else + { + // 第一次点击:选择目录项并等待确认 + toc_index = clicked_toc_index; + last_clicked_toc_index = clicked_toc_index; + waiting_for_confirmation = true; + action = SELECT_BOX; + } + } + } + + break; + case SETTINGS_PAGE: // 设置页面 + // 设置页面每行左右箭头触控区域(与设置页布局一致) + if (x >= 100 && x <= 650 && y >= 160 && y <= 260) + { + settings_selected_idx = SET_TOUCH; + action = SELECT_BOX; + rt_kprintf("select touch switch\n"); + } + else if (x >= 100 && x <= 650 && y >= 300 && y <= 400) + { + settings_selected_idx = SET_TIMEOUT; + action = SELECT_BOX; + rt_kprintf("select timeout switch\n"); + } + else if (x >= 100 && x <= 650 && y >= 450 && y <= 540) + { + settings_selected_idx = SET_FULL_REFRESH; + action = SELECT_BOX; + rt_kprintf("select full refresh switch \n"); + } + else if (x >= 100 && x <= 650 && y >= 830 && y <= 950) + { + settings_selected_idx = SET_CONFIRM; + action = SELECT; + rt_kprintf("select touch switch\n"); + } + + if(settings_selected_idx == SET_TOUCH && 0<=x && x<= 50 && 160<=y && y<=260) + { + action = SELECT; + } + else if(settings_selected_idx == SET_TOUCH && 700<=x && x<=750 && 160<=y && y<=260) + { + action = SELECT; + } + else if(settings_selected_idx == SET_TIMEOUT && 0 <= x && x<=50 && 300 <= y && y<= 400) + { + action = PREV_OPTION; + rt_kprintf("select timeout Reduce\n"); + } + else if(settings_selected_idx == SET_TIMEOUT && 700<=x && x<=750 && 300<=y && y<= 400) + { + action = NEXT_OPTION; + rt_kprintf("select timeout increase\n"); + } + else if(settings_selected_idx == SET_FULL_REFRESH && 0 <= x && x<= 50 && 450 <= y && y<= 540) + { + action = PREV_OPTION; + } + else if(settings_selected_idx == SET_FULL_REFRESH && 700 <= x && x<= 750 && 450 <= y && y<= 540) + { + action = NEXT_OPTION; + } + break; + +} + + instance->last_action = action; if (action != NONE) @@ -133,7 +440,6 @@ void SF32_TouchControls::powerOffTouch() rt_kprintf("no touch device found\n"); } } - void SF32_TouchControls::powerOnTouch() { if (tp_device) { diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.h b/epdiy-epub/src/boards/controls/SF32_TouchControls.h index d9dfba6..1983a55 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.h +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.h @@ -14,7 +14,14 @@ class SF32_TouchControls : public TouchControls uint8_t ui_button_width = 120; uint8_t ui_button_height = 34; UIAction last_action = NONE; - + // 添加手势检测状态 + bool is_touch_down = false; // 是否正在触摸 + int touch_start_x = 0; // 按下时的 X 坐标 + int touch_start_y = 0; // 按下时的 Y 坐标 + int touch_current_x = 0; // 当前触摸 X 坐标 + int touch_current_y = 0; // 当前触摸 Y 坐标 + // 滑动检测阈值 + static const int SWIPE_THRESHOLD = 50; // 最小滑动距离阈值 public: static rt_err_t tp_rx_indicate(rt_device_t dev, rt_size_t size); diff --git a/epdiy-epub/src/boards/controls/TouchControls.h b/epdiy-epub/src/boards/controls/TouchControls.h index b0c8ba9..cc04d1f 100644 --- a/epdiy-epub/src/boards/controls/TouchControls.h +++ b/epdiy-epub/src/boards/controls/TouchControls.h @@ -8,7 +8,7 @@ class Renderer; class TouchControls { protected: - bool touch_enable = false; + bool touch_enable = 1; public: TouchControls(){}; diff --git a/epdiy-epub/src/boards/touch/gt967/SConscript b/epdiy-epub/src/boards/touch/gt967/SConscript new file mode 100644 index 0000000..6eb93f8 --- /dev/null +++ b/epdiy-epub/src/boards/touch/gt967/SConscript @@ -0,0 +1,8 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd + '/../common', cwd] +group = DefineGroup('Drivers', src, depend = ['TSC_USING_GT967'], CPPPATH = CPPPATH) + +Return('group') diff --git a/epdiy-epub/src/boards/touch/gt967/gt967.c b/epdiy-epub/src/boards/touch/gt967/gt967.c new file mode 100644 index 0000000..1f7672a --- /dev/null +++ b/epdiy-epub/src/boards/touch/gt967/gt967.c @@ -0,0 +1,262 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 SiFli Technologies(Nanjing) Co., Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "board.h" +#include "gt967.h" +#include "drv_touch.h" + +/* Define -------------------------------------------------------------------*/ + +#define DBG_LEVEL DBG_INFO // DBG_ERROR // +#define LOG_TAG "drv.gt967" +#include +#define TP_DEV_ADDR (0x14) +#define TP_TD_STATUS (0x814e) +#define TP_P1_XL (0x8150) +#define TP_P1_XH (0x8151) +#define TP_P1_YL (0x8152) +#define TP_P1_YH (0x8153) + +#define TP_ID_CONTROL (0x8040) + +// rotate to left with 90, 180, 270 +// rotate to left with 360 for mirror +//#define TP_ROTATE_LEFT (90) + +/* function and value-----------------------------------------------------------*/ + +static void correct_pos(touch_msg_t ppos); +static rt_err_t write_reg(uint16_t reg, rt_uint8_t data); +static rt_err_t read_regs(rt_uint16_t reg, rt_uint8_t len, rt_uint8_t *buf); + +static struct rt_i2c_bus_device *ft_bus = NULL; + +static struct touch_drivers driver; + +static rt_err_t write_reg(uint16_t reg, rt_uint8_t data) +{ + rt_int8_t res = 0; + struct rt_i2c_msg msgs; + rt_uint8_t buf[3] = {(uint8_t)(reg >> 8), (uint8_t)reg, data}; + + msgs.addr = TP_DEV_ADDR; /* slave address */ + msgs.flags = RT_I2C_WR; /* write flag */ + msgs.buf = buf; /* Send data pointer */ + msgs.len = 3; + + if (rt_i2c_transfer(ft_bus, &msgs, 1) == 1) + { + res = RT_EOK; + } + else + { + res = -RT_ERROR; + } + return res; +} + +static rt_err_t read_regs(rt_uint16_t reg, rt_uint8_t len, rt_uint8_t *buf) +{ + rt_int8_t res = 0; + struct rt_i2c_msg msgs[2]; + rt_uint8_t reg_w[2] = {(uint8_t)(reg >> 8), (uint8_t)reg}; + + msgs[0].addr = TP_DEV_ADDR; /* Slave address */ + msgs[0].flags = RT_I2C_WR; /* Write flag */ + msgs[0].buf = reg_w; /* Slave register address */ + msgs[0].len = 2; /* Number of bytes sent */ + + msgs[1].addr = TP_DEV_ADDR; /* Slave address */ + msgs[1].flags = RT_I2C_RD; /* Read flag */ + msgs[1].buf = buf; /* Read data pointer */ + msgs[1].len = len; /* Number of bytes read */ + + if (rt_i2c_transfer(ft_bus, msgs, 2) == 2) + { + res = RT_EOK; + } + else + { + res = -RT_ERROR; + } + return res; +} + +static void correct_pos(touch_msg_t ppos) +{ + int temp_x = ppos->x; + ppos->x = ppos->y; + ppos->y = LCD_VER_RES_MAX - (temp_x ) - 1; + + return; +} + +static rt_err_t read_point(touch_msg_t p_msg) +{ + uint8_t buf[80] = {0}; + uint8_t point_num = 0, touch_down = 0; + int ret = 0, retry = 2; + uint8_t reg_value[8] = {0}; + reg_value[0] = 0x81; + reg_value[1] = 0x40; + // reg_value[2] = 0x00; + // reg_value[3] = 0x00; +// rt_kprintf("tp read_point\n"); + read_regs(0x814e, 1, buf); + if ((buf[0] & 0x80) != 0x80) + { + rt_thread_delay(1); //delay 1ms if buffer status is not relay; + LOG_D("tp\n"); + read_regs(0x814e, 1, buf); + } + rt_touch_irq_pin_enable(1); + + point_num = buf[0] & 0x0f; + if (point_num) // the number of touch points + { + p_msg->event = TOUCH_EVENT_DOWN; + } + else + { + p_msg->event = TOUCH_EVENT_UP; + } + read_regs(0x8150, 6, buf); + p_msg->x = buf[0] + ((uint16_t)(buf[1] & 0xff) << 8); + p_msg->y = buf[2] + ((uint16_t)(buf[3] & 0xff) << 8); + correct_pos(p_msg); + LOG_D("piont:%d, x:%d, y:%d,event:%d,byte:%d\n", point_num, p_msg->x, p_msg->y, p_msg->event, buf[4]); + + write_reg(0x814e, 0); //clear tp interrupt + + return RT_EEMPTY; +} + +static void irq_handler(void *arg) +{ + rt_err_t ret = RT_ERROR; + + int value = (int)arg; + LOG_D("gt967 touch_irq_handler\n"); + + rt_touch_irq_pin_enable(0); + + ret = rt_sem_release(driver.isr_sem); + RT_ASSERT(RT_EOK == ret); +} +static rt_err_t init(void) +{ + rt_err_t err; + struct touch_message msg; + + LOG_D("gt967 init"); + + rt_pin_mode(TOUCH_IRQ_PIN, PIN_MODE_OUTPUT); //上电复位I2C地址选择(通过RESET/INT时序选择0x28/0x29的I2C地址) + rt_pin_write(TOUCH_IRQ_PIN, 0); + BSP_TP_Reset(0); + rt_thread_delay(1); + rt_pin_write(TOUCH_IRQ_PIN, 1); + rt_thread_delay(1); + BSP_TP_Reset(1); + rt_thread_delay(8); + rt_pin_write(TOUCH_IRQ_PIN, 0); + rt_thread_delay(60); + + rt_touch_irq_pin_attach(PIN_IRQ_MODE_FALLING, irq_handler, NULL); + rt_touch_irq_pin_enable(1); //Must enable before read I2C + + uint8_t buf[6] = {0}; + read_regs(0x8144, 4, buf); + uint16_t firmware_version; + firmware_version = buf[0] + ((uint16_t)(buf[1] & 0xff) << 8); + + LOG_I("Firmware version = 0x%x(%d)", firmware_version, firmware_version); + + //Soft reset + err = write_reg(TP_ID_CONTROL, 2); + if (RT_EOK != err) + { + LOG_E("SoftReset fail\n"); + return RT_FALSE; + } + err = write_reg(TP_ID_CONTROL, 0); + if (RT_EOK != err) + { + LOG_E("SoftReset stop fail\n"); + return RT_FALSE; + } + + LOG_D("gt967 init OK"); + return RT_EOK; + +} + +static rt_err_t deinit(void) +{ + LOG_D("gt967 deinit"); + + rt_touch_irq_pin_enable(0); + return RT_EOK; + +} + +static rt_bool_t probe(void) +{ + + ft_bus = (struct rt_i2c_bus_device *)rt_device_find(TOUCH_DEVICE_NAME); + if (RT_Device_Class_I2CBUS != ft_bus->parent.type) + { + ft_bus = NULL; + } + if (ft_bus) + { + rt_device_open((rt_device_t)ft_bus, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX); + } + else + { + LOG_I("bus not find\n"); + return RT_FALSE; + } + + { + struct rt_i2c_configuration configuration = + { + .mode = 0, + .addr = 0, + .timeout = 500, + .max_hz = 400000, + }; + + rt_i2c_configure(ft_bus, &configuration); + } + + LOG_I("probe OK"); + + return RT_TRUE; +} + +static struct touch_ops ops = +{ + read_point, + init, + deinit +}; + +static int rt_tp_device_init(void) +{ + + driver.probe = probe; + driver.ops = &ops; + driver.user_data = RT_NULL; + driver.isr_sem = rt_sem_create("gt967", 0, RT_IPC_FLAG_FIFO); + + rt_touch_drivers_register(&driver); + + return 0; + +} +INIT_COMPONENT_EXPORT(rt_tp_device_init); + diff --git a/epdiy-epub/src/boards/touch/gt967/gt967.h b/epdiy-epub/src/boards/touch/gt967/gt967.h new file mode 100644 index 0000000..17dd8f0 --- /dev/null +++ b/epdiy-epub/src/boards/touch/gt967/gt967.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 SiFli Technologies(Nanjing) Co., Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __GT967_H +#define __GT967_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/* type ------------------------------------------------------------------*/ + +/* function ------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif /* __GT911_H */ + diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index b06ae54..523b704 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -2,7 +2,7 @@ #include "EpubList/EpubList.h" #include "epub_screen.h" #include - +#include "type.h" extern TouchControls *touch_controls; extern "C" @@ -16,9 +16,9 @@ extern int g_last_read_index; // 主页面选项 typedef enum { - OPTION_OPEN_LIBRARY = 0, - OPTION_CONTINUE_READING, - OPTION_ENTER_SETTINGS + OPTION_OPEN_LIBRARY = 0, // 打开书库 + OPTION_CONTINUE_READING, // 继续阅读 + OPTION_ENTER_SETTINGS // 进入设置 } MainOption; static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” @@ -34,9 +34,18 @@ int screen_get_full_refresh_period() } // 切换全刷周期(循环) -void screen_cycle_full_refresh_period() +void screen_cycle_full_refresh_period(bool refresh) { - full_refresh_idx = (full_refresh_idx + 1) % kFullRefreshOptionsCount; // ?% 4 + if(refresh) + { + full_refresh_idx = (full_refresh_idx + 1) % kFullRefreshOptionsCount; // ?% 4 + + } + else + { + full_refresh_idx = (full_refresh_idx - 1) % kFullRefreshOptionsCount; // ?% 4 + + } } // 设置全刷周期索引 @@ -51,9 +60,8 @@ int screen_get_full_refresh_idx() return full_refresh_idx; } -// 设置页列表项 -typedef enum { SET_TOUCH = 0, SET_TIMEOUT = 1, SET_FULL_REFRESH = 2, SET_CONFIRM = 3 } SettingsItem; -static int settings_selected_idx = 0; + +int settings_selected_idx = 0; // 超时关机:5/10/30分钟、1小时、不关机(0) static const int kTimeoutOptions[] = {5, 10, 30, 60, 0}; // 单位:分钟,0为不关机 @@ -79,7 +87,7 @@ static void adjust_timeout(bool increase) } else { - timeout_idx = (timeout_idx - 1 + kTimeoutOptionsCount) % kTimeoutOptionsCount; + timeout_idx = (timeout_idx - 1) % kTimeoutOptionsCount; } timeout_shutdown_minutes = kTimeoutOptions[timeout_idx]; } @@ -101,7 +109,7 @@ int screen_get_main_selected_option() return (int)main_option; // 0: 打开书库, 1: 继续阅读, 2: 进入设置 } -// 主页面 +// 绘制主页面 static void render_main_page(Renderer *renderer) { renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); @@ -152,12 +160,12 @@ static void render_main_page(Renderer *renderer) int opt_h = renderer->get_line_height(); renderer->draw_text(mid_x + (mid_w - opt_w) / 2, y + (rect_h - opt_h) / 2, opt_text, false, true); } - +//主界面处理 void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw) { if (needs_redraw || action == NONE) { - render_main_page(renderer); + render_main_page(renderer);//绘制主界面 return; } switch (action) @@ -195,7 +203,7 @@ void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw) } // 设置页面 -static void render_settings_page(Renderer *renderer) +void render_settings_page(Renderer *renderer) { renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); @@ -334,6 +342,7 @@ static void render_settings_page(Renderer *renderer) renderer->draw_text(confirm_x + (confirm_w - c_w) / 2, confirm_y + (confirm_h - c_h) / 2, confirm, false, true); } +// 设置页面交互处理 bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) { // 读取并清除一次性的触控箭头标记,避免后续硬件按键误用 @@ -376,6 +385,56 @@ bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) render_settings_page(renderer); } break; + case SELECT_BOX: + if(settings_selected_idx == SET_TOUCH) + { + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_TIMEOUT) + { + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_FULL_REFRESH) + { + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_CONFIRM) + { + render_settings_page(renderer); + return true; + } + break; + case PREV_OPTION: + if (settings_selected_idx == SET_TIMEOUT) + { + // SELECT 在超时关机项上为加操作(循环) + adjust_timeout(false); + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_FULL_REFRESH) + { + + screen_cycle_full_refresh_period(false); + set_part_disp_times(screen_get_full_refresh_period()); + render_settings_page(renderer); + } + + break; + case NEXT_OPTION: + if (settings_selected_idx == SET_TIMEOUT) + { + // SELECT 在超时关机项上为加操作(循环) + adjust_timeout(true); + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_FULL_REFRESH) + { + + screen_cycle_full_refresh_period(true); + set_part_disp_times(screen_get_full_refresh_period()); + render_settings_page(renderer); + } + break; case SELECT: if (settings_selected_idx == SET_TOUCH) { @@ -399,7 +458,7 @@ bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) if (settings_selected_idx == SET_FULL_REFRESH) { // SELECT 在全刷周期项上为加操作(循环) - screen_cycle_full_refresh_period(); + screen_cycle_full_refresh_period(true); set_part_disp_times(screen_get_full_refresh_period()); render_settings_page(renderer); break; diff --git a/epdiy-epub/src/epub_screen.h b/epdiy-epub/src/epub_screen.h index d3f1646..148141b 100644 --- a/epdiy-epub/src/epub_screen.h +++ b/epdiy-epub/src/epub_screen.h @@ -22,6 +22,6 @@ void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw); // 设置页面交互与渲染;返回 true 表示确认并退出到主页面 bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw); // 切换全刷周期(循环) -void screen_cycle_full_refresh_period(); +void screen_cycle_full_refresh_period(bool refresh); // 获取当前全刷周期值 int screen_get_full_refresh_period(); \ No newline at end of file diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 4d61b12..9f00ed6 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -5,13 +5,14 @@ #include "EpubList/EpubToc.h" #include #include "boards/Board.h" +#include "boards/controls/Actions.h" #include "boards/controls/SF32_TouchControls.h" #include "epub_screen.h" #include "boards/SF32PaperRenderer.h" #include "gui_app_pm.h" #include "bf0_pm.h" #include "epd_driver.h" - +#include "type.h" #undef LOG_TAG #undef DBG_LEVEL #define DBG_LEVEL DBG_LOG //DBG_INFO // @@ -32,20 +33,9 @@ extern "C" extern const uint8_t shutdown_map[]; } - const char *TAG = "main"; -typedef enum { - MAIN_PAGE, // 新主页面 - SELECTING_EPUB, // 电子书列表页面(书库) - SELECTING_TABLE_CONTENTS, // 电子书目录页面 - READING_EPUB, // 阅读页面 - SETTINGS_PAGE, // 通用功能设置页面 - WELCOME_PAGE, // 欢迎页面 - LOW_POWER_PAGE, // 低电量页面 - CHARGING_PAGE, // 充电页面 - SHUTDOWN_PAGE // 关机页面 -} AppUIState; + // 默认显示新主页面,而非书库页面 AppUIState ui_state = MAIN_PAGE; @@ -62,7 +52,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw); void back_to_main_page(); static EpubList *epub_list = nullptr; -static EpubReader *reader = nullptr; +EpubReader *reader = nullptr; static EpubToc *contents = nullptr; static bool charge_full = false; Battery *battery = nullptr; @@ -71,9 +61,18 @@ Renderer *renderer = nullptr; TouchControls *touch_controls = nullptr; // 书库页底部按钮选择状态 -static bool library_bottom_mode = false; // 是否处于底部三按钮选择模式 -static int library_bottom_idx = 1; // 当前底部按钮索引:0上一页,1主页面,2下一页 - +bool library_bottom_mode = false; // 是否处于底部三按钮选择模式 +int library_bottom_idx = 1; // 当前底部按钮索引:0上一页,1主页面,2下一页 +int book_index;//用于记录电子书触控选择 +int current_page; // 当前页面 +int start_index; // 当前页起始索引 +// 计算全局索引 = 页起始索引 + 页内偏移 +int global_index; +bool toc_bottom_mode = false; +int toc_index;//用于记录目录触控选择 +int toc_bottom_idx = 1; // 0:上一页,1:主页面,2:下一页 +int sel; +int touch_sel; rt_mq_t ui_queue = RT_NULL; // 主页面选项 @@ -86,169 +85,178 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red void handleEpub(Renderer *renderer, UIAction action) { - if (!reader) - { - reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); - reader->load(); - // 记录最近一次进入阅读的书籍索引 - g_last_read_index = epub_list_state.selected_item; - } - switch (action) - { - case UP: - if (reader->is_overlay_active()) - { - reader->overlay_move_left(); - } - else - { - reader->prev(); - } - break; - case DOWN: - if (reader->is_overlay_active()) + if (!reader) { - reader->overlay_move_right(); - } - else - { - reader->next(); + reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); + reader->load(); + // 记录最近一次进入阅读的书籍索引 + g_last_read_index = epub_list_state.selected_item; } - break; - case SELECT: - if (reader->is_overlay_active()) + + switch (action) { - int sel = reader->get_overlay_selected(); - // 1/3:改变中心属性;2:执行当前属性(触控取反 / 全刷周期循环) - if (sel == 0) - { - if(reader->overlay_is_center_touch()) + case UP: + if (reader->is_overlay_active()) { - reader->overlay_set_center_mode_full_refresh(); + reader->overlay_move_left(); } else { - reader->overlay_set_center_mode_touch(); + reader->prev(); } - } - else if (sel == 2) - { - if(reader->overlay_is_center_touch()) + break; + case DOWN: + if (reader->is_overlay_active()) { - reader->overlay_set_center_mode_full_refresh(); + reader->overlay_move_right(); } else { - reader->overlay_set_center_mode_touch(); + reader->next(); } - - } - else if (sel == 1) - { - // 中心矩形:根据当前属性执行 - if (reader->overlay_is_center_touch()) + break; + case SELECT: + if (reader->is_overlay_active()) { - bool cur = touch_controls ? touch_controls->isTouchEnabled() : false; - if (touch_controls) - { - touch_controls->setTouchEnable(!cur); - if (!cur) touch_controls->powerOnTouch(); else touch_controls->powerOffTouch(); - } - reader->overlay_set_touch_enabled(!cur); + int sel = reader->get_overlay_selected(); + // 1/3:改变中心属性;2:执行当前属性(触控取反 / 全刷周期循环) + if(touch_sel >=0 && touch_sel <=10) + { + sel = -1; + } + if (sel == 0 || touch_sel == 0) + { + if(reader->overlay_is_center_touch()) + { + reader->overlay_set_center_mode_full_refresh(); + } + else + { + reader->overlay_set_center_mode_touch(); + } + } + else if (sel == 2 || touch_sel == 2) + { + if(reader->overlay_is_center_touch()) + { + reader->overlay_set_center_mode_full_refresh(); + } + else + { + reader->overlay_set_center_mode_touch(); + } + } + else if (sel == 1 || touch_sel == 1) + { + // 中心矩形:根据当前属性执行 + if (reader->overlay_is_center_touch()) + { + bool cur = touch_controls ? touch_controls->isTouchEnabled() : false; + if (touch_controls) + { + touch_controls->setTouchEnable(!cur); + if (!cur) touch_controls->powerOnTouch(); else touch_controls->powerOffTouch(); + } + reader->overlay_set_touch_enabled(!cur); + } + else + { + reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/每次(0) 之间循环 + set_part_disp_times(reader->overlay_get_full_refresh_value()); + } + } + if (sel == 9 || touch_sel == 9) //目录 + { + ui_state = SELECTING_TABLE_CONTENTS; + renderer->set_margin_bottom(0); + reader->stop_overlay(); + delete reader; + reader = nullptr; + contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); + contents->load(); + contents->set_needs_redraw(); + handleEpubTableContents(renderer, NONE, true); + touch_sel = -1; + return; + } + else if (sel == 8 || touch_sel == 8) //确认:1.按第六格累积值跳页 + { + // 跳转到第六格显示的目标页 + int target = reader->overlay_get_target_page(); + if (target < 1) target = 1; + extern EpubListState epub_list_state; + epub_list_state.epub_list[epub_list_state.selected_item].current_page = (uint16_t)(target - 1); + reader->overlay_reset_jump(); + reader->stop_overlay(); + } + else if (sel == 10 || touch_sel == 10) //书库 + { + ui_state = SELECTING_EPUB; + renderer->set_margin_bottom(0); + reader->stop_overlay(); + renderer->clear_screen(); + delete reader; + reader = nullptr; + if (!epub_list) + { + epub_list = new EpubList(renderer, epub_list_state); + } + handleEpubList(renderer, NONE, true); + touch_sel = -1; + return; + } + else if (sel == 3 || touch_sel == 3) + { + reader->overlay_adjust_target_page(-5); + } + else if (sel == 4 || touch_sel == 4) + { + reader->overlay_adjust_target_page(-1); + } + else if (sel == 6 || touch_sel == 6) + { + reader->overlay_adjust_target_page(1); + } + else if (sel == 7 || touch_sel == 7) + { + reader->overlay_adjust_target_page(5); + } + touch_sel = -1; } else { - reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/每次(0) 之间循环 - set_part_disp_times(reader->overlay_get_full_refresh_value()); + // switch back to main screen + renderer->clear_screen(); + // clear the epub reader away + delete reader; + reader = nullptr; + // force a redraw + if (!epub_list) + { + epub_list = new EpubList(renderer, epub_list_state); + } + renderer->set_margin_bottom(0); + back_to_main_page(); + + return; } - } - if (sel == 9) //目录 - { - ui_state = SELECTING_TABLE_CONTENTS; - renderer->set_margin_bottom(0); - reader->stop_overlay(); - delete reader; - reader = nullptr; - contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); - contents->load(); - contents->set_needs_redraw(); - handleEpubTableContents(renderer, NONE, true); - return; - } - else if (sel == 8) //确认:1.按第六格累积值跳页 - { - // 跳转到第六格显示的目标页 - int target = reader->overlay_get_target_page(); - if (target < 1) target = 1; - extern EpubListState epub_list_state; - epub_list_state.epub_list[epub_list_state.selected_item].current_page = (uint16_t)(target - 1); - reader->overlay_reset_jump(); - reader->stop_overlay(); - } - else if (sel == 10) //书库 - { - ui_state = SELECTING_EPUB; - renderer->set_margin_bottom(0); - reader->stop_overlay(); - renderer->clear_screen(); - delete reader; - reader = nullptr; - if (!epub_list) - { - epub_list = new EpubList(renderer, epub_list_state); + break; + case UPGLIDE: + // 激活阅读页下半屏覆盖操作层 + // 防止重复激活 + if (!reader->is_overlay_active()) { + reader->start_overlay(); + // 默认中心属性为触控开关,初始同步当前触控状态 + reader->overlay_set_center_mode_touch(); + if (touch_controls) + reader->overlay_set_touch_enabled(touch_controls->isTouchEnabled()); } - handleEpubList(renderer, NONE, true); - return; - } - else if (sel == 3) - { - reader->overlay_adjust_target_page(-5); - } - else if (sel == 4) - { - reader->overlay_adjust_target_page(-1); - } - else if (sel == 6) - { - reader->overlay_adjust_target_page(1); - } - else if (sel == 7) - { - reader->overlay_adjust_target_page(5); - } - - } - else - { - // switch back to main screen - renderer->clear_screen(); - // clear the epub reader away - delete reader; - reader = nullptr; - // force a redraw - if (!epub_list) - { - epub_list = new EpubList(renderer, epub_list_state); - } - renderer->set_margin_bottom(0); - back_to_main_page(); - - return; + break; + case NONE: + default: + break; } - break; - case UPGLIDE: - // 激活阅读页下半屏覆盖操作层 - reader->start_overlay(); - // 默认中心属性为触控开关,初始同步当前触控状态 - reader->overlay_set_center_mode_touch(); - if (touch_controls) - reader->overlay_set_touch_enabled(touch_controls->isTouchEnabled()); - break; - case NONE: - default: - break; - } - reader->render(); + reader->render(); } //目录页的处理 void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw) @@ -259,8 +267,7 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red contents->set_needs_redraw(); contents->load(); } - static bool toc_bottom_mode = false; - static int toc_bottom_idx = 1; // 0:上一页,1:主页面,2:下一页 + if (needs_redraw) { toc_bottom_mode = false; @@ -338,6 +345,44 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red } } break; + case SELECT_BOX: + // 计算当前页面相关信息 + current_page = epub_index_state.selected_item / 6; // 每页6个目录项 + start_index = current_page * 6; // 当前页起始索引 + // 计算全局索引 = 页起始索引 + 页内偏移 + global_index = start_index + toc_index; + // 边界检查:确保点击的目录项存在 + if (global_index < contents->get_items_count() && contents->get_items_count() > 0) + { + // 更新选中的目录项 + epub_index_state.selected_item = global_index; + + // 根据toc_index确定点击的是哪个位置的目录项(0-5) + switch(toc_index) + { + case 0: + contents->switch_book(global_index); + break; + case 1: + contents->switch_book(global_index); + break; + case 2: + contents->switch_book(global_index); + break; + case 3: + contents->switch_book(global_index); + break; + case 4: + contents->switch_book(global_index); + break; + case 5: + contents->switch_book(global_index); + break; + default: + break; + } + } + break; case SELECT: if (toc_bottom_mode) { @@ -499,6 +544,33 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) } } break; + case SELECT_BOX: + current_page = epub_list_state.selected_item / 4; // 当前页面 + start_index = current_page * 4; // 当前页起始索引 + // 计算全局索引 = 页起始索引 + 页内偏移 + global_index = start_index + book_index; + // 边界检查 + if (global_index < epub_list_state.num_epubs) + { + + if(book_index == 0) + { + epub_list->switch_book(global_index); + } + else if(book_index == 1) + { + epub_list->switch_book(global_index); + } + else if(book_index == 2) + { + epub_list->switch_book(global_index); + } + else if(book_index == 3) + { + epub_list->switch_book(global_index); + } + } + break; case SELECT: if (library_bottom_mode) { @@ -1076,7 +1148,7 @@ extern "C" int main() { // dump out the epub list state - //rt_pm_request(PM_SLEEP_MODE_IDLE); + rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item); diff --git a/epdiy-epub/src/type.h b/epdiy-epub/src/type.h new file mode 100644 index 0000000..820485d --- /dev/null +++ b/epdiy-epub/src/type.h @@ -0,0 +1,38 @@ +#ifndef TYPES_H +#define TYPES_H + +// typedef enum { +// MAIN_PAGE, +// SELECTING_EPUB, +// SELECTING_TABLE_CONTENTS, +// READING_EPUB, +// SETTINGS_PAGE +// } UIState; + +// typedef enum { +// MAIN_MENU, +// WELCOME_PAGE, +// LOW_POWER_PAGE, +// CHARGING_PAGE +// } UIState2; + +// 设置页列表项 +typedef enum { + SET_TOUCH = 0, + SET_TIMEOUT = 1, + SET_FULL_REFRESH = 2, + SET_CONFIRM = 3 +} SettingsItem; + +typedef enum { + MAIN_PAGE, // 新主页面 + SELECTING_EPUB, // 电子书列表页面(书库) + SELECTING_TABLE_CONTENTS, // 电子书目录页面 + READING_EPUB, // 阅读页面 + SETTINGS_PAGE, // 通用功能设置页面 + WELCOME_PAGE, // 欢迎页面 + LOW_POWER_PAGE, // 低电量页面 + CHARGING_PAGE, // 充电页面 + SHUTDOWN_PAGE // 关机页面 +} AppUIState; +#endif \ No newline at end of file From 892caf7b1f1aafc3b8f09aca4314b32621fc1ec4 Mon Sep 17 00:00:00 2001 From: minjiezhong Date: Thu, 22 Jan 2026 10:48:45 +0800 Subject: [PATCH 10/25] =?UTF-8?q?1.=E8=A7=A3=E5=86=B3=E4=BA=86=E4=B9=A6?= =?UTF-8?q?=E5=BA=93=E9=A1=B5=E9=9D=A2=E3=80=81=E7=9B=AE=E5=BD=95=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E7=82=B9=E5=87=BB=E4=B8=8B=E4=B8=80=E9=A1=B5=EF=BC=8C?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E4=B9=A6=E7=B1=8D=E5=92=8C=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E5=A4=B1=E6=95=88=E7=9A=84bug=202.=E8=A7=A3=E5=86=B3=E4=BA=86?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E9=A1=B5=E9=9D=A2=E7=82=B9=E5=87=BB=E5=8F=B3?= =?UTF-8?q?=E4=B8=8B=E8=A7=92=E4=BC=9A=E5=87=BA=E7=8E=B0=E5=94=A4=E9=86=92?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E8=AE=BE=E7=BD=AE=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../boards/controls/SF32_TouchControls.cpp | 37 +++--- .../src/boards/controls/SF32_TouchControls.h | 3 - epdiy-epub/src/main.cpp | 109 +++++++++++------- 3 files changed, 89 insertions(+), 60 deletions(-) diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index c8e73c8..673c99a 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -26,12 +26,15 @@ static bool waiting_for_confirmation = false; // 是否正在等待确认 extern int touch_sel; extern EpubReader *reader; +static const int SWIPE_THRESHOLD = 100; // 最小滑动距离阈值 +static bool is_touch_started = false; // 全局或类成员变量 rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) { SF32_TouchControls *instance = static_cast (dev->user_data); struct touch_message touch_data; rt_uint16_t x,y; + int i = 0;//用于记录第一次按下的情况 /*Read touch point data*/ rt_device_read(dev, 0, &touch_data, 1); @@ -50,48 +53,50 @@ rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) rt_kprintf("Touch down [%d,%d]\r\n", x, y); // 记录按下时的位置 - instance->touch_start_x = x; - instance->touch_start_y = y; + if (!is_touch_started) // 只允许第一次触发 + { + instance->touch_start_y = y; + rt_kprintf("Touch start\r\n"); + is_touch_started = true; + } instance->is_touch_down = true; - + instance->touch_current_y = 0; // 处理其他触控逻辑... } else { rt_kprintf("Touch up [%d,%d]\r\n", x, y); - instance->touch_current_x = x; instance->touch_current_y = y; // 检查是否构成向上滑动手势 - if (instance->is_touch_down) { - int y_diff = instance->touch_start_y - touch_data.y; // 注意坐标转换 - int x_diff = abs(instance->touch_start_x - touch_data.x); - rt_kprintf("Touch up diff Y: %d, X: %d\r\n", y_diff, x_diff); + if (instance->is_touch_down) + { + int y_diff = instance->touch_start_y - instance->touch_current_y; // 注意坐标转换 + rt_kprintf("Touch up diff Y: %d\r\n", y_diff); - // 检查时间间隔,防止连续触发 - rt_tick_t current_time = rt_tick_get(); if(reader->is_overlay_active() == false) { - if (y_diff > instance->SWIPE_THRESHOLD && y_diff > abs(x_diff)) + if (y_diff > SWIPE_THRESHOLD) { rt_kprintf("Up swipe detected! Diff: %d\n", y_diff); // 发送向上滑动动作 UIAction action = UPGLIDE; instance->last_action = action; - instance->on_action(action); - + instance->on_action(action); - // 重置状态 - instance->is_touch_down = false; - return RT_EOK; } } + + } + // 清空坐标值,避免下次误用 + instance->touch_start_y = 0; // 重置触摸状态 instance->is_touch_down = false; + is_touch_started = false; } // 只处理按下事件,忽略释放事件 diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.h b/epdiy-epub/src/boards/controls/SF32_TouchControls.h index 1983a55..0ad4b12 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.h +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.h @@ -16,12 +16,9 @@ class SF32_TouchControls : public TouchControls UIAction last_action = NONE; // 添加手势检测状态 bool is_touch_down = false; // 是否正在触摸 - int touch_start_x = 0; // 按下时的 X 坐标 int touch_start_y = 0; // 按下时的 Y 坐标 - int touch_current_x = 0; // 当前触摸 X 坐标 int touch_current_y = 0; // 当前触摸 Y 坐标 // 滑动检测阈值 - static const int SWIPE_THRESHOLD = 50; // 最小滑动距离阈值 public: static rt_err_t tp_rx_indicate(rt_device_t dev, rt_size_t size); diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 9f00ed6..fe453bb 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -346,6 +346,11 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red } break; case SELECT_BOX: + // 如果在底部模式,先退出底部模式 + if (toc_bottom_mode) + { + toc_bottom_mode = false; + } // 计算当前页面相关信息 current_page = epub_index_state.selected_item / 6; // 每页6个目录项 start_index = current_page * 6; // 当前页起始索引 @@ -403,28 +408,37 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red handleEpubList(renderer, NONE, true); return; } - else if (toc_bottom_idx == 0) + else if (toc_bottom_idx == 0) // 上一页 { - // 上一页 if (current_page > 0) { - epub_index_state.selected_item -= per_page; - if (epub_index_state.selected_item < 0) epub_index_state.selected_item = 0; + // 计算新页面(上一页) + int new_page = current_page - 1; + // 将选中项设置为新页面的第一项 + epub_index_state.selected_item = new_page * per_page; + if (epub_index_state.selected_item < 0) + epub_index_state.selected_item = 0; + + // 退出底部选择模式,回到列表选择状态 + toc_bottom_mode = false; contents->set_needs_redraw(); } - // 保持底部模式,允许连续翻页 } - else if (toc_bottom_idx == 2) + else if (toc_bottom_idx == 2) // 下一页 { - // 下一页 if (current_page < max_page) { - epub_index_state.selected_item += per_page; + // 计算新页面(下一页) + int new_page = current_page + 1; + // 将选中项设置为新页面的第一项 + epub_index_state.selected_item = new_page * per_page; if (epub_index_state.selected_item >= count) - epub_index_state.selected_item = count - 1; + epub_index_state.selected_item = ((count - 1) / per_page) * per_page; // 确保在最后一页的第一项 + + // 退出底部选择模式,回到列表选择状态 + toc_bottom_mode = false; contents->set_needs_redraw(); } - // 保持底部模式,允许连续翻页 } } else @@ -545,6 +559,10 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) } break; case SELECT_BOX: + // 如果在底部模式,先退出底部模式 + if (library_bottom_mode) { + library_bottom_mode = false; + } current_page = epub_list_state.selected_item / 4; // 当前页面 start_index = current_page * 4; // 当前页起始索引 // 计算全局索引 = 页起始索引 + 页内偏移 @@ -572,44 +590,53 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) } break; case SELECT: - if (library_bottom_mode) - { + if (library_bottom_mode) + { int per_page = 4; int current_page = epub_list_state.selected_item / per_page; int max_page = (epub_list_state.num_epubs == 0) ? 0 : ( (epub_list_state.num_epubs - 1) / per_page ); if (library_bottom_idx == 1) { - // 主页面:返回主页面 - rt_kprintf("从书库页返回主页面\n"); - back_to_main_page(); - return; + // 主页面:返回主页面 + rt_kprintf("从书库页返回主页面\n"); + back_to_main_page(); + return; } - else if (library_bottom_idx == 0) + else if (library_bottom_idx == 0) // 上一页 { - // 上一页 - if (current_page > 0) - { - epub_list_state.selected_item -= per_page; - if (epub_list_state.selected_item < 0) epub_list_state.selected_item = 0; - epub_list->set_needs_redraw(); - } - + if (current_page > 0) + { + // 计算新页面(上一页) + int new_page = current_page - 1; + // 将选中项设置为新页面的第一本书 + epub_list_state.selected_item = new_page * per_page; + if (epub_list_state.selected_item < 0) + epub_list_state.selected_item = 0; + + // 退出底部选择模式,回到列表选择状态 + library_bottom_mode = false; + epub_list->set_needs_redraw(); + } } - else if (library_bottom_idx == 2) + else if (library_bottom_idx == 2) // 下一页 { - // 下一页 - if (current_page < max_page) - { - epub_list_state.selected_item += per_page; - if (epub_list_state.selected_item >= epub_list_state.num_epubs) - epub_list_state.selected_item = epub_list_state.num_epubs - 1; - epub_list->set_needs_redraw(); - } - + if (current_page < max_page) + { + // 计算新页面(下一页) + int new_page = current_page + 1; + // 将选中项设置为新页面的第一本书 + epub_list_state.selected_item = new_page * per_page; + if (epub_list_state.selected_item >= epub_list_state.num_epubs) + epub_list_state.selected_item = ((epub_list_state.num_epubs - 1) / per_page) * per_page; // 确保在最后一页的第一本书 + + // 退出底部选择模式,回到列表选择状态 + library_bottom_mode = false; + epub_list->set_needs_redraw(); + } } - } - else - { + } + else + { // 进入目录选择页面 ui_state = SELECTING_TABLE_CONTENTS; contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); @@ -617,8 +644,8 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) contents->set_needs_redraw(); handleEpubTableContents(renderer, NONE, true); return; - } - break; + } + break; case NONE: default: // nothing to do @@ -1148,7 +1175,7 @@ extern "C" int main() { // dump out the epub list state - rt_pm_request(PM_SLEEP_MODE_IDLE); + //rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item); From aa413336237cfb7b5fc739f287acbfccb69e4c4c Mon Sep 17 00:00:00 2001 From: smiling boy Date: Fri, 23 Jan 2026 19:05:40 +0800 Subject: [PATCH 11/25] =?UTF-8?q?=E6=96=B0=E5=BB=BA=E6=9D=BF=E5=AD=90base?= =?UTF-8?q?=E4=B8=8E1.2=E7=9A=84board=EF=BC=8C1.1=E4=B8=8E1.2=E5=A4=8D?= =?UTF-8?q?=E7=94=A8base?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/sf32-oed-epd_v12_hcpu/link.lds | 556 ++++++++++++++++++ .../project/sf32-oed-epd_v12_hcpu/link.sct | 157 +++++ epdiy-epub/sf32-oed-epd_base/Kconfig.board | 86 +++ epdiy-epub/sf32-oed-epd_base/SConscript | 14 + .../battery_table.c | 0 .../board.h | 0 .../bsp_board.h | 0 .../bsp_init.c | 0 .../bsp_lcd_tp.c | 0 .../bsp_pinmux.c | 0 .../bsp_power.c | 0 epdiy-epub/sf32-oed-epd_v11/Kconfig.board | 86 +-- epdiy-epub/sf32-oed-epd_v11/SConscript | 7 +- epdiy-epub/sf32-oed-epd_v12/Kconfig.board | 2 + epdiy-epub/sf32-oed-epd_v12/SConscript | 14 + epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig | 3 + .../sf32-oed-epd_v12/hcpu/Kconfig.board | 7 + epdiy-epub/sf32-oed-epd_v12/hcpu/board.conf | 55 ++ .../sf32-oed-epd_v12/hcpu/custom_mem_map.h | 21 + epdiy-epub/sf32-oed-epd_v12/hcpu/rtconfig.py | 9 + epdiy-epub/sf32-oed-epd_v12/lcpu/Kconfig | 3 + .../sf32-oed-epd_v12/lcpu/Kconfig.board | 7 + epdiy-epub/sf32-oed-epd_v12/lcpu/board.conf | 9 + .../sf32-oed-epd_v12/lcpu/custom_mem_map.h | 21 + epdiy-epub/sf32-oed-epd_v12/lcpu/rtconfig.py | 6 + epdiy-epub/sf32-oed-epd_v12/ptab.json | 192 ++++++ .../boards/controls/SF32_ButtonControls.cpp | 4 +- 27 files changed, 1168 insertions(+), 91 deletions(-) create mode 100644 epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.lds create mode 100644 epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.sct create mode 100644 epdiy-epub/sf32-oed-epd_base/Kconfig.board create mode 100644 epdiy-epub/sf32-oed-epd_base/SConscript rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/battery_table.c (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/board.h (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_board.h (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_init.c (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_lcd_tp.c (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_pinmux.c (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_power.c (100%) create mode 100644 epdiy-epub/sf32-oed-epd_v12/Kconfig.board create mode 100644 epdiy-epub/sf32-oed-epd_v12/SConscript create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/board.conf create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/custom_mem_map.h create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/rtconfig.py create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/Kconfig create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/Kconfig.board create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/board.conf create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/custom_mem_map.h create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/rtconfig.py create mode 100644 epdiy-epub/sf32-oed-epd_v12/ptab.json diff --git a/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.lds b/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.lds new file mode 100644 index 0000000..005fec4 --- /dev/null +++ b/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.lds @@ -0,0 +1,556 @@ +/****************************************************************************** + * @file gcc_arm.ld + * @brief GNU Linker Script for Cortex-M based device + * @version V2.0.0 + * @date 21. May 2019 + ******************************************************************************/ +#include "rtconfig.h" +#include "mem_map.h" +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + *-------- <<< Use Configuration Wizard in Context Menu >>> ------------------- + */ + +/*---------------------- Flash Configuration ---------------------------------- + Flash Configuration + Flash Base Address <0x0-0xFFFFFFFF:8> + Flash Size (in Bytes) <0x0-0xFFFFFFFF:8> + + -----------------------------------------------------------------------------*/ +__ROM_BASE = CODE_START_ADDR; +__ROM_SIZE = CODE_SIZE; + +/*--------------------- Embedded RAM Configuration ---------------------------- + RAM Configuration + RAM Base Address <0x0-0xFFFFFFFF:8> + RAM Size (in Bytes) <0x0-0xFFFFFFFF:8> + + -----------------------------------------------------------------------------*/ +__RAM_BASE = HPSYS_RAM0_BASE; +__RAM_SIZE = HCPU_RAM_DATA_SIZE; + +/*--------------------- Stack / Heap Configuration ---------------------------- + Stack / Heap Configuration + Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> + Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> + + -----------------------------------------------------------------------------*/ +__STACK_SIZE = 0x00002000; +__HEAP_SIZE = 0x00000C00; + +__ROM_EX_BASE = HCPU_RO_DATA_START_ADDR; +__ROM_EX_SIZE = HCPU_RO_DATA_SIZE; + +__PSRAM_BASE = PSRAM_DATA_START_ADDR; +__PSRAM_SIZE = PSRAM_DATA_SIZE; + +__ROM2_BASE = BUILTIN_RESOURCE_START_ADDR; +__ROM2_SIZE = BUILTIN_RESOURCE_SIZE; + + + +/* + *-------------------- <<< end of configuration section >>> ------------------- + */ +MEMORY +{ + ROM (rx) : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE + RAM (rw) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE + ROM_EX(rw):ORIGIN = __ROM_EX_BASE, LENGTH = __ROM_EX_SIZE + PSRAM(rw): ORIGIN = __PSRAM_BASE, LENGTH = __PSRAM_SIZE + ROM2 (rx): ORIGIN = __ROM2_BASE, LENGTH = __ROM2_SIZE +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ +#ifndef FLASH_TABLE_ONLY + .vectors : + { + _stext = ABSOLUTE(.); + KEEP(*(.vectors)); + /* workaround to avoid load address of .retm_data doesn't skip .vectors region */ + . = . + 4; + } > ROM + + .stack : + { + . = ALIGN(8); + __StackLimit = .; + . = . + __STACK_SIZE; + . = ALIGN(8); + __StackTop = .; + } > RAM + PROVIDE(__stack = __StackTop); + + .heap : + { + . = ALIGN(8); + __end__ = .; + PROVIDE(end = .); + . = . + __HEAP_SIZE; + . = ALIGN(8); + __HeapLimit = .; + } > RAM + + .retm_data : + { + . = ALIGN(4); + __rw_retm_data_start__ = .; + * (.*l1_ret_text_*) + * (.*l1_ret_rodata_*) + + *drv_spi_flash.o (.text* .rodata*) + *flash_table.o (.text* .rodata*) + *bf0_hal_mpi.o (.text* .rodata*) + *bf0_hal_mpi_ex.o (.text* .rodata*) + *bf0_hal_mpi_psram.o (.text* .rodata*) + *flash.o (.text* .rodata*) + *drv_psram.o (.text* .rodata*) + + *context_gcc.o (.text* .rodata*) + *drv_common.o (.text.HAL_GetTick) + *bf0_hal_rcc.o (.text* .rodata*) + + *bf0_pm.o (.text.sifli_light_handler) + *bf0_pm.o (.text.sifli_deep_handler) + *bf0_pm.o (.text.sifli_standby_handler) + *bf0_pm.o (.text.SystemInitFromStandby) + *.o (.text.SystemPowerOnModeGet) + + *bsp_init.o (.text* .rodata*) + *bsp_lcd_tp.o (.text* .rodata*) + *bsp_pinmux.o (.text* .rodata*) + *bsp_power.o (.text* .rodata*) + *bf0_hal_gpio.o (.text* .rodata*) + + *bf0_hal_hpaon.o (.text* .rodata*) + *bf0_hal.o (.text.HAL_Init) + *.o (.text.HAL_Delay_us) + *.o (.text.HAL_Delay_us_) + *.o (.text.HAL_Delay_us2_) + *.o (.text.HAL_MspInit) + *.o (.text.HAL_Delay) + *bf0_hal_pinmux.o (.text* .rodata*) + *bf0_pin_const.o (.text* .rodata*) + *drv_common.o (.text.rt_hw_us_delay) + *.o (.text.rt_memset) + *rt_memclr*.o (.text*) + *memset*.o (.text*) + + *.o (.retm_data_*) + + . = ALIGN(4); + __rw_retm_data_end__ = .; + + } > RAM AT > ROM +#endif /* !FLASH_TABLE_ONLY */ + + + .rom2 : + { + *epub_fonts.o (.text* .rodata*) + } > ROM2 + + + .text : + { +#ifdef FLASH_TABLE_ONLY + KEEP(*ftab.o(.text* .rodata*)) +#else + *(.text*) + *(.rodata*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + /* + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + */ + + /* .dtors */ + /* + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + */ + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + + . = ALIGN(4); + LcdDriverDescTab_start = .; + KEEP(*(LcdDriverDescTab)) + LcdDriverDescTab_end = .; + + . = ALIGN(4); + __rt_utest_tc_tab_start = .; + KEEP(*(UtestTcTab)) + __rt_utest_tc_tab_end = .; + + /* section information for initial. */ + . = ALIGN(4); + __rt_init_start = .; + KEEP(*(SORT(.rti_fn*))) + __rt_init_end = .; + + . = ALIGN(4); + BuiltinAppTab_start = .; + KEEP(*(BuiltinAppTab)) + BuiltinAppTab_end = .; + + . = ALIGN(4); + __app_font_start__ = .; + KEEP(*(.app_font)) + __app_font_end__ = .; + + . = ALIGN(4); + __SerialTranExport_start__ = .; + KEEP(*(SerialTranExport)) + __SerialTranExport_end__ = .; + + . = ALIGN(4); + __sifli_reg_start__ = .; + KEEP(*(SORT(.sifli_reg*))) + __sifli_reg_end__ = .; + + . = ALIGN(4); + __bt_sifli_reg_start__ = .; + KEEP(*(SORT(.bt_sifli_reg*))) + __bt_sifli_reg_end__ = .; + + /* section information for modules */ + . = ALIGN(4); + __rtmsymtab_start = .; + KEEP(*(RTMSymTab)) + __rtmsymtab_end = .; + + . = ALIGN(4); + __usbh_class_info_start__ = .; + KEEP(*(.usbh_class_info)) + __usbh_class_info_end__ = .; + + KEEP(*(.eh_frame*)) + _etext = ABSOLUTE(.); +#endif + } > ROM + +#ifdef ZBT +#include "zbt_rom.lds" +#endif + +#ifndef FLASH_TABLE_ONLY + .rom_ex : + { + + . = ALIGN(4); + __rw_rom_ex_start__ = .; + __ER_IROM1_EX$$RO_start__ = .; + __ER_IROM1_EX$$RO_load_start__ = LOADADDR(.rom_ex); + + *(.l1_non_ret_text_*) + *(.l1_non_ret_rodata_*) + + . = ALIGN(4); + __rw_rom_ex_end__ = .; + __ER_IROM1_EX$$RO_end__ = .; + __ER_IROM1_EX$$RO_load_end__ = LOADADDR(.rom_ex) + SIZEOF(.rom_ex); + + } > ROM_EX AT > ROM + + /* + * SG veneers: + * All SG veneers are placed in the special output section .gnu.sgstubs. Its start address + * must be set, either with the command line option `--section-start` or in a linker script, + * to indicate where to place these veneers in memory. + */ +/* + .gnu.sgstubs : + { + . = ALIGN(32); + } > ROM +*/ + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > ROM + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > ROM + __exidx_end = .; + + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (LOADADDR(.data)) + LONG (ADDR(.data)) + LONG (SIZEOF(.data)) + + LONG (LOADADDR(.retm_data)) + LONG (ADDR(.retm_data)) + LONG (SIZEOF(.retm_data)) + + LONG (LOADADDR(.rom_ex)) + LONG (ADDR(.rom_ex)) + LONG (SIZEOF(.rom_ex)) + + __copy_table_end__ = .; + } > ROM + + + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + /* Add each additional bss section here */ + + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + + LONG (ADDR(.retm_bss)) + LONG (SIZEOF(.retm_bss)) + + __zero_table_end__ = .; + } > ROM + + .retm_bss : + { + . = ALIGN(4); + __rw_retm_bss_start__ = .; + __RW_IRAM_RET$$ZI_start__ = .; + * (.bss.retm_bss_*) + + . = ALIGN(4); + __RW_IRAM_RET$$ZI_end__ = .; + } > RAM + + .RW_IRAM0 : + { + *(non_ret) + *(.*l1_non_ret_data_*) + *(.*l1_non_ret_bss_*) +#ifndef BSP_USING_PSRAM + *(.nand_cache) + *(.*l2_non_ret_data_*) + *(.*l2_non_ret_bss_*) + *(.*l2_cache_non_ret_data_*) + *(.*l2_cache_non_ret_bss_*) +#endif /* BSP_USING_PSRAM */ + } > RAM + + /** + * Location counter can end up 2byte aligned with narrow Thumb code but + * __etext is assumed by startup code to be the LMA of a section in RAM + * which must be 4byte aligned + */ + __etext = ALIGN (4); + + .data : + { + _sdata = ABSOLUTE(.); + __data_start__ = .; + __RW_IRAM1_start__ = .; + *(vtable) + *(.data) + *(.data.*) + *(.l1_ret_data_*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + _sinit = ABSOLUTE(.); + PROVIDE(__ctors_start__ = .); + PROVIDE_HIDDEN (__init_array_start = .); + /* old GCC version uses .ctors */ + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + /* new GCC version uses .init_array */ + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + _einit = ABSOLUTE(.); + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE(__ctors_end__ = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE(__dtors_start__ = .); + PROVIDE_HIDDEN (__fini_array_start = .); + + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + PROVIDE(__dtors_end__ = .); + +#ifdef ZBT +#include "zbt_data.lds" +#endif + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + __RW_IRAM1_end__ = .; + _edata = ABSOLUTE(.); + } > RAM AT > ROM + + /* + * Secondary data section, optional + * + * Remember to add each additional data section + * to the .copy.table above to asure proper + * initialization during startup. + */ + + __etext2 = ALIGN (4); + +#ifdef BSP_USING_PSRAM + .RW_PSRAM1 : + { + . = ALIGN(4); + __rw_psram1_start__ = .; + *(.*l2_ret_data_*) + *(.*l2_ret_bss_*) + *(.*l2_cache_ret_data_*) + *(.*l2_cache_ret_bss_*) + . = ALIGN(4); + __rw_psram1_end__ = .; + + } > PSRAM + + .RW_PSRAM_NON_RET : + { + /* aligned to cache line size */ + . = ALIGN(32); + __RW_PSRAM_NON_RET_start__ = .; + *(.nand_cache) + *(.*l2_non_ret_data_*) + *(.*l2_non_ret_bss_*) + *(.*l2_cache_non_ret_data_*) + *(.*l2_cache_non_ret_bss_*) + . = ALIGN(4); + __RW_PSRAM_NON_RET_end__ = .; + + } > PSRAM +#endif /* BSP_USING_PSRAM */ + + .bss : + { + _sbss = ABSOLUTE(.); + . = ALIGN(4); + __bss_start__ = .; + *(.bss) + *(.bss.*) + *(COMMON) + *(.l1_ret_bss_*) + . = ALIGN(4); + __bss_end__ = .; + __bss_end = .; + _ebss = ABSOLUTE(.); + __end__ = .; + PROVIDE(end = .); + } > RAM AT > RAM + + /* + * Secondary bss section, optional + * + * Remember to add each additional bss section + * to the .zero.table above to asure proper + * initialization during startup. + */ +/* + .bss2 : + { + . = ALIGN(4); + __bss2_start__ = .; + *(.bss2) + *(.bss2.*) + . = ALIGN(4); + __bss2_end__ = .; + } > RAM2 AT > RAM2 +*/ + + /* Check if data + heap + stack exceeds RAM limit */ + /* ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") */ + + + +#endif + +} + diff --git a/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.sct b/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.sct new file mode 100644 index 0000000..6f8b4bc --- /dev/null +++ b/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.sct @@ -0,0 +1,157 @@ +#! armclang -E --target=arm-arm-none-eabi -mcpu=cortex-m33 -xc -I $SDK_ROOT/drivers/cmsis/sf32lb52x +#include "rtconfig.h" +#include "mem_map.h" + + +; ************************************************************* +; *** Scatter-Loading Description File generated by uVision *** +; ************************************************************* + +LR_IROM1 CODE_START_ADDR CODE_SIZE { ; load region size_region + ER_IROM1 CODE_START_ADDR CODE_SIZE { ; load address = execution address + *.o (RESET, +First) + *(InRoot$$Sections) + .ANY (+RO) + *(FSymTab) + *.o (.rodata.*) + } + ER_IROM1_EX HCPU_RO_DATA_START_ADDR HCPU_RO_DATA_SIZE { ; load address = execution address + *.o (.l1_non_ret_text_*) + *.o (.l1_non_ret_rodata_*) + } + +#ifdef BSP_USING_PSRAM + RW_PSRAM1 PSRAM_DATA_START_ADDR { +#ifdef PKG_USING_FFMPEG + mpeg*.o (.bss.*) + h264*.o (.bss.*) +#endif + } + RW_PSRAM_RET +0 UNINIT{ ; ZI data, retained + *.o (.l2_ret_data_*) + *.o (.l2_ret_bss_*) + *.o (.l2_cache_ret_data_*) + *.o (.l2_cache_ret_bss_*) + } + RW_PSRAM_NON_RET +0 UNINIT{ ; ZI data, not retained and reused by SRAM retention + *.o (.l2_non_ret_data_*) + *.o (.l2_non_ret_bss_*) + *.o (.l2_cache_non_ret_data_*) + *.o (.l2_cache_non_ret_bss_*) + } + ScatterAssert((ImageLength(RW_PSRAM1)+ ImageLength(RW_PSRAM_RET) + ImageLength(RW_PSRAM_NON_RET)) Date: Wed, 14 Jan 2026 10:57:46 +0800 Subject: [PATCH 12/25] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=92=8C=E4=B8=BB=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 121 +----- epdiy-epub/src/SConscript | 2 +- .../boards/controls/SF32_TouchControls.cpp | 76 +++- .../src/boards/controls/SF32_TouchControls.h | 8 +- epdiy-epub/src/epub_screen.cpp | 358 ++++++++++++++++++ epdiy-epub/src/epub_screen.h | 24 ++ epdiy-epub/src/main.cpp | 88 ++--- 7 files changed, 508 insertions(+), 169 deletions(-) create mode 100644 epdiy-epub/src/epub_screen.cpp create mode 100644 epdiy-epub/src/epub_screen.h diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index efd6603..2998a34 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -16,45 +16,24 @@ static const char *TAG = "PUBLIST"; #define PADDING 20 #define EPUBS_PER_PAGE 5 -#define BOTTOM_AREA_HEIGHT 50 -#define BOTTOM_AREA_ITEM_INDEX -1 void EpubList::next() { - // 如果当前选中的是最后一个电子书项,则切换到底部区域 - if (state.selected_item == state.num_epubs - 1) - { - state.selected_item = BOTTOM_AREA_ITEM_INDEX; - } - else if (state.selected_item == BOTTOM_AREA_ITEM_INDEX) - { - // 如果当前已在底部区域,则回到第一个电子书项 + if (state.num_epubs == 0) return; + // 正常切换到下一个电子书项 + if (state.selected_item >= 0 && state.selected_item < state.num_epubs - 1) + state.selected_item++; + else state.selected_item = 0; - } - else - { - // 正常切换到下一个电子书项 - state.selected_item = (state.selected_item + 1) % state.num_epubs; - } } void EpubList::prev() { - if (state.selected_item == 0) - { - // 如果当前是第一个电子书项,则切换到底部区域 - state.selected_item = BOTTOM_AREA_ITEM_INDEX; - } - else if (state.selected_item == BOTTOM_AREA_ITEM_INDEX) - { - // 如果当前已在底部区域,则切换到最后一个电子书项 - state.selected_item = state.num_epubs > 0 ? state.num_epubs - 1 : 0; - } - else - { - // 正常切换到上一个电子书项 - state.selected_item = (state.selected_item - 1 + state.num_epubs) % state.num_epubs; - } + if (state.num_epubs == 0) return; + if (state.selected_item <= 0) + state.selected_item = state.num_epubs - 1; + else + state.selected_item--; } bool EpubList::load(const char *path) @@ -149,8 +128,8 @@ void EpubList::render() ulog_d(TAG, "Rendering EPUB list"); // what page are we on? int current_page = state.selected_item / EPUBS_PER_PAGE; - // 计算单元格高度,减去底部区域的高度 - int cell_height = (renderer->get_page_height() - BOTTOM_AREA_HEIGHT) / EPUBS_PER_PAGE; + // 计算单元格高度(不再预留底部区域) + int cell_height = (renderer->get_page_height()) / EPUBS_PER_PAGE; ulog_d(TAG, "Cell height is %d", cell_height); int start_index = current_page * EPUBS_PER_PAGE; int ypos = 0; @@ -225,79 +204,5 @@ void EpubList::render() state.previous_selected_item = state.selected_item; state.previous_rendered_page = current_page; - // touch 开关底部区域 - - int screen_height = renderer->get_page_height(); - int bottom_area_y = screen_height - BOTTOM_AREA_HEIGHT - 11; - - - int original_width = renderer->get_page_width() - 2 * PADDING; - int rect_width = original_width * 2 / 3; - int rect_x = PADDING + (original_width - rect_width) / 2; - - int rect_height = BOTTOM_AREA_HEIGHT; - - if (bottom_area_y < 0) - { - bottom_area_y = 5; - rect_height = BOTTOM_AREA_HEIGHT; - } - - - renderer->fill_rect(rect_x, bottom_area_y, rect_width, rect_height, 255); - - bool touch_state = touch_controls ? touch_controls->isTouchEnabled() : false; - const char* text = touch_state ? "Touch : On" : "Touch : Off"; - - int text_height = renderer->get_line_height(); - int text_y = bottom_area_y + (rect_height - text_height) / 2; - - if (text_y < bottom_area_y + 2) - { - text_y = bottom_area_y + 2; - } - if (text_y + text_height > bottom_area_y + rect_height - 2) - { - text_y = bottom_area_y + rect_height - text_height - 2; - } - - int text_length = strlen(text); - int estimated_text_width = text_length * 12; - int text_x = rect_x + (rect_width - estimated_text_width) / 2; - - - if (text_x < rect_x + 5) - { - text_x = rect_x + 5; - } - if (text_x + estimated_text_width > rect_x + rect_width - 5) - { - text_x = rect_x + rect_width - estimated_text_width - 5; - } - - renderer->draw_text(text_x, text_y, text, 0); - - if (state.selected_item == BOTTOM_AREA_ITEM_INDEX) - { - int border_thickness = 3; - for (int i = 0; i < border_thickness; i++) - { - renderer->draw_rect(rect_x + i, bottom_area_y + i, - rect_width - 2 * i, - rect_height - 2 * i, 0); - } - } - else - { - if (state.previous_selected_item == BOTTOM_AREA_ITEM_INDEX) - { - int border_thickness = 3; - for (int i = 0; i < border_thickness; i++) - { - renderer->draw_rect(rect_x + i, bottom_area_y + i, - rect_width - 2 * i, - rect_height - 2 * i, 255); - } - } - } + // 移除书库页底部触控开关区域 } \ No newline at end of file diff --git a/epdiy-epub/src/SConscript b/epdiy-epub/src/SConscript index dd9b659..6c590b3 100644 --- a/epdiy-epub/src/SConscript +++ b/epdiy-epub/src/SConscript @@ -4,7 +4,7 @@ from building import * import rtconfig cwd = GetCurrentDir() -src = ['main.cpp','epub_mem.c','epub_fonts.c'] +src = ['main.cpp','epub_screen.cpp','epub_mem.c','epub_fonts.c'] src = src + Glob('./assets/*.c') CPPPATH = [cwd] diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index a2f85c9..9d17027 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -6,6 +6,9 @@ #include "drv_touch.h" #endif +volatile int g_touch_last_settings_row = -1; +volatile int g_touch_last_settings_dir = 0; + rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) { SF32_TouchControls *instance = static_cast (dev->user_data); @@ -29,24 +32,65 @@ rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) UIAction action = NONE; // LOG_I("TOUCH", "Received touch event %d,%d", x, y); - if (x >= 10 && x <= 10 + instance->ui_button_width && y < 200) - { - action = DOWN; - instance->renderPressedState(instance->renderer, UP, false); - } - else if (x >= 150 && x <= 150 + instance->ui_button_width && y < 200) - { - action = UP; - instance->renderPressedState(instance->renderer, DOWN, false); - } - else if (x >= 300 && x <= 300 + instance->ui_button_width && y < 200) + // 主页面底部按键区域:左"<"、右">"、中间文本框 + int page_w = instance->renderer->get_page_width(); + int page_h = instance->renderer->get_page_height(); + int margin_side = 10; + int margin_bottom = 60; + int rect_w = 80; + int rect_h = 40; + int y_bottom = page_h - rect_h - margin_bottom; + int left_x = margin_side; + int right_x = page_w - rect_w - margin_side; + int mid_x = left_x + rect_w + margin_side; + int mid_w = right_x - margin_side - mid_x; + + if (x >= left_x && x <= left_x + rect_w && y >= y_bottom && y <= y_bottom + rect_h) + { + rt_kprintf("Touch left < \n"); + action = UP; + } + + else if (x >= right_x && x <= right_x + rect_w && y >= y_bottom && y <= y_bottom + rect_h) + { + action = DOWN; + rt_kprintf("Touch right > \n"); + } + + // 设置页面每行左右箭头触控区域(与设置页布局一致) + if (action == NONE) { - action = SELECT; + int page_w2 = instance->renderer->get_page_width(); + int margin_lr2 = 6; + int item_h2 = 100; + int gap2 = 54; + int arrow_col_w2 = 40; + int lh2 = instance->renderer->get_line_height(); + int y_start2 = 40 + lh2 + 20; + g_touch_last_settings_row = -1; + g_touch_last_settings_dir = 0; + for (int row = 0; row < 3; ++row) + { + int ry = y_start2 + row * (item_h2 + gap2); + int left_ax = margin_lr2; + int right_ax = page_w2 - margin_lr2 - arrow_col_w2; + if (x >= left_ax && x <= left_ax + arrow_col_w2 && y >= ry && y <= ry + item_h2) + { + action = UP; + g_touch_last_settings_row = row; + g_touch_last_settings_dir = -1; // 左=减 + break; + } + if (x >= right_ax && x <= right_ax + arrow_col_w2 && y >= ry && y <= ry + item_h2) + { + action = DOWN; + g_touch_last_settings_row = row; + g_touch_last_settings_dir = +1; // 右=加 + break; + } + } } - else - { - } instance->last_action = action; if (action != NONE) { @@ -157,6 +201,8 @@ void SF32_TouchControls::renderPressedState(Renderer *renderer, UIAction action, case LAST_INTERACTION: case NONE: break; + default: + break; } renderer->set_margin_top(35); } \ No newline at end of file diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.h b/epdiy-epub/src/boards/controls/SF32_TouchControls.h index 23f2c56..d9dfba6 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.h +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.h @@ -23,4 +23,10 @@ class SF32_TouchControls : public TouchControls void renderPressedState(Renderer *renderer, UIAction action, bool state = true) override; void powerOnTouch() override; void powerOffTouch() override; -}; \ No newline at end of file +}; + +// 最近一次设置页左右箭头触控标记 +// 行号:0=触控开关,1=超时关机,2=全刷周期;-1=无 +extern volatile int g_touch_last_settings_row; +// 方向:-1=左(减),+1=右(加),0=无 +extern volatile int g_touch_last_settings_dir; \ No newline at end of file diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp new file mode 100644 index 0000000..ede9f23 --- /dev/null +++ b/epdiy-epub/src/epub_screen.cpp @@ -0,0 +1,358 @@ +#include "epub_screen.h" +#include + + +extern TouchControls *touch_controls; + +// 主页面选项 +typedef enum +{ + OPTION_OPEN_LIBRARY = 0, + OPTION_CONTINUE_READING, + OPTION_ENTER_SETTINGS +} MainOption; + +static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” +static int full_refresh_period = 10; // 全刷周期次数,仅用于设置页显示 + +// 设置页列表项 +typedef enum { SET_TOUCH = 0, SET_TIMEOUT = 1, SET_FULL_REFRESH = 2, SET_CONFIRM = 3 } SettingsItem; +static int settings_selected_idx = 0; + +// 超时关机:1/3/5/7/10/不关机(0) +static const int kTimeoutOptions[] = {1, 3, 5, 7, 10, 0}; +static const int kTimeoutOptionsCount = sizeof(kTimeoutOptions) / sizeof(kTimeoutOptions[0]); +static int timeout_shutdown_hours = 5; // 运行时关机超时(小时),0 表示不关机 +static int timeout_idx = -1; // 指向 kTimeoutOptions 的索引 + +static int find_timeout_idx(int hours) +{ + for (int i = 0; i < kTimeoutOptionsCount; ++i) + { + if (kTimeoutOptions[i] == hours) return i; + } + return 2; // 默认索引:5小时 +} + +static void adjust_timeout(bool increase) +{ + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_hours); + if (increase) + { + timeout_idx = (timeout_idx + 1) % kTimeoutOptionsCount; + } + else + { + timeout_idx = (timeout_idx - 1 + kTimeoutOptionsCount) % kTimeoutOptionsCount; + } + timeout_shutdown_hours = kTimeoutOptions[timeout_idx]; +} + +void screen_init(int default_timeout_hours) +{ + timeout_shutdown_hours = default_timeout_hours; + timeout_idx = find_timeout_idx(timeout_shutdown_hours); +} + +int screen_get_timeout_shutdown_hours() +{ + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_hours); + return timeout_shutdown_hours; +} + +int screen_get_main_selected_option() +{ + return (int)main_option; // 0: 打开书库, 1: 继续阅读, 2: 进入设置 +} + +// 主页面 +static void render_main_page(Renderer *renderer) +{ + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); + + const char *title = "S I F L I"; + int title_w = renderer->get_text_width(title); + int title_h = renderer->get_line_height(); + int center_x = renderer->get_page_width() / 2; + int center_y = 35 + (renderer->get_page_height() - 35) / 2; + renderer->draw_text(center_x - title_w / 2, center_y - title_h / 2, title, true, true); + + int margin_side = 10; + int margin_bottom = 60; // 与底部距离 + int rect_w = 80; + int rect_h = 40; + int y = renderer->get_page_height() - rect_h - margin_bottom; + int left_x = margin_side; + int right_x = renderer->get_page_width() - rect_w - margin_side; + + // 左 "<" + const char *lt = "<"; + int lt_w = renderer->get_text_width(lt); + int lt_h = renderer->get_line_height(); + renderer->draw_text(left_x + (rect_w - lt_w) / 2, y + (rect_h - lt_h) / 2, lt, false, true); + + // 右 ">" + const char *gt = ">"; + int gt_w = renderer->get_text_width(gt); + int gt_h = renderer->get_line_height(); + renderer->draw_text(right_x + (rect_w - gt_w) / 2, y + (rect_h - gt_h) / 2, gt, false, true); + + // 中间选项文本 + int mid_x = left_x + rect_w + margin_side; + int mid_w = right_x - margin_side - mid_x; + + const char *opt_text = NULL; + switch (main_option) + { + case OPTION_OPEN_LIBRARY: opt_text = "打开书库"; break; + case OPTION_CONTINUE_READING: opt_text = "继续阅读"; break; + case OPTION_ENTER_SETTINGS: opt_text = "进入设置"; break; + } + int opt_w = renderer->get_text_width(opt_text); + int opt_h = renderer->get_line_height(); + renderer->draw_text(mid_x + (mid_w - opt_w) / 2, y + (rect_h - opt_h) / 2, opt_text, false, true); +} + +void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw) +{ + if (needs_redraw || action == NONE) + { + render_main_page(renderer); + return; + } + switch (action) + { + case UP: // 左切换 + if (main_option == OPTION_OPEN_LIBRARY) main_option = OPTION_ENTER_SETTINGS; + else if (main_option == OPTION_CONTINUE_READING) main_option = OPTION_OPEN_LIBRARY; + else main_option = OPTION_CONTINUE_READING; + render_main_page(renderer); + break; + case DOWN: // 右切换 + if (main_option == OPTION_OPEN_LIBRARY) main_option = OPTION_CONTINUE_READING; + else if (main_option == OPTION_CONTINUE_READING) main_option = OPTION_ENTER_SETTINGS; + else main_option = OPTION_OPEN_LIBRARY; + render_main_page(renderer); + break; + case SELECT: + // 由上层 main.cpp 负责切换 页面UIState + switch (main_option) + { + case OPTION_OPEN_LIBRARY: + rt_kprintf("1\n"); + break; + case OPTION_CONTINUE_READING: + rt_kprintf("2\n"); + break; + case OPTION_ENTER_SETTINGS: + rt_kprintf("3\n"); + break; + } + break; + default: + break; + } +} + +// 设置页面 +static void render_settings_page(Renderer *renderer) +{ + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); + + // 标题 + const char *title = "设置"; + int title_w = renderer->get_text_width(title); + int title_h = renderer->get_line_height(); + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + renderer->draw_text((page_w - title_w) / 2, 40, title, true, true); + + // 列表项布局参数 + int margin_lr = 6; // 左右边距,给左右触控箭头 + int item_h = 100; // 矩形高度 + int gap = 54; // 列表项之间的间距 + int arrow_col_w = 40; // 左右触控箭头列宽度 + int y = 40 + title_h + 20; // 第一项起始Y + + // 1) 触控开关 + int item_w = page_w - margin_lr * 2 - arrow_col_w * 2; // 为左右箭头列留边 + int item_x = margin_lr + arrow_col_w; + { + const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); + const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); + } + if (settings_selected_idx == SET_TOUCH) + { + for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + } + else + { + renderer->draw_rect(item_x, y, item_w, item_h, 0); //画框线 + } + bool touch_on = touch_controls ? touch_controls->isTouchEnabled() : false; + char buf1[48]; + rt_snprintf(buf1, sizeof(buf1), "触控开关:%s", touch_on ? "开" : "关"); + int t1_w = renderer->get_text_width(buf1); + int lh = renderer->get_line_height(); + { + int tx = item_x + (item_w - t1_w) / 2; + if (tx < item_x + 4) tx = item_x + 4; + if (tx + t1_w > item_x + item_w - 4) tx = item_x + item_w - t1_w - 4; + renderer->draw_text(tx, y + (item_h - lh) / 2, buf1, false, true); + } + y += item_h + gap; + + // 2) 超时关机 + { + const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); + const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); + } + if (settings_selected_idx == SET_TIMEOUT) + { + for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + } + else + { + renderer->draw_rect(item_x, y, item_w, item_h, 0); + } + char buf2[64]; + if (timeout_shutdown_hours == 0) + { + rt_snprintf(buf2, sizeof(buf2), "超时关机:不关机"); + } + else + { + rt_snprintf(buf2, sizeof(buf2), "超时关机:%d 小时", timeout_shutdown_hours); + } + { + int t2_w = renderer->get_text_width(buf2); + int tx = item_x + (item_w - t2_w) / 2; + if (tx < item_x + 4) tx = item_x + 4; + if (tx + t2_w > item_x + item_w - 4) tx = item_x + item_w - t2_w - 4; + renderer->draw_text(tx, y + (item_h - lh) / 2, buf2, false, true); + } + y += item_h + gap; + + // 3) 全刷周期 + { + const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); + const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); + } + if (settings_selected_idx == SET_FULL_REFRESH) + { + for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + } + else + { + renderer->draw_rect(item_x, y, item_w, item_h, 0); + } + char buf3[64]; + rt_snprintf(buf3, sizeof(buf3), "全刷周期:%d 次", full_refresh_period); + { + int t3_w = renderer->get_text_width(buf3); + int tx = item_x + (item_w - t3_w) / 2; + if (tx < item_x + 4) tx = item_x + 4; + if (tx + t3_w > item_x + item_w - 4) tx = item_x + item_w - t3_w - 4; + renderer->draw_text(tx, y + (item_h - lh) / 2, buf3, false, true); + } + y += item_h + gap; + + // 底部 确认 按钮 + int confirm_h = 120; // 矩形框高度 + int confirm_w = item_w; // 宽度 + int confirm_x = (page_w - confirm_w) / 2; // 居中 + int confirm_y = page_h - confirm_h - 60; // 距离底部位置 + if (settings_selected_idx == SET_CONFIRM) + { + for (int i = 0; i < 2; ++i) renderer->draw_rect(confirm_x + i, confirm_y + i, confirm_w - 2 * i, confirm_h - 2 * i, 0); + } + else + { + renderer->draw_rect(confirm_x, confirm_y, confirm_w, confirm_h, 0); + } + const char *confirm = "确认"; + int c_w = renderer->get_text_width(confirm); + int c_h = renderer->get_line_height(); + renderer->draw_text(confirm_x + (confirm_w - c_w) / 2, confirm_y + (confirm_h - c_h) / 2, confirm, false, true); +} + +bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) +{ + // 读取并清除一次性的触控箭头标记,避免后续硬件按键误用 + int touch_row = g_touch_last_settings_row; + int touch_dir = g_touch_last_settings_dir; + g_touch_last_settings_row = -1; + g_touch_last_settings_dir = 0; + + if (needs_redraw || action == NONE) + { + render_settings_page(renderer); + return false; + } + + switch (action) + { + case UP: + // 触控箭头若命中“超时关机”行且为左箭头(减),执行减;否则执行上下选择 + if (settings_selected_idx == SET_TIMEOUT && touch_row == 1 && touch_dir == -1) + { + adjust_timeout(false); + render_settings_page(renderer); + } + else + { + if (settings_selected_idx > 0) settings_selected_idx--; else settings_selected_idx = SET_CONFIRM; + render_settings_page(renderer); + } + break; + case DOWN: + // 触控箭头若命中“超时关机”行且为右箭头(加),执行加;否则执行上下选择 + if (settings_selected_idx == SET_TIMEOUT && touch_row == 1 && touch_dir == +1) + { + adjust_timeout(true); + render_settings_page(renderer); + } + else + { + if (settings_selected_idx < SET_CONFIRM) settings_selected_idx++; else settings_selected_idx = SET_TOUCH; + render_settings_page(renderer); + } + break; + case SELECT: + if (settings_selected_idx == SET_TOUCH) + { + bool current_state = touch_controls ? touch_controls->isTouchEnabled() : false; + if (touch_controls) + { + touch_controls->setTouchEnable(!current_state); + if (!current_state) touch_controls->powerOnTouch(); + else touch_controls->powerOffTouch(); + } + render_settings_page(renderer); + break; + } + if (settings_selected_idx == SET_TIMEOUT) + { + // SELECT 在超时关机项上为加操作(循环) + adjust_timeout(true); + render_settings_page(renderer); + break; + } + if (settings_selected_idx == SET_CONFIRM) + { + // 由上层切回主页面 + return true; + } + // 其他项当前不处理 + break; + default: + break; + } + return false; +} diff --git a/epdiy-epub/src/epub_screen.h b/epdiy-epub/src/epub_screen.h new file mode 100644 index 0000000..c97c3c4 --- /dev/null +++ b/epdiy-epub/src/epub_screen.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include "boards/SF32PaperRenderer.h" +#include "boards/controls/Actions.h" +#include "boards/controls/TouchControls.h" +#include "boards/controls/SF32_TouchControls.h" + + +// 初始化屏幕模块(设置默认的关机超时小时数,0 表示不关机) +void screen_init(int default_timeout_hours); + +// 获取当前关机超时设置(小时;0 表示不关机) +int screen_get_timeout_shutdown_hours(); + +// 获取当前主页面选中的选项(0: 打开书库, 1: 继续阅读, 2: 进入设置) +int screen_get_main_selected_option(); + +// 主页面交互与渲染 +void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw); + +// 设置页面交互与渲染;返回 true 表示确认并退出到主页面 +bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw); + diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 171f083..ebe3d87 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -6,6 +6,7 @@ #include #include "boards/Board.h" #include "boards/controls/SF32_TouchControls.h" +#include "epub_screen.h" #include "boards/SF32PaperRenderer.h" #include "gui_app_pm.h" #include "bf0_pm.h" @@ -15,7 +16,7 @@ #undef DBG_LEVEL #define DBG_LEVEL DBG_LOG //DBG_INFO // #define LOG_TAG "EPUB.main" - +#define TIMEOUT_SHUTDOWN_TIME 5 // 默认关机超时(小时);0 表示不关机 #include @@ -35,9 +36,11 @@ const char *TAG = "main"; typedef enum { - SELECTING_EPUB, + MAIN_PAGE, // 新主页面 + SELECTING_EPUB, SELECTING_TABLE_CONTENTS, READING_EPUB, + SETTINGS_PAGE // 通用功能设置页面 } UIState; typedef enum { @@ -47,8 +50,8 @@ typedef enum CHARGING_PAGE } UIState2; -// default to showing the list of epubs to the user -UIState ui_state = SELECTING_EPUB; +// 默认显示新主页面,而非书库页面 +UIState ui_state = MAIN_PAGE; UIState2 lowpower_ui_state = MAIN_MENU; // the state data for the epub list and reader EpubListState epub_list_state; @@ -63,12 +66,19 @@ static EpubReader *reader = nullptr; static EpubToc *contents = nullptr; static bool charge_full = false; Battery *battery = nullptr; -// 声明全局变量,以便open_tp_lcd和close_tp_lcd函数可以访问 +// 给open_tp_lcd和close_tp_lcd用的 Renderer *renderer = nullptr; TouchControls *touch_controls = nullptr; rt_mq_t ui_queue = RT_NULL; +// 主页面选项 +typedef enum { + OPTION_OPEN_LIBRARY = 0, // 打开书库 -> 打印 1 + OPTION_CONTINUE_READING, // 继续阅读 -> 打印 2 + OPTION_ENTER_SETTINGS // 进入设置 -> 打印 3 +} MainOption; + void handleEpub(Renderer *renderer, UIAction action) { if (!reader) @@ -168,30 +178,6 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) epub_list->next(); break; case SELECT: - // 检查是否选中了底部特殊区域 - if (epub_list_state.selected_item == -1) { - // 打印"1" - rt_kprintf("touch open or off\n"); - bool current_state = touch_controls->isTouchEnabled(); - touch_controls->setTouchEnable(!current_state); - - // 刷新屏幕以更新底部区域的文本显示 - if (!current_state) // 之前是关闭状态,现在要打开 - { - touch_controls->powerOnTouch(); - } - else // 之前是打开状态,现在要关闭 - { - touch_controls->powerOffTouch(); - } - - epub_list->render(); - - - return; - } - else - { // switch to reading the epub // setup the reader state ui_state = SELECTING_TABLE_CONTENTS; @@ -201,7 +187,6 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) contents->set_needs_redraw(); handleEpubTableContents(renderer, NONE, true); return; - } case NONE: default: // nothing to do @@ -288,13 +273,31 @@ void handleUserInteraction(Renderer *renderer, UIAction ui_action, bool needs_re uint32_t start_tick = rt_tick_get(); switch (ui_state) { + case MAIN_PAGE: // 新主页面 + handleMainPage(renderer, ui_action, needs_redraw); + if (ui_action == SELECT && screen_get_main_selected_option() == 2) + { + ui_state = SETTINGS_PAGE; + (void)handleSettingsPage(renderer, NONE, true); + } + break; case READING_EPUB: //阅读界面 handleEpub(renderer, ui_action); break; case SELECTING_TABLE_CONTENTS: //目录界面 handleEpubTableContents(renderer, ui_action, needs_redraw); break; - case SELECTING_EPUB: //电子书列表(主界面) + case SETTINGS_PAGE: // 设置页面 + { + bool exit_to_main = handleSettingsPage(renderer, ui_action, needs_redraw); + if (exit_to_main) + { + ui_state = MAIN_PAGE; + handleMainPage(renderer, NONE, true); + } + break; + } + case SELECTING_EPUB: //电子书列表页面(书库页面) default: handleEpubList(renderer, ui_action, needs_redraw); break; @@ -338,15 +341,8 @@ void back_to_main_page() renderer->set_margin_top(35); renderer->set_margin_left(10); renderer->set_margin_right(10); - - if (!epub_list) - { - epub_list = new EpubList(renderer, epub_list_state); - if (epub_list->load("/")) - { - ulog_i("main", "Epub files loaded"); - } - } + // 返回新的主页面,不再默认进入书库页面 + ui_state = MAIN_PAGE; handleUserInteraction(renderer, NONE, true); if (battery) @@ -538,6 +534,7 @@ void main_task(void *param) // reset the screen renderer->reset(); // make sure the UI is in the right state + ui_state = MAIN_PAGE; handleUserInteraction(renderer, NONE, true); } @@ -557,9 +554,12 @@ void main_task(void *param) // keep track of when the user last interacted and go to sleep after N seconds rt_tick_t last_user_interaction = rt_tick_get_millisecond(); + // 初始化屏幕模块默认关机超时 + screen_init(TIMEOUT_SHUTDOWN_TIME); -while (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 *5) //5小时无操作自动关机 -{ + while ((screen_get_timeout_shutdown_hours() == 0) || + (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 * screen_get_timeout_shutdown_hours())) // 按设置的小时数无操作自动关机;0为不关机 + { // 检查是否超过5分钟无操作,如果是在欢迎页面、充电页面或低电量页面则不跳转 if (rt_tick_get_millisecond() - last_user_interaction >= 60 * 1000 *5 && @@ -687,7 +687,7 @@ extern "C" int main() { // dump out the epub list state - //rt_pm_request(PM_SLEEP_MODE_IDLE); + rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item); @@ -701,4 +701,4 @@ extern "C" } return 0; } -} \ No newline at end of file +} From 987ba43ee1e394505368fd14a6bcf3fcbf076435 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Wed, 14 Jan 2026 16:28:44 +0800 Subject: [PATCH 13/25] =?UTF-8?q?1.=E5=AE=8C=E5=96=84=20=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=EF=BC=8C=E4=B9=A6=E5=BA=93=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=EF=BC=8C=E7=9B=AE=E5=BD=95=E9=A1=B5=E9=9D=A2=EF=BC=9A=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=AF=B9=E5=BA=94=E4=B8=8B=E6=A0=8F=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=202.=E5=A2=9E=E5=8A=A0=E9=98=85=E8=AF=BB=E8=A6=86=E7=9B=96?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=EF=BC=88=E7=B2=97=E7=B3=99=E7=89=88=EF=BC=9A?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86=E5=B8=83=E5=B1=80=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E8=BF=9B=E5=85=A5=E5=92=8C=E9=80=80=E5=87=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 51 ++- epdiy-epub/lib/Epub/EpubList/EpubList.h | 7 + epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 79 +++++ epdiy-epub/lib/Epub/EpubList/EpubReader.h | 11 + epdiy-epub/lib/Epub/EpubList/EpubToc.cpp | 47 ++- epdiy-epub/lib/Epub/EpubList/EpubToc.h | 7 + epdiy-epub/src/boards/controls/Actions.h | 1 + .../boards/controls/SF32_ButtonControls.cpp | 11 +- epdiy-epub/src/epub_screen.cpp | 9 +- epdiy-epub/src/main.cpp | 309 +++++++++++++++--- 10 files changed, 472 insertions(+), 60 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index 2998a34..2853941 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -15,7 +15,7 @@ static const char *TAG = "PUBLIST"; #define PADDING 20 -#define EPUBS_PER_PAGE 5 +#define EPUBS_PER_PAGE 4 void EpubList::next() { @@ -128,8 +128,10 @@ void EpubList::render() ulog_d(TAG, "Rendering EPUB list"); // what page are we on? int current_page = state.selected_item / EPUBS_PER_PAGE; - // 计算单元格高度(不再预留底部区域) - int cell_height = (renderer->get_page_height()) / EPUBS_PER_PAGE; + // 计算单元格高度,并为底部按钮预留区域与底部间距 + const int bottom_area_height = 100; // 底部三按钮区域高度 + const int bottom_margin = 30; // 与屏幕底部的间距 + int cell_height = (renderer->get_page_height() - bottom_area_height - bottom_margin) / EPUBS_PER_PAGE; ulog_d(TAG, "Cell height is %d", cell_height); int start_index = current_page * EPUBS_PER_PAGE; int ypos = 0; @@ -203,6 +205,45 @@ void EpubList::render() } state.previous_selected_item = state.selected_item; state.previous_rendered_page = current_page; - - // 移除书库页底部触控开关区域 + // 绘制底部三按钮区域 + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + int area_y = page_h - bottom_area_height - bottom_margin; + // 背景 + renderer->fill_rect(0, area_y, page_w, bottom_area_height, 255); + // 三个等宽按钮 + int btn_gap = 10; + int btn_w = (page_w - btn_gap * 4) / 3; + int btn_h = 80; + int btn_y = area_y + (bottom_area_height - btn_h) / 2; + int btn_x0 = btn_gap; // 上一页 + int btn_x1 = btn_gap * 2 + btn_w; // 主页面 + int btn_x2 = btn_gap * 3 + btn_w * 2; // 下一页 + + // 高亮边框:当处于底部模式时,高亮当前选择 + auto draw_button = [&](int x, const char* text, bool selected) + { + if (selected) + { + // 加粗描边,表示选中 + for (int i = 0; i < 5; ++i) + { + renderer->draw_rect(x + i, btn_y + i, btn_w - 2 * i, btn_h - 2 * i, 0); + } + } + else + { + // 非选中用细描边 + renderer->draw_rect(x, btn_y, btn_w, btn_h, 80); + } + int t_w = renderer->get_text_width(text); + int t_h = renderer->get_line_height(); + int tx = x + (btn_w - t_w) / 2; + int ty = btn_y + (btn_h - t_h) / 2; + renderer->draw_text(tx, ty, text, false, true); + }; + + draw_button(btn_x0, "上一页", m_bottom_mode && m_bottom_idx == 0); + draw_button(btn_x1, "主页面", m_bottom_mode && m_bottom_idx == 1); + draw_button(btn_x2, "下一页", m_bottom_mode && m_bottom_idx == 2); } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.h b/epdiy-epub/lib/Epub/EpubList/EpubList.h index c70a727..da2c910 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.h @@ -31,9 +31,16 @@ class EpubList EpubListState &state; bool m_needs_redraw = false; TouchControls* touch_controls = nullptr; + // 底部按钮选择状态:是否处于底部按钮选择模式与当前索引(0:上一页,1:主页面,2:下一页) + bool m_bottom_mode = false; + int m_bottom_idx = 1; public: EpubList(Renderer *renderer, EpubListState &state) : renderer(renderer), state(state){}; void setTouchControls(TouchControls* controls) { touch_controls = controls; } + // 设置底部按钮选择状态 + void set_bottom_selection(bool enabled, int idx) { m_bottom_mode = enabled; m_bottom_idx = idx; } + bool is_bottom_mode() const { return m_bottom_mode; } + int bottom_index() const { return m_bottom_idx; } ~EpubList() {} bool load(const char *path); void set_needs_redraw() { m_needs_redraw = true; } diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index 5be05ac..dc7b515 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -103,9 +103,88 @@ void EpubReader::render() parser->render_page(state.current_page, renderer, epub); ulog_d(TAG, "rendered page %d of %d", state.current_page, parser->get_page_count()); ulog_d(TAG, "after render: %d", heap_free_size()); + // 绘制半屏覆盖操作层 + if (overlay_active) + { + render_overlay(); + } } void EpubReader::set_state_section(uint16_t current_section) { ulog_i(TAG, "go to section:%d", current_section); state.current_section = current_section; +} + +void EpubReader::render_overlay() +{ + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + int area_y = (page_h * 2) / 3; // 覆盖下方 1/3 屏幕 + int area_h = page_h - area_y; + // 半透明效果不可用,使用浅灰底区分 + renderer->fill_rect(0, area_y, page_w, area_h, 240); + + // 三行布局:3,5,3 + const int rows = 3; + const int cols[rows] = {3, 5, 3}; + const int gap_h = 20; // 行间距 + const int gap_w = 10; + const int row_h = 80; // 每行高度 + // 纵向居中放置三行 + int content_h = rows * row_h + (rows + 1) * gap_h; + int y0 = area_y + (area_h - content_h) / 2; + if (y0 < area_y + 4) y0 = area_y + 4; + + int index = 0; + for (int r = 0; r < rows; ++r) + { + int c = cols[r]; + int usable_w = page_w - (c + 1) * gap_w; + int btn_w = usable_w / c; + int y = y0 + gap_h + r * (row_h + gap_h); + for (int i = 0; i < c; ++i) + { + int x = gap_w + i * (btn_w + gap_w); + bool selected = (index == overlay_selected); + if (selected) + { + for (int k = 0; k < 5; ++k) + { + renderer->draw_rect(x + k, y + k, btn_w - 2 * k, row_h - 2 * k, 0); + } + } + else + { + renderer->draw_rect(x, y, btn_w, row_h, 80); + } + // 文本:第9个显示"确认",其余显示编号 + char label[16]; + if (index == 8) + { + rt_snprintf(label, sizeof(label), "确认"); + } + else + { + rt_snprintf(label, sizeof(label), "%d", index + 1); + } + int t_w = renderer->get_text_width(label); + int t_h = renderer->get_line_height(); + int tx = x + (btn_w - t_w) / 2; + int ty = y + (row_h - t_h) / 2; + renderer->draw_text(tx, ty, label, false, true); + index++; + } + } +} + +void EpubReader::overlay_move_left() +{ + if (!overlay_active) return; + overlay_selected = (overlay_selected - 1 + 11) % 11; +} + +void EpubReader::overlay_move_right() +{ + if (!overlay_active) return; + overlay_selected = (overlay_selected + 1) % 11; } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index 5d46081..75f10ae 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -13,8 +13,12 @@ class EpubReader Epub *epub = nullptr; Renderer *renderer = nullptr; RubbishHtmlParser *parser = nullptr; + // 阅读页半屏覆盖操作层状态 + bool overlay_active = false; + int overlay_selected = 0; // 0..10,共11个 void parse_and_layout_current_section(); + void render_overlay(); public: EpubReader(EpubListItem &state, Renderer *renderer) : state(state), renderer(renderer){}; @@ -24,4 +28,11 @@ class EpubReader void prev(); void render(); void set_state_section(uint16_t current_section); + // 覆盖层控制 + void start_overlay() { overlay_active = true; overlay_selected = 0; } + void stop_overlay() { overlay_active = false; } + bool is_overlay_active() const { return overlay_active; } + void overlay_move_left(); + void overlay_move_right(); + int get_overlay_selected() const { return overlay_selected; } }; \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp index 46ca552..c6c5061 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp @@ -60,8 +60,10 @@ void EpubToc::render() ulog_d(TAG, "Rendering EPUB index"); // what page are we on? int current_page = state.selected_item / ITEMS_PER_PAGE; - // show five items per page - int cell_height = renderer->get_page_height() / ITEMS_PER_PAGE; + // 为底部按钮预留区域与底部间距 + const int bottom_area_height = 100; + const int bottom_margin = 30; + int cell_height = (renderer->get_page_height() - bottom_area_height - bottom_margin) / ITEMS_PER_PAGE; int start_index = current_page * ITEMS_PER_PAGE; int ypos = 0; // starting a fresh page or rendering from scratch? @@ -118,6 +120,47 @@ void EpubToc::render() } state.previous_selected_item = state.selected_item; state.previous_rendered_page = current_page; + + // 绘制底部三按钮区域 + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + int area_y = page_h - bottom_area_height - bottom_margin; + // 背景 + renderer->fill_rect(0, area_y, page_w, bottom_area_height, 255); + // 三个等宽按钮 + int btn_gap = 10; + int btn_w = (page_w - btn_gap * 4) / 3; // 左右边距各一个gap,再加中间两个gap + int btn_h = 80; + int btn_y = area_y + (bottom_area_height - btn_h) / 2; + int btn_x0 = btn_gap; // 上一页 + int btn_x1 = btn_gap * 2 + btn_w; // 主页面 + int btn_x2 = btn_gap * 3 + btn_w * 2; // 下一页 + + auto draw_button = [&](int x, const char* text, bool selected) + { + if (selected) + { + // 多重描边(黑色),与列表选中效果一致 + for (int i = 0; i < 5; ++i) + { + renderer->draw_rect(x + i, btn_y + i, btn_w - 2 * i, btn_h - 2 * i, 0); + } + } + else + { + // 非选中用细描边(灰色) + renderer->draw_rect(x, btn_y, btn_w, btn_h, 80); + } + int t_w = renderer->get_text_width(text); + int t_h = renderer->get_line_height(); + int tx = x + (btn_w - t_w) / 2; + int ty = btn_y + (btn_h - t_h) / 2; + renderer->draw_text(tx, ty, text, false, true); + }; + + draw_button(btn_x0, "上一页", m_bottom_mode && m_bottom_idx == 0); + draw_button(btn_x1, "书库", m_bottom_mode && m_bottom_idx == 1); + draw_button(btn_x2, "下一页", m_bottom_mode && m_bottom_idx == 2); } uint16_t EpubToc::get_selected_toc() diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.h b/epdiy-epub/lib/Epub/EpubList/EpubToc.h index 5ef96a8..56563f0 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.h @@ -32,6 +32,9 @@ class EpubToc EpubListItem &selected_epub; EpubTocState &state; bool m_needs_redraw = false; + // 底部按钮选择状态:是否处于底部按钮选择模式与当前索引(0:上一页,1:主页面,2:下一页) + bool m_bottom_mode = false; + int m_bottom_idx = 1; public: EpubToc(EpubListItem &selected_epub, EpubTocState &state, Renderer *renderer) : renderer(renderer), selected_epub(selected_epub), state(state){}; @@ -42,4 +45,8 @@ class EpubToc void render(); void set_needs_redraw() { m_needs_redraw = true; } uint16_t get_selected_toc(); + // 目录项总数 + int get_items_count() const { return epub ? epub->get_toc_items_count() : 0; } + // 设置底部按钮选择状态 + void set_bottom_selection(bool enabled, int idx) { m_bottom_mode = enabled; m_bottom_idx = idx; } }; \ No newline at end of file diff --git a/epdiy-epub/src/boards/controls/Actions.h b/epdiy-epub/src/boards/controls/Actions.h index 785384d..8e83835 100644 --- a/epdiy-epub/src/boards/controls/Actions.h +++ b/epdiy-epub/src/boards/controls/Actions.h @@ -8,6 +8,7 @@ typedef enum UP, DOWN, SELECT, + UPGLIDE, // 长按触发的上滑操作,用于阅读页半屏操作覆盖 LAST_INTERACTION, MSG_DRAW_LOW_POWER_PAGE, MSG_DRAW_CHARGE_PAGE, diff --git a/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp b/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp index 4f075d2..ebb4e74 100644 --- a/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp @@ -12,6 +12,11 @@ void button_event_handler(int32_t pin, button_action_t action) { action_cbk(UIAction::UP); } + else if (action == BUTTON_LONG_PRESSED) + { + rt_kprintf("长按 1"); + action_cbk(UIAction::UPGLIDE); + } } #else if (pin == EPD_KEY1) @@ -28,10 +33,7 @@ void button_event_handler(int32_t pin, button_action_t action) { action_cbk(UIAction::SELECT); } - else if (action == BUTTON_LONG_PRESSED) - { - rt_kprintf("长按 1"); - } + } else if (pin == EPD_KEY3) { @@ -39,6 +41,7 @@ void button_event_handler(int32_t pin, button_action_t action) { action_cbk(UIAction::UP); } + } #endif diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index ede9f23..d58ca7b 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -185,7 +185,8 @@ static void render_settings_page(Renderer *renderer) } if (settings_selected_idx == SET_TOUCH) { - for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + // 选中强化:多重描边,提高可见度 + for (int i = 0; i < 5; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); } else { @@ -213,7 +214,7 @@ static void render_settings_page(Renderer *renderer) } if (settings_selected_idx == SET_TIMEOUT) { - for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + for (int i = 0; i < 5; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); } else { @@ -246,7 +247,7 @@ static void render_settings_page(Renderer *renderer) } if (settings_selected_idx == SET_FULL_REFRESH) { - for (int i = 0; i < 2; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); + for (int i = 0; i < 5; ++i) renderer->draw_rect(item_x + i, y + i, item_w - 2 * i, item_h - 2 * i, 0); } else { @@ -270,7 +271,7 @@ static void render_settings_page(Renderer *renderer) int confirm_y = page_h - confirm_h - 60; // 距离底部位置 if (settings_selected_idx == SET_CONFIRM) { - for (int i = 0; i < 2; ++i) renderer->draw_rect(confirm_x + i, confirm_y + i, confirm_w - 2 * i, confirm_h - 2 * i, 0); + for (int i = 0; i < 5; ++i) renderer->draw_rect(confirm_x + i, confirm_y + i, confirm_w - 2 * i, confirm_h - 2 * i, 0); } else { diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index ebe3d87..b765824 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -37,9 +37,9 @@ const char *TAG = "main"; typedef enum { MAIN_PAGE, // 新主页面 - SELECTING_EPUB, - SELECTING_TABLE_CONTENTS, - READING_EPUB, + SELECTING_EPUB, // 电子书列表页面(书库) + SELECTING_TABLE_CONTENTS, // 电子书目录页面 + READING_EPUB, // 阅读页面 SETTINGS_PAGE // 通用功能设置页面 } UIState; typedef enum @@ -60,6 +60,7 @@ EpubTocState epub_index_state; void handleEpub(Renderer *renderer, UIAction action); void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw); +void back_to_main_page(); static EpubList *epub_list = nullptr; static EpubReader *reader = nullptr; @@ -70,6 +71,10 @@ Battery *battery = nullptr; Renderer *renderer = nullptr; TouchControls *touch_controls = nullptr; +// 书库页底部按钮选择状态 +static bool library_bottom_mode = false; // 是否处于底部三按钮选择模式 +static int library_bottom_idx = 1; // 当前底部按钮索引:0上一页,1主页面,2下一页 + rt_mq_t ui_queue = RT_NULL; // 主页面选项 @@ -89,34 +94,64 @@ void handleEpub(Renderer *renderer, UIAction action) switch (action) { case UP: - reader->prev(); + if (reader->is_overlay_active()) + { + reader->overlay_move_left(); + } + else + { + reader->prev(); + } break; case DOWN: - reader->next(); + if (reader->is_overlay_active()) + { + reader->overlay_move_right(); + } + else + { + reader->next(); + } break; case SELECT: - - // switch back to main screen - ui_state = SELECTING_EPUB; - renderer->clear_screen(); - // clear the epub reader away - delete reader; - reader = nullptr; - // force a redraw - if (!epub_list) + if (reader->is_overlay_active()) { - epub_list = new EpubList(renderer, epub_list_state); + // 在覆盖层中,SELECT仅作用于覆盖区域:当选中"确认"时关闭覆盖层 + if (reader->get_overlay_selected() == 8) + { + reader->stop_overlay(); + } + // 非“确认”暂不执行其他操作 } - handleEpubList(renderer, NONE, true); + else + { + // switch back to main screen + ui_state = SELECTING_EPUB; + renderer->clear_screen(); + // clear the epub reader away + delete reader; + reader = nullptr; + // force a redraw + if (!epub_list) + { + epub_list = new EpubList(renderer, epub_list_state); + } + handleEpubList(renderer, NONE, true); - return; + return; + } + break; + case UPGLIDE: + // 激活阅读页下半屏覆盖操作层 + reader->start_overlay(); + break; case NONE: default: break; } reader->render(); } - +//目录页的处理 void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw) { if (!contents) @@ -125,32 +160,122 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red contents->set_needs_redraw(); contents->load(); } + static bool toc_bottom_mode = false; + static int toc_bottom_idx = 1; // 0:上一页,1:主页面,2:下一页 + if (needs_redraw) + { + toc_bottom_mode = false; + toc_bottom_idx = 1; + } switch (action) { case UP: - contents->prev(); + if (toc_bottom_mode) + { + toc_bottom_idx = (toc_bottom_idx + 2) % 3; // 左移 + } + else + { + int per_page = 6; + int start_idx = (epub_index_state.selected_item / per_page) * per_page; + if (contents->get_items_count() > 0 && epub_index_state.selected_item == start_idx) + { + toc_bottom_mode = true; + } + else + { + contents->prev(); + } + } break; case DOWN: - contents->next(); + if (toc_bottom_mode) + { + toc_bottom_idx = (toc_bottom_idx + 1) % 3; // 右移 + } + else + { + int per_page = 6; + int start_idx = (epub_index_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + int count = contents->get_items_count(); + if (end_idx >= count) end_idx = count - 1; + if (count > 0 && epub_index_state.selected_item == end_idx) + { + toc_bottom_mode = true; + } + else + { + contents->next(); + } + } break; case SELECT: - // setup the reader state - ui_state = READING_EPUB; - // create the reader and load the book - reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); - reader->set_state_section(contents->get_selected_toc()); - reader->load(); - //switch to reading the epub - delete contents; - handleEpub(renderer, NONE); - return; + if (toc_bottom_mode) + { + int per_page = 6; + int count = contents->get_items_count(); + int current_page = (count > 0) ? (epub_index_state.selected_item / per_page) : 0; + int max_page = (count == 0) ? 0 : ((count - 1) / per_page); + if (toc_bottom_idx == 1) + { + // 书库:切换到书库页面 + rt_kprintf("从目录页返回书库页\n"); + ui_state = SELECTING_EPUB; + if (contents) + { + delete contents; + contents = nullptr; + } + handleEpubList(renderer, NONE, true); + return; + } + else if (toc_bottom_idx == 0) + { + // 上一页 + if (current_page > 0) + { + epub_index_state.selected_item -= per_page; + if (epub_index_state.selected_item < 0) epub_index_state.selected_item = 0; + contents->set_needs_redraw(); + } + toc_bottom_mode = false; + } + else if (toc_bottom_idx == 2) + { + // 下一页 + if (current_page < max_page) + { + epub_index_state.selected_item += per_page; + if (epub_index_state.selected_item >= count) + epub_index_state.selected_item = count - 1; + contents->set_needs_redraw(); + } + toc_bottom_mode = false; + } + } + else + { + // 进入阅读界面 + ui_state = READING_EPUB; + reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); + reader->set_state_section(contents->get_selected_toc()); + reader->load(); + delete contents; + handleEpub(renderer, NONE); + return; + } + break; case NONE: default: break; } + // 将底部选择状态传递给目录渲染 + contents->set_bottom_selection(toc_bottom_mode, toc_bottom_idx); contents->render(); } +//书库页的处理 void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) { // load up the epub list from the filesystem @@ -167,31 +292,114 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) if (needs_redraw) { epub_list->set_needs_redraw(); + // 进入书库页时重置底部选择状态 + library_bottom_mode = false; + library_bottom_idx = 1; } // work out what the user wants us to do switch (action) { case UP: - epub_list->prev(); + if (library_bottom_mode) + { + // UP 表示向左选择 + library_bottom_idx = (library_bottom_idx + 2) % 3; + } + else + { + // 若处于当前页第一个条目,UP 切换到底部按钮模式 + int per_page = 4; + int start_idx = (epub_list_state.selected_item / per_page) * per_page; + if (epub_list_state.num_epubs > 0 && epub_list_state.selected_item == start_idx) + { + library_bottom_mode = true; + } + else + { + epub_list->prev(); + } + } break; case DOWN: - epub_list->next(); + if (library_bottom_mode) + { + // DOWN 表示向右选择 + library_bottom_idx = (library_bottom_idx + 1) % 3; + } + else + { + int per_page = 4; + int start_idx = (epub_list_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + if (end_idx >= epub_list_state.num_epubs) end_idx = epub_list_state.num_epubs - 1; + // 若处于当前页最后一个条目,DOWN 切换到底部按钮模式 + if (epub_list_state.num_epubs > 0 && epub_list_state.selected_item == end_idx) + { + library_bottom_mode = true; + } + else + { + epub_list->next(); + } + } break; case SELECT: - // switch to reading the epub - // setup the reader state - ui_state = SELECTING_TABLE_CONTENTS; - // create the reader and load the book - contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); - contents->load(); - contents->set_needs_redraw(); - handleEpubTableContents(renderer, NONE, true); - return; + if (library_bottom_mode) + { + int per_page = 4; + int current_page = epub_list_state.selected_item / per_page; + int max_page = (epub_list_state.num_epubs == 0) ? 0 : ( (epub_list_state.num_epubs - 1) / per_page ); + if (library_bottom_idx == 1) + { + // 主页面:返回主页面 + rt_kprintf("从书库页返回主页面\n"); + back_to_main_page(); + return; + } + else if (library_bottom_idx == 0) + { + // 上一页 + if (current_page > 0) + { + epub_list_state.selected_item -= per_page; + if (epub_list_state.selected_item < 0) epub_list_state.selected_item = 0; + epub_list->set_needs_redraw(); + } + // 切回条目选择模式 + library_bottom_mode = false; + } + else if (library_bottom_idx == 2) + { + // 下一页 + if (current_page < max_page) + { + epub_list_state.selected_item += per_page; + if (epub_list_state.selected_item >= epub_list_state.num_epubs) + epub_list_state.selected_item = epub_list_state.num_epubs - 1; + epub_list->set_needs_redraw(); + } + // 切回条目选择模式 + library_bottom_mode = false; + } + } + else + { + // 进入目录选择页面 + ui_state = SELECTING_TABLE_CONTENTS; + contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); + contents->load(); + contents->set_needs_redraw(); + handleEpubTableContents(renderer, NONE, true); + return; + } + break; case NONE: default: // nothing to do break; } + // 将底部选择状态传递给列表渲染 + epub_list->set_bottom_selection(library_bottom_mode, library_bottom_idx); epub_list->render(); } // TODO - add the battery level @@ -275,10 +483,20 @@ void handleUserInteraction(Renderer *renderer, UIAction ui_action, bool needs_re { case MAIN_PAGE: // 新主页面 handleMainPage(renderer, ui_action, needs_redraw); - if (ui_action == SELECT && screen_get_main_selected_option() == 2) + if (ui_action == SELECT && screen_get_main_selected_option() == 2) //切换到设置页面 { ui_state = SETTINGS_PAGE; - (void)handleSettingsPage(renderer, NONE, true); + (void)handleSettingsPage(renderer, NONE, true); + } + else if (ui_action == SELECT && screen_get_main_selected_option() == 1) //切换到阅读页面 + { + // ui_state = READING_EPUB; + // handleEpub(renderer, NONE); + } + else if (ui_action == SELECT && screen_get_main_selected_option() == 0) //切换到书库页面 + { + ui_state = SELECTING_EPUB; + handleEpubList(renderer, NONE, true); } break; case READING_EPUB: //阅读界面 @@ -322,8 +540,9 @@ const char* getCurrentPageName() { //回到主界面接口 void back_to_main_page() { - if (strcmp(getCurrentPageName(), "MAIN_MENU") == 0) + if (ui_state == MAIN_PAGE) { + rt_kprintf("已经在主页面,无需返回\n"); return; } lowpower_ui_state = MAIN_MENU; @@ -389,7 +608,7 @@ void draw_welcome_page(Battery *battery) } -// 绘制低电量页面 +// 低电量页面 void draw_low_power_page(Battery *battery) { if (strcmp(getCurrentPageName(), "LOW_POWER_PAGE") == 0) From bddf90d93d5ec3d97a51bbf51035741a6d14d832 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Wed, 14 Jan 2026 17:58:27 +0800 Subject: [PATCH 14/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=98=85=E8=AF=BB?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=EF=BC=9A1.=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20=E7=9B=AE=E5=BD=95=E9=A1=B5=E9=9D=A2=20=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=20=E4=B9=A6=E5=BA=93=E9=A1=B5=E9=9D=A2=E7=9A=84?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD=202.=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=B4=AF=E7=A7=AF=E8=B7=B3=E8=BD=AC=E9=A1=B5=E9=9D=A2=E7=9A=84?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 70 ++++++++++++++++++--- epdiy-epub/lib/Epub/EpubList/EpubReader.h | 8 ++- epdiy-epub/src/main.cpp | 56 +++++++++++++++-- 3 files changed, 122 insertions(+), 12 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index dc7b515..a13ace7 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -157,15 +157,24 @@ void EpubReader::render_overlay() { renderer->draw_rect(x, y, btn_w, row_h, 80); } - // 文本:第9个显示"确认",其余显示编号 + // 文本映射: + // 1:"<" 2:保留原编号 3:">" 4:"-5" 5:"-1" 6:"acc" 7:"+1" 8:"+5" 9:"确认" 10:"目录" 11:"书库" char label[16]; - if (index == 8) + switch (index) { - rt_snprintf(label, sizeof(label), "确认"); - } - else - { - rt_snprintf(label, sizeof(label), "%d", index + 1); + case 0: rt_snprintf(label, sizeof(label), "<"); break; + case 1: rt_snprintf(label, sizeof(label), "2"); break; + case 2: rt_snprintf(label, sizeof(label), ">"); break; + case 3: rt_snprintf(label, sizeof(label), "-5"); break; + case 4: rt_snprintf(label, sizeof(label), "-1"); break; + case 5: rt_snprintf(label, sizeof(label), "%d", overlay_jump_acc); break; + case 6: rt_snprintf(label, sizeof(label), "+1"); break; + case 7: rt_snprintf(label, sizeof(label), "+5"); break; + case 8: rt_snprintf(label, sizeof(label), "确认"); break; + case 9: rt_snprintf(label, sizeof(label), "目录"); break; + case 10: rt_snprintf(label, sizeof(label), "书库"); break; + default: + break; } int t_w = renderer->get_text_width(label); int t_h = renderer->get_line_height(); @@ -187,4 +196,51 @@ void EpubReader::overlay_move_right() { if (!overlay_active) return; overlay_selected = (overlay_selected + 1) % 11; +} + +void EpubReader::jump_pages(int delta) +{ + if (delta == 0) return; + if (!parser) //没解析的情况下 则解析当前节 + { + parse_and_layout_current_section(); + } + int spine_count = epub ? epub->get_spine_items_count() : 0; //获取章节总数 + if (spine_count <= 0) return; + + auto at_book_start = [&]() -> bool { + return state.current_section == 0 && state.current_page == 0; + }; + auto at_book_end = [&]() -> bool { + // 需要知道当前节页数;parser 非空时有效 + if (!parser) return false; + return (state.current_section == spine_count - 1) && (state.current_page >= state.pages_in_current_section - 1); + }; + // 开始实现页面跳转 + if (delta > 0) + { + for (int i = 0; i < delta; ++i) + { + if (at_book_end()) break; + next(); + // 如果跨节,parser 在 next() 时会置空;后续渲染时会自动 parse + if (!parser) + { + parse_and_layout_current_section(); + } + } + } + else // delta < 0 + { + for (int i = 0; i < -delta; ++i) + { + if (at_book_start()) break; + prev(); + if (!parser) + { + //空则解析 + parse_and_layout_current_section(); + } + } + } } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index 75f10ae..1ceebe8 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -16,6 +16,7 @@ class EpubReader // 阅读页半屏覆盖操作层状态 bool overlay_active = false; int overlay_selected = 0; // 0..10,共11个 + int overlay_jump_acc = 0; // 覆盖层累积跳页值(可为负) void parse_and_layout_current_section(); void render_overlay(); @@ -26,13 +27,18 @@ class EpubReader bool load(); void next(); void prev(); + void jump_pages(int delta); void render(); void set_state_section(uint16_t current_section); // 覆盖层控制 - void start_overlay() { overlay_active = true; overlay_selected = 0; } + void start_overlay() { overlay_active = true; overlay_selected = 0; overlay_jump_acc = 0; } void stop_overlay() { overlay_active = false; } bool is_overlay_active() const { return overlay_active; } void overlay_move_left(); void overlay_move_right(); int get_overlay_selected() const { return overlay_selected; } + // 覆盖层跳页累积控制 + void overlay_add_jump(int d) { overlay_jump_acc += d; } + void overlay_reset_jump() { overlay_jump_acc = 0; } + int overlay_get_jump() const { return overlay_jump_acc; } }; \ No newline at end of file diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index b765824..adaecd9 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -83,7 +83,7 @@ typedef enum { OPTION_CONTINUE_READING, // 继续阅读 -> 打印 2 OPTION_ENTER_SETTINGS // 进入设置 -> 打印 3 } MainOption; - +void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw); void handleEpub(Renderer *renderer, UIAction action) { if (!reader) @@ -116,12 +116,60 @@ void handleEpub(Renderer *renderer, UIAction action) case SELECT: if (reader->is_overlay_active()) { - // 在覆盖层中,SELECT仅作用于覆盖区域:当选中"确认"时关闭覆盖层 - if (reader->get_overlay_selected() == 8) + int sel = reader->get_overlay_selected(); + if (sel == 9) //目录 { + ui_state = SELECTING_TABLE_CONTENTS; reader->stop_overlay(); + delete reader; + reader = nullptr; + contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); + contents->load(); + contents->set_needs_redraw(); + handleEpubTableContents(renderer, NONE, true); + return; } - // 非“确认”暂不执行其他操作 + else if (sel == 8) //确认:1.按第六格累积值跳页 + { + int delta = reader->overlay_get_jump(); + if (delta != 0) + { + reader->jump_pages(delta); + } + reader->overlay_reset_jump(); + reader->stop_overlay(); + } + else if (sel == 10) //书库 + { + ui_state = SELECTING_EPUB; + reader->stop_overlay(); + renderer->clear_screen(); + delete reader; + reader = nullptr; + if (!epub_list) + { + epub_list = new EpubList(renderer, epub_list_state); + } + handleEpubList(renderer, NONE, true); + return; + } + else if (sel == 3) + { + reader->overlay_add_jump(-5); + } + else if (sel == 4) + { + reader->overlay_add_jump(-1); + } + else if (sel == 6) + { + reader->overlay_add_jump(1); + } + else if (sel == 7) + { + reader->overlay_add_jump(5); + } + } else { From 6e5506a981f6f4da53bdaaa04202c1cd3b5833dc Mon Sep 17 00:00:00 2001 From: smiling boy Date: Thu, 15 Jan 2026 11:22:33 +0800 Subject: [PATCH 15/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=98=85=E8=AF=BB?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E9=A1=B5=EF=BC=9A1=EF=BC=8C2=EF=BC=8C3?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E7=9F=A9=E5=BD=A2=E5=AE=9E=E7=8E=B0=20?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E8=A7=A6=E6=8E=A7=20=E4=B8=8E=20=E5=85=A8?= =?UTF-8?q?=E5=88=B7=E5=91=A8=E6=9C=9F=E6=AC=A1=E6=95=B0=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8A=9F=E8=83=BD=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=EF=BC=9A=E5=85=A8=E5=88=B7?= =?UTF-8?q?=E5=91=A8=E6=9C=9F=E6=AC=A1=E6=95=B0=E5=8A=A8=E6=80=81=E6=98=BE?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 125 +++++++++++++++----- epdiy-epub/lib/Epub/EpubList/EpubReader.h | 15 +++ epdiy-epub/src/epub_screen.cpp | 42 ++++++- epdiy-epub/src/epub_screen.h | 5 +- epdiy-epub/src/main.cpp | 46 +++++++ 5 files changed, 202 insertions(+), 31 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index a13ace7..c885238 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -12,6 +12,7 @@ #include "../RubbishHtmlParser/RubbishHtmlParser.h" #include "../Renderer/Renderer.h" #include "epub_mem.h" +#include "epub_screen.h" static const char *TAG = "EREADER"; extern "C" rt_uint32_t heap_free_size(void); @@ -121,7 +122,7 @@ void EpubReader::render_overlay() int page_h = renderer->get_page_height(); int area_y = (page_h * 2) / 3; // 覆盖下方 1/3 屏幕 int area_h = page_h - area_y; - // 半透明效果不可用,使用浅灰底区分 + renderer->fill_rect(0, area_y, page_w, area_h, 240); // 三行布局:3,5,3 @@ -136,15 +137,86 @@ void EpubReader::render_overlay() if (y0 < area_y + 4) y0 = area_y + 4; int index = 0; + auto fill_label = [&](int idx, char *label, size_t cap) { + switch (idx) + { + case 0: rt_snprintf(label, cap, "<"); break; + case 1: + { + if (overlay_center_mode == CENTER_TOUCH) + { + rt_snprintf(label, cap, "触摸开关:%s", overlay_touch_enabled ? "开" : "关"); + } + else + { + int v = overlay_get_full_refresh_value(); + if (v == 0) + rt_snprintf(label, cap, "全刷周期:不刷新"); + else + rt_snprintf(label, cap, "全刷周期:%d次", v); + } + break; + } + case 2: rt_snprintf(label, cap, ">"); break; + case 3: rt_snprintf(label, cap, "-5"); break; + case 4: rt_snprintf(label, cap, "-1"); break; + case 5: rt_snprintf(label, cap, "%d", overlay_jump_acc); break; + case 6: rt_snprintf(label, cap, "+1"); break; + case 7: rt_snprintf(label, cap, "+5"); break; + case 8: rt_snprintf(label, cap, "确认"); break; + case 9: rt_snprintf(label, cap, "目录"); break; + case 10: rt_snprintf(label, cap, "书库"); break; + default: label[0] = '\0'; break; + } + }; for (int r = 0; r < rows; ++r) { int c = cols[r]; - int usable_w = page_w - (c + 1) * gap_w; - int btn_w = usable_w / c; int y = y0 + gap_h + r * (row_h + gap_h); - for (int i = 0; i < c; ++i) + // 顶部第1行(3列)采用不等宽布局:1/3半宽,2双宽 + if (r == 0) { - int x = gap_w + i * (btn_w + gap_w); + int usable_w = page_w - (c + 1) * gap_w; + // 宽度权重为 1:3:1(约 左20% / 中60% / 右20%) + int w0 = (usable_w * 1) / 5; + int w1 = (usable_w * 3) / 5; + int w2 = usable_w - w0 - w1; + int widths[3] = { w0, w1, w2 }; + int cur_x = gap_w; + for (int i = 0; i < c; ++i) + { + int w = widths[i]; + int x = cur_x; + bool selected = (index == overlay_selected); + if (selected) + { + for (int k = 0; k < 5; ++k) + { + renderer->draw_rect(x + k, y + k, w - 2 * k, row_h - 2 * k, 0); + } + } + else + { + renderer->draw_rect(x, y, w, row_h, 80); + } + char label[32]; + fill_label(index, label, sizeof(label)); + int t_w = renderer->get_text_width(label); + int t_h = renderer->get_line_height(); + int tx = x + (w - t_w) / 2; + int ty = y + (row_h - t_h) / 2; + renderer->draw_text(tx, ty, label, false, true); + index++; + cur_x = x + w + gap_w; + } + } + else + { + int usable_w = page_w - (c + 1) * gap_w; + int btn_w = usable_w / c; + for (int i = 0; i < c; ++i) + { + int x = gap_w + i * (btn_w + gap_w); bool selected = (index == overlay_selected); if (selected) { @@ -157,31 +229,15 @@ void EpubReader::render_overlay() { renderer->draw_rect(x, y, btn_w, row_h, 80); } - // 文本映射: - // 1:"<" 2:保留原编号 3:">" 4:"-5" 5:"-1" 6:"acc" 7:"+1" 8:"+5" 9:"确认" 10:"目录" 11:"书库" - char label[16]; - switch (index) - { - case 0: rt_snprintf(label, sizeof(label), "<"); break; - case 1: rt_snprintf(label, sizeof(label), "2"); break; - case 2: rt_snprintf(label, sizeof(label), ">"); break; - case 3: rt_snprintf(label, sizeof(label), "-5"); break; - case 4: rt_snprintf(label, sizeof(label), "-1"); break; - case 5: rt_snprintf(label, sizeof(label), "%d", overlay_jump_acc); break; - case 6: rt_snprintf(label, sizeof(label), "+1"); break; - case 7: rt_snprintf(label, sizeof(label), "+5"); break; - case 8: rt_snprintf(label, sizeof(label), "确认"); break; - case 9: rt_snprintf(label, sizeof(label), "目录"); break; - case 10: rt_snprintf(label, sizeof(label), "书库"); break; - default: - break; - } + char label[32]; + fill_label(index, label, sizeof(label)); int t_w = renderer->get_text_width(label); int t_h = renderer->get_line_height(); int tx = x + (btn_w - t_w) / 2; int ty = y + (row_h - t_h) / 2; renderer->draw_text(tx, ty, label, false, true); index++; + } } } } @@ -208,11 +264,14 @@ void EpubReader::jump_pages(int delta) int spine_count = epub ? epub->get_spine_items_count() : 0; //获取章节总数 if (spine_count <= 0) return; - auto at_book_start = [&]() -> bool { + //检查是不是第一页 + auto at_book_start = [&]() -> bool + { return state.current_section == 0 && state.current_page == 0; }; - auto at_book_end = [&]() -> bool { - // 需要知道当前节页数;parser 非空时有效 + //检查是不是最后一页 + auto at_book_end = [&]() -> bool + { if (!parser) return false; return (state.current_section == spine_count - 1) && (state.current_page >= state.pages_in_current_section - 1); }; @@ -238,9 +297,19 @@ void EpubReader::jump_pages(int delta) prev(); if (!parser) { - //空则解析 + //空就解析 parse_and_layout_current_section(); } } } +} + +void EpubReader::overlay_cycle_full_refresh() +{ + screen_cycle_full_refresh_period(); +} + +int EpubReader::overlay_get_full_refresh_value() const +{ + return screen_get_full_refresh_period(); } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index 1ceebe8..355278f 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -17,6 +17,13 @@ class EpubReader bool overlay_active = false; int overlay_selected = 0; // 0..10,共11个 int overlay_jump_acc = 0; // 覆盖层累积跳页值(可为负) + // 覆盖层中心属性模式:触控开关 或 全刷周期 + enum OverlayCenterMode { CENTER_TOUCH = 0, CENTER_FULL_REFRESH = 1 }; + OverlayCenterMode overlay_center_mode = CENTER_TOUCH; + // 触控开关当前状态(由上层同步) + bool overlay_touch_enabled = false; + // 全刷周期索引:0->5, 1->10, 2->20, 3->不刷新(0) + int overlay_fr_idx = 0; void parse_and_layout_current_section(); void render_overlay(); @@ -41,4 +48,12 @@ class EpubReader void overlay_add_jump(int d) { overlay_jump_acc += d; } void overlay_reset_jump() { overlay_jump_acc = 0; } int overlay_get_jump() const { return overlay_jump_acc; } + // 覆盖层中心属性控制 + void overlay_set_center_mode_touch() { overlay_center_mode = CENTER_TOUCH; } + void overlay_set_center_mode_full_refresh() { overlay_center_mode = CENTER_FULL_REFRESH; } + bool overlay_is_center_touch() const { return overlay_center_mode == CENTER_TOUCH; } + void overlay_set_touch_enabled(bool en) { overlay_touch_enabled = en; } + bool overlay_get_touch_enabled() const { return overlay_touch_enabled; } + void overlay_cycle_full_refresh(); + int overlay_get_full_refresh_value() const; }; \ No newline at end of file diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index d58ca7b..1750d5d 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -13,7 +13,34 @@ typedef enum } MainOption; static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” -static int full_refresh_period = 10; // 全刷周期次数,仅用于设置页显示 +// 全刷周期选项:5、10、20、不刷新(0) +static const int kFullRefreshOptions[] = {5, 10, 20, 0}; +static const int kFullRefreshOptionsCount = sizeof(kFullRefreshOptions) / sizeof(kFullRefreshOptions[0]); +static int full_refresh_idx = 1; // 默认10次 + +// 获取当前全刷周期值 +int screen_get_full_refresh_period() +{ + return kFullRefreshOptions[full_refresh_idx]; +} + +// 切换全刷周期(循环) +void screen_cycle_full_refresh_period() +{ + full_refresh_idx = (full_refresh_idx + 1) % kFullRefreshOptionsCount; // ?% 4 +} + +// 设置全刷周期索引 +void screen_set_full_refresh_idx(int idx) +{ + if (idx >= 0 && idx < kFullRefreshOptionsCount) full_refresh_idx = idx; +} + +// 获取当前全刷周期索引 +int screen_get_full_refresh_idx() +{ + return full_refresh_idx; +} // 设置页列表项 typedef enum { SET_TOUCH = 0, SET_TIMEOUT = 1, SET_FULL_REFRESH = 2, SET_CONFIRM = 3 } SettingsItem; @@ -254,7 +281,11 @@ static void render_settings_page(Renderer *renderer) renderer->draw_rect(item_x, y, item_w, item_h, 0); } char buf3[64]; - rt_snprintf(buf3, sizeof(buf3), "全刷周期:%d 次", full_refresh_period); + int fr_val = screen_get_full_refresh_period(); + if (fr_val == 0) + rt_snprintf(buf3, sizeof(buf3), "全刷周期:不刷新"); + else + rt_snprintf(buf3, sizeof(buf3), "全刷周期:%d 次", fr_val); { int t3_w = renderer->get_text_width(buf3); int tx = item_x + (item_w - t3_w) / 2; @@ -345,6 +376,13 @@ bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) render_settings_page(renderer); break; } + if (settings_selected_idx == SET_FULL_REFRESH) + { + // SELECT 在全刷周期项上为加操作(循环) + screen_cycle_full_refresh_period(); + render_settings_page(renderer); + break; + } if (settings_selected_idx == SET_CONFIRM) { // 由上层切回主页面 diff --git a/epdiy-epub/src/epub_screen.h b/epdiy-epub/src/epub_screen.h index c97c3c4..a1b589d 100644 --- a/epdiy-epub/src/epub_screen.h +++ b/epdiy-epub/src/epub_screen.h @@ -21,4 +21,7 @@ void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw); // 设置页面交互与渲染;返回 true 表示确认并退出到主页面 bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw); - +// 切换全刷周期(循环) +void screen_cycle_full_refresh_period(); +// 获取当前全刷周期值 +int screen_get_full_refresh_period(); \ No newline at end of file diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index adaecd9..8e34237 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -117,6 +117,48 @@ void handleEpub(Renderer *renderer, UIAction action) if (reader->is_overlay_active()) { int sel = reader->get_overlay_selected(); + // 1/3:改变中心属性;2:执行当前属性(触控取反 / 全刷周期循环) + if (sel == 0) + { + if(reader->overlay_is_center_touch()) + { + reader->overlay_set_center_mode_full_refresh(); + } + else + { + reader->overlay_set_center_mode_touch(); + } + } + else if (sel == 2) + { + if(reader->overlay_is_center_touch()) + { + reader->overlay_set_center_mode_full_refresh(); + } + else + { + reader->overlay_set_center_mode_touch(); + } + + } + else if (sel == 1) + { + // 中心矩形:根据当前属性执行 + if (reader->overlay_is_center_touch()) + { + bool cur = touch_controls ? touch_controls->isTouchEnabled() : false; + if (touch_controls) + { + touch_controls->setTouchEnable(!cur); + if (!cur) touch_controls->powerOnTouch(); else touch_controls->powerOffTouch(); + } + reader->overlay_set_touch_enabled(!cur); + } + else + { + reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/不刷新 之间循环 + } + } if (sel == 9) //目录 { ui_state = SELECTING_TABLE_CONTENTS; @@ -192,6 +234,10 @@ void handleEpub(Renderer *renderer, UIAction action) case UPGLIDE: // 激活阅读页下半屏覆盖操作层 reader->start_overlay(); + // 默认中心属性为触控开关,初始同步当前触控状态 + reader->overlay_set_center_mode_touch(); + if (touch_controls) + reader->overlay_set_touch_enabled(touch_controls->isTouchEnabled()); break; case NONE: default: From 35a06a36327db5c4725d6c1579e41a7c07fdd72b Mon Sep 17 00:00:00 2001 From: smiling boy Date: Thu, 15 Jan 2026 16:33:03 +0800 Subject: [PATCH 16/25] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=85=A8=E5=88=B7=E5=91=A8=E6=9C=9F=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 2 +- epdiy-epub/lib/Epub/EpubList/EpubReader.h | 2 +- .../boards/display_dbi/epd_configs_custom.c | 8 +---- .../boards/display_dbi/epd_configs_r7d005.c | 6 +--- .../boards/display_dbi/epd_configs_yzc085.c | 7 ++-- .../src/boards/display_dbi/epd_display.c | 30 +++++++++++++++-- .../src/boards/display_spi/epd_display.c | 32 +++++++++++++------ epdiy-epub/src/epub_screen.cpp | 9 ++++-- epdiy-epub/src/main.cpp | 5 ++- 9 files changed, 67 insertions(+), 34 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index c885238..90685cb 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -151,7 +151,7 @@ void EpubReader::render_overlay() { int v = overlay_get_full_refresh_value(); if (v == 0) - rt_snprintf(label, cap, "全刷周期:不刷新"); + rt_snprintf(label, cap, "全刷周期:每次"); else rt_snprintf(label, cap, "全刷周期:%d次", v); } diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index 355278f..a5a71b0 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -22,7 +22,7 @@ class EpubReader OverlayCenterMode overlay_center_mode = CENTER_TOUCH; // 触控开关当前状态(由上层同步) bool overlay_touch_enabled = false; - // 全刷周期索引:0->5, 1->10, 2->20, 3->不刷新(0) + // 全刷周期索引:0->5, 1->10, 2->20, 3->每次(0) int overlay_fr_idx = 0; void parse_and_layout_current_section(); diff --git a/epdiy-epub/src/boards/display_dbi/epd_configs_custom.c b/epdiy-epub/src/boards/display_dbi/epd_configs_custom.c index 439b08f..7fd95f0 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_configs_custom.c +++ b/epdiy-epub/src/boards/display_dbi/epd_configs_custom.c @@ -11,9 +11,6 @@ -#define PART_DISP_TIMES 10 // After PART_DISP_TIMES-1 partial refreshes, perform a full refresh once -static int reflesh_times = 0; - void epd_wave_table(void) { @@ -28,14 +25,11 @@ void epd_wave_table(void) uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) { uint32_t frames = 0; - if (reflesh_times % PART_DISP_TIMES == 0) { + if (mode = = EPD_DRAW_MODE_FULL) { frames = waveform_bin_reader_get_frames(temperature, EPD_DRAW_MODE_FULL); - reflesh_times = 0; } else { frames = waveform_bin_reader_get_frames(temperature, EPD_DRAW_MODE_PARTIAL); } - reflesh_times++; - return frames; } diff --git a/epdiy-epub/src/boards/display_dbi/epd_configs_r7d005.c b/epdiy-epub/src/boards/display_dbi/epd_configs_r7d005.c index 8e78e44..733a806 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_configs_r7d005.c +++ b/epdiy-epub/src/boards/display_dbi/epd_configs_r7d005.c @@ -3,8 +3,6 @@ #include "mem_section.h" #include "string.h" #ifdef LCD_USING_EPD_R7D005 -#define PART_DISP_TIMES 10 // After PART_DISP_TIMES-1 partial refreshes, perform a full refresh once -static int reflesh_times = 0; // 8bit lookup table for the current frame (high 4 bits: old data, low 4 bits: new data). // The output is 2-bit data. @@ -83,8 +81,7 @@ void epd_wave_table(void) uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) { const WaveTableEntry *selected_table = NULL; - - if (reflesh_times % PART_DISP_TIMES == 0) { + if (EPD_DRAW_MODE_FULL == mode) { selected_table = &full_wave_table; } else { @@ -95,7 +92,6 @@ uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) selected_table = &full_wave_table; } p_current_wave_from = (const uint8_t *)&selected_table->wave_table[0][0]; - reflesh_times++; return selected_table->frame_count; } diff --git a/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c b/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c index fd9556b..4d6e60e 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c +++ b/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c @@ -3,8 +3,7 @@ #include "mem_section.h" #include "string.h" #if defined(LCD_USING_EPD_YZC085_V100) || defined(LCD_USING_EPD_YZC146_V100) -#define PART_DISP_TIMES 10 // After PART_DISP_TIMES-1 partial refreshes, perform a full refresh once -static int reflesh_times = 0; + // 8bit lookup table for the current frame (high 4 bits: old data, low 4 bits: new data). // The output is 2-bit data. @@ -84,8 +83,7 @@ void epd_wave_table(void) uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) { const WaveTableEntry *wave_table = NULL; - - if (reflesh_times % PART_DISP_TIMES == 0) { + if (EPD_DRAW_MODE_FULL == mode) { wave_table = &full_wave_table; } else { @@ -96,7 +94,6 @@ uint32_t epd_wave_table_get_frames(int temperature, EpdDrawMode mode) wave_table = &full_wave_table; } p_current_wave_from = (const uint8_t *)&wave_table->wave_table[0][0]; - reflesh_times++; return wave_table->frame_count; } diff --git a/epdiy-epub/src/boards/display_dbi/epd_display.c b/epdiy-epub/src/boards/display_dbi/epd_display.c index 600b260..8cf0ebf 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_display.c +++ b/epdiy-epub/src/boards/display_dbi/epd_display.c @@ -91,6 +91,9 @@ static uint32_t wait_lcd_ticks; static uint16_t epic_out_buffer_idx = 0; static uint16_t epic_out_buffer[2][LCD_HOR_RES_MAX]; static uint32_t lut_copy_ticks; + +static int g_part_disp_times = 10; // After g_part_disp_times-1 partial refreshes, perform a full refresh once +static int reflesh_times = 0; // Total number of refreshes performed /* Define a mixed grey framebuffer on PSRAM high 4 bits for old pixel and low 4 bits for new pixel in every byte. @@ -525,6 +528,15 @@ void epd_load_and_send_pic(LCDC_HandleTypeDef *hlcdc, uint32_t line_type, const } } +void set_part_disp_times(int val) +{ + g_part_disp_times = val > 0 ? val : 1; + reflesh_times = 1; +} +int get_part_disp_times(void) +{ + return g_part_disp_times; +} L1_RET_CODE_SECT(epd_codes, static void LCD_WriteMultiplePixels(LCDC_HandleTypeDef *hlcdc, const uint8_t *RGBCode, uint16_t Xpos0, uint16_t Ypos0, uint16_t Xpos1, uint16_t Ypos1)) { @@ -554,9 +566,21 @@ L1_RET_CODE_SECT(epd_codes, static void LCD_WriteMultiplePixels(LCDC_HandleTypeD uint8_t temperature = 26; + EpdDrawMode mode; + if (reflesh_times % g_part_disp_times == 0) + { + rt_kprintf("cleared all \n"); + mode = EPD_DRAW_MODE_FULL; + } + else + { + rt_kprintf("executing partial refresh, this is the %dth partial refresh (there are %d partial refreshes left until the next full refresh)\n", + (reflesh_times % g_part_disp_times), + g_part_disp_times - (reflesh_times % g_part_disp_times)); + mode = EPD_DRAW_MODE_PARTIAL; + } - - frame_times = epd_wave_table_get_frames(temperature, EPD_DRAW_MODE_AUTO); + frame_times = epd_wave_table_get_frames(temperature, mode); CopyToMixedGrayBuffer(hlcdc, RGBCode, Xpos0, Ypos0, Xpos1, Ypos1); LOG_I("Convert layer data take=%d(ms) \r\n", rt_tick_get() - start_tick); @@ -664,6 +688,8 @@ L1_RET_CODE_SECT(epd_codes, static void LCD_WriteMultiplePixels(LCDC_HandleTypeD rt_tick_get() - start_tick, wait_lcd_ticks / 240, lut_copy_ticks / 240); + reflesh_times++; + EPD_GMODE_L_hs(); EPD_STV_L_hs(); TPS_WAKEUP_L_hs(); diff --git a/epdiy-epub/src/boards/display_spi/epd_display.c b/epdiy-epub/src/boards/display_spi/epd_display.c index 60860bd..09f0563 100644 --- a/epdiy-epub/src/boards/display_spi/epd_display.c +++ b/epdiy-epub/src/boards/display_spi/epd_display.c @@ -47,10 +47,11 @@ #define REG_VDCS 0x82 #define REG_WRITE_NEW_DATA 0x13 -static int reflesh_times; +static int reflesh_times = 0; static uint8_t current_refresh_mode; static unsigned char LUT_Flag = 0; // LUT切换标志 static unsigned char Var_Temp = 0; // 温度值 +static int g_part_disp_times = 10; // After g_part_disp_times-1 partial refreshes, perform a full refresh once static LCDC_InitTypeDef lcdc_int_cfg = { .lcd_itf = LCDC_INTF_SPI_DCX_1DATA, @@ -79,6 +80,16 @@ static void EPD_LoadLUT(LCDC_HandleTypeDef *hlcdc, uint8_t lut_mode); static rt_sem_t epd_busy_sem = RT_NULL; +void set_part_disp_times(int val) +{ + g_part_disp_times = val > 0 ? val : 1; + reflesh_times = 1; +} +int get_part_disp_times(void) +{ + return g_part_disp_times; +} + static void epd_busy_callback(void *args) { rt_sem_release(epd_busy_sem); @@ -123,18 +134,19 @@ static void EPD_ReadBusy(void) } static uint8_t epd_get_refresh_mode(void) { - uint8_t mode = 2; // 默认局刷(DU模式) - - if (reflesh_times % PART_DISP_TIMES == 0) + uint8_t mode; + if (reflesh_times % g_part_disp_times == 0) { - mode = 1; // 全刷(GC模式) - } - - if (Var_Temp < 0 || Var_Temp > 50) + rt_kprintf("cleared all \n"); + mode = 1; //全刷 + } + else { - mode = 1; + rt_kprintf("executing partial refresh, this is the %dth partial refresh (there are %d partial refreshes left until the next full refresh)\n", + (reflesh_times % g_part_disp_times), + g_part_disp_times - (reflesh_times % g_part_disp_times)); + mode = 2; //局刷 } - current_refresh_mode = mode; return mode; } diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index 1750d5d..fbfdc7e 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -3,6 +3,10 @@ extern TouchControls *touch_controls; +extern "C" +{ + extern void set_part_disp_times(int val); +} // 主页面选项 typedef enum @@ -13,7 +17,7 @@ typedef enum } MainOption; static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” -// 全刷周期选项:5、10、20、不刷新(0) +// 全刷周期选项:5、10、20、每次(0) static const int kFullRefreshOptions[] = {5, 10, 20, 0}; static const int kFullRefreshOptionsCount = sizeof(kFullRefreshOptions) / sizeof(kFullRefreshOptions[0]); static int full_refresh_idx = 1; // 默认10次 @@ -283,7 +287,7 @@ static void render_settings_page(Renderer *renderer) char buf3[64]; int fr_val = screen_get_full_refresh_period(); if (fr_val == 0) - rt_snprintf(buf3, sizeof(buf3), "全刷周期:不刷新"); + rt_snprintf(buf3, sizeof(buf3), "全刷周期:每次"); else rt_snprintf(buf3, sizeof(buf3), "全刷周期:%d 次", fr_val); { @@ -380,6 +384,7 @@ bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) { // SELECT 在全刷周期项上为加操作(循环) screen_cycle_full_refresh_period(); + set_part_disp_times(screen_get_full_refresh_period()); render_settings_page(renderer); break; } diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 8e34237..7d020f9 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -25,6 +25,7 @@ extern "C" { int main(); rt_uint32_t heap_free_size(void); + extern void set_part_disp_times(int val); extern const uint8_t low_power_map[]; extern const uint8_t chargeing_map[]; extern const uint8_t welcome_map[]; @@ -84,6 +85,7 @@ typedef enum { OPTION_ENTER_SETTINGS // 进入设置 -> 打印 3 } MainOption; void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw); + void handleEpub(Renderer *renderer, UIAction action) { if (!reader) @@ -156,7 +158,8 @@ void handleEpub(Renderer *renderer, UIAction action) } else { - reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/不刷新 之间循环 + reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/每次(0) 之间循环 + set_part_disp_times(reader->overlay_get_full_refresh_value()); } } if (sel == 9) //目录 From c8b98cb5c0705ab2c798595b80064df914aa2101 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Fri, 16 Jan 2026 14:05:04 +0800 Subject: [PATCH 17/25] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=EF=BC=9A=20=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E9=98=85=E8=AF=BB=E8=BF=9B=E5=BA=A6=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E9=A1=B5=E9=9D=A2=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E7=BC=BA=E9=99=B7=EF=BC=8C=E5=AE=8C=E5=96=84=E7=BB=A7=E7=BB=AD?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 23 +- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 18 + epdiy-epub/lib/Epub/EpubList/EpubToc.cpp | 21 +- .../boards/controls/SF32_TouchControls.cpp | 59 ---- epdiy-epub/src/epub_screen.cpp | 52 ++- epdiy-epub/src/epub_screen.h | 2 +- epdiy-epub/src/main.cpp | 326 ++++++++++-------- 7 files changed, 262 insertions(+), 239 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index 2853941..0394e57 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -193,12 +193,27 @@ void EpubList::render() renderer->draw_rect(i, ypos + PADDING / 2 + i, renderer->get_page_width() - 2 * i, cell_height - PADDING - 2 * i, 255); } } - // draw the selection box around the current selection - if (state.selected_item == i) + // 当不处于底部按钮选择模式时,绘制列表高亮 + // 若处于底部模式,则擦除列表高亮,避免同时双高亮 + if (!m_bottom_mode) { - for (int i = 0; i < 5; i++) + if (state.selected_item == i) + { + for (int line = 0; line < 5; line++) + { + renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 0); + } + } + } + else + { + if (state.selected_item == i) { - renderer->draw_rect(i, ypos + PADDING / 2 + i, renderer->get_page_width() - 2 * i, cell_height - PADDING - 2 * i, 0); + // 擦除之前的黑色高亮边框 + for (int line = 0; line < 5; line++) + { + renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 255); + } } } ypos += cell_height; diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index 90685cb..ca3c17b 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -58,6 +58,9 @@ void EpubReader::parse_and_layout_current_section() parser = new RubbishHtmlParser(html, strlen(html), base_path); epub_mem_free(html); ulog_d(TAG, "After parse: %d", heap_free_size()); + // 为底部章节进度预留高度 + int reserved_bottom = renderer->get_line_height() + 10; + renderer->set_margin_bottom(reserved_bottom); parser->layout(renderer, epub); ulog_d(TAG, "After layout: %d", heap_free_size()); state.pages_in_current_section = parser->get_page_count(); @@ -104,6 +107,21 @@ void EpubReader::render() parser->render_page(state.current_page, renderer, epub); ulog_d(TAG, "rendered page %d of %d", state.current_page, parser->get_page_count()); ulog_d(TAG, "after render: %d", heap_free_size()); + // 章节进度 + if (state.pages_in_current_section > 0) + { + char buf[32]; + rt_snprintf(buf, sizeof(buf), "%d页/%d页", state.current_page + 1, state.pages_in_current_section); + int page_w = renderer->get_page_width(); + int page_h = renderer->get_page_height(); + int text_w = renderer->get_text_width(buf); + int text_h = renderer->get_line_height(); + int x = (page_w - text_w) / 2; + int reserved_bottom = renderer->get_line_height() + 4; + const int progress_up = 6; // 上抬 + int y = page_h - text_h - 10 + reserved_bottom - progress_up; + renderer->draw_text(x, y, buf, false, true); + } // 绘制半屏覆盖操作层 if (overlay_active) { diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp index c6c5061..6f08ff5 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp @@ -108,12 +108,25 @@ void EpubToc::render() renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 255); } } - // draw the selection box around the current selection - if (state.selected_item == i) + // 目录页:仅在非底部按钮模式时显示列表高亮;底部模式下擦除列表高亮 + if (!m_bottom_mode) { - for (int line = 0; line < 3; line++) + if (state.selected_item == i) + { + for (int line = 0; line < 3; line++) + { + renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 0); + } + } + } + else + { + if (state.selected_item == i) { - renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 0); + for (int line = 0; line < 3; line++) + { + renderer->draw_rect(line, ypos + PADDING / 2 + line, renderer->get_page_width() - 2 * line, cell_height - PADDING - 2 * line, 255); + } } } ypos += cell_height; diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index 9d17027..43f4a5a 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -120,21 +120,6 @@ SF32_TouchControls::SF32_TouchControls(Renderer *renderer, ActionCallback_t on_a void SF32_TouchControls::render(Renderer *renderer) { - renderer->set_margin_top(0); - uint16_t x_offset = 10; - uint16_t x_triangle = x_offset + 70; - // DOWN - renderer->draw_rect(x_offset, 1, ui_button_width, ui_button_height, 0); - renderer->draw_triangle(x_triangle, 20, x_triangle - 5, 6, x_triangle + 5, 6, 0); - // UP - x_offset = ui_button_width + 30; - x_triangle = x_offset + 70; - renderer->draw_rect(x_offset, 1, ui_button_width, ui_button_height, 0); - renderer->draw_triangle(x_triangle, 6, x_triangle - 5, 20, x_triangle + 5, 20, 0); - // SELECT - x_offset = ui_button_width * 2 + 60; - renderer->draw_rect(x_offset, 1, ui_button_width, ui_button_height, 0); - renderer->draw_circle(x_offset + (ui_button_width / 2) + 9, 15, 5, 0); renderer->set_margin_top(35); } @@ -160,49 +145,5 @@ void SF32_TouchControls::powerOnTouch() } void SF32_TouchControls::renderPressedState(Renderer *renderer, UIAction action, bool state) { - renderer->set_margin_top(0); - switch (action) - { - case DOWN: - { - if (state) - { - renderer->fill_triangle(80, 20, 75, 6, 85, 6, 0); - } - else - { - renderer->fill_triangle(81, 19, 76, 7, 86, 7, 255); - } - //renderer->flush_area(76, 6, 10, 15); - break; - } - case UP: - { - if (state) - { - renderer->fill_triangle(220, 6, 220 - 5, 20, 220 + 5, 20, 0); - } - else - { - renderer->fill_triangle(221, 7, 221 - 5, 19, 221 + 5, 19, 255); - } - //renderer->flush_area(195, 225, 10, 15); - } - break; - case SELECT: - { - uint16_t x_circle = (ui_button_width * 2 + 60) + (ui_button_width / 2) + 9; - renderer->fill_circle(x_circle, 15, 5, 0); - //renderer->flush_area(x_circle - 3, 12, 6, 6); - // TODO - this causes a stack overflow when select is picked - // renderPressedState(renderer, last_action, false); - } - break; - case LAST_INTERACTION: - case NONE: - break; - default: - break; - } renderer->set_margin_top(35); } \ No newline at end of file diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index fbfdc7e..b06ae54 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -1,3 +1,5 @@ + +#include "EpubList/EpubList.h" #include "epub_screen.h" #include @@ -8,6 +10,9 @@ extern "C" extern void set_part_disp_times(int val); } +// 最近一次真实打开并阅读的书本索引(由 main.cpp 维护) +extern int g_last_read_index; + // 主页面选项 typedef enum { @@ -50,24 +55,24 @@ int screen_get_full_refresh_idx() typedef enum { SET_TOUCH = 0, SET_TIMEOUT = 1, SET_FULL_REFRESH = 2, SET_CONFIRM = 3 } SettingsItem; static int settings_selected_idx = 0; -// 超时关机:1/3/5/7/10/不关机(0) -static const int kTimeoutOptions[] = {1, 3, 5, 7, 10, 0}; +// 超时关机:5/10/30分钟、1小时、不关机(0) +static const int kTimeoutOptions[] = {5, 10, 30, 60, 0}; // 单位:分钟,0为不关机 static const int kTimeoutOptionsCount = sizeof(kTimeoutOptions) / sizeof(kTimeoutOptions[0]); -static int timeout_shutdown_hours = 5; // 运行时关机超时(小时),0 表示不关机 -static int timeout_idx = -1; // 指向 kTimeoutOptions 的索引 +static int timeout_shutdown_minutes = 30; // 默认30分钟 +static int timeout_idx = -1; // -static int find_timeout_idx(int hours) +static int find_timeout_idx(int minutes) { for (int i = 0; i < kTimeoutOptionsCount; ++i) { - if (kTimeoutOptions[i] == hours) return i; + if (kTimeoutOptions[i] == minutes) return i; } - return 2; // 默认索引:5小时 + return 2; // 默认索引:30分钟 } static void adjust_timeout(bool increase) { - if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_hours); + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_minutes); if (increase) { timeout_idx = (timeout_idx + 1) % kTimeoutOptionsCount; @@ -76,19 +81,19 @@ static void adjust_timeout(bool increase) { timeout_idx = (timeout_idx - 1 + kTimeoutOptionsCount) % kTimeoutOptionsCount; } - timeout_shutdown_hours = kTimeoutOptions[timeout_idx]; + timeout_shutdown_minutes = kTimeoutOptions[timeout_idx]; } -void screen_init(int default_timeout_hours) +void screen_init(int default_timeout_minutes) { - timeout_shutdown_hours = default_timeout_hours; - timeout_idx = find_timeout_idx(timeout_shutdown_hours); + timeout_shutdown_minutes = default_timeout_minutes; + timeout_idx = find_timeout_idx(timeout_shutdown_minutes); } -int screen_get_timeout_shutdown_hours() +int screen_get_timeout_shutdown_minutes() { - if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_hours); - return timeout_shutdown_hours; + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_minutes); + return timeout_shutdown_minutes; } int screen_get_main_selected_option() @@ -133,10 +138,14 @@ static void render_main_page(Renderer *renderer) int mid_w = right_x - margin_side - mid_x; const char *opt_text = NULL; + extern EpubListState epub_list_state; + bool has_continue_reading = (epub_list_state.num_epubs > 0 && g_last_read_index >= 0 && g_last_read_index < epub_list_state.num_epubs); switch (main_option) { case OPTION_OPEN_LIBRARY: opt_text = "打开书库"; break; - case OPTION_CONTINUE_READING: opt_text = "继续阅读"; break; + case OPTION_CONTINUE_READING: + opt_text = has_continue_reading ? "继续阅读" : "无阅读记录"; + break; case OPTION_ENTER_SETTINGS: opt_text = "进入设置"; break; } int opt_w = renderer->get_text_width(opt_text); @@ -208,6 +217,7 @@ static void render_settings_page(Renderer *renderer) // 1) 触控开关 int item_w = page_w - margin_lr * 2 - arrow_col_w * 2; // 为左右箭头列留边 int item_x = margin_lr + arrow_col_w; + if (settings_selected_idx == SET_TOUCH) { const char *lt = "<"; int lt_w = renderer->get_text_width(lt); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); @@ -237,6 +247,7 @@ static void render_settings_page(Renderer *renderer) y += item_h + gap; // 2) 超时关机 + if (settings_selected_idx == SET_TIMEOUT) { const char *lt = "<"; int lt_w = renderer->get_text_width(lt); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); @@ -252,13 +263,17 @@ static void render_settings_page(Renderer *renderer) renderer->draw_rect(item_x, y, item_w, item_h, 0); } char buf2[64]; - if (timeout_shutdown_hours == 0) + if (timeout_shutdown_minutes == 0) { rt_snprintf(buf2, sizeof(buf2), "超时关机:不关机"); } + else if (timeout_shutdown_minutes < 60) + { + rt_snprintf(buf2, sizeof(buf2), "超时关机:%d分钟", timeout_shutdown_minutes); + } else { - rt_snprintf(buf2, sizeof(buf2), "超时关机:%d 小时", timeout_shutdown_hours); + rt_snprintf(buf2, sizeof(buf2), "超时关机:%d小时", timeout_shutdown_minutes / 60); } { int t2_w = renderer->get_text_width(buf2); @@ -270,6 +285,7 @@ static void render_settings_page(Renderer *renderer) y += item_h + gap; // 3) 全刷周期 + if (settings_selected_idx == SET_FULL_REFRESH) { const char *lt = "<"; int lt_w = renderer->get_text_width(lt); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); diff --git a/epdiy-epub/src/epub_screen.h b/epdiy-epub/src/epub_screen.h index a1b589d..d3f1646 100644 --- a/epdiy-epub/src/epub_screen.h +++ b/epdiy-epub/src/epub_screen.h @@ -11,7 +11,7 @@ void screen_init(int default_timeout_hours); // 获取当前关机超时设置(小时;0 表示不关机) -int screen_get_timeout_shutdown_hours(); +int screen_get_timeout_shutdown_minutes(); // 获取当前主页面选中的选项(0: 打开书库, 1: 继续阅读, 2: 进入设置) int screen_get_main_selected_option(); diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 7d020f9..cd3c7ae 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -35,30 +35,28 @@ extern "C" const char *TAG = "main"; -typedef enum -{ +typedef enum { MAIN_PAGE, // 新主页面 - SELECTING_EPUB, // 电子书列表页面(书库) + SELECTING_EPUB, // 电子书列表页面(书库) SELECTING_TABLE_CONTENTS, // 电子书目录页面 - READING_EPUB, // 阅读页面 - SETTINGS_PAGE // 通用功能设置页面 -} UIState; -typedef enum -{ - MAIN_MENU, - WELCOME_PAGE, - LOW_POWER_PAGE, - CHARGING_PAGE -} UIState2; + READING_EPUB, // 阅读页面 + SETTINGS_PAGE, // 通用功能设置页面 + WELCOME_PAGE, // 欢迎页面 + LOW_POWER_PAGE, // 低电量页面 + CHARGING_PAGE, // 充电页面 + SHUTDOWN_PAGE // 关机页面 +} AppUIState; // 默认显示新主页面,而非书库页面 -UIState ui_state = MAIN_PAGE; -UIState2 lowpower_ui_state = MAIN_MENU; +AppUIState ui_state = MAIN_PAGE; // the state data for the epub list and reader EpubListState epub_list_state; // the state data for the epub index list EpubTocState epub_index_state; +// 最近一次真实打开并阅读的书本索引(-1 表示无记录) +int g_last_read_index = -1; + void handleEpub(Renderer *renderer, UIAction action); void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw); void back_to_main_page(); @@ -92,6 +90,8 @@ void handleEpub(Renderer *renderer, UIAction action) { reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); reader->load(); + // 记录最近一次进入阅读的书籍索引 + g_last_read_index = epub_list_state.selected_item; } switch (action) { @@ -165,6 +165,7 @@ void handleEpub(Renderer *renderer, UIAction action) if (sel == 9) //目录 { ui_state = SELECTING_TABLE_CONTENTS; + renderer->set_margin_bottom(0); reader->stop_overlay(); delete reader; reader = nullptr; @@ -187,6 +188,7 @@ void handleEpub(Renderer *renderer, UIAction action) else if (sel == 10) //书库 { ui_state = SELECTING_EPUB; + renderer->set_margin_bottom(0); reader->stop_overlay(); renderer->clear_screen(); delete reader; @@ -219,7 +221,6 @@ void handleEpub(Renderer *renderer, UIAction action) else { // switch back to main screen - ui_state = SELECTING_EPUB; renderer->clear_screen(); // clear the epub reader away delete reader; @@ -229,7 +230,8 @@ void handleEpub(Renderer *renderer, UIAction action) { epub_list = new EpubList(renderer, epub_list_state); } - handleEpubList(renderer, NONE, true); + renderer->set_margin_bottom(0); + back_to_main_page(); return; } @@ -358,6 +360,8 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); reader->set_state_section(contents->get_selected_toc()); reader->load(); + // 记录最近一次进入阅读的书籍索引 + g_last_read_index = epub_list_state.selected_item; delete contents; handleEpub(renderer, NONE); return; @@ -585,10 +589,21 @@ void handleUserInteraction(Renderer *renderer, UIAction ui_action, bool needs_re ui_state = SETTINGS_PAGE; (void)handleSettingsPage(renderer, NONE, true); } - else if (ui_action == SELECT && screen_get_main_selected_option() == 1) //切换到阅读页面 + else if (ui_action == SELECT && screen_get_main_selected_option() == 1) //继续阅读 { - // ui_state = READING_EPUB; - // handleEpub(renderer, NONE); + // 判断是否有继续阅读记录 + if (!(g_last_read_index >= 0 && g_last_read_index < epub_list_state.num_epubs)) { + return; // 无记录,忽略 + } + // 有记录,恢复阅读 + if (reader) { delete reader; reader = nullptr; } + int last_idx = g_last_read_index; + EpubListItem &last_item = epub_list_state.epub_list[last_idx]; + reader = new EpubReader(last_item, renderer); + reader->set_state_section(last_item.current_section); + reader->load(); + ui_state = READING_EPUB; + handleEpub(renderer, NONE); } else if (ui_action == SELECT && screen_get_main_selected_option() == 0) //切换到书库页面 { @@ -620,151 +635,154 @@ void handleUserInteraction(Renderer *renderer, UIAction ui_action, bool needs_re rt_kprintf("Renderer time=%d \r\n", rt_tick_get() - start_tick); } const char* getCurrentPageName() { - switch (lowpower_ui_state) - { - case MAIN_MENU: - return "MAIN_MENU"; - case WELCOME_PAGE: - return "WELCOME_PAGE"; - case LOW_POWER_PAGE: - return "LOW_POWER_PAGE"; - case CHARGING_PAGE: - return "CHARGING_PAGE"; - default: - return "UNKNOWN_PAGE"; - } + switch (ui_state) + { + case MAIN_PAGE: + return "MAIN_PAGE"; + case SELECTING_EPUB: + return "SELECTING_EPUB"; + case SELECTING_TABLE_CONTENTS: + return "SELECTING_TABLE_CONTENTS"; + case READING_EPUB: + return "READING_EPUB"; + case SETTINGS_PAGE: + return "SETTINGS_PAGE"; + case WELCOME_PAGE: + return "WELCOME_PAGE"; + case LOW_POWER_PAGE: + return "LOW_POWER_PAGE"; + case CHARGING_PAGE: + return "CHARGING_PAGE"; + case SHUTDOWN_PAGE: + return "SHUTDOWN_PAGE"; + default: + return "UNKNOWN_PAGE"; + } } //回到主界面接口 void back_to_main_page() -{ - if (ui_state == MAIN_PAGE) - { - rt_kprintf("已经在主页面,无需返回\n"); - return; - } - lowpower_ui_state = MAIN_MENU; - if (ui_state == SELECTING_TABLE_CONTENTS) - { - if (contents) - { - delete contents; - contents = nullptr; - } +{ + if (ui_state == MAIN_PAGE) + { + rt_kprintf("已经在主页面,无需返回\n"); + return; + } + if (ui_state == SELECTING_TABLE_CONTENTS) + { + if (contents) + { + delete contents; + contents = nullptr; } - bool hydrate_success = renderer->hydrate(); - - renderer->reset(); - renderer->set_margin_top(35); - renderer->set_margin_left(10); - renderer->set_margin_right(10); - // 返回新的主页面,不再默认进入书库页面 - ui_state = MAIN_PAGE; - handleUserInteraction(renderer, NONE, true); - - if (battery) - { - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - } - touch_controls->render(renderer); - renderer->flush_display(); + } + bool hydrate_success = renderer->hydrate(); + + renderer->reset(); + renderer->set_margin_top(35); + renderer->set_margin_left(10); + renderer->set_margin_right(10); + // 返回新的主页面,不再默认进入书库页面 + ui_state = MAIN_PAGE; + handleUserInteraction(renderer, NONE, true); + if (battery) + { + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + } + touch_controls->render(renderer); + renderer->flush_display(); } //欢迎页面 void draw_welcome_page(Battery *battery) { - if (strcmp(getCurrentPageName(), "WELCOME_PAGE") == 0) - { - return; - } - lowpower_ui_state = WELCOME_PAGE; - touch_controls->powerOffTouch(); - touch_controls->setTouchEnable(false); - // 设置黑色背景 - renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); - if (battery) { - renderer->set_margin_top(35); - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - } + if (ui_state == WELCOME_PAGE) + { + return; + } + ui_state = WELCOME_PAGE; + // 设置黑色背景 + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); + if (battery) { + renderer->set_margin_top(35); + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + } - const int img_width = 649; - const int img_height = 150; - - int center_x = renderer->get_page_width() / 2; - int center_y = 35 + (renderer->get_page_height() - 35) / 2; - int x_pos = center_x - img_width / 2; - int y_pos = center_y - img_height / 2; - - EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); - fb_renderer->show_img(x_pos, y_pos, img_width, img_height, welcome_map); + const int img_width = 649; + const int img_height = 150; - // 显示 - renderer->flush_display(); - + int center_x = renderer->get_page_width() / 2; + int center_y = 35 + (renderer->get_page_height() - 35) / 2; + int x_pos = center_x - img_width / 2; + int y_pos = center_y - img_height / 2; + + EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); + fb_renderer->show_img(x_pos, y_pos, img_width, img_height, welcome_map); + + // 显示 + renderer->flush_display(); } // 低电量页面 void draw_low_power_page(Battery *battery) { - if (strcmp(getCurrentPageName(), "LOW_POWER_PAGE") == 0) - { - return; - } - lowpower_ui_state = LOW_POWER_PAGE; - - // 设置黑色背景 - renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); - if (battery) { - renderer->set_margin_top(35); - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - } + if (ui_state == LOW_POWER_PAGE) + { + return; + } + ui_state = LOW_POWER_PAGE; + // 设置黑色背景 + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); + if (battery) { + renderer->set_margin_top(35); + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + } - const int img_width = 200; - const int img_height = 200; - - int center_x = renderer->get_page_width() / 2; - int center_y = 35 + (renderer->get_page_height() - 35) / 2; - int x_pos = center_x - img_width / 2; - int y_pos = center_y - img_height / 2; - - EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); - fb_renderer->show_img(x_pos, y_pos, img_width, img_height, low_power_map); - // 显示 - renderer->flush_display(); - + const int img_width = 200; + const int img_height = 200; + + int center_x = renderer->get_page_width() / 2; + int center_y = 35 + (renderer->get_page_height() - 35) / 2; + int x_pos = center_x - img_width / 2; + int y_pos = center_y - img_height / 2; + + EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); + fb_renderer->show_img(x_pos, y_pos, img_width, img_height, low_power_map); + // 显示 + renderer->flush_display(); } //充电页面 void draw_charge_page(Battery *battery) { - if (strcmp(getCurrentPageName(), "CHARGING_PAGE") == 0) - { - return; - } - lowpower_ui_state = CHARGING_PAGE; - // 设置黑色背景 - renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); - if (battery) { - renderer->set_margin_top(35); - draw_charge_status(renderer, battery); - draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); - } + if (ui_state == CHARGING_PAGE) + { + return; + } + ui_state = CHARGING_PAGE; + // 设置黑色背景 + renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 0); + if (battery) { + renderer->set_margin_top(35); + draw_charge_status(renderer, battery); + draw_battery_level(renderer, battery->get_voltage(), battery->get_percentage()); + } - const int img_width = 200; - const int img_height = 200; - - int center_x = renderer->get_page_width() / 2; - int center_y = 35 + (renderer->get_page_height() - 35) / 2; - int x_pos = center_x - img_width / 2; - int y_pos = center_y - img_height / 2; - - EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); - fb_renderer->show_img(x_pos, y_pos, img_width, img_height, chargeing_map); - // 显示 - renderer->flush_display(); + const int img_width = 200; + const int img_height = 200; + + int center_x = renderer->get_page_width() / 2; + int center_y = 35 + (renderer->get_page_height() - 35) / 2; + int x_pos = center_x - img_width / 2; + int y_pos = center_y - img_height / 2; + + EpdiyFrameBufferRenderer* fb_renderer = static_cast(renderer); + fb_renderer->show_img(x_pos, y_pos, img_width, img_height, chargeing_map); + // 显示 + renderer->flush_display(); } //关机页面 @@ -873,18 +891,19 @@ void main_task(void *param) // 初始化屏幕模块默认关机超时 screen_init(TIMEOUT_SHUTDOWN_TIME); - while ((screen_get_timeout_shutdown_hours() == 0) || - (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 * screen_get_timeout_shutdown_hours())) // 按设置的小时数无操作自动关机;0为不关机 + while ((rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 * TIMEOUT_SHUTDOWN_TIME)) // 5小时 { - // 检查是否超过5分钟无操作,如果是在欢迎页面、充电页面或低电量页面则不跳转 - if (rt_tick_get_millisecond() - last_user_interaction >= 60 * 1000 *5 && - battery && battery->get_low_power_state() != 1 && - strcmp(getCurrentPageName(), "WELCOME_PAGE") != 0 && - strcmp(getCurrentPageName(), "CHARGING_PAGE") != 0 && - strcmp(getCurrentPageName(), "LOW_POWER_PAGE") != 0) + // 检查是否超过设置分钟无操作,如果是在欢迎页面、充电页面或低电量页面则不跳转 + if (rt_tick_get_millisecond() - last_user_interaction >= 60 * 1000 * screen_get_timeout_shutdown_minutes() && + battery && battery->get_low_power_state() != 1 && + ui_state != WELCOME_PAGE && + ui_state != CHARGING_PAGE && + ui_state != LOW_POWER_PAGE && + screen_get_timeout_shutdown_minutes()) { - draw_welcome_page(battery); + renderer->set_margin_bottom(0); + draw_welcome_page(battery); } uint32_t msg_data; if (rt_mq_recv(ui_queue, &msg_data, sizeof(uint32_t), rt_tick_from_millisecond(60500)) == RT_EOK) //一分钟自动刷一下 @@ -924,6 +943,7 @@ void main_task(void *param) { case MSG_DRAW_LOW_POWER_PAGE: rt_kprintf("low_power\n"); + renderer->set_margin_bottom(0); draw_low_power_page(battery); break; case MSG_DRAW_CHARGE_PAGE: @@ -946,14 +966,13 @@ void main_task(void *param) if (ui_action != NONE) { // 如果之前在欢迎页面,现在需要返回主界面 - if(strcmp(getCurrentPageName(), "WELCOME_PAGE") == 0) + if(ui_state == WELCOME_PAGE) { back_to_main_page(); - last_user_interaction = rt_tick_get_millisecond(); board->sleep_filesystem(); continue; - } + } //rt_kprintf("ui_action = %d\n", ui_action); // something happened! last_user_interaction = rt_tick_get_millisecond(); @@ -987,6 +1006,7 @@ void main_task(void *param) // turn off the filesystem board->stop_filesystem(); // get ready to go to sleep + renderer->set_margin_bottom(0); draw_shutdown_page(); board->prepare_to_sleep(); //ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup()); From 375cc6e1bfe92f275300714fcfd7aa702c4673f9 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Fri, 16 Jan 2026 14:14:53 +0800 Subject: [PATCH 18/25] =?UTF-8?q?=E5=BC=80=E5=90=AF=E4=BD=8E=E5=8A=9F?= =?UTF-8?q?=E8=80=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index cd3c7ae..24f875a 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -1023,7 +1023,7 @@ extern "C" int main() { // dump out the epub list state - rt_pm_request(PM_SLEEP_MODE_IDLE); + //rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item); From af9565bfedd82eee56a31115a4dfb78133355037 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Fri, 16 Jan 2026 18:55:56 +0800 Subject: [PATCH 19/25] =?UTF-8?q?1.=E4=BF=AE=E6=94=B9=E7=B4=AF=E7=A7=AF?= =?UTF-8?q?=E8=B7=B3=E9=A1=B5=E4=BD=BF=E7=94=A8=E9=80=BB=E8=BE=91=202.?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B9=A6=E5=BA=93=E4=BB=A5=E5=8F=8A=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E9=A1=B5=E7=9A=84up=EF=BC=8Cdown=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 34 +++++++- epdiy-epub/lib/Epub/EpubList/EpubReader.h | 9 +- epdiy-epub/src/main.cpp | 95 ++++++++++++++++----- 3 files changed, 114 insertions(+), 24 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index ca3c17b..8e0a4e5 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -103,6 +103,11 @@ void EpubReader::render() { parse_and_layout_current_section(); } + // 确保覆盖层目标页初始与当前页同步(1-based) + if (overlay_active && overlay_target_page < 1) + { + overlay_set_target_page(state.current_page + 1); + } ulog_d(TAG, "rendering page %d of %d", state.current_page, parser->get_page_count()); parser->render_page(state.current_page, renderer, epub); ulog_d(TAG, "rendered page %d of %d", state.current_page, parser->get_page_count()); @@ -178,7 +183,15 @@ void EpubReader::render_overlay() case 2: rt_snprintf(label, cap, ">"); break; case 3: rt_snprintf(label, cap, "-5"); break; case 4: rt_snprintf(label, cap, "-1"); break; - case 5: rt_snprintf(label, cap, "%d", overlay_jump_acc); break; + // 第六格显示:x/n 页 + case 5: + { + int total = state.pages_in_current_section; + if (total <= 0 && parser) total = parser->get_page_count(); + if (total <= 0) total = 1; + rt_snprintf(label, cap, "%d/%d", overlay_target_page, total); + break; + } case 6: rt_snprintf(label, cap, "+1"); break; case 7: rt_snprintf(label, cap, "+5"); break; case 8: rt_snprintf(label, cap, "确认"); break; @@ -330,4 +343,23 @@ void EpubReader::overlay_cycle_full_refresh() int EpubReader::overlay_get_full_refresh_value() const { return screen_get_full_refresh_period(); +} + +void EpubReader::overlay_set_target_page(int p) +{ + if (p < 1) p = 1; + int maxp = state.pages_in_current_section; + if (maxp <= 0 && parser) + { + maxp = parser->get_page_count(); + } + if (maxp <= 0) maxp = 1; + if (p > maxp) p = maxp; + overlay_target_page = p; +} + +void EpubReader::overlay_adjust_target_page(int d) +{ + int p = overlay_target_page + d; + overlay_set_target_page(p); } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.h b/epdiy-epub/lib/Epub/EpubList/EpubReader.h index a5a71b0..d65ef72 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -17,6 +17,8 @@ class EpubReader bool overlay_active = false; int overlay_selected = 0; // 0..10,共11个 int overlay_jump_acc = 0; // 覆盖层累积跳页值(可为负) + // 覆盖层目标页(当前章节内的页,1-based) + int overlay_target_page = 1; // 覆盖层中心属性模式:触控开关 或 全刷周期 enum OverlayCenterMode { CENTER_TOUCH = 0, CENTER_FULL_REFRESH = 1 }; OverlayCenterMode overlay_center_mode = CENTER_TOUCH; @@ -38,16 +40,19 @@ class EpubReader void render(); void set_state_section(uint16_t current_section); // 覆盖层控制 - void start_overlay() { overlay_active = true; overlay_selected = 0; overlay_jump_acc = 0; } + void start_overlay() { overlay_active = true; overlay_selected = 0; overlay_jump_acc = 0; overlay_target_page = state.current_page + 1; } void stop_overlay() { overlay_active = false; } bool is_overlay_active() const { return overlay_active; } void overlay_move_left(); void overlay_move_right(); int get_overlay_selected() const { return overlay_selected; } // 覆盖层跳页累积控制 - void overlay_add_jump(int d) { overlay_jump_acc += d; } void overlay_reset_jump() { overlay_jump_acc = 0; } int overlay_get_jump() const { return overlay_jump_acc; } + // 覆盖层目标页控制 + void overlay_set_target_page(int p); + void overlay_adjust_target_page(int d); + int overlay_get_target_page() const { return overlay_target_page; } // 覆盖层中心属性控制 void overlay_set_center_mode_touch() { overlay_center_mode = CENTER_TOUCH; } void overlay_set_center_mode_full_refresh() { overlay_center_mode = CENTER_FULL_REFRESH; } diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 24f875a..4d61b12 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -177,11 +177,11 @@ void handleEpub(Renderer *renderer, UIAction action) } else if (sel == 8) //确认:1.按第六格累积值跳页 { - int delta = reader->overlay_get_jump(); - if (delta != 0) - { - reader->jump_pages(delta); - } + // 跳转到第六格显示的目标页 + int target = reader->overlay_get_target_page(); + if (target < 1) target = 1; + extern EpubListState epub_list_state; + epub_list_state.epub_list[epub_list_state.selected_item].current_page = (uint16_t)(target - 1); reader->overlay_reset_jump(); reader->stop_overlay(); } @@ -202,19 +202,19 @@ void handleEpub(Renderer *renderer, UIAction action) } else if (sel == 3) { - reader->overlay_add_jump(-5); + reader->overlay_adjust_target_page(-5); } else if (sel == 4) { - reader->overlay_add_jump(-1); + reader->overlay_adjust_target_page(-1); } else if (sel == 6) { - reader->overlay_add_jump(1); + reader->overlay_adjust_target_page(1); } else if (sel == 7) { - reader->overlay_add_jump(5); + reader->overlay_adjust_target_page(5); } } @@ -271,15 +271,31 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red case UP: if (toc_bottom_mode) { - toc_bottom_idx = (toc_bottom_idx + 2) % 3; // 左移 + // 底部模式下:UP 向左移动;若已在最左(上一页),则返回当前页目录的最后一项 + if (toc_bottom_idx > 0) + { + toc_bottom_idx--; + } + else + { + int per_page = 6; + int start_idx = (epub_index_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + int count = contents->get_items_count(); + if (end_idx >= count) end_idx = count - 1; + toc_bottom_mode = false; + epub_index_state.selected_item = end_idx; + } } else { + // 若处于当前页第一个条目,UP 切换到底部按钮模式并选择“下一页” int per_page = 6; int start_idx = (epub_index_state.selected_item / per_page) * per_page; if (contents->get_items_count() > 0 && epub_index_state.selected_item == start_idx) { toc_bottom_mode = true; + toc_bottom_idx = 2; // 下一页 } else { @@ -290,7 +306,18 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red case DOWN: if (toc_bottom_mode) { - toc_bottom_idx = (toc_bottom_idx + 1) % 3; // 右移 + // 底部模式下:DOWN 向右移动;若已在最右(下一页),则返回当前页目录的第一项 + if (toc_bottom_idx < 2) + { + toc_bottom_idx++; + } + else + { + int per_page = 6; + int start_idx = (epub_index_state.selected_item / per_page) * per_page; + toc_bottom_mode = false; + epub_index_state.selected_item = start_idx; + } } else { @@ -299,9 +326,11 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red int end_idx = start_idx + per_page - 1; int count = contents->get_items_count(); if (end_idx >= count) end_idx = count - 1; + // 若处于当前页最后一个条目,DOWN 切换到底部按钮模式并选择“上一页” if (count > 0 && epub_index_state.selected_item == end_idx) { toc_bottom_mode = true; + toc_bottom_idx = 0; // 上一页 } else { @@ -338,7 +367,7 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red if (epub_index_state.selected_item < 0) epub_index_state.selected_item = 0; contents->set_needs_redraw(); } - toc_bottom_mode = false; + // 保持底部模式,允许连续翻页 } else if (toc_bottom_idx == 2) { @@ -350,7 +379,7 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red epub_index_state.selected_item = count - 1; contents->set_needs_redraw(); } - toc_bottom_mode = false; + // 保持底部模式,允许连续翻页 } } else @@ -403,8 +432,20 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) case UP: if (library_bottom_mode) { - // UP 表示向左选择 - library_bottom_idx = (library_bottom_idx + 2) % 3; + // 底部模式下:UP 向左移动;若已在最左(上一页),则返回当前页的列表最后一项 + if (library_bottom_idx > 0) + { + library_bottom_idx--; + } + else + { + int per_page = 4; + int start_idx = (epub_list_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + if (end_idx >= epub_list_state.num_epubs) end_idx = epub_list_state.num_epubs - 1; + library_bottom_mode = false; + epub_list_state.selected_item = end_idx; + } } else { @@ -414,6 +455,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) if (epub_list_state.num_epubs > 0 && epub_list_state.selected_item == start_idx) { library_bottom_mode = true; + library_bottom_idx = 2; // 下一页 } else { @@ -424,8 +466,20 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) case DOWN: if (library_bottom_mode) { - // DOWN 表示向右选择 - library_bottom_idx = (library_bottom_idx + 1) % 3; + // 底部模式下:DOWN 向右移动;若已在最右(下一页),则返回当前页的列表第一项 + if (library_bottom_idx < 2) + { + library_bottom_idx++; + } + else + { + int per_page = 4; + int start_idx = (epub_list_state.selected_item / per_page) * per_page; + int end_idx = start_idx + per_page - 1; + if (end_idx >= epub_list_state.num_epubs) end_idx = epub_list_state.num_epubs - 1; + library_bottom_mode = false; + epub_list_state.selected_item = start_idx; + } } else { @@ -437,6 +491,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) if (epub_list_state.num_epubs > 0 && epub_list_state.selected_item == end_idx) { library_bottom_mode = true; + library_bottom_idx = 0; // 上一页 } else { @@ -466,8 +521,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) if (epub_list_state.selected_item < 0) epub_list_state.selected_item = 0; epub_list->set_needs_redraw(); } - // 切回条目选择模式 - library_bottom_mode = false; + } else if (library_bottom_idx == 2) { @@ -479,8 +533,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) epub_list_state.selected_item = epub_list_state.num_epubs - 1; epub_list->set_needs_redraw(); } - // 切回条目选择模式 - library_bottom_mode = false; + } } else From 97cc296f2c37a3d63c8b777572be6db44830cc2b Mon Sep 17 00:00:00 2001 From: minjiezhong Date: Tue, 20 Jan 2026 11:19:36 +0800 Subject: [PATCH 20/25] =?UTF-8?q?1=E3=80=82=E6=B7=BB=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E6=89=80=E6=9C=89=E9=A1=B5=E9=9D=A2=E7=9A=84=E8=A7=A6=E6=8E=A7?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 9 + epdiy-epub/lib/Epub/EpubList/EpubList.h | 1 + epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 2 +- epdiy-epub/lib/Epub/EpubList/EpubToc.cpp | 9 + epdiy-epub/lib/Epub/EpubList/EpubToc.h | 1 + epdiy-epub/lib/Epub/EpubList/State.h | 16 +- epdiy-epub/project/Kconfig.proj | 10 +- epdiy-epub/src/boards/controls/Actions.h | 3 + .../boards/controls/SF32_TouchControls.cpp | 412 +++++++++++++++--- .../src/boards/controls/SF32_TouchControls.h | 9 +- .../src/boards/controls/TouchControls.h | 2 +- epdiy-epub/src/boards/touch/gt967/SConscript | 8 + epdiy-epub/src/boards/touch/gt967/gt967.c | 262 +++++++++++ epdiy-epub/src/boards/touch/gt967/gt967.h | 25 ++ epdiy-epub/src/epub_screen.cpp | 89 +++- epdiy-epub/src/epub_screen.h | 2 +- epdiy-epub/src/main.cpp | 398 ++++++++++------- epdiy-epub/src/type.h | 38 ++ 18 files changed, 1049 insertions(+), 247 deletions(-) create mode 100644 epdiy-epub/src/boards/touch/gt967/SConscript create mode 100644 epdiy-epub/src/boards/touch/gt967/gt967.c create mode 100644 epdiy-epub/src/boards/touch/gt967/gt967.h create mode 100644 epdiy-epub/src/type.h diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index 0394e57..55f42d0 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -36,6 +36,15 @@ void EpubList::prev() state.selected_item--; } +void EpubList::switch_book(int target_index) +{ + if (state.num_epubs == 0) return; + if (target_index < 0 || target_index >= state.num_epubs) + return; + state.selected_item = target_index; +} + + bool EpubList::load(const char *path) { if (state.is_loaded) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.h b/epdiy-epub/lib/Epub/EpubList/EpubList.h index da2c910..f73eec5 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.h @@ -47,4 +47,5 @@ class EpubList void next(); void prev(); void render(); + void switch_book(int target_index); }; \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index 8e0a4e5..201478f 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -337,7 +337,7 @@ void EpubReader::jump_pages(int delta) void EpubReader::overlay_cycle_full_refresh() { - screen_cycle_full_refresh_period(); + screen_cycle_full_refresh_period(true); } int EpubReader::overlay_get_full_refresh_value() const diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp index 6f08ff5..88c45d2 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp @@ -31,6 +31,15 @@ void EpubToc::prev() } state.selected_item = (state.selected_item - 1 + epub->get_toc_items_count()) % epub->get_toc_items_count(); } +void EpubToc::switch_book(int target_index) +{ + if (!epub) + { + load(); + } + state.selected_item = target_index % epub->get_toc_items_count(); + +} bool EpubToc::load() { diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.h b/epdiy-epub/lib/Epub/EpubList/EpubToc.h index 56563f0..4fc09d9 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.h @@ -43,6 +43,7 @@ class EpubToc void next(); void prev(); void render(); + void switch_book(int target_index); void set_needs_redraw() { m_needs_redraw = true; } uint16_t get_selected_toc(); // 目录项总数 diff --git a/epdiy-epub/lib/Epub/EpubList/State.h b/epdiy-epub/lib/Epub/EpubList/State.h index d5e5999..fe8c4a0 100644 --- a/epdiy-epub/lib/Epub/EpubList/State.h +++ b/epdiy-epub/lib/Epub/EpubList/State.h @@ -9,11 +9,11 @@ const int MAX_TITLE_SIZE = 100; // nice and simple state that can be persisted easily typedef struct { - char path[MAX_PATH_SIZE]; - char title[MAX_TITLE_SIZE]; - uint16_t current_section; - uint16_t current_page; - uint16_t pages_in_current_section; + char path[MAX_PATH_SIZE];//存储 EPUB 文件的路径 + char title[MAX_TITLE_SIZE];//存储 EPUB 文件的标题 + uint16_t current_section;//记录当前阅读的章节编号(从0开始) + uint16_t current_page;//记录当前章节内的页码(从0开始) + uint16_t pages_in_current_section;//记录当前章节总共有多少页 } EpubListItem; // this is held in the RTC memory @@ -30,7 +30,7 @@ typedef struct // this is held in the RTC memory typedef struct { - int previous_rendered_page; - int previous_selected_item; - int selected_item; + int previous_rendered_page;//记录当前选中的目录项索引 + int previous_selected_item;//记录上一次选中的目录项索引 + int selected_item;//记录上次渲染的页面索引 } EpubTocState; diff --git a/epdiy-epub/project/Kconfig.proj b/epdiy-epub/project/Kconfig.proj index 67fb310..fc9ba05 100644 --- a/epdiy-epub/project/Kconfig.proj +++ b/epdiy-epub/project/Kconfig.proj @@ -48,26 +48,28 @@ if !BSP_USING_BUILT_LCD config LCD_USING_EPD_CUSTOM bool default n - + config TSC_USING_GT967 + bool + default n choice prompt "Custom LCD driver" default LCD_USING_EPD_YZC085_V100 config LCD_USING_EPD_R7D005 bool "6.0 rect electronic paper display(EPD R7D005_-1.30 1448x1072)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD + select TSC_USING_GT967 if BSP_USING_TOUCHD select LCD_USING_R7D005_130 select BSP_LCDC_USING_EPD_8BIT config LCD_USING_EPD_YZC085_V100 bool "6.0 rect electronic paper display(EPD YZC085_V1.05 1032x758)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD + select TSC_USING_GT967 if BSP_USING_TOUCHD select LCD_USING_YZC085_V100 select BSP_LCDC_USING_EPD_8BIT config LCD_USING_EPD_YZC146_V100 bool "6.0 rect electronic paper display(EPD YZC146_1.00 1032x758)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD + select TSC_TSC_USING_GT967USING_FT5446U_V01 if BSP_USING_TOUCHD select LCD_USING_YZC085_V100 select BSP_LCDC_USING_EPD_8BIT diff --git a/epdiy-epub/src/boards/controls/Actions.h b/epdiy-epub/src/boards/controls/Actions.h index 8e83835..5e22d6b 100644 --- a/epdiy-epub/src/boards/controls/Actions.h +++ b/epdiy-epub/src/boards/controls/Actions.h @@ -9,6 +9,9 @@ typedef enum DOWN, SELECT, UPGLIDE, // 长按触发的上滑操作,用于阅读页半屏操作覆盖 + PREV_OPTION, // 上一选项(用于列表选择) + NEXT_OPTION, // 下一选项(用于列表选择) + SELECT_BOX, // 选择框(用于触控选择) LAST_INTERACTION, MSG_DRAW_LOW_POWER_PAGE, MSG_DRAW_CHARGE_PAGE, diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index 43f4a5a..c8e73c8 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -1,13 +1,31 @@ - #include "SF32_TouchControls.h" #include +#include "Actions.h" #include "epd_driver.h" +#include "type.h" +#include "epub_screen.h" +#include "EpubReader.h" #ifdef BSP_USING_TOUCHD #include "drv_touch.h" #endif volatile int g_touch_last_settings_row = -1; volatile int g_touch_last_settings_dir = 0; +extern int settings_selected_idx; +extern AppUIState ui_state; +extern int book_index; +extern bool library_bottom_mode; +extern int library_bottom_idx; +extern int toc_index; +extern int toc_bottom_idx; +extern bool toc_bottom_mode;//控制目录页面中功能选项的开关 +static int last_clicked_toc_index = -1; // -1 表示没有目录项被选中 +// 添加一个变量来记录上次点击的书籍索引 +static int last_clicked_book_index = -1; // -1 表示没有书籍被选中 +static bool waiting_for_confirmation = false; // 是否正在等待确认 +extern int touch_sel; +extern EpubReader *reader; + rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) { @@ -23,73 +41,362 @@ rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) y = touch_data.x; - if (TOUCH_EVENT_DOWN == touch_data.event) + // if (TOUCH_EVENT_DOWN == touch_data.event) + // rt_kprintf("Touch down [%d,%d]\r\n", x, y); + // else + // rt_kprintf("Touch up [%d,%d]\r\n", x, y); + if (TOUCH_EVENT_DOWN == touch_data.event) + { rt_kprintf("Touch down [%d,%d]\r\n", x, y); + + // 记录按下时的位置 + instance->touch_start_x = x; + instance->touch_start_y = y; + + instance->is_touch_down = true; + + // 处理其他触控逻辑... + } else - rt_kprintf("Touch up [%d,%d]\r\n", x, y); - + { + rt_kprintf("Touch up [%d,%d]\r\n", x, y); + instance->touch_current_x = x; + instance->touch_current_y = y; + + // 检查是否构成向上滑动手势 + if (instance->is_touch_down) { + int y_diff = instance->touch_start_y - touch_data.y; // 注意坐标转换 + int x_diff = abs(instance->touch_start_x - touch_data.x); + rt_kprintf("Touch up diff Y: %d, X: %d\r\n", y_diff, x_diff); + + // 检查时间间隔,防止连续触发 + rt_tick_t current_time = rt_tick_get(); + if(reader->is_overlay_active() == false) + { + if (y_diff > instance->SWIPE_THRESHOLD && y_diff > abs(x_diff)) + { + rt_kprintf("Up swipe detected! Diff: %d\n", y_diff); + + // 发送向上滑动动作 + UIAction action = UPGLIDE; + instance->last_action = action; + instance->on_action(action); + + + // 重置状态 + instance->is_touch_down = false; + return RT_EOK; + } + } + } + + // 重置触摸状态 + instance->is_touch_down = false; + } + // 只处理按下事件,忽略释放事件 + if (TOUCH_EVENT_UP == touch_data.event) { + return RT_EOK; + } UIAction action = NONE; // LOG_I("TOUCH", "Received touch event %d,%d", x, y); // 主页面底部按键区域:左"<"、右">"、中间文本框 - int page_w = instance->renderer->get_page_width(); - int page_h = instance->renderer->get_page_height(); - int margin_side = 10; - int margin_bottom = 60; - int rect_w = 80; - int rect_h = 40; - int y_bottom = page_h - rect_h - margin_bottom; - int left_x = margin_side; - int right_x = page_w - rect_w - margin_side; - int mid_x = left_x + rect_w + margin_side; - int mid_w = right_x - margin_side - mid_x; - - if (x >= left_x && x <= left_x + rect_w && y >= y_bottom && y <= y_bottom + rect_h) +switch (ui_state) +{ + case MAIN_PAGE://主页面 + if (x >= 10 && x <= 80 && y >= 950 && y <= 1000) { rt_kprintf("Touch left < \n"); - action = UP; + action = UP; // 对应 KEY3 功能 } - - else if (x >= right_x && x <= right_x + rect_w && y >= y_bottom && y <= y_bottom + rect_h) + else if (x >= 650 && x <= 750 && y >= 950 && y <= 1000) { - action = DOWN; + action = DOWN; // 对应 KEY1 功能 rt_kprintf("Touch right > \n"); } - - // 设置页面每行左右箭头触控区域(与设置页布局一致) - if (action == NONE) - { - int page_w2 = instance->renderer->get_page_width(); - int margin_lr2 = 6; - int item_h2 = 100; - int gap2 = 54; - int arrow_col_w2 = 40; - int lh2 = instance->renderer->get_line_height(); - int y_start2 = 40 + lh2 + 20; - g_touch_last_settings_row = -1; - g_touch_last_settings_dir = 0; - for (int row = 0; row < 3; ++row) - { - int ry = y_start2 + row * (item_h2 + gap2); - int left_ax = margin_lr2; - int right_ax = page_w2 - margin_lr2 - arrow_col_w2; - if (x >= left_ax && x <= left_ax + arrow_col_w2 && y >= ry && y <= ry + item_h2) - { + else if (x >= 250 && x <= 500 && y >= 950 && y <= 1000) + { + action = SELECT; // 对应 KEY2 功能 + rt_kprintf("Touch middle SELECT \n"); + } + break; + case SELECTING_EPUB://书库页面 + // 检查是否点击了功能控制按钮 + if(x >= 10 && x <= 250 && y >= 920 && y <= 1010) + { + library_bottom_mode = true; + library_bottom_idx = 0; + action = SELECT; + } + else if(x >= 280 && x <= 500 && y >= 920 && y <= 1010) + { + library_bottom_mode = true; + library_bottom_idx = 1; + action = SELECT; + } + else if(x >= 520 && x <= 750 && y >= 920 && y <= 1010) + { + library_bottom_mode = true; + library_bottom_idx = 2; + action = SELECT; + } + else + { + // 处理书籍选择区域 + int clicked_book_index = -1; + + if(x >= 10 && x <= 740 && y >= 60 && y <= 240) + { + clicked_book_index = 0; + } + else if(x >= 10 && x <= 740 && y >= 270 && y <= 450) + { + clicked_book_index = 1; + } + else if(x >= 10 && x <= 740 && y >= 470 && y <= 680) + { + clicked_book_index = 2; + } + else if(x >= 10 && x <= 740 && y >= 700 && y <= 900) + { + clicked_book_index = 3; + } + + // 如果点击了书籍区域 + if(clicked_book_index != -1) + { + // 判断是第一次点击还是第二次点击 + if(waiting_for_confirmation && last_clicked_book_index == clicked_book_index) + { + // 第二次点击:执行打开操作 + book_index = clicked_book_index; + library_bottom_mode = false; + rt_kprintf("Open book%d %d\n", book_index, book_index); + action = SELECT; + + // 重置状态 + waiting_for_confirmation = false; + last_clicked_book_index = -1; + } + else + { + // 第一次点击:选择书籍并等待确认 + book_index = clicked_book_index; + last_clicked_book_index = clicked_book_index; + waiting_for_confirmation = true; + action = SELECT_BOX; + rt_kprintf("Select book%d for confirmation, waiting for second click\n", book_index); + } + } + } + break; + case READING_EPUB: //阅读界面 + //翻页操作 + if(x >= 10 && x <= 200 && y >=10 && y <= 1010 && reader->is_overlay_active() == false) + { action = UP; - g_touch_last_settings_row = row; - g_touch_last_settings_dir = -1; // 左=减 - break; - } - if (x >= right_ax && x <= right_ax + arrow_col_w2 && y >= ry && y <= ry + item_h2) - { + } + else if(x >= 550 && x <= 750 && y >=10 && y <= 1010 && reader->is_overlay_active() == false) + { action = DOWN; - g_touch_last_settings_row = row; - g_touch_last_settings_dir = +1; // 右=加 - break; - } } - } + //点击正文,推出阅读设置 + if(x >= 10 && x <= 750 && y >=10 && y <= 630 && reader->is_overlay_active()) + { + touch_sel = 8; + action = SELECT; + } + + //阅读页面控制区域设置 + if(x >= 10 && x <= 250 && y >= 900 && y <= 960 && reader->is_overlay_active()) + { + touch_sel = 8; + action = SELECT; + } + else if(x >= 280 && x <= 480 && y >= 900 && y <= 960 && reader->is_overlay_active()) + { + touch_sel = 9; + action = SELECT; + } + else if(x >= 520 && x <= 750 && y >= 900 && y <= 960 && reader->is_overlay_active()) + { + touch_sel = 10; + action = SELECT; + } + else if(x >= 10 && x <= 150 && y >= 690 && y <= 750 && reader->is_overlay_active()) + { + touch_sel= 0; + rt_kprintf("Touch middle SELECT %d\n",touch_sel); + action = SELECT; + } + else if(x >= 170 && x <= 570 && y >= 690 && y <= 750 && reader->is_overlay_active()) + { + touch_sel= 1; + rt_kprintf("Touch middle SELECT %d\n",touch_sel); + action = SELECT; + } + else if(x >= 610 && x <= 750 && y >= 690 && y <= 750 && reader->is_overlay_active()) + { + touch_sel= 2; + rt_kprintf("Touch middle SELECT %d\n",touch_sel); + action = SELECT; + } + else if(x >= 10 && x <= 140 && y >= 790 && y <= 850 && reader->is_overlay_active()) + { + touch_sel = 3;//跳转-5页 + action = SELECT; + } + else if(x >= 165 && x <=300 && y >= 790 && y <= 850 && reader->is_overlay_active()) + { + touch_sel = 4;//跳转-1页 + action = SELECT; + } + else if(x >= 480 && x <= 570 && y >= 790 && y <= 850 && reader->is_overlay_active()) + { + touch_sel = 6;//跳转+1页 + action = SELECT; + } + else if(x >= 620 && x <= 750 && y >= 790 && y <= 850 && reader->is_overlay_active()) + { + touch_sel = 7;//跳转5页 + action = SELECT; + } + + break; + case SELECTING_TABLE_CONTENTS: //目录界面 + if(x >= 10 && x <= 250 && y >= 920 && y <= 1010) + { + toc_bottom_mode = true; + toc_bottom_idx = 0; + action = SELECT; + } + else if(x >= 280 && x <= 500 && y >= 920 && y <= 1010) + { + toc_bottom_mode = true; + toc_bottom_idx = 1; + action = SELECT; + } + else if(x >= 520 && x <= 750 && y >= 920 && y <= 1010) + { + toc_bottom_mode = true; + toc_bottom_idx = 2; + action = SELECT; + } + else// 目录项选择区域 + { + int clicked_toc_index = -1; + + if(x >= 10 && x <= 750 && y >= 20 && y <= 170) + { + clicked_toc_index = 0; + } + else if(x >= 10 && x <= 750 && y >= 180 && y <= 310) + { + clicked_toc_index = 1; + } + else if(x >= 10 && x <= 750 && y >= 330 && y <= 450) + { + clicked_toc_index = 2; + } + else if(x >= 10 && x <= 750 && y >= 470 && y <= 590) + { + clicked_toc_index = 3; + } + else if(x >= 10 && x <= 750 && y >= 620 && y <= 750) + { + clicked_toc_index = 4; + } + else if(x >= 10 && x <= 750 && y >= 770 && y <= 890) + { + clicked_toc_index = 5; + } + // 如果点击了目录项区域 + if(clicked_toc_index != -1) + { + // 判断是第一次点击还是第二次点击 + if(waiting_for_confirmation && last_clicked_toc_index == clicked_toc_index) + { + // 第二次点击:执行打开操作 + toc_index = clicked_toc_index; + library_bottom_mode = false; + rt_kprintf("Open book%d %d\n", toc_index, toc_index); + action = SELECT; + + // 重置状态 + waiting_for_confirmation = false; + last_clicked_toc_index = -1; + } + else + { + // 第一次点击:选择目录项并等待确认 + toc_index = clicked_toc_index; + last_clicked_toc_index = clicked_toc_index; + waiting_for_confirmation = true; + action = SELECT_BOX; + } + } + } + + break; + case SETTINGS_PAGE: // 设置页面 + // 设置页面每行左右箭头触控区域(与设置页布局一致) + if (x >= 100 && x <= 650 && y >= 160 && y <= 260) + { + settings_selected_idx = SET_TOUCH; + action = SELECT_BOX; + rt_kprintf("select touch switch\n"); + } + else if (x >= 100 && x <= 650 && y >= 300 && y <= 400) + { + settings_selected_idx = SET_TIMEOUT; + action = SELECT_BOX; + rt_kprintf("select timeout switch\n"); + } + else if (x >= 100 && x <= 650 && y >= 450 && y <= 540) + { + settings_selected_idx = SET_FULL_REFRESH; + action = SELECT_BOX; + rt_kprintf("select full refresh switch \n"); + } + else if (x >= 100 && x <= 650 && y >= 830 && y <= 950) + { + settings_selected_idx = SET_CONFIRM; + action = SELECT; + rt_kprintf("select touch switch\n"); + } + + if(settings_selected_idx == SET_TOUCH && 0<=x && x<= 50 && 160<=y && y<=260) + { + action = SELECT; + } + else if(settings_selected_idx == SET_TOUCH && 700<=x && x<=750 && 160<=y && y<=260) + { + action = SELECT; + } + else if(settings_selected_idx == SET_TIMEOUT && 0 <= x && x<=50 && 300 <= y && y<= 400) + { + action = PREV_OPTION; + rt_kprintf("select timeout Reduce\n"); + } + else if(settings_selected_idx == SET_TIMEOUT && 700<=x && x<=750 && 300<=y && y<= 400) + { + action = NEXT_OPTION; + rt_kprintf("select timeout increase\n"); + } + else if(settings_selected_idx == SET_FULL_REFRESH && 0 <= x && x<= 50 && 450 <= y && y<= 540) + { + action = PREV_OPTION; + } + else if(settings_selected_idx == SET_FULL_REFRESH && 700 <= x && x<= 750 && 450 <= y && y<= 540) + { + action = NEXT_OPTION; + } + break; + +} + + instance->last_action = action; if (action != NONE) @@ -133,7 +440,6 @@ void SF32_TouchControls::powerOffTouch() rt_kprintf("no touch device found\n"); } } - void SF32_TouchControls::powerOnTouch() { if (tp_device) { diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.h b/epdiy-epub/src/boards/controls/SF32_TouchControls.h index d9dfba6..1983a55 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.h +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.h @@ -14,7 +14,14 @@ class SF32_TouchControls : public TouchControls uint8_t ui_button_width = 120; uint8_t ui_button_height = 34; UIAction last_action = NONE; - + // 添加手势检测状态 + bool is_touch_down = false; // 是否正在触摸 + int touch_start_x = 0; // 按下时的 X 坐标 + int touch_start_y = 0; // 按下时的 Y 坐标 + int touch_current_x = 0; // 当前触摸 X 坐标 + int touch_current_y = 0; // 当前触摸 Y 坐标 + // 滑动检测阈值 + static const int SWIPE_THRESHOLD = 50; // 最小滑动距离阈值 public: static rt_err_t tp_rx_indicate(rt_device_t dev, rt_size_t size); diff --git a/epdiy-epub/src/boards/controls/TouchControls.h b/epdiy-epub/src/boards/controls/TouchControls.h index b0c8ba9..cc04d1f 100644 --- a/epdiy-epub/src/boards/controls/TouchControls.h +++ b/epdiy-epub/src/boards/controls/TouchControls.h @@ -8,7 +8,7 @@ class Renderer; class TouchControls { protected: - bool touch_enable = false; + bool touch_enable = 1; public: TouchControls(){}; diff --git a/epdiy-epub/src/boards/touch/gt967/SConscript b/epdiy-epub/src/boards/touch/gt967/SConscript new file mode 100644 index 0000000..6eb93f8 --- /dev/null +++ b/epdiy-epub/src/boards/touch/gt967/SConscript @@ -0,0 +1,8 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd + '/../common', cwd] +group = DefineGroup('Drivers', src, depend = ['TSC_USING_GT967'], CPPPATH = CPPPATH) + +Return('group') diff --git a/epdiy-epub/src/boards/touch/gt967/gt967.c b/epdiy-epub/src/boards/touch/gt967/gt967.c new file mode 100644 index 0000000..1f7672a --- /dev/null +++ b/epdiy-epub/src/boards/touch/gt967/gt967.c @@ -0,0 +1,262 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 SiFli Technologies(Nanjing) Co., Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "board.h" +#include "gt967.h" +#include "drv_touch.h" + +/* Define -------------------------------------------------------------------*/ + +#define DBG_LEVEL DBG_INFO // DBG_ERROR // +#define LOG_TAG "drv.gt967" +#include +#define TP_DEV_ADDR (0x14) +#define TP_TD_STATUS (0x814e) +#define TP_P1_XL (0x8150) +#define TP_P1_XH (0x8151) +#define TP_P1_YL (0x8152) +#define TP_P1_YH (0x8153) + +#define TP_ID_CONTROL (0x8040) + +// rotate to left with 90, 180, 270 +// rotate to left with 360 for mirror +//#define TP_ROTATE_LEFT (90) + +/* function and value-----------------------------------------------------------*/ + +static void correct_pos(touch_msg_t ppos); +static rt_err_t write_reg(uint16_t reg, rt_uint8_t data); +static rt_err_t read_regs(rt_uint16_t reg, rt_uint8_t len, rt_uint8_t *buf); + +static struct rt_i2c_bus_device *ft_bus = NULL; + +static struct touch_drivers driver; + +static rt_err_t write_reg(uint16_t reg, rt_uint8_t data) +{ + rt_int8_t res = 0; + struct rt_i2c_msg msgs; + rt_uint8_t buf[3] = {(uint8_t)(reg >> 8), (uint8_t)reg, data}; + + msgs.addr = TP_DEV_ADDR; /* slave address */ + msgs.flags = RT_I2C_WR; /* write flag */ + msgs.buf = buf; /* Send data pointer */ + msgs.len = 3; + + if (rt_i2c_transfer(ft_bus, &msgs, 1) == 1) + { + res = RT_EOK; + } + else + { + res = -RT_ERROR; + } + return res; +} + +static rt_err_t read_regs(rt_uint16_t reg, rt_uint8_t len, rt_uint8_t *buf) +{ + rt_int8_t res = 0; + struct rt_i2c_msg msgs[2]; + rt_uint8_t reg_w[2] = {(uint8_t)(reg >> 8), (uint8_t)reg}; + + msgs[0].addr = TP_DEV_ADDR; /* Slave address */ + msgs[0].flags = RT_I2C_WR; /* Write flag */ + msgs[0].buf = reg_w; /* Slave register address */ + msgs[0].len = 2; /* Number of bytes sent */ + + msgs[1].addr = TP_DEV_ADDR; /* Slave address */ + msgs[1].flags = RT_I2C_RD; /* Read flag */ + msgs[1].buf = buf; /* Read data pointer */ + msgs[1].len = len; /* Number of bytes read */ + + if (rt_i2c_transfer(ft_bus, msgs, 2) == 2) + { + res = RT_EOK; + } + else + { + res = -RT_ERROR; + } + return res; +} + +static void correct_pos(touch_msg_t ppos) +{ + int temp_x = ppos->x; + ppos->x = ppos->y; + ppos->y = LCD_VER_RES_MAX - (temp_x ) - 1; + + return; +} + +static rt_err_t read_point(touch_msg_t p_msg) +{ + uint8_t buf[80] = {0}; + uint8_t point_num = 0, touch_down = 0; + int ret = 0, retry = 2; + uint8_t reg_value[8] = {0}; + reg_value[0] = 0x81; + reg_value[1] = 0x40; + // reg_value[2] = 0x00; + // reg_value[3] = 0x00; +// rt_kprintf("tp read_point\n"); + read_regs(0x814e, 1, buf); + if ((buf[0] & 0x80) != 0x80) + { + rt_thread_delay(1); //delay 1ms if buffer status is not relay; + LOG_D("tp\n"); + read_regs(0x814e, 1, buf); + } + rt_touch_irq_pin_enable(1); + + point_num = buf[0] & 0x0f; + if (point_num) // the number of touch points + { + p_msg->event = TOUCH_EVENT_DOWN; + } + else + { + p_msg->event = TOUCH_EVENT_UP; + } + read_regs(0x8150, 6, buf); + p_msg->x = buf[0] + ((uint16_t)(buf[1] & 0xff) << 8); + p_msg->y = buf[2] + ((uint16_t)(buf[3] & 0xff) << 8); + correct_pos(p_msg); + LOG_D("piont:%d, x:%d, y:%d,event:%d,byte:%d\n", point_num, p_msg->x, p_msg->y, p_msg->event, buf[4]); + + write_reg(0x814e, 0); //clear tp interrupt + + return RT_EEMPTY; +} + +static void irq_handler(void *arg) +{ + rt_err_t ret = RT_ERROR; + + int value = (int)arg; + LOG_D("gt967 touch_irq_handler\n"); + + rt_touch_irq_pin_enable(0); + + ret = rt_sem_release(driver.isr_sem); + RT_ASSERT(RT_EOK == ret); +} +static rt_err_t init(void) +{ + rt_err_t err; + struct touch_message msg; + + LOG_D("gt967 init"); + + rt_pin_mode(TOUCH_IRQ_PIN, PIN_MODE_OUTPUT); //上电复位I2C地址选择(通过RESET/INT时序选择0x28/0x29的I2C地址) + rt_pin_write(TOUCH_IRQ_PIN, 0); + BSP_TP_Reset(0); + rt_thread_delay(1); + rt_pin_write(TOUCH_IRQ_PIN, 1); + rt_thread_delay(1); + BSP_TP_Reset(1); + rt_thread_delay(8); + rt_pin_write(TOUCH_IRQ_PIN, 0); + rt_thread_delay(60); + + rt_touch_irq_pin_attach(PIN_IRQ_MODE_FALLING, irq_handler, NULL); + rt_touch_irq_pin_enable(1); //Must enable before read I2C + + uint8_t buf[6] = {0}; + read_regs(0x8144, 4, buf); + uint16_t firmware_version; + firmware_version = buf[0] + ((uint16_t)(buf[1] & 0xff) << 8); + + LOG_I("Firmware version = 0x%x(%d)", firmware_version, firmware_version); + + //Soft reset + err = write_reg(TP_ID_CONTROL, 2); + if (RT_EOK != err) + { + LOG_E("SoftReset fail\n"); + return RT_FALSE; + } + err = write_reg(TP_ID_CONTROL, 0); + if (RT_EOK != err) + { + LOG_E("SoftReset stop fail\n"); + return RT_FALSE; + } + + LOG_D("gt967 init OK"); + return RT_EOK; + +} + +static rt_err_t deinit(void) +{ + LOG_D("gt967 deinit"); + + rt_touch_irq_pin_enable(0); + return RT_EOK; + +} + +static rt_bool_t probe(void) +{ + + ft_bus = (struct rt_i2c_bus_device *)rt_device_find(TOUCH_DEVICE_NAME); + if (RT_Device_Class_I2CBUS != ft_bus->parent.type) + { + ft_bus = NULL; + } + if (ft_bus) + { + rt_device_open((rt_device_t)ft_bus, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX); + } + else + { + LOG_I("bus not find\n"); + return RT_FALSE; + } + + { + struct rt_i2c_configuration configuration = + { + .mode = 0, + .addr = 0, + .timeout = 500, + .max_hz = 400000, + }; + + rt_i2c_configure(ft_bus, &configuration); + } + + LOG_I("probe OK"); + + return RT_TRUE; +} + +static struct touch_ops ops = +{ + read_point, + init, + deinit +}; + +static int rt_tp_device_init(void) +{ + + driver.probe = probe; + driver.ops = &ops; + driver.user_data = RT_NULL; + driver.isr_sem = rt_sem_create("gt967", 0, RT_IPC_FLAG_FIFO); + + rt_touch_drivers_register(&driver); + + return 0; + +} +INIT_COMPONENT_EXPORT(rt_tp_device_init); + diff --git a/epdiy-epub/src/boards/touch/gt967/gt967.h b/epdiy-epub/src/boards/touch/gt967/gt967.h new file mode 100644 index 0000000..17dd8f0 --- /dev/null +++ b/epdiy-epub/src/boards/touch/gt967/gt967.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 SiFli Technologies(Nanjing) Co., Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __GT967_H +#define __GT967_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/* type ------------------------------------------------------------------*/ + +/* function ------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif /* __GT911_H */ + diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index b06ae54..523b704 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -2,7 +2,7 @@ #include "EpubList/EpubList.h" #include "epub_screen.h" #include - +#include "type.h" extern TouchControls *touch_controls; extern "C" @@ -16,9 +16,9 @@ extern int g_last_read_index; // 主页面选项 typedef enum { - OPTION_OPEN_LIBRARY = 0, - OPTION_CONTINUE_READING, - OPTION_ENTER_SETTINGS + OPTION_OPEN_LIBRARY = 0, // 打开书库 + OPTION_CONTINUE_READING, // 继续阅读 + OPTION_ENTER_SETTINGS // 进入设置 } MainOption; static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” @@ -34,9 +34,18 @@ int screen_get_full_refresh_period() } // 切换全刷周期(循环) -void screen_cycle_full_refresh_period() +void screen_cycle_full_refresh_period(bool refresh) { - full_refresh_idx = (full_refresh_idx + 1) % kFullRefreshOptionsCount; // ?% 4 + if(refresh) + { + full_refresh_idx = (full_refresh_idx + 1) % kFullRefreshOptionsCount; // ?% 4 + + } + else + { + full_refresh_idx = (full_refresh_idx - 1) % kFullRefreshOptionsCount; // ?% 4 + + } } // 设置全刷周期索引 @@ -51,9 +60,8 @@ int screen_get_full_refresh_idx() return full_refresh_idx; } -// 设置页列表项 -typedef enum { SET_TOUCH = 0, SET_TIMEOUT = 1, SET_FULL_REFRESH = 2, SET_CONFIRM = 3 } SettingsItem; -static int settings_selected_idx = 0; + +int settings_selected_idx = 0; // 超时关机:5/10/30分钟、1小时、不关机(0) static const int kTimeoutOptions[] = {5, 10, 30, 60, 0}; // 单位:分钟,0为不关机 @@ -79,7 +87,7 @@ static void adjust_timeout(bool increase) } else { - timeout_idx = (timeout_idx - 1 + kTimeoutOptionsCount) % kTimeoutOptionsCount; + timeout_idx = (timeout_idx - 1) % kTimeoutOptionsCount; } timeout_shutdown_minutes = kTimeoutOptions[timeout_idx]; } @@ -101,7 +109,7 @@ int screen_get_main_selected_option() return (int)main_option; // 0: 打开书库, 1: 继续阅读, 2: 进入设置 } -// 主页面 +// 绘制主页面 static void render_main_page(Renderer *renderer) { renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); @@ -152,12 +160,12 @@ static void render_main_page(Renderer *renderer) int opt_h = renderer->get_line_height(); renderer->draw_text(mid_x + (mid_w - opt_w) / 2, y + (rect_h - opt_h) / 2, opt_text, false, true); } - +//主界面处理 void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw) { if (needs_redraw || action == NONE) { - render_main_page(renderer); + render_main_page(renderer);//绘制主界面 return; } switch (action) @@ -195,7 +203,7 @@ void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw) } // 设置页面 -static void render_settings_page(Renderer *renderer) +void render_settings_page(Renderer *renderer) { renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); @@ -334,6 +342,7 @@ static void render_settings_page(Renderer *renderer) renderer->draw_text(confirm_x + (confirm_w - c_w) / 2, confirm_y + (confirm_h - c_h) / 2, confirm, false, true); } +// 设置页面交互处理 bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) { // 读取并清除一次性的触控箭头标记,避免后续硬件按键误用 @@ -376,6 +385,56 @@ bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) render_settings_page(renderer); } break; + case SELECT_BOX: + if(settings_selected_idx == SET_TOUCH) + { + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_TIMEOUT) + { + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_FULL_REFRESH) + { + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_CONFIRM) + { + render_settings_page(renderer); + return true; + } + break; + case PREV_OPTION: + if (settings_selected_idx == SET_TIMEOUT) + { + // SELECT 在超时关机项上为加操作(循环) + adjust_timeout(false); + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_FULL_REFRESH) + { + + screen_cycle_full_refresh_period(false); + set_part_disp_times(screen_get_full_refresh_period()); + render_settings_page(renderer); + } + + break; + case NEXT_OPTION: + if (settings_selected_idx == SET_TIMEOUT) + { + // SELECT 在超时关机项上为加操作(循环) + adjust_timeout(true); + render_settings_page(renderer); + } + else if(settings_selected_idx == SET_FULL_REFRESH) + { + + screen_cycle_full_refresh_period(true); + set_part_disp_times(screen_get_full_refresh_period()); + render_settings_page(renderer); + } + break; case SELECT: if (settings_selected_idx == SET_TOUCH) { @@ -399,7 +458,7 @@ bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw) if (settings_selected_idx == SET_FULL_REFRESH) { // SELECT 在全刷周期项上为加操作(循环) - screen_cycle_full_refresh_period(); + screen_cycle_full_refresh_period(true); set_part_disp_times(screen_get_full_refresh_period()); render_settings_page(renderer); break; diff --git a/epdiy-epub/src/epub_screen.h b/epdiy-epub/src/epub_screen.h index d3f1646..148141b 100644 --- a/epdiy-epub/src/epub_screen.h +++ b/epdiy-epub/src/epub_screen.h @@ -22,6 +22,6 @@ void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw); // 设置页面交互与渲染;返回 true 表示确认并退出到主页面 bool handleSettingsPage(Renderer *renderer, UIAction action, bool needs_redraw); // 切换全刷周期(循环) -void screen_cycle_full_refresh_period(); +void screen_cycle_full_refresh_period(bool refresh); // 获取当前全刷周期值 int screen_get_full_refresh_period(); \ No newline at end of file diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 4d61b12..9f00ed6 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -5,13 +5,14 @@ #include "EpubList/EpubToc.h" #include #include "boards/Board.h" +#include "boards/controls/Actions.h" #include "boards/controls/SF32_TouchControls.h" #include "epub_screen.h" #include "boards/SF32PaperRenderer.h" #include "gui_app_pm.h" #include "bf0_pm.h" #include "epd_driver.h" - +#include "type.h" #undef LOG_TAG #undef DBG_LEVEL #define DBG_LEVEL DBG_LOG //DBG_INFO // @@ -32,20 +33,9 @@ extern "C" extern const uint8_t shutdown_map[]; } - const char *TAG = "main"; -typedef enum { - MAIN_PAGE, // 新主页面 - SELECTING_EPUB, // 电子书列表页面(书库) - SELECTING_TABLE_CONTENTS, // 电子书目录页面 - READING_EPUB, // 阅读页面 - SETTINGS_PAGE, // 通用功能设置页面 - WELCOME_PAGE, // 欢迎页面 - LOW_POWER_PAGE, // 低电量页面 - CHARGING_PAGE, // 充电页面 - SHUTDOWN_PAGE // 关机页面 -} AppUIState; + // 默认显示新主页面,而非书库页面 AppUIState ui_state = MAIN_PAGE; @@ -62,7 +52,7 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw); void back_to_main_page(); static EpubList *epub_list = nullptr; -static EpubReader *reader = nullptr; +EpubReader *reader = nullptr; static EpubToc *contents = nullptr; static bool charge_full = false; Battery *battery = nullptr; @@ -71,9 +61,18 @@ Renderer *renderer = nullptr; TouchControls *touch_controls = nullptr; // 书库页底部按钮选择状态 -static bool library_bottom_mode = false; // 是否处于底部三按钮选择模式 -static int library_bottom_idx = 1; // 当前底部按钮索引:0上一页,1主页面,2下一页 - +bool library_bottom_mode = false; // 是否处于底部三按钮选择模式 +int library_bottom_idx = 1; // 当前底部按钮索引:0上一页,1主页面,2下一页 +int book_index;//用于记录电子书触控选择 +int current_page; // 当前页面 +int start_index; // 当前页起始索引 +// 计算全局索引 = 页起始索引 + 页内偏移 +int global_index; +bool toc_bottom_mode = false; +int toc_index;//用于记录目录触控选择 +int toc_bottom_idx = 1; // 0:上一页,1:主页面,2:下一页 +int sel; +int touch_sel; rt_mq_t ui_queue = RT_NULL; // 主页面选项 @@ -86,169 +85,178 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red void handleEpub(Renderer *renderer, UIAction action) { - if (!reader) - { - reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); - reader->load(); - // 记录最近一次进入阅读的书籍索引 - g_last_read_index = epub_list_state.selected_item; - } - switch (action) - { - case UP: - if (reader->is_overlay_active()) - { - reader->overlay_move_left(); - } - else - { - reader->prev(); - } - break; - case DOWN: - if (reader->is_overlay_active()) + if (!reader) { - reader->overlay_move_right(); - } - else - { - reader->next(); + reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); + reader->load(); + // 记录最近一次进入阅读的书籍索引 + g_last_read_index = epub_list_state.selected_item; } - break; - case SELECT: - if (reader->is_overlay_active()) + + switch (action) { - int sel = reader->get_overlay_selected(); - // 1/3:改变中心属性;2:执行当前属性(触控取反 / 全刷周期循环) - if (sel == 0) - { - if(reader->overlay_is_center_touch()) + case UP: + if (reader->is_overlay_active()) { - reader->overlay_set_center_mode_full_refresh(); + reader->overlay_move_left(); } else { - reader->overlay_set_center_mode_touch(); + reader->prev(); } - } - else if (sel == 2) - { - if(reader->overlay_is_center_touch()) + break; + case DOWN: + if (reader->is_overlay_active()) { - reader->overlay_set_center_mode_full_refresh(); + reader->overlay_move_right(); } else { - reader->overlay_set_center_mode_touch(); + reader->next(); } - - } - else if (sel == 1) - { - // 中心矩形:根据当前属性执行 - if (reader->overlay_is_center_touch()) + break; + case SELECT: + if (reader->is_overlay_active()) { - bool cur = touch_controls ? touch_controls->isTouchEnabled() : false; - if (touch_controls) - { - touch_controls->setTouchEnable(!cur); - if (!cur) touch_controls->powerOnTouch(); else touch_controls->powerOffTouch(); - } - reader->overlay_set_touch_enabled(!cur); + int sel = reader->get_overlay_selected(); + // 1/3:改变中心属性;2:执行当前属性(触控取反 / 全刷周期循环) + if(touch_sel >=0 && touch_sel <=10) + { + sel = -1; + } + if (sel == 0 || touch_sel == 0) + { + if(reader->overlay_is_center_touch()) + { + reader->overlay_set_center_mode_full_refresh(); + } + else + { + reader->overlay_set_center_mode_touch(); + } + } + else if (sel == 2 || touch_sel == 2) + { + if(reader->overlay_is_center_touch()) + { + reader->overlay_set_center_mode_full_refresh(); + } + else + { + reader->overlay_set_center_mode_touch(); + } + } + else if (sel == 1 || touch_sel == 1) + { + // 中心矩形:根据当前属性执行 + if (reader->overlay_is_center_touch()) + { + bool cur = touch_controls ? touch_controls->isTouchEnabled() : false; + if (touch_controls) + { + touch_controls->setTouchEnable(!cur); + if (!cur) touch_controls->powerOnTouch(); else touch_controls->powerOffTouch(); + } + reader->overlay_set_touch_enabled(!cur); + } + else + { + reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/每次(0) 之间循环 + set_part_disp_times(reader->overlay_get_full_refresh_value()); + } + } + if (sel == 9 || touch_sel == 9) //目录 + { + ui_state = SELECTING_TABLE_CONTENTS; + renderer->set_margin_bottom(0); + reader->stop_overlay(); + delete reader; + reader = nullptr; + contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); + contents->load(); + contents->set_needs_redraw(); + handleEpubTableContents(renderer, NONE, true); + touch_sel = -1; + return; + } + else if (sel == 8 || touch_sel == 8) //确认:1.按第六格累积值跳页 + { + // 跳转到第六格显示的目标页 + int target = reader->overlay_get_target_page(); + if (target < 1) target = 1; + extern EpubListState epub_list_state; + epub_list_state.epub_list[epub_list_state.selected_item].current_page = (uint16_t)(target - 1); + reader->overlay_reset_jump(); + reader->stop_overlay(); + } + else if (sel == 10 || touch_sel == 10) //书库 + { + ui_state = SELECTING_EPUB; + renderer->set_margin_bottom(0); + reader->stop_overlay(); + renderer->clear_screen(); + delete reader; + reader = nullptr; + if (!epub_list) + { + epub_list = new EpubList(renderer, epub_list_state); + } + handleEpubList(renderer, NONE, true); + touch_sel = -1; + return; + } + else if (sel == 3 || touch_sel == 3) + { + reader->overlay_adjust_target_page(-5); + } + else if (sel == 4 || touch_sel == 4) + { + reader->overlay_adjust_target_page(-1); + } + else if (sel == 6 || touch_sel == 6) + { + reader->overlay_adjust_target_page(1); + } + else if (sel == 7 || touch_sel == 7) + { + reader->overlay_adjust_target_page(5); + } + touch_sel = -1; } else { - reader->overlay_cycle_full_refresh(); //设置全刷周期,在 5/10/20/每次(0) 之间循环 - set_part_disp_times(reader->overlay_get_full_refresh_value()); + // switch back to main screen + renderer->clear_screen(); + // clear the epub reader away + delete reader; + reader = nullptr; + // force a redraw + if (!epub_list) + { + epub_list = new EpubList(renderer, epub_list_state); + } + renderer->set_margin_bottom(0); + back_to_main_page(); + + return; } - } - if (sel == 9) //目录 - { - ui_state = SELECTING_TABLE_CONTENTS; - renderer->set_margin_bottom(0); - reader->stop_overlay(); - delete reader; - reader = nullptr; - contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); - contents->load(); - contents->set_needs_redraw(); - handleEpubTableContents(renderer, NONE, true); - return; - } - else if (sel == 8) //确认:1.按第六格累积值跳页 - { - // 跳转到第六格显示的目标页 - int target = reader->overlay_get_target_page(); - if (target < 1) target = 1; - extern EpubListState epub_list_state; - epub_list_state.epub_list[epub_list_state.selected_item].current_page = (uint16_t)(target - 1); - reader->overlay_reset_jump(); - reader->stop_overlay(); - } - else if (sel == 10) //书库 - { - ui_state = SELECTING_EPUB; - renderer->set_margin_bottom(0); - reader->stop_overlay(); - renderer->clear_screen(); - delete reader; - reader = nullptr; - if (!epub_list) - { - epub_list = new EpubList(renderer, epub_list_state); + break; + case UPGLIDE: + // 激活阅读页下半屏覆盖操作层 + // 防止重复激活 + if (!reader->is_overlay_active()) { + reader->start_overlay(); + // 默认中心属性为触控开关,初始同步当前触控状态 + reader->overlay_set_center_mode_touch(); + if (touch_controls) + reader->overlay_set_touch_enabled(touch_controls->isTouchEnabled()); } - handleEpubList(renderer, NONE, true); - return; - } - else if (sel == 3) - { - reader->overlay_adjust_target_page(-5); - } - else if (sel == 4) - { - reader->overlay_adjust_target_page(-1); - } - else if (sel == 6) - { - reader->overlay_adjust_target_page(1); - } - else if (sel == 7) - { - reader->overlay_adjust_target_page(5); - } - - } - else - { - // switch back to main screen - renderer->clear_screen(); - // clear the epub reader away - delete reader; - reader = nullptr; - // force a redraw - if (!epub_list) - { - epub_list = new EpubList(renderer, epub_list_state); - } - renderer->set_margin_bottom(0); - back_to_main_page(); - - return; + break; + case NONE: + default: + break; } - break; - case UPGLIDE: - // 激活阅读页下半屏覆盖操作层 - reader->start_overlay(); - // 默认中心属性为触控开关,初始同步当前触控状态 - reader->overlay_set_center_mode_touch(); - if (touch_controls) - reader->overlay_set_touch_enabled(touch_controls->isTouchEnabled()); - break; - case NONE: - default: - break; - } - reader->render(); + reader->render(); } //目录页的处理 void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw) @@ -259,8 +267,7 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red contents->set_needs_redraw(); contents->load(); } - static bool toc_bottom_mode = false; - static int toc_bottom_idx = 1; // 0:上一页,1:主页面,2:下一页 + if (needs_redraw) { toc_bottom_mode = false; @@ -338,6 +345,44 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red } } break; + case SELECT_BOX: + // 计算当前页面相关信息 + current_page = epub_index_state.selected_item / 6; // 每页6个目录项 + start_index = current_page * 6; // 当前页起始索引 + // 计算全局索引 = 页起始索引 + 页内偏移 + global_index = start_index + toc_index; + // 边界检查:确保点击的目录项存在 + if (global_index < contents->get_items_count() && contents->get_items_count() > 0) + { + // 更新选中的目录项 + epub_index_state.selected_item = global_index; + + // 根据toc_index确定点击的是哪个位置的目录项(0-5) + switch(toc_index) + { + case 0: + contents->switch_book(global_index); + break; + case 1: + contents->switch_book(global_index); + break; + case 2: + contents->switch_book(global_index); + break; + case 3: + contents->switch_book(global_index); + break; + case 4: + contents->switch_book(global_index); + break; + case 5: + contents->switch_book(global_index); + break; + default: + break; + } + } + break; case SELECT: if (toc_bottom_mode) { @@ -499,6 +544,33 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) } } break; + case SELECT_BOX: + current_page = epub_list_state.selected_item / 4; // 当前页面 + start_index = current_page * 4; // 当前页起始索引 + // 计算全局索引 = 页起始索引 + 页内偏移 + global_index = start_index + book_index; + // 边界检查 + if (global_index < epub_list_state.num_epubs) + { + + if(book_index == 0) + { + epub_list->switch_book(global_index); + } + else if(book_index == 1) + { + epub_list->switch_book(global_index); + } + else if(book_index == 2) + { + epub_list->switch_book(global_index); + } + else if(book_index == 3) + { + epub_list->switch_book(global_index); + } + } + break; case SELECT: if (library_bottom_mode) { @@ -1076,7 +1148,7 @@ extern "C" int main() { // dump out the epub list state - //rt_pm_request(PM_SLEEP_MODE_IDLE); + rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item); diff --git a/epdiy-epub/src/type.h b/epdiy-epub/src/type.h new file mode 100644 index 0000000..820485d --- /dev/null +++ b/epdiy-epub/src/type.h @@ -0,0 +1,38 @@ +#ifndef TYPES_H +#define TYPES_H + +// typedef enum { +// MAIN_PAGE, +// SELECTING_EPUB, +// SELECTING_TABLE_CONTENTS, +// READING_EPUB, +// SETTINGS_PAGE +// } UIState; + +// typedef enum { +// MAIN_MENU, +// WELCOME_PAGE, +// LOW_POWER_PAGE, +// CHARGING_PAGE +// } UIState2; + +// 设置页列表项 +typedef enum { + SET_TOUCH = 0, + SET_TIMEOUT = 1, + SET_FULL_REFRESH = 2, + SET_CONFIRM = 3 +} SettingsItem; + +typedef enum { + MAIN_PAGE, // 新主页面 + SELECTING_EPUB, // 电子书列表页面(书库) + SELECTING_TABLE_CONTENTS, // 电子书目录页面 + READING_EPUB, // 阅读页面 + SETTINGS_PAGE, // 通用功能设置页面 + WELCOME_PAGE, // 欢迎页面 + LOW_POWER_PAGE, // 低电量页面 + CHARGING_PAGE, // 充电页面 + SHUTDOWN_PAGE // 关机页面 +} AppUIState; +#endif \ No newline at end of file From eb475f80eff14bf10c472cf7683848128fdeff19 Mon Sep 17 00:00:00 2001 From: minjiezhong Date: Thu, 22 Jan 2026 10:48:45 +0800 Subject: [PATCH 21/25] =?UTF-8?q?1.=E8=A7=A3=E5=86=B3=E4=BA=86=E4=B9=A6?= =?UTF-8?q?=E5=BA=93=E9=A1=B5=E9=9D=A2=E3=80=81=E7=9B=AE=E5=BD=95=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E7=82=B9=E5=87=BB=E4=B8=8B=E4=B8=80=E9=A1=B5=EF=BC=8C?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E4=B9=A6=E7=B1=8D=E5=92=8C=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E5=A4=B1=E6=95=88=E7=9A=84bug=202.=E8=A7=A3=E5=86=B3=E4=BA=86?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E9=A1=B5=E9=9D=A2=E7=82=B9=E5=87=BB=E5=8F=B3?= =?UTF-8?q?=E4=B8=8B=E8=A7=92=E4=BC=9A=E5=87=BA=E7=8E=B0=E5=94=A4=E9=86=92?= =?UTF-8?q?=E9=98=85=E8=AF=BB=E8=AE=BE=E7=BD=AE=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../boards/controls/SF32_TouchControls.cpp | 37 +++--- .../src/boards/controls/SF32_TouchControls.h | 3 - epdiy-epub/src/main.cpp | 109 +++++++++++------- 3 files changed, 89 insertions(+), 60 deletions(-) diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index c8e73c8..673c99a 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -26,12 +26,15 @@ static bool waiting_for_confirmation = false; // 是否正在等待确认 extern int touch_sel; extern EpubReader *reader; +static const int SWIPE_THRESHOLD = 100; // 最小滑动距离阈值 +static bool is_touch_started = false; // 全局或类成员变量 rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) { SF32_TouchControls *instance = static_cast (dev->user_data); struct touch_message touch_data; rt_uint16_t x,y; + int i = 0;//用于记录第一次按下的情况 /*Read touch point data*/ rt_device_read(dev, 0, &touch_data, 1); @@ -50,48 +53,50 @@ rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) rt_kprintf("Touch down [%d,%d]\r\n", x, y); // 记录按下时的位置 - instance->touch_start_x = x; - instance->touch_start_y = y; + if (!is_touch_started) // 只允许第一次触发 + { + instance->touch_start_y = y; + rt_kprintf("Touch start\r\n"); + is_touch_started = true; + } instance->is_touch_down = true; - + instance->touch_current_y = 0; // 处理其他触控逻辑... } else { rt_kprintf("Touch up [%d,%d]\r\n", x, y); - instance->touch_current_x = x; instance->touch_current_y = y; // 检查是否构成向上滑动手势 - if (instance->is_touch_down) { - int y_diff = instance->touch_start_y - touch_data.y; // 注意坐标转换 - int x_diff = abs(instance->touch_start_x - touch_data.x); - rt_kprintf("Touch up diff Y: %d, X: %d\r\n", y_diff, x_diff); + if (instance->is_touch_down) + { + int y_diff = instance->touch_start_y - instance->touch_current_y; // 注意坐标转换 + rt_kprintf("Touch up diff Y: %d\r\n", y_diff); - // 检查时间间隔,防止连续触发 - rt_tick_t current_time = rt_tick_get(); if(reader->is_overlay_active() == false) { - if (y_diff > instance->SWIPE_THRESHOLD && y_diff > abs(x_diff)) + if (y_diff > SWIPE_THRESHOLD) { rt_kprintf("Up swipe detected! Diff: %d\n", y_diff); // 发送向上滑动动作 UIAction action = UPGLIDE; instance->last_action = action; - instance->on_action(action); - + instance->on_action(action); - // 重置状态 - instance->is_touch_down = false; - return RT_EOK; } } + + } + // 清空坐标值,避免下次误用 + instance->touch_start_y = 0; // 重置触摸状态 instance->is_touch_down = false; + is_touch_started = false; } // 只处理按下事件,忽略释放事件 diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.h b/epdiy-epub/src/boards/controls/SF32_TouchControls.h index 1983a55..0ad4b12 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.h +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.h @@ -16,12 +16,9 @@ class SF32_TouchControls : public TouchControls UIAction last_action = NONE; // 添加手势检测状态 bool is_touch_down = false; // 是否正在触摸 - int touch_start_x = 0; // 按下时的 X 坐标 int touch_start_y = 0; // 按下时的 Y 坐标 - int touch_current_x = 0; // 当前触摸 X 坐标 int touch_current_y = 0; // 当前触摸 Y 坐标 // 滑动检测阈值 - static const int SWIPE_THRESHOLD = 50; // 最小滑动距离阈值 public: static rt_err_t tp_rx_indicate(rt_device_t dev, rt_size_t size); diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index 9f00ed6..fe453bb 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -346,6 +346,11 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red } break; case SELECT_BOX: + // 如果在底部模式,先退出底部模式 + if (toc_bottom_mode) + { + toc_bottom_mode = false; + } // 计算当前页面相关信息 current_page = epub_index_state.selected_item / 6; // 每页6个目录项 start_index = current_page * 6; // 当前页起始索引 @@ -403,28 +408,37 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red handleEpubList(renderer, NONE, true); return; } - else if (toc_bottom_idx == 0) + else if (toc_bottom_idx == 0) // 上一页 { - // 上一页 if (current_page > 0) { - epub_index_state.selected_item -= per_page; - if (epub_index_state.selected_item < 0) epub_index_state.selected_item = 0; + // 计算新页面(上一页) + int new_page = current_page - 1; + // 将选中项设置为新页面的第一项 + epub_index_state.selected_item = new_page * per_page; + if (epub_index_state.selected_item < 0) + epub_index_state.selected_item = 0; + + // 退出底部选择模式,回到列表选择状态 + toc_bottom_mode = false; contents->set_needs_redraw(); } - // 保持底部模式,允许连续翻页 } - else if (toc_bottom_idx == 2) + else if (toc_bottom_idx == 2) // 下一页 { - // 下一页 if (current_page < max_page) { - epub_index_state.selected_item += per_page; + // 计算新页面(下一页) + int new_page = current_page + 1; + // 将选中项设置为新页面的第一项 + epub_index_state.selected_item = new_page * per_page; if (epub_index_state.selected_item >= count) - epub_index_state.selected_item = count - 1; + epub_index_state.selected_item = ((count - 1) / per_page) * per_page; // 确保在最后一页的第一项 + + // 退出底部选择模式,回到列表选择状态 + toc_bottom_mode = false; contents->set_needs_redraw(); } - // 保持底部模式,允许连续翻页 } } else @@ -545,6 +559,10 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) } break; case SELECT_BOX: + // 如果在底部模式,先退出底部模式 + if (library_bottom_mode) { + library_bottom_mode = false; + } current_page = epub_list_state.selected_item / 4; // 当前页面 start_index = current_page * 4; // 当前页起始索引 // 计算全局索引 = 页起始索引 + 页内偏移 @@ -572,44 +590,53 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) } break; case SELECT: - if (library_bottom_mode) - { + if (library_bottom_mode) + { int per_page = 4; int current_page = epub_list_state.selected_item / per_page; int max_page = (epub_list_state.num_epubs == 0) ? 0 : ( (epub_list_state.num_epubs - 1) / per_page ); if (library_bottom_idx == 1) { - // 主页面:返回主页面 - rt_kprintf("从书库页返回主页面\n"); - back_to_main_page(); - return; + // 主页面:返回主页面 + rt_kprintf("从书库页返回主页面\n"); + back_to_main_page(); + return; } - else if (library_bottom_idx == 0) + else if (library_bottom_idx == 0) // 上一页 { - // 上一页 - if (current_page > 0) - { - epub_list_state.selected_item -= per_page; - if (epub_list_state.selected_item < 0) epub_list_state.selected_item = 0; - epub_list->set_needs_redraw(); - } - + if (current_page > 0) + { + // 计算新页面(上一页) + int new_page = current_page - 1; + // 将选中项设置为新页面的第一本书 + epub_list_state.selected_item = new_page * per_page; + if (epub_list_state.selected_item < 0) + epub_list_state.selected_item = 0; + + // 退出底部选择模式,回到列表选择状态 + library_bottom_mode = false; + epub_list->set_needs_redraw(); + } } - else if (library_bottom_idx == 2) + else if (library_bottom_idx == 2) // 下一页 { - // 下一页 - if (current_page < max_page) - { - epub_list_state.selected_item += per_page; - if (epub_list_state.selected_item >= epub_list_state.num_epubs) - epub_list_state.selected_item = epub_list_state.num_epubs - 1; - epub_list->set_needs_redraw(); - } - + if (current_page < max_page) + { + // 计算新页面(下一页) + int new_page = current_page + 1; + // 将选中项设置为新页面的第一本书 + epub_list_state.selected_item = new_page * per_page; + if (epub_list_state.selected_item >= epub_list_state.num_epubs) + epub_list_state.selected_item = ((epub_list_state.num_epubs - 1) / per_page) * per_page; // 确保在最后一页的第一本书 + + // 退出底部选择模式,回到列表选择状态 + library_bottom_mode = false; + epub_list->set_needs_redraw(); + } } - } - else - { + } + else + { // 进入目录选择页面 ui_state = SELECTING_TABLE_CONTENTS; contents = new EpubToc(epub_list_state.epub_list[epub_list_state.selected_item], epub_index_state, renderer); @@ -617,8 +644,8 @@ void handleEpubList(Renderer *renderer, UIAction action, bool needs_redraw) contents->set_needs_redraw(); handleEpubTableContents(renderer, NONE, true); return; - } - break; + } + break; case NONE: default: // nothing to do @@ -1148,7 +1175,7 @@ extern "C" int main() { // dump out the epub list state - rt_pm_request(PM_SLEEP_MODE_IDLE); + //rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item); From 62eb9886a0c6349f0144300eeb18df689c62c2e1 Mon Sep 17 00:00:00 2001 From: smiling boy Date: Fri, 23 Jan 2026 19:05:40 +0800 Subject: [PATCH 22/25] =?UTF-8?q?=E6=96=B0=E5=BB=BA=E6=9D=BF=E5=AD=90base?= =?UTF-8?q?=E4=B8=8E1.2=E7=9A=84board=EF=BC=8C1.1=E4=B8=8E1.2=E5=A4=8D?= =?UTF-8?q?=E7=94=A8base?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/sf32-oed-epd_v12_hcpu/link.lds | 556 ++++++++++++++++++ .../project/sf32-oed-epd_v12_hcpu/link.sct | 157 +++++ epdiy-epub/sf32-oed-epd_base/Kconfig.board | 86 +++ epdiy-epub/sf32-oed-epd_base/SConscript | 14 + .../battery_table.c | 0 .../board.h | 0 .../bsp_board.h | 0 .../bsp_init.c | 0 .../bsp_lcd_tp.c | 0 .../bsp_pinmux.c | 0 .../bsp_power.c | 0 epdiy-epub/sf32-oed-epd_v11/Kconfig.board | 86 +-- epdiy-epub/sf32-oed-epd_v11/SConscript | 7 +- epdiy-epub/sf32-oed-epd_v12/Kconfig.board | 2 + epdiy-epub/sf32-oed-epd_v12/SConscript | 14 + epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig | 3 + .../sf32-oed-epd_v12/hcpu/Kconfig.board | 7 + epdiy-epub/sf32-oed-epd_v12/hcpu/board.conf | 55 ++ .../sf32-oed-epd_v12/hcpu/custom_mem_map.h | 21 + epdiy-epub/sf32-oed-epd_v12/hcpu/rtconfig.py | 9 + epdiy-epub/sf32-oed-epd_v12/lcpu/Kconfig | 3 + .../sf32-oed-epd_v12/lcpu/Kconfig.board | 7 + epdiy-epub/sf32-oed-epd_v12/lcpu/board.conf | 9 + .../sf32-oed-epd_v12/lcpu/custom_mem_map.h | 21 + epdiy-epub/sf32-oed-epd_v12/lcpu/rtconfig.py | 6 + epdiy-epub/sf32-oed-epd_v12/ptab.json | 192 ++++++ .../boards/controls/SF32_ButtonControls.cpp | 4 +- 27 files changed, 1168 insertions(+), 91 deletions(-) create mode 100644 epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.lds create mode 100644 epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.sct create mode 100644 epdiy-epub/sf32-oed-epd_base/Kconfig.board create mode 100644 epdiy-epub/sf32-oed-epd_base/SConscript rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/battery_table.c (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/board.h (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_board.h (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_init.c (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_lcd_tp.c (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_pinmux.c (100%) rename epdiy-epub/{sf32-oed-epd_v11 => sf32-oed-epd_base}/bsp_power.c (100%) create mode 100644 epdiy-epub/sf32-oed-epd_v12/Kconfig.board create mode 100644 epdiy-epub/sf32-oed-epd_v12/SConscript create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/board.conf create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/custom_mem_map.h create mode 100644 epdiy-epub/sf32-oed-epd_v12/hcpu/rtconfig.py create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/Kconfig create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/Kconfig.board create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/board.conf create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/custom_mem_map.h create mode 100644 epdiy-epub/sf32-oed-epd_v12/lcpu/rtconfig.py create mode 100644 epdiy-epub/sf32-oed-epd_v12/ptab.json diff --git a/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.lds b/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.lds new file mode 100644 index 0000000..005fec4 --- /dev/null +++ b/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.lds @@ -0,0 +1,556 @@ +/****************************************************************************** + * @file gcc_arm.ld + * @brief GNU Linker Script for Cortex-M based device + * @version V2.0.0 + * @date 21. May 2019 + ******************************************************************************/ +#include "rtconfig.h" +#include "mem_map.h" +/* + * Copyright (c) 2009-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + *-------- <<< Use Configuration Wizard in Context Menu >>> ------------------- + */ + +/*---------------------- Flash Configuration ---------------------------------- + Flash Configuration + Flash Base Address <0x0-0xFFFFFFFF:8> + Flash Size (in Bytes) <0x0-0xFFFFFFFF:8> + + -----------------------------------------------------------------------------*/ +__ROM_BASE = CODE_START_ADDR; +__ROM_SIZE = CODE_SIZE; + +/*--------------------- Embedded RAM Configuration ---------------------------- + RAM Configuration + RAM Base Address <0x0-0xFFFFFFFF:8> + RAM Size (in Bytes) <0x0-0xFFFFFFFF:8> + + -----------------------------------------------------------------------------*/ +__RAM_BASE = HPSYS_RAM0_BASE; +__RAM_SIZE = HCPU_RAM_DATA_SIZE; + +/*--------------------- Stack / Heap Configuration ---------------------------- + Stack / Heap Configuration + Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> + Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> + + -----------------------------------------------------------------------------*/ +__STACK_SIZE = 0x00002000; +__HEAP_SIZE = 0x00000C00; + +__ROM_EX_BASE = HCPU_RO_DATA_START_ADDR; +__ROM_EX_SIZE = HCPU_RO_DATA_SIZE; + +__PSRAM_BASE = PSRAM_DATA_START_ADDR; +__PSRAM_SIZE = PSRAM_DATA_SIZE; + +__ROM2_BASE = BUILTIN_RESOURCE_START_ADDR; +__ROM2_SIZE = BUILTIN_RESOURCE_SIZE; + + + +/* + *-------------------- <<< end of configuration section >>> ------------------- + */ +MEMORY +{ + ROM (rx) : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE + RAM (rw) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE + ROM_EX(rw):ORIGIN = __ROM_EX_BASE, LENGTH = __ROM_EX_SIZE + PSRAM(rw): ORIGIN = __PSRAM_BASE, LENGTH = __PSRAM_SIZE + ROM2 (rx): ORIGIN = __ROM2_BASE, LENGTH = __ROM2_SIZE +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ +#ifndef FLASH_TABLE_ONLY + .vectors : + { + _stext = ABSOLUTE(.); + KEEP(*(.vectors)); + /* workaround to avoid load address of .retm_data doesn't skip .vectors region */ + . = . + 4; + } > ROM + + .stack : + { + . = ALIGN(8); + __StackLimit = .; + . = . + __STACK_SIZE; + . = ALIGN(8); + __StackTop = .; + } > RAM + PROVIDE(__stack = __StackTop); + + .heap : + { + . = ALIGN(8); + __end__ = .; + PROVIDE(end = .); + . = . + __HEAP_SIZE; + . = ALIGN(8); + __HeapLimit = .; + } > RAM + + .retm_data : + { + . = ALIGN(4); + __rw_retm_data_start__ = .; + * (.*l1_ret_text_*) + * (.*l1_ret_rodata_*) + + *drv_spi_flash.o (.text* .rodata*) + *flash_table.o (.text* .rodata*) + *bf0_hal_mpi.o (.text* .rodata*) + *bf0_hal_mpi_ex.o (.text* .rodata*) + *bf0_hal_mpi_psram.o (.text* .rodata*) + *flash.o (.text* .rodata*) + *drv_psram.o (.text* .rodata*) + + *context_gcc.o (.text* .rodata*) + *drv_common.o (.text.HAL_GetTick) + *bf0_hal_rcc.o (.text* .rodata*) + + *bf0_pm.o (.text.sifli_light_handler) + *bf0_pm.o (.text.sifli_deep_handler) + *bf0_pm.o (.text.sifli_standby_handler) + *bf0_pm.o (.text.SystemInitFromStandby) + *.o (.text.SystemPowerOnModeGet) + + *bsp_init.o (.text* .rodata*) + *bsp_lcd_tp.o (.text* .rodata*) + *bsp_pinmux.o (.text* .rodata*) + *bsp_power.o (.text* .rodata*) + *bf0_hal_gpio.o (.text* .rodata*) + + *bf0_hal_hpaon.o (.text* .rodata*) + *bf0_hal.o (.text.HAL_Init) + *.o (.text.HAL_Delay_us) + *.o (.text.HAL_Delay_us_) + *.o (.text.HAL_Delay_us2_) + *.o (.text.HAL_MspInit) + *.o (.text.HAL_Delay) + *bf0_hal_pinmux.o (.text* .rodata*) + *bf0_pin_const.o (.text* .rodata*) + *drv_common.o (.text.rt_hw_us_delay) + *.o (.text.rt_memset) + *rt_memclr*.o (.text*) + *memset*.o (.text*) + + *.o (.retm_data_*) + + . = ALIGN(4); + __rw_retm_data_end__ = .; + + } > RAM AT > ROM +#endif /* !FLASH_TABLE_ONLY */ + + + .rom2 : + { + *epub_fonts.o (.text* .rodata*) + } > ROM2 + + + .text : + { +#ifdef FLASH_TABLE_ONLY + KEEP(*ftab.o(.text* .rodata*)) +#else + *(.text*) + *(.rodata*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + /* + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + */ + + /* .dtors */ + /* + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + */ + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + + . = ALIGN(4); + LcdDriverDescTab_start = .; + KEEP(*(LcdDriverDescTab)) + LcdDriverDescTab_end = .; + + . = ALIGN(4); + __rt_utest_tc_tab_start = .; + KEEP(*(UtestTcTab)) + __rt_utest_tc_tab_end = .; + + /* section information for initial. */ + . = ALIGN(4); + __rt_init_start = .; + KEEP(*(SORT(.rti_fn*))) + __rt_init_end = .; + + . = ALIGN(4); + BuiltinAppTab_start = .; + KEEP(*(BuiltinAppTab)) + BuiltinAppTab_end = .; + + . = ALIGN(4); + __app_font_start__ = .; + KEEP(*(.app_font)) + __app_font_end__ = .; + + . = ALIGN(4); + __SerialTranExport_start__ = .; + KEEP(*(SerialTranExport)) + __SerialTranExport_end__ = .; + + . = ALIGN(4); + __sifli_reg_start__ = .; + KEEP(*(SORT(.sifli_reg*))) + __sifli_reg_end__ = .; + + . = ALIGN(4); + __bt_sifli_reg_start__ = .; + KEEP(*(SORT(.bt_sifli_reg*))) + __bt_sifli_reg_end__ = .; + + /* section information for modules */ + . = ALIGN(4); + __rtmsymtab_start = .; + KEEP(*(RTMSymTab)) + __rtmsymtab_end = .; + + . = ALIGN(4); + __usbh_class_info_start__ = .; + KEEP(*(.usbh_class_info)) + __usbh_class_info_end__ = .; + + KEEP(*(.eh_frame*)) + _etext = ABSOLUTE(.); +#endif + } > ROM + +#ifdef ZBT +#include "zbt_rom.lds" +#endif + +#ifndef FLASH_TABLE_ONLY + .rom_ex : + { + + . = ALIGN(4); + __rw_rom_ex_start__ = .; + __ER_IROM1_EX$$RO_start__ = .; + __ER_IROM1_EX$$RO_load_start__ = LOADADDR(.rom_ex); + + *(.l1_non_ret_text_*) + *(.l1_non_ret_rodata_*) + + . = ALIGN(4); + __rw_rom_ex_end__ = .; + __ER_IROM1_EX$$RO_end__ = .; + __ER_IROM1_EX$$RO_load_end__ = LOADADDR(.rom_ex) + SIZEOF(.rom_ex); + + } > ROM_EX AT > ROM + + /* + * SG veneers: + * All SG veneers are placed in the special output section .gnu.sgstubs. Its start address + * must be set, either with the command line option `--section-start` or in a linker script, + * to indicate where to place these veneers in memory. + */ +/* + .gnu.sgstubs : + { + . = ALIGN(32); + } > ROM +*/ + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > ROM + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > ROM + __exidx_end = .; + + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (LOADADDR(.data)) + LONG (ADDR(.data)) + LONG (SIZEOF(.data)) + + LONG (LOADADDR(.retm_data)) + LONG (ADDR(.retm_data)) + LONG (SIZEOF(.retm_data)) + + LONG (LOADADDR(.rom_ex)) + LONG (ADDR(.rom_ex)) + LONG (SIZEOF(.rom_ex)) + + __copy_table_end__ = .; + } > ROM + + + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + /* Add each additional bss section here */ + + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + + LONG (ADDR(.retm_bss)) + LONG (SIZEOF(.retm_bss)) + + __zero_table_end__ = .; + } > ROM + + .retm_bss : + { + . = ALIGN(4); + __rw_retm_bss_start__ = .; + __RW_IRAM_RET$$ZI_start__ = .; + * (.bss.retm_bss_*) + + . = ALIGN(4); + __RW_IRAM_RET$$ZI_end__ = .; + } > RAM + + .RW_IRAM0 : + { + *(non_ret) + *(.*l1_non_ret_data_*) + *(.*l1_non_ret_bss_*) +#ifndef BSP_USING_PSRAM + *(.nand_cache) + *(.*l2_non_ret_data_*) + *(.*l2_non_ret_bss_*) + *(.*l2_cache_non_ret_data_*) + *(.*l2_cache_non_ret_bss_*) +#endif /* BSP_USING_PSRAM */ + } > RAM + + /** + * Location counter can end up 2byte aligned with narrow Thumb code but + * __etext is assumed by startup code to be the LMA of a section in RAM + * which must be 4byte aligned + */ + __etext = ALIGN (4); + + .data : + { + _sdata = ABSOLUTE(.); + __data_start__ = .; + __RW_IRAM1_start__ = .; + *(vtable) + *(.data) + *(.data.*) + *(.l1_ret_data_*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + _sinit = ABSOLUTE(.); + PROVIDE(__ctors_start__ = .); + PROVIDE_HIDDEN (__init_array_start = .); + /* old GCC version uses .ctors */ + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + /* new GCC version uses .init_array */ + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + _einit = ABSOLUTE(.); + PROVIDE_HIDDEN (__init_array_end = .); + PROVIDE(__ctors_end__ = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE(__dtors_start__ = .); + PROVIDE_HIDDEN (__fini_array_start = .); + + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + PROVIDE(__dtors_end__ = .); + +#ifdef ZBT +#include "zbt_data.lds" +#endif + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + __RW_IRAM1_end__ = .; + _edata = ABSOLUTE(.); + } > RAM AT > ROM + + /* + * Secondary data section, optional + * + * Remember to add each additional data section + * to the .copy.table above to asure proper + * initialization during startup. + */ + + __etext2 = ALIGN (4); + +#ifdef BSP_USING_PSRAM + .RW_PSRAM1 : + { + . = ALIGN(4); + __rw_psram1_start__ = .; + *(.*l2_ret_data_*) + *(.*l2_ret_bss_*) + *(.*l2_cache_ret_data_*) + *(.*l2_cache_ret_bss_*) + . = ALIGN(4); + __rw_psram1_end__ = .; + + } > PSRAM + + .RW_PSRAM_NON_RET : + { + /* aligned to cache line size */ + . = ALIGN(32); + __RW_PSRAM_NON_RET_start__ = .; + *(.nand_cache) + *(.*l2_non_ret_data_*) + *(.*l2_non_ret_bss_*) + *(.*l2_cache_non_ret_data_*) + *(.*l2_cache_non_ret_bss_*) + . = ALIGN(4); + __RW_PSRAM_NON_RET_end__ = .; + + } > PSRAM +#endif /* BSP_USING_PSRAM */ + + .bss : + { + _sbss = ABSOLUTE(.); + . = ALIGN(4); + __bss_start__ = .; + *(.bss) + *(.bss.*) + *(COMMON) + *(.l1_ret_bss_*) + . = ALIGN(4); + __bss_end__ = .; + __bss_end = .; + _ebss = ABSOLUTE(.); + __end__ = .; + PROVIDE(end = .); + } > RAM AT > RAM + + /* + * Secondary bss section, optional + * + * Remember to add each additional bss section + * to the .zero.table above to asure proper + * initialization during startup. + */ +/* + .bss2 : + { + . = ALIGN(4); + __bss2_start__ = .; + *(.bss2) + *(.bss2.*) + . = ALIGN(4); + __bss2_end__ = .; + } > RAM2 AT > RAM2 +*/ + + /* Check if data + heap + stack exceeds RAM limit */ + /* ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") */ + + + +#endif + +} + diff --git a/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.sct b/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.sct new file mode 100644 index 0000000..6f8b4bc --- /dev/null +++ b/epdiy-epub/project/sf32-oed-epd_v12_hcpu/link.sct @@ -0,0 +1,157 @@ +#! armclang -E --target=arm-arm-none-eabi -mcpu=cortex-m33 -xc -I $SDK_ROOT/drivers/cmsis/sf32lb52x +#include "rtconfig.h" +#include "mem_map.h" + + +; ************************************************************* +; *** Scatter-Loading Description File generated by uVision *** +; ************************************************************* + +LR_IROM1 CODE_START_ADDR CODE_SIZE { ; load region size_region + ER_IROM1 CODE_START_ADDR CODE_SIZE { ; load address = execution address + *.o (RESET, +First) + *(InRoot$$Sections) + .ANY (+RO) + *(FSymTab) + *.o (.rodata.*) + } + ER_IROM1_EX HCPU_RO_DATA_START_ADDR HCPU_RO_DATA_SIZE { ; load address = execution address + *.o (.l1_non_ret_text_*) + *.o (.l1_non_ret_rodata_*) + } + +#ifdef BSP_USING_PSRAM + RW_PSRAM1 PSRAM_DATA_START_ADDR { +#ifdef PKG_USING_FFMPEG + mpeg*.o (.bss.*) + h264*.o (.bss.*) +#endif + } + RW_PSRAM_RET +0 UNINIT{ ; ZI data, retained + *.o (.l2_ret_data_*) + *.o (.l2_ret_bss_*) + *.o (.l2_cache_ret_data_*) + *.o (.l2_cache_ret_bss_*) + } + RW_PSRAM_NON_RET +0 UNINIT{ ; ZI data, not retained and reused by SRAM retention + *.o (.l2_non_ret_data_*) + *.o (.l2_non_ret_bss_*) + *.o (.l2_cache_non_ret_data_*) + *.o (.l2_cache_non_ret_bss_*) + } + ScatterAssert((ImageLength(RW_PSRAM1)+ ImageLength(RW_PSRAM_RET) + ImageLength(RW_PSRAM_NON_RET)) Date: Mon, 26 Jan 2026 11:19:51 +0800 Subject: [PATCH 23/25] =?UTF-8?q?=E8=A7=A6=E6=8E=A7=E5=B1=8F=E9=A9=B1?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=9D=BF=E5=AD=90=E8=BF=9B=E8=A1=8C=E5=8C=BA?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/project/Kconfig.proj | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/epdiy-epub/project/Kconfig.proj b/epdiy-epub/project/Kconfig.proj index fc9ba05..6267af4 100644 --- a/epdiy-epub/project/Kconfig.proj +++ b/epdiy-epub/project/Kconfig.proj @@ -57,19 +57,22 @@ if !BSP_USING_BUILT_LCD config LCD_USING_EPD_R7D005 bool "6.0 rect electronic paper display(EPD R7D005_-1.30 1448x1072)" - select TSC_USING_GT967 if BSP_USING_TOUCHD + select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V11 + select TSC_USING_GT967 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V12 select LCD_USING_R7D005_130 select BSP_LCDC_USING_EPD_8BIT config LCD_USING_EPD_YZC085_V100 bool "6.0 rect electronic paper display(EPD YZC085_V1.05 1032x758)" - select TSC_USING_GT967 if BSP_USING_TOUCHD + select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V11 + select TSC_USING_GT967 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V12 select LCD_USING_YZC085_V100 select BSP_LCDC_USING_EPD_8BIT config LCD_USING_EPD_YZC146_V100 bool "6.0 rect electronic paper display(EPD YZC146_1.00 1032x758)" - select TSC_TSC_USING_GT967USING_FT5446U_V01 if BSP_USING_TOUCHD + select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V11 + select TSC_USING_GT967 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V12 select LCD_USING_YZC085_V100 select BSP_LCDC_USING_EPD_8BIT From 7f5287ca9e62c72977cf93fbd88f5c706c35c31d Mon Sep 17 00:00:00 2001 From: smiling boy Date: Tue, 27 Jan 2026 14:48:45 +0800 Subject: [PATCH 24/25] =?UTF-8?q?=E6=B7=BB=E5=8A=A01.2=E5=B1=8F=E5=B9=95?= =?UTF-8?q?=E6=A8=A1=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/project/Kconfig.proj | 35 ++++++++++++------- .../sf32-oed-epd_v11/hcpu/Kconfig.board | 2 +- .../sf32-oed-epd_v12/hcpu/Kconfig.board | 2 +- .../boards/display_dbi/epd_configs_yzc085.c | 6 ++-- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/epdiy-epub/project/Kconfig.proj b/epdiy-epub/project/Kconfig.proj index 6267af4..a227ea1 100644 --- a/epdiy-epub/project/Kconfig.proj +++ b/epdiy-epub/project/Kconfig.proj @@ -45,34 +45,42 @@ if !BSP_USING_BUILT_LCD config TSC_USING_FT6336U bool default n - config LCD_USING_EPD_CUSTOM - bool - default n + config TSC_USING_GT967 bool default n - choice - prompt "Custom LCD driver" - default LCD_USING_EPD_YZC085_V100 + + config LCD_USING_EPD_CUSTOM + bool + default n + + choice + prompt "Custom LCD driver" + default LCD_USING_EPD_YZC085_V100 if BSP_USING_BOARD_SF32_OED_EPD_V11 + default LCD_USING_EPD_YZC085_V100_V12 if BSP_USING_BOARD_SF32_OED_EPD_V12 + default LCD_USING_EPD_YZC085_V100 config LCD_USING_EPD_R7D005 bool "6.0 rect electronic paper display(EPD R7D005_-1.30 1448x1072)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V11 - select TSC_USING_GT967 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V12 + select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD select LCD_USING_R7D005_130 select BSP_LCDC_USING_EPD_8BIT + config LCD_USING_EPD_YZC085_V100_V12 + bool "6.0 rect electronic paper display(EPD YZC085_V1.05 1032x758)" + select TSC_USING_GT967 if BSP_USING_TOUCHD + select LCD_USING_YZC085_V100 + select BSP_LCDC_USING_EPD_8BIT + config LCD_USING_EPD_YZC085_V100 bool "6.0 rect electronic paper display(EPD YZC085_V1.05 1032x758)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V11 - select TSC_USING_GT967 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V12 + select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD select LCD_USING_YZC085_V100 select BSP_LCDC_USING_EPD_8BIT config LCD_USING_EPD_YZC146_V100 bool "6.0 rect electronic paper display(EPD YZC146_1.00 1032x758)" - select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V11 - select TSC_USING_GT967 if BSP_USING_TOUCHD && BSP_USING_BOARD_SF32_OED_EPD_V12 + select TSC_USING_FT5446U_V01 if BSP_USING_TOUCHD select LCD_USING_YZC085_V100 select BSP_LCDC_USING_EPD_8BIT @@ -99,6 +107,7 @@ if !BSP_USING_BUILT_LCD int default 1448 if LCD_USING_EPD_R7D005 default 1032 if LCD_USING_EPD_YZC085_V100 + default 1032 if LCD_USING_EPD_YZC085_V100_V12 default 1920 if LCD_USING_EPD_TE067XJHE01_V10 default 1032 if LCD_USING_EPD_YZC146_V100 default 1032 if LCD_USING_EPD_CUSTOM_MODULE @@ -107,6 +116,7 @@ if !BSP_USING_BUILT_LCD int default 1072 if LCD_USING_EPD_R7D005 default 758 if LCD_USING_EPD_YZC085_V100 + default 758 if LCD_USING_EPD_YZC085_V100_V12 default 960 if LCD_USING_EPD_TE067XJHE01_V10 default 758 if LCD_USING_EPD_YZC146_V100 default 758 if LCD_USING_EPD_CUSTOM_MODULE @@ -115,6 +125,7 @@ if !BSP_USING_BUILT_LCD int default 315 if LCD_USING_EPD_R7D005 default 300 if LCD_USING_EPD_YZC085_V100 + default 300 if LCD_USING_EPD_YZC085_V100_V12 default 320 if LCD_USING_EPD_TE067XJHE01_V10 default 300 if LCD_USING_EPD_YZC146_V100 default 300 if LCD_USING_EPD_CUSTOM_MODULE diff --git a/epdiy-epub/sf32-oed-epd_v11/hcpu/Kconfig.board b/epdiy-epub/sf32-oed-epd_v11/hcpu/Kconfig.board index dab564a..62e49bf 100644 --- a/epdiy-epub/sf32-oed-epd_v11/hcpu/Kconfig.board +++ b/epdiy-epub/sf32-oed-epd_v11/hcpu/Kconfig.board @@ -4,4 +4,4 @@ config BSP_USING_BOARD_SF32_OED_EPD_V11 select BF0_HCPU default y -rsource "../Kconfig.board" +rsource "../../sf32-oed-epd_base/Kconfig.board" diff --git a/epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board b/epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board index e681144..580a350 100644 --- a/epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board +++ b/epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board @@ -4,4 +4,4 @@ config BSP_USING_BOARD_SF32_OED_EPD_V12 select BF0_HCPU default y -rsource "../Kconfig.board" +rsource "../../sf32-oed-epd_base/Kconfig.board" diff --git a/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c b/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c index 4d6e60e..8eaaf33 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c +++ b/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c @@ -2,7 +2,7 @@ #include "epd_configs.h" #include "mem_section.h" #include "string.h" -#if defined(LCD_USING_EPD_YZC085_V100) || defined(LCD_USING_EPD_YZC146_V100) +#if defined(LCD_USING_EPD_YZC085_V100) || defined(LCD_USING_EPD_YZC146_V100) || defined(LCD_USING_EPD_YZC085_V100_V12) // 8bit lookup table for the current frame (high 4 bits: old data, low 4 bits: new data). @@ -111,7 +111,7 @@ void epd_wave_table_fill_lut(uint32_t *p_epic_lut, uint32_t frame_num) uint16_t epd_get_vcom_voltage(void) { -#if defined(LCD_USING_EPD_YZC085_V100) || defined(LCD_USING_EPD_YZC146_V100) +#if defined(LCD_USING_EPD_YZC085_V100) || defined(LCD_USING_EPD_YZC146_V100) || defined(LCD_USING_EPD_YZC085_V100_V12) return 1050; #else return 2100; @@ -139,4 +139,4 @@ const EPD_TimingConfig *epd_get_timing_config(void) return &timing_config; } -#endif /*LCD_USING_EPD_YZC085_V100 || LCD_USING_EPD_YZC146_V100*/ \ No newline at end of file +#endif /*LCD_USING_EPD_YZC085_V100 || LCD_USING_EPD_YZC146_V100 || LCD_USING_EPD_YZC085_V100_V12*/ \ No newline at end of file From cccec93e60eb16e3844929c6b9757aa8d7b50b22 Mon Sep 17 00:00:00 2001 From: minjiezhong Date: Wed, 4 Feb 2026 15:55:10 +0800 Subject: [PATCH 25/25] =?UTF-8?q?1=E3=80=81=E5=B0=86=E6=AF=8F=E4=B8=AA?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=BB=98=E5=88=B6=E5=9D=90=E6=A0=87=E8=B7=9F?= =?UTF-8?q?=E8=A7=A6=E6=8E=A7=E5=8C=BA=E5=9F=9F=E8=BF=9B=E8=A1=8C=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- epdiy-epub/lib/Epub/EpubList/EpubList.cpp | 30 +++++- epdiy-epub/lib/Epub/EpubList/EpubReader.cpp | 44 ++++++++- epdiy-epub/lib/Epub/EpubList/EpubToc.cpp | 32 +++++- epdiy-epub/src/SConscript | 2 +- .../boards/controls/SF32_TouchControls.cpp | 97 +++++++++++-------- epdiy-epub/src/epub_screen.cpp | 66 ++++++++++++- epdiy-epub/src/main.cpp | 4 +- 7 files changed, 223 insertions(+), 52 deletions(-) diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index 55f42d0..c8ed77b 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp @@ -1,6 +1,6 @@ #include "EpubList.h" #include - +#include "UIRegionsManager.h" #ifndef UNIT_TEST @@ -134,6 +134,7 @@ bool EpubList::load(const char *path) void EpubList::render() { + //clear_areas(); ulog_d(TAG, "Rendering EPUB list"); // what page are we on? int current_page = state.selected_item / EPUBS_PER_PAGE; @@ -157,6 +158,7 @@ void EpubList::render() } for (int i = start_index; i < start_index + EPUBS_PER_PAGE && i < state.num_epubs; i++) { + // do we need to draw a new page of items? if (current_page != state.previous_rendered_page) { @@ -191,6 +193,16 @@ void EpubList::render() title_block->render(renderer, i, text_xpos, text_ypos + y_offset); y_offset += renderer->get_line_height(); } + // 计算整体区域范围 + int area_start_x = image_xpos; + int area_start_y = image_ypos; + int area_end_x = std::max(image_xpos + image_width, text_xpos + text_width); + int area_end_y = std::max(image_ypos + image_height, text_ypos + title_height); + if((i%4)<4) + { + static_add_area(area_start_x, area_start_y, area_end_x - area_start_x, area_end_y - area_start_y, (i%4)); + } + delete title_block; delete epub; } @@ -268,6 +280,22 @@ void EpubList::render() }; draw_button(btn_x0, "上一页", m_bottom_mode && m_bottom_idx == 0); + int start_up_page_x = btn_x0; + int start_up_page_y = btn_y + btn_gap * 2; + int end_up_page_x = btn_w; + int end_up_page_y = btn_h; + int start_page_x = btn_x0; + static_add_area(start_up_page_x, start_up_page_y, end_up_page_x, end_up_page_y, 4); draw_button(btn_x1, "主页面", m_bottom_mode && m_bottom_idx == 1); + int start_main_page_x = btn_x1; + int start_main_page_y = btn_y + btn_gap *2; + int end_main_page_x = btn_w; + int end_main_page_y = btn_h; + static_add_area(start_main_page_x, start_main_page_y, end_main_page_x, end_main_page_y, 5); draw_button(btn_x2, "下一页", m_bottom_mode && m_bottom_idx == 2); + int start_down_page_x = btn_x2; + int start_down_page_y = btn_y + btn_gap *2; + int end_down_page_x = btn_w; + int end_down_page_y = btn_h; + static_add_area(start_down_page_x, start_down_page_y, end_down_page_x, end_down_page_y, 6); } \ No newline at end of file diff --git a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp index 201478f..34d09e2 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -13,6 +13,7 @@ #include "../Renderer/Renderer.h" #include "epub_mem.h" #include "epub_screen.h" +#include "UIRegionsManager.h" static const char *TAG = "EREADER"; extern "C" rt_uint32_t heap_free_size(void); @@ -141,18 +142,20 @@ void EpubReader::set_state_section(uint16_t current_section) { void EpubReader::render_overlay() { + clear_areas(); // 清除之前的区域记录 + int page_w = renderer->get_page_width(); int page_h = renderer->get_page_height(); int area_y = (page_h * 2) / 3; // 覆盖下方 1/3 屏幕 int area_h = page_h - area_y; - renderer->fill_rect(0, area_y, page_w, area_h, 240); + renderer->fill_rect(0, area_y, page_w, area_h, 240);//绘制灰色背景 // 三行布局:3,5,3 const int rows = 3; const int cols[rows] = {3, 5, 3}; const int gap_h = 20; // 行间距 - const int gap_w = 10; + const int gap_w = 10; // 列间距 const int row_h = 80; // 每行高度 // 纵向居中放置三行 int content_h = rows * row_h + (rows + 1) * gap_h; @@ -214,6 +217,19 @@ void EpubReader::render_overlay() int w2 = usable_w - w0 - w1; int widths[3] = { w0, w1, w2 }; int cur_x = gap_w; + //将坐标位置映射到触控中 + int first_one_x = cur_x;; + int first_one_y = y; + static_add_area(first_one_x, first_one_y, widths[0], row_h,0); + + int second_one_x = cur_x + widths[0] + gap_w; + int second_one_y = y; + static_add_area(second_one_x, second_one_y, widths[1], row_h,1); + + int third_one_x = cur_x + widths[0] + widths[1] + 2 * gap_w; + int third_one_y = y; + static_add_area(third_one_x, third_one_y, widths[2], row_h,2); + for (int i = 0; i < c; ++i) { int w = widths[i]; @@ -245,6 +261,30 @@ void EpubReader::render_overlay() { int usable_w = page_w - (c + 1) * gap_w; int btn_w = usable_w / c; + // 第二行触控区域映射(索引3-7) + if (r == 1) // 第二行 + { + for (int i = 0; i < c; ++i) // c = 5 + { + int x = gap_w + i * (btn_w + gap_w); + int y_coord = y0 + gap_h + r * (row_h + gap_h); + + // 添加触控区域(索引3-7对应按钮) + static_add_area(x, y_coord, btn_w, row_h, 3 + i); + } + } + // 第三行触控区域映射(索引8-10) + else if (r == 2) // 第三行 + { + for (int i = 0; i < c; ++i) // c = 3 + { + int x = gap_w + i * (btn_w + gap_w); + int y_coord = y0 + gap_h + r * (row_h + gap_h); + + // 添加触控区域(索引8-10对应按钮) + static_add_area(x, y_coord, btn_w, row_h, 8 + i); + } + } for (int i = 0; i < c; ++i) { int x = gap_w + i * (btn_w + gap_w); diff --git a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp index 88c45d2..1e23d1c 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp @@ -1,4 +1,5 @@ #include "EpubToc.h" +#include "UIRegionsManager.h" static const char *TAG = "PUBINDEX"; #define PADDING 14 @@ -66,6 +67,7 @@ bool EpubToc::load() // required as we're not rendering thumbnails void EpubToc::render() { + // 初始化固定区域(仅首次调用) ulog_d(TAG, "Rendering EPUB index"); // what page are we on? int current_page = state.selected_item / ITEMS_PER_PAGE; @@ -75,6 +77,7 @@ void EpubToc::render() int cell_height = (renderer->get_page_height() - bottom_area_height - bottom_margin) / ITEMS_PER_PAGE; int start_index = current_page * ITEMS_PER_PAGE; int ypos = 0; + // starting a fresh page or rendering from scratch? ulog_i(TAG, "Current page is %d, previous page %d, redraw=%d", current_page, state.previous_rendered_page, m_needs_redraw); if (current_page != state.previous_rendered_page || m_needs_redraw) @@ -108,6 +111,16 @@ void EpubToc::render() } // clean up the temporary index block delete title_block; + // 计算整体区域范围并写入 + int area_start_x = 0; + int area_start_y = ypos + PADDING / 2; + int area_end_x = renderer->get_page_width(); + int area_end_y = ypos + cell_height - PADDING / 2; + + if ((i % ITEMS_PER_PAGE) < ITEMS_PER_PAGE) + { + static_add_area(area_start_x, area_start_y, area_end_x - area_start_x, area_end_y - area_start_y, (i % ITEMS_PER_PAGE)); + } } // clear the selection box around the previous selected item if (state.previous_selected_item == i) @@ -155,7 +168,7 @@ void EpubToc::render() int btn_h = 80; int btn_y = area_y + (bottom_area_height - btn_h) / 2; int btn_x0 = btn_gap; // 上一页 - int btn_x1 = btn_gap * 2 + btn_w; // 主页面 + int btn_x1 = btn_gap * 2 + btn_w; // 书库 int btn_x2 = btn_gap * 3 + btn_w * 2; // 下一页 auto draw_button = [&](int x, const char* text, bool selected) @@ -181,8 +194,25 @@ void EpubToc::render() }; draw_button(btn_x0, "上一页", m_bottom_mode && m_bottom_idx == 0); + int start_up_page_x = btn_x0; + int start_up_page_y = btn_y + btn_gap * 2; + int end_up_page_x = btn_w; + int end_up_page_y = btn_h; + int start_page_x = btn_x0; + static_add_area(start_up_page_x, start_up_page_y, end_up_page_x, end_up_page_y, 6); + draw_button(btn_x1, "书库", m_bottom_mode && m_bottom_idx == 1); + int start_main_page_x = btn_x1; + int start_main_page_y = btn_y + btn_gap *2; + int end_main_page_x = btn_w; + int end_main_page_y = btn_h; + static_add_area(start_main_page_x, start_main_page_y, end_main_page_x, end_main_page_y, 7); draw_button(btn_x2, "下一页", m_bottom_mode && m_bottom_idx == 2); + int start_down_page_x = btn_x2; + int start_down_page_y = btn_y + btn_gap *2; + int end_down_page_x = btn_w; + int end_down_page_y = btn_h; + static_add_area(start_down_page_x, start_down_page_y, end_down_page_x, end_down_page_y, 8); } uint16_t EpubToc::get_selected_toc() diff --git a/epdiy-epub/src/SConscript b/epdiy-epub/src/SConscript index 6c590b3..d1f0436 100644 --- a/epdiy-epub/src/SConscript +++ b/epdiy-epub/src/SConscript @@ -4,7 +4,7 @@ from building import * import rtconfig cwd = GetCurrentDir() -src = ['main.cpp','epub_screen.cpp','epub_mem.c','epub_fonts.c'] +src = ['main.cpp','UIRegionsManager.cpp','epub_screen.cpp','epub_mem.c','epub_fonts.c'] src = src + Glob('./assets/*.c') CPPPATH = [cwd] diff --git a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index 673c99a..fb4609c 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -5,6 +5,7 @@ #include "type.h" #include "epub_screen.h" #include "EpubReader.h" +#include "UIRegionsManager.h" #ifdef BSP_USING_TOUCHD #include "drv_touch.h" #endif @@ -29,6 +30,7 @@ extern EpubReader *reader; static const int SWIPE_THRESHOLD = 100; // 最小滑动距离阈值 static bool is_touch_started = false; // 全局或类成员变量 +extern AreaRect g_area_array[]; rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) { SF32_TouchControls *instance = static_cast (dev->user_data); @@ -110,17 +112,17 @@ rt_err_t SF32_TouchControls::tp_rx_indicate(rt_device_t dev, rt_size_t size) switch (ui_state) { case MAIN_PAGE://主页面 - if (x >= 10 && x <= 80 && y >= 950 && y <= 1000) + if (x >= g_area_array[0].start_x && x <= g_area_array[0].end_x && y >= g_area_array[0].start_y && y <= g_area_array[0].end_y) { rt_kprintf("Touch left < \n"); action = UP; // 对应 KEY3 功能 } - else if (x >= 650 && x <= 750 && y >= 950 && y <= 1000) + else if (x >= g_area_array[1].start_x && x <= g_area_array[1].end_x && y >= g_area_array[1].start_y && y <= g_area_array[1].end_y) { action = DOWN; // 对应 KEY1 功能 rt_kprintf("Touch right > \n"); } - else if (x >= 250 && x <= 500 && y >= 950 && y <= 1000) + else if (x >= g_area_array[2].start_x && x <= g_area_array[2].end_x && y >= g_area_array[2].start_y && y <= g_area_array[2].end_y) { action = SELECT; // 对应 KEY2 功能 rt_kprintf("Touch middle SELECT \n"); @@ -128,19 +130,19 @@ switch (ui_state) break; case SELECTING_EPUB://书库页面 // 检查是否点击了功能控制按钮 - if(x >= 10 && x <= 250 && y >= 920 && y <= 1010) + if(x >= g_area_array[4].start_x && x <= g_area_array[4].end_x && y >= g_area_array[4].start_y && y <= g_area_array[4].end_y) { library_bottom_mode = true; library_bottom_idx = 0; action = SELECT; } - else if(x >= 280 && x <= 500 && y >= 920 && y <= 1010) + else if(x >= g_area_array[5].start_x && x <= g_area_array[5].end_x && y >= g_area_array[5].start_y && y <= g_area_array[5].end_y) { library_bottom_mode = true; library_bottom_idx = 1; action = SELECT; } - else if(x >= 520 && x <= 750 && y >= 920 && y <= 1010) + else if(x >= g_area_array[6].start_x && x <= g_area_array[6].end_x && y >= g_area_array[6].start_y && y <= g_area_array[6].end_y) { library_bottom_mode = true; library_bottom_idx = 2; @@ -151,19 +153,19 @@ switch (ui_state) // 处理书籍选择区域 int clicked_book_index = -1; - if(x >= 10 && x <= 740 && y >= 60 && y <= 240) + if(x >= g_area_array[0].start_x && x <= g_area_array[0].end_x && y >= g_area_array[0].start_y && y <= g_area_array[0].end_y) { clicked_book_index = 0; } - else if(x >= 10 && x <= 740 && y >= 270 && y <= 450) + else if(x >= g_area_array[1].start_x && x <= g_area_array[1].end_x && y >= g_area_array[1].start_y && y <= g_area_array[1].end_y) { clicked_book_index = 1; } - else if(x >= 10 && x <= 740 && y >= 470 && y <= 680) + else if(x >= g_area_array[2].start_x && x <= g_area_array[2].end_x && y >= g_area_array[2].start_y && y <= g_area_array[2].end_y) { clicked_book_index = 2; } - else if(x >= 10 && x <= 740 && y >= 700 && y <= 900) + else if(x >= g_area_array[3].start_x && x <= g_area_array[3].end_x && y >= g_area_array[3].start_y && y <= g_area_array[3].end_y) { clicked_book_index = 3; } @@ -212,57 +214,57 @@ switch (ui_state) touch_sel = 8; action = SELECT; } - + //阅读页面控制区域设置 - if(x >= 10 && x <= 250 && y >= 900 && y <= 960 && reader->is_overlay_active()) + if(x >= g_area_array[8].start_x && x <= g_area_array[8].end_x && y >= g_area_array[8].start_y && y <= g_area_array[8].end_y && reader->is_overlay_active())//第三层 { touch_sel = 8; action = SELECT; } - else if(x >= 280 && x <= 480 && y >= 900 && y <= 960 && reader->is_overlay_active()) + else if(x >= g_area_array[9].start_x && x <= g_area_array[9].end_x && y >= g_area_array[9].start_y && y <= g_area_array[9].end_y && reader->is_overlay_active()) { touch_sel = 9; action = SELECT; } - else if(x >= 520 && x <= 750 && y >= 900 && y <= 960 && reader->is_overlay_active()) + else if(x >= g_area_array[10].start_x && x <= g_area_array[10].end_x && y >= g_area_array[10].start_y && y <= g_area_array[10].end_y && reader->is_overlay_active()) { touch_sel = 10; action = SELECT; } - else if(x >= 10 && x <= 150 && y >= 690 && y <= 750 && reader->is_overlay_active()) + else if(x >= g_area_array[0].start_x && x <= g_area_array[0].end_x && y >= g_area_array[0].start_y && y <= g_area_array[0].end_y && reader->is_overlay_active())//第一层 { touch_sel= 0; rt_kprintf("Touch middle SELECT %d\n",touch_sel); action = SELECT; } - else if(x >= 170 && x <= 570 && y >= 690 && y <= 750 && reader->is_overlay_active()) + else if(x >= g_area_array[1].start_x && x <= g_area_array[1].end_x && y >= g_area_array[1].start_y && y <= g_area_array[1].end_y && reader->is_overlay_active()) { touch_sel= 1; rt_kprintf("Touch middle SELECT %d\n",touch_sel); action = SELECT; } - else if(x >= 610 && x <= 750 && y >= 690 && y <= 750 && reader->is_overlay_active()) + else if(x >= g_area_array[2].start_x && x <= g_area_array[2].end_x && y >= g_area_array[2].start_y && y <= g_area_array[2].end_y && reader->is_overlay_active()) { touch_sel= 2; rt_kprintf("Touch middle SELECT %d\n",touch_sel); action = SELECT; } - else if(x >= 10 && x <= 140 && y >= 790 && y <= 850 && reader->is_overlay_active()) + else if(x >= g_area_array[3].start_x && x <= g_area_array[3].end_x && y >= g_area_array[3].start_y && y <= g_area_array[3].end_y && reader->is_overlay_active()) { touch_sel = 3;//跳转-5页 action = SELECT; } - else if(x >= 165 && x <=300 && y >= 790 && y <= 850 && reader->is_overlay_active()) + else if(x >= g_area_array[4].start_x && x <= g_area_array[4].end_x && y >= g_area_array[4].start_y && y <= g_area_array[4].end_y && reader->is_overlay_active()) { touch_sel = 4;//跳转-1页 action = SELECT; } - else if(x >= 480 && x <= 570 && y >= 790 && y <= 850 && reader->is_overlay_active()) + else if(x >= g_area_array[6].start_x && x <= g_area_array[6].end_x && y >= g_area_array[6].start_y && y <= g_area_array[6].end_y && reader->is_overlay_active()) { touch_sel = 6;//跳转+1页 action = SELECT; } - else if(x >= 620 && x <= 750 && y >= 790 && y <= 850 && reader->is_overlay_active()) + else if(x >= g_area_array[7].start_x && x <= g_area_array[7].end_x && y >= g_area_array[7].start_y && y <= g_area_array[7].end_y && reader->is_overlay_active()) { touch_sel = 7;//跳转5页 action = SELECT; @@ -270,19 +272,31 @@ switch (ui_state) break; case SELECTING_TABLE_CONTENTS: //目录界面 - if(x >= 10 && x <= 250 && y >= 920 && y <= 1010) + rt_kprintf("g_area_array[0].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[0].start_x ,g_area_array[0].end_x ,g_area_array[0].start_y ,g_area_array[0].end_y); + rt_kprintf("g_area_array[1].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[1].start_x ,g_area_array[1].end_x ,g_area_array[1].start_y ,g_area_array[1].end_y); + rt_kprintf("g_area_array[2].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[2].start_x ,g_area_array[2].end_x ,g_area_array[2].start_y ,g_area_array[2].end_y); + rt_kprintf("g_area_array[3].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[3].start_x ,g_area_array[3].end_x ,g_area_array[3].start_y ,g_area_array[3].end_y); + rt_kprintf("g_area_array[4].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[4].start_x ,g_area_array[4].end_x ,g_area_array[4].start_y ,g_area_array[4].end_y); + rt_kprintf("g_area_array[5].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[5].start_x ,g_area_array[5].end_x ,g_area_array[5].start_y ,g_area_array[5].end_y); + rt_kprintf("g_area_array[6].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[6].start_x ,g_area_array[6].end_x ,g_area_array[6].start_y ,g_area_array[6].end_y); + rt_kprintf("g_area_array[7].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[7].start_x ,g_area_array[7].end_x ,g_area_array[7].start_y ,g_area_array[7].end_y); + rt_kprintf("g_area_array[8].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[8].start_x ,g_area_array[8].end_x ,g_area_array[8].start_y ,g_area_array[8].end_y); + rt_kprintf("g_area_array[9].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[9].start_x ,g_area_array[9].end_x ,g_area_array[9].start_y ,g_area_array[9].end_y); + rt_kprintf("g_area_array[10].start_x %d end_x %d start_y %d end_y %d\n",g_area_array[10].start_x ,g_area_array[10].end_x ,g_area_array[10].start_y ,g_area_array[10].end_y); + + if(x >= g_area_array[6].start_x && x <= g_area_array[6].end_x && y >= g_area_array[6].start_y && y <= g_area_array[6].end_y) { toc_bottom_mode = true; toc_bottom_idx = 0; action = SELECT; } - else if(x >= 280 && x <= 500 && y >= 920 && y <= 1010) + else if(x >= g_area_array[7].start_x && x <= g_area_array[7].end_x && y >= g_area_array[7].start_y && y <= g_area_array[7].end_y) { toc_bottom_mode = true; toc_bottom_idx = 1; action = SELECT; } - else if(x >= 520 && x <= 750 && y >= 920 && y <= 1010) + else if(x >= g_area_array[8].start_x && x <= g_area_array[8].end_x && y >= g_area_array[8].start_y && y <= g_area_array[8].end_y) { toc_bottom_mode = true; toc_bottom_idx = 2; @@ -292,27 +306,27 @@ switch (ui_state) { int clicked_toc_index = -1; - if(x >= 10 && x <= 750 && y >= 20 && y <= 170) + if(x >= g_area_array[0].start_x && x <= g_area_array[0].end_x && y >= g_area_array[0].start_y && y <= g_area_array[0].end_y) { clicked_toc_index = 0; } - else if(x >= 10 && x <= 750 && y >= 180 && y <= 310) + else if(x >= g_area_array[1].start_x && x <= g_area_array[1].end_x && y >= g_area_array[1].start_y && y <= g_area_array[1].end_y) { clicked_toc_index = 1; } - else if(x >= 10 && x <= 750 && y >= 330 && y <= 450) + else if(x >= g_area_array[2].start_x && x <= g_area_array[2].end_x && y >= g_area_array[2].start_y && y <= g_area_array[2].end_y) { clicked_toc_index = 2; } - else if(x >= 10 && x <= 750 && y >= 470 && y <= 590) + else if(x >= g_area_array[3].start_x && x <= g_area_array[3].end_x && y >= g_area_array[3].start_y && y <= g_area_array[3].end_y) { clicked_toc_index = 3; } - else if(x >= 10 && x <= 750 && y >= 620 && y <= 750) + else if(x >= g_area_array[4].start_x && x <= g_area_array[4].end_x && y >= g_area_array[4].start_y && y <= g_area_array[4].end_y) { clicked_toc_index = 4; } - else if(x >= 10 && x <= 750 && y >= 770 && y <= 890) + else if(x >= g_area_array[5].start_x && x <= g_area_array[5].end_x && y >= g_area_array[5].start_y && y <= g_area_array[5].end_y) { clicked_toc_index = 5; } @@ -346,54 +360,55 @@ switch (ui_state) break; case SETTINGS_PAGE: // 设置页面 // 设置页面每行左右箭头触控区域(与设置页布局一致) - if (x >= 100 && x <= 650 && y >= 160 && y <= 260) + if (x >= g_area_array[2].start_x && x <= g_area_array[2].end_x && y >= g_area_array[2].start_y && y <= g_area_array[2].end_y) { settings_selected_idx = SET_TOUCH; action = SELECT_BOX; rt_kprintf("select touch switch\n"); } - else if (x >= 100 && x <= 650 && y >= 300 && y <= 400) + else if (x >= g_area_array[5].start_x && x <= g_area_array[5].end_x && y >= g_area_array[5].start_y && y <= g_area_array[5].end_y) { settings_selected_idx = SET_TIMEOUT; action = SELECT_BOX; rt_kprintf("select timeout switch\n"); } - else if (x >= 100 && x <= 650 && y >= 450 && y <= 540) + else if (x >= g_area_array[8].start_x && x <= g_area_array[8].end_x && y >= g_area_array[8].start_y && y <= g_area_array[8].end_y) { settings_selected_idx = SET_FULL_REFRESH; action = SELECT_BOX; rt_kprintf("select full refresh switch \n"); } - else if (x >= 100 && x <= 650 && y >= 830 && y <= 950) + else if (x >= g_area_array[9].start_x && x <= g_area_array[9].end_x && y >= g_area_array[9].start_y && y <= g_area_array[9].end_y) { settings_selected_idx = SET_CONFIRM; action = SELECT; - rt_kprintf("select touch switch\n"); + rt_kprintf("select confirm button\n"); } + - if(settings_selected_idx == SET_TOUCH && 0<=x && x<= 50 && 160<=y && y<=260) + if(settings_selected_idx == SET_TOUCH && g_area_array[0].start_x<=x && x<= g_area_array[0].end_x && g_area_array[0].start_y<=y && y<=g_area_array[0].end_y) { action = SELECT; } - else if(settings_selected_idx == SET_TOUCH && 700<=x && x<=750 && 160<=y && y<=260) + else if(settings_selected_idx == SET_TOUCH && g_area_array[1].start_x<=x && x<= g_area_array[1].end_x && g_area_array[1].start_y<=y && y<=g_area_array[1].end_y) { action = SELECT; } - else if(settings_selected_idx == SET_TIMEOUT && 0 <= x && x<=50 && 300 <= y && y<= 400) + else if(settings_selected_idx == SET_TIMEOUT && g_area_array[3].start_x<=x && x<= g_area_array[3].end_x && g_area_array[3].start_y<=y && y<=g_area_array[3].end_y) { action = PREV_OPTION; rt_kprintf("select timeout Reduce\n"); } - else if(settings_selected_idx == SET_TIMEOUT && 700<=x && x<=750 && 300<=y && y<= 400) + else if(settings_selected_idx == SET_TIMEOUT && g_area_array[4].start_x<=x && x<= g_area_array[4].end_x && g_area_array[4].start_y<=y && y<=g_area_array[4].end_y) { action = NEXT_OPTION; rt_kprintf("select timeout increase\n"); } - else if(settings_selected_idx == SET_FULL_REFRESH && 0 <= x && x<= 50 && 450 <= y && y<= 540) + else if(settings_selected_idx == SET_FULL_REFRESH && g_area_array[6].start_x<=x && x<= g_area_array[6].end_x && g_area_array[6].start_y<=y && y<=g_area_array[6].end_y) { action = PREV_OPTION; } - else if(settings_selected_idx == SET_FULL_REFRESH && 700 <= x && x<= 750 && 450 <= y && y<= 540) + else if(settings_selected_idx == SET_FULL_REFRESH && g_area_array[7].start_x<=x && x<= g_area_array[7].end_x && g_area_array[7].start_y<=y && y<=g_area_array[7].end_y) { action = NEXT_OPTION; } diff --git a/epdiy-epub/src/epub_screen.cpp b/epdiy-epub/src/epub_screen.cpp index 523b704..115e80a 100644 --- a/epdiy-epub/src/epub_screen.cpp +++ b/epdiy-epub/src/epub_screen.cpp @@ -3,6 +3,7 @@ #include "epub_screen.h" #include #include "type.h" +#include "UIRegionsManager.h" extern TouchControls *touch_controls; extern "C" @@ -112,6 +113,7 @@ int screen_get_main_selected_option() // 绘制主页面 static void render_main_page(Renderer *renderer) { + clear_areas(); // 清除之前的区域记录 renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); const char *title = "S I F L I"; @@ -133,12 +135,22 @@ static void render_main_page(Renderer *renderer) const char *lt = "<"; int lt_w = renderer->get_text_width(lt); int lt_h = renderer->get_line_height(); + int left_arrow_x = margin_side;//矩形的X轴起始坐标 + int left_arrow_y = y + margin_bottom;//矩形的Y轴起始坐标 + // 记录左箭头区域 + add_area(left_arrow_x, left_arrow_y, rect_w, rect_h); + renderer->draw_text(left_x + (rect_w - lt_w) / 2, y + (rect_h - lt_h) / 2, lt, false, true); // 右 ">" const char *gt = ">"; int gt_w = renderer->get_text_width(gt); int gt_h = renderer->get_line_height(); + int right_arrow_x = right_x ;//矩形的X轴起始坐标 + int right_arrow_y = y + margin_bottom;//矩形的Y轴起始坐标 + // 记录右箭头区域 + add_area(right_arrow_x, right_arrow_y, rect_w, rect_h); + renderer->draw_text(right_x + (rect_w - gt_w) / 2, y + (rect_h - gt_h) / 2, gt, false, true); // 中间选项文本 @@ -158,6 +170,11 @@ static void render_main_page(Renderer *renderer) } int opt_w = renderer->get_text_width(opt_text); int opt_h = renderer->get_line_height(); + int option_x = mid_x + (mid_w - opt_w) / 2 ; + int option_y = y + margin_bottom; + + // 记录选项区域 + add_area(option_x, option_y, opt_w, opt_h); renderer->draw_text(mid_x + (mid_w - opt_w) / 2, y + (rect_h - opt_h) / 2, opt_text, false, true); } //主界面处理 @@ -205,6 +222,7 @@ void handleMainPage(Renderer *renderer, UIAction action, bool needs_redraw) // 设置页面 void render_settings_page(Renderer *renderer) { + clear_areas(); // 清除之前的区域记录 renderer->fill_rect(0, 0, renderer->get_page_width(), renderer->get_page_height(), 255); // 标题 @@ -227,9 +245,17 @@ void render_settings_page(Renderer *renderer) int item_x = margin_lr + arrow_col_w; if (settings_selected_idx == SET_TOUCH) { - const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + const char *lt = "<"; + int lt_w = renderer->get_text_width(lt); + int touch_left_x = margin_lr; + int touch_left_y = y; + static_add_area(touch_left_x, touch_left_y, arrow_col_w, item_h,0); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); + const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + int touch_right_x = page_w - arrow_col_w + margin_lr; + int touch_right_y = y; + static_add_area(touch_right_x, touch_right_y, arrow_col_w, item_h,1); renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); } if (settings_selected_idx == SET_TOUCH) @@ -250,6 +276,9 @@ void render_settings_page(Renderer *renderer) int tx = item_x + (item_w - t1_w) / 2; if (tx < item_x + 4) tx = item_x + 4; if (tx + t1_w > item_x + item_w - 4) tx = item_x + item_w - t1_w - 4; + int touch_switch_x = item_x; + int touch_switch_y = y ; + static_add_area(touch_switch_x, touch_switch_y, item_w, item_h,2); renderer->draw_text(tx, y + (item_h - lh) / 2, buf1, false, true); } y += item_h + gap; @@ -257,9 +286,18 @@ void render_settings_page(Renderer *renderer) // 2) 超时关机 if (settings_selected_idx == SET_TIMEOUT) { - const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + const char *lt = "<"; + int lt_w = renderer->get_text_width(lt); + int timeout_left_x = margin_lr; + int timeout_left_y = y; + static_add_area(timeout_left_x, timeout_left_y, arrow_col_w, item_h,3); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); - const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + + const char *gt = ">"; + int gt_w = renderer->get_text_width(gt); + int timeout_right_x = page_w - arrow_col_w + margin_lr; + int timeout_right_y = y; + static_add_area(timeout_right_x, timeout_right_y, arrow_col_w, item_h,4); renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); } if (settings_selected_idx == SET_TIMEOUT) @@ -288,6 +326,9 @@ void render_settings_page(Renderer *renderer) int tx = item_x + (item_w - t2_w) / 2; if (tx < item_x + 4) tx = item_x + 4; if (tx + t2_w > item_x + item_w - 4) tx = item_x + item_w - t2_w - 4; + int timeout_setting_x = item_x; + int timeout_setting_y = y; + static_add_area(timeout_setting_x, timeout_setting_y, item_w, item_h,5); renderer->draw_text(tx, y + (item_h - lh) / 2, buf2, false, true); } y += item_h + gap; @@ -295,9 +336,18 @@ void render_settings_page(Renderer *renderer) // 3) 全刷周期 if (settings_selected_idx == SET_FULL_REFRESH) { - const char *lt = "<"; int lt_w = renderer->get_text_width(lt); + const char *lt = "<"; + int lt_w = renderer->get_text_width(lt); + int full_refresh_left_x = margin_lr; + int full_refresh_left_y = y; + static_add_area(full_refresh_left_x, full_refresh_left_y, arrow_col_w, item_h,6); renderer->draw_text(margin_lr + (arrow_col_w - lt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, lt, false, true); - const char *gt = ">"; int gt_w = renderer->get_text_width(gt); + + const char *gt = ">"; + int gt_w = renderer->get_text_width(gt); + int full_refresh_right_x = page_w - arrow_col_w + margin_lr; + int full_refresh_right_y = y; + static_add_area(full_refresh_right_x, full_refresh_right_y, arrow_col_w, item_h,7); renderer->draw_text(page_w - margin_lr - arrow_col_w + (arrow_col_w - gt_w) / 2, y + (item_h - renderer->get_line_height()) / 2, gt, false, true); } if (settings_selected_idx == SET_FULL_REFRESH) @@ -319,6 +369,9 @@ void render_settings_page(Renderer *renderer) int tx = item_x + (item_w - t3_w) / 2; if (tx < item_x + 4) tx = item_x + 4; if (tx + t3_w > item_x + item_w - 4) tx = item_x + item_w - t3_w - 4; + int full_refresh_setting_x = item_x; + int full_refresh_setting_y = y; + static_add_area(full_refresh_setting_x, full_refresh_setting_y, item_w, item_h,8); renderer->draw_text(tx, y + (item_h - lh) / 2, buf3, false, true); } y += item_h + gap; @@ -339,6 +392,9 @@ void render_settings_page(Renderer *renderer) const char *confirm = "确认"; int c_w = renderer->get_text_width(confirm); int c_h = renderer->get_line_height(); + int confirm_button_x = confirm_x; + int confirm_button_y = confirm_y; + static_add_area(confirm_button_x, confirm_button_y, confirm_w, confirm_h,9); renderer->draw_text(confirm_x + (confirm_w - c_w) / 2, confirm_y + (confirm_h - c_h) / 2, confirm, false, true); } diff --git a/epdiy-epub/src/main.cpp b/epdiy-epub/src/main.cpp index fe453bb..2d3de64 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -13,6 +13,7 @@ #include "bf0_pm.h" #include "epd_driver.h" #include "type.h" +#include "UIRegionsManager.h" #undef LOG_TAG #undef DBG_LEVEL #define DBG_LEVEL DBG_LOG //DBG_INFO // @@ -83,6 +84,7 @@ typedef enum { } MainOption; void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw); +//阅读设置页面 void handleEpub(Renderer *renderer, UIAction action) { if (!reader) @@ -1175,7 +1177,7 @@ extern "C" int main() { // dump out the epub list state - //rt_pm_request(PM_SLEEP_MODE_IDLE); + rt_pm_request(PM_SLEEP_MODE_IDLE); ulog_i("main", "epub list state num_epubs=%d", epub_list_state.num_epubs); ulog_i("main", "epub list state is_loaded=%d", epub_list_state.is_loaded); ulog_i("main", "epub list state selected_item=%d", epub_list_state.selected_item);