Introduce egui_extras with RetainedImage for loading svg,png,jpeg,… (#1282)
This commit is contained in:
parent
713917e481
commit
c3fc8997d6
18 changed files with 453 additions and 176 deletions
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
|
@ -132,7 +132,7 @@ jobs:
|
||||||
toolchain: 1.56.0
|
toolchain: 1.56.0
|
||||||
override: true
|
override: true
|
||||||
- run: sudo apt-get update && sudo apt-get install libspeechd-dev
|
- run: sudo apt-get update && sudo apt-get install libspeechd-dev
|
||||||
- run: cargo doc -p emath -p epaint -p egui -p eframe -p epi -p egui_web -p egui-winit -p egui_glium -p egui_glow --lib --no-deps --all-features
|
- run: cargo doc -p emath -p epaint -p egui -p eframe -p epi -p egui_web -p egui-winit -p egui_extras -p egui_glium -p egui_glow --lib --no-deps --all-features
|
||||||
|
|
||||||
doc_web:
|
doc_web:
|
||||||
name: cargo doc web
|
name: cargo doc web
|
||||||
|
|
|
@ -5,7 +5,7 @@ Also see [`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/CONTRIBUT
|
||||||
|
|
||||||
|
|
||||||
## Crate overview
|
## Crate overview
|
||||||
The crates in this repository are: `egui, emath, epaint, egui, epi, egui-winit, egui_web, egui_glium, egui_glow, egui_demo_lib, egui_demo_app`.
|
The crates in this repository are: `egui, emath, epaint, egui_extras, epi, egui-winit, egui_web, egui_glium, egui_glow, egui_demo_lib, egui_demo_app`.
|
||||||
|
|
||||||
### `egui`: The main GUI library.
|
### `egui`: The main GUI library.
|
||||||
Example code: `if ui.button("Click me").clicked() { … }`
|
Example code: `if ui.button("Click me").clicked() { … }`
|
||||||
|
@ -21,6 +21,9 @@ Example: `Shape::Circle { center, radius, fill, stroke }`
|
||||||
|
|
||||||
Depends on `emath`, [`ab_glyph`](https://crates.io/crates/ab_glyph), [`atomic_refcell`](https://crates.io/crates/atomic_refcell), [`ahash`](https://crates.io/crates/ahash).
|
Depends on `emath`, [`ab_glyph`](https://crates.io/crates/ab_glyph), [`atomic_refcell`](https://crates.io/crates/atomic_refcell), [`ahash`](https://crates.io/crates/ahash).
|
||||||
|
|
||||||
|
### `egui_extras`
|
||||||
|
This adds additional features on top of `egui`.
|
||||||
|
|
||||||
### `epi`
|
### `epi`
|
||||||
Depends only on `egui`.
|
Depends only on `egui`.
|
||||||
Adds a thin application level wrapper around `egui` for hosting an `egui` app inside of `eframe`.
|
Adds a thin application level wrapper around `egui` for hosting an `egui` app inside of `eframe`.
|
||||||
|
|
94
Cargo.lock
generated
94
Cargo.lock
generated
|
@ -994,6 +994,7 @@ version = "0.16.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"egui",
|
"egui",
|
||||||
"egui-winit",
|
"egui-winit",
|
||||||
|
"egui_extras",
|
||||||
"egui_glium",
|
"egui_glium",
|
||||||
"egui_glow",
|
"egui_glow",
|
||||||
"egui_web",
|
"egui_web",
|
||||||
|
@ -1001,10 +1002,7 @@ dependencies = [
|
||||||
"epi",
|
"epi",
|
||||||
"image",
|
"image",
|
||||||
"poll-promise",
|
"poll-promise",
|
||||||
"resvg",
|
|
||||||
"rfd",
|
"rfd",
|
||||||
"tiny-skia",
|
|
||||||
"usvg",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1053,6 +1051,7 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"criterion",
|
"criterion",
|
||||||
"egui",
|
"egui",
|
||||||
|
"egui_extras",
|
||||||
"ehttp",
|
"ehttp",
|
||||||
"enum-map",
|
"enum-map",
|
||||||
"epi",
|
"epi",
|
||||||
|
@ -1063,6 +1062,18 @@ dependencies = [
|
||||||
"unicode_names2",
|
"unicode_names2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "egui_extras"
|
||||||
|
version = "0.16.0"
|
||||||
|
dependencies = [
|
||||||
|
"egui",
|
||||||
|
"image",
|
||||||
|
"parking_lot",
|
||||||
|
"resvg",
|
||||||
|
"tiny-skia",
|
||||||
|
"usvg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui_glium"
|
name = "egui_glium"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
|
@ -1335,14 +1346,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fontdb"
|
name = "fontconfig-parser"
|
||||||
version = "0.7.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "01b07f5c05414a0d8caba4c17eef8dc8b5c8955fc7c68d324191c7a56d3f3449"
|
checksum = "82cea2adebf32a9b104b8ffb308b5fb3b456f04cc76c294c3c85025c8a5d75f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"roxmltree",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fontdb"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db856ee8cca3b9f23dd11c13bf3d4854b663ae86ed0c4a627a354431fc265f66"
|
||||||
|
dependencies = [
|
||||||
|
"fontconfig-parser",
|
||||||
"log",
|
"log",
|
||||||
"memmap2 0.5.2",
|
"memmap2 0.5.2",
|
||||||
"ttf-parser 0.12.3",
|
"ttf-parser 0.15.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1515,6 +1536,16 @@ dependencies = [
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gif"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3a7187e78088aead22ceedeee99779455b23fc231fe13ec443f99bb71694e5b"
|
||||||
|
dependencies = [
|
||||||
|
"color_quant",
|
||||||
|
"weezl",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.26.1"
|
version = "0.26.1"
|
||||||
|
@ -1764,7 +1795,7 @@ dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"color_quant",
|
"color_quant",
|
||||||
"jpeg-decoder 0.2.1",
|
"jpeg-decoder",
|
||||||
"num-iter",
|
"num-iter",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
@ -1836,15 +1867,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jpeg-decoder"
|
name = "jpeg-decoder"
|
||||||
version = "0.1.22"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
|
checksum = "105fb082d64e2100074587f59a74231f771750c664af903f1f9f76c9dedfc6f1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jpeg-decoder"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fbcf0244f6597be39ab8d9203f574cafb529ae8c698afa2182f7b3c3205a4a9c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
|
@ -2671,11 +2696,12 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "resvg"
|
name = "resvg"
|
||||||
version = "0.20.0"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d94a32ca845cdda27237a40beba9bd3d3858ac8fc5356eb9442bdeecfe34d9e0"
|
checksum = "2e702d1e8e00a3a0717b96244cba840f34f542d8f23097c8903266c4e2975658"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jpeg-decoder 0.1.22",
|
"gif",
|
||||||
|
"jpeg-decoder",
|
||||||
"log",
|
"log",
|
||||||
"pico-args",
|
"pico-args",
|
||||||
"png",
|
"png",
|
||||||
|
@ -2801,14 +2827,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustybuzz"
|
name = "rustybuzz"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44561062e583c4873162861261f16fd1d85fe927c4904d71329a4fe43dc355ef"
|
checksum = "25ff94f20221325d000e552781713e53b0d85c1d9551b6f420d12daf5a08eace"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"ttf-parser 0.12.3",
|
"ttf-parser 0.15.0",
|
||||||
"unicode-bidi-mirroring",
|
"unicode-bidi-mirroring",
|
||||||
"unicode-ccc",
|
"unicode-ccc",
|
||||||
"unicode-general-category",
|
"unicode-general-category",
|
||||||
|
@ -3339,18 +3365,18 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ttf-parser"
|
|
||||||
version = "0.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ttf-parser"
|
name = "ttf-parser"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281"
|
checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ttf-parser"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c74c96594835e10fa545e2a51e8709f30b173a092bfd6036ef2cec53376244f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tts"
|
name = "tts"
|
||||||
version = "0.20.2"
|
version = "0.20.2"
|
||||||
|
@ -3472,9 +3498,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usvg"
|
name = "usvg"
|
||||||
version = "0.20.0"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00f064d38f79ff69e3160e2fba884e4ede897061c15178041a3976371c68cab1"
|
checksum = "a261d60a7215fa339482047cc3dafd4e22e2bf34396aaebef2b707355bbb39c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"data-url",
|
"data-url",
|
||||||
|
@ -3490,7 +3516,7 @@ dependencies = [
|
||||||
"simplecss",
|
"simplecss",
|
||||||
"siphasher",
|
"siphasher",
|
||||||
"svgtypes",
|
"svgtypes",
|
||||||
"ttf-parser 0.12.3",
|
"ttf-parser 0.15.0",
|
||||||
"unicode-bidi",
|
"unicode-bidi",
|
||||||
"unicode-script",
|
"unicode-script",
|
||||||
"unicode-vo",
|
"unicode-vo",
|
||||||
|
@ -3733,6 +3759,12 @@ dependencies = [
|
||||||
"webpki",
|
"webpki",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "weezl"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wepoll-ffi"
|
name = "wepoll-ffi"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
|
|
@ -3,6 +3,7 @@ resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"egui_demo_app",
|
"egui_demo_app",
|
||||||
"egui_demo_lib",
|
"egui_demo_lib",
|
||||||
|
"egui_extras",
|
||||||
"egui_glium",
|
"egui_glium",
|
||||||
"egui_glow",
|
"egui_glow",
|
||||||
"egui_web",
|
"egui_web",
|
||||||
|
|
|
@ -64,12 +64,9 @@ egui_web = { version = "0.16.0", path = "../egui_web", default-features = false,
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
# For examples:
|
||||||
|
egui_extras = { path = "../egui_extras", features = ["image", "svg"] }
|
||||||
ehttp = "0.2"
|
ehttp = "0.2"
|
||||||
image = { version = "0.24", default-features = false, features = ["jpeg", "png"] }
|
image = { version = "0.24", default-features = false, features = ["jpeg", "png"] }
|
||||||
poll-promise = "0.1"
|
poll-promise = "0.1"
|
||||||
rfd = "0.7"
|
rfd = "0.7"
|
||||||
|
|
||||||
# svg.rs example:
|
|
||||||
resvg = "0.20"
|
|
||||||
tiny-skia = "0.6"
|
|
||||||
usvg = "0.20"
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::{egui, epi};
|
||||||
|
use egui_extras::RetainedImage;
|
||||||
use poll_promise::Promise;
|
use poll_promise::Promise;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -11,7 +12,7 @@ fn main() {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
/// `None` when download hasn't started yet.
|
/// `None` when download hasn't started yet.
|
||||||
promise: Option<Promise<ehttp::Result<egui::TextureHandle>>>,
|
promise: Option<Promise<ehttp::Result<RetainedImage>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl epi::App for MyApp {
|
||||||
|
@ -24,14 +25,13 @@ impl epi::App for MyApp {
|
||||||
// Begin download.
|
// Begin download.
|
||||||
// We download the image using `ehttp`, a library that works both in WASM and on native.
|
// 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.
|
// We use the `poll-promise` library to communicate with the UI thread.
|
||||||
let ctx = ctx.clone();
|
|
||||||
let frame = frame.clone();
|
let frame = frame.clone();
|
||||||
let (sender, promise) = Promise::new();
|
let (sender, promise) = Promise::new();
|
||||||
let request = ehttp::Request::get("https://picsum.photos/seed/1.759706314/1024");
|
let request = ehttp::Request::get("https://picsum.photos/seed/1.759706314/1024");
|
||||||
ehttp::fetch(request, move |response| {
|
ehttp::fetch(request, move |response| {
|
||||||
|
let image = response.and_then(parse_response);
|
||||||
|
sender.send(image); // send the results back to the UI thread.
|
||||||
frame.request_repaint(); // wake up UI thread
|
frame.request_repaint(); // wake up UI thread
|
||||||
let texture = response.and_then(|response| parse_response(&ctx, response));
|
|
||||||
sender.send(texture); // send the results back to the UI thread.
|
|
||||||
});
|
});
|
||||||
promise
|
promise
|
||||||
});
|
});
|
||||||
|
@ -43,24 +43,17 @@ impl epi::App for MyApp {
|
||||||
Some(Err(err)) => {
|
Some(Err(err)) => {
|
||||||
ui.colored_label(egui::Color32::RED, err); // something went wrong
|
ui.colored_label(egui::Color32::RED, err); // something went wrong
|
||||||
}
|
}
|
||||||
Some(Ok(texture)) => {
|
Some(Ok(image)) => {
|
||||||
let mut size = texture.size_vec2();
|
image.show_max_size(ui, ui.available_size());
|
||||||
size *= (ui.available_width() / size.x).min(1.0);
|
|
||||||
size *= (ui.available_height() / size.y).min(1.0);
|
|
||||||
ui.image(texture, size);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_response(
|
fn parse_response(response: ehttp::Response) -> Result<RetainedImage, String> {
|
||||||
ctx: &egui::Context,
|
|
||||||
response: ehttp::Response,
|
|
||||||
) -> Result<egui::TextureHandle, String> {
|
|
||||||
let content_type = response.content_type().unwrap_or_default();
|
let content_type = response.content_type().unwrap_or_default();
|
||||||
if content_type.starts_with("image/") {
|
if content_type.starts_with("image/") {
|
||||||
let image = load_image(&response.bytes).map_err(|err| err.to_string())?;
|
RetainedImage::from_image_bytes(&response.url, &response.bytes)
|
||||||
Ok(ctx.load_texture("my-image", image))
|
|
||||||
} else {
|
} else {
|
||||||
Err(format!(
|
Err(format!(
|
||||||
"Expected image, found content-type {:?}",
|
"Expected image, found content-type {:?}",
|
||||||
|
@ -68,14 +61,3 @@ fn parse_response(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_image(image_data: &[u8]) -> Result<egui::ColorImage, image::ImageError> {
|
|
||||||
let image = image::load_from_memory(image_data)?;
|
|
||||||
let size = [image.width() as _, image.height() as _];
|
|
||||||
let image_buffer = image.to_rgba8();
|
|
||||||
let pixels = image_buffer.as_flat_samples();
|
|
||||||
Ok(egui::ColorImage::from_rgba_unmultiplied(
|
|
||||||
size,
|
|
||||||
pixels.as_slice(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,22 @@
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::{egui, epi};
|
use eframe::{egui, epi};
|
||||||
|
use egui_extras::RetainedImage;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
texture: Option<egui::TextureHandle>,
|
image: RetainedImage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MyApp {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
image: RetainedImage::from_image_bytes(
|
||||||
|
"rust-logo-256x256.png",
|
||||||
|
include_bytes!("rust-logo-256x256.png"),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl epi::App for MyApp {
|
impl epi::App for MyApp {
|
||||||
|
@ -13,17 +25,15 @@ impl epi::App for MyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
|
||||||
let texture: &egui::TextureHandle = self.texture.get_or_insert_with(|| {
|
|
||||||
let image = load_image(include_bytes!("rust-logo-256x256.png")).unwrap();
|
|
||||||
ctx.load_texture("rust-logo", image)
|
|
||||||
});
|
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("This is an image:");
|
ui.heading("This is an image:");
|
||||||
ui.image(texture, texture.size_vec2());
|
self.image.show(ui);
|
||||||
|
|
||||||
ui.heading("This is an image you can click:");
|
ui.heading("This is an image you can click:");
|
||||||
ui.add(egui::ImageButton::new(texture, texture.size_vec2()));
|
ui.add(egui::ImageButton::new(
|
||||||
|
self.image.texture_id(ctx),
|
||||||
|
self.image.size_vec2(),
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,14 +42,3 @@ fn main() {
|
||||||
let options = eframe::NativeOptions::default();
|
let options = eframe::NativeOptions::default();
|
||||||
eframe::run_native(Box::new(MyApp::default()), options);
|
eframe::run_native(Box::new(MyApp::default()), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_image(image_data: &[u8]) -> Result<egui::ColorImage, image::ImageError> {
|
|
||||||
let image = image::load_from_memory(image_data)?;
|
|
||||||
let size = [image.width() as _, image.height() as _];
|
|
||||||
let image_buffer = image.to_rgba8();
|
|
||||||
let pixels = image_buffer.as_flat_samples();
|
|
||||||
Ok(egui::ColorImage::from_rgba_unmultiplied(
|
|
||||||
size,
|
|
||||||
pixels.as_slice(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,82 +1,23 @@
|
||||||
//! A good way of displaying an SVG image in egui.
|
//! A good way of displaying an SVG image in egui.
|
||||||
//!
|
//!
|
||||||
//! Requires the dependencies `resvg`, `tiny-skia`, `usvg`
|
//! 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, epi};
|
use eframe::{egui, epi};
|
||||||
|
|
||||||
/// Load an SVG and rasterize it into an egui image.
|
|
||||||
fn load_svg_data(svg_data: &[u8]) -> Result<egui::ColorImage, String> {
|
|
||||||
let mut opt = usvg::Options::default();
|
|
||||||
opt.fontdb.load_system_fonts();
|
|
||||||
|
|
||||||
let rtree = usvg::Tree::from_data(svg_data, &opt.to_ref()).map_err(|err| err.to_string())?;
|
|
||||||
|
|
||||||
let pixmap_size = rtree.svg_node().size.to_screen_size();
|
|
||||||
let [w, h] = [pixmap_size.width(), pixmap_size.height()];
|
|
||||||
|
|
||||||
let mut pixmap = tiny_skia::Pixmap::new(w, h)
|
|
||||||
.ok_or_else(|| format!("Failed to create SVG Pixmap of size {}x{}", w, h))?;
|
|
||||||
|
|
||||||
resvg::render(
|
|
||||||
&rtree,
|
|
||||||
usvg::FitTo::Original,
|
|
||||||
tiny_skia::Transform::default(),
|
|
||||||
pixmap.as_mut(),
|
|
||||||
)
|
|
||||||
.ok_or_else(|| "Failed to render SVG".to_owned())?;
|
|
||||||
|
|
||||||
let image = egui::ColorImage::from_rgba_unmultiplied(
|
|
||||||
[pixmap.width() as _, pixmap.height() as _],
|
|
||||||
pixmap.data(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(image)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// An SVG image to be shown in egui
|
|
||||||
struct SvgImage {
|
|
||||||
image: egui::ColorImage,
|
|
||||||
texture: Option<egui::TextureHandle>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SvgImage {
|
|
||||||
/// Pass itn the bytes of an SVG that you've loaded from disk
|
|
||||||
pub fn from_svg_data(bytes: &[u8]) -> Result<Self, String> {
|
|
||||||
Ok(Self {
|
|
||||||
image: load_svg_data(bytes)?,
|
|
||||||
texture: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_max_size(&mut self, ui: &mut egui::Ui, max_size: egui::Vec2) -> egui::Response {
|
|
||||||
let mut desired_size = egui::vec2(self.image.width() as _, self.image.height() as _);
|
|
||||||
desired_size *= (max_size.x / desired_size.x).min(1.0);
|
|
||||||
desired_size *= (max_size.y / desired_size.y).min(1.0);
|
|
||||||
self.show_size(ui, desired_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show_size(&mut self, ui: &mut egui::Ui, desired_size: egui::Vec2) -> egui::Response {
|
|
||||||
// We need to convert the SVG to a texture to display it:
|
|
||||||
// Future improvement: tell backend to do mip-mapping of the image to
|
|
||||||
// make it look smoother when downsized.
|
|
||||||
let svg_texture = self
|
|
||||||
.texture
|
|
||||||
.get_or_insert_with(|| ui.ctx().load_texture("svg", self.image.clone()));
|
|
||||||
ui.image(svg_texture, desired_size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
svg_image: SvgImage,
|
svg_image: egui_extras::RetainedImage,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MyApp {
|
impl Default for MyApp {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
svg_image: SvgImage::from_svg_data(include_bytes!("rustacean-flat-happy.svg")).unwrap(),
|
svg_image: egui_extras::RetainedImage::from_svg_bytes(
|
||||||
|
"rustacean-flat-happy.svg",
|
||||||
|
include_bytes!("rustacean-flat-happy.svg"),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,13 @@ impl From<&String> for RichText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&mut String> for RichText {
|
||||||
|
#[inline]
|
||||||
|
fn from(text: &mut String) -> Self {
|
||||||
|
RichText::new(text.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<String> for RichText {
|
impl From<String> for RichText {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(text: String) -> Self {
|
fn from(text: String) -> Self {
|
||||||
|
|
|
@ -40,6 +40,7 @@ syntax_highlighting = ["syntect"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
egui = { version = "0.16.0", path = "../egui", default-features = false }
|
egui = { version = "0.16.0", path = "../egui", default-features = false }
|
||||||
|
egui_extras = { version = "0.16.0", path = "../egui_extras", features = ["image"] }
|
||||||
epi = { version = "0.16.0", path = "../epi" }
|
epi = { version = "0.16.0", path = "../epi" }
|
||||||
|
|
||||||
chrono = { version = "0.4", features = ["js-sys", "wasmbind"], optional = true }
|
chrono = { version = "0.4", features = ["js-sys", "wasmbind"], optional = true }
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use egui_extras::RetainedImage;
|
||||||
use poll_promise::Promise;
|
use poll_promise::Promise;
|
||||||
|
|
||||||
struct Resource {
|
struct Resource {
|
||||||
|
@ -7,7 +8,7 @@ struct Resource {
|
||||||
text: Option<String>,
|
text: Option<String>,
|
||||||
|
|
||||||
/// If set, the response was an image.
|
/// If set, the response was an image.
|
||||||
texture: Option<egui::TextureHandle>,
|
image: Option<RetainedImage>,
|
||||||
|
|
||||||
/// If set, the response was text with some supported syntax highlighting (e.g. ".rs" or ".md").
|
/// If set, the response was text with some supported syntax highlighting (e.g. ".rs" or ".md").
|
||||||
colored_text: Option<ColoredText>,
|
colored_text: Option<ColoredText>,
|
||||||
|
@ -17,13 +18,11 @@ impl Resource {
|
||||||
fn from_response(ctx: &egui::Context, response: ehttp::Response) -> Self {
|
fn from_response(ctx: &egui::Context, response: ehttp::Response) -> Self {
|
||||||
let content_type = response.content_type().unwrap_or_default();
|
let content_type = response.content_type().unwrap_or_default();
|
||||||
let image = if content_type.starts_with("image/") {
|
let image = if content_type.starts_with("image/") {
|
||||||
load_image(&response.bytes).ok()
|
RetainedImage::from_image_bytes(&response.url, &response.bytes).ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let texture = image.map(|image| ctx.load_texture(&response.url, image));
|
|
||||||
|
|
||||||
let text = response.text();
|
let text = response.text();
|
||||||
let colored_text = text.and_then(|text| syntax_highlighting(ctx, &response, text));
|
let colored_text = text.and_then(|text| syntax_highlighting(ctx, &response, text));
|
||||||
let text = text.map(|text| text.to_owned());
|
let text = text.map(|text| text.to_owned());
|
||||||
|
@ -31,7 +30,7 @@ impl Resource {
|
||||||
Self {
|
Self {
|
||||||
response,
|
response,
|
||||||
text,
|
text,
|
||||||
texture,
|
image,
|
||||||
colored_text,
|
colored_text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +150,7 @@ fn ui_resource(ui: &mut egui::Ui, resource: &Resource) {
|
||||||
let Resource {
|
let Resource {
|
||||||
response,
|
response,
|
||||||
text,
|
text,
|
||||||
texture,
|
image,
|
||||||
colored_text,
|
colored_text,
|
||||||
} = resource;
|
} = resource;
|
||||||
|
|
||||||
|
@ -198,10 +197,10 @@ fn ui_resource(ui: &mut egui::Ui, resource: &Resource) {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(texture) = texture {
|
if let Some(image) = image {
|
||||||
let mut size = texture.size_vec2();
|
let mut size = image.size_vec2();
|
||||||
size *= (ui.available_width() / size.x).min(1.0);
|
size *= (ui.available_width() / size.x).min(1.0);
|
||||||
ui.image(texture, size);
|
image.show_size(ui, size);
|
||||||
} else if let Some(colored_text) = colored_text {
|
} else if let Some(colored_text) = colored_text {
|
||||||
colored_text.ui(ui);
|
colored_text.ui(ui);
|
||||||
} else if let Some(text) = &text {
|
} else if let Some(text) = &text {
|
||||||
|
@ -270,16 +269,3 @@ impl ColoredText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
fn load_image(image_data: &[u8]) -> Result<egui::ColorImage, image::ImageError> {
|
|
||||||
let image = image::load_from_memory(image_data)?;
|
|
||||||
let size = [image.width() as _, image.height() as _];
|
|
||||||
let image_buffer = image.to_rgba8();
|
|
||||||
let pixels = image_buffer.as_flat_samples();
|
|
||||||
Ok(egui::ColorImage::from_rgba_unmultiplied(
|
|
||||||
size,
|
|
||||||
pixels.as_slice(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
6
egui_extras/CHANGELOG.md
Normal file
6
egui_extras/CHANGELOG.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Changelog for egui_extras
|
||||||
|
All notable changes to the `egui_extras` integration will be noted in this file.
|
||||||
|
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
* `RetainedImage`: conventience for loading svg, png, jpeg etc and showing them in egui.
|
48
egui_extras/Cargo.toml
Normal file
48
egui_extras/Cargo.toml
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
[package]
|
||||||
|
name = "egui_extras"
|
||||||
|
version = "0.16.0"
|
||||||
|
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
|
||||||
|
description = "Extra functionality and widgets for the egui GUI library"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.56"
|
||||||
|
homepage = "https://github.com/emilk/egui"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
readme = "../README.md"
|
||||||
|
repository = "https://github.com/emilk/egui"
|
||||||
|
categories = ["gui", "game-development"]
|
||||||
|
keywords = ["gui", "imgui", "immediate", "portable", "gamedev"]
|
||||||
|
include = [
|
||||||
|
"../LICENSE-APACHE",
|
||||||
|
"../LICENSE-MIT",
|
||||||
|
"**/*.rs",
|
||||||
|
"Cargo.toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
|
||||||
|
# Support loading svg images
|
||||||
|
svg = ["resvg", "tiny-skia", "usvg"]
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
egui = { version = "0.16.1", path = "../egui", default-features = false, features = ["single_threaded"] }
|
||||||
|
parking_lot = "0.11"
|
||||||
|
|
||||||
|
# Optional dependencies:
|
||||||
|
|
||||||
|
# Add support for loading images with the `image` crate.
|
||||||
|
# You also need to ALSO opt-in to the image formats you want to support, like so:
|
||||||
|
# image = { version = "0.24", features = ["jpeg", "png"] }
|
||||||
|
image = { version = "0.24", optional = true, default-features = false, features = [] }
|
||||||
|
|
||||||
|
# svg feature
|
||||||
|
resvg = { version = "0.22", optional = true }
|
||||||
|
tiny-skia = { version = "0.6", optional = true }
|
||||||
|
usvg = { version = "0.22", optional = true }
|
8
egui_extras/README.md
Normal file
8
egui_extras/README.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# egui_extras
|
||||||
|
|
||||||
|
[](https://crates.io/crates/egui_extras)
|
||||||
|
[](https://docs.rs/egui_extras)
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
This is a crate that adds some features on top top of [`egui`](https://github.com/emilk/egui). This crate are for experimental features, and features that require big dependencies that does not belong in `egui`.
|
177
egui_extras/src/image.rs
Normal file
177
egui_extras/src/image.rs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
/// An image to be shown in egui.
|
||||||
|
///
|
||||||
|
/// Load once, and save somewhere in your app state.
|
||||||
|
///
|
||||||
|
/// Use the `svg` and `image` features to enable more constructors.
|
||||||
|
pub struct RetainedImage {
|
||||||
|
debug_name: String,
|
||||||
|
size: [usize; 2],
|
||||||
|
/// Cleared once [`Self::texture`] has been loaded.
|
||||||
|
image: Mutex<egui::ColorImage>,
|
||||||
|
/// Lazily loaded when we have an egui context.
|
||||||
|
texture: Mutex<Option<egui::TextureHandle>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RetainedImage {
|
||||||
|
pub fn from_color_image(debug_name: impl Into<String>, image: ColorImage) -> Self {
|
||||||
|
Self {
|
||||||
|
debug_name: debug_name.into(),
|
||||||
|
size: image.size,
|
||||||
|
image: Mutex::new(image),
|
||||||
|
texture: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load a (non-svg) image.
|
||||||
|
///
|
||||||
|
/// Requires the "image" feature. You must also opt-in to the image formats you need
|
||||||
|
/// with e.g. `image = { version = "0.24", features = ["jpeg", "png"] }`.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// On invalid image or unsupported image format.
|
||||||
|
#[cfg(feature = "image")]
|
||||||
|
pub fn from_image_bytes(
|
||||||
|
debug_name: impl Into<String>,
|
||||||
|
image_bytes: &[u8],
|
||||||
|
) -> Result<Self, String> {
|
||||||
|
Ok(Self::from_color_image(
|
||||||
|
debug_name,
|
||||||
|
load_image_bytes(image_bytes)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pass in the bytes of an SVG that you've loaded.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// On invalid image
|
||||||
|
#[cfg(feature = "svg")]
|
||||||
|
pub fn from_svg_bytes(debug_name: impl Into<String>, svg_bytes: &[u8]) -> Result<Self, String> {
|
||||||
|
Ok(Self::from_color_image(
|
||||||
|
debug_name,
|
||||||
|
load_svg_bytes(svg_bytes)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pass in the str of an SVG that you've loaded.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// On invalid image
|
||||||
|
#[cfg(feature = "svg")]
|
||||||
|
pub fn from_svg_str(debug_name: impl Into<String>, svg_str: &str) -> Result<Self, String> {
|
||||||
|
Self::from_svg_bytes(debug_name, svg_str.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The size of the image data (number of pixels wide/high).
|
||||||
|
pub fn size(&self) -> [usize; 2] {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The size of the image data (number of pixels wide/high).
|
||||||
|
pub fn size_vec2(&self) -> egui::Vec2 {
|
||||||
|
let [w, h] = self.size();
|
||||||
|
egui::vec2(w as f32, h as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The debug name of the image, e.g. the file name.
|
||||||
|
pub fn debug_name(&self) -> &str {
|
||||||
|
&self.debug_name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The texture if for this image.
|
||||||
|
pub fn texture_id(&self, ctx: &egui::Context) -> egui::TextureId {
|
||||||
|
self.texture
|
||||||
|
.lock()
|
||||||
|
.get_or_insert_with(|| {
|
||||||
|
let image: &mut ColorImage = &mut self.image.lock();
|
||||||
|
let image = std::mem::take(image);
|
||||||
|
ctx.load_texture(&self.debug_name, image)
|
||||||
|
})
|
||||||
|
.id()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show the image with the given maximum size.
|
||||||
|
pub fn show_max_size(&self, ui: &mut egui::Ui, max_size: egui::Vec2) -> egui::Response {
|
||||||
|
let mut desired_size = self.size_vec2();
|
||||||
|
desired_size *= (max_size.x / desired_size.x).min(1.0);
|
||||||
|
desired_size *= (max_size.y / desired_size.y).min(1.0);
|
||||||
|
self.show_size(ui, desired_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show the image with the original size (one image pixel = one gui point).
|
||||||
|
pub fn show(&self, ui: &mut egui::Ui) -> egui::Response {
|
||||||
|
self.show_size(ui, self.size_vec2())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show the image with the given scale factor (1.0 = original size).
|
||||||
|
pub fn show_scaled(&self, ui: &mut egui::Ui, scale: f32) -> egui::Response {
|
||||||
|
self.show_size(ui, self.size_vec2() * scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show the image with the given size.
|
||||||
|
pub fn show_size(&self, ui: &mut egui::Ui, desired_size: egui::Vec2) -> egui::Response {
|
||||||
|
// We need to convert the SVG to a texture to display it:
|
||||||
|
// Future improvement: tell backend to do mip-mapping of the image to
|
||||||
|
// make it look smoother when downsized.
|
||||||
|
ui.image(self.texture_id(ui.ctx()), desired_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
use egui::ColorImage;
|
||||||
|
|
||||||
|
/// Load a (non-svg) image.
|
||||||
|
///
|
||||||
|
/// Requires the "image" feature. You must also opt-in to the image formats you need
|
||||||
|
/// with e.g. `image = { version = "0.24", features = ["jpeg", "png"] }`.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// On invalid image or unsupported image format.
|
||||||
|
#[cfg(feature = "image")]
|
||||||
|
pub fn load_image_bytes(image_bytes: &[u8]) -> Result<egui::ColorImage, String> {
|
||||||
|
let image = image::load_from_memory(image_bytes).map_err(|err| err.to_string())?;
|
||||||
|
let size = [image.width() as _, image.height() as _];
|
||||||
|
let image_buffer = image.to_rgba8();
|
||||||
|
let pixels = image_buffer.as_flat_samples();
|
||||||
|
Ok(egui::ColorImage::from_rgba_unmultiplied(
|
||||||
|
size,
|
||||||
|
pixels.as_slice(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load an SVG and rasterize it into an egui image.
|
||||||
|
///
|
||||||
|
/// Requires the "svg" feature.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// On invalid image
|
||||||
|
#[cfg(feature = "svg")]
|
||||||
|
pub fn load_svg_bytes(svg_bytes: &[u8]) -> Result<egui::ColorImage, String> {
|
||||||
|
let mut opt = usvg::Options::default();
|
||||||
|
opt.fontdb.load_system_fonts();
|
||||||
|
|
||||||
|
let rtree = usvg::Tree::from_data(svg_bytes, &opt.to_ref()).map_err(|err| err.to_string())?;
|
||||||
|
|
||||||
|
let pixmap_size = rtree.svg_node().size.to_screen_size();
|
||||||
|
let [w, h] = [pixmap_size.width(), pixmap_size.height()];
|
||||||
|
|
||||||
|
let mut pixmap = tiny_skia::Pixmap::new(w, h)
|
||||||
|
.ok_or_else(|| format!("Failed to create SVG Pixmap of size {}x{}", w, h))?;
|
||||||
|
|
||||||
|
resvg::render(
|
||||||
|
&rtree,
|
||||||
|
usvg::FitTo::Original,
|
||||||
|
tiny_skia::Transform::default(),
|
||||||
|
pixmap.as_mut(),
|
||||||
|
)
|
||||||
|
.ok_or_else(|| "Failed to render SVG".to_owned())?;
|
||||||
|
|
||||||
|
let image = egui::ColorImage::from_rgba_unmultiplied(
|
||||||
|
[pixmap.width() as _, pixmap.height() as _],
|
||||||
|
pixmap.data(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(image)
|
||||||
|
}
|
87
egui_extras/src/lib.rs
Normal file
87
egui_extras/src/lib.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
//! This is a crate that adds some features on top top of [`egui`](https://github.com/emilk/egui). This crate are for experimental features, and features that require big dependencies that does not belong in `egui`.
|
||||||
|
|
||||||
|
// Forbid warnings in release builds:
|
||||||
|
#![cfg_attr(not(debug_assertions), deny(warnings))]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
#![warn(
|
||||||
|
clippy::all,
|
||||||
|
clippy::await_holding_lock,
|
||||||
|
clippy::char_lit_as_u8,
|
||||||
|
clippy::checked_conversions,
|
||||||
|
clippy::dbg_macro,
|
||||||
|
clippy::debug_assert_with_mut_call,
|
||||||
|
clippy::disallowed_method,
|
||||||
|
clippy::doc_markdown,
|
||||||
|
clippy::empty_enum,
|
||||||
|
clippy::enum_glob_use,
|
||||||
|
clippy::exit,
|
||||||
|
clippy::expl_impl_clone_on_copy,
|
||||||
|
clippy::explicit_deref_methods,
|
||||||
|
clippy::explicit_into_iter_loop,
|
||||||
|
clippy::fallible_impl_from,
|
||||||
|
clippy::filter_map_next,
|
||||||
|
clippy::flat_map_option,
|
||||||
|
clippy::float_cmp_const,
|
||||||
|
clippy::fn_params_excessive_bools,
|
||||||
|
clippy::from_iter_instead_of_collect,
|
||||||
|
clippy::if_let_mutex,
|
||||||
|
clippy::implicit_clone,
|
||||||
|
clippy::imprecise_flops,
|
||||||
|
clippy::inefficient_to_string,
|
||||||
|
clippy::invalid_upcast_comparisons,
|
||||||
|
clippy::large_digit_groups,
|
||||||
|
clippy::large_stack_arrays,
|
||||||
|
clippy::large_types_passed_by_value,
|
||||||
|
clippy::let_unit_value,
|
||||||
|
clippy::linkedlist,
|
||||||
|
clippy::lossy_float_literal,
|
||||||
|
clippy::macro_use_imports,
|
||||||
|
clippy::manual_ok_or,
|
||||||
|
clippy::map_err_ignore,
|
||||||
|
clippy::map_flatten,
|
||||||
|
clippy::map_unwrap_or,
|
||||||
|
clippy::match_on_vec_items,
|
||||||
|
clippy::match_same_arms,
|
||||||
|
clippy::match_wild_err_arm,
|
||||||
|
clippy::match_wildcard_for_single_variants,
|
||||||
|
clippy::mem_forget,
|
||||||
|
clippy::mismatched_target_os,
|
||||||
|
clippy::missing_errors_doc,
|
||||||
|
clippy::missing_safety_doc,
|
||||||
|
clippy::mut_mut,
|
||||||
|
clippy::mutex_integer,
|
||||||
|
clippy::needless_borrow,
|
||||||
|
clippy::needless_continue,
|
||||||
|
clippy::needless_for_each,
|
||||||
|
clippy::needless_pass_by_value,
|
||||||
|
clippy::option_option,
|
||||||
|
clippy::path_buf_push_overwrite,
|
||||||
|
clippy::ptr_as_ptr,
|
||||||
|
clippy::ref_option_ref,
|
||||||
|
clippy::rest_pat_in_fully_bound_structs,
|
||||||
|
clippy::same_functions_in_if_condition,
|
||||||
|
clippy::semicolon_if_nothing_returned,
|
||||||
|
clippy::single_match_else,
|
||||||
|
clippy::string_add_assign,
|
||||||
|
clippy::string_add,
|
||||||
|
clippy::string_lit_as_bytes,
|
||||||
|
clippy::string_to_string,
|
||||||
|
clippy::todo,
|
||||||
|
clippy::trait_duplication_in_bounds,
|
||||||
|
clippy::unimplemented,
|
||||||
|
clippy::unnested_or_patterns,
|
||||||
|
clippy::unused_self,
|
||||||
|
clippy::useless_transmute,
|
||||||
|
clippy::verbose_file_reads,
|
||||||
|
clippy::zero_sized_map_values,
|
||||||
|
future_incompatible,
|
||||||
|
nonstandard_style,
|
||||||
|
rust_2018_idioms,
|
||||||
|
rustdoc::missing_crate_level_docs
|
||||||
|
)]
|
||||||
|
#![allow(clippy::float_cmp)]
|
||||||
|
#![allow(clippy::manual_range_contains)]
|
||||||
|
|
||||||
|
pub mod image;
|
||||||
|
|
||||||
|
pub use crate::image::RetainedImage;
|
|
@ -28,6 +28,7 @@ cargo doc --document-private-items --no-deps --all-features
|
||||||
(cd eframe && cargo check --no-default-features --features "egui_glow")
|
(cd eframe && cargo check --no-default-features --features "egui_glow")
|
||||||
(cd epi && cargo check --no-default-features)
|
(cd epi && cargo check --no-default-features)
|
||||||
(cd egui_demo_lib && cargo check --no-default-features)
|
(cd egui_demo_lib && cargo check --no-default-features)
|
||||||
|
(cd egui_extras && cargo check --no-default-features)
|
||||||
# (cd egui_web && cargo check --no-default-features) # we need to pick webgl or glow backend
|
# (cd egui_web && cargo check --no-default-features) # we need to pick webgl or glow backend
|
||||||
# (cd egui-winit && cargo check --no-default-features) # we don't pick singlethreaded or multithreaded
|
# (cd egui-winit && cargo check --no-default-features) # we don't pick singlethreaded or multithreaded
|
||||||
(cd egui_glium && cargo check --no-default-features)
|
(cd egui_glium && cargo check --no-default-features)
|
||||||
|
@ -36,6 +37,7 @@ cargo doc --document-private-items --no-deps --all-features
|
||||||
|
|
||||||
(cd eframe && cargo check --all-features)
|
(cd eframe && cargo check --all-features)
|
||||||
(cd egui && cargo check --all-features)
|
(cd egui && cargo check --all-features)
|
||||||
|
(cd egui_extras && cargo check --all-features)
|
||||||
(cd egui_glium && cargo check --all-features)
|
(cd egui_glium && cargo check --all-features)
|
||||||
(cd egui_glow && cargo check --all-features)
|
(cd egui_glow && cargo check --all-features)
|
||||||
(cd egui_web && cargo check --all-features)
|
(cd egui_web && cargo check --all-features)
|
||||||
|
|
|
@ -4,6 +4,6 @@ script_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
||||||
cd "$script_path/.."
|
cd "$script_path/.."
|
||||||
|
|
||||||
cargo doc -p egui_web --target wasm32-unknown-unknown --lib --no-deps --all-features
|
cargo doc -p egui_web --target wasm32-unknown-unknown --lib --no-deps --all-features
|
||||||
cargo doc -p emath -p epaint -p egui -p eframe -p epi -p egui_web -p egui-winit -p egui_glium -p egui_glow --lib --no-deps --all-features --open
|
cargo doc -p emath -p epaint -p egui -p eframe -p epi -p egui_web -p egui-winit -p egui_extras -p egui_glium -p egui_glow --lib --no-deps --all-features --open
|
||||||
|
|
||||||
# cargo watch -c -x 'doc -p emath -p epaint -p egui --lib --no-deps --all-features'
|
# cargo watch -c -x 'doc -p emath -p epaint -p egui --lib --no-deps --all-features'
|
||||||
|
|
Loading…
Reference in a new issue