improve documentation

This commit is contained in:
Emil Ernerfeldt 2021-02-28 18:53:45 +01:00
parent 8be37b3d6c
commit fdb1aa6bec
10 changed files with 151 additions and 44 deletions

View file

@ -25,6 +25,7 @@ Sections:
* [How it works](#how-it-works)
* [Integrations](#integrations)
* [Why immediate mode](#why-immediate-mode)
* [FAQ](#faq)
* [Other](#other)
## Quick start
@ -141,7 +142,7 @@ Loop:
* Gather input (mouse, touches, keyboard, screen size, etc) and give it to egui
* Run application code (Immediate Mode GUI)
* Tell egui to tessellate the frame graphics to a triangle mesh
* Render the triangle mesh with your favorite graphics API (see [OpenGL example](https://github.com/emilk/egui/blob/master/egui_glium/src/painter.rs))
* Render the triangle mesh with your favorite graphics API (see [OpenGL example](https://github.com/emilk/egui/blob/master/egui_glium/src/painter.rs)) or use `eframe`, the egui framework crate.
## Integrations
@ -266,13 +267,28 @@ There are some GUI state that you want the GUI library to retain, even in an imm
Overall, ID handling is a rare invonvenience, and not a big disadvantage.
## FAQ
Also see [GitHub Discussions](https://github.com/emilk/egui/discussions/categories/q-a).
### 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` has no idea if it is running on the web or natively, and does not know how to collect input or show things on screen.
That is the job of *the integration* or *backend*.
It is common to use `egui` from a game engine (using e.g. [`bevy_egui`](https://docs.rs/bevy_egui)),
but you can also use `egui` stand-alone using `eframe`. `eframe` has integration for web and native, and handles input and rendering.
The _frame_ in `eframe` stands both for the frame in which your egui app resides and also for "framework" (`frame` is a framework, `egui` is a library).
## Other
### Conventions and design choices
All coordinates are in screen space coordinates, with (0, 0) in the top left corner
All coordinates are in locial "points" which may consist of many physical pixels.
All coordinates are in "points" which may consist of many physical pixels.
All colors have premultiplied alpha.
@ -286,7 +302,7 @@ The one and only [Dear ImGui](https://github.com/ocornut/imgui) is a great Immed
### Name
The name of the library and the project is "egui" and pronounced as "e-gooey".
The name of the library and the project is "egui" and pronounced as "e-gooey". Please don't write it as "EGUI".
The library was originally called "Emigui", but was renamed to "egui" in 2020.

View file

@ -7,3 +7,7 @@ This aims to be the entry-level crate if you want to write an egui app.
`eframe` is a very thin crate that re-exports [`egui`](https://crates.io/crates/egui), [`epi`](https://crates.io/crates/epi) and thin wrappers over the backends.
On Linux you need to first run `sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev` to compile `eframe` natively.
## Name
The _frame_ in `eframe` stands both for the frame in which your egui app resides and also for "framework" (`frame` is a framework, `egui` is a library).

View file

@ -122,6 +122,18 @@ pub(crate) fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) {
}
/// A header which can be collapsed/expanded, revealing a contained [`Ui`] region.
///
///
/// ```
/// # let ui = &mut egui::Ui::__test();
/// egui::CollapsingHeader::new("Heading")
/// .show(ui, |ui| {
/// ui.label("Contents");
/// });
///
/// // Short version:
/// ui.collapsing("Heading", |ui| { ui.label("Contents"); });
/// ```
pub struct CollapsingHeader {
label: Label,
default_open: bool,
@ -130,6 +142,11 @@ pub struct CollapsingHeader {
impl CollapsingHeader {
/// The `CollapsingHeader` starts out collapsed unless you call `default_open`.
///
/// The label is used as an [`Id`] source.
/// If the label is unique and static this is fine,
/// but if it changes or there are several `CollapsingHeader` with the same title
/// you need to provide a unique id source with [`Self::id_source`].
pub fn new(label: impl Into<String>) -> Self {
let label = Label::new(label).text_style(TextStyle::Button).wrap(false);
let id_source = Id::new(label.text());
@ -140,6 +157,8 @@ impl CollapsingHeader {
}
}
/// By default, the `CollapsingHeader` is collapsed.
/// Call `.default_open(true)` to change this.
pub fn default_open(mut self, open: bool) -> Self {
self.default_open = open;
self

View file

@ -42,7 +42,11 @@ pub struct RawInput {
/// Which modifier keys are down at the start of the frame?
pub modifiers: Modifiers,
/// In-order events received this frame
/// In-order events received this frame.
///
/// There is currently no way to know if egui handles a particular event,
/// but you can check if egui is using the keyboard with [`crate::Context::wants_keyboard_input`]
/// and/or the pointer (mouse/touch) with [`crate::Context::is_using_pointer`].
pub events: Vec<Event>,
}

View file

@ -215,7 +215,9 @@ impl GridLayout {
/// A simple grid layout.
///
/// The contents of each cell be aligned to the left and center.
/// The cells are always layed out left to right, top-down.
/// The contents of each cell will be aligned to the left and center.
///
/// If you want to add multiple widgets to a cell you need to group them with
/// [`Ui::horizontal`], [`Ui::vertical`] etc.
///

View file

@ -9,41 +9,32 @@
//! Then you add a [`Window`] or a [`SidePanel`] to get a [`Ui`], which is what you'll be using to add all the buttons and labels that you need.
//!
//!
//! ## Integrating with egui
//! # Using egui
//!
//! To write your own integration for egui you need to do this:
//! To see what is possible to build with egui you can check out the online demo at <https://emilk.github.io/egui/#demo>.
//!
//! ``` no_run
//! # fn handle_output(_: egui::Output) {}
//! # fn paint(_: Vec<egui::ClippedMesh>) {}
//! # fn gather_input() -> egui::RawInput { egui::RawInput::default() }
//! let mut ctx = egui::CtxRef::default();
//! If you like the "learning by doing" approach, clone <https://github.com/emilk/egui_template> and get started using egui right away.
//!
//! // Game loop:
//! loop {
//! let raw_input: egui::RawInput = gather_input();
//! ctx.begin_frame(raw_input);
//! ### A simple example
//!
//! egui::CentralPanel::default().show(&ctx, |ui| {
//! ui.label("Hello world!");
//! if ui.button("Click me").clicked() {
//! /* take some action here */
//! Here is a simple counter that can be incremented and decremented using two buttons:
//! ```
//! fn ui_counter(ui: &mut egui::Ui, counter: &mut i32) {
//! // Put the buttons and label on the same row:
//! ui.horizontal(|ui| {
//! if ui.button("-").clicked() {
//! *counter -= 1;
//! }
//! ui.label(counter.to_string());
//! if ui.button("+").clicked() {
//! *counter += 1;
//! }
//! });
//!
//! let (output, shapes) = ctx.end_frame();
//! let clipped_meshes = ctx.tessellate(shapes); // create triangles to paint
//! handle_output(output);
//! paint(clipped_meshes);
//! }
//! ```
//!
//!
//! ## Using egui
//!
//! To see what is possible to build we egui you can check out the online demo at <https://emilk.github.io/egui/#demo>.
//!
//! If you like the "learning by doing" approach, clone <https://github.com/emilk/egui_template> and get started using egui right away.
//! In some GUI frameworks this would require defining multiple types and functions with callbacks or message handlers,
//! but thanks to `egui` being immediate mode everything is one self-contained function!
//!
//! ### Getting a [`Ui`]
//!
@ -89,6 +80,9 @@
//!
//! ui.separator();
//!
//! # let my_image = egui::TextureId::default();
//! ui.image(my_image, [640.0, 480.0]);
//!
//! ui.collapsing("Click to see what is hidden!", |ui| {
//! ui.label("Not much, as it turns out");
//! });
@ -101,9 +95,42 @@
//! * angles are in radians
//! * `Vec2::X` is right and `Vec2::Y` is down.
//! * `Pos2::ZERO` is left top.
//! * Positions and sizes are measured in _points_. Each point may consist of many physical pixels.
//!
//! # Integrating with egui
//!
//! Most likely you are using an existing `egui` backend/integration such as [`eframe`](https://docs.rs/eframe) or [`bevy_egui`](https://docs.rs/bevy_egui),
//! but if you want to integrate `egui` into a new game engine, this is the section for you.
//!
//! To write your own integration for egui you need to do this:
//!
//! ``` no_run
//! # fn handle_output(_: egui::Output) {}
//! # fn paint(_: Vec<egui::ClippedMesh>) {}
//! # fn gather_input() -> egui::RawInput { egui::RawInput::default() }
//! let mut ctx = egui::CtxRef::default();
//!
//! // Game loop:
//! loop {
//! let raw_input: egui::RawInput = gather_input();
//! ctx.begin_frame(raw_input);
//!
//! egui::CentralPanel::default().show(&ctx, |ui| {
//! ui.label("Hello world!");
//! if ui.button("Click me").clicked() {
//! /* take some action here */
//! }
//! });
//!
//! let (output, shapes) = ctx.end_frame();
//! let clipped_meshes = ctx.tessellate(shapes); // create triangles to paint
//! handle_output(output);
//! paint(clipped_meshes);
//! }
//! ```
//!
//!
//! ## Understanding immediate mode
//! # Understanding immediate mode
//!
//! `egui` is an immediate mode GUI library. It is useful to fully grok what "immediate mode" implies.
//!
@ -111,7 +138,9 @@
//!
//! ```
//! # let ui = &mut egui::Ui::__test();
//! if ui.button("click me").clicked() { take_action() }
//! if ui.button("click me").clicked() {
//! take_action()
//! }
//! # fn take_action() {}
//! ```
//!
@ -169,7 +198,7 @@
//! }
//! ```
//!
//! # Code snippets
//! ## Code snippets
//!
//! ```
//! # let ui = &mut egui::Ui::__test();

View file

@ -76,7 +76,7 @@ pub struct Spacing {
/// Anything clickable should be (at least) this size.
pub interact_size: Vec2, // TODO: rename min_interact_size ?
/// Default width of a `Slider`.
/// Default width of a `Slider` and `ComboBox`.
pub slider_width: f32, // TODO: rename big_interact_size ?
/// Default width of a `TextEdit`.

View file

@ -747,7 +747,7 @@ impl Ui {
/// # Adding widgets
impl Ui {
/// Add a widget to this `Ui` at a location dependent on the current [`Layout`].
/// Add a [`Widget`] to this `Ui` at a location dependent on the current [`Layout`].
///
/// The returned [`Response`] can be used to check for interactions,
/// as well as adding tooltips using [`Response::on_hover_text`].
@ -762,7 +762,7 @@ impl Ui {
widget.ui(self)
}
/// Add a widget to this `Ui` with a given max size.
/// Add a [`Widget`] to this `Ui` with a given max size.
pub fn add_sized(&mut self, max_size: Vec2, widget: impl Widget) -> Response {
self.allocate_ui(max_size, |ui| {
ui.centered_and_justified(|ui| ui.add(widget)).inner
@ -770,7 +770,7 @@ impl Ui {
.inner
}
/// Add a widget to this `Ui` at a specific location (manual layout).
/// Add a [`Widget`] to this `Ui` at a specific location (manual layout).
pub fn put(&mut self, max_rect: Rect, widget: impl Widget) -> Response {
self.allocate_ui_at_rect(max_rect, |ui| {
ui.centered_and_justified(|ui| ui.add(widget)).inner
@ -779,6 +779,8 @@ impl Ui {
}
/// Shortcut for `add(Label::new(text))`
///
/// Se also [`Label`].
pub fn label(&mut self, label: impl Into<Label>) -> Response {
self.add(label.into())
}
@ -815,6 +817,8 @@ impl Ui {
}
/// Shortcut for `add(Hyperlink::new(url))`
///
/// Se also [`Hyperlink`].
pub fn hyperlink(&mut self, url: impl Into<String>) -> Response {
self.add(Hyperlink::new(url))
}
@ -825,6 +829,8 @@ impl Ui {
/// # let ui = &mut egui::Ui::__test();
/// ui.hyperlink_to("egui on GitHub", "https://www.github.com/emilk/egui/");
/// ```
///
/// Se also [`Hyperlink`].
pub fn hyperlink_to(&mut self, label: impl Into<String>, url: impl Into<String>) -> Response {
self.add(Hyperlink::new(url).text(label))
}
@ -835,11 +841,15 @@ impl Ui {
}
/// Now newlines (`\n`) allowed. Pressing enter key will result in the `TextEdit` loosing focus (`response.lost_kb_focus`).
///
/// Se also [`TextEdit`].
pub fn text_edit_singleline(&mut self, text: &mut String) -> Response {
self.add(TextEdit::singleline(text))
}
/// A `TextEdit` for multiple lines. Pressing enter key will create a new line.
///
/// Se also [`TextEdit`].
pub fn text_edit_multiline(&mut self, text: &mut String) -> Response {
self.add(TextEdit::multiline(text))
}
@ -847,6 +857,8 @@ impl Ui {
/// Usage: `if ui.button("Click me").clicked() { … }`
///
/// Shortcut for `add(Button::new(text))`
///
/// Se also [`Button`].
#[must_use = "You should check if the user clicked this with `if ui.button(…).clicked() { … } "]
pub fn button(&mut self, text: impl Into<String>) -> Response {
self.add(Button::new(text))
@ -867,14 +879,14 @@ impl Ui {
self.add(Checkbox::new(checked, text))
}
/// Show a radio button.
/// Often you want to use `ui.radio_value` instead.
/// Show a [`RadioButton`].
/// Often you want to use [`Self::radio_value`] instead.
#[must_use = "You should check if the user clicked this with `if ui.radio(…).clicked() { … } "]
pub fn radio(&mut self, selected: bool, text: impl Into<String>) -> Response {
self.add(RadioButton::new(selected, text))
}
/// Show a radio button. It is selected if `*current_value == selected_value`.
/// Show a [`RadioButton`]. It is selected if `*current_value == selected_value`.
/// If clicked, `selected_value` is assigned to `*current_value`.
///
/// ```
@ -906,6 +918,8 @@ impl Ui {
}
/// Show a label which can be selected or not.
///
/// Se also [`SelectableLabel`].
#[must_use = "You should check if the user clicked this with `if ui.selectable_label(…).clicked() { … } "]
pub fn selectable_label(&mut self, checked: bool, text: impl Into<String>) -> Response {
self.add(SelectableLabel::new(checked, text))
@ -915,6 +929,8 @@ impl Ui {
/// If clicked, `selected_value` is assigned to `*current_value`.
///
/// Example: `ui.selectable_value(&mut my_enum, Enum::Alternative, "Alternative")`.
///
/// Se also [`SelectableLabel`].
pub fn selectable_value<Value: PartialEq>(
&mut self,
current_value: &mut Value,
@ -929,7 +945,7 @@ impl Ui {
response
}
/// Shortcut for `add(Separator::new())`
/// Shortcut for `add(Separator::new())` (see [`Separator`]).
pub fn separator(&mut self) -> Response {
self.add(Separator::new())
}
@ -974,6 +990,8 @@ impl Ui {
}
/// Show an image here with the given size.
///
/// See also [`Image`].
pub fn image(&mut self, texture_id: TextureId, size: impl Into<Vec2>) -> Response {
self.add(Image::new(texture_id, size))
}
@ -1102,7 +1120,7 @@ impl Ui {
self.allocate_ui(desired_size, add_contents).response.rect
}
/// A `CollapsingHeader` that starts out collapsed.
/// A [`CollapsingHeader`] that starts out collapsed.
pub fn collapsing<R>(
&mut self,
heading: impl Into<String>,
@ -1111,7 +1129,7 @@ impl Ui {
CollapsingHeader::new(heading).show(self, add_contents)
}
/// Create a child ui which is indented to the right
/// Create a child ui which is indented to the right.
pub fn indent<R>(
&mut self,
id_source: impl Hash,

View file

@ -1,6 +1,15 @@
use crate::*;
/// An widget to show an image of a given size.
///
/// ```
/// # let ui = &mut egui::Ui::__test();
/// # let my_texture_id = egui::TextureId::User(0);
/// ui.add(egui::Image::new(my_texture_id, [640.0, 480.0]));
///
/// // Shorter version:
/// ui.image(my_texture_id, [640.0, 480.0]);
/// ```
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
#[derive(Clone, Copy, Debug)]
pub struct Image {

View file

@ -76,6 +76,12 @@ pub trait App {
fn load(&mut self, _storage: &dyn Storage) {}
/// Called on shutdown, and perhaps at regular intervals. Allows you to save state.
///
/// On web the states is stored to "Local Storage".
/// On native the path is picked using [`directories_next::ProjectDirs`](https://docs.rs/directories-next/latest/directories_next/struct.ProjectDirs.html) which is:
/// * Linux: `/home/UserName/.config/appname`
/// * macOS: `/Users/UserName/Library/Application Support/appname`
/// * Windows: `C:\Users\UserName\AppData\Roaming\appname`
fn save(&mut self, _storage: &mut dyn Storage) {}
/// Called once on shutdown (before or after `save()`)