Skip to main content

Panel

Struct Panel 

Source
pub struct Panel {
    pub title: Option<String>,
    pub border: BorderStyle,
    pub shadow: bool,
}
Expand description

A bordered container panel with optional title and shadow.

Fields§

§title: Option<String>§border: BorderStyle§shadow: bool

Implementations§

Source§

impl Panel

Source

pub fn new() -> Self

Source

pub fn titled(title: impl Into<String>) -> Self

Examples found in repository?
examples/fancyui.rs (line 37)
24fn setup(world: &mut World) {
25    world.insert_resource(FrameCount(0));
26
27    // Root container fills the terminal
28    let root = world.spawn((
29        Node::new(0, 0, 0, 0),
30        Container,
31        Anchor::fill(),
32    ));
33
34    // ═══ Header Panel ═══
35    let header = world.spawn((
36        Node::new(0, 0, 0, 0),
37        Panel::titled("\u{2726} Decay Fancy UI").border(BorderStyle::Double).shadow(),
38        UiStyle::fg(90, 130, 220),
39        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 1, -2, 4) },
40        Parent(root),
41    ));
42
43    // Subtitle inside panel
44    world.spawn((
45        Node::new(0, 0, 0, 0),
46        Text::new("zero-dependency TUI framework"),
47        UiStyle { fg: Some((130, 130, 145)), italic: true, ..UiStyle::new() },
48        TextAlign::Center,
49        Anchor { min: (0.0, 0.0), max: (1.0, 1.0), offset: (2, 1, -2, -1) },
50        Parent(header),
51    ));
52
53    // ─── System Monitor ───
54    world.spawn((
55        Node::new(0, 0, 0, 0),
56        Separator::labeled("System Monitor"),
57        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 4, -2, 5) },
58        Parent(root),
59    ));
60
61    // Progress bar labels
62    world.spawn((
63        Node::new(0, 0, 0, 0), Text::new("CPU"), UiStyle::dim(),
64        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 5, 11, 6) },
65        Parent(root),
66    ));
67    world.spawn((
68        Node::new(0, 0, 0, 0), Text::new("Memory"), UiStyle::dim(),
69        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 6, 11, 7) },
70        Parent(root),
71    ));
72    world.spawn((
73        Node::new(0, 0, 0, 0), Text::new("Disk"), UiStyle::dim(),
74        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 7, 11, 8) },
75        Parent(root),
76    ));
77    world.spawn((
78        Node::new(0, 0, 0, 0), Text::new("Network"), UiStyle::dim(),
79        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 8, 11, 9) },
80        Parent(root),
81    ));
82
83    // Progress bars (proportional width)
84    let cpu = world.spawn((
85        Node::new(0, 0, 0, 0),
86        ProgressBar::new(0.64).with_gradient((255, 100, 80)).with_label(),
87        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 5, 0, 6) },
88        Parent(root),
89    ));
90    let mem = world.spawn((
91        Node::new(0, 0, 0, 0),
92        ProgressBar::new(0.78)
93            .with_gradient((100, 180, 255))
94            .with_label()
95            .with_colors((60, 160, 240), (40, 40, 50)),
96        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 6, 0, 7) },
97        Parent(root),
98    ));
99    let disk = world.spawn((
100        Node::new(0, 0, 0, 0),
101        ProgressBar::new(0.21).with_label(),
102        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 7, 0, 8) },
103        Parent(root),
104    ));
105    let net = world.spawn((
106        Node::new(0, 0, 0, 0),
107        ProgressBar::classic(0.45)
108            .with_colors((200, 180, 60), (50, 50, 60))
109            .with_label(),
110        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 8, 0, 9) },
111        Parent(root),
112    ));
113    world.insert_resource(Bars { cpu, mem, disk, net });
114
115    // ─── Controls ───
116    world.spawn((
117        Node::new(0, 0, 0, 0),
118        Separator::labeled("Controls"),
119        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 10, -2, 11) },
120        Parent(root),
121    ));
122
123    // Buttons (2x2 grid, proportional width)
124    world.spawn((
125        Node::new(0, 0, 0, 0),
126        Text::new("Dashboard"), Button, Interaction::None,
127        Anchor { min: (0.0, 0.0), max: (0.48, 0.0), offset: (3, 11, 0, 14) },
128        Parent(root),
129    ));
130    world.spawn((
131        Node::new(0, 0, 0, 0),
132        Text::new("Reports"), Button, Interaction::None,
133        Anchor { min: (0.5, 0.0), max: (1.0, 0.0), offset: (0, 11, -2, 14) },
134        Parent(root),
135    ));
136    world.spawn((
137        Node::new(0, 0, 0, 0),
138        Text::new("Settings"), Button, Interaction::None,
139        Anchor { min: (0.0, 0.0), max: (0.48, 0.0), offset: (3, 14, 0, 17) },
140        Parent(root),
141    ));
142    world.spawn((
143        Node::new(0, 0, 0, 0),
144        Text::new("Exit"), Button, Interaction::None,
145        Anchor { min: (0.5, 0.0), max: (1.0, 0.0), offset: (0, 14, -2, 17) },
146        Parent(root),
147    ));
148
149    // ─── Activity ───
150    world.spawn((
151        Node::new(0, 0, 0, 0),
152        Separator::labeled("Activity"),
153        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 17, -2, 18) },
154        Parent(root),
155    ));
156
157    // Spinner
158    world.spawn((
159        Node::new(0, 0, 0, 0),
160        Spinner::new(SpinnerStyle::Dots).with_label("Processing data..."),
161        UiStyle::fg(100, 200, 255),
162        Anchor { min: (0.0, 0.0), max: (0.5, 0.0), offset: (3, 18, 0, 19) },
163        Parent(root),
164    ));
165
166    // Animated typewriter text
167    world.spawn((
168        Node::new(0, 0, 0, 0),
169        AnimatedText::new("The quick brown fox jumps over the lazy dog", 15.0),
170        UiStyle::fg(180, 180, 195),
171        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 19, 0, 20) },
172        Parent(root),
173    ));
174
175    // Status
176    let status = world.spawn((
177        Node::new(0, 0, 0, 0),
178        Text::new("Select a button and press Enter..."),
179        UiStyle::dim(),
180        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 21, 0, 22) },
181        Parent(root),
182    ));
183    world.insert_resource(StatusLabel(status));
184
185    // Footer
186    world.spawn((
187        Node::new(0, 0, 0, 0),
188        Text::new("\u{2191}\u{2193}/Tab Navigate   Enter/Space Click   q Quit"),
189        UiStyle::dim(),
190        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 22, 0, 23) },
191        Parent(root),
192    ));
193}
Source

