Move egui/math into new crate emath
This commit is contained in:
parent
aee1474b6e
commit
a0b0f36d29
38 changed files with 187 additions and 97 deletions
|
@ -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
generated
8
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -5,6 +5,7 @@ members = [
|
|||
"egui_glium",
|
||||
"egui_web",
|
||||
"egui",
|
||||
"emath",
|
||||
"epi",
|
||||
]
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,6 +1,5 @@
|
|||
//! uis for egui types.
|
||||
use crate::{
|
||||
math::*,
|
||||
paint::{self, PaintCmd, Texture, Triangles},
|
||||
*,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,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`].
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
Normal file
24
emath/Cargo.toml
Normal file
|
@ -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
Normal file
5
emath/README.md
Normal file
|
@ -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/).
|
|
@ -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(),
|
|
@ -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);
|
|
@ -1,6 +1,6 @@
|
|||
use std::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign};
|
||||
|
||||
use crate::math::*;
|
||||
use crate::*;
|
||||
|
||||
/// A position on screen.
|
||||
///
|
|
@ -1,6 +1,6 @@
|
|||
use std::ops::RangeInclusive;
|
||||
|
||||
use crate::math::*;
|
||||
use crate::*;
|
||||
|
||||
/// A rectangular region of space.
|
||||
///
|
|
@ -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…
Reference in a new issue