use std::env;
use macroquad::prelude::*;
use rae::{compute_shell_layout, Palette, Rect, Rgba};
fn window_conf() -> Conf {
Conf {
window_title: "rae layout demo".to_string(),
window_width: 1440,
window_height: 900,
high_dpi: true,
sample_count: 4,
..Default::default()
}
}
#[macroquad::main(window_conf)]
async fn main() {
let palette = Palette::midnight();
let max_frames = env::var("RAE_RENDER_DEMO_FRAMES")
.ok()
.and_then(|value| value.parse::<u64>().ok());
let mut frames = 0u64;
loop {
if is_key_pressed(KeyCode::Escape) {
break;
}
let viewport = Rect::new(0.0, 0.0, screen_width(), screen_height());
let layout = compute_shell_layout(viewport);
let time = get_time() as f32;
clear_background(to_mq(palette.background));
draw_background(&palette, viewport, time);
draw_shell_layout(&palette, layout);
draw_device_previews(&palette, layout);
frames = frames.saturating_add(1);
if max_frames.is_some_and(|max_frames| frames >= max_frames) {
break;
}
next_frame().await;
}
}
fn draw_shell_layout(palette: &Palette, layout: rae::AppLayout) {
if layout.header.height > 0.0 {
draw_panel(
layout.header,
palette.panel_hot.with_alpha(0.72),
palette.accent,
"header",
"Desktop shell chrome. Resize the window; Esc closes.",
);
}
draw_panel(
layout.main,
palette.panel.with_alpha(0.72),
palette.success,
"main",
"Primary content surface. This is rendered, not printed coordinates.",
);
if layout.sidebar_collapsed {
let badge = Rect::new(
layout.main.right() - 184.0,
layout.main.y + 18.0,
156.0,
34.0,
);
draw_rounded_rect(badge, 13.0, to_mq(palette.warning.with_alpha(0.22)));
draw_text_line(
"sidebar collapsed",
badge.x + 14.0,
badge.y + 22.0,
14.0,
to_mq(palette.warning),
);
} else {
draw_panel(
layout.sidebar,
palette.panel_hot.with_alpha(0.68),
palette.warning,
"sidebar",
"Inspector/responsive secondary surface.",
);
}
draw_panel(
layout.prompt,
palette.panel_hot.with_alpha(0.74),
palette.accent,
"prompt",
"Input surface pinned above status.",
);
draw_panel(
layout.status,
palette.panel.with_alpha(0.78),
palette.muted,
"status",
"status bar",
);
}
fn draw_device_previews(palette: &Palette, layout: rae::AppLayout) {
if layout.sidebar.is_empty() || layout.sidebar.width < 300.0 || layout.sidebar.height < 420.0 {
return;
}
let presets = [
("desktop", Rect::new(0.0, 0.0, 1920.0, 1080.0)),
("laptop", Rect::new(0.0, 0.0, 1366.0, 768.0)),
("tablet", Rect::new(0.0, 0.0, 900.0, 720.0)),
("phone", Rect::new(0.0, 0.0, 430.0, 860.0)),
];
let x = layout.sidebar.x + 22.0;
let mut y = layout.sidebar.y + 92.0;
draw_text_line(
"responsive previews",
x,
y - 28.0,
16.0,
to_mq(palette.accent),
);
for (label, viewport) in presets {
let preview = Rect::new(x, y, layout.sidebar.width - 44.0, 116.0);
draw_preview_card(palette, label, viewport, preview);
y += 132.0;
}
}
fn draw_preview_card(palette: &Palette, label: &str, viewport: Rect, card: Rect) {
draw_rounded_rect(card, 16.0, to_mq(palette.background.with_alpha(0.86)));
draw_rectangle_lines(
card.x,
card.y,
card.width,
card.height,
1.0,
to_mq(palette.accent.with_alpha(0.32)),
);
draw_text_line(
label,
card.x + 12.0,
card.y + 22.0,
13.0,
to_mq(palette.text),
);
let target = Rect::new(
card.x + 12.0,
card.y + 34.0,
card.width - 24.0,
card.height - 46.0,
);
let scale = (target.width / viewport.width).min(target.height / viewport.height);
let scaled_root = Rect::new(
target.x + (target.width - viewport.width * scale) * 0.5,
target.y + (target.height - viewport.height * scale) * 0.5,
viewport.width * scale,
viewport.height * scale,
);
let layout = compute_shell_layout(viewport);
draw_rectangle(
scaled_root.x,
scaled_root.y,
scaled_root.width,
scaled_root.height,
to_mq(palette.panel.with_alpha(0.34)),
);
draw_scaled_rect(
layout.header,
scale,
scaled_root,
palette.accent.with_alpha(0.70),
);
draw_scaled_rect(
layout.main,
scale,
scaled_root,
palette.success.with_alpha(0.66),
);
draw_scaled_rect(
layout.sidebar,
scale,
scaled_root,
palette.warning.with_alpha(0.66),
);
draw_scaled_rect(
layout.prompt,
scale,
scaled_root,
palette.accent.with_alpha(0.42),
);
draw_scaled_rect(
layout.status,
scale,
scaled_root,
palette.muted.with_alpha(0.72),
);
}
fn draw_scaled_rect(rect: Rect, scale: f32, root: Rect, color: Rgba) {
if rect.is_empty() {
return;
}
draw_rectangle(
root.x + rect.x * scale,
root.y + rect.y * scale,
rect.width * scale,
rect.height * scale,
to_mq(color),
);
}
fn draw_panel(rect: Rect, fill: Rgba, accent: Rgba, title: &str, detail: &str) {
draw_rounded_rect(rect, 18.0, to_mq(fill));
draw_rectangle_lines(
rect.x,
rect.y,
rect.width,
rect.height,
1.4,
to_mq(accent.with_alpha(0.54)),
);
draw_text_line(title, rect.x + 18.0, rect.y + 29.0, 18.0, to_mq(accent));
if rect.height > 72.0 {
draw_text_line(detail, rect.x + 18.0, rect.y + 56.0, 15.0, WHITE);
let bounds = format!(
"x:{:.0} y:{:.0} w:{:.0} h:{:.0}",
rect.x, rect.y, rect.width, rect.height
);
draw_text_line(
&bounds,
rect.x + 18.0,
rect.bottom() - 18.0,
13.0,
LIGHTGRAY,
);
}
}
fn draw_background(palette: &Palette, viewport: Rect, time: f32) {
for index in 0..9 {
let radius = 180.0 + index as f32 * 62.0;
let alpha = 0.05 - index as f32 * 0.004;
let x = viewport.width * (0.46 + (time * 0.08).sin() * 0.06);
let y = viewport.height * (0.36 + (time * 0.11).cos() * 0.08);
draw_circle(
x,
y,
radius,
to_mq(palette.accent.with_alpha(alpha.max(0.006))),
);
}
}
fn draw_rounded_rect(rect: Rect, radius: f32, color: Color) {
let radius = radius.min(rect.width * 0.5).min(rect.height * 0.5).max(0.0);
draw_rectangle(
rect.x + radius,
rect.y,
rect.width - radius * 2.0,
rect.height,
color,
);
draw_rectangle(
rect.x,
rect.y + radius,
rect.width,
rect.height - radius * 2.0,
color,
);
draw_circle(rect.x + radius, rect.y + radius, radius, color);
draw_circle(rect.right() - radius, rect.y + radius, radius, color);
draw_circle(rect.x + radius, rect.bottom() - radius, radius, color);
draw_circle(rect.right() - radius, rect.bottom() - radius, radius, color);
}
fn draw_text_line(text: &str, x: f32, y: f32, size: f32, color: Color) {
draw_text_ex(
text,
x,
y,
TextParams {
font_size: size as u16,
color,
..Default::default()
},
);
}
fn to_mq(color: Rgba) -> Color {
Color::new(color.r, color.g, color.b, color.a)
}