Skip to main content

edit_xlsx/api/format/
border.rs

1//!
2//! This module contains the [`FormatBorder`] struct,
3//! which used to edit the border style of the [`Cell`] in each direction.
4//!
5//! # Examples
6//!
7//! Wrap cells
8//! ```
9//! use std::cell;
10//! use edit_xlsx::{Cell, Format, FormatBorder, FormatBorderElement, FormatBorderType, FormatColor, Workbook, Write};
11//! let format = Format::default().set_border(FormatBorderType::Thin);
12//! // Or use
13//! // let mut format = Format::default();
14//! // let mut format_border = FormatBorder::default();
15//! // let format_border_element = FormatBorderElement::from_border_type(&FormatBorderType::Thin);
16//! // format_border.left = format_border_element;
17//! // format_border.right = format_border_element;
18//! // format_border.top = format_border_element;
19//! // format_border.bottom = format_border_element;
20//! // format.border = format_border;
21//! let mut workbook = Workbook::from_path("./examples/xlsx/accounting.xlsx").unwrap();
22//! let worksheet = workbook.get_worksheet_mut_by_name("worksheet").unwrap();
23//! let mut cell: Cell<String> = Cell::default();
24//! cell.format = Some(format);
25//! for row in 6..=15 {
26//!     for col in 3..=12 {
27//!         worksheet.write_cell((row, col), &cell).unwrap()
28//!     }
29//! }
30//! workbook.save_as("./examples/border_wrap_cells.xlsx").unwrap();
31//! ```
32//!
33//! Use diagonal to creat a table
34//! ```
35//! use std::cell;
36//! use edit_xlsx::{Cell, Format, FormatBorder, FormatBorderElement, FormatBorderType, FormatColor, Read, Workbook, Write};
37//! let mut workbook = Workbook::new();
38//! let worksheet = workbook.get_worksheet_mut(1).unwrap();
39//! let mut cell: Cell<String> = Cell::default();
40//! let mut format = Format::default();
41//! format.border.diagonal = FormatBorderElement::from_border_type(&FormatBorderType::Thin);
42//! cell.format = Some(format);
43//! worksheet.write_cell("A1", &cell).unwrap();
44//! // todo bug fix
45//! worksheet.write_column("A2", &[1, 2, 3]).unwrap();
46//! worksheet.write_column("B1", &["Region", "East", "West", "North"]).unwrap();
47//! worksheet.write_column("C1", &["Sales Rep", "Tom", "Fred", "Amy"]).unwrap();
48//! worksheet.write_column("C1", &["Product", "Apple", "Grape", "Pear"]).unwrap();
49//! workbook.save_as("./examples/border_diagonal_cell.xlsx").unwrap();
50//! ```
51//!
52//! Wrap merged cells
53//! ```
54//! use std::cell;
55//! use edit_xlsx::{Cell, Format, FormatBorder, FormatBorderElement, FormatBorderType, FormatColor, Read, Workbook, Write};
56//! let mut workbook = Workbook::from_path("./examples/xlsx/accounting.xlsx").unwrap();
57//! let worksheet = workbook.get_worksheet_mut_by_name("worksheet").unwrap();
58//! for row in 18..=21 {
59//!     for col in 2..=11 {
60//!         let mut cell: Cell<String> = worksheet.read_cell((row, col)).unwrap();
61//!         cell.format = match cell.format.take() {
62//!             None => None,
63//!             Some(mut format) => Some(format.set_border(FormatBorderType::Double)),
64//!         };
65//!         worksheet.write_cell((row, col), &cell).unwrap()
66//!     }
67//! }
68//! workbook.save_as("./examples/border_wrap_merged_cells.xlsx").unwrap();
69//! ```
70//!
71
72use std::fmt::{Display, Formatter};
73use crate::{Cell, FormatColor};
74use crate::xml::common::FromFormat;
75use crate::xml::style::border::{Border, BorderElement};
76use crate::xml::style::color::Color;
77
78///
79/// [`FormatBorder`] is used to edit the border style of the [`Cell`] in each direction.
80/// # Fields
81/// | field        | type        | meaning                                                      |
82/// | ------------ | ----------- | ------------------------------------------------------------ |
83/// | `left`     | [`FormatBorderElement`] | The [`Cell`]'s left border style               |
84/// | `right`    | [`FormatBorderElement`] | The [`Cell`]'s right border style               |
85/// | `top`      | [`FormatBorderElement`] | The [`Cell`]'s top border style               |
86/// | `bottom`   | [`FormatBorderElement`] | The [`Cell`]'s bottom border style               |
87/// | `diagonal` | [`FormatBorderElement`] | The [`Cell`]'s diagonal border style               |
88///
89#[derive(Clone, Debug, PartialEq, Default)]
90pub struct FormatBorder {
91    pub left: FormatBorderElement,
92    pub right: FormatBorderElement,
93    pub top: FormatBorderElement,
94    pub bottom: FormatBorderElement,
95    pub diagonal: FormatBorderElement,
96}
97
98///
99/// [`FormatBorderElement`] is used to edit one of the direction of the [`Cell`]'s border style.
100/// # Fields
101/// | field        | type        | meaning                                                      |
102/// | ------------ | ----------- | ------------------------------------------------------------ |
103/// | `border_type`     | [`FormatBorderType`] | Type of the border               |
104/// | `color`    | [`FormatColor`] | Color of the border               |
105///
106#[derive(Clone, Debug, PartialEq, Copy, Default)]
107pub struct FormatBorderElement {
108    pub border_type: FormatBorderType,
109    pub color: FormatColor,
110}
111
112impl FormatBorderElement {
113    pub fn new(border_type: &FormatBorderType, color: &FormatColor) -> FormatBorderElement {
114        FormatBorderElement {
115            border_type: *border_type,
116            color: *color,
117        }
118    }
119
120    ///
121    /// Create a new [`FormatBorderElement`] based on the border color,
122    /// the border type defaults to [`FormatBorderType::Thin`]
123    ///
124    pub fn from_color(color: &FormatColor) -> FormatBorderElement {
125        FormatBorderElement {
126            border_type: FormatBorderType::Thin,
127            color: *color,
128        }
129    }
130
131    ///
132    /// Create a new [`FormatBorderElement`] based on the border type,
133    /// the border color defaults to [`FormatColor::Default`]
134    ///
135    pub fn from_border_type(border_type: &FormatBorderType) -> FormatBorderElement {
136        FormatBorderElement {
137            border_type: *border_type,
138            color: FormatColor::default(),
139        }
140    }
141}
142
143///
144/// Enumeration of different border type
145///
146/// # Fields:
147/// | unit | meaning |
148/// | ---- | ---- |
149/// | `None` | Default, No border |
150/// | `Thin` | Thin line |
151/// | `Medium` | Medium line |
152/// | `Dashed` | Dashed line |
153/// | `Dotted` | Dotted line |
154/// | `Thick` | Thick line |
155/// | `Double` | Double line |
156/// | `Hair` | Hairline |
157/// | `MediumDashed` | Medium dashed line |
158/// | `DashDot` | Dash-dot line |
159/// | `MediumDashDot` | Medium dash-dot line |
160/// | `DashDotDot` | Dash-dot-dot line |
161/// | `MediumDashDotDot` | Medium dash-dot-dot line |
162/// | `SlantDashDot` | Slanted dash-dot-dot line |
163///
164#[derive(Copy, Clone, Debug, PartialEq)]
165pub enum FormatBorderType {
166    /// Default, No border
167    None,
168    /// Thin line
169    Thin,
170    /// Medium line
171    Medium,
172    /// Dashed line
173    Dashed,
174    /// Dotted line
175    Dotted,
176    /// Thick line
177    Thick,
178    /// Double line
179    Double,
180    /// Hairline
181    Hair,
182    /// Medium dashed line
183    MediumDashed,
184    /// Dash-dot line
185    DashDot,
186    /// Medium dash-dot line
187    MediumDashDot,
188    /// Dash-dot-dot line
189    DashDotDot,
190    /// Medium dash-dot-dot line
191    MediumDashDotDot,
192    /// Slanted dash-dot-dot line
193    SlantDashDot,
194}
195
196impl Display for FormatBorderType {
197    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
198        f.write_str(self.to_str())
199    }
200}
201
202impl Default for FormatBorderType {
203    fn default() -> FormatBorderType {
204        FormatBorderType::None
205    }
206}
207
208impl FormatBorderType {
209    pub(crate) fn to_str(&self) -> &str {
210        match self {
211            FormatBorderType::None => "none",
212            FormatBorderType::Thin => "thin",
213            FormatBorderType::Medium => "medium",
214            FormatBorderType::Dashed => "dashed",
215            FormatBorderType::Dotted => "dotted",
216            FormatBorderType::Thick => "thick",
217            FormatBorderType::Double => "double",
218            FormatBorderType::Hair => "hair",
219            FormatBorderType::MediumDashed => "mediumDashed",
220            FormatBorderType::DashDot => "dashDot",
221            FormatBorderType::MediumDashDot => "mediumDashDot",
222            FormatBorderType::DashDotDot => "dashDotDot",
223            FormatBorderType::MediumDashDotDot => "mediumDashDotDot",
224            FormatBorderType::SlantDashDot => "slantDashDot",
225        }
226    }
227
228    pub(crate) fn from_str(border_str: &str) -> Self {
229        match border_str {
230            "thin" => FormatBorderType::Thin,
231            "medium" => FormatBorderType::Medium,
232            "dashed" => FormatBorderType::Dashed,
233            "dotted" => FormatBorderType::Dotted,
234            "thick" => FormatBorderType::Thick,
235            "double" => FormatBorderType::Double,
236            "hair" => FormatBorderType::Hair,
237            "mediumDashed" => FormatBorderType::MediumDashed,
238            "dashDot" => FormatBorderType::DashDot,
239            "mediumDashDot" => FormatBorderType::MediumDashDot,
240            "dashDotDot" => FormatBorderType::DashDotDot,
241            "mediumDashDotDot" => FormatBorderType::MediumDashDotDot,
242            "slantDashDot" => FormatBorderType::SlantDashDot,
243            _ => FormatBorderType::None,
244        }
245    }
246}
247
248impl FromFormat<FormatBorder> for Border {
249    fn set_attrs_by_format(&mut self, format: &FormatBorder) {
250        self.left = Some(BorderElement::from_format(&format.left));
251        self.right = Some(BorderElement::from_format(&format.right));
252        self.top = Some(BorderElement::from_format(&format.top));
253        self.bottom = Some(BorderElement::from_format(&format.bottom));
254        self.diagonal = Some(BorderElement::from_format(&format.diagonal));
255    }
256
257    fn set_format(&self, format: &mut FormatBorder) {
258        format.left = {
259            if let Some(left) = &self.left {
260                left.get_format()
261            } else {
262                FormatBorderElement::default()
263            }
264        };
265        format.right = {
266            if let Some(right) = &self.right {
267                right.get_format()
268            } else {
269                FormatBorderElement::default()
270            }
271        };
272        format.top = {
273            if let Some(top) = &self.top {
274                top.get_format()
275            } else {
276                FormatBorderElement::default()
277            }
278        };
279        format.bottom = {
280            if let Some(bottom) = &self.bottom {
281                bottom.get_format()
282            } else {
283                FormatBorderElement::default()
284            }
285        };
286        format.diagonal = {
287            if let Some(diagonal) = &self.diagonal {
288                diagonal.get_format()
289            } else {
290                FormatBorderElement::default()
291            }
292        }
293    }
294}
295
296impl FromFormat<FormatBorderElement> for BorderElement {
297    fn set_attrs_by_format(&mut self, format: &FormatBorderElement) {
298        self.style = Some(String::from(format.border_type.to_str()));
299        self.color = Some(Color::from_format(&format.color));
300    }
301
302    fn set_format(&self, format: &mut FormatBorderElement) {
303        // format.color = self.color.unwrap_or_default();
304        match &self.style {
305            None => format.border_type = FormatBorderType::default(),
306            Some(style) => format.border_type = FormatBorderType::from_str(style)
307        }
308    }
309}