diff --git a/CHANGELOG.md b/CHANGELOG.md
index 81e84aadb..e2a583b05 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
* `TextStyle` is no longer `Copy` ([#1154](https://github.com/emilk/egui/pull/1154)).
* Replaced `TextEdit::text_style` with `TextEdit::font` ([#1154](https://github.com/emilk/egui/pull/1154)).
* Replaced `corner_radius: f32` with `rounding: Rounding`, allowing per-corner rounding settings ([#1206](https://github.com/emilk/egui/pull/1206)).
+* Replaced Frame's `margin: Vec2` with `margin: Margin`, allowing for different margins on opposing sides ([#1219](https://github.com/emilk/egui/pull/1219)).
* `Plot::highlight` now takes a `bool` argument ([#1159](https://github.com/emilk/egui/pull/1159)).
* `ScrollArea::show` now returns a `ScrollAreaOutput`, so you might need to add `.inner` after the call to it ([#1166](https://github.com/emilk/egui/pull/1166)).
diff --git a/Cargo.lock b/Cargo.lock
index 34c914909..3ca72ef73 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -81,6 +81,18 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "arrayref"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
+
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
[[package]]
name = "ashpd"
version = "0.2.2"
@@ -831,6 +843,15 @@ dependencies = [
"syn",
]
+[[package]]
+name = "data-url"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193"
+dependencies = [
+ "matches",
+]
+
[[package]]
name = "dconf_rs"
version = "0.3.0"
@@ -980,7 +1001,10 @@ dependencies = [
"epi",
"image",
"poll-promise",
+ "resvg",
"rfd",
+ "tiny-skia",
+ "usvg",
]
[[package]]
@@ -1070,7 +1094,6 @@ dependencies = [
"epi",
"glow",
"glutin",
- "image",
"memoffset",
"tracing",
"wasm-bindgen",
@@ -1308,12 +1331,29 @@ dependencies = [
"miniz_oxide",
]
+[[package]]
+name = "float-cmp"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
+
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+[[package]]
+name = "fontdb"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01b07f5c05414a0d8caba4c17eef8dc8b5c8955fc7c68d324191c7a56d3f3449"
+dependencies = [
+ "log",
+ "memmap2 0.5.2",
+ "ttf-parser 0.12.3",
+]
+
[[package]]
name = "foreign-types"
version = "0.3.2"
@@ -1733,7 +1773,7 @@ dependencies = [
"bytemuck",
"byteorder",
"color_quant",
- "jpeg-decoder",
+ "jpeg-decoder 0.2.1",
"num-iter",
"num-rational",
"num-traits",
@@ -1803,6 +1843,12 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+[[package]]
+name = "jpeg-decoder"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
+
[[package]]
name = "jpeg-decoder"
version = "0.2.1"
@@ -1824,6 +1870,15 @@ version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
+[[package]]
+name = "kurbo"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb348d766edbac91ba1eb83020d96f4f8867924d194393083c15a51f185e6a82"
+dependencies = [
+ "arrayvec",
+]
+
[[package]]
name = "lazy-bytes-cast"
version = "5.0.1"
@@ -1921,6 +1976,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "memmap2"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe3179b85e1fd8b14447cbebadb75e45a1002f541b925f0bfec366d56a81c56d"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "memoffset"
version = "0.6.5"
@@ -2249,12 +2313,6 @@ version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
-[[package]]
-name = "openssl-probe"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
-
[[package]]
name = "ordered-multimap"
version = "0.3.1"
@@ -2290,7 +2348,7 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ef05f2882a8b3e7acc10c153ade2631f7bfc8ce00d2bf3fb8f4e9d2ae6ea5c3"
dependencies = [
- "ttf-parser",
+ "ttf-parser 0.14.0",
]
[[package]]
@@ -2348,6 +2406,12 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+[[package]]
+name = "pico-args"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
+
[[package]]
name = "pin-project-lite"
version = "0.2.8"
@@ -2566,6 +2630,12 @@ dependencies = [
"num_cpus",
]
+[[package]]
+name = "rctree"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ae028b272a6e99d9f8260ceefa3caa09300a8d6c8d2b2001316474bc52122e9"
+
[[package]]
name = "redox_syscall"
version = "0.2.10"
@@ -2608,6 +2678,23 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+[[package]]
+name = "resvg"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d94a32ca845cdda27237a40beba9bd3d3858ac8fc5356eb9442bdeecfe34d9e0"
+dependencies = [
+ "jpeg-decoder 0.1.22",
+ "log",
+ "pico-args",
+ "png",
+ "rgb",
+ "svgfilters",
+ "svgtypes",
+ "tiny-skia",
+ "usvg",
+]
+
[[package]]
name = "rfd"
version = "0.7.0"
@@ -2634,6 +2721,15 @@ dependencies = [
"windows",
]
+[[package]]
+name = "rgb"
+version = "0.8.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a374af9a0e5fdcdd98c1c7b64f05004f9ea2555b6c75f211daa81268a3c50f1"
+dependencies = [
+ "bytemuck",
+]
+
[[package]]
name = "ring"
version = "0.16.20"
@@ -2660,6 +2756,15 @@ dependencies = [
"serde",
]
+[[package]]
+name = "roxmltree"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b"
+dependencies = [
+ "xmlparser",
+]
+
[[package]]
name = "rust-ini"
version = "0.17.0"
@@ -2704,24 +2809,19 @@ dependencies = [
]
[[package]]
-name = "rustls-native-certs"
-version = "0.6.1"
+name = "rustybuzz"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943"
+checksum = "44561062e583c4873162861261f16fd1d85fe927c4904d71329a4fe43dc355ef"
dependencies = [
- "openssl-probe",
- "rustls-pemfile",
- "schannel",
- "security-framework",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9"
-dependencies = [
- "base64",
+ "bitflags",
+ "bytemuck",
+ "smallvec",
+ "ttf-parser 0.12.3",
+ "unicode-bidi-mirroring",
+ "unicode-ccc",
+ "unicode-general-category",
+ "unicode-script",
]
[[package]]
@@ -2730,6 +2830,15 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
+[[package]]
+name = "safe_arch"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05"
+dependencies = [
+ "bytemuck",
+]
+
[[package]]
name = "safemem"
version = "0.3.3"
@@ -2745,16 +2854,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "schannel"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
-dependencies = [
- "lazy_static",
- "winapi",
-]
-
[[package]]
name = "scoped-tls"
version = "1.0.0"
@@ -2777,29 +2876,6 @@ dependencies = [
"untrusted",
]
-[[package]]
-name = "security-framework"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fed7948b6c68acbb6e20c334f55ad635dc0f75506963de4464289fbd3b051ac"
-dependencies = [
- "bitflags",
- "core-foundation 0.9.2",
- "core-foundation-sys 0.8.3",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a57321bf8bc2362081b2599912d2961fe899c0efadf1b4b2f8d48b3e253bb96c"
-dependencies = [
- "core-foundation-sys 0.8.3",
- "libc",
-]
-
[[package]]
name = "semver"
version = "1.0.4"
@@ -2898,6 +2974,21 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+[[package]]
+name = "simplecss"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "siphasher"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e"
+
[[package]]
name = "slab"
version = "0.4.5"
@@ -2930,7 +3021,7 @@ dependencies = [
"dlib",
"lazy_static",
"log",
- "memmap2",
+ "memmap2 0.3.1",
"nix 0.22.3",
"pkg-config",
"wayland-client",
@@ -3001,6 +3092,25 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+[[package]]
+name = "svgfilters"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "639abcebc15fdc2df179f37d6f5463d660c1c79cd552c12343a4600827a04bce"
+dependencies = [
+ "float-cmp",
+ "rgb",
+]
+
+[[package]]
+name = "svgtypes"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dabb3eb59a457c56d5282ab4545609e2cc382b41f6af239bb8d59a7267ef94b3"
+dependencies = [
+ "siphasher",
+]
+
[[package]]
name = "syn"
version = "1.0.86"
@@ -3012,12 +3122,6 @@ dependencies = [
"unicode-xid",
]
-[[package]]
-name = "sync_wrapper"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
-
[[package]]
name = "syntect"
version = "4.6.0"
@@ -3127,6 +3231,20 @@ dependencies = [
"num_threads",
]
+[[package]]
+name = "tiny-skia"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bcfd4339bdd4545eabed74b208f2f1555f2e6540fb58135c01f46c0940aa138"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if 1.0.0",
+ "png",
+ "safe_arch",
+]
+
[[package]]
name = "tinytemplate"
version = "1.2.1"
@@ -3230,6 +3348,12 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "ttf-parser"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6"
+
[[package]]
name = "ttf-parser"
version = "0.14.0"
@@ -3263,6 +3387,24 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
+[[package]]
+name = "unicode-bidi-mirroring"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694"
+
+[[package]]
+name = "unicode-ccc"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
+
+[[package]]
+name = "unicode-general-category"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742"
+
[[package]]
name = "unicode-normalization"
version = "0.1.19"
@@ -3272,6 +3414,18 @@ dependencies = [
"tinyvec",
]
+[[package]]
+name = "unicode-script"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58dd944fd05f2f0b5c674917aea8a4df6af84f2d8de3fe8d988b95d28fb8fb09"
+
+[[package]]
+name = "unicode-vo"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
+
[[package]]
name = "unicode-width"
version = "0.1.9"
@@ -3299,7 +3453,8 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "ureq"
version = "2.4.0"
-source = "git+https://github.com/emilk/ureq/?branch=opt-in-webpki-roots#d4ca2ca620b65854c3428306b03ab7ef562bf796"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5"
dependencies = [
"base64",
"chunked_transfer",
@@ -3307,10 +3462,9 @@ dependencies = [
"log",
"once_cell",
"rustls",
- "rustls-native-certs",
- "sync_wrapper",
"url",
"webpki",
+ "webpki-roots",
]
[[package]]
@@ -3325,6 +3479,33 @@ dependencies = [
"percent-encoding",
]
+[[package]]
+name = "usvg"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00f064d38f79ff69e3160e2fba884e4ede897061c15178041a3976371c68cab1"
+dependencies = [
+ "base64",
+ "data-url",
+ "flate2",
+ "float-cmp",
+ "fontdb",
+ "kurbo",
+ "log",
+ "pico-args",
+ "rctree",
+ "roxmltree",
+ "rustybuzz",
+ "simplecss",
+ "siphasher",
+ "svgtypes",
+ "ttf-parser 0.12.3",
+ "unicode-bidi",
+ "unicode-script",
+ "unicode-vo",
+ "xmlwriter",
+]
+
[[package]]
name = "valuable"
version = "0.1.0"
@@ -3552,6 +3733,15 @@ dependencies = [
"untrusted",
]
+[[package]]
+name = "webpki-roots"
+version = "0.22.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449"
+dependencies = [
+ "webpki",
+]
+
[[package]]
name = "wepoll-ffi"
version = "0.1.2"
@@ -3740,6 +3930,18 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
+[[package]]
+name = "xmlparser"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
+
+[[package]]
+name = "xmlwriter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
+
[[package]]
name = "yaml-rust"
version = "0.4.5"
diff --git a/Cargo.toml b/Cargo.toml
index da9c7db18..a81138331 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,6 +25,3 @@ opt-level = 2 # fast and small wasm, basically same as `opt-level = 's'`
# opt-level = 3 # unecessarily large wasm for no performance gain
# debug = true # include debug symbols, useful when profiling wasm
-
-[patch.crates-io]
-ureq = { git = "https://github.com/emilk/ureq/", branch = "opt-in-webpki-roots" } # See https://github.com/algesten/ureq/pull/479 / https://github.com/algesten/ureq/issues/478
diff --git a/deny.toml b/deny.toml
index afd1bb457..c58fa9ba6 100644
--- a/deny.toml
+++ b/deny.toml
@@ -49,6 +49,7 @@ allow = [
"CC0-1.0", # https://creativecommons.org/publicdomain/zero/1.0/
"ISC", # https://tldrlegal.com/license/-isc-license
"MIT", # https://tldrlegal.com/license/mit-license
+ "MPL-2.0", # https://www.mozilla.org/en-US/MPL/2.0/FAQ/ - see Q11
"OpenSSL", # https://www.openssl.org/source/license.html
"Zlib", # https://tldrlegal.com/license/zlib-libpng-license-(zlib)
]
diff --git a/eframe/Cargo.toml b/eframe/Cargo.toml
index 35265b999..a9ff85c31 100644
--- a/eframe/Cargo.toml
+++ b/eframe/Cargo.toml
@@ -62,9 +62,14 @@ egui_glow = { version = "0.16.0", path = "../egui_glow", default-features = fals
[target.'cfg(target_arch = "wasm32")'.dependencies]
egui_web = { version = "0.16.0", path = "../egui_web", default-features = false, features = ["glow"] }
+
[dev-dependencies]
ehttp = "0.2"
image = { version = "0.24", default-features = false, features = ["jpeg", "png"] }
poll-promise = "0.1"
rfd = "0.7"
+# svg.rs example:
+resvg = "0.20"
+tiny-skia = "0.6"
+usvg = "0.20"
diff --git a/eframe/examples/rustacean-flat-happy.svg b/eframe/examples/rustacean-flat-happy.svg
new file mode 100644
index 000000000..c7f240dd9
--- /dev/null
+++ b/eframe/examples/rustacean-flat-happy.svg
@@ -0,0 +1,33 @@
+
+
+
diff --git a/eframe/examples/svg.rs b/eframe/examples/svg.rs
new file mode 100644
index 000000000..e4aff0cfa
--- /dev/null
+++ b/eframe/examples/svg.rs
@@ -0,0 +1,108 @@
+//! A good way of displaying an SVG image in egui.
+//!
+//! Requires the dependencies `resvg`, `tiny-skia`, `usvg`
+use eframe::{egui, epi};
+
+/// Load an SVG and rasterize it into an egui image.
+fn load_svg_data(svg_data: &[u8]) -> Result {
+ 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,
+}
+
+impl SvgImage {
+ /// Pass itn the bytes of an SVG that you've loaded from disk
+ pub fn from_svg_data(bytes: &[u8]) -> Result {
+ 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 {
+ svg_image: SvgImage,
+}
+
+impl Default for MyApp {
+ fn default() -> Self {
+ Self {
+ svg_image: SvgImage::from_svg_data(include_bytes!("rustacean-flat-happy.svg")).unwrap(),
+ }
+ }
+}
+
+impl epi::App for MyApp {
+ fn name(&self) -> &str {
+ "svg example"
+ }
+
+ fn update(&mut self, ctx: &egui::Context, _frame: &epi::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_max_size(ui, max_size);
+ });
+ }
+}
+
+fn main() {
+ let options = eframe::NativeOptions {
+ initial_window_size: Some(egui::vec2(1000.0, 700.0)),
+ ..Default::default()
+ };
+ eframe::run_native(Box::new(MyApp::default()), options);
+}
diff --git a/eframe/src/lib.rs b/eframe/src/lib.rs
index d0ba574db..31e9643ec 100644
--- a/eframe/src/lib.rs
+++ b/eframe/src/lib.rs
@@ -65,7 +65,7 @@
)]
#![allow(clippy::needless_doctest_main)]
-pub use {egui, epi};
+pub use {egui, egui::emath, egui::epaint, epi};
#[cfg(not(target_arch = "wasm32"))]
pub use epi::NativeOptions;
diff --git a/egui/src/containers/frame.rs b/egui/src/containers/frame.rs
index c5c5a61a0..044b96a9a 100644
--- a/egui/src/containers/frame.rs
+++ b/egui/src/containers/frame.rs
@@ -3,12 +3,55 @@
use crate::{layers::ShapeIdx, *};
use epaint::*;
+#[derive(Clone, Copy, Debug, Default, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
+pub struct Margin {
+ pub left: f32,
+ pub right: f32,
+ pub top: f32,
+ pub bottom: f32,
+}
+
+impl Margin {
+ #[inline]
+ pub fn same(margin: f32) -> Self {
+ Self {
+ left: margin,
+ right: margin,
+ top: margin,
+ bottom: margin,
+ }
+ }
+
+ /// Margins with the same size on opposing sides
+ #[inline]
+ pub fn symmetric(x: f32, y: f32) -> Self {
+ Self {
+ left: x,
+ right: x,
+ top: y,
+ bottom: y,
+ }
+ }
+
+ /// Total margins on both sides
+ pub fn sum(&self) -> Vec2 {
+ Vec2::new(self.left + self.right, self.top + self.bottom)
+ }
+}
+
+impl From for Margin {
+ fn from(v: Vec2) -> Self {
+ Self::symmetric(v.x, v.y)
+ }
+}
+
/// Color and margin of a rectangular background of a [`Ui`].
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[must_use = "You should call .show()"]
pub struct Frame {
/// On each side
- pub margin: Vec2,
+ pub margin: Margin,
pub rounding: Rounding,
pub shadow: Shadow,
pub fill: Color32,
@@ -23,7 +66,7 @@ impl Frame {
/// For when you want to group a few widgets together within a frame.
pub fn group(style: &Style) -> Self {
Self {
- margin: Vec2::splat(6.0), // symmetric looks best in corners when nesting
+ margin: Margin::same(6.0), // symmetric looks best in corners when nesting
rounding: style.visuals.widgets.noninteractive.rounding,
stroke: style.visuals.widgets.noninteractive.bg_stroke,
..Default::default()
@@ -32,7 +75,7 @@ impl Frame {
pub(crate) fn side_top_panel(style: &Style) -> Self {
Self {
- margin: Vec2::new(8.0, 2.0),
+ margin: Margin::symmetric(8.0, 2.0),
rounding: Rounding::none(),
fill: style.visuals.window_fill(),
stroke: style.visuals.window_stroke(),
@@ -42,7 +85,7 @@ impl Frame {
pub(crate) fn central_panel(style: &Style) -> Self {
Self {
- margin: Vec2::new(8.0, 8.0),
+ margin: Margin::symmetric(8.0, 8.0),
rounding: Rounding::none(),
fill: style.visuals.window_fill(),
stroke: Default::default(),
@@ -52,7 +95,7 @@ impl Frame {
pub fn window(style: &Style) -> Self {
Self {
- margin: style.spacing.window_padding,
+ margin: style.spacing.window_margin,
rounding: style.visuals.window_rounding,
shadow: style.visuals.window_shadow,
fill: style.visuals.window_fill(),
@@ -62,7 +105,7 @@ impl Frame {
pub fn menu(style: &Style) -> Self {
Self {
- margin: Vec2::splat(1.0),
+ margin: Margin::same(1.0),
rounding: style.visuals.widgets.noninteractive.rounding,
shadow: style.visuals.popup_shadow,
fill: style.visuals.window_fill(),
@@ -72,7 +115,7 @@ impl Frame {
pub fn popup(style: &Style) -> Self {
Self {
- margin: style.spacing.window_padding,
+ margin: style.spacing.window_margin,
rounding: style.visuals.widgets.noninteractive.rounding,
shadow: style.visuals.popup_shadow,
fill: style.visuals.window_fill(),
@@ -83,7 +126,7 @@ impl Frame {
/// dark canvas to draw on
pub fn dark_canvas(style: &Style) -> Self {
Self {
- margin: Vec2::new(10.0, 10.0),
+ margin: Margin::symmetric(10.0, 10.0),
rounding: style.visuals.widgets.noninteractive.rounding,
fill: Color32::from_black_alpha(250),
stroke: style.visuals.window_stroke(),
@@ -109,7 +152,7 @@ impl Frame {
}
/// Margin on each side of the frame.
- pub fn margin(mut self, margin: impl Into) -> Self {
+ pub fn margin(mut self, margin: impl Into) -> Self {
self.margin = margin.into();
self
}
@@ -137,7 +180,10 @@ impl Frame {
pub fn begin(self, ui: &mut Ui) -> Prepared {
let where_to_put_background = ui.painter().add(Shape::Noop);
let outer_rect_bounds = ui.available_rect_before_wrap();
- let mut inner_rect = outer_rect_bounds.shrink2(self.margin);
+
+ let mut inner_rect = outer_rect_bounds;
+ inner_rect.min += Vec2::new(self.margin.left, self.margin.top);
+ inner_rect.max -= Vec2::new(self.margin.right, self.margin.bottom);
// Make sure we don't shrink to the negative:
inner_rect.max.x = inner_rect.max.x.max(inner_rect.min.x);
@@ -197,7 +243,10 @@ impl Frame {
impl Prepared {
pub fn outer_rect(&self) -> Rect {
- self.content_ui.min_rect().expand2(self.frame.margin)
+ let mut rect = self.content_ui.min_rect();
+ rect.min -= Vec2::new(self.frame.margin.left, self.frame.margin.top);
+ rect.max += Vec2::new(self.frame.margin.right, self.frame.margin.bottom);
+ rect
}
pub fn end(self, ui: &mut Ui) -> Response {
diff --git a/egui/src/containers/mod.rs b/egui/src/containers/mod.rs
index f151b8e9e..cc457a511 100644
--- a/egui/src/containers/mod.rs
+++ b/egui/src/containers/mod.rs
@@ -16,7 +16,7 @@ pub use {
area::Area,
collapsing_header::{CollapsingHeader, CollapsingResponse},
combo_box::*,
- frame::Frame,
+ frame::{Frame, Margin},
panel::{CentralPanel, SidePanel, TopBottomPanel},
popup::*,
resize::Resize,
diff --git a/egui/src/containers/popup.rs b/egui/src/containers/popup.rs
index ffe366721..c8cbdb67f 100644
--- a/egui/src/containers/popup.rs
+++ b/egui/src/containers/popup.rs
@@ -302,7 +302,7 @@ pub fn popup_below_widget(
frame
.show(ui, |ui| {
ui.with_layout(Layout::top_down_justified(Align::LEFT), |ui| {
- ui.set_width(widget_response.rect.width() - 2.0 * frame_margin.x);
+ ui.set_width(widget_response.rect.width() - frame_margin.sum().x);
add_contents(ui)
})
.inner
diff --git a/egui/src/containers/resize.rs b/egui/src/containers/resize.rs
index 5dd46dbe4..2f31ff054 100644
--- a/egui/src/containers/resize.rs
+++ b/egui/src/containers/resize.rs
@@ -178,7 +178,7 @@ impl Resize {
.at_least(self.min_size)
.at_most(self.max_size)
.at_most(
- ui.input().screen_rect().size() - 2.0 * ui.spacing().window_padding, // hack for windows
+ ui.input().screen_rect().size() - ui.spacing().window_margin.sum(), // hack for windows
);
State {
diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs
index 9c439b26e..4e1eb70d5 100644
--- a/egui/src/containers/window.rs
+++ b/egui/src/containers/window.rs
@@ -301,7 +301,7 @@ impl<'open> Window<'open> {
} else {
0.0
};
- let margins = 2.0 * frame.margin + vec2(0.0, title_bar_height);
+ let margins = frame.margin.sum() + vec2(0.0, title_bar_height);
interact(
window_interaction,
diff --git a/egui/src/introspection.rs b/egui/src/introspection.rs
index d0b346380..3726b8081 100644
--- a/egui/src/introspection.rs
+++ b/egui/src/introspection.rs
@@ -24,8 +24,6 @@ pub fn font_id_ui(ui: &mut Ui, font_id: &mut FontId) {
// Show font texture in demo Ui
pub(crate) fn font_texture_ui(ui: &mut Ui, [width, height]: [usize; 2]) -> Response {
- use epaint::Mesh;
-
ui.vertical(|ui| {
let color = if ui.visuals().dark_mode {
Color32::WHITE
diff --git a/egui/src/lib.rs b/egui/src/lib.rs
index 646780f39..fdf37174a 100644
--- a/egui/src/lib.rs
+++ b/egui/src/lib.rs
@@ -387,7 +387,7 @@ pub use epaint::{
color, mutex,
text::{FontData, FontDefinitions, FontFamily, FontId},
textures::TexturesDelta,
- AlphaImage, ClippedMesh, Color32, ColorImage, ImageData, Rgba, Rounding, Shape, Stroke,
+ AlphaImage, ClippedMesh, Color32, ColorImage, ImageData, Mesh, Rgba, Rounding, Shape, Stroke,
TextureHandle, TextureId,
};
diff --git a/egui/src/style.rs b/egui/src/style.rs
index a1430850d..d13548a6b 100644
--- a/egui/src/style.rs
+++ b/egui/src/style.rs
@@ -2,7 +2,7 @@
#![allow(clippy::if_same_then_else)]
-use crate::{color::*, emath::*, FontFamily, FontId, Response, RichText, WidgetText};
+use crate::{color::*, emath::*, FontFamily, FontId, Margin, Response, RichText, WidgetText};
use epaint::{mutex::Arc, Rounding, Shadow, Stroke};
use std::collections::BTreeMap;
@@ -220,8 +220,8 @@ pub struct Spacing {
/// widgets `A` and `B` you need to change `item_spacing` before adding `A`.
pub item_spacing: Vec2,
- /// Horizontal and vertical padding within a window frame.
- pub window_padding: Vec2,
+ /// Horizontal and vertical margins within a window frame.
+ pub window_margin: Margin,
/// Button size is text size plus this on each side
pub button_padding: Vec2,
@@ -528,7 +528,7 @@ impl Default for Spacing {
fn default() -> Self {
Self {
item_spacing: vec2(8.0, 3.0),
- window_padding: Vec2::splat(6.0),
+ window_margin: Margin::same(6.0),
button_padding: vec2(4.0, 1.0),
indent: 18.0, // match checkbox/radio-button with `button_padding.x + icon_width + icon_spacing`
interact_size: vec2(40.0, 18.0),
@@ -803,7 +803,7 @@ impl Spacing {
pub fn ui(&mut self, ui: &mut crate::Ui) {
let Self {
item_spacing,
- window_padding,
+ window_margin,
button_padding,
indent,
interact_size,
@@ -818,7 +818,37 @@ impl Spacing {
} = self;
ui.add(slider_vec2(item_spacing, 0.0..=20.0, "Item spacing"));
- ui.add(slider_vec2(window_padding, 0.0..=20.0, "Window padding"));
+
+ let margin_range = 0.0..=20.0;
+ ui.horizontal(|ui| {
+ ui.add(
+ DragValue::new(&mut window_margin.left)
+ .clamp_range(margin_range.clone())
+ .prefix("left: "),
+ );
+ ui.add(
+ DragValue::new(&mut window_margin.right)
+ .clamp_range(margin_range.clone())
+ .prefix("right: "),
+ );
+
+ ui.label("Window margins x");
+ });
+
+ ui.horizontal(|ui| {
+ ui.add(
+ DragValue::new(&mut window_margin.top)
+ .clamp_range(margin_range.clone())
+ .prefix("top: "),
+ );
+ ui.add(
+ DragValue::new(&mut window_margin.bottom)
+ .clamp_range(margin_range)
+ .prefix("bottom: "),
+ );
+ ui.label("Window margins y");
+ });
+
ui.add(slider_vec2(button_padding, 0.0..=20.0, "Button padding"));
ui.add(slider_vec2(interact_size, 4.0..=60.0, "Interact size"))
.on_hover_text("Minimum size of an interactive widget");
diff --git a/egui/src/widgets/plot/legend.rs b/egui/src/widgets/plot/legend.rs
index 71f3dfdcb..6c60c6a36 100644
--- a/egui/src/widgets/plot/legend.rs
+++ b/egui/src/widgets/plot/legend.rs
@@ -239,7 +239,7 @@ impl Widget for &mut LegendWidget {
legend_ui
.scope(|ui| {
let background_frame = Frame {
- margin: vec2(8.0, 4.0),
+ margin: vec2(8.0, 4.0).into(),
rounding: ui.style().visuals.window_rounding,
shadow: epaint::Shadow::default(),
fill: ui.style().visuals.extreme_bg_color,
diff --git a/egui_glow/Cargo.toml b/egui_glow/Cargo.toml
index fe6870eec..30c680e49 100644
--- a/egui_glow/Cargo.toml
+++ b/egui_glow/Cargo.toml
@@ -73,6 +73,3 @@ glutin = { version = "0.28.0", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-sys = { version = "0.3", features=["console"] }
wasm-bindgen = { version = "0.2" }
-
-[dev-dependencies]
-image = { version = "0.24", default-features = false, features = ["png"] }