Skip to content

Commit

Permalink
Merge pull request #21 from lucasmerlin/type-map-inboxes-and-router-e…
Browse files Browse the repository at this point in the history
…xample

Create type-map based inboxes and a broadcast channel.
  • Loading branch information
lucasmerlin authored May 4, 2024
2 parents ed660f4 + 887ea03 commit becfc8b
Show file tree
Hide file tree
Showing 9 changed files with 638 additions and 1 deletion.
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions crates/egui_inbox/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# egui_inbox changelog

## Unreleased

- Add broadcast (mpmc) channel to egui_inbox.
- Add [type-map](https://crates.io/crates/type-map) based versions of `UiInbox` and `Broadcast`.
- Add a complex example showcasing a simple application with different independent components interacting with each
other.

## 0.4.0

- egui_inbox now can be used without egui
Expand Down
10 changes: 9 additions & 1 deletion crates/egui_inbox/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ async = ["dep:hello_egui_utils", "hello_egui_utils/async", "dep:futures-channel"
tokio = ["async", "hello_egui_utils/tokio"]
egui = ["dep:egui"]
default = ["egui"]
broadcast = []
type_inbox = ["dep:type-map"]
type_broadcast = ["dep:type-map", "broadcast"]

[[example]]
name = "inbox_spawn"
Expand All @@ -26,8 +29,13 @@ futures = { version = "0.3", optional = true }
# Egui uses parking_lot so we should be fine with using it too (regarding compile times).
parking_lot = "0.12"

# For TypeInbox and TypeBroadcast
type-map = { version = "0.5.0", optional = true }

[dev-dependencies]
eframe = { workspace = true, default-features = true }
tokio = { version = "1", features = ["full"] }
ehttp = { version = "0.5.0", features = ["json"] }
serde_json = "1"
serde_json = "1"
rand = "0.8"
derive-new = "0.6"
133 changes: 133 additions & 0 deletions crates/egui_inbox/examples/broadcast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use eframe::NativeOptions;
use std::mem;

#[derive(Debug, Clone)]
enum AuthBroadcastMessage {
LoggedIn { user: String },
LoggedOut,
}

#[derive(Debug, Clone)]
struct AppState {
auth_broadcast: egui_inbox::broadcast::Broadcast<AuthBroadcastMessage>,
}

struct AuthUi {
app_state: AppState,
logged_in_as: Option<String>,

username_input: String,
}

impl AuthUi {
fn ui(&mut self, ui: &mut egui::Ui) {
let mut logout = false;
if let Some(user) = &self.logged_in_as {
ui.label(format!("Logged in as: {}", user));
if ui.button("Log out").clicked() {
self.app_state
.auth_broadcast
.send(AuthBroadcastMessage::LoggedOut);
logout = true;
}
} else {
ui.label("Not logged in");

ui.label("Username:");
ui.text_edit_singleline(&mut self.username_input);

if ui.button("Log in").clicked() {
self.app_state
.auth_broadcast
.send(AuthBroadcastMessage::LoggedIn {
user: self.username_input.clone(),
});

self.logged_in_as = Some(mem::take(&mut self.username_input));
self.username_input.clear();
}
}

if logout {
self.logged_in_as = None;
}
}
}

struct UserRandomNumberUi {
user: Option<String>,
random_number: Option<u32>,
auth_rx: egui_inbox::broadcast::BroadcastReceiver<AuthBroadcastMessage>,
}

impl UserRandomNumberUi {
fn ui(&mut self, ui: &mut egui::Ui) {
self.auth_rx.read(ui).for_each(|event| match event {
AuthBroadcastMessage::LoggedIn { user } => {
self.user = Some(user);
self.random_number = Some(rand::random());
}
AuthBroadcastMessage::LoggedOut => {
self.user = None;
self.random_number = None;
}
});

if let Some((user, number)) = self.user.as_ref().zip(self.random_number.as_ref()) {
ui.label(format!("{user}'s random number: {number}"));
} else {
ui.label("Not logged in");
}
}
}

impl AppState {
fn new() -> Self {
Self {
auth_broadcast: egui_inbox::broadcast::Broadcast::new(),
}
}
}

#[cfg(feature = "broadcast")]
fn main() {
let state = AppState::new();

let mut auth_ui = AuthUi {
app_state: state.clone(),
logged_in_as: None,
username_input: String::new(),
};

let mut user_random_number_ui = UserRandomNumberUi {
user: None,
random_number: None,
auth_rx: state.auth_broadcast.subscribe(),
};

eframe::run_simple_native(
"Broadcast Example",
NativeOptions::default(),
move |ctx, _frame| {
egui::CentralPanel::default().show(ctx, |ui| {
ui.vertical(|ui| {
ui.group(|ui| {
ui.heading("Auth");
auth_ui.ui(ui);
});

ui.group(|ui| {
ui.heading("User Random Number");
user_random_number_ui.ui(ui);
});
});
});
},
)
.unwrap();
}

#[cfg(not(feature = "broadcast"))]
fn main() {
panic!("This example requires the `broadcast` feature to be enabled.");
}
Loading

0 comments on commit becfc8b

Please sign in to comment.