pub fn border(self, style: BorderStyle) -> Self

Examples found in repository?
examples/fancyui.rs (line 37)
24fn setup(world: &mut World) {
25    world.insert_resource(FrameCount(0));
26
27    // Root container fills the terminal
28    let root = world.spawn((
29        Node::new(0, 0, 0, 0),
30        Container,
31        Anchor::fill(),
32    ));
33
34    // ═══ Header Panel ═══
35    let header = world.spawn((
36        Node::new(0, 0, 0, 0),
37        Panel::titled("\u{2726} Decay Fancy UI").border(BorderStyle::Double).shadow(),
38        UiStyle::fg(90, 130, 220),
39        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 1, -2, 4) },
40        Parent(root),
41    ));
42
43    // Subtitle inside panel
44    world.spawn((
45        Node::new(0, 0, 0, 0),
46        Text::new("zero-dependency TUI framework"),
47        UiStyle { fg: Some((130, 130, 145)), italic: true, ..UiStyle::new() },
48        TextAlign::Center,
49        Anchor { min: (0.0, 0.0), max: (1.0, 1.0), offset: (2, 1, -2, -1) },
50        Parent(header),
51    ));
52
53    // ─── System Monitor ───
54    world.spawn((
55        Node::new(0, 0, 0, 0),
56        Separator::labeled("System Monitor"),
57        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 4, -2, 5) },
58        Parent(root),
59    ));
60
61    // Progress bar labels
62    world.spawn((
63        Node::new(0, 0, 0, 0), Text::new("CPU"), UiStyle::dim(),
64        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 5, 11, 6) },
65        Parent(root),
66    ));
67    world.spawn((
68        Node::new(0, 0, 0, 0), Text::new("Memory"), UiStyle::dim(),
69        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 6, 11, 7) },
70        Parent(root),
71    ));
72    world.spawn((
73        Node::new(0, 0, 0, 0), Text::new("Disk"), UiStyle::dim(),
74        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 7, 11, 8) },
75        Parent(root),
76    ));
77    world.spawn((
78        Node::new(0, 0, 0, 0), Text::new("Network"), UiStyle::dim(),
79        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 8, 11, 9) },
80        Parent(root),
81    ));
82
83    // Progress bars (proportional width)
84    let cpu = world.spawn((
85        Node::new(0, 0, 0, 0),
86        ProgressBar::new(0.64).with_gradient((255, 100, 80)).with_label(),
87        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 5, 0, 6) },
88        Parent(root),
89    ));
90    let mem = world.spawn((
91        Node::new(0, 0, 0, 0),
92        ProgressBar::new(0.78)
93            .with_gradient((100, 180, 255))
94            .with_label()
95            .with_colors((60, 160, 240), (40, 40, 50)),
96        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 6, 0, 7) },
97        Parent(root),
98    ));
99    let disk = world.spawn((
100        Node::new(0, 0, 0, 0),
101        ProgressBar::new(0.21).with_label(),
102        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 7, 0, 8) },
103        Parent(root),
104    ));
105    let net = world.spawn((
106        Node::new(0, 0, 0, 0),
107        ProgressBar::classic(0.45)
108            .with_colors((200, 180, 60), (50, 50, 60))
109            .with_label(),
110        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 8, 0, 9) },
111        Parent(root),
112    ));
113    world.insert_resource(Bars { cpu, mem, disk, net });
114
115    // ─── Controls ───
116    world.spawn((
117        Node::new(0, 0, 0, 0),
118        Separator::labeled("Controls"),
119        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 10, -2, 11) },
120        Parent(root),
121    ));
122
123    // Buttons (2x2 grid, proportional width)
124    world.spawn((
125        Node::new(0, 0, 0, 0),
126        Text::new("Dashboard"), Button, Interaction::None,
127        Anchor { min: (0.0, 0.0), max: (0.48, 0.0), offset: (3, 11, 0, 14) },
128        Parent(root),
129    ));
130    world.spawn((
131        Node::new(0, 0, 0, 0),
132        Text::new("Reports"), Button, Interaction::None,
133        Anchor { min: (0.5, 0.0), max: (1.0, 0.0), offset: (0, 11, -2, 14) },
134        Parent(root),
135    ));
136    world.spawn((
137        Node::new(0, 0, 0, 0),
138        Text::new("Settings"), Button, Interaction::None,
139        Anchor { min: (0.0, 0.0), max: (0.48, 0.0), offset: (3, 14, 0, 17) },
140        Parent(root),
141    ));
142    world.spawn((
143        Node::new(0, 0, 0, 0),
144        Text::new("Exit"), Button, Interaction::None,
145        Anchor { min: (0.5, 0.0), max: (1.0, 0.0), offset: (0, 14, -2, 17) },
146        Parent(root),
147    ));
148
149    // ─── Activity ───
150    world.spawn((
151        Node::new(0, 0, 0, 0),
152        Separator::labeled("Activity"),
153        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 17, -2, 18) },
154        Parent(root),
155    ));
156
157    // Spinner
158    world.spawn((
159        Node::new(0, 0, 0, 0),
160        Spinner::new(SpinnerStyle::Dots).with_label("Processing data..."),
161        UiStyle::fg(100, 200, 255),
162        Anchor { min: (0.0, 0.0), max: (0.5, 0.0), offset: (3, 18, 0, 19) },
163        Parent(root),
164    ));
165
166    // Animated typewriter text
167    world.spawn((
168        Node::new(0, 0, 0, 0),
169        AnimatedText::new("The quick brown fox jumps over the lazy dog", 15.0),
170        UiStyle::fg(180, 180, 195),
171        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 19, 0, 20) },
172        Parent(root),
173    ));
174
175    // Status
176    let status = world.spawn((
177        Node::new(0, 0, 0, 0),
178        Text::new("Select a button and press Enter..."),
179        UiStyle::dim(),
180        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 21, 0, 22) },
181        Parent(root),
182    ));
183    world.insert_resource(StatusLabel(status));
184
185    // Footer
186    world.spawn((
187        Node::new(0, 0, 0, 0),
188        Text::new("\u{2191}\u{2193}/Tab Navigate   Enter/Space Click   q Quit"),
189        UiStyle::dim(),
190        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 22, 0, 23) },
191        Parent(root),
192    ));
193}
Source

