feat: add typography style system with profiles, alignment, line spacing, first-line indent
This commit is contained in:
@@ -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()
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user