Browse Source

Move egui/math into new crate emath

pull/107/head
Emil Ernerfeldt 4 years ago
parent
commit
a0b0f36d29
  1. 1
      CHANGELOG.md
  2. 8
      Cargo.lock
  3. 1
      Cargo.toml
  4. 3
      egui/Cargo.toml
  5. 2
      egui/src/containers/area.rs
  6. 6
      egui/src/containers/collapsing_header.rs
  7. 2
      egui/src/containers/resize.rs
  8. 8
      egui/src/containers/scroll_area.rs
  9. 2
      egui/src/containers/window.rs
  10. 2
      egui/src/id.rs
  11. 1
      egui/src/introspection.rs
  12. 4
      egui/src/layers.rs
  13. 6
      egui/src/layout.rs
  14. 5
      egui/src/lib.rs
  15. 26
      egui/src/memory.rs
  16. 4
      egui/src/paint/color.rs
  17. 2
      egui/src/paint/command.rs
  18. 14
      egui/src/paint/fonts.rs
  19. 8
      egui/src/paint/galley.rs
  20. 2
      egui/src/paint/shadow.rs
  21. 4
      egui/src/paint/tessellator.rs
  22. 28
      egui/src/style.rs
  23. 10
      egui/src/types.rs
  24. 6
      egui/src/util/undoer.rs
  25. 4
      egui/src/widgets/drag_value.rs
  26. 8
      egui/src/widgets/slider.rs
  27. 10
      egui/src/widgets/text_edit.rs
  28. 4
      egui_demo_lib/src/apps/fractal_clock.rs
  29. 2
      egui_glium/Cargo.toml
  30. 24
      emath/Cargo.toml
  31. 5
      emath/README.md
  32. 10
      emath/src/align.rs
  33. 56
      emath/src/lib.rs
  34. 2
      emath/src/pos2.rs
  35. 2
      emath/src/rect.rs
  36. 0
      emath/src/rot2.rs
  37. 0
      emath/src/smart_aim.rs
  38. 2
      emath/src/vec2.rs

1
CHANGELOG.md

@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Center window titles.
* Tweak size and alignment of some emojis to match other text.
* Rename feature "serde" to "persistence".
### Fixed 🐛

8
Cargo.lock

