[doc] improve Egui documentation

This commit is contained in:
Emil Ernerfeldt 2020-07-23 14:35:12 +02:00
parent 61cdec8fca
commit b79c76b9ce
17 changed files with 124 additions and 87 deletions

View file

@ -1,11 +1,11 @@
pub mod area;
pub mod collapsing_header;
pub mod frame;
pub mod menu;
pub mod popup;
pub mod resize;
pub mod scroll_area;
pub mod window;
pub(crate) mod area;
pub(crate) mod collapsing_header;
pub(crate) mod frame;
pub(crate) mod menu;
pub(crate) mod popup;
pub(crate) mod resize;
pub(crate) mod scroll_area;
pub(crate) mod window;
pub use {
area::Area, collapsing_header::CollapsingHeader, frame::Frame, popup::*, resize::Resize,

View file

@ -1,6 +1,6 @@
use std::sync::Arc;
use crate::{widgets::*, *};
use crate::{paint::*, widgets::*, *};
use super::*;

View file

@ -1,6 +1,6 @@
use std::sync::Arc;
use crate::{color::*, containers::*, demos::FractalClock, widgets::*, *};
use crate::{color::*, containers::*, demos::FractalClock, paint::*, widgets::*, *};
// ----------------------------------------------------------------------------
@ -298,15 +298,9 @@ impl Widgets {
});
ui.horizontal(|ui| {
if ui.add(radio(self.radio == 0, "First")).clicked {
self.radio = 0;
}
if ui.add(radio(self.radio == 1, "Second")).clicked {
self.radio = 1;
}
if ui.add(radio(self.radio == 2, "Final")).clicked {
self.radio = 2;
}
ui.radio_value("First", &mut self.radio, 0);
ui.radio_value("Second", &mut self.radio, 1);
ui.radio_value("Final", &mut self.radio, 2);
});
ui.add(Checkbox::new(&mut self.button_enabled, "Button enabled"));

View file

@ -1,6 +1,6 @@
use std::sync::Arc;
use crate::{containers::*, widgets::*, *};
use crate::{containers::*, paint::PaintCmd, widgets::*, *};
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "with_serde", serde(default))]

View file

@ -1,34 +1,32 @@
//! Egui tracks widgets frame-to-frame using `Id`s.
//!
//! For instance, if you start dragging a slider one frame, egui stores
//! the sliders `Id` as the current active id so that next frame when
//! you move the mouse the same slider changes, even if the mouse has
//! moved outside the slider.
//!
//! For some widgets `Id`s are also used to persist some state about the
//! widgets, such as Window position or wether not a collapsing header region is open.
//!
//! This implicates that the `Id`s must be unqiue.
//!
//! For simple things like sliders and buttons that don't have any memory and
//! doesn't move we can use the location of the widget as a source of identity.
//! For instance, a slider only needs a unique and persistent ID while you are
//! dragging the slider. As long as it is still while moving, that is fine.
//!
//! For things that need to persist state even after moving (windows, collapsing headers)
//! the location of the widgets is obviously not good enough. For instance,
//! a collapsing region needs to remember wether or not it is open even
//! if the layout next frame is different and the collapsing is not lower down
//! on the screen.
//!
//! Then there are widgets that need no identifiers at all, like labels,
//! because they have no state nor are interacted with.
//!
//! So we have two type of Ids: `PositionId` and `UniqueId`.
//! TODO: have separate types for `PositionId` and `UniqueId`.
// TODO: have separate types `PositionId` and `UniqueId`. ?
use std::hash::Hash;
/// Egui tracks widgets frame-to-frame using `Id`s.
///
/// For instance, if you start dragging a slider one frame, egui stores
/// the sliders `Id` as the current active id so that next frame when
/// you move the mouse the same slider changes, even if the mouse has
/// moved outside the slider.
///
/// For some widgets `Id`s are also used to persist some state about the
/// widgets, such as Window position or wether not a collapsing header region is open.
///
/// This implies that the `Id`s must be unqiue.
///
/// For simple things like sliders and buttons that don't have any memory and
/// doesn't move we can use the location of the widget as a source of identity.
/// For instance, a slider only needs a unique and persistent ID while you are
/// dragging the slider. As long as it is still while moving, that is fine.
///
/// For things that need to persist state even after moving (windows, collapsing headers)
/// the location of the widgets is obviously not good enough. For instance,
/// a collapsing region needs to remember wether or not it is open even
/// if the layout next frame is different and the collapsing is not lower down
/// on the screen.
///
/// Then there are widgets that need no identifiers at all, like labels,
/// because they have no state nor are interacted with.
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Id(u64);

