1//! The page templates Snowbound offers: OneNote 2010's background art, recreated
2//! (`gpu::page::template_picture`), placed where OneNote's templates place it, plain
3//! page colours and rule lines.
4
5use onestore::page::{RuleLines, VerticalRule};
6
7/// One background picture of a template: the recreated art's name, and the picture's
8/// position and size in points from the page origin as OneNote's template stores them.
9/// Art without a size draws at its natural size.
10#[derive(Clone, Copy, Debug, PartialEq)]
11pub struct Art {
12 pub art: &'static str,
13 pub position: [f32; 2],
14 pub size: Option<[f32; 2]>,
15}
16
17/// A template by OneNote's name for it, with the art it puts behind the page.
18#[derive(Clone, Copy, Debug, PartialEq)]
19pub struct Template {
20 pub name: &'static str,
21 pub art: &'static [Art],
22}
23
24impl Template {
25 /// The background pictures a page stores for this template: OneNote's places, our
26 /// recreations' bytes.
27 #[cfg(feature = "gpu")]
28 pub fn pictures(&self) -> Result<Vec<onestore::page::Image>, onestore::page::text::EditError> {
29 self.art
30 .iter()
31 .map(|art| {
32 let bytes = crate::gpu::page::template_picture(art.art)
33 .expect("Every template's art is recreated");
34 Ok(onestore::page::Image {
35 id: onestore::page::text::new_id()?,
36 layout: onestore::document::Layout {
37 x: Some(art.position[0]),
38 y: Some(art.position[1]),
39 max_width: art.size.map(|size| size[0]),
40 max_height: art.size.map(|size| size[1]),
41 width_set_by_user: art.size.map(|_| true),
42 ..Default::default()
43 },
44 size: art.size,
45 bytes: Some(bytes.into()),
46 display: None,
47 alt: None,
48 background: true,
49 printout: None,
50 tags: Vec::new(),
51 link: None,
52 text: None,
53 })
54 })
55 .collect()
56 }
57}
58
59/// OneNote 2010's Decorative templates and Informal Meeting Notes (resources/onenote-templates.md),
60/// in the order the gallery lists them.
61pub const TEMPLATES: &[Template] = &[
62 Template {
63 name: "Informal Meeting Notes",
64 art: &[Art {
65 art: "small-push-pins",
66 position: [-18.0, -39.6],
67 size: Some([610.3, 789.8]),
68 }],
69 },
70 Template {
71 name: "Bamboo",
72 art: &[Art {
73 art: "bamboo",
74 position: [-36.0, -75.6],
75 size: Some([581.1, 754.3]),
76 }],
77 },
78 Template {
79 name: "Binoculars Corner",
80 art: &[Art {
81 art: "binoculars-corner",
82 position: [-54.0, -12.6],
83 size: Some([353.7, 80.0]),
84 }],
85 },
86 Template {
87 name: "Black and Green Title",
88 art: &[Art {
89 art: "black-and-green-title",
90 position: [0.0, -36.6],
91 size: Some([633.7, 39.6]),
92 }],
93 },
94 Template {
95 name: "Blue Bubbles Corner",
96 art: &[
97 Art {
98 art: "blue-bubbles-corner-margin",
99 position: [-54.0, -3.6],
100 size: Some([59.6, 247.5]),
101 },
102 Art {
103 art: "blue-bubbles-corner-top",
104 position: [443.2, -3.6],
105 size: Some([47.7, 63.7]),
106 },
107 ],
108 },
109 Template {
110 name: "Blue Clouds",
111 art: &[Art {
112 art: "blue-clouds",
113 position: [-2.2, 0.9],
114 size: Some([662.2, 905.0]),
115 }],
116 },
117 Template {
118 name: "Blue Dots",
119 art: &[Art {
120 art: "blue-dots",
121 position: [-1.5, 0.1],
122 size: Some([602.7, 780.0]),
123 }],
124 },
125 Template {
126 name: "Blue Flow",
127 art: &[Art {
128 art: "blue-flow",
129 position: [0.0, -0.6],
130 size: Some([33.1, 498.0]),
131 }],
132 },
133 Template {
134 name: "Blue Mist Margin",
135 art: &[Art {
136 art: "blue-mist-margin",
137 position: [-26.2, -3.6],
138 size: Some([36.0, 431.8]),
139 }],
140 },
141 Template {
142 name: "Blue Stripe Title",
143 art: &[Art {
144 art: "blue-stripe-title",
145 position: [0.0, -12.6],
146 size: Some([662.2, 103.0]),
147 }],
148 },
149 Template {
150 name: "Blue Stripes",
151 art: &[Art {
152 art: "blue-stripes",
153 position: [-63.0, -21.6],
154 size: Some([611.2, 791.0]),
155 }],
156 },
157 Template {
158 name: "Blue Swirls",
159 art: &[Art {
160 art: "blue-swirls",
161 position: [0.0, -3.6],
162 size: Some([595.6, 775.0]),
163 }],
164 },
165 Template {
166 name: "Blue Wave Title",
167 art: &[Art {
168 art: "blue-wave-title",
169 position: [-25.5, -15.6],
170 size: Some([547.2, 42.9]),
171 }],
172 },
173 Template {
174 name: "Blue Waves",
175 art: &[Art {
176 art: "blue-waves",
177 position: [0.0, -12.6],
178 size: Some([634.3, 812.5]),
179 }],
180 },
181 Template {
182 name: "Books",
183 art: &[Art {
184 art: "books",
185 position: [-72.0, -3.6],
186 size: Some([183.9, 658.9]),
187 }],
188 },
189 Template {
190 name: "Bouquet",
191 art: &[Art {
192 art: "bouquet",
193 position: [-45.0, -39.6],
194 size: Some([505.9, 654.8]),
195 }],
196 },
197 Template {
198 name: "Boxes",
199 art: &[Art {
200 art: "boxes",
201 position: [-36.0, -3.6],
202 size: None,
203 }],
204 },
205 Template {
206 name: "Boxes - Shadow",
207 art: &[Art {
208 art: "boxes-shadow",
209 position: [-18.0, 14.4],
210 size: Some([30.0, 456.8]),
211 }],
212 },
213 Template {
214 name: "Bubbles",
215 art: &[Art {
216 art: "bubbles",
217 position: [-18.0, -3.6],
218 size: Some([36.0, 425.3]),
219 }],
220 },
221 Template {
222 name: "Bubbles Margin",
223 art: &[
224 Art {
225 art: "bubbles-margin-margin",
226 position: [-54.0, 68.4],
227 size: Some([54.9, 288.0]),
228 },
229 Art {
230 art: "bubbles-margin-top",
231 position: [-54.0, -21.6],
232 size: Some([432.0, 70.4]),
233 },
234 ],
235 },
236 Template {
237 name: "Buildings",
238 art: &[Art {
239 art: "buildings",
240 position: [-36.0, -21.6],
241 size: Some([597.5, 773.3]),
242 }],
243 },
244 Template {
245 name: "Chain Title",
246 art: &[Art {
247 art: "chain-title",
248 position: [0.0, -11.1],
249 size: Some([533.7, 95.7]),
250 }],
251 },
252 Template {
253 name: "Circles",
254 art: &[Art {
255 art: "circles",
256 position: [-54.0, -3.6],
257 size: Some([68.7, 549.8]),
258 }],
259 },
260 Template {
261 name: "Clock",
262 art: &[Art {
263 art: "clock",
264 position: [-18.0, -3.6],
265 size: Some([607.9, 786.7]),
266 }],
267 },
268 Template {
269 name: "Columns",
270 art: &[Art {
271 art: "columns",
272 position: [-37.5, -8.9],
273 size: Some([602.1, 779.2]),
274 }],
275 },
276 Template {
277 name: "Computer",
278 art: &[Art {
279 art: "computer",
280 position: [-18.0, -21.6],
281 size: Some([462.7, 618.0]),
282 }],
283 },
284 Template {
285 name: "Cyan Title",
286 art: &[Art {
287 art: "cyan-title",
288 position: [0.7, -12.6],
289 size: Some([717.0, 102.3]),
290 }],
291 },
292 Template {
293 name: "Day Planner",
294 art: &[Art {
295 art: "day-planner",
296 position: [-36.0, -3.6],
297 size: Some([482.5, 487.2]),
298 }],
299 },
300 Template {
301 name: "Fireworks",
302 art: &[Art {
303 art: "fireworks",
304 position: [-72.0, -3.6],
305 size: Some([98.8, 288.0]),
306 }],
307 },
308 Template {
309 name: "Flat Squares",
310 art: &[Art {
311 art: "flat-squares",
312 position: [-18.0, -3.6],
313 size: Some([30.0, 492.8]),
314 }],
315 },
316 Template {
317 name: "Flowers and Hearts",
318 art: &[Art {
319 art: "flowers-and-hearts",
320 position: [-54.0, -3.6],
321 size: Some([88.8, 689.8]),
322 }],
323 },
324 Template {
325 name: "Glasses Corner",
326 art: &[Art {
327 art: "glasses-corner",
328 position: [-81.0, -56.1],
329 size: Some([229.5, 120.7]),
330 }],
331 },
332 Template {
333 name: "Globe",
334 art: &[Art {
335 art: "globe",
336 position: [-54.0, -3.6],
337 size: Some([142.7, 557.7]),
338 }],
339 },
340 Template {
341 name: "Graph",
342 art: &[Art {
343 art: "graph",
344 position: [-36.0, -3.6],
345 size: Some([46.5, 495.7]),
346 }],
347 },
348 Template {
349 name: "Green Stripes",
350 art: &[Art {
351 art: "green-stripes",
352 position: [-72.0, -21.6],
353 size: Some([612.0, 792.0]),
354 }],
355 },
356 Template {
357 name: "Hearts",
358 art: &[Art {
359 art: "hearts",
360 position: [-90.0, -3.6],
361 size: Some([89.2, 288.0]),
362 }],
363 },
364 Template {
365 name: "Ivy",
366 art: &[Art {
367 art: "ivy",
368 position: [-27.0, -3.6],
369 size: Some([174.5, 640.0]),
370 }],
371 },
372 Template {
373 name: "Large Push Pins",
374 art: &[Art {
375 art: "large-push-pins",
376 position: [-18.0, -21.6],
377 size: Some([529.7, 685.5]),
378 }],
379 },
380 Template {
381 name: "Light Bulb Corner",
382 art: &[Art {
383 art: "light-bulb-corner",
384 position: [0.0, -5.9],
385 size: Some([155.7, 164.7]),
386 }],
387 },
388 Template {
389 name: "Lilies",
390 art: &[Art {
391 art: "lilies",
392 position: [0.0, -3.6],
393 size: Some([618.5, 811.5]),
394 }],
395 },
396 Template {
397 name: "Math",
398 art: &[Art {
399 art: "math",
400 position: [-36.0, -21.6],
401 size: Some([512.6, 568.1]),
402 }],
403 },
404 Template {
405 name: "Networking",
406 art: &[
407 Art {
408 art: "networking",
409 position: [-36.0, 212.4],
410 size: None,
411 },
412 Art {
413 art: "networking",
414 position: [-36.0, 104.4],
415 size: None,
416 },
417 Art {
418 art: "networking",
419 position: [-36.0, -3.6],
420 size: None,
421 },
422 ],
423 },
424 Template {
425 name: "Notebook",
426 art: &[Art {
427 art: "notebook",
428 position: [-18.0, -21.6],
429 size: Some([483.9, 626.3]),
430 }],
431 },
432 Template {
433 name: "Orange Margin",
434 art: &[Art {
435 art: "orange-margin",
436 position: [-27.0, -3.6],
437 size: Some([37.4, 483.0]),
438 }],
439 },
440 Template {
441 name: "Paper",
442 art: &[Art {
443 art: "paper",
444 position: [-18.0, -57.6],
445 size: Some([612.6, 792.7]),
446 }],
447 },
448 Template {
449 name: "Paws - Cyan",
450 art: &[Art {
451 art: "paws-cyan",
452 position: [-18.0, -3.6],
453 size: Some([36.0, 288.0]),
454 }],
455 },
456 Template {
457 name: "Pencil and Notebook",
458 art: &[Art {
459 art: "pencil-and-notebook",
460 position: [-18.0, -57.6],
461 size: Some([620.8, 469.5]),
462 }],
463 },
464 Template {
465 name: "Pens",
466 art: &[Art {
467 art: "pens",
468 position: [-36.0, -39.6],
469 size: Some([601.0, 777.8]),
470 }],
471 },
472 Template {
473 name: "Pixel",
474 art: &[Art {
475 art: "pixel",
476 position: [-18.0, -21.6],
477 size: Some([432.0, 26.3]),
478 }],
479 },
480 Template {
481 name: "Pixel - Blends",
482 art: &[Art {
483 art: "pixel-blends",
484 position: [-18.0, -3.6],
485 size: Some([29.2, 354.0]),
486 }],
487 },
488 Template {
489 name: "Plain and Simple",
490 art: &[Art {
491 art: "plain-and-simple",
492 position: [-36.0, -12.6],
493 size: Some([606.8, 785.3]),
494 }],
495 },
496 Template {
497 name: "Purple Clouds",
498 art: &[Art {
499 art: "purple-clouds",
500 position: [0.0, -21.6],
501 size: Some([613.5, 163.7]),
502 }],
503 },
504 Template {
505 name: "Pushpins Corner",
506 art: &[Art {
507 art: "pushpins-corner",
508 position: [-36.0, -39.6],
509 size: Some([162.0, 111.9]),
510 }],
511 },
512 Template {
513 name: "Rainbow",
514 art: &[Art {
515 art: "rainbow",
516 position: [-36.0, -3.6],
517 size: Some([612.0, 792.0]),
518 }],
519 },
520 Template {
521 name: "Rainbow Border",
522 art: &[Art {
523 art: "rainbow-border",
524 position: [-18.0, -3.6],
525 size: Some([29.2, 399.0]),
526 }],
527 },
528 Template {
529 name: "Rainbow Mini Border",
530 art: &[Art {
531 art: "rainbow-mini-border",
532 position: [-18.0, -3.6],
533 size: Some([24.0, 368.2]),
534 }],
535 },
536 Template {
537 name: "Recipe",
538 art: &[Art {
539 art: "recipe",
540 position: [-45.0, -3.6],
541 size: Some([533.2, 690.0]),
542 }],
543 },
544 Template {
545 name: "Red and Black Margin",
546 art: &[Art {
547 art: "red-and-black-margin",
548 position: [0.7, 6.9],
549 size: Some([11.8, 484.5]),
550 }],
551 },
552 Template {
553 name: "Side Stripes",
554 art: &[Art {
555 art: "side-stripes",
556 position: [-36.0, -3.6],
557 size: Some([40.2, 848.4]),
558 }],
559 },
560 Template {
561 name: "Small Push Pins",
562 art: &[Art {
563 art: "small-push-pins",
564 position: [-36.0, -39.6],
565 size: Some([610.3, 789.8]),
566 }],
567 },
568 Template {
569 name: "Sparks",
570 art: &[Art {
571 art: "sparks",
572 position: [-18.0, -3.6],
573 size: Some([611.4, 791.3]),
574 }],
575 },
576 Template {
577 name: "Stars",
578 art: &[Art {
579 art: "stars",
580 position: [-36.0, -3.6],
581 size: Some([61.8, 341.9]),
582 }],
583 },
584 Template {
585 name: "Swirls",
586 art: &[Art {
587 art: "swirls",
588 position: [-36.0, -3.6],
589 size: Some([56.2, 366.3]),
590 }],
591 },
592 Template {
593 name: "Tiles",
594 art: &[Art {
595 art: "tiles",
596 position: [-36.0, -3.6],
597 size: Some([606.2, 784.5]),
598 }],
599 },
600 Template {
601 name: "Triangles Title",
602 art: &[
603 Art {
604 art: "triangles-title-top",
605 position: [0.0, -21.6],
606 size: Some([274.2, 53.0]),
607 },
608 Art {
609 art: "triangles-title-margin",
610 position: [5.2, 231.9],
611 size: Some([11.8, 288.0]),
612 },
613 ],
614 },
615 Template {
616 name: "Tulips",
617 art: &[Art {
618 art: "tulips",
619 position: [-72.0, -3.6],
620 size: Some([605.0, 783.0]),
621 }],
622 },
623 Template {
624 name: "Window Reflection",
625 art: &[Art {
626 art: "window-reflection",
627 position: [-18.0, -75.6],
628 size: Some([603.3, 780.7]),
629 }],
630 },
631 Template {
632 name: "Writing",
633 art: &[Art {
634 art: "writing",
635 position: [-54.0, -39.6],
636 size: Some([597.5, 773.2]),
637 }],
638 },
639];
640
641/// OneNote 2010's page colours in its View, Page Color menu order, with the names its
642/// tooltips give them; COLORREF, as the page XML reports each
643/// (`corpus/notebook-management/native/page-color`).
644pub const PAGE_COLORS: &[(&str, u32)] = &[
645 ("Blue", 0xfef5ed),
646 ("Red", 0xefeeff),
647 ("Lemon", 0xddfdfd),
648 ("Apple", 0xe5f9ec),
649 ("Blue Mist", 0xf3ede5),
650 ("Magenta", 0xf6edfb),
651 ("Yellow", 0xdffaff),
652 ("Green", 0xe5f0ec),
653 ("Silver", 0xede9e9),
654 ("Purple", 0xffe9f3),
655 ("Tan", 0xe7f4f9),
656 ("Cyan", 0xebefe5),
657 ("Purple Mist", 0xebe3e8),
658 ("Red Chalk", 0xdedeef),
659 ("Orange", 0xe1f2fb),
660 ("Teal", 0xf2f9d4),
661];
662
663/// OneNote 2010's View, Rule Lines presets in its menu order, in its default light blue
664/// with a red margin line
665/// (`corpus/rule-lines/native`).
666pub const RULE_LINES: &[(&str, RuleLines)] = &[
667 ("Narrow Ruled", ruled(0x3ebe_f8d2)),
668 ("College Ruled", ruled(0x3f28_f5c3)),
669 ("Standard Ruled", ruled(0x3f6b_851f)),
670 ("Wide Ruled", ruled(0x3fa6_6666)),
671 ("Small Grid", grid(0x3eaa_aaab)),
672 ("Medium Grid", grid(0x3f49_930c)),
673 ("Large Grid", grid(0x3f97_2e49)),
674 ("Very Large Grid", grid(0x3fc9_930c)),
675];
676
677const RULE_COLOR: u32 = 0xfdebca;
678
679/// Lines `spacing` apart, the bits of the half inches OneNote stores.
680const fn ruled(spacing: u32) -> RuleLines {
681 RuleLines {
682 spacing: f32::from_bits(spacing),
683 color: RULE_COLOR,
684 vertical: VerticalRule::Margin(0x5050ff),
685 }
686}
687
688const fn grid(spacing: u32) -> RuleLines {
689 RuleLines {
690 spacing: f32::from_bits(spacing),
691 color: RULE_COLOR,
692 vertical: VerticalRule::Grid {
693 spacing: f32::from_bits(spacing),
694 color: RULE_COLOR,
695 },
696 }
697}
698
699/// The template named `name`.
700pub fn find(name: &str) -> Option<&'static Template> {
701 TEMPLATES.iter().find(|template| template.name == name)
702}
703
704#[cfg(test)]
705mod tests {
706 use super::*;
707
708 #[test]
709 fn templates_have_unique_names_and_art() {
710 let mut names: Vec<_> = TEMPLATES.iter().map(|template| template.name).collect();
711 names.sort_unstable();
712 names.dedup();
713 assert_eq!(names.len(), TEMPLATES.len());
714 assert!(TEMPLATES.iter().all(|template| !template.art.is_empty()));
715 assert_eq!(find("Ivy").unwrap().art[0].art, "ivy");
716 }
717}