@ -642,6 +642,7 @@ version = "0.7.0"
dependencies = [
"ahash",
"atomic_refcell",
"emath",
"parking_lot",
"rusttype",
"serde",
@ -703,6 +704,13 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "emath"
version = "0.7.0"
dependencies = [
"serde",
]
[[package]]
name = "epi"
version = "0.7.0"

1
Cargo.toml

@ -5,6 +5,7 @@ members = [
"egui_glium",
"egui_web",
"egui",
"emath",
"epi",
]

3
egui/Cargo.toml

@ -19,6 +19,8 @@ include = [
[lib]
[dependencies]
emath = { path = "../emath" }
ahash = { version = "0.6", features = ["std"], default-features = false }
atomic_refcell = { version = "0.1", optional = true } # Used instead of parking_lot when you are always using Egui in a single thread. About as fast as parking_lot. Panics on multi-threaded use of egui::Context.
parking_lot = { version = "0.11", optional = true } # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios
@ -27,6 +29,7 @@ serde = { version = "1", features = ["derive", "rc"], optional = true }
[features]
default = ["atomic_refcell", "default_fonts"]
persistence = ["serde", "emath/serde"]
# If set, egui will use `include_bytes!` to bundle some fonts.
# If you plan on specifying your own fonts you may disable this feature.

2
egui/src/containers/area.rs

@ -8,7 +8,7 @@ use crate::*;
/// State that is persisted between frames
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub(crate) struct State {
/// Last known pos
pub pos: Pos2,

6
egui/src/containers/collapsing_header.rs

@ -7,8 +7,8 @@ use crate::{
};
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub(crate) struct State {
open: bool,
@ -114,7 +114,7 @@ pub(crate) fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) {
let rect = Rect::from_center_size(rect.center(), vec2(rect.width(), rect.height()) * 0.75);
let mut points = vec![rect.left_top(), rect.right_top(), rect.center_bottom()];
use std::f32::consts::TAU;
let rotation = Rot2::from_angle(remap(openness, 0.0..=1.0, -TAU / 4.0..=0.0));
let rotation = math::Rot2::from_angle(remap(openness, 0.0..=1.0, -TAU / 4.0..=0.0));
for p in &mut points {
*p = rect.center() + rotation * (*p - rect.center());
}

2
egui/src/containers/resize.rs

@ -1,7 +1,7 @@
use crate::*;
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub(crate) struct State {
/// This is the size that the user has picked by dragging the resize handles.
/// This may be smaller and/or larger than the actual size.

8
egui/src/containers/scroll_area.rs

@ -1,8 +1,8 @@
use crate::*;
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub(crate) struct State {
/// Positive offset means scrolling down/right
offset: Vec2,
@ -10,7 +10,7 @@ pub(crate) struct State {
show_scroll: bool,
/// Momentum, used for kinetic scrolling
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
pub vel: Vec2,
/// Mouse offset relative to the top of the handle when started moving the handle.
scroll_start_offset_from_top: Option<f32>,
@ -177,7 +177,7 @@ impl Prepared {
// We take the scroll target so only this ScrollArea will use it.
let scroll_target = content_ui.ctx().frame_state().scroll_target.take();
if let Some((scroll_y, align)) = scroll_target {
let center_factor = align.scroll_center_factor();
let center_factor = align.to_factor();
let top = content_ui.min_rect().top();
let visible_range = top..=top + content_ui.clip_rect().height();

2
egui/src/containers/window.rs

@ -720,7 +720,7 @@ impl TitleBar {
self.title_label = self.title_label.text_color(style.fg_stroke.color);
let full_top_rect = Rect::from_x_y_ranges(self.rect.x_range(), self.min_rect.y_range());
let text_pos = align::center_size_in_rect(self.title_galley.size, full_top_rect);
let text_pos = math::align::center_size_in_rect(self.title_galley.size, full_top_rect);
let text_pos = text_pos.left_top() - 2.0 * Vec2::Y; // HACK: center on x-height of text (looks better)
self.title_label
.paint_galley(ui, text_pos, self.title_galley);

2
egui/src/id.rs

@ -28,7 +28,7 @@ use std::hash::Hash;
/// Then there are widgets that need no identifiers at all, like labels,
/// because they have no state nor are interacted with.
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Id(u64);
impl Id {

1
egui/src/introspection.rs

@ -1,6 +1,5 @@
//! uis for egui types.
use crate::{
math::*,
paint::{self, PaintCmd, Texture, Triangles},
*,
};

4
egui/src/layers.rs

@ -4,7 +4,7 @@ use crate::{math::Rect, paint::PaintCmd, Id, *};
/// Different layer categories
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub enum Order {
/// Painted behind all floating windows
Background,
@ -40,7 +40,7 @@ impl Order {
/// An identifier for a paint layer.
/// Also acts as an identifier for [`Area`]:s.
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct LayerId {
pub order: Order,
pub id: Id,

6
egui/src/layout.rs

@ -66,8 +66,8 @@ impl Region {
/// Layout direction, one of `LeftToRight`, `RightToLeft`, `TopDown`, `BottomUp`.
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(rename_all = "snake_case"))]
pub enum Direction {
LeftToRight,
RightToLeft,
@ -95,7 +95,7 @@ impl Direction {
/// The layout of a [`Ui`][`crate::Ui`], e.g. "vertical & centered".
#[derive(Clone, Copy, Debug, PartialEq)]
// #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
// #[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Layout {
/// Main axis direction
main_dir: Direction,

5
egui/src/lib.rs

@ -86,7 +86,6 @@ mod input;
mod introspection;
mod layers;
mod layout;
pub mod math;
mod memory;
pub mod menu;
pub mod paint;
@ -97,6 +96,8 @@ mod ui;
pub mod util;
pub mod widgets;
pub use emath as math;
pub use {
containers::*,
context::{Context, CtxRef},
@ -104,7 +105,7 @@ pub use {
input::*,
layers::*,
layout::*,
math::*,
math::{clamp, lerp, pos2, remap, remap_clamp, vec2, Align, Align2, NumExt, Pos2, Rect, Vec2},
memory::Memory,
paint::{
color, Color32, FontDefinitions, FontFamily, PaintCmd, PaintJobs, Rgba, Stroke, TextStyle,

26
egui/src/memory.rs

@ -18,50 +18,50 @@ use crate::{
///
/// If you want this to persist when closing your app you should serialize `Memory` and store it.
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct Memory {
pub(crate) options: Options,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) interaction: Interaction,
// states of various types of widgets
pub(crate) collapsing_headers: HashMap<Id, collapsing_header::State>,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) menu_bar: HashMap<Id, menu::BarState>,
pub(crate) resize: HashMap<Id, resize::State>,
pub(crate) scroll_areas: HashMap<Id, scroll_area::State>,
pub(crate) text_edit: HashMap<Id, text_edit::State>,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) window_interaction: Option<window::WindowInteraction>,
/// For temporary edit of e.g. a slider value.
/// Couples with [`Interaction::kb_focus_id`].
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) temp_edit_string: Option<String>,
pub(crate) areas: Areas,
/// Used by color picker
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) color_cache: Cache<Color32, Hsva>,
/// Which popup-window is open (if any)?
/// Could be a combo box, color picker, menu etc.
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
popup: Option<Id>,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
everything_is_visible: bool,
}
// ----------------------------------------------------------------------------
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub(crate) struct Options {
/// The default style for new `Ui`:s.
pub(crate) style: std::sync::Arc<Style>,
@ -304,8 +304,8 @@ impl Memory {
/// Keeps track of `Area`s, which are free-floating `Ui`s.
/// These `Area`s can be in any `Order`.
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct Areas {
areas: HashMap<Id, area::State>,
/// Top is last

4
egui/src/paint/color.rs

@ -8,7 +8,7 @@ use crate::math::clamp;
/// Internally this uses 0-255 gamma space `sRGBA` color with premultiplied alpha.
/// Alpha channel is in linear space.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Color32(pub(crate) [u8; 4]);
impl std::ops::Index<usize> for Color32 {
@ -130,7 +130,7 @@ impl Color32 {
/// 0-1 linear space `RGBA` color with premultiplied alpha.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Rgba(pub(crate) [f32; 4]);
impl std::ops::Index<usize> for Rgba {

2
egui/src/paint/command.rs

@ -192,7 +192,7 @@ impl PaintCmd {
/// Describes the width and color of a line.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Stroke {
pub width: f32,
pub color: Color32,

14
egui/src/paint/fonts.rs

@ -14,8 +14,8 @@ use super::{
// TODO: rename
/// One of a few categories of styles of text, e.g. body, button or heading.
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(rename_all = "snake_case"))]
pub enum TextStyle {
/// Used when small text is needed.
Small,
@ -45,8 +45,8 @@ impl TextStyle {
/// Which style of font: [`Monospace`][`FontFamily::Monospace`] or [`Proportional`][`FontFamily::Proportional`].
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(rename_all = "snake_case"))]
pub enum FontFamily {
/// A font where each character is the same width (`w` is the same width as `i`).
Monospace,
@ -81,15 +81,15 @@ fn rusttype_font_from_font_data(name: &str, data: &FontData) -> rusttype::Font<'
/// ctx.set_fonts(fonts);
/// ```
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct FontDefinitions {
/// List of font names and their definitions.
/// The definition must be the contents of either a `.ttf` or `.otf` font file.
///
/// Egui has built-in-default for these,
/// but you can override them if you like.
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
pub font_data: BTreeMap<String, FontData>,
/// Which fonts (names) to use for each [`FontFamily`].

8
egui/src/paint/galley.rs

@ -20,7 +20,7 @@ use crate::math::{pos2, NumExt, Rect, Vec2};
/// Character cursor
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct CCursor {
/// Character offset (NOT byte offset!).
pub index: usize,
@ -71,7 +71,7 @@ impl std::ops::Sub<usize> for CCursor {
/// Row Cursor
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct RCursor {
/// 0 is first row, and so on.
/// Note that a single paragraph can span multiple rows.
@ -86,7 +86,7 @@ pub struct RCursor {
/// Paragraph Cursor
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct PCursor {
/// 0 is first paragraph, and so on.
/// Note that a single paragraph can span multiple rows.
@ -118,7 +118,7 @@ impl PartialEq for PCursor {
/// pcursor/rcursor can also point to after the end of the paragraph/row.
/// Does not implement `PartialEq` because you must think which cursor should be equivalent.
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Cursor {
pub ccursor: CCursor,
pub rcursor: RCursor,

2
egui/src/paint/shadow.rs

@ -1,7 +1,7 @@
use super::*;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Shadow {
// The shadow extends this much outside the rect.
pub extrusion: f32,

4
egui/src/paint/tessellator.rs

@ -446,8 +446,8 @@ use self::PathType::{Closed, Open};
/// Tessellation quality options
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct TessellationOptions {
/// Size of a pixel in points, e.g. 0.5
pub aa_size: f32,

28
egui/src/style.rs

@ -1,3 +1,5 @@
//! Egui theme (spacing, colors, etc).
#![allow(clippy::if_same_then_else)]
use crate::{
@ -9,8 +11,8 @@ use crate::{
/// Specifies the look and feel of a [`Ui`].
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct Style {
/// Default `TextStyle` for normal text (i.e. for `Label` and `TextEdit`).
pub body_text_style: TextStyle,
@ -39,8 +41,8 @@ impl Style {
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct Spacing {
/// Horizontal and vertical spacing between widgets
pub item_spacing: Vec2,
@ -95,8 +97,8 @@ impl Spacing {
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct Interaction {
/// Mouse must be the close to the side of a window to resize
pub resize_grab_radius_side: f32,
@ -106,8 +108,8 @@ pub struct Interaction {
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct Visuals {
/// Override default text color for all text.
///
@ -168,16 +170,16 @@ impl Visuals {
/// Selected text, selected elements etc
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct Selection {
pub bg_fill: Color32,
pub stroke: Stroke,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub struct Widgets {
/// For an interactive widget that is being interacted with
pub active: WidgetVisuals,
@ -207,7 +209,7 @@ impl Widgets {
/// bg = background, fg = foreground.
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct WidgetVisuals {
/// Background color of widget
pub bg_fill: Color32,

10
egui/src/types.rs

@ -5,7 +5,7 @@ use crate::{lerp, math::Rect, Align, CtxRef, Id, LayerId, Ui};
/// What Egui emits each frame.
/// The backend should use this.
#[derive(Clone, Default)]
// #[cfg_attr(feature = "serde", derive(serde::Serialize))]
// #[cfg_attr(feature = "persistence", derive(serde::Serialize))]
pub struct Output {
/// Set the cursor to this icon.
pub cursor_icon: CursorIcon,
@ -26,8 +26,8 @@ pub struct Output {
///
/// Egui emits a `CursorIcond` in [`Output`] each frame as a request to the integration.
#[derive(Clone, Copy)]
// #[cfg_attr(feature = "serde", derive(serde::Serialize))]
// #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
// #[cfg_attr(feature = "persistence", derive(serde::Serialize))]
// #[cfg_attr(feature = "persistence", serde(rename_all = "snake_case"))]
pub enum CursorIcon {
Default,
/// Pointing hand, used for e.g. web links
@ -187,7 +187,7 @@ impl Response {
/// });
/// ```
pub fn scroll_to_me(&self, align: Align) {
let scroll_target = lerp(self.rect.y_range(), align.scroll_center_factor());
let scroll_target = lerp(self.rect.y_range(), align.to_factor());
self.ctx.frame_state().scroll_target = Some((scroll_target, align));
}
}
@ -254,7 +254,7 @@ impl std::ops::BitOrAssign for Response {
/// What sort of interaction is a widget sensitive to?
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
// #[cfg_attr(feature = "serde", derive(serde::Serialize))]
// #[cfg_attr(feature = "persistence", derive(serde::Serialize))]
pub struct Sense {
/// buttons, sliders, windows ...
pub click: bool,

6
egui/src/util/undoer.rs

@ -1,7 +1,7 @@
use std::collections::VecDeque;
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Settings {
/// Maximum number of undos.
/// If your state is resource intensive, you should keep this low.
@ -48,7 +48,7 @@ impl Default for Settings {
/// Rule 1) will make sure an undo point is not created until you _stop_ dragging that slider.
/// Rule 2) will make sure that you will get some undo points even if you are constantly changing the state.
#[derive(Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
pub struct Undoer<State> {
settings: Settings,
@ -57,7 +57,7 @@ pub struct Undoer<State> {
/// The latest undo point may (often) be the current state.
undos: VecDeque<State>,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
flux: Option<Flux<State>>,
}

4
egui/src/widgets/drag_value.rs

@ -149,7 +149,7 @@ impl<'a> Widget for DragValue<'a> {
let auto_decimals = (aim_rad / speed.abs()).log10().ceil().at_least(0.0) as usize;
let max_decimals = max_decimals.unwrap_or(auto_decimals + 2);
let auto_decimals = clamp(auto_decimals, min_decimals..=max_decimals);
let value_text = format_with_decimals_in_range(value, auto_decimals..=max_decimals);
let value_text = math::format_with_decimals_in_range(value, auto_decimals..=max_decimals);
let kb_edit_id = ui.auto_id_with("edit");
let is_kb_editing = ui.memory().has_kb_focus(kb_edit_id);
@ -193,7 +193,7 @@ impl<'a> Widget for DragValue<'a> {
let delta_value = speed * delta_points;
if delta_value != 0.0 {
let new_value = value + delta_value as f64;
let new_value = round_to_decimals(new_value, auto_decimals);
let new_value = math::round_to_decimals(new_value, auto_decimals);
let new_value = clamp(new_value, range);
set(&mut value_function, new_value);
// TODO: To make use or `smart_aim` for `DragValue` we need to store some state somewhere,

8
egui/src/widgets/slider.rs

@ -2,7 +2,7 @@
use std::ops::RangeInclusive;
use crate::{math::NumExt, paint::*, widgets::Label, *};
use crate::{paint::*, widgets::Label, *};
// ----------------------------------------------------------------------------
@ -209,7 +209,7 @@ impl<'a> Slider<'a> {
fn set_value(&mut self, mut value: f64) {
if let Some(max_decimals) = self.max_decimals {
value = round_to_decimals(value, max_decimals);
value = math::round_to_decimals(value, max_decimals);
}
set(&mut self.get_set_value, value);
}
@ -366,13 +366,13 @@ impl<'a> Slider<'a> {
let auto_decimals = clamp(auto_decimals, min_decimals..=max_decimals);
if min_decimals == max_decimals {
format_with_minimum_decimals(value, max_decimals)
math::format_with_minimum_decimals(value, max_decimals)
} else if value == 0.0 {
"0".to_owned()
} else if range == 0.0 {
value.to_string()
} else {
format_with_decimals_in_range(value, auto_decimals..=max_decimals)
math::format_with_decimals_in_range(value, auto_decimals..=max_decimals)
}
}
}

10
egui/src/widgets/text_edit.rs

@ -1,17 +1,17 @@
use crate::{paint::*, util::undoer::Undoer, *};
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", serde(default))]
pub(crate) struct State {
cursorp: Option<CursorPair>,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "persistence", serde(skip))]
undoer: Undoer<(CCursorPair, String)>,
}
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
struct CursorPair {
/// When selecting with a mouse, this is where the mouse was released.
/// When moving with e.g. shift+arrows, this is what moves.
@ -75,7 +75,7 @@ impl CursorPair {
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
struct CCursorPair {
/// When selecting with a mouse, this is where the mouse was released.
/// When moving with e.g. shift+arrows, this is what moves.

4
egui_demo_lib/src/apps/fractal_clock.rs

@ -144,8 +144,8 @@ impl FractalClock {
];
let hand_rotors = [
hands[0].length * Rot2::from_angle(hand_rotations[0]),
hands[1].length * Rot2::from_angle(hand_rotations[1]),
hands[0].length * math::Rot2::from_angle(hand_rotations[0]),
hands[1].length * math::Rot2::from_angle(hand_rotations[1]),
];
#[derive(Clone, Copy)]

2
egui_glium/Cargo.toml

@ -35,7 +35,7 @@ default = []
http = ["ureq"]
persistence = [
"directories-next",
"egui/serde",
"egui/persistence",
"epi/serde_json",
"epi/serde",
"serde_json",

24
emath/Cargo.toml

@ -0,0 +1,24 @@
[package]
name = "emath"
version = "0.7.0"
authors = ["Emil Ernerfeldt <emil.ernerfeldt@gmail.com>"]
description = "Minimal 2D math library for GUI work"
edition = "2018"
homepage = "https://github.com/emilk/egui"
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/emilk/egui"
categories = ["gui", "math"]
keywords = ["gui", "math"]
include = [
"**/*.rs",
"Cargo.toml",
]
[lib]
[dependencies]
serde = { version = "1", features = ["derive"], optional = true }
[features]
default = []

5
emath/README.md

@ -0,0 +1,5 @@
# emath - Egui Math Library
A bare-bones 2D math library with types and functions useful for GUI building.
Made for [`egui`](https://github.com/emilk/egui/).

10
egui/src/math/align.rs → emath/src/align.rs

@ -1,6 +1,6 @@
//! One- and two-dimensional alignment ([`Align::Center`], [`LEFT_TOP`] etc).
//! One- and two-dimensional alignment ([`Align::Center`], [`Align2::LEFT_TOP`] etc).
use crate::math::*;
use crate::*;
/// left/center/right or top/center/bottom alignment for e.g. anchors and `Layout`s.
#[derive(Clone, Copy, Debug, PartialEq)]
@ -35,7 +35,8 @@ impl Align {
Self::Max
}
pub(crate) fn scroll_center_factor(&self) -> f32 {
/// Convert `Min => 0.0`, `Center => 0.5` or `Max => 1.0`.
pub fn to_factor(&self) -> f32 {
match self {
Self::Min => 0.0,
Self::Center => 0.5,
@ -52,6 +53,7 @@ impl Default for Align {
// ----------------------------------------------------------------------------
/// Two-dimension alignment, e.g. [`Align2::LEFT_TOP`].
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
@ -79,7 +81,7 @@ impl Align2 {
/// 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(crate) fn anchor_rect(self, rect: Rect) -> Rect {
pub fn anchor_rect(self, rect: Rect) -> Rect {
let x = match self.x() {
Align::Min => rect.left(),
Align::Center => rect.left() - 0.5 * rect.width(),

56
egui/src/math/mod.rs → emath/src/lib.rs

@ -1,8 +1,55 @@
//! Vectors, positions, rectangles etc.
//!
//! Conventions (unless otherwise specified):
//!
//! * All angles are in radians
//! * All metrics are in points (logical pixels)
//! * X+ is right and Y+ is down.
//! * (0,0) is left top.
//! * Dimension order is always `x y`
#![cfg_attr(not(debug_assertions), deny(warnings))] // Forbid warnings in release builds
#![forbid(unsafe_code)]
#![warn(
clippy::all,
clippy::await_holding_lock,
clippy::dbg_macro,
clippy::doc_markdown,
clippy::empty_enum,
clippy::enum_glob_use,
clippy::exit,
clippy::filter_map_next,
clippy::fn_params_excessive_bools,
clippy::if_let_mutex,
clippy::imprecise_flops,
clippy::inefficient_to_string,
clippy::linkedlist,
clippy::lossy_float_literal,
clippy::macro_use_imports,
clippy::match_on_vec_items,
clippy::match_wildcard_for_single_variants,
clippy::mem_forget,
clippy::mismatched_target_os,
clippy::missing_errors_doc,
clippy::missing_safety_doc,
clippy::needless_borrow,
clippy::needless_continue,
clippy::needless_pass_by_value,
clippy::option_option,
clippy::pub_enum_variant_names,
clippy::rest_pat_in_fully_bound_structs,
clippy::todo,
clippy::unimplemented,
clippy::unnested_or_patterns,
clippy::verbose_file_reads,
future_incompatible,
missing_crate_level_docs,
missing_doc_code_examples,
// missing_docs,
nonstandard_style,
rust_2018_idioms,
unused_doc_comments,
)]
#![allow(clippy::manual_range_contains)]
use std::ops::{Add, Div, Mul, RangeInclusive, Sub};
@ -130,14 +177,11 @@ pub fn round_to_decimals(value: f64, decimal_places: usize) -> f64 {
.unwrap_or(value)
}
pub(crate) fn format_with_minimum_decimals(value: f64, decimals: usize) -> String {
pub fn format_with_minimum_decimals(value: f64, decimals: usize) -> String {
format_with_decimals_in_range(value, decimals..=6)
}
pub(crate) fn format_with_decimals_in_range(
value: f64,
decimal_range: RangeInclusive<usize>,
) -> String {
pub fn format_with_decimals_in_range(value: f64, decimal_range: RangeInclusive<usize>) -> String {
let min_decimals = *decimal_range.start();
let max_decimals = *decimal_range.end();
debug_assert!(min_decimals <= max_decimals);

2
egui/src/math/pos2.rs → emath/src/pos2.rs

@ -1,6 +1,6 @@
use std::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign};
use crate::math::*;
use crate::*;
/// A position on screen.
///

2
egui/src/math/rect.rs → emath/src/rect.rs

@ -1,6 +1,6 @@
use std::ops::RangeInclusive;
use crate::math::*;
use crate::*;
/// A rectangular region of space.
///

0
egui/src/math/rot2.rs → emath/src/rot2.rs

0
egui/src/math/smart_aim.rs → emath/src/smart_aim.rs

2
egui/src/math/vec2.rs → emath/src/vec2.rs

@ -1,6 +1,6 @@
use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, RangeInclusive, Sub, SubAssign};
use crate::math::*;
use crate::*;
/// A vector has a direction and length.
/// A [`Vec2`] is often used to represent a size.
Loading…
Cancel
Save