fix(pagination): paginate styled content to account for indent and paragraph spacing
This commit is contained in:
BIN
sample-short.epub
Normal file
BIN
sample-short.epub
Normal file
Binary file not shown.
@@ -3,11 +3,9 @@ use crate::book::Book;
|
||||
use crate::style::{StyleProfile, TextAlignment};
|
||||
use crate::theme::{self, BgType, Theme};
|
||||
|
||||
pub fn recalculate_pages(book: &mut Book, font_size: f32, line_height: f32, panel_width: f32, panel_height: f32) {
|
||||
// 中文全角字符宽度 ≈ 1.0 × font_size
|
||||
pub fn recalculate_pages(book: &mut Book, font_size: f32, line_height: f32, panel_width: f32, panel_height: f32, style: &StyleProfile) {
|
||||
let char_width = font_size * 1.0;
|
||||
// 安全系数 0.97:抵消段落间距/缩进等样式增加的内容
|
||||
let safety = 0.97;
|
||||
let safety = 0.95;
|
||||
let chars_per_line = if char_width > 0.0 {
|
||||
((panel_width / char_width) * safety).max(1.0) as usize
|
||||
} else {
|
||||
@@ -20,7 +18,8 @@ pub fn recalculate_pages(book: &mut Book, font_size: f32, line_height: f32, pane
|
||||
};
|
||||
let chars_per_page = chars_per_line * lines_per_page;
|
||||
for section in &mut book.sections {
|
||||
section.pages = calculate_pages(§ion.content, chars_per_page);
|
||||
let styled = style.apply_to_text(§ion.content);
|
||||
section.pages = calculate_pages(&styled, chars_per_page);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +155,7 @@ egui::ComboBox::from_id_salt("bg_type_selector")
|
||||
let panel_size = ui.available_size();
|
||||
let recalc_width = (panel_size.x - 48.0).max(100.0);
|
||||
let recalc_height = (panel_size.y - 60.0).max(200.0);
|
||||
recalculate_pages(book, style.font_size, style.line_height(), recalc_width, recalc_height);
|
||||
recalculate_pages(book, style.font_size, style.line_height(), recalc_width, recalc_height, style);
|
||||
|
||||
// --- Bottom progress bar ---
|
||||
let total_pages = if *current_section < book.sections.len() {
|
||||
@@ -242,8 +241,8 @@ egui::ComboBox::from_id_salt("bg_type_selector")
|
||||
if *current_page < section.pages.len().saturating_sub(1) {
|
||||
let start = section.pages[*current_page];
|
||||
let end = section.pages[*current_page + 1];
|
||||
let raw_text: String = section.content.chars().skip(start).take(end - start).collect();
|
||||
let indented = style.apply_to_text(&raw_text);
|
||||
let styled_full = style.apply_to_text(§ion.content);
|
||||
let page_text: String = styled_full.chars().skip(start).take(end - start).collect();
|
||||
|
||||
let align = match style.alignment {
|
||||
TextAlignment::Left => egui::Align::LEFT,
|
||||
@@ -256,13 +255,13 @@ egui::ComboBox::from_id_salt("bg_type_selector")
|
||||
|ui| {
|
||||
let mut is_heading = false;
|
||||
let mut text_start = 0usize;
|
||||
let char_indices: Vec<_> = indented.char_indices().collect();
|
||||
let char_indices: Vec<_> = page_text.char_indices().collect();
|
||||
let mut idx = 0;
|
||||
while idx < char_indices.len() {
|
||||
let (byte_pos, ch) = char_indices[idx];
|
||||
if ch == '\x01' || ch == '\x02' {
|
||||
if byte_pos > text_start {
|
||||
let text = &indented[text_start..byte_pos];
|
||||
let text = &page_text[text_start..byte_pos];
|
||||
let mut rt = egui::RichText::new(text)
|
||||
.size(style.font_size)
|
||||
.color(colors.text);
|
||||
@@ -276,14 +275,14 @@ egui::ComboBox::from_id_salt("bg_type_selector")
|
||||
if idx < char_indices.len() {
|
||||
text_start = char_indices[idx].0;
|
||||
} else {
|
||||
text_start = indented.len();
|
||||
text_start = page_text.len();
|
||||
}
|
||||
} else {
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
if text_start < indented.len() {
|
||||
let text = &indented[text_start..];
|
||||
if text_start < page_text.len() {
|
||||
let text = &page_text[text_start..];
|
||||
let mut rt = egui::RichText::new(text)
|
||||
.size(style.font_size)
|
||||
.color(colors.text);
|
||||
|
||||
Reference in New Issue
Block a user