|
| 1 | +//! Showcase: Wearable OS Subsystems & UI Patterns |
| 2 | +//! |
| 3 | +//! Demonstrates: |
| 4 | +//! 1. **Timeline Relationship Bars (`TimelineNodeWidget`)**: Chronological connective bars linking past, active, and future event pins. |
| 5 | +//! 2. **Reactive Peek Banners (`PeekBannerWidget`)**: Heads-up reminder ribbon modifying unobstructed screen canvas. |
| 6 | +//! 3. **Modal Notification Sheets (`NotificationSheetWidget`)**: Priority alert popups with action choices and auto-dismiss countdowns. |
| 7 | +//! 4. **Cascading Action Menus (`ActionMenuWidget`)**: Hierarchical nested action sheets with highlight cursor. |
| 8 | +//! 5. **Rich Multi-Span Text Nodes (`RichTextNodeWidget`)**: Formatted inline text tags and badge spans. |
| 9 | +
|
| 10 | +use embedded_graphics_core::pixelcolor::{Rgb565, WebColors}; |
| 11 | +use embedded_gui::{ |
| 12 | + framebuffer::Framebuffer, |
| 13 | + geometry::Rect, |
| 14 | + render::RenderCtx, |
| 15 | + round::UnobstructedArea, |
| 16 | + widgets::{ |
| 17 | + ActionMenuWidget, NotificationPriority, NotificationSheetWidget, PeekBannerWidget, |
| 18 | + RichTextNodeWidget, TextSpan, TimelineNodeState, TimelineNodeWidget, |
| 19 | + }, |
| 20 | +}; |
| 21 | + |
| 22 | +fn main() { |
| 23 | + println!("=== embedded-gui: Wearable OS Subsystems Showcase ==="); |
| 24 | + |
| 25 | + let screen = Rect::new(0, 0, 240, 240); |
| 26 | + let mut fb = Framebuffer::<{ 240 * 240 }>::new(240, 240); |
| 27 | + let mut ctx = RenderCtx::new(&mut fb, screen); |
| 28 | + |
| 29 | + // 1. Timeline Connective RelBar Demonstration |
| 30 | + println!("\n1. Timeline Relationship Connector Bars:"); |
| 31 | + let past_node = TimelineNodeWidget::new(TimelineNodeState::Past); |
| 32 | + let mut active_node = TimelineNodeWidget::new(TimelineNodeState::ActiveNow); |
| 33 | + active_node.active_color = Rgb565::CSS_ORANGE; |
| 34 | + let future_node = TimelineNodeWidget::new(TimelineNodeState::Future); |
| 35 | + |
| 36 | + let past_slot = Rect::new(12, 10, 16, 40); |
| 37 | + let active_slot = Rect::new(12, 50, 16, 40); |
| 38 | + let future_slot = Rect::new(12, 90, 16, 40); |
| 39 | + |
| 40 | + past_node.render(&mut ctx, past_slot).unwrap(); |
| 41 | + active_node.render(&mut ctx, active_slot).unwrap(); |
| 42 | + future_node.render(&mut ctx, future_slot).unwrap(); |
| 43 | + |
| 44 | + println!(" Past pin connector: {:?}", past_slot); |
| 45 | + println!(" Active NOW pin node: {:?}", active_slot); |
| 46 | + println!(" Upcoming pin node: {:?}", future_slot); |
| 47 | + |
| 48 | + // 2. Reactive Peek Banner adapting UnobstructedArea |
| 49 | + println!("\n2. Reactive Canvas Peek Banner:"); |
| 50 | + let mut unobstructed = UnobstructedArea::new(screen); |
| 51 | + let peek = PeekBannerWidget::new("TEAM SYNC (10m)"); |
| 52 | + peek.apply_to_unobstructed_area(&mut unobstructed); |
| 53 | + |
| 54 | + let banner_rect = Rect::new(screen.x, screen.y, screen.w, peek.height as u32); |
| 55 | + peek.render(&mut ctx, banner_rect).unwrap(); |
| 56 | + println!(" Peek banner rendered at: {:?}", banner_rect); |
| 57 | + println!( |
| 58 | + " Canvas area adjusted to: {:?}", |
| 59 | + unobstructed.visible_rect() |
| 60 | + ); |
| 61 | + |
| 62 | + // 3. Multi-Span Rich Text Flow Node |
| 63 | + println!("\n3. Multi-Span Rich Text Node with Badges:"); |
| 64 | + let mut text_node = RichTextNodeWidget::<4>::new(); |
| 65 | + text_node |
| 66 | + .push_span(TextSpan::badge( |
| 67 | + "CRITICAL", |
| 68 | + Rgb565::CSS_WHITE, |
| 69 | + Rgb565::new(28, 4, 4), |
| 70 | + )) |
| 71 | + .unwrap(); |
| 72 | + text_node |
| 73 | + .push_span(TextSpan::plain("CPU core temp 48C", Rgb565::CSS_WHITE)) |
| 74 | + .unwrap(); |
| 75 | + |
| 76 | + let text_rect = Rect::new(40, 60, 190, 24); |
| 77 | + text_node.render(&mut ctx, text_rect).unwrap(); |
| 78 | + println!( |
| 79 | + " Rendered {} styled text spans in {:?}", |
| 80 | + text_node.spans.len(), |
| 81 | + text_rect |
| 82 | + ); |
| 83 | + |
| 84 | + // 4. Modal Notification Sheet with Action Buttons & Progress Bar |
| 85 | + println!("\n4. Modal Notification Sheet:"); |
| 86 | + let mut notif = NotificationSheetWidget::<3>::new( |
| 87 | + "CALENDAR REMINDER", |
| 88 | + "Architecture Design Review @ 10:00", |
| 89 | + NotificationPriority::Important, |
| 90 | + ); |
| 91 | + notif.add_action("DISMISS", 101).unwrap(); |
| 92 | + notif.add_action("SNOOZE", 102).unwrap(); |
| 93 | + notif.auto_dismiss_progress = 0.75; // 75% timer remaining |
| 94 | + |
| 95 | + let notif_rect = Rect::new(20, 140, 200, 85); |
| 96 | + notif.render(&mut ctx, notif_rect).unwrap(); |
| 97 | + println!( |
| 98 | + " Rendered modal notification card with {} actions & 75% countdown timer.", |
| 99 | + notif.actions.len() |
| 100 | + ); |
| 101 | + |
| 102 | + // 5. Cascading Hierarchical Action Menu |
| 103 | + println!("\n5. Cascading Action Menu:"); |
| 104 | + let mut menu = ActionMenuWidget::<4>::new(Some("SYSTEM ACTIONS")); |
| 105 | + menu.add_item("Wireless Sync", 1, true).unwrap(); |
| 106 | + menu.add_item("Do Not Disturb", 2, false).unwrap(); |
| 107 | + menu.add_item("Power Options", 3, true).unwrap(); |
| 108 | + menu.selected_index = 0; |
| 109 | + |
| 110 | + let menu_rect = Rect::new(30, 40, 180, 75); |
| 111 | + menu.render(&mut ctx, menu_rect).unwrap(); |
| 112 | + println!( |
| 113 | + " Rendered action menu with {} items, highlighted index {}.", |
| 114 | + menu.items.len(), |
| 115 | + menu.selected_index |
| 116 | + ); |
| 117 | + |
| 118 | + println!("\nWearable OS subsystems showcase executed and rendered successfully!"); |
| 119 | +} |
0 commit comments