Improve docs, especially of epaint, and add epaint/CHANGELOG.md
This commit is contained in:
parent
88d087b462
commit
e547b149ca
15 changed files with 160 additions and 90 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
All notable changes to the egui crate will be documented in this file.
|
||||
|
||||
NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md), [`egui-winit`](egui-winit/CHANGELOG.md) and [`egui_glium`](egui_glium/CHANGELOG.md) have their own changelogs!
|
||||
NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md), [`egui-winit`](egui-winit/CHANGELOG.md) and [`egui_glium`](egui_glium/CHANGELOG.md) have their own changelogs!
|
||||
|
||||
|
||||
## Unreleased
|
||||
|
@ -10,7 +10,7 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md), [`eg
|
|||
### Added ⭐
|
||||
* Add horizontal scrolling support to `ScrollArea` and `Window` (opt-in).
|
||||
* `TextEdit::layouter`: Add custom text layout for e.g. syntax highlighting or WYSIWYG.
|
||||
* `Fonts::layout_job*`: New text layout engine allowing mixing fonts, colors and styles, with underlining and strikethrough.
|
||||
* `Fonts::layout_job`: New text layout engine allowing mixing fonts, colors and styles, with underlining and strikethrough.
|
||||
* Add feature `"serialize"` separatedly from `"persistence"`.
|
||||
* Add `egui::widgets::global_dark_light_mode_buttons` to easily add buttons for switching the egui theme.
|
||||
* `TextEdit` can now be used to show text which can be selectedd and copied, but not edited.
|
||||
|
|
|
@ -624,10 +624,14 @@ impl Context {
|
|||
|
||||
/// Tessellate the given shapes into triangle meshes.
|
||||
pub fn tessellate(&self, shapes: Vec<ClippedShape>) -> Vec<ClippedMesh> {
|
||||
// A tempting optimization is to reuse the tessellation from last frame if the
|
||||
// shapes are the same, but just comparing the shapes takes about 50% of the time
|
||||
// it takes to tessellate them, so it is not a worth optimization.
|
||||
|
||||
let mut tessellation_options = self.memory().options.tessellation_options;
|
||||
tessellation_options.pixels_per_point = self.pixels_per_point();
|
||||
tessellation_options.aa_size = 1.0 / self.pixels_per_point();
|
||||
let paint_stats = PaintStats::from_shapes(&shapes); // TODO: internal allocations
|
||||
let paint_stats = PaintStats::from_shapes(&shapes);
|
||||
let clipped_meshes = tessellator::tessellate_shapes(
|
||||
shapes,
|
||||
tessellation_options,
|
||||
|
|
|
@ -472,8 +472,8 @@ macro_rules! trace {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// An assert that is only active when `egui` is compiled with the `egui_assert` feature
|
||||
/// or with the `debug_egui_assert` feature in debug builds.
|
||||
/// An assert that is only active when `egui` is compiled with the `extra_asserts` feature
|
||||
/// or with the `extra_debug_asserts` feature in debug builds.
|
||||
#[macro_export]
|
||||
macro_rules! egui_assert {
|
||||
($($arg: tt)*) => {
|
||||
|
|
|
@ -408,7 +408,7 @@ impl Response {
|
|||
/// Check for more interactions (e.g. sense clicks on a `Response` returned from a label).
|
||||
///
|
||||
/// Note that this call will not add any hover-effects to the widget, so when possible
|
||||
/// it is better to give the widget a `Sense` instead, e.g. using `[Label::sense]`.
|
||||
/// it is better to give the widget a `Sense` instead, e.g. using [`crate::Label::sense`].
|
||||
///
|
||||
/// ```
|
||||
/// # let mut ui = egui::Ui::__test();
|
||||
|
|
|
@ -19,18 +19,22 @@ mod separator;
|
|||
mod slider;
|
||||
pub(crate) mod text_edit;
|
||||
|
||||
pub use button::*;
|
||||
pub use drag_value::DragValue;
|
||||
pub use hyperlink::*;
|
||||
pub use image::Image;
|
||||
pub use label::*;
|
||||
pub use progress_bar::ProgressBar;
|
||||
pub use selected_label::*;
|
||||
pub use separator::*;
|
||||
pub use {button::*, drag_value::DragValue, image::Image, slider::*, text_edit::*};
|
||||
pub use selected_label::SelectableLabel;
|
||||
pub use separator::Separator;
|
||||
pub use slider::*;
|
||||
pub use text_edit::*;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Anything implementing Widget can be added to a [`Ui`] with [`Ui::add`].
|
||||
///
|
||||
/// `[Button]`, `[Label]`, [`Slider`], etc all implement the `Widget` trait.
|
||||
/// [`Button`], [`Label`], [`Slider`], etc all implement the `Widget` trait.
|
||||
///
|
||||
/// Note that the widgets (`Button`, `TextEdit` etc) are
|
||||
/// [builders](https://doc.rust-lang.org/1.0.0/style/ownership/builders.html),
|
||||
|
|
|
@ -24,9 +24,9 @@ all-features = true
|
|||
|
||||
[dependencies]
|
||||
# Add compatability with https://github.com/kvark/mint
|
||||
bytemuck = { version = "1.7.2", features = ["derive"], optional = true }
|
||||
mint = { version = "0.5.6", optional = true }
|
||||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
bytemuck = { version = "1.7.2", features = ["derive"], optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
@ -358,8 +358,8 @@ fn test_normalized_angle() {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// An assert that is only active when `egui` is compiled with the `egui_assert` feature
|
||||
/// or with the `debug_egui_assert` feature in debug builds.
|
||||
/// An assert that is only active when `emath` is compiled with the `extra_asserts` feature
|
||||
/// or with the `extra_debug_asserts` feature in debug builds.
|
||||
#[macro_export]
|
||||
macro_rules! emath_assert {
|
||||
($($arg: tt)*) => {
|
||||
|
|
9
epaint/CHANGELOG.md
Normal file
9
epaint/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# epaint changelog
|
||||
|
||||
All notable changes to the epaint crate will be documented in this file.
|
||||
|
||||
## Unreleased
|
||||
* `Fonts::layout_job`: New text layout engine allowing mixing fonts, colors and styles, with underlining and strikethrough.
|
||||
* New `CircleShape`, `PathShape`, `RectShape` and `TextShape` used in `enum Shape`.
|
||||
* Add support for rotated text (see `TextShape`).
|
||||
* Added `"convert_bytemuck"` feature.
|
|
@ -30,11 +30,11 @@ emath = { version = "0.14.0", path = "../emath" }
|
|||
ab_glyph = "0.2.11"
|
||||
ahash = { version = "0.7", features = ["std"], default-features = false }
|
||||
atomic_refcell = { version = "0.1", optional = true } # Used instead of parking_lot when you are always using epaint in a single thread. About as fast as parking_lot. Panics on multi-threaded use.
|
||||
bytemuck = { version = "1.7.2", features = ["derive"], optional = true }
|
||||
cint = { version = "^0.2.2", optional = true }
|
||||
nohash-hasher = "0.2"
|
||||
parking_lot = { version = "0.11", optional = true } # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios.
|
||||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
bytemuck = { version = "1.7.2", features = ["derive"], optional = true }
|
||||
|
||||
[features]
|
||||
default = ["default_fonts", "multi_threaded"]
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
//! 2D graphics/rendering. Fonts, textures, color, geometry, tessellation etc.
|
||||
//! A simple 2D graphics library for turning simple 2D shapes and text into textured triangles.
|
||||
//!
|
||||
//! Made for [`egui`](https://github.com/emilk/egui/).
|
||||
//!
|
||||
//! Create some [`Shape`]:s and pass them to [`tessellate_shapes`] to generate [`Mesh`]:es
|
||||
//! that you can then paint using some graphics API of your choice (e.g. OpenGL).
|
||||
|
||||
// Forbid warnings in release builds:
|
||||
#![cfg_attr(not(debug_assertions), deny(warnings))]
|
||||
|
@ -91,8 +96,8 @@ pub use {
|
|||
shape::{CircleShape, PathShape, RectShape, Shape, TextShape},
|
||||
stats::PaintStats,
|
||||
stroke::Stroke,
|
||||
tessellator::{TessellationOptions, Tessellator},
|
||||
text::{Galley, TextStyle},
|
||||
tessellator::{tessellate_shapes, TessellationOptions, Tessellator},
|
||||
text::{Fonts, Galley, TextStyle},
|
||||
texture_atlas::{Texture, TextureAtlas},
|
||||
};
|
||||
|
||||
|
@ -129,7 +134,7 @@ impl Default for TextureId {
|
|||
/// A [`Shape`] within a clip rectangle.
|
||||
///
|
||||
/// Everything is using logical points.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ClippedShape(
|
||||
/// Clip / scissor rectangle.
|
||||
/// Only show the part of the [`Shape`] that falls within this.
|
||||
|
@ -153,8 +158,8 @@ pub struct ClippedMesh(
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// An assert that is only active when `egui` is compiled with the `egui_assert` feature
|
||||
/// or with the `debug_egui_assert` feature in debug builds.
|
||||
/// An assert that is only active when `epaint` is compiled with the `extra_asserts` feature
|
||||
/// or with the `extra_debug_asserts` feature in debug builds.
|
||||
#[macro_export]
|
||||
macro_rules! epaint_assert {
|
||||
($($arg: tt)*) => {
|
||||
|
|
|
@ -123,6 +123,57 @@ impl Shape {
|
|||
pub fn galley(pos: Pos2, galley: std::sync::Arc<Galley>) -> Self {
|
||||
TextShape::new(pos, galley).into()
|
||||
}
|
||||
|
||||
pub fn mesh(mesh: Mesh) -> Self {
|
||||
crate::epaint_assert!(mesh.is_valid());
|
||||
Self::Mesh(mesh)
|
||||
}
|
||||
}
|
||||
|
||||
/// ## Inspection and transforms
|
||||
impl Shape {
|
||||
#[inline(always)]
|
||||
pub fn texture_id(&self) -> super::TextureId {
|
||||
if let Shape::Mesh(mesh) = self {
|
||||
mesh.texture_id
|
||||
} else {
|
||||
super::TextureId::Egui
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the shape by this many points, in-place.
|
||||
pub fn translate(&mut self, delta: Vec2) {
|
||||
match self {
|
||||
Shape::Noop => {}
|
||||
Shape::Vec(shapes) => {
|
||||
for shape in shapes {
|
||||
shape.translate(delta);
|
||||
}
|
||||
}
|
||||
Shape::Circle(circle_shape) => {
|
||||
circle_shape.center += delta;
|
||||
}
|
||||
Shape::LineSegment { points, .. } => {
|
||||
for p in points {
|
||||
*p += delta;
|
||||
}
|
||||
}
|
||||
Shape::Path(path_shape) => {
|
||||
for p in &mut path_shape.points {
|
||||
*p += delta;
|
||||
}
|
||||
}
|
||||
Shape::Rect(rect_shape) => {
|
||||
rect_shape.rect = rect_shape.rect.translate(delta);
|
||||
}
|
||||
Shape::Text(text_shape) => {
|
||||
text_shape.pos += delta;
|
||||
}
|
||||
Shape::Mesh(mesh) => {
|
||||
mesh.translate(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -398,54 +449,3 @@ fn dashes_from_line(
|
|||
position_on_segment -= segment_length;
|
||||
});
|
||||
}
|
||||
|
||||
/// ## Operations
|
||||
impl Shape {
|
||||
pub fn mesh(mesh: Mesh) -> Self {
|
||||
crate::epaint_assert!(mesh.is_valid());
|
||||
Self::Mesh(mesh)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn texture_id(&self) -> super::TextureId {
|
||||
if let Shape::Mesh(mesh) = self {
|
||||
mesh.texture_id
|
||||
} else {
|
||||
super::TextureId::Egui
|
||||
}
|
||||
}
|
||||
|
||||
/// Translate location by this much, in-place
|
||||
pub fn translate(&mut self, delta: Vec2) {
|
||||
match self {
|
||||
Shape::Noop => {}
|
||||
Shape::Vec(shapes) => {
|
||||
for shape in shapes {
|
||||
shape.translate(delta);
|
||||
}
|
||||
}
|
||||
Shape::Circle(circle_shape) => {
|
||||
circle_shape.center += delta;
|
||||
}
|
||||
Shape::LineSegment { points, .. } => {
|
||||
for p in points {
|
||||
*p += delta;
|
||||
}
|
||||
}
|
||||
Shape::Path(path_shape) => {
|
||||
for p in &mut path_shape.points {
|
||||
*p += delta;
|
||||
}
|
||||
}
|
||||
Shape::Rect(rect_shape) => {
|
||||
rect_shape.rect = rect_shape.rect.translate(delta);
|
||||
}
|
||||
Shape::Text(text_shape) => {
|
||||
text_shape.pos += delta;
|
||||
}
|
||||
Shape::Mesh(mesh) => {
|
||||
mesh.translate(delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,21 +257,30 @@ pub enum PathType {
|
|||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
pub struct TessellationOptions {
|
||||
/// Size of a point in pixels, e.g. 2.0. Used to snap text to pixel boundaries.
|
||||
/// Size of a point in pixels (DPI scaling), e.g. 2.0. Used to snap text to pixel boundaries.
|
||||
pub pixels_per_point: f32,
|
||||
/// Size of a pixel in points, e.g. 0.5, or larger if you want more blurry edges.
|
||||
|
||||
/// The size of a pixel (in points), used for anti-aliasing (smoothing of edges).
|
||||
/// This is normally the inverse of [`Self::pixels_per_point`],
|
||||
/// but you can make it larger if you want more blurry edges.
|
||||
pub aa_size: f32,
|
||||
|
||||
/// Anti-aliasing makes shapes appear smoother, but requires more triangles and is therefore slower.
|
||||
/// This setting does not affect text.
|
||||
/// Default: `true`.
|
||||
pub anti_alias: bool,
|
||||
/// If `true` (default) cull certain primitives before tessellating them
|
||||
|
||||
/// If `true` (default) cull certain primitives before tessellating them.
|
||||
/// This likely makes
|
||||
pub coarse_tessellation_culling: bool,
|
||||
/// Output the clip rectangles to be painted?
|
||||
|
||||
/// Output the clip rectangles to be painted.
|
||||
pub debug_paint_clip_rects: bool,
|
||||
/// Output the text-containing rectangles
|
||||
|
||||
/// Output the text-containing rectangles.
|
||||
pub debug_paint_text_rects: bool,
|
||||
/// If true, no clipping will be done
|
||||
|
||||
/// If true, no clipping will be done.
|
||||
pub debug_ignore_clip_rects: bool,
|
||||
}
|
||||
|
||||
|
@ -503,7 +512,11 @@ fn mul_color(color: Color32, factor: f32) -> Color32 {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Converts [`Shape`]s into [`Mesh`].
|
||||
/// Converts [`Shape`]s into triangles ([`Mesh`]).
|
||||
///
|
||||
/// For performance reasons it is smart to reuse the same `Tessellator`.
|
||||
///
|
||||
/// Se also [`tessellate_shapes`], a convenient wrapper around [`Tessellator`].
|
||||
pub struct Tessellator {
|
||||
options: TessellationOptions,
|
||||
/// Only used for culling
|
||||
|
@ -513,6 +526,7 @@ pub struct Tessellator {
|
|||
}
|
||||
|
||||
impl Tessellator {
|
||||
/// Create a new [`Tessellator`].
|
||||
pub fn from_options(options: TessellationOptions) -> Self {
|
||||
Self {
|
||||
options,
|
||||
|
@ -524,12 +538,9 @@ impl Tessellator {
|
|||
|
||||
/// Tessellate a single [`Shape`] into a [`Mesh`].
|
||||
///
|
||||
/// * `shape`: the shape to tessellate
|
||||
/// * `options`: tessellation quality
|
||||
/// * `tex_size`: size of the font texture (required to normalize glyph uv rectangles)
|
||||
/// * `out`: where the triangles are put
|
||||
/// * `scratchpad_path`: if you plan to run `tessellate_shape`
|
||||
/// many times, pass it a reference to the same `Path` to avoid excessive allocations.
|
||||
/// * `tex_size`: size of the font texture (required to normalize glyph uv rectangles).
|
||||
/// * `shape`: the shape to tessellate.
|
||||
/// * `out`: triangles are appended to this.
|
||||
pub fn tessellate_shape(&mut self, tex_size: [usize; 2], shape: Shape, out: &mut Mesh) {
|
||||
let clip_rect = self.clip_rect;
|
||||
let options = &self.options;
|
||||
|
@ -776,13 +787,15 @@ impl Tessellator {
|
|||
|
||||
/// Turns [`Shape`]:s into sets of triangles.
|
||||
///
|
||||
/// The given shapes will be painted back-to-front (painters algorithm).
|
||||
/// The given shapes will tessellated in the same order as they are given.
|
||||
/// They will be batched together by clip rectangle.
|
||||
///
|
||||
/// * `shapes`: the shape to tessellate
|
||||
/// * `shapes`: what to tessellate
|
||||
/// * `options`: tessellation quality
|
||||
/// * `tex_size`: size of the font texture (required to normalize glyph uv rectangles)
|
||||
///
|
||||
/// The implementation uses a [`Tessellator`].
|
||||
///
|
||||
/// ## Returns
|
||||
/// A list of clip rectangles with matching [`Mesh`].
|
||||
pub fn tessellate_shapes(
|
||||
|
|
|
@ -201,6 +201,8 @@ impl Default for FontDefinitions {
|
|||
}
|
||||
|
||||
/// The collection of fonts used by `epaint`.
|
||||
///
|
||||
/// Required in order to paint text.
|
||||
pub struct Fonts {
|
||||
pixels_per_point: f32,
|
||||
definitions: FontDefinitions,
|
||||
|
@ -214,6 +216,8 @@ pub struct Fonts {
|
|||
}
|
||||
|
||||
impl Fonts {
|
||||
/// Create a new [`Fonts`] for text layout.
|
||||
/// This call is expensive, so only create on [`Fonts`] and then reuse it.
|
||||
pub fn new(pixels_per_point: f32, definitions: FontDefinitions) -> Self {
|
||||
assert!(
|
||||
0.0 < pixels_per_point && pixels_per_point < 100.0,
|
||||
|
|
|
@ -11,12 +11,37 @@ use emath::*;
|
|||
///
|
||||
/// This supports mixing different fonts, color and formats (underline etc).
|
||||
///
|
||||
/// Pass this to [`Fonts::layout_job]` or [`crate::text::layout`].
|
||||
/// Pass this to [`crate::Fonts::layout_job`] or [`crate::text::layout`].
|
||||
///
|
||||
/// ## Example:
|
||||
/// ```
|
||||
/// use epaint::{Color32, text::{LayoutJob, TextFormat}, TextStyle};
|
||||
///
|
||||
/// let mut job = LayoutJob::default();
|
||||
/// job.append(
|
||||
/// "Hello ",
|
||||
/// 0.0,
|
||||
/// TextFormat {
|
||||
/// style: TextStyle::Body,
|
||||
/// color: Color32::WHITE,
|
||||
/// ..Default::default()
|
||||
/// },
|
||||
/// );
|
||||
/// job.append(
|
||||
/// "World!",
|
||||
/// 0.0,
|
||||
/// TextFormat {
|
||||
/// style: TextStyle::Monospace,
|
||||
/// color: Color32::BLACK,
|
||||
/// ..Default::default()
|
||||
/// },
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct LayoutJob {
|
||||
/// The complete text of this job, referenced by `LayoutSection`.
|
||||
pub text: String, // TODO: Cow<'static, str>
|
||||
pub text: String,
|
||||
|
||||
/// The different section, which can have different fonts, colors, etc.
|
||||
pub sections: Vec<LayoutSection>,
|
||||
|
@ -206,6 +231,9 @@ impl TextFormat {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Text that has been layed out, ready for painting.
|
||||
///
|
||||
/// You can create a [`Galley`] using [`crate::Fonts::layout_job`];
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Galley {
|
||||
/// The job that this galley is the result of.
|
||||
|
|
|
@ -91,8 +91,8 @@ pub trait App {
|
|||
|
||||
/// Called once before the first frame.
|
||||
///
|
||||
/// Allows you to do setup code, e.g to call `[egui::Context::set_fonts]`,
|
||||
/// `[egui::Context::set_visuals]` etc.
|
||||
/// Allows you to do setup code, e.g to call [`egui::Context::set_fonts`],
|
||||
/// [`egui::Context::set_visuals`] etc.
|
||||
///
|
||||
/// Also allows you to restore state, if there is a storage (required the "persistence" feature).
|
||||
fn setup(
|
||||
|
@ -106,6 +106,9 @@ pub trait App {
|
|||
/// If `true` a warm-up call to [`Self::update`] will be issued where
|
||||
/// `ctx.memory().everything_is_visible()` will be set to `true`.
|
||||
///
|
||||
/// This will help pre-caching all text, preventing stutter when
|
||||
/// opening a window containing new glyphs.
|
||||
///
|
||||
/// In this warm-up call, all painted shapes will be ignored.
|
||||
fn warm_up_enabled(&self) -> bool {
|
||||
false
|
||||
|
|
Loading…
Reference in a new issue