umya_spreadsheet/structs/
pattern_fill.rs

1// patternFill
2use super::Color;
3use super::EnumValue;
4use super::PatternValues;
5use crate::reader::driver::*;
6use crate::writer::driver::*;
7use md5::Digest;
8use quick_xml::events::{BytesStart, Event};
9use quick_xml::Reader;
10use quick_xml::Writer;
11use std::io::Cursor;
12
13#[derive(Default, Debug, Clone, PartialEq, PartialOrd)]
14pub struct PatternFill {
15    pub(crate) pattern_type: EnumValue<PatternValues>,
16    foreground_color: Option<Box<Color>>,
17    background_color: Option<Box<Color>>,
18}
19
20impl PatternFill {
21    #[inline]
22    pub fn get_pattern_type(&self) -> &PatternValues {
23        self.pattern_type.get_value()
24    }
25
26    #[inline]
27    pub fn set_pattern_type(&mut self, value: PatternValues) -> &mut Self {
28        self.pattern_type.set_value(value);
29        self
30    }
31
32    fn auto_set_pattern_type(&mut self) -> &mut Self {
33        if self.get_pattern_type() == &PatternValues::None {
34            if self.get_foreground_color().is_some() {
35                self.set_pattern_type(PatternValues::Solid);
36            }
37        } else if self.get_foreground_color().is_none() {
38            self.set_pattern_type(PatternValues::None);
39        }
40        self
41    }
42
43    #[inline]
44    pub fn get_foreground_color(&self) -> Option<&Color> {
45        self.foreground_color.as_deref()
46    }
47
48    #[inline]
49    pub fn get_foreground_color_mut(&mut self) -> &mut Color {
50        self.foreground_color
51            .get_or_insert(Box::new(Color::default()))
52    }
53
54    #[inline]
55    pub fn set_foreground_color(&mut self, value: Color) -> &mut Self {
56        self.foreground_color = Some(Box::new(value));
57        self.auto_set_pattern_type();
58        self
59    }
60
61    #[inline]
62    pub fn remove_foreground_color(&mut self) -> &mut Self {
63        self.foreground_color = None;
64        self
65    }
66
67    #[inline]
68    pub fn get_background_color(&self) -> Option<&Color> {
69        self.background_color.as_deref()
70    }
71
72    #[inline]
73    pub fn get_background_color_mut(&mut self) -> &mut Color {
74        self.background_color
75            .get_or_insert(Box::new(Color::default()))
76    }
77
78    #[inline]
79    pub fn set_background_color(&mut self, value: Color) -> &mut Self {
80        self.background_color = Some(Box::new(value));
81        self
82    }
83
84    #[inline]
85    pub fn remove_background_color(&mut self) -> &mut Self {
86        self.background_color = None;
87        self
88    }
89
90    pub(crate) fn get_hash_code(&self) -> String {
91        let pattern_type = self.pattern_type.get_value_string();
92        let foreground_color = self
93            .foreground_color
94            .as_ref()
95            .map_or("None".into(), |v| v.get_hash_code());
96        let background_color = self
97            .background_color
98            .as_ref()
99            .map_or("None".into(), |v| v.get_hash_code());
100        format!(
101            "{:x}",
102            md5::Md5::digest(format!(
103                "{}{}{}",
104                pattern_type, foreground_color, background_color
105            ))
106        )
107    }
108
109    // When opened in software such as Excel, it is visually blank.
110    pub(crate) fn is_visually_empty(&self) -> bool {
111        !(self.pattern_type.get_value() != &PatternValues::None
112            || self
113                .foreground_color
114                .as_ref()
115                .is_some_and(|x| !x.is_visually_empty())
116            || self
117                .background_color
118                .as_ref()
119                .is_some_and(|x| x.is_visually_empty()))
120    }
121
122    pub(crate) fn set_attributes<R: std::io::BufRead>(
123        &mut self,
124        reader: &mut Reader<R>,
125        e: &BytesStart,
126        empty_flag: bool,
127    ) {
128        set_string_from_xml!(self, e, pattern_type, "patternType");
129
130        if empty_flag {
131            return;
132        }
133
134        xml_read_loop!(
135            reader,
136            Event::Empty(ref e) => {
137                match e.name().into_inner() {
138                    b"fgColor" => {
139                        let mut obj = Color::default();
140                        obj.set_attributes(reader, e, true);
141                        self.set_foreground_color(obj);
142                    }
143                    b"bgColor" => {
144                        let mut obj = Color::default();
145                        obj.set_attributes(reader, e, true);
146                        self.set_background_color(obj);
147                    }
148                    _ => (),
149                }
150            },
151            Event::End(ref e) => {
152                if e.name().into_inner() == b"patternFill" {
153                    return
154                }
155            },
156            Event::Eof => panic!("Error: Could not find {} end element", "patternFill")
157        );
158    }
159
160    pub(crate) fn write_to(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
161        let empty_flag = self.foreground_color.is_none() && self.background_color.is_none();
162
163        // patternFill
164        let mut attributes: Vec<(&str, &str)> = Vec::new();
165        if self.pattern_type.has_value() {
166            attributes.push(("patternType", self.pattern_type.get_value_string()));
167        }
168        write_start_tag(writer, "patternFill", attributes, empty_flag);
169
170        if !empty_flag {
171            // fgColor
172            if let Some(v) = &self.foreground_color {
173                v.write_to_fg_color(writer);
174            }
175
176            // bgColor
177            if let Some(v) = &self.background_color {
178                v.write_to_bg_color(writer);
179            }
180
181            write_end_tag(writer, "patternFill");
182        }
183    }
184}