diff --git a/README.md b/README.md index 80a9e690..e454dc60 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/eframe/README.md b/eframe/README.md index 5ec75fff..5a816d99 100644 --- a/eframe/README.md +++ b/eframe/README.md @@ -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). diff --git a/egui/src/containers/collapsing_header.rs b/egui/src/containers/collapsing_header.rs index f561d264..d984513b 100644 --- a/egui/src/containers/collapsing_header.rs +++ b/egui/src/containers/collapsing_header.rs @@ -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) -> 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 diff --git a/egui/src/data/input.rs b/egui/src/data/input.rs index 10f7f7a7..898c9c0e 100644 --- a/egui/src/data/input.rs +++ b/egui/src/data/input.rs @@ -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, } diff --git a/egui/src/grid.rs b/egui/src/grid.rs index 4af3b6f8..ddd3ca01 100644 --- a/egui/src/grid.rs +++ b/egui/src/grid.rs @@ -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. /// diff --git a/egui/src/lib.rs b/egui/src/lib.rs index 1b814541..95875d1f 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -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 . //! -//! ``` no_run -//! # fn handle_output(_: egui::Output) {} -//! # fn paint(_: Vec) {} -//! # fn gather_input() -> egui::RawInput { egui::RawInput::default() } -//! let mut ctx = egui::CtxRef::default(); +//! If you like the "learning by doing" approach, clone 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 . -//! -//! If you like the "learning by doing" approach, clone 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) {} +//! # 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(); diff --git a/egui/src/style.rs b/egui/src/style.rs index 81b16733..f033acac 100644 --- a/egui/src/style.rs +++ b/egui/src/style.rs @@ -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`. diff --git a/egui/src/ui.rs b/egui/src/ui.rs index 3227bf95..f0a1e188 100644 --- a/egui/src/ui.rs +++ b/egui/src/ui.rs @@ -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