View file

@ -37,7 +37,7 @@ impl Layer {
/// Each `PaintCmd` is paired with a clip rectangle.
type PaintList = Vec<(Rect, PaintCmd)>;
/// TODO: improve this
// TODO: improve this
#[derive(Clone, Default)]
pub struct GraphicLayers(AHashMap<Layer, PaintList>);

View file

@ -39,7 +39,7 @@ impl Default for Align {
/// Used e.g. to anchor a piece of text to a part of the rectangle.
/// Give a position within the rect, specified by the aligns
pub fn align_rect(rect: Rect, align: (Align, Align)) -> Rect {
pub(crate) fn align_rect(rect: Rect, align: (Align, Align)) -> Rect {
let x = match align.0 {
Align::Min => rect.left(),
Align::Center => rect.left() - 0.5 * rect.width(),
@ -55,6 +55,7 @@ pub fn align_rect(rect: Rect, align: (Align, Align)) -> Rect {
// ----------------------------------------------------------------------------
/// The layout of a `Ui`, e.g. horizontal left-aligned.
#[derive(Clone, Copy, Debug, PartialEq)]
// #[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Layout {
@ -146,7 +147,7 @@ impl Layout {
/// Reserve this much space and move the cursor.
/// Returns where to put the widget.
///
/// # How sizes are negotiated
/// ## How sizes are negotiated
/// Each widget should have a *minimum desired size* and a *desired size*.
/// When asking for space, ask AT LEAST for you minimum, and don't ask for more than you need.
/// If you want to fill the space, ask about `available().size()` and use that.

View file

@ -50,7 +50,7 @@ pub use {
math::*,
memory::Memory,
movement_tracker::MovementTracker,
paint::{color, Color, TextStyle, Texture},
paint::{color, Color, PaintJobs, TextStyle, Texture},
style::Style,
types::*,
ui::Ui,

View file

@ -1,5 +1,8 @@
use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, RangeInclusive, Sub, SubAssign};
/// A size or direction in 2D space.
///
/// Normally given in points, e.g. logical pixels.
#[derive(Clone, Copy, Default)]
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Vec2 {
@ -220,7 +223,10 @@ impl std::fmt::Debug for Vec2 {
// ----------------------------------------------------------------------------
/// Sometimes called a Point. I prefer the shorter Pos2 so it is equal length to Vec2
// Sometimes called a Point. I prefer the shorter Pos2 so it is equal length to Vec2
/// A position on screen.
///
/// Normally given in points, e.g. logical pixels.
#[derive(Clone, Copy, Default)]
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Pos2 {
@ -353,6 +359,9 @@ impl std::fmt::Debug for Pos2 {
// ----------------------------------------------------------------------------
/// A rectangular region of space.
///
/// Normally given in points, e.g. logical pixels.
#[derive(Clone, Copy, Default, Eq, PartialEq)]
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Rect {
@ -594,6 +603,11 @@ pub fn ease_in_ease_out(t: f32) -> f32 {
3.0 * t * t - 2.0 * t * t * t
}
/// The circumference of a circle divided by its radius.
///
/// Represents one turn in radian angles. Equal to `2 * pi`.
///
/// See https://tauday.com/
pub const TAU: f32 = 2.0 * std::f32::consts::PI;
pub fn round_to_precision(value: f32, precision: usize) -> f32 {

View file

@ -6,6 +6,12 @@ use crate::{
Id, Layer, Pos2, Rect,
};
/// The data that Egui persists between frames.
///
/// This includes window positions and sizes,
/// how far the user has scrolled in a `ScrollArea` etc.
///
/// If you want this to persist when closing your app you should serialize `Memory` and store it.
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "with_serde", serde(default))]
@ -30,7 +36,7 @@ pub struct Memory {
pub(crate) areas: Areas,
}
/// Say there is a butotn in a scroll area.
/// Say there is a button in a scroll area.
/// If the user clicks the button, the button should click.
/// If the user drags the button we should scroll the scroll area.
/// So what we do is that when the mouse is pressed we register both the button

View file

@ -1,5 +1,5 @@
/// 0-255 `sRGBA`. TODO: rename `sRGBA` for clarity.
/// Uses premultiplied alpha.
// TODO: rename `Color` to `sRGBA` for clarity.
/// 0-255 `sRGBA`. Uses premultiplied alpha.
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Color {

View file

@ -11,7 +11,7 @@ use super::{
texture_atlas::{Texture, TextureAtlas},
};
/// TODO: rename
// TODO: rename
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
// #[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
pub enum TextStyle {

View file

@ -1,7 +1,8 @@
/// An 8-bit texture containing font data.
#[derive(Clone, Default)]
pub struct Texture {
/// e.g. a hash of the data. Use this to detect changes!
pub id: u64, // TODO
pub id: u64,
pub width: usize,
pub height: usize,
pub pixels: Vec<u8>,
@ -25,7 +26,9 @@ impl std::ops::IndexMut<(usize, usize)> for Texture {
}
}
/// A texture pixels, used for fonts.
/// Contains font data in an atlas, where each character occupied a small rectangle.
///
/// More characters can be added, possibly expanding the texture.
#[derive(Clone, Default)]
pub struct TextureAtlas {
texture: Texture,

View file

@ -3,6 +3,7 @@
use crate::{color::*, math::*, paint::LineStyle, types::*};
// TODO: split into Spacing and Style?
/// Specifies the look and feel of a `Ui`.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "with_serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Style {

View file

@ -4,9 +4,12 @@ use crate::{math::Rect, Context, Ui};
// ----------------------------------------------------------------------------
/// What Egui emits each frame.
/// The backend should use this.
#[derive(Clone, Default)]
// #[cfg_attr(feature = "with_serde", derive(serde::Serialize))]
pub struct Output {
/// Set the cursor to this icon.
pub cursor_icon: CursorIcon,
/// If set, open this url.
@ -43,6 +46,9 @@ impl Default for CursorIcon {
// ----------------------------------------------------------------------------
/// The result of an interaction.
///
/// For instance, this lets you know whether or not a widget has been clicked this frame.
#[derive(Clone, Copy, Debug)]
// #[cfg_attr(feature = "with_serde", derive(serde::Serialize))]
pub struct InteractInfo {
@ -90,7 +96,10 @@ impl InteractInfo {
// ----------------------------------------------------------------------------
// TODO: rename GuiResponse
/// The result of adding a widget to an `Ui`.
///
/// This lets you know whether or not a widget has been clicked this frame.
/// It also lets you easily show a tooltip on hover.
pub struct GuiResponse {
/// The senses (click or drag) that the widget is interested in (if any).
pub sense: Sense,

View file

@ -112,7 +112,7 @@ impl Ui {
self.id
}
/// Options for this ui, and any child uis we may spawn.
/// Style options for this `Ui` and its children.
pub fn style(&self) -> &Style {
&self.style
}
@ -279,9 +279,10 @@ impl Ui {
pub fn request_kb_focus(&self, id: Id) {
self.memory().kb_focus_id = Some(id);
}
}
// ------------------------------------------------------------------------
/// # `Id` creation
impl Ui {
/// Will warn if the returned id is not guaranteed unique.
/// Use this to generate widget ids for widgets that have persistent state in Memory.
/// If the `id_source` is not unique within this ui
@ -328,10 +329,10 @@ impl Ui {
pub fn make_child_id(&self, id_seed: impl Hash) -> Id {
self.id.with(id_seed)
}
}
// ------------------------------------------------------------------------
// Interaction
/// # Interaction
impl Ui {
pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> InteractInfo {
self.ctx
.interact(self.layer, self.clip_rect, rect, Some(id), sense)
@ -374,7 +375,7 @@ impl Ui {
/// Reserve this much space and move the cursor.
/// Returns where to put the widget.
///
/// # How sizes are negotiated
/// ## How sizes are negotiated
/// Each widget should have a *minimum desired size* and a *desired size*.
/// When asking for space, ask AT LEAST for you minimum, and don't ask for more than you need.
/// If you want to fill the space, ask about `available().size()` and use that.
@ -434,10 +435,10 @@ impl Ui {
self.child_count += 1;
child_rect
}
}
// ------------------------------------------------
// Painting related stuff
/// # Painting related stuff
impl Ui {
/// It is up to the caller to make sure there is room for this.
/// Can be used for free painting.
/// NOTE: all coordinates are screen coordinates!
@ -524,39 +525,44 @@ impl Ui {
color,
});
}
}
// ------------------------------------------------------------------------
// Addding Widgets
/// # Adding widgets
impl Ui {
pub fn add(&mut self, widget: impl Widget) -> GuiResponse {
let interact = widget.ui(self);
self.response(interact)
}
// Convenience functions:
/// Shortcut for `add(Label::new(text))`
pub fn label(&mut self, label: impl Into<Label>) -> GuiResponse {
self.add(label.into())
}
/// Shortcut for `add(Hyperlink::new(url))`
pub fn hyperlink(&mut self, url: impl Into<String>) -> GuiResponse {
self.add(Hyperlink::new(url))
}
/// Shortcut for `add(Button::new(text))`
pub fn button(&mut self, text: impl Into<String>) -> GuiResponse {
self.add(Button::new(text))
}
// Argument order matching that of Dear ImGui
/// Show a checkbox.
pub fn checkbox(&mut self, text: impl Into<String>, checked: &mut bool) -> GuiResponse {
self.add(Checkbox::new(checked, text))
}
// Argument order matching that of Dear ImGui
/// Show a radio button.
pub fn radio(&mut self, text: impl Into<String>, checked: bool) -> GuiResponse {
self.add(RadioButton::new(checked, text))
}
/// Show a radio button. It is selected if `*curr_value == radio_value`.
/// If clicked, `radio_value` is assigned to `*curr_value`;
pub fn radio_value<Value: PartialEq>(
&mut self,
text: impl Into<String>,
@ -570,13 +576,14 @@ impl Ui {
response
}
/// Shortcut for `add(Separator::new())`
pub fn separator(&mut self) -> GuiResponse {
self.add(Separator::new())
}
}
// ------------------------------------------------------------------------
// Addding Containers / Sub-uis:
/// # Addding Containers / Sub-uis:
impl Ui {
pub fn collapsing<R>(
&mut self,
text: impl Into<String>,
@ -737,6 +744,4 @@ impl Ui {
self.allocate_space(size);
result
}
// ------------------------------------------------
}

View file

@ -1,11 +1,19 @@
//! Example widget uses:
//!
//! * `ui.add(Label::new("Text").text_color(color::red));`
//!
//! * `if ui.add(Button::new("Click me")).clicked { ... }`
#![allow(clippy::new_without_default)]
use crate::{layout::Direction, *};
mod slider;
pub mod text_edit;
pub(crate) mod text_edit;
pub use {paint::*, slider::*, text_edit::*};
pub use {slider::*, text_edit::*};
use paint::*;
// ----------------------------------------------------------------------------
@ -98,7 +106,9 @@ impl Label {
}
}
/// Usage: label!("Foo: {}", bar)
/// Shortcut for creating a `Label` widget.
///
/// Usage: `label!("Foo: {}", bar)` equivalent to `Label::new(format!("Foo: {}", bar))`.
#[macro_export]
macro_rules! label {
($fmt:expr) => ($crate::widgets::Label::new($fmt));
@ -382,10 +392,6 @@ impl RadioButton {
}
}
pub fn radio(checked: bool, text: impl Into<String>) -> RadioButton {
RadioButton::new(checked, text)
}
impl Widget for RadioButton {
fn ui(self, ui: &mut Ui) -> InteractInfo {
let RadioButton {