Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: const-ify the core primitives #5032

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
689e99b
refactor(math): use `Option::zip` for cleaner code
BastiDood Aug 29, 2024
e13d754
feat(math): add `const` where stable
BastiDood Aug 29, 2024
2fbf71d
feat(math): introduce `const` alternatives for `Vec2b::and` and `Vec2…
BastiDood Aug 29, 2024
d1c37ed
feat(color): use `const` where stable
BastiDood Aug 29, 2024
fdfe280
refactor(paint): use `default` attribute when deriving `Default`
BastiDood Aug 29, 2024
278c5fb
feat(paint): add `const` where stable
BastiDood Aug 29, 2024
9139060
feat(paint): add `Self::DEFAULT` constants
BastiDood Aug 29, 2024
1586664
feat(paint): add `const` alternatives to constructors
BastiDood Aug 29, 2024
789bcf5
refactor(paint): prefer `f32::INFINITY` constant
BastiDood Aug 29, 2024
f59abbc
refactor(gui): use `const` functions where stable
BastiDood Aug 29, 2024
fe73fa2
refactor(gui): implement `const` alternatives for various constructors
BastiDood Aug 29, 2024
a56382b
refactor(gui): prefer destructuring width and height
BastiDood Aug 29, 2024
ffc0dd3
refactor(gui): prefer using the `f32::recip` helper
BastiDood Aug 29, 2024
c105ef0
fix(gui): remove `const` for runtime-only functions
BastiDood Aug 29, 2024
860aab0
refactor(frame): add `const` where stable
BastiDood Aug 29, 2024
f05de6f
fix(gui): add `inline` to builder methods
BastiDood Aug 30, 2024
4f34491
chore: update branch from `main`
BastiDood Aug 30, 2024
b3c847f
fix(gui): add missing `const` in builders
BastiDood Aug 30, 2024
fa1f6ac
chore(paint): fix typo on `Shadow`
BastiDood Sep 1, 2024
fae5fdd
fix(gui): revert `const` for `UiBuilder::style`
BastiDood Sep 1, 2024
ec12532
chore: update branch from `master`
BastiDood Sep 2, 2024
f17659b
chore(clippy): remove needless borrow
BastiDood Sep 2, 2024
7028897
fix(paint): use correct default value for `PathShape::fill`
BastiDood Sep 2, 2024
59a351e
chore: update branch from `main`
BastiDood Sep 2, 2024
c93ea59
feat(gui): add `const` to `Sides`
BastiDood Sep 2, 2024
6cc2eee
chore: merge updates from `master`
BastiDood Sep 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor(gui): implement const alternatives for various constructors
BastiDood committed Aug 29, 2024
commit fe73fa25819435e54527237cd584882ca4f7d704
33 changes: 27 additions & 6 deletions crates/egui/src/containers/area.rs
Original file line number Diff line number Diff line change
@@ -222,11 +222,18 @@ impl Area {
}

#[inline]
pub fn default_pos(mut self, default_pos: impl Into<Pos2>) -> Self {
self.default_pos = Some(default_pos.into());
pub const fn const_default_pos(mut self, default_pos: Pos2) -> Self {
self.default_pos = Some(default_pos);
self
}

/// See [`Self::const_default_pos`].
#[inline]
pub fn default_pos(self, default_pos: impl Into<Pos2>) -> Self {
let default_pos = default_pos.into();
self.const_default_pos(default_pos)
}
Comment on lines +225 to +235
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems excessive - realistically, why would you want to construct a const Area?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does sound funny, but the overall goal of this PR is to at least enable the user to compute certain initial states at compile-time. I presume that the #[inline] already does this for optimized builds, but the added bonus feature of const is that the user can now store these Area configurations inside a const or a static so that they are guaranteed to be initialized at compile-time (rather than hoping that #[inline] would do that for us).

So yes, semantically, a "movable const container" is silly. Though I think the const-ness is a misnomer for what we're actually enabling here. That is, we're not enforcing an immutable Area; rather, we are enabling the compile-time initialization of an Area. The const keyword is just an unfortunately overloaded term.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding const to some methods is fine, but duplicating methods is not - please revert those changes

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the trivially const methods in the higher-level abstractions rely on the lower-level const_* duplicates. For instance, this PR's modification of the egui::style:Visuals::dark constructor invokes Stroke::const_new in order to be trivially const.

window_stroke: Stroke::const_new(1.0, Color32::from_gray(60)),

Would it be amenable to keep the const alternatives private in the meantime (i.e., until const traits stabilize) just so we can keep the powers of const available even in the higher-level abstractions without cluttering the public interface with duplicates?


/// The size used for the [`Ui::max_rect`] the first frame.
///
/// Text will wrap at this width, and images that expand to fill the available space
@@ -312,11 +319,18 @@ impl Area {

/// Positions the window but you can still move it.
#[inline]
pub fn current_pos(mut self, current_pos: impl Into<Pos2>) -> Self {
self.new_pos = Some(current_pos.into());
pub const fn const_current_pos(mut self, current_pos: Pos2) -> Self {
self.new_pos = Some(current_pos);
self
}

/// See [`Self::const_current_pos`].
#[inline]
pub fn current_pos(self, current_pos: impl Into<Pos2>) -> Self {
let current_pos = current_pos.into();
self.const_current_pos(current_pos)
}

/// Set anchor and distance.
///
/// An anchor of `Align2::RIGHT_TOP` means "put the right-top corner of the window
@@ -329,11 +343,18 @@ impl Area {
///
/// It is an error to set both an anchor and a position.
#[inline]
pub fn anchor(mut self, align: Align2, offset: impl Into<Vec2>) -> Self {
self.anchor = Some((align, offset.into()));
pub const fn const_anchor(mut self, align: Align2, offset: Vec2) -> Self {
self.anchor = Some((align, offset));
self.movable(false)
}

/// See [`Self::const_anchor`].
#[inline]
pub fn anchor(self, align: Align2, offset: impl Into<Vec2>) -> Self {
let offset = offset.into();
self.const_anchor(align, offset)
}

pub(crate) const fn get_pivot(&self) -> Align2 {
if let Some((pivot, _)) = self.anchor {
pivot
44 changes: 36 additions & 8 deletions crates/egui/src/containers/frame.rs
Original file line number Diff line number Diff line change
@@ -169,31 +169,59 @@ impl Frame {
}

#[inline]
pub fn stroke(mut self, stroke: impl Into<Stroke>) -> Self {
self.stroke = stroke.into();
pub const fn const_stroke(mut self, stroke: Stroke) -> Self {
self.stroke = stroke;
self
}

/// See [`Self::const_stroke`].
#[inline]
pub fn rounding(mut self, rounding: impl Into<Rounding>) -> Self {
self.rounding = rounding.into();
pub fn stroke(self, stroke: impl Into<Stroke>) -> Self {
let stroke = stroke.into();
self.const_stroke(stroke)
}

#[inline]
pub const fn const_rounding(mut self, rounding: Rounding) -> Self {
self.rounding = rounding;
self
}

/// See [`Self::const_rounding`].
#[inline]
pub fn rounding(self, rounding: impl Into<Rounding>) -> Self {
let rounding = rounding.into();
self.const_rounding(rounding)
}

/// Margin within the painted frame.
#[inline]
pub fn inner_margin(mut self, inner_margin: impl Into<Margin>) -> Self {
self.inner_margin = inner_margin.into();
pub const fn const_inner_margin(mut self, inner_margin: Margin) -> Self {
self.inner_margin = inner_margin;
self
}

/// See [`Self::const_inner_margin`].
#[inline]
pub fn inner_margin(self, inner_margin: impl Into<Margin>) -> Self {
let inner_margin = inner_margin.into();
self.const_inner_margin(inner_margin)
}

/// Margin outside the painted frame.
#[inline]
pub fn outer_margin(mut self, outer_margin: impl Into<Margin>) -> Self {
self.outer_margin = outer_margin.into();
pub const fn const_outer_margin(mut self, outer_margin: Margin) -> Self {
self.outer_margin = outer_margin;
self
}

/// See [`Self::const_outer_margin`].
#[inline]
pub fn outer_margin(self, outer_margin: impl Into<Margin>) -> Self {
let outer_margin = outer_margin.into();
self.const_outer_margin(outer_margin)
}

#[inline]
pub const fn shadow(mut self, shadow: Shadow) -> Self {
self.shadow = shadow;
52 changes: 44 additions & 8 deletions crates/egui/src/containers/panel.rs
Original file line number Diff line number Diff line change
@@ -109,20 +109,32 @@ pub struct SidePanel {

impl SidePanel {
/// The id should be globally unique, e.g. `Id::new("my_left_panel")`.
pub const fn const_left(id: Id) -> Self {
Self::const_new(Side::Left, id)
}

/// See [`Self::const_left`].
pub fn left(id: impl Into<Id>) -> Self {
Self::new(Side::Left, id)
let id = id.into();
Self::const_left(id)
}

/// The id should be globally unique, e.g. `Id::new("my_right_panel")`.
pub const fn const_right(id: Id) -> Self {
Self::const_new(Side::Right, id)
}

/// See [`Self::const_right`].
pub fn right(id: impl Into<Id>) -> Self {
Self::new(Side::Right, id)
let id = id.into();
Self::const_right(id)
}

/// The id should be globally unique, e.g. `Id::new("my_panel")`.
pub fn new(side: Side, id: impl Into<Id>) -> Self {
pub const fn const_new(side: Side, id: Id) -> Self {
Self {
side,
id: id.into(),
id,
frame: None,
resizable: true,
show_separator_line: true,
@@ -131,6 +143,12 @@ impl SidePanel {
}
}

/// See [`Self::const_new`].
pub fn new(side: Side, id: impl Into<Id>) -> Self {
let id = id.into();
Self::const_new(side, id)
}

/// Can panel be resized by dragging the edge of it?
///
/// Default is `true`.
@@ -587,20 +605,32 @@ pub struct TopBottomPanel {

impl TopBottomPanel {
/// The id should be globally unique, e.g. `Id::new("my_top_panel")`.
pub const fn const_top(id: Id) -> Self {
Self::const_new(TopBottomSide::Top, id)
}

/// See [`Self::const_top`].
pub fn top(id: impl Into<Id>) -> Self {
Self::new(TopBottomSide::Top, id)
let id = id.into();
Self::const_top(id)
}

/// The id should be globally unique, e.g. `Id::new("my_bottom_panel")`.
pub const fn const_bottom(id: Id) -> Self {
Self::const_new(TopBottomSide::Bottom, id)
}

/// See [`Self::const_bottom`].
pub fn bottom(id: impl Into<Id>) -> Self {
Self::new(TopBottomSide::Bottom, id)
let id = id.into();
Self::const_bottom(id)
}

/// The id should be globally unique, e.g. `Id::new("my_panel")`.
pub fn new(side: TopBottomSide, id: impl Into<Id>) -> Self {
pub const fn const_new(side: TopBottomSide, id: Id) -> Self {
Self {
side,
id: id.into(),
id,
frame: None,
resizable: false,
show_separator_line: true,
@@ -609,6 +639,12 @@ impl TopBottomPanel {
}
}

/// See [`Self::const_new`].
pub fn new(side: TopBottomSide, id: impl Into<Id>) -> Self {
let id = id.into();
Self::const_new(side, id)
}

/// Can panel be resized by dragging the edge of it?
///
/// Default is `false`.
73 changes: 57 additions & 16 deletions crates/egui/src/containers/resize.rs
Original file line number Diff line number Diff line change
@@ -71,11 +71,18 @@ impl Resize {

/// A source for the unique [`Id`], e.g. `.id_source("second_resize_area")` or `.id_source(loop_index)`.
#[inline]
pub fn id_source(mut self, id_source: impl std::hash::Hash) -> Self {
self.id_source = Some(Id::new(id_source));
pub const fn const_id_source(mut self, id: Id) -> Self {
self.id_source = Some(id);
self
}

/// See [`Self::const_id_source`].
#[inline]
pub fn id_source(self, id_source: impl std::hash::Hash) -> Self {
let id = Id::new(id_source);
self.const_id_source(id)
}

/// Preferred / suggested width. Actual width will depend on contents.
///
/// Examples:
@@ -102,18 +109,32 @@ impl Resize {
}

#[inline]
pub fn default_size(mut self, default_size: impl Into<Vec2>) -> Self {
self.default_size = default_size.into();
pub const fn const_default_size(mut self, default_size: Vec2) -> Self {
self.default_size = default_size;
self
}

/// See [`Self::const_default_size`].
#[inline]
pub fn default_size(self, default_size: impl Into<Vec2>) -> Self {
let default_size = default_size.into();
self.const_default_size(default_size)
}

/// Won't shrink to smaller than this
#[inline]
pub fn min_size(mut self, min_size: impl Into<Vec2>) -> Self {
self.min_size = min_size.into();
pub const fn const_min_size(mut self, min_size: Vec2) -> Self {
self.min_size = min_size;
self
}

/// See [`Self::const_min_size`].
#[inline]
pub fn min_size(self, min_size: impl Into<Vec2>) -> Self {
let min_size = min_size.into();
self.const_min_size(min_size)
}

/// Won't shrink to smaller than this
#[inline]
pub const fn min_width(mut self, min_width: f32) -> Self {
@@ -130,11 +151,18 @@ impl Resize {

/// Won't expand to larger than this
#[inline]
pub fn max_size(mut self, max_size: impl Into<Vec2>) -> Self {
self.max_size = max_size.into();
pub const fn const_max_size(mut self, max_size: Vec2) -> Self {
self.max_size = max_size;
self
}

/// See [`Self::const_max_size`].
#[inline]
pub fn max_size(self, max_size: impl Into<Vec2>) -> Self {
let max_size = max_size.into();
self.const_max_size(max_size)
}

/// Won't expand to larger than this
#[inline]
pub const fn max_width(mut self, max_width: f32) -> Self {
@@ -155,34 +183,47 @@ impl Resize {
///
/// Default is `true`.
#[inline]
pub fn resizable(mut self, resizable: impl Into<Vec2b>) -> Self {
self.resizable = resizable.into();
pub const fn const_resizable(mut self, resizable: Vec2b) -> Self {
self.resizable = resizable;
self
}

/// See [`Self::const_resizable`].
#[inline]
pub fn resizable(self, resizable: impl Into<Vec2b>) -> Self {
let resizable = resizable.into();
self.const_resizable(resizable)
}

#[inline]
pub const fn is_resizable(&self) -> Vec2b {
self.resizable
}

/// Not manually resizable, just takes the size of its contents.
/// Text will not wrap, but will instead make your window width expand.
pub fn auto_sized(self) -> Self {
self.min_size(Vec2::ZERO)
.default_size(Vec2::splat(f32::INFINITY))
.resizable(false)
pub const fn auto_sized(self) -> Self {
self.const_min_size(Vec2::ZERO)
.const_default_size(Vec2::splat(f32::INFINITY))
.const_resizable(Vec2b::FALSE)
}

#[inline]
pub fn fixed_size(mut self, size: impl Into<Vec2>) -> Self {
let size = size.into();
pub const fn const_fixed_size(mut self, size: Vec2) -> Self {
self.default_size = size;
self.min_size = size;
self.max_size = size;
self.resizable = Vec2b::FALSE;
self
}

/// See [`Self::const_fixed_size`].
#[inline]
pub fn fixed_size(self, size: impl Into<Vec2>) -> Self {
let size = size.into();
self.const_fixed_size(size)
}

#[inline]
pub const fn with_stroke(mut self, with_stroke: bool) -> Self {
self.with_stroke = with_stroke;
Loading