feat: add typography style system with profiles, alignment, line spacing, first-line indent

This commit is contained in:
Developer
2026-05-14 21:02:34 +08:00
parent d69229b1ca
commit 7d056e2670
5 changed files with 160 additions and 18 deletions

View File

@@ -1,10 +1,10 @@
use eframe::egui;
use crate::book::Book;
use crate::style::{StyleProfile, TextAlignment};
use crate::theme::{self, Theme};
pub fn recalculate_pages(book: &mut Book, font_size: f32, panel_width: f32, panel_height: f32) {
pub fn recalculate_pages(book: &mut Book, font_size: f32, line_height: f32, panel_width: f32, panel_height: f32) {
let char_width = font_size * 0.6;
let line_height = font_size * 1.5;
let chars_per_line = if char_width > 0.0 {
(panel_width / char_width).max(1.0) as usize
} else {
@@ -26,6 +26,7 @@ pub struct ReaderAction {
pub toggle_theme: bool,
pub toggle_bookmark: bool,
pub toggle_kraft_bg: bool,
pub cycle_profile: bool,
pub page_next: bool,
pub page_prev: bool,
}
@@ -36,7 +37,7 @@ pub fn reading_view(
current_section: &mut usize,
current_page: &mut usize,
sidebar_open: &mut bool,
font_size: &mut f32,
style: &mut StyleProfile,
theme: &Theme,
_file_path: &str,
kraft_texture: Option<&egui::TextureHandle>,
@@ -47,12 +48,14 @@ pub fn reading_view(
toggle_theme: false,
toggle_bookmark: false,
toggle_kraft_bg: false,
cycle_profile: false,
page_next: false,
page_prev: false,
};
let panel_size = ui.available_size();
recalculate_pages(book, *font_size, panel_size.x, panel_size.y);
let line_h = style.line_height();
recalculate_pages(book, style.font_size, line_h, panel_size.x, panel_size.y);
let colors = theme::reader_colors(theme);
@@ -90,10 +93,16 @@ pub fn reading_view(
action.toggle_bookmark = true;
}
if ui.button("A⁻").on_hover_text("缩小字体").clicked() {
*font_size = (*font_size - 2.0).max(10.0);
style.font_size = (style.font_size - 2.0).max(10.0);
}
if ui.button("A⁺").on_hover_text("放大字体").clicked() {
*font_size = (*font_size + 2.0).min(48.0);
style.font_size = (style.font_size + 2.0).min(48.0);
}
if ui.button(&style.name)
.on_hover_text(format!("样式: {} (点击切换)", style.name))
.clicked()
{
action.cycle_profile = true;
}
let kraft_icon = if use_kraft_bg { "📄" } else { "📋" };
if ui.button(kraft_icon).on_hover_text("牛皮纸背景").clicked() {
@@ -189,15 +198,28 @@ pub fn reading_view(
if *current_page < section.pages.len().saturating_sub(1) {
let start = section.pages[*current_page];
let end = section.pages[*current_page + 1];
let text: String = section.content.chars().skip(start).take(end - start).collect();
ui.put(text_rect, |ui: &mut egui::Ui| {
ui.add(
egui::Label::new(
egui::RichText::new(&text)
.size(*font_size)
.color(colors.text)
).wrap()
)
let raw_text: String = section.content.chars().skip(start).take(end - start).collect();
let indented = crate::style::apply_indent(&raw_text, style.first_line_indent);
let align = match style.alignment {
TextAlignment::Left => egui::Align::LEFT,
TextAlignment::Center => egui::Align::Center,
TextAlignment::Right => egui::Align::RIGHT,
};
ui.allocate_new_ui(egui::UiBuilder::new().max_rect(text_rect), |ui| {
ui.with_layout(
egui::Layout::top_down(align).with_main_justify(false),
|ui| {
ui.add(
egui::Label::new(
egui::RichText::new(&indented)
.size(style.font_size)
.line_height(Some(style.line_height()))
.color(colors.text)
).wrap()
);
},
);
});
}
}