diff --git a/epdiy-epub/lib/Epub/EpubList/EpubList.cpp b/epdiy-epub/lib/Epub/EpubList/EpubList.cpp index efd6603..025b402 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 @@ -15,48 +15,36 @@ static const char *TAG = "PUBLIST"; #define PADDING 20 -#define EPUBS_PER_PAGE 5 -#define BOTTOM_AREA_HEIGHT 50 -#define BOTTOM_AREA_ITEM_INDEX -1 +#define EPUBS_PER_PAGE 4 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--; +} + +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) @@ -146,11 +134,14 @@ 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; - // 计算单元格高度,减去底部区域的高度 - int cell_height = (renderer->get_page_height() - BOTTOM_AREA_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; @@ -167,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) { @@ -201,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; } @@ -212,92 +214,92 @@ 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) + { - 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, 0); + } + } + } + else + { + 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, 255); + } } } ypos += cell_height; } 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 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; // 下一页 - 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) + // 高亮边框:当处于底部模式时,高亮当前选择 + auto draw_button = [&](int x, const char* text, bool selected) { - 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 (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); + }; - 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; - } + 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); - 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/lib/Epub/EpubList/EpubList.h b/epdiy-epub/lib/Epub/EpubList/EpubList.h index c70a727..f73eec5 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubList.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubList.h @@ -31,13 +31,21 @@ 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; } 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 5be05ac..0263f5b 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.cpp @@ -12,6 +12,10 @@ #include "../RubbishHtmlParser/RubbishHtmlParser.h" #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); @@ -57,6 +61,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(); @@ -99,13 +106,310 @@ 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()); 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) + { + 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() +{ + + 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);//绘制灰色背景 + + + // 三行布局: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; + 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; + // 第六格显示: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; + 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 y = y0 + gap_h + r * (row_h + gap_h); + // 顶部第1行(3列)采用不等宽布局:1/3半宽,2双宽 + if (r == 0) + { + 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; + + //将坐标位置映射到触控中 + 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]; + 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; + + // 第二行触控区域映射(索引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); + 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); + } + 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++; + } + } + } +} + +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; +} + +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 + { + 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(); + } + } + } +} + +void EpubReader::overlay_cycle_full_refresh() +{ + screen_cycle_full_refresh_period(true); +} + +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 5d46081..d65ef72 100644 --- a/epdiy-epub/lib/Epub/EpubList/EpubReader.h +++ b/epdiy-epub/lib/Epub/EpubList/EpubReader.h @@ -13,8 +13,22 @@ class EpubReader Epub *epub = nullptr; Renderer *renderer = nullptr; RubbishHtmlParser *parser = nullptr; + // 阅读页半屏覆盖操作层状态 + 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; + // 触控开关当前状态(由上层同步) + 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(); public: EpubReader(EpubListItem &state, Renderer *renderer) : state(state), renderer(renderer){}; @@ -22,6 +36,29 @@ 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; 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_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; } + 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/lib/Epub/EpubList/EpubToc.cpp b/epdiy-epub/lib/Epub/EpubList/EpubToc.cpp index 46ca552..64d530f 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 @@ -31,6 +32,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() { @@ -57,13 +67,17 @@ 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; - // 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? 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) @@ -97,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) @@ -106,18 +130,95 @@ 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; } 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); + + 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/lib/Epub/EpubList/EpubToc.h b/epdiy-epub/lib/Epub/EpubList/EpubToc.h index 5ef96a8..4fc09d9 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){}; @@ -40,6 +43,11 @@ 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(); + // 目录项总数 + 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/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 a227ea1..4827026 100644 --- a/epdiy-epub/project/Kconfig.proj +++ b/epdiy-epub/project/Kconfig.proj @@ -54,15 +54,17 @@ if !BSP_USING_BUILT_LCD 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 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 @@ -74,13 +76,13 @@ if !BSP_USING_BUILT_LCD 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/sf32-oed-epd_base/battery_table.c b/epdiy-epub/sf32-oed-epd_base/battery_table.c index 962b4fb..d9ad30b 100644 --- a/epdiy-epub/sf32-oed-epd_base/battery_table.c +++ b/epdiy-epub/sf32-oed-epd_base/battery_table.c @@ -4,6 +4,7 @@ // Discharging curve table const battery_lookup_point_t discharge_curve_table[] = { + { 100, 41950}, { 99, 41926}, { 98, 41860}, @@ -428,3 +429,4 @@ const battery_lookup_point_t charging_curve_table[] = const uint32_t discharge_curve_table_size = sizeof(discharge_curve_table) / sizeof(discharge_curve_table[0]); const uint32_t charging_curve_table_size = sizeof(charging_curve_table) / sizeof(charging_curve_table[0]); + diff --git a/epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board b/epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board index 580a350..ab18566 100644 --- a/epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board +++ b/epdiy-epub/sf32-oed-epd_v12/hcpu/Kconfig.board @@ -4,4 +4,6 @@ config BSP_USING_BOARD_SF32_OED_EPD_V12 select BF0_HCPU default y + rsource "../../sf32-oed-epd_base/Kconfig.board" + diff --git a/epdiy-epub/src/SConscript b/epdiy-epub/src/SConscript index dd9b659..d23b4c4 100644 --- a/epdiy-epub/src/SConscript +++ b/epdiy-epub/src/SConscript @@ -4,7 +4,9 @@ from building import * import rtconfig cwd = GetCurrentDir() -src = ['main.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/Actions.h b/epdiy-epub/src/boards/controls/Actions.h index 785384d..5e22d6b 100644 --- a/epdiy-epub/src/boards/controls/Actions.h +++ b/epdiy-epub/src/boards/controls/Actions.h @@ -8,6 +8,10 @@ typedef enum UP, 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_ButtonControls.cpp b/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp index 91cb956..cac26e8 100644 --- a/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_ButtonControls.cpp @@ -6,12 +6,17 @@ static ActionCallback_t action_cbk ; void button_event_handler(int32_t pin, button_action_t action) { -#if defined (BSP_USING_BOARD_SF32_OED_EPD_V11) || defined(BSP_USING_BOARD_SF32_OED_EPD_V12_SPI) || defined(BSP_USING_BOARD_SF32_OED_EPD_V12) +#if defined (BSP_USING_BOARD_SF32_OED_EPD_V11) || defined(BSP_USING_BOARD_SF32_OED_EPD_V12_SPI) || defined (BSP_USING_BOARD_SF32_OED_EPD_V12) { if (action == BUTTON_CLICKED) { 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/boards/controls/SF32_TouchControls.cpp b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp index a2f85c9..19c1557 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.cpp @@ -1,16 +1,46 @@ - #include "SF32_TouchControls.h" #include +#include "Actions.h" #include "epd_driver.h" +#include "type.h" +#include "epub_screen.h" +#include "EpubReader.h" + +#include "UIRegionsManager.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; + +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); 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); @@ -20,33 +50,418 @@ 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); + + // 记录按下时的位置 + 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); - + { + rt_kprintf("Touch up [%d,%d]\r\n", x, y); + instance->touch_current_y = y; + + // 检查是否构成向上滑动手势 + 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); + + if(reader->is_overlay_active() == false) + { + 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->touch_start_y = 0; + // 重置触摸状态 + instance->is_touch_down = false; + is_touch_started = false; + } + // 只处理按下事件,忽略释放事件 + if (TOUCH_EVENT_UP == touch_data.event) { + return RT_EOK; + } 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) - { - action = SELECT; - } - else - { + // 主页面底部按键区域:左"<"、右">"、中间文本框 +switch (ui_state) +{ + case MAIN_PAGE://主页面 + + 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 >= 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 >= 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"); + } + break; + case SELECTING_EPUB://书库页面 + // 检查是否点击了功能控制按钮 + + 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 >= 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 >= 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; + action = SELECT; + } + else + { + // 处理书籍选择区域 + int clicked_book_index = -1; + + + 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 >= 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 >= 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 >= 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; + } + + // 如果点击了书籍区域 + 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; + } + else if(x >= 550 && x <= 750 && y >=10 && y <= 1010 && reader->is_overlay_active() == false) + { + action = DOWN; + } + //点击正文,推出阅读设置 + if(x >= 10 && x <= 750 && y >=10 && y <= 630 && reader->is_overlay_active()) + { + touch_sel = 8; + action = SELECT; + } + + + //阅读页面控制区域设置 + 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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 >= 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; + } + + break; + case SELECTING_TABLE_CONTENTS: //目录界面 + + 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 >= 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 >= 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; + action = SELECT; + } + else// 目录项选择区域 + { + int clicked_toc_index = -1; + + + 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 >= 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 >= 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 >= 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 >= 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 >= 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; + } + // 如果点击了目录项区域 + 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 >= 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 >= 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 >= 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 >= 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 confirm button\n"); + } + + + 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 && 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 && 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 && 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 && 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 && 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; + } + break; + +} + + - } instance->last_action = action; if (action != NONE) { @@ -76,21 +491,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); } @@ -104,7 +504,6 @@ void SF32_TouchControls::powerOffTouch() rt_kprintf("no touch device found\n"); } } - void SF32_TouchControls::powerOnTouch() { if (tp_device) { @@ -116,47 +515,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; - } 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..0ad4b12 100644 --- a/epdiy-epub/src/boards/controls/SF32_TouchControls.h +++ b/epdiy-epub/src/boards/controls/SF32_TouchControls.h @@ -14,7 +14,11 @@ 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_y = 0; // 按下时的 Y 坐标 + int touch_current_y = 0; // 当前触摸 Y 坐标 + // 滑动检测阈值 public: static rt_err_t tp_rx_indicate(rt_device_t dev, rt_size_t size); @@ -23,4 +27,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/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/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 8eaaf33..762abc9 100644 --- a/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c +++ b/epdiy-epub/src/boards/display_dbi/epd_configs_yzc085.c @@ -2,9 +2,11 @@ #include "epd_configs.h" #include "mem_section.h" #include "string.h" + #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). // The output is 2-bit data. 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 new file mode 100644 index 0000000..b05dbc6 --- /dev/null +++ b/epdiy-epub/src/epub_screen.cpp @@ -0,0 +1,559 @@ + +#include "EpubList/EpubList.h" +#include "epub_screen.h" +#include +#include "type.h" + +#include "UIRegionsManager.h" + + +extern TouchControls *touch_controls; +extern "C" +{ + extern void set_part_disp_times(int val); +} + +// 最近一次真实打开并阅读的书本索引(由 main.cpp 维护) +extern int g_last_read_index; + +// 主页面选项 +typedef enum +{ + OPTION_OPEN_LIBRARY = 0, // 打开书库 + OPTION_CONTINUE_READING, // 继续阅读 + OPTION_ENTER_SETTINGS // 进入设置 +} MainOption; + +static MainOption main_option = OPTION_OPEN_LIBRARY; // 默认“打开书库” +// 全刷周期选项: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(bool refresh) +{ + if(refresh) + { + full_refresh_idx = (full_refresh_idx + 1) % kFullRefreshOptionsCount; // ?% 4 + + } + else + { + 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; +} + + +int settings_selected_idx = 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_minutes = 30; // 默认30分钟 +static int timeout_idx = -1; // + +static int find_timeout_idx(int minutes) +{ + for (int i = 0; i < kTimeoutOptionsCount; ++i) + { + if (kTimeoutOptions[i] == minutes) return i; + } + return 2; // 默认索引:30分钟 +} + +static void adjust_timeout(bool increase) +{ + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_minutes); + if (increase) + { + timeout_idx = (timeout_idx + 1) % kTimeoutOptionsCount; + } + else + { + timeout_idx = (timeout_idx - 1) % kTimeoutOptionsCount; + } + timeout_shutdown_minutes = kTimeoutOptions[timeout_idx]; +} + +void screen_init(int default_timeout_minutes) +{ + timeout_shutdown_minutes = default_timeout_minutes; + timeout_idx = find_timeout_idx(timeout_shutdown_minutes); +} + +int screen_get_timeout_shutdown_minutes() +{ + if (timeout_idx < 0) timeout_idx = find_timeout_idx(timeout_shutdown_minutes); + return timeout_shutdown_minutes; +} + +int screen_get_main_selected_option() +{ + return (int)main_option; // 0: 打开书库, 1: 继续阅读, 2: 进入设置 +} + +// 绘制主页面 +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"; + 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(); + + 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); + + // 中间选项文本 + int mid_x = left_x + rect_w + margin_side; + 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 = has_continue_reading ? "继续阅读" : "无阅读记录"; + break; + case OPTION_ENTER_SETTINGS: opt_text = "进入设置"; break; + } + 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); +} +//主界面处理 +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; + } +} + +// 设置页面 +void render_settings_page(Renderer *renderer) +{ + + clear_areas(); // 清除之前的区域记录 + + 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; + if (settings_selected_idx == SET_TOUCH) + { + + 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) + { + // 选中强化:多重描边,提高可见度 + 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 + { + 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; + + 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; + + // 2) 超时关机 + if (settings_selected_idx == SET_TIMEOUT) + { + + 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); + 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) + { + 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 + { + renderer->draw_rect(item_x, y, item_w, item_h, 0); + } + char buf2[64]; + 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_minutes / 60); + } + { + 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; + + 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); +ain + renderer->draw_text(tx, y + (item_h - lh) / 2, buf2, false, true); + } + y += item_h + gap; + + // 3) 全刷周期 + if (settings_selected_idx == SET_FULL_REFRESH) + { + + 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); + 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) + { + 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 + { + renderer->draw_rect(item_x, y, item_w, item_h, 0); + } + char buf3[64]; + 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; + 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; + + // 底部 确认 按钮 + 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 < 5; ++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(); + + 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); +} + +// 设置页面交互处理 +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_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) + { + 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_FULL_REFRESH) + { + // SELECT 在全刷周期项上为加操作(循环) + screen_cycle_full_refresh_period(true); + set_part_disp_times(screen_get_full_refresh_period()); + 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..148141b --- /dev/null +++ b/epdiy-epub/src/epub_screen.h @@ -0,0 +1,27 @@ +#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_minutes(); + +// 获取当前主页面选中的选项(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); +// 切换全刷周期(循环) +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 171f083..73d59da 100644 --- a/epdiy-epub/src/main.cpp +++ b/epdiy-epub/src/main.cpp @@ -5,17 +5,22 @@ #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" + +#include "UIRegionsManager.h" #undef LOG_TAG #undef DBG_LEVEL #define DBG_LEVEL DBG_LOG //DBG_INFO // #define LOG_TAG "EPUB.main" - +#define TIMEOUT_SHUTDOWN_TIME 5 // 默认关机超时(小时);0 表示不关机 #include @@ -24,89 +29,242 @@ 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[]; extern const uint8_t shutdown_map[]; } - const char *TAG = "main"; -typedef enum -{ - SELECTING_EPUB, - SELECTING_TABLE_CONTENTS, - READING_EPUB, -} UIState; -typedef enum -{ - MAIN_MENU, - WELCOME_PAGE, - LOW_POWER_PAGE, - CHARGING_PAGE -} UIState2; - -// default to showing the list of epubs to the user -UIState ui_state = SELECTING_EPUB; -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(); static EpubList *epub_list = nullptr; -static EpubReader *reader = nullptr; +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; +// 书库页底部按钮选择状态 +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; +// 主页面选项 +typedef enum { + OPTION_OPEN_LIBRARY = 0, // 打开书库 -> 打印 1 + 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) - { - reader = new EpubReader(epub_list_state.epub_list[epub_list_state.selected_item], renderer); - reader->load(); - } - switch (action) - { - case UP: - reader->prev(); - break; - case DOWN: - 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) { - epub_list = new EpubList(renderer, epub_list_state); + 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; } - handleEpubList(renderer, NONE, true); + + switch (action) + { + case UP: + if (reader->is_overlay_active()) + { + reader->overlay_move_left(); + } + else + { + reader->prev(); + } + break; + case DOWN: + if (reader->is_overlay_active()) + { + reader->overlay_move_right(); + } + else + { + reader->next(); + } + break; + case SELECT: + if (reader->is_overlay_active()) + { + 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 + { + // 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; - case NONE: - default: - break; - } - reader->render(); + return; + } + 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()); + } + break; + case NONE: + default: + break; + } + reader->render(); } - +//目录页的处理 void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_redraw) { if (!contents) @@ -115,32 +273,204 @@ void handleEpubTableContents(Renderer *renderer, UIAction action, bool needs_red contents->set_needs_redraw(); contents->load(); } + + if (needs_redraw) + { + toc_bottom_mode = false; + toc_bottom_idx = 1; + } switch (action) { case UP: - contents->prev(); + if (toc_bottom_mode) + { + // 底部模式下: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 + { + contents->prev(); + } + } break; case DOWN: - contents->next(); + if (toc_bottom_mode) + { + // 底部模式下: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 + { + 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; + // 若处于当前页最后一个条目,DOWN 切换到底部按钮模式并选择“上一页” + if (count > 0 && epub_index_state.selected_item == end_idx) + { + toc_bottom_mode = true; + toc_bottom_idx = 0; // 上一页 + } + else + { + contents->next(); + } + } + 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; // 当前页起始索引 + // 计算全局索引 = 页起始索引 + 页内偏移 + 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: - // 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) + { + // 计算新页面(上一页) + 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) // 下一页 + { + if (current_page < max_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) / per_page) * per_page; // 确保在最后一页的第一项 + + // 退出底部选择模式,回到列表选择状态 + toc_bottom_mode = false; + contents->set_needs_redraw(); + } + } + } + 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(); + // 记录最近一次进入阅读的书籍索引 + g_last_read_index = epub_list_state.selected_item; + 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 @@ -157,56 +487,178 @@ 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 向左移动;若已在最左(上一页),则返回当前页的列表最后一项 + 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 + { + // 若处于当前页第一个条目,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; + library_bottom_idx = 2; // 下一页 + } + else + { + epub_list->prev(); + } + } break; case DOWN: - 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(); + if (library_bottom_mode) + { + // 底部模式下:DOWN 向右移动;若已在最右(下一页),则返回当前页的列表第一项 + if (library_bottom_idx < 2) + { + library_bottom_idx++; } - else // 之前是打开状态,现在要关闭 + else { - touch_controls->powerOffTouch(); + 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 + { + 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; + library_bottom_idx = 0; // 上一页 + } + else + { + epub_list->next(); + } + } + 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; // 当前页起始索引 + // 计算全局索引 = 页起始索引 + 页内偏移 + global_index = start_index + book_index; + // 边界检查 + if (global_index < epub_list_state.num_epubs) + { - epub_list->render(); - - - return; - } - else + 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) { - // 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; + 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) + { + // 计算新页面(上一页) + 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) // 下一页 + { + 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 + { + // 进入目录选择页面 + 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 @@ -288,13 +740,52 @@ 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); + } + else if (ui_action == SELECT && screen_get_main_selected_option() == 1) //继续阅读 + { + // 判断是否有继续阅读记录 + 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) //切换到书库页面 + { + ui_state = SELECTING_EPUB; + handleEpubList(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; @@ -302,157 +793,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 (strcmp(getCurrentPageName(), "MAIN_MENU") == 0) - { - 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); - - if (!epub_list) - { - epub_list = new EpubList(renderer, epub_list_state); - if (epub_list->load("/")) - { - ulog_i("main", "Epub files loaded"); - } - } - 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(); } //关机页面 @@ -538,6 +1026,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,18 +1046,22 @@ 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 ((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) //一分钟自动刷一下 @@ -608,6 +1101,7 @@ while (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 *5) // { 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: @@ -630,14 +1124,13 @@ while (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 *5) // 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(); @@ -671,6 +1164,7 @@ while (rt_tick_get_millisecond() - last_user_interaction < 60 * 1000 * 60 *5) // // 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()); @@ -687,7 +1181,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 +1195,4 @@ extern "C" } return 0; } -} \ No newline at end of file +} 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