Reference: The eframe::App Immediate-Mode Loop

One-page syntax and mental-model reference for Lessons 0001 & 0002. Keep open or print while writing egui panels.

1. The Mental Model (One Frame = One Function Call)

flowchart TD
    State["Persistent Rust Struct<br/>struct PcbReviewerApp { show_top_copper: bool, ... }"]
    State -->|"1. eframe calls ui(&mut self, ui, frame)"| Side["Panel::left('layers').show(ui, |ui| { ... })"]
    Side --> Checkbox["ui.checkbox(&mut self.show_top_copper, 'Top Copper (F.Cu)')"]
    Checkbox -->|"Reads bool to draw box<br/>Flips bool in-place if clicked"| Central["CentralPanel::default().show(ui, |ui| { ... })"]
    Central -->|"2. Reads updated self.show_top_copper"| Paint["Paints visible F.Cu traces & pads for this frame"]
    Paint -->|"3. End of ui(): borrow released"| State
  

The eframe::App::ui lifecycle across a single frame.

2. Complete Runnable Skeleton (src/main.rs)

use eframe::egui;

fn main() -> eframe::Result {
    let mut options = eframe::NativeOptions::default();
    options.viewport = egui::ViewportBuilder::default()
        .with_inner_size([1024.0, 720.0]);

    eframe::run_native(
        "Schematic & PCB Design Reviewer",
        options,
        Box::new(|_cc| Ok(Box::new(PcbReviewerApp::default()))),
    )
}

// 1. Persistent domain & view state lives in your struct
pub struct PcbReviewerApp {
    pub show_top_copper: bool,
    pub show_bottom_copper: bool,
    pub show_silkscreen: bool,
    pub show_ratsnest: bool,
}

impl Default for PcbReviewerApp {
    fn default() -> Self {
        let mut app = Self {
            show_top_copper: false,
            show_bottom_copper: false,
            show_silkscreen: false,
            show_ratsnest: false,
        };
        app.reset_layers();
        app
    }
}

impl PcbReviewerApp {
    pub fn reset_layers(&mut self) {
        self.show_top_copper = true;
        self.show_bottom_copper = true;
        self.show_silkscreen = true;
        self.show_ratsnest = false;
    }

    pub fn isolate_top_copper(&mut self) {
        self.show_top_copper = true;
        self.show_bottom_copper = false;
        self.show_silkscreen = false;
        self.show_ratsnest = false;
    }

    pub fn show_all_layers(&mut self) {
        self.show_top_copper = true;
        self.show_bottom_copper = true;
        self.show_silkscreen = true;
        self.show_ratsnest = true;
    }
}

// 2. Implement eframe::App to define the per-frame UI
impl eframe::App for PcbReviewerApp {
    fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
        // Always declare edge Panels (left/right/top/bottom) BEFORE CentralPanel!
        egui::Panel::left("layer_panel").show(ui, |ui| {
            ui.heading("PCB Layers");
            ui.checkbox(&mut self.show_top_copper, "Top Copper (F.Cu)");
            ui.checkbox(&mut self.show_bottom_copper, "Bottom Copper (B.Cu)");
            ui.checkbox(&mut self.show_silkscreen, "Silkscreen (F.SilkS)");
            ui.checkbox(&mut self.show_ratsnest, "Ratsnest (Unrouted)");

            ui.separator();
            if ui.button("Isolate Top Copper").clicked() {
                self.isolate_top_copper();
            }
            if ui.button("Show All Layers").clicked() {
                self.show_all_layers();
            }
        });

        egui::CentralPanel::default().show(ui, |ui| {
            ui.heading("PCB Viewport Ready");
        });
    }
}

3. Common Panel & Widget Signatures

Pattern Rust Code Why It Works This Way
Two-way boolean toggle ui.checkbox(&mut self.flag, "Label") Borrows self.flag mutably for the duration of the call; flips the boolean if clicked and returns a Response.
Momentary action button if ui.button("Reset").clicked() { ... } Buttons don't store a boolean; they return a Response whose .clicked() method is true on the frame the click occurred.
Panel ordering rule Panel first, CentralPanel last CentralPanel claims all remaining area left over in the root Ui after outer panels allocate their widths/heights (docs.rs).