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) -> FrameLayout {
87 let border = params.border_width;
88 let pad = params.padding;
89 let frame_width = params.width.unwrap_or(available_width);
90 let content_width =
91 (frame_width - border * 2.0 - pad * 2.0 - params.margin_left - params.margin_right)
92 .max(0.0);
93
94 let mut blocks = Vec::new();
96 let mut content_y = 0.0f32;
97
98 for block_params in ¶ms.blocks {
99 let mut block = layout_block(registry, block_params, content_width);
100 block.y = content_y + block.top_margin;
101 let block_content = block.height - block.top_margin - block.bottom_margin;
102 content_y = block.y + block_content + block.bottom_margin;
103 blocks.push(block);
104 }
105
106 let mut tables = Vec::new();
108 for (_flow_idx, table_params) in ¶ms.tables {
109 let mut table = layout_table(registry, table_params, content_width);
110 table.y = content_y;
111 content_y += table.total_height;
112 tables.push(table);
113 }
114
115 let mut nested_frames = Vec::new();
117 for (_flow_idx, frame_params) in ¶ms.frames {
118 let mut nested = layout_frame(registry, frame_params, content_width);
119 nested.y = content_y;
120 nested.x = 0.0;
121 content_y += nested.total_height;
122 nested_frames.push(nested);
123 }
124
125 let auto_content_height = content_y;
126 let content_height = params
127 .height
128 .map(|h| (h - border * 2.0 - pad * 2.0).max(0.0))
129 .unwrap_or(auto_content_height);
130
131 let total_height =
132 params.margin_top + border + pad + content_height + pad + border + params.margin_bottom;
133 let total_width =
134 params.margin_left + border + pad + content_width + pad + border + params.margin_right;
135
136 let content_x = params.margin_left + border + pad;
137 let content_y_offset = params.margin_top + border + pad;
138
139 FrameLayout {
140 frame_id: params.frame_id,
141 y: 0.0, x: 0.0,
143 total_width,
144 total_height,
145 content_x,
146 content_y: content_y_offset,
147 content_width,
148 content_height,
149 blocks,
150 tables,
151 frames: nested_frames,
152 border_width: border,
153 border_style: params.border_style,
154 }
155}