text_typeset/layout/
frame.rs1use crate::font::registry::FontRegistry;
2use crate::layout::block::layout_block;
3use crate::layout::block::{BlockLayout, BlockLayoutParams};
4use crate::layout::table::{TableLayout, TableLayoutParams, layout_table};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
15pub enum FramePosition {
16 #[default]
18 Inline,
19 FloatLeft,
22 FloatRight,
25 Absolute,
28}
29
30#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
32pub enum FrameBorderStyle {
33 #[default]
35 Full,
36 LeftOnly,
38 None,
40}
41
42pub struct FrameLayoutParams {
44 pub frame_id: usize,
45 pub position: FramePosition,
46 pub width: Option<f32>,
48 pub height: Option<f32>,
50 pub margin_top: f32,
51 pub margin_bottom: f32,
52 pub margin_left: f32,
53 pub margin_right: f32,
54 pub padding: f32,
55 pub border_width: f32,
56 pub border_style: FrameBorderStyle,
57 pub blocks: Vec<BlockLayoutParams>,
59 pub tables: Vec<(usize, TableLayoutParams)>, pub frames: Vec<(usize, FrameLayoutParams)>, }
62
63pub struct FrameLayout {
65 pub frame_id: usize,
66 pub y: f32,
67 pub x: f32,
68 pub total_width: f32,
69 pub total_height: f32,
70 pub content_x: f32,
71 pub content_y: f32,
72 pub content_width: f32,
73 pub content_height: f32,
74 pub blocks: Vec<BlockLayout>,
75 pub tables: Vec<TableLayout>,
76 pub frames: Vec<FrameLayout>,
77 pub border_width: f32,
78 pub border_style: FrameBorderStyle,
79}
80
81pub fn layout_frame(
83 registry: &FontRegistry,
84 params: &FrameLayoutParams,
85 available_width: f32,
86 scale_factor: f32,
87) -> FrameLayout {
88 let border = params.border_width;
89 let pad = params.padding;
90 let frame_width = params.width.unwrap_or(available_width);
91 let content_width =
92 (frame_width - border * 2.0 - pad * 2.0 - params.margin_left - params.margin_right)
93 .max(0.0);
94
95 let mut blocks = Vec::new();
97 let mut content_y = 0.0f32;
98
99 for block_params in ¶ms.blocks {
100 let mut block = layout_block(registry, block_params, content_width, scale_factor);
101 block.y = content_y + block.top_margin;
102 let block_content = block.height - block.top_margin - block.bottom_margin;
103 content_y = block.y + block_content + block.bottom_margin;
104 blocks.push(block);
105 }
106
107 let mut tables = Vec::new();
109 for (_flow_idx, table_params) in ¶ms.tables {
110 let mut table = layout_table(registry, table_params, content_width, scale_factor);
111 table.y = content_y;
112 content_y += table.total_height;
113 tables.push(table);
114 }
115
116 let mut nested_frames = Vec::new();
118 for (_flow_idx, frame_params) in ¶ms.frames {
119 let mut nested = layout_frame(registry, frame_params, content_width, scale_factor);
120 nested.y = content_y;
121 nested.x = 0.0;
122 content_y += nested.total_height;
123 nested_frames.push(nested);
124 }
125
126 let auto_content_height = content_y;
127 let content_height = params
128 .height
129 .map(|h| (h - border * 2.0 - pad * 2.0).max(0.0))
130 .unwrap_or(auto_content_height);
131
132 let total_height =
133 params.margin_top + border + pad + content_height + pad + border + params.margin_bottom;
134 let total_width =
135 params.margin_left + border + pad + content_width + pad + border + params.margin_right;
136
137 let content_x = params.margin_left + border + pad;
138 let content_y_offset = params.margin_top + border + pad;
139
140 FrameLayout {
141 frame_id: params.frame_id,
142 y: 0.0, x: 0.0,
144 total_width,
145 total_height,
146 content_x,
147 content_y: content_y_offset,
148 content_width,
149 content_height,
150 blocks,
151 tables,
152 frames: nested_frames,
153 border_width: border,
154 border_style: params.border_style,
155 }
156}