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 dark_bg: Option<Color>,
570 pub dark_border_style: Option<Style>,
571 pub padding: Option<Padding>,
572 pub margin: Option<Margin>,
573 pub gap: Option<u32>,
574 pub grow: Option<u16>,
575 pub align: Option<Align>,
576 pub justify: Option<Justify>,
577 pub w: Option<u32>,
578 pub h: Option<u32>,
579 pub min_w: Option<u32>,
580 pub max_w: Option<u32>,
581 pub min_h: Option<u32>,
582 pub max_h: Option<u32>,
583 pub w_pct: Option<u8>,
584 pub h_pct: Option<u8>,
585}
586
587impl ContainerStyle {
588 pub const fn new() -> Self {
590 Self {
591 border: None,
592 border_sides: None,
593 border_style: None,
594 bg: None,
595 dark_bg: None,
596 dark_border_style: None,
597 padding: None,
598 margin: None,
599 gap: None,
600 grow: None,
601 align: None,
602 justify: None,
603 w: None,
604 h: None,
605 min_w: None,
606 max_w: None,
607 min_h: None,
608 max_h: None,
609 w_pct: None,
610 h_pct: None,
611 }
612 }
613
614 pub const fn border(mut self, border: Border) -> Self {
616 self.border = Some(border);
617 self
618 }
619
620 pub const fn border_sides(mut self, sides: BorderSides) -> Self {
622 self.border_sides = Some(sides);
623 self
624 }
625
626 pub const fn bg(mut self, color: Color) -> Self {
628 self.bg = Some(color);
629 self
630 }
631
632 pub const fn dark_bg(mut self, color: Color) -> Self {
634 self.dark_bg = Some(color);
635 self
636 }
637
638 pub const fn p(mut self, value: u32) -> Self {
640 self.padding = Some(Padding {
641 top: value,
642 bottom: value,
643 left: value,
644 right: value,
645 });
646 self
647 }
648
649 pub const fn px(mut self, value: u32) -> Self {
651 let p = match self.padding {
652 Some(p) => Padding {
653 left: value,
654 right: value,
655 ..p
656 },
657 None => Padding {
658 top: 0,
659 bottom: 0,
660 left: value,
661 right: value,
662 },
663 };
664 self.padding = Some(p);
665 self
666 }
667
668 pub const fn py(mut self, value: u32) -> Self {
670 let p = match self.padding {
671 Some(p) => Padding {
672 top: value,
673 bottom: value,
674 ..p
675 },
676 None => Padding {
677 top: value,
678 bottom: value,
679 left: 0,
680 right: 0,
681 },
682 };
683 self.padding = Some(p);
684 self
685 }
686
687 pub const fn m(mut self, value: u32) -> Self {
689 self.margin = Some(Margin {
690 top: value,
691 bottom: value,
692 left: value,
693 right: value,
694 });
695 self
696 }
697
698 pub const fn gap(mut self, value: u32) -> Self {
700 self.gap = Some(value);
701 self
702 }
703
704 pub const fn grow(mut self, value: u16) -> Self {
706 self.grow = Some(value);
707 self
708 }
709
710 pub const fn w(mut self, value: u32) -> Self {
712 self.w = Some(value);
713 self
714 }
715
716 pub const fn h(mut self, value: u32) -> Self {
718 self.h = Some(value);
719 self
720 }
721
722 pub const fn min_w(mut self, value: u32) -> Self {
724 self.min_w = Some(value);
725 self
726 }
727
728 pub const fn max_w(mut self, value: u32) -> Self {
730 self.max_w = Some(value);
731 self
732 }
733
734 pub const fn align(mut self, value: Align) -> Self {
736 self.align = Some(value);
737 self
738 }
739
740 pub const fn justify(mut self, value: Justify) -> Self {
742 self.justify = Some(value);
743 self
744 }
745
746 pub const fn min_h(mut self, value: u32) -> Self {
748 self.min_h = Some(value);
749 self
750 }
751
752 pub const fn max_h(mut self, value: u32) -> Self {
754 self.max_h = Some(value);
755 self
756 }
757
758 pub const fn w_pct(mut self, value: u8) -> Self {
760 self.w_pct = Some(value);
761 self
762 }
763
764 pub const fn h_pct(mut self, value: u8) -> Self {
766 self.h_pct = Some(value);
767 self
768 }
769}
770
771#[derive(Debug, Clone, Copy, Default)]
772#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
773pub struct WidgetColors {
774 pub fg: Option<Color>,
775 pub bg: Option<Color>,
776 pub border: Option<Color>,
777 pub accent: Option<Color>,
778}
779
780impl WidgetColors {
781 pub const fn new() -> Self {
782 Self {
783 fg: None,
784 bg: None,
785 border: None,
786 accent: None,
787 }
788 }
789
790 pub const fn fg(mut self, color: Color) -> Self {
791 self.fg = Some(color);
792 self
793 }
794
795 pub const fn bg(mut self, color: Color) -> Self {
796 self.bg = Some(color);
797 self
798 }
799
800 pub const fn border(mut self, color: Color) -> Self {
801 self.border = Some(color);
802 self
803 }
804
805 pub const fn accent(mut self, color: Color) -> Self {
806 self.accent = Some(color);
807 self
808 }
809}