1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-31 05:40:03 -04:00

Merge branch 'main' into lucas/experiments/helpful-id-debug

# Conflicts:
#	crates/egui/src/containers/combo_box.rs
#	crates/egui/src/id.rs
#	crates/egui/src/lib.rs
#	crates/egui/src/ui.rs
#	crates/egui/src/ui_builder.rs
This commit is contained in:
lucasmerlin
2026-02-17 17:13:12 +01:00
594 changed files with 22240 additions and 11164 deletions

View File

@@ -1,10 +1,10 @@
# `egui` and `eframe` examples
All the examples in this folder uses [`eframe`](https://github.com/emilk/egui/tree/master/crates/eframe) to set up a window for [`egui`](https://github.com/emilk/egui/). Some examples are specific to `eframe`, but many are applicable to any `egui` integration.
All the examples in this folder uses [`eframe`](https://github.com/emilk/egui/tree/main/crates/eframe) to set up a window for [`egui`](https://github.com/emilk/egui/). Some examples are specific to `eframe`, but many are applicable to any `egui` integration.
There are a lot more examples at <https://www.egui.rs>, and it has links to the source code of each example.
Also check out the official docs at <https://docs.rs/egui> and <https://docs.rs/eframe>.
Note that all the examples on `master` are for the latest `master` version of `egui`.
Note that all the examples on `main` are for the latest `main` version of `egui`.
If you want to look for examples for a specific version of egui, go to that tag, e.g. <https://github.com/emilk/egui/tree/latest/examples>.

View File

@@ -3,8 +3,8 @@ name = "confirm_exit"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,10 +13,7 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3122591a76a063f1db0b88b54ecc4afe012ee27a1404c0948d0b9d639aeeece6
size 3124
oid sha256:79ee820be9374c44e684373acb62fe7bcfaa2347346d1aed8083a706f6cae8c9
size 3798

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
@@ -23,16 +23,16 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("Try to close the window");
});
if ctx.input(|i| i.viewport().close_requested()) {
if ui.input(|i| i.viewport().close_requested()) {
if self.allowed_to_close {
// do nothing - we will close
} else {
ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);
ui.send_viewport_cmd(egui::ViewportCommand::CancelClose);
self.show_confirmation_dialog = true;
}
}
@@ -41,7 +41,7 @@ impl eframe::App for MyApp {
egui::Window::new("Do you want to quit?")
.collapsible(false)
.resizable(false)
.show(ctx, |ui| {
.show(ui.ctx(), |ui| {
ui.horizontal(|ui| {
if ui.button("No").clicked() {
self.show_confirmation_dialog = false;
@@ -51,7 +51,7 @@ impl eframe::App for MyApp {
if ui.button("Yes").clicked() {
self.show_confirmation_dialog = false;
self.allowed_to_close = true;
ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close);
ui.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
});

View File

@@ -3,8 +3,8 @@ name = "custom_3d_glow"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,10 +13,8 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"glow",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4dd5ffcf5a530f6fbe959fd74e2f5b4aeaee335baf79ad1cde8e42c34d84156c
size 24590
oid sha256:c02ea6a9b0f2d215255b5550237f3d9aa43b257849591cc8a1cd206f401c2747
size 28455

View File

@@ -1,7 +1,7 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![allow(unsafe_code)]
#![allow(clippy::undocumented_unsafe_blocks)]
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(unsafe_code)]
#![expect(clippy::undocumented_unsafe_blocks)]
use eframe::{egui, egui_glow, glow};
@@ -43,8 +43,8 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
ui.label("The triangle is being painted using ");
@@ -75,7 +75,7 @@ impl MyApp {
// Clone locals so we can move them into the paint callback:
let angle = self.angle;
let rotating_triangle = self.rotating_triangle.clone();
let rotating_triangle = Arc::clone(&self.rotating_triangle);
let callback = egui::PaintCallback {
rect,

View File

@@ -3,8 +3,8 @@ name = "custom_font"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,10 +13,7 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d0ab12a55c0d87f044ef7675f5b94b39977f2c5d3a2ea74eb843dfc85d5b9f31
size 5645
oid sha256:c13f5b5f70c194316bbb116700619fd1611f423ae86244d1668f21ba622aaa45
size 7104

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::{
egui,
@@ -86,8 +86,8 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("egui using custom fonts");
ui.text_edit_multiline(&mut self.text);
});

View File

@@ -3,8 +3,8 @@ name = "custom_font_style"
version = "0.1.0"
authors = ["tami5 <kkharji@proton.me>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,10 +13,7 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5d443ef30cf12d2c4367135fd663270ed46f4864af2f3aae424610be86c73197
size 66193
oid sha256:3d705d757b1689f3730a673988ffd2b3f8c1729c8c84b4236cd72593420ff0bd
size 109694

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
use egui::{FontFamily, FontId, RichText, TextStyle};
@@ -65,8 +65,8 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, content);
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, content);
}
}

View File

@@ -3,8 +3,8 @@ name = "custom_keypad"
version = "0.1.0"
authors = ["Varphone Wong <varphone@qq.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,14 +13,11 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
# For image support:
egui_extras = { workspace = true, features = ["default", "image"] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,4 +1,4 @@
use eframe::egui::{self, pos2, vec2, Button, Ui, Vec2};
use eframe::egui::{self, Button, Ui, Vec2, pos2, vec2};
#[derive(Clone, Copy, Debug, Default, PartialEq)]
enum Transition {
@@ -179,9 +179,9 @@ impl Keypad {
)
});
let mut is_first_show = false;
if ctx.wants_keyboard_input() && state.focus != focus {
let y = ctx.style().spacing.interact_size.y * 1.25;
let is_first_show = ctx.egui_wants_keyboard_input() && state.focus != focus;
if is_first_show {
let y = ctx.global_style().spacing.interact_size.y * 1.25;
state.open = true;
state.start_pos = ctx.input(|i| {
i.pointer
@@ -189,7 +189,6 @@ impl Keypad {
.map_or(pos2(100.0, 100.0), |p| p + vec2(0.0, y))
});
state.focus = focus;
is_first_show = true;
}
if state.close_on_next_frame {

View File

@@ -1,5 +1,5 @@
// #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
mod keypad;
@@ -44,11 +44,11 @@ impl Default for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::Window::new("Custom Keypad")
.default_pos([100.0, 100.0])
.title_bar(true)
.show(ctx, |ui| {
.show(ui.ctx(), |ui| {
ui.horizontal(|ui| {
ui.label("Your name: ");
ui.text_edit_singleline(&mut self.name);
@@ -60,7 +60,7 @@ impl eframe::App for MyApp {
ui.label(format!("Hello '{}', age {}", self.name, self.age));
});
self.keypad.show(ctx);
self.keypad.show(ui.ctx());
}
fn raw_input_hook(&mut self, ctx: &egui::Context, raw_input: &mut egui::RawInput) {

View File

@@ -2,8 +2,8 @@
name = "custom_style"
version = "0.1.0"
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -16,13 +16,10 @@ ignored = ["image"] # We need the .png feature
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
egui_demo_lib.workspace = true
egui_extras = { workspace = true, features = ["image"] }
image = { workspace = true, features = ["png"] }

View File

@@ -1,10 +1,10 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui::{
self, global_theme_preference_buttons, style::Selection, Color32, Stroke, Style, Theme,
self, Color32, Stroke, Style, Theme, global_theme_preference_buttons, style::Selection,
};
use egui_demo_lib::{View, WidgetGallery};
use egui_demo_lib::{View as _, WidgetGallery};
fn main() -> eframe::Result {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
@@ -57,8 +57,8 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("egui using a customized style");
ui.label("Switch between dark and light mode to see the different styles in action.");
global_theme_preference_buttons(ui);

View File

@@ -3,8 +3,8 @@ name = "custom_window_frame"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,10 +13,7 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bfdf77d119ae7926f52ac781455c4b1574eea53276069614738ba8b13b9921ea
size 6024
oid sha256:8d153d2468d7099f2da099c5ea65329196a83baf112b292de1c5a6ce758dfced
size 17635

View File

@@ -31,8 +31,8 @@ impl eframe::App for MyApp {
egui::Rgba::TRANSPARENT.to_array() // Make sure we don't paint anything behind the rounded corners
}
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
custom_window_frame(ctx, "egui with custom frame", |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
custom_window_frame(ui, "egui with custom frame", |ui| {
ui.label("This is just the contents of the window.");
ui.horizontal(|ui| {
ui.label("egui theme:");
@@ -42,18 +42,20 @@ impl eframe::App for MyApp {
}
}
fn custom_window_frame(ctx: &egui::Context, title: &str, add_contents: impl FnOnce(&mut egui::Ui)) {
use egui::{CentralPanel, UiBuilder};
fn custom_window_frame(ui: &mut egui::Ui, title: &str, add_contents: impl FnOnce(&mut egui::Ui)) {
use egui::UiBuilder;
let panel_frame = egui::Frame::new()
.fill(ctx.style().visuals.window_fill())
.fill(ui.global_style().visuals.window_fill())
.corner_radius(10)
.stroke(ctx.style().visuals.widgets.noninteractive.fg_stroke)
.stroke(ui.global_style().visuals.widgets.noninteractive.fg_stroke)
.outer_margin(1); // so the stroke is within the bounds
CentralPanel::default().frame(panel_frame).show(ctx, |ui| {
panel_frame.show(ui, |ui| {
let app_rect = ui.max_rect();
ui.expand_to_include_rect(app_rect); // Expand frame to include it all
let title_bar_height = 32.0;
let title_bar_rect = {
let mut rect = app_rect;
@@ -75,7 +77,7 @@ fn custom_window_frame(ctx: &egui::Context, title: &str, add_contents: impl FnOn
}
fn title_bar_ui(ui: &mut egui::Ui, title_bar_rect: eframe::epaint::Rect, title: &str) {
use egui::{vec2, Align2, FontId, Id, PointerButton, Sense, UiBuilder};
use egui::{Align2, FontId, Id, PointerButton, Sense, UiBuilder, vec2};
let painter = ui.painter();
@@ -106,12 +108,11 @@ fn title_bar_ui(ui: &mut egui::Ui, title_bar_rect: eframe::epaint::Rect, title:
// Interact with the title bar (drag to move window):
if title_bar_response.double_clicked() {
let is_maximized = ui.input(|i| i.viewport().maximized.unwrap_or(false));
ui.ctx()
.send_viewport_cmd(ViewportCommand::Maximized(!is_maximized));
ui.send_viewport_cmd(ViewportCommand::Maximized(!is_maximized));
}
if title_bar_response.drag_started_by(PointerButton::Primary) {
ui.ctx().send_viewport_cmd(ViewportCommand::StartDrag);
ui.send_viewport_cmd(ViewportCommand::StartDrag);
}
ui.scope_builder(
@@ -137,7 +138,7 @@ fn close_maximize_minimize(ui: &mut egui::Ui) {
.add(Button::new(RichText::new("").size(button_height)))
.on_hover_text("Close the window");
if close_response.clicked() {
ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close);
ui.send_viewport_cmd(egui::ViewportCommand::Close);
}
let is_maximized = ui.input(|i| i.viewport().maximized.unwrap_or(false));
@@ -146,15 +147,14 @@ fn close_maximize_minimize(ui: &mut egui::Ui) {
.add(Button::new(RichText::new("🗗").size(button_height)))
.on_hover_text("Restore window");
if maximized_response.clicked() {
ui.ctx()
.send_viewport_cmd(ViewportCommand::Maximized(false));
ui.send_viewport_cmd(ViewportCommand::Maximized(false));
}
} else {
let maximized_response = ui
.add(Button::new(RichText::new("🗗").size(button_height)))
.on_hover_text("Maximize window");
if maximized_response.clicked() {
ui.ctx().send_viewport_cmd(ViewportCommand::Maximized(true));
ui.send_viewport_cmd(ViewportCommand::Maximized(true));
}
}
@@ -162,6 +162,6 @@ fn close_maximize_minimize(ui: &mut egui::Ui) {
.add(Button::new(RichText::new("🗕").size(button_height)))
.on_hover_text("Minimize the window");
if minimized_response.clicked() {
ui.ctx().send_viewport_cmd(ViewportCommand::Minimized(true));
ui.send_viewport_cmd(ViewportCommand::Minimized(true));
}
}

View File

@@ -0,0 +1,22 @@
[package]
name = "external_eventloop"
version = "0.1.0"
authors = ["Will Brown <opensource@rebeagle.com>"]
license = "MIT OR Apache-2.0"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
winit.workspace = true

View File

@@ -0,0 +1,7 @@
Example running an eframe application on an external eventloop.
This allows you to run your eframe application alongside other windows and/or toolkits on the same event loop.
```sh
cargo run -p external_eventloop
```

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:52c47927d0c4caace5e5489cb3c6e4880f4f29b34378e072222ad8492225fef0
size 9366

View File

@@ -0,0 +1,89 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![expect(rustdoc::missing_crate_level_docs, clippy::unwrap_used)] // it's an example
use eframe::{UserEvent, egui};
use std::{cell::Cell, rc::Rc};
use winit::event_loop::{ControlFlow, EventLoop};
fn main() -> eframe::Result {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
..Default::default()
};
let eventloop = EventLoop::<UserEvent>::with_user_event().build().unwrap();
eventloop.set_control_flow(ControlFlow::Poll);
let mut winit_app = eframe::create_native(
"External Eventloop Application",
options,
Box::new(|_| Ok(Box::<MyApp>::default())),
&eventloop,
);
eventloop.run_app(&mut winit_app)?;
Ok(())
}
struct MyApp {
value: Rc<Cell<u32>>,
spin: bool,
blinky: bool,
}
impl Default for MyApp {
fn default() -> Self {
Self {
value: Rc::new(Cell::new(42)),
spin: false,
blinky: false,
}
}
}
impl eframe::App for MyApp {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("My External Eventloop Application");
ui.horizontal(|ui| {
if ui.button("Increment Now").clicked() {
self.value.set(self.value.get() + 1);
}
});
ui.label(format!("Value: {}", self.value.get()));
if ui.button("Toggle Spinner").clicked() {
self.spin = !self.spin;
}
if ui.button("Toggle Blinky").clicked() {
self.blinky = !self.blinky;
}
if self.spin {
ui.spinner();
}
if self.blinky {
let now = ui.input(|i| i.time);
let blink = now % 1.0 < 0.5;
egui::Frame::new()
.inner_margin(3)
.corner_radius(5)
.fill(if blink {
egui::Color32::RED
} else {
egui::Color32::TRANSPARENT
})
.show(ui, |ui| {
ui.label("Blinky!");
});
ui.request_repaint_after_secs((0.5 - (now % 0.5)) as f32);
}
});
}
}

View File

@@ -0,0 +1,32 @@
[package]
name = "external_eventloop_async"
version = "0.1.0"
authors = ["Will Brown <opensource@rebeagle.com>"]
license = "MIT OR Apache-2.0"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
workspace = true
[features]
linux-example = []
[[bin]]
name = "external_eventloop_async"
required-features = ["linux-example"]
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
log.workspace = true
winit.workspace = true
tokio = { workspace = true, features = ["rt", "time", "net"] }

View File

@@ -0,0 +1,10 @@
Example running an eframe application on an external eventloop on top of a tokio executor on Linux.
By running the event loop, eframe, and tokio in the same thread, one can leverage local async tasks.
These tasks can share data with the UI without the need for locks or message passing.
In tokio CPU-bound async tasks can be run with `spawn_blocking` to avoid impacting the UI frame rate.
```sh
cargo run -p external_eventloop_async --features linux-example
```

View File

@@ -0,0 +1,134 @@
#![expect(clippy::unwrap_used)] // It's an example
use std::{cell::Cell, io, os::fd::AsRawFd as _, rc::Rc, time::Duration};
use tokio::task::LocalSet;
use winit::event_loop::{ControlFlow, EventLoop};
use eframe::{EframePumpStatus, UserEvent, egui};
pub fn run() -> io::Result<()> {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
..Default::default()
};
let mut eventloop = EventLoop::<UserEvent>::with_user_event().build().unwrap();
eventloop.set_control_flow(ControlFlow::Poll);
let mut winit_app = eframe::create_native(
"External Eventloop Application",
options,
Box::new(|_| Ok(Box::<MyApp>::default())),
&eventloop,
);
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
let local = LocalSet::new();
local.block_on(&rt, async {
let eventloop_fd = tokio::io::unix::AsyncFd::new(eventloop.as_raw_fd())?;
let mut control_flow = ControlFlow::Poll;
loop {
let mut guard = match control_flow {
ControlFlow::Poll => None,
ControlFlow::Wait => Some(eventloop_fd.readable().await?),
ControlFlow::WaitUntil(deadline) => {
tokio::time::timeout_at(deadline.into(), eventloop_fd.readable())
.await
.ok()
.transpose()?
}
};
match winit_app.pump_eframe_app(&mut eventloop, None) {
EframePumpStatus::Continue(next) => control_flow = next,
EframePumpStatus::Exit(code) => {
log::info!("exit code: {code}");
break;
}
}
if let Some(mut guard) = guard.take() {
guard.clear_ready();
}
}
Ok::<_, io::Error>(())
})
}
struct MyApp {
value: Rc<Cell<u32>>,
spin: bool,
blinky: bool,
}
impl Default for MyApp {
fn default() -> Self {
Self {
value: Rc::new(Cell::new(42)),
spin: false,
blinky: false,
}
}
}
impl eframe::App for MyApp {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("My External Eventloop Application");
ui.horizontal(|ui| {
if ui.button("Increment Now").clicked() {
self.value.set(self.value.get() + 1);
}
if ui.button("Increment Later").clicked() {
let value = Rc::clone(&self.value);
let ctx = ui.ctx().clone();
tokio::task::spawn_local(async move {
tokio::time::sleep(Duration::from_secs(1)).await;
value.set(value.get() + 1);
ctx.request_repaint();
});
}
});
ui.label(format!("Value: {}", self.value.get()));
if ui.button("Toggle Spinner").clicked() {
self.spin = !self.spin;
}
if ui.button("Toggle Blinky").clicked() {
self.blinky = !self.blinky;
}
if self.spin {
ui.spinner();
}
if self.blinky {
let now = ui.input(|i| i.time);
let blink = now % 1.0 < 0.5;
egui::Frame::new()
.inner_margin(3)
.corner_radius(5)
.fill(if blink {
egui::Color32::RED
} else {
egui::Color32::TRANSPARENT
})
.show(ui, |ui| {
ui.label("Blinky!");
});
ui.request_repaint_after_secs((0.5 - (now % 0.5)) as f32);
}
});
}
}

View File

@@ -0,0 +1,16 @@
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
#[cfg(target_os = "linux")]
mod app;
#[cfg(target_os = "linux")]
fn main() -> std::io::Result<()> {
app::run()
}
// Do not check `app` on unsupported platforms when check "--all-features" is used in CI.
#[cfg(not(target_os = "linux"))]
fn main() {
#![expect(clippy::print_stdout)]
println!("This example only supports Linux.");
}

View File

@@ -3,8 +3,8 @@ name = "file_dialog"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,11 +13,8 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
] }
rfd = "0.15.3"
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
rfd.workspace = true

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fb8e0b6d09f6d4c598f4a4d91f849a6221acbfaab55711f890b03d551967d3a8
size 3996
oid sha256:93689f54b621ab0e978a123492ba64615e67815c39df7e3869f233cdd16f6ded
size 5558

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
@@ -25,14 +25,14 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.label("Drag-and-drop files onto the window!");
if ui.button("Open file…").clicked() {
if let Some(path) = rfd::FileDialog::new().pick_file() {
self.picked_path = Some(path.display().to_string());
}
if ui.button("Open file…").clicked()
&& let Some(path) = rfd::FileDialog::new().pick_file()
{
self.picked_path = Some(path.display().to_string());
}
if let Some(picked_path) = &self.picked_path {
@@ -73,10 +73,10 @@ impl eframe::App for MyApp {
}
});
preview_files_being_dropped(ctx);
preview_files_being_dropped(ui.ctx());
// Collect dropped files:
ctx.input(|i| {
ui.input(|i| {
if !i.raw.dropped_files.is_empty() {
self.dropped_files.clone_from(&i.raw.dropped_files);
}
@@ -107,13 +107,13 @@ fn preview_files_being_dropped(ctx: &egui::Context) {
let painter =
ctx.layer_painter(LayerId::new(Order::Foreground, Id::new("file_drop_target")));
let screen_rect = ctx.screen_rect();
painter.rect_filled(screen_rect, 0.0, Color32::from_black_alpha(192));
let content_rect = ctx.content_rect();
painter.rect_filled(content_rect, 0.0, Color32::from_black_alpha(192));
painter.text(
screen_rect.center(),
content_rect.center(),
Align2::CENTER_CENTER,
text,
TextStyle::Heading.resolve(&ctx.style()),
TextStyle::Heading.resolve(&ctx.global_style()),
Color32::WHITE,
);
}

View File

@@ -3,8 +3,8 @@ name = "hello_android"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
# `unsafe_code` is required for `#[no_mangle]`, disable workspace lints to workaround lint error.
@@ -17,15 +17,19 @@ crate-type = ["cdylib", "lib"]
[dependencies]
eframe = { workspace = true, features = ["default", "android-native-activity"] }
eframe = { workspace = true, default-features = false, features = [
"default_fonts",
"glow",
"android-native-activity",
] }
egui_demo_lib = { workspace = true, features = ["chrono"] }
# For image support:
egui_extras = { workspace = true, features = ["default", "image"] }
log = { workspace = true }
winit = { workspace = true }
android_logger = "0.14"
android_logger.workspace = true
log.workspace = true
winit.workspace = true
[package.metadata.android]
build_targets = ["armv7-linux-androideabi", "aarch64-linux-android"]

View File

@@ -1,6 +1,6 @@
#![doc = include_str!("../README.md")]
use eframe::{egui, CreationContext};
use eframe::{CreationContext, egui};
#[cfg(target_os = "android")]
#[no_mangle]
@@ -36,15 +36,17 @@ impl MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
// Reserve some space at the top so the demo ui isn't hidden behind the android status bar
// TODO(lucasmerlin): This is a pretty big hack, should be fixed once safe_area implemented
// for android:
// https://github.com/rust-windowing/winit/issues/3910
egui::TopBottomPanel::top("status_bar_space").show(ctx, |ui| {
egui::Panel::top("status_bar_space").show_inside(ui, |ui| {
ui.set_height(32.0);
});
self.demo.ui(ctx);
egui::CentralPanel::default().show_inside(ui, |ui| {
self.demo.ui(ui);
});
}
}

View File

@@ -3,8 +3,8 @@ name = "hello_world"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,14 +13,11 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
# For image support:
egui_extras = { workspace = true, features = ["default", "image"] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
@@ -36,8 +36,8 @@ impl Default for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("My egui Application");
ui.horizontal(|ui| {
let name_label = ui.label("Your name: ");

View File

@@ -3,8 +3,8 @@ name = "hello_world_par"
version = "0.1.0"
authors = ["Maxim Osipenko <maxim1999max@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -17,16 +17,13 @@ ignored = ["winit"] # Just enable some features of it; see below
[dependencies]
eframe = { workspace = true, default-features = false, features = [
# accesskit struggles with threading
"default_fonts",
"wayland",
"x11",
"wgpu",
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
# accesskit struggles with threading
"default_fonts",
"wayland",
"x11",
"wgpu",
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
# This is normally enabled by eframe/default, which is not being used here
# because of accesskit, as mentioned above
winit = { workspace = true, features = ["default"] }

View File

@@ -1,7 +1,7 @@
//! This example shows that you can use egui in parallel from multiple threads.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(clippy::unwrap_used)] // it's an example
use std::sync::mpsc;
use std::thread::JoinHandle;
@@ -116,15 +116,15 @@ impl std::ops::Drop for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::Window::new("Main thread").show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::Window::new("Main thread").show(ui.ctx(), |ui| {
if ui.button("Spawn another thread").clicked() {
self.spawn_thread();
}
});
for (_handle, show_tx) in &self.threads {
let _ = show_tx.send(ctx.clone());
let _ = show_tx.send(ui.ctx().clone());
}
for _ in 0..self.threads.len() {

View File

@@ -3,8 +3,8 @@ name = "hello_world_simple"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,10 +13,7 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0bb13d0cb819d30ffbcd12d9327589a1e3ca226943cb381fa17eccfb8f7c06fb
size 3229
oid sha256:7cde6a351fbcf5a5d3b5474353c627a9c93801563880b7ff41dfa025da3c6d37
size 8587

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
use eframe::egui::{Id, Ui};
@@ -16,8 +16,8 @@ fn main() -> eframe::Result {
let mut name = "Arthur".to_owned();
let mut age = 42;
eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
egui::CentralPanel::default().show(ctx, |ui| {
eframe::run_ui_native("My egui App", options, move |ui, _frame| {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("My egui Application");
ui.horizontal(|ui| {
let name_label = ui.label("Your name: ");

View File

@@ -3,8 +3,8 @@ name = "images"
version = "0.1.0"
authors = ["Jan Procházka <github.com/jprochazk>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -21,8 +21,5 @@ eframe = { workspace = true, features = [
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
egui_extras = { workspace = true, features = ["default", "all_loaders"] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
image = { workspace = true, features = ["jpeg", "png"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a836741d52e1972b2047cefaabf59f601637d430d4b41bf6407ebda4f7931dac
size 273450
oid sha256:aab48522ee4e3382982a0ee558a78e7b501ab4205c793a66078c6e74631bd7a5
size 79718

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
@@ -24,8 +24,8 @@ fn main() -> eframe::Result {
struct MyApp {}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
egui::ScrollArea::both().show(ui, |ui| {
ui.image(egui::include_image!("cat.webp"))
.on_hover_text_at_pointer("WebP");

View File

@@ -3,8 +3,8 @@ name = "keyboard_events"
version = "0.1.0"
authors = ["Jose Palazon <jose@palako.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,10 +13,7 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6cf53e0da26c4295bafe9cbb9ea0ad8c50933e29eb67467c3a11783697ec5494
size 7525
oid sha256:c4b314fc336e6cf027594b3ca123318bc4772fb611486170fd370cfa6a56edc5
size 9599

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
use egui::{Key, ScrollArea};
@@ -20,8 +20,8 @@ struct Content {
}
impl eframe::App for Content {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("Press/Hold/Release example. Press A to test.");
if ui.button("Clear").clicked() {
self.text.clear();
@@ -33,14 +33,14 @@ impl eframe::App for Content {
ui.label(&self.text);
});
if ctx.input(|i| i.key_pressed(Key::A)) {
if ui.input(|i| i.key_pressed(Key::A)) {
self.text.push_str("\nPressed");
}
if ctx.input(|i| i.key_down(Key::A)) {
if ui.input(|i| i.key_down(Key::A)) {
self.text.push_str("\nHeld");
ui.ctx().request_repaint(); // make sure we note the holding.
ui.request_repaint(); // make sure we note the holding.
}
if ctx.input(|i| i.key_released(Key::A)) {
if ui.input(|i| i.key_released(Key::A)) {
self.text.push_str("\nReleased");
}
});

View File

@@ -3,8 +3,8 @@ name = "multiple_viewports"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -15,10 +15,7 @@ wgpu = ["eframe/wgpu"]
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,9 +1,9 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
atomic::{AtomicBool, Ordering},
};
use eframe::egui;
@@ -35,8 +35,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.label("Hello from the root viewport");
ui.checkbox(
@@ -44,55 +44,68 @@ impl eframe::App for MyApp {
"Show immediate child viewport",
);
let mut show_deferred_viewport = self.show_deferred_viewport.load(Ordering::Relaxed);
ui.checkbox(&mut show_deferred_viewport, "Show deferred child viewport");
self.show_deferred_viewport
.store(show_deferred_viewport, Ordering::Relaxed);
{
let mut show_deferred_viewport =
self.show_deferred_viewport.load(Ordering::Relaxed);
ui.checkbox(&mut show_deferred_viewport, "Show deferred child viewport");
self.show_deferred_viewport
.store(show_deferred_viewport, Ordering::Relaxed);
}
ui.add_space(16.0);
{
let mut embedded = ui.embed_viewports();
ui.checkbox(&mut embedded, "Embed all viewports");
ui.set_embed_viewports(embedded);
}
});
if self.show_immediate_viewport {
ctx.show_viewport_immediate(
ui.ctx().show_viewport_immediate(
egui::ViewportId::from_hash_of("immediate_viewport"),
egui::ViewportBuilder::default()
.with_title("Immediate Viewport")
.with_inner_size([200.0, 100.0]),
|ctx, class| {
assert!(
class == egui::ViewportClass::Immediate,
"This egui backend doesn't support multiple viewports"
);
|ui, class| {
if class == egui::ViewportClass::EmbeddedWindow {
ui.label(
"This viewport is embedded in the parent window, and cannot be moved outside of it.",
);
} else {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.label("Hello from immediate viewport");
egui::CentralPanel::default().show(ctx, |ui| {
ui.label("Hello from immediate viewport");
});
if ctx.input(|i| i.viewport().close_requested()) {
// Tell parent viewport that we should not show next frame:
self.show_immediate_viewport = false;
if ui.input(|i| i.viewport().close_requested()) {
// Tell parent viewport that we should not show next frame:
self.show_immediate_viewport = false;
}
});
}
},
);
}
if self.show_deferred_viewport.load(Ordering::Relaxed) {
let show_deferred_viewport = self.show_deferred_viewport.clone();
ctx.show_viewport_deferred(
let show_deferred_viewport = Arc::clone(&self.show_deferred_viewport);
ui.ctx().show_viewport_deferred(
egui::ViewportId::from_hash_of("deferred_viewport"),
egui::ViewportBuilder::default()
.with_title("Deferred Viewport")
.with_inner_size([200.0, 100.0]),
move |ctx, class| {
assert!(
class == egui::ViewportClass::Deferred,
"This egui backend doesn't support multiple viewports"
);
move |ui, class| {
if class == egui::ViewportClass::EmbeddedWindow {
ui.label(
"This viewport is embedded in the parent window, and cannot be moved outside of it.",
);
} else {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.label("Hello from deferred viewport");
egui::CentralPanel::default().show(ctx, |ui| {
ui.label("Hello from deferred viewport");
});
if ctx.input(|i| i.viewport().close_requested()) {
// Tell parent to close us.
show_deferred_viewport.store(false, Ordering::Relaxed);
if ui.input(|i| i.viewport().close_requested()) {
// Tell parent to close us.
show_deferred_viewport.store(false, Ordering::Relaxed);
}
});
}
},
);

View File

@@ -9,13 +9,10 @@ version.workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
[lints]

View File

@@ -3,3 +3,5 @@ Example of how to use menus, popups, context menus and tooltips.
```sh
cargo run -p popups
```
![](screenshot.png)

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fb79ed9f98a4e5b452f52c9d5a857126481aad7c98e871895b8eea90d89c61c7
size 20053

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui::{CentralPanel, ComboBox, Popup, PopupCloseBehavior};
@@ -18,8 +18,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &eframe::egui::Context, _frame: &mut eframe::Frame) {
CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut eframe::egui::Ui, _frame: &mut eframe::Frame) {
CentralPanel::default().show_inside(ui, |ui| {
ui.label("PopupCloseBehavior::CloseOnClick popup");
ComboBox::from_label("ComboBox")
.selected_text(format!("{}", self.number))

View File

@@ -3,8 +3,8 @@ name = "puffin_profiler"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[package.metadata.cargo-machete]
@@ -20,14 +20,11 @@ wgpu = ["eframe/wgpu"]
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
] }
log = { workspace = true }
puffin = "0.19"
puffin_http = "0.16"
profiling = {workspace = true, features = ["profile-with-puffin"] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
log.workspace = true
puffin.workspace = true
puffin_http.workspace = true
profiling = { workspace = true, features = ["profile-with-puffin"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:610b003b4c7715751d2d3753d304e2c5a0af17c9259fa24f21a97b33b9d0c3c7
size 8549
oid sha256:bfc5dcdf4e4a606cc5b656cfe61d9def9ce1a2eb515003a6a339fefc9335079e
size 29711

View File

@@ -1,16 +1,22 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
atomic::{AtomicBool, Ordering},
};
use eframe::egui;
fn main() -> eframe::Result {
let rust_log = std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_owned());
std::env::set_var("RUST_LOG", rust_log);
// SAFETY: we call this from the main thread without any other threads running.
#[expect(unsafe_code)]
unsafe {
std::env::set_var("RUST_LOG", rust_log);
};
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
start_puffin_server(); // NOTE: you may only want to call this if the users specifies some flag or clicks a button!
@@ -48,8 +54,8 @@ impl Default for MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.heading("Example of how to use the puffin profiler with egui");
ui.separator();
@@ -59,7 +65,7 @@ impl eframe::App for MyApp {
ui.horizontal(|ui| {
ui.monospace(cmd);
if ui.small_button("📋").clicked() {
ui.ctx().copy_text(cmd.into());
ui.copy_text(cmd.into());
}
});
@@ -69,7 +75,7 @@ impl eframe::App for MyApp {
ui.checkbox(&mut self.keep_repainting, "Keep repainting");
if self.keep_repainting {
ui.spinner();
ui.ctx().request_repaint();
ui.request_repaint();
} else {
ui.label("Repainting on events (e.g. mouse movement)");
}
@@ -97,12 +103,12 @@ impl eframe::App for MyApp {
});
if self.show_immediate_viewport {
ctx.show_viewport_immediate(
ui.ctx().show_viewport_immediate(
egui::ViewportId::from_hash_of("immediate_viewport"),
egui::ViewportBuilder::default()
.with_title("Immediate Viewport")
.with_inner_size([200.0, 100.0]),
|ctx, class| {
|ui, class| {
puffin::profile_scope!("immediate_viewport");
assert!(
@@ -110,11 +116,11 @@ impl eframe::App for MyApp {
"This egui backend doesn't support multiple viewports"
);
egui::CentralPanel::default().show(ctx, |ui| {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.label("Hello from immediate viewport");
});
if ctx.input(|i| i.viewport().close_requested()) {
if ui.input(|i| i.viewport().close_requested()) {
// Tell parent viewport that we should not show next frame:
self.show_immediate_viewport = false;
}
@@ -123,13 +129,13 @@ impl eframe::App for MyApp {
}
if self.show_deferred_viewport.load(Ordering::Relaxed) {
let show_deferred_viewport = self.show_deferred_viewport.clone();
ctx.show_viewport_deferred(
let show_deferred_viewport = Arc::clone(&self.show_deferred_viewport);
ui.ctx().show_viewport_deferred(
egui::ViewportId::from_hash_of("deferred_viewport"),
egui::ViewportBuilder::default()
.with_title("Deferred Viewport")
.with_inner_size([200.0, 100.0]),
move |ctx, class| {
move |ui, class| {
puffin::profile_scope!("deferred_viewport");
assert!(
@@ -137,10 +143,10 @@ impl eframe::App for MyApp {
"This egui backend doesn't support multiple viewports"
);
egui::CentralPanel::default().show(ctx, |ui| {
egui::CentralPanel::default().show_inside(ui, |ui| {
ui.label("Hello from deferred viewport");
});
if ctx.input(|i| i.viewport().close_requested()) {
if ui.input(|i| i.viewport().close_requested()) {
// Tell parent to close us.
show_deferred_viewport.store(false, Ordering::Relaxed);
}
@@ -165,11 +171,11 @@ fn start_puffin_server() {
// We can store the server if we want, but in this case we just want
// it to keep running. Dropping it closes the server, so let's not drop it!
#[allow(clippy::mem_forget)]
#[expect(clippy::mem_forget)]
std::mem::forget(puffin_server);
}
Err(err) => {
log::error!("Failed to start puffin server: {err}");
}
};
}
}

View File

@@ -1,13 +1,10 @@
[package]
name = "screenshot"
version = "0.1.0"
authors = [
"René Rössler <rene@freshx.de>",
"Andreas Faber <andreas.mfaber@gmail.com",
]
authors = ["René Rössler <rene@freshx.de>", "Andreas Faber <andreas.mfaber@gmail.com"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -16,12 +13,9 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
"wgpu",
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
"wgpu",
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
image = { workspace = true, features = ["png"] }

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs, clippy::unwrap_used)] // it's an example
use std::sync::Arc;
@@ -27,8 +27,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
if let Some(screenshot) = self.screenshot.take() {
self.texture = Some(ui.ctx().load_texture(
"screenshot",
@@ -45,7 +45,7 @@ impl eframe::App for MyApp {
if ui.button("save to 'top_left.png'").clicked() {
self.save_to_file = true;
ctx.send_viewport_cmd(egui::ViewportCommand::Screenshot(Default::default()));
ui.send_viewport_cmd(egui::ViewportCommand::Screenshot(Default::default()));
}
ui.with_layout(egui::Layout::top_down(egui::Align::RIGHT), |ui| {
@@ -54,17 +54,13 @@ impl eframe::App for MyApp {
.add(egui::Label::new("hover me!").sense(egui::Sense::hover()))
.hovered()
{
ctx.set_theme(egui::Theme::Dark);
ui.ctx().set_theme(egui::Theme::Dark);
} else {
ctx.set_theme(egui::Theme::Light);
};
ctx.send_viewport_cmd(
egui::ViewportCommand::Screenshot(Default::default()),
);
ui.ctx().set_theme(egui::Theme::Light);
}
ui.send_viewport_cmd(egui::ViewportCommand::Screenshot(Default::default()));
} else if ui.button("take screenshot!").clicked() {
ctx.send_viewport_cmd(
egui::ViewportCommand::Screenshot(Default::default()),
);
ui.send_viewport_cmd(egui::ViewportCommand::Screenshot(Default::default()));
}
});
});
@@ -96,12 +92,12 @@ impl eframe::App for MyApp {
.unwrap();
self.save_to_file = false;
}
self.screenshot = Some(image.clone());
self.screenshot = Some(Arc::clone(image));
}
}
});
ctx.request_repaint();
ui.request_repaint();
});
}
}

View File

@@ -3,8 +3,8 @@ name = "serial_windows"
version = "0.1.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -13,11 +13,8 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
] }
log = { workspace = true }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }
log.workspace = true

View File

@@ -7,8 +7,7 @@ Expected order of execution:
- Similarly, when the second window is closed after a delay a third will be shown.
- Once the third is closed the program will stop.
NOTE: this doesn't work on Mac due to <https://github.com/rust-windowing/winit/issues/2431>.
See also <https://github.com/emilk/egui/issues/1918>.
NOTE: this doesn't work on Mac. See also <https://github.com/emilk/egui/issues/1918>.
```sh
cargo run -p serial_windows

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::egui;
@@ -43,8 +43,8 @@ struct MyApp {
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show_inside(ui, |ui| {
let label_text = if self.has_next {
"When this window is closed the next will be opened after a short delay"
} else {
@@ -54,7 +54,7 @@ impl eframe::App for MyApp {
if ui.button("Close").clicked() {
log::info!("Pressed Close button");
ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close);
ui.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
}

View File

@@ -3,8 +3,8 @@ name = "user_attention"
version = "0.1.0"
authors = ["TicClick <ya@ticclick.ch>"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.81"
edition = "2024"
rust-version = "1.92"
publish = false
[lints]
@@ -12,10 +12,7 @@ workspace = true
[dependencies]
eframe = { workspace = true, features = [
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { version = "0.10", default-features = false, features = [
"auto-color",
"humantime",
"default",
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
] }
env_logger = { workspace = true, features = ["auto-color", "humantime"] }

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:85a508fa7d16d9bc51f38d3531b30f024d8888f7f74bf2f351453fd13d13e0aa
size 5928
oid sha256:d3b56bdd917a8f789f5bad954bbd37fc27ddec404025dd0608894e5d50e9f37f
size 7375

View File

@@ -1,8 +1,8 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs)] // it's an example
use eframe::{egui, CreationContext, NativeOptions};
use egui::{Button, CentralPanel, Context, UserAttentionType};
use eframe::{CreationContext, NativeOptions, egui};
use egui::{Button, CentralPanel, UserAttentionType};
use std::time::{Duration, SystemTime};
@@ -55,28 +55,28 @@ impl Application {
}
impl eframe::App for Application {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
if let Some(request_at) = self.request_at {
if request_at < SystemTime::now() {
self.request_at = None;
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(self.attention));
if self.auto_reset {
self.auto_reset = false;
self.reset_at = Some(SystemTime::now() + Self::attention_reset_timeout());
}
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
if let Some(request_at) = self.request_at
&& request_at < SystemTime::now()
{
self.request_at = None;
ui.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(self.attention));
if self.auto_reset {
self.auto_reset = false;
self.reset_at = Some(SystemTime::now() + Self::attention_reset_timeout());
}
}
if let Some(reset_at) = self.reset_at {
if reset_at < SystemTime::now() {
self.reset_at = None;
ctx.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(
UserAttentionType::Reset,
));
}
if let Some(reset_at) = self.reset_at
&& reset_at < SystemTime::now()
{
self.reset_at = None;
ui.send_viewport_cmd(egui::ViewportCommand::RequestUserAttention(
UserAttentionType::Reset,
));
}
CentralPanel::default().show(ctx, |ui| {
CentralPanel::default().show_inside(ui, |ui| {
ui.vertical(|ui| {
ui.horizontal(|ui| {
ui.label("Attention type:");
@@ -131,6 +131,6 @@ impl eframe::App for Application {
});
});
ctx.request_repaint_after(Self::repaint_max_timeout());
ui.request_repaint_after(Self::repaint_max_timeout());
}
}