1mod color;
7mod theme;
8pub use color::{Color, ColorDepth};
9pub use theme::{Theme, ThemeBuilder};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum Breakpoint {
17 Xs,
19 Sm,
21 Md,
23 Lg,
25 Xl,
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub enum Border {
36 Single,
38 Double,
40 Rounded,
42 Thick,
44 Dashed,
46 DashedThick,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
55pub struct BorderChars {
56 pub tl: char,
58 pub tr: char,
60 pub bl: char,
62 pub br: char,
64 pub h: char,
66 pub v: char,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
72#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
73pub struct BorderSides {
74 pub top: bool,
75 pub right: bool,
76 pub bottom: bool,
77 pub left: bool,
78}
79
80impl BorderSides {
81 pub const fn all() -> Self {
82 Self {
83 top: true,
84 right: true,
85 bottom: true,
86 left: true,
87 }
88 }
89
90 pub const fn none() -> Self {
91 Self {
92 top: false,
93 right: false,
94 bottom: false,
95 left: false,
96 }
97 }
98
99 pub const fn horizontal() -> Self {
100 Self {
101 top: true,
102 right: false,
103 bottom: true,
104 left: false,
105 }
106 }
107
108 pub const fn vertical() -> Self {
109 Self {
110 top: false,
111 right: true,
112 bottom: false,
113 left: true,
114 }
115 }
116
117 pub fn has_horizontal(&self) -> bool {
118 self.top || self.bottom
119 }
120
121 pub fn has_vertical(&self) -> bool {
122 self.left || self.right
123 }
124}
125
126impl Default for BorderSides {
127 fn default() -> Self {
128 Self::all()
129 }
130}
131
132impl Border {
133 pub const fn chars(self) -> BorderChars {
135 match self {
136 Self::Single => BorderChars {
137 tl: '┌',
138 tr: '┐',
139 bl: '└',
140 br: '┘',
141 h: '─',
142 v: '│',
143 },
144 Self::Double => BorderChars {
145 tl: '╔',
146 tr: '╗',
147 bl: '╚',
148 br: '╝',
149 h: '═',
150 v: '║',
151 },
152 Self::Rounded => BorderChars {
153 tl: '╭',
154 tr: '╮',
155 bl: '╰',
156 br: '╯',
157 h: '─',
158 v: '│',
159 },
160 Self::Thick => BorderChars {
161 tl: '┏',
162 tr: '┓',
163 bl: '┗',
164 br: '┛',
165 h: '━',
166 v: '┃',
167 },
168 Self::Dashed => BorderChars {
169 tl: '┌',
170 tr: '┐',
171 bl: '└',
172 br: '┘',
173 h: '┄',
174 v: '┆',
175 },
176 Self::DashedThick => BorderChars {
177 tl: '┏',
178 tr: '┓',
179 bl: '┗',
180 br: '┛',
181 h: '┅',
182 v: '┇',
183 },
184 }
185 }
186}
187
188#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
193#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
194pub struct Padding {
195 pub top: u32,
197 pub right: u32,
199 pub bottom: u32,
201 pub left: u32,
203}
204
205impl Padding {
206 pub const fn all(v: u32) -> Self {
208 Self::new(v, v, v, v)
209 }
210
211 pub const fn xy(x: u32, y: u32) -> Self {
213 Self::new(y, x, y, x)
214 }
215
216 pub const fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
218 Self {
219 top,
220 right,
221 bottom,
222 left,
223 }
224 }
225
226 pub const fn horizontal(self) -> u32 {
228 self.left + self.right
229 }
230
231 pub const fn vertical(self) -> u32 {
233 self.top + self.bottom
234 }
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
242#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
243pub struct Margin {
244 pub top: u32,
246 pub right: u32,
248 pub bottom: u32,
250 pub left: u32,
252}
253
254impl Margin {
255 pub const fn all(v: u32) -> Self {
257 Self::new(v, v, v, v)
258 }
259
260 pub const fn xy(x: u32, y: u32) -> Self {
262 Self::new(y, x, y, x)
263 }
264
265 pub const fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
267 Self {
268 top,
269 right,
270 bottom,
271 left,
272 }
273 }
274
275 pub const fn horizontal(self) -> u32 {
277 self.left + self.right
278 }
279
280 pub const fn vertical(self) -> u32 {
282 self.top + self.bottom
283 }
284}
285
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
299#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
300#[must_use = "configure constraints using the returned value"]
301pub struct Constraints {
302 pub min_width: Option<u32>,
304 pub max_width: Option<u32>,
306 pub min_height: Option<u32>,
308 pub max_height: Option<u32>,
310 pub width_pct: Option<u8>,
312 pub height_pct: Option<u8>,
314}
315
316impl Constraints {
317 pub const fn min_w(mut self, min_width: u32) -> Self {
319 self.min_width = Some(min_width);
320 self
321 }
322
323 pub const fn max_w(mut self, max_width: u32) -> Self {
325 self.max_width = Some(max_width);
326 self
327 }
328
329 pub const fn min_h(mut self, min_height: u32) -> Self {
331 self.min_height = Some(min_height);
332 self
333 }
334
335 pub const fn max_h(mut self, max_height: u32) -> Self {
337 self.max_height = Some(max_height);
338 self
339 }
340
341 pub const fn w_pct(mut self, pct: u8) -> Self {
343 self.width_pct = Some(pct);
344 self
345 }
346
347 pub const fn h_pct(mut self, pct: u8) -> Self {
349 self.height_pct = Some(pct);
350 self
351 }
352}
353
354#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
360#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
361pub enum Align {
362 #[default]
364 Start,
365 Center,
367 End,
369}
370
371#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
380#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
381pub enum Justify {
382 #[default]
384 Start,
385 Center,
387 End,
389 SpaceBetween,
391 SpaceAround,
393 SpaceEvenly,
395}
396
397#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
402#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
403#[cfg_attr(feature = "serde", serde(transparent))]
404pub struct Modifiers(pub u8);
405
406impl Modifiers {
407 pub const NONE: Self = Self(0);
409 pub const BOLD: Self = Self(1 << 0);
411 pub const DIM: Self = Self(1 << 1);
413 pub const ITALIC: Self = Self(1 << 2);
415 pub const UNDERLINE: Self = Self(1 << 3);
417 pub const REVERSED: Self = Self(1 << 4);
419 pub const STRIKETHROUGH: Self = Self(1 << 5);
421
422 #[inline]
424 pub fn contains(self, other: Self) -> bool {
425 (self.0 & other.0) == other.0
426 }
427
428 #[inline]
430 pub fn insert(&mut self, other: Self) {
431 self.0 |= other.0;
432 }
433
434 #[inline]
436 pub fn is_empty(self) -> bool {
437 self.0 == 0
438 }
439}
440
441impl std::ops::BitOr for Modifiers {
442 type Output = Self;
443 #[inline]
444 fn bitor(self, rhs: Self) -> Self {
445 Self(self.0 | rhs.0)
446 }
447}
448
449impl std::ops::BitOrAssign for Modifiers {
450 #[inline]
451 fn bitor_assign(&mut self, rhs: Self) {
452 self.0 |= rhs.0;
453 }
454}
455
456#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
470#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
471#[must_use = "build and pass the returned Style value"]
472pub struct Style {
473 pub fg: Option<Color>,
475 pub bg: Option<Color>,
477 pub modifiers: Modifiers,
479}
480
481impl Style {
482 pub const fn new() -> Self {
484 Self {
485 fg: None,
486 bg: None,
487 modifiers: Modifiers::NONE,
488 }
489 }
490
491 pub const fn fg(mut self, color: Color) -> Self {
493 self.fg = Some(color);
494 self
495 }
496
497 pub const fn bg(mut self, color: Color) -> Self {
499 self.bg = Some(color);
500 self
501 }
502
503 pub fn bold(mut self) -> Self {
505 self.modifiers |= Modifiers::BOLD;
506 self
507 }
508
509 pub fn dim(mut self) -> Self {
511 self.modifiers |= Modifiers::DIM;
512 self
513 }
514
515 pub fn italic(mut self) -> Self {
517 self.modifiers |= Modifiers::ITALIC;
518 self
519 }
520
521 pub fn underline(mut self) -> Self {
523 self.modifiers |= Modifiers::UNDERLINE;
524 self
525 }
526
527 pub fn reversed(mut self) -> Self {
529 self.modifiers |= Modifiers::REVERSED;
530 self
531 }
532
533 pub fn strikethrough(mut self) -> Self {
535 self.modifiers |= Modifiers::STRIKETHROUGH;
536 self
537 }
538}
539
540#[derive(Debug, Clone, Copy, Default)]
564pub struct ContainerStyle {
565 pub border: Option<Border>,
566 pub border_sides: Option<BorderSides>,
567 pub border_style: Option<Style>,
568 pub bg: Option<Color>,
569 pub text_color: Option<Color>,
570 pub dark_bg: Option<Color>,
571 pub dark_border_style: Option<Style>,
572 pub padding: Option<Padding>,
573 pub margin: Option<Margin>,
574 pub gap: Option<u32>,
575 pub row_gap: Option<u32>,
576 pub col_gap: Option<u32>,
577 pub grow: Option<u16>,
578 pub align: Option<Align>,
579 pub align_self: Option<Align>,
580 pub justify: Option<Justify>,
581 pub w: Option<u32>,
582 pub h: Option<u32>,
583 pub min_w: Option<u32>,
584 pub max_w: Option<u32>,
585 pub min_h: Option<u32>,
586 pub max_h: Option<u32>,
587 pub w_pct: Option<u8>,
588 pub h_pct: Option<u8>,
589}
590
591impl ContainerStyle {
592 pub const fn new() -> Self {
594 Self {
595 border: None,
596 border_sides: None,
597 border_style: None,
598 bg: None,
599 text_color: None,
600 dark_bg: None,
601 dark_border_style: None,
602 padding: None,
603 margin: None,
604 gap: None,
605 row_gap: None,
606 col_gap: None,
607 grow: None,
608 align: None,
609 align_self: None,
610 justify: None,
611 w: None,
612 h: None,
613 min_w: None,
614 max_w: None,
615 min_h: None,
616 max_h: None,
617 w_pct: None,
618 h_pct: None,
619 }
620 }
621
622 pub const fn border(mut self, border: Border) -> Self {
624 self.border = Some(border);
625 self
626 }
627
628 pub const fn border_sides(mut self, sides: BorderSides) -> Self {
630 self.border_sides = Some(sides);
631 self
632 }
633
634 pub const fn bg(mut self, color: Color) -> Self {
636 self.bg = Some(color);
637 self
638 }
639
640 pub const fn text_color(mut self, color: Color) -> Self {
642 self.text_color = Some(color);
643 self
644 }
645
646 pub const fn dark_bg(mut self, color: Color) -> Self {
648 self.dark_bg = Some(color);
649 self
650 }
651
652 pub const fn p(mut self, value: u32) -> Self {
654 self.padding = Some(Padding {
655 top: value,
656 bottom: value,
657 left: value,
658 right: value,
659 });
660 self
661 }
662
663 pub const fn px(mut self, value: u32) -> Self {
665 let p = match self.padding {
666 Some(p) => Padding {
667 left: value,
668 right: value,
669 ..p
670 },
671 None => Padding {
672 top: 0,
673 bottom: 0,
674 left: value,
675 right: value,
676 },
677 };
678 self.padding = Some(p);
679 self
680 }
681
682 pub const fn py(mut self, value: u32) -> Self {
684 let p = match self.padding {
685 Some(p) => Padding {
686 top: value,
687 bottom: value,
688 ..p
689 },
690 None => Padding {
691 top: value,
692 bottom: value,
693 left: 0,
694 right: 0,
695 },
696 };
697 self.padding = Some(p);
698 self
699 }
700
701 pub const fn m(mut self, value: u32) -> Self {
703 self.margin = Some(Margin {
704 top: value,
705 bottom: value,
706 left: value,
707 right: value,
708 });
709 self
710 }
711
712 pub const fn gap(mut self, value: u32) -> Self {
714 self.gap = Some(value);
715 self
716 }
717
718 pub const fn row_gap(mut self, value: u32) -> Self {
720 self.row_gap = Some(value);
721 self
722 }
723
724 pub const fn col_gap(mut self, value: u32) -> Self {
726 self.col_gap = Some(value);
727 self
728 }
729
730 pub const fn grow(mut self, value: u16) -> Self {
732 self.grow = Some(value);
733 self
734 }
735
736 pub const fn w(mut self, value: u32) -> Self {
738 self.w = Some(value);
739 self
740 }
741
742 pub const fn h(mut self, value: u32) -> Self {
744 self.h = Some(value);
745 self
746 }
747
748 pub const fn min_w(mut self, value: u32) -> Self {
750 self.min_w = Some(value);
751 self
752 }
753
754 pub const fn max_w(mut self, value: u32) -> Self {
756 self.max_w = Some(value);
757 self
758 }
759
760 pub const fn align(mut self, value: Align) -> Self {
762 self.align = Some(value);
763 self
764 }
765
766 pub const fn align_self(mut self, value: Align) -> Self {
768 self.align_self = Some(value);
769 self
770 }
771
772 pub const fn justify(mut self, value: Justify) -> Self {
774 self.justify = Some(value);
775 self
776 }
777
778 pub const fn min_h(mut self, value: u32) -> Self {
780 self.min_h = Some(value);
781 self
782 }
783
784 pub const fn max_h(mut self, value: u32) -> Self {
786 self.max_h = Some(value);
787 self
788 }
789
790 pub const fn w_pct(mut self, value: u8) -> Self {
792 self.w_pct = Some(value);
793 self
794 }
795
796 pub const fn h_pct(mut self, value: u8) -> Self {
798 self.h_pct = Some(value);
799 self
800 }
801}
802
803#[derive(Debug, Clone, Copy, Default)]
804#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
805pub struct WidgetColors {
806 pub fg: Option<Color>,
807 pub bg: Option<Color>,
808 pub border: Option<Color>,
809 pub accent: Option<Color>,
810}
811
812impl WidgetColors {
813 pub const fn new() -> Self {
814 Self {
815 fg: None,
816 bg: None,
817 border: None,
818 accent: None,
819 }
820 }
821
822 pub const fn fg(mut self, color: Color) -> Self {
823 self.fg = Some(color);
824 self
825 }
826
827 pub const fn bg(mut self, color: Color) -> Self {
828 self.bg = Some(color);
829 self
830 }
831
832 pub const fn border(mut self, color: Color) -> Self {
833 self.border = Some(color);
834 self
835 }
836
837 pub const fn accent(mut self, color: Color) -> Self {
838 self.accent = Some(color);
839 self
840 }
841}