delta-egui — egui Backend Edition

examples/delta-egui is the same RGB delay effect as delta — same DeltaEffect, same FrameHistory ring buffer, same DeltaState and DeltaUniforms — built with the egui control backend instead of ImGui.

cargo run -p delta-egui

Read the delta page for everything about the effect itself. This page covers only what changes when switching to egui.

Enabling the egui feature

# Cargo.toml
[dependencies]
rustjay-engine = { git = "...", features = ["egui"] }

Entry point

#![allow(unused)]
fn main() {
// ImGui version:
rustjay_engine::run_with_tabs(DeltaEffect::default(), vec![Box::new(MotionTab)])

// egui version:
rustjay_engine::run_with_egui_tabs(DeltaEffect::default(), vec![Box::new(MotionTab)])
}

One function name difference. The rest of the plugin — EffectPlugin impl, state, uniforms, render() — is identical.

Implementing a tab with egui

Implement AnyEguiTab instead of AnyGuiTab. The trait signature is the same, but draw receives &mut egui::Ui instead of &imgui::Ui:

#![allow(unused)]
fn main() {
// ImGui
impl AnyGuiTab for MotionTab {
    fn name(&self) -> &str { "Motion" }
    fn replaces(&self) -> Option<GuiTab> { Some(GuiTab::Motion) }

    fn draw(&mut self, ui: &imgui::Ui, app_state: &mut dyn Any, engine: &mut EngineState) {
        ui.slider_config("Intensity", 0.0_f32, 1.0_f32).build(&mut state.intensity);
    }
}

// egui
impl AnyEguiTab for MotionTab {
    fn name(&self) -> &str { "Motion" }
    fn replaces(&self) -> Option<GuiTab> { Some(GuiTab::Motion) }

    fn draw(&mut self, ui: &mut egui::Ui, app_state: &mut dyn Any, engine: &mut EngineState) {
        param_slider(ui, engine, "intensity", "Intensity", 0.0, 1.0);
    }
}
}

param_slider helpers

The prelude exports two egui-specific helpers that keep the engine's parameter registry in sync without boilerplate:

#![allow(unused)]
fn main() {
// Float slider — reads get_param_base, writes set_param_base on change
param_slider(ui, engine, "intensity", "Intensity", 0.0, 1.0);

// Integer slider
param_slider_int(ui, engine, "red_delay", "Red", 0, 16);
}

These are equivalent to:

#![allow(unused)]
fn main() {
let mut val = engine.get_param_base("intensity").unwrap_or(1.0);
if ui.add(egui::Slider::new(&mut val, 0.0..=1.0).text("Intensity")).changed() {
    engine.set_param_base("intensity", val);
}
}

For types not covered by the helpers (bool checkboxes, enum combo boxes), call engine.get_param_base / engine.set_param_base directly:

#![allow(unused)]
fn main() {
// Bool
let mut grayscale = engine.get_param_base("grayscale_input").unwrap_or(1.0) > 0.5;
if ui.checkbox(&mut grayscale, "Grayscale Input").changed() {
    engine.set_param_base("grayscale_input", if grayscale { 1.0 } else { 0.0 });
}

// Enum / combo
let mut idx = engine.get_param_base("blend_mode").unwrap_or(0.0).round() as usize;
egui::ComboBox::from_id_salt("blend_mode")
    .selected_text(blend_names[idx])
    .show_ui(ui, |ui| {
        for (i, name) in blend_names.iter().enumerate() {
            if ui.selectable_label(idx == i, *name).clicked() { idx = i; }
        }
    });
engine.set_param_base("blend_mode", idx as f32);
}

egui widget quick reference

#![allow(unused)]
fn main() {
// Headings and labels
ui.heading("Section title");
ui.label(egui::RichText::new("Bold label").strong());
ui.separator();

// Sliders (param_slider covers the common case)
ui.add(egui::Slider::new(&mut val, min..=max).text("Label"));

// Checkbox
ui.checkbox(&mut flag, "Label");

// Combo box
egui::ComboBox::from_id_salt("unique_id")
    .selected_text(current_label)
    .show_ui(ui, |ui| { /* selectable_label calls */ });

// Horizontal layout
ui.horizontal(|ui| { ui.label("Key:"); ui.label("Value"); });

// Group scoping (prevents id collisions across tabs)
ui.push_id("my_tab", |ui| { /* widgets */ });
}