1use std::collections::HashMap;
7
8#[derive(Debug, Clone, Default)]
10pub struct XForm {
11 pub pin_x: f64,
12 pub pin_y: f64,
13 pub width: f64,
14 pub height: f64,
15 pub loc_pin_x: f64,
16 pub loc_pin_y: f64,
17 pub angle: f64,
18 pub flip_x: bool,
19 pub flip_y: bool,
20}
21
22#[derive(Debug, Clone, Default)]
24pub struct TextXForm {
25 pub txt_pin_x: f64,
26 pub txt_pin_y: f64,
27 pub txt_width: f64,
28 pub txt_height: f64,
29 pub txt_loc_pin_x: f64,
30 pub txt_loc_pin_y: f64,
31 pub txt_angle: f64,
32}
33
34#[derive(Debug, Clone, Default)]
36pub struct XForm1D {
37 pub begin_x: f64,
38 pub begin_y: f64,
39 pub end_x: f64,
40 pub end_y: f64,
41}
42
43#[derive(Debug, Clone, Default)]
45pub struct CellValue {
46 pub v: String,
47 pub f: String,
48}
49
50impl CellValue {
51 pub fn new(v: impl Into<String>, f: impl Into<String>) -> Self {
52 Self {
53 v: v.into(),
54 f: f.into(),
55 }
56 }
57 pub fn val(v: impl Into<String>) -> Self {
58 Self {
59 v: v.into(),
60 f: String::new(),
61 }
62 }
63 pub fn as_f64(&self) -> f64 {
64 self.v.parse().unwrap_or(0.0)
65 }
66 pub fn as_f64_or(&self, default: f64) -> f64 {
67 self.v.parse().unwrap_or(default)
68 }
69 pub fn is_empty(&self) -> bool {
70 self.v.is_empty() && self.f.is_empty()
71 }
72}
73
74#[derive(Debug, Clone)]
76pub struct GeomRow {
77 pub row_type: String,
78 pub ix: String,
79 pub cells: HashMap<String, CellValue>,
80}
81
82impl GeomRow {
83 pub fn new(row_type: &str) -> Self {
84 Self {
85 row_type: row_type.to_string(),
86 ix: String::new(),
87 cells: HashMap::new(),
88 }
89 }
90 pub fn cell_f64(&self, name: &str) -> f64 {
91 self.cells.get(name).map(|c| c.as_f64()).unwrap_or(0.0)
92 }
93}
94
95#[derive(Debug, Clone, Default)]
97pub struct GeomSection {
98 pub no_fill: bool,
99 pub no_line: bool,
100 pub no_show: bool,
101 pub ix: String,
102 pub rows: Vec<GeomRow>,
103}
104
105#[derive(Debug, Clone)]
107pub struct CharFormat {
108 pub size: String,
109 pub color: String,
110 pub style: String,
111 pub font: String,
112}
113
114impl Default for CharFormat {
115 fn default() -> Self {
116 Self {
117 size: "0.1111".to_string(),
118 color: String::new(),
119 style: "0".to_string(),
120 font: String::new(),
121 }
122 }
123}
124
125#[derive(Debug, Clone, Default)]
127pub struct ParaFormat {
128 pub horiz_align: String,
129 pub indent_first: String,
130 pub indent_left: String,
131 pub indent_right: String,
132 pub bullet: String,
133 pub bullet_str: String,
134 pub sp_line: String,
135 pub sp_before: String,
136 pub sp_after: String,
137}
138
139#[derive(Debug, Clone)]
141pub struct TextPart {
142 pub text: String,
143 pub cp: String,
144 pub pp: String,
145}
146
147#[derive(Debug, Clone, Default)]
149pub struct ForeignDataInfo {
150 pub foreign_type: String,
151 pub compression: String,
152 pub data: Option<String>,
153 pub rel_id: Option<String>,
154}
155
156#[derive(Debug, Clone, Default)]
158pub struct Hyperlink {
159 pub description: String,
160 pub address: String,
161 pub sub_address: String,
162 pub frame: String,
163}
164
165#[derive(Debug, Clone)]
167pub struct GradientStop {
168 pub position: f64,
169 pub color: String,
170}
171
172#[derive(Debug, Clone)]
174pub struct GradientDef {
175 pub id: String,
176 pub start: String,
177 pub end: String,
178 pub mid: Option<String>,
179 pub dir: f64,
180 pub radial: bool,
181 pub stops: Vec<GradientStop>,
182 pub cx: f64,
183 pub cy: f64,
184 pub fx: f64,
185 pub fy: f64,
186 pub r: f64,
187}
188
189impl Default for GradientDef {
190 fn default() -> Self {
191 Self {
192 id: String::new(),
193 start: "#FFFFFF".to_string(),
194 end: "#000000".to_string(),
195 mid: None,
196 dir: 0.0,
197 radial: false,
198 stops: Vec::new(),
199 cx: 50.0,
200 cy: 50.0,
201 fx: 50.0,
202 fy: 50.0,
203 r: 50.0,
204 }
205 }
206}
207
208#[derive(Debug, Clone)]
210pub struct FillPatternDef {
211 pub id: String,
212 pub fg: String,
213 pub bg: String,
214 pub pattern_type: i32,
215}
216
217#[derive(Debug, Clone)]
219pub struct Shape {
220 pub id: String,
221 pub name: String,
222 pub name_u: String,
223 pub shape_type: String,
224 pub master: String,
225 pub master_shape: String,
226 pub cells: HashMap<String, CellValue>,
227 pub geometry: Vec<GeomSection>,
228 pub text: String,
229 pub text_parts: Vec<TextPart>,
230 pub char_formats: HashMap<String, CharFormat>,
231 pub para_formats: HashMap<String, ParaFormat>,
232 pub sub_shapes: Vec<Shape>,
233 pub controls: HashMap<String, HashMap<String, String>>,
234 pub connections: HashMap<String, HashMap<String, CellValue>>,
235 pub user: HashMap<String, HashMap<String, String>>,
236 pub foreign_data: Option<ForeignDataInfo>,
237 pub hyperlinks: Vec<Hyperlink>,
238 pub line_style: String,
239 pub fill_style: String,
240 pub text_style: String,
241 pub gradient_stops: Vec<Vec<GradientStop>>,
242 pub has_text_elem: bool,
243 pub master_w: f64,
244 pub master_h: f64,
245 pub has_own_geometry: bool,
246 pub theme_text_color: Option<String>,
247}
248
249impl Default for Shape {
250 fn default() -> Self {
251 Self {
252 id: String::new(),
253 name: String::new(),
254 name_u: String::new(),
255 shape_type: "Shape".to_string(),
256 master: String::new(),
257 master_shape: String::new(),
258 cells: HashMap::new(),
259 geometry: Vec::new(),
260 text: String::new(),
261 text_parts: Vec::new(),
262 char_formats: HashMap::new(),
263 para_formats: HashMap::new(),
264 sub_shapes: Vec::new(),
265 controls: HashMap::new(),
266 connections: HashMap::new(),
267 user: HashMap::new(),
268 foreign_data: None,
269 hyperlinks: Vec::new(),
270 line_style: String::new(),
271 fill_style: String::new(),
272 text_style: String::new(),
273 gradient_stops: Vec::new(),
274 has_text_elem: false,
275 master_w: 0.0,
276 master_h: 0.0,
277 has_own_geometry: false,
278 theme_text_color: None,
279 }
280 }
281}
282
283impl Shape {
284 pub fn cell_val(&self, name: &str) -> &str {
285 self.cells.get(name).map(|c| c.v.as_str()).unwrap_or("")
286 }
287
288 pub fn cell_f64(&self, name: &str) -> f64 {
289 self.cells.get(name).map(|c| c.as_f64()).unwrap_or(0.0)
290 }
291
292 pub fn cell_f64_or(&self, name: &str, default: f64) -> f64 {
293 self.cells
294 .get(name)
295 .map(|c| c.as_f64_or(default))
296 .unwrap_or(default)
297 }
298}
299
300#[derive(Debug, Clone)]
302pub struct Connect {
303 pub from_sheet: String,
304 pub from_cell: String,
305 pub to_sheet: String,
306 pub to_cell: String,
307}
308
309#[derive(Debug, Clone)]
311pub struct LayerDef {
312 pub name: String,
313 pub visible: bool,
314}
315
316#[derive(Debug, Clone)]
318pub struct Page {
319 pub name: String,
320 pub index: usize,
321 pub width: f64,
322 pub height: f64,
323 pub shapes: Vec<Shape>,
324 pub connects: Vec<Connect>,
325 pub layers: HashMap<String, LayerDef>,
326 pub background: bool,
327}
328
329impl Default for Page {
330 fn default() -> Self {
331 Self {
332 name: String::new(),
333 index: 0,
334 width: 8.5,
335 height: 11.0,
336 shapes: Vec::new(),
337 connects: Vec::new(),
338 layers: HashMap::new(),
339 background: false,
340 }
341 }
342}
343
344#[derive(Debug, Clone, Default)]
346pub struct StyleSheet {
347 pub cells: HashMap<String, CellValue>,
348 pub line_style: String,
349 pub fill_style: String,
350 pub text_style: String,
351}
352
353#[derive(Debug, Clone, Default)]
355pub struct Document {
356 pub pages: Vec<Page>,
357 pub masters: HashMap<String, HashMap<String, Shape>>,
358 pub theme_colors: HashMap<String, String>,
359 pub media: HashMap<String, Vec<u8>>,
360 pub stylesheets: HashMap<String, StyleSheet>,
361 pub background_map: HashMap<usize, usize>,
362}
363
364#[derive(Debug, Clone)]
366pub struct PageInfo {
367 pub name: String,
368 pub index: usize,
369 pub width: f64,
370 pub height: f64,
371}