From e2ed63a982ebf078003e82405897c0405303bfad Mon Sep 17 00:00:00 2001 From: Developer Date: Fri, 15 May 2026 20:47:31 +0800 Subject: [PATCH] fix(pagination): paginate styled content to account for indent and paragraph spacing --- sample-short.epub | Bin 0 -> 2633 bytes src/reader.rs | 25 ++++++++++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) create mode 100644 sample-short.epub diff --git a/sample-short.epub b/sample-short.epub new file mode 100644 index 0000000000000000000000000000000000000000..af9abc0113904e196c4b500c81750e80e805c9c8 GIT binary patch literal 2633 zcma);2{e>#8^?zkOxeaVma)q+C0nG>OejlaZx9B9k-^MZ#+z;Mp&^lsBFS0^4MUc< z!b^Kfk;2&5kbOwo_DbN{W(fFMD@x3%sV>rBLy z9sKt6t-#E}si6f-2TO*j*_M=Wq3c1b-(#k*{);F^NrP2{Fsu z@Ql9lDGMW24Q@rt4@Qf4O)M!O#Qq$Z6TTmvS<%faZErYt-I2gs^OX1Z@w%_BbS|+lMF9Z-5axJ> zRw#q-qhSdo6{5davaNYamKvmCzJlI&f(LqCt}Ig8?L+D8PV`!J#*0dhLymN`h8!cx z^*Q8`DY{0{Z|h^j#F5dF;l7#~aHFwr%LkoSJFcWEn7M5^duf_wS^TGRe;dRrb_czz z#xV}r49)`z5WB=kXv5J+s%NOy|dim@HVn>q3ME3$aW?4PNDg*Nfipj$#G-6VNb-cla#hQNg?bCj}v@i-tPGID5ZVlCo9f zBJc9qT3qr@9LT>1d>UV!Q2GeIESpk3? zra$06{Si#?#0CbDFa%E=;hd`{?i`MU@pJVe2I4WKAe9hr65j8^8FON<8dt--y+1=H z<29j&#g|p_DLoP(_JGZy3vX;xpqyVjb}I1ZN>>UsOL_{Maguc~d~Dx-Vf)@93b%Fz z?QBvpgCX()tW;AXG^%oSUiG>Ct0PZ)r{{B}cJ31NE);zX-vSoF{t_vH^n~VoCg-jS zX9lB?*{xn*wA_t=-WK>eq`nU$eNTAgA8YD$G%5Wjubqqw2ULvS3g2Uli(eMuuNjm# zO;isE%OT!v3Z9FdJ~=5qK5t~TF9Ru?X7iS}Zd@$dfUhNF$fGU4XxwriBV12_`*BS< zsR>4)`KqnUO6jF$&X+vxY3aX2xv^sz%?GST&v_J`2_1YApS3h5}6%KAg?@AtRSk>Fv~m-n>W$WBzIu&>*#~P)PNx zw#-+Py<;%^i`Xjiff&xF7vqw*+TWf|p~69-mWPy<*4#d>b;s!eePe3w!KWo$fv8S- z7JLkwr87d8_hI_h*3d{(#i~H_rwy&bQNzvck$LD)FPb&tZ2xR>?vr_Y;r%<)9isuN zE*RwPw(YLx0=h@w?;CaZBD@v42mFO4G7rFW9T3B57aJBtx9HsZ)0&%HGoTkPeW>a z1^n*e;IU05B=a8^$n-JSPY;ub9x4QnkYuX49?_yACQ787OKWT^hR*cl!jPF>fjf;_{y}Cm;qu z_^G*rF^2k1xErvK9X8r2>Y8Yyi`UpesOvNx8ho=O`{pY_O$W5>$@r>)7yOdwbBp}( zsoQx`^QYM(HT|_#pIm!&T(i@EOnT+|KpICyzO?G_l3rV?BKnh6`Y~OiTPmZ?x zxlZ@P(^~nUT4Ke@{4`Lj5<_|&Z}7ZhaSP>TWqGk=qZl;|wdxr@{8g2#MjwPk-ekd% zRlLt%?kVM~Q8qf$XYc)~1H>Q=R#uciky}ZmHQ?_$$Fj$!-;~-9e>#=_fs&F#I zo%V1L!tzm)v=KSha?{qh(q(V@hb3f>AZOq`a`?u2SQO=1?K@0VbXqCWIJpK*Sv-1q zF+|MQb`*7^Xnj%}e&x^r_oh;j8~SiS*Qvnx;I4gF-iOMTE10icN@N4zj$$MIZ$a&r zMpz`1hoJR5F#&W~ZGlj_X-IofVXflPg?f>aEBB1rf$L{75y8id?J~fiSE+8` zr1ZJOslcg<*rs@gua7%Zy&BV(C!+<=4M|^kws62W*1bH!>>4rR`J-AiwDxKKIDfBMAXd_LjujV_{<84If*@P7vurkvkbG*jPS@#Pow?_uR1 z1^|d=(P7^Hdvw{|V|OC>)kBo|?cMocH@*A3_(f|2f6)KO>9M=(?j8KA>o(huu0Qtk iZgRILf00;@ALM@>YGua8{_Q 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);