x11-overlay 0.1.0

A library for creating overlay interfaces on X11 systems using Cairo for rendering
Documentation
use crate::graphics::{Color, FontDesc, Rectangle};
use crate::ui::{
    Alignment, Component, LayoutBuilder, LayoutContainer, NotificationComponent,
    ProgressBarComponent, Spacing, StatusPanel, TextComponent,
};
use anyhow::Result;

mod animation;
mod graphics;
mod overlay;
mod ui;
mod x11;

fn main() -> Result<()> {
    println!("Starting x11-overlay with component demo...");

    let mut overlay = overlay::Overlay::new()?;

    // Get screen dimensions for positioning
    let screen_width = overlay.screen_width();
    let screen_height = overlay.screen_height();

    // Create demo components
    create_component_demo(&mut overlay, screen_width, screen_height)?;

    overlay.run()?;

    Ok(())
}

fn create_component_demo(
    overlay: &mut overlay::Overlay,
    screen_width: u16,
    screen_height: u16,
) -> Result<()> {
    println!("Creating layout-based component demo...");

    // Create layout containers to demonstrate different layout strategies
    let layout_containers = create_layout_demo(screen_width, screen_height)?;

    // Add layout containers as components
    for container in layout_containers {
        overlay.add_component(Box::new(container));
    }

    println!("Created layout demo with multiple layout containers:");
    [
        "Left sidebar with vertical layout",
        "Main content area with grid layout",
        "Top header with horizontal layout",
        "Bottom status bar with horizontal layout",
    ]
    .iter()
    .enumerate()
    .for_each(|(i, desc)| println!("- {}: {}", i + 1, desc));

    Ok(())
}

fn create_layout_demo(screen_width: u16, screen_height: u16) -> Result<Vec<LayoutContainer>> {
    let mut containers = Vec::new();

    // Create header layout (horizontal)
    let header_bounds = Rectangle::new(0, 0, screen_width, 80);
    let mut header_layout = LayoutBuilder::horizontal(header_bounds)
        .with_padding(Spacing::uniform(10))
        .with_gap(20)
        .with_alignment(Alignment::Start);

    let header_text = TextComponent::new("X11 Overlay - Layout Demo", 0, 0, 400, 60)
        .with_font(FontDesc::new("DejaVu Sans", 18.0))
        .with_color(Color::rgba(1.0, 1.0, 1.0, 0.9));

    header_layout.add_component(Box::new(header_text));
    header_layout.layout()?; // Explicitly call layout
    containers.push(header_layout);

    // Create sidebar layout (vertical)
    let sidebar_bounds = Rectangle::new(0, 80, 200, screen_height.saturating_sub(80));
    let mut sidebar_layout = LayoutBuilder::vertical(sidebar_bounds)
        .with_padding(Spacing::uniform(10))
        .with_gap(10)
        .with_alignment(Alignment::Start);

    let status_panel = create_status_panel_component()?;
    sidebar_layout.add_component(status_panel);

    let info_text = create_info_text_component()?;
    sidebar_layout.add_component(info_text);
    sidebar_layout.layout()?; // Explicitly call layout

    containers.push(sidebar_layout);

    // Create main content area (grid layout)
    let main_bounds = Rectangle::new(
        200,
        80,
        screen_width.saturating_sub(200),
        screen_height.saturating_sub(160),
    );
    let mut main_layout = LayoutBuilder::grid(main_bounds, 2)
        .with_padding(Spacing::uniform(15))
        .with_gap(15)
        .with_alignment(Alignment::Center);

    let welcome_text = create_welcome_text_component()?;
    main_layout.add_component(welcome_text);

    let progress_bars = create_progress_bars_components()?;
    for bar in progress_bars {
        main_layout.add_component(bar);
    }
    main_layout.layout()?; // Explicitly call layout

    containers.push(main_layout);

    // Create bottom status bar (horizontal)
    let status_bounds =
        Rectangle::new(0, screen_height.saturating_sub(80) as i16, screen_width, 80);
    let mut status_layout = LayoutBuilder::horizontal(status_bounds)
        .with_padding(Spacing::uniform(10))
        .with_gap(20)
        .with_alignment(Alignment::End);

    let notification = create_notification_component()?;
    status_layout.add_component(notification);
    status_layout.layout()?; // Explicitly call layout

    containers.push(status_layout);

    Ok(containers)
}

fn create_status_panel_component() -> Result<Box<dyn Component>> {
    let mut status_panel = StatusPanel::new("System Status", 0, 0, 180, 120)
        .with_background_color(Color::rgba(0.059, 0.071, 0.090, 0.95)); // SLATE_900 with high opacity

    [
        "CPU: 45% (4.2GHz)",
        "Memory: 2.1GB / 8GB",
        "Disk: 78% (SSD)",
        "Network: Up 1.2MB/s Down 850KB/s",
        "Battery: 87%",
    ]
    .iter()
    .for_each(|line| status_panel.add_line(line));

    Ok(Box::new(status_panel))
}

fn create_welcome_text_component() -> Result<Box<dyn Component>> {
    let welcome_text = TextComponent::new("Welcome to X11 Overlay!", 0, 0, 300, 80)
        .with_font(FontDesc::new("DejaVu Sans", 20.0))
        .with_color(Color::rgba(0.376, 0.647, 0.984, 1.0)) // BLUE_400
        .centered();

    Ok(Box::new(welcome_text))
}

fn create_progress_bars_components() -> Result<Vec<Box<dyn Component>>> {
    let progress_configs = [
        (
            "Download Progress",
            0.75,
            Color::rgba(0.200, 0.831, 0.522, 1.0),
        ), // EMERALD_400
        (
            "Upload Progress",
            0.45,
            Color::rgba(0.235, 0.561, 0.969, 1.0),
        ), // BLUE_500
        ("Sync Progress", 0.85, Color::rgba(0.663, 0.408, 0.992, 1.0)), // PURPLE_500
    ];

    let progress_bars: Vec<Box<dyn Component>> = progress_configs
        .iter()
        .map(|(label, progress, color)| {
            let mut bar = ProgressBarComponent::new(label, 0, 0, 180)
                .with_colors(Color::rgba(0.118, 0.145, 0.180, 0.8), *color); // SLATE_800 background
            bar.set_progress(*progress);
            Box::new(bar) as Box<dyn Component>
        })
        .collect();

    Ok(progress_bars)
}

fn create_notification_component() -> Result<Box<dyn Component>> {
    let notification = NotificationComponent::new("System update available!", 0, 0, 250, 10.0)
        .with_background_color(Color::rgba(0.957, 0.620, 0.039, 0.95)); // AMBER_500

    Ok(Box::new(notification))
}

fn create_info_text_component() -> Result<Box<dyn Component>> {
    let info_text = TextComponent::new(
        "Layout System:\n- Automatic positioning\n- Flexible alignment\n- Grid/Flow layouts",
        0,
        0,
        180,
        80,
    )
    .with_font(FontDesc::new("DejaVu Sans", 11.0))
    .with_color(Color::rgba(0.925, 0.286, 0.631, 0.9)); // PINK_500

    Ok(Box::new(info_text))
}