Skip to content

Commit

Permalink
Improve docs concerning custom fonts, themes and accessibility
Browse files Browse the repository at this point in the history
Closes #370
Closes #372
  • Loading branch information
emilk committed May 11, 2021
1 parent 8f8ba16 commit 7b0f991
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 16 deletions.
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.

Expand Down Expand Up @@ -68,7 +68,7 @@ ui.label(format!("Hello '{}', age {}", name, age));

## Goals

* The easiest to use GUI libary
* The easiest to use GUI library
* Responsive: target 60 Hz in debug build
* Friendly: difficult to make mistakes, and shouldn't panic
* Portable: the same code works on the web and as a native app
Expand All @@ -79,15 +79,15 @@ 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)
* 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
* 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.

**NOTE**: egui does not claim to have reached all these goals yet! egui is still work in progress.

### Non-goals

* Become the most powerful GUI libary
* Become the most powerful GUI library
* Native looking interface
* Advanced and flexible layouts (that's fundamentally incompatible with immediate mode)

Expand Down Expand Up @@ -134,7 +134,11 @@ egui is in active development. It works well for what it does, but it lacks many
* Tooltips on hover
* 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

Expand Down Expand Up @@ -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:

* 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).
* 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*.

Expand Down Expand Up @@ -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).

### 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?

`egui` is a 2D user interface library for laying out and interacting with buttons, sliders, etc.
Expand Down
9 changes: 8 additions & 1 deletion egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,12 @@ impl Context {
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) {
if let Some(current_fonts) = &self.fonts {
// NOTE: this comparison is expensive since it checks TTF data for equality
Expand All @@ -434,6 +439,8 @@ impl Context {

/// 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:
/// ```
/// # let mut ctx = egui::CtxRef::default();
Expand Down
3 changes: 3 additions & 0 deletions egui/src/data/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use crate::emath::*;
///
/// 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.
#[derive(Clone, Debug)]
pub struct RawInput {
Expand Down
3 changes: 3 additions & 0 deletions egui/src/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

/// 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)]
pub struct InputState {
/// The raw input we got this frame from the backend.
Expand Down
23 changes: 21 additions & 2 deletions egui/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
use crate::{color::*, emath::*, Response};
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)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
Expand All @@ -22,11 +27,16 @@ pub struct Style {
/// * `Some(false)`: default off
pub wrap: Option<bool>,

/// Sizes and distances between widgets
pub spacing: Spacing,

/// How and when interaction happens.
pub interaction: Interaction,

/// Colors etc.
pub visuals: Visuals,

/// How many seconds a typical animation should last
/// How many seconds a typical animation should last.
pub animation_time: f32,

/// Options to help debug why egui behaves strangely.
Expand Down Expand Up @@ -58,6 +68,7 @@ impl Style {
}
}

/// Controls the sizes and distances between widgets.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
Expand Down Expand Up @@ -119,6 +130,7 @@ impl Spacing {
}
}

/// How and when interaction happens.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
Expand All @@ -133,6 +145,12 @@ pub struct Interaction {
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)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
Expand Down Expand Up @@ -224,6 +242,7 @@ pub struct Selection {
pub stroke: Stroke,
}

/// The visuals of widgets for different states of interaction.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
Expand Down
21 changes: 20 additions & 1 deletion egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,26 @@ impl Ui {
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) {
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
Expand Down
15 changes: 14 additions & 1 deletion egui_demo_lib/src/apps/demo/font_book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,24 @@ impl super::View for FontBook {
use super::font_contents_ubuntu::UBUNTU_FONT_CHARACTERS;

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(),
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();

egui::ComboBox::from_label("Text style")
Expand Down
5 changes: 3 additions & 2 deletions egui_demo_lib/src/apps/demo/misc_demo_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ impl View for MiscDemoWindow {
ui.horizontal(|ui| {
ui.label("You can pretty easily paint your own small icons:");
use std::f32::consts::TAU;
let (rect, _response) = ui.allocate_at_least(Vec2::splat(16.0), Sense::hover());
let painter = ui.painter();
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);
Expand Down
37 changes: 34 additions & 3 deletions epaint/src/text/fonts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
/// ```
/// 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:
/// fonts.family_and_size.insert(
/// epaint::text::TextStyle::Button,
/// (epaint::text::FontFamily::Proportional, 32.0));
/// TextStyle::Button,
/// (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)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
Expand Down
Binary file added media/light_theme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added media/widget_gallery.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 7b0f991

Please sign in to comment.