dental_notation/display/
cli.rs1use super::JawKind;
2use crate::display::ToothDisplay;
3use crate::{NotationKind, QuadrantKind, Tooth, ToothType};
4use alloc::format;
5use alloc::string::String;
6use owo_colors::{OwoColorize, Style};
7
8pub struct ToothCliFormatter;
10
11impl ToothCliFormatter {
12 fn format_tooth(
13 tooth: &Tooth,
14 notation: &NotationKind,
15 selected_value: &Option<Tooth>,
16 ) -> String {
17 let tooth_label = tooth.to(notation);
18
19 let mut style = Style::new();
20 style = match &tooth.get_type() {
21 ToothType::Canine => style.yellow(),
22 ToothType::Incisor => style.green(),
23 ToothType::Premolar => style.cyan(),
24 ToothType::Molar => style.blue(),
25 };
26
27 if let Some(t) = selected_value {
28 if t == tooth {
29 style = style.reversed();
30 }
31 }
32 format!(" {}", tooth_label.style(style))
33 }
34
35 fn format_quadrant(
36 notation: &NotationKind,
37
38 permanent: bool,
39 quadrant: QuadrantKind,
40 selected_value: &Option<Tooth>,
41 ) -> String {
42 let max = Tooth::quadrant_max(permanent);
43 let format_tooth = |i| {
44 let tooth = Tooth::new(i, quadrant, permanent).unwrap();
45 ToothCliFormatter::format_tooth(&tooth, notation, selected_value)
46 };
47 if quadrant == QuadrantKind::TopLeft || quadrant == QuadrantKind::BottomLeft {
48 (1..=max).rev().map(format_tooth).collect()
49 } else {
50 (1..=max).map(format_tooth).collect()
51 }
52 }
53
54 fn format_jaw(
55 notation: &NotationKind,
56 permanent: bool,
57 jaw: JawKind,
58 selected_value: &Option<Tooth>,
59 ) -> String {
60 let (quadrant_1, quadrant_2) = match jaw {
61 JawKind::Top => (QuadrantKind::TopLeft, QuadrantKind::TopRight),
62 JawKind::Bottom => (QuadrantKind::BottomLeft, QuadrantKind::BottomRight),
63 };
64 format!(
65 " {} |{}",
66 ToothCliFormatter::format_quadrant(notation, permanent, quadrant_1, selected_value),
67 ToothCliFormatter::format_quadrant(notation, permanent, quadrant_2, selected_value)
68 )
69 }
70
71 fn calculate_separator_len(notation: &NotationKind, permanent: bool) -> u8 {
72 let item_count = Tooth::quadrant_max(permanent);
73 let item_width = match (notation, permanent) {
74 (NotationKind::Iso, _) => 2,
75 (NotationKind::Uns, true) => 2,
76 (NotationKind::Uns, false) => 1,
77 (NotationKind::Alphanumeric, _) => 3,
78 };
79 (item_width + 1) * (item_count * 2 + 1)
80 }
81}
82
83impl ToothDisplay for ToothCliFormatter {
84 fn format(notation: &NotationKind, permanent: bool, selected_value: &Option<Tooth>) -> String {
85 let jaw_len = ToothCliFormatter::calculate_separator_len(notation, permanent);
86 let mut result = String::with_capacity((jaw_len * 4).into());
87 result.push_str(&ToothCliFormatter::format_jaw(
88 notation,
89 permanent,
90 JawKind::Top,
91 selected_value,
92 ));
93 result.push_str("\nR ");
94 result.push_str(&"-".repeat(jaw_len.into()));
95 result.push_str(" L\n");
96 result.push_str(&ToothCliFormatter::format_jaw(
97 notation,
98 permanent,
99 JawKind::Bottom,
100 selected_value,
101 ));
102
103 result
104 }
105}