vendor
10
egui/examples/README.md
Normal file
|
|
@ -0,0 +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.
|
||||
|
||||
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`.
|
||||
|
||||
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>.
|
||||
14
egui/examples/confirm_exit/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
7
egui/examples/confirm_exit/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example how to show a confirm dialog before exiting an application.
|
||||
|
||||
```sh
|
||||
cargo run -p confirm_exit
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/confirm_exit/screenshot.png
Normal file
|
After Width: | Height: | Size: 3 KiB |
53
egui/examples/confirm_exit/src/main.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(320.0, 240.0)),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"Confirm exit",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MyApp {
|
||||
allowed_to_close: bool,
|
||||
show_confirmation_dialog: bool,
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn on_close_event(&mut self) -> bool {
|
||||
self.show_confirmation_dialog = true;
|
||||
self.allowed_to_close
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("Try to close the window");
|
||||
});
|
||||
|
||||
if self.show_confirmation_dialog {
|
||||
// Show confirmation dialog:
|
||||
egui::Window::new("Do you want to quit?")
|
||||
.collapsible(false)
|
||||
.resizable(false)
|
||||
.show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Cancel").clicked() {
|
||||
self.show_confirmation_dialog = false;
|
||||
}
|
||||
|
||||
if ui.button("Yes!").clicked() {
|
||||
self.allowed_to_close = true;
|
||||
frame.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
16
egui/examples/custom_3d_glow/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
egui_glow = { path = "../../crates/egui_glow" }
|
||||
glow = "0.12"
|
||||
17
egui/examples/custom_3d_glow/README.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
This demo shows how to embed 3D rendering using [`glow`](https://github.com/grovesNL/glow) in `eframe`.
|
||||
|
||||
This is very advanced usage, and you need to be careful.
|
||||
|
||||
If you want an easier way to show 3D graphics with egui, take a look at the `custom_3d_three-d.rs` example.
|
||||
|
||||
If you are content of having egui sit on top of a 3D background, take a look at:
|
||||
|
||||
* [`bevy_egui`](https://github.com/mvlabat/bevy_egui)
|
||||
* [`three-d`](https://github.com/asny/three-d)
|
||||
|
||||
|
||||
```sh
|
||||
cargo run -p custom_3d_glow
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/custom_3d_glow/screenshot.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
199
egui/examples/custom_3d_glow/src/main.rs
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
use egui::mutex::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(350.0, 380.0)),
|
||||
multisampling: 4,
|
||||
renderer: eframe::Renderer::Glow,
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"Custom 3D painting in eframe using glow",
|
||||
options,
|
||||
Box::new(|cc| Box::new(MyApp::new(cc))),
|
||||
)
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
/// Behind an `Arc<Mutex<…>>` so we can pass it to [`egui::PaintCallback`] and paint later.
|
||||
rotating_triangle: Arc<Mutex<RotatingTriangle>>,
|
||||
angle: f32,
|
||||
}
|
||||
|
||||
impl MyApp {
|
||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
let gl = cc
|
||||
.gl
|
||||
.as_ref()
|
||||
.expect("You need to run eframe with the glow backend");
|
||||
Self {
|
||||
rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(gl))),
|
||||
angle: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label("The triangle is being painted using ");
|
||||
ui.hyperlink_to("glow", "https://github.com/grovesNL/glow");
|
||||
ui.label(" (OpenGL).");
|
||||
});
|
||||
|
||||
egui::Frame::canvas(ui.style()).show(ui, |ui| {
|
||||
self.custom_painting(ui);
|
||||
});
|
||||
ui.label("Drag to rotate!");
|
||||
});
|
||||
}
|
||||
|
||||
fn on_exit(&mut self, gl: Option<&glow::Context>) {
|
||||
if let Some(gl) = gl {
|
||||
self.rotating_triangle.lock().destroy(gl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MyApp {
|
||||
fn custom_painting(&mut self, ui: &mut egui::Ui) {
|
||||
let (rect, response) =
|
||||
ui.allocate_exact_size(egui::Vec2::splat(300.0), egui::Sense::drag());
|
||||
|
||||
self.angle += response.drag_delta().x * 0.01;
|
||||
|
||||
// Clone locals so we can move them into the paint callback:
|
||||
let angle = self.angle;
|
||||
let rotating_triangle = self.rotating_triangle.clone();
|
||||
|
||||
let callback = egui::PaintCallback {
|
||||
rect,
|
||||
callback: std::sync::Arc::new(egui_glow::CallbackFn::new(move |_info, painter| {
|
||||
rotating_triangle.lock().paint(painter.gl(), angle);
|
||||
})),
|
||||
};
|
||||
ui.painter().add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
struct RotatingTriangle {
|
||||
program: glow::Program,
|
||||
vertex_array: glow::VertexArray,
|
||||
}
|
||||
|
||||
impl RotatingTriangle {
|
||||
fn new(gl: &glow::Context) -> Self {
|
||||
use glow::HasContext as _;
|
||||
|
||||
let shader_version = if cfg!(target_arch = "wasm32") {
|
||||
"#version 300 es"
|
||||
} else {
|
||||
"#version 330"
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let program = gl.create_program().expect("Cannot create program");
|
||||
|
||||
let (vertex_shader_source, fragment_shader_source) = (
|
||||
r#"
|
||||
const vec2 verts[3] = vec2[3](
|
||||
vec2(0.0, 1.0),
|
||||
vec2(-1.0, -1.0),
|
||||
vec2(1.0, -1.0)
|
||||
);
|
||||
const vec4 colors[3] = vec4[3](
|
||||
vec4(1.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 1.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 1.0, 1.0)
|
||||
);
|
||||
out vec4 v_color;
|
||||
uniform float u_angle;
|
||||
void main() {
|
||||
v_color = colors[gl_VertexID];
|
||||
gl_Position = vec4(verts[gl_VertexID], 0.0, 1.0);
|
||||
gl_Position.x *= cos(u_angle);
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
precision mediump float;
|
||||
in vec4 v_color;
|
||||
out vec4 out_color;
|
||||
void main() {
|
||||
out_color = v_color;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
let shader_sources = [
|
||||
(glow::VERTEX_SHADER, vertex_shader_source),
|
||||
(glow::FRAGMENT_SHADER, fragment_shader_source),
|
||||
];
|
||||
|
||||
let shaders: Vec<_> = shader_sources
|
||||
.iter()
|
||||
.map(|(shader_type, shader_source)| {
|
||||
let shader = gl
|
||||
.create_shader(*shader_type)
|
||||
.expect("Cannot create shader");
|
||||
gl.shader_source(shader, &format!("{}\n{}", shader_version, shader_source));
|
||||
gl.compile_shader(shader);
|
||||
assert!(
|
||||
gl.get_shader_compile_status(shader),
|
||||
"Failed to compile {shader_type}: {}",
|
||||
gl.get_shader_info_log(shader)
|
||||
);
|
||||
gl.attach_shader(program, shader);
|
||||
shader
|
||||
})
|
||||
.collect();
|
||||
|
||||
gl.link_program(program);
|
||||
if !gl.get_program_link_status(program) {
|
||||
panic!("{}", gl.get_program_info_log(program));
|
||||
}
|
||||
|
||||
for shader in shaders {
|
||||
gl.detach_shader(program, shader);
|
||||
gl.delete_shader(shader);
|
||||
}
|
||||
|
||||
let vertex_array = gl
|
||||
.create_vertex_array()
|
||||
.expect("Cannot create vertex array");
|
||||
|
||||
Self {
|
||||
program,
|
||||
vertex_array,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn destroy(&self, gl: &glow::Context) {
|
||||
use glow::HasContext as _;
|
||||
unsafe {
|
||||
gl.delete_program(self.program);
|
||||
gl.delete_vertex_array(self.vertex_array);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&self, gl: &glow::Context, angle: f32) {
|
||||
use glow::HasContext as _;
|
||||
unsafe {
|
||||
gl.use_program(Some(self.program));
|
||||
gl.uniform_1_f32(
|
||||
gl.get_uniform_location(self.program, "u_angle").as_ref(),
|
||||
angle,
|
||||
);
|
||||
gl.bind_vertex_array(Some(self.vertex_array));
|
||||
gl.draw_arrays(glow::TRIANGLES, 0, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
egui/examples/custom_font/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
7
egui/examples/custom_font/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example of how to use custom fonts.
|
||||
|
||||
```sh
|
||||
cargo run -p custom_font
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/custom_font/screenshot.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
68
egui/examples/custom_font/src/main.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(320.0, 240.0)),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"egui example: custom font",
|
||||
options,
|
||||
Box::new(|cc| Box::new(MyApp::new(cc))),
|
||||
)
|
||||
}
|
||||
|
||||
fn setup_custom_fonts(ctx: &egui::Context) {
|
||||
// Start with the default fonts (we will be adding to them rather than replacing them).
|
||||
let mut fonts = egui::FontDefinitions::default();
|
||||
|
||||
// Install my own font (maybe supporting non-latin characters).
|
||||
// .ttf and .otf files supported.
|
||||
fonts.font_data.insert(
|
||||
"my_font".to_owned(),
|
||||
egui::FontData::from_static(include_bytes!(
|
||||
"../../../crates/epaint/fonts/Hack-Regular.ttf"
|
||||
)),
|
||||
);
|
||||
|
||||
// Put my font first (highest priority) for proportional text:
|
||||
fonts
|
||||
.families
|
||||
.entry(egui::FontFamily::Proportional)
|
||||
.or_default()
|
||||
.insert(0, "my_font".to_owned());
|
||||
|
||||
// Put my font as last fallback for monospace:
|
||||
fonts
|
||||
.families
|
||||
.entry(egui::FontFamily::Monospace)
|
||||
.or_default()
|
||||
.push("my_font".to_owned());
|
||||
|
||||
// Tell egui to use these fonts:
|
||||
ctx.set_fonts(fonts);
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
text: String,
|
||||
}
|
||||
|
||||
impl MyApp {
|
||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
setup_custom_fonts(&cc.egui_ctx);
|
||||
Self {
|
||||
text: "Edit this text field if you want".to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("egui using custom fonts");
|
||||
ui.text_edit_multiline(&mut self.text);
|
||||
});
|
||||
}
|
||||
}
|
||||
14
egui/examples/custom_font_style/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "custom_font_style"
|
||||
version = "0.1.0"
|
||||
authors = ["tami5 <kkharji@proton.me>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
7
egui/examples/custom_font_style/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example how to define custom test styles.
|
||||
|
||||
```sh
|
||||
cargo run -p custom_font_style
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/custom_font_style/screenshot.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
71
egui/examples/custom_font_style/src/main.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
use egui::{FontFamily, FontId, RichText, TextStyle};
|
||||
|
||||
#[inline]
|
||||
fn heading2() -> TextStyle {
|
||||
TextStyle::Name("Heading2".into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn heading3() -> TextStyle {
|
||||
TextStyle::Name("ContextHeading".into())
|
||||
}
|
||||
|
||||
fn configure_text_styles(ctx: &egui::Context) {
|
||||
use FontFamily::{Monospace, Proportional};
|
||||
|
||||
let mut style = (*ctx.style()).clone();
|
||||
style.text_styles = [
|
||||
(TextStyle::Heading, FontId::new(25.0, Proportional)),
|
||||
(heading2(), FontId::new(22.0, Proportional)),
|
||||
(heading3(), FontId::new(19.0, Proportional)),
|
||||
(TextStyle::Body, FontId::new(16.0, Proportional)),
|
||||
(TextStyle::Monospace, FontId::new(12.0, Monospace)),
|
||||
(TextStyle::Button, FontId::new(12.0, Proportional)),
|
||||
(TextStyle::Small, FontId::new(8.0, Proportional)),
|
||||
]
|
||||
.into();
|
||||
ctx.set_style(style);
|
||||
}
|
||||
|
||||
fn content(ui: &mut egui::Ui) {
|
||||
ui.heading("Top Heading");
|
||||
ui.add_space(5.);
|
||||
ui.label(LOREM_IPSUM);
|
||||
ui.add_space(15.);
|
||||
ui.label(RichText::new("Sub Heading").text_style(heading2()).strong());
|
||||
ui.monospace(LOREM_IPSUM);
|
||||
ui.add_space(15.);
|
||||
ui.label(RichText::new("Context").text_style(heading3()).strong());
|
||||
ui.add_space(5.);
|
||||
ui.label(LOREM_IPSUM);
|
||||
}
|
||||
|
||||
struct MyApp;
|
||||
|
||||
impl MyApp {
|
||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
configure_text_styles(&cc.egui_ctx);
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, content);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions::default();
|
||||
|
||||
eframe::run_native(
|
||||
"egui example: global font style",
|
||||
options,
|
||||
Box::new(|cc| Box::new(MyApp::new(cc))),
|
||||
)
|
||||
}
|
||||
|
||||
pub const LOREM_IPSUM: &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
|
||||
14
egui/examples/custom_window_frame/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
7
egui/examples/custom_window_frame/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example how to show a custom window frame instead of the default OS window chrome decorations.
|
||||
|
||||
```sh
|
||||
cargo run -p custom_window_frame
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/custom_window_frame/screenshot.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
164
egui/examples/custom_window_frame/src/main.rs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
//! Show a custom window frame instead of the default OS window chrome decorations.
|
||||
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
// Hide the OS-specific "chrome" around the window:
|
||||
decorated: false,
|
||||
// To have rounded corners we need transparency:
|
||||
transparent: true,
|
||||
min_window_size: Some(egui::vec2(400.0, 100.0)),
|
||||
initial_window_size: Some(egui::vec2(400.0, 240.0)),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"Custom window frame", // unused title
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MyApp {}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn clear_color(&self, _visuals: &egui::Visuals) -> [f32; 4] {
|
||||
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, frame, "egui with custom frame", |ui| {
|
||||
ui.label("This is just the contents of the window.");
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("egui theme:");
|
||||
egui::widgets::global_dark_light_mode_buttons(ui);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn custom_window_frame(
|
||||
ctx: &egui::Context,
|
||||
frame: &mut eframe::Frame,
|
||||
title: &str,
|
||||
add_contents: impl FnOnce(&mut egui::Ui),
|
||||
) {
|
||||
use egui::*;
|
||||
|
||||
let panel_frame = egui::Frame {
|
||||
fill: ctx.style().visuals.window_fill(),
|
||||
rounding: 10.0.into(),
|
||||
stroke: ctx.style().visuals.widgets.noninteractive.fg_stroke,
|
||||
outer_margin: 0.5.into(), // so the stroke is within the bounds
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
CentralPanel::default().frame(panel_frame).show(ctx, |ui| {
|
||||
let app_rect = ui.max_rect();
|
||||
|
||||
let title_bar_height = 32.0;
|
||||
let title_bar_rect = {
|
||||
let mut rect = app_rect;
|
||||
rect.max.y = rect.min.y + title_bar_height;
|
||||
rect
|
||||
};
|
||||
title_bar_ui(ui, frame, title_bar_rect, title);
|
||||
|
||||
// Add the contents:
|
||||
let content_rect = {
|
||||
let mut rect = app_rect;
|
||||
rect.min.y = title_bar_rect.max.y;
|
||||
rect
|
||||
}
|
||||
.shrink(4.0);
|
||||
let mut content_ui = ui.child_ui(content_rect, *ui.layout());
|
||||
add_contents(&mut content_ui);
|
||||
});
|
||||
}
|
||||
|
||||
fn title_bar_ui(
|
||||
ui: &mut egui::Ui,
|
||||
frame: &mut eframe::Frame,
|
||||
title_bar_rect: eframe::epaint::Rect,
|
||||
title: &str,
|
||||
) {
|
||||
use egui::*;
|
||||
|
||||
let painter = ui.painter();
|
||||
|
||||
let title_bar_response = ui.interact(title_bar_rect, Id::new("title_bar"), Sense::click());
|
||||
|
||||
// Paint the title:
|
||||
painter.text(
|
||||
title_bar_rect.center(),
|
||||
Align2::CENTER_CENTER,
|
||||
title,
|
||||
FontId::proportional(20.0),
|
||||
ui.style().visuals.text_color(),
|
||||
);
|
||||
|
||||
// Paint the line under the title:
|
||||
painter.line_segment(
|
||||
[
|
||||
title_bar_rect.left_bottom() + vec2(1.0, 0.0),
|
||||
title_bar_rect.right_bottom() + vec2(-1.0, 0.0),
|
||||
],
|
||||
ui.visuals().widgets.noninteractive.bg_stroke,
|
||||
);
|
||||
|
||||
// Interact with the title bar (drag to move window):
|
||||
if title_bar_response.double_clicked() {
|
||||
frame.set_maximized(!frame.info().window_info.maximized);
|
||||
} else if title_bar_response.is_pointer_button_down_on() {
|
||||
frame.drag_window();
|
||||
}
|
||||
|
||||
ui.allocate_ui_at_rect(title_bar_rect, |ui| {
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.visuals_mut().button_frame = false;
|
||||
ui.add_space(8.0);
|
||||
close_maximize_minimize(ui, frame);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Show some close/maximize/minimize buttons for the native window.
|
||||
fn close_maximize_minimize(ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||
use egui::{Button, RichText};
|
||||
|
||||
let button_height = 12.0;
|
||||
|
||||
let close_response = ui
|
||||
.add(Button::new(RichText::new("❌").size(button_height)))
|
||||
.on_hover_text("Close the window");
|
||||
if close_response.clicked() {
|
||||
frame.close();
|
||||
}
|
||||
|
||||
if frame.info().window_info.maximized {
|
||||
let maximized_response = ui
|
||||
.add(Button::new(RichText::new("🗗").size(button_height)))
|
||||
.on_hover_text("Restore window");
|
||||
if maximized_response.clicked() {
|
||||
frame.set_maximized(false);
|
||||
}
|
||||
} else {
|
||||
let maximized_response = ui
|
||||
.add(Button::new(RichText::new("🗗").size(button_height)))
|
||||
.on_hover_text("Maximize window");
|
||||
if maximized_response.clicked() {
|
||||
frame.set_maximized(true);
|
||||
}
|
||||
}
|
||||
|
||||
let minimized_response = ui
|
||||
.add(Button::new(RichText::new("🗕").size(button_height)))
|
||||
.on_hover_text("Minimize the window");
|
||||
if minimized_response.clicked() {
|
||||
frame.set_minimized(true);
|
||||
}
|
||||
}
|
||||
18
egui/examples/download_image/Cargo.toml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "download_image"
|
||||
version = "0.1.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
egui_extras = { path = "../../crates/egui_extras", features = ["image"] }
|
||||
ehttp = "0.2"
|
||||
image = { version = "0.24", default-features = false, features = ["jpeg"] }
|
||||
poll-promise = "0.2"
|
||||
7
egui/examples/download_image/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example how to download and show an image with eframe/egui.
|
||||
|
||||
```sh
|
||||
cargo run -p download_image
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/download_image/screenshot.png
Normal file
|
After Width: | Height: | Size: 353 KiB |
64
egui/examples/download_image/src/main.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
use egui_extras::RetainedImage;
|
||||
use poll_promise::Promise;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions::default();
|
||||
eframe::run_native(
|
||||
"Download and show an image with eframe/egui",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MyApp {
|
||||
/// `None` when download hasn't started yet.
|
||||
promise: Option<Promise<ehttp::Result<RetainedImage>>>,
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
let promise = self.promise.get_or_insert_with(|| {
|
||||
// Begin download.
|
||||
// We download the image using `ehttp`, a library that works both in WASM and on native.
|
||||
// We use the `poll-promise` library to communicate with the UI thread.
|
||||
let ctx = ctx.clone();
|
||||
let (sender, promise) = Promise::new();
|
||||
let request = ehttp::Request::get("https://picsum.photos/seed/1.759706314/1024");
|
||||
ehttp::fetch(request, move |response| {
|
||||
let image = response.and_then(parse_response);
|
||||
sender.send(image); // send the results back to the UI thread.
|
||||
ctx.request_repaint(); // wake up UI thread
|
||||
});
|
||||
promise
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| match promise.ready() {
|
||||
None => {
|
||||
ui.spinner(); // still loading
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
ui.colored_label(ui.visuals().error_fg_color, err); // something went wrong
|
||||
}
|
||||
Some(Ok(image)) => {
|
||||
image.show_max_size(ui, ui.available_size());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
fn parse_response(response: ehttp::Response) -> Result<RetainedImage, String> {
|
||||
let content_type = response.content_type().unwrap_or_default();
|
||||
if content_type.starts_with("image/") {
|
||||
RetainedImage::from_image_bytes(&response.url, &response.bytes)
|
||||
} else {
|
||||
Err(format!(
|
||||
"Expected image, found content-type {:?}",
|
||||
content_type
|
||||
))
|
||||
}
|
||||
}
|
||||
15
egui/examples/file_dialog/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
rfd = "0.11"
|
||||
7
egui/examples/file_dialog/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
How to show a file dialog using [`rfd`](https://github.com/PolyMeilex/rfd).
|
||||
|
||||
```sh
|
||||
cargo run -p file_dialog
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/file_dialog/screenshot.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
109
egui/examples/file_dialog/src/main.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
drag_and_drop_support: true,
|
||||
initial_window_size: Some(egui::vec2(320.0, 240.0)),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"Native file dialogs and drag-and-drop files",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MyApp {
|
||||
dropped_files: Vec<egui::DroppedFile>,
|
||||
picked_path: Option<String>,
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |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 let Some(picked_path) = &self.picked_path {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Picked file:");
|
||||
ui.monospace(picked_path);
|
||||
});
|
||||
}
|
||||
|
||||
// Show dropped files (if any):
|
||||
if !self.dropped_files.is_empty() {
|
||||
ui.group(|ui| {
|
||||
ui.label("Dropped files:");
|
||||
|
||||
for file in &self.dropped_files {
|
||||
let mut info = if let Some(path) = &file.path {
|
||||
path.display().to_string()
|
||||
} else if !file.name.is_empty() {
|
||||
file.name.clone()
|
||||
} else {
|
||||
"???".to_owned()
|
||||
};
|
||||
if let Some(bytes) = &file.bytes {
|
||||
use std::fmt::Write as _;
|
||||
write!(info, " ({} bytes)", bytes.len()).ok();
|
||||
}
|
||||
ui.label(info);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
preview_files_being_dropped(ctx);
|
||||
|
||||
// Collect dropped files:
|
||||
ctx.input(|i| {
|
||||
if !i.raw.dropped_files.is_empty() {
|
||||
self.dropped_files = i.raw.dropped_files.clone();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Preview hovering files:
|
||||
fn preview_files_being_dropped(ctx: &egui::Context) {
|
||||
use egui::*;
|
||||
use std::fmt::Write as _;
|
||||
|
||||
if !ctx.input(|i| i.raw.hovered_files.is_empty()) {
|
||||
let text = ctx.input(|i| {
|
||||
let mut text = "Dropping files:\n".to_owned();
|
||||
for file in &i.raw.hovered_files {
|
||||
if let Some(path) = &file.path {
|
||||
write!(text, "\n{}", path.display()).ok();
|
||||
} else if !file.mime.is_empty() {
|
||||
write!(text, "\n{}", file.mime).ok();
|
||||
} else {
|
||||
text += "\n???";
|
||||
}
|
||||
}
|
||||
text
|
||||
});
|
||||
|
||||
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));
|
||||
painter.text(
|
||||
screen_rect.center(),
|
||||
Align2::CENTER_CENTER,
|
||||
text,
|
||||
TextStyle::Heading.resolve(&ctx.style()),
|
||||
Color32::WHITE,
|
||||
);
|
||||
}
|
||||
}
|
||||
15
egui/examples/hello_world/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
tracing-subscriber = "0.3"
|
||||
7
egui/examples/hello_world/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example showing some UI controls like `Label`, `TextEdit`, `Slider`, `Button`.
|
||||
|
||||
```sh
|
||||
cargo run -p hello_world
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/hello_world/screenshot.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
50
egui/examples/hello_world/src/main.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
// Log to stdout (if you run with `RUST_LOG=debug`).
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(320.0, 240.0)),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"My egui App",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
name: String,
|
||||
age: u32,
|
||||
}
|
||||
|
||||
impl Default for MyApp {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "Arthur".to_owned(),
|
||||
age: 42,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("My egui Application");
|
||||
ui.horizontal(|ui| {
|
||||
let name_label = ui.label("Your name: ");
|
||||
ui.text_edit_singleline(&mut self.name)
|
||||
.labelled_by(name_label.id);
|
||||
});
|
||||
ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
|
||||
if ui.button("Click each year").clicked() {
|
||||
self.age += 1;
|
||||
}
|
||||
ui.label(format!("Hello '{}', age {}", self.name, self.age));
|
||||
});
|
||||
}
|
||||
}
|
||||
16
egui/examples/hello_world_par/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", default-features = false, features = [
|
||||
# accesskit struggles with threading
|
||||
"default_fonts",
|
||||
"wgpu",
|
||||
] }
|
||||
5
egui/examples/hello_world_par/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
This example shows that you can use egui in parallel from multiple threads.
|
||||
|
||||
```sh
|
||||
cargo run -p hello_world_par
|
||||
```
|
||||
132
egui/examples/hello_world_par/src/main.rs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
//! 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
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(1024.0, 768.0)),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"My parallel egui App",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::new())),
|
||||
)
|
||||
}
|
||||
|
||||
/// State per thread.
|
||||
struct ThreadState {
|
||||
thread_nr: usize,
|
||||
title: String,
|
||||
name: String,
|
||||
age: u32,
|
||||
}
|
||||
|
||||
impl ThreadState {
|
||||
fn new(thread_nr: usize) -> Self {
|
||||
let title = format!("Background thread {thread_nr}");
|
||||
Self {
|
||||
thread_nr,
|
||||
title,
|
||||
name: "Arthur".into(),
|
||||
age: 12 + thread_nr as u32 * 10,
|
||||
}
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::Context) {
|
||||
let pos = egui::pos2(16.0, 128.0 * (self.thread_nr as f32 + 1.0));
|
||||
egui::Window::new(&self.title)
|
||||
.default_pos(pos)
|
||||
.show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Your name: ");
|
||||
ui.text_edit_singleline(&mut self.name);
|
||||
});
|
||||
ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
|
||||
if ui.button("Click each year").clicked() {
|
||||
self.age += 1;
|
||||
}
|
||||
ui.label(format!("Hello '{}', age {}", self.name, self.age));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn new_worker(
|
||||
thread_nr: usize,
|
||||
on_done_tx: mpsc::SyncSender<()>,
|
||||
) -> (JoinHandle<()>, mpsc::SyncSender<egui::Context>) {
|
||||
let (show_tx, show_rc) = mpsc::sync_channel(0);
|
||||
let handle = std::thread::Builder::new()
|
||||
.name(format!("EguiPanelWorker {}", thread_nr))
|
||||
.spawn(move || {
|
||||
let mut state = ThreadState::new(thread_nr);
|
||||
while let Ok(ctx) = show_rc.recv() {
|
||||
state.show(&ctx);
|
||||
let _ = on_done_tx.send(());
|
||||
}
|
||||
})
|
||||
.expect("failed to spawn thread");
|
||||
(handle, show_tx)
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
threads: Vec<(JoinHandle<()>, mpsc::SyncSender<egui::Context>)>,
|
||||
on_done_tx: mpsc::SyncSender<()>,
|
||||
on_done_rc: mpsc::Receiver<()>,
|
||||
}
|
||||
|
||||
impl MyApp {
|
||||
fn new() -> Self {
|
||||
let threads = Vec::with_capacity(3);
|
||||
let (on_done_tx, on_done_rc) = mpsc::sync_channel(0);
|
||||
|
||||
let mut slf = Self {
|
||||
threads,
|
||||
on_done_tx,
|
||||
on_done_rc,
|
||||
};
|
||||
|
||||
slf.spawn_thread();
|
||||
slf.spawn_thread();
|
||||
|
||||
slf
|
||||
}
|
||||
|
||||
fn spawn_thread(&mut self) {
|
||||
let thread_nr = self.threads.len();
|
||||
self.threads
|
||||
.push(new_worker(thread_nr, self.on_done_tx.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Drop for MyApp {
|
||||
fn drop(&mut self) {
|
||||
for (handle, show_tx) in self.threads.drain(..) {
|
||||
std::mem::drop(show_tx);
|
||||
handle.join().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::Window::new("Main thread").show(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());
|
||||
}
|
||||
|
||||
for _ in 0..self.threads.len() {
|
||||
let _ = self.on_done_rc.recv();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
egui/examples/hello_world_simple/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
tracing-subscriber = "0.3"
|
||||
7
egui/examples/hello_world_simple/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example showing some UI controls like `Label`, `TextEdit`, `Slider`, `Button`.
|
||||
|
||||
```sh
|
||||
cargo run -p hello_world
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/hello_world_simple/screenshot.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
33
egui/examples/hello_world_simple/src/main.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
// Log to stdout (if you run with `RUST_LOG=debug`).
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(320.0, 240.0)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Our application state:
|
||||
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| {
|
||||
ui.heading("My egui Application");
|
||||
ui.horizontal(|ui| {
|
||||
let name_label = ui.label("Your name: ");
|
||||
ui.text_edit_singleline(&mut name)
|
||||
.labelled_by(name_label.id);
|
||||
});
|
||||
ui.add(egui::Slider::new(&mut age, 0..=120).text("age"));
|
||||
if ui.button("Click each year").clicked() {
|
||||
age += 1;
|
||||
}
|
||||
ui.label(format!("Hello '{}', age {}", name, age));
|
||||
});
|
||||
})
|
||||
}
|
||||
15
egui/examples/keyboard_events/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "keyboard_events"
|
||||
version = "0.1.0"
|
||||
authors = ["Jose Palazon <jose@palako.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
tracing-subscriber = "0.3"
|
||||
5
egui/examples/keyboard_events/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
```sh
|
||||
cargo run -p keyboard_events
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/keyboard_events/screenshot.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
49
egui/examples/keyboard_events/src/main.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
use egui::*;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
// Log to stdout (if you run with `RUST_LOG=debug`).
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let options = eframe::NativeOptions::default();
|
||||
eframe::run_native(
|
||||
"Keyboard events",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(Content::default())),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Content {
|
||||
text: String,
|
||||
}
|
||||
|
||||
impl eframe::App for Content {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("Press/Hold/Release example. Press A to test.");
|
||||
if ui.button("Clear").clicked() {
|
||||
self.text.clear();
|
||||
}
|
||||
ScrollArea::vertical()
|
||||
.auto_shrink([false; 2])
|
||||
.stick_to_bottom(true)
|
||||
.show(ui, |ui| {
|
||||
ui.label(&self.text);
|
||||
});
|
||||
|
||||
if ctx.input(|i| i.key_pressed(Key::A)) {
|
||||
self.text.push_str("\nPressed");
|
||||
}
|
||||
if ctx.input(|i| i.key_down(Key::A)) {
|
||||
self.text.push_str("\nHeld");
|
||||
ui.ctx().request_repaint(); // make sure we note the holding.
|
||||
}
|
||||
if ctx.input(|i| i.key_released(Key::A)) {
|
||||
self.text.push_str("\nReleased");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
17
egui/examples/puffin_profiler/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"puffin",
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
puffin = "0.14"
|
||||
puffin_http = "0.11"
|
||||
11
egui/examples/puffin_profiler/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Example how to use the [puffin profiler](https://github.com/EmbarkStudios/puffin) with an `eframe` app.
|
||||
|
||||
|
||||
```sh
|
||||
cargo run -p puffin_profiler &
|
||||
|
||||
cargo install puffin_viewer
|
||||
puffin_viewer --url 127.0.0.1:8585
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/puffin_profiler/screenshot.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
68
egui/examples/puffin_profiler/src/main.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
start_puffin_server(); // NOTE: you may only want to call this if the users specifies some flag or clicks a button!
|
||||
|
||||
let options = eframe::NativeOptions::default();
|
||||
eframe::run_native(
|
||||
"My egui App",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MyApp {}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("Example of how to use the puffin profiler with egui");
|
||||
ui.separator();
|
||||
|
||||
let cmd = "cargo install puffin_viewer && puffin_viewer --url 127.0.0.1:8585";
|
||||
|
||||
ui.label("To connect, run this:");
|
||||
ui.horizontal(|ui| {
|
||||
ui.monospace(cmd);
|
||||
if ui.small_button("📋").clicked() {
|
||||
ui.output_mut(|o| o.copied_text = cmd.into());
|
||||
}
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
ui.label("Note that this app runs in 'reactive' mode, so you must interact with the app for new profile events to be sent. Waving the mouse over this window is enough.");
|
||||
|
||||
if ui
|
||||
.button(
|
||||
"Click to sleep a bit. That should be visible as a spike in the profiler view!",
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
puffin::profile_scope!("sleep");
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn start_puffin_server() {
|
||||
puffin::set_scopes_on(true); // tell puffin to collect data
|
||||
|
||||
match puffin_http::Server::new("0.0.0.0:8585") {
|
||||
Ok(puffin_server) => {
|
||||
eprintln!("Run: cargo install puffin_viewer && puffin_viewer --url 127.0.0.1:8585");
|
||||
|
||||
// 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)]
|
||||
std::mem::forget(puffin_server);
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Failed to start puffin server: {}", err);
|
||||
}
|
||||
};
|
||||
}
|
||||
16
egui/examples/retained_image/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "retained_image"
|
||||
version = "0.1.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
egui_extras = { path = "../../crates/egui_extras", features = ["image"] }
|
||||
image = { version = "0.24", default-features = false, features = ["png"] }
|
||||
7
egui/examples/retained_image/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example how to show an image with eframe/egui.
|
||||
|
||||
```sh
|
||||
cargo run -p retained_image
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/retained_image/screenshot.png
Normal file
|
After Width: | Height: | Size: 148 KiB |
66
egui/examples/retained_image/src/main.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
use egui_extras::RetainedImage;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(300.0, 900.0)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"Show an image with eframe/egui",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
image: RetainedImage,
|
||||
tint: egui::Color32,
|
||||
}
|
||||
|
||||
impl Default for MyApp {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
image: RetainedImage::from_image_bytes(
|
||||
"rust-logo-256x256.png",
|
||||
include_bytes!("rust-logo-256x256.png"),
|
||||
)
|
||||
.unwrap(),
|
||||
tint: egui::Color32::from_rgb(255, 0, 255),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("This is an image:");
|
||||
self.image.show(ui);
|
||||
|
||||
ui.heading("This is a rotated image with a tint:");
|
||||
ui.add(
|
||||
egui::Image::new(self.image.texture_id(ctx), self.image.size_vec2())
|
||||
.rotate(45.0_f32.to_radians(), egui::Vec2::splat(0.5))
|
||||
.tint(self.tint),
|
||||
);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Tint:");
|
||||
egui::color_picker::color_edit_button_srgba(
|
||||
ui,
|
||||
&mut self.tint,
|
||||
egui::color_picker::Alpha::BlendOrAdditive,
|
||||
);
|
||||
});
|
||||
|
||||
ui.heading("This is an image you can click:");
|
||||
ui.add(egui::ImageButton::new(
|
||||
self.image.texture_id(ctx),
|
||||
self.image.size_vec2(),
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
BIN
egui/examples/retained_image/src/rust-logo-256x256.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
1
egui/examples/retained_image/src/rust-logo-license.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
Rust logo by Mozilla, from https://github.com/rust-lang/rust-artwork
|
||||
20
egui/examples/screenshot/Cargo.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "screenshot"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"René Rössler <rene@freshx.de>",
|
||||
"Andreas Faber <andreas.mfaber@gmail.com",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
"wgpu",
|
||||
] }
|
||||
itertools = "0.10.3"
|
||||
image = { version = "0.24", default-features = false, features = ["png"] }
|
||||
7
egui/examples/screenshot/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example how to take screenshots and display them with eframe/egui.
|
||||
|
||||
```sh
|
||||
cargo run -p screenshot
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/screenshot/screenshot.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
94
egui/examples/screenshot/src/main.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui::{self, ColorImage};
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
renderer: eframe::Renderer::Wgpu,
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"Take screenshots and display with eframe/egui",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MyApp {
|
||||
continuously_take_screenshots: bool,
|
||||
texture: Option<egui::TextureHandle>,
|
||||
screenshot: Option<ColorImage>,
|
||||
save_to_file: bool,
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
if let Some(screenshot) = self.screenshot.take() {
|
||||
self.texture = Some(ui.ctx().load_texture(
|
||||
"screenshot",
|
||||
screenshot,
|
||||
Default::default(),
|
||||
));
|
||||
}
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.checkbox(
|
||||
&mut self.continuously_take_screenshots,
|
||||
"continuously take screenshots",
|
||||
);
|
||||
|
||||
if ui.button("save to 'top_left.png'").clicked() {
|
||||
self.save_to_file = true;
|
||||
frame.request_screenshot();
|
||||
}
|
||||
|
||||
ui.with_layout(egui::Layout::top_down(egui::Align::RIGHT), |ui| {
|
||||
if self.continuously_take_screenshots {
|
||||
if ui
|
||||
.add(egui::Label::new("hover me!").sense(egui::Sense::hover()))
|
||||
.hovered()
|
||||
{
|
||||
ctx.set_visuals(egui::Visuals::dark());
|
||||
} else {
|
||||
ctx.set_visuals(egui::Visuals::light());
|
||||
};
|
||||
frame.request_screenshot();
|
||||
} else if ui.button("take screenshot!").clicked() {
|
||||
frame.request_screenshot();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if let Some(texture) = self.texture.as_ref() {
|
||||
ui.image(texture, ui.available_size());
|
||||
} else {
|
||||
ui.spinner();
|
||||
}
|
||||
|
||||
ctx.request_repaint();
|
||||
});
|
||||
}
|
||||
|
||||
fn post_rendering(&mut self, _window_size: [u32; 2], frame: &eframe::Frame) {
|
||||
if let Some(screenshot) = frame.screenshot() {
|
||||
if self.save_to_file {
|
||||
let pixels_per_point = frame.info().native_pixels_per_point;
|
||||
let region =
|
||||
egui::Rect::from_two_pos(egui::Pos2::ZERO, egui::Pos2 { x: 100., y: 100. });
|
||||
let top_left_corner = screenshot.region(®ion, pixels_per_point);
|
||||
image::save_buffer(
|
||||
"top_left.png",
|
||||
top_left_corner.as_raw(),
|
||||
top_left_corner.width() as u32,
|
||||
top_left_corner.height() as u32,
|
||||
image::ColorType::Rgba8,
|
||||
)
|
||||
.unwrap();
|
||||
self.save_to_file = false;
|
||||
}
|
||||
self.screenshot = Some(screenshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
egui/examples/serial_windows/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
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.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
17
egui/examples/serial_windows/README.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
Demonstrates how to open several windows after each other.
|
||||
|
||||
Expected order of execution:
|
||||
|
||||
- When the example runs a first window will be shown.
|
||||
- Once the first window is closed after a delay a second window will be shown.
|
||||
- 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>.
|
||||
|
||||
```sh
|
||||
cargo run -p serial_windows
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/serial_windows/screenshot.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
61
egui/examples/serial_windows/src/main.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
if cfg!(target_os = "macos") {
|
||||
eprintln!("WARNING: this example does not work on Mac! See https://github.com/emilk/egui/issues/1918");
|
||||
}
|
||||
|
||||
let options = eframe::NativeOptions {
|
||||
run_and_return: true,
|
||||
initial_window_size: Some(egui::vec2(320.0, 240.0)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eprintln!("Starting first window…");
|
||||
eframe::run_native(
|
||||
"First Window",
|
||||
options.clone(),
|
||||
Box::new(|_cc| Box::new(MyApp { has_next: true })),
|
||||
)?;
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||
|
||||
eprintln!("Starting second window…");
|
||||
eframe::run_native(
|
||||
"Second Window",
|
||||
options.clone(),
|
||||
Box::new(|_cc| Box::new(MyApp { has_next: true })),
|
||||
)?;
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||
|
||||
eprintln!("Starting third window…");
|
||||
eframe::run_native(
|
||||
"Third Window",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp { has_next: false })),
|
||||
)
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
pub(crate) has_next: bool,
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
let label_text = if self.has_next {
|
||||
"When this window is closed the next will be opened after a short delay"
|
||||
} else {
|
||||
"This is the last window. Program will end when closed"
|
||||
};
|
||||
ui.label(label_text);
|
||||
if ui.button("Close").clicked() {
|
||||
eprintln!("Pressed Close button");
|
||||
frame.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
15
egui/examples/svg/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "svg"
|
||||
version = "0.1.0"
|
||||
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
publish = false
|
||||
|
||||
|
||||
[dependencies]
|
||||
eframe = { path = "../../crates/eframe", features = [
|
||||
"__screenshot", # __screenshot is so we can dump a screenshot using EFRAME_SCREENSHOT_TO
|
||||
] }
|
||||
egui_extras = { path = "../../crates/egui_extras", features = ["svg"] }
|
||||
7
egui/examples/svg/README.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Example how to show an SVG image.
|
||||
|
||||
```sh
|
||||
cargo run -p svg
|
||||
```
|
||||
|
||||

|
||||
BIN
egui/examples/svg/screenshot.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
50
egui/examples/svg/src/main.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
//! A good way of displaying an SVG image in egui.
|
||||
//!
|
||||
//! Requires the dependency `egui_extras` with the `svg` feature.
|
||||
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn main() -> Result<(), eframe::Error> {
|
||||
let options = eframe::NativeOptions {
|
||||
initial_window_size: Some(egui::vec2(1000.0, 700.0)),
|
||||
..Default::default()
|
||||
};
|
||||
eframe::run_native(
|
||||
"svg example",
|
||||
options,
|
||||
Box::new(|_cc| Box::new(MyApp::default())),
|
||||
)
|
||||
}
|
||||
|
||||
struct MyApp {
|
||||
svg_image: egui_extras::RetainedImage,
|
||||
}
|
||||
|
||||
impl Default for MyApp {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
svg_image: egui_extras::RetainedImage::from_svg_bytes_with_size(
|
||||
"rustacean-flat-happy.svg",
|
||||
include_bytes!("rustacean-flat-happy.svg"),
|
||||
egui_extras::image::FitTo::Original,
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for MyApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("SVG example");
|
||||
ui.label("The SVG is rasterized and displayed as a texture.");
|
||||
|
||||
ui.separator();
|
||||
|
||||
let max_size = ui.available_size();
|
||||
self.svg_image.show_size(ui, max_size);
|
||||
});
|
||||
}
|
||||
}
|
||||
1
egui/examples/svg/src/rust-logo-license.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
Rust logo by Mozilla, from https://github.com/rust-lang/rust-artwork
|
||||
33
egui/examples/svg/src/rustacean-flat-happy.svg
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 1200 800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
|
||||
<g id="Layer-1" serif:id="Layer 1">
|
||||
<g transform="matrix(1,0,0,1,1009.4,506.362)">
|
||||
<path d="M0,-7.203L-12.072,-32.209C-12.009,-33.156 -11.961,-34.107 -11.961,-35.062C-11.961,-63.408 -41.439,-89.533 -91.03,-110.451L-91.03,-93.058C-95.866,-94.977 -100.901,-96.845 -106.147,-98.651L-106.147,-106.759C-177.021,-132.319 -282.53,-148.537 -400.388,-148.537C-503.361,-148.537 -596.917,-136.157 -666.179,-115.983L-666.179,-87.737L-666.181,-87.737L-666.181,-121.925C-737.141,-99.375 -781.135,-68.048 -781.135,-33.41C-781.135,-27.95 -780.034,-22.572 -777.918,-17.297L-785.146,-4.43C-785.146,-4.43 -790.938,3.082 -780.74,18.932C-771.746,32.909 -726.692,87.617 -702.913,116.267C-692.699,130.954 -685.772,140.001 -685.167,139.126C-684.212,137.74 -691.518,110.165 -711.802,78.703C-721.268,61.808 -732.57,39.42 -739.356,22.884C-720.414,34.874 -609.126,90.913 -382.124,90.685C-150.13,90.453 -47.009,17.834 -35.691,7.948C-39.646,23.837 -53.159,55.981 -63.936,78.586C-81.642,110.917 -88.056,139.064 -87.232,140.456C-86.708,141.334 -80.667,132.015 -71.756,116.913C-51.025,87.37 -11.739,30.974 -3.889,16.608C5.007,0.323 0,-7.203 0,-7.203" style="fill:rgb(165,43,0);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,1079.49,294.885)">
|
||||
<path d="M0,204.135L-79.343,145.689C-80.088,143.089 -80.833,140.488 -81.603,137.908L-55.541,100.154C-52.881,96.314 -52.345,91.322 -54.072,86.943C-55.803,82.585 -59.587,79.461 -64.062,78.696L-108.128,71.217C-109.837,67.732 -111.626,64.301 -113.422,60.898L-94.907,18.51C-93.004,14.193 -93.402,9.175 -95.929,5.256C-98.446,1.319 -102.715,-0.981 -107.267,-0.802L-151.991,0.823C-154.306,-2.193 -156.658,-5.18 -159.058,-8.114L-148.78,-53.546C-147.738,-58.158 -149.054,-62.989 -152.267,-66.34C-155.462,-69.679 -160.105,-71.062 -164.52,-69.979L-208.082,-59.27C-210.902,-61.763 -213.77,-64.223 -216.67,-66.635L-215.103,-113.276C-214.935,-117.997 -217.136,-122.484 -220.915,-125.105C-224.692,-127.741 -229.485,-128.137 -233.616,-126.179L-274.254,-106.858C-277.527,-108.736 -280.819,-110.595 -284.146,-112.395L-291.327,-158.356C-292.056,-163.012 -295.051,-166.968 -299.246,-168.774C-303.431,-170.591 -308.222,-170.002 -311.894,-167.238L-348.126,-140.053C-351.695,-141.238 -355.279,-142.373 -358.905,-143.46L-374.522,-187.045C-376.11,-191.488 -379.772,-194.751 -384.238,-195.669C-388.688,-196.578 -393.266,-195.037 -396.352,-191.589L-426.851,-157.47C-430.536,-157.893 -434.228,-158.28 -437.927,-158.601L-461.476,-198.277C-463.86,-202.295 -468.073,-204.741 -472.615,-204.741C-477.144,-204.741 -481.365,-202.295 -483.733,-198.277L-507.288,-158.601C-510.989,-158.28 -514.696,-157.893 -518.376,-157.47L-548.875,-191.589C-551.965,-195.037 -556.559,-196.578 -560.997,-195.669C-565.457,-194.739 -569.125,-191.488 -570.704,-187.045L-586.333,-143.46C-589.954,-142.373 -593.538,-141.23 -597.113,-140.053L-633.333,-167.238C-637.016,-170.012 -641.811,-170.599 -646.001,-168.774C-650.182,-166.968 -653.189,-163.012 -653.914,-158.356L-661.1,-112.395C-664.422,-110.595 -667.714,-108.746 -670.995,-106.858L-711.629,-126.179C-715.756,-128.145 -720.574,-127.741 -724.333,-125.105C-728.106,-122.484 -730.313,-117.997 -730.143,-113.276L-728.581,-66.635C-731.475,-64.223 -734.337,-61.763 -737.172,-59.27L-780.726,-69.979C-785.149,-71.053 -789.788,-69.679 -792.991,-66.34C-796.212,-62.989 -797.517,-58.158 -796.482,-53.546L-786.225,-8.114C-788.603,-5.169 -790.958,-2.193 -793.267,0.823L-837.991,-0.802C-842.504,-0.937 -846.812,1.319 -849.334,5.256C-851.861,9.175 -852.244,14.193 -850.363,18.51L-831.835,60.898C-833.634,64.301 -835.421,67.732 -837.144,71.217L-881.207,78.696C-885.686,79.45 -889.459,82.572 -891.201,86.943C-892.929,91.322 -892.368,96.314 -889.727,100.154L-863.661,137.908C-863.862,138.575 -864.048,139.247 -864.248,139.916L-937.944,218.201C-937.944,218.201 -949.24,227.052 -932.797,247.855C-918.297,266.206 -843.846,338.951 -804.526,377.06C-787.92,396.408 -776.542,408.389 -775.354,407.353C-773.478,405.708 -783.326,370.506 -816.036,329.204C-841.252,292.148 -873.977,235.155 -866.303,228.586C-866.303,228.586 -857.574,217.505 -840.061,209.529C-839.42,210.041 -840.723,209.022 -840.061,209.529C-840.061,209.529 -470.466,380.02 -127.632,212.413C-88.468,205.388 -64.759,226.368 -64.759,226.368C-56.583,231.108 -77.755,289.712 -95.166,328.505C-118.845,372.555 -122.317,406.927 -120.31,408.119C-119.042,408.876 -110.427,395.766 -98.138,374.902C-67.814,332.649 -10.492,252.1 0,232.534C11.895,210.352 0,204.135 0,204.135" style="fill:rgb(247,76,0);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,917.896,244.679)">
|
||||
<path d="M0,232.466C0,232.466 53.179,230 123.032,159.004L132.93,137.025C132.93,137.025 24.513,29.177 193.048,-45.266C193.048,-45.266 178.293,-21.154 182.622,72.006C182.622,72.006 233.437,54.357 248.336,-27.934C248.336,-27.934 322.456,69.79 167.834,161.443C167.834,161.443 95.294,277.732 -6.971,266.593L0,232.466Z" style="fill:rgb(247,76,0);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,676.997,488.361)">
|
||||
<path d="M0,-78.192C0,-78.192 36.935,-118.635 73.871,-78.192C73.871,-78.192 102.893,-24.265 73.871,2.695C73.871,2.695 26.384,40.443 0,2.695C0,2.695 -31.658,-26.964 0,-78.192" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,719.761,425.169)">
|
||||
<path d="M0,0.004C0,15.75 -9.282,28.518 -20.732,28.518C-32.18,28.518 -41.462,15.75 -41.462,0.004C-41.462,-15.746 -32.18,-28.514 -20.732,-28.514C-9.282,-28.514 0,-15.746 0,0.004" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,512.148,482.736)">
|
||||
<path d="M0,-83.609C0,-83.609 63.355,-111.661 80.648,-49.047C80.648,-49.047 98.762,23.933 28.618,28.052C28.618,28.052 -60.826,10.824 0,-83.609" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,543.968,426.204)">
|
||||
<path d="M0,0.002C0,16.241 -9.572,29.411 -21.381,29.411C-33.185,29.411 -42.76,16.241 -42.76,0.002C-42.76,-16.242 -33.185,-29.409 -21.381,-29.409C-9.572,-29.409 0,-16.242 0,0.002" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,593.317,576.574)">
|
||||
<path d="M0,-40.271L80.796,-46.755C80.796,-46.755 78.058,-33.749 67.517,-23.986C67.517,-23.986 39.727,6.484 7.844,-26.519C7.844,-26.519 2.627,-32.148 0,-40.271" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,269.796,270.778)">
|
||||
<path d="M0,190.741C-0.667,190.741 -1.321,190.79 -1.973,190.842C-28.207,184.871 -101.946,165.657 -121.437,134.479C-121.437,134.479 -22.21,21.607 -177.297,-50.54L-159.24,74.338C-159.24,74.338 -207.049,42.389 -217.366,-27.008C-217.366,-27.008 -333.789,57.486 -165.982,138.466C-165.982,138.466 -150.762,195.653 -4.633,241.281L-4.526,240.846C-3.055,241.118 -1.549,241.281 0,241.281C13.808,241.281 25.003,229.969 25.003,216.01C25.003,202.054 13.808,190.741 0,190.741" style="fill:rgb(247,76,0);fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.3 KiB |