Reference

A single-page summary of the public API. For full signatures, doc comments, and version-tracked details, see docs.rs/egui_citizen.

Dispatcher

use egui_citizen::Dispatcher;
CallWhat it does
Dispatcher::new()Empty dispatcher.
register(id) -> CitizenStateRegister a citizen; return a CitizenState handle.
get(&id) -> Option<&CitizenState>Look up a registered citizen's state.
activate(&id)One-hot: this one on, all others off. Emits messages.
send(message)Push a CitizenMessage onto the queue without activating.
drain_messages() -> Vec<CitizenMessage>Take all pending messages. Call once per frame.
len() / is_empty()Citizen count / emptiness.

See the dispatcher chapter for the one-hot invariant and the canonical drain loop.

Citizen trait

use egui_citizen::Citizen;
MethodProvided?Purpose
id() -> &CitizenIdrequiredStable identity.
citizen_state() -> &CitizenStaterequiredRead access to lifecycle state.
citizen_state_mut() -> &mut CitizenStaterequiredMutable access to lifecycle state.
on_activate()defaultSets citizen_state.active = true.
on_deactivate()defaultSets citizen_state.active = false.
on_click()defaultSets citizen_state.clicked = true.
is_active() -> booldefaultcitizen_state.active.get().
is_selected() -> booldefaultcitizen_state.selected.get().

See the Citizen trait chapter for the minimum-viable impl and override semantics.

CitizenState

use egui_citizen::CitizenState;

Six reactive Dynamic<T> fields:

FieldTypeMeaning
activeDynamic<bool>This citizen is the active one (one-hot).
clickedDynamic<bool>True for the frame this citizen was clicked.
selectedDynamic<bool>Persistent selection toggle.
movedDynamic<bool>Citizen moved to a new dock location.
locationDynamic<[f32; 2]>Last known dock-layout position.
visibleDynamic<bool>Citizen is currently visible.

Cloning a CitizenState clones the Arcs — every clone refers to the same storage. See Reactive lifecycle and Inside Dynamic<T> for the underlying machinery.

CitizenMessage

use egui_citizen::CitizenMessage;
VariantEmitted by
Activated { id }Dispatcher::activate(&id)
Deactivated { id }Dispatcher::activate(&id) for the previously active citizen
Clicked { id }App code via Dispatcher::send
Selected { id, selected: bool }App code via Dispatcher::send
Moved { id, location: [f32; 2] }App code via Dispatcher::send
VisibilityChanged { id, visible: bool }App code via Dispatcher::send

Derives: Debug, Clone. See the messages chapter.

CitizenId

pub struct CitizenId(pub String);

impl CitizenId {
    pub fn new(id: impl Into<String>) -> Self { /* ... */ }
}

Stable string identifier for a citizen. Define ids as consts in your app to make typos a compile-time error:

const PLOT_ID:    &str = "plot";
const LOGGER_ID:  &str = "logger";

Common idioms

Register and activate

let mut dispatcher = Dispatcher::new();
let plot_state = dispatcher.register(CitizenId::new("plot"));
dispatcher.activate(&CitizenId::new("plot"));

Implement Citizen on a panel struct

struct PlotPanel {
    citizen_id: CitizenId,
    citizen_state: CitizenState,
}

impl Citizen for PlotPanel {
    fn id(&self) -> &CitizenId               { &self.citizen_id }
    fn citizen_state(&self) -> &CitizenState  { &self.citizen_state }
    fn citizen_state_mut(&mut self) -> &mut CitizenState {
        &mut self.citizen_state
    }
}

Wire activation through egui_dock::TabViewer

fn on_tab_button(&mut self, tab: &mut Tab, response: &egui::Response) {
    if response.clicked() {
        self.dispatcher.activate(&tab.citizen_id());
    }
}

Drain messages once per frame

for msg in self.dispatcher.drain_messages() {
    match msg {
        CitizenMessage::Activated { id } => { /* ... */ }
        CitizenMessage::Deactivated { id } => { /* ... */ }
        _ => {}
    }
}

Wrap in your own AppMessage

pub enum AppMessage {
    Citizen(CitizenMessage),
    /* domain variants ... */
}

for msg in self.dispatcher.drain_messages() {
    let _ = self.tx_backend.send(AppMessage::Citizen(msg));
}

See also