| 1 | //! This module contains an [`Alignment`] setting for cells on the [`Table`]. |
| 2 | //! |
| 3 | //! # Example |
| 4 | //! |
| 5 | #![cfg_attr (feature = "std" , doc = "```" )] |
| 6 | #![cfg_attr (not(feature = "std" ), doc = "```ignore" )] |
| 7 | //! # use tabled::{Table, settings::{Alignment, Modify, object::Rows}}; |
| 8 | //! # let data: Vec<&'static str> = Vec::new(); |
| 9 | //! let mut table = Table::new(&data); |
| 10 | //! table.with(Modify::new(Rows::single(0)).with(Alignment::center())); |
| 11 | //! ``` |
| 12 | //! |
| 13 | //! [`Table`]: crate::Table |
| 14 | |
| 15 | use crate::{ |
| 16 | grid::config::{ |
| 17 | AlignmentHorizontal, AlignmentVertical, CompactConfig, CompactMultilineConfig, Entity, |
| 18 | }, |
| 19 | settings::TableOption, |
| 20 | }; |
| 21 | |
| 22 | use AlignmentInner::*; |
| 23 | |
| 24 | #[cfg (feature = "std" )] |
| 25 | use crate::grid::config::ColoredConfig; |
| 26 | |
| 27 | /// Alignment represent a horizontal and vertical alignment setting for any cell on a [`Table`]. |
| 28 | /// |
| 29 | /// An alignment strategy can be set by [`AlignmentStrategy`]. |
| 30 | /// |
| 31 | /// # Example |
| 32 | /// |
| 33 | #[cfg_attr (feature = "std" , doc = "```" )] |
| 34 | #[cfg_attr (not(feature = "std" ), doc = "```ignore" )] |
| 35 | /// use tabled::{ |
| 36 | /// Table, |
| 37 | /// settings::{ |
| 38 | /// formatting::AlignmentStrategy, |
| 39 | /// object::Segment, Alignment, Modify, Style, |
| 40 | /// } |
| 41 | /// }; |
| 42 | /// |
| 43 | /// let data = [ |
| 44 | /// ["1" , "2" , "3" ], |
| 45 | /// ["Some \nMulti \nLine \nText" , "and a line" , "here" ], |
| 46 | /// ["4" , "5" , "6" ], |
| 47 | /// ]; |
| 48 | /// |
| 49 | /// let mut table = Table::new(&data); |
| 50 | /// table |
| 51 | /// .with(Style::modern()) |
| 52 | /// .with( |
| 53 | /// Modify::new(Segment::all()) |
| 54 | /// .with(Alignment::right()) |
| 55 | /// .with(Alignment::center()) |
| 56 | /// .with(AlignmentStrategy::PerCell) |
| 57 | /// ); |
| 58 | /// |
| 59 | /// assert_eq!( |
| 60 | /// table.to_string(), |
| 61 | /// concat!( |
| 62 | /// "┌───────┬────────────┬──────┐ \n" , |
| 63 | /// "│ 0 │ 1 │ 2 │ \n" , |
| 64 | /// "├───────┼────────────┼──────┤ \n" , |
| 65 | /// "│ 1 │ 2 │ 3 │ \n" , |
| 66 | /// "├───────┼────────────┼──────┤ \n" , |
| 67 | /// "│ Some │ and a line │ here │ \n" , |
| 68 | /// "│ Multi │ │ │ \n" , |
| 69 | /// "│ Line │ │ │ \n" , |
| 70 | /// "│ Text │ │ │ \n" , |
| 71 | /// "├───────┼────────────┼──────┤ \n" , |
| 72 | /// "│ 4 │ 5 │ 6 │ \n" , |
| 73 | /// "└───────┴────────────┴──────┘" , |
| 74 | /// ), |
| 75 | /// ) |
| 76 | /// ``` |
| 77 | /// |
| 78 | /// [`Table`]: crate::Table |
| 79 | /// [`AlignmentStrategy`]: crate::settings::formatting::AlignmentStrategy |
| 80 | #[derive (Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] |
| 81 | pub struct Alignment { |
| 82 | inner: AlignmentInner, |
| 83 | } |
| 84 | |
| 85 | #[derive (Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] |
| 86 | enum AlignmentInner { |
| 87 | /// A horizontal alignment. |
| 88 | Horizontal(AlignmentHorizontal), |
| 89 | /// A vertical alignment. |
| 90 | Vertical(AlignmentVertical), |
| 91 | } |
| 92 | |
| 93 | impl Alignment { |
| 94 | /// Left constructs a horizontal alignment to [`AlignmentHorizontal::Left`] |
| 95 | pub const fn left() -> Self { |
| 96 | Self::horizontal(AlignmentHorizontal::Left) |
| 97 | } |
| 98 | |
| 99 | /// Right constructs a horizontal alignment to [`AlignmentHorizontal::Right`] |
| 100 | /// |
| 101 | /// ## Notice |
| 102 | /// |
| 103 | /// When you use [`MinWidth`] the alignment might not work as you expected. |
| 104 | /// You could try to apply [`TrimStrategy`] which may help. |
| 105 | /// |
| 106 | /// [`MinWidth`]: crate::settings::width::MinWidth |
| 107 | /// [`TrimStrategy`]: crate::settings::formatting::TrimStrategy |
| 108 | pub const fn right() -> Self { |
| 109 | Self::horizontal(AlignmentHorizontal::Right) |
| 110 | } |
| 111 | |
| 112 | /// Center constructs a horizontal alignment to [`AlignmentHorizontal::Center`] |
| 113 | /// |
| 114 | /// ## Notice |
| 115 | /// |
| 116 | /// When you use [`MinWidth`] the alignment might not work as you expected. |
| 117 | /// You could try to apply [`TrimStrategy`] which may help. |
| 118 | /// |
| 119 | /// [`MinWidth`]: crate::settings::width::MinWidth |
| 120 | /// [`TrimStrategy`]: crate::settings::formatting::TrimStrategy |
| 121 | pub const fn center() -> Self { |
| 122 | Self::horizontal(AlignmentHorizontal::Center) |
| 123 | } |
| 124 | |
| 125 | /// Top constructs a vertical alignment to [`AlignmentVertical::Top`] |
| 126 | pub const fn top() -> Self { |
| 127 | Self::vertical(AlignmentVertical::Top) |
| 128 | } |
| 129 | |
| 130 | /// Bottom constructs a vertical alignment to [`AlignmentVertical::Bottom`] |
| 131 | pub const fn bottom() -> Self { |
| 132 | Self::vertical(AlignmentVertical::Bottom) |
| 133 | } |
| 134 | |
| 135 | /// `Center_vertical` constructs a vertical alignment to [`AlignmentVertical::Center`] |
| 136 | pub const fn center_vertical() -> Self { |
| 137 | Self::vertical(AlignmentVertical::Center) |
| 138 | } |
| 139 | |
| 140 | /// Returns an alignment with the given horizontal alignment. |
| 141 | const fn horizontal(alignment: AlignmentHorizontal) -> Self { |
| 142 | Self::new(Horizontal(alignment)) |
| 143 | } |
| 144 | |
| 145 | /// Returns an alignment with the given vertical alignment. |
| 146 | const fn vertical(alignment: AlignmentVertical) -> Self { |
| 147 | Self::new(Vertical(alignment)) |
| 148 | } |
| 149 | |
| 150 | const fn new(inner: AlignmentInner) -> Self { |
| 151 | Self { inner } |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | #[cfg (feature = "std" )] |
| 156 | impl<R> crate::settings::CellOption<R, ColoredConfig> for Alignment { |
| 157 | fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) { |
| 158 | match self.inner { |
| 159 | Horizontal(a: AlignmentHorizontal) => cfg.set_alignment_horizontal(entity, alignment:a), |
| 160 | Vertical(a: AlignmentVertical) => cfg.set_alignment_vertical(entity, alignment:a), |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | #[cfg (feature = "std" )] |
| 166 | impl<R, D> TableOption<R, ColoredConfig, D> for Alignment { |
| 167 | fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { |
| 168 | match self.inner { |
| 169 | Horizontal(a: AlignmentHorizontal) => cfg.set_alignment_horizontal(Entity::Global, alignment:a), |
| 170 | Vertical(a: AlignmentVertical) => cfg.set_alignment_vertical(Entity::Global, alignment:a), |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | fn hint_change(&self) -> Option<Entity> { |
| 175 | None |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | impl<R, D> TableOption<R, CompactConfig, D> for Alignment { |
| 180 | fn change(self, _: &mut R, cfg: &mut CompactConfig, _: &mut D) { |
| 181 | if let Horizontal(a: AlignmentHorizontal) = self.inner { |
| 182 | *cfg = cfg.set_alignment_horizontal(alignment:a) |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | fn hint_change(&self) -> Option<Entity> { |
| 187 | None |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | impl<R, D> TableOption<R, CompactMultilineConfig, D> for Alignment { |
| 192 | fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) { |
| 193 | match self.inner { |
| 194 | Horizontal(a: AlignmentHorizontal) => cfg.set_alignment_horizontal(alignment:a), |
| 195 | Vertical(a: AlignmentVertical) => cfg.set_alignment_vertical(alignment:a), |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | fn hint_change(&self) -> Option<Entity> { |
| 200 | None |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | impl From<AlignmentHorizontal> for Alignment { |
| 205 | fn from(value: AlignmentHorizontal) -> Self { |
| 206 | match value { |
| 207 | AlignmentHorizontal::Center => Self::center(), |
| 208 | AlignmentHorizontal::Left => Self::left(), |
| 209 | AlignmentHorizontal::Right => Self::right(), |
| 210 | } |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | impl From<AlignmentVertical> for Alignment { |
| 215 | fn from(value: AlignmentVertical) -> Self { |
| 216 | match value { |
| 217 | AlignmentVertical::Center => Self::center_vertical(), |
| 218 | AlignmentVertical::Top => Self::top(), |
| 219 | AlignmentVertical::Bottom => Self::bottom(), |
| 220 | } |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | impl From<Alignment> for Option<AlignmentHorizontal> { |
| 225 | fn from(value: Alignment) -> Self { |
| 226 | match value.inner { |
| 227 | Horizontal(alignment: AlignmentHorizontal) => Some(alignment), |
| 228 | Vertical(_) => None, |
| 229 | } |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | impl From<Alignment> for Option<AlignmentVertical> { |
| 234 | fn from(value: Alignment) -> Self { |
| 235 | match value.inner { |
| 236 | Vertical(alignment: AlignmentVertical) => Some(alignment), |
| 237 | Horizontal(_) => None, |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | |