mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 06:40:06 -04:00
Deduplicate shared builder fns
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
AtomKind, Atoms, FontSelection, Frame, Id, Image, IntoAtoms, SizedAtom, SizedAtomKind, Ui,
|
AtomKind, Atoms, FontSelection, Frame, Id, Image, IntoAtoms, SizedAtom, SizedAtomKind, Ui,
|
||||||
|
WidgetAtom,
|
||||||
};
|
};
|
||||||
use emath::{Align2, GuiRounding as _, NumExt as _, Rect, Vec2};
|
use emath::{Align2, GuiRounding as _, NumExt as _, Rect, Vec2};
|
||||||
use epaint::text::TextWrapMode;
|
use epaint::text::TextWrapMode;
|
||||||
@@ -64,99 +65,6 @@ impl<'a> ContainerAtom<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the gap between atoms.
|
|
||||||
///
|
|
||||||
/// Default: `Spacing::icon_spacing`
|
|
||||||
#[inline]
|
|
||||||
pub fn gap(mut self, gap: f32) -> Self {
|
|
||||||
self.gap = Some(gap);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the [`Frame`].
|
|
||||||
#[inline]
|
|
||||||
pub fn frame(mut self, frame: Frame) -> Self {
|
|
||||||
self.frame = frame;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the fallback (default) text color.
|
|
||||||
///
|
|
||||||
/// Default: [`crate::Visuals::text_color`]
|
|
||||||
#[inline]
|
|
||||||
pub fn fallback_text_color(mut self, color: Color32) -> Self {
|
|
||||||
self.fallback_text_color = Some(color);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the fallback (default) font.
|
|
||||||
#[inline]
|
|
||||||
pub fn fallback_font(mut self, font: impl Into<FontSelection>) -> Self {
|
|
||||||
self.fallback_font = Some(font.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the minimum size of the Widget.
|
|
||||||
///
|
|
||||||
/// This will find and expand atoms with `grow: true`.
|
|
||||||
/// If there are no growable atoms then everything will be left-aligned.
|
|
||||||
#[inline]
|
|
||||||
pub fn min_size(mut self, size: Vec2) -> Self {
|
|
||||||
self.min_size = size;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum size of the Widget.
|
|
||||||
///
|
|
||||||
/// By default, the size is limited by the available size in the [`Ui`].
|
|
||||||
#[inline]
|
|
||||||
pub fn max_size(mut self, size: Vec2) -> Self {
|
|
||||||
self.max_size = size;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum width of the Widget.
|
|
||||||
///
|
|
||||||
/// By default, the width is limited by the available width in the [`Ui`].
|
|
||||||
#[inline]
|
|
||||||
pub fn max_width(mut self, width: f32) -> Self {
|
|
||||||
self.max_size.x = width;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum height of the Widget.
|
|
||||||
///
|
|
||||||
/// By default, the height is limited by the available height in the [`Ui`].
|
|
||||||
#[inline]
|
|
||||||
pub fn max_height(mut self, height: f32) -> Self {
|
|
||||||
self.max_size.y = height;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the [`TextWrapMode`] for the [`crate::Atom`] marked as `shrink`.
|
|
||||||
///
|
|
||||||
/// Only a single [`crate::Atom`] may shrink. If this (or `ui.wrap_mode()`) is not
|
|
||||||
/// [`TextWrapMode::Extend`] and no item is set to shrink, the first (left-most)
|
|
||||||
/// [`AtomKind::Text`] will be set to shrink.
|
|
||||||
#[inline]
|
|
||||||
pub fn wrap_mode(mut self, wrap_mode: TextWrapMode) -> Self {
|
|
||||||
self.wrap_mode = Some(wrap_mode);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the [`Align2`].
|
|
||||||
///
|
|
||||||
/// This will align the [`crate::Atom`]s within the [`Rect`] returned by [`Ui::allocate_space`].
|
|
||||||
///
|
|
||||||
/// The default is chosen based on the [`Ui`]s [`crate::Layout`]. See
|
|
||||||
/// [this snapshot](https://github.com/emilk/egui/blob/master/tests/egui_tests/tests/snapshots/layout/button.png)
|
|
||||||
/// for info on how the [`crate::Layout`] affects the alignment.
|
|
||||||
#[inline]
|
|
||||||
pub fn align2(mut self, align2: Align2) -> Self {
|
|
||||||
self.align2 = Some(align2);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Measure the atoms (sizing only), without allocating space or interacting.
|
/// Measure the atoms (sizing only), without allocating space or interacting.
|
||||||
///
|
///
|
||||||
/// This converts texts to [`Galley`]s and calculates sizes, but it does *not* call
|
/// This converts texts to [`Galley`]s and calculates sizes, but it does *not* call
|
||||||
@@ -312,6 +220,118 @@ impl<'a> ContainerAtom<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates the layout-builder methods shared by [`ContainerAtom`] and [`WidgetAtom`] from a
|
||||||
|
/// single definition, so the two can never drift apart.
|
||||||
|
///
|
||||||
|
/// Each entry is written as it appears on [`ContainerAtom`] (mutating its own fields). The
|
||||||
|
/// matching method on [`WidgetAtom`] is generated automatically, forwarding to its inner
|
||||||
|
/// `container`. [`WidgetAtom`]-only builders (`id`, `sense`) stay inherent on [`WidgetAtom`].
|
||||||
|
macro_rules! shared_container_builders {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
$(#[$meta:meta])*
|
||||||
|
fn $name:ident($self:ident, $($arg:ident: $arg_ty:ty),* $(,)?) $body:block
|
||||||
|
)*
|
||||||
|
) => {
|
||||||
|
impl<'a> ContainerAtom<'a> {
|
||||||
|
$(
|
||||||
|
$(#[$meta])*
|
||||||
|
#[inline]
|
||||||
|
pub fn $name(mut $self, $($arg: $arg_ty),*) -> Self {
|
||||||
|
$body
|
||||||
|
$self
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> WidgetAtom<'a> {
|
||||||
|
$(
|
||||||
|
$(#[$meta])*
|
||||||
|
#[inline]
|
||||||
|
pub fn $name(mut self, $($arg: $arg_ty),*) -> Self {
|
||||||
|
self.container = self.container.$name($($arg),*);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_container_builders! {
|
||||||
|
/// Set the gap between atoms.
|
||||||
|
///
|
||||||
|
/// Default: `Spacing::icon_spacing`
|
||||||
|
fn gap(self, gap: f32) {
|
||||||
|
self.gap = Some(gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the [`Frame`].
|
||||||
|
fn frame(self, frame: Frame) {
|
||||||
|
self.frame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the fallback (default) text color.
|
||||||
|
///
|
||||||
|
/// Default: [`crate::Visuals::text_color`]
|
||||||
|
fn fallback_text_color(self, color: Color32) {
|
||||||
|
self.fallback_text_color = Some(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the fallback (default) font.
|
||||||
|
fn fallback_font(self, font: impl Into<FontSelection>) {
|
||||||
|
self.fallback_font = Some(font.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the minimum size of the Widget.
|
||||||
|
///
|
||||||
|
/// This will find and expand atoms with `grow: true`.
|
||||||
|
/// If there are no growable atoms then everything will be left-aligned.
|
||||||
|
fn min_size(self, size: Vec2) {
|
||||||
|
self.min_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the maximum size of the Widget.
|
||||||
|
///
|
||||||
|
/// By default, the size is limited by the available size in the [`Ui`].
|
||||||
|
fn max_size(self, size: Vec2) {
|
||||||
|
self.max_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the maximum width of the Widget.
|
||||||
|
///
|
||||||
|
/// By default, the width is limited by the available width in the [`Ui`].
|
||||||
|
fn max_width(self, width: f32) {
|
||||||
|
self.max_size.x = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the maximum height of the Widget.
|
||||||
|
///
|
||||||
|
/// By default, the height is limited by the available height in the [`Ui`].
|
||||||
|
fn max_height(self, height: f32) {
|
||||||
|
self.max_size.y = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the [`TextWrapMode`] for the [`crate::Atom`] marked as `shrink`.
|
||||||
|
///
|
||||||
|
/// Only a single [`crate::Atom`] may shrink. If this (or `ui.wrap_mode()`) is not
|
||||||
|
/// [`TextWrapMode::Extend`] and no item is set to shrink, the first (left-most)
|
||||||
|
/// [`AtomKind::Text`] will be set to shrink.
|
||||||
|
fn wrap_mode(self, wrap_mode: TextWrapMode) {
|
||||||
|
self.wrap_mode = Some(wrap_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the [`Align2`].
|
||||||
|
///
|
||||||
|
/// This will align the [`crate::Atom`]s within the [`Rect`] returned by [`Ui::allocate_space`].
|
||||||
|
///
|
||||||
|
/// The default is chosen based on the [`Ui`]s [`crate::Layout`]. See
|
||||||
|
/// [this snapshot](https://github.com/emilk/egui/blob/master/tests/egui_tests/tests/snapshots/layout/button.png)
|
||||||
|
/// for info on how the [`crate::Layout`] affects the alignment.
|
||||||
|
fn align2(self, align2: Align2) {
|
||||||
|
self.align2 = Some(align2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A measured [`ContainerAtom`], ready to be painted at a [`Rect`].
|
/// A measured [`ContainerAtom`], ready to be painted at a [`Rect`].
|
||||||
///
|
///
|
||||||
/// Produced by [`ContainerAtom::measure`]. It has not yet allocated space or interacted, so it
|
/// Produced by [`ContainerAtom::measure`]. It has not yet allocated space or interacted, so it
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
use crate::{
|
use crate::{ContainerAtom, Id, IntoAtoms, Response, Sense, SizedContainerAtom, Ui, Widget};
|
||||||
Align2, Color32, ContainerAtom, FontSelection, Frame, Id, IntoAtoms, Response, Sense,
|
|
||||||
SizedContainerAtom, Ui, Widget,
|
|
||||||
};
|
|
||||||
use emath::{Rect, Vec2};
|
use emath::{Rect, Vec2};
|
||||||
use epaint::text::TextWrapMode;
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
@@ -20,9 +16,9 @@ use std::ops::{Deref, DerefMut};
|
|||||||
/// - allocates a [`Response`]
|
/// - allocates a [`Response`]
|
||||||
/// - returns an [`AllocatedWidgetAtom`]
|
/// - returns an [`AllocatedWidgetAtom`]
|
||||||
/// - [`AllocatedWidgetAtom::paint`]
|
/// - [`AllocatedWidgetAtom::paint`]
|
||||||
/// - paints the [`Frame`] and each single atom
|
/// - paints the [`crate::Frame`] and each single atom
|
||||||
///
|
///
|
||||||
/// You can use this to first allocate a response and then modify, e.g., the [`Frame`] on the
|
/// You can use this to first allocate a response and then modify, e.g., the [`crate::Frame`] on the
|
||||||
/// [`AllocatedWidgetAtom`] for interaction styling.
|
/// [`AllocatedWidgetAtom`] for interaction styling.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WidgetAtom<'a> {
|
pub struct WidgetAtom<'a> {
|
||||||
@@ -60,98 +56,9 @@ impl<'a> WidgetAtom<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the gap between atoms.
|
// The builders shared with `ContainerAtom` (`gap`, `frame`, `fallback_font`, `min_size`,
|
||||||
///
|
// `wrap_mode`, …) are generated by the `shared_container_builders!` macro in
|
||||||
/// Default: `Spacing::icon_spacing`
|
// `container_atom.rs`, so the two types can never drift apart.
|
||||||
#[inline]
|
|
||||||
pub fn gap(mut self, gap: f32) -> Self {
|
|
||||||
self.container = self.container.gap(gap);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the [`Frame`].
|
|
||||||
#[inline]
|
|
||||||
pub fn frame(mut self, frame: Frame) -> Self {
|
|
||||||
self.container = self.container.frame(frame);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the fallback (default) text color.
|
|
||||||
///
|
|
||||||
/// Default: [`crate::Visuals::text_color`]
|
|
||||||
#[inline]
|
|
||||||
pub fn fallback_text_color(mut self, color: Color32) -> Self {
|
|
||||||
self.container = self.container.fallback_text_color(color);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the fallback (default) font.
|
|
||||||
#[inline]
|
|
||||||
pub fn fallback_font(mut self, font: impl Into<FontSelection>) -> Self {
|
|
||||||
self.container = self.container.fallback_font(font);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the minimum size of the Widget.
|
|
||||||
///
|
|
||||||
/// This will find and expand atoms with `grow: true`.
|
|
||||||
/// If there are no growable atoms then everything will be left-aligned.
|
|
||||||
#[inline]
|
|
||||||
pub fn min_size(mut self, size: Vec2) -> Self {
|
|
||||||
self.container = self.container.min_size(size);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum size of the Widget.
|
|
||||||
///
|
|
||||||
/// By default, the size is limited by the available size in the [`Ui`].
|
|
||||||
#[inline]
|
|
||||||
pub fn max_size(mut self, size: Vec2) -> Self {
|
|
||||||
self.container = self.container.max_size(size);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum width of the Widget.
|
|
||||||
///
|
|
||||||
/// By default, the width is limited by the available width in the [`Ui`].
|
|
||||||
#[inline]
|
|
||||||
pub fn max_width(mut self, width: f32) -> Self {
|
|
||||||
self.container = self.container.max_width(width);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum height of the Widget.
|
|
||||||
///
|
|
||||||
/// By default, the height is limited by the available height in the [`Ui`].
|
|
||||||
#[inline]
|
|
||||||
pub fn max_height(mut self, height: f32) -> Self {
|
|
||||||
self.container = self.container.max_height(height);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the [`TextWrapMode`] for the [`crate::Atom`] marked as `shrink`.
|
|
||||||
///
|
|
||||||
/// Only a single [`crate::Atom`] may shrink. If this (or `ui.wrap_mode()`) is not
|
|
||||||
/// [`TextWrapMode::Extend`] and no item is set to shrink, the first (left-most)
|
|
||||||
/// [`crate::AtomKind::Text`] will be set to shrink.
|
|
||||||
#[inline]
|
|
||||||
pub fn wrap_mode(mut self, wrap_mode: TextWrapMode) -> Self {
|
|
||||||
self.container = self.container.wrap_mode(wrap_mode);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the [`Align2`].
|
|
||||||
///
|
|
||||||
/// This will align the [`crate::Atom`]s within the [`Rect`] returned by [`Ui::allocate_space`].
|
|
||||||
///
|
|
||||||
/// The default is chosen based on the [`Ui`]s [`crate::Layout`]. See
|
|
||||||
/// [this snapshot](https://github.com/emilk/egui/blob/master/tests/egui_tests/tests/snapshots/layout/button.png)
|
|
||||||
/// for info on how the [`crate::Layout`] affects the alignment.
|
|
||||||
#[inline]
|
|
||||||
pub fn align2(mut self, align2: Align2) -> Self {
|
|
||||||
self.container = self.container.align2(align2);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [`WidgetAtom::allocate`] and [`AllocatedWidgetAtom::paint`] in one go.
|
/// [`WidgetAtom::allocate`] and [`AllocatedWidgetAtom::paint`] in one go.
|
||||||
pub fn show(self, ui: &mut Ui) -> WidgetAtomResponse {
|
pub fn show(self, ui: &mut Ui) -> WidgetAtomResponse {
|
||||||
@@ -223,7 +130,7 @@ impl<'a> SizedWidgetAtom<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interact at `rect` and paint the [`Frame`] and atoms there.
|
/// Interact at `rect` and paint the [`crate::Frame`] and atoms there.
|
||||||
///
|
///
|
||||||
/// Unlike [`Self::allocate`] this does not call [`Ui::allocate_space`]; it interacts at the
|
/// Unlike [`Self::allocate`] this does not call [`Ui::allocate_space`]; it interacts at the
|
||||||
/// given `rect` using this widget's [`Id`] and [`Sense`]. This is used when nesting one
|
/// given `rect` using this widget's [`Id`] and [`Sense`]. This is used when nesting one
|
||||||
@@ -251,7 +158,7 @@ pub struct AllocatedWidgetAtom<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AllocatedWidgetAtom<'_> {
|
impl AllocatedWidgetAtom<'_> {
|
||||||
/// Paint the [`Frame`] and individual [`crate::Atom`]s at the allocated [`Response`]'s rect.
|
/// Paint the [`crate::Frame`] and individual [`crate::Atom`]s at the allocated [`Response`]'s rect.
|
||||||
pub fn paint(self, ui: &Ui) -> WidgetAtomResponse {
|
pub fn paint(self, ui: &Ui) -> WidgetAtomResponse {
|
||||||
let rect = self.response.rect;
|
let rect = self.response.rect;
|
||||||
let custom_rects = self.container.paint_at(ui, rect);
|
let custom_rects = self.container.paint_at(ui, rect);
|
||||||
|
|||||||
Reference in New Issue
Block a user