use embedded_charts::prelude::*;
#[path = "../common/mod.rs"]
mod common;
use common::{data, window, WindowConfig, WindowTheme};
#[cfg(feature = "std")]
fn main() -> ChartResult<()> {
println!("🎨 Beautiful Theme Showcase - Making Eyes Happier!");
println!("==================================================");
println!("This example shows all themes in a single window grid layout.");
println!("Each theme displays with real chart data for comparison.");
println!("Press ESC or close the window to exit.\n");
let temperature_data = data::temperature_data(24)?; let cpu_data = data::system_metrics(50, data::SystemMetric::CpuUsage)?;
let window_config = WindowConfig::new("Theme Showcase - All Themes")
.theme(WindowTheme::Default)
.fps(30)
.background(Rgb565::new(10, 20, 10));
let themes = [
("Light", Theme::<Rgb565>::light()),
("Dark", Theme::<Rgb565>::dark()),
("Vibrant", Theme::<Rgb565>::vibrant()),
("Pastel", Theme::<Rgb565>::pastel()),
("Nature", Theme::<Rgb565>::nature()),
("Ocean", Theme::<Rgb565>::ocean()),
("Sunset", Theme::<Rgb565>::sunset()),
("Cyberpunk", create_improved_cyberpunk_theme()),
("Minimal", Theme::<Rgb565>::minimal()),
("Retro", Theme::<Rgb565>::retro()),
];
let cols = 5u32;
let rows = 2u32;
let margin = 10u32;
let spacing = 8u32;
window::run(window_config, move |display, viewport, _elapsed| {
draw_theme_grid(
display,
viewport,
&temperature_data,
&cpu_data,
&themes,
&ThemeGridParams {
cols,
rows,
margin,
spacing,
},
)
})
}
#[cfg(feature = "std")]
struct ThemeGridParams {
cols: u32,
rows: u32,
margin: u32,
spacing: u32,
}
#[cfg(feature = "std")]
#[allow(clippy::too_many_arguments)]
fn draw_theme_grid(
display: &mut embedded_graphics_simulator::SimulatorDisplay<
embedded_graphics::pixelcolor::Rgb565,
>,
viewport: embedded_graphics::primitives::Rectangle,
temperature_data: &StaticDataSeries<Point2D, 256>,
cpu_data: &StaticDataSeries<Point2D, 256>,
themes: &[(&str, Theme<Rgb565>); 10],
params: &ThemeGridParams,
) -> ChartResult<()> {
use embedded_graphics::{
mono_font::{ascii::FONT_6X10, MonoTextStyle},
prelude::*,
primitives::Rectangle,
text::{Alignment, Text},
Drawable,
};
let title_color = Rgb565::new(31, 41, 20); let title_style = MonoTextStyle::new(&FONT_6X10, title_color);
Text::with_alignment(
"🎨 Theme Showcase - Beautiful Eye-Friendly Color Palettes",
Point::new(
viewport.top_left.x + viewport.size.width as i32 / 2,
viewport.top_left.y + 15,
),
title_style,
Alignment::Center,
)
.draw(display)
.map_err(|_| ChartError::RenderingError)?;
let available_width =
viewport.size.width - (2 * params.margin) - ((params.cols - 1) * params.spacing);
let available_height =
viewport.size.height - 40 - (2 * params.margin) - ((params.rows - 1) * params.spacing);
let cell_width = available_width / params.cols;
let cell_height = available_height / params.rows;
for (i, (theme_name, theme)) in themes.iter().enumerate() {
let col = i % (params.cols as usize);
let row = i / (params.cols as usize);
let x = viewport.top_left.x
+ params.margin as i32
+ (col as u32 * (cell_width + params.spacing)) as i32;
let y = viewport.top_left.y
+ 30i32
+ params.margin as i32
+ (row as u32 * (cell_height + params.spacing)) as i32;
let cell_area = Rectangle::new(Point::new(x, y), Size::new(cell_width, cell_height));
draw_theme_cell(
display,
cell_area,
theme,
theme_name,
temperature_data,
cpu_data,
)?;
}
Ok(())
}
#[cfg(feature = "std")]
fn create_improved_cyberpunk_theme() -> Theme<embedded_graphics::pixelcolor::Rgb565> {
Theme {
background: Rgb565::new(2, 3, 2), primary: Rgb565::new(0, 63, 15), secondary: Rgb565::new(31, 0, 31), text: Rgb565::new(0, 63, 31), grid: Rgb565::new(8, 16, 8), accent: Rgb565::new(31, 63, 0), success: Rgb565::new(6, 51, 6), warning: Rgb565::new(31, 41, 0), error: Rgb565::new(31, 17, 0), }
}
#[cfg(feature = "std")]
fn draw_theme_cell(
display: &mut embedded_graphics_simulator::SimulatorDisplay<
embedded_graphics::pixelcolor::Rgb565,
>,
area: Rectangle,
theme: &Theme<embedded_graphics::pixelcolor::Rgb565>,
theme_name: &str,
temperature_data: &StaticDataSeries<Point2D, 256>,
cpu_data: &StaticDataSeries<Point2D, 256>,
) -> ChartResult<()> {
use embedded_graphics::{
mono_font::{ascii::FONT_6X10, MonoTextStyle},
prelude::*,
primitives::{PrimitiveStyle, Rectangle},
text::{Alignment, Text},
Drawable,
};
area.into_styled(PrimitiveStyle::with_fill(theme.background))
.draw(display)
.map_err(|_| ChartError::RenderingError)?;
area.into_styled(PrimitiveStyle::with_stroke(theme.grid, 1))
.draw(display)
.map_err(|_| ChartError::RenderingError)?;
let title_style = MonoTextStyle::new(&FONT_6X10, theme.text);
Text::with_alignment(
theme_name,
Point::new(
area.top_left.x + area.size.width as i32 / 2,
area.top_left.y + 12,
),
title_style,
Alignment::Center,
)
.draw(display)
.map_err(|_| ChartError::RenderingError)?;
let chart_margin = 4;
let chart_area = Rectangle::new(
Point::new(area.top_left.x + chart_margin, area.top_left.y + 18),
Size::new(
area.size.width - 2 * chart_margin as u32,
area.size.height - 18 - chart_margin as u32,
),
);
let chart_height = chart_area.size.height / 2;
let temp_area = Rectangle::new(
chart_area.top_left,
Size::new(chart_area.size.width, chart_height - 2),
);
let cpu_area = Rectangle::new(
Point::new(
chart_area.top_left.x,
chart_area.top_left.y + chart_height as i32 + 2,
),
Size::new(chart_area.size.width, chart_height - 2),
);
draw_mini_chart(
display,
temp_area,
temperature_data,
theme.primary,
theme.grid,
"Temp",
)?;
draw_mini_chart(
display,
cpu_area,
cpu_data,
theme.secondary,
theme.grid,
"CPU",
)?;
draw_mini_color_palette(display, area, theme)?;
Ok(())
}
#[cfg(feature = "std")]
fn draw_mini_chart(
display: &mut embedded_graphics_simulator::SimulatorDisplay<
embedded_graphics::pixelcolor::Rgb565,
>,
area: Rectangle,
data: &StaticDataSeries<Point2D, 256>,
line_color: embedded_graphics::pixelcolor::Rgb565,
grid_color: embedded_graphics::pixelcolor::Rgb565,
_label: &str,
) -> ChartResult<()> {
use embedded_graphics::{
prelude::*,
primitives::{Line, PrimitiveStyle},
Drawable,
};
let grid_style = PrimitiveStyle::with_stroke(grid_color, 1);
let mid_x = area.top_left.x + area.size.width as i32 / 2;
Line::new(
Point::new(mid_x, area.top_left.y),
Point::new(mid_x, area.top_left.y + area.size.height as i32),
)
.into_styled(grid_style)
.draw(display)
.map_err(|_| ChartError::RenderingError)?;
let mid_y = area.top_left.y + area.size.height as i32 / 2;
Line::new(
Point::new(area.top_left.x, mid_y),
Point::new(area.top_left.x + area.size.width as i32, mid_y),
)
.into_styled(grid_style)
.draw(display)
.map_err(|_| ChartError::RenderingError)?;
let line_style = PrimitiveStyle::with_stroke(line_color, 2);
let mut min_x = f32::INFINITY;
let mut max_x = f32::NEG_INFINITY;
let mut min_y = f32::INFINITY;
let mut max_y = f32::NEG_INFINITY;
for i in 0..data.len() {
if let Some(point) = data.get(i) {
min_x = min_x.min(point.x);
max_x = max_x.max(point.x);
min_y = min_y.min(point.y);
max_y = max_y.max(point.y);
}
}
if max_x == min_x {
max_x = min_x + 1.0;
}
if max_y == min_y {
max_y = min_y + 1.0;
}
for i in 0..data.len().saturating_sub(1) {
if let (Some(p1), Some(p2)) = (data.get(i), data.get(i + 1)) {
let x1 = area.top_left.x
+ ((p1.x - min_x) / (max_x - min_x) * area.size.width as f32) as i32;
let y1 = area.top_left.y + area.size.height as i32
- ((p1.y - min_y) / (max_y - min_y) * area.size.height as f32) as i32;
let x2 = area.top_left.x
+ ((p2.x - min_x) / (max_x - min_x) * area.size.width as f32) as i32;
let y2 = area.top_left.y + area.size.height as i32
- ((p2.y - min_y) / (max_y - min_y) * area.size.height as f32) as i32;
Line::new(Point::new(x1, y1), Point::new(x2, y2))
.into_styled(line_style)
.draw(display)
.map_err(|_| ChartError::RenderingError)?;
}
}
Ok(())
}
#[cfg(feature = "std")]
fn draw_mini_color_palette(
display: &mut embedded_graphics_simulator::SimulatorDisplay<
embedded_graphics::pixelcolor::Rgb565,
>,
area: Rectangle,
theme: &Theme<embedded_graphics::pixelcolor::Rgb565>,
) -> ChartResult<()> {
use embedded_graphics::{
prelude::*,
primitives::{PrimitiveStyle, Rectangle},
Drawable,
};
let colors = [
theme.primary,
theme.secondary,
theme.accent,
theme.success,
theme.warning,
theme.error,
];
let palette_height = 8;
let palette_y = area.top_left.y + area.size.height as i32 - palette_height - 2;
let swatch_width = (area.size.width - 8) / colors.len() as u32;
for (i, color) in colors.iter().enumerate() {
let x = area.top_left.x + 4 + (i as u32 * swatch_width) as i32;
Rectangle::new(
Point::new(x, palette_y),
Size::new(swatch_width - 1, palette_height as u32),
)
.into_styled(PrimitiveStyle::with_fill(*color))
.draw(display)
.map_err(|_| ChartError::RenderingError)?;
}
Ok(())
}
#[cfg(not(feature = "std"))]
fn main() {
println!("⚠️ This visual example requires the 'std' feature to run");
println!(" Run with: cargo run --example theme_showcase --features std");
}