egelm 0.2.1

A simple Elm-like framework for building GUI applications in Rust using egui.
Documentation

egelm

egelm is a small app framework for building native GUI applications in Rust with egui. It adds a typed, message-driven widget lifecycle, child-widget management, asynchronous tasks, error routing, and reusable dialogs on top of egui.

Features

  • Typed messages, outputs, and errors for each widget
  • Managed<T> child widgets with automatic message processing
  • A #[derive(Widget)] macro that updates managed children
  • Background work through Tokio
  • Window hide/show controls and customizable close behavior
  • Root-level error handling with a built-in error dialog
  • Reusable about dialog and emoji helpers

Installation

Add egelm and Tokio to your application:

[dependencies]
egelm = "0.1.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

The default egelm features enable Ctrl-C handling, tracing, and emoji support.

Quick start

use egelm::prelude::*;

#[derive(Debug)]
enum Message {
    Increment,
}

#[derive(Debug, Widget)]
struct Counter {
    count: u32,
}

impl Widget for Counter {
    type Message = Message;
    type Output = ();
    type Error = ();

    fn view(&mut self, ui: &mut egui::Ui, _frame: &mut Frame, ctx: &Context<Self>) {
        ui.heading(format!("Count: {}", self.count));

        if ui.button("Increment").clicked() {
            ctx.emit(Message::Increment);
        }
    }

    fn update(&mut self, message: Self::Message, _handle: &Handle, _ctx: &Context<Self>) -> Result<(), Self::Error> {
        match message {
            Message::Increment => self.count += 1,
        }

        Ok(())
    }
}

impl RootWidget for Counter {}

#[tokio::main]
async fn main() {
    App::new(Counter { count: 0 })
        .run(ViewportBuilder::default().with_title("Counter"))
        .unwrap();
}

Run the application with:

cargo run

How it works

An egelm application is composed of widgets:

  • Widget is the full lifecycle trait. Its view method renders UI, while update handles typed messages and tick performs per-cycle work.
  • LeafWidget is a simpler rendering-only trait for components that do not need messages, outputs, or errors.
  • RootWidget represents the top-level application and can customize window closing, error presentation, and initial egui setup.
  • Context<W> lets a widget emit messages, send output to its parent, report errors, and spawn asynchronous tasks.
  • Managed<W> owns a child widget together with its message queue and context.

Deriving Widget implements child ticking for all named Managed<T> fields:

#[derive(Debug, Widget)]
struct Parent {
    child: Managed<Child>,
}

This keeps child message routing automatic while preserving concrete, compile-time message types.

AI usage

AI tools are used only to help create documentation, including this README. No AI-assisted content is committed without first being read and reviewed by a human.

License

This project is available under the MIT License.