pub fn shadow(self) -> Self

Examples found in repository?
examples/fancyui.rs (line 37)
24fn setup(world: &mut World) {
25    world.insert_resource(FrameCount(0));
26
27    // Root container fills the terminal
28    let root = world.spawn((
29        Node::new(0, 0, 0, 0),
30        Container,
31        Anchor::fill(),
32    ));
33
34    // ═══ Header Panel ═══
35    let header = world.spawn((
36        Node::new(0, 0, 0, 0),
37        Panel::titled("\u{2726} Decay Fancy UI").border(BorderStyle::Double).shadow(),
38        UiStyle::fg(90, 130, 220),
39        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 1, -2, 4) },
40        Parent(root),
41    ));
42
43    // Subtitle inside panel
44    world.spawn((
45        Node::new(0, 0, 0, 0),
46        Text::new("zero-dependency TUI framework"),
47        UiStyle { fg: Some((130, 130, 145)), italic: true, ..UiStyle::new() },
48        TextAlign::Center,
49        Anchor { min: (0.0, 0.0), max: (1.0, 1.0), offset: (2, 1, -2, -1) },
50        Parent(header),
51    ));
52
53    // ─── System Monitor ───
54    world.spawn((
55        Node::new(0, 0, 0, 0),
56        Separator::labeled("System Monitor"),
57        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 4, -2, 5) },
58        Parent(root),
59    ));
60
61    // Progress bar labels
62    world.spawn((
63        Node::new(0, 0, 0, 0), Text::new("CPU"), UiStyle::dim(),
64        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 5, 11, 6) },
65        Parent(root),
66    ));
67    world.spawn((
68        Node::new(0, 0, 0, 0), Text::new("Memory"), UiStyle::dim(),
69        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 6, 11, 7) },
70        Parent(root),
71    ));
72    world.spawn((
73        Node::new(0, 0, 0, 0), Text::new("Disk"), UiStyle::dim(),
74        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 7, 11, 8) },
75        Parent(root),
76    ));
77    world.spawn((
78        Node::new(0, 0, 0, 0), Text::new("Network"), UiStyle::dim(),
79        Anchor { min: (0.0, 0.0), max: (0.0, 0.0), offset: (3, 8, 11, 9) },
80        Parent(root),
81    ));
82
83    // Progress bars (proportional width)
84    let cpu = world.spawn((
85        Node::new(0, 0, 0, 0),
86        ProgressBar::new(0.64).with_gradient((255, 100, 80)).with_label(),
87        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 5, 0, 6) },
88        Parent(root),
89    ));
90    let mem = world.spawn((
91        Node::new(0, 0, 0, 0),
92        ProgressBar::new(0.78)
93            .with_gradient((100, 180, 255))
94            .with_label()
95            .with_colors((60, 160, 240), (40, 40, 50)),
96        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 6, 0, 7) },
97        Parent(root),
98    ));
99    let disk = world.spawn((
100        Node::new(0, 0, 0, 0),
101        ProgressBar::new(0.21).with_label(),
102        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 7, 0, 8) },
103        Parent(root),
104    ));
105    let net = world.spawn((
106        Node::new(0, 0, 0, 0),
107        ProgressBar::classic(0.45)
108            .with_colors((200, 180, 60), (50, 50, 60))
109            .with_label(),
110        Anchor { min: (0.15, 0.0), max: (0.55, 0.0), offset: (0, 8, 0, 9) },
111        Parent(root),
112    ));
113    world.insert_resource(Bars { cpu, mem, disk, net });
114
115    // ─── Controls ───
116    world.spawn((
117        Node::new(0, 0, 0, 0),
118        Separator::labeled("Controls"),
119        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 10, -2, 11) },
120        Parent(root),
121    ));
122
123    // Buttons (2x2 grid, proportional width)
124    world.spawn((
125        Node::new(0, 0, 0, 0),
126        Text::new("Dashboard"), Button, Interaction::None,
127        Anchor { min: (0.0, 0.0), max: (0.48, 0.0), offset: (3, 11, 0, 14) },
128        Parent(root),
129    ));
130    world.spawn((
131        Node::new(0, 0, 0, 0),
132        Text::new("Reports"), Button, Interaction::None,
133        Anchor { min: (0.5, 0.0), max: (1.0, 0.0), offset: (0, 11, -2, 14) },
134        Parent(root),
135    ));
136    world.spawn((
137        Node::new(0, 0, 0, 0),
138        Text::new("Settings"), Button, Interaction::None,
139        Anchor { min: (0.0, 0.0), max: (0.48, 0.0), offset: (3, 14, 0, 17) },
140        Parent(root),
141    ));
142    world.spawn((
143        Node::new(0, 0, 0, 0),
144        Text::new("Exit"), Button, Interaction::None,
145        Anchor { min: (0.5, 0.0), max: (1.0, 0.0), offset: (0, 14, -2, 17) },
146        Parent(root),
147    ));
148
149    // ─── Activity ───
150    world.spawn((
151        Node::new(0, 0, 0, 0),
152        Separator::labeled("Activity"),
153        Anchor { min: (0.0, 0.0), max: (1.0, 0.0), offset: (2, 17, -2, 18) },
154        Parent(root),
155    ));
156
157    // Spinner
158    world.spawn((
159        Node::new(0, 0, 0, 0),
160        Spinner::new(SpinnerStyle::Dots).with_label("Processing data..."),
161        UiStyle::fg(100, 200, 255),
162        Anchor { min: (0.0, 0.0), max: (0.5, 0.0), offset: (3, 18, 0, 19) },
163        Parent(root),
164    ));
165
166    // Animated typewriter text
167    world.spawn((
168        Node::new(0, 0, 0, 0),
169        AnimatedText::new("The quick brown fox jumps over the lazy dog", 15.0),
170        UiStyle::fg(180, 180, 195),
171        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 19, 0, 20) },
172        Parent(root),
173    ));
174
175    // Status
176    let status = world.spawn((
177        Node::new(0, 0, 0, 0),
178        Text::new("Select a button and press Enter..."),
179        UiStyle::dim(),
180        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 21, 0, 22) },
181        Parent(root),
182    ));
183    world.insert_resource(StatusLabel(status));
184
185    // Footer
186    world.spawn((
187        Node::new(0, 0, 0, 0),
188        Text::new("\u{2191}\u{2193}/Tab Navigate   Enter/Space Click   q Quit"),
189        UiStyle::dim(),
190        Anchor { min: (0.0, 0.0), max: (0.8, 0.0), offset: (3, 22, 0, 23) },
191        Parent(root),
192    ));
193}

Trait Implementations§

Auto Trait Implementations§

§

impl Freeze for Panel

§

impl RefUnwindSafe for Panel

§

impl Send for Panel

§

impl Sync for Panel

§

impl Unpin for Panel

§

impl UnsafeUnpin for Panel

§

impl UnwindSafe for Panel

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.