Improve docs concerning custom fonts, themes and accessibility
Closes https://github.com/emilk/egui/pull/370 Closes https://github.com/emilk/egui/issues/372
This commit is contained in:
parent
8f8ba16696
commit
7b0f991b20
11 changed files with 127 additions and 16 deletions
27
README.md
27
README.md
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
egui is a simple, fast, and highly portable immediate mode GUI library for Rust. egui runs on the web, natively, and [in your favorite game engine](#integrations) (or will soon).
|
egui is a simple, fast, and highly portable immediate mode GUI library for Rust. egui runs on the web, natively, and [in your favorite game engine](#integrations) (or will soon).
|
||||||
|
|
||||||
egui aims to be the easiest-to-use Rust GUI libary, and the simplest way to make a web app in Rust.
|
egui aims to be the easiest-to-use Rust GUI library, and the simplest way to make a web app in Rust.
|
||||||
|
|
||||||
egui can be used anywhere you can draw textured triangles, which means you can easily integrate it into your game engine of choice.
|
egui can be used anywhere you can draw textured triangles, which means you can easily integrate it into your game engine of choice.
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ ui.label(format!("Hello '{}', age {}", name, age));
|
||||||
|
|
||||||
## Goals
|
## Goals
|
||||||
|
|
||||||
* The easiest to use GUI libary
|
* The easiest to use GUI library
|
||||||
* Responsive: target 60 Hz in debug build
|
* Responsive: target 60 Hz in debug build
|
||||||
* Friendly: difficult to make mistakes, and shouldn't panic
|
* Friendly: difficult to make mistakes, and shouldn't panic
|
||||||
* Portable: the same code works on the web and as a native app
|
* Portable: the same code works on the web and as a native app
|
||||||
|
@ -79,7 +79,7 @@ ui.label(format!("Hello '{}', age {}", name, age));
|
||||||
* Extensible: [easy to write your own widgets for egui](https://github.com/emilk/egui/blob/master/egui_demo_lib/src/apps/demo/toggle_switch.rs)
|
* Extensible: [easy to write your own widgets for egui](https://github.com/emilk/egui/blob/master/egui_demo_lib/src/apps/demo/toggle_switch.rs)
|
||||||
* Modular: You should be able to use small parts of egui and combine them in new ways
|
* Modular: You should be able to use small parts of egui and combine them in new ways
|
||||||
* Safe: there is no `unsafe` code in egui
|
* Safe: there is no `unsafe` code in egui
|
||||||
* Minimal dependencies: [`ahash`](https://crates.io/crates/ahash) [`atomic_refcell`](https://crates.io/crates/atomic_refcell) [`ordered-float`](https://crates.io/crates/) [`rusttype`](https://crates.io/crates/rusttype).
|
* Minimal dependencies: [`ahash`](https://crates.io/crates/ahash) [`atomic_refcell`](https://crates.io/crates/atomic_refcell) [`ordered-float`](https://crates.io/crates/ordered-float) [`rusttype`](https://crates.io/crates/rusttype).
|
||||||
|
|
||||||
egui is *not* a framework. egui is a library you call into, not an environment you program for.
|
egui is *not* a framework. egui is a library you call into, not an environment you program for.
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ egui is *not* a framework. egui is a library you call into, not an environment y
|
||||||
|
|
||||||
### Non-goals
|
### Non-goals
|
||||||
|
|
||||||
* Become the most powerful GUI libary
|
* Become the most powerful GUI library
|
||||||
* Native looking interface
|
* Native looking interface
|
||||||
* Advanced and flexible layouts (that's fundamentally incompatible with immediate mode)
|
* Advanced and flexible layouts (that's fundamentally incompatible with immediate mode)
|
||||||
|
|
||||||
|
@ -134,7 +134,11 @@ egui is in active development. It works well for what it does, but it lacks many
|
||||||
* Tooltips on hover
|
* Tooltips on hover
|
||||||
* More
|
* More
|
||||||
|
|
||||||
<img src="media/widget_gallery_0.8.0.gif" width="50%">
|
<img src="media/widget_gallery.gif" width="50%">
|
||||||
|
|
||||||
|
Light Theme:
|
||||||
|
|
||||||
|
<img src="media/light_theme.png" width="50%">
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
|
@ -234,7 +238,7 @@ The short of it is this: immediate mode GUI libraries are easier to use, but les
|
||||||
The main advantage of immediate mode is that the application code becomes vastly simpler:
|
The main advantage of immediate mode is that the application code becomes vastly simpler:
|
||||||
|
|
||||||
* You never need to have any on-click handlers and callbacks that disrupts your code flow.
|
* You never need to have any on-click handlers and callbacks that disrupts your code flow.
|
||||||
* You don't have to worry about a linger callback calling something that is gone.
|
* You don't have to worry about a lingering callback calling something that is gone.
|
||||||
* Your GUI code can easily live in a simple function (no need for an object just for the UI).
|
* Your GUI code can easily live in a simple function (no need for an object just for the UI).
|
||||||
* You don't have to worry about app state and GUI state being out-of-sync (i.e. the GUI showing something outdated), because the GUI isn't storing any state - it is showing the latest state *immediately*.
|
* You don't have to worry about app state and GUI state being out-of-sync (i.e. the GUI showing something outdated), because the GUI isn't storing any state - it is showing the latest state *immediately*.
|
||||||
|
|
||||||
|
@ -275,6 +279,17 @@ Overall, ID handling is a rare inconvenience, and not a big disadvantage.
|
||||||
|
|
||||||
Also see [GitHub Discussions](https://github.com/emilk/egui/discussions/categories/q-a).
|
Also see [GitHub Discussions](https://github.com/emilk/egui/discussions/categories/q-a).
|
||||||
|
|
||||||
|
### Can I use `egui` with non-latin characters?
|
||||||
|
Yes! But you need to install your own font (`.ttf` or `.otf`) using `Context::set_fonts`.
|
||||||
|
|
||||||
|
### Can I customize the look of egui?
|
||||||
|
Yes! You can customize the colors, spacing and sizes of everything. By default egui comes with a dark and a light theme.
|
||||||
|
|
||||||
|
### What about accessibility, such as screen readers?
|
||||||
|
There is experimental support for a screen reader. In [the web demo](https://emilk.github.io/egui/index.html) you can enable it in the "Backend" tab.
|
||||||
|
|
||||||
|
Read more at <https://github.com/emilk/egui/issues/167>.
|
||||||
|
|
||||||
### What is the difference between egui and eframe?
|
### What is the difference between egui and eframe?
|
||||||
|
|
||||||
`egui` is a 2D user interface library for laying out and interacting with buttons, sliders, etc.
|
`egui` is a 2D user interface library for laying out and interacting with buttons, sliders, etc.
|
||||||
|
|
|
@ -415,7 +415,12 @@ impl Context {
|
||||||
self.fonts().texture()
|
self.fonts().texture()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Will become active at the start of the next frame.
|
/// Tell `egui` which fonts to use.
|
||||||
|
///
|
||||||
|
/// The default `egui` fonts only support latin and cyrillic alphabets,
|
||||||
|
/// but you can call this to install additional fonts that support e.g. korean characters.
|
||||||
|
///
|
||||||
|
/// The new fonts will become active at the start of the next frame.
|
||||||
pub fn set_fonts(&self, font_definitions: FontDefinitions) {
|
pub fn set_fonts(&self, font_definitions: FontDefinitions) {
|
||||||
if let Some(current_fonts) = &self.fonts {
|
if let Some(current_fonts) = &self.fonts {
|
||||||
// NOTE: this comparison is expensive since it checks TTF data for equality
|
// NOTE: this comparison is expensive since it checks TTF data for equality
|
||||||
|
@ -434,6 +439,8 @@ impl Context {
|
||||||
|
|
||||||
/// The [`Style`] used by all new windows, panels etc.
|
/// The [`Style`] used by all new windows, panels etc.
|
||||||
///
|
///
|
||||||
|
/// You can also use [`Ui::style_mut`] to change the style of a single [`Ui`].
|
||||||
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
/// ```
|
/// ```
|
||||||
/// # let mut ctx = egui::CtxRef::default();
|
/// # let mut ctx = egui::CtxRef::default();
|
||||||
|
|
|
@ -6,6 +6,9 @@ use crate::emath::*;
|
||||||
///
|
///
|
||||||
/// Set the values that make sense, leave the rest at their `Default::default()`.
|
/// Set the values that make sense, leave the rest at their `Default::default()`.
|
||||||
///
|
///
|
||||||
|
/// You can check if `egui` is using the inputs using
|
||||||
|
/// [`crate::Context::wants_pointer_input`] and [`crate::Context::wants_keyboard_input`].
|
||||||
|
///
|
||||||
/// All coordinates are in points (logical pixels) with origin (0, 0) in the top left corner.
|
/// All coordinates are in points (logical pixels) with origin (0, 0) in the top left corner.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RawInput {
|
pub struct RawInput {
|
||||||
|
|
|
@ -14,6 +14,9 @@ const MAX_CLICK_DIST: f32 = 6.0; // TODO: move to settings
|
||||||
const MAX_CLICK_DELAY: f64 = 0.3; // TODO: move to settings
|
const MAX_CLICK_DELAY: f64 = 0.3; // TODO: move to settings
|
||||||
|
|
||||||
/// Input state that egui updates each frame.
|
/// Input state that egui updates each frame.
|
||||||
|
///
|
||||||
|
/// You can check if `egui` is using the inputs using
|
||||||
|
/// [`crate::Context::wants_pointer_input`] and [`crate::Context::wants_keyboard_input`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct InputState {
|
pub struct InputState {
|
||||||
/// The raw input we got this frame from the backend.
|
/// The raw input we got this frame from the backend.
|
||||||
|
|
|
@ -5,7 +5,12 @@
|
||||||
use crate::{color::*, emath::*, Response};
|
use crate::{color::*, emath::*, Response};
|
||||||
use epaint::{Shadow, Stroke, TextStyle};
|
use epaint::{Shadow, Stroke, TextStyle};
|
||||||
|
|
||||||
/// Specifies the look and feel of a [`Ui`].
|
/// Specifies the look and feel of egui.
|
||||||
|
///
|
||||||
|
/// You can change the visuals of a [`Ui`] with [`Ui::style_mut`]
|
||||||
|
/// and of everything with [`crate::Context::set_style`].
|
||||||
|
///
|
||||||
|
/// If you want to change fonts, use [`crate::Context::set_fonts`] instead.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "persistence", serde(default))]
|
#[cfg_attr(feature = "persistence", serde(default))]
|
||||||
|
@ -22,11 +27,16 @@ pub struct Style {
|
||||||
/// * `Some(false)`: default off
|
/// * `Some(false)`: default off
|
||||||
pub wrap: Option<bool>,
|
pub wrap: Option<bool>,
|
||||||
|
|
||||||
|
/// Sizes and distances between widgets
|
||||||
pub spacing: Spacing,
|
pub spacing: Spacing,
|
||||||
|
|
||||||
|
/// How and when interaction happens.
|
||||||
pub interaction: Interaction,
|
pub interaction: Interaction,
|
||||||
|
|
||||||
|
/// Colors etc.
|
||||||
pub visuals: Visuals,
|
pub visuals: Visuals,
|
||||||
|
|
||||||
/// How many seconds a typical animation should last
|
/// How many seconds a typical animation should last.
|
||||||
pub animation_time: f32,
|
pub animation_time: f32,
|
||||||
|
|
||||||
/// Options to help debug why egui behaves strangely.
|
/// Options to help debug why egui behaves strangely.
|
||||||
|
@ -58,6 +68,7 @@ impl Style {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Controls the sizes and distances between widgets.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "persistence", serde(default))]
|
#[cfg_attr(feature = "persistence", serde(default))]
|
||||||
|
@ -119,6 +130,7 @@ impl Spacing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How and when interaction happens.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "persistence", serde(default))]
|
#[cfg_attr(feature = "persistence", serde(default))]
|
||||||
|
@ -133,6 +145,12 @@ pub struct Interaction {
|
||||||
pub show_tooltips_only_when_still: bool,
|
pub show_tooltips_only_when_still: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Controls the visual style (colors etc) of egui.
|
||||||
|
///
|
||||||
|
/// You can change the visuals of a [`Ui`] with [`Ui::visuals_mut`]
|
||||||
|
/// and of everything with [`crate::Context::set_visuals`].
|
||||||
|
///
|
||||||
|
/// If you want to change fonts, use [`crate::Context::set_fonts`] instead.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "persistence", serde(default))]
|
#[cfg_attr(feature = "persistence", serde(default))]
|
||||||
|
@ -224,6 +242,7 @@ pub struct Selection {
|
||||||
pub stroke: Stroke,
|
pub stroke: Stroke,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The visuals of widgets for different states of interaction.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "persistence", serde(default))]
|
#[cfg_attr(feature = "persistence", serde(default))]
|
||||||
|
|
|
@ -769,7 +769,26 @@ impl Ui {
|
||||||
InnerResponse::new(ret, response)
|
InnerResponse::new(ret, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience function to get a region to paint on
|
/// Convenience function to get a region to paint on.
|
||||||
|
///
|
||||||
|
/// Note that egui uses screen coordinates for everything.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use egui::*;
|
||||||
|
/// # let mut ui = &mut egui::Ui::__test();
|
||||||
|
/// # use std::f32::consts::TAU;
|
||||||
|
/// let size = Vec2::splat(16.0);
|
||||||
|
/// let (response, painter) = ui.allocate_painter(size, Sense::hover());
|
||||||
|
/// let rect = response.rect;
|
||||||
|
/// let c = rect.center();
|
||||||
|
/// let r = rect.width() / 2.0 - 1.0;
|
||||||
|
/// let color = Color32::from_gray(128);
|
||||||
|
/// let stroke = Stroke::new(1.0, color);
|
||||||
|
/// painter.circle_stroke(c, r, stroke);
|
||||||
|
/// painter.line_segment([c - vec2(0.0, r), c + vec2(0.0, r)], stroke);
|
||||||
|
/// painter.line_segment([c, c + r * Vec2::angled(TAU * 1.0 / 8.0)], stroke);
|
||||||
|
/// painter.line_segment([c, c + r * Vec2::angled(TAU * 3.0 / 8.0)], stroke);
|
||||||
|
/// ```
|
||||||
pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) {
|
pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) {
|
||||||
let response = self.allocate_response(desired_size, sense);
|
let response = self.allocate_response(desired_size, sense);
|
||||||
let clip_rect = self.clip_rect().intersect(response.rect); // Make sure we don't paint out of bounds
|
let clip_rect = self.clip_rect().intersect(response.rect); // Make sure we don't paint out of bounds
|
||||||
|
|
|
@ -58,11 +58,24 @@ impl super::View for FontBook {
|
||||||
use super::font_contents_ubuntu::UBUNTU_FONT_CHARACTERS;
|
use super::font_contents_ubuntu::UBUNTU_FONT_CHARACTERS;
|
||||||
|
|
||||||
ui.label(format!(
|
ui.label(format!(
|
||||||
"egui supports {} standard characters and {} emojis.\nClick on a character to copy it.",
|
"The default egui fonts supports {} standard characters and {} emojis.",
|
||||||
UBUNTU_FONT_CHARACTERS.len(),
|
UBUNTU_FONT_CHARACTERS.len(),
|
||||||
FULL_EMOJI_LIST.len(),
|
FULL_EMOJI_LIST.len(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
ui.horizontal_wrapped(|ui| {
|
||||||
|
ui.spacing_mut().item_spacing.x = 0.0;
|
||||||
|
ui.label("You can add more characters by installing additional fonts with ");
|
||||||
|
ui.add(
|
||||||
|
egui::Hyperlink::from_label_and_url(
|
||||||
|
"Context::set_fonts",
|
||||||
|
"https://docs.rs/egui/latest/egui/struct.Context.html#method.set_fonts",
|
||||||
|
)
|
||||||
|
.text_style(egui::TextStyle::Monospace),
|
||||||
|
);
|
||||||
|
ui.label(".");
|
||||||
|
});
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
egui::ComboBox::from_label("Text style")
|
egui::ComboBox::from_label("Text style")
|
||||||
|
|
|
@ -88,8 +88,9 @@ impl View for MiscDemoWindow {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("You can pretty easily paint your own small icons:");
|
ui.label("You can pretty easily paint your own small icons:");
|
||||||
use std::f32::consts::TAU;
|
use std::f32::consts::TAU;
|
||||||
let (rect, _response) = ui.allocate_at_least(Vec2::splat(16.0), Sense::hover());
|
let size = Vec2::splat(16.0);
|
||||||
let painter = ui.painter();
|
let (response, painter) = ui.allocate_painter(size, Sense::hover());
|
||||||
|
let rect = response.rect;
|
||||||
let c = rect.center();
|
let c = rect.center();
|
||||||
let r = rect.width() / 2.0 - 1.0;
|
let r = rect.width() / 2.0 - 1.0;
|
||||||
let color = Color32::from_gray(128);
|
let color = Color32::from_gray(128);
|
||||||
|
|
|
@ -74,11 +74,42 @@ fn rusttype_font_from_font_data(name: &str, data: &FontData) -> rusttype::Font<'
|
||||||
/// Often you would start with [`FontDefinitions::default()`] and then add/change the contents.
|
/// Often you would start with [`FontDefinitions::default()`] and then add/change the contents.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let mut fonts = epaint::text::FontDefinitions::default();
|
/// # use {epaint::text::{FontDefinitions, TextStyle, FontFamily}};
|
||||||
|
/// # struct FakeEguiCtx {};
|
||||||
|
/// # impl FakeEguiCtx { fn set_fonts(&self, _: FontDefinitions) {} }
|
||||||
|
/// # let ctx = FakeEguiCtx {};
|
||||||
|
/// let mut fonts = FontDefinitions::default();
|
||||||
|
///
|
||||||
/// // Large button text:
|
/// // Large button text:
|
||||||
/// fonts.family_and_size.insert(
|
/// fonts.family_and_size.insert(
|
||||||
/// epaint::text::TextStyle::Button,
|
/// TextStyle::Button,
|
||||||
/// (epaint::text::FontFamily::Proportional, 32.0));
|
/// (FontFamily::Proportional, 32.0)
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// ctx.set_fonts(fonts);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// You can also install your own custom fonts:
|
||||||
|
/// ```
|
||||||
|
/// # use {epaint::text::{FontDefinitions, TextStyle, FontFamily}};
|
||||||
|
/// # struct FakeEguiCtx {};
|
||||||
|
/// # impl FakeEguiCtx { fn set_fonts(&self, _: FontDefinitions) {} }
|
||||||
|
/// # let ctx = FakeEguiCtx {};
|
||||||
|
/// let mut fonts = FontDefinitions::default();
|
||||||
|
///
|
||||||
|
/// // Install my own font (maybe supporting non-latin characters):
|
||||||
|
/// fonts.font_data.insert("my_font".to_owned(),
|
||||||
|
/// std::borrow::Cow::Borrowed(include_bytes!("../../fonts/Ubuntu-Light.ttf"))); // .ttf and .otf supported
|
||||||
|
///
|
||||||
|
/// // Put my font first (highest priority):
|
||||||
|
/// fonts.fonts_for_family.get_mut(&FontFamily::Proportional).unwrap()
|
||||||
|
/// .insert(0, "my_font".to_owned());
|
||||||
|
///
|
||||||
|
/// // Put my font as last fallback for monospace:
|
||||||
|
/// fonts.fonts_for_family.get_mut(&FontFamily::Monospace).unwrap()
|
||||||
|
/// .push("my_font".to_owned());
|
||||||
|
///
|
||||||
|
/// ctx.set_fonts(fonts);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
|
BIN
media/light_theme.png
Normal file
BIN
media/light_theme.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
BIN
media/widget_gallery.gif
Normal file
BIN
media/widget_gallery.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 MiB |
Loading…
Reference in a new issue